36#include <wx/wfstream.h>
37#include <wx/tokenzr.h>
38#include <wx/filename.h>
40#include <wx/fileconf.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;
87bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
97ThumbData::ThumbData() { pDIBThumb = NULL; }
99ThumbData::~ThumbData() {
delete pDIBThumb; }
104opncpnPalette::opncpnPalette() {
108 FwdPalette = (
int *)malloc(
sizeof(
int));
109 RevPalette = (
int *)malloc(
sizeof(
int));
114opncpnPalette::~opncpnPalette() {
115 if (NULL != FwdPalette) free(FwdPalette);
116 if (NULL != RevPalette) free(RevPalette);
122ChartBase::ChartBase() {
123 m_depth_unit_id = DEPTH_UNIT_UNKNOWN;
127 m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB;
129 bReadyToRender =
false;
131 Chart_Error_Factor = 0;
133 m_Chart_Scale = 10000;
138 m_pCOVRTablePoints = NULL;
140 m_nNoCOVREntries = 0;
141 m_pNoCOVRTable = NULL;
142 m_pNoCOVRTablePoints = NULL;
144 m_EdDate = wxInvalidDateTime;
146 m_lon_datum_adjust = 0.;
147 m_lat_datum_adjust = 0.;
149 m_projection = PROJECTION_MERCATOR;
152ChartBase::~ChartBase() {
157 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++)
158 free(m_pCOVRTable[j]);
161 free(m_pCOVRTablePoints);
165 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++)
166 free(m_pNoCOVRTable[j]);
168 free(m_pNoCOVRTable);
169 free(m_pNoCOVRTablePoints);
172wxString ChartBase::GetHashKey()
const {
173 wxString key = GetFullPath();
174 wxChar separator = wxFileName::GetPathSeparator();
175 for (
unsigned int pos = 0; pos < key.size(); pos = key.find(separator, pos))
176 key.replace(pos, 1,
"!");
191ChartDummy::ChartDummy() {
193 m_ChartType = CHART_TYPE_DUMMY;
194 m_ChartFamily = CHART_FAMILY_UNKNOWN;
195 m_Chart_Scale = 22000000;
197 m_FullPath =
"No Chart Available";
198 m_Description = m_FullPath;
201ChartDummy::~ChartDummy() {
delete m_pBM; }
203InitReturn ChartDummy::Init(
const wxString &name, ChartInitFlag init_flags) {
207void ChartDummy::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {}
209ThumbData *ChartDummy::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
213bool ChartDummy::UpdateThumbData(
double lat,
double lon) {
return FALSE; }
215bool ChartDummy::GetChartExtent(
Extent *pext) {
224bool ChartDummy::RenderRegionViewOnGL(
const wxGLContext &glc,
227 const LLRegion &Region) {
231bool ChartDummy::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
233 return RenderViewOnDC(dc, VPoint);
236bool ChartDummy::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
237 if (m_pBM && m_pBM->IsOk()) {
238 if ((m_pBM->GetWidth() != VPoint.
pix_width) ||
252 dc.SelectObject(*m_pBM);
254 dc.SetBackground(*wxBLACK_BRUSH);
265void ChartDummy::GetValidCanvasRegion(
const ViewPort &VPoint,
267 pValidRegion->Clear();
268 pValidRegion->Union(0, 0, 1, 1);
271LLRegion ChartDummy::GetValidRegion() {
return LLRegion(); }
276ChartGEO::ChartGEO() { m_ChartType = CHART_TYPE_GEO; }
278ChartGEO::~ChartGEO() {}
280InitReturn ChartGEO::Init(
const wxString &name, ChartInitFlag init_flags) {
281#define BUF_LEN_MAX 4096
283 PreInit(name, init_flags, GLOBAL_COLOR_SCHEME_DAY);
285 char buffer[BUF_LEN_MAX];
288 new wxFFileInputStream(name);
290 m_filesize = wxFileName::GetSize(name);
292 if (!ifs_hdr->IsOk())
return INIT_FAIL_REMOVE;
298 m_Description = m_FullPath;
300 wxFileName GEOFile(m_FullPath);
303 Path = GEOFile.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME);
307 ifs_hdr->SeekI(0, wxFromStart);
311 while ((ReadBSBHdrLine(ifs_hdr, &buffer[0], BUF_LEN_MAX)) != 0) {
312 wxString str_buf(buffer, wxConvUTF8);
313 if (!strncmp(buffer,
"Bitmap", 6)) {
314 wxStringTokenizer tkz(str_buf,
"=");
315 wxString token = tkz.GetNextToken();
316 if (token.IsSameAs(
"Bitmap", TRUE)) {
317 pBitmapFilePath =
new wxString();
320 i = tkz.GetPosition();
321 pBitmapFilePath->Clear();
323 pBitmapFilePath->Append(buffer[i]);
329 else if (!strncmp(buffer,
"Scale", 5)) {
330 wxStringTokenizer tkz(str_buf,
"=");
331 wxString token = tkz.GetNextToken();
332 if (token.IsSameAs(
"Scale", TRUE))
335 i = tkz.GetPosition();
336 m_Chart_Scale = atoi(&buffer[i]);
340 else if (!strncmp(buffer,
"Depth", 5)) {
341 wxStringTokenizer tkz(str_buf,
"=");
342 wxString token = tkz.GetNextToken();
343 if (token.IsSameAs(
"Depth Units", FALSE))
346 i = tkz.GetPosition();
347 wxString str(&buffer[i], wxConvUTF8);
348 m_DepthUnits = str.Trim();
352 else if (!strncmp(buffer,
"Point", 5))
356 sscanf(&buffer[0],
"Point%d=%f %f %d %d", &i, &lnr, <r, &yr, &xr);
359 pRefTable[nRefpoint].xr = xr;
360 pRefTable[nRefpoint].yr = yr;
361 pRefTable[nRefpoint].latr = ltr;
362 pRefTable[nRefpoint].lonr = lnr;
363 pRefTable[nRefpoint].bXValid = 1;
364 pRefTable[nRefpoint].bYValid = 1;
370 else if (!strncmp(buffer,
"Vertex", 6)) {
373 sscanf(buffer,
"Vertex%d=%f %f", &i, <p, &lnp);
377 if (NULL == pPlyTable) {
381 pPlyTable[nPlypoint].ltp = ltp;
382 pPlyTable[nPlypoint].lnp = lnp;
387 else if (!strncmp(buffer,
"Date Pub", 8)) {
388 char date_string[40];
390 sscanf(buffer,
"Date Published=%s\r\n", &date_string[0]);
391 wxString date_wxstr(date_string, wxConvUTF8);
393 if (dt.ParseDate(date_wxstr))
395 sprintf(date_buf,
"%d", dt.GetYear());
397 sscanf(date_string,
"%s", date_buf);
399 m_PubYear = wxString(date_buf, wxConvUTF8);
402 else if (!strncmp(buffer,
"Skew", 4)) {
403 wxStringTokenizer tkz(str_buf,
"=");
404 wxString token = tkz.GetNextToken();
405 if (token.IsSameAs(
"Skew Angle", FALSE))
408 i = tkz.GetPosition();
410 sscanf(&buffer[i],
"%f,", &fcs);
415 else if (!strncmp(buffer,
"Latitude Offset", 15)) {
416 wxStringTokenizer tkz(str_buf,
"=");
417 wxString token = tkz.GetNextToken();
418 if (token.IsSameAs(
"Latitude Offset", FALSE)) {
420 i = tkz.GetPosition();
422 sscanf(&buffer[i],
"%f,", <o);
427 else if (!strncmp(buffer,
"Longitude Offset", 16)) {
428 wxStringTokenizer tkz(str_buf,
"=");
429 wxString token = tkz.GetNextToken();
430 if (token.IsSameAs(
"Longitude Offset", FALSE)) {
432 i = tkz.GetPosition();
434 sscanf(&buffer[i],
"%f,", &lno);
439 else if (!strncmp(buffer,
"Datum", 5)) {
440 wxStringTokenizer tkz(str_buf,
"=");
441 wxString token = tkz.GetNextToken();
442 if (token.IsSameAs(
"Datum", FALSE)) {
443 token = tkz.GetNextToken();
448 else if (!strncmp(buffer,
"Name", 4)) {
449 wxStringTokenizer tkz(str_buf,
"=");
450 wxString token = tkz.GetNextToken();
451 if (token.IsSameAs(
"Name", FALSE))
454 i = tkz.GetPosition();
456 while (isprint(buffer[i]) && (i < 80)) m_Name.Append(buffer[i++]);
468 if (pBitmapFilePath == NULL) {
470 return INIT_FAIL_REMOVE;
473 wxString NOS_Name(*pBitmapFilePath);
475 wxDir target_dir(Path);
476 wxArrayString file_array;
477 int nfiles = wxDir::GetAllFiles(Path, &file_array);
480 pBitmapFilePath->Prepend(Path);
482 wxFileName NOS_filename(*pBitmapFilePath);
483 if (!NOS_filename.FileExists()) {
487 wxString fname(NOS_filename.GetName());
488 wxString fext(NOS_filename.GetExt());
494 NOS_filename.SetName(fname);
495 NOS_filename.SetExt(fext);
497 if (NOS_filename.FileExists())
goto found_uclc_file;
502 NOS_filename.SetName(fname);
503 NOS_filename.SetExt(fext);
505 if (NOS_filename.FileExists())
goto found_uclc_file;
510 NOS_filename.SetName(fname);
511 NOS_filename.SetExt(fext);
513 if (NOS_filename.FileExists())
goto found_uclc_file;
518 NOS_filename.SetName(fname);
519 NOS_filename.SetExt(fext);
521 if (NOS_filename.FileExists())
goto found_uclc_file;
525 for (ifile = 0; ifile < nfiles; ifile++) {
526 wxString file_up = file_array[ifile];
529 wxString target_up = *pBitmapFilePath;
530 target_up.MakeUpper();
532 if (file_up.IsSameAs(target_up)) {
533 NOS_filename.Clear();
534 NOS_filename.Assign(file_array[ifile]);
535 goto found_uclc_file;
540 return INIT_FAIL_REMOVE;
544 delete pBitmapFilePath;
545 pBitmapFilePath =
new wxString(NOS_filename.GetFullPath());
548 new wxFFileInputStream(*pBitmapFilePath);
549 ifs_bitmap =
new wxBufferedInputStream(*ifss_bitmap);
551 if (!ifss_bitmap->IsOk()) {
553 return INIT_FAIL_REMOVE;
556 while ((ReadBSBHdrLine(ifss_bitmap, &buffer[0], BUF_LEN_MAX)) != 0) {
557 wxString str_buf(buffer, wxConvUTF8);
559 if (!strncmp(buffer,
"NOS", 3)) {
560 wxStringTokenizer tkz(str_buf,
",=");
561 while (tkz.HasMoreTokens()) {
562 wxString token = tkz.GetNextToken();
563 if (token.IsSameAs(
"RA", TRUE))
568 i = tkz.GetPosition();
569 Size_X = atoi(&buffer[i]);
570 wxString token = tkz.GetNextToken();
571 i = tkz.GetPosition();
572 Size_Y = atoi(&buffer[i]);
573 }
else if (token.IsSameAs(
"DU", TRUE))
575 token = tkz.GetNextToken();
577 if (token.ToLong(&temp_du)) m_Chart_DU = temp_du;
583 else if (!strncmp(buffer,
"RGB", 3))
584 CreatePaletteEntry(buffer, COLOR_RGB_DEFAULT);
586 else if (!strncmp(buffer,
"DAY", 3))
587 CreatePaletteEntry(buffer, DAY);
589 else if (!strncmp(buffer,
"DSK", 3))
590 CreatePaletteEntry(buffer, DUSK);
592 else if (!strncmp(buffer,
"NGT", 3))
593 CreatePaletteEntry(buffer, NIGHT);
595 else if (!strncmp(buffer,
"NGR", 3))
596 CreatePaletteEntry(buffer, NIGHTRED);
598 else if (!strncmp(buffer,
"GRY", 3))
599 CreatePaletteEntry(buffer, GRAY);
601 else if (!strncmp(buffer,
"PRC", 3))
602 CreatePaletteEntry(buffer, PRC);
604 else if (!strncmp(buffer,
"PRG", 3))
605 CreatePaletteEntry(buffer, PRG);
609 if (Size_X <= 0 || Size_Y <= 0) {
611 return INIT_FAIL_REMOVE;
615 wxString msg(
" Chart File contains less than 3 PLY points: ");
616 msg.Append(m_FullPath);
620 return INIT_FAIL_REMOVE;
623 if (m_datum_str.IsEmpty()) {
624 wxString msg(
" Chart datum not specified on chart ");
625 msg.Append(m_FullPath);
627 wxLogMessage(
" Default datum (WGS84) substituted.");
632 strncpy(d_str, m_datum_str.mb_str(), 99);
635 int datum_index = GetDatumIndex(d_str);
637 if (datum_index < 0) {
638 wxString msg(
" Chart datum {");
640 msg +=
"} invalid on chart ";
641 msg.Append(m_FullPath);
643 wxLogMessage(
" Default datum (WGS84) substituted.");
645 datum_index = DATUM_INDEX_WGS84;
647 m_datum_index = datum_index;
652 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
653 *m_pCOVRTablePoints = nPlypoint;
654 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
655 *m_pCOVRTable = (
float *)malloc(nPlypoint * 2 *
sizeof(
float));
656 memcpy(*m_pCOVRTable, pPlyTable, nPlypoint * 2 *
sizeof(
float));
660 if (!SetMinMax())
return INIT_FAIL_REMOVE;
664 if (init_flags == HEADER_ONLY)
return INIT_OK;
668 if ((c = ifs_bitmap->GetC()) != 0x1a) {
669 return INIT_FAIL_REMOVE;
671 if ((c = ifs_bitmap->GetC()) == 0x0d) {
672 if ((c = ifs_bitmap->GetC()) != 0x0a) {
673 return INIT_FAIL_REMOVE;
675 if ((c = ifs_bitmap->GetC()) != 0x1a) {
676 return INIT_FAIL_REMOVE;
678 if ((c = ifs_bitmap->GetC()) != 0x00) {
679 return INIT_FAIL_REMOVE;
683 else if (c != 0x00) {
684 return INIT_FAIL_REMOVE;
688 nColorSize = ifs_bitmap->GetC();
689 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
690 wxString msg(
" Invalid nColorSize data, corrupt on chart ");
691 msg.Append(m_FullPath);
693 return INIT_FAIL_REMOVE;
697 InitReturn pi_ret = PostInit();
698 if (pi_ret != INIT_OK)
708ChartKAP::ChartKAP() { m_ChartType = CHART_TYPE_KAP; }
710ChartKAP::~ChartKAP() {}
712InitReturn ChartKAP::Init(
const wxString &name, ChartInitFlag init_flags) {
713#define BUF_LEN_MAX 4096
715 ifs_hdr =
new ChartDataNonSeekableInputStream(
718 if (!ifs_hdr->IsOk())
return INIT_FAIL_REMOVE;
723 PreInit(name, init_flags, GLOBAL_COLOR_SCHEME_DAY);
725 char buffer[BUF_LEN_MAX];
728 m_Description = m_FullPath;
731 for (
int icl = 0; icl < 12; icl++) {
741 unsigned int TestBlockSize = 1999;
742 ifs_hdr->Read(buffer, TestBlockSize);
744 if (ifs_hdr->LastRead() != TestBlockSize) {
746 msg.Printf(
" Could not read first %d bytes of header for chart file: ",
751 return INIT_FAIL_REMOVE;
755 for (i = 0; i < TestBlockSize - 4; i++) {
757 if (buffer[i + 0] ==
'B' && buffer[i + 1] ==
'S' && buffer[i + 2] ==
'B' &&
758 buffer[i + 3] ==
'/')
762 if (buffer[i + 0] ==
'N' && buffer[i + 1] ==
'O' && buffer[i + 2] ==
'S' &&
763 buffer[i + 3] ==
'/')
766 if (i == TestBlockSize - 4) {
767 wxString msg(
" Chart file has no BSB header, cannot Init.");
771 return INIT_FAIL_REMOVE;
775 ifs_hdr->SeekI(0, wxFromStart);
779 int done_header_parse = 0;
780 wxCSConv iso_conv(
"ISO-8859-1");
782 while (done_header_parse == 0) {
783 if (ReadBSBHdrLine(ifs_hdr, buffer, BUF_LEN_MAX) == 0) {
789 done_header_parse = 1;
792 return INIT_FAIL_REMOVE;
798 wxString str_buf(buffer, wxConvUTF8);
800 str_buf = wxString(buffer, iso_conv);
802 if (str_buf.Find(
"SHOM") != wxNOT_FOUND) m_b_SHOM =
true;
804 if (!strncmp(buffer,
"BSB", 3)) {
805 wxString clip_str_buf(
808 wxStringTokenizer tkz(clip_str_buf,
"/,=");
809 while (tkz.HasMoreTokens()) {
810 wxString token = tkz.GetNextToken();
811 if (token.IsSameAs(
"RA", TRUE))
814 i = tkz.GetPosition();
815 Size_X = atoi(&buffer[i]);
816 wxString token = tkz.GetNextToken();
817 i = tkz.GetPosition();
818 Size_Y = atoi(&buffer[i]);
819 }
else if (token.IsSameAs(
"NA", TRUE))
821 int i = tkz.GetPosition();
824 while ((buffer[i] !=
',') && (i < 80)) nbuf[j++] = buffer[i++];
826 wxString n_str(nbuf, iso_conv);
828 }
else if (token.IsSameAs(
"NU", TRUE))
830 int i = tkz.GetPosition();
833 while ((buffer[i] !=
',') && (i < 80)) nbuf[j++] = buffer[i++];
835 wxString n_str(nbuf, iso_conv);
837 }
else if (token.IsSameAs(
"DU", TRUE))
839 token = tkz.GetNextToken();
841 if (token.ToLong(&temp_du)) m_Chart_DU = temp_du;
846 else if (!strncmp(buffer,
"KNP", 3)) {
847 wxString conv_buf(buffer, iso_conv);
848 wxStringTokenizer tkz(conv_buf,
"/,=");
849 while (tkz.HasMoreTokens()) {
850 wxString token = tkz.GetNextToken();
851 if (token.IsSameAs(
"SC", TRUE))
854 i = tkz.GetPosition();
855 m_Chart_Scale = atoi(&buffer[i]);
856 if (0 == m_Chart_Scale) m_Chart_Scale = 100000000;
857 }
else if (token.IsSameAs(
"SK", TRUE))
860 i = tkz.GetPosition();
862 sscanf(&buffer[i],
"%f,", &fcs);
864 }
else if (token.IsSameAs(
"UN", TRUE))
867 i = tkz.GetPosition();
868 wxString str(&buffer[i], iso_conv);
869 m_DepthUnits = str.BeforeFirst(
',');
870 }
else if (token.IsSameAs(
"GD", TRUE))
873 i = tkz.GetPosition();
874 wxString str(&buffer[i], iso_conv);
875 m_datum_str = str.BeforeFirst(
',').Trim();
876 }
else if (token.IsSameAs(
"SD", TRUE))
879 i = tkz.GetPosition();
880 wxString str(&buffer[i], iso_conv);
881 m_SoundingsDatum = str.BeforeFirst(
',').Trim();
882 }
else if (token.IsSameAs(
"PP",
886 i = tkz.GetPosition();
888 wxString str(&buffer[i], iso_conv);
889 wxString str1 = str.BeforeFirst(
',').Trim();
890 if (str1.ToDouble(&fcs)) m_proj_parameter = fcs;
891 }
else if (token.IsSameAs(
"PR", TRUE))
894 i = tkz.GetPosition();
895 wxString str(&buffer[i], iso_conv);
896 wxString stru = str.MakeUpper();
900 if (stru.Matches(
"*MERCATOR*")) {
901 m_projection = PROJECTION_MERCATOR;
905 if (stru.Matches(
"*TRANSVERSE*")) {
906 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
910 if (stru.Matches(
"*CONIC*")) {
911 m_projection = PROJECTION_POLYCONIC;
915 if (stru.Matches(
"*TM*")) {
916 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
920 if (stru.Matches(
"*GAUSS CONFORMAL*")) {
921 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
926 m_projection = PROJECTION_UNKNOWN;
927 wxString msg(
" Chart projection is ");
928 msg += tkz.GetNextToken();
929 msg +=
" which is unsupported. Disabling chart ";
933 return INIT_FAIL_REMOVE;
935 }
else if (token.IsSameAs(
940 i = tkz.GetPosition();
942 sscanf(&buffer[i],
"%f,", &x);
944 }
else if (token.IsSameAs(
949 i = tkz.GetPosition();
951 sscanf(&buffer[i],
"%f,", &x);
957 else if (!strncmp(buffer,
"RGB", 3))
958 CreatePaletteEntry(buffer, COLOR_RGB_DEFAULT);
960 else if (!strncmp(buffer,
"DAY", 3))
961 CreatePaletteEntry(buffer, DAY);
963 else if (!strncmp(buffer,
"DSK", 3))
964 CreatePaletteEntry(buffer, DUSK);
966 else if (!strncmp(buffer,
"NGT", 3))
967 CreatePaletteEntry(buffer, NIGHT);
969 else if (!strncmp(buffer,
"NGR", 3))
970 CreatePaletteEntry(buffer, NIGHTRED);
972 else if (!strncmp(buffer,
"GRY", 3))
973 CreatePaletteEntry(buffer, GRAY);
975 else if (!strncmp(buffer,
"PRC", 3))
976 CreatePaletteEntry(buffer, PRC);
978 else if (!strncmp(buffer,
"PRG", 3))
979 CreatePaletteEntry(buffer, PRG);
981 else if (!strncmp(buffer,
"REF", 3)) {
984 sscanf(&buffer[4],
"%d,%d,%d,%f,%f", &i, &xr, &yr, <r, &lnr);
987 pRefTable[nRefpoint].xr = xr;
988 pRefTable[nRefpoint].yr = yr;
989 pRefTable[nRefpoint].latr = ltr;
990 pRefTable[nRefpoint].lonr = lnr;
991 pRefTable[nRefpoint].bXValid = 1;
992 pRefTable[nRefpoint].bYValid = 1;
998 else if (!strncmp(buffer,
"WPX", 3)) {
1001 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1002 wxString token = tkz.GetNextToken();
1004 if (token.ToLong((
long int *)&wpx_type)) {
1005 while (tkz.HasMoreTokens() && (idx < 12)) {
1006 token = tkz.GetNextToken();
1007 if (token.ToDouble(&d)) {
1016 else if (!strncmp(buffer,
"WPY", 3)) {
1019 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1020 wxString token = tkz.GetNextToken();
1022 if (token.ToLong((
long int *)&wpy_type)) {
1023 while (tkz.HasMoreTokens() && (idx < 12)) {
1024 token = tkz.GetNextToken();
1025 if (token.ToDouble(&d)) {
1034 else if (!strncmp(buffer,
"PWX", 3)) {
1037 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1038 wxString token = tkz.GetNextToken();
1040 if (token.ToLong((
long int *)&pwx_type)) {
1041 while (tkz.HasMoreTokens() && (idx < 12)) {
1042 token = tkz.GetNextToken();
1043 if (token.ToDouble(&d)) {
1052 else if (!strncmp(buffer,
"PWY", 3)) {
1055 wxStringTokenizer tkz(str_buf.Mid(4),
",");
1056 wxString token = tkz.GetNextToken();
1058 if (token.ToLong((
long int *)&pwy_type)) {
1059 while (tkz.HasMoreTokens() && (idx < 12)) {
1060 token = tkz.GetNextToken();
1061 if (token.ToDouble(&d)) {
1070 else if (!strncmp(buffer,
"CPH", 3)) {
1072 sscanf(&buffer[4],
"%f", &float_cph);
1076 else if (!strncmp(buffer,
"VER", 3)) {
1077 wxStringTokenizer tkz(str_buf,
"/,=");
1078 wxString token = tkz.GetNextToken();
1080 m_bsb_ver = tkz.GetNextToken();
1083 else if (!strncmp(buffer,
"DTM", 3)) {
1085 wxStringTokenizer tkz(str_buf,
"/,=");
1086 wxString token = tkz.GetNextToken();
1088 token = tkz.GetNextToken();
1089 if (token.ToDouble(&val)) m_dtm_lat = val;
1091 token = tkz.GetNextToken();
1092 if (token.ToDouble(&val)) m_dtm_lon = val;
1100 else if (!strncmp(buffer,
"PLY", 3)) {
1103 if (sscanf(&buffer[4],
"%d,%f,%f", &i, <p, &lnp) != 3) {
1105 return INIT_FAIL_REMOVE;
1110 if (NULL == pPlyTable) {
1114 pPlyTable[nPlypoint].ltp = ltp;
1115 pPlyTable[nPlypoint].lnp = lnp;
1118 if (NULL == pPlyTable || nPlypoint > 1000000) {
1125 else if (!strncmp(buffer,
"CED", 3)) {
1126 wxStringTokenizer tkz(str_buf,
"/,=");
1127 while (tkz.HasMoreTokens()) {
1128 wxString token = tkz.GetNextToken();
1129 if (token.IsSameAs(
"ED", TRUE))
1132 i = tkz.GetPosition();
1134 char date_string[40];
1138 sscanf(&buffer[i],
"%s\r\n", date_string);
1139 wxString date_wxstr(date_string, wxConvUTF8);
1142 if (dt.ParseDate(date_wxstr))
1153 }
else if ((iyear >= 50) && (iyear < 100)) {
1157 assert(iyear <= 9999);
1158 sprintf(date_buf,
"%d", iyear);
1163 sscanf(date_string,
"%s", date_buf);
1164 m_EdDate.Set(1, wxDateTime::Jan,
1168 m_PubYear = wxString(date_buf, wxConvUTF8);
1169 }
else if (token.IsSameAs(
"SE", TRUE))
1172 i = tkz.GetPosition();
1173 wxString str(&buffer[i], iso_conv);
1174 m_SE = str.BeforeFirst(
',');
1182 if (m_b_SHOM && (m_bsb_ver ==
"1.1")) m_b_apply_dtm =
false;
1186 if (n_pwx && n_pwy && n_pwx && n_pwy) bHaveEmbeddedGeoref =
true;
1189 if (m_projection == PROJECTION_MERCATOR)
1190 m_proj_lat = m_proj_parameter;
1191 else if (m_projection == PROJECTION_TRANSVERSE_MERCATOR)
1192 m_proj_lon = m_proj_parameter;
1193 else if (m_projection == PROJECTION_POLYCONIC)
1194 m_proj_lon = m_proj_parameter;
1198 if (m_proj_lat > 82.0 || m_proj_lat < -82.0) m_proj_lat = 0.0;
1201 if (Size_X <= 0 || Size_Y <= 0) {
1203 return INIT_FAIL_REMOVE;
1206 if (nPlypoint < 3) {
1207 wxString msg(
" Chart File contains less than 3 or too many PLY points: ");
1208 msg.Append(m_FullPath);
1211 return INIT_FAIL_REMOVE;
1214 if (m_datum_str.IsEmpty()) {
1215 wxString msg(
" Chart datum not specified on chart ");
1216 msg.Append(m_FullPath);
1218 wxLogMessage(
" Default datum (WGS84) substituted.");
1223 strncpy(d_str, m_datum_str.mb_str(), 99);
1226 int datum_index = GetDatumIndex(d_str);
1228 if (datum_index < 0) {
1229 wxString msg(
" Chart datum {");
1231 msg +=
"} invalid on chart ";
1232 msg.Append(m_FullPath);
1234 wxLogMessage(
" Default datum (WGS84) substituted.");
1246 if ((m_projection != PROJECTION_MERCATOR &&
1247 m_projection != PROJECTION_TRANSVERSE_MERCATOR) ||
1250 AnalyzeRefpoints(
false);
1259 for (
int i = 0; i < nPlypoint; i++) {
1260 m_LatMax = wxMax(m_LatMax, pPlyTable[i].ltp);
1261 m_LatMin = wxMin(m_LatMin, pPlyTable[i].ltp);
1262 m_LonMax = wxMax(m_LonMax, pPlyTable[i].lnp);
1263 m_LonMin = wxMin(m_LonMin, pPlyTable[i].lnp);
1266 int count = nPlypoint;
1268 Plypoint *pOldPlyTable = pPlyTable;
1270 double lastplylat = 0.0, lastplylon = 0.0, x1 = 0.0, y1 = 0.0, x2, y2;
1271 double plylat, plylon;
1272 for (
int i = 0; i < count + 1; i++) {
1273 plylat = pOldPlyTable[i % count].ltp;
1274 plylon = pOldPlyTable[i % count].lnp;
1275 latlong_to_chartpix(plylat, plylon, x2, y2);
1277 if (lastplylon - plylon > 180.)
1279 else if (lastplylon - plylon < -180.)
1284 ceil((fabs(lastplylat - plylat) + fabs(lastplylon - plylon)) / 2);
1285 for (
double c = 0; c < steps; c++) {
1286 double d = c / steps, lat, lon;
1288 double x = (1 - d) * x1 + d * x2, y = (1 - d) * y1 + d * y2;
1289 chartpix_to_latlong(x, y, &lat, &lon);
1290 pPlyTable = (
Plypoint *)realloc(pPlyTable,
1291 sizeof(
Plypoint) * (nPlypoint + 1));
1292 pPlyTable[nPlypoint].ltp = lat;
1293 pPlyTable[nPlypoint].lnp = lon;
1298 lastplylat = plylat, lastplylon = plylon;
1312 for (
int i = 0; i < nPlypoint; i++) {
1313 m_LonMin = wxMin(m_LonMin, pPlyTable[i].lnp);
1314 m_LonMax = wxMax(m_LonMax, pPlyTable[i].lnp);
1318 bool b_adjusted =
false;
1319 if (m_LonMax * m_LonMin < 0) {
1320 if ((m_LonMax - m_LonMin) > 180.) b_test =
false;
1324 if (!bHaveEmbeddedGeoref) {
1327 AnalyzeRefpoints(
false);
1330 bool bAdjustPly =
false;
1331 wxRect bitRect(0, 0, Size_X, Size_Y);
1333 for (
int i = 0; i < nPlypoint; i++) {
1334 double pix_x, pix_y;
1335 latlong_to_chartpix(pPlyTable[i].ltp, pPlyTable[i].lnp, pix_x, pix_y);
1336 if (!bitRect.Contains(pix_x, pix_y)) {
1339 printf(
"Adjusting COVR region on: %s\n", name.ToUTF8().data());
1345 float *points =
new float[2 * nPlypoint];
1346 for (
int i = 0; i < nPlypoint; i++)
1347 points[2 * i + 0] = pPlyTable[i].ltp,
1348 points[2 * i + 1] = pPlyTable[i].lnp;
1349 LLRegion covrRegion(nPlypoint, points);
1351 covrRegion.Intersect(GetValidRegion());
1353 if (covrRegion.contours.size()) {
1355 m_nCOVREntries = covrRegion.contours.size();
1356 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
1357 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
1358 auto it = covrRegion.contours.begin();
1359 for (
int i = 0; i < m_nCOVREntries; i++) {
1360 m_pCOVRTablePoints[i] = it->size();
1362 (
float *)malloc(m_pCOVRTablePoints[i] * 2 *
sizeof(
float));
1363 auto jt = it->begin();
1364 for (
int j = 0; j < m_pCOVRTablePoints[i]; j++) {
1365 m_pCOVRTable[i][2 * j + 0] = jt->y;
1366 m_pCOVRTable[i][2 * j + 1] = jt->x;
1378 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
1379 *m_pCOVRTablePoints = nPlypoint;
1380 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
1381 *m_pCOVRTable = (
float *)malloc(nPlypoint * 2 *
sizeof(
float));
1382 memcpy(*m_pCOVRTable, pPlyTable, nPlypoint * 2 *
sizeof(
float));
1389 strncpy(d_str, m_datum_str.mb_str(), 99);
1392 int datum_index = GetDatumIndex(d_str);
1393 m_datum_index = datum_index;
1395 if (datum_index < 0)
1396 m_ExtraInfo =
"---<<< Warning: Chart Datum may be incorrect. >>>---";
1399 m_lon_datum_adjust = (-m_dtm_lon) / 3600.;
1400 m_lat_datum_adjust = (-m_dtm_lat) / 3600.;
1404 int cnPlypoint = GetCOVRTablenPoints(0);
1406 for (
int u = 0; u < cnPlypoint; u++) {
1410 if (m_datum_index == DATUM_INDEX_WGS84 ||
1411 m_datum_index == DATUM_INDEX_UNKNOWN) {
1412 dlon = m_dtm_lon / 3600.;
1413 dlat = m_dtm_lat / 3600.;
1417 double to_lat, to_lon;
1418 MolodenskyTransform(ppp->ltp, ppp->lnp, &to_lat, &to_lon, m_datum_index,
1420 dlon = (to_lon - ppp->lnp);
1421 dlat = (to_lat - ppp->ltp);
1422 if (m_b_apply_dtm) {
1423 dlon += m_dtm_lon / 3600.;
1424 dlat += m_dtm_lat / 3600.;
1433 if (!SetMinMax())
return INIT_FAIL_REMOVE;
1437 if (init_flags == HEADER_ONLY)
return INIT_OK;
1441 bool bcorrupt =
false;
1443 if ((c = ifs_hdr->GetC()) != 0x1a) {
1446 if ((c = ifs_hdr->GetC()) == 0x0d) {
1447 if ((c = ifs_hdr->GetC()) != 0x0a) {
1450 if ((c = ifs_hdr->GetC()) != 0x1a) {
1453 if ((c = ifs_hdr->GetC()) != 0x00) {
1458 else if (c != 0x00) {
1463 wxString msg(
" Chart File RLL data corrupt on chart ");
1464 msg.Append(m_FullPath);
1467 return INIT_FAIL_REMOVE;
1471 nColorSize = ifs_hdr->GetC();
1472 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
1473 wxString msg(
" Invalid nColorSize data, corrupt on chart ");
1474 msg.Append(m_FullPath);
1476 return INIT_FAIL_REMOVE;
1479 nFileOffsetDataStart = ifs_hdr->TellI();
1483 ChartDataInputStream *stream =
1484 new ChartDataInputStream(name);
1487 tempfile = stream->TempFileName();
1489 m_filesize = wxFileName::GetSize(tempfile.empty() ? name : tempfile);
1491 ifss_bitmap = stream;
1492 ifs_bitmap =
new wxBufferedInputStream(*ifss_bitmap);
1495 InitReturn pi_ret = PostInit();
1496 if (pi_ret != INIT_OK)
return pi_ret;
1504ChartBaseBSB::ChartBaseBSB() {
1506 m_ChartFamily = CHART_FAMILY_RASTER;
1508 pBitmapFilePath = NULL;
1513 cached_image_ok = 0;
1518 bHaveEmbeddedGeoref =
false;
1525 bUseLineCache =
false;
1527 bUseLineCache =
true;
1536 m_bilinear_limit = 8;
1542 for (
int i = 0; i < N_BSB_COLORS; i++) pPalettes[i] = NULL;
1544 bGeoErrorSent =
false;
1548 m_mapped_color_index = COLOR_RGB_DEFAULT;
1550 m_datum_str =
"WGS84";
1559 m_proj_parameter = 0.;
1561 m_b_apply_dtm =
true;
1565#ifdef OCPN_USE_CONFIG
1566 wxFileConfig *pfc = (wxFileConfig *)
pConfig;
1567 pfc->SetPath(
"/Settings");
1568 pfc->Read(
"DebugBSBImg", &m_b_cdebug, 0);
1572ChartBaseBSB::~ChartBaseBSB() {
1573 if (pBitmapFilePath)
delete pBitmapFilePath;
1575 if (pline_table) free(pline_table);
1577 if (ifs_buf) free(ifs_buf);
1599 FreeLineCacheRows();
1604 for (
int i = 0; i < N_BSB_COLORS; i++)
delete pPalettes[i];
1607void ChartBaseBSB::FreeLineCacheRows(
int start,
int end) {
1612 end = wxMin(end, Size_Y);
1613 for (
int ylc = start; ylc < end; ylc++) {
1616 free(pt->pTileOffset);
1624bool ChartBaseBSB::HaveLineCacheRow(
int row) {
1635double ChartBaseBSB::GetNormalScaleMin(
double canvas_scale_factor,
1636 bool b_allow_overzoom) {
1638 return (canvas_scale_factor / m_ppm_avg) /
1645double ChartBaseBSB::GetNormalScaleMax(
double canvas_scale_factor,
1647 return (canvas_scale_factor / m_ppm_avg) *
1653 target_scale_ppm, .01, 64.);
1658 double scale_factor_min,
1659 double scale_factor_max) {
1660 double chart_1x_scale = GetPPM();
1662 double binary_scale_factor = 1.;
1665 if (chart_1x_scale > target_scale) {
1666 double binary_scale_factor_max = 1 / scale_factor_min;
1668 while (binary_scale_factor < binary_scale_factor_max) {
1669 if (fabs((chart_1x_scale / binary_scale_factor) - target_scale) <
1670 (target_scale * 0.05))
1672 if ((chart_1x_scale / binary_scale_factor) < target_scale)
1675 binary_scale_factor *= 2.;
1682 int isf_max = (int)scale_factor_max;
1683 while (ibsf < isf_max) {
1684 if (fabs((chart_1x_scale * ibsf) - target_scale) < (target_scale * 0.05))
1687 else if ((chart_1x_scale * ibsf) > target_scale) {
1688 if (ibsf > 1) ibsf /= 2;
1694 binary_scale_factor = 1. / ibsf;
1697 return chart_1x_scale / binary_scale_factor;
1700InitReturn ChartBaseBSB::Init(
const wxString &name, ChartInitFlag init_flags) {
1701 m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB;
1705InitReturn ChartBaseBSB::PreInit(
const wxString &name, ChartInitFlag init_flags,
1707 m_global_color_scheme = cs;
1711void ChartBaseBSB::CreatePaletteEntry(
char *buffer,
int palette_index) {
1712 if (palette_index < N_BSB_COLORS) {
1713 if (!pPalettes[palette_index]) pPalettes[palette_index] =
new opncpnPalette;
1717 (
int *)realloc(pp->FwdPalette, (pp->nFwd + 1) *
sizeof(int));
1719 (
int *)realloc(pp->RevPalette, (pp->nRev + 1) *
sizeof(int));
1725 sscanf(&buffer[4],
"%d,%d,%d,%d", &n, &r, &g, &b);
1730 fcolor = (b << 16) + (g << 8) + r;
1731 rcolor = (r << 16) + (g << 8) + b;
1733 pp->RevPalette[i] = rcolor;
1734 pp->FwdPalette[i] = fcolor;
1738InitReturn ChartBaseBSB::PostInit() {
1740 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
1741 wxString msg(
" Invalid nColorSize data, corrupt in PostInit() on chart ");
1742 msg.Append(m_FullPath);
1744 return INIT_FAIL_REMOVE;
1747 if (Size_X <= 0 || Size_X > INT_MAX / 4 || Size_Y <= 0 ||
1748 Size_Y - 1 > INT_MAX / 4) {
1750 " Invalid Size_X/Size_Y data, corrupt in PostInit() on chart ");
1751 msg.Append(m_FullPath);
1753 return INIT_FAIL_REMOVE;
1759 if (pPalettes[COLOR_RGB_DEFAULT]) {
1760 nrev_def = pPalettes[COLOR_RGB_DEFAULT]->nRev;
1761 nfwd_def = pPalettes[COLOR_RGB_DEFAULT]->nFwd;
1764 for (
int i = 0; i < N_BSB_COLORS; i++) {
1765 if (pPalettes[i] == NULL) {
1768 pNullSubPal->nFwd = nfwd_def;
1769 pNullSubPal->nRev = nrev_def;
1771 free(pNullSubPal->FwdPalette);
1772 pNullSubPal->FwdPalette = (
int *)malloc(pNullSubPal->nFwd *
sizeof(
int));
1773 if (pPalettes[COLOR_RGB_DEFAULT])
1774 memcpy(pNullSubPal->FwdPalette,
1775 pPalettes[COLOR_RGB_DEFAULT]->FwdPalette,
1776 pNullSubPal->nFwd *
sizeof(
int));
1778 free(pNullSubPal->RevPalette);
1779 pNullSubPal->RevPalette = (
int *)malloc(pNullSubPal->nRev *
sizeof(
int));
1780 if (pPalettes[COLOR_RGB_DEFAULT])
1781 memcpy(pNullSubPal->RevPalette,
1782 pPalettes[COLOR_RGB_DEFAULT]->RevPalette,
1783 pNullSubPal->nRev *
sizeof(
int));
1785 pPalettes[i] = pNullSubPal;
1790 palette_direction = GetPaletteDir();
1792 SetColorScheme(m_global_color_scheme,
false);
1795 ifs_bufsize = Size_X * 4;
1796 ifs_buf = (
unsigned char *)malloc(ifs_bufsize);
1797 if (!ifs_buf)
return INIT_FAIL_REMOVE;
1799 ifs_bufend = ifs_buf + ifs_bufsize;
1800 ifs_lp = ifs_bufend;
1801 ifs_file_offset = -ifs_bufsize;
1805 pline_table = (
int *)malloc((Size_Y + 1) *
sizeof(int));
1806 if (!pline_table)
return INIT_FAIL_REMOVE;
1808 ifs_bitmap->SeekI((Size_Y + 1) * -4,
1810 pline_table[Size_Y] = ifs_bitmap->TellI();
1812 unsigned char *tmp = (
unsigned char *)malloc(Size_Y *
sizeof(
int));
1813 ifs_bitmap->Read(tmp, Size_Y *
sizeof(
int));
1814 if (ifs_bitmap->LastRead() != Size_Y *
sizeof(int)) {
1815 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1816 msg.Append(m_FullPath);
1820 return INIT_FAIL_REMOVE;
1824 unsigned char *b = tmp;
1825 for (
int ifplt = 0; ifplt < Size_Y; ifplt++) {
1827 offset += *b++ * 256 * 256 * 256;
1828 offset += *b++ * 256 * 256;
1829 offset += *b++ * 256;
1832 pline_table[ifplt] = offset;
1837 bool bline_index_ok =
true;
1840 wxULongLong bitmap_filesize = m_filesize;
1841 if ((m_ChartType == CHART_TYPE_GEO) && pBitmapFilePath)
1842 bitmap_filesize = wxFileName::GetSize(*pBitmapFilePath);
1845 for (
int iplt = 0; iplt < Size_Y - 1; iplt++) {
1846 if (pline_table[iplt] > bitmap_filesize) {
1847 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1848 msg.Append(m_FullPath);
1851 return INIT_FAIL_REMOVE;
1854 int thisline_size = pline_table[iplt + 1] - pline_table[iplt];
1855 if (thisline_size < 0) {
1856 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1857 msg.Append(m_FullPath);
1860 return INIT_FAIL_REMOVE;
1869 m_bsb_ver.ToDouble(&ver);
1871 for (
int iplt = 0; iplt < 10; iplt++) {
1872 if (wxInvalidOffset ==
1873 ifs_bitmap->SeekI(pline_table[iplt], wxFromStart)) {
1874 wxString msg(
" Chart File corrupt in PostInit() on chart ");
1875 msg.Append(m_FullPath);
1878 return INIT_FAIL_REMOVE;
1881 int thisline_size = pline_table[iplt + 1] - pline_table[iplt];
1882 ifs_bitmap->Read(ifs_buf, thisline_size);
1884 unsigned char *lp = ifs_buf;
1886 unsigned char byNext;
1887 int nLineMarker = 0;
1890 nLineMarker = nLineMarker * 128 + (byNext & 0x7f);
1891 }
while ((byNext & 0x80) != 0);
1898 if (iplt == 0) m_nLineOffset = nLineMarker;
1900 if (nLineMarker != iplt + m_nLineOffset) {
1901 bline_index_ok =
false;
1908 if (!bline_index_ok) {
1909 wxString msg(
" Line Index corrupt, recreating Index for chart ");
1910 msg.Append(m_FullPath);
1912 if (!CreateLineIndex()) {
1913 wxString msg(
" Error creating Line Index for chart ");
1914 msg.Append(m_FullPath);
1916 return INIT_FAIL_REMOVE;
1921 if (bUseLineCache) {
1925 for (
int ylc = 0; ylc < Size_Y; ylc++) {
1926 pt = &pLineCache[ylc];
1929 pt->pTileOffset = NULL;
1935 wxString test_str = m_DepthUnits.Upper();
1936 if (test_str.IsSameAs(
"FEET", FALSE))
1937 m_depth_unit_id = DEPTH_UNIT_FEET;
1938 else if (test_str.IsSameAs(
"METERS", FALSE))
1939 m_depth_unit_id = DEPTH_UNIT_METERS;
1940 else if (test_str.IsSameAs(
"METRES",
1942 m_depth_unit_id = DEPTH_UNIT_METERS;
1943 else if (test_str.IsSameAs(
"METRIC", FALSE))
1944 m_depth_unit_id = DEPTH_UNIT_METERS;
1945 else if (test_str.IsSameAs(
"FATHOMS", FALSE))
1946 m_depth_unit_id = DEPTH_UNIT_FATHOMS;
1947 else if (test_str.Find(
"FATHOMS") !=
1949 m_depth_unit_id = DEPTH_UNIT_FATHOMS;
1950 else if (test_str.Find(
"METERS") !=
1952 m_depth_unit_id = DEPTH_UNIT_METERS;
1955 int analyze_ret_val = AnalyzeRefpoints();
1956 if (0 != analyze_ret_val)
return INIT_FAIL_REMOVE;
1958 bReadyToRender =
true;
1962bool ChartBaseBSB::CreateLineIndex() {
1968 ifs_bitmap->SeekI(nFileOffsetDataStart);
1970 for (
int iplt = 0; iplt < Size_Y; iplt++) {
1971 int offset = ifs_bitmap->TellI();
1973 int iscan = BSBScanScanline(ifs_bitmap);
1997 pline_table[iplt] = offset;
2004void ChartBaseBSB::InvalidateLineCache() {
2007 for (
int ylc = 0; ylc < Size_Y; ylc++) {
2008 pt = &pLineCache[ylc];
2012 free(pt->pTileOffset);
2013 pt->pTileOffset = NULL;
2020bool ChartBaseBSB::GetChartExtent(
Extent *pext) {
2021 pext->NLAT = m_LatMax;
2022 pext->SLAT = m_LatMin;
2023 pext->ELON = m_LonMax;
2024 pext->WLON = m_LonMin;
2029bool ChartBaseBSB::SetMinMax() {
2038 int cnPlypoint = GetCOVRTablenPoints(0);
2040 for (
int u = 0; u < cnPlypoint; u++) {
2041 if (ppp->lnp > m_LonMax) m_LonMax = ppp->lnp;
2042 if (ppp->lnp < m_LonMin) m_LonMin = ppp->lnp;
2044 if (ppp->ltp > m_LatMax) m_LatMax = ppp->ltp;
2045 if (ppp->ltp < m_LatMin) m_LatMin = ppp->ltp;
2054 if ((m_LonMax * m_LonMin) < 0)
2059 if (0 == nRefpoint)
return false;
2062 double min_dist_x = 360;
2064 for (
int ic = 0; ic < nRefpoint; ic++) {
2066 ((m_LatMax - pRefTable[ic].latr) * (m_LatMax - pRefTable[ic].latr)) +
2067 ((m_LonMax - pRefTable[ic].lonr) * (m_LonMax - pRefTable[ic].lonr)));
2069 if (dist < min_dist_x) {
2076 double min_dist_n = 360;
2078 for (
int id = 0;
id < nRefpoint;
id++) {
2080 ((m_LatMin - pRefTable[
id].latr) * (m_LatMin - pRefTable[
id].latr)) +
2081 ((m_LonMin - pRefTable[
id].lonr) * (m_LonMin - pRefTable[
id].lonr)));
2083 if (dist < min_dist_n) {
2091 if (pRefTable[imaxclose].xr < pRefTable[iminclose].xr) {
2104 int cnPlypoint = GetCOVRTablenPoints(0);
2106 for (
int u = 0; u < cnPlypoint; u++) {
2107 if (ppp->lnp < 0.) ppp->lnp += 360.;
2109 if (ppp->lnp > m_LonMax) m_LonMax = ppp->lnp;
2110 if (ppp->lnp < m_LonMin) m_LonMin = ppp->lnp;
2112 if (ppp->ltp > m_LatMax) m_LatMax = ppp->ltp;
2113 if (ppp->ltp < m_LatMin) m_LatMin = ppp->ltp;
2124 if ((m_LonMax < -180.) && (m_LonMin < -180.)) {
2129 int cnPlypoint = GetCOVRTablenPoints(0);
2131 for (
int u = 0; u < cnPlypoint; u++) {
2140void ChartBaseBSB::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
2145 case GLOBAL_COLOR_SCHEME_RGB:
2146 m_mapped_color_index = COLOR_RGB_DEFAULT;
2148 case GLOBAL_COLOR_SCHEME_DAY:
2149 case GLOBAL_COLOR_SCHEME_DAY_HICON:
2150 m_mapped_color_index = DAY;
2152 case GLOBAL_COLOR_SCHEME_DUSK:
2153 case GLOBAL_COLOR_SCHEME_NIGHT_HICON:
2154 m_mapped_color_index = DUSK;
2156 case GLOBAL_COLOR_SCHEME_NIGHT:
2157 m_mapped_color_index = NIGHT;
2160 m_mapped_color_index = DAY;
2164 pPalette = GetPalettePtr(m_mapped_color_index);
2166 m_global_color_scheme = cs;
2169 if (bApplyImmediate) {
2170 m_cached_scale_ppm = 1.0;
2174 if (pThumbData) pThumbData->pDIBThumb = NULL;
2177wxBitmap *ChartBaseBSB::CreateThumbnail(
int tnx,
int tny, ColorScheme cs) {
2180 int divx = wxMax(1, Size_X / (4 * tnx));
2181 int divy = wxMax(1, Size_Y / (4 * tny));
2183 int div_factor = std::min(divx, divy);
2185 int des_width = Size_X / div_factor;
2186 int des_height = Size_Y / div_factor;
2192 gts.height = Size_Y;
2196 unsigned char *pLineT = (
unsigned char *)malloc((Size_X + 1) * BPP / 8);
2199 unsigned char *pPixTN =
2200 (
unsigned char *)malloc(des_width * des_height * this_bpp / 8);
2211 ColorScheme cs_tmp = m_global_color_scheme;
2212 SetColorScheme(cs,
false);
2214 while (iyd < des_height) {
2215 if (0 == BSBGetScanline(pLineT, iy, 0, Size_X, 1))
2222 yoffd = iyd * des_width * this_bpp / 8;
2226 while (ixd < des_width) {
2227 pxs = pLineT + (ix * BPP / 8);
2228 pxd = pPixTN + (yoffd + (ixd * this_bpp / 8));
2244 SetColorScheme(cs_tmp,
false);
2248#ifdef ocpnUSE_ocpnBitmap
2249 wxBitmap *bmx2 =
new ocpnBitmap(pPixTN, des_width, des_height, -1);
2250 wxImage imgx2 = bmx2->ConvertToImage();
2251 imgx2.Rescale(des_width / 4, des_height / 4, wxIMAGE_QUALITY_HIGH);
2252 retBMP =
new wxBitmap(imgx2);
2255 wxImage thumb_image(des_width, des_height, pPixTN,
true);
2256 thumb_image.Rescale(des_width / 4, des_height / 4, wxIMAGE_QUALITY_HIGH);
2257 retBMP =
new wxBitmap(thumb_image);
2270ThumbData *ChartBaseBSB::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
2272 if (!pThumbData->pDIBThumb)
2273 pThumbData->pDIBThumb = CreateThumbnail(tnx, tny, m_global_color_scheme);
2275 pThumbData->Thumb_Size_X = tnx;
2276 pThumbData->Thumb_Size_Y = tny;
2279 int divx = Size_X / tnx;
2280 int divy = Size_Y / tny;
2282 int div_factor = std::min(divx, divy);
2295 latlong_to_pix_vp(lat, lon, pixx, pixy, tvp);
2298 pThumbData->ShipX = pixx;
2299 pThumbData->ShipY = pixy;
2304bool ChartBaseBSB::UpdateThumbData(
double lat,
double lon) {
2308 int divx = Size_X / pThumbData->Thumb_Size_X;
2309 int divy = Size_Y / pThumbData->Thumb_Size_Y;
2311 int div_factor = std::min(divx, divy);
2313 double pixx_test, pixy_test;
2318 tvp.
pix_width = pThumbData->Thumb_Size_X;
2324 latlong_to_pix_vp(lat, lon, pixx_test, pixy_test, tvp);
2327 if ((pixx_test != pThumbData->ShipX) || (pixy_test != pThumbData->ShipY)) {
2328 pThumbData->ShipX = pixx_test;
2329 pThumbData->ShipY = pixy_test;
2338static double polytrans(
double *coeff,
double lon,
double lat);
2340int ChartBaseBSB::vp_pix_to_latlong(
ViewPort &vp,
double pixx,
double pixy,
2341 double *plat,
double *plon) {
2342 if (bHaveEmbeddedGeoref) {
2345 double px = pixx * raster_scale + Rsrc.x;
2346 double py = pixy * raster_scale + Rsrc.y;
2350 double lon = polytrans(pwx, px, py);
2351 lon = (lon < 0) ? lon + m_cph : lon - m_cph;
2352 *plon = lon - m_lon_datum_adjust;
2353 *plat = polytrans(pwy, px, py) - m_lat_datum_adjust;
2361 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2367 double easting, northing;
2368 toTM(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2369 m_proj_lat, m_proj_lon, &easting, &northing);
2370 double xc = polytrans(cPoints.
wpx, easting, northing);
2371 double yc = polytrans(cPoints.
wpy, easting, northing);
2374 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2375 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2378 double east = polytrans(cPoints.
pwx, px, py);
2379 double north = polytrans(cPoints.
pwy, px, py);
2383 fromTM(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2387 double slon_p = lon - m_lon_datum_adjust;
2388 double slat_p = lat - m_lat_datum_adjust;
2395 }
else if (m_projection == PROJECTION_MERCATOR) {
2401 double easting, northing;
2402 toSM_ECC(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2403 m_proj_lat, m_proj_lon, &easting, &northing);
2404 double xc = polytrans(cPoints.
wpx, easting, northing);
2405 double yc = polytrans(cPoints.
wpy, easting, northing);
2408 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2409 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2412 double east = polytrans(cPoints.
pwx, px, py);
2413 double north = polytrans(cPoints.
pwy, px, py);
2417 fromSM_ECC(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2420 double slon_p = lon - m_lon_datum_adjust;
2421 double slat_p = lat - m_lat_datum_adjust;
2429 }
else if (m_projection == PROJECTION_POLYCONIC) {
2435 double easting, northing;
2436 toPOLY(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2437 m_proj_lat, m_proj_lon, &easting, &northing);
2438 double xc = polytrans(cPoints.
wpx, easting, northing);
2439 double yc = polytrans(cPoints.
wpy, easting, northing);
2442 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2443 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2446 double east = polytrans(cPoints.
pwx, px, py);
2447 double north = polytrans(cPoints.
pwy, px, py);
2451 fromPOLY(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2454 double slon_p = lon - m_lon_datum_adjust;
2455 double slat_p = lat - m_lat_datum_adjust;
2465 xp = (dx * cos(vp.
skew)) - (dy * sin(vp.
skew));
2466 yp = (dy * cos(vp.
skew)) + (dx * sin(vp.
skew));
2471 fromSM_ECC(d_east, d_north, vp.
clat, vp.
clon, &slat, &slon);
2478 else if (slon > 180.)
2486int ChartBaseBSB::latlong_to_pix_vp(
double lat,
double lon,
double &pixx,
2490 if (bHaveEmbeddedGeoref) {
2493 alon = lon + m_lon_datum_adjust;
2494 alat = lat + m_lat_datum_adjust;
2496 AdjustLongitude(alon);
2500 double lonp = (alon < 0) ? alon + m_cph : alon - m_cph;
2501 double xd = polytrans(wpx, lonp, alat);
2502 double yd = polytrans(wpy, lonp, alat);
2506 pixx = (xd - Rsrc.x) / raster_scale;
2507 pixy = (yd - Rsrc.y) / raster_scale;
2512 double easting, northing;
2534 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2537 alon = lon + m_lon_datum_adjust;
2538 alat = lat + m_lat_datum_adjust;
2541 toTM(alat, alon, m_proj_lat, m_proj_lon, &easting, &northing);
2544 double xd = polytrans(cPoints.
wpx, easting, northing);
2545 double yd = polytrans(cPoints.
wpy, easting, northing);
2548 toTM(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2549 m_proj_lat, m_proj_lon, &easting, &northing);
2550 double xc = polytrans(cPoints.
wpx, easting, northing);
2551 double yc = polytrans(cPoints.
wpy, easting, northing);
2556 double xs = xc - vp.
pix_width * raster_scale / 2;
2557 double ys = yc - vp.
pix_height * raster_scale / 2;
2559 pixx = (xd - xs) / raster_scale;
2560 pixy = (yd - ys) / raster_scale;
2562 }
else if (m_projection == PROJECTION_MERCATOR) {
2565 alon = lon + m_lon_datum_adjust;
2566 alat = lat + m_lat_datum_adjust;
2570 AdjustLongitude(xlon);
2571 toSM_ECC(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2574 double xd = polytrans(cPoints.
wpx, easting, northing);
2575 double yd = polytrans(cPoints.
wpy, easting, northing);
2578 double xlonc = vp.
clon;
2579 AdjustLongitude(xlonc);
2581 toSM_ECC(vp.
clat + m_lat_datum_adjust, xlonc + m_lon_datum_adjust,
2582 m_proj_lat, m_proj_lon, &easting, &northing);
2583 double xc = polytrans(cPoints.
wpx, easting, northing);
2584 double yc = polytrans(cPoints.
wpy, easting, northing);
2589 double xs = xc - vp.
pix_width * raster_scale / 2;
2590 double ys = yc - vp.
pix_height * raster_scale / 2;
2592 pixx = (xd - xs) / raster_scale;
2593 pixy = (yd - ys) / raster_scale;
2595 }
else if (m_projection == PROJECTION_POLYCONIC) {
2598 alon = lon + m_lon_datum_adjust;
2599 alat = lat + m_lat_datum_adjust;
2602 xlon = AdjustLongitude(alon);
2603 toPOLY(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2606 double xd = polytrans(cPoints.
wpx, easting, northing);
2607 double yd = polytrans(cPoints.
wpy, easting, northing);
2610 double xlonc = AdjustLongitude(vp.
clon);
2612 toPOLY(vp.
clat + m_lat_datum_adjust, xlonc + m_lon_datum_adjust,
2613 m_proj_lat, m_proj_lon, &easting, &northing);
2614 double xc = polytrans(cPoints.
wpx, easting, northing);
2615 double yc = polytrans(cPoints.
wpy, easting, northing);
2620 double xs = xc - vp.
pix_width * raster_scale / 2;
2621 double ys = yc - vp.
pix_height * raster_scale / 2;
2623 pixx = (xd - xs) / raster_scale;
2624 pixy = (yd - ys) / raster_scale;
2627 toSM_ECC(lat, xlon, vp.
clat, vp.
clon, &easting, &northing);
2632 double dx = epix * cos(vp.
skew) + npix * sin(vp.
skew);
2633 double dy = npix * cos(vp.
skew) - epix * sin(vp.
skew);
2644void ChartBaseBSB::latlong_to_chartpix(
double lat,
double lon,
double &pixx,
2650 if (bHaveEmbeddedGeoref) {
2653 alon = lon + m_lon_datum_adjust;
2654 alat = lat + m_lat_datum_adjust;
2656 alon = AdjustLongitude(alon);
2659 double lonp = (alon < 0) ? alon + m_cph : alon - m_cph;
2660 pixx = polytrans(wpx, lonp, alat);
2661 pixy = polytrans(wpy, lonp, alat);
2663 double easting, northing;
2666 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2669 alon = lon + m_lon_datum_adjust;
2670 alat = lat + m_lat_datum_adjust;
2673 toTM(alat, alon, m_proj_lat, m_proj_lon, &easting, &northing);
2676 pixx = polytrans(cPoints.
wpx, easting, northing);
2677 pixy = polytrans(cPoints.
wpy, easting, northing);
2679 }
else if (m_projection == PROJECTION_MERCATOR) {
2682 alon = lon + m_lon_datum_adjust;
2683 alat = lat + m_lat_datum_adjust;
2686 xlon = AdjustLongitude(alon);
2688 toSM_ECC(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2691 pixx = polytrans(cPoints.
wpx, easting, northing);
2692 pixy = polytrans(cPoints.
wpy, easting, northing);
2694 }
else if (m_projection == PROJECTION_POLYCONIC) {
2697 alon = lon + m_lon_datum_adjust;
2698 alat = lat + m_lat_datum_adjust;
2701 xlon = AdjustLongitude(alon);
2702 toPOLY(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2705 pixx = polytrans(cPoints.
wpx, easting, northing);
2706 pixy = polytrans(cPoints.
wpy, easting, northing);
2711void ChartBaseBSB::chartpix_to_latlong(
double pixx,
double pixy,
double *plat,
2713 if (bHaveEmbeddedGeoref) {
2714 double lon = polytrans(pwx, pixx, pixy);
2715 lon = (lon < 0) ? lon + m_cph : lon - m_cph;
2716 *plon = lon - m_lon_datum_adjust;
2717 *plat = polytrans(pwy, pixx, pixy) - m_lat_datum_adjust;
2720 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2724 double east = polytrans(cPoints.
pwx, pixx, pixy);
2725 double north = polytrans(cPoints.
pwy, pixx, pixy);
2729 fromTM(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2733 slon = lon - m_lon_datum_adjust;
2734 slat = lat - m_lat_datum_adjust;
2736 }
else if (m_projection == PROJECTION_MERCATOR) {
2739 double east = polytrans(cPoints.
pwx, pixx, pixy);
2740 double north = polytrans(cPoints.
pwy, pixx, pixy);
2744 fromSM_ECC(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2747 slon = lon - m_lon_datum_adjust;
2748 slat = lat - m_lat_datum_adjust;
2749 }
else if (m_projection == PROJECTION_POLYCONIC) {
2752 double east = polytrans(cPoints.
pwx, pixx, pixy);
2753 double north = polytrans(cPoints.
pwy, pixx, pixy);
2757 fromPOLY(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2760 slon = lon - m_lon_datum_adjust;
2761 slat = lat - m_lat_datum_adjust;
2772 else if (slon > 180.)
2778void ChartBaseBSB::ComputeSourceRectangle(
const ViewPort &vp,
2779 wxRect *pSourceRect) {
2780 m_raster_scale_factor = GetRasterScaleFactor(vp);
2782 latlong_to_chartpix(vp.
clat, vp.
clon, xd, yd);
2784 wxRealPoint pos, size;
2786 pos.x = xd - (vp.
pix_width * m_raster_scale_factor / 2);
2787 pos.y = yd - (vp.
pix_height * m_raster_scale_factor / 2);
2789 size.x = vp.
pix_width * m_raster_scale_factor;
2790 size.y = vp.
pix_height * m_raster_scale_factor;
2793 wxRect(wxRound(pos.x), wxRound(pos.y), wxRound(size.x), wxRound(size.y));
2796double ChartBaseBSB::GetRasterScaleFactor(
const ViewPort &vp) {
2799 return (wxRound(100000 * GetPPM() / vp.
view_scale_ppm)) / 100000.;
2802void ChartBaseBSB::SetVPRasterParms(
const ViewPort &vpt) {
2806 if (m_datum_index == DATUM_INDEX_WGS84 ||
2807 m_datum_index == DATUM_INDEX_UNKNOWN) {
2808 m_lon_datum_adjust = (-m_dtm_lon) / 3600.;
2809 m_lat_datum_adjust = (-m_dtm_lat) / 3600.;
2813 double to_lat, to_lon;
2814 MolodenskyTransform(vpt.
clat, vpt.
clon, &to_lat, &to_lon, m_datum_index,
2816 m_lon_datum_adjust = -(to_lon - vpt.
clon);
2817 m_lat_datum_adjust = -(to_lat - vpt.
clat);
2818 if (m_b_apply_dtm) {
2819 m_lon_datum_adjust -= m_dtm_lon / 3600.;
2820 m_lat_datum_adjust -= m_dtm_lat / 3600.;
2824 ComputeSourceRectangle(vpt, &Rsrc);
2826 if (vpt.IsValid()) m_vp_render_last = vpt;
2830 bool bInside = G_FloatPtInPolygon((
MyFlPoint *)GetCOVRTableHead(0),
2831 GetCOVRTablenPoints(0), vp_proposed.
clon,
2833 if (!bInside)
return false;
2836 double binary_scale_factor = GetPPM() / vp_proposed.
view_scale_ppm;
2838 if (vp_last.IsValid()) {
2844 if (cached_image_ok && (binary_scale_factor > 1.0) &&
2845 (fabs(binary_scale_factor - wxRound(binary_scale_factor)) < 1e-5)) {
2847 printf(
" Possible Adjust VP for integer scale: %g\n",
2848 binary_scale_factor);
2851 ComputeSourceRectangle(vp_proposed, &rprop);
2854 double lon_adj, lat_adj;
2855 latlong_to_pix_vp(vp_proposed.
clat, vp_proposed.
clon, pixx, pixy,
2857 vp_pix_to_latlong(vp_proposed, pixx, pixy, &lat_adj, &lon_adj);
2859 vp_proposed.
clat = lat_adj;
2860 vp_proposed.
clon = lon_adj;
2865 return (ret_val > 0);
2868bool ChartBaseBSB::IsRenderCacheable(wxRect &source, wxRect &dest) {
2869 double scale_x = (double)source.width / (
double)dest.width;
2878 if ((fabs(scale_x - wxRound(scale_x))) > .0001) {
2885 if ((
int)(source.width / dest.width) != (
int)wxRound(scale_x)) {
2894void ChartBaseBSB::GetValidCanvasRegion(
const ViewPort &VPoint,
2896 SetVPRasterParms(VPoint);
2903 rxl = wxMax(-Rsrc.x * raster_scale, VPoint.rv_rect.x);
2904 rxr = wxMin((Size_X - Rsrc.x) * raster_scale,
2905 VPoint.rv_rect.width + VPoint.rv_rect.x);
2907 ryt = wxMax(-Rsrc.y * raster_scale, VPoint.rv_rect.y);
2908 ryb = wxMin((Size_Y - Rsrc.y) * raster_scale,
2909 VPoint.rv_rect.height + VPoint.rv_rect.y);
2911 pValidRegion->Clear();
2912 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
2915LLRegion ChartBaseBSB::GetValidRegion() {
2918 chartpix_to_latlong(0, 0, ll + 0, ll + 1);
2919 chartpix_to_latlong(0, Size_Y, ll + 2, ll + 3);
2920 chartpix_to_latlong(Size_X, Size_Y, ll + 4, ll + 5);
2921 chartpix_to_latlong(Size_X, 0, ll + 6, ll + 7);
2925 for (
int i = 1; i < 6; i += 2)
2926 if (fabs(ll[i] - ll[i + 2]) > 180) {
2928 for (
int i = 1; i < 8; i += 2)
2929 if (ll[i] < 0) ll[i] += 360;
2933 return LLRegion(4, ll);
2936bool ChartBaseBSB::GetViewUsingCache(wxRect &source, wxRect &dest,
2938 ScaleTypeEnum scale_type) {
2940 ScaleTypeEnum scale_type_corrected;
2942 if (m_b_cdebug) printf(
" source: %d %d\n", source.x, source.y);
2943 if (m_b_cdebug) printf(
" cache: %d %d\n", cache_rect.x, cache_rect.y);
2946 if ((source == cache_rect) &&
2947 (cached_image_ok)) {
2948 if (m_b_cdebug) printf(
" GVUC: Cache is good, nothing to do\n");
2952 double scale_x = (double)source.width / (
double)dest.width;
2954 if (m_b_cdebug) printf(
"GVUC: scale_x: %g\n", scale_x);
2957 scale_type_corrected = scale_type;
2958 if (scale_x > m_bilinear_limit) scale_type_corrected = RENDER_LODEF;
2966 if ((fabs(scale_x - wxRound(scale_x))) > .0001) {
2967 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Not digital scale test 1\n");
2968 return GetView(source, dest, scale_type_corrected);
2973 if (!cached_image_ok) {
2974 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Cache NOk\n");
2975 return GetView(source, dest, scale_type_corrected);
2980 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Overzoom\n");
2981 return GetView(source, dest, scale_type_corrected);
2985 if ((
int)(source.width / dest.width) != (
int)wxRound(scale_x)) {
2986 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Not digital scale test 2\n");
2987 return GetView(source, dest, scale_type_corrected);
2991 int cs1d = source.width / dest.width;
2992 if (abs(source.x - cache_rect.x) % cs1d) {
2994 printf(
" source.x: %d cache_rect.x: %d cs1d: %d\n", source.x,
2995 cache_rect.x, cs1d);
2996 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: x mismatch\n");
2997 return GetView(source, dest, scale_type_corrected);
2999 if (abs(source.y - cache_rect.y) % cs1d) {
3000 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: y mismatch\n");
3001 return GetView(source, dest, scale_type_corrected);
3004 if (pPixCache && ((pPixCache->GetWidth() != dest.width) ||
3005 (pPixCache->GetHeight() != dest.height))) {
3006 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: dest size mismatch\n");
3007 return GetView(source, dest, scale_type_corrected);
3011 (source.y + source.height) - (cache_rect.y + cache_rect.height);
3012 int scaled_stride_rows = (int)(stride_rows / scale_x);
3014 if (abs(stride_rows) >= source.height)
3015 return GetView(source, dest, scale_type_corrected);
3018 (source.x + source.width) - (cache_rect.x + cache_rect.width);
3019 int scaled_stride_pixels = (int)(stride_pixels / scale_x);
3021 if (abs(stride_pixels) >= source.width)
3022 return GetView(source, dest, scale_type_corrected);
3024 if (m_b_cdebug) printf(
" GVUC Using raster data cache\n");
3026 ScaleTypeEnum pan_scale_type_x = scale_type_corrected;
3027 ScaleTypeEnum pan_scale_type_y = scale_type_corrected;
3031 int height = pPixCache->GetHeight();
3032 int width = pPixCache->GetWidth();
3033 int buffer_stride_bytes = pPixCache->GetLinePitch();
3038 if (stride_rows > 0)
3040 ps = pPixCache->GetpData() +
3041 (abs(scaled_stride_rows) * buffer_stride_bytes);
3042 if (stride_pixels > 0) ps += scaled_stride_pixels * BPP / 8;
3044 pd = pPixCache->GetpData();
3045 if (stride_pixels <= 0) pd += abs(scaled_stride_pixels) * BPP / 8;
3047 for (
int iy = 0; iy < (height - abs(scaled_stride_rows)); iy++) {
3048 memmove(pd, ps, (width - abs(scaled_stride_pixels)) * BPP / 8);
3049 ps += buffer_stride_bytes;
3050 pd += buffer_stride_bytes;
3054 ps = pPixCache->GetpData() +
3055 ((height - abs(scaled_stride_rows) - 1) * buffer_stride_bytes);
3056 if (stride_pixels > 0)
3057 ps += scaled_stride_pixels * BPP / 8;
3059 pd = pPixCache->GetpData() + ((height - 1) * buffer_stride_bytes);
3060 if (stride_pixels <= 0)
3061 pd += abs(scaled_stride_pixels) * BPP / 8;
3063 for (
int iy = 0; iy < (height - abs(scaled_stride_rows)); iy++) {
3064 memmove(pd, ps, (width - abs(scaled_stride_pixels)) * BPP / 8);
3065 ps -= buffer_stride_bytes;
3066 pd -= buffer_stride_bytes;
3071 if (source.y != cache_rect.y) {
3072 wxRect sub_dest = dest;
3073 sub_dest.height = abs(scaled_stride_rows);
3075 if (stride_rows > 0)
3077 sub_dest.y = height - scaled_stride_rows;
3088 wxRegionContain rc = Region.Contains(sub_dest);
3089 if ((wxPartRegion == rc) || (wxInRegion == rc)) {
3090 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3091 source.width, sub_dest, width, cs1d, pan_scale_type_y);
3093 pPixCache->Update();
3097 cache_rect.y = source.y;
3099 cache_rect_scaled = dest;
3100 cached_image_ok = 1;
3105 if (source.x != cache_rect.x) {
3106 wxRect sub_dest = dest;
3107 sub_dest.width = abs(scaled_stride_pixels);
3109 if (stride_pixels > 0)
3111 sub_dest.x = width - scaled_stride_pixels;
3122 wxRegionContain rc = Region.Contains(sub_dest);
3123 if ((wxPartRegion == rc) || (wxInRegion == rc)) {
3124 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3125 source.width, sub_dest, width, cs1d, pan_scale_type_x);
3128 pPixCache->Update();
3131 cache_rect = source;
3132 cache_rect_scaled = dest;
3133 cached_image_ok = 1;
3144bool ChartBaseBSB::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
3145 SetVPRasterParms(VPoint);
3149 bool bsame_region = (rgn == m_last_region);
3151 if (!bsame_region) cached_image_ok =
false;
3153 m_last_region = rgn;
3155 return RenderRegionViewOnDC(dc, VPoint, rgn);
3158bool ChartBaseBSB::RenderRegionViewOnGL(
const wxGLContext &glc,
3161 const LLRegion &Region) {
3165bool ChartBaseBSB::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
3167 SetVPRasterParms(VPoint);
3171 double factor = GetRasterScaleFactor(VPoint);
3173 printf(
"%d RenderRegion ScaleType: %d factor: %g\n", s_dc++,
3174 RENDER_HIDEF, factor);
3175 printf(
"Rect list:\n");
3177 while (upd.HaveRects()) {
3178 wxRect rect = upd.GetRect();
3179 printf(
" %d %d %d %d\n", rect.x, rect.y, rect.width, rect.height);
3187 (m_last_vprect != dest)) {
3188 cached_image_ok =
false;
3189 m_vp_render_last.Invalidate();
3206 m_last_vprect = dest;
3208 if (cached_image_ok) {
3210 bool bsame_region = (Region == m_last_region);
3212 if ((bsame_region) && (Rsrc == cache_rect)) {
3213 pPixCache->SelectIntoDC(dc);
3214 if (m_b_cdebug) printf(
" Using Current PixelCache\n");
3219 m_last_region = Region;
3240 while (upd.HaveRects()) {
3245 if ((!IsRenderCacheable(Rsrc, dest) && (n_rect > 4) && (n_rect < 20)) ||
3248 printf(
" RenderRegion by rect iterator n_rect: %d\n", n_rect);
3252 wxRect dest_check_rect = dest;
3254 while (upd_check.HaveRects()) {
3255 wxRect rect = upd_check.GetRect();
3256 dest_check_rect.Union(rect);
3257 upd_check.NextRect();
3261 if ((pPixCache->GetWidth() != dest_check_rect.width) ||
3262 (pPixCache->GetHeight() != dest_check_rect.height)) {
3265 new PixelCache(dest_check_rect.width, dest_check_rect.height, BPP);
3269 new PixelCache(dest_check_rect.width, dest_check_rect.height, BPP);
3271 ScaleTypeEnum ren_type = RENDER_LODEF;
3277 while (upd.HaveRects()) {
3278 wxRect rect = upd.GetRect();
3283 if (rect.y < 0) rect.Offset(0, -rect.y);
3284 if (rect.x < 0) rect.Offset(-rect.x, 0);
3286 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), Rsrc,
3287 Rsrc.width, rect, pPixCache->GetWidth(), factor,
3295 pPixCache->Update();
3299 cache_scale_method = ren_type;
3300 cached_image_ok =
false;
3303 pPixCache->SelectIntoDC(dc);
3311 if ((pPixCache->GetWidth() != dest.width) ||
3312 (pPixCache->GetHeight() != dest.height)) {
3314 pPixCache =
new PixelCache(dest.width, dest.height, BPP);
3317 pPixCache =
new PixelCache(dest.width, dest.height, BPP);
3319 if (m_b_cdebug) printf(
" Render Region By GVUC\n");
3322 ScaleTypeEnum scale_type_zoom = RENDER_HIDEF;
3324 if (binary_scale_factor < .20) scale_type_zoom = RENDER_LODEF;
3326 bool bnewview = GetViewUsingCache(Rsrc, dest, Region, scale_type_zoom);
3329 pPixCache->SelectIntoDC(dc);
3334wxImage *ChartBaseBSB::GetImage() {
3335 int img_size_x = ((Size_X >> 2) * 4) + 4;
3336 wxImage *img =
new wxImage(img_size_x, Size_Y,
false);
3338 unsigned char *ppnx = img->GetData();
3340 for (
int i = 0; i < Size_Y; i++) {
3341 wxRect source_rect(0, i, Size_X, 1);
3342 wxRect dest_rect(0, 0, Size_X, 1);
3344 GetAndScaleData(img->GetData(), img_size_x * Size_Y * 3, source_rect,
3345 Size_X, dest_rect, Size_X, 1.0, RENDER_HIDEF);
3347 ppnx += img_size_x * 3;
3353bool ChartBaseBSB::GetView(wxRect &source, wxRect &dest,
3354 ScaleTypeEnum scale_type) {
3355 assert(pPixCache != 0);
3361 double factor = ((double)source.width) / ((double)dest.width);
3376 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3377 source.width, dest, dest.width, factor, scale_type);
3378 pPixCache->Update();
3382 cache_rect = source;
3383 cache_rect_scaled = dest;
3384 cache_scale_method = scale_type;
3386 cached_image_ok = 1;
3391bool ChartBaseBSB::GetAndScaleData(
unsigned char *ppn,
size_t data_size,
3392 wxRect &source,
int source_stride,
3393 wxRect &dest,
int dest_stride,
3394 double scale_factor,
3395 ScaleTypeEnum scale_type) {
3396 unsigned char *s_data = NULL;
3398 double factor = scale_factor;
3399 int Factor = (int)factor;
3401 int target_width = (int)wxRound((
double)source.width / factor);
3402 int target_height = (int)wxRound((
double)source.height / factor);
3404 int dest_line_length = dest_stride * BPP / 8;
3408#ifdef __PIX_CACHE_DIBSECTION__
3409 dest_line_length = (((dest_stride * 24) + 31) & ~31) >> 3;
3412 if ((target_height == 0) || (target_width == 0))
return false;
3416 unsigned char *
volatile target_data = ppn;
3417 unsigned char *data = ppn;
3421 if (scale_type == RENDER_HIDEF) {
3423 int blur_factor = wxMax(2, Factor);
3424 int wb_size = (source.width) * (blur_factor * 2) * BPP / 8;
3425 s_data = (
unsigned char *)malloc(wb_size);
3426 unsigned char *pixel;
3429 for (
int y = dest.y; y < (dest.y + dest.height); y++) {
3434 s1.y = source.y + (int)(y * factor);
3435 s1.width = source.width;
3436 s1.height = blur_factor;
3437 GetChartBits(s1, s_data, 1);
3439 target_data = data + (y * dest_line_length );
3441 for (
int x = 0; x < target_width; x++) {
3442 unsigned int avgRed = 0;
3443 unsigned int avgGreen = 0;
3444 unsigned int avgBlue = 0;
3445 unsigned int pixel_count = 0;
3446 unsigned char *pix0 = s_data + BPP / 8 * ((int)(x * factor));
3449 if ((x * Factor) < (Size_X - source.x)) {
3451 for (
int y1 = 0; y1 < blur_factor; ++y1) {
3452 pixel = pix0 + (BPP / 8 * y_offset);
3453 for (
int x1 = 0; x1 < blur_factor; ++x1) {
3455 avgGreen += pixel[1];
3456 avgBlue += pixel[2];
3462 y_offset += source.width;
3465 if (0 == pixel_count)
3468 target_data[0] = avgRed / pixel_count;
3469 target_data[1] = avgGreen / pixel_count;
3470 target_data[2] = avgBlue / pixel_count;
3471 target_data += BPP / 8;
3476 target_data += BPP / 8;
3485 else if (scale_type == RENDER_LODEF) {
3486 int get_bits_submap = 1;
3490 if (source.width > 32767)
3493 int wb_size = (Size_X) * (( 1) * 2) * BPP / 8;
3494 s_data = (
unsigned char *)malloc(wb_size);
3496 long x_delta = (source.width << scaler) / target_width;
3497 long y_delta = (source.height << scaler) / target_height;
3500 long ys = dest.y * y_delta;
3502 while (y < dest.y + dest.height) {
3507 s1.y = source.y + (ys >> scaler);
3510 GetChartBits(s1, s_data, get_bits_submap);
3512 target_data = data + (y * dest_line_length ) +
3515 long x = (source.x << scaler) + (dest.x * x_delta);
3516 long sizex16 = Size_X << scaler;
3519 while ((xt < dest.x + dest.width) && (x < 0)) {
3524 target_data += BPP / 8;
3529 while ((xt < dest.x + dest.width) && (x < sizex16)) {
3530 unsigned char *src_pixel = &s_data[(x >> scaler) * BPP / 8];
3532 target_data[0] = src_pixel[0];
3533 target_data[1] = src_pixel[1];
3534 target_data[2] = src_pixel[2];
3536 target_data += BPP / 8;
3541 while (xt < dest.x + dest.width) {
3546 target_data += BPP / 8;
3560 unsigned char *target_line_start = NULL;
3561 unsigned char *target_data_x = NULL;
3565 sigaction(SIGSEGV, NULL,
3568 struct sigaction temp;
3569 sigaction(SIGSEGV, NULL, &temp);
3571 temp.sa_handler = catch_signals_chart;
3572 sigemptyset(&temp.sa_mask);
3577 sigaction(SIGSEGV, &temp, NULL);
3579 if (sigsetjmp(env_chart,
3582 sigaction(SIGSEGV, &sa_all_previous, NULL);
3585 msg.Printf(
" Caught SIGSEGV on GetandScaleData, Factor < 1");
3589 " m_raster_scale_factor: %g source.width: %d dest.y: %d "
3590 "dest.x: %d dest.width: %d dest.height: %d ",
3591 m_raster_scale_factor, source.width, dest.y, dest.x, dest.width,
3596 " i: %d j: %d dest_stride: %d target_line_start: %p "
3597 "target_data_x: %p y_offset: %d",
3598 i, j, dest_stride, target_line_start, target_data_x, y_offset);
3611 latlong_to_chartpix(m_vp_render_last.
clat, m_vp_render_last.
clon, xd, yd);
3613 xd - (m_vp_render_last.
pix_width * m_raster_scale_factor / 2);
3615 yd - (m_vp_render_last.
pix_height * m_raster_scale_factor / 2);
3616 double x_vernier = (xrd - wxRound(xrd));
3617 double y_vernier = (yrd - wxRound(yrd));
3618 int x_vernier_i = (int)wxRound(x_vernier / m_raster_scale_factor);
3619 int y_vernier_i = (int)wxRound(y_vernier / m_raster_scale_factor);
3624 int sx = wxMax(source.x, 0);
3625 s_data = (
unsigned char *)malloc((sx + source.width + 2) *
3626 (source.height + 2) * BPP / 8);
3628 wxRect vsource = source;
3629 vsource.height += 2;
3634 GetChartBits(vsource, s_data, 1);
3635 unsigned char *source_data = s_data;
3639 while (j < dest.y + dest.height) {
3640 y_offset = (int)((j - y_vernier_i) * m_raster_scale_factor) *
3644 target_data + (j * dest_line_length );
3645 target_data_x = target_line_start + ((dest.x) * BPP / 8);
3650 if ((target_data_x + (dest.width * BPP / 8)) >
3651 (target_data + data_size)) {
3652 j = dest.y + dest.height;
3654 while (i < dest.x + dest.width) {
3655 memcpy(target_data_x,
3656 source_data + BPP / 8 *
3657 (y_offset + (
int)((i + x_vernier_i) *
3658 m_raster_scale_factor)),
3661 target_data_x += BPP / 8;
3671 sigaction(SIGSEGV, &sa_all_previous, NULL);
3680bool ChartBaseBSB::GetChartBits(wxRect &source,
unsigned char *pPix,
3682 wxCriticalSectionLocker locker(m_critSect);
3694 while (iy < source.y + source.height) {
3695 if ((iy >= 0) && (iy < Size_Y)) {
3696 if (source.x >= 0) {
3697 if ((source.x + source.width) > Size_X) {
3698 if ((Size_X - source.x) < 0)
3699 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3701 BSBGetScanline(pCP, iy, source.x, Size_X, sub_samp);
3702 memset(pCP + (Size_X - source.x) * BPP / 8, FILL_BYTE,
3703 (source.x + source.width - Size_X) * BPP / 8);
3706 BSBGetScanline(pCP, iy, source.x, source.x + source.width, sub_samp);
3708 if ((source.width + source.x) >= 0) {
3712 int xfill_corrected = -source.x + (source.x % sub_samp);
3713 memset(pCP, FILL_BYTE, (xfill_corrected * BPP / 8));
3714 BSBGetScanline(pCP + (xfill_corrected * BPP / 8), iy, 0,
3715 source.width + source.x, sub_samp);
3718 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3725 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3728 pCP += source.width * BPP / 8 * sub_samp;
3746int ChartBaseBSB::ReadBSBHdrLine(wxInputStream *ifs,
char *buf,
int buf_len_max)
3751 int line_length = 0;
3756 while (!ifs->Eof() && line_length < buf_len_max) {
3757 int c = ifs->GetC();
3760 if (0x1A == read_char) {
3761 ifs->Ungetch(read_char);
3769 if (read_char == 10 || read_char == 13) {
3771 cr_test = ifs->GetC();
3772 if (cr_test == 13) cr_test = ifs->GetC();
3774 if (cr_test != 10 && cr_test != 13) ifs->Ungetch(cr_test);
3779 if (read_char ==
'\n') {
3781 cr_test = ifs->GetC();
3783 if (cr_test !=
' ') {
3784 ifs->Ungetch(cr_test);
3790 while (cr_test ==
' ') cr_test = ifs->GetC();
3791 ifs->Ungetch(cr_test);
3807 if (line_length) *(lbuf - 1) =
'\0';
3816int ChartBaseBSB::BSBScanScanline(wxInputStream *pinStream) {
3817 int nLineMarker, nValueShift, iPixel = 0;
3818 unsigned char byValueMask, byCountMask;
3819 unsigned char byNext;
3827 byNext = pinStream->GetC();
3828 nLineMarker = nLineMarker * 128 + (byNext & 0x7f);
3829 }
while ((byNext & 0x80) != 0);
3832 nValueShift = 7 - nColorSize;
3833 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
3834 byCountMask = (1 << (7 - nColorSize)) - 1;
3838 while (((byNext = pinStream->GetC()) != 0) && (iPixel < Size_X)) {
3843 nRunCount = byNext & byCountMask;
3845 while ((byNext & 0x80) != 0) {
3846 byNext = pinStream->GetC();
3847 nRunCount = nRunCount * 128 + (byNext & 0x7f);
3850 if (iPixel + nRunCount + 1 > Size_X) nRunCount = Size_X - iPixel - 1;
3855 iPixel += nRunCount + 1;
3857 coffset = pinStream->TellI();
3867inline void memset_short(
unsigned char *dst,
unsigned char cbyte,
int count) {
3879 memset(dst, cbyte, count);
3884#define TILE_SIZE 512
3893 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
3897 clock_gettime(CLOCK_REALTIME, &tp_end);
3898 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
3899 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
3909 free(pt->pTileOffset); \
3910 pt->pTileOffset = NULL; \
3913 pt->bValid = false; \
3920int ChartBaseBSB::BSBGetScanline(
unsigned char *pLineBuf,
int y,
int xs,
int xl,
3924 unsigned char *prgb = pLineBuf;
3926 unsigned char byValueMask, byCountMask;
3927 unsigned char byNext;
3935 if (bUseLineCache && pLineCache) {
3937 pt = &pLineCache[y];
3945 static double ttime;
3952 pt->size = pline_table[y + 1] - pline_table[y];
3955 pt->pPix = (
unsigned char *)malloc(Size_X);
3959 pt->pPix = (
unsigned char *)malloc(pt->size);
3961 if (pline_table[y] == 0 || pline_table[y + 1] == 0) FAIL;
3966 if (ifs_bitmap->TellI() != pline_table[y] &&
3967 wxInvalidOffset == ifs_bitmap->SeekI(pline_table[y], wxFromStart))
3971 if (pt->size > ifs_bufsize) {
3972 unsigned char *tmp = ifs_buf;
3973 if (!(ifs_buf = (
unsigned char *)realloc(ifs_buf, pt->size))) {
3977 ifs_bufsize = pt->size;
3984 ifs_bitmap->Read(lp, pt->size);
3989 if (!bUseLineCache) {
3993 if (pos < pt->size) {
3999 }
while ((byNext & 0x80) != 0);
4004 if (Size_X > ifs_bufsize) {
4005 unsigned char *tmp = ifs_buf;
4006 if (!(ifs_buf = (
unsigned char *)realloc(ifs_buf, Size_X))) {
4010 ifs_bufsize = Size_X;
4018 if (pos < pt->size) {
4024 }
while ((byNext & 0x80) != 0);
4027 nValueShift = 7 - nColorSize;
4028 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
4029 byCountMask = (1 << (7 - nColorSize)) - 1;
4032 unsigned int iPixel = 0;
4034#ifndef USE_OLD_CACHE
4035 pt->pTileOffset[0].offset = lp - pt->pPix;
4036 pt->pTileOffset[0].pixel = 0;
4037 unsigned int tileindex = 1, nextTile = TILE_SIZE;
4039 unsigned int nRunCount;
4040 unsigned char *end = pt->pPix + pt->size;
4041 while (iPixel < (
unsigned int)Size_X)
4044 nPixValue = (byNext & byValueMask) >> nValueShift;
4046 nRunCount = byNext & byCountMask;
4048 while ((byNext & 0x80) != 0) {
4050 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4055 if (iPixel + nRunCount >
4056 (
unsigned int)Size_X)
4057 nRunCount = nRunCount - iPixel;
4060 memset_short(pCL + iPixel, nPixValue, nRunCount);
4061 iPixel += nRunCount;
4066 if (pos < pt->size) {
4072 unsigned char *offset = lp - 1;
4073 if (byNext == 0 || lp == end) {
4075 while (tileindex < (
unsigned int)Size_X / TILE_SIZE + 1) {
4076 pt->pTileOffset[tileindex].offset = pt->pTileOffset[0].offset;
4077 pt->pTileOffset[tileindex].pixel = 0;
4083 nRunCount = byNext & byCountMask;
4085 while ((byNext & 0x80) != 0) {
4086 if (pos < pt->size) {
4092 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4097 if (iPixel + nRunCount >
4098 (
unsigned int)Size_X)
4099 nRunCount = Size_X - iPixel;
4101 while (iPixel + nRunCount > nextTile) {
4102 pt->pTileOffset[tileindex].offset = offset - pt->pPix;
4103 pt->pTileOffset[tileindex].pixel = iPixel;
4105 nextTile += TILE_SIZE;
4107 iPixel += nRunCount;
4116 if (xl > Size_X) xl = Size_X;
4119 pCL = pt->pPix + xs;
4122 if ((BPP == 24) && (1 == sub_samp)) {
4124 while (ix < xl - 1) {
4125 unsigned char cur_by = *pCL;
4126 rgbval = (int)(pPalette[cur_by]);
4127 while ((ix < xl - 1)) {
4128 if (cur_by != *pCL)
break;
4129 *((
int *)prgb) = rgbval;
4136 int dest_inc_val_bytes = (BPP / 8) * sub_samp;
4138 while (ix < xl - 1) {
4139 unsigned char cur_by = *pCL;
4140 rgbval = (int)(pPalette[cur_by]);
4141 while ((ix < xl - 1)) {
4142 if (cur_by != *pCL)
break;
4143 *((
int *)prgb) = rgbval;
4144 prgb += dest_inc_val_bytes;
4155 unsigned char *pCLast = pt->pPix + (xl - 1);
4156 unsigned char *prgb_last = pLineBuf + ((xl - 1) - xs) * BPP / 8;
4158 rgbval = (int)(pPalette[*pCLast]);
4159 unsigned char a = rgbval & 0xff;
4161 a = (rgbval >> 8) & 0xff;
4163 a = (rgbval >> 16) & 0xff;
4168 int tileindex = xs / TILE_SIZE;
4169 int tileoffset = pt->pTileOffset[tileindex].offset;
4171 lp = pt->pPix + tileoffset;
4173 ix = pt->pTileOffset[tileindex].pixel;
4177 nValueShift = 7 - nColorSize;
4178 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
4179 byCountMask = (1 << (7 - nColorSize)) - 1;
4181 bool bLastPixValueValid =
false;
4182 while (ix < xl - 1) {
4183 if (pos < pt->size) {
4190 nPixValue = (byNext & byValueMask) >> nValueShift;
4191 unsigned int nRunCount;
4194 nRunCount = xl - ix;
4196 nRunCount = byNext & byCountMask;
4197 while ((byNext & 0x80) != 0) {
4198 if (pos < pt->size) {
4202 nRunCount = xl - ix;
4205 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4212 if (ix + nRunCount <= (
unsigned int)xs) {
4216 nRunCount -= xs - ix;
4220 if (ix + nRunCount >= (
unsigned int)xl) {
4221 nRunCount = xl - 1 - ix;
4222 bLastPixValueValid =
true;
4225 rgbval = (int)(pPalette[nPixValue]);
4231 int count = nRunCount;
4235 *(uint32_t *)prgb = rgbval;
4238 }
else if (rgbval == 0 || rgbval == 0xffffff) {
4240 memset(prgb, rgbval, nRunCount * 3);
4241 prgb += nRunCount * 3;
4255 if ((
long)prgb & 7) {
4257 *(uint32_t *)prgb = rgbval;
4259 if (!((
long)prgb & 7)) {
4260 if (count >= 8)
break;
4267 uint64_t *b = (uint64_t *)prgb;
4268 for (
int i = 0; i < 8; i++) {
4269 *(uint32_t *)prgb = rgbval;
4275 uint64_t *y = (uint64_t *)prgb;
4276 int count_d8 = count >> 3;
4277 prgb += 24 * count_d8;
4278 while (count_d8--) {
4285 int rcount = count & 0x7;
4287 *(uint32_t *)prgb = rgbval;
4300 if (!bLastPixValueValid) {
4301 if (pos < pt->size) {
4307 nPixValue = (byNext & byValueMask) >> nValueShift;
4309 rgbval = (int)(pPalette[nPixValue]);
4310 unsigned char a = rgbval & 0xff;
4313 a = (rgbval >> 8) & 0xff;
4315 a = (rgbval >> 16) & 0xff;
4323 if (cnt == 500000) {
4325 printf(
"cache time: %d %f\n", d, ttime / 1000.0);
4332 if (!bUseLineCache) {
4333#ifndef USE_OLD_CACHE
4334 free(pt->pTileOffset);
4342int *ChartBaseBSB::GetPalettePtr(BSB_Color_Capability color_index) {
4343 if (pPalettes[color_index]) {
4344 if (palette_direction == PaletteFwd)
4345 return (
int *)(pPalettes[color_index]->FwdPalette);
4347 return (
int *)(pPalettes[color_index]->RevPalette);
4352PaletteDir ChartBaseBSB::GetPaletteDir() {
4355 RGBO r = pc->GetRGBO();
4364bool ChartBaseBSB::AnalyzeSkew() {
4365 double lonmin = 1000;
4366 double lonmax = -1000;
4367 double latmin = 90.;
4368 double latmax = -90.;
4370 int nlonmin, nlonmax;
4377 for (
int n = 0; n < nRefpoint; n++) {
4379 if (pRefTable[n].lonr > lonmax) {
4380 lonmax = pRefTable[n].lonr;
4383 if (pRefTable[n].lonr < lonmin) {
4384 lonmin = pRefTable[n].lonr;
4389 if (pRefTable[n].latr < latmin) {
4390 latmin = pRefTable[n].latr;
4392 if (pRefTable[n].latr > latmax) {
4393 latmax = pRefTable[n].latr;
4398 if ((lonmin * lonmax) < 0) {
4399 if (pRefTable[nlonmin].xr > pRefTable[nlonmax].xr) {
4401 for (
int n = 0; n < nRefpoint; n++) {
4402 if (pRefTable[n].lonr < 0.0) pRefTable[n].lonr += 360.;
4409 for (
int n = 0; n < nRefpoint; n++) {
4411 if (pRefTable[n].lonr > lonmax) {
4412 lonmax = pRefTable[n].lonr;
4415 if (pRefTable[n].lonr < lonmin) {
4416 lonmin = pRefTable[n].lonr;
4421 if (pRefTable[n].latr < latmin) {
4422 latmin = pRefTable[n].latr;
4424 if (pRefTable[n].latr > latmax) {
4425 latmax = pRefTable[n].latr;
4432 double dist_max = 0.;
4436 for (
int i = 0; i < nRefpoint; i++) {
4437 for (
int j = i + 1; j < nRefpoint; j++) {
4438 double dx = pRefTable[i].xr - pRefTable[j].xr;
4439 double dy = pRefTable[i].yr - pRefTable[j].yr;
4440 double dist = (dx * dx) + (dy * dy);
4441 if (dist > dist_max) {
4449 double apparent_skew = 0;
4451 if (m_projection == PROJECTION_MERCATOR) {
4452 double easting0, easting1, northing0, northing1;
4454 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4455 &easting0, &northing0);
4456 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4457 &easting1, &northing1);
4460 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4461 double skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4462 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4465 apparent_skew = skew_points - skew_proj + 90.;
4468 if (fabs(apparent_skew) > 180.) {
4469 if (apparent_skew < 0.)
4470 apparent_skew += 360.;
4472 apparent_skew -= 360.;
4476 else if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
4477 double easting0, easting1, northing0, northing1;
4479 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4480 &easting0, &northing0);
4481 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4482 &easting1, &northing1);
4485 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4486 double skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4487 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4490 apparent_skew = skew_points - skew_proj + 90.;
4493 if (fabs(apparent_skew) > 180.) {
4494 if (apparent_skew < 0.)
4495 apparent_skew += 360.;
4497 apparent_skew -= 360.;
4500 if (fabs(apparent_skew - m_Chart_Skew) > 2) {
4503 double dskew = fabs(apparent_skew - m_Chart_Skew);
4504 if ((m_proj_lon < lonmin) || (m_proj_lon > lonmax)) {
4506 double tentative_proj_lon = (lonmin + lonmax) / 2.;
4508 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat,
4509 tentative_proj_lon, &easting0, &northing0);
4510 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat,
4511 tentative_proj_lon, &easting1, &northing1);
4514 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4515 skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4516 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4519 apparent_skew = skew_points - skew_proj + 90.;
4522 if (fabs(apparent_skew) > 180.) {
4523 if (apparent_skew < 0.)
4524 apparent_skew += 360.;
4526 apparent_skew -= 360.;
4530 if (fabs(apparent_skew - m_Chart_Skew) < dskew) {
4531 m_proj_lon = tentative_proj_lon;
4537 apparent_skew = m_Chart_Skew;
4539 if (fabs(apparent_skew - m_Chart_Skew) >
4541 m_Chart_Skew = apparent_skew;
4543 wxString msg =
" Warning: Skew override on chart ";
4544 msg.Append(m_FullPath);
4546 msg1.Printf(
" is %5g degrees", apparent_skew);
4557int ChartBaseBSB::AnalyzeRefpoints(
bool b_testSolution) {
4563 float lonmin = 1000;
4564 float lonmax = -1000;
4566 float latmax = -90.;
4568 int plonmin = 100000;
4570 int platmin = 100000;
4572 int nlonmin = 0, nlonmax = 0;
4577 for (n = 0; n < nRefpoint; n++) {
4579 if (pRefTable[n].lonr > lonmax) {
4580 lonmax = pRefTable[n].lonr;
4581 plonmax = (int)pRefTable[n].xr;
4584 if (pRefTable[n].lonr < lonmin) {
4585 lonmin = pRefTable[n].lonr;
4586 plonmin = (int)pRefTable[n].xr;
4591 if (pRefTable[n].latr < latmin) {
4592 latmin = pRefTable[n].latr;
4593 platmin = (int)pRefTable[n].yr;
4595 if (pRefTable[n].latr > latmax) {
4596 latmax = pRefTable[n].latr;
4597 platmax = (int)pRefTable[n].yr;
4602 if ((lonmin * lonmax) < 0) {
4603 if (pRefTable[nlonmin].xr > pRefTable[nlonmax].xr) {
4605 for (n = 0; n < nRefpoint; n++) {
4606 if (pRefTable[n].lonr < 0.0) pRefTable[n].lonr += 360.;
4613 for (n = 0; n < nRefpoint; n++) {
4615 if (pRefTable[n].lonr > lonmax) {
4616 lonmax = pRefTable[n].lonr;
4617 plonmax = (int)pRefTable[n].xr;
4620 if (pRefTable[n].lonr < lonmin) {
4621 lonmin = pRefTable[n].lonr;
4622 plonmin = (int)pRefTable[n].xr;
4627 if (pRefTable[n].latr < latmin) {
4628 latmin = pRefTable[n].latr;
4629 platmin = (int)pRefTable[n].yr;
4631 if (pRefTable[n].latr > latmax) {
4632 latmax = pRefTable[n].latr;
4633 platmax = (int)pRefTable[n].yr;
4640 cPoints.
count = nRefpoint;
4654 cPoints.
tx = (
double *)malloc(nRefpoint *
sizeof(
double));
4655 cPoints.
ty = (
double *)malloc(nRefpoint *
sizeof(
double));
4656 cPoints.
lon = (
double *)malloc(nRefpoint *
sizeof(
double));
4657 cPoints.
lat = (
double *)malloc(nRefpoint *
sizeof(
double));
4659 cPoints.
pwx = (
double *)malloc(12 *
sizeof(
double));
4660 cPoints.
wpx = (
double *)malloc(12 *
sizeof(
double));
4661 cPoints.
pwy = (
double *)malloc(12 *
sizeof(
double));
4662 cPoints.
wpy = (
double *)malloc(12 *
sizeof(
double));
4666 double dist_max = 0.;
4670 for (i = 0; i < nRefpoint; i++) {
4671 for (
int j = i + 1; j < nRefpoint; j++) {
4672 double dx = pRefTable[i].xr - pRefTable[j].xr;
4673 double dy = pRefTable[i].yr - pRefTable[j].yr;
4674 double dist = (dx * dx) + (dy * dy);
4675 if (dist > dist_max) {
4685 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
4686 double easting0, easting1, northing0, northing1;
4688 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4689 &easting0, &northing0);
4690 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4691 &easting1, &northing1);
4694 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4695 (pRefTable[jmax].xr - pRefTable[imax].xr);
4696 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4697 (pRefTable[jmax].yr - pRefTable[imax].yr);
4698 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4699 double de2 = (easting1 - easting0) * (easting1 - easting0);
4701 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4706 for (
int n = 0; n < nRefpoint; n++) {
4707 double easting, northing;
4708 toTM(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4709 &easting, &northing);
4711 cPoints.
tx[n] = pRefTable[n].xr;
4712 cPoints.
ty[n] = pRefTable[n].yr;
4713 cPoints.
lon[n] = easting;
4714 cPoints.
lat[n] = northing;
4718 cPoints.
txmax = plonmax;
4719 cPoints.
txmin = plonmin;
4720 cPoints.
tymax = platmax;
4721 cPoints.
tymin = platmin;
4722 toTM(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.
lonmax,
4724 toTM(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.
lonmin,
4727 Georef_Calculate_Coefficients_Proj(&cPoints);
4731 else if (m_projection == PROJECTION_MERCATOR) {
4732 double easting0, easting1, northing0, northing1;
4734 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4735 &easting0, &northing0);
4736 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4737 &easting1, &northing1);
4744 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4745 (pRefTable[jmax].xr - pRefTable[imax].xr);
4746 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4747 (pRefTable[jmax].yr - pRefTable[imax].yr);
4748 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4749 double de2 = (easting1 - easting0) * (easting1 - easting0);
4751 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4756 for (
int n = 0; n < nRefpoint; n++) {
4757 double easting, northing;
4758 toSM_ECC(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4759 &easting, &northing);
4761 cPoints.
tx[n] = pRefTable[n].xr;
4762 cPoints.
ty[n] = pRefTable[n].yr;
4763 cPoints.
lon[n] = easting;
4764 cPoints.
lat[n] = northing;
4771 cPoints.
txmax = plonmax;
4772 cPoints.
txmin = plonmin;
4773 cPoints.
tymax = platmax;
4774 cPoints.
tymin = platmin;
4775 toSM_ECC(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.
lonmax,
4777 toSM_ECC(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.
lonmin,
4780 Georef_Calculate_Coefficients_Proj(&cPoints);
4802 else if (m_projection == PROJECTION_POLYCONIC) {
4811 double proj_meridian = m_proj_lon;
4813 if ((pRefTable[nlonmax].lonr >= -proj_meridian) &&
4814 (-proj_meridian >= pRefTable[nlonmin].lonr))
4815 m_proj_lon = -m_proj_lon;
4817 double easting0, easting1, northing0, northing1;
4819 toPOLY(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4820 &easting0, &northing0);
4821 toPOLY(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4822 &easting1, &northing1);
4825 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4826 (pRefTable[jmax].xr - pRefTable[imax].xr);
4827 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4828 (pRefTable[jmax].yr - pRefTable[imax].yr);
4829 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4830 double de2 = (easting1 - easting0) * (easting1 - easting0);
4832 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4845 for (
int n = 0; n < nRefpoint; n++) {
4846 double easting, northing;
4847 toPOLY(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4848 &easting, &northing);
4855 cPoints.
tx[n] = pRefTable[n].xr;
4856 cPoints.
ty[n] = pRefTable[n].yr;
4857 cPoints.
lon[n] = easting;
4858 cPoints.
lat[n] = northing;
4865 cPoints.
txmax = plonmax;
4866 cPoints.
txmin = plonmin;
4867 cPoints.
tymax = platmax;
4868 cPoints.
tymin = platmin;
4869 toPOLY(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.
lonmax,
4871 toPOLY(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.
lonmin,
4874 Georef_Calculate_Coefficients_Proj(&cPoints);
4886 else if (bHaveEmbeddedGeoref) {
4888 double easting0, easting1, northing0, northing1;
4890 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4891 &easting0, &northing0);
4892 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4893 &easting1, &northing1);
4898 double dx = (pRefTable[jmax].xr - pRefTable[imax].xr);
4899 double de = (easting1 - easting0);
4901 m_ppm_avg = fabs(dx / de);
4903 m_ExtraInfo =
"---<<< Warning: Chart georef accuracy may be poor. >>>---";
4912 vps.
clat = pRefTable[0].latr;
4913 vps.
clon = pRefTable[0].lonr;
4920 latlong_to_pix_vp(latmin, (lonmax + lonmin)/2., x1, y1, vps);
4921 latlong_to_pix_vp(latmax, (lonmax + lonmin)/2., x2, y2, vps);
4923 double apparent_skew = (atan2( (y2-y1), (x2-x1) ) * 180./PI) + 90.;
4924 if(apparent_skew < 0.)
4925 apparent_skew += 360;
4926 if(apparent_skew > 360.)
4927 apparent_skew -= 360;
4929 if(fabs( apparent_skew - m_Chart_Skew ) > 2) {
4930 m_Chart_Skew = apparent_skew;
4934 if (!b_testSolution)
return (0);
4938 vp.
clat = pRefTable[0].latr;
4939 vp.
clon = pRefTable[0].lonr;
4945 SetVPRasterParms(vp);
4947 double xpl_err_max = 0;
4948 double ypl_err_max = 0;
4952 pxref = (int)pRefTable[0].xr;
4953 pyref = (int)pRefTable[0].yr;
4955 for (i = 0; i < nRefpoint; i++) {
4956 px = (int)(vp.
pix_width / 2 + pRefTable[i].xr) - pxref;
4957 py = (int)(vp.
pix_height / 2 + pRefTable[i].yr) - pyref;
4959 vp_pix_to_latlong(vp, px, py, &elt, &elg);
4961 double lat_error = elt - pRefTable[i].latr;
4962 pRefTable[i].ypl_error = lat_error;
4964 double lon_error = elg - pRefTable[i].lonr;
4967 if (fabs(lon_error) > 180.) {
4970 else if (lon_error < 0.)
4973 pRefTable[i].xpl_error = lon_error;
4975 if (fabs(pRefTable[i].ypl_error) > fabs(ypl_err_max))
4976 ypl_err_max = pRefTable[i].ypl_error;
4977 if (fabs(pRefTable[i].xpl_error) > fabs(xpl_err_max))
4978 xpl_err_max = pRefTable[i].xpl_error;
4981 Chart_Error_Factor = fmax(fabs(xpl_err_max / (lonmax - lonmin)),
4982 fabs(ypl_err_max / (latmax - latmin)));
4983 double chart_error_meters =
4984 fmax(fabs(xpl_err_max * 60. * 1852.), fabs(ypl_err_max * 60. * 1852.));
4988 double chart_error_pixels = chart_error_meters * 4000. / m_Chart_Scale;
4991 int max_pixel_error = 4;
4993 if (chart_error_pixels > max_pixel_error) {
4995 " VP Final Check: Georeference Chart_Error_Factor on chart ";
4996 msg.Append(m_FullPath);
4998 msg1.Printf(
" is %5g \n nominal pixel error is: %5g",
4999 Chart_Error_Factor, chart_error_pixels);
5004 m_ExtraInfo =
"---<<< Warning: Chart georef accuracy is poor. >>>---";
5010 if ((chart_error_pixels > max_pixel_error) && bHaveEmbeddedGeoref) {
5012 " Trying again with internally calculated georef solution ";
5015 bHaveEmbeddedGeoref =
false;
5016 SetVPRasterParms(vp);
5021 pxref = (int)pRefTable[0].xr;
5022 pyref = (int)pRefTable[0].yr;
5024 for (i = 0; i < nRefpoint; i++) {
5025 px = (int)(vp.
pix_width / 2 + pRefTable[i].xr) - pxref;
5026 py = (int)(vp.
pix_height / 2 + pRefTable[i].yr) - pyref;
5028 vp_pix_to_latlong(vp, px, py, &elt, &elg);
5030 double lat_error = elt - pRefTable[i].latr;
5031 pRefTable[i].ypl_error = lat_error;
5033 double lon_error = elg - pRefTable[i].lonr;
5036 if (fabs(lon_error) > 180.) {
5039 else if (lon_error < 0.)
5042 pRefTable[i].xpl_error = lon_error;
5044 if (fabs(pRefTable[i].ypl_error) > fabs(ypl_err_max))
5045 ypl_err_max = pRefTable[i].ypl_error;
5046 if (fabs(pRefTable[i].xpl_error) > fabs(xpl_err_max))
5047 xpl_err_max = pRefTable[i].xpl_error;
5050 Chart_Error_Factor = fmax(fabs(xpl_err_max / (lonmax - lonmin)),
5051 fabs(ypl_err_max / (latmax - latmin)));
5053 chart_error_meters =
5054 fmax(fabs(xpl_err_max * 60. * 1852.), fabs(ypl_err_max * 60. * 1852.));
5055 chart_error_pixels = chart_error_meters * 4000. / m_Chart_Scale;
5058 if (chart_error_pixels > max_pixel_error) {
5060 " VP Final Check with internal georef: Georeference "
5061 "Chart_Error_Factor on chart ";
5062 msg.Append(m_FullPath);
5064 msg1.Printf(
" is %5g\n nominal pixel error is: %5g",
5065 Chart_Error_Factor, chart_error_pixels);
5070 m_ExtraInfo =
"---<<< Warning: Chart georef accuracy is poor. >>>---";
5072 wxString msg =
" Result: OK, Internal georef solution used.";
5083double ChartBaseBSB::AdjustLongitude(
double lon) {
5084 double lond = (m_LonMin + m_LonMax) / 2 - lon;
5087 else if (lond < -180)
5123static double polytrans(
double *coeff,
double lon,
double lat) {
5124 double ret = coeff[0] + coeff[1] * lon + coeff[2] * lat;
5125 ret += coeff[3] * lon * lon;
5126 ret += coeff[4] * lon * lat;
5127 ret += coeff[5] * lat * lat;
5128 ret += coeff[6] * lon * lon * lon;
5129 ret += coeff[7] * lon * lon * lat;
5130 ret += coeff[8] * lon * lat * lat;
5131 ret += coeff[9] * lat * lat * lat;
5153extern int bsb_LLtoXY(BSBImage *p,
double lon,
double lat,
int* x,
int* y)
5156 lon = (lon < 0) ? lon + p->cph : lon - p->cph;
5157 double xd = polytrans( p->wpx, lon, lat );
5158 double yd = polytrans( p->wpy, lon, lat );
5159 *x = (int)(xd + 0.5);
5160 *y = (int)(yd + 0.5);
5175extern int bsb_XYtoLL(BSBImage *p,
int x,
int y,
double* lonout,
double* latout)
5177 double lon = polytrans( p->pwx, x, y );
5178 lon = (lon < 0) ? lon + p->cph : lon - p->cph;
5180 *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.
MyConfig * pConfig
Global instance.
Optimized wxBitmap Object.
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.