32#include "ocpn_pixel.h"
34#ifdef __OCPN__ANDROID__
35#include "androidUTIL.h"
41#include <wx/listimpl.cpp>
42WX_DEFINE_LIST(PatchList);
45extern s52plib *ps52plib;
46extern ColorScheme global_color_scheme;
47extern int g_chart_zoom_modifier_raster;
48extern int g_chart_zoom_modifier_vector;
49extern bool g_fog_overzoom;
50extern double g_overzoom_emphasis_base;
61#ifndef __OCPN__ANDROID__
62#define GetChartTableEntry(i) GetChartTable()[i]
71#define NOCOVR_PLY_PERF_LIMIT 500
72#define AUX_PLY_PERF_LIMIT 500
74static int CompareScales(
int i1,
int i2) {
75 if (!ChartData)
return 0;
80 if (cte1.Scale_eq(cte2.GetScale())) {
82 lat1 = cte1.GetLatMax();
83 lat2 = cte2.GetLatMax();
84 if (roundf(lat1 * 100.) == roundf(lat2 * 100.)) {
86 lon1 = cte1.GetLonMin();
87 lon2 = cte2.GetLonMin();
91 return (lon1 < lon2) ? -1 : 1;
93 return (lat1 < lat2) ? 1 : -1;
95 return cte1.GetScale() - cte2.GetScale();
97static bool CompareScalesStd(
int i1,
int i2) {
98 return CompareScales(i1, i2) < 0;
103 if (!ChartData)
return 0;
104 return CompareScales(qc1->dbIndex, qc2->dbIndex);
107const LLRegion &QuiltCandidate::GetCandidateRegion() {
109 LLRegion &candidate_region =
110 const_cast<LLRegion &
>(cte.quilt_candidate_region);
112 if (!candidate_region.Empty())
return candidate_region;
114 LLRegion world_region(-90, -180, 90, 180);
118 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93COMP) {
119 double cm93_ll_bounds[8] = {-80, -180, -80, 180, 80, 180, 80, -180};
120 candidate_region = LLRegion(4, cm93_ll_bounds);
121 return candidate_region;
125 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
126 if (nAuxPlyEntries >= 1) {
127 candidate_region.Clear();
128 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
129 float *pfp = cte.GetpAuxPlyTableEntry(ip);
130 int nAuxPly = cte.GetAuxCntTableEntry(ip);
132 candidate_region.Union(LLRegion(nAuxPly, pfp));
145 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
147 std::vector<float> vecr;
148 for (
size_t i = 0; i < vec.size() / 2; i++) {
149 float a = vec[i * 2 + 1];
155 std::vector<float>::iterator it = vecr.begin();
157 if (vecr.size() / 2 >= 3) {
160 candidate_region = LLRegion(vecr.size() / 2, (
float *)&(*it));
162 candidate_region = world_region;
166 if (!candidate_region
168 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
169 if (nNoCovrPlyEntries) {
170 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
171 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
172 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
174 LLRegion t_region = LLRegion(nNoCovrPly, pfp);
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;
202LLRegion &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;
212void 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();
266bool Quilt::IsVPBlittable(
ViewPort &VPoint,
int dx,
int dy,
267 bool b_allow_vector) {
268 if (!m_vp_rendered.IsValid())
return false;
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;
281bool 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());
291bool 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);
322bool 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)
334bool 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;
346std::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());
384void 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);
434ChartBase *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);
454ChartBase *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;
584bool 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();
614bool 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();
643int Quilt::GetChartdbIndexAtPix(
ViewPort &VPoint, wxPoint p) {
644 if (m_bbusy)
return -1;
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;
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;
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();
718void Quilt::InvalidateAllQuiltPatchs(
void) {
729std::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();
749bool Quilt::IsQuiltDelta(
ViewPort &vp) {
750 if (!m_vp_quilt.IsValid() || !m_bcomposed)
return true;
754 if (m_vp_quilt.m_projection_type != vp.m_projection_type)
return true;
759 wxPoint cp_last, cp_this;
764 return (cp_last != cp_this);
772 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
774 if (pRefChart) pRefChart->AdjustVP(vp_last, vp_proposed);
777double 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();
787int 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;
815int Quilt::GetNomScaleMax(
int scale, ChartTypeEnum type,
816 ChartFamilyEnum family) {
818 case CHART_FAMILY_RASTER: {
822 case CHART_FAMILY_VECTOR: {
832int 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;
871int 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;
995int 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;
1028int 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;
1079bool 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);
1101LLRegion Quilt::GetHiliteRegion() {
1107 for (
auto &index : m_HiLiteIndexArray) {
1109 LLRegion cell_region = GetChartQuiltRegion(cte, m_vp_quilt);
1110 r.Union(cell_region);
1114 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1115 wxPatchListNode *pcinode = m_PatchList.Item(i);
1117 if ((index == piqp->dbIndex) && (piqp->b_Valid))
1119 r.Union(piqp->ActiveRegion);
1128LLRegion Quilt::GetHiliteRegion() {
1130 if (m_nHiLiteIndex >= 0) {
1132 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
1133 wxPatchListNode *pcinode = m_PatchList.Item(i);
1135 if ((m_nHiLiteIndex == piqp->dbIndex) && (piqp->b_Valid))
1137 r = piqp->ActiveRegion;
1144 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1146 if (m_nHiLiteIndex == pqc->dbIndex) {
1147 LLRegion chart_region = pqc->GetCandidateRegion();
1148 if (!chart_region.Empty()) {
1150 bool b_eclipsed =
false;
1151 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size();
1153 if (m_nHiLiteIndex == m_eclipsed_stack_array[ir]) {
1159 if (!b_eclipsed) r = chart_region;
1169 ChartData->GetChartTableEntry(m_nHiLiteIndex);
1170 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
1171 r = GetTilesetRegion(m_nHiLiteIndex);
1179const LLRegion &Quilt::GetTilesetRegion(
int dbIndex) {
1180 LLRegion world_region(-90, -180, 90, 180);
1183 LLRegion &target_region =
const_cast<LLRegion &
>(cte.quilt_candidate_region);
1185 if (!target_region.Empty())
return target_region;
1188 int nAuxPlyEntries = cte.GetnAuxPlyEntries();
1189 if (nAuxPlyEntries >= 1) {
1190 target_region.Clear();
1191 for (
int ip = 0; ip < nAuxPlyEntries; ip++) {
1192 float *pfp = cte.GetpAuxPlyTableEntry(ip);
1193 int nAuxPly = cte.GetAuxCntTableEntry(ip);
1195 target_region.Union(LLRegion(nAuxPly, pfp));
1198 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
1200 std::vector<float> vecr;
1201 for (
size_t i = 0; i < vec.size() / 2; i++) {
1202 float a = vec[i * 2 + 1];
1208 std::vector<float>::iterator it = vecr.begin();
1210 if (vecr.size() / 2 >= 3) {
1213 target_region = LLRegion(vecr.size() / 2, (
float *)&(*it));
1215 target_region = world_region;
1219 if (!target_region.Empty()) {
1220 int nNoCovrPlyEntries = cte.GetnNoCovrPlyEntries();
1221 if (nNoCovrPlyEntries) {
1222 for (
int ip = 0; ip < nNoCovrPlyEntries; ip++) {
1223 float *pfp = cte.GetpNoCovrPlyTableEntry(ip);
1224 int nNoCovrPly = cte.GetNoCovrCntTableEntry(ip);
1226 LLRegion t_region = LLRegion(nNoCovrPly, pfp);
1233 if (!t_region.Empty()) {
1234 LLRegion test_region = target_region;
1235 test_region.Subtract(t_region);
1237 if (!test_region.Empty()) target_region = test_region;
1251 return target_region;
1254bool Quilt::BuildExtendedChartStackAndCandidateArray(
int ref_db_index,
1256 double zoom_test_val = .002;
1259 EmptyCandidateArray();
1260 m_extended_stack_array.clear();
1261 m_fullscreen_index_array.clear();
1263 int reference_scale = 1e8;
1264 int reference_type = -1;
1265 int reference_family = -1;
1267 m_bquiltanyproj ? vp_in.m_projection_type : PROJECTION_UNKNOWN;
1269 if (ref_db_index >= 0) {
1271 ChartData->GetChartTableEntry(ref_db_index);
1272 reference_scale = cte_ref.GetScale();
1273 reference_type = cte_ref.GetChartType();
1274 if (!m_bquiltanyproj) quilt_proj = ChartData->GetDBChartProj(ref_db_index);
1275 reference_family = cte_ref.GetChartFamily();
1278 bool b_need_resort =
false;
1288 int n_charts = m_parent->GetpCurrentStack()->nEntry;
1292 for (
int ics = 0; ics < n_charts; ics++) {
1293 int istack = m_parent->GetpCurrentStack()->GetDBIndex(ics);
1294 if (istack < 0)
continue;
1295 m_extended_stack_array.push_back(istack);
1301 if (reference_type == CHART_TYPE_CM93COMP)
continue;
1311 if ((cte.GetChartType() == CHART_TYPE_PLUGIN) ||
1312 (reference_type == CHART_TYPE_PLUGIN)) {
1313 if (reference_family != cte.GetChartFamily()) {
1317 if (reference_type != cte.GetChartType()) {
1322 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1325 int candidate_chart_scale = cte.GetScale();
1326 double chart_native_ppm =
1327 m_canvas_scale_factor / (double)candidate_chart_scale;
1329 if ((zoom_factor < zoom_test_val) &&
1334 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
1335 m_extended_stack_array.pop_back();
1339 double skew_norm = cte.GetChartSkew();
1340 if (skew_norm > 180.) skew_norm -= 360.;
1342 if ((m_bquiltskew ? 1 : fabs(skew_norm) < 1.0) &&
1343 (m_bquiltanyproj || cte.GetChartProjectionType() == quilt_proj)) {
1345 qcnew->dbIndex = istack;
1346 qcnew->SetScale(cte.GetScale());
1347 m_pcandidate_array->push_back(qcnew);
1374 int n_all_charts = ChartData->GetChartTableEntries();
1376 LLBBox viewbox = vp_local.GetBBox();
1377 int sure_index = -1;
1378 int sure_index_scale = 0;
1379 int sure_index_type = -1;
1381 for (
int i = 0; i < n_all_charts; i++) {
1385 int groupIndex = m_parent->m_groupIndex;
1386 if ((groupIndex > 0) && (!ChartData->IsChartInGroup(i, groupIndex)))
1391 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
1392 m_fullscreen_index_array.push_back(i);
1396#ifdef __OCPN__ANDROID__
1397 wxFileName fn(cte.GetFullSystemPath());
1398 if (!androidIsDirWritable(fn.GetPath()))
continue;
1400 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
1402 const LLBBox &chart_box = cte.GetBBox();
1403 if ((viewbox.IntersectOut(chart_box)))
continue;
1405 m_fullscreen_index_array.push_back(i);
1407 if (reference_family != cte.GetChartFamily()) {
1408 if (cte.GetChartType() != CHART_TYPE_MBTILES)
continue;
1411 if (!m_bquiltanyproj && quilt_proj != cte.GetChartProjectionType())
1414 double skew_norm = cte.GetChartSkew();
1415 if (skew_norm > 180.) skew_norm -= 360.;
1417 if (!m_bquiltskew && fabs(skew_norm) > 1.0)
continue;
1422 if( CHART_TYPE_S57 == cte.GetChartType() ) {
1424 double chart_area = (cte.GetLonMax() - cte.GetLonMin()) *
1425 (cte.GetLatMax() - cte.GetLatMin());
1426 double quilt_area = viewbox.GetLonRange() * viewbox.GetLatRange();
1427 if ((chart_area / quilt_area) < .01)
continue;
1430 int candidate_chart_scale = cte.GetScale();
1436 if (!cte.Scale_ge(reference_scale)) {
1437 if (cte.Scale_gt(sure_index_scale)) {
1439 sure_index_scale = candidate_chart_scale;
1440 sure_index_type = cte.GetChartType();
1449 double chart_native_ppm =
1450 m_canvas_scale_factor / (double)candidate_chart_scale;
1452 double zoom_factor_test_extra = 0.2;
1458 double ref_scale_test = reference_scale;
1459 if (cte.GetChartType() == CHART_TYPE_MBTILES)
1460 ref_scale_test = candidate_chart_scale;
1462 if ((cte.Scale_ge(ref_scale_test) && (zoom_factor > zoom_test_val)) ||
1463 (zoom_factor > zoom_factor_test_extra)) {
1464 LLRegion cell_region = GetChartQuiltRegion(cte, vp_local);
1469 if (!cell_region.Empty()) {
1472 bool b_exists =
false;
1473 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1474 if (i == m_extended_stack_array[ir]) {
1488 bool b_noadd =
false;
1490 for (
unsigned int id = 0;
id < m_extended_stack_array.size();
id++) {
1491 if (m_extended_stack_array[
id] != -1) {
1493 ChartData->GetpChartTableEntry(m_extended_stack_array[
id]);
1494 bool bsameTime =
false;
1495 if (pm->GetFileTime() && pn->GetFileTime()) {
1496 if (labs(pm->GetFileTime() - pn->GetFileTime()) < 60)
1499 if (pm->GetChartEditionDate() == pn->GetChartEditionDate())
1503 if (pn->GetpFileName()->IsSameAs(*(pm->GetpFileName())))
1510 m_extended_stack_array.push_back(i);
1515 candidate_chart_scale);
1517 m_pcandidate_array->push_back(qcnew);
1519 b_need_resort =
true;
1528 if (-1 != sure_index) {
1530 bool sure_exists =
false;
1531 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1532 if (sure_index == m_extended_stack_array[ir]) {
1539 if (!sure_exists && (sure_index_type != CHART_TYPE_MBTILES)) {
1540 m_extended_stack_array.push_back(sure_index);
1543 qcnew->dbIndex = sure_index;
1544 qcnew->SetScale(ChartData->GetDBChartScale(sure_index));
1545 m_pcandidate_array->push_back(qcnew);
1547 b_need_resort =
true;
1552 if (b_need_resort && m_extended_stack_array.size() > 1) {
1553 std::sort(m_extended_stack_array.begin(), m_extended_stack_array.end(),
1559int Quilt::AdjustRefSelection(
const ViewPort &vp_in) {
1564 if (!ChartData)
return false;
1574 vp_local.SetRotationAngle(0.);
1576 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1578 ChartFamilyEnum family = CHART_FAMILY_RASTER;
1579 ChartTypeEnum type = CHART_TYPE_KAP;
1582 if (m_refchart_dbIndex >= 0) {
1584 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1585 type = (ChartTypeEnum)cte_ref.GetChartType();
1586 family = (ChartFamilyEnum)cte_ref.GetChartFamily();
1589 int ret_index = AdjustRefOnZoom(
true, family, type, vp_in.
chart_scale);
1594double Quilt::GetBestStartScale(
int dbi_ref_hint,
const ViewPort &vp_in) {
1604 int tentative_ref_index = dbi_ref_hint;
1605 if (dbi_ref_hint < 0) {
1612 tentative_ref_index = m_parent->GetpCurrentStack()->GetDBIndex(0);
1619 vp_local.SetRotationAngle(0.);
1621 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1625 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1627 if (qc->dbIndex == tentative_ref_index) {
1633 if (!bf && m_pcandidate_array->GetCount()) {
1634 tentative_ref_index = GetNewRefChart();
1635 BuildExtendedChartStackAndCandidateArray(tentative_ref_index, vp_local);
1638 double proposed_scale_onscreen = vp_in.
chart_scale;
1640 if (m_pcandidate_array->GetCount()) {
1641 m_refchart_dbIndex = tentative_ref_index;
1645 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1647 if (IsChartQuiltableRef(qc->dbIndex)) {
1648 m_refchart_dbIndex = qc->dbIndex;
1655 m_refchart_dbIndex = m_parent->GetpCurrentStack()->GetDBIndex(0);
1658 if (m_refchart_dbIndex >= 0) {
1661 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
1663 double min_ref_scale =
1665 double max_ref_scale = pc->GetNormalScaleMax(
1667 if ((proposed_scale_onscreen >= min_ref_scale) &&
1668 (proposed_scale_onscreen <= max_ref_scale))
1671 proposed_scale_onscreen = wxMin(proposed_scale_onscreen, max_ref_scale);
1672 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, min_ref_scale);
1680 if (m_refchart_dbIndex >= 0 && ChartData)
1681 return ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
1685void Quilt::UnlockQuilt() {
1686 wxASSERT(m_bbusy ==
false);
1687 ChartData->UnLockCache();
1689 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1691 ChartData->UnLockCacheChart(pqc->dbIndex);
1696 if (!ChartData)
return false;
1702 if (!m_parent->GetpCurrentStack())
return false;
1704 if (m_bbusy)
return false;
1713 if (m_refchart_dbIndex >= 0) {
1715 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1716 m_reference_scale = cte_ref.GetScale();
1717 m_reference_type = cte_ref.GetChartType();
1718 if (!m_bquiltanyproj)
1719 m_quilt_proj = ChartData->GetDBChartProj(m_refchart_dbIndex);
1720 m_reference_family = cte_ref.GetChartFamily();
1724 if (!m_bquiltanyproj) vp_local.SetProjectionType(m_quilt_proj);
1731 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1771 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
1773 if (qc->dbIndex == m_refchart_dbIndex) {
1779 if (!bf && m_pcandidate_array->GetCount() &&
1780 (m_reference_type != CHART_TYPE_CM93COMP)) {
1781 m_lost_refchart_dbIndex = m_refchart_dbIndex;
1782 int candidate_ref_index = GetNewRefChart();
1783 if (m_refchart_dbIndex != candidate_ref_index) {
1784 m_refchart_dbIndex = candidate_ref_index;
1785 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1790 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1791 if (m_pcandidate_array->GetCount()) {
1792 m_refchart_dbIndex =
1793 m_pcandidate_array->Item(m_pcandidate_array->GetCount() - 1)
1795 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1800 if ((-1 != m_lost_refchart_dbIndex) &&
1801 (m_lost_refchart_dbIndex != m_refchart_dbIndex)) {
1804 for (
unsigned int ir = 0; ir < m_extended_stack_array.size(); ir++) {
1805 if (m_lost_refchart_dbIndex == m_extended_stack_array[ir]) {
1806 m_refchart_dbIndex = m_lost_refchart_dbIndex;
1807 BuildExtendedChartStackAndCandidateArray(m_refchart_dbIndex, vp_local);
1808 m_lost_refchart_dbIndex = -1;
1814 bool b_has_overlays =
false;
1817 if (CHART_FAMILY_VECTOR == m_reference_family) {
1818 for (
unsigned int ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1820 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1822 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1823 b_has_overlays =
true;
1836 const LLRegion cvp_region = vp_local.GetLLRegion(vp_local.rv_rect);
1837 LLRegion vp_region = cvp_region;
1843 for (ir = 0; ir < m_pcandidate_array->GetCount();
1847 if (pqc->dbIndex == m_refchart_dbIndex) {
1856 const double z = 111274.96299695622;
1862 ChartData->GetChartTableEntry(m_refchart_dbIndex);
1864 LLRegion vpu_region(cvp_region);
1867 LLRegion &chart_region = pqc_ref->GetReducedCandidateRegion(factor);
1869 if (cte_ref.GetChartType() != CHART_TYPE_MBTILES) {
1870 if (!chart_region.Empty()) {
1871 vpu_region.Intersect(chart_region);
1873 if (vpu_region.Empty())
1874 pqc_ref->b_include =
false;
1876 pqc_ref->b_include =
true;
1877 vp_region.Subtract(chart_region);
1880 pqc_ref->b_include =
false;
1882 pqc_ref->b_include =
false;
1887 if (!vp_region.Empty()) {
1888 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1891 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1893 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1898 if (CHART_FAMILY_VECTOR == m_reference_family) {
1899 if (s57chart::IsCellOverlayType(cte.GetFullSystemPath())) {
1905 if (CHART_TYPE_MBTILES == cte.GetChartType()) {
1906 pqc->b_include =
false;
1910 if (cte.Scale_ge(m_reference_scale)) {
1914 bool b_in_noshow =
false;
1915 for (
unsigned int ins = 0;
1916 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1917 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
1927 LLRegion vpu_region(cvp_region);
1930 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
1932 if (!chart_region.Empty()) {
1933 vpu_region.Intersect(chart_region);
1935 if (vpu_region.Empty())
1936 pqc->b_include =
false;
1938 pqc->b_include =
true;
1939 vp_region.Subtract(chart_region);
1942 pqc->b_include =
false;
1944 pqc->b_include =
true;
1948 pqc->b_include =
false;
1951 if (vp_region.Empty())
1958 if (b_has_overlays && (CHART_FAMILY_VECTOR == m_reference_family)) {
1959 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
1962 if (pqc->dbIndex == m_refchart_dbIndex)
continue;
1964 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
1966 if (cte.Scale_ge(m_reference_scale)) {
1967 bool b_in_noshow =
false;
1968 for (
unsigned int ins = 0;
1969 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
1970 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
1980 LLRegion vpu_region(cvp_region);
1983 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
1985 if (!chart_region.Empty()) vpu_region.Intersect(chart_region);
1987 if (vpu_region.Empty())
1988 pqc->b_include =
false;
1991 s57chart::IsCellOverlayType(cte.GetFullSystemPath());
1992 if (b_overlay) pqc->b_include =
true;
1999 ChartData->GetChartTableEntry(m_refchart_dbIndex);
2000 if (s57chart::IsCellOverlayType(cte_ref.GetFullSystemPath())) {
2001 pqc->b_include =
true;
2013 m_eclipsed_stack_array.clear();
2015 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2018 if (!pqc->b_include) {
2019 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
2020 if (cte.Scale_ge(m_reference_scale) &&
2021 (cte.GetChartType() != CHART_TYPE_MBTILES)) {
2022 m_eclipsed_stack_array.push_back(pqc->dbIndex);
2023 pqc->b_eclipsed =
true;
2030 if (((m_bquiltanyproj || m_quilt_proj == PROJECTION_MERCATOR)) &&
2031 !vp_region.Empty()) {
2032 bool b_must_add_cm93 =
true;
2039 while( updd .HaveRects()) {
2040 wxRect rect = updd.GetRect();
2041 if( ( rect.width > 2 ) && ( rect.height > 2 ) ) {
2042 b_must_add_cm93 =
true;
2049 if (b_must_add_cm93) {
2050 for (
int ics = 0; ics < m_parent->GetpCurrentStack()->nEntry; ics++) {
2051 int i = m_parent->GetpCurrentStack()->GetDBIndex(ics);
2052 if (CHART_TYPE_CM93COMP == ChartData->GetDBChartType(i)) {
2055 qcnew->SetScale(ChartData->GetDBChartScale(i));
2057 m_pcandidate_array->Add(qcnew);
2068 for (
unsigned int i = 0; i < m_pcandidate_array->GetCount(); i++) {
2070 if (pqc->b_include) {
2076 if (!b_vis && m_pcandidate_array->GetCount()) {
2079 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2081 const ChartTableEntry &cte = ChartData->GetChartTableEntry(pqc->dbIndex);
2084 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2087 if (cte.GetChartType() == CHART_TYPE_MBTILES)
continue;
2090 LLRegion vpck_region(vp_local.GetBBox());
2093 LLRegion &chart_region = pqc->GetReducedCandidateRegion(factor);
2095 if (!chart_region.Empty()) vpck_region.Intersect(chart_region);
2097 if (!vpck_region.Empty()) {
2099 if (cte.Scale_eq(add_scale)) {
2100 pqc->b_include =
true;
2103 pqc->b_include =
true;
2104 add_scale = cte.GetScale();
2113 m_PatchList.DeleteContents(
true);
2114 m_PatchList.Clear();
2116 if (m_pcandidate_array->GetCount()) {
2117 for (
int i = m_pcandidate_array->GetCount() - 1; i >= 0; i--) {
2123 const ChartTableEntry &m = ChartData->GetChartTableEntry(pqc->dbIndex);
2125 if (m.GetChartType() == CHART_TYPE_CM93COMP)
2126 pqc->b_include =
true;
2129 if (pqc->b_include) {
2131 pqp->dbIndex = pqc->dbIndex;
2132 pqp->ProjType = m.GetChartProjectionType();
2135 pqp->quilt_region = pqc->GetCandidateRegion();
2138 pqp->b_Valid =
true;
2140 m_PatchList.Append(pqp);
2147 if (!m_bquiltanyproj) {
2149 m_quilt_proj = PROJECTION_MERCATOR;
2150 ChartBase *ppc = GetLargestScaleChart();
2151 if (ppc) m_quilt_proj = ppc->GetChartProjectionType();
2155 if (!m_bquiltanyproj) {
2158 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2159 wxPatchListNode *pcinode = m_PatchList.Item(i);
2161 if ((piqp->ProjType != m_quilt_proj) &&
2162 (piqp->ProjType != PROJECTION_UNKNOWN))
2163 piqp->b_Valid =
false;
2168 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2169 wxPatchListNode *pcinode = m_PatchList.Item(i);
2171 for (
unsigned int ins = 0;
2172 ins < m_parent->GetQuiltNoshowIindexArray().size(); ins++) {
2173 if (m_parent->GetQuiltNoshowIindexArray()[ins] ==
2176 piqp->b_Valid =
false;
2184 m_covered_region.Clear();
2189 bool b_skipCM93 =
false;
2190 if (m_reference_type == CHART_TYPE_CM93COMP) {
2192 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2193 wxPatchListNode *pcinode = m_PatchList.Item(i);
2198 const ChartTableEntry &m = ChartData->GetChartTableEntry(piqp->dbIndex);
2200 if (m.GetChartType() == CHART_TYPE_CM93COMP) {
2202 piqp->ActiveRegion = piqp->quilt_region;
2203 piqp->ActiveRegion.Intersect(cvp_region);
2207 m_covered_region.Union(piqp->quilt_region);
2217 for (
int i = m_PatchList.GetCount() - 1; i >= 0; i--) {
2218 wxPatchListNode *pcinode = m_PatchList.Item(i);
2223 const ChartTableEntry &cte = ChartData->GetChartTableEntry(piqp->dbIndex);
2226 if (cte.GetChartType() == CHART_TYPE_CM93COMP)
continue;
2230 piqp->ActiveRegion = piqp->quilt_region;
2233 if (!b_has_overlays && m_PatchList.GetCount() < 25)
2234 piqp->ActiveRegion.Subtract(m_covered_region);
2236 piqp->ActiveRegion.Intersect(cvp_region);
2240 if (piqp->ActiveRegion.Empty() && (piqp->dbIndex != m_refchart_dbIndex))
2241 piqp->b_eclipsed =
true;
2244 piqp->b_overlay =
false;
2245 if (cte.GetChartFamily() == CHART_FAMILY_VECTOR) {
2246 piqp->b_overlay = s57chart::IsCellOverlayType(cte.GetFullSystemPath());
2249 if (!piqp->b_overlay) m_covered_region.Union(piqp->quilt_region);
2254 for (
unsigned int i = 0; i < m_PatchList.GetCount(); i++) {
2255 wxPatchListNode *pcinode = m_PatchList.Item(i);
2261 const ChartTableEntry &ctei = ChartData->GetChartTableEntry(piqp->dbIndex);
2264 LLRegion vpr_region = piqp->quilt_region;
2272 for (
unsigned int k = i + 1; k < m_PatchList.GetCount(); k++) {
2273 wxPatchListNode *pnode = m_PatchList.Item(k);
2294 if (!b_has_overlays) {
2295 if (!vpr_region.Empty()) {
2297 ChartData->GetChartTableEntry(pqp->dbIndex);
2298 LLRegion larger_scale_chart_region =
2301 vpr_region.Subtract(larger_scale_chart_region);
2310 wxPatchListNode *pinode = m_PatchList.Item(i);
2312 pqpi->ActiveRegion = vpr_region;
2321 if (pqpi->ActiveRegion.Empty()) pqpi->b_eclipsed =
true;
2329 m_covered_region.Union(pqpi->ActiveRegion);
2336 unsigned int il = 0;
2337 while (il < m_PatchList.GetCount()) {
2338 wxPatchListNode *pcinode = m_PatchList.Item(il);
2340 if (piqp->b_eclipsed) {
2343 bool b_noadd =
false;
2344 for (
unsigned int ir = 0; ir < m_eclipsed_stack_array.size(); ir++) {
2345 if (piqp->dbIndex == m_eclipsed_stack_array[ir]) {
2350 if (!b_noadd) m_eclipsed_stack_array.push_back(piqp->dbIndex);
2352 m_PatchList.DeleteNode(pcinode);
2371 m_parent->EnablePaint(
false);
2378 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2380 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2381 if (!ChartData->IsChartLocked(pqc->dbIndex))
2382 ChartData->LockCacheChart(pqc->dbIndex);
2387 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2389 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2390 if (!ChartData->IsChartLocked(pqc->dbIndex))
2391 ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
true);
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 pqc->b_locked =
true;
2406 pqc->b_locked = ChartData->LockCacheChart(pqc->dbIndex);
2411 for (ir = 0; ir < m_pcandidate_array->GetCount(); ir++) {
2413 if ((pqc->b_include) && (!pqc->b_eclipsed)) {
2419 if (ChartData->OpenChartFromDBAndLock(pqc->dbIndex, FULL_INIT,
2421 pqc->b_locked =
true;
2426 m_parent->EnablePaint(
true);
2429 m_last_index_array = m_index_array;
2431 m_index_array.clear();
2434 unsigned int kl = m_PatchList.GetCount();
2435 for (
unsigned int k = 0; k < kl; k++) {
2436 wxPatchListNode *cnode = m_PatchList.Item((kl - k) - 1);
2437 m_index_array.push_back(cnode->GetData()->dbIndex);
2438 cnode = cnode->GetNext();
2444 m_quilt_depth_unit = _T(
"");
2445 ChartBase *pc = ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
2447 m_quilt_depth_unit = pc->GetDepthUnits();
2449 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2450 int units = ps52plib->m_nDepthUnitDisplay;
2453 m_quilt_depth_unit = _T(
"Feet");
2456 m_quilt_depth_unit = _T(
"Meters");
2459 m_quilt_depth_unit = _T(
"Fathoms");
2465 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2466 wxPatchListNode *pnode = m_PatchList.Item(k);
2472 ChartBase *pc = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2474 wxString du = pc->GetDepthUnits();
2475 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2476 int units = ps52plib->m_nDepthUnitDisplay;
2489 wxString dul = du.Lower();
2490 wxString ml = m_quilt_depth_unit.Lower();
2494 if (dul.StartsWith(_T(
"meters")) && ml.StartsWith(_T(
"meters")))
2496 else if (dul.StartsWith(_T(
"metres")) && ml.StartsWith(_T(
"metres")))
2498 else if (dul.StartsWith(_T(
"fathoms")) && ml.StartsWith(_T(
"fathoms")))
2500 else if (dul.StartsWith(_T(
"met")) && ml.StartsWith(_T(
"met")))
2504 m_quilt_depth_unit = _T(
"");
2514 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2515 wxPatchListNode *pnode = m_PatchList.Item(k);
2519 if (!ChartData->IsChartInCache(pqp->dbIndex)) {
2520 wxLogMessage(_T(
" Quilt Compose cache miss..."));
2521 ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2522 if (!ChartData->IsChartInCache(pqp->dbIndex)) {
2523 wxLogMessage(_T(
" Oops, removing from quilt..."));
2524 pqp->b_Valid =
false;
2531 if (!ChartData->IsChartInCache(m_refchart_dbIndex))
2532 ChartData->OpenChartFromDB(m_refchart_dbIndex, FULL_INIT);
2538 m_bquilt_has_overlays =
false;
2539 m_max_error_factor = 0.;
2540 for (
unsigned int k = 0; k < m_PatchList.GetCount(); k++) {
2541 wxPatchListNode *pnode = m_PatchList.Item(k);
2547 ChartBase *pc = ChartData->OpenChartFromDB(pqp->dbIndex, FULL_INIT);
2549 m_max_error_factor =
2550 wxMax(m_max_error_factor, pc->GetChart_Error_Factor());
2551 if (pc->GetChartFamily() == CHART_FAMILY_VECTOR) {
2552 bool isOverlay = IsChartS57Overlay(pqp->dbIndex);
2553 pqp->b_overlay = isOverlay;
2554 if (isOverlay) m_bquilt_has_overlays =
true;
2563 ChartData->LockCache();
2567 unsigned long xa_hash = 5381;
2568 for (
unsigned int im = 0; im < m_extended_stack_array.size(); im++) {
2569 int dbindex = m_extended_stack_array[im];
2570 xa_hash = ((xa_hash << 5) + xa_hash) + dbindex;
2573 m_xa_hash = xa_hash;
2582 if (!m_bcomposed)
return;
2586 if (GetnCharts() && !m_bbusy && !chart_region.Empty()) {
2592 if (!(chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2593 vp.b_MercatorProjectionOverride)) {
2597 chart_region, pqp->ActiveRegion, chart->GetNativeScale());
2598 if (!get_screen_region.Empty())
2599 rendered_region.Union(get_screen_region);
2602 chart = GetNextChart();
2606 m_rendered_region = rendered_region;
2611bool Quilt::RenderQuiltRegionViewOnDCNoText(wxMemoryDC &dc,
ViewPort &vp,
2613 return DoRenderQuiltRegionViewOnDC(dc, vp, chart_region);
2616bool Quilt::RenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
2618 return DoRenderQuiltRegionViewOnDCTextOnly(dc, vp, chart_region);
2621bool Quilt::DoRenderQuiltRegionViewOnDC(wxMemoryDC &dc,
ViewPort &vp,
2623#ifdef ocpnUSE_DIBSECTION
2629 if (!m_bcomposed)
return false;
2633 if (GetnCharts() && !m_bbusy) {
2641 int chartsDrawn = 0;
2643 if (!chart_region.Empty()) {
2645 bool okToRender =
true;
2647 if (chart->GetChartProjectionType() != PROJECTION_MERCATOR &&
2648 vp.b_MercatorProjectionOverride)
2652 chart = GetNextChart();
2657 bool b_chart_rendered =
false;
2658 LLRegion get_region = pqp->ActiveRegion;
2661 chart_region, get_region, chart->GetNativeScale());
2662 if (!get_screen_region.Empty()) {
2663 if (!pqp->b_overlay) {
2664 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
2666 chart->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2670 if (Chs57->m_RAZBuilt) {
2671 b_chart_rendered = Chs57->RenderRegionViewOnDCNoText(
2672 tmp_dc, vp, get_screen_region);
2678 b_chart_rendered = ChPI->RenderRegionViewOnDCNoText(
2679 tmp_dc, vp, get_screen_region);
2681 b_chart_rendered = chart->RenderRegionViewOnDC(
2682 tmp_dc, vp, get_screen_region);
2684 b_chart_rendered =
true;
2691 screen_region.Subtract(get_screen_region);
2696 while (upd.HaveRects()) {
2697 wxRect rect = upd.GetRect();
2698 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc, rect.x,
2699 rect.y, wxCOPY,
true);
2703 tmp_dc.SelectObject(wxNullBitmap);
2705 if (b_chart_rendered) rendered_region.Union(get_screen_region);
2709 chart = GetNextChart();
2713 if (!chartsDrawn) m_parent->GetVP().SetProjectionType(PROJECTION_MERCATOR);
2716 if (m_bquilt_has_overlays && !chart_region.Empty()) {
2717 chart = GetFirstChart();
2721 if (pqp->b_overlay) {
2722 LLRegion get_region = pqp->ActiveRegion;
2724 chart_region, get_region, chart->GetNativeScale());
2725 if (!get_region.Empty()) {
2728 Chs57->RenderOverlayRegionViewOnDC(tmp_dc, vp,
2734 ChPI->RenderRegionViewOnDC(tmp_dc, vp, get_screen_region);
2739 while (upd.HaveRects()) {
2740 wxRect rect = upd.GetRect();
2741 dc.Blit(rect.x, rect.y, rect.width, rect.height, &tmp_dc,
2742 rect.x, rect.y, wxCOPY,
true);
2745 tmp_dc.SelectObject(wxNullBitmap);
2750 chart = GetNextChart();
2757 while (clrit.HaveRects()) {
2758 wxRect rect = clrit.GetRect();
2760 dc.SetPen(*wxBLACK_PEN);
2761 dc.SetBrush(*wxBLACK_BRUSH);
2762 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
2764 dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y,
2771 if (m_nHiLiteIndex >= 0) {
2774 wxRect box = hiregion.GetBox();
2776 if (!box.IsEmpty()) {
2779 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2780 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2787 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2791 q_dc.SelectObject(*m_pBM);
2792 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2793 q_dc.SelectObject(wxNullBitmap);
2798 wxBitmap hl_mask_bm(vp.rv_rect.width, vp.rv_rect.height, 1);
2800 mdc.SelectObject(hl_mask_bm);
2801 mdc.SetBackground(*wxBLACK_BRUSH);
2803 mdc.SetClippingRegion(box);
2804 mdc.SetBackground(*wxWHITE_BRUSH);
2806 mdc.SelectObject(wxNullBitmap);
2808 if (hl_mask_bm.IsOk()) {
2809 wxMask *phl_mask =
new wxMask(hl_mask_bm);
2810 m_pBM->SetMask(phl_mask);
2811 q_dc.SelectObject(*m_pBM);
2814 wxBitmap rbm(vp.rv_rect.width, vp.rv_rect.height);
2815 wxMask *pr_mask =
new wxMask(hl_mask_bm);
2817 rbm.SetMask(pr_mask);
2818 rdc.SelectObject(rbm);
2819 unsigned char hlcolor = 255;
2820 switch (global_color_scheme) {
2821 case GLOBAL_COLOR_SCHEME_DAY:
2824 case GLOBAL_COLOR_SCHEME_DUSK:
2827 case GLOBAL_COLOR_SCHEME_NIGHT:
2835 rdc.SetBackground(wxBrush(wxColour(hlcolor, 0, 0)));
2839 while (upd.HaveRects()) {
2840 wxRect rect = upd.GetRect();
2841 rdc.Blit(rect.x, rect.y, rect.width, rect.height, &q_dc, rect.x,
2842 rect.y, wxOR,
true);
2847 while (updq.HaveRects()) {
2848 wxRect rect = updq.GetRect();
2849 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &rdc, rect.x,
2850 rect.y, wxCOPY,
true);
2854 q_dc.SelectObject(wxNullBitmap);
2855 m_pBM->SetMask(NULL);
2858 dc.SelectObject(*m_pBM);
2861 rdc.SelectObject(wxNullBitmap);
2867 if (g_fog_overzoom) {
2870 if (scale_factor > g_overzoom_emphasis_base) {
2871 float fog = ((scale_factor - g_overzoom_emphasis_base) * 255.) / 20.;
2872 fog = wxMin(fog, 200.);
2876 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2877 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2884 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2888 q_dc.SelectObject(*m_pBM);
2889 q_dc.Blit(0, 0, vp.rv_rect.width, vp.rv_rect.height, &dc, 0, 0);
2890 q_dc.SelectObject(wxNullBitmap);
2892 wxImage src = m_pBM->ConvertToImage();
2895 wxMin((scale_factor - g_overzoom_emphasis_base) / 4, 4);
2897 wxImage dest = src.Blur(blur_factor);
2901 unsigned char *bg = src.GetData();
2902 wxColour color = m_parent->GetFogColor();
2904 float transparency = fog;
2907 wxImage dest(vp.rv_rect.width, vp.rv_rect.height);
2908 unsigned char *dest_data = (
unsigned char *) malloc( vp.rv_rect.width * vp.rv_rect.height * 3 *
sizeof(
unsigned char) );
2909 unsigned char *d = dest_data;
2911 float alpha = 1.0 - (float)transparency / 255.0;
2912 int sb = vp.rv_rect.width * vp.rv_rect.height;
2913 for(
int i = 0; i < sb; i++ ) {
2916 int r = ( ( *bg++ ) * a ) + (1.0-a) * color.Red();
2918 int g = ( ( *bg++ ) * a ) + (1.0-a) * color.Green();
2920 int b = ( ( *bg++ ) * a ) + (1.0-a) * color.Blue();
2924 dest.SetData( dest_data );
2929 ddc.SelectObject(dim);
2931 q_dc.SelectObject(*m_pBM);
2933 while (upd.HaveRects()) {
2934 wxRect rect = upd.GetRect();
2935 q_dc.Blit(rect.x, rect.y, rect.width, rect.height, &ddc, rect.x,
2940 ddc.SelectObject(wxNullBitmap);
2941 q_dc.SelectObject(wxNullBitmap);
2944 dc.SelectObject(*m_pBM);
2952 SubstituteClearDC(dc, vp);
2956 SubstituteClearDC(dc, vp);
2960 m_rendered_region = rendered_region;
2966void Quilt::SubstituteClearDC(wxMemoryDC &dc,
ViewPort &vp) {
2968 if ((m_pBM->GetWidth() != vp.rv_rect.width) ||
2969 (m_pBM->GetHeight() != vp.rv_rect.height)) {
2975 if (NULL == m_pBM) {
2976 m_pBM =
new wxBitmap(vp.rv_rect.width, vp.rv_rect.height);
2979 dc.SelectObject(wxNullBitmap);
2980 dc.SelectObject(*m_pBM);
2981 dc.SetBackground(*wxBLACK_BRUSH);
2983 m_covered_region.Clear();
2986bool Quilt::DoRenderQuiltRegionViewOnDCTextOnly(wxMemoryDC &dc,
ViewPort &vp,
2988 if (!m_bcomposed)
return false;
2992 if (GetnCharts() && !m_bbusy) {
2997 ChartBase *chart = GetLargestScaleChart();
3004 Chs57->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3008 ChPI->RenderRegionViewOnDCTextOnly(dc, vp, chart_region);
3013 chart = GetNextSmallerScaleChart();
3017 SubstituteClearDC(dc, vp);
Base class for all chart types.
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)
Represents the view port for chart display in OpenCPN.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
double rotation
Rotation angle of the viewport in radians.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
OCPNRegion GetVPRegionIntersect(const OCPNRegion ®ion, const LLRegion &llregion, int chart_native_scale)
Get the intersection of the viewport with a given region.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents an S57 format electronic navigational chart in OpenCPN.
Represents an entry in the chart table, containing information about a single chart.