36#include <wx/wfstream.h>
37#include <wx/tokenzr.h>
38#include <wx/filename.h>
40#include <wx/fileconf.h>
46#include "ocpn_pixel.h"
53#define OCPN_USE_CONFIG 1
57struct sigaction sa_all_chart;
58struct sigaction sa_all_previous;
62void catch_signals_chart(
int signo) {
65 siglongjmp(env_chart, 1);
77typedef __int32 int32_t;
78typedef unsigned __int32 uint32_t;
79typedef __int64 int64_t;
80typedef unsigned __int64 uint64_t;
92bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
102ThumbData::ThumbData() { pDIBThumb = NULL; }
104ThumbData::~ThumbData() {
delete pDIBThumb; }
109opncpnPalette::opncpnPalette() {
113 FwdPalette = (
int *)malloc(
sizeof(
int));
114 RevPalette = (
int *)malloc(
sizeof(
int));
119opncpnPalette::~opncpnPalette() {
120 if (NULL != FwdPalette) free(FwdPalette);
121 if (NULL != RevPalette) free(RevPalette);
127ChartBase::ChartBase() {
128 m_depth_unit_id = DEPTH_UNIT_UNKNOWN;
132 m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB;
134 bReadyToRender =
false;
136 Chart_Error_Factor = 0;
138 m_Chart_Scale = 10000;
143 m_pCOVRTablePoints = NULL;
145 m_nNoCOVREntries = 0;
146 m_pNoCOVRTable = NULL;
147 m_pNoCOVRTablePoints = NULL;
149 m_EdDate = wxInvalidDateTime;
151 m_lon_datum_adjust = 0.;
152 m_lat_datum_adjust = 0.;
154 m_projection = PROJECTION_MERCATOR;
157ChartBase::~ChartBase() {
162 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++)
163 free(m_pCOVRTable[j]);
166 free(m_pCOVRTablePoints);
170 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++)
171 free(m_pNoCOVRTable[j]);
173 free(m_pNoCOVRTable);
174 free(m_pNoCOVRTablePoints);
177wxString ChartBase::GetHashKey()
const {
178 wxString key = GetFullPath();
179 wxChar separator = wxFileName::GetPathSeparator();
180 for (
unsigned int pos = 0; pos < key.size(); pos = key.find(separator, pos))
181 key.replace(pos, 1,
"!");
196ChartDummy::ChartDummy() {
198 m_ChartType = CHART_TYPE_DUMMY;
199 m_ChartFamily = CHART_FAMILY_UNKNOWN;
200 m_Chart_Scale = 22000000;
202 m_FullPath =
"No Chart Available";
203 m_Description = m_FullPath;
206ChartDummy::~ChartDummy() {
delete m_pBM; }
208InitReturn ChartDummy::Init(
const wxString &name, ChartInitFlag init_flags) {
212void ChartDummy::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {}
214ThumbData *ChartDummy::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
218bool ChartDummy::UpdateThumbData(
double lat,
double lon) {
return FALSE; }
220bool ChartDummy::GetChartExtent(
Extent *pext) {
229bool ChartDummy::RenderRegionViewOnGL(
const wxGLContext &glc,
232 const LLRegion &Region) {
236bool ChartDummy::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
238 return RenderViewOnDC(dc, VPoint);
241bool ChartDummy::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
242 if (m_pBM && m_pBM->IsOk()) {
243 if ((m_pBM->GetWidth() != VPoint.
pix_width) ||
257 dc.SelectObject(*m_pBM);
259 dc.SetBackground(*wxBLACK_BRUSH);
270void ChartDummy::GetValidCanvasRegion(
const ViewPort &VPoint,
272 pValidRegion->Clear();
273 pValidRegion->Union(0, 0, 1, 1);
276LLRegion ChartDummy::GetValidRegion() {
return LLRegion(); }
281ChartGEO::ChartGEO() { m_ChartType = CHART_TYPE_GEO; }
283ChartGEO::~ChartGEO() {}
285InitReturn ChartGEO::Init(
const wxString &name, ChartInitFlag init_flags) {
286#define BUF_LEN_MAX 4096
288 PreInit(name, init_flags, GLOBAL_COLOR_SCHEME_DAY);
290 char buffer[BUF_LEN_MAX];
293 new wxFFileInputStream(name);
295 m_filesize = wxFileName::GetSize(name);
297 if (!ifs_hdr->IsOk())
return INIT_FAIL_REMOVE;
303 m_Description = m_FullPath;
305 wxFileName GEOFile(m_FullPath);
308 Path = GEOFile.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME);
312 ifs_hdr->SeekI(0, wxFromStart);
316 while ((ReadBSBHdrLine(ifs_hdr, &buffer[0], BUF_LEN_MAX)) != 0) {
317 wxString str_buf(buffer, wxConvUTF8);
318 if (!strncmp(buffer,
"Bitmap", 6)) {
319 wxStringTokenizer tkz(str_buf,
"=");
320 wxString token = tkz.GetNextToken();
321 if (token.IsSameAs(
"Bitmap", TRUE)) {
322 pBitmapFilePath =
new wxString();
325 i = tkz.GetPosition();
326 pBitmapFilePath->Clear();
328 pBitmapFilePath->Append(buffer[i]);
334 else if (!strncmp(buffer,
"Scale", 5)) {
335 wxStringTokenizer tkz(str_buf,
"=");
336 wxString token = tkz.GetNextToken();
337 if (token.IsSameAs(
"Scale", TRUE))
340 i = tkz.GetPosition();
341 m_Chart_Scale = atoi(&buffer[i]);
345 else if (!strncmp(buffer,
"Depth", 5)) {
346 wxStringTokenizer tkz(str_buf,
"=");
347 wxString token = tkz.GetNextToken();
348 if (token.IsSameAs(
"Depth Units", FALSE))
351 i = tkz.GetPosition();
352 wxString str(&buffer[i], wxConvUTF8);
353 m_DepthUnits = str.Trim();
357 else if (!strncmp(buffer,
"Point", 5))
361 sscanf(&buffer[0],
"Point%d=%f %f %d %d", &i, &lnr, <r, &yr, &xr);
364 pRefTable[nRefpoint].xr = xr;
365 pRefTable[nRefpoint].yr = yr;
366 pRefTable[nRefpoint].latr = ltr;
367 pRefTable[nRefpoint].lonr = lnr;
368 pRefTable[nRefpoint].bXValid = 1;
369 pRefTable[nRefpoint].bYValid = 1;
375 else if (!strncmp(buffer,
"Vertex", 6)) {
378 sscanf(buffer,
"Vertex%d=%f %f", &i, <p, &lnp);
382 if (NULL == pPlyTable) {
386 pPlyTable[nPlypoint].ltp = ltp;
387 pPlyTable[nPlypoint].lnp = lnp;
392 else if (!strncmp(buffer,
"Date Pub", 8)) {
393 char date_string[40];
395 sscanf(buffer,
"Date Published=%s\r\n", &date_string[0]);
396 wxString date_wxstr(date_string, wxConvUTF8);
398 if (dt.ParseDate(date_wxstr))
400 sprintf(date_buf,
"%d", dt.GetYear());
402 sscanf(date_string,
"%s", date_buf);
404 m_PubYear = wxString(date_buf, wxConvUTF8);
407 else if (!strncmp(buffer,
"Skew", 4)) {
408 wxStringTokenizer tkz(str_buf,
"=");
409 wxString token = tkz.GetNextToken();
410 if (token.IsSameAs(
"Skew Angle", FALSE))
413 i = tkz.GetPosition();
415 sscanf(&buffer[i],
"%f,", &fcs);
420 else if (!strncmp(buffer,
"Latitude Offset", 15)) {
421 wxStringTokenizer tkz(str_buf,
"=");
422 wxString token = tkz.GetNextToken();
423 if (token.IsSameAs(
"Latitude Offset", FALSE)) {
425 i = tkz.GetPosition();
427 sscanf(&buffer[i],
"%f,", <o);
432 else if (!strncmp(buffer,
"Longitude Offset", 16)) {
433 wxStringTokenizer tkz(str_buf,
"=");
434 wxString token = tkz.GetNextToken();
435 if (token.IsSameAs(
"Longitude Offset", FALSE)) {
437 i = tkz.GetPosition();
439 sscanf(&buffer[i],
"%f,", &lno);
444 else if (!strncmp(buffer,
"Datum", 5)) {
445 wxStringTokenizer tkz(str_buf,
"=");
446 wxString token = tkz.GetNextToken();
447 if (token.IsSameAs(
"Datum", FALSE)) {
448 token = tkz.GetNextToken();
453 else if (!strncmp(buffer,
"Name", 4)) {
454 wxStringTokenizer tkz(str_buf,
"=");
455 wxString token = tkz.GetNextToken();
456 if (token.IsSameAs(
"Name", FALSE))
459 i = tkz.GetPosition();
461 while (isprint(buffer[i]) && (i < 80)) m_Name.Append(buffer[i++]);
473 if (pBitmapFilePath == NULL) {
475 return INIT_FAIL_REMOVE;
478 wxString NOS_Name(*pBitmapFilePath);
480 wxDir target_dir(Path);
481 wxArrayString file_array;
482 int nfiles = wxDir::GetAllFiles(Path, &file_array);
485 pBitmapFilePath->Prepend(Path);
487 wxFileName NOS_filename(*pBitmapFilePath);
488 if (!NOS_filename.FileExists()) {
492 wxString fname(NOS_filename.GetName());
493 wxString fext(NOS_filename.GetExt());
499 NOS_filename.SetName(fname);
500 NOS_filename.SetExt(fext);
502 if (NOS_filename.FileExists())
goto found_uclc_file;
507 NOS_filename.SetName(fname);
508 NOS_filename.SetExt(fext);
510 if (NOS_filename.FileExists())
goto found_uclc_file;
515 NOS_filename.SetName(fname);
516 NOS_filename.SetExt(fext);
518 if (NOS_filename.FileExists())
goto found_uclc_file;
523 NOS_filename.SetName(fname);
524 NOS_filename.SetExt(fext);
526 if (NOS_filename.FileExists())
goto found_uclc_file;
530 for (ifile = 0; ifile < nfiles; ifile++) {
531 wxString file_up = file_array[ifile];
534 wxString target_up = *pBitmapFilePath;
535 target_up.MakeUpper();
537 if (file_up.IsSameAs(target_up)) {
538 NOS_filename.Clear();
539 NOS_filename.Assign(file_array[ifile]);
540 goto found_uclc_file;
545 return INIT_FAIL_REMOVE;
549 delete pBitmapFilePath;
550 pBitmapFilePath =
new wxString(NOS_filename.GetFullPath());
553 new wxFFileInputStream(*pBitmapFilePath);
554 ifs_bitmap =
new wxBufferedInputStream(*ifss_bitmap);
556 if (!ifss_bitmap->IsOk()) {
558 return INIT_FAIL_REMOVE;
561 while ((ReadBSBHdrLine(ifss_bitmap, &buffer[0], BUF_LEN_MAX)) != 0) {
562 wxString str_buf(buffer, wxConvUTF8);
564 if (!strncmp(buffer,
"NOS", 3)) {
565 wxStringTokenizer tkz(str_buf,
",=");
566 while (tkz.HasMoreTokens()) {
567 wxString token = tkz.GetNextToken();
568 if (token.IsSameAs(
"RA", TRUE))
573 i = tkz.GetPosition();
574 Size_X = atoi(&buffer[i]);
575 wxString token = tkz.GetNextToken();
576 i = tkz.GetPosition();
577 Size_Y = atoi(&buffer[i]);
578 }
else if (token.IsSameAs(
"DU", TRUE))
580 token = tkz.GetNextToken();
582 if (token.ToLong(&temp_du)) m_Chart_DU = temp_du;
588 else if (!strncmp(buffer,
"RGB", 3))
589 CreatePaletteEntry(buffer, COLOR_RGB_DEFAULT);
591 else if (!strncmp(buffer,
"DAY", 3))
592 CreatePaletteEntry(buffer, DAY);
594 else if (!strncmp(buffer,
"DSK", 3))
595 CreatePaletteEntry(buffer, DUSK);
597 else if (!strncmp(buffer,
"NGT", 3))
598 CreatePaletteEntry(buffer, NIGHT);
600 else if (!strncmp(buffer,
"NGR", 3))
601 CreatePaletteEntry(buffer, NIGHTRED);
603 else if (!strncmp(buffer,
"GRY", 3))
604 CreatePaletteEntry(buffer, GRAY);
606 else if (!strncmp(buffer,
"PRC", 3))
607 CreatePaletteEntry(buffer, PRC);
609 else if (!strncmp(buffer,
"PRG", 3))
610 CreatePaletteEntry(buffer, PRG);
614 if (Size_X <= 0 || Size_Y <= 0) {
616 return INIT_FAIL_REMOVE;
620 wxString msg(
" Chart File contains less than 3 PLY points: ");
621 msg.Append(m_FullPath);
625 return INIT_FAIL_REMOVE;
628 if (m_datum_str.IsEmpty()) {
629 wxString msg(
" Chart datum not specified on chart ");
630 msg.Append(m_FullPath);
632 wxLogMessage(
" Default datum (WGS84) substituted.");
637 strncpy(d_str, m_datum_str.mb_str(), 99);
640 int datum_index = GetDatumIndex(d_str);
642 if (datum_index < 0) {
643 wxString msg(
" Chart datum {");
645 msg +=
"} invalid on chart ";
646 msg.Append(m_FullPath);
648 wxLogMessage(
" Default datum (WGS84) substituted.");
650 datum_index = DATUM_INDEX_WGS84;
652 m_datum_index = datum_index;
657 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
658 *m_pCOVRTablePoints = nPlypoint;
659 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
660 *m_pCOVRTable = (
float *)malloc(nPlypoint * 2 *
sizeof(
float));
661 memcpy(*m_pCOVRTable, pPlyTable, nPlypoint * 2 *
sizeof(
float));
665 if (!SetMinMax())
return INIT_FAIL_REMOVE;
669 if (init_flags == HEADER_ONLY)
return INIT_OK;
673 if ((c = ifs_bitmap->GetC()) != 0x1a) {
674 return INIT_FAIL_REMOVE;
676 if ((c = ifs_bitmap->GetC()) == 0x0d) {
677 if ((c = ifs_bitmap->GetC()) != 0x0a) {
678 return INIT_FAIL_REMOVE;
680 if ((c = ifs_bitmap->GetC()) != 0x1a) {
681 return INIT_FAIL_REMOVE;
683 if ((c = ifs_bitmap->GetC()) != 0x00) {
684 return INIT_FAIL_REMOVE;
688 else if (c != 0x00) {
689 return INIT_FAIL_REMOVE;
693 nColorSize = ifs_bitmap->GetC();
694 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
695 wxString msg(
" Invalid nColorSize data, corrupt on chart ");
696 msg.Append(m_FullPath);
698 return INIT_FAIL_REMOVE;
702 InitReturn pi_ret = PostInit();
703 if (pi_ret != INIT_OK)
713ChartKAP::ChartKAP() { m_ChartType = CHART_TYPE_KAP; }
715ChartKAP::~ChartKAP() {}
717InitReturn ChartKAP::Init(
const wxString &name, ChartInitFlag init_flags) {
718#define BUF_LEN_MAX 4096
720 ifs_hdr =
new ChartDataNonSeekableInputStream(
723 if (!ifs_hdr->IsOk())
return INIT_FAIL_REMOVE;
728 PreInit(name, init_flags, GLOBAL_COLOR_SCHEME_DAY);
730 char buffer[BUF_LEN_MAX];
733 m_Description = m_FullPath;
736 for (
int icl = 0; icl < 12; icl++) {
746 unsigned int TestBlockSize = 1999;
747 ifs_hdr->Read(buffer, TestBlockSize);
749 if (ifs_hdr->LastRead() != TestBlockSize) {
751 msg.Printf(
" Could not read first %d bytes of header for chart file: ",
756 return INIT_FAIL_REMOVE;
760 for (i = 0; i < TestBlockSize - 4; i++) {
762 if (buffer[i + 0] ==
'B' && buffer[i + 1] ==
'S' && buffer[i + 2] ==
'B' &&
763 buffer[i + 3] ==
'/')
767 if (buffer[i + 0] ==
'N' && buffer[i + 1] ==
'O' && buffer[i + 2] ==
'S' &&
768 buffer[i + 3] ==
'/')
771 if (i == TestBlockSize - 4) {
772 wxString msg(
" Chart file has no BSB header, cannot Init.");
776 return INIT_FAIL_REMOVE;
780 ifs_hdr->SeekI(0, wxFromStart);
784 int done_header_parse = 0;
785 wxCSConv iso_conv(
"ISO-8859-1");
787 while (done_header_parse == 0) {
788 if (ReadBSBHdrLine(ifs_hdr, buffer, BUF_LEN_MAX) == 0) {
794 done_header_parse = 1;
797 return INIT_FAIL_REMOVE;
803 wxString str_buf(buffer, wxConvUTF8);
805 str_buf = wxString(buffer, iso_conv);
807 if (str_buf.Find(
"SHOM") != wxNOT_FOUND) m_b_SHOM =
true;
809 if (!strncmp(buffer,
"BSB", 3)) {
810 wxString clip_str_buf(
813 wxStringTokenizer tkz(clip_str_buf,
"/,=");
814 while (tkz.HasMoreTokens()) {
815 wxString token = tkz.GetNextToken();
816 if (token.IsSameAs(
"RA", TRUE))
819 i = tkz.GetPosition();
820 Size_X = atoi(&buffer[i]);
821 wxString token = tkz.GetNextToken();
822 i = tkz.GetPosition();
823 Size_Y = atoi(&buffer[i]);
824 }
else if (token.IsSameAs(
"NA", TRUE))
826 int i = tkz.GetPosition();
829 while ((buffer[i] !=
',') && (i < 80)) nbuf[j++] = buffer[i++];
831 wxString n_str(nbuf, iso_conv);
833 }
else if (token.IsSameAs(
"NU", TRUE))
835 int i = tkz.GetPosition();
838 while ((buffer[i] !=
',') && (i < 80)) nbuf[j++] = buffer[i++];
840 wxString n_str(nbuf, iso_conv);
842 }
else if (token.IsSameAs(
"DU", TRUE))
844 token = tkz.GetNextToken();
846 if (token.ToLong(&temp_du)) m_Chart_DU = temp_du;
851 else if (!strncmp(buffer,
"KNP", 3)) {
852 wxString conv_buf(buffer, iso_conv);
853 wxStringTokenizer tkz(conv_buf,
"/,=");
854 while (tkz.HasMoreTokens()) {
855 wxString token = tkz.GetNextToken();
856 if (token.IsSameAs(
"SC", TRUE))
859 i = tkz.GetPosition();
860 m_Chart_Scale = atoi(&buffer[i]);
861 if (0 == m_Chart_Scale) m_Chart_Scale = 100000000;
862 }
else if (token.IsSameAs(
"SK", TRUE))
865 i = tkz.GetPosition();
867 sscanf(&buffer[i],
"%f,", &fcs);
869 }
else if (token.IsSameAs(
"UN", TRUE))
872 i = tkz.GetPosition();
873 wxString str(&buffer[i], iso_conv);
874 m_DepthUnits = str.BeforeFirst(
',');
875 }
else if (token.IsSameAs(
"GD", TRUE))
878 i = tkz.GetPosition();
879 wxString str(&buffer[i], iso_conv);
880 m_datum_str = str.BeforeFirst(
',').Trim();
881 }
else if (token.IsSameAs(
"SD", TRUE))
884 i = tkz.GetPosition();
885 wxString str(&buffer[i], iso_conv);
886 m_SoundingsDatum = str.BeforeFirst(
',').Trim();
887 }
else if (token.IsSameAs(
"PP",
891 i = tkz.GetPosition();
893 wxString str(&buffer[i], iso_conv);
894 wxString str1 = str.BeforeFirst(
',').Trim();
895 if (str1.ToDouble(&fcs)) m_proj_parameter = fcs;
896 }
else if (token.IsSameAs(
"PR", TRUE))
899 i = tkz.GetPosition();
900 wxString str(&buffer[i], iso_conv);
901 wxString stru = str.MakeUpper();
905 if (stru.Matches(
"*MERCATOR*")) {
906 m_projection = PROJECTION_MERCATOR;
910 if (stru.Matches(
"*TRANSVERSE*")) {
911 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
915 if (stru.Matches(
"*CONIC*")) {
916 m_projection = PROJECTION_POLYCONIC;
920 if (stru.Matches(
"*TM*")) {
921 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
925 if (stru.Matches(
"*GAUSS CONFORMAL*")) {
926 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
931 m_projection = PROJECTION_UNKNOWN;
932 wxString msg(
" Chart projection is ");
933 msg += tkz.GetNextToken();
934 msg +=
" which is unsupported. Disabling chart ";
938 return INIT_FAIL_REMOVE;
940 }
else if (token.IsSameAs(
945 i = tkz.GetPosition();
947 sscanf(&buffer[i],
"%f,", &x);
949 }
else if (token.IsSameAs(
954 i = tkz.GetPosition();
956 sscanf(&buffer[i],
"%f,", &x);
962 else if (!strncmp(buffer,
"RGB", 3))
963 CreatePaletteEntry(buffer, COLOR_RGB_DEFAULT);
965 else if (!strncmp(buffer,
"DAY", 3))
966 CreatePaletteEntry(buffer, DAY);
968 else if (!strncmp(buffer,
"DSK", 3))
969 CreatePaletteEntry(buffer, DUSK);
971 else if (!strncmp(buffer,
"NGT", 3))
972 CreatePaletteEntry(buffer, NIGHT);
974 else if (!strncmp(buffer,
"NGR", 3))
975 CreatePaletteEntry(buffer, NIGHTRED);
977 else if (!strncmp(buffer,
"GRY", 3))
978 CreatePaletteEntry(buffer, GRAY);
980 else if (!strncmp(buffer,
"PRC", 3))
981 CreatePaletteEntry(buffer, PRC);
983 else if (!strncmp(buffer,
"PRG", 3))
984 CreatePaletteEntry(buffer, PRG);
986 else if (!strncmp(buffer,
"REF", 3)) {
989 sscanf(&buffer[4],
"%d,%d,%d,%f,%f", &i, &xr, &yr, <r, &lnr);
992 pRefTable[nRefpoint].xr = xr;
993 pRefTable[nRefpoint].yr = yr;
994 pRefTable[nRefpoint].latr = ltr;
995 pRefTable[nRefpoint].lonr = lnr;
996 pRefTable[nRefpoint].bXValid = 1;
997 pRefTable[nRefpoint].bYValid = 1;
1003 else if (!strncmp(buffer,
"WPX", 3)) {
1006 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1007 wxString token = tkz.GetNextToken();
1009 if (token.ToLong((
long int *)&wpx_type)) {
1010 while (tkz.HasMoreTokens() && (idx < 12)) {
1011 token = tkz.GetNextToken();
1012 if (token.ToDouble(&d)) {
1021 else if (!strncmp(buffer,
"WPY", 3)) {
1024 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1025 wxString token = tkz.GetNextToken();
1027 if (token.ToLong((
long int *)&wpy_type)) {
1028 while (tkz.HasMoreTokens() && (idx < 12)) {
1029 token = tkz.GetNextToken();
1030 if (token.ToDouble(&d)) {
1039 else if (!strncmp(buffer,
"PWX", 3)) {
1042 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1043 wxString token = tkz.GetNextToken();
1045 if (token.ToLong((
long int *)&pwx_type)) {
1046 while (tkz.HasMoreTokens() && (idx < 12)) {
1047 token = tkz.GetNextToken();
1048 if (token.ToDouble(&d)) {
1057 else if (!strncmp(buffer,
"PWY", 3)) {
1060 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1061 wxString token = tkz.GetNextToken();
1063 if (token.ToLong((
long int *)&pwy_type)) {
1064 while (tkz.HasMoreTokens() && (idx < 12)) {
1065 token = tkz.GetNextToken();
1066 if (token.ToDouble(&d)) {
1075 else if (!strncmp(buffer,
"CPH", 3)) {
1077 sscanf(&buffer[4],
"%f", &float_cph);
1081 else if (!strncmp(buffer,
"VER", 3)) {
1082 wxStringTokenizer tkz(str_buf,
"/,=");
1083 wxString token = tkz.GetNextToken();
1085 m_bsb_ver = tkz.GetNextToken();
1088 else if (!strncmp(buffer,
"DTM", 3)) {
1090 wxStringTokenizer tkz(str_buf,
"/,=");
1091 wxString token = tkz.GetNextToken();
1093 token = tkz.GetNextToken();
1094 if (token.ToDouble(&val)) m_dtm_lat = val;
1096 token = tkz.GetNextToken();
1097 if (token.ToDouble(&val)) m_dtm_lon = val;
1105 else if (!strncmp(buffer,
"PLY", 3)) {
1108 if (sscanf(&buffer[4],
"%d,%f,%f", &i, <p, &lnp) != 3) {
1110 return INIT_FAIL_REMOVE;
1115 if (NULL == pPlyTable) {
1119 pPlyTable[nPlypoint].ltp = ltp;
1120 pPlyTable[nPlypoint].lnp = lnp;
1123 if (NULL == pPlyTable || nPlypoint > 1000000) {
1130 else if (!strncmp(buffer,
"CED", 3)) {
1131 wxStringTokenizer tkz(str_buf,
"/,=");
1132 while (tkz.HasMoreTokens()) {
1133 wxString token = tkz.GetNextToken();
1134 if (token.IsSameAs(
"ED", TRUE))
1137 i = tkz.GetPosition();
1139 char date_string[40];
1143 sscanf(&buffer[i],
"%s\r\n", date_string);
1144 wxString date_wxstr(date_string, wxConvUTF8);
1147 if (dt.ParseDate(date_wxstr))
1158 }
else if ((iyear >= 50) && (iyear < 100)) {
1162 assert(iyear <= 9999);
1163 sprintf(date_buf,
"%d", iyear);
1168 sscanf(date_string,
"%s", date_buf);
1169 m_EdDate.Set(1, wxDateTime::Jan,
1173 m_PubYear = wxString(date_buf, wxConvUTF8);
1174 }
else if (token.IsSameAs(
"SE", TRUE))
1177 i = tkz.GetPosition();
1178 wxString str(&buffer[i], iso_conv);
1179 m_SE = str.BeforeFirst(
',');
1187 if (m_b_SHOM && (m_bsb_ver ==
"1.1")) m_b_apply_dtm =
false;
1191 if (n_pwx && n_pwy && n_pwx && n_pwy) bHaveEmbeddedGeoref =
true;
1194 if (m_projection == PROJECTION_MERCATOR)
1195 m_proj_lat = m_proj_parameter;
1196 else if (m_projection == PROJECTION_TRANSVERSE_MERCATOR)
1197 m_proj_lon = m_proj_parameter;
1198 else if (m_projection == PROJECTION_POLYCONIC)
1199 m_proj_lon = m_proj_parameter;
1203 if (m_proj_lat > 82.0 || m_proj_lat < -82.0) m_proj_lat = 0.0;
1206 if (Size_X <= 0 || Size_Y <= 0) {
1208 return INIT_FAIL_REMOVE;
1211 if (nPlypoint < 3) {
1212 wxString msg(
" Chart File contains less than 3 or too many PLY points: ");
1213 msg.Append(m_FullPath);
1216 return INIT_FAIL_REMOVE;
1219 if (m_datum_str.IsEmpty()) {
1220 wxString msg(
" Chart datum not specified on chart ");
1221 msg.Append(m_FullPath);
1223 wxLogMessage(
" Default datum (WGS84) substituted.");
1228 strncpy(d_str, m_datum_str.mb_str(), 99);
1231 int datum_index = GetDatumIndex(d_str);
1233 if (datum_index < 0) {
1234 wxString msg(
" Chart datum {");
1236 msg +=
"} invalid on chart ";
1237 msg.Append(m_FullPath);
1239 wxLogMessage(
" Default datum (WGS84) substituted.");
1251 if ((m_projection != PROJECTION_MERCATOR &&
1252 m_projection != PROJECTION_TRANSVERSE_MERCATOR) ||
1255 AnalyzeRefpoints(
false);
1264 for (
int i = 0; i < nPlypoint; i++) {
1265 m_LatMax = wxMax(m_LatMax, pPlyTable[i].ltp);
1266 m_LatMin = wxMin(m_LatMin, pPlyTable[i].ltp);
1267 m_LonMax = wxMax(m_LonMax, pPlyTable[i].lnp);
1268 m_LonMin = wxMin(m_LonMin, pPlyTable[i].lnp);
1271 int count = nPlypoint;
1273 Plypoint *pOldPlyTable = pPlyTable;
1275 double lastplylat = 0.0, lastplylon = 0.0, x1 = 0.0, y1 = 0.0, x2, y2;
1276 double plylat, plylon;
1277 for (
int i = 0; i < count + 1; i++) {
1278 plylat = pOldPlyTable[i % count].ltp;
1279 plylon = pOldPlyTable[i % count].lnp;
1280 latlong_to_chartpix(plylat, plylon, x2, y2);
1282 if (lastplylon - plylon > 180.)
1284 else if (lastplylon - plylon < -180.)
1289 ceil((fabs(lastplylat - plylat) + fabs(lastplylon - plylon)) / 2);
1290 for (
double c = 0; c < steps; c++) {
1291 double d = c / steps, lat, lon;
1293 double x = (1 - d) * x1 + d * x2, y = (1 - d) * y1 + d * y2;
1294 chartpix_to_latlong(x, y, &lat, &lon);
1295 pPlyTable = (
Plypoint *)realloc(pPlyTable,
1296 sizeof(
Plypoint) * (nPlypoint + 1));
1297 pPlyTable[nPlypoint].ltp = lat;
1298 pPlyTable[nPlypoint].lnp = lon;
1303 lastplylat = plylat, lastplylon = plylon;
1317 for (
int i = 0; i < nPlypoint; i++) {
1318 m_LonMin = wxMin(m_LonMin, pPlyTable[i].lnp);
1319 m_LonMax = wxMax(m_LonMax, pPlyTable[i].lnp);
1323 bool b_adjusted =
false;
1324 if (m_LonMax * m_LonMin < 0) {
1325 if ((m_LonMax - m_LonMin) > 180.) b_test =
false;
1329 if (!bHaveEmbeddedGeoref) {
1332 AnalyzeRefpoints(
false);
1335 bool bAdjustPly =
false;
1336 wxRect bitRect(0, 0, Size_X, Size_Y);
1338 for (
int i = 0; i < nPlypoint; i++) {
1339 double pix_x, pix_y;
1340 latlong_to_chartpix(pPlyTable[i].ltp, pPlyTable[i].lnp, pix_x, pix_y);
1341 if (!bitRect.Contains(pix_x, pix_y)) {
1344 printf(
"Adjusting COVR region on: %s\n", name.ToUTF8().data());
1350 float *points =
new float[2 * nPlypoint];
1351 for (
int i = 0; i < nPlypoint; i++)
1352 points[2 * i + 0] = pPlyTable[i].ltp,
1353 points[2 * i + 1] = pPlyTable[i].lnp;
1354 LLRegion covrRegion(nPlypoint, points);
1356 covrRegion.Intersect(GetValidRegion());
1358 if (covrRegion.contours.size()) {
1360 m_nCOVREntries = covrRegion.contours.size();
1361 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
1362 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
1363 std::list<poly_contour>::iterator it = covrRegion.contours.begin();
1364 for (
int i = 0; i < m_nCOVREntries; i++) {
1365 m_pCOVRTablePoints[i] = it->size();
1367 (
float *)malloc(m_pCOVRTablePoints[i] * 2 *
sizeof(
float));
1368 std::list<contour_pt>::iterator jt = it->begin();
1369 for (
int j = 0; j < m_pCOVRTablePoints[i]; j++) {
1370 m_pCOVRTable[i][2 * j + 0] = jt->y;
1371 m_pCOVRTable[i][2 * j + 1] = jt->x;
1383 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
1384 *m_pCOVRTablePoints = nPlypoint;
1385 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
1386 *m_pCOVRTable = (
float *)malloc(nPlypoint * 2 *
sizeof(
float));
1387 memcpy(*m_pCOVRTable, pPlyTable, nPlypoint * 2 *
sizeof(
float));
1394 strncpy(d_str, m_datum_str.mb_str(), 99);
1397 int datum_index = GetDatumIndex(d_str);
1398 m_datum_index = datum_index;
1400 if (datum_index < 0)
1401 m_ExtraInfo =
"---<<< Warning: Chart Datum may be incorrect. >>>---";
1404 m_lon_datum_adjust = (-m_dtm_lon) / 3600.;
1405 m_lat_datum_adjust = (-m_dtm_lat) / 3600.;
1409 int cnPlypoint = GetCOVRTablenPoints(0);
1411 for (
int u = 0; u < cnPlypoint; u++) {
1415 if (m_datum_index == DATUM_INDEX_WGS84 ||
1416 m_datum_index == DATUM_INDEX_UNKNOWN) {
1417 dlon = m_dtm_lon / 3600.;
1418 dlat = m_dtm_lat / 3600.;
1422 double to_lat, to_lon;
1423 MolodenskyTransform(ppp->ltp, ppp->lnp, &to_lat, &to_lon, m_datum_index,
1425 dlon = (to_lon - ppp->lnp);
1426 dlat = (to_lat - ppp->ltp);
1427 if (m_b_apply_dtm) {
1428 dlon += m_dtm_lon / 3600.;
1429 dlat += m_dtm_lat / 3600.;
1438 if (!SetMinMax())
return INIT_FAIL_REMOVE;
1442 if (init_flags == HEADER_ONLY)
return INIT_OK;
1446 bool bcorrupt =
false;
1448 if ((c = ifs_hdr->GetC()) != 0x1a) {
1451 if ((c = ifs_hdr->GetC()) == 0x0d) {
1452 if ((c = ifs_hdr->GetC()) != 0x0a) {
1455 if ((c = ifs_hdr->GetC()) != 0x1a) {
1458 if ((c = ifs_hdr->GetC()) != 0x00) {
1463 else if (c != 0x00) {
1468 wxString msg(
" Chart File RLL data corrupt on chart ");
1469 msg.Append(m_FullPath);
1472 return INIT_FAIL_REMOVE;
1476 nColorSize = ifs_hdr->GetC();
1477 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
1478 wxString msg(
" Invalid nColorSize data, corrupt on chart ");
1479 msg.Append(m_FullPath);
1481 return INIT_FAIL_REMOVE;
1484 nFileOffsetDataStart = ifs_hdr->TellI();
1488 ChartDataInputStream *stream =
1489 new ChartDataInputStream(name);
1492 tempfile = stream->TempFileName();
1494 m_filesize = wxFileName::GetSize(tempfile.empty() ? name : tempfile);
1496 ifss_bitmap = stream;
1497 ifs_bitmap =
new wxBufferedInputStream(*ifss_bitmap);
1500 InitReturn pi_ret = PostInit();
1501 if (pi_ret != INIT_OK)
return pi_ret;
1509ChartBaseBSB::ChartBaseBSB() {
1511 m_ChartFamily = CHART_FAMILY_RASTER;
1513 pBitmapFilePath = NULL;
1518 cached_image_ok = 0;
1523 bHaveEmbeddedGeoref =
false;
1530 bUseLineCache =
false;
1532 bUseLineCache =
true;
1541 m_bilinear_limit = 8;
1547 for (
int i = 0; i < N_BSB_COLORS; i++) pPalettes[i] = NULL;
1549 bGeoErrorSent =
false;
1553 m_mapped_color_index = COLOR_RGB_DEFAULT;
1555 m_datum_str =
"WGS84";
1564 m_proj_parameter = 0.;
1566 m_b_apply_dtm =
true;
1570#ifdef OCPN_USE_CONFIG
1571 wxFileConfig *pfc = (wxFileConfig *)pConfig;
1572 pfc->SetPath(_T (
"/Settings" ));
1573 pfc->Read(_T (
"DebugBSBImg" ), &m_b_cdebug, 0);
1577ChartBaseBSB::~ChartBaseBSB() {
1578 if (pBitmapFilePath)
delete pBitmapFilePath;
1580 if (pline_table) free(pline_table);
1582 if (ifs_buf) free(ifs_buf);
1604 FreeLineCacheRows();
1609 for (
int i = 0; i < N_BSB_COLORS; i++)
delete pPalettes[i];
1612void ChartBaseBSB::FreeLineCacheRows(
int start,
int end) {
1617 end = wxMin(end, Size_Y);
1618 for (
int ylc = start; ylc < end; ylc++) {
1621 free(pt->pTileOffset);
1629bool ChartBaseBSB::HaveLineCacheRow(
int row) {
1640double ChartBaseBSB::GetNormalScaleMin(
double canvas_scale_factor,
1641 bool b_allow_overzoom) {
1643 return (canvas_scale_factor / m_ppm_avg) /
1650double ChartBaseBSB::GetNormalScaleMax(
double canvas_scale_factor,
1652 return (canvas_scale_factor / m_ppm_avg) *
1658 target_scale_ppm, .01, 64.);
1663 double scale_factor_min,
1664 double scale_factor_max) {
1665 double chart_1x_scale = GetPPM();
1667 double binary_scale_factor = 1.;
1670 if (chart_1x_scale > target_scale) {
1671 double binary_scale_factor_max = 1 / scale_factor_min;
1673 while (binary_scale_factor < binary_scale_factor_max) {
1674 if (fabs((chart_1x_scale / binary_scale_factor) - target_scale) <
1675 (target_scale * 0.05))
1677 if ((chart_1x_scale / binary_scale_factor) < target_scale)
1680 binary_scale_factor *= 2.;
1687 int isf_max = (int)scale_factor_max;
1688 while (ibsf < isf_max) {
1689 if (fabs((chart_1x_scale * ibsf) - target_scale) < (target_scale * 0.05))
1692 else if ((chart_1x_scale * ibsf) > target_scale) {
1693 if (ibsf > 1) ibsf /= 2;
1699 binary_scale_factor = 1. / ibsf;
1702 return chart_1x_scale / binary_scale_factor;
1705InitReturn ChartBaseBSB::Init(
const wxString &name, ChartInitFlag init_flags) {
1706 m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB;
1710InitReturn ChartBaseBSB::PreInit(
const wxString &name, ChartInitFlag init_flags,
1712 m_global_color_scheme = cs;
1716void ChartBaseBSB::CreatePaletteEntry(
char *buffer,
int palette_index) {
1717 if (palette_index < N_BSB_COLORS) {
1718 if (!pPalettes[palette_index]) pPalettes[palette_index] =
new opncpnPalette;
1722 (
int *)realloc(pp->FwdPalette, (pp->nFwd + 1) *
sizeof(int));
1724 (
int *)realloc(pp->RevPalette, (pp->nRev + 1) *
sizeof(int));
1730 sscanf(&buffer[4],
"%d,%d,%d,%d", &n, &r, &g, &b);
1735 fcolor = (b << 16) + (g << 8) + r;
1736 rcolor = (r << 16) + (g << 8) + b;
1738 pp->RevPalette[i] = rcolor;
1739 pp->FwdPalette[i] = fcolor;
1743InitReturn ChartBaseBSB::PostInit(
void) {
1745 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
1746 wxString msg(
" Invalid nColorSize data, corrupt in PostInit() on chart ");
1747 msg.Append(m_FullPath);
1749 return INIT_FAIL_REMOVE;
1752 if (Size_X <= 0 || Size_X > INT_MAX / 4 || Size_Y <= 0 ||
1753 Size_Y - 1 > INT_MAX / 4) {
1755 " Invalid Size_X/Size_Y data, corrupt in PostInit() on chart ");
1756 msg.Append(m_FullPath);
1758 return INIT_FAIL_REMOVE;
1764 if (pPalettes[COLOR_RGB_DEFAULT]) {
1765 nrev_def = pPalettes[COLOR_RGB_DEFAULT]->nRev;
1766 nfwd_def = pPalettes[COLOR_RGB_DEFAULT]->nFwd;
1769 for (
int i = 0; i < N_BSB_COLORS; i++) {
1770 if (pPalettes[i] == NULL) {
1773 pNullSubPal->nFwd = nfwd_def;
1774 pNullSubPal->nRev = nrev_def;
1776 free(pNullSubPal->FwdPalette);
1777 pNullSubPal->FwdPalette = (
int *)malloc(pNullSubPal->nFwd *
sizeof(
int));
1778 if (pPalettes[COLOR_RGB_DEFAULT])
1779 memcpy(pNullSubPal->FwdPalette,
1780 pPalettes[COLOR_RGB_DEFAULT]->FwdPalette,
1781 pNullSubPal->nFwd *
sizeof(
int));
1783 free(pNullSubPal->RevPalette);
1784 pNullSubPal->RevPalette = (
int *)malloc(pNullSubPal->nRev *
sizeof(
int));
1785 if (pPalettes[COLOR_RGB_DEFAULT])
1786 memcpy(pNullSubPal->RevPalette,
1787 pPalettes[COLOR_RGB_DEFAULT]->RevPalette,
1788 pNullSubPal->nRev *
sizeof(
int));
1790 pPalettes[i] = pNullSubPal;
1795 palette_direction = GetPaletteDir();
1797 SetColorScheme(m_global_color_scheme,
false);
1800 ifs_bufsize = Size_X * 4;
1801 ifs_buf = (
unsigned char *)malloc(ifs_bufsize);
1802 if (!ifs_buf)
return INIT_FAIL_REMOVE;
1804 ifs_bufend = ifs_buf + ifs_bufsize;
1805 ifs_lp = ifs_bufend;
1806 ifs_file_offset = -ifs_bufsize;
1810 pline_table = (
int *)malloc((Size_Y + 1) *
sizeof(int));
1811 if (!pline_table)
return INIT_FAIL_REMOVE;
1813 ifs_bitmap->SeekI((Size_Y + 1) * -4,
1815 pline_table[Size_Y] = ifs_bitmap->TellI();
1817 unsigned char *tmp = (
unsigned char *)malloc(Size_Y *
sizeof(
int));
1818 ifs_bitmap->Read(tmp, Size_Y *
sizeof(
int));
1819 if (ifs_bitmap->LastRead() != Size_Y *
sizeof(int)) {
1820 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1821 msg.Append(m_FullPath);
1825 return INIT_FAIL_REMOVE;
1829 unsigned char *b = tmp;
1830 for (
int ifplt = 0; ifplt < Size_Y; ifplt++) {
1832 offset += *b++ * 256 * 256 * 256;
1833 offset += *b++ * 256 * 256;
1834 offset += *b++ * 256;
1837 pline_table[ifplt] = offset;
1842 bool bline_index_ok =
true;
1845 wxULongLong bitmap_filesize = m_filesize;
1846 if ((m_ChartType == CHART_TYPE_GEO) && pBitmapFilePath)
1847 bitmap_filesize = wxFileName::GetSize(*pBitmapFilePath);
1850 for (
int iplt = 0; iplt < Size_Y - 1; iplt++) {
1851 if (pline_table[iplt] > bitmap_filesize) {
1852 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1853 msg.Append(m_FullPath);
1856 return INIT_FAIL_REMOVE;
1859 int thisline_size = pline_table[iplt + 1] - pline_table[iplt];
1860 if (thisline_size < 0) {
1861 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1862 msg.Append(m_FullPath);
1865 return INIT_FAIL_REMOVE;
1874 m_bsb_ver.ToDouble(&ver);
1876 for (
int iplt = 0; iplt < 10; iplt++) {
1877 if (wxInvalidOffset ==
1878 ifs_bitmap->SeekI(pline_table[iplt], wxFromStart)) {
1879 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1880 msg.Append(m_FullPath);
1883 return INIT_FAIL_REMOVE;
1886 int thisline_size = pline_table[iplt + 1] - pline_table[iplt];
1887 ifs_bitmap->Read(ifs_buf, thisline_size);
1889 unsigned char *lp = ifs_buf;
1891 unsigned char byNext;
1892 int nLineMarker = 0;
1895 nLineMarker = nLineMarker * 128 + (byNext & 0x7f);
1896 }
while ((byNext & 0x80) != 0);
1903 if (iplt == 0) m_nLineOffset = nLineMarker;
1905 if (nLineMarker != iplt + m_nLineOffset) {
1906 bline_index_ok =
false;
1913 if (!bline_index_ok) {
1914 wxString msg(
" Line Index corrupt, recreating Index for chart ");
1915 msg.Append(m_FullPath);
1917 if (!CreateLineIndex()) {
1918 wxString msg(
" Error creating Line Index for chart ");
1919 msg.Append(m_FullPath);
1921 return INIT_FAIL_REMOVE;
1926 if (bUseLineCache) {
1930 for (
int ylc = 0; ylc < Size_Y; ylc++) {
1931 pt = &pLineCache[ylc];
1934 pt->pTileOffset = NULL;
1940 wxString test_str = m_DepthUnits.Upper();
1941 if (test_str.IsSameAs(
"FEET", FALSE))
1942 m_depth_unit_id = DEPTH_UNIT_FEET;
1943 else if (test_str.IsSameAs(
"METERS", FALSE))
1944 m_depth_unit_id = DEPTH_UNIT_METERS;
1945 else if (test_str.IsSameAs(
"METRES",
1947 m_depth_unit_id = DEPTH_UNIT_METERS;
1948 else if (test_str.IsSameAs(
"METRIC", FALSE))
1949 m_depth_unit_id = DEPTH_UNIT_METERS;
1950 else if (test_str.IsSameAs(
"FATHOMS", FALSE))
1951 m_depth_unit_id = DEPTH_UNIT_FATHOMS;
1952 else if (test_str.Find(
"FATHOMS") !=
1954 m_depth_unit_id = DEPTH_UNIT_FATHOMS;
1955 else if (test_str.Find(
"METERS") !=
1957 m_depth_unit_id = DEPTH_UNIT_METERS;
1960 int analyze_ret_val = AnalyzeRefpoints();
1961 if (0 != analyze_ret_val)
return INIT_FAIL_REMOVE;
1963 bReadyToRender =
true;
1967bool ChartBaseBSB::CreateLineIndex() {
1973 ifs_bitmap->SeekI(nFileOffsetDataStart);
1975 for (
int iplt = 0; iplt < Size_Y; iplt++) {
1976 int offset = ifs_bitmap->TellI();
1978 int iscan = BSBScanScanline(ifs_bitmap);
2002 pline_table[iplt] = offset;
2009void ChartBaseBSB::InvalidateLineCache(
void) {
2012 for (
int ylc = 0; ylc < Size_Y; ylc++) {
2013 pt = &pLineCache[ylc];
2017 free(pt->pTileOffset);
2018 pt->pTileOffset = NULL;
2025bool ChartBaseBSB::GetChartExtent(
Extent *pext) {
2026 pext->NLAT = m_LatMax;
2027 pext->SLAT = m_LatMin;
2028 pext->ELON = m_LonMax;
2029 pext->WLON = m_LonMin;
2034bool ChartBaseBSB::SetMinMax(
void) {
2043 int cnPlypoint = GetCOVRTablenPoints(0);
2045 for (
int u = 0; u < cnPlypoint; u++) {
2046 if (ppp->lnp > m_LonMax) m_LonMax = ppp->lnp;
2047 if (ppp->lnp < m_LonMin) m_LonMin = ppp->lnp;
2049 if (ppp->ltp > m_LatMax) m_LatMax = ppp->ltp;
2050 if (ppp->ltp < m_LatMin) m_LatMin = ppp->ltp;
2059 if ((m_LonMax * m_LonMin) < 0)
2064 if (0 == nRefpoint)
return false;
2067 double min_dist_x = 360;
2069 for (
int ic = 0; ic < nRefpoint; ic++) {
2071 ((m_LatMax - pRefTable[ic].latr) * (m_LatMax - pRefTable[ic].latr)) +
2072 ((m_LonMax - pRefTable[ic].lonr) * (m_LonMax - pRefTable[ic].lonr)));
2074 if (dist < min_dist_x) {
2081 double min_dist_n = 360;
2083 for (
int id = 0;
id < nRefpoint;
id++) {
2085 ((m_LatMin - pRefTable[
id].latr) * (m_LatMin - pRefTable[
id].latr)) +
2086 ((m_LonMin - pRefTable[
id].lonr) * (m_LonMin - pRefTable[
id].lonr)));
2088 if (dist < min_dist_n) {
2096 if (pRefTable[imaxclose].xr < pRefTable[iminclose].xr) {
2109 int cnPlypoint = GetCOVRTablenPoints(0);
2111 for (
int u = 0; u < cnPlypoint; u++) {
2112 if (ppp->lnp < 0.) ppp->lnp += 360.;
2114 if (ppp->lnp > m_LonMax) m_LonMax = ppp->lnp;
2115 if (ppp->lnp < m_LonMin) m_LonMin = ppp->lnp;
2117 if (ppp->ltp > m_LatMax) m_LatMax = ppp->ltp;
2118 if (ppp->ltp < m_LatMin) m_LatMin = ppp->ltp;
2129 if ((m_LonMax < -180.) && (m_LonMin < -180.)) {
2134 int cnPlypoint = GetCOVRTablenPoints(0);
2136 for (
int u = 0; u < cnPlypoint; u++) {
2145void ChartBaseBSB::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
2150 case GLOBAL_COLOR_SCHEME_RGB:
2151 m_mapped_color_index = COLOR_RGB_DEFAULT;
2153 case GLOBAL_COLOR_SCHEME_DAY:
2154 m_mapped_color_index = DAY;
2156 case GLOBAL_COLOR_SCHEME_DUSK:
2157 m_mapped_color_index = DUSK;
2159 case GLOBAL_COLOR_SCHEME_NIGHT:
2160 m_mapped_color_index = NIGHT;
2163 m_mapped_color_index = DAY;
2167 pPalette = GetPalettePtr(m_mapped_color_index);
2169 m_global_color_scheme = cs;
2172 if (bApplyImmediate) {
2173 m_cached_scale_ppm = 1.0;
2177 if (pThumbData) pThumbData->pDIBThumb = NULL;
2180wxBitmap *ChartBaseBSB::CreateThumbnail(
int tnx,
int tny, ColorScheme cs) {
2183 int divx = wxMax(1, Size_X / (4 * tnx));
2184 int divy = wxMax(1, Size_Y / (4 * tny));
2186 int div_factor = std::min(divx, divy);
2188 int des_width = Size_X / div_factor;
2189 int des_height = Size_Y / div_factor;
2195 gts.height = Size_Y;
2199 unsigned char *pLineT = (
unsigned char *)malloc((Size_X + 1) * BPP / 8);
2202 unsigned char *pPixTN =
2203 (
unsigned char *)malloc(des_width * des_height * this_bpp / 8);
2214 ColorScheme cs_tmp = m_global_color_scheme;
2215 SetColorScheme(cs,
false);
2217 while (iyd < des_height) {
2218 if (0 == BSBGetScanline(pLineT, iy, 0, Size_X, 1))
2225 yoffd = iyd * des_width * this_bpp / 8;
2229 while (ixd < des_width) {
2230 pxs = pLineT + (ix * BPP / 8);
2231 pxd = pPixTN + (yoffd + (ixd * this_bpp / 8));
2247 SetColorScheme(cs_tmp,
false);
2251#ifdef ocpnUSE_ocpnBitmap
2252 wxBitmap *bmx2 =
new ocpnBitmap(pPixTN, des_width, des_height, -1);
2253 wxImage imgx2 = bmx2->ConvertToImage();
2254 imgx2.Rescale(des_width / 4, des_height / 4, wxIMAGE_QUALITY_HIGH);
2255 retBMP =
new wxBitmap(imgx2);
2258 wxImage thumb_image(des_width, des_height, pPixTN,
true);
2259 thumb_image.Rescale(des_width / 4, des_height / 4, wxIMAGE_QUALITY_HIGH);
2260 retBMP =
new wxBitmap(thumb_image);
2273ThumbData *ChartBaseBSB::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
2275 if (!pThumbData->pDIBThumb)
2276 pThumbData->pDIBThumb = CreateThumbnail(tnx, tny, m_global_color_scheme);
2278 pThumbData->Thumb_Size_X = tnx;
2279 pThumbData->Thumb_Size_Y = tny;
2282 int divx = Size_X / tnx;
2283 int divy = Size_Y / tny;
2285 int div_factor = std::min(divx, divy);
2298 latlong_to_pix_vp(lat, lon, pixx, pixy, tvp);
2301 pThumbData->ShipX = pixx;
2302 pThumbData->ShipY = pixy;
2307bool ChartBaseBSB::UpdateThumbData(
double lat,
double lon) {
2311 int divx = Size_X / pThumbData->Thumb_Size_X;
2312 int divy = Size_Y / pThumbData->Thumb_Size_Y;
2314 int div_factor = std::min(divx, divy);
2316 double pixx_test, pixy_test;
2321 tvp.
pix_width = pThumbData->Thumb_Size_X;
2327 latlong_to_pix_vp(lat, lon, pixx_test, pixy_test, tvp);
2330 if ((pixx_test != pThumbData->ShipX) || (pixy_test != pThumbData->ShipY)) {
2331 pThumbData->ShipX = pixx_test;
2332 pThumbData->ShipY = pixy_test;
2341static double polytrans(
double *coeff,
double lon,
double lat);
2343int ChartBaseBSB::vp_pix_to_latlong(
ViewPort &vp,
double pixx,
double pixy,
2344 double *plat,
double *plon) {
2345 if (bHaveEmbeddedGeoref) {
2348 double px = pixx * raster_scale + Rsrc.x;
2349 double py = pixy * raster_scale + Rsrc.y;
2353 double lon = polytrans(pwx, px, py);
2354 lon = (lon < 0) ? lon + m_cph : lon - m_cph;
2355 *plon = lon - m_lon_datum_adjust;
2356 *plat = polytrans(pwy, px, py) - m_lat_datum_adjust;
2364 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2370 double easting, northing;
2371 toTM(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2372 m_proj_lat, m_proj_lon, &easting, &northing);
2373 double xc = polytrans(cPoints.
wpx, easting, northing);
2374 double yc = polytrans(cPoints.
wpy, easting, northing);
2377 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2378 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2381 double east = polytrans(cPoints.
pwx, px, py);
2382 double north = polytrans(cPoints.
pwy, px, py);
2386 fromTM(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2390 double slon_p = lon - m_lon_datum_adjust;
2391 double slat_p = lat - m_lat_datum_adjust;
2398 }
else if (m_projection == PROJECTION_MERCATOR) {
2404 double easting, northing;
2405 toSM_ECC(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2406 m_proj_lat, m_proj_lon, &easting, &northing);
2407 double xc = polytrans(cPoints.
wpx, easting, northing);
2408 double yc = polytrans(cPoints.
wpy, easting, northing);
2411 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2412 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2415 double east = polytrans(cPoints.
pwx, px, py);
2416 double north = polytrans(cPoints.
pwy, px, py);
2420 fromSM_ECC(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2423 double slon_p = lon - m_lon_datum_adjust;
2424 double slat_p = lat - m_lat_datum_adjust;
2432 }
else if (m_projection == PROJECTION_POLYCONIC) {
2438 double easting, northing;
2439 toPOLY(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2440 m_proj_lat, m_proj_lon, &easting, &northing);
2441 double xc = polytrans(cPoints.
wpx, easting, northing);
2442 double yc = polytrans(cPoints.
wpy, easting, northing);
2445 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2446 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2449 double east = polytrans(cPoints.
pwx, px, py);
2450 double north = polytrans(cPoints.
pwy, px, py);
2454 fromPOLY(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2457 double slon_p = lon - m_lon_datum_adjust;
2458 double slat_p = lat - m_lat_datum_adjust;
2468 xp = (dx * cos(vp.
skew)) - (dy * sin(vp.
skew));
2469 yp = (dy * cos(vp.
skew)) + (dx * sin(vp.
skew));
2474 fromSM_ECC(d_east, d_north, vp.
clat, vp.
clon, &slat, &slon);
2481 else if (slon > 180.)
2489int ChartBaseBSB::latlong_to_pix_vp(
double lat,
double lon,
double &pixx,
2493 if (bHaveEmbeddedGeoref) {
2496 alon = lon + m_lon_datum_adjust;
2497 alat = lat + m_lat_datum_adjust;
2499 AdjustLongitude(alon);
2503 double lonp = (alon < 0) ? alon + m_cph : alon - m_cph;
2504 double xd = polytrans(wpx, lonp, alat);
2505 double yd = polytrans(wpy, lonp, alat);
2509 pixx = (xd - Rsrc.x) / raster_scale;
2510 pixy = (yd - Rsrc.y) / raster_scale;
2515 double easting, northing;
2537 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2540 alon = lon + m_lon_datum_adjust;
2541 alat = lat + m_lat_datum_adjust;
2544 toTM(alat, alon, m_proj_lat, m_proj_lon, &easting, &northing);
2547 double xd = polytrans(cPoints.
wpx, easting, northing);
2548 double yd = polytrans(cPoints.
wpy, easting, northing);
2551 toTM(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2552 m_proj_lat, m_proj_lon, &easting, &northing);
2553 double xc = polytrans(cPoints.
wpx, easting, northing);
2554 double yc = polytrans(cPoints.
wpy, easting, northing);
2559 double xs = xc - vp.
pix_width * raster_scale / 2;
2560 double ys = yc - vp.
pix_height * raster_scale / 2;
2562 pixx = (xd - xs) / raster_scale;
2563 pixy = (yd - ys) / raster_scale;
2565 }
else if (m_projection == PROJECTION_MERCATOR) {
2568 alon = lon + m_lon_datum_adjust;
2569 alat = lat + m_lat_datum_adjust;
2573 AdjustLongitude(xlon);
2574 toSM_ECC(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2577 double xd = polytrans(cPoints.
wpx, easting, northing);
2578 double yd = polytrans(cPoints.
wpy, easting, northing);
2581 double xlonc = vp.
clon;
2582 AdjustLongitude(xlonc);
2584 toSM_ECC(vp.
clat + m_lat_datum_adjust, xlonc + m_lon_datum_adjust,
2585 m_proj_lat, m_proj_lon, &easting, &northing);
2586 double xc = polytrans(cPoints.
wpx, easting, northing);
2587 double yc = polytrans(cPoints.
wpy, easting, northing);
2592 double xs = xc - vp.
pix_width * raster_scale / 2;
2593 double ys = yc - vp.
pix_height * raster_scale / 2;
2595 pixx = (xd - xs) / raster_scale;
2596 pixy = (yd - ys) / raster_scale;
2598 }
else if (m_projection == PROJECTION_POLYCONIC) {
2601 alon = lon + m_lon_datum_adjust;
2602 alat = lat + m_lat_datum_adjust;
2605 xlon = AdjustLongitude(alon);
2606 toPOLY(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2609 double xd = polytrans(cPoints.
wpx, easting, northing);
2610 double yd = polytrans(cPoints.
wpy, easting, northing);
2613 double xlonc = AdjustLongitude(vp.
clon);
2615 toPOLY(vp.
clat + m_lat_datum_adjust, xlonc + m_lon_datum_adjust,
2616 m_proj_lat, m_proj_lon, &easting, &northing);
2617 double xc = polytrans(cPoints.
wpx, easting, northing);
2618 double yc = polytrans(cPoints.
wpy, easting, northing);
2623 double xs = xc - vp.
pix_width * raster_scale / 2;
2624 double ys = yc - vp.
pix_height * raster_scale / 2;
2626 pixx = (xd - xs) / raster_scale;
2627 pixy = (yd - ys) / raster_scale;
2630 toSM_ECC(lat, xlon, vp.
clat, vp.
clon, &easting, &northing);
2635 double dx = epix * cos(vp.
skew) + npix * sin(vp.
skew);
2636 double dy = npix * cos(vp.
skew) - epix * sin(vp.
skew);
2647void ChartBaseBSB::latlong_to_chartpix(
double lat,
double lon,
double &pixx,
2653 if (bHaveEmbeddedGeoref) {
2656 alon = lon + m_lon_datum_adjust;
2657 alat = lat + m_lat_datum_adjust;
2659 alon = AdjustLongitude(alon);
2662 double lonp = (alon < 0) ? alon + m_cph : alon - m_cph;
2663 pixx = polytrans(wpx, lonp, alat);
2664 pixy = polytrans(wpy, lonp, alat);
2666 double easting, northing;
2669 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2672 alon = lon + m_lon_datum_adjust;
2673 alat = lat + m_lat_datum_adjust;
2676 toTM(alat, alon, m_proj_lat, m_proj_lon, &easting, &northing);
2679 pixx = polytrans(cPoints.
wpx, easting, northing);
2680 pixy = polytrans(cPoints.
wpy, easting, northing);
2682 }
else if (m_projection == PROJECTION_MERCATOR) {
2685 alon = lon + m_lon_datum_adjust;
2686 alat = lat + m_lat_datum_adjust;
2689 xlon = AdjustLongitude(alon);
2691 toSM_ECC(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2694 pixx = polytrans(cPoints.
wpx, easting, northing);
2695 pixy = polytrans(cPoints.
wpy, easting, northing);
2697 }
else if (m_projection == PROJECTION_POLYCONIC) {
2700 alon = lon + m_lon_datum_adjust;
2701 alat = lat + m_lat_datum_adjust;
2704 xlon = AdjustLongitude(alon);
2705 toPOLY(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2708 pixx = polytrans(cPoints.
wpx, easting, northing);
2709 pixy = polytrans(cPoints.
wpy, easting, northing);
2714void ChartBaseBSB::chartpix_to_latlong(
double pixx,
double pixy,
double *plat,
2716 if (bHaveEmbeddedGeoref) {
2717 double lon = polytrans(pwx, pixx, pixy);
2718 lon = (lon < 0) ? lon + m_cph : lon - m_cph;
2719 *plon = lon - m_lon_datum_adjust;
2720 *plat = polytrans(pwy, pixx, pixy) - m_lat_datum_adjust;
2723 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2727 double east = polytrans(cPoints.
pwx, pixx, pixy);
2728 double north = polytrans(cPoints.
pwy, pixx, pixy);
2732 fromTM(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2736 slon = lon - m_lon_datum_adjust;
2737 slat = lat - m_lat_datum_adjust;
2739 }
else if (m_projection == PROJECTION_MERCATOR) {
2742 double east = polytrans(cPoints.
pwx, pixx, pixy);
2743 double north = polytrans(cPoints.
pwy, pixx, pixy);
2747 fromSM_ECC(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2750 slon = lon - m_lon_datum_adjust;
2751 slat = lat - m_lat_datum_adjust;
2752 }
else if (m_projection == PROJECTION_POLYCONIC) {
2755 double east = polytrans(cPoints.
pwx, pixx, pixy);
2756 double north = polytrans(cPoints.
pwy, pixx, pixy);
2760 fromPOLY(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2763 slon = lon - m_lon_datum_adjust;
2764 slat = lat - m_lat_datum_adjust;
2775 else if (slon > 180.)
2781void ChartBaseBSB::ComputeSourceRectangle(
const ViewPort &vp,
2782 wxRect *pSourceRect) {
2783 m_raster_scale_factor = GetRasterScaleFactor(vp);
2785 latlong_to_chartpix(vp.
clat, vp.
clon, xd, yd);
2787 wxRealPoint pos, size;
2789 pos.x = xd - (vp.
pix_width * m_raster_scale_factor / 2);
2790 pos.y = yd - (vp.
pix_height * m_raster_scale_factor / 2);
2792 size.x = vp.
pix_width * m_raster_scale_factor;
2793 size.y = vp.
pix_height * m_raster_scale_factor;
2796 wxRect(wxRound(pos.x), wxRound(pos.y), wxRound(size.x), wxRound(size.y));
2799double ChartBaseBSB::GetRasterScaleFactor(
const ViewPort &vp) {
2802 return (wxRound(100000 * GetPPM() / vp.
view_scale_ppm)) / 100000.;
2805void ChartBaseBSB::SetVPRasterParms(
const ViewPort &vpt) {
2809 if (m_datum_index == DATUM_INDEX_WGS84 ||
2810 m_datum_index == DATUM_INDEX_UNKNOWN) {
2811 m_lon_datum_adjust = (-m_dtm_lon) / 3600.;
2812 m_lat_datum_adjust = (-m_dtm_lat) / 3600.;
2816 double to_lat, to_lon;
2817 MolodenskyTransform(vpt.
clat, vpt.
clon, &to_lat, &to_lon, m_datum_index,
2819 m_lon_datum_adjust = -(to_lon - vpt.
clon);
2820 m_lat_datum_adjust = -(to_lat - vpt.
clat);
2821 if (m_b_apply_dtm) {
2822 m_lon_datum_adjust -= m_dtm_lon / 3600.;
2823 m_lat_datum_adjust -= m_dtm_lat / 3600.;
2827 ComputeSourceRectangle(vpt, &Rsrc);
2829 if (vpt.IsValid()) m_vp_render_last = vpt;
2833 bool bInside = G_FloatPtInPolygon((
MyFlPoint *)GetCOVRTableHead(0),
2834 GetCOVRTablenPoints(0), vp_proposed.
clon,
2836 if (!bInside)
return false;
2839 double binary_scale_factor = GetPPM() / vp_proposed.
view_scale_ppm;
2841 if (vp_last.IsValid()) {
2847 if (cached_image_ok && (binary_scale_factor > 1.0) &&
2848 (fabs(binary_scale_factor - wxRound(binary_scale_factor)) < 1e-5)) {
2850 printf(
" Possible Adjust VP for integer scale: %g\n",
2851 binary_scale_factor);
2854 ComputeSourceRectangle(vp_proposed, &rprop);
2857 double lon_adj, lat_adj;
2858 latlong_to_pix_vp(vp_proposed.
clat, vp_proposed.
clon, pixx, pixy,
2860 vp_pix_to_latlong(vp_proposed, pixx, pixy, &lat_adj, &lon_adj);
2862 vp_proposed.
clat = lat_adj;
2863 vp_proposed.
clon = lon_adj;
2868 return (ret_val > 0);
2871bool ChartBaseBSB::IsRenderCacheable(wxRect &source, wxRect &dest) {
2872 double scale_x = (double)source.width / (
double)dest.width;
2881 if ((fabs(scale_x - wxRound(scale_x))) > .0001) {
2888 if ((
int)(source.width / dest.width) != (
int)wxRound(scale_x)) {
2897void ChartBaseBSB::GetValidCanvasRegion(
const ViewPort &VPoint,
2899 SetVPRasterParms(VPoint);
2906 rxl = wxMax(-Rsrc.x * raster_scale, VPoint.rv_rect.x);
2907 rxr = wxMin((Size_X - Rsrc.x) * raster_scale,
2908 VPoint.rv_rect.width + VPoint.rv_rect.x);
2910 ryt = wxMax(-Rsrc.y * raster_scale, VPoint.rv_rect.y);
2911 ryb = wxMin((Size_Y - Rsrc.y) * raster_scale,
2912 VPoint.rv_rect.height + VPoint.rv_rect.y);
2914 pValidRegion->Clear();
2915 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
2918LLRegion ChartBaseBSB::GetValidRegion() {
2921 chartpix_to_latlong(0, 0, ll + 0, ll + 1);
2922 chartpix_to_latlong(0, Size_Y, ll + 2, ll + 3);
2923 chartpix_to_latlong(Size_X, Size_Y, ll + 4, ll + 5);
2924 chartpix_to_latlong(Size_X, 0, ll + 6, ll + 7);
2928 for (
int i = 1; i < 6; i += 2)
2929 if (fabs(ll[i] - ll[i + 2]) > 180) {
2931 for (
int i = 1; i < 8; i += 2)
2932 if (ll[i] < 0) ll[i] += 360;
2936 return LLRegion(4, ll);
2939bool ChartBaseBSB::GetViewUsingCache(wxRect &source, wxRect &dest,
2941 ScaleTypeEnum scale_type) {
2943 ScaleTypeEnum scale_type_corrected;
2945 if (m_b_cdebug) printf(
" source: %d %d\n", source.x, source.y);
2946 if (m_b_cdebug) printf(
" cache: %d %d\n", cache_rect.x, cache_rect.y);
2949 if ((source == cache_rect) &&
2950 (cached_image_ok)) {
2951 if (m_b_cdebug) printf(
" GVUC: Cache is good, nothing to do\n");
2955 double scale_x = (double)source.width / (
double)dest.width;
2957 if (m_b_cdebug) printf(
"GVUC: scale_x: %g\n", scale_x);
2960 scale_type_corrected = scale_type;
2961 if (scale_x > m_bilinear_limit) scale_type_corrected = RENDER_LODEF;
2969 if ((fabs(scale_x - wxRound(scale_x))) > .0001) {
2970 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Not digital scale test 1\n");
2971 return GetView(source, dest, scale_type_corrected);
2976 if (!cached_image_ok) {
2977 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Cache NOk\n");
2978 return GetView(source, dest, scale_type_corrected);
2983 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Overzoom\n");
2984 return GetView(source, dest, scale_type_corrected);
2988 if ((
int)(source.width / dest.width) != (
int)wxRound(scale_x)) {
2989 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Not digital scale test 2\n");
2990 return GetView(source, dest, scale_type_corrected);
2994 int cs1d = source.width / dest.width;
2995 if (abs(source.x - cache_rect.x) % cs1d) {
2997 printf(
" source.x: %d cache_rect.x: %d cs1d: %d\n", source.x,
2998 cache_rect.x, cs1d);
2999 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: x mismatch\n");
3000 return GetView(source, dest, scale_type_corrected);
3002 if (abs(source.y - cache_rect.y) % cs1d) {
3003 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: y mismatch\n");
3004 return GetView(source, dest, scale_type_corrected);
3007 if (pPixCache && ((pPixCache->GetWidth() != dest.width) ||
3008 (pPixCache->GetHeight() != dest.height))) {
3009 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: dest size mismatch\n");
3010 return GetView(source, dest, scale_type_corrected);
3014 (source.y + source.height) - (cache_rect.y + cache_rect.height);
3015 int scaled_stride_rows = (int)(stride_rows / scale_x);
3017 if (abs(stride_rows) >= source.height)
3018 return GetView(source, dest, scale_type_corrected);
3021 (source.x + source.width) - (cache_rect.x + cache_rect.width);
3022 int scaled_stride_pixels = (int)(stride_pixels / scale_x);
3024 if (abs(stride_pixels) >= source.width)
3025 return GetView(source, dest, scale_type_corrected);
3027 if (m_b_cdebug) printf(
" GVUC Using raster data cache\n");
3029 ScaleTypeEnum pan_scale_type_x = scale_type_corrected;
3030 ScaleTypeEnum pan_scale_type_y = scale_type_corrected;
3034 int height = pPixCache->GetHeight();
3035 int width = pPixCache->GetWidth();
3036 int buffer_stride_bytes = pPixCache->GetLinePitch();
3041 if (stride_rows > 0)
3043 ps = pPixCache->GetpData() +
3044 (abs(scaled_stride_rows) * buffer_stride_bytes);
3045 if (stride_pixels > 0) ps += scaled_stride_pixels * BPP / 8;
3047 pd = pPixCache->GetpData();
3048 if (stride_pixels <= 0) pd += abs(scaled_stride_pixels) * BPP / 8;
3050 for (
int iy = 0; iy < (height - abs(scaled_stride_rows)); iy++) {
3051 memmove(pd, ps, (width - abs(scaled_stride_pixels)) * BPP / 8);
3052 ps += buffer_stride_bytes;
3053 pd += buffer_stride_bytes;
3057 ps = pPixCache->GetpData() +
3058 ((height - abs(scaled_stride_rows) - 1) * buffer_stride_bytes);
3059 if (stride_pixels > 0)
3060 ps += scaled_stride_pixels * BPP / 8;
3062 pd = pPixCache->GetpData() + ((height - 1) * buffer_stride_bytes);
3063 if (stride_pixels <= 0)
3064 pd += abs(scaled_stride_pixels) * BPP / 8;
3066 for (
int iy = 0; iy < (height - abs(scaled_stride_rows)); iy++) {
3067 memmove(pd, ps, (width - abs(scaled_stride_pixels)) * BPP / 8);
3068 ps -= buffer_stride_bytes;
3069 pd -= buffer_stride_bytes;
3074 if (source.y != cache_rect.y) {
3075 wxRect sub_dest = dest;
3076 sub_dest.height = abs(scaled_stride_rows);
3078 if (stride_rows > 0)
3080 sub_dest.y = height - scaled_stride_rows;
3091 wxRegionContain rc = Region.Contains(sub_dest);
3092 if ((wxPartRegion == rc) || (wxInRegion == rc)) {
3093 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3094 source.width, sub_dest, width, cs1d, pan_scale_type_y);
3096 pPixCache->Update();
3100 cache_rect.y = source.y;
3102 cache_rect_scaled = dest;
3103 cached_image_ok = 1;
3108 if (source.x != cache_rect.x) {
3109 wxRect sub_dest = dest;
3110 sub_dest.width = abs(scaled_stride_pixels);
3112 if (stride_pixels > 0)
3114 sub_dest.x = width - scaled_stride_pixels;
3125 wxRegionContain rc = Region.Contains(sub_dest);
3126 if ((wxPartRegion == rc) || (wxInRegion == rc)) {
3127 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3128 source.width, sub_dest, width, cs1d, pan_scale_type_x);
3131 pPixCache->Update();
3134 cache_rect = source;
3135 cache_rect_scaled = dest;
3136 cached_image_ok = 1;
3147bool ChartBaseBSB::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
3148 SetVPRasterParms(VPoint);
3152 bool bsame_region = (rgn == m_last_region);
3154 if (!bsame_region) cached_image_ok =
false;
3156 m_last_region = rgn;
3158 return RenderRegionViewOnDC(dc, VPoint, rgn);
3161bool ChartBaseBSB::RenderRegionViewOnGL(
const wxGLContext &glc,
3164 const LLRegion &Region) {
3168bool ChartBaseBSB::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
3170 SetVPRasterParms(VPoint);
3174 double factor = GetRasterScaleFactor(VPoint);
3176 printf(
"%d RenderRegion ScaleType: %d factor: %g\n", s_dc++,
3177 RENDER_HIDEF, factor);
3178 printf(
"Rect list:\n");
3180 while (upd.HaveRects()) {
3181 wxRect rect = upd.GetRect();
3182 printf(
" %d %d %d %d\n", rect.x, rect.y, rect.width, rect.height);
3190 (m_last_vprect != dest)) {
3191 cached_image_ok =
false;
3192 m_vp_render_last.Invalidate();
3209 m_last_vprect = dest;
3211 if (cached_image_ok) {
3213 bool bsame_region = (Region == m_last_region);
3215 if ((bsame_region) && (Rsrc == cache_rect)) {
3216 pPixCache->SelectIntoDC(dc);
3217 if (m_b_cdebug) printf(
" Using Current PixelCache\n");
3222 m_last_region = Region;
3243 while (upd.HaveRects()) {
3248 if ((!IsRenderCacheable(Rsrc, dest) && (n_rect > 4) && (n_rect < 20)) ||
3251 printf(
" RenderRegion by rect iterator n_rect: %d\n", n_rect);
3255 wxRect dest_check_rect = dest;
3257 while (upd_check.HaveRects()) {
3258 wxRect rect = upd_check.GetRect();
3259 dest_check_rect.Union(rect);
3260 upd_check.NextRect();
3264 if ((pPixCache->GetWidth() != dest_check_rect.width) ||
3265 (pPixCache->GetHeight() != dest_check_rect.height)) {
3268 new PixelCache(dest_check_rect.width, dest_check_rect.height, BPP);
3272 new PixelCache(dest_check_rect.width, dest_check_rect.height, BPP);
3274 ScaleTypeEnum ren_type = RENDER_LODEF;
3280 while (upd.HaveRects()) {
3281 wxRect rect = upd.GetRect();
3286 if (rect.y < 0) rect.Offset(0, -rect.y);
3287 if (rect.x < 0) rect.Offset(-rect.x, 0);
3289 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), Rsrc,
3290 Rsrc.width, rect, pPixCache->GetWidth(), factor,
3298 pPixCache->Update();
3302 cache_scale_method = ren_type;
3303 cached_image_ok =
false;
3306 pPixCache->SelectIntoDC(dc);
3314 if ((pPixCache->GetWidth() != dest.width) ||
3315 (pPixCache->GetHeight() != dest.height)) {
3317 pPixCache =
new PixelCache(dest.width, dest.height, BPP);
3320 pPixCache =
new PixelCache(dest.width, dest.height, BPP);
3322 if (m_b_cdebug) printf(
" Render Region By GVUC\n");
3325 ScaleTypeEnum scale_type_zoom = RENDER_HIDEF;
3327 if (binary_scale_factor < .20) scale_type_zoom = RENDER_LODEF;
3329 bool bnewview = GetViewUsingCache(Rsrc, dest, Region, scale_type_zoom);
3332 pPixCache->SelectIntoDC(dc);
3337wxImage *ChartBaseBSB::GetImage() {
3338 int img_size_x = ((Size_X >> 2) * 4) + 4;
3339 wxImage *img =
new wxImage(img_size_x, Size_Y,
false);
3341 unsigned char *ppnx = img->GetData();
3343 for (
int i = 0; i < Size_Y; i++) {
3344 wxRect source_rect(0, i, Size_X, 1);
3345 wxRect dest_rect(0, 0, Size_X, 1);
3347 GetAndScaleData(img->GetData(), img_size_x * Size_Y * 3, source_rect,
3348 Size_X, dest_rect, Size_X, 1.0, RENDER_HIDEF);
3350 ppnx += img_size_x * 3;
3356bool ChartBaseBSB::GetView(wxRect &source, wxRect &dest,
3357 ScaleTypeEnum scale_type) {
3358 assert(pPixCache != 0);
3364 double factor = ((double)source.width) / ((double)dest.width);
3379 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3380 source.width, dest, dest.width, factor, scale_type);
3381 pPixCache->Update();
3385 cache_rect = source;
3386 cache_rect_scaled = dest;
3387 cache_scale_method = scale_type;
3389 cached_image_ok = 1;
3394bool ChartBaseBSB::GetAndScaleData(
unsigned char *ppn,
size_t data_size,
3395 wxRect &source,
int source_stride,
3396 wxRect &dest,
int dest_stride,
3397 double scale_factor,
3398 ScaleTypeEnum scale_type) {
3399 unsigned char *s_data = NULL;
3401 double factor = scale_factor;
3402 int Factor = (int)factor;
3404 int target_width = (int)wxRound((
double)source.width / factor);
3405 int target_height = (int)wxRound((
double)source.height / factor);
3407 int dest_line_length = dest_stride * BPP / 8;
3411#ifdef __PIX_CACHE_DIBSECTION__
3412 dest_line_length = (((dest_stride * 24) + 31) & ~31) >> 3;
3415 if ((target_height == 0) || (target_width == 0))
return false;
3419 unsigned char *
volatile target_data = ppn;
3420 unsigned char *data = ppn;
3424 if (scale_type == RENDER_HIDEF) {
3426 int blur_factor = wxMax(2, Factor);
3427 int wb_size = (source.width) * (blur_factor * 2) * BPP / 8;
3428 s_data = (
unsigned char *)malloc(wb_size);
3429 unsigned char *pixel;
3432 for (
int y = dest.y; y < (dest.y + dest.height); y++) {
3437 s1.y = source.y + (int)(y * factor);
3438 s1.width = source.width;
3439 s1.height = blur_factor;
3440 GetChartBits(s1, s_data, 1);
3442 target_data = data + (y * dest_line_length );
3444 for (
int x = 0; x < target_width; x++) {
3445 unsigned int avgRed = 0;
3446 unsigned int avgGreen = 0;
3447 unsigned int avgBlue = 0;
3448 unsigned int pixel_count = 0;
3449 unsigned char *pix0 = s_data + BPP / 8 * ((int)(x * factor));
3452 if ((x * Factor) < (Size_X - source.x)) {
3454 for (
int y1 = 0; y1 < blur_factor; ++y1) {
3455 pixel = pix0 + (BPP / 8 * y_offset);
3456 for (
int x1 = 0; x1 < blur_factor; ++x1) {
3458 avgGreen += pixel[1];
3459 avgBlue += pixel[2];
3465 y_offset += source.width;
3468 if (0 == pixel_count)
3471 target_data[0] = avgRed / pixel_count;
3472 target_data[1] = avgGreen / pixel_count;
3473 target_data[2] = avgBlue / pixel_count;
3474 target_data += BPP / 8;
3479 target_data += BPP / 8;
3488 else if (scale_type == RENDER_LODEF) {
3489 int get_bits_submap = 1;
3493 if (source.width > 32767)
3496 int wb_size = (Size_X) * (( 1) * 2) * BPP / 8;
3497 s_data = (
unsigned char *)malloc(wb_size);
3499 long x_delta = (source.width << scaler) / target_width;
3500 long y_delta = (source.height << scaler) / target_height;
3503 long ys = dest.y * y_delta;
3505 while (y < dest.y + dest.height) {
3510 s1.y = source.y + (ys >> scaler);
3513 GetChartBits(s1, s_data, get_bits_submap);
3515 target_data = data + (y * dest_line_length ) +
3518 long x = (source.x << scaler) + (dest.x * x_delta);
3519 long sizex16 = Size_X << scaler;
3522 while ((xt < dest.x + dest.width) && (x < 0)) {
3527 target_data += BPP / 8;
3532 while ((xt < dest.x + dest.width) && (x < sizex16)) {
3533 unsigned char *src_pixel = &s_data[(x >> scaler) * BPP / 8];
3535 target_data[0] = src_pixel[0];
3536 target_data[1] = src_pixel[1];
3537 target_data[2] = src_pixel[2];
3539 target_data += BPP / 8;
3544 while (xt < dest.x + dest.width) {
3549 target_data += BPP / 8;
3563 unsigned char *target_line_start = NULL;
3564 unsigned char *target_data_x = NULL;
3568 sigaction(SIGSEGV, NULL,
3571 struct sigaction temp;
3572 sigaction(SIGSEGV, NULL, &temp);
3574 temp.sa_handler = catch_signals_chart;
3575 sigemptyset(&temp.sa_mask);
3580 sigaction(SIGSEGV, &temp, NULL);
3582 if (sigsetjmp(env_chart,
3585 sigaction(SIGSEGV, &sa_all_previous, NULL);
3588 msg.Printf(
" Caught SIGSEGV on GetandScaleData, Factor < 1");
3592 " m_raster_scale_factor: %g source.width: %d dest.y: %d "
3593 "dest.x: %d dest.width: %d dest.height: %d ",
3594 m_raster_scale_factor, source.width, dest.y, dest.x, dest.width,
3599 " i: %d j: %d dest_stride: %d target_line_start: %p "
3600 "target_data_x: %p y_offset: %d",
3601 i, j, dest_stride, target_line_start, target_data_x, y_offset);
3614 latlong_to_chartpix(m_vp_render_last.
clat, m_vp_render_last.
clon, xd, yd);
3616 xd - (m_vp_render_last.
pix_width * m_raster_scale_factor / 2);
3618 yd - (m_vp_render_last.
pix_height * m_raster_scale_factor / 2);
3619 double x_vernier = (xrd - wxRound(xrd));
3620 double y_vernier = (yrd - wxRound(yrd));
3621 int x_vernier_i = (int)wxRound(x_vernier / m_raster_scale_factor);
3622 int y_vernier_i = (int)wxRound(y_vernier / m_raster_scale_factor);
3627 int sx = wxMax(source.x, 0);
3628 s_data = (
unsigned char *)malloc((sx + source.width + 2) *
3629 (source.height + 2) * BPP / 8);
3631 wxRect vsource = source;
3632 vsource.height += 2;
3637 GetChartBits(vsource, s_data, 1);
3638 unsigned char *source_data = s_data;
3642 while (j < dest.y + dest.height) {
3643 y_offset = (int)((j - y_vernier_i) * m_raster_scale_factor) *
3647 target_data + (j * dest_line_length );
3648 target_data_x = target_line_start + ((dest.x) * BPP / 8);
3653 if ((target_data_x + (dest.width * BPP / 8)) >
3654 (target_data + data_size)) {
3655 j = dest.y + dest.height;
3657 while (i < dest.x + dest.width) {
3658 memcpy(target_data_x,
3659 source_data + BPP / 8 *
3660 (y_offset + (
int)((i + x_vernier_i) *
3661 m_raster_scale_factor)),
3664 target_data_x += BPP / 8;
3674 sigaction(SIGSEGV, &sa_all_previous, NULL);
3683bool ChartBaseBSB::GetChartBits(wxRect &source,
unsigned char *pPix,
3685 wxCriticalSectionLocker locker(m_critSect);
3697 while (iy < source.y + source.height) {
3698 if ((iy >= 0) && (iy < Size_Y)) {
3699 if (source.x >= 0) {
3700 if ((source.x + source.width) > Size_X) {
3701 if ((Size_X - source.x) < 0)
3702 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3704 BSBGetScanline(pCP, iy, source.x, Size_X, sub_samp);
3705 memset(pCP + (Size_X - source.x) * BPP / 8, FILL_BYTE,
3706 (source.x + source.width - Size_X) * BPP / 8);
3709 BSBGetScanline(pCP, iy, source.x, source.x + source.width, sub_samp);
3711 if ((source.width + source.x) >= 0) {
3715 int xfill_corrected = -source.x + (source.x % sub_samp);
3716 memset(pCP, FILL_BYTE, (xfill_corrected * BPP / 8));
3717 BSBGetScanline(pCP + (xfill_corrected * BPP / 8), iy, 0,
3718 source.width + source.x, sub_samp);
3721 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3728 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3731 pCP += source.width * BPP / 8 * sub_samp;
3749int ChartBaseBSB::ReadBSBHdrLine(wxInputStream *ifs,
char *buf,
int buf_len_max)
3754 int line_length = 0;
3759 while (!ifs->Eof() && line_length < buf_len_max) {
3760 int c = ifs->GetC();
3763 if (0x1A == read_char) {
3764 ifs->Ungetch(read_char);
3772 if (read_char == 10 || read_char == 13) {
3774 cr_test = ifs->GetC();
3775 if (cr_test == 13) cr_test = ifs->GetC();
3777 if (cr_test != 10 && cr_test != 13) ifs->Ungetch(cr_test);
3782 if (read_char ==
'\n') {
3784 cr_test = ifs->GetC();
3786 if (cr_test !=
' ') {
3787 ifs->Ungetch(cr_test);
3793 while (cr_test ==
' ') cr_test = ifs->GetC();
3794 ifs->Ungetch(cr_test);
3810 if (line_length) *(lbuf - 1) =
'\0';
3819int ChartBaseBSB::BSBScanScanline(wxInputStream *pinStream) {
3820 int nLineMarker, nValueShift, iPixel = 0;
3821 unsigned char byValueMask, byCountMask;
3822 unsigned char byNext;
3830 byNext = pinStream->GetC();
3831 nLineMarker = nLineMarker * 128 + (byNext & 0x7f);
3832 }
while ((byNext & 0x80) != 0);
3835 nValueShift = 7 - nColorSize;
3836 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
3837 byCountMask = (1 << (7 - nColorSize)) - 1;
3841 while (((byNext = pinStream->GetC()) != 0) && (iPixel < Size_X)) {
3846 nRunCount = byNext & byCountMask;
3848 while ((byNext & 0x80) != 0) {
3849 byNext = pinStream->GetC();
3850 nRunCount = nRunCount * 128 + (byNext & 0x7f);
3853 if (iPixel + nRunCount + 1 > Size_X) nRunCount = Size_X - iPixel - 1;
3858 iPixel += nRunCount + 1;
3860 coffset = pinStream->TellI();
3870inline void memset_short(
unsigned char *dst,
unsigned char cbyte,
int count) {
3882 memset(dst, cbyte, count);
3887#define TILE_SIZE 512
3896 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
3900 clock_gettime(CLOCK_REALTIME, &tp_end);
3901 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
3902 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
3912 free(pt->pTileOffset); \
3913 pt->pTileOffset = NULL; \
3916 pt->bValid = false; \
3923int ChartBaseBSB::BSBGetScanline(
unsigned char *pLineBuf,
int y,
int xs,
int xl,
3927 unsigned char *prgb = pLineBuf;
3929 unsigned char byValueMask, byCountMask;
3930 unsigned char byNext;
3938 if (bUseLineCache && pLineCache) {
3940 pt = &pLineCache[y];
3948 static double ttime;
3955 pt->size = pline_table[y + 1] - pline_table[y];
3958 pt->pPix = (
unsigned char *)malloc(Size_X);
3962 pt->pPix = (
unsigned char *)malloc(pt->size);
3964 if (pline_table[y] == 0 || pline_table[y + 1] == 0) FAIL;
3969 if (ifs_bitmap->TellI() != pline_table[y] &&
3970 wxInvalidOffset == ifs_bitmap->SeekI(pline_table[y], wxFromStart))
3974 if (pt->size > ifs_bufsize) {
3975 unsigned char *tmp = ifs_buf;
3976 if (!(ifs_buf = (
unsigned char *)realloc(ifs_buf, pt->size))) {
3980 ifs_bufsize = pt->size;
3987 ifs_bitmap->Read(lp, pt->size);
3992 if (!bUseLineCache) {
3996 if (pos < pt->size) {
4002 }
while ((byNext & 0x80) != 0);
4007 if (Size_X > ifs_bufsize) {
4008 unsigned char *tmp = ifs_buf;
4009 if (!(ifs_buf = (
unsigned char *)realloc(ifs_buf, Size_X))) {
4013 ifs_bufsize = Size_X;
4021 if (pos < pt->size) {
4027 }
while ((byNext & 0x80) != 0);
4030 nValueShift = 7 - nColorSize;
4031 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
4032 byCountMask = (1 << (7 - nColorSize)) - 1;
4035 unsigned int iPixel = 0;
4037#ifndef USE_OLD_CACHE
4038 pt->pTileOffset[0].offset = lp - pt->pPix;
4039 pt->pTileOffset[0].pixel = 0;
4040 unsigned int tileindex = 1, nextTile = TILE_SIZE;
4042 unsigned int nRunCount;
4043 unsigned char *end = pt->pPix + pt->size;
4044 while (iPixel < (
unsigned int)Size_X)
4047 nPixValue = (byNext & byValueMask) >> nValueShift;
4049 nRunCount = byNext & byCountMask;
4051 while ((byNext & 0x80) != 0) {
4053 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4058 if (iPixel + nRunCount >
4059 (
unsigned int)Size_X)
4060 nRunCount = nRunCount - iPixel;
4063 memset_short(pCL + iPixel, nPixValue, nRunCount);
4064 iPixel += nRunCount;
4069 if (pos < pt->size) {
4075 unsigned char *offset = lp - 1;
4076 if (byNext == 0 || lp == end) {
4078 while (tileindex < (
unsigned int)Size_X / TILE_SIZE + 1) {
4079 pt->pTileOffset[tileindex].offset = pt->pTileOffset[0].offset;
4080 pt->pTileOffset[tileindex].pixel = 0;
4086 nRunCount = byNext & byCountMask;
4088 while ((byNext & 0x80) != 0) {
4089 if (pos < pt->size) {
4095 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4100 if (iPixel + nRunCount >
4101 (
unsigned int)Size_X)
4102 nRunCount = Size_X - iPixel;
4104 while (iPixel + nRunCount > nextTile) {
4105 pt->pTileOffset[tileindex].offset = offset - pt->pPix;
4106 pt->pTileOffset[tileindex].pixel = iPixel;
4108 nextTile += TILE_SIZE;
4110 iPixel += nRunCount;
4119 if (xl > Size_X) xl = Size_X;
4122 pCL = pt->pPix + xs;
4125 if ((BPP == 24) && (1 == sub_samp)) {
4127 while (ix < xl - 1) {
4128 unsigned char cur_by = *pCL;
4129 rgbval = (int)(pPalette[cur_by]);
4130 while ((ix < xl - 1)) {
4131 if (cur_by != *pCL)
break;
4132 *((
int *)prgb) = rgbval;
4139 int dest_inc_val_bytes = (BPP / 8) * sub_samp;
4141 while (ix < xl - 1) {
4142 unsigned char cur_by = *pCL;
4143 rgbval = (int)(pPalette[cur_by]);
4144 while ((ix < xl - 1)) {
4145 if (cur_by != *pCL)
break;
4146 *((
int *)prgb) = rgbval;
4147 prgb += dest_inc_val_bytes;
4158 unsigned char *pCLast = pt->pPix + (xl - 1);
4159 unsigned char *prgb_last = pLineBuf + ((xl - 1) - xs) * BPP / 8;
4161 rgbval = (int)(pPalette[*pCLast]);
4162 unsigned char a = rgbval & 0xff;
4164 a = (rgbval >> 8) & 0xff;
4166 a = (rgbval >> 16) & 0xff;
4171 int tileindex = xs / TILE_SIZE;
4172 int tileoffset = pt->pTileOffset[tileindex].offset;
4174 lp = pt->pPix + tileoffset;
4176 ix = pt->pTileOffset[tileindex].pixel;
4180 nValueShift = 7 - nColorSize;
4181 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
4182 byCountMask = (1 << (7 - nColorSize)) - 1;
4184 bool bLastPixValueValid =
false;
4185 while (ix < xl - 1) {
4186 if (pos < pt->size) {
4193 nPixValue = (byNext & byValueMask) >> nValueShift;
4194 unsigned int nRunCount;
4197 nRunCount = xl - ix;
4199 nRunCount = byNext & byCountMask;
4200 while ((byNext & 0x80) != 0) {
4201 if (pos < pt->size) {
4205 nRunCount = xl - ix;
4208 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4215 if (ix + nRunCount <= (
unsigned int)xs) {
4219 nRunCount -= xs - ix;
4223 if (ix + nRunCount >= (
unsigned int)xl) {
4224 nRunCount = xl - 1 - ix;
4225 bLastPixValueValid =
true;
4228 rgbval = (int)(pPalette[nPixValue]);
4234 int count = nRunCount;
4238 *(uint32_t *)prgb = rgbval;
4241 }
else if (rgbval == 0 || rgbval == 0xffffff) {
4243 memset(prgb, rgbval, nRunCount * 3);
4244 prgb += nRunCount * 3;
4258 if ((
long)prgb & 7) {
4260 *(uint32_t *)prgb = rgbval;
4262 if (!((
long)prgb & 7)) {
4263 if (count >= 8)
break;
4270 uint64_t *b = (uint64_t *)prgb;
4271 for (
int i = 0; i < 8; i++) {
4272 *(uint32_t *)prgb = rgbval;
4278 uint64_t *y = (uint64_t *)prgb;
4279 int count_d8 = count >> 3;
4280 prgb += 24 * count_d8;
4281 while (count_d8--) {
4288 int rcount = count & 0x7;
4290 *(uint32_t *)prgb = rgbval;
4303 if (!bLastPixValueValid) {
4304 if (pos < pt->size) {
4310 nPixValue = (byNext & byValueMask) >> nValueShift;
4312 rgbval = (int)(pPalette[nPixValue]);
4313 unsigned char a = rgbval & 0xff;
4316 a = (rgbval >> 8) & 0xff;
4318 a = (rgbval >> 16) & 0xff;
4326 if (cnt == 500000) {
4328 printf(
"cache time: %d %f\n", d, ttime / 1000.0);
4335 if (!bUseLineCache) {
4336#ifndef USE_OLD_CACHE
4337 free(pt->pTileOffset);
4345int *ChartBaseBSB::GetPalettePtr(BSB_Color_Capability color_index) {
4346 if (pPalettes[color_index]) {
4347 if (palette_direction == PaletteFwd)
4348 return (
int *)(pPalettes[color_index]->FwdPalette);
4350 return (
int *)(pPalettes[color_index]->RevPalette);
4355PaletteDir ChartBaseBSB::GetPaletteDir(
void) {
4358 RGBO r = pc->GetRGBO();
4367bool ChartBaseBSB::AnalyzeSkew(
void) {
4368 double lonmin = 1000;
4369 double lonmax = -1000;
4370 double latmin = 90.;
4371 double latmax = -90.;
4373 int nlonmin, nlonmax;
4380 for (
int n = 0; n < nRefpoint; n++) {
4382 if (pRefTable[n].lonr > lonmax) {
4383 lonmax = pRefTable[n].lonr;
4386 if (pRefTable[n].lonr < lonmin) {
4387 lonmin = pRefTable[n].lonr;
4392 if (pRefTable[n].latr < latmin) {
4393 latmin = pRefTable[n].latr;
4395 if (pRefTable[n].latr > latmax) {
4396 latmax = pRefTable[n].latr;
4401 if ((lonmin * lonmax) < 0) {
4402 if (pRefTable[nlonmin].xr > pRefTable[nlonmax].xr) {
4404 for (
int n = 0; n < nRefpoint; n++) {
4405 if (pRefTable[n].lonr < 0.0) pRefTable[n].lonr += 360.;
4412 for (
int n = 0; n < nRefpoint; n++) {
4414 if (pRefTable[n].lonr > lonmax) {
4415 lonmax = pRefTable[n].lonr;
4418 if (pRefTable[n].lonr < lonmin) {
4419 lonmin = pRefTable[n].lonr;
4424 if (pRefTable[n].latr < latmin) {
4425 latmin = pRefTable[n].latr;
4427 if (pRefTable[n].latr > latmax) {
4428 latmax = pRefTable[n].latr;
4435 double dist_max = 0.;
4439 for (
int i = 0; i < nRefpoint; i++) {
4440 for (
int j = i + 1; j < nRefpoint; j++) {
4441 double dx = pRefTable[i].xr - pRefTable[j].xr;
4442 double dy = pRefTable[i].yr - pRefTable[j].yr;
4443 double dist = (dx * dx) + (dy * dy);
4444 if (dist > dist_max) {
4452 double apparent_skew = 0;
4454 if (m_projection == PROJECTION_MERCATOR) {
4455 double easting0, easting1, northing0, northing1;
4457 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4458 &easting0, &northing0);
4459 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4460 &easting1, &northing1);
4463 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4464 double skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4465 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4468 apparent_skew = skew_points - skew_proj + 90.;
4471 if (fabs(apparent_skew) > 180.) {
4472 if (apparent_skew < 0.)
4473 apparent_skew += 360.;
4475 apparent_skew -= 360.;
4479 else if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
4480 double easting0, easting1, northing0, northing1;
4482 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4483 &easting0, &northing0);
4484 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4485 &easting1, &northing1);
4488 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4489 double skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4490 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4493 apparent_skew = skew_points - skew_proj + 90.;
4496 if (fabs(apparent_skew) > 180.) {
4497 if (apparent_skew < 0.)
4498 apparent_skew += 360.;
4500 apparent_skew -= 360.;
4503 if (fabs(apparent_skew - m_Chart_Skew) > 2) {
4506 double dskew = fabs(apparent_skew - m_Chart_Skew);
4507 if ((m_proj_lon < lonmin) || (m_proj_lon > lonmax)) {
4509 double tentative_proj_lon = (lonmin + lonmax) / 2.;
4511 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat,
4512 tentative_proj_lon, &easting0, &northing0);
4513 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat,
4514 tentative_proj_lon, &easting1, &northing1);
4517 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4518 skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4519 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4522 apparent_skew = skew_points - skew_proj + 90.;
4525 if (fabs(apparent_skew) > 180.) {
4526 if (apparent_skew < 0.)
4527 apparent_skew += 360.;
4529 apparent_skew -= 360.;
4533 if (fabs(apparent_skew - m_Chart_Skew) < dskew) {
4534 m_proj_lon = tentative_proj_lon;
4540 apparent_skew = m_Chart_Skew;
4542 if (fabs(apparent_skew - m_Chart_Skew) >
4544 m_Chart_Skew = apparent_skew;
4546 wxString msg =
" Warning: Skew override on chart ";
4547 msg.Append(m_FullPath);
4549 msg1.Printf(
" is %5g degrees", apparent_skew);
4560int ChartBaseBSB::AnalyzeRefpoints(
bool b_testSolution) {
4566 float lonmin = 1000;
4567 float lonmax = -1000;
4569 float latmax = -90.;
4571 int plonmin = 100000;
4573 int platmin = 100000;
4575 int nlonmin = 0, nlonmax = 0;
4580 for (n = 0; n < nRefpoint; n++) {
4582 if (pRefTable[n].lonr > lonmax) {
4583 lonmax = pRefTable[n].lonr;
4584 plonmax = (int)pRefTable[n].xr;
4587 if (pRefTable[n].lonr < lonmin) {
4588 lonmin = pRefTable[n].lonr;
4589 plonmin = (int)pRefTable[n].xr;
4594 if (pRefTable[n].latr < latmin) {
4595 latmin = pRefTable[n].latr;
4596 platmin = (int)pRefTable[n].yr;
4598 if (pRefTable[n].latr > latmax) {
4599 latmax = pRefTable[n].latr;
4600 platmax = (int)pRefTable[n].yr;
4605 if ((lonmin * lonmax) < 0) {
4606 if (pRefTable[nlonmin].xr > pRefTable[nlonmax].xr) {
4608 for (n = 0; n < nRefpoint; n++) {
4609 if (pRefTable[n].lonr < 0.0) pRefTable[n].lonr += 360.;
4616 for (n = 0; n < nRefpoint; n++) {
4618 if (pRefTable[n].lonr > lonmax) {
4619 lonmax = pRefTable[n].lonr;
4620 plonmax = (int)pRefTable[n].xr;
4623 if (pRefTable[n].lonr < lonmin) {
4624 lonmin = pRefTable[n].lonr;
4625 plonmin = (int)pRefTable[n].xr;
4630 if (pRefTable[n].latr < latmin) {
4631 latmin = pRefTable[n].latr;
4632 platmin = (int)pRefTable[n].yr;
4634 if (pRefTable[n].latr > latmax) {
4635 latmax = pRefTable[n].latr;
4636 platmax = (int)pRefTable[n].yr;
4643 cPoints.
count = nRefpoint;
4657 cPoints.
tx = (
double *)malloc(nRefpoint *
sizeof(
double));
4658 cPoints.
ty = (
double *)malloc(nRefpoint *
sizeof(
double));
4659 cPoints.
lon = (
double *)malloc(nRefpoint *
sizeof(
double));
4660 cPoints.
lat = (
double *)malloc(nRefpoint *
sizeof(
double));
4662 cPoints.
pwx = (
double *)malloc(12 *
sizeof(
double));
4663 cPoints.
wpx = (
double *)malloc(12 *
sizeof(
double));
4664 cPoints.
pwy = (
double *)malloc(12 *
sizeof(
double));
4665 cPoints.
wpy = (
double *)malloc(12 *
sizeof(
double));
4669 double dist_max = 0.;
4673 for (i = 0; i < nRefpoint; i++) {
4674 for (
int j = i + 1; j < nRefpoint; j++) {
4675 double dx = pRefTable[i].xr - pRefTable[j].xr;
4676 double dy = pRefTable[i].yr - pRefTable[j].yr;
4677 double dist = (dx * dx) + (dy * dy);
4678 if (dist > dist_max) {
4688 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
4689 double easting0, easting1, northing0, northing1;
4691 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4692 &easting0, &northing0);
4693 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4694 &easting1, &northing1);
4697 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4698 (pRefTable[jmax].xr - pRefTable[imax].xr);
4699 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4700 (pRefTable[jmax].yr - pRefTable[imax].yr);
4701 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4702 double de2 = (easting1 - easting0) * (easting1 - easting0);
4704 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4709 for (
int n = 0; n < nRefpoint; n++) {
4710 double easting, northing;
4711 toTM(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4712 &easting, &northing);
4714 cPoints.
tx[n] = pRefTable[n].xr;
4715 cPoints.
ty[n] = pRefTable[n].yr;
4716 cPoints.
lon[n] = easting;
4717 cPoints.
lat[n] = northing;
4721 cPoints.
txmax = plonmax;
4722 cPoints.
txmin = plonmin;
4723 cPoints.
tymax = platmax;
4724 cPoints.
tymin = platmin;
4725 toTM(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.
lonmax,
4727 toTM(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.
lonmin,
4730 Georef_Calculate_Coefficients_Proj(&cPoints);
4734 else if (m_projection == PROJECTION_MERCATOR) {
4735 double easting0, easting1, northing0, northing1;
4737 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4738 &easting0, &northing0);
4739 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4740 &easting1, &northing1);
4747 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4748 (pRefTable[jmax].xr - pRefTable[imax].xr);
4749 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4750 (pRefTable[jmax].yr - pRefTable[imax].yr);
4751 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4752 double de2 = (easting1 - easting0) * (easting1 - easting0);
4754 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4759 for (
int n = 0; n < nRefpoint; n++) {
4760 double easting, northing;
4761 toSM_ECC(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4762 &easting, &northing);
4764 cPoints.
tx[n] = pRefTable[n].xr;
4765 cPoints.
ty[n] = pRefTable[n].yr;
4766 cPoints.
lon[n] = easting;
4767 cPoints.
lat[n] = northing;
4774 cPoints.
txmax = plonmax;
4775 cPoints.
txmin = plonmin;
4776 cPoints.
tymax = platmax;
4777 cPoints.
tymin = platmin;
4778 toSM_ECC(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.
lonmax,
4780 toSM_ECC(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.
lonmin,
4783 Georef_Calculate_Coefficients_Proj(&cPoints);
4805 else if (m_projection == PROJECTION_POLYCONIC) {
4814 double proj_meridian = m_proj_lon;
4816 if ((pRefTable[nlonmax].lonr >= -proj_meridian) &&
4817 (-proj_meridian >= pRefTable[nlonmin].lonr))
4818 m_proj_lon = -m_proj_lon;
4820 double easting0, easting1, northing0, northing1;
4822 toPOLY(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4823 &easting0, &northing0);
4824 toPOLY(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4825 &easting1, &northing1);
4828 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4829 (pRefTable[jmax].xr - pRefTable[imax].xr);
4830 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4831 (pRefTable[jmax].yr - pRefTable[imax].yr);
4832 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4833 double de2 = (easting1 - easting0) * (easting1 - easting0);
4835 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4848 for (
int n = 0; n < nRefpoint; n++) {
4849 double easting, northing;
4850 toPOLY(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4851 &easting, &northing);
4858 cPoints.
tx[n] = pRefTable[n].xr;
4859 cPoints.
ty[n] = pRefTable[n].yr;
4860 cPoints.
lon[n] = easting;
4861 cPoints.
lat[n] = northing;
4868 cPoints.
txmax = plonmax;
4869 cPoints.
txmin = plonmin;
4870 cPoints.
tymax = platmax;
4871 cPoints.
tymin = platmin;
4872 toPOLY(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.
lonmax,
4874 toPOLY(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.
lonmin,
4877 Georef_Calculate_Coefficients_Proj(&cPoints);
4889 else if (bHaveEmbeddedGeoref) {
4891 double easting0, easting1, northing0, northing1;
4893 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4894 &easting0, &northing0);
4895 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4896 &easting1, &northing1);
4901 double dx = (pRefTable[jmax].xr - pRefTable[imax].xr);
4902 double de = (easting1 - easting0);
4904 m_ppm_avg = fabs(dx / de);
4906 m_ExtraInfo =
"---<<< Warning: Chart georef accuracy may be poor. >>>---";
4915 vps.
clat = pRefTable[0].latr;
4916 vps.
clon = pRefTable[0].lonr;
4923 latlong_to_pix_vp(latmin, (lonmax + lonmin)/2., x1, y1, vps);
4924 latlong_to_pix_vp(latmax, (lonmax + lonmin)/2., x2, y2, vps);
4926 double apparent_skew = (atan2( (y2-y1), (x2-x1) ) * 180./PI) + 90.;
4927 if(apparent_skew < 0.)
4928 apparent_skew += 360;
4929 if(apparent_skew > 360.)
4930 apparent_skew -= 360;
4932 if(fabs( apparent_skew - m_Chart_Skew ) > 2) {
4933 m_Chart_Skew = apparent_skew;
4937 if (!b_testSolution)
return (0);
4941 vp.
clat = pRefTable[0].latr;
4942 vp.
clon = pRefTable[0].lonr;
4948 SetVPRasterParms(vp);
4950 double xpl_err_max = 0;
4951 double ypl_err_max = 0;
4955 pxref = (int)pRefTable[0].xr;
4956 pyref = (int)pRefTable[0].yr;
4958 for (i = 0; i < nRefpoint; i++) {
4959 px = (int)(vp.
pix_width / 2 + pRefTable[i].xr) - pxref;
4960 py = (int)(vp.
pix_height / 2 + pRefTable[i].yr) - pyref;
4962 vp_pix_to_latlong(vp, px, py, &elt, &elg);
4964 double lat_error = elt - pRefTable[i].latr;
4965 pRefTable[i].ypl_error = lat_error;
4967 double lon_error = elg - pRefTable[i].lonr;
4970 if (fabs(lon_error) > 180.) {
4973 else if (lon_error < 0.)
4976 pRefTable[i].xpl_error = lon_error;
4978 if (fabs(pRefTable[i].ypl_error) > fabs(ypl_err_max))
4979 ypl_err_max = pRefTable[i].ypl_error;
4980 if (fabs(pRefTable[i].xpl_error) > fabs(xpl_err_max))
4981 xpl_err_max = pRefTable[i].xpl_error;
4984 Chart_Error_Factor = fmax(fabs(xpl_err_max / (lonmax - lonmin)),
4985 fabs(ypl_err_max / (latmax - latmin)));
4986 double chart_error_meters =
4987 fmax(fabs(xpl_err_max * 60. * 1852.), fabs(ypl_err_max * 60. * 1852.));
4991 double chart_error_pixels = chart_error_meters * 4000. / m_Chart_Scale;
4994 int max_pixel_error = 4;
4996 if (chart_error_pixels > max_pixel_error) {
4998 " VP Final Check: Georeference Chart_Error_Factor on chart ";
4999 msg.Append(m_FullPath);
5001 msg1.Printf(
" is %5g \n nominal pixel error is: %5g",
5002 Chart_Error_Factor, chart_error_pixels);
5007 m_ExtraInfo =
"---<<< Warning: Chart georef accuracy is poor. >>>---";
5013 if ((chart_error_pixels > max_pixel_error) && bHaveEmbeddedGeoref) {
5015 " Trying again with internally calculated georef solution ";
5018 bHaveEmbeddedGeoref =
false;
5019 SetVPRasterParms(vp);
5024 pxref = (int)pRefTable[0].xr;
5025 pyref = (int)pRefTable[0].yr;
5027 for (i = 0; i < nRefpoint; i++) {
5028 px = (int)(vp.
pix_width / 2 + pRefTable[i].xr) - pxref;
5029 py = (int)(vp.
pix_height / 2 + pRefTable[i].yr) - pyref;
5031 vp_pix_to_latlong(vp, px, py, &elt, &elg);
5033 double lat_error = elt - pRefTable[i].latr;
5034 pRefTable[i].ypl_error = lat_error;
5036 double lon_error = elg - pRefTable[i].lonr;
5039 if (fabs(lon_error) > 180.) {
5042 else if (lon_error < 0.)
5045 pRefTable[i].xpl_error = lon_error;
5047 if (fabs(pRefTable[i].ypl_error) > fabs(ypl_err_max))
5048 ypl_err_max = pRefTable[i].ypl_error;
5049 if (fabs(pRefTable[i].xpl_error) > fabs(xpl_err_max))
5050 xpl_err_max = pRefTable[i].xpl_error;
5053 Chart_Error_Factor = fmax(fabs(xpl_err_max / (lonmax - lonmin)),
5054 fabs(ypl_err_max / (latmax - latmin)));
5056 chart_error_meters =
5057 fmax(fabs(xpl_err_max * 60. * 1852.), fabs(ypl_err_max * 60. * 1852.));
5058 chart_error_pixels = chart_error_meters * 4000. / m_Chart_Scale;
5061 if (chart_error_pixels > max_pixel_error) {
5063 " VP Final Check with internal georef: Georeference "
5064 "Chart_Error_Factor on chart ";
5065 msg.Append(m_FullPath);
5067 msg1.Printf(
" is %5g\n nominal pixel error is: %5g",
5068 Chart_Error_Factor, chart_error_pixels);
5073 m_ExtraInfo =
"---<<< Warning: Chart georef accuracy is poor. >>>---";
5075 wxString msg =
" Result: OK, Internal georef solution used.";
5086double ChartBaseBSB::AdjustLongitude(
double lon) {
5087 double lond = (m_LonMin + m_LonMax) / 2 - lon;
5090 else if (lond < -180)
5126static double polytrans(
double *coeff,
double lon,
double lat) {
5127 double ret = coeff[0] + coeff[1] * lon + coeff[2] * lat;
5128 ret += coeff[3] * lon * lon;
5129 ret += coeff[4] * lon * lat;
5130 ret += coeff[5] * lat * lat;
5131 ret += coeff[6] * lon * lon * lon;
5132 ret += coeff[7] * lon * lon * lat;
5133 ret += coeff[8] * lon * lat * lat;
5134 ret += coeff[9] * lat * lat * lat;
5156extern int bsb_LLtoXY(BSBImage *p,
double lon,
double lat,
int* x,
int* y)
5159 lon = (lon < 0) ? lon + p->cph : lon - p->cph;
5160 double xd = polytrans( p->wpx, lon, lat );
5161 double yd = polytrans( p->wpy, lon, lat );
5162 *x = (int)(xd + 0.5);
5163 *y = (int)(yd + 0.5);
5178extern int bsb_XYtoLL(BSBImage *p,
int x,
int y,
double* lonout,
double* latout)
5180 double lon = polytrans( p->pwx, x, y );
5181 lon = (lon < 0) ? lon + p->cph : lon - p->cph;
5183 *latout = polytrans( p->pwy, x, y );
virtual double GetNearestPreferredScalePPM(double target_scale_ppm)
Find the nearest preferred viewport scale (in pixels/meter) for this chart.
double GetClosestValidNaturalScalePPM(double target_scale, double scale_factor_min, double scale_factor_max)
Find closest valid scale that's a power of 2 multiple of chart's native scale.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
int pix_height
Height of the viewport in physical pixels.
int pix_width
Width of the viewport in physical pixels.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
double lonmin
Minimum longitude in reference data.
int count
Number of reference points used.
double lonmax
Maximum longitude in reference data.
int txmin
Minimum x value in target space.
double * pwx
Polynomial coefficients for pixel-to-world longitude transformation.
double * tx
Array of x-coordinates in target (typically pixel) space.
double * wpx
Polynomial coefficients for world-to-pixel x transformation.
double * lat
Array of latitudes corresponding to reference points.
double * lon
Array of longitudes corresponding to reference points.
int status
Status of the georeferencing (0 = valid, other values indicate errors)
int tymin
Minimum y value in target space.
double * ty
Array of y-coordinates in target (typically pixel) space.
int tymax
Maximum y value in target space.
double latmin
Minimum latitude in reference data.
int txmax
Maximum x value in target space.
double latmax
Maximum latitude in reference data.
double * wpy
Polynomial coefficients for world-to-pixel y transformation.
double * pwy
Polynomial coefficients for pixel-to-world latitude transformation.