32#include "ocpn_pixel.h"
34#ifdef __OCPN__ANDROID__
35#include "androidUTIL.h"
41#include <wx/listimpl.cpp>
42WX_DEFINE_LIST(PatchList);
45extern s52plib *ps52plib;
46extern ColorScheme global_color_scheme;
47extern int g_chart_zoom_modifier_raster;
48extern int g_chart_zoom_modifier_vector;
49extern bool g_fog_overzoom;
50extern double g_overzoom_emphasis_base;
61#ifndef __OCPN__ANDROID__
62#define GetChartTableEntry(i) GetChartTable()[i]
71#define NOCOVR_PLY_PERF_LIMIT 500
72#define AUX_PLY_PERF_LIMIT 500
74static int CompareScales(
int i1,
int i2) {
75 if (!ChartData)
return 0;
80 if (cte1.Scale_eq(cte2.GetScale())) {
82 lat1 = cte1.GetLatMax();
83 lat2 = cte2.GetLatMax();
84 if (roundf(lat1 * 100.) == roundf(lat2 * 100.)) {
86 lon1 = cte1.GetLonMin();
87 lon2 = cte2.GetLonMin();
91 return (lon1 < lon2) ? -1 : 1;
93 return (lat1 < lat2) ? 1 : -1;
95 return cte1.GetScale() - cte2.GetScale();
97static bool CompareScalesStd(
int i1,
int i2) {
98 return CompareScales(i1, i2) < 0;
103 if (!ChartData)
return 0;
104 return CompareScales(qc1->dbIndex, qc2->dbIndex);
107const LLRegion &QuiltCandidate::GetCandidateRegion() {
109 LLRegion &candidate_region =
110 const_cast<LLRegion &
>(cte.quilt_candidate_region);
112 if (!candidate_region.Empty())
return candidate_region;
114 LLRegion world_region(-90, -180, 90, 180);
118 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93COMP) {
119 double cm93_ll_bounds[8] = {-80, -180, -80, 180, 80, 180, 80, -180};
120 candidate_region = LLRegion(4, cm93_ll_bounds);
121 return candidate_region;
125 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
126 if (nAuxPlyEntries >= 1) {
127 candidate_region.Clear();
128 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
129 float *pfp = cte.GetpAuxPlyTableEntry(ip);
130 int nAuxPly = cte.GetAuxCntTableEntry(ip);
132 candidate_region.Union(LLRegion(nAuxPly, pfp));
145 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
147 std::vector<float> vecr;
148 for (
size_t i = 0; i < vec.size() / 2; i++) {
149 float a = vec[i * 2 + 1];
155 std::vector<float>::iterator it = vecr.begin();
157 if (vecr.size() / 2 >= 3) {
160 candidate_region = LLRegion(vecr.size() / 2, (
float *)&(*it));
162 candidate_region = world_region;
166 if (!candidate_region
168 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
169 if (nNoCovrPlyEntries) {
170 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
171 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
172 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
174 LLRegion t_region = LLRegion(nNoCovrPly, pfp);
183 if (nAuxPlyEntries > 1) {
184 for (
int ipr = 0; ipr < nAuxPlyEntries; ipr++) {
185 float *pfpr = cte.GetpAuxPlyTableEntry(ipr);
186 int nAuxPly = cte.GetAuxCntTableEntry(ipr);
187 t_region.Subtract(LLRegion(nAuxPly, pfpr));
196 if (!t_region.Empty()) {
197 LLRegion test_region = candidate_region;
198 test_region.Subtract(t_region);
199 if (!test_region.Empty()) candidate_region = test_region;
209 if ((cte.GetScale() > 90000000) &&
210 (cte.GetChartFamily() == CHART_FAMILY_RASTER))
211 candidate_region = world_region;
213 return candidate_region;
216LLRegion &QuiltCandidate::GetReducedCandidateRegion(
double factor) {
217 if (factor != last_factor) {
218 reduced_candidate_region = GetCandidateRegion();
219 reduced_candidate_region.Reduce(factor);
220 last_factor = factor;
223 return reduced_candidate_region;
226void QuiltCandidate::SetScale(
int scale) {
230 if (
scale >= 1000) rounding = 5 * pow(10, log10(
scale) - 2);
239 m_reference_scale = 1;
240 m_refchart_dbIndex = -1;
241 m_reference_type = CHART_TYPE_UNKNOWN;
242 m_reference_family = CHART_FAMILY_UNKNOWN;
243 m_quilt_proj = PROJECTION_UNKNOWN;
245 m_lost_refchart_dbIndex = -1;
255 new ArrayOfSortedQuiltCandidates(CompareQuiltCandidateScales);
260 m_preferred_family = CHART_FAMILY_RASTER;
263 m_bquiltskew = g_bopengl;
265 m_bquiltanyproj = g_bopengl;
269 m_PatchList.DeleteContents(
true);
272 EmptyCandidateArray();
273 delete m_pcandidate_array;
275 m_extended_stack_array.clear();
280bool Quilt::IsVPBlittable(
ViewPort &VPoint,
int dx,
int dy,
281 bool b_allow_vector) {
282 if (!m_vp_rendered.IsValid())
return false;
287 double deltax = p2.m_x - p1.m_x;
288 double deltay = p2.m_y - p1.m_y;
290 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
return false;
295bool Quilt::IsChartS57Overlay(
int db_index) {
296 if (db_index < 0)
return false;
299 if (CHART_FAMILY_VECTOR == cte.GetChartFamily()) {
300 return s57chart::IsCellOverlayType(cte.GetFullSystemPath());
305bool Quilt::IsChartQuiltableRef(
int db_index) {
306 if (db_index < 0 || db_index > ChartData->GetChartTableEntries() - 1)
312 bool bproj_match =
true;
314 double skew_norm = ctei.GetChartSkew();
315 if (skew_norm > 180.) skew_norm -= 360.;
318 fabs(skew_norm) < 1.;
319 if (m_bquiltskew) skew_match =
true;
322 bool b_noshow =
false;
323 for (
unsigned int i = 0; i < m_parent->GetQuiltNoshowIindexArray().size();
325 if (m_parent->GetQuiltNoshowIindexArray()[i] ==
333 return (bproj_match & skew_match & !b_noshow);
336bool Quilt::IsChartInQuilt(
ChartBase *pc) {
338 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
340 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
341 if (ChartData->OpenChartFromDB(pqc->dbIndex, FULL_INIT) == pc)
348bool Quilt::IsChartInQuilt(wxString &full_path) {
350 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
352 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
354 if (pcte->GetpsFullPath()->IsSameAs(full_path))
return true;
360std::vector<int> Quilt::GetCandidatedbIndexArray(
bool from_ref_chart,
361 bool exclude_user_hidden) {
362 std::vector<int> ret;
363 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
367 if (pqc->Scale_ge(m_reference_scale)) {
369 if (exclude_user_hidden) {
370 bool b_noshow =
false;
371 for (
unsigned int i = 0;
372 i < m_parent->GetQuiltNoshowIindexArray().size(); i++) {
373 if (m_parent->GetQuiltNoshowIindexArray()[i] ==
380 if (!b_noshow) ret.push_back(pqc->dbIndex);
382 ret.push_back(pqc->dbIndex);
386 ret.push_back(pqc->dbIndex);
393 return (cnode->GetData());
398void Quilt::EmptyCandidateArray(
void) {
399 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
400 delete m_pcandidate_array->Item(i);
403 m_pcandidate_array->Clear();
407 if (!ChartData)
return NULL;
409 if (!ChartData->IsValid())
413 if (!m_bcomposed)
return NULL;
415 if (m_bbusy)
return NULL;
419 cnode = m_PatchList.GetFirst();
420 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetNext();
421 if (cnode && cnode->GetData()->b_Valid)
422 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
429 if (!ChartData)
return NULL;
431 if (!ChartData->IsValid())
return NULL;
433 if (m_bbusy)
return NULL;
438 cnode = cnode->GetNext();
439 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetNext();
440 if (cnode && cnode->GetData()->b_Valid)
441 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
448ChartBase *Quilt::GetNextSmallerScaleChart() {
449 if (!ChartData)
return NULL;
451 if (!ChartData->IsValid())
return NULL;
453 if (m_bbusy)
return NULL;
458 cnode = cnode->GetPrevious();
459 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetPrevious();
460 if (cnode && cnode->GetData()->b_Valid)
461 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
468ChartBase *Quilt::GetLargestScaleChart() {
469 if (!ChartData)
return NULL;
471 if (m_bbusy)
return NULL;
475 cnode = m_PatchList.GetLast();
477 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
484 LLRegion chart_region;
485 LLRegion screen_region(vp.GetBBox());
490 if (fabs(cte.GetLonMax() - cte.GetLonMin()) > 180.) {
507 return LLRegion(-80, vp.GetBBox().GetMinLon(), 80,
508 vp.GetBBox().GetMaxLon());
512 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
513 bool aux_ply_skipped =
false;
514 if (nAuxPlyEntries >= 1) {
515 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
516 int nAuxPly = cte.GetAuxCntTableEntry(ip);
517 if (nAuxPly > AUX_PLY_PERF_LIMIT) {
520 aux_ply_skipped =
true;
523 float *pfp = cte.GetpAuxPlyTableEntry(ip);
524 LLRegion t_region(nAuxPly, pfp);
525 t_region.Intersect(screen_region);
529 if (!t_region.Empty()) chart_region.Union(t_region);
533 if (aux_ply_skipped || nAuxPlyEntries == 0) {
534 int n_ply_entries = cte.GetnPlyEntries();
535 float *pfp = cte.GetpPlyTable();
537 if (n_ply_entries >= 3)
540 LLRegion t_region(n_ply_entries, pfp);
541 t_region.Intersect(screen_region);
545 if (!t_region.Empty()) chart_region.Union(t_region);
548 chart_region = screen_region;
552 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
553 if (nNoCovrPlyEntries) {
554 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
555 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
556 if (nNoCovrPly > NOCOVR_PLY_PERF_LIMIT) {
561 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
563 LLRegion t_region(nNoCovrPly, pfp);
564 t_region.Intersect(screen_region);
575 if (!t_region.Empty()) {
576 LLRegion test_region = chart_region;
577 test_region.Subtract(t_region);
579 if (!test_region.Empty()) chart_region = test_region;
588 if ((cte.GetScale() > 90000000) &&
589 (cte.GetChartFamily() == CHART_FAMILY_RASTER))
590 chart_region = screen_region;
598bool Quilt::IsQuiltVector(
void) {
599 if (m_bbusy)
return false;
605 wxPatchListNode *cnode = m_PatchList.GetFirst();
607 if (cnode->GetData()) {
610 if ((pqp->b_Valid) && (!pqp->b_eclipsed) &&
611 (pqp->dbIndex < ChartData->GetChartTableEntries())) {
613 ChartData->GetChartTableEntry(pqp->dbIndex);
615 if (ctei.GetChartFamily() == CHART_FAMILY_VECTOR) {
621 cnode = cnode->GetNext();
628bool Quilt::DoesQuiltContainPlugins(
void) {
629 if (m_bbusy)
return false;
635 wxPatchListNode *cnode = m_PatchList.GetFirst();
637 if (cnode->GetData()) {
640 if ((pqp->b_Valid) && (!pqp->b_eclipsed)) {
642 ChartData->GetChartTableEntry(pqp->dbIndex);
644 if (ctei.GetChartType() == CHART_TYPE_PLUGIN) {
650 cnode = cnode->GetNext();
657int Quilt::GetChartdbIndexAtPix(
ViewPort &VPoint, wxPoint p) {
658 if (m_bbusy)
return -1;
667 wxPatchListNode *cnode = m_PatchList.GetFirst();
669 if (cnode->GetData()->ActiveRegion.Contains(lat, lon)) {
670 ret = cnode->GetData()->dbIndex;
673 cnode = cnode->GetNext();
681 if (m_bbusy)
return NULL;
693 wxPatchListNode *cnode = m_PatchList.GetFirst();
696 if (!pqp->b_overlay && (pqp->ActiveRegion.Contains(lat, lon)))
697 if (ChartData->IsChartInCache(pqp->dbIndex)) {
698 pret = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
700 cnode = cnode->GetNext();
708 if (m_bbusy)
return NULL;
720 wxPatchListNode *cnode = m_PatchList.GetFirst();
723 if (pqp->b_overlay && (pqp->ActiveRegion.Contains(lat, lon)))
724 pret = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
725 cnode = cnode->GetNext();
732void Quilt::InvalidateAllQuiltPatchs(
void) {
743std::vector<int> Quilt::GetQuiltIndexArray(
void) {
744 return m_index_array;
746 std::vector<int> ret;
748 if (m_bbusy)
return ret;
752 wxPatchListNode *cnode = m_PatchList.GetFirst();
754 ret.push_back(cnode->GetData()->dbIndex);
755 cnode = cnode->GetNext();
763bool Quilt::IsQuiltDelta(
ViewPort &vp) {
764 if (!m_vp_quilt.IsValid() || !m_bcomposed)
return true;
768 if (m_vp_quilt.m_projection_type != vp.m_projection_type)
return true;
773 wxPoint cp_last, cp_this;
778 return (cp_last != cp_this);
786 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
788 if (pRefChart) pRefChart->AdjustVP(vp_last, vp_proposed);
791double Quilt::GetRefNativeScale() {
792 double ret_val = 1.0;
794 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
795 if (pc) ret_val = pc->GetNativeScale();
801int Quilt::GetNewRefChart(
void) {
807 int new_ref_dbIndex = m_refchart_dbIndex;
808 unsigned int im = m_extended_stack_array.size();
810 for (
unsigned int is = 0; is < im; is++) {
812 ChartData->GetChartTableEntry(m_extended_stack_array[is]);
814 double skew_norm = m.GetChartSkew();
815 if (skew_norm > 180.) skew_norm -= 360.;
817 if ((m.Scale_ge(m_reference_scale)) &&
818 (m_reference_family == m.GetChartFamily()) &&
819 (m_bquiltanyproj || m_quilt_proj == m.GetChartProjectionType()) &&
820 (m_bquiltskew || (fabs(skew_norm) < 1.0))) {
821 new_ref_dbIndex = m_extended_stack_array[is];
826 return new_ref_dbIndex;
829int Quilt::GetNomScaleMax(
int scale, ChartTypeEnum type,
830 ChartFamilyEnum family) {
832 case CHART_FAMILY_RASTER: {
836 case CHART_FAMILY_VECTOR: {
846int Quilt::GetNomScaleMin(
int scale, ChartTypeEnum type,
847 ChartFamilyEnum family) {
848 double zoom_mod = (double)g_chart_zoom_modifier_raster;
850 if (family == CHART_FAMILY_VECTOR)
851 zoom_mod = (double)g_chart_zoom_modifier_vector;
853 double modf = zoom_mod / 5.;
854 double mod = pow(16., modf);
855 mod = wxMax(mod, .2);
856 mod = wxMin(mod, 16.0);
860 case CHART_FAMILY_RASTER: {
861 if (CHART_TYPE_MBTILES == type)
867 return scale * 1 * mod;
870 case CHART_FAMILY_VECTOR: {
871 return scale * 4 * mod;
875 mod = wxMin(mod, 2.0);
876 return scale * 2 * mod;
882 int index, nom, min, max;
885int Quilt::AdjustRefOnZoom(
bool b_zin, ChartFamilyEnum family,
886 ChartTypeEnum type,
double proposed_scale_onscreen) {
887 std::vector<scale> scales;
888 std::vector<scale> scales_mbtiles;
897 bool b_allow_fullscreen_ref =
898 (family == CHART_FAMILY_VECTOR) || b_zin || g_bopengl;
902 int smallest_scale = 1;
903 for (
size_t i = 0; i < m_extended_stack_array.size(); i++) {
904 int index = m_extended_stack_array[i];
905 if (ChartData->GetDBChartType(index) == type)
906 smallest_scale = wxMax(smallest_scale, ChartData->GetDBChartScale(index));
911 for (
size_t i = 0; i < m_extended_stack_array.size(); i++) {
912 int test_db_index = m_extended_stack_array[i];
914 if (b_allow_fullscreen_ref ||
915 m_parent->GetpCurrentStack()->DoesStackContaindbIndex(test_db_index)) {
916 if ((family == ChartData->GetDBChartFamily(test_db_index)) &&
917 IsChartQuiltableRef(test_db_index)
919 int nscale = ChartData->GetDBChartScale(test_db_index);
921 int nmax_scale = GetNomScaleMax(nscale, type, family);
925 if (0 == i_first) nmax_scale = 1;
927 int nmin_scale = GetNomScaleMin(nscale, type, family);
930 if ((type == CHART_TYPE_KAP) && (nscale == smallest_scale))
935 if ((type == CHART_TYPE_MBTILES) && (nscale == smallest_scale))
938 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(test_db_index))
939 scales_mbtiles.push_back(
940 scale{test_db_index, nscale, nmin_scale, nmax_scale});
943 scale{test_db_index, nscale, nmin_scale, nmax_scale});
950 if (scales.empty()) scales = scales_mbtiles;
957 if (CHART_FAMILY_VECTOR == family) {
958 for (
size_t i = scales.size(); i; i--) {
959 int test_db_index = scales[i - 1].index;
960 if (type == ChartData->GetDBChartType(test_db_index)) {
961 scales[i - 1].min = scales[i - 1].nom * 80;
973 if (scales.size() > 1) {
974 for (
unsigned i = 0; i < scales.size() - 1; i++) {
975 int min_scale_test = wxMax(scales[i].min, scales[i + 1].max + 1);
976 min_scale_test = wxMin(min_scale_test, scales[i].min * 2);
977 scales[i].min = min_scale_test;
986 if (scales.size() > 2) {
987 for (
size_t i = scales.size() - 2; i >= 1; i--) {
988 scales[i].max = wxMin(scales[i].max, scales[i - 1].min - 1);
992 int new_ref_dbIndex = -1;
996 for (
size_t i = 0; i < scales.size(); i++) {
997 if ((proposed_scale_onscreen <
1000 (proposed_scale_onscreen > scales[i].max)) {
1001 new_ref_dbIndex = scales[i].index;
1006 return new_ref_dbIndex;
1009int Quilt::AdjustRefOnZoomOut(
double proposed_scale_onscreen) {
1011 m_lost_refchart_dbIndex = -1;
1013 int current_db_index = m_refchart_dbIndex;
1014 int current_family = m_reference_family;
1015 ChartTypeEnum current_type = (ChartTypeEnum)m_reference_type;
1017 if (m_refchart_dbIndex >= 0) {
1019 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1020 current_family = cte.GetChartFamily();
1021 current_type = (ChartTypeEnum)cte.GetChartType();
1024 if (current_type == CHART_TYPE_CM93COMP)
return current_db_index;
1026 int proposed_ref_index =
1027 AdjustRefOnZoom(
false, (ChartFamilyEnum)current_family, current_type,
1028 proposed_scale_onscreen);
1031 if (proposed_ref_index < 0) {
1032 m_zout_family = current_family;
1033 m_zout_type = current_type;
1034 m_zout_dbindex = current_db_index;
1037 SetReferenceChart(proposed_ref_index);
1039 return proposed_ref_index;
1042int Quilt::AdjustRefOnZoomIn(
double proposed_scale_onscreen) {
1044 m_lost_refchart_dbIndex = -1;
1046 int current_db_index = m_refchart_dbIndex;
1047 int current_family = m_reference_family;
1048 ChartTypeEnum current_type = (ChartTypeEnum)m_reference_type;
1050 if (m_zout_family >= 0) {
1051 current_type = (ChartTypeEnum)m_zout_type;
1052 current_family = m_zout_family;
1058 if (current_type == CHART_TYPE_CM93COMP) {
1059 if (m_zout_family >= 0) {
1060 current_family = ChartData->GetDBChartFamily(m_zout_dbindex);
1062 return current_db_index;
1065 if ((-1 == m_refchart_dbIndex) && (m_zout_dbindex >= 0))
1066 BuildExtendedChartStackAndCandidateArray(m_zout_dbindex, m_vp_quilt);
1068 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, m_vp_quilt);
1070 int proposed_ref_index =
1071 AdjustRefOnZoom(
true, (ChartFamilyEnum)current_family, current_type,
1072 proposed_scale_onscreen);
1074 if (current_db_index == -1) {
1075 SetReferenceChart(proposed_ref_index);
1076 return proposed_ref_index;
1079 if (proposed_ref_index != -1) {
1080 if (ChartData->GetDBChartScale(current_db_index) >=
1081 ChartData->GetDBChartScale(proposed_ref_index)) {
1082 SetReferenceChart(proposed_ref_index);
1083 return proposed_ref_index;
1086 proposed_ref_index = current_db_index;
1088 SetReferenceChart(proposed_ref_index);
1090 return proposed_ref_index;
1093bool Quilt::IsChartSmallestScale(
int dbIndex) {
1094 if (!ChartData)
return false;
1098 int specified_type = ChartData->GetDBChartType(dbIndex);
1099 int target_dbindex = -1;
1101 unsigned int target_stack_index = 0;
1102 if (m_extended_stack_array.size()) {
1103 while ((target_stack_index <= (m_extended_stack_array.size() - 1))) {
1104 int test_db_index = m_extended_stack_array[target_stack_index];
1106 if (specified_type == ChartData->GetDBChartType(test_db_index))
1107 target_dbindex = test_db_index;
1109 target_stack_index++;
1112 return (dbIndex == target_dbindex);
1115LLRegion Quilt::GetHiliteRegion() {
1121 for (
auto &index : m_HiLiteIndexArray) {
1123 LLRegion cell_region = GetChartQuiltRegion(cte, m_vp_quilt);
1124 r.Union(cell_region);
1128 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1129 wxPatchListNode *pcinode = m_PatchList.Item(i);
1131 if ((index == piqp->dbIndex) && (piqp->b_Valid))
1133 r.Union(piqp->ActiveRegion);
1142LLRegion Quilt::GetHiliteRegion() {
1144 if (m_nHiLiteIndex >= 0) {
1146 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1147 wxPatchListNode *pcinode = m_PatchList.Item(i);
1149 if ((m_nHiLiteIndex == piqp->dbIndex) && (piqp->b_Valid))
1151 r = piqp->ActiveRegion;
1158 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1160 if (m_nHiLiteIndex == pqc->dbIndex) {
1161 LLRegion chart_region = pqc->GetCandidateRegion();
1162 if (!chart_region.Empty()) {
1164 bool b_eclipsed =
false;
1165 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size();
1167 if (m_nHiLiteIndex == m_eclipsed_stack_array[ir]) {
1173 if (!b_eclipsed) r = chart_region;
1183 ChartData->GetChartTableEntry(m_nHiLiteIndex);
1184 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
1185 r = GetTilesetRegion(m_nHiLiteIndex);
1193const LLRegion &Quilt::GetTilesetRegion(
int dbIndex) {
1194 LLRegion world_region(-90, -180, 90, 180);
1197 LLRegion &target_region =
const_cast<LLRegion &
>(cte.quilt_candidate_region);
1199 if (!target_region.Empty())
return target_region;
1202 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
1203 if (nAuxPlyEntries >= 1) {
1204 target_region.Clear();
1205 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
1206 float *pfp = cte.GetpAuxPlyTableEntry(ip);
1207 int nAuxPly = cte.GetAuxCntTableEntry(ip);
1209 target_region.Union(LLRegion(nAuxPly, pfp));
1212 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
1214 std::vector<float> vecr;
1215 for (
size_t i = 0; i < vec.size() / 2; i++) {
1216 float a = vec[i * 2 + 1];
1222 std::vector<float>::iterator it = vecr.begin();
1224 if (vecr.size() / 2 >= 3) {
1227 target_region = LLRegion(vecr.size() / 2, (
float *)&(*it));
1229 target_region = world_region;
1233 if (!target_region.Empty()) {
1234 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
1235 if (nNoCovrPlyEntries) {
1236 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
1237 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
1238 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
1240 LLRegion t_region = LLRegion(nNoCovrPly, pfp);
1247 if (!t_region.Empty()) {
1248 LLRegion test_region = target_region;
1249 test_region.Subtract(t_region);
1251 if (!test_region.Empty()) target_region = test_region;
1265 return target_region;
1268bool Quilt::BuildExtendedChartStackAndCandidateArray(
int ref_db_index,
1270 double zoom_test_val = .002;
1273 EmptyCandidateArray();
1274 m_extended_stack_array.clear();
1275 m_fullscreen_index_array.clear();
1277 int reference_scale = 1e8;
1278 int reference_type = -1;
1279 int reference_family = -1;
1281 m_bquiltanyproj ? vp_in.m_projection_type : PROJECTION_UNKNOWN;
1283 if (ref_db_index >= 0) {
1285 ChartData->GetChartTableEntry(ref_db_index);
1286 reference_scale = cte_ref.GetScale();
1287 reference_type = cte_ref.GetChartType();
1288 if (!m_bquiltanyproj) quilt_proj = ChartData->GetDBChartProj(ref_db_index);
1289 reference_family = cte_ref.GetChartFamily();
1292 bool b_need_resort =
false;
1302 int n_charts = m_parent->GetpCurrentStack()->nEntry;
1306 for (
int ics = 0; ics < n_charts; ics++) {
1307 int istack = m_parent->GetpCurrentStack()->GetDBIndex(ics);
1308 if (istack < 0)
continue;
1309 m_extended_stack_array.push_back(istack);
1315 if (reference_type == CHART_TYPE_CM93COMP)
continue;
1325 if ((cte.GetChartType() == CHART_TYPE_PLUGIN) ||
1326 (reference_type == CHART_TYPE_PLUGIN)) {
1327 if (reference_family != cte.GetChartFamily()) {
1331 if (reference_type != cte.GetChartType()) {
1336 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1339 int candidate_chart_scale = cte.GetScale();
1340 double chart_native_ppm =
1341 m_canvas_scale_factor / (double)candidate_chart_scale;
1343 if ((zoom_factor < zoom_test_val) &&
1348 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
1349 m_extended_stack_array.pop_back();
1353 double skew_norm = cte.GetChartSkew();
1354 if (skew_norm > 180.) skew_norm -= 360.;
1356 if ((m_bquiltskew ? 1 : fabs(skew_norm) < 1.0) &&
1357 (m_bquiltanyproj || cte.GetChartProjectionType() == quilt_proj)) {
1359 qcnew->dbIndex = istack;
1360 qcnew->SetScale(cte.GetScale());
1361 m_pcandidate_array->push_back(qcnew);
1388 int n_all_charts = ChartData->GetChartTableEntries();
1390 LLBBox viewbox = vp_local.GetBBox();
1391 int sure_index = -1;
1392 int sure_index_scale = 0;
1393 int sure_index_type = -1;
1395 for (
int i = 0; i < n_all_charts; i++) {
1399 int groupIndex = m_parent->m_groupIndex;
1400 if ((groupIndex > 0) && (!ChartData->IsChartInGroup(i, groupIndex)))
1405 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
1406 m_fullscreen_index_array.push_back(i);
1410#ifdef __OCPN__ANDROID__
1411 wxFileName fn(cte.GetFullSystemPath());
1412 if (!androidIsDirWritable(fn.GetPath()))
continue;
1414 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1416 const LLBBox &chart_box = cte.GetBBox();
1417 if ((viewbox.IntersectOut(chart_box)))
continue;
1419 m_fullscreen_index_array.push_back(i);
1421 if (reference_family != cte.GetChartFamily()) {
1422 if (cte.GetChartType() != CHART_TYPE_MBTILES)
continue;
1425 if (!m_bquiltanyproj && quilt_proj != cte.GetChartProjectionType())
1428 double skew_norm = cte.GetChartSkew();
1429 if (skew_norm > 180.) skew_norm -= 360.;
1431 if (!m_bquiltskew && fabs(skew_norm) > 1.0)
continue;
1436 if( CHART_TYPE_S57 == cte.GetChartType() ) {
1438 double chart_area = (cte.GetLonMax() - cte.GetLonMin()) *
1439 (cte.GetLatMax() - cte.GetLatMin());
1440 double quilt_area = viewbox.GetLonRange() * viewbox.GetLatRange();
1441 if ((chart_area / quilt_area) < .01)
continue;
1444 int candidate_chart_scale = cte.GetScale();
1450 if (!cte.Scale_ge(reference_scale)) {
1451 if (cte.Scale_gt(sure_index_scale)) {
1453 sure_index_scale = candidate_chart_scale;
1454 sure_index_type = cte.GetChartType();
1463 double chart_native_ppm =
1464 m_canvas_scale_factor / (double)candidate_chart_scale;
1466 double zoom_factor_test_extra = 0.2;
1472 double ref_scale_test = reference_scale;
1473 if (cte.GetChartType() == CHART_TYPE_MBTILES)
1474 ref_scale_test = candidate_chart_scale;
1476 if ((cte.Scale_ge(ref_scale_test) && (zoom_factor > zoom_test_val)) ||
1477 (zoom_factor > zoom_factor_test_extra)) {
1478 LLRegion cell_region = GetChartQuiltRegion(cte, vp_local);
1483 if (!cell_region.Empty()) {
1486 bool b_exists =
false;
1487 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1488 if (i == m_extended_stack_array[ir]) {
1502 bool b_noadd =
false;
1504 for (
unsigned int id = 0;
id < m_extended_stack_array.size();
id++) {
1505 if (m_extended_stack_array[
id] != -1) {
1507 ChartData->GetpChartTableEntry(m_extended_stack_array[
id]);
1508 bool bsameTime =
false;
1509 if (pm->GetFileTime() && pn->GetFileTime()) {
1510 if (labs(pm->GetFileTime() - pn->GetFileTime()) < 60)
1513 if (pm->GetChartEditionDate() == pn->GetChartEditionDate())
1517 if (pn->GetpFileName()->IsSameAs(*(pm->GetpFileName())))
1524 m_extended_stack_array.push_back(i);
1529 candidate_chart_scale);
1531 m_pcandidate_array->push_back(qcnew);
1533 b_need_resort =
true;
1542 if (-1 != sure_index) {
1544 bool sure_exists =
false;
1545 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1546 if (sure_index == m_extended_stack_array[ir]) {
1553 if (!sure_exists && (sure_index_type != CHART_TYPE_MBTILES)) {
1554 m_extended_stack_array.push_back(sure_index);
1557 qcnew->dbIndex = sure_index;
1558 qcnew->SetScale(ChartData->GetDBChartScale(sure_index));
1559 m_pcandidate_array->push_back(qcnew);
1561 b_need_resort =
true;
1566 if (b_need_resort && m_extended_stack_array.size() > 1) {
1567 std::sort(m_extended_stack_array.begin(), m_extended_stack_array.end(),
1573int Quilt::AdjustRefSelection(
const ViewPort &vp_in) {
1578 if (!ChartData)
return false;
1588 vp_local.SetRotationAngle(0.);
1590 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1592 ChartFamilyEnum family = CHART_FAMILY_RASTER;
1593 ChartTypeEnum type = CHART_TYPE_KAP;
1596 if (m_refchart_dbIndex >= 0) {
1598 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1599 type = (ChartTypeEnum)cte_ref.GetChartType();
1600 family = (ChartFamilyEnum)cte_ref.GetChartFamily();
1603 int ret_index = AdjustRefOnZoom(
true, family, type, vp_in.
chart_scale);
1608double Quilt::GetBestStartScale(
int dbi_ref_hint,
const ViewPort &vp_in) {
1618 int tentative_ref_index = dbi_ref_hint;
1619 if (dbi_ref_hint < 0) {
1626 tentative_ref_index = m_parent->GetpCurrentStack()->GetDBIndex(0);
1633 vp_local.SetRotationAngle(0.);
1635 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1639 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1641 if (qc->dbIndex == tentative_ref_index) {
1647 if (!bf && m_pcandidate_array->GetCount()) {
1648 tentative_ref_index = GetNewRefChart();
1649 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1652 double proposed_scale_onscreen = vp_in.
chart_scale;
1654 if (m_pcandidate_array->GetCount()) {
1655 m_refchart_dbIndex = tentative_ref_index;
1659 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1661 if (IsChartQuiltableRef(qc->dbIndex)) {
1662 m_refchart_dbIndex = qc->dbIndex;
1669 m_refchart_dbIndex = m_parent->GetpCurrentStack()->GetDBIndex(0);
1672 if (m_refchart_dbIndex >= 0) {
1675 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
1677 double min_ref_scale =
1679 double max_ref_scale = pc->GetNormalScaleMax(
1681 if ((proposed_scale_onscreen >= min_ref_scale) &&
1682 (proposed_scale_onscreen <= max_ref_scale))
1685 proposed_scale_onscreen = wxMin(proposed_scale_onscreen, max_ref_scale);
1686 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, min_ref_scale);
1694 if (m_refchart_dbIndex >= 0 && ChartData)
1695 return ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
1699void Quilt::UnlockQuilt() {
1700 wxASSERT(m_bbusy ==
false);
1701 ChartData->UnLockCache();
1703 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1705 ChartData->UnLockCacheChart(pqc->dbIndex);
1710 if (!ChartData)
return false;
1716 if (!m_parent->GetpCurrentStack())
return false;
1718 if (m_bbusy)
return false;
1727 if (m_refchart_dbIndex >= 0) {
1729 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1730 m_reference_scale = cte_ref.GetScale();
1731 m_reference_type = cte_ref.GetChartType();
1732 if (!m_bquiltanyproj)
1733 m_quilt_proj = ChartData->GetDBChartProj(m_refchart_dbIndex);
1734 m_reference_family = cte_ref.GetChartFamily();
1738 if (!m_bquiltanyproj) vp_local.SetProjectionType(m_quilt_proj);
1745 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1785 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1787 if (qc->dbIndex == m_refchart_dbIndex) {
1793 if (!bf && m_pcandidate_array->GetCount() &&
1794 (m_reference_type != CHART_TYPE_CM93COMP)) {
1795 m_lost_refchart_dbIndex = m_refchart_dbIndex;
1796 int candidate_ref_index = GetNewRefChart();
1797 if (m_refchart_dbIndex != candidate_ref_index) {
1798 m_refchart_dbIndex = candidate_ref_index;
1799 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1804 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1805 if (m_pcandidate_array->GetCount()) {
1806 m_refchart_dbIndex =
1807 m_pcandidate_array->Item(m_pcandidate_array->GetCount() - 1)
1809 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1814 if ((-1 != m_lost_refchart_dbIndex) &&
1815 (m_lost_refchart_dbIndex != m_refchart_dbIndex)) {
1818 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1819 if (m_lost_refchart_dbIndex == m_extended_stack_array[ir]) {
1820 m_refchart_dbIndex = m_lost_refchart_dbIndex;
1821 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1822 m_lost_refchart_dbIndex = -1;
1828 bool b_has_overlays =
false;
1831 if (CHART_FAMILY_VECTOR == m_reference_family) {
1832 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1834 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1836 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1837 b_has_overlays =
true;
1850 const LLRegion cvp_region = vp_local.GetLLRegion(vp_local.rv_rect);
1851 LLRegion vp_region = cvp_region;
1857 for (ir = 0; ir < m_pcandidate_array->GetCount();
1861 if (pqc->dbIndex == m_refchart_dbIndex) {
1870 const double z = 111274.96299695622;
1876 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1878 LLRegion vpu_region(cvp_region);
1881 LLRegion &chart_region = pqc_ref->GetReducedCandidateRegion(factor);
1883 if (cte_ref.GetChartType() != CHART_TYPE_MBTILES) {
1884 if (!chart_region.Empty()) {
1885 vpu_region.Intersect(chart_region);
1887 if (vpu_region.Empty())
1888 pqc_ref->b_include =
false;
1890 pqc_ref->b_include =
true;
1891 vp_region.Subtract(chart_region);
1894 pqc_ref->b_include =
false;
1896 pqc_ref->b_include =
false;
1901 if (!vp_region.Empty()) {
1902 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1905 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1907 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1912 if (CHART_FAMILY_VECTOR == m_reference_family) {
1913 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1919 if (CHART_TYPE_MBTILES == cte.GetChartType()) {
1920 pqc->b_include =
false;
1924 if (cte.Scale_ge(m_reference_scale)) {
1928 bool b_in_noshow =
false;
1929 for (
unsigned int ins = 0;
1930 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1931 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
1941 LLRegion vpu_region(cvp_region);
1944 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
1946 if (!chart_region.Empty()) {
1947 vpu_region.Intersect(chart_region);
1949 if (vpu_region.Empty())
1950 pqc->b_include =
false;
1952 pqc->b_include =
true;
1953 vp_region.Subtract(chart_region);
1956 pqc->b_include =
false;
1958 pqc->b_include =
true;
1962 pqc->b_include =
false;
1965 if (vp_region.Empty())
1972 if (b_has_overlays && (CHART_FAMILY_VECTOR == m_reference_family)) {
1973 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1976 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1978 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1980 if (cte.Scale_ge(m_reference_scale)) {
1981 bool b_in_noshow =
false;
1982 for (
unsigned int ins = 0;
1983 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1984 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
1994 LLRegion vpu_region(cvp_region);
1997 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
1999 if (!chart_region.Empty()) vpu_region.Intersect(chart_region);
2001 if (vpu_region.Empty())
2002 pqc->b_include =
false;
2005 s57chart::IsCellOverlayType(cte.GetFullSystemPath());
2006 if (b_overlay) pqc->b_include =
true;
2013 ChartData->GetChartTableEntry(m_refchart_dbIndex);
2014 if (s57chart::IsCellOverlayType(cte_ref.GetFullSystemPath())) {
2015 pqc->b_include =
true;
2027 m_eclipsed_stack_array.clear();
2029 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2032 if (!pqc->b_include) {
2033 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
2034 if (cte.Scale_ge(m_reference_scale) &&
2035 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
2036 m_eclipsed_stack_array.push_back(pqc->dbIndex);
2037 pqc->b_eclipsed =
true;
2044 if (((m_bquiltanyproj || m_quilt_proj == PROJECTION_MERCATOR)) &&
2045 !vp_region.Empty()) {
2046 bool b_must_add_cm93 =
true;
2053 while( updd .HaveRects()) {
2054 wxRect rect = updd.GetRect();
2055 if( ( rect.width > 2 ) && ( rect.height > 2 ) ) {
2056 b_must_add_cm93 =
true;
2063 if (b_must_add_cm93) {
2064 for (
int ics = 0; ics < m_parent->GetpCurrentStack()->nEntry; ics++) {
2065 int i = m_parent->GetpCurrentStack()->GetDBIndex(ics);
2066 if (CHART_TYPE_CM93COMP == ChartData->GetDBChartType(i)) {
2069 qcnew->SetScale(ChartData->GetDBChartScale(i));
2071 m_pcandidate_array->Add(qcnew);
2082 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
2084 if (pqc->b_include) {
2090 if (!b_vis && m_pcandidate_array->GetCount()) {
2093 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2095 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
2098 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2101 if (cte.GetChartType() == CHART_TYPE_MBTILES)
continue;
2104 LLRegion vpck_region(vp_local.GetBBox());
2107 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
2109 if (!chart_region.Empty()) vpck_region.Intersect(chart_region);
2111 if (!vpck_region.Empty()) {
2113 if (cte.Scale_eq(add_scale)) {
2114 pqc->b_include =
true;
2117 pqc->b_include =
true;
2118 add_scale = cte.GetScale();
2127 m_PatchList.DeleteContents(
true);
2128 m_PatchList.Clear();
2130 if (m_pcandidate_array->GetCount()) {
2131 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2137 const ChartTableEntry &m = ChartData->GetChartTableEntry(pqc->dbIndex);
2139 if (m.GetChartType() == CHART_TYPE_CM93COMP)
2140 pqc->b_include =
true;
2143 if (pqc->b_include) {
2145 pqp->dbIndex = pqc->dbIndex;
2146 pqp->ProjType = m.GetChartProjectionType();
2149 pqp->quilt_region = pqc->GetCandidateRegion();
2152 pqp->b_Valid =
true;
2154 m_PatchList.Append(pqp);
2161 if (!m_bquiltanyproj) {
2163 m_quilt_proj = PROJECTION_MERCATOR;
2164 ChartBase *ppc = GetLargestScaleChart();
2165 if (ppc) m_quilt_proj = ppc->GetChartProjectionType();
2169 if (!m_bquiltanyproj) {
2172 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2173 wxPatchListNode *pcinode = m_PatchList.Item(i);
2175 if ((piqp->ProjType != m_quilt_proj) &&
2176 (piqp->ProjType != PROJECTION_UNKNOWN))
2177 piqp->b_Valid =
false;
2182 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2183 wxPatchListNode *pcinode = m_PatchList.Item(i);
2185 for (
unsigned int ins = 0;
2186 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
2187 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
2190 piqp->b_Valid =
false;
2198 m_covered_region.Clear();
2203 bool b_skipCM93 =
false;
2204 if (m_reference_type == CHART_TYPE_CM93COMP) {
2206 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2207 wxPatchListNode *pcinode = m_PatchList.Item(i);
2212 const ChartTableEntry &m = ChartData->GetChartTableEntry(piqp->dbIndex);
2214 if (m.GetChartType() == CHART_TYPE_CM93COMP) {
2216 piqp->ActiveRegion = piqp->quilt_region;
2217 piqp->ActiveRegion.Intersect(cvp_region);
2221 m_covered_region.Union(piqp->quilt_region);
2231 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2232 wxPatchListNode *pcinode = m_PatchList.Item(i);
2237 const ChartTableEntry &cte = ChartData->GetChartTableEntry(piqp->dbIndex);
2240 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2244 piqp->ActiveRegion = piqp->quilt_region;
2247 if (!b_has_overlays && m_PatchList.GetCount() < 25)
2248 piqp->ActiveRegion.Subtract(m_covered_region);
2250 piqp->ActiveRegion.Intersect(cvp_region);
2254 if (piqp->ActiveRegion.Empty() && (piqp->dbIndex != m_refchart_dbIndex))
2255 piqp->b_eclipsed =
true;
2258 piqp->b_overlay =
false;
2259 if (cte.GetChartFamily() == CHART_FAMILY_VECTOR) {
2260 piqp->b_overlay = s57chart::IsCellOverlayType(cte.GetFullSystemPath());
2263 if (!piqp->b_overlay) m_covered_region.Union(piqp->quilt_region);
2268 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2269 wxPatchListNode *pcinode = m_PatchList.Item(i);
2275 const ChartTableEntry &ctei = ChartData->GetChartTableEntry(piqp->dbIndex);
2278 LLRegion vpr_region = piqp->quilt_region;
2286 for (
unsigned int k = i + 1; k < m_PatchList.GetCount(); k++) {
2287 wxPatchListNode *pnode = m_PatchList.Item(k);
2308 if (!b_has_overlays) {
2309 if (!vpr_region.Empty()) {
2311 ChartData->GetChartTableEntry(pqp->dbIndex);
2312 LLRegion larger_scale_chart_region =
2315 vpr_region.Subtract(larger_scale_chart_region);
2324 wxPatchListNode *pinode = m_PatchList.Item(i);
2326 pqpi->ActiveRegion = vpr_region;
2335 if (pqpi->ActiveRegion.Empty()) pqpi->b_eclipsed =
true;
2343 m_covered_region.Union(pqpi->ActiveRegion);
2350 unsigned int il = 0;
2351 while (il < m_PatchList.GetCount()) {
2352 wxPatchListNode *pcinode = m_PatchList.Item(il);
2354 if (piqp->b_eclipsed) {
2357 bool b_noadd =
false;
2358 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size(); ir++) {
2359 if (piqp->dbIndex == m_eclipsed_stack_array[ir]) {
2364 if (!b_noadd) m_eclipsed_stack_array.push_back(piqp->dbIndex);
2366 m_PatchList.DeleteNode(pcinode);
2385 m_parent->EnablePaint(
false);
2392 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2394 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2395 if (!ChartData->IsChartLocked(pqc->dbIndex))
2396 ChartData->LockCacheChart(pqc->dbIndex);
2401 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2403 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2404 if (!ChartData->IsChartLocked(pqc->dbIndex))
2405 ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
true);
2414 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2416 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2417 if (ChartData->IsChartLocked(pqc->dbIndex))
2418 pqc->b_locked =
true;
2420 pqc->b_locked = ChartData->LockCacheChart(pqc->dbIndex);
2425 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2427 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2433 if (ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
2435 pqc->b_locked =
true;
2440 m_parent->EnablePaint(
true);
2443 m_last_index_array = m_index_array;
2445 m_index_array.clear();
2448 unsigned int kl = m_PatchList.GetCount();
2449 for (
unsigned int k = 0; k < kl; k++) {
2450 wxPatchListNode *cnode = m_PatchList.Item((kl - k) - 1);
2451 m_index_array.push_back(cnode->GetData()->dbIndex);
2452 cnode = cnode->GetNext();
2458 m_quilt_depth_unit = _T(
"");
2459 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
2461 m_quilt_depth_unit = pc->GetDepthUnits();
2463 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2464 int units = ps52plib->m_nDepthUnitDisplay;
2467 m_quilt_depth_unit = _T(
"Feet");
2470 m_quilt_depth_unit = _T(
"Meters");
2473 m_quilt_depth_unit = _T(
"Fathoms");
2479 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2480 wxPatchListNode *pnode = m_PatchList.Item(k);
2486 ChartBase *pc = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2488 wxString du = pc->GetDepthUnits();
2489 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2490 int units = ps52plib->m_nDepthUnitDisplay;
2503 wxString dul = du.Lower();
2504 wxString ml = m_quilt_depth_unit.Lower();
2508 if (dul.StartsWith(_T(
"meters")) && ml.StartsWith(_T(
"meters")))
2510 else if (dul.StartsWith(_T(
"metres")) && ml.StartsWith(_T(
"metres")))
2512 else if (dul.StartsWith(_T(
"fathoms")) && ml.StartsWith(_T(
"fathoms")))
2514 else if (dul.StartsWith(_T(
"met")) && ml.StartsWith(_T(
"met")))
2518 m_quilt_depth_unit = _T(
"");
2528 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2529 wxPatchListNode *pnode = m_PatchList.Item(k);
2533 if (!ChartData->IsChartInCache(pqp->dbIndex)) {
2534 wxLogMessage(_T(
" Quilt Compose cache miss..."));
2535 ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2536 if (!ChartData->IsChartInCache(pqp->dbIndex)) {
2537 wxLogMessage(_T(
" Oops, removing from quilt..."));
2538 pqp->b_Valid =
false;
2545 if (!ChartData->IsChartInCache(m_refchart_dbIndex))
2546 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
2552 m_bquilt_has_overlays =
false;
2553 m_max_error_factor = 0.;
2554 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2555 wxPatchListNode *pnode = m_PatchList.Item(k);
2561 ChartBase *pc = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2563 m_max_error_factor =
2564 wxMax(m_max_error_factor, pc->GetChart_Error_Factor());
2565 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2566 bool isOverlay = IsChartS57Overlay(pqp->dbIndex);
2567 pqp->b_overlay = isOverlay;
2568 if (isOverlay) m_bquilt_has_overlays =
true;
2577 ChartData->LockCache();
2581 unsigned long xa_hash = 5381;
2582 for (
unsigned int im = 0; im < m_extended_stack_array.size(); im++) {
2583 int dbindex = m_extended_stack_array[im];
2584 xa_hash = ((xa_hash << 5) + xa_hash) + dbindex;
2587 m_xa_hash = xa_hash;
2596 if (!m_bcomposed)
return;
2600 if (GetnCharts() && !m_bbusy && !chart_region.Empty()) {
2606 if (!(chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2607 vp.b_MercatorProjectionOverride)) {
2611 chart_region, pqp->ActiveRegion, chart->GetNativeScale());
2612 if (!get_screen_region.Empty())
2613 rendered_region.Union(get_screen_region);
2616 chart = GetNextChart();
2620 m_rendered_region = rendered_region;
2625bool Quilt::RenderQuiltRegionViewOnDCNoText(wxMemoryDC &dc,
ViewPort &vp,
2627 return DoRenderQuiltRegionViewOnDC(dc, vp, chart_region);
2630bool Quilt::RenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
2632 return DoRenderQuiltRegionViewOnDCTextOnly(dc, vp, chart_region);
2635bool Quilt::DoRenderQuiltRegionViewOnDC(wxMemoryDC &dc,
ViewPort &vp,
2637#ifdef ocpnUSE_DIBSECTION
2643 if (!m_bcomposed)
return false;
2647 if (GetnCharts() && !m_bbusy) {
2655 int chartsDrawn = 0;
2657 if (!chart_region.Empty()) {
2659 bool okToRender =
true;
2661 if (chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2662 vp.b_MercatorProjectionOverride)
2666 chart = GetNextChart();
2671 bool b_chart_rendered =
false;
2672 LLRegion get_region = pqp->ActiveRegion;
2675 chart_region, get_region, chart->GetNativeScale());
2676 if (!get_screen_region.Empty()) {
2677 if (!pqp->b_overlay) {
2678 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
2680 chart->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2684 if (Chs57->m_RAZBuilt) {
2685 b_chart_rendered = Chs57->RenderRegionViewOnDCNoText(
2686 tmp_dc, vp, get_screen_region);
2692 b_chart_rendered = ChPI->RenderRegionViewOnDCNoText(
2693 tmp_dc, vp, get_screen_region);
2695 b_chart_rendered = chart->RenderRegionViewOnDC(
2696 tmp_dc, vp, get_screen_region);
2698 b_chart_rendered =
true;
2705 screen_region.Subtract(get_screen_region);
2710 while (upd.HaveRects()) {
2711 wxRect rect = upd.GetRect();
2712 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc, rect.x,
2713 rect.y, wxCOPY,
true);
2717 tmp_dc.SelectObject(wxNullBitmap);
2719 if (b_chart_rendered) rendered_region.Union(get_screen_region);
2723 chart = GetNextChart();
2727 if (!chartsDrawn) m_parent->GetVP().SetProjectionType(PROJECTION_MERCATOR);
2730 if (m_bquilt_has_overlays && !chart_region.Empty()) {
2731 chart = GetFirstChart();
2735 if (pqp->b_overlay) {
2736 LLRegion get_region = pqp->ActiveRegion;
2738 chart_region, get_region, chart->GetNativeScale());
2739 if (!get_region.Empty()) {
2742 Chs57->RenderOverlayRegionViewOnDC(tmp_dc, vp,
2748 ChPI->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2753 while (upd.HaveRects()) {
2754 wxRect rect = upd.GetRect();
2755 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc,
2756 rect.x, rect.y, wxCOPY,
true);
2759 tmp_dc.SelectObject(wxNullBitmap);
2764 chart = GetNextChart();
2771 while (clrit.HaveRects()) {
2772 wxRect rect = clrit.GetRect();
2774 dc.SetPen(*wxBLACK_PEN);
2775 dc.SetBrush(*wxBLACK_BRUSH);
2776 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
2778 dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y,
2785 if (m_nHiLiteIndex >= 0) {
2788 wxRect box = hiregion.GetBox();
2790 if (!box.IsEmpty()) {
2793 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2794 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2801 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2805 q_dc.SelectObject(*m_pBM);
2806 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2807 q_dc.SelectObject(wxNullBitmap);
2812 wxBitmap hl_mask_bm(vp.rv_rect.width, vp.rv_rect.height, 1);
2814 mdc.SelectObject(hl_mask_bm);
2815 mdc.SetBackground(*wxBLACK_BRUSH);
2817 mdc.SetClippingRegion(box);
2818 mdc.SetBackground(*wxWHITE_BRUSH);
2820 mdc.SelectObject(wxNullBitmap);
2822 if (hl_mask_bm.IsOk()) {
2823 wxMask *phl_mask =
new wxMask(hl_mask_bm);
2824 m_pBM->SetMask(phl_mask);
2825 q_dc.SelectObject(*m_pBM);
2828 wxBitmap rbm(vp.rv_rect.width, vp.rv_rect.height);
2829 wxMask *pr_mask =
new wxMask(hl_mask_bm);
2831 rbm.SetMask(pr_mask);
2832 rdc.SelectObject(rbm);
2833 unsigned char hlcolor = 255;
2834 switch (global_color_scheme) {
2835 case GLOBAL_COLOR_SCHEME_DAY:
2838 case GLOBAL_COLOR_SCHEME_DUSK:
2841 case GLOBAL_COLOR_SCHEME_NIGHT:
2849 rdc.SetBackground(wxBrush(wxColour(hlcolor, 0, 0)));
2853 while (upd.HaveRects()) {
2854 wxRect rect = upd.GetRect();
2855 rdc.Blit(rect.x, rect.y, rect.width, rect.height, &q_dc, rect.x,
2856 rect.y, wxOR,
true);
2861 while (updq.HaveRects()) {
2862 wxRect rect = updq.GetRect();
2863 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &rdc, rect.x,
2864 rect.y, wxCOPY,
true);
2868 q_dc.SelectObject(wxNullBitmap);
2869 m_pBM->SetMask(NULL);
2872 dc.SelectObject(*m_pBM);
2875 rdc.SelectObject(wxNullBitmap);
2881 if (g_fog_overzoom) {
2884 if (scale_factor > g_overzoom_emphasis_base) {
2885 float fog = ((scale_factor - g_overzoom_emphasis_base) * 255.) / 20.;
2886 fog = wxMin(fog, 200.);
2890 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2891 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2898 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2902 q_dc.SelectObject(*m_pBM);
2903 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2904 q_dc.SelectObject(wxNullBitmap);
2906 wxImage src = m_pBM->ConvertToImage();
2909 wxMin((scale_factor - g_overzoom_emphasis_base) / 4, 4);
2911 wxImage dest = src.Blur(blur_factor);
2915 unsigned char *bg = src.GetData();
2916 wxColour color = m_parent->GetFogColor();
2918 float transparency = fog;
2921 wxImage dest(vp.rv_rect.width, vp.rv_rect.height);
2922 unsigned char *dest_data = (
unsigned char *) malloc( vp.rv_rect.width * vp.rv_rect.height * 3 *
sizeof(
unsigned char) );
2923 unsigned char *d = dest_data;
2925 float alpha = 1.0 - (float)transparency / 255.0;
2926 int sb = vp.rv_rect.width * vp.rv_rect.height;
2927 for(
int i = 0; i < sb; i++ ) {
2930 int r = ( ( *bg++ ) * a ) + (1.0-a) * color.Red();
2932 int g = ( ( *bg++ ) * a ) + (1.0-a) * color.Green();
2934 int b = ( ( *bg++ ) * a ) + (1.0-a) * color.Blue();
2938 dest.SetData( dest_data );
2943 ddc.SelectObject(dim);
2945 q_dc.SelectObject(*m_pBM);
2947 while (upd.HaveRects()) {
2948 wxRect rect = upd.GetRect();
2949 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &ddc, rect.x,
2954 ddc.SelectObject(wxNullBitmap);
2955 q_dc.SelectObject(wxNullBitmap);
2958 dc.SelectObject(*m_pBM);
2966 SubstituteClearDC(dc, vp);
2970 SubstituteClearDC(dc, vp);
2974 m_rendered_region = rendered_region;
2980void Quilt::SubstituteClearDC(wxMemoryDC &dc,
ViewPort &vp) {
2982 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2983 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2989 if (NULL == m_pBM) {
2990 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2993 dc.SelectObject(wxNullBitmap);
2994 dc.SelectObject(*m_pBM);
2995 dc.SetBackground(*wxBLACK_BRUSH);
2997 m_covered_region.Clear();
3000bool Quilt::DoRenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
3002 if (!m_bcomposed)
return false;
3006 if (GetnCharts() && !m_bbusy) {
3011 ChartBase *chart = GetLargestScaleChart();
3018 Chs57->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3022 ChPI->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3027 chart = GetNextSmallerScaleChart();
3031 SubstituteClearDC(dc, vp);
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
Manages the chart database and provides access to chart data.
Wrapper class for plugin-based charts.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
double rotation
Rotation angle of the viewport in radians.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
OCPNRegion GetVPRegionIntersect(const OCPNRegion ®ion, const LLRegion &llregion, int chart_native_scale)
Get the intersection of the viewport with a given region.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents an S57 format electronic navigational chart in OpenCPN.
Represents an entry in the chart table, containing information about a single chart.