48#include <wx/wfstream.h>
49#include <wx/tokenzr.h>
50#include <wx/filename.h>
52#include <wx/fileconf.h>
57#include "ocpn_pixel.h"
58#include "model/chartdata_input_stream.h"
64#define OCPN_USE_CONFIG 1
66struct sigaction sa_all_chart;
67struct sigaction sa_all_previous;
71void catch_signals_chart(
int signo) {
74 siglongjmp(env_chart, 1);
86typedef __int32 int32_t;
87typedef unsigned __int32 uint32_t;
88typedef __int64 int64_t;
89typedef unsigned __int64 uint64_t;
106bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
116ThumbData::ThumbData() { pDIBThumb = NULL; }
118ThumbData::~ThumbData() {
delete pDIBThumb; }
123opncpnPalette::opncpnPalette() {
127 FwdPalette = (
int *)malloc(
sizeof(
int));
128 RevPalette = (
int *)malloc(
sizeof(
int));
133opncpnPalette::~opncpnPalette() {
134 if (NULL != FwdPalette) free(FwdPalette);
135 if (NULL != RevPalette) free(RevPalette);
141ChartBase::ChartBase() {
142 m_depth_unit_id = DEPTH_UNIT_UNKNOWN;
146 m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB;
148 bReadyToRender =
false;
150 Chart_Error_Factor = 0;
152 m_Chart_Scale = 10000;
157 m_pCOVRTablePoints = NULL;
159 m_nNoCOVREntries = 0;
160 m_pNoCOVRTable = NULL;
161 m_pNoCOVRTablePoints = NULL;
163 m_EdDate = wxInvalidDateTime;
165 m_lon_datum_adjust = 0.;
166 m_lat_datum_adjust = 0.;
168 m_projection = PROJECTION_MERCATOR;
171ChartBase::~ChartBase() {
176 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++)
177 free(m_pCOVRTable[j]);
180 free(m_pCOVRTablePoints);
184 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++)
185 free(m_pNoCOVRTable[j]);
187 free(m_pNoCOVRTable);
188 free(m_pNoCOVRTablePoints);
191wxString ChartBase::GetHashKey()
const {
192 wxString key = GetFullPath();
193 wxChar separator = wxFileName::GetPathSeparator();
194 for (
unsigned int pos = 0; pos < key.size(); pos = key.find(separator, pos))
195 key.replace(pos, 1, _T(
"!"));
210ChartDummy::ChartDummy() {
212 m_ChartType = CHART_TYPE_DUMMY;
213 m_ChartFamily = CHART_FAMILY_UNKNOWN;
214 m_Chart_Scale = 22000000;
216 m_FullPath = _T(
"No Chart Available");
217 m_Description = m_FullPath;
220ChartDummy::~ChartDummy() {
delete m_pBM; }
222InitReturn ChartDummy::Init(
const wxString &name, ChartInitFlag init_flags) {
226void ChartDummy::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {}
228ThumbData *ChartDummy::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
232bool ChartDummy::UpdateThumbData(
double lat,
double lon) {
return FALSE; }
234bool ChartDummy::GetChartExtent(
Extent *pext) {
243bool ChartDummy::RenderRegionViewOnGL(
const wxGLContext &glc,
246 const LLRegion &Region) {
250bool ChartDummy::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
252 return RenderViewOnDC(dc, VPoint);
255bool ChartDummy::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
256 if (m_pBM && m_pBM->IsOk()) {
257 if ((m_pBM->GetWidth() != VPoint.
pix_width) ||
271 dc.SelectObject(*m_pBM);
273 dc.SetBackground(*wxBLACK_BRUSH);
284void ChartDummy::GetValidCanvasRegion(
const ViewPort &VPoint,
286 pValidRegion->Clear();
287 pValidRegion->Union(0, 0, 1, 1);
290LLRegion ChartDummy::GetValidRegion() {
return LLRegion(); }
295ChartGEO::ChartGEO() { m_ChartType = CHART_TYPE_GEO; }
297ChartGEO::~ChartGEO() {}
299InitReturn ChartGEO::Init(
const wxString &name, ChartInitFlag init_flags) {
300#define BUF_LEN_MAX 4096
302 PreInit(name, init_flags, GLOBAL_COLOR_SCHEME_DAY);
304 char buffer[BUF_LEN_MAX];
307 new wxFFileInputStream(name);
309 m_filesize = wxFileName::GetSize(name);
311 if (!ifs_hdr->IsOk())
return INIT_FAIL_REMOVE;
317 m_Description = m_FullPath;
319 wxFileName GEOFile(m_FullPath);
322 Path = GEOFile.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME);
326 ifs_hdr->SeekI(0, wxFromStart);
330 while ((ReadBSBHdrLine(ifs_hdr, &buffer[0], BUF_LEN_MAX)) != 0) {
331 wxString str_buf(buffer, wxConvUTF8);
332 if (!strncmp(buffer,
"Bitmap", 6)) {
333 wxStringTokenizer tkz(str_buf, _T(
"="));
334 wxString token = tkz.GetNextToken();
335 if (token.IsSameAs(_T(
"Bitmap"), TRUE)) {
336 pBitmapFilePath =
new wxString();
339 i = tkz.GetPosition();
340 pBitmapFilePath->Clear();
342 pBitmapFilePath->Append(buffer[i]);
348 else if (!strncmp(buffer,
"Scale", 5)) {
349 wxStringTokenizer tkz(str_buf, _T(
"="));
350 wxString token = tkz.GetNextToken();
351 if (token.IsSameAs(_T(
"Scale"), TRUE))
354 i = tkz.GetPosition();
355 m_Chart_Scale = atoi(&buffer[i]);
359 else if (!strncmp(buffer,
"Depth", 5)) {
360 wxStringTokenizer tkz(str_buf, _T(
"="));
361 wxString token = tkz.GetNextToken();
362 if (token.IsSameAs(_T(
"Depth Units"), FALSE))
365 i = tkz.GetPosition();
366 wxString str(&buffer[i], wxConvUTF8);
367 m_DepthUnits = str.Trim();
371 else if (!strncmp(buffer,
"Point", 5))
375 sscanf(&buffer[0],
"Point%d=%f %f %d %d", &i, &lnr, <r, &yr, &xr);
378 pRefTable[nRefpoint].xr = xr;
379 pRefTable[nRefpoint].yr = yr;
380 pRefTable[nRefpoint].latr = ltr;
381 pRefTable[nRefpoint].lonr = lnr;
382 pRefTable[nRefpoint].bXValid = 1;
383 pRefTable[nRefpoint].bYValid = 1;
389 else if (!strncmp(buffer,
"Vertex", 6)) {
392 sscanf(buffer,
"Vertex%d=%f %f", &i, <p, &lnp);
396 if (NULL == pPlyTable) {
400 pPlyTable[nPlypoint].ltp = ltp;
401 pPlyTable[nPlypoint].lnp = lnp;
406 else if (!strncmp(buffer,
"Date Pub", 8)) {
407 char date_string[40];
409 sscanf(buffer,
"Date Published=%s\r\n", &date_string[0]);
410 wxString date_wxstr(date_string, wxConvUTF8);
412 if (dt.ParseDate(date_wxstr))
414 sprintf(date_buf,
"%d", dt.GetYear());
416 sscanf(date_string,
"%s", date_buf);
418 m_PubYear = wxString(date_buf, wxConvUTF8);
421 else if (!strncmp(buffer,
"Skew", 4)) {
422 wxStringTokenizer tkz(str_buf, _T(
"="));
423 wxString token = tkz.GetNextToken();
424 if (token.IsSameAs(_T(
"Skew Angle"), FALSE))
427 i = tkz.GetPosition();
429 sscanf(&buffer[i],
"%f,", &fcs);
434 else if (!strncmp(buffer,
"Latitude Offset", 15)) {
435 wxStringTokenizer tkz(str_buf, _T(
"="));
436 wxString token = tkz.GetNextToken();
437 if (token.IsSameAs(_T(
"Latitude Offset"), FALSE)) {
439 i = tkz.GetPosition();
441 sscanf(&buffer[i],
"%f,", <o);
446 else if (!strncmp(buffer,
"Longitude Offset", 16)) {
447 wxStringTokenizer tkz(str_buf, _T(
"="));
448 wxString token = tkz.GetNextToken();
449 if (token.IsSameAs(_T(
"Longitude Offset"), FALSE)) {
451 i = tkz.GetPosition();
453 sscanf(&buffer[i],
"%f,", &lno);
458 else if (!strncmp(buffer,
"Datum", 5)) {
459 wxStringTokenizer tkz(str_buf, _T(
"="));
460 wxString token = tkz.GetNextToken();
461 if (token.IsSameAs(_T(
"Datum"), FALSE)) {
462 token = tkz.GetNextToken();
467 else if (!strncmp(buffer,
"Name", 4)) {
468 wxStringTokenizer tkz(str_buf, _T(
"="));
469 wxString token = tkz.GetNextToken();
470 if (token.IsSameAs(_T(
"Name"), FALSE))
473 i = tkz.GetPosition();
475 while (isprint(buffer[i]) && (i < 80)) m_Name.Append(buffer[i++]);
487 if (pBitmapFilePath == NULL) {
489 return INIT_FAIL_REMOVE;
492 wxString NOS_Name(*pBitmapFilePath);
494 wxDir target_dir(Path);
495 wxArrayString file_array;
496 int nfiles = wxDir::GetAllFiles(Path, &file_array);
499 pBitmapFilePath->Prepend(Path);
501 wxFileName NOS_filename(*pBitmapFilePath);
502 if (!NOS_filename.FileExists()) {
506 wxString fname(NOS_filename.GetName());
507 wxString fext(NOS_filename.GetExt());
513 NOS_filename.SetName(fname);
514 NOS_filename.SetExt(fext);
516 if (NOS_filename.FileExists())
goto found_uclc_file;
521 NOS_filename.SetName(fname);
522 NOS_filename.SetExt(fext);
524 if (NOS_filename.FileExists())
goto found_uclc_file;
529 NOS_filename.SetName(fname);
530 NOS_filename.SetExt(fext);
532 if (NOS_filename.FileExists())
goto found_uclc_file;
537 NOS_filename.SetName(fname);
538 NOS_filename.SetExt(fext);
540 if (NOS_filename.FileExists())
goto found_uclc_file;
544 for (ifile = 0; ifile < nfiles; ifile++) {
545 wxString file_up = file_array[ifile];
548 wxString target_up = *pBitmapFilePath;
549 target_up.MakeUpper();
551 if (file_up.IsSameAs(target_up)) {
552 NOS_filename.Clear();
553 NOS_filename.Assign(file_array[ifile]);
554 goto found_uclc_file;
559 return INIT_FAIL_REMOVE;
563 delete pBitmapFilePath;
564 pBitmapFilePath =
new wxString(NOS_filename.GetFullPath());
567 new wxFFileInputStream(*pBitmapFilePath);
568 ifs_bitmap =
new wxBufferedInputStream(*ifss_bitmap);
570 if (!ifss_bitmap->IsOk()) {
572 return INIT_FAIL_REMOVE;
575 while ((ReadBSBHdrLine(ifss_bitmap, &buffer[0], BUF_LEN_MAX)) != 0) {
576 wxString str_buf(buffer, wxConvUTF8);
578 if (!strncmp(buffer,
"NOS", 3)) {
579 wxStringTokenizer tkz(str_buf, _T(
",="));
580 while (tkz.HasMoreTokens()) {
581 wxString token = tkz.GetNextToken();
582 if (token.IsSameAs(_T(
"RA"), TRUE))
587 i = tkz.GetPosition();
588 Size_X = atoi(&buffer[i]);
589 wxString token = tkz.GetNextToken();
590 i = tkz.GetPosition();
591 Size_Y = atoi(&buffer[i]);
592 }
else if (token.IsSameAs(_T(
"DU"), TRUE))
594 token = tkz.GetNextToken();
596 if (token.ToLong(&temp_du)) m_Chart_DU = temp_du;
602 else if (!strncmp(buffer,
"RGB", 3))
603 CreatePaletteEntry(buffer, COLOR_RGB_DEFAULT);
605 else if (!strncmp(buffer,
"DAY", 3))
606 CreatePaletteEntry(buffer, DAY);
608 else if (!strncmp(buffer,
"DSK", 3))
609 CreatePaletteEntry(buffer, DUSK);
611 else if (!strncmp(buffer,
"NGT", 3))
612 CreatePaletteEntry(buffer, NIGHT);
614 else if (!strncmp(buffer,
"NGR", 3))
615 CreatePaletteEntry(buffer, NIGHTRED);
617 else if (!strncmp(buffer,
"GRY", 3))
618 CreatePaletteEntry(buffer, GRAY);
620 else if (!strncmp(buffer,
"PRC", 3))
621 CreatePaletteEntry(buffer, PRC);
623 else if (!strncmp(buffer,
"PRG", 3))
624 CreatePaletteEntry(buffer, PRG);
628 if (Size_X <= 0 || Size_Y <= 0) {
630 return INIT_FAIL_REMOVE;
634 wxString msg(_T(
" Chart File contains less than 3 PLY points: "));
635 msg.Append(m_FullPath);
639 return INIT_FAIL_REMOVE;
642 if (m_datum_str.IsEmpty()) {
643 wxString msg(_T(
" Chart datum not specified on chart "));
644 msg.Append(m_FullPath);
646 wxLogMessage(_T(
" Default datum (WGS84) substituted."));
651 strncpy(d_str, m_datum_str.mb_str(), 99);
654 int datum_index = GetDatumIndex(d_str);
656 if (datum_index < 0) {
657 wxString msg(_T(
" Chart datum {"));
659 msg += _T(
"} invalid on chart ");
660 msg.Append(m_FullPath);
662 wxLogMessage(_T(
" Default datum (WGS84) substituted."));
664 datum_index = DATUM_INDEX_WGS84;
666 m_datum_index = datum_index;
671 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
672 *m_pCOVRTablePoints = nPlypoint;
673 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
674 *m_pCOVRTable = (
float *)malloc(nPlypoint * 2 *
sizeof(
float));
675 memcpy(*m_pCOVRTable, pPlyTable, nPlypoint * 2 *
sizeof(
float));
679 if (!SetMinMax())
return INIT_FAIL_REMOVE;
683 if (init_flags == HEADER_ONLY)
return INIT_OK;
687 if ((c = ifs_bitmap->GetC()) != 0x1a) {
688 return INIT_FAIL_REMOVE;
690 if ((c = ifs_bitmap->GetC()) == 0x0d) {
691 if ((c = ifs_bitmap->GetC()) != 0x0a) {
692 return INIT_FAIL_REMOVE;
694 if ((c = ifs_bitmap->GetC()) != 0x1a) {
695 return INIT_FAIL_REMOVE;
697 if ((c = ifs_bitmap->GetC()) != 0x00) {
698 return INIT_FAIL_REMOVE;
702 else if (c != 0x00) {
703 return INIT_FAIL_REMOVE;
707 nColorSize = ifs_bitmap->GetC();
708 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
709 wxString msg(_T(
" Invalid nColorSize data, corrupt on chart "));
710 msg.Append(m_FullPath);
712 return INIT_FAIL_REMOVE;
716 InitReturn pi_ret = PostInit();
717 if (pi_ret != INIT_OK)
727ChartKAP::ChartKAP() { m_ChartType = CHART_TYPE_KAP; }
729ChartKAP::~ChartKAP() {}
731InitReturn ChartKAP::Init(
const wxString &name, ChartInitFlag init_flags) {
732#define BUF_LEN_MAX 4096
734 ifs_hdr =
new ChartDataNonSeekableInputStream(
737 if (!ifs_hdr->IsOk())
return INIT_FAIL_REMOVE;
742 PreInit(name, init_flags, GLOBAL_COLOR_SCHEME_DAY);
744 char buffer[BUF_LEN_MAX];
747 m_Description = m_FullPath;
750 for (
int icl = 0; icl < 12; icl++) {
760 unsigned int TestBlockSize = 1999;
761 ifs_hdr->Read(buffer, TestBlockSize);
763 if (ifs_hdr->LastRead() != TestBlockSize) {
766 _T(
" Could not read first %d bytes of header for chart file: "),
771 return INIT_FAIL_REMOVE;
775 for (i = 0; i < TestBlockSize - 4; i++) {
777 if (buffer[i + 0] ==
'B' && buffer[i + 1] ==
'S' && buffer[i + 2] ==
'B' &&
778 buffer[i + 3] ==
'/')
782 if (buffer[i + 0] ==
'N' && buffer[i + 1] ==
'O' && buffer[i + 2] ==
'S' &&
783 buffer[i + 3] ==
'/')
786 if (i == TestBlockSize - 4) {
787 wxString msg(_T(
" Chart file has no BSB header, cannot Init."));
791 return INIT_FAIL_REMOVE;
795 ifs_hdr->SeekI(0, wxFromStart);
799 int done_header_parse = 0;
800 wxCSConv iso_conv(wxT(
"ISO-8859-1"));
802 while (done_header_parse == 0) {
803 if (ReadBSBHdrLine(ifs_hdr, buffer, BUF_LEN_MAX) == 0) {
809 done_header_parse = 1;
812 return INIT_FAIL_REMOVE;
818 wxString str_buf(buffer, wxConvUTF8);
820 str_buf = wxString(buffer, iso_conv);
822 if (str_buf.Find(_T(
"SHOM")) != wxNOT_FOUND) m_b_SHOM =
true;
824 if (!strncmp(buffer,
"BSB", 3)) {
825 wxString clip_str_buf(
828 wxStringTokenizer tkz(clip_str_buf, _T(
"/,="));
829 while (tkz.HasMoreTokens()) {
830 wxString token = tkz.GetNextToken();
831 if (token.IsSameAs(_T(
"RA"), TRUE))
834 i = tkz.GetPosition();
835 Size_X = atoi(&buffer[i]);
836 wxString token = tkz.GetNextToken();
837 i = tkz.GetPosition();
838 Size_Y = atoi(&buffer[i]);
839 }
else if (token.IsSameAs(_T(
"NA"), TRUE))
841 int i = tkz.GetPosition();
844 while ((buffer[i] !=
',') && (i < 80)) nbuf[j++] = buffer[i++];
846 wxString n_str(nbuf, iso_conv);
848 }
else if (token.IsSameAs(_T(
"NU"), TRUE))
850 int i = tkz.GetPosition();
853 while ((buffer[i] !=
',') && (i < 80)) nbuf[j++] = buffer[i++];
855 wxString n_str(nbuf, iso_conv);
857 }
else if (token.IsSameAs(_T(
"DU"), TRUE))
859 token = tkz.GetNextToken();
861 if (token.ToLong(&temp_du)) m_Chart_DU = temp_du;
866 else if (!strncmp(buffer,
"KNP", 3)) {
867 wxString conv_buf(buffer, iso_conv);
868 wxStringTokenizer tkz(conv_buf, _T(
"/,="));
869 while (tkz.HasMoreTokens()) {
870 wxString token = tkz.GetNextToken();
871 if (token.IsSameAs(_T(
"SC"), TRUE))
874 i = tkz.GetPosition();
875 m_Chart_Scale = atoi(&buffer[i]);
876 if (0 == m_Chart_Scale) m_Chart_Scale = 100000000;
877 }
else if (token.IsSameAs(_T(
"SK"), TRUE))
880 i = tkz.GetPosition();
882 sscanf(&buffer[i],
"%f,", &fcs);
884 }
else if (token.IsSameAs(_T(
"UN"), TRUE))
887 i = tkz.GetPosition();
888 wxString str(&buffer[i], iso_conv);
889 m_DepthUnits = str.BeforeFirst(
',');
890 }
else if (token.IsSameAs(_T(
"GD"), TRUE))
893 i = tkz.GetPosition();
894 wxString str(&buffer[i], iso_conv);
895 m_datum_str = str.BeforeFirst(
',').Trim();
896 }
else if (token.IsSameAs(_T(
"SD"), TRUE))
899 i = tkz.GetPosition();
900 wxString str(&buffer[i], iso_conv);
901 m_SoundingsDatum = str.BeforeFirst(
',').Trim();
902 }
else if (token.IsSameAs(_T(
"PP"),
906 i = tkz.GetPosition();
908 wxString str(&buffer[i], iso_conv);
909 wxString str1 = str.BeforeFirst(
',').Trim();
910 if (str1.ToDouble(&fcs)) m_proj_parameter = fcs;
911 }
else if (token.IsSameAs(_T(
"PR"), TRUE))
914 i = tkz.GetPosition();
915 wxString str(&buffer[i], iso_conv);
916 wxString stru = str.MakeUpper();
920 if (stru.Matches(_T(
"*MERCATOR*"))) {
921 m_projection = PROJECTION_MERCATOR;
925 if (stru.Matches(_T(
"*TRANSVERSE*"))) {
926 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
930 if (stru.Matches(_T(
"*CONIC*"))) {
931 m_projection = PROJECTION_POLYCONIC;
935 if (stru.Matches(_T(
"*TM*"))) {
936 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
940 if (stru.Matches(_T(
"*GAUSS CONFORMAL*"))) {
941 m_projection = PROJECTION_TRANSVERSE_MERCATOR;
946 m_projection = PROJECTION_UNKNOWN;
947 wxString msg(_T(
" Chart projection is "));
948 msg += tkz.GetNextToken();
949 msg += _T(
" which is unsupported. Disabling chart ");
953 return INIT_FAIL_REMOVE;
955 }
else if (token.IsSameAs(
960 i = tkz.GetPosition();
962 sscanf(&buffer[i],
"%f,", &x);
964 }
else if (token.IsSameAs(
969 i = tkz.GetPosition();
971 sscanf(&buffer[i],
"%f,", &x);
977 else if (!strncmp(buffer,
"RGB", 3))
978 CreatePaletteEntry(buffer, COLOR_RGB_DEFAULT);
980 else if (!strncmp(buffer,
"DAY", 3))
981 CreatePaletteEntry(buffer, DAY);
983 else if (!strncmp(buffer,
"DSK", 3))
984 CreatePaletteEntry(buffer, DUSK);
986 else if (!strncmp(buffer,
"NGT", 3))
987 CreatePaletteEntry(buffer, NIGHT);
989 else if (!strncmp(buffer,
"NGR", 3))
990 CreatePaletteEntry(buffer, NIGHTRED);
992 else if (!strncmp(buffer,
"GRY", 3))
993 CreatePaletteEntry(buffer, GRAY);
995 else if (!strncmp(buffer,
"PRC", 3))
996 CreatePaletteEntry(buffer, PRC);
998 else if (!strncmp(buffer,
"PRG", 3))
999 CreatePaletteEntry(buffer, PRG);
1001 else if (!strncmp(buffer,
"REF", 3)) {
1004 sscanf(&buffer[4],
"%d,%d,%d,%f,%f", &i, &xr, &yr, <r, &lnr);
1007 pRefTable[nRefpoint].xr = xr;
1008 pRefTable[nRefpoint].yr = yr;
1009 pRefTable[nRefpoint].latr = ltr;
1010 pRefTable[nRefpoint].lonr = lnr;
1011 pRefTable[nRefpoint].bXValid = 1;
1012 pRefTable[nRefpoint].bYValid = 1;
1018 else if (!strncmp(buffer,
"WPX", 3)) {
1021 wxStringTokenizer tkz(str_buf.Mid(4), _T(
","));
1022 wxString token = tkz.GetNextToken();
1024 if (token.ToLong((
long int *)&wpx_type)) {
1025 while (tkz.HasMoreTokens() && (idx < 12)) {
1026 token = tkz.GetNextToken();
1027 if (token.ToDouble(&d)) {
1036 else if (!strncmp(buffer,
"WPY", 3)) {
1039 wxStringTokenizer tkz(str_buf.Mid(4), _T(
","));
1040 wxString token = tkz.GetNextToken();
1042 if (token.ToLong((
long int *)&wpy_type)) {
1043 while (tkz.HasMoreTokens() && (idx < 12)) {
1044 token = tkz.GetNextToken();
1045 if (token.ToDouble(&d)) {
1054 else if (!strncmp(buffer,
"PWX", 3)) {
1057 wxStringTokenizer tkz(str_buf.Mid(4), _T(
","));
1058 wxString token = tkz.GetNextToken();
1060 if (token.ToLong((
long int *)&pwx_type)) {
1061 while (tkz.HasMoreTokens() && (idx < 12)) {
1062 token = tkz.GetNextToken();
1063 if (token.ToDouble(&d)) {
1072 else if (!strncmp(buffer,
"PWY", 3)) {
1075 wxStringTokenizer tkz(str_buf.Mid(4), _T(
","));
1076 wxString token = tkz.GetNextToken();
1078 if (token.ToLong((
long int *)&pwy_type)) {
1079 while (tkz.HasMoreTokens() && (idx < 12)) {
1080 token = tkz.GetNextToken();
1081 if (token.ToDouble(&d)) {
1090 else if (!strncmp(buffer,
"CPH", 3)) {
1092 sscanf(&buffer[4],
"%f", &float_cph);
1096 else if (!strncmp(buffer,
"VER", 3)) {
1097 wxStringTokenizer tkz(str_buf, _T(
"/,="));
1098 wxString token = tkz.GetNextToken();
1100 m_bsb_ver = tkz.GetNextToken();
1103 else if (!strncmp(buffer,
"DTM", 3)) {
1105 wxStringTokenizer tkz(str_buf, _T(
"/,="));
1106 wxString token = tkz.GetNextToken();
1108 token = tkz.GetNextToken();
1109 if (token.ToDouble(&val)) m_dtm_lat = val;
1111 token = tkz.GetNextToken();
1112 if (token.ToDouble(&val)) m_dtm_lon = val;
1120 else if (!strncmp(buffer,
"PLY", 3)) {
1123 if (sscanf(&buffer[4],
"%d,%f,%f", &i, <p, &lnp) != 3) {
1125 return INIT_FAIL_REMOVE;
1130 if (NULL == pPlyTable) {
1134 pPlyTable[nPlypoint].ltp = ltp;
1135 pPlyTable[nPlypoint].lnp = lnp;
1138 if (NULL == pPlyTable || nPlypoint > 1000000) {
1145 else if (!strncmp(buffer,
"CED", 3)) {
1146 wxStringTokenizer tkz(str_buf, _T(
"/,="));
1147 while (tkz.HasMoreTokens()) {
1148 wxString token = tkz.GetNextToken();
1149 if (token.IsSameAs(_T(
"ED"), TRUE))
1152 i = tkz.GetPosition();
1154 char date_string[40];
1158 sscanf(&buffer[i],
"%s\r\n", date_string);
1159 wxString date_wxstr(date_string, wxConvUTF8);
1162 if (dt.ParseDate(date_wxstr))
1173 }
else if ((iyear >= 50) && (iyear < 100)) {
1177 assert(iyear <= 9999);
1178 sprintf(date_buf,
"%d", iyear);
1183 sscanf(date_string,
"%s", date_buf);
1184 m_EdDate.Set(1, wxDateTime::Jan,
1188 m_PubYear = wxString(date_buf, wxConvUTF8);
1189 }
else if (token.IsSameAs(_T(
"SE"), TRUE))
1192 i = tkz.GetPosition();
1193 wxString str(&buffer[i], iso_conv);
1194 m_SE = str.BeforeFirst(
',');
1202 if (m_b_SHOM && (m_bsb_ver == _T(
"1.1"))) m_b_apply_dtm =
false;
1206 if (n_pwx && n_pwy && n_pwx && n_pwy) bHaveEmbeddedGeoref =
true;
1209 if (m_projection == PROJECTION_MERCATOR)
1210 m_proj_lat = m_proj_parameter;
1211 else if (m_projection == PROJECTION_TRANSVERSE_MERCATOR)
1212 m_proj_lon = m_proj_parameter;
1213 else if (m_projection == PROJECTION_POLYCONIC)
1214 m_proj_lon = m_proj_parameter;
1218 if (m_proj_lat > 82.0 || m_proj_lat < -82.0) m_proj_lat = 0.0;
1221 if (Size_X <= 0 || Size_Y <= 0) {
1223 return INIT_FAIL_REMOVE;
1226 if (nPlypoint < 3) {
1228 _T(
" Chart File contains less than 3 or too many PLY points: "));
1229 msg.Append(m_FullPath);
1232 return INIT_FAIL_REMOVE;
1235 if (m_datum_str.IsEmpty()) {
1236 wxString msg(_T(
" Chart datum not specified on chart "));
1237 msg.Append(m_FullPath);
1239 wxLogMessage(_T(
" Default datum (WGS84) substituted."));
1244 strncpy(d_str, m_datum_str.mb_str(), 99);
1247 int datum_index = GetDatumIndex(d_str);
1249 if (datum_index < 0) {
1250 wxString msg(_T(
" Chart datum {"));
1252 msg += _T(
"} invalid on chart ");
1253 msg.Append(m_FullPath);
1255 wxLogMessage(_T(
" Default datum (WGS84) substituted."));
1267 if ((m_projection != PROJECTION_MERCATOR &&
1268 m_projection != PROJECTION_TRANSVERSE_MERCATOR) ||
1271 AnalyzeRefpoints(
false);
1280 for (
int i = 0; i < nPlypoint; i++) {
1281 m_LatMax = wxMax(m_LatMax, pPlyTable[i].ltp);
1282 m_LatMin = wxMin(m_LatMin, pPlyTable[i].ltp);
1283 m_LonMax = wxMax(m_LonMax, pPlyTable[i].lnp);
1284 m_LonMin = wxMin(m_LonMin, pPlyTable[i].lnp);
1287 int count = nPlypoint;
1289 Plypoint *pOldPlyTable = pPlyTable;
1291 double lastplylat = 0.0, lastplylon = 0.0, x1 = 0.0, y1 = 0.0, x2, y2;
1292 double plylat, plylon;
1293 for (
int i = 0; i < count + 1; i++) {
1294 plylat = pOldPlyTable[i % count].ltp;
1295 plylon = pOldPlyTable[i % count].lnp;
1296 latlong_to_chartpix(plylat, plylon, x2, y2);
1298 if (lastplylon - plylon > 180.)
1300 else if (lastplylon - plylon < -180.)
1305 ceil((fabs(lastplylat - plylat) + fabs(lastplylon - plylon)) / 2);
1306 for (
double c = 0; c < steps; c++) {
1307 double d = c / steps, lat, lon;
1309 double x = (1 - d) * x1 + d * x2, y = (1 - d) * y1 + d * y2;
1310 chartpix_to_latlong(x, y, &lat, &lon);
1311 pPlyTable = (
Plypoint *)realloc(pPlyTable,
1312 sizeof(
Plypoint) * (nPlypoint + 1));
1313 pPlyTable[nPlypoint].ltp = lat;
1314 pPlyTable[nPlypoint].lnp = lon;
1319 lastplylat = plylat, lastplylon = plylon;
1333 for (
int i = 0; i < nPlypoint; i++) {
1334 m_LonMin = wxMin(m_LonMin, pPlyTable[i].lnp);
1335 m_LonMax = wxMax(m_LonMax, pPlyTable[i].lnp);
1339 bool b_adjusted =
false;
1340 if (m_LonMax * m_LonMin < 0) {
1341 if ((m_LonMax - m_LonMin) > 180.) b_test =
false;
1345 if (!bHaveEmbeddedGeoref) {
1348 AnalyzeRefpoints(
false);
1351 bool bAdjustPly =
false;
1352 wxRect bitRect(0, 0, Size_X, Size_Y);
1354 for (
int i = 0; i < nPlypoint; i++) {
1355 double pix_x, pix_y;
1356 latlong_to_chartpix(pPlyTable[i].ltp, pPlyTable[i].lnp, pix_x, pix_y);
1357 if (!bitRect.Contains(pix_x, pix_y)) {
1360 printf(
"Adjusting COVR region on: %s\n", name.ToUTF8().data());
1366 float *points =
new float[2 * nPlypoint];
1367 for (
int i = 0; i < nPlypoint; i++)
1368 points[2 * i + 0] = pPlyTable[i].ltp,
1369 points[2 * i + 1] = pPlyTable[i].lnp;
1370 LLRegion covrRegion(nPlypoint, points);
1372 covrRegion.Intersect(GetValidRegion());
1374 if (covrRegion.contours.size()) {
1376 m_nCOVREntries = covrRegion.contours.size();
1377 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
1378 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
1379 std::list<poly_contour>::iterator it = covrRegion.contours.begin();
1380 for (
int i = 0; i < m_nCOVREntries; i++) {
1381 m_pCOVRTablePoints[i] = it->size();
1383 (
float *)malloc(m_pCOVRTablePoints[i] * 2 *
sizeof(
float));
1384 std::list<contour_pt>::iterator jt = it->begin();
1385 for (
int j = 0; j < m_pCOVRTablePoints[i]; j++) {
1386 m_pCOVRTable[i][2 * j + 0] = jt->y;
1387 m_pCOVRTable[i][2 * j + 1] = jt->x;
1399 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
1400 *m_pCOVRTablePoints = nPlypoint;
1401 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
1402 *m_pCOVRTable = (
float *)malloc(nPlypoint * 2 *
sizeof(
float));
1403 memcpy(*m_pCOVRTable, pPlyTable, nPlypoint * 2 *
sizeof(
float));
1410 strncpy(d_str, m_datum_str.mb_str(), 99);
1413 int datum_index = GetDatumIndex(d_str);
1414 m_datum_index = datum_index;
1416 if (datum_index < 0)
1417 m_ExtraInfo = _T(
"---<<< Warning: Chart Datum may be incorrect. >>>---");
1420 m_lon_datum_adjust = (-m_dtm_lon) / 3600.;
1421 m_lat_datum_adjust = (-m_dtm_lat) / 3600.;
1425 int cnPlypoint = GetCOVRTablenPoints(0);
1427 for (
int u = 0; u < cnPlypoint; u++) {
1431 if (m_datum_index == DATUM_INDEX_WGS84 ||
1432 m_datum_index == DATUM_INDEX_UNKNOWN) {
1433 dlon = m_dtm_lon / 3600.;
1434 dlat = m_dtm_lat / 3600.;
1438 double to_lat, to_lon;
1439 MolodenskyTransform(ppp->ltp, ppp->lnp, &to_lat, &to_lon, m_datum_index,
1441 dlon = (to_lon - ppp->lnp);
1442 dlat = (to_lat - ppp->ltp);
1443 if (m_b_apply_dtm) {
1444 dlon += m_dtm_lon / 3600.;
1445 dlat += m_dtm_lat / 3600.;
1454 if (!SetMinMax())
return INIT_FAIL_REMOVE;
1458 if (init_flags == HEADER_ONLY)
return INIT_OK;
1462 bool bcorrupt =
false;
1464 if ((c = ifs_hdr->GetC()) != 0x1a) {
1467 if ((c = ifs_hdr->GetC()) == 0x0d) {
1468 if ((c = ifs_hdr->GetC()) != 0x0a) {
1471 if ((c = ifs_hdr->GetC()) != 0x1a) {
1474 if ((c = ifs_hdr->GetC()) != 0x00) {
1479 else if (c != 0x00) {
1484 wxString msg(_T(
" Chart File RLL data corrupt on chart "));
1485 msg.Append(m_FullPath);
1488 return INIT_FAIL_REMOVE;
1492 nColorSize = ifs_hdr->GetC();
1493 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
1494 wxString msg(_T(
" Invalid nColorSize data, corrupt on chart "));
1495 msg.Append(m_FullPath);
1497 return INIT_FAIL_REMOVE;
1500 nFileOffsetDataStart = ifs_hdr->TellI();
1504 ChartDataInputStream *stream =
1505 new ChartDataInputStream(name);
1508 tempfile = stream->TempFileName();
1510 m_filesize = wxFileName::GetSize(tempfile.empty() ? name : tempfile);
1512 ifss_bitmap = stream;
1513 ifs_bitmap =
new wxBufferedInputStream(*ifss_bitmap);
1516 InitReturn pi_ret = PostInit();
1517 if (pi_ret != INIT_OK)
return pi_ret;
1525ChartBaseBSB::ChartBaseBSB() {
1527 m_ChartFamily = CHART_FAMILY_RASTER;
1529 pBitmapFilePath = NULL;
1534 cached_image_ok = 0;
1539 bHaveEmbeddedGeoref =
false;
1545#ifdef __OCPN__ANDROID__
1546 bUseLineCache =
false;
1548 bUseLineCache =
true;
1557 m_bilinear_limit = 8;
1563 for (
int i = 0; i < N_BSB_COLORS; i++) pPalettes[i] = NULL;
1565 bGeoErrorSent =
false;
1569 m_mapped_color_index = COLOR_RGB_DEFAULT;
1571 m_datum_str = _T(
"WGS84");
1580 m_proj_parameter = 0.;
1582 m_b_apply_dtm =
true;
1586#ifdef OCPN_USE_CONFIG
1587 wxFileConfig *pfc = (wxFileConfig *)pConfig;
1588 pfc->SetPath(_T (
"/Settings" ));
1589 pfc->Read(_T (
"DebugBSBImg" ), &m_b_cdebug, 0);
1593ChartBaseBSB::~ChartBaseBSB() {
1594 if (pBitmapFilePath)
delete pBitmapFilePath;
1596 if (pline_table) free(pline_table);
1598 if (ifs_buf) free(ifs_buf);
1607 if (cPoints.status) {
1620 FreeLineCacheRows();
1625 for (
int i = 0; i < N_BSB_COLORS; i++)
delete pPalettes[i];
1628void ChartBaseBSB::FreeLineCacheRows(
int start,
int end) {
1633 end = wxMin(end, Size_Y);
1634 for (
int ylc = start; ylc < end; ylc++) {
1637 free(pt->pTileOffset);
1645bool ChartBaseBSB::HaveLineCacheRow(
int row) {
1656double ChartBaseBSB::GetNormalScaleMin(
double canvas_scale_factor,
1657 bool b_allow_overzoom) {
1659 return (canvas_scale_factor / m_ppm_avg) /
1666double ChartBaseBSB::GetNormalScaleMax(
double canvas_scale_factor,
1668 return (canvas_scale_factor / m_ppm_avg) *
1674 target_scale_ppm, .01, 64.);
1679 double scale_factor_min,
1680 double scale_factor_max) {
1681 double chart_1x_scale = GetPPM();
1683 double binary_scale_factor = 1.;
1686 if (chart_1x_scale > target_scale) {
1687 double binary_scale_factor_max = 1 / scale_factor_min;
1689 while (binary_scale_factor < binary_scale_factor_max) {
1690 if (fabs((chart_1x_scale / binary_scale_factor) - target_scale) <
1691 (target_scale * 0.05))
1693 if ((chart_1x_scale / binary_scale_factor) < target_scale)
1696 binary_scale_factor *= 2.;
1703 int isf_max = (int)scale_factor_max;
1704 while (ibsf < isf_max) {
1705 if (fabs((chart_1x_scale * ibsf) - target_scale) < (target_scale * 0.05))
1708 else if ((chart_1x_scale * ibsf) > target_scale) {
1709 if (ibsf > 1) ibsf /= 2;
1715 binary_scale_factor = 1. / ibsf;
1718 return chart_1x_scale / binary_scale_factor;
1721InitReturn ChartBaseBSB::Init(
const wxString &name, ChartInitFlag init_flags) {
1722 m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB;
1726InitReturn ChartBaseBSB::PreInit(
const wxString &name, ChartInitFlag init_flags,
1728 m_global_color_scheme = cs;
1732void ChartBaseBSB::CreatePaletteEntry(
char *buffer,
int palette_index) {
1733 if (palette_index < N_BSB_COLORS) {
1734 if (!pPalettes[palette_index]) pPalettes[palette_index] =
new opncpnPalette;
1738 (
int *)realloc(pp->FwdPalette, (pp->nFwd + 1) *
sizeof(int));
1740 (
int *)realloc(pp->RevPalette, (pp->nRev + 1) *
sizeof(int));
1746 sscanf(&buffer[4],
"%d,%d,%d,%d", &n, &r, &g, &b);
1751 fcolor = (b << 16) + (g << 8) + r;
1752 rcolor = (r << 16) + (g << 8) + b;
1754 pp->RevPalette[i] = rcolor;
1755 pp->FwdPalette[i] = fcolor;
1759InitReturn ChartBaseBSB::PostInit(
void) {
1761 if (nColorSize == wxEOF || nColorSize <= 0 || nColorSize > 7) {
1763 _T(
" Invalid nColorSize data, corrupt in PostInit() on chart "));
1764 msg.Append(m_FullPath);
1766 return INIT_FAIL_REMOVE;
1769 if (Size_X <= 0 || Size_X > INT_MAX / 4 || Size_Y <= 0 ||
1770 Size_Y - 1 > INT_MAX / 4) {
1772 _T(
" Invalid Size_X/Size_Y data, corrupt in PostInit() on chart "));
1773 msg.Append(m_FullPath);
1775 return INIT_FAIL_REMOVE;
1781 if (pPalettes[COLOR_RGB_DEFAULT]) {
1782 nrev_def = pPalettes[COLOR_RGB_DEFAULT]->nRev;
1783 nfwd_def = pPalettes[COLOR_RGB_DEFAULT]->nFwd;
1786 for (
int i = 0; i < N_BSB_COLORS; i++) {
1787 if (pPalettes[i] == NULL) {
1790 pNullSubPal->nFwd = nfwd_def;
1791 pNullSubPal->nRev = nrev_def;
1793 free(pNullSubPal->FwdPalette);
1794 pNullSubPal->FwdPalette = (
int *)malloc(pNullSubPal->nFwd *
sizeof(
int));
1795 if (pPalettes[COLOR_RGB_DEFAULT])
1796 memcpy(pNullSubPal->FwdPalette,
1797 pPalettes[COLOR_RGB_DEFAULT]->FwdPalette,
1798 pNullSubPal->nFwd *
sizeof(
int));
1800 free(pNullSubPal->RevPalette);
1801 pNullSubPal->RevPalette = (
int *)malloc(pNullSubPal->nRev *
sizeof(
int));
1802 if (pPalettes[COLOR_RGB_DEFAULT])
1803 memcpy(pNullSubPal->RevPalette,
1804 pPalettes[COLOR_RGB_DEFAULT]->RevPalette,
1805 pNullSubPal->nRev *
sizeof(
int));
1807 pPalettes[i] = pNullSubPal;
1812 palette_direction = GetPaletteDir();
1814 SetColorScheme(m_global_color_scheme,
false);
1817 ifs_bufsize = Size_X * 4;
1818 ifs_buf = (
unsigned char *)malloc(ifs_bufsize);
1819 if (!ifs_buf)
return INIT_FAIL_REMOVE;
1821 ifs_bufend = ifs_buf + ifs_bufsize;
1822 ifs_lp = ifs_bufend;
1823 ifs_file_offset = -ifs_bufsize;
1827 pline_table = (
int *)malloc((Size_Y + 1) *
sizeof(int));
1828 if (!pline_table)
return INIT_FAIL_REMOVE;
1830 ifs_bitmap->SeekI((Size_Y + 1) * -4,
1832 pline_table[Size_Y] = ifs_bitmap->TellI();
1834 unsigned char *tmp = (
unsigned char *)malloc(Size_Y *
sizeof(
int));
1835 ifs_bitmap->Read(tmp, Size_Y *
sizeof(
int));
1836 if (ifs_bitmap->LastRead() != Size_Y *
sizeof(int)) {
1837 wxString msg(_T(
" Chart File corrupt in PostInit() on chart "));
1838 msg.Append(m_FullPath);
1842 return INIT_FAIL_REMOVE;
1846 unsigned char *b = tmp;
1847 for (
int ifplt = 0; ifplt < Size_Y; ifplt++) {
1849 offset += *b++ * 256 * 256 * 256;
1850 offset += *b++ * 256 * 256;
1851 offset += *b++ * 256;
1854 pline_table[ifplt] = offset;
1859 bool bline_index_ok =
true;
1862 wxULongLong bitmap_filesize = m_filesize;
1863 if ((m_ChartType == CHART_TYPE_GEO) && pBitmapFilePath)
1864 bitmap_filesize = wxFileName::GetSize(*pBitmapFilePath);
1867 for (
int iplt = 0; iplt < Size_Y - 1; iplt++) {
1868 if (pline_table[iplt] > bitmap_filesize) {
1869 wxString msg(_T(
" Chart File corrupt in PostInit() on chart "));
1870 msg.Append(m_FullPath);
1873 return INIT_FAIL_REMOVE;
1876 int thisline_size = pline_table[iplt + 1] - pline_table[iplt];
1877 if (thisline_size < 0) {
1878 wxString msg(_T(
" Chart File corrupt in PostInit() on chart "));
1879 msg.Append(m_FullPath);
1882 return INIT_FAIL_REMOVE;
1891 m_bsb_ver.ToDouble(&ver);
1893 for (
int iplt = 0; iplt < 10; iplt++) {
1894 if (wxInvalidOffset ==
1895 ifs_bitmap->SeekI(pline_table[iplt], wxFromStart)) {
1896 wxString msg(_T(
" Chart File corrupt in PostInit() on chart "));
1897 msg.Append(m_FullPath);
1900 return INIT_FAIL_REMOVE;
1903 int thisline_size = pline_table[iplt + 1] - pline_table[iplt];
1904 ifs_bitmap->Read(ifs_buf, thisline_size);
1906 unsigned char *lp = ifs_buf;
1908 unsigned char byNext;
1909 int nLineMarker = 0;
1912 nLineMarker = nLineMarker * 128 + (byNext & 0x7f);
1913 }
while ((byNext & 0x80) != 0);
1920 if (iplt == 0) m_nLineOffset = nLineMarker;
1922 if (nLineMarker != iplt + m_nLineOffset) {
1923 bline_index_ok =
false;
1930 if (!bline_index_ok) {
1931 wxString msg(_T(
" Line Index corrupt, recreating Index for chart "));
1932 msg.Append(m_FullPath);
1934 if (!CreateLineIndex()) {
1935 wxString msg(_T(
" Error creating Line Index for chart "));
1936 msg.Append(m_FullPath);
1938 return INIT_FAIL_REMOVE;
1943 if (bUseLineCache) {
1947 for (
int ylc = 0; ylc < Size_Y; ylc++) {
1948 pt = &pLineCache[ylc];
1951 pt->pTileOffset = NULL;
1957 wxString test_str = m_DepthUnits.Upper();
1958 if (test_str.IsSameAs(_T(
"FEET"), FALSE))
1959 m_depth_unit_id = DEPTH_UNIT_FEET;
1960 else if (test_str.IsSameAs(_T(
"METERS"), FALSE))
1961 m_depth_unit_id = DEPTH_UNIT_METERS;
1962 else if (test_str.IsSameAs(_T(
"METRES"),
1964 m_depth_unit_id = DEPTH_UNIT_METERS;
1965 else if (test_str.IsSameAs(_T(
"METRIC"), FALSE))
1966 m_depth_unit_id = DEPTH_UNIT_METERS;
1967 else if (test_str.IsSameAs(_T(
"FATHOMS"), FALSE))
1968 m_depth_unit_id = DEPTH_UNIT_FATHOMS;
1969 else if (test_str.Find(_T(
"FATHOMS")) !=
1971 m_depth_unit_id = DEPTH_UNIT_FATHOMS;
1972 else if (test_str.Find(_T(
"METERS")) !=
1974 m_depth_unit_id = DEPTH_UNIT_METERS;
1977 int analyze_ret_val = AnalyzeRefpoints();
1978 if (0 != analyze_ret_val)
return INIT_FAIL_REMOVE;
1980 bReadyToRender =
true;
1984bool ChartBaseBSB::CreateLineIndex() {
1990 ifs_bitmap->SeekI(nFileOffsetDataStart);
1992 for (
int iplt = 0; iplt < Size_Y; iplt++) {
1993 int offset = ifs_bitmap->TellI();
1995 int iscan = BSBScanScanline(ifs_bitmap);
2019 pline_table[iplt] = offset;
2026void ChartBaseBSB::InvalidateLineCache(
void) {
2029 for (
int ylc = 0; ylc < Size_Y; ylc++) {
2030 pt = &pLineCache[ylc];
2034 free(pt->pTileOffset);
2035 pt->pTileOffset = NULL;
2042bool ChartBaseBSB::GetChartExtent(
Extent *pext) {
2043 pext->NLAT = m_LatMax;
2044 pext->SLAT = m_LatMin;
2045 pext->ELON = m_LonMax;
2046 pext->WLON = m_LonMin;
2051bool ChartBaseBSB::SetMinMax(
void) {
2060 int cnPlypoint = GetCOVRTablenPoints(0);
2062 for (
int u = 0; u < cnPlypoint; u++) {
2063 if (ppp->lnp > m_LonMax) m_LonMax = ppp->lnp;
2064 if (ppp->lnp < m_LonMin) m_LonMin = ppp->lnp;
2066 if (ppp->ltp > m_LatMax) m_LatMax = ppp->ltp;
2067 if (ppp->ltp < m_LatMin) m_LatMin = ppp->ltp;
2076 if ((m_LonMax * m_LonMin) < 0)
2081 if (0 == nRefpoint)
return false;
2084 double min_dist_x = 360;
2086 for (
int ic = 0; ic < nRefpoint; ic++) {
2088 ((m_LatMax - pRefTable[ic].latr) * (m_LatMax - pRefTable[ic].latr)) +
2089 ((m_LonMax - pRefTable[ic].lonr) * (m_LonMax - pRefTable[ic].lonr)));
2091 if (dist < min_dist_x) {
2098 double min_dist_n = 360;
2100 for (
int id = 0;
id < nRefpoint;
id++) {
2102 ((m_LatMin - pRefTable[
id].latr) * (m_LatMin - pRefTable[
id].latr)) +
2103 ((m_LonMin - pRefTable[
id].lonr) * (m_LonMin - pRefTable[
id].lonr)));
2105 if (dist < min_dist_n) {
2113 if (pRefTable[imaxclose].xr < pRefTable[iminclose].xr) {
2126 int cnPlypoint = GetCOVRTablenPoints(0);
2128 for (
int u = 0; u < cnPlypoint; u++) {
2129 if (ppp->lnp < 0.) ppp->lnp += 360.;
2131 if (ppp->lnp > m_LonMax) m_LonMax = ppp->lnp;
2132 if (ppp->lnp < m_LonMin) m_LonMin = ppp->lnp;
2134 if (ppp->ltp > m_LatMax) m_LatMax = ppp->ltp;
2135 if (ppp->ltp < m_LatMin) m_LatMin = ppp->ltp;
2146 if ((m_LonMax < -180.) && (m_LonMin < -180.)) {
2151 int cnPlypoint = GetCOVRTablenPoints(0);
2153 for (
int u = 0; u < cnPlypoint; u++) {
2162void ChartBaseBSB::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
2167 case GLOBAL_COLOR_SCHEME_RGB:
2168 m_mapped_color_index = COLOR_RGB_DEFAULT;
2170 case GLOBAL_COLOR_SCHEME_DAY:
2171 m_mapped_color_index = DAY;
2173 case GLOBAL_COLOR_SCHEME_DUSK:
2174 m_mapped_color_index = DUSK;
2176 case GLOBAL_COLOR_SCHEME_NIGHT:
2177 m_mapped_color_index = NIGHT;
2180 m_mapped_color_index = DAY;
2184 pPalette = GetPalettePtr(m_mapped_color_index);
2186 m_global_color_scheme = cs;
2189 if (bApplyImmediate) {
2190 m_cached_scale_ppm = 1.0;
2194 if (pThumbData) pThumbData->pDIBThumb = NULL;
2197wxBitmap *ChartBaseBSB::CreateThumbnail(
int tnx,
int tny, ColorScheme cs) {
2200 int divx = wxMax(1, Size_X / (4 * tnx));
2201 int divy = wxMax(1, Size_Y / (4 * tny));
2203 int div_factor = std::min(divx, divy);
2205 int des_width = Size_X / div_factor;
2206 int des_height = Size_Y / div_factor;
2212 gts.height = Size_Y;
2216 unsigned char *pLineT = (
unsigned char *)malloc((Size_X + 1) * BPP / 8);
2219 unsigned char *pPixTN =
2220 (
unsigned char *)malloc(des_width * des_height * this_bpp / 8);
2231 ColorScheme cs_tmp = m_global_color_scheme;
2232 SetColorScheme(cs,
false);
2234 while (iyd < des_height) {
2235 if (0 == BSBGetScanline(pLineT, iy, 0, Size_X, 1))
2242 yoffd = iyd * des_width * this_bpp / 8;
2246 while (ixd < des_width) {
2247 pxs = pLineT + (ix * BPP / 8);
2248 pxd = pPixTN + (yoffd + (ixd * this_bpp / 8));
2264 SetColorScheme(cs_tmp,
false);
2268#ifdef ocpnUSE_ocpnBitmap
2269 wxBitmap *bmx2 =
new ocpnBitmap(pPixTN, des_width, des_height, -1);
2270 wxImage imgx2 = bmx2->ConvertToImage();
2271 imgx2.Rescale(des_width / 4, des_height / 4, wxIMAGE_QUALITY_HIGH);
2272 retBMP =
new wxBitmap(imgx2);
2275 wxImage thumb_image(des_width, des_height, pPixTN,
true);
2276 thumb_image.Rescale(des_width / 4, des_height / 4, wxIMAGE_QUALITY_HIGH);
2277 retBMP =
new wxBitmap(thumb_image);
2290ThumbData *ChartBaseBSB::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
2292 if (!pThumbData->pDIBThumb)
2293 pThumbData->pDIBThumb = CreateThumbnail(tnx, tny, m_global_color_scheme);
2295 pThumbData->Thumb_Size_X = tnx;
2296 pThumbData->Thumb_Size_Y = tny;
2299 int divx = Size_X / tnx;
2300 int divy = Size_Y / tny;
2302 int div_factor = std::min(divx, divy);
2315 latlong_to_pix_vp(lat, lon, pixx, pixy, tvp);
2318 pThumbData->ShipX = pixx;
2319 pThumbData->ShipY = pixy;
2324bool ChartBaseBSB::UpdateThumbData(
double lat,
double lon) {
2328 int divx = Size_X / pThumbData->Thumb_Size_X;
2329 int divy = Size_Y / pThumbData->Thumb_Size_Y;
2331 int div_factor = std::min(divx, divy);
2333 double pixx_test, pixy_test;
2338 tvp.
pix_width = pThumbData->Thumb_Size_X;
2344 latlong_to_pix_vp(lat, lon, pixx_test, pixy_test, tvp);
2347 if ((pixx_test != pThumbData->ShipX) || (pixy_test != pThumbData->ShipY)) {
2348 pThumbData->ShipX = pixx_test;
2349 pThumbData->ShipY = pixy_test;
2358static double polytrans(
double *coeff,
double lon,
double lat);
2360int ChartBaseBSB::vp_pix_to_latlong(
ViewPort &vp,
double pixx,
double pixy,
2361 double *plat,
double *plon) {
2362 if (bHaveEmbeddedGeoref) {
2365 double px = pixx * raster_scale + Rsrc.x;
2366 double py = pixy * raster_scale + Rsrc.y;
2370 double lon = polytrans(pwx, px, py);
2371 lon = (lon < 0) ? lon + m_cph : lon - m_cph;
2372 *plon = lon - m_lon_datum_adjust;
2373 *plat = polytrans(pwy, px, py) - m_lat_datum_adjust;
2381 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2387 double easting, northing;
2388 toTM(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2389 m_proj_lat, m_proj_lon, &easting, &northing);
2390 double xc = polytrans(cPoints.wpx, easting, northing);
2391 double yc = polytrans(cPoints.wpy, easting, northing);
2394 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2395 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2398 double east = polytrans(cPoints.pwx, px, py);
2399 double north = polytrans(cPoints.pwy, px, py);
2403 fromTM(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2407 double slon_p = lon - m_lon_datum_adjust;
2408 double slat_p = lat - m_lat_datum_adjust;
2415 }
else if (m_projection == PROJECTION_MERCATOR) {
2421 double easting, northing;
2422 toSM_ECC(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2423 m_proj_lat, m_proj_lon, &easting, &northing);
2424 double xc = polytrans(cPoints.wpx, easting, northing);
2425 double yc = polytrans(cPoints.wpy, easting, northing);
2428 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2429 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2432 double east = polytrans(cPoints.pwx, px, py);
2433 double north = polytrans(cPoints.pwy, px, py);
2437 fromSM_ECC(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2440 double slon_p = lon - m_lon_datum_adjust;
2441 double slat_p = lat - m_lat_datum_adjust;
2449 }
else if (m_projection == PROJECTION_POLYCONIC) {
2455 double easting, northing;
2456 toPOLY(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2457 m_proj_lat, m_proj_lon, &easting, &northing);
2458 double xc = polytrans(cPoints.wpx, easting, northing);
2459 double yc = polytrans(cPoints.wpy, easting, northing);
2462 double px = xc + (pixx - (vp.
pix_width / 2)) * raster_scale;
2463 double py = yc + (pixy - (vp.
pix_height / 2)) * raster_scale;
2466 double east = polytrans(cPoints.pwx, px, py);
2467 double north = polytrans(cPoints.pwy, px, py);
2471 fromPOLY(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2474 double slon_p = lon - m_lon_datum_adjust;
2475 double slat_p = lat - m_lat_datum_adjust;
2485 xp = (dx * cos(vp.
skew)) - (dy * sin(vp.
skew));
2486 yp = (dy * cos(vp.
skew)) + (dx * sin(vp.
skew));
2491 fromSM_ECC(d_east, d_north, vp.
clat, vp.
clon, &slat, &slon);
2498 else if (slon > 180.)
2506int ChartBaseBSB::latlong_to_pix_vp(
double lat,
double lon,
double &pixx,
2510 if (bHaveEmbeddedGeoref) {
2513 alon = lon + m_lon_datum_adjust;
2514 alat = lat + m_lat_datum_adjust;
2516 AdjustLongitude(alon);
2520 double lonp = (alon < 0) ? alon + m_cph : alon - m_cph;
2521 double xd = polytrans(wpx, lonp, alat);
2522 double yd = polytrans(wpy, lonp, alat);
2526 pixx = (xd - Rsrc.x) / raster_scale;
2527 pixy = (yd - Rsrc.y) / raster_scale;
2532 double easting, northing;
2554 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2557 alon = lon + m_lon_datum_adjust;
2558 alat = lat + m_lat_datum_adjust;
2561 toTM(alat, alon, m_proj_lat, m_proj_lon, &easting, &northing);
2564 double xd = polytrans(cPoints.wpx, easting, northing);
2565 double yd = polytrans(cPoints.wpy, easting, northing);
2568 toTM(vp.
clat + m_lat_datum_adjust, vp.
clon + m_lon_datum_adjust,
2569 m_proj_lat, m_proj_lon, &easting, &northing);
2570 double xc = polytrans(cPoints.wpx, easting, northing);
2571 double yc = polytrans(cPoints.wpy, easting, northing);
2576 double xs = xc - vp.
pix_width * raster_scale / 2;
2577 double ys = yc - vp.
pix_height * raster_scale / 2;
2579 pixx = (xd - xs) / raster_scale;
2580 pixy = (yd - ys) / raster_scale;
2582 }
else if (m_projection == PROJECTION_MERCATOR) {
2585 alon = lon + m_lon_datum_adjust;
2586 alat = lat + m_lat_datum_adjust;
2590 AdjustLongitude(xlon);
2591 toSM_ECC(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2594 double xd = polytrans(cPoints.wpx, easting, northing);
2595 double yd = polytrans(cPoints.wpy, easting, northing);
2598 double xlonc = vp.
clon;
2599 AdjustLongitude(xlonc);
2601 toSM_ECC(vp.
clat + m_lat_datum_adjust, xlonc + m_lon_datum_adjust,
2602 m_proj_lat, m_proj_lon, &easting, &northing);
2603 double xc = polytrans(cPoints.wpx, easting, northing);
2604 double yc = polytrans(cPoints.wpy, easting, northing);
2609 double xs = xc - vp.
pix_width * raster_scale / 2;
2610 double ys = yc - vp.
pix_height * raster_scale / 2;
2612 pixx = (xd - xs) / raster_scale;
2613 pixy = (yd - ys) / raster_scale;
2615 }
else if (m_projection == PROJECTION_POLYCONIC) {
2618 alon = lon + m_lon_datum_adjust;
2619 alat = lat + m_lat_datum_adjust;
2622 xlon = AdjustLongitude(alon);
2623 toPOLY(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2626 double xd = polytrans(cPoints.wpx, easting, northing);
2627 double yd = polytrans(cPoints.wpy, easting, northing);
2630 double xlonc = AdjustLongitude(vp.
clon);
2632 toPOLY(vp.
clat + m_lat_datum_adjust, xlonc + m_lon_datum_adjust,
2633 m_proj_lat, m_proj_lon, &easting, &northing);
2634 double xc = polytrans(cPoints.wpx, easting, northing);
2635 double yc = polytrans(cPoints.wpy, easting, northing);
2640 double xs = xc - vp.
pix_width * raster_scale / 2;
2641 double ys = yc - vp.
pix_height * raster_scale / 2;
2643 pixx = (xd - xs) / raster_scale;
2644 pixy = (yd - ys) / raster_scale;
2647 toSM_ECC(lat, xlon, vp.
clat, vp.
clon, &easting, &northing);
2652 double dx = epix * cos(vp.
skew) + npix * sin(vp.
skew);
2653 double dy = npix * cos(vp.
skew) - epix * sin(vp.
skew);
2664void ChartBaseBSB::latlong_to_chartpix(
double lat,
double lon,
double &pixx,
2670 if (bHaveEmbeddedGeoref) {
2673 alon = lon + m_lon_datum_adjust;
2674 alat = lat + m_lat_datum_adjust;
2676 alon = AdjustLongitude(alon);
2679 double lonp = (alon < 0) ? alon + m_cph : alon - m_cph;
2680 pixx = polytrans(wpx, lonp, alat);
2681 pixy = polytrans(wpy, lonp, alat);
2683 double easting, northing;
2686 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2689 alon = lon + m_lon_datum_adjust;
2690 alat = lat + m_lat_datum_adjust;
2693 toTM(alat, alon, m_proj_lat, m_proj_lon, &easting, &northing);
2696 pixx = polytrans(cPoints.wpx, easting, northing);
2697 pixy = polytrans(cPoints.wpy, easting, northing);
2699 }
else if (m_projection == PROJECTION_MERCATOR) {
2702 alon = lon + m_lon_datum_adjust;
2703 alat = lat + m_lat_datum_adjust;
2706 xlon = AdjustLongitude(alon);
2708 toSM_ECC(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2711 pixx = polytrans(cPoints.wpx, easting, northing);
2712 pixy = polytrans(cPoints.wpy, easting, northing);
2714 }
else if (m_projection == PROJECTION_POLYCONIC) {
2717 alon = lon + m_lon_datum_adjust;
2718 alat = lat + m_lat_datum_adjust;
2721 xlon = AdjustLongitude(alon);
2722 toPOLY(alat, xlon, m_proj_lat, m_proj_lon, &easting, &northing);
2725 pixx = polytrans(cPoints.wpx, easting, northing);
2726 pixy = polytrans(cPoints.wpy, easting, northing);
2731void ChartBaseBSB::chartpix_to_latlong(
double pixx,
double pixy,
double *plat,
2733 if (bHaveEmbeddedGeoref) {
2734 double lon = polytrans(pwx, pixx, pixy);
2735 lon = (lon < 0) ? lon + m_cph : lon - m_cph;
2736 *plon = lon - m_lon_datum_adjust;
2737 *plat = polytrans(pwy, pixx, pixy) - m_lat_datum_adjust;
2740 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
2744 double east = polytrans(cPoints.pwx, pixx, pixy);
2745 double north = polytrans(cPoints.pwy, pixx, pixy);
2749 fromTM(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2753 slon = lon - m_lon_datum_adjust;
2754 slat = lat - m_lat_datum_adjust;
2756 }
else if (m_projection == PROJECTION_MERCATOR) {
2759 double east = polytrans(cPoints.pwx, pixx, pixy);
2760 double north = polytrans(cPoints.pwy, pixx, pixy);
2764 fromSM_ECC(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2767 slon = lon - m_lon_datum_adjust;
2768 slat = lat - m_lat_datum_adjust;
2769 }
else if (m_projection == PROJECTION_POLYCONIC) {
2772 double east = polytrans(cPoints.pwx, pixx, pixy);
2773 double north = polytrans(cPoints.pwy, pixx, pixy);
2777 fromPOLY(east, north, m_proj_lat, m_proj_lon, &lat, &lon);
2780 slon = lon - m_lon_datum_adjust;
2781 slat = lat - m_lat_datum_adjust;
2792 else if (slon > 180.)
2798void ChartBaseBSB::ComputeSourceRectangle(
const ViewPort &vp,
2799 wxRect *pSourceRect) {
2800 m_raster_scale_factor = GetRasterScaleFactor(vp);
2802 latlong_to_chartpix(vp.
clat, vp.
clon, xd, yd);
2804 wxRealPoint pos, size;
2806 pos.x = xd - (vp.
pix_width * m_raster_scale_factor / 2);
2807 pos.y = yd - (vp.
pix_height * m_raster_scale_factor / 2);
2809 size.x = vp.
pix_width * m_raster_scale_factor;
2810 size.y = vp.
pix_height * m_raster_scale_factor;
2813 wxRect(wxRound(pos.x), wxRound(pos.y), wxRound(size.x), wxRound(size.y));
2816double ChartBaseBSB::GetRasterScaleFactor(
const ViewPort &vp) {
2819 return (wxRound(100000 * GetPPM() / vp.
view_scale_ppm)) / 100000.;
2822void ChartBaseBSB::SetVPRasterParms(
const ViewPort &vpt) {
2826 if (m_datum_index == DATUM_INDEX_WGS84 ||
2827 m_datum_index == DATUM_INDEX_UNKNOWN) {
2828 m_lon_datum_adjust = (-m_dtm_lon) / 3600.;
2829 m_lat_datum_adjust = (-m_dtm_lat) / 3600.;
2833 double to_lat, to_lon;
2834 MolodenskyTransform(vpt.
clat, vpt.
clon, &to_lat, &to_lon, m_datum_index,
2836 m_lon_datum_adjust = -(to_lon - vpt.
clon);
2837 m_lat_datum_adjust = -(to_lat - vpt.
clat);
2838 if (m_b_apply_dtm) {
2839 m_lon_datum_adjust -= m_dtm_lon / 3600.;
2840 m_lat_datum_adjust -= m_dtm_lat / 3600.;
2844 ComputeSourceRectangle(vpt, &Rsrc);
2846 if (vpt.IsValid()) m_vp_render_last = vpt;
2850 bool bInside = G_FloatPtInPolygon((
MyFlPoint *)GetCOVRTableHead(0),
2851 GetCOVRTablenPoints(0), vp_proposed.
clon,
2853 if (!bInside)
return false;
2856 double binary_scale_factor = GetPPM() / vp_proposed.
view_scale_ppm;
2858 if (vp_last.IsValid()) {
2864 if (cached_image_ok && (binary_scale_factor > 1.0) &&
2865 (fabs(binary_scale_factor - wxRound(binary_scale_factor)) < 1e-5)) {
2867 printf(
" Possible Adjust VP for integer scale: %g\n",
2868 binary_scale_factor);
2871 ComputeSourceRectangle(vp_proposed, &rprop);
2874 double lon_adj, lat_adj;
2875 latlong_to_pix_vp(vp_proposed.
clat, vp_proposed.
clon, pixx, pixy,
2877 vp_pix_to_latlong(vp_proposed, pixx, pixy, &lat_adj, &lon_adj);
2879 vp_proposed.
clat = lat_adj;
2880 vp_proposed.
clon = lon_adj;
2885 return (ret_val > 0);
2888bool ChartBaseBSB::IsRenderCacheable(wxRect &source, wxRect &dest) {
2889 double scale_x = (double)source.width / (
double)dest.width;
2898 if ((fabs(scale_x - wxRound(scale_x))) > .0001) {
2905 if ((
int)(source.width / dest.width) != (
int)wxRound(scale_x)) {
2914void ChartBaseBSB::GetValidCanvasRegion(
const ViewPort &VPoint,
2916 SetVPRasterParms(VPoint);
2923 rxl = wxMax(-Rsrc.x * raster_scale, VPoint.rv_rect.x);
2924 rxr = wxMin((Size_X - Rsrc.x) * raster_scale,
2925 VPoint.rv_rect.width + VPoint.rv_rect.x);
2927 ryt = wxMax(-Rsrc.y * raster_scale, VPoint.rv_rect.y);
2928 ryb = wxMin((Size_Y - Rsrc.y) * raster_scale,
2929 VPoint.rv_rect.height + VPoint.rv_rect.y);
2931 pValidRegion->Clear();
2932 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
2935LLRegion ChartBaseBSB::GetValidRegion() {
2938 chartpix_to_latlong(0, 0, ll + 0, ll + 1);
2939 chartpix_to_latlong(0, Size_Y, ll + 2, ll + 3);
2940 chartpix_to_latlong(Size_X, Size_Y, ll + 4, ll + 5);
2941 chartpix_to_latlong(Size_X, 0, ll + 6, ll + 7);
2945 for (
int i = 1; i < 6; i += 2)
2946 if (fabs(ll[i] - ll[i + 2]) > 180) {
2948 for (
int i = 1; i < 8; i += 2)
2949 if (ll[i] < 0) ll[i] += 360;
2953 return LLRegion(4, ll);
2956bool ChartBaseBSB::GetViewUsingCache(wxRect &source, wxRect &dest,
2958 ScaleTypeEnum scale_type) {
2960 ScaleTypeEnum scale_type_corrected;
2962 if (m_b_cdebug) printf(
" source: %d %d\n", source.x, source.y);
2963 if (m_b_cdebug) printf(
" cache: %d %d\n", cache_rect.x, cache_rect.y);
2966 if ((source == cache_rect) &&
2967 (cached_image_ok)) {
2968 if (m_b_cdebug) printf(
" GVUC: Cache is good, nothing to do\n");
2972 double scale_x = (double)source.width / (
double)dest.width;
2974 if (m_b_cdebug) printf(
"GVUC: scale_x: %g\n", scale_x);
2977 scale_type_corrected = scale_type;
2978 if (scale_x > m_bilinear_limit) scale_type_corrected = RENDER_LODEF;
2986 if ((fabs(scale_x - wxRound(scale_x))) > .0001) {
2987 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Not digital scale test 1\n");
2988 return GetView(source, dest, scale_type_corrected);
2993 if (!cached_image_ok) {
2994 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Cache NOk\n");
2995 return GetView(source, dest, scale_type_corrected);
3000 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Overzoom\n");
3001 return GetView(source, dest, scale_type_corrected);
3005 if ((
int)(source.width / dest.width) != (
int)wxRound(scale_x)) {
3006 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: Not digital scale test 2\n");
3007 return GetView(source, dest, scale_type_corrected);
3011 int cs1d = source.width / dest.width;
3012 if (abs(source.x - cache_rect.x) % cs1d) {
3014 printf(
" source.x: %d cache_rect.x: %d cs1d: %d\n", source.x,
3015 cache_rect.x, cs1d);
3016 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: x mismatch\n");
3017 return GetView(source, dest, scale_type_corrected);
3019 if (abs(source.y - cache_rect.y) % cs1d) {
3020 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: y mismatch\n");
3021 return GetView(source, dest, scale_type_corrected);
3024 if (pPixCache && ((pPixCache->GetWidth() != dest.width) ||
3025 (pPixCache->GetHeight() != dest.height))) {
3026 if (m_b_cdebug) printf(
" MISS<<<>>>GVUC: dest size mismatch\n");
3027 return GetView(source, dest, scale_type_corrected);
3031 (source.y + source.height) - (cache_rect.y + cache_rect.height);
3032 int scaled_stride_rows = (int)(stride_rows / scale_x);
3034 if (abs(stride_rows) >= source.height)
3035 return GetView(source, dest, scale_type_corrected);
3038 (source.x + source.width) - (cache_rect.x + cache_rect.width);
3039 int scaled_stride_pixels = (int)(stride_pixels / scale_x);
3041 if (abs(stride_pixels) >= source.width)
3042 return GetView(source, dest, scale_type_corrected);
3044 if (m_b_cdebug) printf(
" GVUC Using raster data cache\n");
3046 ScaleTypeEnum pan_scale_type_x = scale_type_corrected;
3047 ScaleTypeEnum pan_scale_type_y = scale_type_corrected;
3051 int height = pPixCache->GetHeight();
3052 int width = pPixCache->GetWidth();
3053 int buffer_stride_bytes = pPixCache->GetLinePitch();
3058 if (stride_rows > 0)
3060 ps = pPixCache->GetpData() +
3061 (abs(scaled_stride_rows) * buffer_stride_bytes);
3062 if (stride_pixels > 0) ps += scaled_stride_pixels * BPP / 8;
3064 pd = pPixCache->GetpData();
3065 if (stride_pixels <= 0) pd += abs(scaled_stride_pixels) * BPP / 8;
3067 for (
int iy = 0; iy < (height - abs(scaled_stride_rows)); iy++) {
3068 memmove(pd, ps, (width - abs(scaled_stride_pixels)) * BPP / 8);
3069 ps += buffer_stride_bytes;
3070 pd += buffer_stride_bytes;
3074 ps = pPixCache->GetpData() +
3075 ((height - abs(scaled_stride_rows) - 1) * buffer_stride_bytes);
3076 if (stride_pixels > 0)
3077 ps += scaled_stride_pixels * BPP / 8;
3079 pd = pPixCache->GetpData() + ((height - 1) * buffer_stride_bytes);
3080 if (stride_pixels <= 0)
3081 pd += abs(scaled_stride_pixels) * BPP / 8;
3083 for (
int iy = 0; iy < (height - abs(scaled_stride_rows)); iy++) {
3084 memmove(pd, ps, (width - abs(scaled_stride_pixels)) * BPP / 8);
3085 ps -= buffer_stride_bytes;
3086 pd -= buffer_stride_bytes;
3091 if (source.y != cache_rect.y) {
3092 wxRect sub_dest = dest;
3093 sub_dest.height = abs(scaled_stride_rows);
3095 if (stride_rows > 0)
3097 sub_dest.y = height - scaled_stride_rows;
3108 wxRegionContain rc = Region.Contains(sub_dest);
3109 if ((wxPartRegion == rc) || (wxInRegion == rc)) {
3110 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3111 source.width, sub_dest, width, cs1d, pan_scale_type_y);
3113 pPixCache->Update();
3117 cache_rect.y = source.y;
3119 cache_rect_scaled = dest;
3120 cached_image_ok = 1;
3125 if (source.x != cache_rect.x) {
3126 wxRect sub_dest = dest;
3127 sub_dest.width = abs(scaled_stride_pixels);
3129 if (stride_pixels > 0)
3131 sub_dest.x = width - scaled_stride_pixels;
3142 wxRegionContain rc = Region.Contains(sub_dest);
3143 if ((wxPartRegion == rc) || (wxInRegion == rc)) {
3144 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3145 source.width, sub_dest, width, cs1d, pan_scale_type_x);
3148 pPixCache->Update();
3151 cache_rect = source;
3152 cache_rect_scaled = dest;
3153 cached_image_ok = 1;
3164bool ChartBaseBSB::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
3165 SetVPRasterParms(VPoint);
3169 bool bsame_region = (rgn == m_last_region);
3171 if (!bsame_region) cached_image_ok =
false;
3173 m_last_region = rgn;
3175 return RenderRegionViewOnDC(dc, VPoint, rgn);
3178bool ChartBaseBSB::RenderRegionViewOnGL(
const wxGLContext &glc,
3181 const LLRegion &Region) {
3185bool ChartBaseBSB::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
3187 SetVPRasterParms(VPoint);
3191 double factor = GetRasterScaleFactor(VPoint);
3193 printf(
"%d RenderRegion ScaleType: %d factor: %g\n", s_dc++,
3194 RENDER_HIDEF, factor);
3195 printf(
"Rect list:\n");
3197 while (upd.HaveRects()) {
3198 wxRect rect = upd.GetRect();
3199 printf(
" %d %d %d %d\n", rect.x, rect.y, rect.width, rect.height);
3207 (m_last_vprect != dest)) {
3208 cached_image_ok =
false;
3209 m_vp_render_last.Invalidate();
3226 m_last_vprect = dest;
3228 if (cached_image_ok) {
3230 bool bsame_region = (Region == m_last_region);
3232 if ((bsame_region) && (Rsrc == cache_rect)) {
3233 pPixCache->SelectIntoDC(dc);
3234 if (m_b_cdebug) printf(
" Using Current PixelCache\n");
3239 m_last_region = Region;
3260 while (upd.HaveRects()) {
3265 if ((!IsRenderCacheable(Rsrc, dest) && (n_rect > 4) && (n_rect < 20)) ||
3268 printf(
" RenderRegion by rect iterator n_rect: %d\n", n_rect);
3272 wxRect dest_check_rect = dest;
3274 while (upd_check.HaveRects()) {
3275 wxRect rect = upd_check.GetRect();
3276 dest_check_rect.Union(rect);
3277 upd_check.NextRect();
3281 if ((pPixCache->GetWidth() != dest_check_rect.width) ||
3282 (pPixCache->GetHeight() != dest_check_rect.height)) {
3285 new PixelCache(dest_check_rect.width, dest_check_rect.height, BPP);
3289 new PixelCache(dest_check_rect.width, dest_check_rect.height, BPP);
3291 ScaleTypeEnum ren_type = RENDER_LODEF;
3297 while (upd.HaveRects()) {
3298 wxRect rect = upd.GetRect();
3303 if (rect.y < 0) rect.Offset(0, -rect.y);
3304 if (rect.x < 0) rect.Offset(-rect.x, 0);
3306 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), Rsrc,
3307 Rsrc.width, rect, pPixCache->GetWidth(), factor,
3315 pPixCache->Update();
3319 cache_scale_method = ren_type;
3320 cached_image_ok =
false;
3323 pPixCache->SelectIntoDC(dc);
3331 if ((pPixCache->GetWidth() != dest.width) ||
3332 (pPixCache->GetHeight() != dest.height)) {
3334 pPixCache =
new PixelCache(dest.width, dest.height, BPP);
3337 pPixCache =
new PixelCache(dest.width, dest.height, BPP);
3339 if (m_b_cdebug) printf(
" Render Region By GVUC\n");
3342 ScaleTypeEnum scale_type_zoom = RENDER_HIDEF;
3344 if (binary_scale_factor < .20) scale_type_zoom = RENDER_LODEF;
3346 bool bnewview = GetViewUsingCache(Rsrc, dest, Region, scale_type_zoom);
3349 pPixCache->SelectIntoDC(dc);
3354wxImage *ChartBaseBSB::GetImage() {
3355 int img_size_x = ((Size_X >> 2) * 4) + 4;
3356 wxImage *img =
new wxImage(img_size_x, Size_Y,
false);
3358 unsigned char *ppnx = img->GetData();
3360 for (
int i = 0; i < Size_Y; i++) {
3361 wxRect source_rect(0, i, Size_X, 1);
3362 wxRect dest_rect(0, 0, Size_X, 1);
3364 GetAndScaleData(img->GetData(), img_size_x * Size_Y * 3, source_rect,
3365 Size_X, dest_rect, Size_X, 1.0, RENDER_HIDEF);
3367 ppnx += img_size_x * 3;
3373bool ChartBaseBSB::GetView(wxRect &source, wxRect &dest,
3374 ScaleTypeEnum scale_type) {
3375 assert(pPixCache != 0);
3381 double factor = ((double)source.width) / ((double)dest.width);
3396 GetAndScaleData(pPixCache->GetpData(), pPixCache->GetLength(), source,
3397 source.width, dest, dest.width, factor, scale_type);
3398 pPixCache->Update();
3402 cache_rect = source;
3403 cache_rect_scaled = dest;
3404 cache_scale_method = scale_type;
3406 cached_image_ok = 1;
3411bool ChartBaseBSB::GetAndScaleData(
unsigned char *ppn,
size_t data_size,
3412 wxRect &source,
int source_stride,
3413 wxRect &dest,
int dest_stride,
3414 double scale_factor,
3415 ScaleTypeEnum scale_type) {
3416 unsigned char *s_data = NULL;
3418 double factor = scale_factor;
3419 int Factor = (int)factor;
3421 int target_width = (int)wxRound((
double)source.width / factor);
3422 int target_height = (int)wxRound((
double)source.height / factor);
3424 int dest_line_length = dest_stride * BPP / 8;
3428#ifdef __PIX_CACHE_DIBSECTION__
3429 dest_line_length = (((dest_stride * 24) + 31) & ~31) >> 3;
3432 if ((target_height == 0) || (target_width == 0))
return false;
3436 unsigned char *
volatile target_data = ppn;
3437 unsigned char *data = ppn;
3441 if (scale_type == RENDER_HIDEF) {
3443 int blur_factor = wxMax(2, Factor);
3444 int wb_size = (source.width) * (blur_factor * 2) * BPP / 8;
3445 s_data = (
unsigned char *)malloc(wb_size);
3446 unsigned char *pixel;
3449 for (
int y = dest.y; y < (dest.y + dest.height); y++) {
3454 s1.y = source.y + (int)(y * factor);
3455 s1.width = source.width;
3456 s1.height = blur_factor;
3457 GetChartBits(s1, s_data, 1);
3459 target_data = data + (y * dest_line_length );
3461 for (
int x = 0; x < target_width; x++) {
3462 unsigned int avgRed = 0;
3463 unsigned int avgGreen = 0;
3464 unsigned int avgBlue = 0;
3465 unsigned int pixel_count = 0;
3466 unsigned char *pix0 = s_data + BPP / 8 * ((int)(x * factor));
3469 if ((x * Factor) < (Size_X - source.x)) {
3471 for (
int y1 = 0; y1 < blur_factor; ++y1) {
3472 pixel = pix0 + (BPP / 8 * y_offset);
3473 for (
int x1 = 0; x1 < blur_factor; ++x1) {
3475 avgGreen += pixel[1];
3476 avgBlue += pixel[2];
3482 y_offset += source.width;
3485 if (0 == pixel_count)
3488 target_data[0] = avgRed / pixel_count;
3489 target_data[1] = avgGreen / pixel_count;
3490 target_data[2] = avgBlue / pixel_count;
3491 target_data += BPP / 8;
3496 target_data += BPP / 8;
3505 else if (scale_type == RENDER_LODEF) {
3506 int get_bits_submap = 1;
3510 if (source.width > 32767)
3513 int wb_size = (Size_X) * (( 1) * 2) * BPP / 8;
3514 s_data = (
unsigned char *)malloc(wb_size);
3516 long x_delta = (source.width << scaler) / target_width;
3517 long y_delta = (source.height << scaler) / target_height;
3520 long ys = dest.y * y_delta;
3522 while (y < dest.y + dest.height) {
3527 s1.y = source.y + (ys >> scaler);
3530 GetChartBits(s1, s_data, get_bits_submap);
3532 target_data = data + (y * dest_line_length ) +
3535 long x = (source.x << scaler) + (dest.x * x_delta);
3536 long sizex16 = Size_X << scaler;
3539 while ((xt < dest.x + dest.width) && (x < 0)) {
3544 target_data += BPP / 8;
3549 while ((xt < dest.x + dest.width) && (x < sizex16)) {
3550 unsigned char *src_pixel = &s_data[(x >> scaler) * BPP / 8];
3552 target_data[0] = src_pixel[0];
3553 target_data[1] = src_pixel[1];
3554 target_data[2] = src_pixel[2];
3556 target_data += BPP / 8;
3561 while (xt < dest.x + dest.width) {
3566 target_data += BPP / 8;
3580 unsigned char *target_line_start = NULL;
3581 unsigned char *target_data_x = NULL;
3585 sigaction(SIGSEGV, NULL,
3588 struct sigaction temp;
3589 sigaction(SIGSEGV, NULL, &temp);
3591 temp.sa_handler = catch_signals_chart;
3592 sigemptyset(&temp.sa_mask);
3597 sigaction(SIGSEGV, &temp, NULL);
3599 if (sigsetjmp(env_chart,
3602 sigaction(SIGSEGV, &sa_all_previous, NULL);
3605 msg.Printf(_T(
" Caught SIGSEGV on GetandScaleData, Factor < 1"));
3609 _T(
" m_raster_scale_factor: %g source.width: %d dest.y: %d ")
3610 _T(
"dest.x: %d dest.width: %d dest.height: %d "),
3611 m_raster_scale_factor, source.width, dest.y, dest.x, dest.width,
3616 _T(
" i: %d j: %d dest_stride: %d target_line_start: %p ")
3617 _T(
"target_data_x: %p y_offset: %d"),
3618 i, j, dest_stride, target_line_start, target_data_x, y_offset);
3631 latlong_to_chartpix(m_vp_render_last.
clat, m_vp_render_last.
clon, xd, yd);
3633 xd - (m_vp_render_last.
pix_width * m_raster_scale_factor / 2);
3635 yd - (m_vp_render_last.
pix_height * m_raster_scale_factor / 2);
3636 double x_vernier = (xrd - wxRound(xrd));
3637 double y_vernier = (yrd - wxRound(yrd));
3638 int x_vernier_i = (int)wxRound(x_vernier / m_raster_scale_factor);
3639 int y_vernier_i = (int)wxRound(y_vernier / m_raster_scale_factor);
3644 int sx = wxMax(source.x, 0);
3645 s_data = (
unsigned char *)malloc((sx + source.width + 2) *
3646 (source.height + 2) * BPP / 8);
3648 wxRect vsource = source;
3649 vsource.height += 2;
3654 GetChartBits(vsource, s_data, 1);
3655 unsigned char *source_data = s_data;
3659 while (j < dest.y + dest.height) {
3660 y_offset = (int)((j - y_vernier_i) * m_raster_scale_factor) *
3664 target_data + (j * dest_line_length );
3665 target_data_x = target_line_start + ((dest.x) * BPP / 8);
3670 if ((target_data_x + (dest.width * BPP / 8)) >
3671 (target_data + data_size)) {
3672 j = dest.y + dest.height;
3674 while (i < dest.x + dest.width) {
3675 memcpy(target_data_x,
3676 source_data + BPP / 8 *
3677 (y_offset + (
int)((i + x_vernier_i) *
3678 m_raster_scale_factor)),
3681 target_data_x += BPP / 8;
3691 sigaction(SIGSEGV, &sa_all_previous, NULL);
3700bool ChartBaseBSB::GetChartBits(wxRect &source,
unsigned char *pPix,
3702 wxCriticalSectionLocker locker(m_critSect);
3714 while (iy < source.y + source.height) {
3715 if ((iy >= 0) && (iy < Size_Y)) {
3716 if (source.x >= 0) {
3717 if ((source.x + source.width) > Size_X) {
3718 if ((Size_X - source.x) < 0)
3719 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3721 BSBGetScanline(pCP, iy, source.x, Size_X, sub_samp);
3722 memset(pCP + (Size_X - source.x) * BPP / 8, FILL_BYTE,
3723 (source.x + source.width - Size_X) * BPP / 8);
3726 BSBGetScanline(pCP, iy, source.x, source.x + source.width, sub_samp);
3728 if ((source.width + source.x) >= 0) {
3732 int xfill_corrected = -source.x + (source.x % sub_samp);
3733 memset(pCP, FILL_BYTE, (xfill_corrected * BPP / 8));
3734 BSBGetScanline(pCP + (xfill_corrected * BPP / 8), iy, 0,
3735 source.width + source.x, sub_samp);
3738 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3745 memset(pCP, FILL_BYTE, source.width * BPP / 8);
3748 pCP += source.width * BPP / 8 * sub_samp;
3766int ChartBaseBSB::ReadBSBHdrLine(wxInputStream *ifs,
char *buf,
int buf_len_max)
3771 int line_length = 0;
3776 while (!ifs->Eof() && line_length < buf_len_max) {
3777 int c = ifs->GetC();
3780 if (0x1A == read_char) {
3781 ifs->Ungetch(read_char);
3789 if (read_char == 10 || read_char == 13) {
3791 cr_test = ifs->GetC();
3792 if (cr_test == 13) cr_test = ifs->GetC();
3794 if (cr_test != 10 && cr_test != 13) ifs->Ungetch(cr_test);
3799 if (read_char ==
'\n') {
3801 cr_test = ifs->GetC();
3803 if (cr_test !=
' ') {
3804 ifs->Ungetch(cr_test);
3810 while (cr_test ==
' ') cr_test = ifs->GetC();
3811 ifs->Ungetch(cr_test);
3827 if (line_length) *(lbuf - 1) =
'\0';
3836int ChartBaseBSB::BSBScanScanline(wxInputStream *pinStream) {
3837 int nLineMarker, nValueShift, iPixel = 0;
3838 unsigned char byValueMask, byCountMask;
3839 unsigned char byNext;
3847 byNext = pinStream->GetC();
3848 nLineMarker = nLineMarker * 128 + (byNext & 0x7f);
3849 }
while ((byNext & 0x80) != 0);
3852 nValueShift = 7 - nColorSize;
3853 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
3854 byCountMask = (1 << (7 - nColorSize)) - 1;
3858 while (((byNext = pinStream->GetC()) != 0) && (iPixel < Size_X)) {
3863 nRunCount = byNext & byCountMask;
3865 while ((byNext & 0x80) != 0) {
3866 byNext = pinStream->GetC();
3867 nRunCount = nRunCount * 128 + (byNext & 0x7f);
3870 if (iPixel + nRunCount + 1 > Size_X) nRunCount = Size_X - iPixel - 1;
3875 iPixel += nRunCount + 1;
3877 coffset = pinStream->TellI();
3887inline void memset_short(
unsigned char *dst,
unsigned char cbyte,
int count) {
3899 memset(dst, cbyte, count);
3904#define TILE_SIZE 512
3913 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
3917 clock_gettime(CLOCK_REALTIME, &tp_end);
3918 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
3919 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
3929 free(pt->pTileOffset); \
3930 pt->pTileOffset = NULL; \
3933 pt->bValid = false; \
3940int ChartBaseBSB::BSBGetScanline(
unsigned char *pLineBuf,
int y,
int xs,
int xl,
3944 unsigned char *prgb = pLineBuf;
3946 unsigned char byValueMask, byCountMask;
3947 unsigned char byNext;
3955 if (bUseLineCache && pLineCache) {
3957 pt = &pLineCache[y];
3965 static double ttime;
3972 pt->size = pline_table[y + 1] - pline_table[y];
3975 pt->pPix = (
unsigned char *)malloc(Size_X);
3979 pt->pPix = (
unsigned char *)malloc(pt->size);
3981 if (pline_table[y] == 0 || pline_table[y + 1] == 0) FAIL;
3986 if (ifs_bitmap->TellI() != pline_table[y] &&
3987 wxInvalidOffset == ifs_bitmap->SeekI(pline_table[y], wxFromStart))
3991 if (pt->size > ifs_bufsize) {
3992 unsigned char *tmp = ifs_buf;
3993 if (!(ifs_buf = (
unsigned char *)realloc(ifs_buf, pt->size))) {
3997 ifs_bufsize = pt->size;
4004 ifs_bitmap->Read(lp, pt->size);
4009 if (!bUseLineCache) {
4013 if (pos < pt->size) {
4019 }
while ((byNext & 0x80) != 0);
4024 if (Size_X > ifs_bufsize) {
4025 unsigned char *tmp = ifs_buf;
4026 if (!(ifs_buf = (
unsigned char *)realloc(ifs_buf, Size_X))) {
4030 ifs_bufsize = Size_X;
4038 if (pos < pt->size) {
4044 }
while ((byNext & 0x80) != 0);
4047 nValueShift = 7 - nColorSize;
4048 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
4049 byCountMask = (1 << (7 - nColorSize)) - 1;
4052 unsigned int iPixel = 0;
4054#ifndef USE_OLD_CACHE
4055 pt->pTileOffset[0].offset = lp - pt->pPix;
4056 pt->pTileOffset[0].pixel = 0;
4057 unsigned int tileindex = 1, nextTile = TILE_SIZE;
4059 unsigned int nRunCount;
4060 unsigned char *end = pt->pPix + pt->size;
4061 while (iPixel < (
unsigned int)Size_X)
4064 nPixValue = (byNext & byValueMask) >> nValueShift;
4066 nRunCount = byNext & byCountMask;
4068 while ((byNext & 0x80) != 0) {
4070 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4075 if (iPixel + nRunCount >
4076 (
unsigned int)Size_X)
4077 nRunCount = nRunCount - iPixel;
4080 memset_short(pCL + iPixel, nPixValue, nRunCount);
4081 iPixel += nRunCount;
4086 if (pos < pt->size) {
4092 unsigned char *offset = lp - 1;
4093 if (byNext == 0 || lp == end) {
4095 while (tileindex < (
unsigned int)Size_X / TILE_SIZE + 1) {
4096 pt->pTileOffset[tileindex].offset = pt->pTileOffset[0].offset;
4097 pt->pTileOffset[tileindex].pixel = 0;
4103 nRunCount = byNext & byCountMask;
4105 while ((byNext & 0x80) != 0) {
4106 if (pos < pt->size) {
4112 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4117 if (iPixel + nRunCount >
4118 (
unsigned int)Size_X)
4119 nRunCount = Size_X - iPixel;
4121 while (iPixel + nRunCount > nextTile) {
4122 pt->pTileOffset[tileindex].offset = offset - pt->pPix;
4123 pt->pTileOffset[tileindex].pixel = iPixel;
4125 nextTile += TILE_SIZE;
4127 iPixel += nRunCount;
4136 if (xl > Size_X) xl = Size_X;
4139 pCL = pt->pPix + xs;
4142 if ((BPP == 24) && (1 == sub_samp)) {
4144 while (ix < xl - 1) {
4145 unsigned char cur_by = *pCL;
4146 rgbval = (int)(pPalette[cur_by]);
4147 while ((ix < xl - 1)) {
4148 if (cur_by != *pCL)
break;
4149 *((
int *)prgb) = rgbval;
4156 int dest_inc_val_bytes = (BPP / 8) * sub_samp;
4158 while (ix < xl - 1) {
4159 unsigned char cur_by = *pCL;
4160 rgbval = (int)(pPalette[cur_by]);
4161 while ((ix < xl - 1)) {
4162 if (cur_by != *pCL)
break;
4163 *((
int *)prgb) = rgbval;
4164 prgb += dest_inc_val_bytes;
4175 unsigned char *pCLast = pt->pPix + (xl - 1);
4176 unsigned char *prgb_last = pLineBuf + ((xl - 1) - xs) * BPP / 8;
4178 rgbval = (int)(pPalette[*pCLast]);
4179 unsigned char a = rgbval & 0xff;
4181 a = (rgbval >> 8) & 0xff;
4183 a = (rgbval >> 16) & 0xff;
4188 int tileindex = xs / TILE_SIZE;
4189 int tileoffset = pt->pTileOffset[tileindex].offset;
4191 lp = pt->pPix + tileoffset;
4193 ix = pt->pTileOffset[tileindex].pixel;
4197 nValueShift = 7 - nColorSize;
4198 byValueMask = (((1 << nColorSize)) - 1) << nValueShift;
4199 byCountMask = (1 << (7 - nColorSize)) - 1;
4201 bool bLastPixValueValid =
false;
4202 while (ix < xl - 1) {
4203 if (pos < pt->size) {
4210 nPixValue = (byNext & byValueMask) >> nValueShift;
4211 unsigned int nRunCount;
4214 nRunCount = xl - ix;
4216 nRunCount = byNext & byCountMask;
4217 while ((byNext & 0x80) != 0) {
4218 if (pos < pt->size) {
4222 nRunCount = xl - ix;
4225 nRunCount = nRunCount * 128 + (byNext & 0x7f);
4232 if (ix + nRunCount <= (
unsigned int)xs) {
4236 nRunCount -= xs - ix;
4240 if (ix + nRunCount >= (
unsigned int)xl) {
4241 nRunCount = xl - 1 - ix;
4242 bLastPixValueValid =
true;
4245 rgbval = (int)(pPalette[nPixValue]);
4251 int count = nRunCount;
4255 *(uint32_t *)prgb = rgbval;
4258 }
else if (rgbval == 0 || rgbval == 0xffffff) {
4260 memset(prgb, rgbval, nRunCount * 3);
4261 prgb += nRunCount * 3;
4275 if ((
long)prgb & 7) {
4277 *(uint32_t *)prgb = rgbval;
4279 if (!((
long)prgb & 7)) {
4280 if (count >= 8)
break;
4287 uint64_t *b = (uint64_t *)prgb;
4288 for (
int i = 0; i < 8; i++) {
4289 *(uint32_t *)prgb = rgbval;
4295 uint64_t *y = (uint64_t *)prgb;
4296 int count_d8 = count >> 3;
4297 prgb += 24 * count_d8;
4298 while (count_d8--) {
4305 int rcount = count & 0x7;
4307 *(uint32_t *)prgb = rgbval;
4320 if (!bLastPixValueValid) {
4321 if (pos < pt->size) {
4327 nPixValue = (byNext & byValueMask) >> nValueShift;
4329 rgbval = (int)(pPalette[nPixValue]);
4330 unsigned char a = rgbval & 0xff;
4333 a = (rgbval >> 8) & 0xff;
4335 a = (rgbval >> 16) & 0xff;
4343 if (cnt == 500000) {
4345 printf(
"cache time: %d %f\n", d, ttime / 1000.0);
4352 if (!bUseLineCache) {
4353#ifndef USE_OLD_CACHE
4354 free(pt->pTileOffset);
4362int *ChartBaseBSB::GetPalettePtr(BSB_Color_Capability color_index) {
4363 if (pPalettes[color_index]) {
4364 if (palette_direction == PaletteFwd)
4365 return (
int *)(pPalettes[color_index]->FwdPalette);
4367 return (
int *)(pPalettes[color_index]->RevPalette);
4372PaletteDir ChartBaseBSB::GetPaletteDir(
void) {
4375 RGBO r = pc->GetRGBO();
4384bool ChartBaseBSB::AnalyzeSkew(
void) {
4385 double lonmin = 1000;
4386 double lonmax = -1000;
4387 double latmin = 90.;
4388 double latmax = -90.;
4390 int nlonmin, nlonmax;
4397 for (
int n = 0; n < nRefpoint; n++) {
4399 if (pRefTable[n].lonr > lonmax) {
4400 lonmax = pRefTable[n].lonr;
4403 if (pRefTable[n].lonr < lonmin) {
4404 lonmin = pRefTable[n].lonr;
4409 if (pRefTable[n].latr < latmin) {
4410 latmin = pRefTable[n].latr;
4412 if (pRefTable[n].latr > latmax) {
4413 latmax = pRefTable[n].latr;
4418 if ((lonmin * lonmax) < 0) {
4419 if (pRefTable[nlonmin].xr > pRefTable[nlonmax].xr) {
4421 for (
int n = 0; n < nRefpoint; n++) {
4422 if (pRefTable[n].lonr < 0.0) pRefTable[n].lonr += 360.;
4429 for (
int n = 0; n < nRefpoint; n++) {
4431 if (pRefTable[n].lonr > lonmax) {
4432 lonmax = pRefTable[n].lonr;
4435 if (pRefTable[n].lonr < lonmin) {
4436 lonmin = pRefTable[n].lonr;
4441 if (pRefTable[n].latr < latmin) {
4442 latmin = pRefTable[n].latr;
4444 if (pRefTable[n].latr > latmax) {
4445 latmax = pRefTable[n].latr;
4452 double dist_max = 0.;
4456 for (
int i = 0; i < nRefpoint; i++) {
4457 for (
int j = i + 1; j < nRefpoint; j++) {
4458 double dx = pRefTable[i].xr - pRefTable[j].xr;
4459 double dy = pRefTable[i].yr - pRefTable[j].yr;
4460 double dist = (dx * dx) + (dy * dy);
4461 if (dist > dist_max) {
4469 double apparent_skew = 0;
4471 if (m_projection == PROJECTION_MERCATOR) {
4472 double easting0, easting1, northing0, northing1;
4474 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4475 &easting0, &northing0);
4476 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4477 &easting1, &northing1);
4480 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4481 double skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4482 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4485 apparent_skew = skew_points - skew_proj + 90.;
4488 if (fabs(apparent_skew) > 180.) {
4489 if (apparent_skew < 0.)
4490 apparent_skew += 360.;
4492 apparent_skew -= 360.;
4496 else if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
4497 double easting0, easting1, northing0, northing1;
4499 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4500 &easting0, &northing0);
4501 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4502 &easting1, &northing1);
4505 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4506 double skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4507 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4510 apparent_skew = skew_points - skew_proj + 90.;
4513 if (fabs(apparent_skew) > 180.) {
4514 if (apparent_skew < 0.)
4515 apparent_skew += 360.;
4517 apparent_skew -= 360.;
4520 if (fabs(apparent_skew - m_Chart_Skew) > 2) {
4523 double dskew = fabs(apparent_skew - m_Chart_Skew);
4524 if ((m_proj_lon < lonmin) || (m_proj_lon > lonmax)) {
4526 double tentative_proj_lon = (lonmin + lonmax) / 2.;
4528 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat,
4529 tentative_proj_lon, &easting0, &northing0);
4530 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat,
4531 tentative_proj_lon, &easting1, &northing1);
4534 atan2((easting1 - easting0), (northing1 - northing0)) * 180. / PI;
4535 skew_points = atan2((pRefTable[jmax].yr - pRefTable[imax].yr),
4536 (pRefTable[jmax].xr - pRefTable[imax].xr)) *
4539 apparent_skew = skew_points - skew_proj + 90.;
4542 if (fabs(apparent_skew) > 180.) {
4543 if (apparent_skew < 0.)
4544 apparent_skew += 360.;
4546 apparent_skew -= 360.;
4550 if (fabs(apparent_skew - m_Chart_Skew) < dskew) {
4551 m_proj_lon = tentative_proj_lon;
4557 apparent_skew = m_Chart_Skew;
4559 if (fabs(apparent_skew - m_Chart_Skew) >
4561 m_Chart_Skew = apparent_skew;
4563 wxString msg = _T(
" Warning: Skew override on chart ");
4564 msg.Append(m_FullPath);
4566 msg1.Printf(_T(
" is %5g degrees"), apparent_skew);
4577int ChartBaseBSB::AnalyzeRefpoints(
bool b_testSolution) {
4583 float lonmin = 1000;
4584 float lonmax = -1000;
4586 float latmax = -90.;
4588 int plonmin = 100000;
4590 int platmin = 100000;
4592 int nlonmin = 0, nlonmax = 0;
4597 for (n = 0; n < nRefpoint; n++) {
4599 if (pRefTable[n].lonr > lonmax) {
4600 lonmax = pRefTable[n].lonr;
4601 plonmax = (int)pRefTable[n].xr;
4604 if (pRefTable[n].lonr < lonmin) {
4605 lonmin = pRefTable[n].lonr;
4606 plonmin = (int)pRefTable[n].xr;
4611 if (pRefTable[n].latr < latmin) {
4612 latmin = pRefTable[n].latr;
4613 platmin = (int)pRefTable[n].yr;
4615 if (pRefTable[n].latr > latmax) {
4616 latmax = pRefTable[n].latr;
4617 platmax = (int)pRefTable[n].yr;
4622 if ((lonmin * lonmax) < 0) {
4623 if (pRefTable[nlonmin].xr > pRefTable[nlonmax].xr) {
4625 for (n = 0; n < nRefpoint; n++) {
4626 if (pRefTable[n].lonr < 0.0) pRefTable[n].lonr += 360.;
4633 for (n = 0; n < nRefpoint; n++) {
4635 if (pRefTable[n].lonr > lonmax) {
4636 lonmax = pRefTable[n].lonr;
4637 plonmax = (int)pRefTable[n].xr;
4640 if (pRefTable[n].lonr < lonmin) {
4641 lonmin = pRefTable[n].lonr;
4642 plonmin = (int)pRefTable[n].xr;
4647 if (pRefTable[n].latr < latmin) {
4648 latmin = pRefTable[n].latr;
4649 platmin = (int)pRefTable[n].yr;
4651 if (pRefTable[n].latr > latmax) {
4652 latmax = pRefTable[n].latr;
4653 platmax = (int)pRefTable[n].yr;
4660 cPoints.count = nRefpoint;
4661 if (cPoints.status) {
4674 cPoints.tx = (
double *)malloc(nRefpoint *
sizeof(
double));
4675 cPoints.ty = (
double *)malloc(nRefpoint *
sizeof(
double));
4676 cPoints.lon = (
double *)malloc(nRefpoint *
sizeof(
double));
4677 cPoints.lat = (
double *)malloc(nRefpoint *
sizeof(
double));
4679 cPoints.pwx = (
double *)malloc(12 *
sizeof(
double));
4680 cPoints.wpx = (
double *)malloc(12 *
sizeof(
double));
4681 cPoints.pwy = (
double *)malloc(12 *
sizeof(
double));
4682 cPoints.wpy = (
double *)malloc(12 *
sizeof(
double));
4686 double dist_max = 0.;
4690 for (i = 0; i < nRefpoint; i++) {
4691 for (
int j = i + 1; j < nRefpoint; j++) {
4692 double dx = pRefTable[i].xr - pRefTable[j].xr;
4693 double dy = pRefTable[i].yr - pRefTable[j].yr;
4694 double dist = (dx * dx) + (dy * dy);
4695 if (dist > dist_max) {
4705 if (m_projection == PROJECTION_TRANSVERSE_MERCATOR) {
4706 double easting0, easting1, northing0, northing1;
4708 toTM(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4709 &easting0, &northing0);
4710 toTM(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4711 &easting1, &northing1);
4714 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4715 (pRefTable[jmax].xr - pRefTable[imax].xr);
4716 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4717 (pRefTable[jmax].yr - pRefTable[imax].yr);
4718 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4719 double de2 = (easting1 - easting0) * (easting1 - easting0);
4721 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4726 for (
int n = 0; n < nRefpoint; n++) {
4727 double easting, northing;
4728 toTM(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4729 &easting, &northing);
4731 cPoints.tx[n] = pRefTable[n].xr;
4732 cPoints.ty[n] = pRefTable[n].yr;
4733 cPoints.lon[n] = easting;
4734 cPoints.lat[n] = northing;
4738 cPoints.txmax = plonmax;
4739 cPoints.txmin = plonmin;
4740 cPoints.tymax = platmax;
4741 cPoints.tymin = platmin;
4742 toTM(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.lonmax,
4744 toTM(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.lonmin,
4747 Georef_Calculate_Coefficients_Proj(&cPoints);
4751 else if (m_projection == PROJECTION_MERCATOR) {
4752 double easting0, easting1, northing0, northing1;
4754 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4755 &easting0, &northing0);
4756 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4757 &easting1, &northing1);
4764 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4765 (pRefTable[jmax].xr - pRefTable[imax].xr);
4766 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4767 (pRefTable[jmax].yr - pRefTable[imax].yr);
4768 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4769 double de2 = (easting1 - easting0) * (easting1 - easting0);
4771 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4776 for (
int n = 0; n < nRefpoint; n++) {
4777 double easting, northing;
4778 toSM_ECC(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4779 &easting, &northing);
4781 cPoints.tx[n] = pRefTable[n].xr;
4782 cPoints.ty[n] = pRefTable[n].yr;
4783 cPoints.lon[n] = easting;
4784 cPoints.lat[n] = northing;
4791 cPoints.txmax = plonmax;
4792 cPoints.txmin = plonmin;
4793 cPoints.tymax = platmax;
4794 cPoints.tymin = platmin;
4795 toSM_ECC(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.lonmax,
4797 toSM_ECC(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.lonmin,
4800 Georef_Calculate_Coefficients_Proj(&cPoints);
4822 else if (m_projection == PROJECTION_POLYCONIC) {
4831 double proj_meridian = m_proj_lon;
4833 if ((pRefTable[nlonmax].lonr >= -proj_meridian) &&
4834 (-proj_meridian >= pRefTable[nlonmin].lonr))
4835 m_proj_lon = -m_proj_lon;
4837 double easting0, easting1, northing0, northing1;
4839 toPOLY(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4840 &easting0, &northing0);
4841 toPOLY(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4842 &easting1, &northing1);
4845 double dx2 = (pRefTable[jmax].xr - pRefTable[imax].xr) *
4846 (pRefTable[jmax].xr - pRefTable[imax].xr);
4847 double dy2 = (pRefTable[jmax].yr - pRefTable[imax].yr) *
4848 (pRefTable[jmax].yr - pRefTable[imax].yr);
4849 double dn2 = (northing1 - northing0) * (northing1 - northing0);
4850 double de2 = (easting1 - easting0) * (easting1 - easting0);
4852 m_ppm_avg = sqrt(dx2 + dy2) / sqrt(dn2 + de2);
4865 for (
int n = 0; n < nRefpoint; n++) {
4866 double easting, northing;
4867 toPOLY(pRefTable[n].latr, pRefTable[n].lonr, m_proj_lat, m_proj_lon,
4868 &easting, &northing);
4875 cPoints.tx[n] = pRefTable[n].xr;
4876 cPoints.ty[n] = pRefTable[n].yr;
4877 cPoints.lon[n] = easting;
4878 cPoints.lat[n] = northing;
4885 cPoints.txmax = plonmax;
4886 cPoints.txmin = plonmin;
4887 cPoints.tymax = platmax;
4888 cPoints.tymin = platmin;
4889 toPOLY(latmax, lonmax, m_proj_lat, m_proj_lon, &cPoints.lonmax,
4891 toPOLY(latmin, lonmin, m_proj_lat, m_proj_lon, &cPoints.lonmin,
4894 Georef_Calculate_Coefficients_Proj(&cPoints);
4906 else if (bHaveEmbeddedGeoref) {
4908 double easting0, easting1, northing0, northing1;
4910 toSM_ECC(pRefTable[imax].latr, pRefTable[imax].lonr, m_proj_lat, m_proj_lon,
4911 &easting0, &northing0);
4912 toSM_ECC(pRefTable[jmax].latr, pRefTable[jmax].lonr, m_proj_lat, m_proj_lon,
4913 &easting1, &northing1);
4918 double dx = (pRefTable[jmax].xr - pRefTable[imax].xr);
4919 double de = (easting1 - easting0);
4921 m_ppm_avg = fabs(dx / de);
4924 _T(
"---<<< Warning: Chart georef accuracy may be poor. >>>---");
4933 vps.
clat = pRefTable[0].latr;
4934 vps.
clon = pRefTable[0].lonr;
4941 latlong_to_pix_vp(latmin, (lonmax + lonmin)/2., x1, y1, vps);
4942 latlong_to_pix_vp(latmax, (lonmax + lonmin)/2., x2, y2, vps);
4944 double apparent_skew = (atan2( (y2-y1), (x2-x1) ) * 180./PI) + 90.;
4945 if(apparent_skew < 0.)
4946 apparent_skew += 360;
4947 if(apparent_skew > 360.)
4948 apparent_skew -= 360;
4950 if(fabs( apparent_skew - m_Chart_Skew ) > 2) {
4951 m_Chart_Skew = apparent_skew;
4955 if (!b_testSolution)
return (0);
4959 vp.
clat = pRefTable[0].latr;
4960 vp.
clon = pRefTable[0].lonr;
4966 SetVPRasterParms(vp);
4968 double xpl_err_max = 0;
4969 double ypl_err_max = 0;
4973 pxref = (int)pRefTable[0].xr;
4974 pyref = (int)pRefTable[0].yr;
4976 for (i = 0; i < nRefpoint; i++) {
4977 px = (int)(vp.
pix_width / 2 + pRefTable[i].xr) - pxref;
4978 py = (int)(vp.
pix_height / 2 + pRefTable[i].yr) - pyref;
4980 vp_pix_to_latlong(vp, px, py, &elt, &elg);
4982 double lat_error = elt - pRefTable[i].latr;
4983 pRefTable[i].ypl_error = lat_error;
4985 double lon_error = elg - pRefTable[i].lonr;
4988 if (fabs(lon_error) > 180.) {
4991 else if (lon_error < 0.)
4994 pRefTable[i].xpl_error = lon_error;
4996 if (fabs(pRefTable[i].ypl_error) > fabs(ypl_err_max))
4997 ypl_err_max = pRefTable[i].ypl_error;
4998 if (fabs(pRefTable[i].xpl_error) > fabs(xpl_err_max))
4999 xpl_err_max = pRefTable[i].xpl_error;
5002 Chart_Error_Factor = fmax(fabs(xpl_err_max / (lonmax - lonmin)),
5003 fabs(ypl_err_max / (latmax - latmin)));
5004 double chart_error_meters =
5005 fmax(fabs(xpl_err_max * 60. * 1852.), fabs(ypl_err_max * 60. * 1852.));
5009 double chart_error_pixels = chart_error_meters * 4000. / m_Chart_Scale;
5012 int max_pixel_error = 4;
5014 if (chart_error_pixels > max_pixel_error) {
5016 _T(
" VP Final Check: Georeference Chart_Error_Factor on chart ");
5017 msg.Append(m_FullPath);
5019 msg1.Printf(_T(
" is %5g \n nominal pixel error is: %5g"),
5020 Chart_Error_Factor, chart_error_pixels);
5025 m_ExtraInfo = _T(
"---<<< Warning: Chart georef accuracy is poor. >>>---");
5031 if ((chart_error_pixels > max_pixel_error) && bHaveEmbeddedGeoref) {
5033 _T(
" Trying again with internally calculated georef solution ");
5036 bHaveEmbeddedGeoref =
false;
5037 SetVPRasterParms(vp);
5042 pxref = (int)pRefTable[0].xr;
5043 pyref = (int)pRefTable[0].yr;
5045 for (i = 0; i < nRefpoint; i++) {
5046 px = (int)(vp.
pix_width / 2 + pRefTable[i].xr) - pxref;
5047 py = (int)(vp.
pix_height / 2 + pRefTable[i].yr) - pyref;
5049 vp_pix_to_latlong(vp, px, py, &elt, &elg);
5051 double lat_error = elt - pRefTable[i].latr;
5052 pRefTable[i].ypl_error = lat_error;
5054 double lon_error = elg - pRefTable[i].lonr;
5057 if (fabs(lon_error) > 180.) {
5060 else if (lon_error < 0.)
5063 pRefTable[i].xpl_error = lon_error;
5065 if (fabs(pRefTable[i].ypl_error) > fabs(ypl_err_max))
5066 ypl_err_max = pRefTable[i].ypl_error;
5067 if (fabs(pRefTable[i].xpl_error) > fabs(xpl_err_max))
5068 xpl_err_max = pRefTable[i].xpl_error;
5071 Chart_Error_Factor = fmax(fabs(xpl_err_max / (lonmax - lonmin)),
5072 fabs(ypl_err_max / (latmax - latmin)));
5074 chart_error_meters =
5075 fmax(fabs(xpl_err_max * 60. * 1852.), fabs(ypl_err_max * 60. * 1852.));
5076 chart_error_pixels = chart_error_meters * 4000. / m_Chart_Scale;
5079 if (chart_error_pixels > max_pixel_error) {
5081 _T(
" VP Final Check with internal georef: Georeference ")
5082 _T("Chart_Error_Factor on chart ");
5083 msg.Append(m_FullPath);
5085 msg1.Printf(_T(" is %5g\n nominal pixel error is: %5g"),
5086 Chart_Error_Factor, chart_error_pixels);
5092 _T("---<<< Warning:
Chart georef accuracy is poor. >>>---");
5094 wxString msg = _T(
" Result: OK, Internal georef solution used.");
5098 m_ExtraInfo = _T(
"");
5105double ChartBaseBSB::AdjustLongitude(
double lon) {
5106 double lond = (m_LonMin + m_LonMax) / 2 - lon;
5109 else if (lond < -180)
5145static double polytrans(
double *coeff,
double lon,
double lat) {
5146 double ret = coeff[0] + coeff[1] * lon + coeff[2] * lat;
5147 ret += coeff[3] * lon * lon;
5148 ret += coeff[4] * lon * lat;
5149 ret += coeff[5] * lat * lat;
5150 ret += coeff[6] * lon * lon * lon;
5151 ret += coeff[7] * lon * lon * lat;
5152 ret += coeff[8] * lon * lat * lat;
5153 ret += coeff[9] * lat * lat * lat;
5175extern int bsb_LLtoXY(BSBImage *p,
double lon,
double lat,
int* x,
int* y)
5178 lon = (lon < 0) ? lon + p->cph : lon - p->cph;
5179 double xd = polytrans( p->wpx, lon, lat );
5180 double yd = polytrans( p->wpy, lon, lat );
5181 *x = (int)(xd + 0.5);
5182 *y = (int)(yd + 0.5);
5197extern int bsb_XYtoLL(BSBImage *p,
int x,
int y,
double* lonout,
double* latout)
5199 double lon = polytrans( p->pwx, x, y );
5200 lon = (lon < 0) ? lon + p->cph : lon - p->cph;
5202 *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.
Represents the view port for chart display in OpenCPN.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
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.