25 #include <wx/wxprec.h>
32 #include "ocpn_pixel.h"
34 #ifdef __OCPN__ANDROID__
35 #include "androidUTIL.h"
41 #include <wx/listimpl.cpp>
42 WX_DEFINE_LIST(PatchList);
45 extern s52plib *ps52plib;
46 extern ColorScheme global_color_scheme;
47 extern int g_chart_zoom_modifier_raster;
48 extern int g_chart_zoom_modifier_vector;
49 extern bool g_fog_overzoom;
50 extern double g_overzoom_emphasis_base;
51 extern bool g_bopengl;
61 #ifndef __OCPN__ANDROID__
62 #define GetChartTableEntry(i) GetChartTable()[i]
71 #define NOCOVR_PLY_PERF_LIMIT 500
72 #define AUX_PLY_PERF_LIMIT 500
74 static 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();
97 static bool CompareScalesStd(
int i1,
int i2) {
98 return CompareScales(i1, i2) < 0;
103 if (!ChartData)
return 0;
104 return CompareScales(qc1->dbIndex, qc2->dbIndex);
107 const 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);
181 if (!t_region.Empty()) {
182 LLRegion test_region = candidate_region;
183 test_region.Subtract(t_region);
185 if (!test_region.Empty()) candidate_region = test_region;
195 if ((cte.GetScale() > 90000000) &&
196 (cte.GetChartFamily() == CHART_FAMILY_RASTER))
197 candidate_region = world_region;
199 return candidate_region;
202 LLRegion &QuiltCandidate::GetReducedCandidateRegion(
double factor) {
203 if (factor != last_factor) {
204 reduced_candidate_region = GetCandidateRegion();
205 reduced_candidate_region.Reduce(factor);
206 last_factor = factor;
209 return reduced_candidate_region;
212 void QuiltCandidate::SetScale(
int scale) {
216 if (
scale >= 1000) rounding = 5 * pow(10, log10(
scale) - 2);
225 m_reference_scale = 1;
226 m_refchart_dbIndex = -1;
227 m_reference_type = CHART_TYPE_UNKNOWN;
228 m_reference_family = CHART_FAMILY_UNKNOWN;
229 m_quilt_proj = PROJECTION_UNKNOWN;
231 m_lost_refchart_dbIndex = -1;
241 new ArrayOfSortedQuiltCandidates(CompareQuiltCandidateScales);
246 m_preferred_family = CHART_FAMILY_RASTER;
249 m_bquiltskew = g_bopengl;
251 m_bquiltanyproj = g_bopengl;
255 m_PatchList.DeleteContents(
true);
258 EmptyCandidateArray();
259 delete m_pcandidate_array;
261 m_extended_stack_array.clear();
266 bool Quilt::IsVPBlittable(
ViewPort &VPoint,
int dx,
int dy,
267 bool b_allow_vector) {
268 if (!m_vp_rendered.IsValid())
return false;
271 VPoint.GetDoublePixFromLL(m_vp_rendered.clat, m_vp_rendered.clon);
272 wxPoint2DDouble p2 = VPoint.GetDoublePixFromLL(VPoint.clat, VPoint.clon);
273 double deltax = p2.m_x - p1.m_x;
274 double deltay = p2.m_y - p1.m_y;
276 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
return false;
281 bool Quilt::IsChartS57Overlay(
int db_index) {
282 if (db_index < 0)
return false;
285 if (CHART_FAMILY_VECTOR == cte.GetChartFamily()) {
286 return s57chart::IsCellOverlayType(cte.GetFullSystemPath());
291 bool Quilt::IsChartQuiltableRef(
int db_index) {
292 if (db_index < 0 || db_index > ChartData->GetChartTableEntries() - 1)
298 bool bproj_match =
true;
300 double skew_norm = ctei.GetChartSkew();
301 if (skew_norm > 180.) skew_norm -= 360.;
304 fabs(skew_norm) < 1.;
305 if (m_bquiltskew) skew_match =
true;
308 bool b_noshow =
false;
309 for (
unsigned int i = 0; i < m_parent->GetQuiltNoshowIindexArray().size();
311 if (m_parent->GetQuiltNoshowIindexArray()[i] ==
319 return (bproj_match & skew_match & !b_noshow);
322 bool Quilt::IsChartInQuilt(
ChartBase *pc) {
324 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
326 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
327 if (ChartData->OpenChartFromDB(pqc->dbIndex, FULL_INIT) == pc)
334 bool Quilt::IsChartInQuilt(wxString &full_path) {
336 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
338 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
340 if (pcte->GetpsFullPath()->IsSameAs(full_path))
return true;
346 std::vector<int> Quilt::GetCandidatedbIndexArray(
bool from_ref_chart,
347 bool exclude_user_hidden) {
348 std::vector<int> ret;
349 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
353 if (pqc->Scale_ge(m_reference_scale)) {
355 if (exclude_user_hidden) {
356 bool b_noshow =
false;
357 for (
unsigned int i = 0;
358 i < m_parent->GetQuiltNoshowIindexArray().size(); i++) {
359 if (m_parent->GetQuiltNoshowIindexArray()[i] ==
366 if (!b_noshow) ret.push_back(pqc->dbIndex);
368 ret.push_back(pqc->dbIndex);
372 ret.push_back(pqc->dbIndex);
379 return (cnode->GetData());
384 void Quilt::EmptyCandidateArray(
void) {
385 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
386 delete m_pcandidate_array->Item(i);
389 m_pcandidate_array->Clear();
393 if (!ChartData)
return NULL;
395 if (!ChartData->IsValid())
399 if (!m_bcomposed)
return NULL;
401 if (m_bbusy)
return NULL;
405 cnode = m_PatchList.GetFirst();
406 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetNext();
407 if (cnode && cnode->GetData()->b_Valid)
408 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
415 if (!ChartData)
return NULL;
417 if (!ChartData->IsValid())
return NULL;
419 if (m_bbusy)
return NULL;
424 cnode = cnode->GetNext();
425 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetNext();
426 if (cnode && cnode->GetData()->b_Valid)
427 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
434 ChartBase *Quilt::GetNextSmallerScaleChart() {
435 if (!ChartData)
return NULL;
437 if (!ChartData->IsValid())
return NULL;
439 if (m_bbusy)
return NULL;
444 cnode = cnode->GetPrevious();
445 while (cnode && !cnode->GetData()->b_Valid) cnode = cnode->GetPrevious();
446 if (cnode && cnode->GetData()->b_Valid)
447 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
454 ChartBase *Quilt::GetLargestScaleChart() {
455 if (!ChartData)
return NULL;
457 if (m_bbusy)
return NULL;
461 cnode = m_PatchList.GetLast();
463 pret = ChartData->OpenChartFromDB(cnode->GetData()->dbIndex, FULL_INIT);
470 LLRegion chart_region;
471 LLRegion screen_region(vp.GetBBox());
476 if (fabs(cte.GetLonMax() - cte.GetLonMin()) > 180.) {
493 return LLRegion(-80, vp.GetBBox().GetMinLon(), 80,
494 vp.GetBBox().GetMaxLon());
498 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
499 bool aux_ply_skipped =
false;
500 if (nAuxPlyEntries >= 1) {
501 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
502 int nAuxPly = cte.GetAuxCntTableEntry(ip);
503 if (nAuxPly > AUX_PLY_PERF_LIMIT) {
506 aux_ply_skipped =
true;
509 float *pfp = cte.GetpAuxPlyTableEntry(ip);
510 LLRegion t_region(nAuxPly, pfp);
511 t_region.Intersect(screen_region);
515 if (!t_region.Empty()) chart_region.Union(t_region);
519 if (aux_ply_skipped || nAuxPlyEntries == 0) {
520 int n_ply_entries = cte.GetnPlyEntries();
521 float *pfp = cte.GetpPlyTable();
523 if (n_ply_entries >= 3)
526 LLRegion t_region(n_ply_entries, pfp);
527 t_region.Intersect(screen_region);
531 if (!t_region.Empty()) chart_region.Union(t_region);
534 chart_region = screen_region;
538 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
539 if (nNoCovrPlyEntries) {
540 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
541 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
542 if (nNoCovrPly > NOCOVR_PLY_PERF_LIMIT) {
547 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
549 LLRegion t_region(nNoCovrPly, pfp);
550 t_region.Intersect(screen_region);
561 if (!t_region.Empty()) {
562 LLRegion test_region = chart_region;
563 test_region.Subtract(t_region);
565 if (!test_region.Empty()) chart_region = test_region;
574 if ((cte.GetScale() > 90000000) &&
575 (cte.GetChartFamily() == CHART_FAMILY_RASTER))
576 chart_region = screen_region;
584 bool Quilt::IsQuiltVector(
void) {
585 if (m_bbusy)
return false;
591 wxPatchListNode *cnode = m_PatchList.GetFirst();
593 if (cnode->GetData()) {
596 if ((pqp->b_Valid) && (!pqp->b_eclipsed) &&
597 (pqp->dbIndex < ChartData->GetChartTableEntries())) {
599 ChartData->GetChartTableEntry(pqp->dbIndex);
601 if (ctei.GetChartFamily() == CHART_FAMILY_VECTOR) {
607 cnode = cnode->GetNext();
614 bool Quilt::DoesQuiltContainPlugins(
void) {
615 if (m_bbusy)
return false;
621 wxPatchListNode *cnode = m_PatchList.GetFirst();
623 if (cnode->GetData()) {
626 if ((pqp->b_Valid) && (!pqp->b_eclipsed)) {
628 ChartData->GetChartTableEntry(pqp->dbIndex);
630 if (ctei.GetChartType() == CHART_TYPE_PLUGIN) {
636 cnode = cnode->GetNext();
643 int Quilt::GetChartdbIndexAtPix(
ViewPort &VPoint, wxPoint p) {
644 if (m_bbusy)
return -1;
649 VPoint.GetLLFromPix(p, &lat, &lon);
653 wxPatchListNode *cnode = m_PatchList.GetFirst();
655 if (cnode->GetData()->ActiveRegion.Contains(lat, lon)) {
656 ret = cnode->GetData()->dbIndex;
659 cnode = cnode->GetNext();
667 if (m_bbusy)
return NULL;
672 VPoint.GetLLFromPix(p, &lat, &lon);
679 wxPatchListNode *cnode = m_PatchList.GetFirst();
682 if (!pqp->b_overlay && (pqp->ActiveRegion.Contains(lat, lon)))
683 if (ChartData->IsChartInCache(pqp->dbIndex)) {
684 pret = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
686 cnode = cnode->GetNext();
694 if (m_bbusy)
return NULL;
699 VPoint.GetLLFromPix(p, &lat, &lon);
706 wxPatchListNode *cnode = m_PatchList.GetFirst();
709 if (pqp->b_overlay && (pqp->ActiveRegion.Contains(lat, lon)))
710 pret = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
711 cnode = cnode->GetNext();
718 void Quilt::InvalidateAllQuiltPatchs(
void) {
729 std::vector<int> Quilt::GetQuiltIndexArray(
void) {
730 return m_index_array;
732 std::vector<int> ret;
734 if (m_bbusy)
return ret;
738 wxPatchListNode *cnode = m_PatchList.GetFirst();
740 ret.push_back(cnode->GetData()->dbIndex);
741 cnode = cnode->GetNext();
749 bool Quilt::IsQuiltDelta(
ViewPort &vp) {
750 if (!m_vp_quilt.IsValid() || !m_bcomposed)
return true;
752 if (m_vp_quilt.view_scale_ppm != vp.view_scale_ppm)
return true;
754 if (m_vp_quilt.m_projection_type != vp.m_projection_type)
return true;
756 if (m_vp_quilt.rotation != vp.rotation)
return true;
759 wxPoint cp_last, cp_this;
761 cp_last = m_vp_quilt.GetPixFromLL(vp.clat, vp.clon);
762 cp_this = vp.GetPixFromLL(vp.clat, vp.clon);
764 return (cp_last != cp_this);
772 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
774 if (pRefChart) pRefChart->AdjustVP(vp_last, vp_proposed);
777 double Quilt::GetRefNativeScale() {
778 double ret_val = 1.0;
780 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
781 if (pc) ret_val = pc->GetNativeScale();
787 int Quilt::GetNewRefChart(
void) {
793 int new_ref_dbIndex = m_refchart_dbIndex;
794 unsigned int im = m_extended_stack_array.size();
796 for (
unsigned int is = 0; is < im; is++) {
798 ChartData->GetChartTableEntry(m_extended_stack_array[is]);
800 double skew_norm = m.GetChartSkew();
801 if (skew_norm > 180.) skew_norm -= 360.;
803 if ((m.Scale_ge(m_reference_scale)) &&
804 (m_reference_family == m.GetChartFamily()) &&
805 (m_bquiltanyproj || m_quilt_proj == m.GetChartProjectionType()) &&
806 (m_bquiltskew || (fabs(skew_norm) < 1.0))) {
807 new_ref_dbIndex = m_extended_stack_array[is];
812 return new_ref_dbIndex;
815 int Quilt::GetNomScaleMax(
int scale, ChartTypeEnum type,
816 ChartFamilyEnum family) {
818 case CHART_FAMILY_RASTER: {
822 case CHART_FAMILY_VECTOR: {
832 int Quilt::GetNomScaleMin(
int scale, ChartTypeEnum type,
833 ChartFamilyEnum family) {
834 double zoom_mod = (double)g_chart_zoom_modifier_raster;
836 if (family == CHART_FAMILY_VECTOR)
837 zoom_mod = (double)g_chart_zoom_modifier_vector;
839 double modf = zoom_mod / 5.;
840 double mod = pow(16., modf);
841 mod = wxMax(mod, .2);
842 mod = wxMin(mod, 16.0);
846 case CHART_FAMILY_RASTER: {
847 if (CHART_TYPE_MBTILES == type)
853 return scale * 1 * mod;
856 case CHART_FAMILY_VECTOR: {
857 return scale * 4 * mod;
861 mod = wxMin(mod, 2.0);
862 return scale * 2 * mod;
868 int index, nom, min, max;
871 int Quilt::AdjustRefOnZoom(
bool b_zin, ChartFamilyEnum family,
872 ChartTypeEnum type,
double proposed_scale_onscreen) {
873 std::vector<scale> scales;
874 std::vector<scale> scales_mbtiles;
883 bool b_allow_fullscreen_ref =
884 (family == CHART_FAMILY_VECTOR) || b_zin || g_bopengl;
888 int smallest_scale = 1;
889 for (
size_t i = 0; i < m_extended_stack_array.size(); i++) {
890 int index = m_extended_stack_array[i];
891 if (ChartData->GetDBChartType(index) == type)
892 smallest_scale = wxMax(smallest_scale, ChartData->GetDBChartScale(index));
897 for (
size_t i = 0; i < m_extended_stack_array.size(); i++) {
898 int test_db_index = m_extended_stack_array[i];
900 if (b_allow_fullscreen_ref ||
901 m_parent->GetpCurrentStack()->DoesStackContaindbIndex(test_db_index)) {
902 if ((family == ChartData->GetDBChartFamily(test_db_index)) &&
903 IsChartQuiltableRef(test_db_index)
905 int nscale = ChartData->GetDBChartScale(test_db_index);
907 int nmax_scale = GetNomScaleMax(nscale, type, family);
911 if (0 == i_first) nmax_scale = 1;
913 int nmin_scale = GetNomScaleMin(nscale, type, family);
916 if ((type == CHART_TYPE_KAP) && (nscale == smallest_scale))
921 if ((type == CHART_TYPE_MBTILES) && (nscale == smallest_scale))
924 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(test_db_index))
925 scales_mbtiles.push_back(
926 scale{test_db_index, nscale, nmin_scale, nmax_scale});
929 scale{test_db_index, nscale, nmin_scale, nmax_scale});
936 if (scales.empty()) scales = scales_mbtiles;
943 if (CHART_FAMILY_VECTOR == family) {
944 for (
size_t i = scales.size(); i; i--) {
945 int test_db_index = scales[i - 1].index;
946 if (type == ChartData->GetDBChartType(test_db_index)) {
947 scales[i - 1].min = scales[i - 1].nom * 80;
959 if (scales.size() > 1) {
960 for (
unsigned i = 0; i < scales.size() - 1; i++) {
961 int min_scale_test = wxMax(scales[i].min, scales[i + 1].max + 1);
962 min_scale_test = wxMin(min_scale_test, scales[i].min * 2);
963 scales[i].min = min_scale_test;
972 if (scales.size() > 2) {
973 for (
size_t i = scales.size() - 2; i >= 1; i--) {
974 scales[i].max = wxMin(scales[i].max, scales[i - 1].min - 1);
978 int new_ref_dbIndex = -1;
982 for (
size_t i = 0; i < scales.size(); i++) {
983 if ((proposed_scale_onscreen <
986 (proposed_scale_onscreen > scales[i].max)) {
987 new_ref_dbIndex = scales[i].index;
992 return new_ref_dbIndex;
995 int Quilt::AdjustRefOnZoomOut(
double proposed_scale_onscreen) {
997 m_lost_refchart_dbIndex = -1;
999 int current_db_index = m_refchart_dbIndex;
1000 int current_family = m_reference_family;
1001 ChartTypeEnum current_type = (ChartTypeEnum)m_reference_type;
1003 if (m_refchart_dbIndex >= 0) {
1005 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1006 current_family = cte.GetChartFamily();
1007 current_type = (ChartTypeEnum)cte.GetChartType();
1010 if (current_type == CHART_TYPE_CM93COMP)
return current_db_index;
1012 int proposed_ref_index =
1013 AdjustRefOnZoom(
false, (ChartFamilyEnum)current_family, current_type,
1014 proposed_scale_onscreen);
1017 if (proposed_ref_index < 0) {
1018 m_zout_family = current_family;
1019 m_zout_type = current_type;
1020 m_zout_dbindex = current_db_index;
1023 SetReferenceChart(proposed_ref_index);
1025 return proposed_ref_index;
1028 int Quilt::AdjustRefOnZoomIn(
double proposed_scale_onscreen) {
1030 m_lost_refchart_dbIndex = -1;
1032 int current_db_index = m_refchart_dbIndex;
1033 int current_family = m_reference_family;
1034 ChartTypeEnum current_type = (ChartTypeEnum)m_reference_type;
1036 if (m_zout_family >= 0) {
1037 current_type = (ChartTypeEnum)m_zout_type;
1038 current_family = m_zout_family;
1044 if (current_type == CHART_TYPE_CM93COMP) {
1045 if (m_zout_family >= 0) {
1046 current_family = ChartData->GetDBChartFamily(m_zout_dbindex);
1048 return current_db_index;
1051 if ((-1 == m_refchart_dbIndex) && (m_zout_dbindex >= 0))
1052 BuildExtendedChartStackAndCandidateArray(m_zout_dbindex, m_vp_quilt);
1054 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, m_vp_quilt);
1056 int proposed_ref_index =
1057 AdjustRefOnZoom(
true, (ChartFamilyEnum)current_family, current_type,
1058 proposed_scale_onscreen);
1060 if (current_db_index == -1) {
1061 SetReferenceChart(proposed_ref_index);
1062 return proposed_ref_index;
1065 if (proposed_ref_index != -1) {
1066 if (ChartData->GetDBChartScale(current_db_index) >=
1067 ChartData->GetDBChartScale(proposed_ref_index)) {
1068 SetReferenceChart(proposed_ref_index);
1069 return proposed_ref_index;
1072 proposed_ref_index = current_db_index;
1074 SetReferenceChart(proposed_ref_index);
1076 return proposed_ref_index;
1079 bool Quilt::IsChartSmallestScale(
int dbIndex) {
1080 if (!ChartData)
return false;
1084 int specified_type = ChartData->GetDBChartType(dbIndex);
1085 int target_dbindex = -1;
1087 unsigned int target_stack_index = 0;
1088 if (m_extended_stack_array.size()) {
1089 while ((target_stack_index <= (m_extended_stack_array.size() - 1))) {
1090 int test_db_index = m_extended_stack_array[target_stack_index];
1092 if (specified_type == ChartData->GetDBChartType(test_db_index))
1093 target_dbindex = test_db_index;
1095 target_stack_index++;
1098 return (dbIndex == target_dbindex);
1101 LLRegion Quilt::GetHiliteRegion() {
1106 for (
auto &index : m_HiLiteIndexArray) {
1108 LLRegion cell_region = GetChartQuiltRegion(cte, m_vp_quilt);
1109 r.Union(cell_region);
1113 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1114 wxPatchListNode *pcinode = m_PatchList.Item(i);
1116 if ((index == piqp->dbIndex) && (piqp->b_Valid))
1118 r.Union(piqp->ActiveRegion);
1127 LLRegion Quilt::GetHiliteRegion() {
1129 if (m_nHiLiteIndex >= 0) {
1131 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1132 wxPatchListNode *pcinode = m_PatchList.Item(i);
1134 if ((m_nHiLiteIndex == piqp->dbIndex) && (piqp->b_Valid))
1136 r = piqp->ActiveRegion;
1143 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1145 if (m_nHiLiteIndex == pqc->dbIndex) {
1146 LLRegion chart_region = pqc->GetCandidateRegion();
1147 if (!chart_region.Empty()) {
1149 bool b_eclipsed =
false;
1150 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size();
1152 if (m_nHiLiteIndex == m_eclipsed_stack_array[ir]) {
1158 if (!b_eclipsed) r = chart_region;
1168 ChartData->GetChartTableEntry(m_nHiLiteIndex);
1169 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
1170 r = GetTilesetRegion(m_nHiLiteIndex);
1178 const LLRegion &Quilt::GetTilesetRegion(
int dbIndex) {
1179 LLRegion world_region(-90, -180, 90, 180);
1182 LLRegion &target_region =
const_cast<LLRegion &
>(cte.quilt_candidate_region);
1184 if (!target_region.Empty())
return target_region;
1187 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
1188 if (nAuxPlyEntries >= 1) {
1189 target_region.Clear();
1190 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
1191 float *pfp = cte.GetpAuxPlyTableEntry(ip);
1192 int nAuxPly = cte.GetAuxCntTableEntry(ip);
1194 target_region.Union(LLRegion(nAuxPly, pfp));
1197 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
1199 std::vector<float> vecr;
1200 for (
size_t i = 0; i < vec.size() / 2; i++) {
1201 float a = vec[i * 2 + 1];
1207 std::vector<float>::iterator it = vecr.begin();
1209 if (vecr.size() / 2 >= 3) {
1212 target_region = LLRegion(vecr.size() / 2, (
float *)&(*it));
1214 target_region = world_region;
1218 if (!target_region.Empty()) {
1219 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
1220 if (nNoCovrPlyEntries) {
1221 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
1222 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
1223 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
1225 LLRegion t_region = LLRegion(nNoCovrPly, pfp);
1232 if (!t_region.Empty()) {
1233 LLRegion test_region = target_region;
1234 test_region.Subtract(t_region);
1236 if (!test_region.Empty()) target_region = test_region;
1250 return target_region;
1253 bool Quilt::BuildExtendedChartStackAndCandidateArray(
int ref_db_index,
1255 double zoom_test_val = .002;
1258 EmptyCandidateArray();
1259 m_extended_stack_array.clear();
1260 m_fullscreen_index_array.clear();
1262 int reference_scale = 1e8;
1263 int reference_type = -1;
1264 int reference_family = -1;
1266 m_bquiltanyproj ? vp_in.m_projection_type : PROJECTION_UNKNOWN;
1268 if (ref_db_index >= 0) {
1270 ChartData->GetChartTableEntry(ref_db_index);
1271 reference_scale = cte_ref.GetScale();
1272 reference_type = cte_ref.GetChartType();
1273 if (!m_bquiltanyproj) quilt_proj = ChartData->GetDBChartProj(ref_db_index);
1274 reference_family = cte_ref.GetChartFamily();
1277 bool b_need_resort =
false;
1287 int n_charts = m_parent->GetpCurrentStack()->nEntry;
1291 for (
int ics = 0; ics < n_charts; ics++) {
1292 int istack = m_parent->GetpCurrentStack()->GetDBIndex(ics);
1293 if (istack < 0)
continue;
1294 m_extended_stack_array.push_back(istack);
1300 if (reference_type == CHART_TYPE_CM93COMP)
continue;
1310 if ((cte.GetChartType() == CHART_TYPE_PLUGIN) ||
1311 (reference_type == CHART_TYPE_PLUGIN)) {
1312 if (reference_family != cte.GetChartFamily()) {
1316 if (reference_type != cte.GetChartType()) {
1321 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1324 int candidate_chart_scale = cte.GetScale();
1325 double chart_native_ppm =
1326 m_canvas_scale_factor / (double)candidate_chart_scale;
1327 double zoom_factor = vp_local.view_scale_ppm / chart_native_ppm;
1328 if ((zoom_factor < zoom_test_val) &&
1333 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
1334 m_extended_stack_array.pop_back();
1338 double skew_norm = cte.GetChartSkew();
1339 if (skew_norm > 180.) skew_norm -= 360.;
1341 if ((m_bquiltskew ? 1 : fabs(skew_norm) < 1.0) &&
1342 (m_bquiltanyproj || cte.GetChartProjectionType() == quilt_proj)) {
1344 qcnew->dbIndex = istack;
1345 qcnew->SetScale(cte.GetScale());
1346 m_pcandidate_array->push_back(qcnew);
1373 int n_all_charts = ChartData->GetChartTableEntries();
1375 LLBBox viewbox = vp_local.GetBBox();
1376 int sure_index = -1;
1377 int sure_index_scale = 0;
1378 int sure_index_type = -1;
1380 for (
int i = 0; i < n_all_charts; i++) {
1384 int groupIndex = m_parent->m_groupIndex;
1385 if ((groupIndex > 0) && (!ChartData->IsChartInGroup(i, groupIndex)))
1390 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
1391 m_fullscreen_index_array.push_back(i);
1395 #ifdef __OCPN__ANDROID__
1396 wxFileName fn(cte.GetFullSystemPath());
1397 if (!androidIsDirWritable(fn.GetPath()))
continue;
1399 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1401 const LLBBox &chart_box = cte.GetBBox();
1402 if ((viewbox.IntersectOut(chart_box)))
continue;
1404 m_fullscreen_index_array.push_back(i);
1406 if (reference_family != cte.GetChartFamily()) {
1407 if (cte.GetChartType() != CHART_TYPE_MBTILES)
continue;
1410 if (!m_bquiltanyproj && quilt_proj != cte.GetChartProjectionType())
1413 double skew_norm = cte.GetChartSkew();
1414 if (skew_norm > 180.) skew_norm -= 360.;
1416 if (!m_bquiltskew && fabs(skew_norm) > 1.0)
continue;
1421 if( CHART_TYPE_S57 == cte.GetChartType() ) {
1423 double chart_area = (cte.GetLonMax() - cte.GetLonMin()) *
1424 (cte.GetLatMax() - cte.GetLatMin());
1425 double quilt_area = viewbox.GetLonRange() * viewbox.GetLatRange();
1426 if ((chart_area / quilt_area) < .01)
continue;
1429 int candidate_chart_scale = cte.GetScale();
1435 if (!cte.Scale_ge(reference_scale)) {
1436 if (cte.Scale_gt(sure_index_scale)) {
1438 sure_index_scale = candidate_chart_scale;
1439 sure_index_type = cte.GetChartType();
1448 double chart_native_ppm =
1449 m_canvas_scale_factor / (double)candidate_chart_scale;
1450 double zoom_factor = vp_in.view_scale_ppm / chart_native_ppm;
1451 double zoom_factor_test_extra = 0.2;
1457 double ref_scale_test = reference_scale;
1458 if (cte.GetChartType() == CHART_TYPE_MBTILES)
1459 ref_scale_test = candidate_chart_scale;
1461 if ((cte.Scale_ge(ref_scale_test) && (zoom_factor > zoom_test_val)) ||
1462 (zoom_factor > zoom_factor_test_extra)) {
1463 LLRegion cell_region = GetChartQuiltRegion(cte, vp_local);
1468 if (!cell_region.Empty()) {
1471 bool b_exists =
false;
1472 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1473 if (i == m_extended_stack_array[ir]) {
1487 bool b_noadd =
false;
1489 for (
unsigned int id = 0;
id < m_extended_stack_array.size();
id++) {
1490 if (m_extended_stack_array[
id] != -1) {
1492 ChartData->GetpChartTableEntry(m_extended_stack_array[
id]);
1493 bool bsameTime =
false;
1494 if (pm->GetFileTime() && pn->GetFileTime()) {
1495 if (labs(pm->GetFileTime() - pn->GetFileTime()) < 60)
1498 if (pm->GetChartEditionDate() == pn->GetChartEditionDate())
1502 if (pn->GetpFileName()->IsSameAs(*(pm->GetpFileName())))
1509 m_extended_stack_array.push_back(i);
1514 candidate_chart_scale);
1516 m_pcandidate_array->push_back(qcnew);
1518 b_need_resort =
true;
1527 if (-1 != sure_index) {
1529 bool sure_exists =
false;
1530 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1531 if (sure_index == m_extended_stack_array[ir]) {
1538 if (!sure_exists && (sure_index_type != CHART_TYPE_MBTILES)) {
1539 m_extended_stack_array.push_back(sure_index);
1542 qcnew->dbIndex = sure_index;
1543 qcnew->SetScale(ChartData->GetDBChartScale(sure_index));
1544 m_pcandidate_array->push_back(qcnew);
1546 b_need_resort =
true;
1551 if (b_need_resort && m_extended_stack_array.size() > 1) {
1552 std::sort(m_extended_stack_array.begin(), m_extended_stack_array.end(),
1558 int Quilt::AdjustRefSelection(
const ViewPort &vp_in) {
1563 if (!ChartData)
return false;
1573 vp_local.SetRotationAngle(0.);
1575 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1577 ChartFamilyEnum family = CHART_FAMILY_RASTER;
1578 ChartTypeEnum type = CHART_TYPE_KAP;
1581 if (m_refchart_dbIndex >= 0) {
1583 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1584 type = (ChartTypeEnum)cte_ref.GetChartType();
1585 family = (ChartFamilyEnum)cte_ref.GetChartFamily();
1588 int ret_index = AdjustRefOnZoom(
true, family, type, vp_in.chart_scale);
1593 double Quilt::GetBestStartScale(
int dbi_ref_hint,
const ViewPort &vp_in) {
1594 if (!ChartData)
return vp_in.view_scale_ppm;
1598 return vp_in.view_scale_ppm;
1603 int tentative_ref_index = dbi_ref_hint;
1604 if (dbi_ref_hint < 0) {
1611 tentative_ref_index = m_parent->GetpCurrentStack()->GetDBIndex(0);
1618 vp_local.SetRotationAngle(0.);
1620 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1624 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1626 if (qc->dbIndex == tentative_ref_index) {
1632 if (!bf && m_pcandidate_array->GetCount()) {
1633 tentative_ref_index = GetNewRefChart();
1634 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1637 double proposed_scale_onscreen = vp_in.chart_scale;
1639 if (m_pcandidate_array->GetCount()) {
1640 m_refchart_dbIndex = tentative_ref_index;
1644 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1646 if (IsChartQuiltableRef(qc->dbIndex)) {
1647 m_refchart_dbIndex = qc->dbIndex;
1654 m_refchart_dbIndex = m_parent->GetpCurrentStack()->GetDBIndex(0);
1657 if (m_refchart_dbIndex >= 0) {
1660 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
1662 double min_ref_scale =
1663 pc->GetNormalScaleMin(m_parent->GetCanvasScaleFactor(),
false);
1664 double max_ref_scale = pc->GetNormalScaleMax(
1665 m_parent->GetCanvasScaleFactor(), m_canvas_width);
1666 if ((proposed_scale_onscreen >= min_ref_scale) &&
1667 (proposed_scale_onscreen <= max_ref_scale))
1668 return vp_in.view_scale_ppm;
1670 proposed_scale_onscreen = wxMin(proposed_scale_onscreen, max_ref_scale);
1671 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, min_ref_scale);
1675 return m_parent->GetCanvasScaleFactor() / proposed_scale_onscreen;
1679 if (m_refchart_dbIndex >= 0 && ChartData)
1680 return ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
1684 void Quilt::UnlockQuilt() {
1685 wxASSERT(m_bbusy ==
false);
1686 ChartData->UnLockCache();
1688 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1690 ChartData->UnLockCacheChart(pqc->dbIndex);
1695 if (!ChartData)
return false;
1701 if (!m_parent->GetpCurrentStack())
return false;
1703 if (m_bbusy)
return false;
1712 if (m_refchart_dbIndex >= 0) {
1714 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1715 m_reference_scale = cte_ref.GetScale();
1716 m_reference_type = cte_ref.GetChartType();
1717 if (!m_bquiltanyproj)
1718 m_quilt_proj = ChartData->GetDBChartProj(m_refchart_dbIndex);
1719 m_reference_family = cte_ref.GetChartFamily();
1723 if (!m_bquiltanyproj) vp_local.SetProjectionType(m_quilt_proj);
1730 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1770 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1772 if (qc->dbIndex == m_refchart_dbIndex) {
1778 if (!bf && m_pcandidate_array->GetCount() &&
1779 (m_reference_type != CHART_TYPE_CM93COMP)) {
1780 m_lost_refchart_dbIndex = m_refchart_dbIndex;
1781 int candidate_ref_index = GetNewRefChart();
1782 if (m_refchart_dbIndex != candidate_ref_index) {
1783 m_refchart_dbIndex = candidate_ref_index;
1784 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1789 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1790 if (m_pcandidate_array->GetCount()) {
1791 m_refchart_dbIndex =
1792 m_pcandidate_array->Item(m_pcandidate_array->GetCount() - 1)
1794 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1799 if ((-1 != m_lost_refchart_dbIndex) &&
1800 (m_lost_refchart_dbIndex != m_refchart_dbIndex)) {
1803 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1804 if (m_lost_refchart_dbIndex == m_extended_stack_array[ir]) {
1805 m_refchart_dbIndex = m_lost_refchart_dbIndex;
1806 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1807 m_lost_refchart_dbIndex = -1;
1813 bool b_has_overlays =
false;
1816 if (CHART_FAMILY_VECTOR == m_reference_family) {
1817 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1819 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1821 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1822 b_has_overlays =
true;
1835 const LLRegion cvp_region = vp_local.GetLLRegion(vp_local.rv_rect);
1836 LLRegion vp_region = cvp_region;
1842 for (ir = 0; ir < m_pcandidate_array->GetCount();
1846 if (pqc->dbIndex == m_refchart_dbIndex) {
1855 const double z = 111274.96299695622;
1857 double factor = 8.0 / (vp_local.view_scale_ppm * z);
1861 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1863 LLRegion vpu_region(cvp_region);
1866 LLRegion &chart_region = pqc_ref->GetReducedCandidateRegion(factor);
1868 if (cte_ref.GetChartType() != CHART_TYPE_MBTILES) {
1869 if (!chart_region.Empty()) {
1870 vpu_region.Intersect(chart_region);
1872 if (vpu_region.Empty())
1873 pqc_ref->b_include =
false;
1875 pqc_ref->b_include =
true;
1876 vp_region.Subtract(chart_region);
1879 pqc_ref->b_include =
false;
1881 pqc_ref->b_include =
false;
1886 if (!vp_region.Empty()) {
1887 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1890 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1892 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1897 if (CHART_FAMILY_VECTOR == m_reference_family) {
1898 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1904 if (CHART_TYPE_MBTILES == cte.GetChartType()) {
1905 pqc->b_include =
false;
1909 if (cte.Scale_ge(m_reference_scale)) {
1913 bool b_in_noshow =
false;
1914 for (
unsigned int ins = 0;
1915 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1916 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
1926 LLRegion vpu_region(cvp_region);
1929 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
1931 if (!chart_region.Empty()) {
1932 vpu_region.Intersect(chart_region);
1934 if (vpu_region.Empty())
1935 pqc->b_include =
false;
1937 pqc->b_include =
true;
1938 vp_region.Subtract(chart_region);
1941 pqc->b_include =
false;
1943 pqc->b_include =
true;
1947 pqc->b_include =
false;
1950 if (vp_region.Empty())
1957 if (b_has_overlays && (CHART_FAMILY_VECTOR == m_reference_family)) {
1958 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1961 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1963 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1965 if (cte.Scale_ge(m_reference_scale)) {
1966 bool b_in_noshow =
false;
1967 for (
unsigned int ins = 0;
1968 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1969 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
1979 LLRegion vpu_region(cvp_region);
1982 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
1984 if (!chart_region.Empty()) vpu_region.Intersect(chart_region);
1986 if (vpu_region.Empty())
1987 pqc->b_include =
false;
1990 s57chart::IsCellOverlayType(cte.GetFullSystemPath());
1991 if (b_overlay) pqc->b_include =
true;
1998 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1999 if (s57chart::IsCellOverlayType(cte_ref.GetFullSystemPath())) {
2000 pqc->b_include =
true;
2012 m_eclipsed_stack_array.clear();
2014 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2017 if (!pqc->b_include) {
2018 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
2019 if (cte.Scale_ge(m_reference_scale) &&
2020 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
2021 m_eclipsed_stack_array.push_back(pqc->dbIndex);
2022 pqc->b_eclipsed =
true;
2029 if (((m_bquiltanyproj || m_quilt_proj == PROJECTION_MERCATOR)) &&
2030 !vp_region.Empty()) {
2031 bool b_must_add_cm93 =
true;
2038 while( updd .HaveRects()) {
2039 wxRect rect = updd.GetRect();
2040 if( ( rect.width > 2 ) && ( rect.height > 2 ) ) {
2041 b_must_add_cm93 =
true;
2048 if (b_must_add_cm93) {
2049 for (
int ics = 0; ics < m_parent->GetpCurrentStack()->nEntry; ics++) {
2050 int i = m_parent->GetpCurrentStack()->GetDBIndex(ics);
2051 if (CHART_TYPE_CM93COMP == ChartData->GetDBChartType(i)) {
2054 qcnew->SetScale(ChartData->GetDBChartScale(i));
2056 m_pcandidate_array->Add(qcnew);
2067 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
2069 if (pqc->b_include) {
2075 if (!b_vis && m_pcandidate_array->GetCount()) {
2078 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2080 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
2083 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2086 if (cte.GetChartType() == CHART_TYPE_MBTILES)
continue;
2089 LLRegion vpck_region(vp_local.GetBBox());
2092 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
2094 if (!chart_region.Empty()) vpck_region.Intersect(chart_region);
2096 if (!vpck_region.Empty()) {
2098 if (cte.Scale_eq(add_scale)) {
2099 pqc->b_include =
true;
2102 pqc->b_include =
true;
2103 add_scale = cte.GetScale();
2112 m_PatchList.DeleteContents(
true);
2113 m_PatchList.Clear();
2115 if (m_pcandidate_array->GetCount()) {
2116 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2122 const ChartTableEntry &m = ChartData->GetChartTableEntry(pqc->dbIndex);
2124 if (m.GetChartType() == CHART_TYPE_CM93COMP)
2125 pqc->b_include =
true;
2128 if (pqc->b_include) {
2130 pqp->dbIndex = pqc->dbIndex;
2131 pqp->ProjType = m.GetChartProjectionType();
2134 pqp->quilt_region = pqc->GetCandidateRegion();
2137 pqp->b_Valid =
true;
2139 m_PatchList.Append(pqp);
2146 if (!m_bquiltanyproj) {
2148 m_quilt_proj = PROJECTION_MERCATOR;
2149 ChartBase *ppc = GetLargestScaleChart();
2150 if (ppc) m_quilt_proj = ppc->GetChartProjectionType();
2154 if (!m_bquiltanyproj) {
2157 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2158 wxPatchListNode *pcinode = m_PatchList.Item(i);
2160 if ((piqp->ProjType != m_quilt_proj) &&
2161 (piqp->ProjType != PROJECTION_UNKNOWN))
2162 piqp->b_Valid =
false;
2167 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2168 wxPatchListNode *pcinode = m_PatchList.Item(i);
2170 for (
unsigned int ins = 0;
2171 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
2172 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
2175 piqp->b_Valid =
false;
2183 m_covered_region.Clear();
2188 bool b_skipCM93 =
false;
2189 if (m_reference_type == CHART_TYPE_CM93COMP) {
2191 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2192 wxPatchListNode *pcinode = m_PatchList.Item(i);
2197 const ChartTableEntry &m = ChartData->GetChartTableEntry(piqp->dbIndex);
2199 if (m.GetChartType() == CHART_TYPE_CM93COMP) {
2201 piqp->ActiveRegion = piqp->quilt_region;
2202 piqp->ActiveRegion.Intersect(cvp_region);
2206 m_covered_region.Union(piqp->quilt_region);
2216 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2217 wxPatchListNode *pcinode = m_PatchList.Item(i);
2222 const ChartTableEntry &cte = ChartData->GetChartTableEntry(piqp->dbIndex);
2225 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2229 piqp->ActiveRegion = piqp->quilt_region;
2232 if (!b_has_overlays && m_PatchList.GetCount() < 25)
2233 piqp->ActiveRegion.Subtract(m_covered_region);
2235 piqp->ActiveRegion.Intersect(cvp_region);
2239 if (piqp->ActiveRegion.Empty() && (piqp->dbIndex != m_refchart_dbIndex))
2240 piqp->b_eclipsed =
true;
2243 piqp->b_overlay =
false;
2244 if (cte.GetChartFamily() == CHART_FAMILY_VECTOR) {
2245 piqp->b_overlay = s57chart::IsCellOverlayType(cte.GetFullSystemPath());
2248 if (!piqp->b_overlay) m_covered_region.Union(piqp->quilt_region);
2253 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2254 wxPatchListNode *pcinode = m_PatchList.Item(i);
2260 const ChartTableEntry &ctei = ChartData->GetChartTableEntry(piqp->dbIndex);
2263 LLRegion vpr_region = piqp->quilt_region;
2271 for (
unsigned int k = i + 1; k < m_PatchList.GetCount(); k++) {
2272 wxPatchListNode *pnode = m_PatchList.Item(k);
2293 if (!b_has_overlays) {
2294 if (!vpr_region.Empty()) {
2296 ChartData->GetChartTableEntry(pqp->dbIndex);
2297 LLRegion larger_scale_chart_region =
2300 vpr_region.Subtract(larger_scale_chart_region);
2309 wxPatchListNode *pinode = m_PatchList.Item(i);
2311 pqpi->ActiveRegion = vpr_region;
2320 if (pqpi->ActiveRegion.Empty()) pqpi->b_eclipsed =
true;
2328 m_covered_region.Union(pqpi->ActiveRegion);
2335 unsigned int il = 0;
2336 while (il < m_PatchList.GetCount()) {
2337 wxPatchListNode *pcinode = m_PatchList.Item(il);
2339 if (piqp->b_eclipsed) {
2342 bool b_noadd =
false;
2343 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size(); ir++) {
2344 if (piqp->dbIndex == m_eclipsed_stack_array[ir]) {
2349 if (!b_noadd) m_eclipsed_stack_array.push_back(piqp->dbIndex);
2351 m_PatchList.DeleteNode(pcinode);
2370 m_parent->EnablePaint(
false);
2377 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2379 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2380 if (!ChartData->IsChartLocked(pqc->dbIndex))
2381 ChartData->LockCacheChart(pqc->dbIndex);
2386 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2388 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2389 if (!ChartData->IsChartLocked(pqc->dbIndex))
2390 ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
true);
2399 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2401 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2402 if (ChartData->IsChartLocked(pqc->dbIndex))
2403 pqc->b_locked =
true;
2405 pqc->b_locked = ChartData->LockCacheChart(pqc->dbIndex);
2410 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2412 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2418 if (ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
2420 pqc->b_locked =
true;
2425 m_parent->EnablePaint(
true);
2428 m_last_index_array = m_index_array;
2430 m_index_array.clear();
2433 unsigned int kl = m_PatchList.GetCount();
2434 for (
unsigned int k = 0; k < kl; k++) {
2435 wxPatchListNode *cnode = m_PatchList.Item((kl - k) - 1);
2436 m_index_array.push_back(cnode->GetData()->dbIndex);
2437 cnode = cnode->GetNext();
2443 m_quilt_depth_unit = _T(
"");
2444 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
2446 m_quilt_depth_unit = pc->GetDepthUnits();
2448 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2449 int units = ps52plib->m_nDepthUnitDisplay;
2452 m_quilt_depth_unit = _T(
"Feet");
2455 m_quilt_depth_unit = _T(
"Meters");
2458 m_quilt_depth_unit = _T(
"Fathoms");
2464 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2465 wxPatchListNode *pnode = m_PatchList.Item(k);
2471 ChartBase *pc = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2473 wxString du = pc->GetDepthUnits();
2474 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2475 int units = ps52plib->m_nDepthUnitDisplay;
2488 wxString dul = du.Lower();
2489 wxString ml = m_quilt_depth_unit.Lower();
2493 if (dul.StartsWith(_T(
"meters")) && ml.StartsWith(_T(
"meters")))
2495 else if (dul.StartsWith(_T(
"metres")) && ml.StartsWith(_T(
"metres")))
2497 else if (dul.StartsWith(_T(
"fathoms")) && ml.StartsWith(_T(
"fathoms")))
2499 else if (dul.StartsWith(_T(
"met")) && ml.StartsWith(_T(
"met")))
2503 m_quilt_depth_unit = _T(
"");
2513 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2514 wxPatchListNode *pnode = m_PatchList.Item(k);
2518 if (!ChartData->IsChartInCache(pqp->dbIndex)) {
2519 wxLogMessage(_T(
" Quilt Compose cache miss..."));
2520 ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2521 if (!ChartData->IsChartInCache(pqp->dbIndex)) {
2522 wxLogMessage(_T(
" Oops, removing from quilt..."));
2523 pqp->b_Valid =
false;
2530 if (!ChartData->IsChartInCache(m_refchart_dbIndex))
2531 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
2537 m_bquilt_has_overlays =
false;
2538 m_max_error_factor = 0.;
2539 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2540 wxPatchListNode *pnode = m_PatchList.Item(k);
2546 ChartBase *pc = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2548 m_max_error_factor =
2549 wxMax(m_max_error_factor, pc->GetChart_Error_Factor());
2550 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2551 bool isOverlay = IsChartS57Overlay(pqp->dbIndex);
2552 pqp->b_overlay = isOverlay;
2553 if (isOverlay) m_bquilt_has_overlays =
true;
2562 ChartData->LockCache();
2566 unsigned long xa_hash = 5381;
2567 for (
unsigned int im = 0; im < m_extended_stack_array.size(); im++) {
2568 int dbindex = m_extended_stack_array[im];
2569 xa_hash = ((xa_hash << 5) + xa_hash) + dbindex;
2572 m_xa_hash = xa_hash;
2581 if (!m_bcomposed)
return;
2585 if (GetnCharts() && !m_bbusy && !chart_region.Empty()) {
2591 if (!(chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2592 vp.b_MercatorProjectionOverride)) {
2595 OCPNRegion get_screen_region = vp.GetVPRegionIntersect(
2596 chart_region, pqp->ActiveRegion, chart->GetNativeScale());
2597 if (!get_screen_region.Empty())
2598 rendered_region.Union(get_screen_region);
2601 chart = GetNextChart();
2605 m_rendered_region = rendered_region;
2610 bool Quilt::RenderQuiltRegionViewOnDCNoText(wxMemoryDC &dc,
ViewPort &vp,
2612 return DoRenderQuiltRegionViewOnDC(dc, vp, chart_region);
2615 bool Quilt::RenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
2617 return DoRenderQuiltRegionViewOnDCTextOnly(dc, vp, chart_region);
2620 bool Quilt::DoRenderQuiltRegionViewOnDC(wxMemoryDC &dc,
ViewPort &vp,
2622 #ifdef ocpnUSE_DIBSECTION
2628 if (!m_bcomposed)
return false;
2632 if (GetnCharts() && !m_bbusy) {
2640 int chartsDrawn = 0;
2642 if (!chart_region.Empty()) {
2644 bool okToRender =
true;
2646 if (chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2647 vp.b_MercatorProjectionOverride)
2651 chart = GetNextChart();
2656 bool b_chart_rendered =
false;
2657 LLRegion get_region = pqp->ActiveRegion;
2659 OCPNRegion get_screen_region = vp.GetVPRegionIntersect(
2660 chart_region, get_region, chart->GetNativeScale());
2661 if (!get_screen_region.Empty()) {
2662 if (!pqp->b_overlay) {
2663 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
2665 chart->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2669 if (Chs57->m_RAZBuilt) {
2670 b_chart_rendered = Chs57->RenderRegionViewOnDCNoText(
2671 tmp_dc, vp, get_screen_region);
2677 b_chart_rendered = ChPI->RenderRegionViewOnDCNoText(
2678 tmp_dc, vp, get_screen_region);
2680 b_chart_rendered = chart->RenderRegionViewOnDC(
2681 tmp_dc, vp, get_screen_region);
2683 b_chart_rendered =
true;
2690 screen_region.Subtract(get_screen_region);
2695 while (upd.HaveRects()) {
2696 wxRect rect = upd.GetRect();
2697 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc, rect.x,
2698 rect.y, wxCOPY,
true);
2702 tmp_dc.SelectObject(wxNullBitmap);
2704 if (b_chart_rendered) rendered_region.Union(get_screen_region);
2708 chart = GetNextChart();
2712 if (!chartsDrawn) m_parent->GetVP().SetProjectionType(PROJECTION_MERCATOR);
2715 if (m_bquilt_has_overlays && !chart_region.Empty()) {
2716 chart = GetFirstChart();
2720 if (pqp->b_overlay) {
2721 LLRegion get_region = pqp->ActiveRegion;
2722 OCPNRegion get_screen_region = vp.GetVPRegionIntersect(
2723 chart_region, get_region, chart->GetNativeScale());
2724 if (!get_region.Empty()) {
2727 Chs57->RenderOverlayRegionViewOnDC(tmp_dc, vp,
2733 ChPI->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2738 while (upd.HaveRects()) {
2739 wxRect rect = upd.GetRect();
2740 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc,
2741 rect.x, rect.y, wxCOPY,
true);
2744 tmp_dc.SelectObject(wxNullBitmap);
2749 chart = GetNextChart();
2756 while (clrit.HaveRects()) {
2757 wxRect rect = clrit.GetRect();
2759 dc.SetPen(*wxBLACK_PEN);
2760 dc.SetBrush(*wxBLACK_BRUSH);
2761 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
2763 dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y,
2770 if (m_nHiLiteIndex >= 0) {
2772 vp.GetVPRegionIntersect(chart_region, GetHiliteRegion(), 1);
2773 wxRect box = hiregion.GetBox();
2775 if (!box.IsEmpty()) {
2778 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2779 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2786 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2790 q_dc.SelectObject(*m_pBM);
2791 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2792 q_dc.SelectObject(wxNullBitmap);
2797 wxBitmap hl_mask_bm(vp.rv_rect.width, vp.rv_rect.height, 1);
2799 mdc.SelectObject(hl_mask_bm);
2800 mdc.SetBackground(*wxBLACK_BRUSH);
2802 mdc.SetClippingRegion(box);
2803 mdc.SetBackground(*wxWHITE_BRUSH);
2805 mdc.SelectObject(wxNullBitmap);
2807 if (hl_mask_bm.IsOk()) {
2808 wxMask *phl_mask =
new wxMask(hl_mask_bm);
2809 m_pBM->SetMask(phl_mask);
2810 q_dc.SelectObject(*m_pBM);
2813 wxBitmap rbm(vp.rv_rect.width, vp.rv_rect.height);
2814 wxMask *pr_mask =
new wxMask(hl_mask_bm);
2816 rbm.SetMask(pr_mask);
2817 rdc.SelectObject(rbm);
2818 unsigned char hlcolor = 255;
2819 switch (global_color_scheme) {
2820 case GLOBAL_COLOR_SCHEME_DAY:
2823 case GLOBAL_COLOR_SCHEME_DUSK:
2826 case GLOBAL_COLOR_SCHEME_NIGHT:
2834 rdc.SetBackground(wxBrush(wxColour(hlcolor, 0, 0)));
2838 while (upd.HaveRects()) {
2839 wxRect rect = upd.GetRect();
2840 rdc.Blit(rect.x, rect.y, rect.width, rect.height, &q_dc, rect.x,
2841 rect.y, wxOR,
true);
2846 while (updq.HaveRects()) {
2847 wxRect rect = updq.GetRect();
2848 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &rdc, rect.x,
2849 rect.y, wxCOPY,
true);
2853 q_dc.SelectObject(wxNullBitmap);
2854 m_pBM->SetMask(NULL);
2857 dc.SelectObject(*m_pBM);
2860 rdc.SelectObject(wxNullBitmap);
2866 if (g_fog_overzoom) {
2867 double scale_factor = vp.ref_scale / vp.chart_scale;
2869 if (scale_factor > g_overzoom_emphasis_base) {
2870 float fog = ((scale_factor - g_overzoom_emphasis_base) * 255.) / 20.;
2871 fog = wxMin(fog, 200.);
2875 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2876 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2883 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2887 q_dc.SelectObject(*m_pBM);
2888 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2889 q_dc.SelectObject(wxNullBitmap);
2891 wxImage src = m_pBM->ConvertToImage();
2894 wxMin((scale_factor - g_overzoom_emphasis_base) / 4, 4);
2896 wxImage dest = src.Blur(blur_factor);
2900 unsigned char *bg = src.GetData();
2901 wxColour color = m_parent->GetFogColor();
2903 float transparency = fog;
2906 wxImage dest(vp.rv_rect.width, vp.rv_rect.height);
2907 unsigned char *dest_data = (
unsigned char *) malloc( vp.rv_rect.width * vp.rv_rect.height * 3 *
sizeof(
unsigned char) );
2908 unsigned char *d = dest_data;
2910 float alpha = 1.0 - (float)transparency / 255.0;
2911 int sb = vp.rv_rect.width * vp.rv_rect.height;
2912 for(
int i = 0; i < sb; i++ ) {
2915 int r = ( ( *bg++ ) * a ) + (1.0-a) * color.Red();
2917 int g = ( ( *bg++ ) * a ) + (1.0-a) * color.Green();
2919 int b = ( ( *bg++ ) * a ) + (1.0-a) * color.Blue();
2923 dest.SetData( dest_data );
2928 ddc.SelectObject(dim);
2930 q_dc.SelectObject(*m_pBM);
2932 while (upd.HaveRects()) {
2933 wxRect rect = upd.GetRect();
2934 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &ddc, rect.x,
2939 ddc.SelectObject(wxNullBitmap);
2940 q_dc.SelectObject(wxNullBitmap);
2943 dc.SelectObject(*m_pBM);
2951 SubstituteClearDC(dc, vp);
2955 SubstituteClearDC(dc, vp);
2959 m_rendered_region = rendered_region;
2965 void Quilt::SubstituteClearDC(wxMemoryDC &dc,
ViewPort &vp) {
2967 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2968 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2974 if (NULL == m_pBM) {
2975 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2978 dc.SelectObject(wxNullBitmap);
2979 dc.SelectObject(*m_pBM);
2980 dc.SetBackground(*wxBLACK_BRUSH);
2982 m_covered_region.Clear();
2985 bool Quilt::DoRenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
2987 if (!m_bcomposed)
return false;
2991 if (GetnCharts() && !m_bbusy) {
2996 ChartBase *chart = GetLargestScaleChart();
3003 Chs57->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3007 ChPI->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3012 chart = GetNextSmallerScaleChart();
3016 SubstituteClearDC(dc, vp);
bool Compose(const ViewPort &vp)