32#include "ocpn_pixel.h"
35#ifdef __OCPN__ANDROID__
36#include "androidUTIL.h"
42#include <wx/listimpl.cpp>
43WX_DEFINE_LIST(PatchList);
46extern s52plib *ps52plib;
47extern ColorScheme global_color_scheme;
48extern int g_chart_zoom_modifier_raster;
49extern int g_chart_zoom_modifier_vector;
50extern bool g_fog_overzoom;
51extern double g_overzoom_emphasis_base;
62#ifndef __OCPN__ANDROID__
63#define GetChartTableEntry(i) GetChartTable()[i]
72#define NOCOVR_PLY_PERF_LIMIT 500
73#define AUX_PLY_PERF_LIMIT 500
75static int CompareScales(
int i1,
int i2) {
76 if (!ChartData)
return 0;
81 if (cte1.Scale_eq(cte2.GetScale())) {
83 lat1 = cte1.GetLatMax();
84 lat2 = cte2.GetLatMax();
85 if (roundf(lat1 * 100.) == roundf(lat2 * 100.)) {
87 lon1 = cte1.GetLonMin();
88 lon2 = cte2.GetLonMin();
92 return (lon1 < lon2) ? -1 : 1;
94 return (lat1 < lat2) ? 1 : -1;
96 return cte1.GetScale() - cte2.GetScale();
98static bool CompareScalesStd(
int i1,
int i2) {
99 return CompareScales(i1, i2) < 0;
104 if (!ChartData)
return 0;
105 return CompareScales(qc1->dbIndex, qc2->dbIndex);
108const LLRegion &QuiltCandidate::GetCandidateRegion() {
110 LLRegion &candidate_region =
111 const_cast<LLRegion &
>(cte.quilt_candidate_region);
113 if (!candidate_region.Empty())
return candidate_region;
115 LLRegion world_region(-90, -180, 90, 180);
119 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93COMP) {
120 double cm93_ll_bounds[8] = {-80, -180, -80, 180, 80, 180, 80, -180};
121 candidate_region = LLRegion(4, cm93_ll_bounds);
122 return candidate_region;
126 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
127 if (nAuxPlyEntries >= 1) {
128 candidate_region.Clear();
129 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
130 float *pfp = cte.GetpAuxPlyTableEntry(ip);
131 int nAuxPly = cte.GetAuxCntTableEntry(ip);
133 candidate_region.Union(LLRegion(nAuxPly, pfp));
146 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
148 std::vector<float> vecr;
149 for (
size_t i = 0; i < vec.size() / 2; i++) {
150 float a = vec[i * 2 + 1];
156 std::vector<float>::iterator it = vecr.begin();
158 if (vecr.size() / 2 >= 3) {
161 candidate_region = LLRegion(vecr.size() / 2, (
float *)&(*it));
163 candidate_region = world_region;
167 if (!candidate_region
169 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
170 if (nNoCovrPlyEntries) {
171 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
172 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
173 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
175 LLRegion t_region = LLRegion(nNoCovrPly, pfp);
184 if (nAuxPlyEntries > 1) {
185 for (
int ipr = 0; ipr < nAuxPlyEntries; ipr++) {
186 float *pfpr = cte.GetpAuxPlyTableEntry(ipr);
187 int nAuxPly = cte.GetAuxCntTableEntry(ipr);
188 t_region.Subtract(LLRegion(nAuxPly, pfpr));
197 if (!t_region.Empty()) {
198 LLRegion test_region = candidate_region;
199 test_region.Subtract(t_region);
200 if (!test_region.Empty()) candidate_region = test_region;
210 if ((cte.GetScale() > 90000000) &&
211 (cte.GetChartFamily() == CHART_FAMILY_RASTER))
212 candidate_region = world_region;
214 return candidate_region;
217LLRegion &QuiltCandidate::GetReducedCandidateRegion(
double factor) {
218 if (factor != last_factor) {
219 reduced_candidate_region = GetCandidateRegion();
220 reduced_candidate_region.Reduce(factor);
221 last_factor = factor;
224 return reduced_candidate_region;
227void QuiltCandidate::SetScale(
int scale) {
231 if (
scale >= 1000) rounding = 5 * pow(10, log10(
scale) - 2);
240 m_reference_scale = 1;
241 m_refchart_dbIndex = -1;
242 m_reference_type = CHART_TYPE_UNKNOWN;
243 m_reference_family = CHART_FAMILY_UNKNOWN;
244 m_quilt_proj = PROJECTION_UNKNOWN;
246 m_lost_refchart_dbIndex = -1;
256 new ArrayOfSortedQuiltCandidates(CompareQuiltCandidateScales);
261 m_preferred_family = CHART_FAMILY_RASTER;
264 m_bquiltskew = g_bopengl;
266 m_bquiltanyproj = g_bopengl;
270 m_PatchList.DeleteContents(
true);
273 EmptyCandidateArray();
274 delete m_pcandidate_array;
276 m_extended_stack_array.clear();
281bool Quilt::IsVPBlittable(
ViewPort &VPoint,
int dx,
int dy,
282 bool b_allow_vector) {
283 if (!m_vp_rendered.IsValid())
return false;
288 double deltax = p2.m_x - p1.m_x;
289 double deltay = p2.m_y - p1.m_y;
291 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
return false;
296bool Quilt::IsChartS57Overlay(
int db_index) {
297 if (db_index < 0)
return false;
300 if (CHART_FAMILY_VECTOR == cte.GetChartFamily()) {
301 return s57chart::IsCellOverlayType(cte.GetFullSystemPath());
306bool Quilt::IsChartQuiltableRef(
int db_index) {
307 if (db_index < 0 || db_index >
ChartData->GetChartTableEntries() - 1)
313 bool bproj_match =
true;
315 double skew_norm = ctei.GetChartSkew();
316 if (skew_norm > 180.) skew_norm -= 360.;
319 fabs(skew_norm) < 1.;
320 if (m_bquiltskew) skew_match =
true;
323 bool b_noshow =
false;
324 for (
unsigned int i = 0; i < m_parent->GetQuiltNoshowIindexArray().size();
326 if (m_parent->GetQuiltNoshowIindexArray()[i] ==
334 return (bproj_match & skew_match & !b_noshow);
337bool Quilt::IsChartInQuilt(
ChartBase *pc) {
339 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
341 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
342 if (
ChartData->OpenChartFromDB(pqc->dbIndex, FULL_INIT) == pc)
349bool Quilt::IsChartInQuilt(wxString &full_path) {
351 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
353 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
355 if (pcte->GetpsFullPath()->IsSameAs(full_path))
return true;
361std::vector<int> Quilt::GetCandidatedbIndexArray(
bool from_ref_chart,
362 bool exclude_user_hidden) {
363 std::vector<int> ret;
364 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
368 if (pqc->Scale_ge(m_reference_scale)) {
370 if (exclude_user_hidden) {
371 bool b_noshow =
false;
372 for (
unsigned int i = 0;
373 i < m_parent->GetQuiltNoshowIindexArray().size(); i++) {
374 if (m_parent->GetQuiltNoshowIindexArray()[i] ==
381 if (!b_noshow) ret.push_back(pqc->dbIndex);
383 ret.push_back(pqc->dbIndex);
387 ret.push_back(pqc->dbIndex);
394 return (cnode->GetData());
399void Quilt::EmptyCandidateArray(
void) {
400 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
401 delete m_pcandidate_array->Item(i);
404 m_pcandidate_array->Clear();
414 if (!m_bcomposed)
return NULL;
416 if (m_bbusy)
return NULL;
420 cnode = m_PatchList.GetFirst();
421 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetNext();
422 if (cnode && cnode->GetData()->b_Valid)
423 pret =
ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
434 if (m_bbusy)
return NULL;
439 cnode = cnode->GetNext();
440 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetNext();
441 if (cnode && cnode->GetData()->b_Valid)
442 pret =
ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
449ChartBase *Quilt::GetNextSmallerScaleChart() {
454 if (m_bbusy)
return NULL;
459 cnode = cnode->GetPrevious();
460 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetPrevious();
461 if (cnode && cnode->GetData()->b_Valid)
462 pret =
ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
469ChartBase *Quilt::GetLargestScaleChart() {
472 if (m_bbusy)
return NULL;
476 cnode = m_PatchList.GetLast();
478 pret =
ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
485 LLRegion chart_region;
486 LLRegion screen_region(vp.GetBBox());
491 if (fabs(cte.GetLonMax() - cte.GetLonMin()) > 180.) {
508 return LLRegion(-80, vp.GetBBox().GetMinLon(), 80,
509 vp.GetBBox().GetMaxLon());
513 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
514 bool aux_ply_skipped =
false;
515 if (nAuxPlyEntries >= 1) {
516 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
517 int nAuxPly = cte.GetAuxCntTableEntry(ip);
518 if (nAuxPly > AUX_PLY_PERF_LIMIT) {
521 aux_ply_skipped =
true;
524 float *pfp = cte.GetpAuxPlyTableEntry(ip);
525 LLRegion t_region(nAuxPly, pfp);
526 t_region.Intersect(screen_region);
530 if (!t_region.Empty()) chart_region.Union(t_region);
534 if (aux_ply_skipped || nAuxPlyEntries == 0) {
535 int n_ply_entries = cte.GetnPlyEntries();
536 float *pfp = cte.GetpPlyTable();
538 if (n_ply_entries >= 3)
541 LLRegion t_region(n_ply_entries, pfp);
542 t_region.Intersect(screen_region);
546 if (!t_region.Empty()) chart_region.Union(t_region);
549 chart_region = screen_region;
553 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
554 if (nNoCovrPlyEntries) {
555 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
556 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
557 if (nNoCovrPly > NOCOVR_PLY_PERF_LIMIT) {
562 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
564 LLRegion t_region(nNoCovrPly, pfp);
565 t_region.Intersect(screen_region);
576 if (!t_region.Empty()) {
577 LLRegion test_region = chart_region;
578 test_region.Subtract(t_region);
580 if (!test_region.Empty()) chart_region = test_region;
589 if ((cte.GetScale() > 90000000) &&
590 (cte.GetChartFamily() == CHART_FAMILY_RASTER))
591 chart_region = screen_region;
599bool Quilt::IsQuiltVector(
void) {
600 if (m_bbusy)
return false;
606 wxPatchListNode *cnode = m_PatchList.GetFirst();
608 if (cnode->GetData()) {
611 if ((pqp->b_Valid) && (!pqp->b_eclipsed) &&
612 (pqp->dbIndex <
ChartData->GetChartTableEntries())) {
614 ChartData->GetChartTableEntry(pqp->dbIndex);
616 if (ctei.GetChartFamily() == CHART_FAMILY_VECTOR) {
622 cnode = cnode->GetNext();
629bool Quilt::DoesQuiltContainPlugins(
void) {
630 if (m_bbusy)
return false;
636 wxPatchListNode *cnode = m_PatchList.GetFirst();
638 if (cnode->GetData()) {
641 if ((pqp->b_Valid) && (!pqp->b_eclipsed)) {
643 ChartData->GetChartTableEntry(pqp->dbIndex);
645 if (ctei.GetChartType() == CHART_TYPE_PLUGIN) {
651 cnode = cnode->GetNext();
658int Quilt::GetChartdbIndexAtPix(
ViewPort &VPoint, wxPoint p) {
659 if (m_bbusy)
return -1;
668 wxPatchListNode *cnode = m_PatchList.GetFirst();
670 if (cnode->GetData()->ActiveRegion.Contains(lat, lon)) {
671 ret = cnode->GetData()->dbIndex;
674 cnode = cnode->GetNext();
682 if (m_bbusy)
return NULL;
694 wxPatchListNode *cnode = m_PatchList.GetFirst();
697 if (!pqp->b_overlay && (pqp->ActiveRegion.Contains(lat, lon)))
698 if (
ChartData->IsChartInCache(pqp->dbIndex)) {
699 pret =
ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
701 cnode = cnode->GetNext();
709 if (m_bbusy)
return NULL;
721 wxPatchListNode *cnode = m_PatchList.GetFirst();
724 if (pqp->b_overlay && (pqp->ActiveRegion.Contains(lat, lon)))
725 pret =
ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
726 cnode = cnode->GetNext();
733void Quilt::InvalidateAllQuiltPatchs(
void) {
744std::vector<int> Quilt::GetQuiltIndexArray(
void) {
745 return m_index_array;
747 std::vector<int> ret;
749 if (m_bbusy)
return ret;
753 wxPatchListNode *cnode = m_PatchList.GetFirst();
755 ret.push_back(cnode->GetData()->dbIndex);
756 cnode = cnode->GetNext();
764bool Quilt::IsQuiltDelta(
ViewPort &vp) {
765 if (!m_vp_quilt.IsValid() || !m_bcomposed)
return true;
769 if (m_vp_quilt.m_projection_type != vp.m_projection_type)
return true;
774 wxPoint cp_last, cp_this;
779 return (cp_last != cp_this);
787 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
789 if (pRefChart) pRefChart->AdjustVP(vp_last, vp_proposed);
792double Quilt::GetRefNativeScale() {
793 double ret_val = 1.0;
796 if (pc) ret_val = pc->GetNativeScale();
802int Quilt::GetNewRefChart(
void) {
808 int new_ref_dbIndex = m_refchart_dbIndex;
809 unsigned int im = m_extended_stack_array.size();
811 for (
unsigned int is = 0; is < im; is++) {
813 ChartData->GetChartTableEntry(m_extended_stack_array[is]);
815 double skew_norm = m.GetChartSkew();
816 if (skew_norm > 180.) skew_norm -= 360.;
818 if ((m.Scale_ge(m_reference_scale)) &&
819 (m_reference_family == m.GetChartFamily()) &&
820 (m_bquiltanyproj || m_quilt_proj == m.GetChartProjectionType()) &&
821 (m_bquiltskew || (fabs(skew_norm) < 1.0))) {
822 new_ref_dbIndex = m_extended_stack_array[is];
827 return new_ref_dbIndex;
830int Quilt::GetNomScaleMax(
int scale, ChartTypeEnum type,
831 ChartFamilyEnum family) {
833 case CHART_FAMILY_RASTER: {
837 case CHART_FAMILY_VECTOR: {
847int Quilt::GetNomScaleMin(
int scale, ChartTypeEnum type,
848 ChartFamilyEnum family) {
849 double zoom_mod = (double)g_chart_zoom_modifier_raster;
851 if (family == CHART_FAMILY_VECTOR)
852 zoom_mod = (double)g_chart_zoom_modifier_vector;
854 double modf = zoom_mod / 5.;
855 double mod = pow(16., modf);
856 mod = wxMax(mod, .2);
857 mod = wxMin(mod, 16.0);
861 case CHART_FAMILY_RASTER: {
862 if (CHART_TYPE_MBTILES == type)
868 return scale * 1 * mod;
871 case CHART_FAMILY_VECTOR: {
872 return scale * 4 * mod;
876 mod = wxMin(mod, 2.0);
877 return scale * 2 * mod;
883 int index, nom, min, max;
886int Quilt::AdjustRefOnZoom(
bool b_zin, ChartFamilyEnum family,
887 ChartTypeEnum type,
double proposed_scale_onscreen) {
888 std::vector<scale> scales;
889 std::vector<scale> scales_mbtiles;
898 bool b_allow_fullscreen_ref =
899 (family == CHART_FAMILY_VECTOR) || b_zin || g_bopengl;
903 int smallest_scale = 1;
904 for (
size_t i = 0; i < m_extended_stack_array.size(); i++) {
905 int index = m_extended_stack_array[i];
906 if (
ChartData->GetDBChartType(index) == type)
907 smallest_scale = wxMax(smallest_scale,
ChartData->GetDBChartScale(index));
912 for (
size_t i = 0; i < m_extended_stack_array.size(); i++) {
913 int test_db_index = m_extended_stack_array[i];
915 if (b_allow_fullscreen_ref ||
916 m_parent->GetpCurrentStack()->DoesStackContaindbIndex(test_db_index)) {
917 if ((family ==
ChartData->GetDBChartFamily(test_db_index)) &&
918 IsChartQuiltableRef(test_db_index)
920 int nscale =
ChartData->GetDBChartScale(test_db_index);
922 int nmax_scale = GetNomScaleMax(nscale, type, family);
926 if (0 == i_first) nmax_scale = 1;
928 int nmin_scale = GetNomScaleMin(nscale, type, family);
931 if ((type == CHART_TYPE_KAP) && (nscale == smallest_scale))
936 if ((type == CHART_TYPE_MBTILES) && (nscale == smallest_scale))
939 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(test_db_index))
940 scales_mbtiles.push_back(
941 scale{test_db_index, nscale, nmin_scale, nmax_scale});
944 scale{test_db_index, nscale, nmin_scale, nmax_scale});
951 if (scales.empty()) scales = scales_mbtiles;
958 if (CHART_FAMILY_VECTOR == family) {
959 for (
size_t i = scales.size(); i; i--) {
960 int test_db_index = scales[i - 1].index;
961 if (type ==
ChartData->GetDBChartType(test_db_index)) {
962 scales[i - 1].min = scales[i - 1].nom * 80;
974 if (scales.size() > 1) {
975 for (
unsigned i = 0; i < scales.size() - 1; i++) {
976 int min_scale_test = wxMax(scales[i].min, scales[i + 1].max + 1);
977 min_scale_test = wxMin(min_scale_test, scales[i].min * 2);
978 scales[i].min = min_scale_test;
987 if (scales.size() > 2) {
988 for (
size_t i = scales.size() - 2; i >= 1; i--) {
989 scales[i].max = wxMin(scales[i].max, scales[i - 1].min - 1);
993 int new_ref_dbIndex = -1;
997 for (
size_t i = 0; i < scales.size(); i++) {
998 if ((proposed_scale_onscreen <
1001 (proposed_scale_onscreen > scales[i].max)) {
1002 new_ref_dbIndex = scales[i].index;
1007 return new_ref_dbIndex;
1010int Quilt::AdjustRefOnZoomOut(
double proposed_scale_onscreen) {
1012 m_lost_refchart_dbIndex = -1;
1014 int current_db_index = m_refchart_dbIndex;
1015 int current_family = m_reference_family;
1016 ChartTypeEnum current_type = (ChartTypeEnum)m_reference_type;
1018 if (m_refchart_dbIndex >= 0) {
1020 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1021 current_family = cte.GetChartFamily();
1022 current_type = (ChartTypeEnum)cte.GetChartType();
1025 if (current_type == CHART_TYPE_CM93COMP)
return current_db_index;
1027 int proposed_ref_index =
1028 AdjustRefOnZoom(
false, (ChartFamilyEnum)current_family, current_type,
1029 proposed_scale_onscreen);
1032 if (proposed_ref_index < 0) {
1033 m_zout_family = current_family;
1034 m_zout_type = current_type;
1035 m_zout_dbindex = current_db_index;
1038 SetReferenceChart(proposed_ref_index);
1040 return proposed_ref_index;
1043int Quilt::AdjustRefOnZoomIn(
double proposed_scale_onscreen) {
1045 m_lost_refchart_dbIndex = -1;
1047 int current_db_index = m_refchart_dbIndex;
1048 int current_family = m_reference_family;
1049 ChartTypeEnum current_type = (ChartTypeEnum)m_reference_type;
1051 if (m_zout_family >= 0) {
1052 current_type = (ChartTypeEnum)m_zout_type;
1053 current_family = m_zout_family;
1059 if (current_type == CHART_TYPE_CM93COMP) {
1060 if (m_zout_family >= 0) {
1061 current_family =
ChartData->GetDBChartFamily(m_zout_dbindex);
1063 return current_db_index;
1066 if ((-1 == m_refchart_dbIndex) && (m_zout_dbindex >= 0))
1067 BuildExtendedChartStackAndCandidateArray(m_zout_dbindex, m_vp_quilt);
1069 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, m_vp_quilt);
1071 int proposed_ref_index =
1072 AdjustRefOnZoom(
true, (ChartFamilyEnum)current_family, current_type,
1073 proposed_scale_onscreen);
1075 if (current_db_index == -1) {
1076 SetReferenceChart(proposed_ref_index);
1077 return proposed_ref_index;
1080 if (proposed_ref_index != -1) {
1081 if (
ChartData->GetDBChartScale(current_db_index) >=
1082 ChartData->GetDBChartScale(proposed_ref_index)) {
1083 SetReferenceChart(proposed_ref_index);
1084 return proposed_ref_index;
1087 proposed_ref_index = current_db_index;
1089 SetReferenceChart(proposed_ref_index);
1091 return proposed_ref_index;
1094bool Quilt::IsChartSmallestScale(
int dbIndex) {
1099 int specified_type =
ChartData->GetDBChartType(dbIndex);
1100 int target_dbindex = -1;
1102 unsigned int target_stack_index = 0;
1103 if (m_extended_stack_array.size()) {
1104 while ((target_stack_index <= (m_extended_stack_array.size() - 1))) {
1105 int test_db_index = m_extended_stack_array[target_stack_index];
1107 if (specified_type ==
ChartData->GetDBChartType(test_db_index))
1108 target_dbindex = test_db_index;
1110 target_stack_index++;
1113 return (dbIndex == target_dbindex);
1116LLRegion Quilt::GetHiliteRegion() {
1122 for (
auto &index : m_HiLiteIndexArray) {
1124 LLRegion cell_region = GetChartQuiltRegion(cte, m_vp_quilt);
1125 r.Union(cell_region);
1129 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1130 wxPatchListNode *pcinode = m_PatchList.Item(i);
1132 if ((index == piqp->dbIndex) && (piqp->b_Valid))
1134 r.Union(piqp->ActiveRegion);
1143LLRegion Quilt::GetHiliteRegion() {
1145 if (m_nHiLiteIndex >= 0) {
1147 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1148 wxPatchListNode *pcinode = m_PatchList.Item(i);
1150 if ((m_nHiLiteIndex == piqp->dbIndex) && (piqp->b_Valid))
1152 r = piqp->ActiveRegion;
1159 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1161 if (m_nHiLiteIndex == pqc->dbIndex) {
1162 LLRegion chart_region = pqc->GetCandidateRegion();
1163 if (!chart_region.Empty()) {
1165 bool b_eclipsed =
false;
1166 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size();
1168 if (m_nHiLiteIndex == m_eclipsed_stack_array[ir]) {
1174 if (!b_eclipsed) r = chart_region;
1184 ChartData->GetChartTableEntry(m_nHiLiteIndex);
1185 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
1186 r = GetTilesetRegion(m_nHiLiteIndex);
1194const LLRegion &Quilt::GetTilesetRegion(
int dbIndex) {
1195 LLRegion world_region(-90, -180, 90, 180);
1198 LLRegion &target_region =
const_cast<LLRegion &
>(cte.quilt_candidate_region);
1200 if (!target_region.Empty())
return target_region;
1203 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
1204 if (nAuxPlyEntries >= 1) {
1205 target_region.Clear();
1206 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
1207 float *pfp = cte.GetpAuxPlyTableEntry(ip);
1208 int nAuxPly = cte.GetAuxCntTableEntry(ip);
1210 target_region.Union(LLRegion(nAuxPly, pfp));
1213 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1215 std::vector<float> vecr;
1216 for (
size_t i = 0; i < vec.size() / 2; i++) {
1217 float a = vec[i * 2 + 1];
1223 std::vector<float>::iterator it = vecr.begin();
1225 if (vecr.size() / 2 >= 3) {
1228 target_region = LLRegion(vecr.size() / 2, (
float *)&(*it));
1230 target_region = world_region;
1234 if (!target_region.Empty()) {
1235 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
1236 if (nNoCovrPlyEntries) {
1237 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
1238 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
1239 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
1241 LLRegion t_region = LLRegion(nNoCovrPly, pfp);
1248 if (!t_region.Empty()) {
1249 LLRegion test_region = target_region;
1250 test_region.Subtract(t_region);
1252 if (!test_region.Empty()) target_region = test_region;
1266 return target_region;
1269bool Quilt::BuildExtendedChartStackAndCandidateArray(
int ref_db_index,
1271 double zoom_test_val = .002;
1274 EmptyCandidateArray();
1275 m_extended_stack_array.clear();
1276 m_fullscreen_index_array.clear();
1278 int reference_scale = 1e8;
1279 int reference_type = -1;
1280 int reference_family = -1;
1282 m_bquiltanyproj ? vp_in.m_projection_type : PROJECTION_UNKNOWN;
1284 if (ref_db_index >= 0) {
1286 ChartData->GetChartTableEntry(ref_db_index);
1287 reference_scale = cte_ref.GetScale();
1288 reference_type = cte_ref.GetChartType();
1289 if (!m_bquiltanyproj) quilt_proj =
ChartData->GetDBChartProj(ref_db_index);
1290 reference_family = cte_ref.GetChartFamily();
1293 bool b_need_resort =
false;
1303 int n_charts = m_parent->GetpCurrentStack()->nEntry;
1307 for (
int ics = 0; ics < n_charts; ics++) {
1308 int istack = m_parent->GetpCurrentStack()->GetDBIndex(ics);
1309 if (istack < 0)
continue;
1310 m_extended_stack_array.push_back(istack);
1316 if (reference_type == CHART_TYPE_CM93COMP)
continue;
1326 if ((cte.GetChartType() == CHART_TYPE_PLUGIN) ||
1327 (reference_type == CHART_TYPE_PLUGIN)) {
1328 if (reference_family != cte.GetChartFamily()) {
1332 if (reference_type != cte.GetChartType()) {
1337 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1340 int candidate_chart_scale = cte.GetScale();
1341 double chart_native_ppm =
1342 m_canvas_scale_factor / (double)candidate_chart_scale;
1344 if ((zoom_factor < zoom_test_val) &&
1349 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
1350 m_extended_stack_array.pop_back();
1354 double skew_norm = cte.GetChartSkew();
1355 if (skew_norm > 180.) skew_norm -= 360.;
1357 if ((m_bquiltskew ? 1 : fabs(skew_norm) < 1.0) &&
1358 (m_bquiltanyproj || cte.GetChartProjectionType() == quilt_proj)) {
1360 qcnew->dbIndex = istack;
1361 qcnew->SetScale(cte.GetScale());
1362 m_pcandidate_array->push_back(qcnew);
1389 int n_all_charts =
ChartData->GetChartTableEntries();
1391 LLBBox viewbox = vp_local.GetBBox();
1392 int sure_index = -1;
1393 int sure_index_scale = 0;
1394 int sure_index_type = -1;
1396 for (
int i = 0; i < n_all_charts; i++) {
1400 int groupIndex = m_parent->m_groupIndex;
1401 if ((groupIndex > 0) && (!
ChartData->IsChartInGroup(i, groupIndex)))
1407 if (
ChartData->IsChartDirectoryExcluded(cte.GetFullPath()))
continue;
1409 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
1410 m_fullscreen_index_array.push_back(i);
1414#ifdef __OCPN__ANDROID__
1415 wxFileName fn(cte.GetFullSystemPath());
1416 if (!androidIsDirWritable(fn.GetPath()))
continue;
1418 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1420 const LLBBox &chart_box = cte.GetBBox();
1421 if ((viewbox.IntersectOut(chart_box)))
continue;
1423 if (cte.GetChartType() == CHART_TYPE_PLUGIN) {
1424 if (!
ChartData->IsChartAvailable(i))
continue;
1427 m_fullscreen_index_array.push_back(i);
1429 if (reference_family != cte.GetChartFamily()) {
1430 if (cte.GetChartType() != CHART_TYPE_MBTILES)
continue;
1433 if (!m_bquiltanyproj && quilt_proj != cte.GetChartProjectionType())
1436 double skew_norm = cte.GetChartSkew();
1437 if (skew_norm > 180.) skew_norm -= 360.;
1439 if (!m_bquiltskew && fabs(skew_norm) > 1.0)
continue;
1444 if( CHART_TYPE_S57 == cte.GetChartType() ) {
1446 double chart_area = (cte.GetLonMax() - cte.GetLonMin()) *
1447 (cte.GetLatMax() - cte.GetLatMin());
1448 double quilt_area = viewbox.GetLonRange() * viewbox.GetLatRange();
1449 if ((chart_area / quilt_area) < .01)
continue;
1452 int candidate_chart_scale = cte.GetScale();
1458 if (!cte.Scale_ge(reference_scale)) {
1459 if (cte.Scale_gt(sure_index_scale)) {
1461 sure_index_scale = candidate_chart_scale;
1462 sure_index_type = cte.GetChartType();
1471 double chart_native_ppm =
1472 m_canvas_scale_factor / (double)candidate_chart_scale;
1474 double zoom_factor_test_extra = 0.2;
1480 double ref_scale_test = reference_scale;
1481 if (cte.GetChartType() == CHART_TYPE_MBTILES)
1482 ref_scale_test = candidate_chart_scale;
1484 if ((cte.Scale_ge(ref_scale_test) && (zoom_factor > zoom_test_val)) ||
1485 (zoom_factor > zoom_factor_test_extra)) {
1486 LLRegion cell_region = GetChartQuiltRegion(cte, vp_local);
1491 if (!cell_region.Empty()) {
1494 bool b_exists =
false;
1495 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1496 if (i == m_extended_stack_array[ir]) {
1510 bool b_noadd =
false;
1512 for (
unsigned int id = 0;
id < m_extended_stack_array.size();
id++) {
1513 if (m_extended_stack_array[
id] != -1) {
1515 ChartData->GetpChartTableEntry(m_extended_stack_array[
id]);
1516 bool bsameTime =
false;
1517 if (pm->GetFileTime() && pn->GetFileTime()) {
1518 if (labs(pm->GetFileTime() - pn->GetFileTime()) < 60)
1521 if (pm->GetChartEditionDate() == pn->GetChartEditionDate())
1525 if (pn->GetpFileName()->IsSameAs(*(pm->GetpFileName())))
1532 m_extended_stack_array.push_back(i);
1537 candidate_chart_scale);
1539 m_pcandidate_array->push_back(qcnew);
1541 b_need_resort =
true;
1550 if (-1 != sure_index) {
1552 bool sure_exists =
false;
1553 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1554 if (sure_index == m_extended_stack_array[ir]) {
1561 if (!sure_exists && (sure_index_type != CHART_TYPE_MBTILES)) {
1562 m_extended_stack_array.push_back(sure_index);
1565 qcnew->dbIndex = sure_index;
1566 qcnew->SetScale(
ChartData->GetDBChartScale(sure_index));
1567 m_pcandidate_array->push_back(qcnew);
1569 b_need_resort =
true;
1574 if (b_need_resort && m_extended_stack_array.size() > 1) {
1575 std::sort(m_extended_stack_array.begin(), m_extended_stack_array.end(),
1581int Quilt::AdjustRefSelection(
const ViewPort &vp_in) {
1596 vp_local.SetRotationAngle(0.);
1598 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1600 ChartFamilyEnum family = CHART_FAMILY_RASTER;
1601 ChartTypeEnum type = CHART_TYPE_KAP;
1604 if (m_refchart_dbIndex >= 0) {
1606 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1607 type = (ChartTypeEnum)cte_ref.GetChartType();
1608 family = (ChartFamilyEnum)cte_ref.GetChartFamily();
1611 int ret_index = AdjustRefOnZoom(
true, family, type, vp_in.
chart_scale);
1616double Quilt::GetBestStartScale(
int dbi_ref_hint,
const ViewPort &vp_in) {
1626 int tentative_ref_index = dbi_ref_hint;
1627 if (dbi_ref_hint < 0) {
1634 tentative_ref_index = m_parent->GetpCurrentStack()->GetDBIndex(0);
1641 vp_local.SetRotationAngle(0.);
1643 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1647 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1649 if (qc->dbIndex == tentative_ref_index) {
1655 if (!bf && m_pcandidate_array->GetCount()) {
1656 tentative_ref_index = GetNewRefChart();
1657 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1660 double proposed_scale_onscreen = vp_in.
chart_scale;
1662 if (m_pcandidate_array->GetCount()) {
1663 m_refchart_dbIndex = tentative_ref_index;
1667 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1669 if (IsChartQuiltableRef(qc->dbIndex)) {
1670 m_refchart_dbIndex = qc->dbIndex;
1677 m_refchart_dbIndex = m_parent->GetpCurrentStack()->GetDBIndex(0);
1680 if (m_refchart_dbIndex >= 0) {
1685 double min_ref_scale =
1687 double max_ref_scale = pc->GetNormalScaleMax(
1689 if ((proposed_scale_onscreen >= min_ref_scale) &&
1690 (proposed_scale_onscreen <= max_ref_scale))
1693 proposed_scale_onscreen = wxMin(proposed_scale_onscreen, max_ref_scale);
1694 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, min_ref_scale);
1702 if (m_refchart_dbIndex >= 0 &&
ChartData)
1703 return ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
1707void Quilt::UnlockQuilt() {
1708 wxASSERT(m_bbusy ==
false);
1711 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1713 ChartData->UnLockCacheChart(pqc->dbIndex);
1724 if (!m_parent->GetpCurrentStack())
return false;
1726 if (m_bbusy)
return false;
1735 if (m_refchart_dbIndex >= 0) {
1737 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1738 m_reference_scale = cte_ref.GetScale();
1739 m_reference_type = cte_ref.GetChartType();
1740 if (!m_bquiltanyproj)
1741 m_quilt_proj =
ChartData->GetDBChartProj(m_refchart_dbIndex);
1742 m_reference_family = cte_ref.GetChartFamily();
1746 if (!m_bquiltanyproj) vp_local.SetProjectionType(m_quilt_proj);
1753 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1793 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1795 if (qc->dbIndex == m_refchart_dbIndex) {
1801 if (!bf && m_pcandidate_array->GetCount() &&
1802 (m_reference_type != CHART_TYPE_CM93COMP)) {
1803 m_lost_refchart_dbIndex = m_refchart_dbIndex;
1804 int candidate_ref_index = GetNewRefChart();
1805 if (m_refchart_dbIndex != candidate_ref_index) {
1806 m_refchart_dbIndex = candidate_ref_index;
1807 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1812 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1813 if (m_pcandidate_array->GetCount()) {
1814 m_refchart_dbIndex =
1815 m_pcandidate_array->Item(m_pcandidate_array->GetCount() - 1)
1817 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1822 if ((-1 != m_lost_refchart_dbIndex) &&
1823 (m_lost_refchart_dbIndex != m_refchart_dbIndex)) {
1826 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1827 if (m_lost_refchart_dbIndex == m_extended_stack_array[ir]) {
1828 m_refchart_dbIndex = m_lost_refchart_dbIndex;
1829 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1830 m_lost_refchart_dbIndex = -1;
1836 bool b_has_overlays =
false;
1839 if (CHART_FAMILY_VECTOR == m_reference_family) {
1840 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1844 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1845 b_has_overlays =
true;
1858 const LLRegion cvp_region = vp_local.GetLLRegion(vp_local.rv_rect);
1859 LLRegion vp_region = cvp_region;
1865 for (ir = 0; ir < m_pcandidate_array->GetCount();
1869 if (pqc->dbIndex == m_refchart_dbIndex) {
1878 const double z = 111274.96299695622;
1884 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1886 LLRegion vpu_region(cvp_region);
1889 LLRegion &chart_region = pqc_ref->GetReducedCandidateRegion(factor);
1891 if (cte_ref.GetChartType() != CHART_TYPE_MBTILES) {
1892 if (!chart_region.Empty()) {
1893 vpu_region.Intersect(chart_region);
1895 if (vpu_region.Empty())
1896 pqc_ref->b_include =
false;
1898 pqc_ref->b_include =
true;
1899 vp_region.Subtract(chart_region);
1902 pqc_ref->b_include =
false;
1904 pqc_ref->b_include =
false;
1909 if (!vp_region.Empty()) {
1910 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1913 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1920 if (CHART_FAMILY_VECTOR == m_reference_family) {
1921 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1927 if (CHART_TYPE_MBTILES == cte.GetChartType()) {
1928 pqc->b_include =
false;
1932 if (cte.Scale_ge(m_reference_scale)) {
1936 bool b_in_noshow =
false;
1937 for (
unsigned int ins = 0;
1938 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1939 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
1949 LLRegion vpu_region(cvp_region);
1952 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
1954 if (!chart_region.Empty()) {
1955 vpu_region.Intersect(chart_region);
1957 if (vpu_region.Empty())
1958 pqc->b_include =
false;
1960 pqc->b_include =
true;
1961 vp_region.Subtract(chart_region);
1964 pqc->b_include =
false;
1966 pqc->b_include =
true;
1970 pqc->b_include =
false;
1973 if (vp_region.Empty())
1980 if (b_has_overlays && (CHART_FAMILY_VECTOR == m_reference_family)) {
1981 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1984 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1988 if (cte.Scale_ge(m_reference_scale)) {
1989 bool b_in_noshow =
false;
1990 for (
unsigned int ins = 0;
1991 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1992 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
2002 LLRegion vpu_region(cvp_region);
2005 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
2007 if (!chart_region.Empty()) vpu_region.Intersect(chart_region);
2009 if (vpu_region.Empty())
2010 pqc->b_include =
false;
2013 s57chart::IsCellOverlayType(cte.GetFullSystemPath());
2014 if (b_overlay) pqc->b_include =
true;
2021 ChartData->GetChartTableEntry(m_refchart_dbIndex);
2022 if (s57chart::IsCellOverlayType(cte_ref.GetFullSystemPath())) {
2023 pqc->b_include =
true;
2035 m_eclipsed_stack_array.clear();
2037 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2040 if (!pqc->b_include) {
2042 if (cte.Scale_ge(m_reference_scale) &&
2043 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
2044 m_eclipsed_stack_array.push_back(pqc->dbIndex);
2045 pqc->b_eclipsed =
true;
2052 if (((m_bquiltanyproj || m_quilt_proj == PROJECTION_MERCATOR)) &&
2053 !vp_region.Empty()) {
2054 bool b_must_add_cm93 =
true;
2061 while( updd .HaveRects()) {
2062 wxRect rect = updd.GetRect();
2063 if( ( rect.width > 2 ) && ( rect.height > 2 ) ) {
2064 b_must_add_cm93 =
true;
2071 if (b_must_add_cm93) {
2072 for (
int ics = 0; ics < m_parent->GetpCurrentStack()->nEntry; ics++) {
2073 int i = m_parent->GetpCurrentStack()->GetDBIndex(ics);
2074 if (CHART_TYPE_CM93COMP ==
ChartData->GetDBChartType(i)) {
2077 qcnew->SetScale(
ChartData->GetDBChartScale(i));
2079 m_pcandidate_array->Add(qcnew);
2090 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
2092 if (pqc->b_include) {
2098 if (!b_vis && m_pcandidate_array->GetCount()) {
2101 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2106 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2109 if (cte.GetChartType() == CHART_TYPE_MBTILES)
continue;
2112 LLRegion vpck_region(vp_local.GetBBox());
2115 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
2117 if (!chart_region.Empty()) vpck_region.Intersect(chart_region);
2119 if (!vpck_region.Empty()) {
2121 if (cte.Scale_eq(add_scale)) {
2122 pqc->b_include =
true;
2125 pqc->b_include =
true;
2126 add_scale = cte.GetScale();
2135 m_PatchList.DeleteContents(
true);
2136 m_PatchList.Clear();
2138 if (m_pcandidate_array->GetCount()) {
2139 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2147 if (m.GetChartType() == CHART_TYPE_CM93COMP)
2148 pqc->b_include =
true;
2151 if (pqc->b_include) {
2153 pqp->dbIndex = pqc->dbIndex;
2154 pqp->ProjType = m.GetChartProjectionType();
2157 pqp->quilt_region = pqc->GetCandidateRegion();
2160 pqp->b_Valid =
true;
2162 m_PatchList.Append(pqp);
2169 if (!m_bquiltanyproj) {
2171 m_quilt_proj = PROJECTION_MERCATOR;
2172 ChartBase *ppc = GetLargestScaleChart();
2173 if (ppc) m_quilt_proj = ppc->GetChartProjectionType();
2177 if (!m_bquiltanyproj) {
2180 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2181 wxPatchListNode *pcinode = m_PatchList.Item(i);
2183 if ((piqp->ProjType != m_quilt_proj) &&
2184 (piqp->ProjType != PROJECTION_UNKNOWN))
2185 piqp->b_Valid =
false;
2190 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2191 wxPatchListNode *pcinode = m_PatchList.Item(i);
2193 for (
unsigned int ins = 0;
2194 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
2195 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
2198 piqp->b_Valid =
false;
2206 m_covered_region.Clear();
2211 bool b_skipCM93 =
false;
2212 if (m_reference_type == CHART_TYPE_CM93COMP) {
2214 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2215 wxPatchListNode *pcinode = m_PatchList.Item(i);
2222 if (m.GetChartType() == CHART_TYPE_CM93COMP) {
2224 piqp->ActiveRegion = piqp->quilt_region;
2225 piqp->ActiveRegion.Intersect(cvp_region);
2229 m_covered_region.Union(piqp->quilt_region);
2239 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2240 wxPatchListNode *pcinode = m_PatchList.Item(i);
2248 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2252 piqp->ActiveRegion = piqp->quilt_region;
2255 if (!b_has_overlays && m_PatchList.GetCount() < 25)
2256 piqp->ActiveRegion.Subtract(m_covered_region);
2258 piqp->ActiveRegion.Intersect(cvp_region);
2262 if (piqp->ActiveRegion.Empty() && (piqp->dbIndex != m_refchart_dbIndex))
2263 piqp->b_eclipsed =
true;
2266 piqp->b_overlay =
false;
2267 if (cte.GetChartFamily() == CHART_FAMILY_VECTOR) {
2268 piqp->b_overlay = s57chart::IsCellOverlayType(cte.GetFullSystemPath());
2271 if (!piqp->b_overlay) m_covered_region.Union(piqp->quilt_region);
2276 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2277 wxPatchListNode *pcinode = m_PatchList.Item(i);
2286 LLRegion vpr_region = piqp->quilt_region;
2294 for (
unsigned int k = i + 1; k < m_PatchList.GetCount(); k++) {
2295 wxPatchListNode *pnode = m_PatchList.Item(k);
2316 if (!b_has_overlays) {
2317 if (!vpr_region.Empty()) {
2319 ChartData->GetChartTableEntry(pqp->dbIndex);
2320 LLRegion larger_scale_chart_region =
2323 vpr_region.Subtract(larger_scale_chart_region);
2332 wxPatchListNode *pinode = m_PatchList.Item(i);
2334 pqpi->ActiveRegion = vpr_region;
2343 if (pqpi->ActiveRegion.Empty()) pqpi->b_eclipsed =
true;
2351 m_covered_region.Union(pqpi->ActiveRegion);
2358 unsigned int il = 0;
2359 while (il < m_PatchList.GetCount()) {
2360 wxPatchListNode *pcinode = m_PatchList.Item(il);
2362 if (piqp->b_eclipsed) {
2365 bool b_noadd =
false;
2366 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size(); ir++) {
2367 if (piqp->dbIndex == m_eclipsed_stack_array[ir]) {
2372 if (!b_noadd) m_eclipsed_stack_array.push_back(piqp->dbIndex);
2374 m_PatchList.DeleteNode(pcinode);
2393 m_parent->EnablePaint(
false);
2400 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2402 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2403 if (!
ChartData->IsChartLocked(pqc->dbIndex))
2404 ChartData->LockCacheChart(pqc->dbIndex);
2409 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2411 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2412 if (!
ChartData->IsChartLocked(pqc->dbIndex))
2413 ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
true);
2422 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2424 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2425 if (
ChartData->IsChartLocked(pqc->dbIndex))
2426 pqc->b_locked =
true;
2428 pqc->b_locked =
ChartData->LockCacheChart(pqc->dbIndex);
2433 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2435 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2441 if (
ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
2443 pqc->b_locked =
true;
2448 m_parent->EnablePaint(
true);
2451 m_last_index_array = m_index_array;
2453 m_index_array.clear();
2456 unsigned int kl = m_PatchList.GetCount();
2457 for (
unsigned int k = 0; k < kl; k++) {
2458 wxPatchListNode *cnode = m_PatchList.Item((kl - k) - 1);
2459 m_index_array.push_back(cnode->GetData()->dbIndex);
2460 cnode = cnode->GetNext();
2466 m_quilt_depth_unit =
"";
2469 m_quilt_depth_unit = pc->GetDepthUnits();
2471 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2472 int units = ps52plib->m_nDepthUnitDisplay;
2475 m_quilt_depth_unit =
"Feet";
2478 m_quilt_depth_unit =
"Meters";
2481 m_quilt_depth_unit =
"Fathoms";
2487 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2488 wxPatchListNode *pnode = m_PatchList.Item(k);
2496 wxString du = pc->GetDepthUnits();
2497 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2498 int units = ps52plib->m_nDepthUnitDisplay;
2511 wxString dul = du.Lower();
2512 wxString ml = m_quilt_depth_unit.Lower();
2516 if (dul.StartsWith(
"meters") && ml.StartsWith(
"meters"))
2518 else if (dul.StartsWith(
"metres") && ml.StartsWith(
"metres"))
2520 else if (dul.StartsWith(
"fathoms") && ml.StartsWith(
"fathoms"))
2522 else if (dul.StartsWith(
"met") && ml.StartsWith(
"met"))
2526 m_quilt_depth_unit =
"";
2536 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2537 wxPatchListNode *pnode = m_PatchList.Item(k);
2541 if (!
ChartData->IsChartInCache(pqp->dbIndex)) {
2542 wxLogMessage(
" Quilt Compose cache miss...");
2543 ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2544 if (!
ChartData->IsChartInCache(pqp->dbIndex)) {
2545 wxLogMessage(
" Oops, removing from quilt...");
2546 pqp->b_Valid =
false;
2553 if (!
ChartData->IsChartInCache(m_refchart_dbIndex))
2554 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
2560 m_bquilt_has_overlays =
false;
2561 m_max_error_factor = 0.;
2562 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2563 wxPatchListNode *pnode = m_PatchList.Item(k);
2571 m_max_error_factor =
2572 wxMax(m_max_error_factor, pc->GetChart_Error_Factor());
2573 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2574 bool isOverlay = IsChartS57Overlay(pqp->dbIndex);
2575 pqp->b_overlay = isOverlay;
2576 if (isOverlay) m_bquilt_has_overlays =
true;
2589 unsigned long xa_hash = 5381;
2590 for (
unsigned int im = 0; im < m_extended_stack_array.size(); im++) {
2591 int dbindex = m_extended_stack_array[im];
2592 xa_hash = ((xa_hash << 5) + xa_hash) + dbindex;
2595 m_xa_hash = xa_hash;
2604 if (!m_bcomposed)
return;
2608 if (GetnCharts() && !m_bbusy && !chart_region.Empty()) {
2614 if (!(chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2615 vp.b_MercatorProjectionOverride)) {
2619 chart_region, pqp->ActiveRegion, chart->GetNativeScale());
2620 if (!get_screen_region.Empty())
2621 rendered_region.Union(get_screen_region);
2624 chart = GetNextChart();
2628 m_rendered_region = rendered_region;
2633bool Quilt::RenderQuiltRegionViewOnDCNoText(wxMemoryDC &dc,
ViewPort &vp,
2635 return DoRenderQuiltRegionViewOnDC(dc, vp, chart_region);
2638bool Quilt::RenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
2640 return DoRenderQuiltRegionViewOnDCTextOnly(dc, vp, chart_region);
2643bool Quilt::DoRenderQuiltRegionViewOnDC(wxMemoryDC &dc,
ViewPort &vp,
2645#ifdef ocpnUSE_DIBSECTION
2651 if (!m_bcomposed)
return false;
2655 if (GetnCharts() && !m_bbusy) {
2663 int chartsDrawn = 0;
2665 if (!chart_region.Empty()) {
2667 bool okToRender =
true;
2669 if (chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2670 vp.b_MercatorProjectionOverride)
2674 chart = GetNextChart();
2679 bool b_chart_rendered =
false;
2680 LLRegion get_region = pqp->ActiveRegion;
2683 chart_region, get_region, chart->GetNativeScale());
2684 if (!get_screen_region.Empty()) {
2685 if (!pqp->b_overlay) {
2686 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
2688 chart->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2692 if (Chs57->m_RAZBuilt) {
2693 b_chart_rendered = Chs57->RenderRegionViewOnDCNoText(
2694 tmp_dc, vp, get_screen_region);
2700 b_chart_rendered = ChPI->RenderRegionViewOnDCNoText(
2701 tmp_dc, vp, get_screen_region);
2703 b_chart_rendered = chart->RenderRegionViewOnDC(
2704 tmp_dc, vp, get_screen_region);
2706 b_chart_rendered =
true;
2713 screen_region.Subtract(get_screen_region);
2718 while (upd.HaveRects()) {
2719 wxRect rect = upd.GetRect();
2720 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc, rect.x,
2721 rect.y, wxCOPY,
true);
2725 tmp_dc.SelectObject(wxNullBitmap);
2727 if (b_chart_rendered) rendered_region.Union(get_screen_region);
2731 chart = GetNextChart();
2735 if (!chartsDrawn) m_parent->GetVP().SetProjectionType(PROJECTION_MERCATOR);
2738 if (m_bquilt_has_overlays && !chart_region.Empty()) {
2739 chart = GetFirstChart();
2743 if (pqp->b_overlay) {
2744 LLRegion get_region = pqp->ActiveRegion;
2746 chart_region, get_region, chart->GetNativeScale());
2747 if (!get_region.Empty()) {
2750 Chs57->RenderOverlayRegionViewOnDC(tmp_dc, vp,
2756 ChPI->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2761 while (upd.HaveRects()) {
2762 wxRect rect = upd.GetRect();
2763 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc,
2764 rect.x, rect.y, wxCOPY,
true);
2767 tmp_dc.SelectObject(wxNullBitmap);
2772 chart = GetNextChart();
2779 while (clrit.HaveRects()) {
2780 wxRect rect = clrit.GetRect();
2782 dc.SetPen(*wxBLACK_PEN);
2783 dc.SetBrush(*wxBLACK_BRUSH);
2784 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
2786 dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y,
2793 if (m_nHiLiteIndex >= 0) {
2796 wxRect box = hiregion.GetBox();
2798 if (!box.IsEmpty()) {
2801 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2802 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2809 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2813 q_dc.SelectObject(*m_pBM);
2814 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2815 q_dc.SelectObject(wxNullBitmap);
2820 wxBitmap hl_mask_bm(vp.rv_rect.width, vp.rv_rect.height, 1);
2822 mdc.SelectObject(hl_mask_bm);
2823 mdc.SetBackground(*wxBLACK_BRUSH);
2825 mdc.SetClippingRegion(box);
2826 mdc.SetBackground(*wxWHITE_BRUSH);
2828 mdc.SelectObject(wxNullBitmap);
2830 if (hl_mask_bm.IsOk()) {
2831 wxMask *phl_mask =
new wxMask(hl_mask_bm);
2832 m_pBM->SetMask(phl_mask);
2833 q_dc.SelectObject(*m_pBM);
2836 wxBitmap rbm(vp.rv_rect.width, vp.rv_rect.height);
2837 wxMask *pr_mask =
new wxMask(hl_mask_bm);
2839 rbm.SetMask(pr_mask);
2840 rdc.SelectObject(rbm);
2841 unsigned char hlcolor = 255;
2842 switch (global_color_scheme) {
2843 case GLOBAL_COLOR_SCHEME_DAY:
2846 case GLOBAL_COLOR_SCHEME_DUSK:
2849 case GLOBAL_COLOR_SCHEME_NIGHT:
2857 rdc.SetBackground(wxBrush(wxColour(hlcolor, 0, 0)));
2861 while (upd.HaveRects()) {
2862 wxRect rect = upd.GetRect();
2863 rdc.Blit(rect.x, rect.y, rect.width, rect.height, &q_dc, rect.x,
2864 rect.y, wxOR,
true);
2869 while (updq.HaveRects()) {
2870 wxRect rect = updq.GetRect();
2871 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &rdc, rect.x,
2872 rect.y, wxCOPY,
true);
2876 q_dc.SelectObject(wxNullBitmap);
2877 m_pBM->SetMask(NULL);
2880 dc.SelectObject(*m_pBM);
2883 rdc.SelectObject(wxNullBitmap);
2889 if (g_fog_overzoom) {
2892 if (scale_factor > g_overzoom_emphasis_base) {
2893 float fog = ((scale_factor - g_overzoom_emphasis_base) * 255.) / 20.;
2894 fog = wxMin(fog, 200.);
2898 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2899 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2906 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2910 q_dc.SelectObject(*m_pBM);
2911 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2912 q_dc.SelectObject(wxNullBitmap);
2914 wxImage src = m_pBM->ConvertToImage();
2917 wxMin((scale_factor - g_overzoom_emphasis_base) / 4, 4);
2919 wxImage dest = src.Blur(blur_factor);
2923 unsigned char *bg = src.GetData();
2924 wxColour color = m_parent->GetFogColor();
2926 float transparency = fog;
2929 wxImage dest(vp.rv_rect.width, vp.rv_rect.height);
2930 unsigned char *dest_data = (
unsigned char *) malloc( vp.rv_rect.width * vp.rv_rect.height * 3 *
sizeof(
unsigned char) );
2931 unsigned char *d = dest_data;
2933 float alpha = 1.0 - (float)transparency / 255.0;
2934 int sb = vp.rv_rect.width * vp.rv_rect.height;
2935 for(
int i = 0; i < sb; i++ ) {
2938 int r = ( ( *bg++ ) * a ) + (1.0-a) * color.Red();
2940 int g = ( ( *bg++ ) * a ) + (1.0-a) * color.Green();
2942 int b = ( ( *bg++ ) * a ) + (1.0-a) * color.Blue();
2946 dest.SetData( dest_data );
2951 ddc.SelectObject(dim);
2953 q_dc.SelectObject(*m_pBM);
2955 while (upd.HaveRects()) {
2956 wxRect rect = upd.GetRect();
2957 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &ddc, rect.x,
2962 ddc.SelectObject(wxNullBitmap);
2963 q_dc.SelectObject(wxNullBitmap);
2966 dc.SelectObject(*m_pBM);
2974 SubstituteClearDC(dc, vp);
2978 SubstituteClearDC(dc, vp);
2982 m_rendered_region = rendered_region;
2988void Quilt::SubstituteClearDC(wxMemoryDC &dc,
ViewPort &vp) {
2990 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2991 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2997 if (NULL == m_pBM) {
2998 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
3001 dc.SelectObject(wxNullBitmap);
3002 dc.SelectObject(*m_pBM);
3003 dc.SetBackground(*wxBLACK_BRUSH);
3005 m_covered_region.Clear();
3008bool Quilt::DoRenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
3010 if (!m_bcomposed)
return false;
3014 if (GetnCharts() && !m_bbusy) {
3019 ChartBase *chart = GetLargestScaleChart();
3026 Chs57->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3030 ChPI->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3035 chart = GetNextSmallerScaleChart();
3039 SubstituteClearDC(dc, vp);
ChartDB * ChartData
Global instance.
Charts database management
Generic Chart canvas base.
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.
Miscellaneous utilities, many of which string related.
Represents an entry in the chart table, containing information about a single chart.