25#include <unordered_map>
36#include <wx/listctrl.h>
37#include <wx/mstream.h>
39#include <wx/spinctrl.h>
40#include <wx/textfile.h>
41#include <wx/tokenzr.h>
51#include "model/georef.h"
55#include "ocpn_frame.h"
56#include "ocpn_pixel.h"
57#include "OCPNPlatform.h"
64#include "glChartCanvas.h"
68#include <wx/msw/msvcrt.h>
71extern s52plib *ps52plib;
75#include <wx/arrimpl.cpp>
76WX_DEFINE_OBJARRAY(Array_Of_M_COVR_Desc);
78#include <wx/listimpl.cpp>
79WX_DEFINE_LIST(List_Of_M_COVR_Desc);
81static int Get_CM93_CellIndex(
double lat,
double lon,
int scale);
83void Get_CM93_Cell_Origin(
int cellindex,
int scale,
double *lat,
double *lon);
85void appendOSDirSep(wxString *pString) {
86 wxChar sep = wxFileName::GetPathSeparator();
87 if (pString->Last() != sep) pString->Append(sep);
94M_COVR_Desc::M_COVR_Desc() {
96 gl_screen_vertices = NULL;
97 gl_screen_projection_type = PROJECTION_UNKNOWN;
101 m_centerlat_cos = 1.0;
102 m_buser_offsets =
false;
105 gl_screen_vertices = NULL;
108M_COVR_Desc::~M_COVR_Desc() {
110 delete[] gl_screen_vertices;
113int M_COVR_Desc::GetWKBSize() {
121 size += m_nvertices *
sizeof(float_2Dpt);
124 size += 8 *
sizeof(double);
129bool M_COVR_Desc::WriteWKB(
void *p) {
132 *pr++ = GetWKBSize();
134 *pr++ = m_cell_index;
140 float_2Dpt *pfo = (float_2Dpt *)pr;
141 float_2Dpt *pfi = pvertices;
142 for (
int i = 0; i < m_nvertices; i++) *pfo++ = *pfi++;
144 int *pi = (
int *)pfo;
147 double *pd = (
double *)pi;
148 *pd++ = transform_WGS84_offset_x;
149 *pd++ = transform_WGS84_offset_y;
150 *pd++ = m_covr_lat_min;
151 *pd++ = m_covr_lat_max;
152 *pd++ = m_covr_lon_min;
153 *pd++ = m_covr_lon_max;
155 double centerlat_cos =
156 cos(((m_covr_lat_min + m_covr_lat_max) / 2.) * PI / 180.);
158 *pd++ = user_xoff * centerlat_cos;
159 *pd++ = user_yoff * centerlat_cos;
165int M_COVR_Desc::ReadWKB(wxFFileInputStream &ifs) {
168 if (!ifs.Read(&length,
sizeof(
int)).Eof()) {
169 ifs.Read(&m_cell_index,
sizeof(
int));
170 ifs.Read(&m_object_id,
sizeof(
int));
171 ifs.Read(&m_subcell,
sizeof(
int));
173 ifs.Read(&m_nvertices,
sizeof(
int));
175 pvertices =
new float_2Dpt[m_nvertices];
177 ifs.Read(pvertices, m_nvertices *
sizeof(float_2Dpt));
179 ifs.Read(&m_npub_year,
sizeof(
int));
181 ifs.Read(&transform_WGS84_offset_x,
sizeof(
double));
182 ifs.Read(&transform_WGS84_offset_y,
sizeof(
double));
183 ifs.Read(&m_covr_lat_min,
sizeof(
double));
184 ifs.Read(&m_covr_lat_max,
sizeof(
double));
185 ifs.Read(&m_covr_lon_min,
sizeof(
double));
186 ifs.Read(&m_covr_lon_max,
sizeof(
double));
188 m_centerlat_cos = cos(((m_covr_lat_min + m_covr_lat_max) / 2.) * PI / 180.);
190 ifs.Read(&user_xoff,
sizeof(
double));
191 ifs.Read(&user_yoff,
sizeof(
double));
193 user_xoff /= m_centerlat_cos;
194 user_yoff /= m_centerlat_cos;
196 if ((fabs(user_xoff) > 1.) || (fabs(user_yoff) > 1.))
197 m_buser_offsets =
true;
199 m_buser_offsets =
false;
201 m_covr_bbox.Set(m_covr_lat_min, m_covr_lon_min, m_covr_lat_max,
208 float_2Dpt *p = pvertices;
210 for (
int ip = 0; ip < m_nvertices; ip++) {
212 if (fabs(plon - vp.
clon) > 180.) {
219 double easting, northing, epix, npix;
220 toSM(p->y, plon + 360., vp.
clat, vp.
clon + 360, &easting, &northing);
223 easting -= user_xoff;
225 northing -= user_yoff;
230 pwp[ip].x = (int)round((vp.
pix_width / 2) + epix);
231 pwp[ip].y = (int)round((vp.
pix_height / 2) - npix);
245char sig_version[] =
"COVR1002";
252 bool Init(wxChar scale_char, wxString &prefix);
253 unsigned int GetCoverCount() {
return m_covr_array_outlines.GetCount(); }
254 M_COVR_Desc *GetCover(
unsigned int im) {
return &m_covr_array_outlines[im]; }
257 bool IsCovrLoaded(
int cell_index);
259 M_COVR_Desc *Find_MCD(
int cell_index,
int object_id,
int sbcell);
265 wxString m_cachefile;
268 Array_Of_M_COVR_Desc m_covr_array_outlines;
272 std::unordered_map<int, int> m_cell_hash;
275covr_set::covr_set(
cm93chart *parent) { m_pParent = parent; }
277covr_set::~covr_set() {
279 if (m_cachefile.IsEmpty())
283 if (m_covr_array_outlines.GetCount()) {
284 wxFFileOutputStream ofs(m_cachefile);
286 ofs.Write(sig_version, 8);
288 for (
unsigned int i = 0; i < m_covr_array_outlines.GetCount(); i++) {
289 int wkbsize = m_covr_array_outlines[i].GetWKBSize();
291 char *p = (
char *)malloc(wkbsize *
sizeof(
char));
292 m_covr_array_outlines[i].WriteWKB(p);
293 ofs.Write(p, wkbsize);
302bool covr_set::Init(wxChar scale_char, wxString &prefix) {
303 m_scale_char = scale_char;
305 switch (m_scale_char) {
336 wxString prefix_string = prefix;
337 wxString sep(wxFileName::GetPathSeparator());
338 prefix_string.Replace(sep,
"_");
339 prefix_string.Replace(
":",
"_");
342 appendOSDirSep(&m_cachefile);
344 m_cachefile +=
"cm93";
345 appendOSDirSep(&m_cachefile);
351 wxString cache_old_old_name = m_cachefile;
352 cache_old_old_name +=
"coverset.";
353 cache_old_old_name += m_scale_char;
355 wxString cache_old_name = m_cachefile;
356 cache_old_name +=
"coverset_sig.";
357 cache_old_name += m_scale_char;
359 m_cachefile +=
"coverset_sigp.";
360 m_cachefile += m_scale_char;
362 wxFileName fn(m_cachefile);
363 if (!fn.DirExists()) wxFileName::Mkdir(fn.GetPath(), 0777, wxPATH_MKDIR_FULL);
366 if (!wxFileName::FileExists(m_cachefile)) {
369 if (wxFileName::FileExists(cache_old_name)) ::wxRemoveFile(cache_old_name);
370 if (wxFileName::FileExists(cache_old_old_name))
371 ::wxRemoveFile(cache_old_old_name);
375 wxFFileInputStream ifs(m_cachefile);
379 if (!ifs.Read(&sig_bytes, 8).Eof()) {
380 if (strncmp(sig_bytes, sig_version, 8)) {
389 int length = pmcd->ReadWKB(ifs);
392 m_covr_array_outlines.Add(pmcd);
394 if (m_cell_hash.find(pmcd->m_cell_index) == m_cell_hash.end())
395 m_cell_hash[pmcd->m_cell_index] = 0;
397 m_cell_hash[pmcd->m_cell_index]++;
410 m_covr_array_outlines.Add(pmcd);
412 if (m_cell_hash.find(pmcd->m_cell_index) ==
414 m_cell_hash[pmcd->m_cell_index] = 0;
416 m_cell_hash[pmcd->m_cell_index]++;
419bool covr_set::IsCovrLoaded(
int cell_index) {
420 return (m_cell_hash.find(cell_index) != m_cell_hash.end());
424 if (m_cell_hash.find(pmcd->m_cell_index) ==
427 m_covr_array_outlines.Add(pmcd);
428 m_cell_hash[pmcd->m_cell_index] = 1;
436 bool b_found =
false;
437 for (
unsigned int i = 0; i < m_covr_array_outlines.GetCount(); i++) {
438 M_COVR_Desc *pmcd_candidate = &m_covr_array_outlines[i];
439 if ((pmcd_candidate->m_cell_index == pmcd->m_cell_index) &&
440 (pmcd_candidate->m_object_id == pmcd->m_object_id) &&
441 (pmcd_candidate->m_subcell == pmcd->m_subcell))
450 m_covr_array_outlines.Add(pmcd);
451 m_cell_hash[pmcd->m_cell_index]++;
459 if (m_cell_hash.find(pmcd->m_cell_index) ==
467 for (
unsigned int i = 0; i < m_covr_array_outlines.GetCount(); i++) {
468 M_COVR_Desc *pmcd_candidate = &m_covr_array_outlines[i];
469 if ((pmcd_candidate->m_cell_index == pmcd->m_cell_index) &&
470 (pmcd_candidate->m_object_id == pmcd->m_object_id) &&
471 (pmcd_candidate->m_subcell == pmcd->m_subcell)) {
479M_COVR_Desc *covr_set::Find_MCD(
int cell_index,
int object_id,
int subcell) {
480 if (m_cell_hash.find(cell_index) == m_cell_hash.end())
483 for (
unsigned int i = 0; i < m_covr_array_outlines.GetCount(); i++) {
484 M_COVR_Desc *pmcd_candidate = &m_covr_array_outlines[i];
485 if ((pmcd_candidate->m_cell_index == cell_index) &&
486 (pmcd_candidate->m_object_id == object_id) &&
487 (pmcd_candidate->m_subcell == subcell))
489 return pmcd_candidate;
497static unsigned char Table_0[] = {
498 0x0CD, 0x0EA, 0x0DC, 0x048, 0x03E, 0x06D, 0x0CA, 0x07B, 0x052, 0x0E1, 0x0A4,
499 0x08E, 0x0AB, 0x005, 0x0A7, 0x097, 0x0B9, 0x060, 0x039, 0x085, 0x07C, 0x056,
500 0x07A, 0x0BA, 0x068, 0x06E, 0x0F5, 0x05D, 0x002, 0x04E, 0x00F, 0x0A1, 0x027,
501 0x024, 0x041, 0x034, 0x000, 0x05A, 0x0FE, 0x0CB, 0x0D0, 0x0FA, 0x0F8, 0x06C,
502 0x074, 0x096, 0x09E, 0x00E, 0x0C2, 0x049, 0x0E3, 0x0E5, 0x0C0, 0x03B, 0x059,
503 0x018, 0x0A9, 0x086, 0x08F, 0x030, 0x0C3, 0x0A8, 0x022, 0x00A, 0x014, 0x01A,
504 0x0B2, 0x0C9, 0x0C7, 0x0ED, 0x0AA, 0x029, 0x094, 0x075, 0x00D, 0x0AC, 0x00C,
505 0x0F4, 0x0BB, 0x0C5, 0x03F, 0x0FD, 0x0D9, 0x09C, 0x04F, 0x0D5, 0x084, 0x01E,
506 0x0B1, 0x081, 0x069, 0x0B4, 0x009, 0x0B8, 0x03C, 0x0AF, 0x0A3, 0x008, 0x0BF,
507 0x0E0, 0x09A, 0x0D7, 0x0F7, 0x08C, 0x067, 0x066, 0x0AE, 0x0D4, 0x04C, 0x0A5,
508 0x0EC, 0x0F9, 0x0B6, 0x064, 0x078, 0x006, 0x05B, 0x09B, 0x0F2, 0x099, 0x0CE,
509 0x0DB, 0x053, 0x055, 0x065, 0x08D, 0x007, 0x033, 0x004, 0x037, 0x092, 0x026,
510 0x023, 0x0B5, 0x058, 0x0DA, 0x02F, 0x0B3, 0x040, 0x05E, 0x07F, 0x04B, 0x062,
511 0x080, 0x0E4, 0x06F, 0x073, 0x01D, 0x0DF, 0x017, 0x0CC, 0x028, 0x025, 0x02D,
512 0x0EE, 0x03A, 0x098, 0x0E2, 0x001, 0x0EB, 0x0DD, 0x0BC, 0x090, 0x0B0, 0x0FC,
513 0x095, 0x076, 0x093, 0x046, 0x057, 0x02C, 0x02B, 0x050, 0x011, 0x00B, 0x0C1,
514 0x0F0, 0x0E7, 0x0D6, 0x021, 0x031, 0x0DE, 0x0FF, 0x0D8, 0x012, 0x0A6, 0x04D,
515 0x08A, 0x013, 0x043, 0x045, 0x038, 0x0D2, 0x087, 0x0A0, 0x0EF, 0x082, 0x0F1,
516 0x047, 0x089, 0x06A, 0x0C8, 0x054, 0x01B, 0x016, 0x07E, 0x079, 0x0BD, 0x06B,
517 0x091, 0x0A2, 0x071, 0x036, 0x0B7, 0x003, 0x03D, 0x072, 0x0C6, 0x044, 0x08B,
518 0x0CF, 0x015, 0x09F, 0x032, 0x0C4, 0x077, 0x083, 0x063, 0x020, 0x088, 0x0F6,
519 0x0AD, 0x0F3, 0x0E8, 0x04A, 0x0E9, 0x035, 0x01C, 0x05F, 0x019, 0x01F, 0x07D,
520 0x070, 0x0FB, 0x0D1, 0x051, 0x010, 0x0D3, 0x02E, 0x061, 0x09D, 0x05C, 0x02A,
521 0x042, 0x0BE, 0x0E6};
523static unsigned char Encode_table[256];
524static unsigned char Decode_table[256];
526static bool cm93_decode_table_created;
535 virtual wxDirTraverseResult OnFile(
const wxString &filename) {
536 wxString name = filename.AfterLast(wxFileName::GetPathSeparator()).Lower();
537 if (name ==
"cm93obj.dic") {
542 return wxDIR_CONTINUE;
545 virtual wxDirTraverseResult OnDir(
const wxString &WXUNUSED(dirname)) {
546 return wxDIR_CONTINUE;
553cm93_dictionary::cm93_dictionary() {
554 m_S57ClassArray = NULL;
556 m_GeomTypeArray = NULL;
558 m_ValTypeArray = NULL;
563bool cm93_dictionary::LoadDictionary(
const wxString &dictionary_dir) {
566 wxString dir(dictionary_dir);
567 bool ret_val =
false;
569 wxChar sep = wxFileName::GetPathSeparator();
570 if (dir.Last() != sep) dir.Append(sep);
577 sf.Append(
"CM93OBJ.DIC");
579 if (!wxFileName::FileExists(sf)) {
581 sf.Append(
"cm93obj.dic");
582 if (!wxFileName::FileExists(sf))
return false;
586 if (!file.Open(sf))
return false;
588 nline = file.GetLineCount();
590 if (!nline)
return false;
595 for (i = 0; i < nline; i++) {
596 line = file.GetLine(i);
598 wxStringTokenizer tkz(line,
"|");
602 wxString class_name = tkz.GetNextToken();
605 wxString token = tkz.GetNextToken();
607 token.ToLong(&liclass);
608 int iclass = liclass;
609 if (iclass > iclass_max) iclass_max = iclass;
612 wxString geo_type = tkz.GetNextToken();
616 m_max_class = iclass_max;
619 m_S57ClassArray =
new wxArrayString;
620 m_S57ClassArray->Add(
"NULLNM", iclass_max + 1);
623 m_GeomTypeArray = (
int *)malloc((iclass_max + 1) *
sizeof(int));
626 for (i = 0; i < nline; i++) {
627 line = file.GetLine(i);
629 wxStringTokenizer tkz(line,
"|");
633 wxString class_name = tkz.GetNextToken();
636 wxString token = tkz.GetNextToken();
638 token.ToLong(&liclass);
639 int iclass = liclass;
642 wxString geo_type = tkz.GetNextToken();
644 m_S57ClassArray->Insert(class_name, iclass);
645 m_S57ClassArray->RemoveAt(iclass + 1);
648 wxChar geo_type_primary = geo_type[0];
650 if (geo_type_primary ==
'A')
652 else if (geo_type_primary ==
'L')
654 else if (geo_type_primary ==
'P')
661 m_GeomTypeArray[iclass] = igeom_type;
669 sfa.Append(
"ATTRLUT.DIC");
671 if (!wxFileName::FileExists(sfa)) {
673 sfa.Append(
"attrlut.dic");
676 if (wxFileName::FileExists(sfa)) {
677 wxFFileInputStream filea(sfa);
683 while (!filea.Eof()) {
687 char a = filea.GetC();
688 if (filea.Eof())
break;
690 if (a == 0x0a)
break;
693 if (!line.StartsWith((
const wxChar *)
";")) {
694 wxStringTokenizer tkz(line,
"|");
697 wxString class_name = tkz.GetNextToken();
700 wxString token = tkz.GetNextToken();
702 token.ToLong(&liattr);
704 if (iattr > iattr_max) iattr_max = iattr;
709 m_max_attr = iattr_max;
715 m_AttrArray =
new wxArrayString;
716 m_AttrArray->Add(
"NULLNM", iattr_max + 1);
719 m_ValTypeArray = (
char *)malloc((iattr_max + 1) *
sizeof(char));
722 while (!filea.Eof()) {
726 char a = filea.GetC();
727 if (filea.Eof())
break;
729 if (a == 0x0a)
break;
732 if (!line.StartsWith((
const wxChar *)
";")) {
733 wxStringTokenizer tkz(line,
"|");
736 wxString attr_name = tkz.GetNextToken();
739 wxString token = tkz.GetNextToken();
741 token.ToLong(&liattr);
744 m_AttrArray->Insert(attr_name, iattr);
745 m_AttrArray->RemoveAt(iattr + 1);
748 token = tkz.GetNextToken();
749 token = tkz.GetNextToken();
750 token = tkz.GetNextToken();
751 token = tkz.GetNextToken().Trim();
754 if (token.IsSameAs(
"aFLOAT"))
756 else if (token.IsSameAs(
"aBYTE"))
758 else if (token.IsSameAs(
"aSTRING"))
760 else if (token.IsSameAs(
"aCMPLX"))
762 else if (token.IsSameAs(
"aLIST"))
764 else if (token.IsSameAs(
"aWORD10"))
766 else if (token.IsSameAs(
"aLONG"))
769 m_ValTypeArray[iattr] = atype;
783 sfa.Append(
"CM93ATTR.DIC");
785 if (!wxFileName::FileExists(sfa)) {
787 sfa.Append(
"cm93attr.dic");
790 if (wxFileName::FileExists(sfa)) {
791 wxFFileInputStream filea(sfa);
797 while (!filea.Eof()) {
801 char a = filea.GetC();
802 if (filea.Eof())
break;
804 if (a == 0x0a)
break;
807 if (!line.StartsWith((
const wxChar *)
";")) {
808 wxStringTokenizer tkz(line,
"|");
809 if (tkz.CountTokens()) {
811 wxString class_name = tkz.GetNextToken();
814 wxString token = tkz.GetNextToken();
816 token.ToLong(&liattr);
818 if (iattr > iattr_max) iattr_max = iattr;
823 m_max_attr = iattr_max;
829 m_AttrArray =
new wxArrayString;
830 m_AttrArray->Add(
"NULLNM", iattr_max + 1);
833 m_ValTypeArray = (
char *)malloc((iattr_max + 1) *
sizeof(char));
834 for (
int iat = 0; iat < iattr_max + 1; iat++) m_ValTypeArray[iat] =
'?';
837 while (!filea.Eof()) {
841 char a = filea.GetC();
842 if (filea.Eof())
break;
844 if (a == 0x0a)
break;
847 if (!line.StartsWith((
const wxChar *)
";")) {
848 wxStringTokenizer tkz(line,
"|\r\n");
849 if (tkz.CountTokens() >= 3) {
851 wxString attr_name = tkz.GetNextToken();
854 wxString token = tkz.GetNextToken();
856 token.ToLong(&liattr);
859 m_AttrArray->Insert(attr_name, iattr);
860 m_AttrArray->RemoveAt(iattr + 1);
862 token = tkz.GetNextToken().Trim();
865 if (token.IsSameAs(
"aFLOAT"))
867 else if (token.IsSameAs(
"aBYTE"))
869 else if (token.IsSameAs(
"aSTRING"))
871 else if (token.IsSameAs(
"aCMPLX"))
873 else if (token.IsSameAs(
"aLIST"))
875 else if (token.IsSameAs(
"aWORD10"))
877 else if (token.IsSameAs(
"aLONG"))
880 m_ValTypeArray[iattr] = atype;
893 wxString msg(
"Loaded CM93 Dictionary from ");
901wxString cm93_dictionary::GetClassName(
int iclass) {
902 if ((iclass > m_max_class) || (iclass < 0))
905 return (m_S57ClassArray->Item(iclass));
908wxString cm93_dictionary::GetAttrName(
int iattr) {
909 if ((iattr > m_max_attr) || (iattr < 0))
910 return (
"UnknownAttr");
912 return (m_AttrArray->Item(iattr));
916char cm93_dictionary::GetAttrType(
int iattr) {
917 if ((iattr > m_max_attr) || (iattr < 0))
920 return (m_ValTypeArray[iattr]);
923cm93_dictionary::~cm93_dictionary() {
924 delete m_S57ClassArray;
925 free(m_GeomTypeArray);
927 free(m_ValTypeArray);
932void CreateDecodeTable(
void) {
934 for (i = 0; i < 256; i++) {
935 Encode_table[i] = Table_0[i] ^ 8;
938 for (i = 0; i < 256; i++) {
939 unsigned char a = Encode_table[i];
940 Decode_table[(int)a] = (
unsigned char)i;
944static int read_and_decode_bytes(FILE *stream,
void *p,
int nbytes) {
949 if (fread(p, nbytes, 1, stream) != 1)
return 0;
952 unsigned char *q = (
unsigned char *)p;
954 for (
int i = 0; i < nbytes; i++) {
955 unsigned char a = *q;
957 unsigned char c = Decode_table[b];
965static int read_and_decode_double(FILE *stream,
double *p) {
968 if (fread(&t,
sizeof(
double), 1, stream) != 1)
return 0;
971 unsigned char *q = (
unsigned char *)&t;
973 for (
unsigned int i = 0; i <
sizeof(double); i++) {
974 unsigned char a = *q;
976 unsigned char c = Decode_table[b];
988static int read_and_decode_int(FILE *stream,
int *p) {
991 if (fread(&t,
sizeof(
int), 1, stream) != 1)
return 0;
994 unsigned char *q = (
unsigned char *)&t;
996 for (
unsigned int i = 0; i <
sizeof(int); i++) {
997 unsigned char a = *q;
999 unsigned char c = Decode_table[b];
1011static int read_and_decode_ushort(FILE *stream,
unsigned short *p) {
1014 if (fread(&t,
sizeof(
unsigned short), 1, stream) != 1)
return 0;
1017 unsigned char *q = (
unsigned char *)&t;
1019 for (
unsigned int i = 0; i <
sizeof(
unsigned short); i++) {
1020 unsigned char a = *q;
1022 unsigned char c = Decode_table[b];
1036int Get_CM93_CellIndex(
double lat,
double lon,
int scale) {
1071 double lon1 = (lon + 360.) * 3.;
1072 while (lon1 >= 1080.0) lon1 -= 1080.0;
1073 unsigned short lon2 = (
unsigned short)floor(lon1 / dval);
1074 unsigned short lon3 = lon2 * dval;
1079 double lat1 = (lat * 3.) + 270. - 30;
1080 unsigned short lat2 = (
unsigned short)floor(lat1 / dval);
1081 unsigned short lat3 = lat2 * dval;
1083 retval += (lat3 + 30) * 10000;
1091void Get_CM93_Cell_Origin(
int cellindex,
int scale,
double *lat,
double *lon) {
1093 double idx1 = cellindex % 10000;
1094 double lont = (idx1 / 3.);
1099 int idx2 = cellindex / 10000;
1100 double lat1 = idx2 - 270.;
1106bool Is_CM93Cell_Present(wxString &fileprefix,
double lat,
double lon,
1112 switch (scale_index) {
1160 int cellindex = Get_CM93_CellIndex(lat, lon,
scale);
1165 int ilat = cellindex / 10000;
1166 int ilon = cellindex % 10000;
1168 int jlat = (((ilat - 30) / dval) * dval) + 30;
1169 int jlon = (ilon / dval) * dval;
1171 int ilatroot = (((ilat - 30) / 60) * 60) + 30;
1172 int ilonroot = (ilon / 60) * 60;
1175 fileroot.Printf(
"%04d%04d", ilatroot, ilonroot);
1176 appendOSDirSep(&fileroot);
1178 wxString sdir(fileprefix);
1183 tfile.Printf(
"?%03d%04d.", jlat, jlon);
1184 tfile += scale_char;
1187 if (!::wxDirExists(sdir)) {
1188 wxString old_scalechar(scale_char);
1189 wxString new_scalechar = old_scalechar.Lower();
1193 sdir += new_scalechar;
1196 if (::wxDirExists(sdir)) {
1199 wxArrayString file_array;
1200 int n_files = dir.GetAllFiles(sdir, &file_array, tfile, wxDIR_FILES);
1202 if (n_files)
return true;
1205 wxString old_scalechar(scale_char);
1206 wxString new_scalechar = old_scalechar.Lower();
1209 tfile1.Printf(
"?%03d%04d.", jlat, jlon);
1210 tfile1 += new_scalechar;
1212 int n_files1 = dir.GetAllFiles(sdir, &file_array, tfile1, wxDIR_FILES);
1214 if (n_files1)
return true;
1217 n_files = dir.GetAllFiles(sdir, &file_array, tfile +
".xz", wxDIR_FILES);
1219 if (n_files)
return true;
1225static bool read_header_and_populate_cib(FILE *stream,
Cell_Info_Block *pCIB) {
1234 memset((
void *)&header, 0,
sizeof(header));
1236 read_and_decode_double(stream, &header.lon_min);
1237 read_and_decode_double(stream, &header.lat_min);
1238 read_and_decode_double(stream, &header.lon_max);
1239 read_and_decode_double(stream, &header.lat_max);
1241 read_and_decode_double(stream, &header.easting_min);
1242 read_and_decode_double(stream, &header.northing_min);
1243 read_and_decode_double(stream, &header.easting_max);
1244 read_and_decode_double(stream, &header.northing_max);
1246 read_and_decode_ushort(stream, &header.usn_vector_records);
1247 read_and_decode_int(stream, &header.n_vector_record_points);
1248 read_and_decode_int(stream, &header.m_46);
1249 read_and_decode_int(stream, &header.m_4a);
1250 read_and_decode_ushort(stream, &header.usn_point3d_records);
1251 read_and_decode_int(stream, &header.m_50);
1252 read_and_decode_int(stream, &header.m_54);
1253 read_and_decode_ushort(stream, &header.usn_point2d_records);
1254 read_and_decode_ushort(stream, &header.m_5a);
1255 read_and_decode_ushort(stream, &header.m_5c);
1256 read_and_decode_ushort(stream, &header.usn_feature_records);
1258 read_and_decode_int(stream, &header.m_60);
1259 read_and_decode_int(stream, &header.m_64);
1260 read_and_decode_ushort(stream, &header.m_68);
1261 read_and_decode_ushort(stream, &header.m_6a);
1262 read_and_decode_ushort(stream, &header.m_6c);
1263 read_and_decode_int(stream, &header.m_nrelated_object_pointers);
1265 read_and_decode_int(stream, &header.m_72);
1266 read_and_decode_ushort(stream, &header.m_76);
1268 read_and_decode_int(stream, &header.m_78);
1269 read_and_decode_int(stream, &header.m_7c);
1273 double delta_x = header.easting_max - header.easting_min;
1275 delta_x += CM93_semimajor_axis_meters * 2.0 * PI;
1277 pCIB->transform_x_rate = delta_x / 65535;
1278 pCIB->transform_y_rate = (header.northing_max - header.northing_min) / 65535;
1280 pCIB->transform_x_origin = header.easting_min;
1281 pCIB->transform_y_origin = header.northing_min;
1283 pCIB->min_lat = header.lat_min;
1284 pCIB->min_lon = header.lon_min;
1292 pCIB->m_nfeature_records = header.usn_feature_records;
1293 pCIB->pobject_block =
1294 (
Object *)calloc(pCIB->m_nfeature_records *
sizeof(
Object), 1);
1296 pCIB->m_n_point2d_records = header.usn_point2d_records;
1297 pCIB->p2dpoint_array =
1300 pCIB->pprelated_object_block =
1301 (
Object **)malloc(header.m_nrelated_object_pointers *
sizeof(
Object *));
1303 pCIB->object_vector_record_descriptor_block =
1307 pCIB->attribute_block_top = (
unsigned char *)calloc(header.m_78, 1);
1309 pCIB->m_nvector_records = header.usn_vector_records;
1313 pCIB->pvector_record_block_top =
1316 pCIB->m_n_point3d_records = header.usn_point3d_records;
1320 pCIB->p3dpoint_array =
1326static bool read_vector_record_table(FILE *stream,
int count,
1331 cm93_point *q = pCIB->pvector_record_block_top;
1333 for (
int iedge = 0; iedge < count; iedge++) {
1336 unsigned short npoints;
1337 brv = !(read_and_decode_ushort(stream, &npoints) == 0);
1338 if (!brv)
return false;
1340 p->n_points = npoints;
1348 unsigned short x, y;
1349 for (
int index = 0; index < p->n_points; index++) {
1350 if (!read_and_decode_ushort(stream, &x))
return false;
1351 if (!read_and_decode_ushort(stream, &y))
return false;
1367 for (
int j = 0; j < p->n_points - 1; j++) {
1368 if (t->x >= p->x_max) p->x_max = t->x;
1370 if (t->x <= p->x_min) p->x_min = t->x;
1372 if (t->y >= p->y_max) p->y_max = t->y;
1374 if (t->y <= p->y_max) p->y_min = t->y;
1389static bool read_3dpoint_table(FILE *stream,
int count,
Cell_Info_Block *pCIB) {
1393 for (
int i = 0; i < count; i++) {
1394 unsigned short npoints;
1395 if (!read_and_decode_ushort(stream, &npoints))
return false;
1397 p->n_points = npoints;
1405 unsigned short x, y, z;
1406 for (
int index = 0; index < p->n_points; index++) {
1407 if (!read_and_decode_ushort(stream, &x))
return false;
1408 if (!read_and_decode_ushort(stream, &y))
return false;
1409 if (!read_and_decode_ushort(stream, &z))
return false;
1423static bool read_2dpoint_table(FILE *stream,
int count,
Cell_Info_Block *pCIB) {
1427 unsigned short x, y;
1428 for (
int index = 0; index < count; index++) {
1429 if (!read_and_decode_ushort(stream, &x))
return false;
1430 if (!read_and_decode_ushort(stream, &y))
return false;
1432 pCIB->p2dpoint_array[index].x = x;
1433 pCIB->p2dpoint_array[index].y = y;
1439static bool read_feature_record_table(FILE *stream,
int n_features,
1442 Object *pobj = pCIB->pobject_block;
1445 pCIB->object_vector_record_descriptor_block;
1448 pCIB->pprelated_object_block;
1451 unsigned char *puc_var10 = pCIB->attribute_block_top;
1454 unsigned char object_type;
1455 unsigned char geom_prim;
1456 unsigned short obj_desc_bytes = 0;
1459 unsigned short index;
1460 unsigned short n_elements;
1462 for (
int iobject = 0; iobject < n_features; iobject++) {
1464 read_and_decode_bytes(stream, &object_type, 1);
1465 read_and_decode_bytes(stream, &geom_prim,
1467 read_and_decode_ushort(stream,
1470 pobj->otype = object_type;
1471 pobj->geotype = geom_prim;
1473 switch (pobj->geotype & 0x0f) {
1476 if (!read_and_decode_ushort(stream, &n_elements))
return false;
1478 pobj->n_geom_elements = n_elements;
1479 t = (pobj->n_geom_elements * 2) + 2;
1480 obj_desc_bytes -= t;
1483 pobject_vector_collection;
1487 for (
unsigned short i = 0; i < pobj->n_geom_elements; i++) {
1488 if (!read_and_decode_ushort(stream, &index))
return false;
1490 if ((index & 0x1fff) > pCIB->m_nvector_records)
1496 pobject_vector_collection->pGeom_Description = u;
1497 pobject_vector_collection->segment_usage =
1498 (
unsigned char)(index >> 13);
1500 pobject_vector_collection++;
1508 if (!read_and_decode_ushort(
1509 stream, &n_elements))
1512 pobj->n_geom_elements = n_elements;
1513 t = (pobj->n_geom_elements * 2) + 2;
1514 obj_desc_bytes -= t;
1517 pobject_vector_collection;
1521 for (
unsigned short i = 0; i < pobj->n_geom_elements; i++) {
1522 unsigned short geometry_index;
1524 if (!read_and_decode_ushort(stream, &geometry_index))
return false;
1526 if ((geometry_index & 0x1fff) > pCIB->m_nvector_records)
1531 geometry_index & 0x1fff)];
1533 pobject_vector_collection->pGeom_Description = u;
1534 pobject_vector_collection->segment_usage =
1535 (
unsigned char)(geometry_index >> 13);
1537 pobject_vector_collection++;
1544 if (!read_and_decode_ushort(stream, &index))
return false;
1546 obj_desc_bytes -= 2;
1548 pobj->n_geom_elements = 1;
1550 pobj->pGeometry = &pCIB->p2dpoint_array[index];
1556 if (!read_and_decode_ushort(stream, &index))
return false;
1557 obj_desc_bytes -= 2;
1559 pobj->n_geom_elements = 1;
1562 &pCIB->point3d_descriptor_block[index];
1569 if ((pobj->geotype & 0x10) == 0x10)
1571 unsigned char nrelated;
1572 if (!read_and_decode_bytes(stream, &nrelated, 1))
return false;
1574 pobj->n_related_objects = nrelated;
1575 t = (pobj->n_related_objects * 2) + 1;
1576 obj_desc_bytes -= t;
1578 pobj->p_related_object_pointer_array = p_relob;
1579 p_relob += pobj->n_related_objects;
1581 Object **w = (
Object **)pobj->p_related_object_pointer_array;
1582 for (
unsigned char j = 0; j < pobj->n_related_objects; j++) {
1583 if (!read_and_decode_ushort(stream, &index))
return false;
1585 if (index > pCIB->m_nfeature_records)
1589 Object *prelated_object = &pCIB->pobject_block[index];
1590 *w = prelated_object;
1592 prelated_object->p_related_object_pointer_array =
1598 if ((pobj->geotype & 0x20) == 0x20) {
1599 unsigned short nrelated;
1600 if (!read_and_decode_ushort(stream, &nrelated))
return false;
1602 pobj->n_related_objects = (
unsigned char)(nrelated & 0xFF);
1603 obj_desc_bytes -= 2;
1606 if ((pobj->geotype & 0x40) == 0x40) {
1609 if ((pobj->geotype & 0x80) == 0x80)
1611 unsigned char nattr;
1612 if (!read_and_decode_bytes(stream, &nattr, 1))
return false;
1614 pobj->n_attributes = nattr;
1615 obj_desc_bytes -= 5;
1617 pobj->attributes_block = puc_var10;
1618 puc_var10 += obj_desc_bytes;
1620 puc10count += obj_desc_bytes;
1622 if (!read_and_decode_bytes(stream, pobj->attributes_block,
1626 if ((pobj->geotype & 0x0f) == 1) {
1637 printf(
"catch on read_feature_record_table\n");
1643bool Ingest_CM93_Cell(
const char *cell_file_name,
Cell_Info_Block *pCIB) {
1648 FILE *flstream = fopen(cell_file_name,
"rb");
1649 if (!flstream)
return false;
1651 fseek(flstream, 0, SEEK_END);
1652 file_length = ftell(flstream);
1656 FILE *stream = fopen(cell_file_name,
"rb");
1657 if (!stream)
return false;
1661 unsigned short word0 = 0;
1667 read_and_decode_ushort(stream,
1669 read_and_decode_int(stream, &int0);
1670 read_and_decode_int(stream, &int1);
1672 int test = word0 + int0 + int1;
1673 if (test != file_length) {
1680 if (!read_header_and_populate_cib(stream, pCIB)) {
1685 if (!read_vector_record_table(stream, pCIB->m_nvector_records, pCIB)) {
1690 if (!read_3dpoint_table(stream, pCIB->m_n_point3d_records, pCIB)) {
1695 if (!read_2dpoint_table(stream, pCIB->m_n_point2d_records, pCIB)) {
1700 if (!read_feature_record_table(stream, pCIB->m_nfeature_records, pCIB)) {
1723cm93chart::cm93chart() {
1724 m_ChartType = CHART_TYPE_CM93;
1727 if (!cm93_decode_table_created) {
1728 CreateDecodeTable();
1729 cm93_decode_table_created =
true;
1735 m_current_cell_vearray_offset = 0;
1737 m_ncontour_alloc = 100;
1738 m_pcontour_array = (
int *)malloc(m_ncontour_alloc *
sizeof(
int));
1748 m_pDrawBuffer = (wxPoint *)malloc(4 *
sizeof(wxPoint));
1749 m_nDrawBufferSize = 1;
1752 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
1753 m_this_chart_context->chart =
this;
1757cm93chart::~cm93chart() {
1758 free(m_pcontour_array);
1762 free(m_pDrawBuffer);
1765void cm93chart::Unload_CM93_Cell(
void) {
1766 free(m_CIB.pobject_block);
1768 free(m_CIB.p2dpoint_array);
1769 free(m_CIB.pprelated_object_block);
1770 free(m_CIB.object_vector_record_descriptor_block);
1771 free(m_CIB.attribute_block_top);
1772 free(m_CIB.edge_vector_descriptor_block);
1773 free(m_CIB.pvector_record_block_top);
1774 free(m_CIB.point3d_descriptor_block);
1775 free(m_CIB.p3dpoint_array);
1784double cm93chart::GetNormalScaleMin(
double canvas_scale_factor,
1785 bool b_allow_overzoom) {
1786 switch (GetNativeScale()) {
1808double cm93chart::GetNormalScaleMax(
double canvas_scale_factor,
1816 switch (GetNativeScale()) {
1838void cm93chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
1840 wxPoint2DDouble en(east, north);
1841 GetPointPix(rzRules, &en, r, 1);
1844void cm93chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
1845 wxPoint *r,
int nPoints) {
1846 S57Obj *obj = rzRules->obj;
1848 double xr = obj->x_rate;
1849 double xo = obj->x_origin;
1850 double yr = obj->y_rate;
1851 double yo = obj->y_origin;
1853 if (m_vp_current.m_projection_type == PROJECTION_MERCATOR) {
1854 if (m_vp_current.GetBBox().GetMaxLon() >= 180. &&
1855 rzRules->obj->BBObj.GetMaxLon() < m_vp_current.GetBBox().GetMinLon())
1856 xo += mercator_k0 * WGS84_semimajor_axis_meters * 2.0 * PI;
1857 else if ((m_vp_current.GetBBox().GetMinLon() <= -180. &&
1858 rzRules->obj->BBObj.GetMinLon() >
1859 m_vp_current.GetBBox().GetMaxLon()) ||
1860 (rzRules->obj->BBObj.GetMaxLon() >= 180 &&
1861 m_vp_current.GetBBox().GetMinLon() <= 0.))
1862 xo -= mercator_k0 * WGS84_semimajor_axis_meters * 2.0 * PI;
1864 for (
int i = 0; i < nPoints; i++) {
1865 double valx = (en[i].m_x * xr) + xo;
1866 double valy = (en[i].m_y * yr) + yo;
1868 r[i].x = ((valx - m_easting_vp_center) * m_view_scale_ppm) +
1869 m_pixx_vp_center + 0.5;
1870 r[i].y = m_pixy_vp_center -
1871 ((valy - m_northing_vp_center) * m_view_scale_ppm) + 0.5;
1874 for (
int i = 0; i < nPoints; i++) {
1875 double valx = (en[i].m_x * xr) + xo;
1876 double valy = (en[i].m_y * yr) + yo;
1879 fromSM(valx - m_easting_vp_center, valy - m_northing_vp_center,
1880 m_vp_current.
clat, m_vp_current.
clon, &lat, &lon);
1882 double rotation = m_vp_current.
rotation;
1883 m_vp_current.SetRotationAngle(0);
1885 m_vp_current.SetRotationAngle(rotation);
1890void cm93chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
1903 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
1904 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
1910 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
1912 if (slon > 360.) slon -= 360.;
1920 if (IsCacheValid()) {
1930 vp_last.
GetLLFromPix(wxPoint(round(p.m_x), round(p.m_y)), &xlat, &xlon);
1932 double prev_easting_c, prev_northing_c;
1933 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
1936 double easting_c, northing_c;
1937 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
1940 double delta_pix_x =
1942 int dpix_x = (int)round(delta_pix_x);
1943 double dpx = dpix_x;
1945 double delta_pix_y =
1947 int dpix_y = (int)round(delta_pix_y);
1948 double dpy = dpix_y;
1950 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
1951 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
1954 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
1956 vp_proposed.
clon = xlon;
1957 vp_proposed.
clat = xlat;
1970void cm93chart::SetVPParms(
const ViewPort &vpt) {
1971 if (m_vp_current == vpt) {
1982 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
1983 &m_northing_vp_center);
1985 vp_transform.easting_vp_center = m_easting_vp_center;
1986 vp_transform.northing_vp_center = m_northing_vp_center;
1991 LLBBox box = vptl.GetBBox();
1992 double ll_lon = box.GetMinLon();
1993 double ll_lat = box.GetMinLat();
1995 double ur_lon = box.GetMaxLon();
1996 double ur_lat = box.GetMaxLat();
1999 "cm93chart::SetVPParms ll_lon: %g ll_lat: %g ur_lon: %g ur_lat: "
2001 ll_lon, ll_lat, ur_lon, ur_lat, m_dval);
2005 std::vector<int> vpcells = GetVPCellArray(vpt);
2011 for (
unsigned int i = 0; i < vpcells.size(); i++) {
2012 bcell_is_in =
false;
2013 for (
unsigned int j = 0; j < m_cells_loaded_array.size(); j++) {
2014 if (vpcells[i] == m_cells_loaded_array[j]) {
2022#ifndef __OCPN__ANDROID__
2023 AbstractPlatform::ShowBusySpinner();
2025 int cell_index = vpcells[i];
2027 if (loadcell_in_sequence(cell_index,
'0'))
2029 ProcessVectorEdges();
2032 ForceEdgePriorityEvaluate();
2034 m_cells_loaded_array.push_back(cell_index);
2039 char loadcell_key =
'A';
2043 while (loadcell_in_sequence(cell_index, loadcell_key)) {
2044 ProcessVectorEdges();
2045 CreateObjChain(cell_index, (
int)loadcell_key, vpt.
view_scale_ppm);
2047 ForceEdgePriorityEvaluate();
2049 if (std::find(m_cells_loaded_array.begin(), m_cells_loaded_array.end(),
2050 cell_index) == m_cells_loaded_array.end())
2051 m_cells_loaded_array.push_back(cell_index);
2058 AssembleLineGeometry();
2060 ClearDepthContourArray();
2061 BuildDepthContourArray();
2064 m_this_chart_context->m_pvc_hash = &Get_vc_hash();
2065 m_this_chart_context->m_pve_hash = &Get_ve_hash();
2067 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2068 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2069 m_this_chart_context->chart =
this;
2070 m_this_chart_context->chart_type = GetChartType();
2072 m_this_chart_context->safety_contour = m_next_safe_cnt;
2073 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2074 m_this_chart_context->pt2GetAssociatedObjects =
2075 &s57chart::GetAssociatedObjects;
2080 ObjRazRules *top = razRules[i][j];
2082 if (top->obj) top->obj->m_chart_context = m_this_chart_context;
2088 AbstractPlatform::HideBusySpinner();
2093std::vector<int> cm93chart::GetVPCellArray(
const ViewPort &vpt) {
2096 LLBBox box = vptl.GetBBox();
2097 double ll_lon = box.GetMinLon();
2098 double ll_lat = box.GetMinLat();
2100 double ur_lon = box.GetMaxLon();
2101 double ur_lat = box.GetMaxLat();
2104 ur_lat = wxMin(ur_lat, 79.99999);
2107 ur_lat = wxMin(ur_lat, 79.99999);
2116 std::vector<int> vpcells;
2118 int lower_left_cell = Get_CM93_CellIndex(ll_lat, ll_lon, GetNativeScale());
2119 vpcells.push_back(lower_left_cell);
2122 printf(
"cm93chart::GetVPCellArray Adding %d\n", lower_left_cell);
2125 Get_CM93_Cell_Origin(lower_left_cell, GetNativeScale(), &rlat, &rlon);
2130 int loni_0 = (int)wxRound(rlon * 3);
2131 int loni_20 = loni_0 + (int)m_dval;
2132 int lati_20 = (int)wxRound(rlat * 3);
2134 while (lati_20 < (ur_lat * 3.)) {
2135 while (loni_20 < (ur_lon * 3.)) {
2136 unsigned int next_lon = loni_20 + 1080;
2137 while (next_lon >= 1080) next_lon -= 1080;
2139 unsigned int next_cell = next_lon;
2141 next_cell += (lati_20 + 270) * 10000;
2143 vpcells.push_back((
int)next_cell);
2145 printf(
"cm93chart::GetVPCellArray Adding %d\n", next_cell);
2147 loni_20 += (int)m_dval;
2149 lati_20 += (int)m_dval;
2156void cm93chart::ProcessVectorEdges(
void) {
2159 auto &vehash = Get_ve_hash();
2161 m_current_cell_vearray_offset =
2165 for (
int iedge = 0; iedge < m_CIB.m_nvector_records; iedge++) {
2166 VE_Element *vep =
new VE_Element;
2167 vep->index = iedge + m_current_cell_vearray_offset;
2168 vep->nCount = pgd->n_points;
2169 vep->pPoints = NULL;
2170 vep->max_priority = -99;
2172 if (pgd->n_points) {
2173 float *pPoints = (
float *)malloc(pgd->n_points * 2 *
sizeof(
float));
2174 vep->pPoints = pPoints;
2179 double east_max = -1e7;
2180 double east_min = 1e7;
2181 double north_max = -1e7;
2182 double north_min = 1e7;
2184 for (
int ip = 0; ip < pgd->n_points; ip++) {
2185 *pPoints++ = ppt->x;
2186 *pPoints++ = ppt->y;
2188 east_max = wxMax(east_max, ppt->x);
2189 east_min = wxMin(east_min, ppt->x);
2190 north_max = wxMax(north_max, ppt->y);
2191 north_min = wxMin(north_min, ppt->y);
2197 double lat1, lon1, lat2, lon2;
2203 Transform(&p, 0, 0, &lat1, &lon1);
2207 Transform(&p, 0, 0, &lat2, &lon2);
2212 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
2215 vehash[vep->index] = vep;
2221int cm93chart::CreateObjChain(
int cell_index,
int subcell,
2222 double view_scale_ppm) {
2224 LUPname LUP_Name = PAPER_CHART;
2226 m_CIB.m_cell_mcovr_list.Clear();
2230 Object *pobjectDef = m_CIB.pobject_block;
2231 m_CIB.b_have_offsets =
false;
2233 m_CIB.b_have_user_offsets =
false;
2239 double scale = gFrame->GetBestVPScale(
this);
2240 int nativescale = GetNativeScale();
2242 while (iObj < m_CIB.m_nfeature_records) {
2243 if ((pobjectDef != NULL)) {
2244 Extended_Geometry *xgeom = BuildGeom(pobjectDef, NULL, iObj);
2249 CreateS57Obj(cell_index, iObj, subcell, pobjectDef, m_pDict, xgeom,
2250 ref_lat, ref_lon, GetNativeScale(), view_scale_ppm);
2253 wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
2254 wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
2255 if (fe_name ==
"_texto") objnam = obj->GetAttrValueAsString(
"_texta");
2256 if (objnam.Len() > 0) {
2257 wxString cellname = wxString::Format(
"%i_%i", cell_index, subcell);
2258 SendVectorChartObjectInfo(cellname, fe_name, objnam, obj->m_lat,
2259 obj->m_lon,
scale, nativescale);
2262 if (GEO_POINT == obj->Primitive_type) {
2264 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
2265 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
2266 (!strncmp(obj->FeatureName,
"BOY", 3))) {
2267 pFloatingATONArray->Add(obj);
2271 if (!strncmp(obj->FeatureName,
"BCN", 3)) pRigidATONArray->Add(obj);
2274 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
2275 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
2276 (!strncmp(obj->FeatureName,
"BCN", 3)) ||
2277 (!strncmp(obj->FeatureName,
"_slgto", 6)) ||
2278 (!strncmp(obj->FeatureName,
"_boygn", 6)) ||
2279 (!strncmp(obj->FeatureName,
"_bcngn", 6)) ||
2280 (!strncmp(obj->FeatureName,
"_extgn", 6)) ||
2281 (!strncmp(obj->FeatureName,
"TOWERS", 6)) ||
2282 (!strncmp(obj->FeatureName,
"BOY", 3))) {
2283 obj->bIsAton =
true;
2289 if (GEO_AREA == obj->Primitive_type) {
2290 if (!strncmp(obj->FeatureName,
"DEPARE", 6) ||
2291 !strncmp(obj->FeatureName,
"DRGARE", 6))
2292 obj->bIsAssociable =
true;
2300 switch (obj->Primitive_type) {
2304 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
2305 LUP_Name = PAPER_CHART;
2307 LUP_Name = SIMPLIFIED;
2309 if (m_b2pointLUPS) {
2311 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
2312 LUPO_Name = SIMPLIFIED;
2314 LUPO_Name = PAPER_CHART;
2318 ps52plib->S52_LUPLookup(LUPO_Name, obj->FeatureName, obj);
2320 ps52plib->_LUP2rules(LUPO, obj);
2321 _insertRules(obj, LUPO,
this);
2331 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
2332 LUP_Name = PLAIN_BOUNDARIES;
2334 LUP_Name = SYMBOLIZED_BOUNDARIES;
2338 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
2339 LUPO_Name = SYMBOLIZED_BOUNDARIES;
2341 LUPO_Name = PLAIN_BOUNDARIES;
2345 ps52plib->S52_LUPLookup(LUPO_Name, obj->FeatureName, obj);
2347 ps52plib->_LUP2rules(LUPO, obj);
2348 _insertRules(obj, LUPO,
this);
2354 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
2358 wxString msg(obj->FeatureName, wxConvUTF8);
2359 msg.Prepend(
" CM93 could not find LUP for ");
2360 LogMessageOnce(msg);
2362 if (0 == obj->nRef)
delete obj;
2365 ps52plib->_LUP2rules(LUP, obj);
2368 _insertRules(obj, LUP,
this);
2371 obj->m_DisplayCat = LUP->DISC;
2374 obj->m_DPRI = LUP->DPRI -
'0';
2377 obj->m_chart_context = m_this_chart_context;
2396InitReturn cm93chart::Init(
const wxString &name, ChartInitFlag flags) {
2398 m_Description = m_FullPath;
2400 wxFileName fn(name);
2402 if (!m_prefix.Len())
2403 m_prefix = fn.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
2405 m_scalechar = fn.GetExt();
2410 switch ((m_scalechar.mb_str())[(
size_t)0]) {
2440 m_Chart_Scale =
scale;
2442 switch (GetNativeScale()) {
2473 wxString data =
"CM93Chart ";
2474 data.Append(m_scalechar);
2476 s.Printf(
" 1/%d", m_Chart_Scale);
2481 if (
scale != 20000000)
2482 m_pcovr_set->Init(m_scalechar.mb_str()[(
size_t)0], m_prefix);
2484 if (flags == THUMB_ONLY) {
2492 if (flags == HEADER_ONLY)
return CreateHeaderDataFromCM93Cell();
2497 if (m_pManager->Loadcm93Dictionary(name))
2498 m_pDict = m_pManager->m_pcm93Dict;
2500 wxLogMessage(
" CM93Chart Init cannot locate CM93 dictionary.");
2501 return INIT_FAIL_REMOVE;
2506 bReadyToRender =
true;
2511Extended_Geometry *cm93chart::BuildGeom(
Object *pobject,
2512 wxFileOutputStream *postream,
2519 int geom_type_maybe = pobject->geotype;
2521 switch (geom_type_maybe) {
2559 Extended_Geometry *ret_ptr =
new Extended_Geometry;
2561 int lon_max, lat_max, lon_min, lat_min;
2573 int nsegs = pobject->n_geom_elements;
2575 ret_ptr->n_vector_indices = nsegs;
2576 ret_ptr->pvector_index = (
int *)malloc(nsegs * 3 *
sizeof(
int));
2579 int n_maxvertex = 0;
2580 for (
int i = 0; i < nsegs; i++) {
2583 n_maxvertex += pgd->n_points;
2589 wxPoint2DDouble *pPoints =
2590 (wxPoint2DDouble *)calloc((n_maxvertex) *
sizeof(wxPoint2DDouble), 1);
2593 int n_prev_vertex_index = 1;
2594 bool bnew_ring =
true;
2603 cur_end_point.x = 1;
2604 cur_end_point.y = 1;
2606 int n_max_points = -1;
2607 while (iseg < nsegs) {
2608 int type_seg = psegs[iseg].segment_usage;
2613 int npoints = pgd->n_points;
2616 n_max_points = wxMax(n_max_points, npoints);
2622 if ((type_seg & 4) == 0)
2623 start_point = rseg[0];
2625 start_point = rseg[npoints - 1];
2628 if (((type_seg & 4) == 0)) {
2629 cur_end_point = rseg[npoints - 1];
2630 for (
int j = 0; j < npoints; j++) {
2634 lon_max = wxMax(lon_max, rseg[j].x);
2635 lon_min = wxMin(lon_min, rseg[j].x);
2636 lat_max = wxMax(lat_max, rseg[j].y);
2637 lat_min = wxMin(lat_min, rseg[j].y);
2640 pPoints[ip].m_x = rseg[j].x;
2641 pPoints[ip].m_y = rseg[j].y;
2644 }
else if ((type_seg & 4) == 4)
2646 cur_end_point = rseg[0];
2647 for (
int j = npoints - 1; j >= 0; j--) {
2651 lon_max = wxMax(lon_max, rseg[j].x);
2652 lon_min = wxMin(lon_min, rseg[j].x);
2653 lat_max = wxMax(lat_max, rseg[j].y);
2654 lat_min = wxMin(lat_min, rseg[j].y);
2657 pPoints[ip].m_x = rseg[j].x;
2658 pPoints[ip].m_y = rseg[j].y;
2665 ret_ptr->pvector_index[iseg * 3 + 0] =
2667 ret_ptr->pvector_index[iseg * 3 + 1] =
2668 pgd->index + m_current_cell_vearray_offset;
2669 ret_ptr->pvector_index[iseg * 3 + 2] =
2672 if ((cur_end_point.x == start_point.x) &&
2673 (cur_end_point.y == start_point.y)) {
2678 int nRingVertex = ip - n_prev_vertex_index;
2681 if (ncontours > m_ncontour_alloc - 1) {
2682 m_ncontour_alloc *= 2;
2683 int *tmp = m_pcontour_array;
2684 m_pcontour_array = (
int *)realloc(m_pcontour_array,
2685 m_ncontour_alloc *
sizeof(
int));
2691 m_pcontour_array[ncontours] = nRingVertex;
2694 n_prev_vertex_index = ip;
2700 ret_ptr->n_max_edge_points = n_max_points;
2702 ret_ptr->n_contours =
2705 if (0 == ncontours) ncontours = 1;
2706 ret_ptr->contour_array = (
int *)malloc(ncontours *
sizeof(
int));
2707 memcpy(ret_ptr->contour_array, m_pcontour_array, ncontours *
sizeof(
int));
2709 ret_ptr->vertex_array = pPoints;
2710 ret_ptr->n_max_vertex = n_maxvertex;
2712 ret_ptr->pogrGeom = NULL;
2714 ret_ptr->xmin = lon_min;
2715 ret_ptr->xmax = lon_max;
2716 ret_ptr->ymin = lat_min;
2717 ret_ptr->ymax = lat_max;
2725 ret_ptr->pogrGeom = NULL;
2727 ret_ptr->pointx = pt->x;
2728 ret_ptr->pointy = pt->y;
2737 int nsegs = pobject->n_geom_elements;
2739 ret_ptr->n_vector_indices = nsegs;
2740 ret_ptr->pvector_index = (
int *)malloc(nsegs * 3 *
sizeof(
int));
2743 int n_maxvertex = 0;
2744 for (
int imseg = 0; imseg < nsegs; imseg++) {
2748 n_maxvertex += pgd->n_points;
2752 wxPoint2DDouble *pPoints =
2753 (wxPoint2DDouble *)malloc(n_maxvertex *
sizeof(wxPoint2DDouble));
2758 int lon_max, lat_max, lon_min, lat_min;
2763 int n_max_points = -1;
2765 for (
int iseg = 0; iseg < nsegs; iseg++) {
2766 int type_seg = psegs->segment_usage;
2773 int npoints = pgd->n_points;
2776 n_max_points = wxMax(n_max_points, npoints);
2778 if (((type_seg & 4) != 4)) {
2779 for (
int j = 0; j < npoints; j++) {
2780 lon_max = wxMax(lon_max, rseg[j].x);
2781 lon_min = wxMin(lon_min, rseg[j].x);
2782 lat_max = wxMax(lat_max, rseg[j].y);
2783 lat_min = wxMin(lat_min, rseg[j].y);
2785 pPoints[ip].m_x = rseg[j].x;
2786 pPoints[ip].m_y = rseg[j].y;
2791 else if ((type_seg & 4) == 4)
2793 for (
int j = npoints - 1; j >= 0; j--) {
2794 lon_max = wxMax(lon_max, rseg[j].x);
2795 lon_min = wxMin(lon_min, rseg[j].x);
2796 lat_max = wxMax(lat_max, rseg[j].y);
2797 lat_min = wxMin(lat_min, rseg[j].y);
2799 pPoints[ip].m_x = rseg[j].x;
2800 pPoints[ip].m_y = rseg[j].y;
2805 ret_ptr->pvector_index[iseg * 3 + 0] =
2807 ret_ptr->pvector_index[iseg * 3 + 1] =
2808 pgd->index + m_current_cell_vearray_offset;
2809 ret_ptr->pvector_index[iseg * 3 + 2] =
2814 ret_ptr->n_max_edge_points = n_max_points;
2816 ret_ptr->vertex_array = pPoints;
2817 ret_ptr->n_max_vertex = n_maxvertex;
2819 ret_ptr->pogrGeom = NULL;
2821 ret_ptr->xmin = lon_min;
2822 ret_ptr->xmax = lon_max;
2823 ret_ptr->ymin = lat_min;
2824 ret_ptr->ymax = lat_max;
2832 int npoints = pgd->n_points;
2835 OGRMultiPoint *pSMP =
new OGRMultiPoint;
2839 for (
int ip = 0; ip < npoints; ip++) {
2844 zp = double(z - 12000);
2848 OGRPoint *ppoint =
new OGRPoint(rseg[ip].x, rseg[ip].y, zp);
2849 pSMP->addGeometryDirectly(ppoint);
2851 lon_max = wxMax(lon_max, rseg[ip].x);
2852 lon_min = wxMin(lon_min, rseg[ip].x);
2853 lat_max = wxMax(lat_max, rseg[ip].y);
2854 lat_min = wxMin(lat_min, rseg[ip].y);
2857 ret_ptr->pogrGeom = pSMP;
2859 ret_ptr->xmin = lon_min;
2860 ret_ptr->xmax = lon_max;
2861 ret_ptr->ymin = lat_min;
2862 ret_ptr->ymax = lat_max;
2872 wxPrintf(
"Unexpected geomtype %d for Feature %d\n", geomtype, iobject);
2881void cm93chart::Transform(
cm93_point *s,
double trans_x,
double trans_y,
2882 double *lat,
double *lon) {
2884 double valx = (s->x * m_CIB.transform_x_rate) + m_CIB.transform_x_origin;
2885 double valy = (s->y * m_CIB.transform_y_rate) + m_CIB.transform_y_origin;
2893 (2.0 * atan(exp(valy / CM93_semimajor_axis_meters)) - PI / 2.) / DEGREE;
2894 *lon = (valx / (DEGREE * CM93_semimajor_axis_meters));
2899 m_block = (
unsigned char *)
block;
2903unsigned char *cm93_attr_block::GetNextAttr() {
2905 unsigned char *ret_val = m_block + m_cptr;
2909 unsigned char iattr = *(m_block + m_cptr);
2913 char vtype = m_pDict->GetAttrType(iattr);
2926 while (*(m_block + m_cptr)) m_cptr++;
2943 while (*(m_block + m_cptr)) m_cptr++;
2949 unsigned char nl = *(m_block + m_cptr);
2976wxString ParseSLGTA(wxString &val) {
2981 wxStringTokenizer tkz(val,
"|");
2983 s = tkz.GetNextToken();
2984 s = tkz.GetNextToken();
2985 s = tkz.GetNextToken();
2988 wxString sc, st, sp;
3001 else if (s[0] ==
'G') {
3004 }
else if (s.Mid(0, 3) ==
"W/O") {
3010 }
else if (s.Mid(0, 5) ==
"LIGHT") {
3015 if (val.Find(
"Spar") != wxNOT_FOUND) {
3019 if (val.Find(
"SPAR") != wxNOT_FOUND) {
3024 if ((type == 2) && (color == 3))
3031 sprintf(line,
" %s (%c) = %s",
"COLOUR",
'I', (
const char *)sc.mb_str());
3032 result += wxString(line, wxConvUTF8);
3035 sprintf(line,
" %s (%c) = %s",
"BOYSHP",
'I',
"4");
3036 result += wxString(line, wxConvUTF8);
3042 sprintf(line,
" %s (%c) = %s",
"BOYSHP",
'I', (
const char *)st.mb_str());
3043 result += wxString(line, wxConvUTF8);
3046 sprintf(line,
" %s (%c) = %s",
"COLOUR",
'I',
"2");
3047 result += wxString(line, wxConvUTF8);
3053 sprintf(line,
" %s (%c) = %s",
"COLPAT",
'I', (
const char *)sp.mb_str());
3054 result += wxString(line, wxConvUTF8);
3061wxString ParseTEXTA(wxString &val) {
3065 if (val.Contains(
"WK S")) {
3066 sprintf(line,
" %s (%c) = %s",
"WRKATT",
'I',
"1");
3067 result += wxString(line, wxConvUTF8);
3074void cm93chart::translate_colmar(
const wxString &sclass,
3075 S57attVal *pattValTmp) {
3076 int *pcur_attr = (
int *)pattValTmp->value;
3077 int cur_attr = *pcur_attr;
3140 if (lstring.Len()) {
3141 free(pattValTmp->value);
3143 pattValTmp->valType = OGR_STR;
3144 pattValTmp->value = strdup(lstring.mb_str());
3148S57Obj *cm93chart::CreateS57Obj(
int cell_index,
int iobject,
int subcell,
3150 Extended_Geometry *xgeom,
double ref_lat,
3151 double ref_lon,
double scale,
3152 double view_scale_ppm) {
3153#define MAX_HDR_LINE 4000
3157 int npub_year = 1993;
3159 int iclass = pobject->otype;
3160 int geomtype = pobject->geotype & 0x0f;
3162 double tmp_transform_x = 0.;
3163 double tmp_transform_y = 0.;
3166 double trans_WGS84_offset_x = 0.;
3167 double trans_WGS84_offset_y = 0.;
3169 wxString sclass = pDict->GetClassName(iclass);
3170 if (sclass ==
"Unknown") {
3172 msg.Printf(
" CM93 Error...object type %d not found in CM93OBJ.DIC",
3179 wxString sclass_sub = sclass;
3182 if (sclass.IsSameAs(
"ITDARE")) sclass_sub =
"DEPARE";
3184 if (sclass.IsSameAs(
"_m_sor")) sclass_sub =
"M_COVR";
3186 if (sclass.IsSameAs(
"SPOGRD")) sclass_sub =
"DMPGRD";
3188 if (sclass.IsSameAs(
"FSHHAV")) sclass_sub =
"FSHFAC";
3190 if (sclass.IsSameAs(
"OFSPRD")) sclass_sub =
"CTNARE";
3193 S57Obj *pobj =
new S57Obj();
3195 pobj->Index = iobject;
3198 strncpy(u, sclass_sub.mb_str(), 199);
3200 memcpy(pobj->FeatureName, u, 7);
3202 pobj->attVal =
new wxArrayOfS57attVal();
3206 for (
int jattr = 0; jattr < pobject->n_attributes; jattr++) {
3207 unsigned char *curr_attr = pab.GetNextAttr();
3209 unsigned char iattr = *curr_attr;
3211 wxString sattr = pDict->GetAttrName(iattr);
3213 char vtype = pDict->GetAttrType(iattr);
3215 unsigned char *aval = curr_attr + 1;
3228 S57attVal *pattValTmp =
new S57attVal;
3233 pAVI = (
int *)malloc(
sizeof(
int));
3235 pattValTmp->valType = OGR_INT;
3236 pattValTmp->value = pAVI;
3239 pb = (
unsigned char *)aval;
3240 pAVI = (
int *)malloc(
sizeof(
int));
3242 pattValTmp->valType = OGR_INT;
3243 pattValTmp->value = pAVI;
3246 pw = (
unsigned short *)aval;
3250 pAVR = (
double *)malloc(
sizeof(
double));
3251 *pAVR = dival / 10.;
3252 pattValTmp->valType = OGR_REAL;
3253 pattValTmp->value = pAVR;
3257 pAVI = (
int *)malloc(
sizeof(
int));
3259 pattValTmp->valType = OGR_INT;
3260 pattValTmp->value = pAVI;
3264 pAVS = strdup((
char *)aval);
3265 pattValTmp->valType = OGR_STR;
3266 pattValTmp->value = pAVS;
3270 pAVS = strdup((
const char *)&aval[3]);
3271 pattValTmp->valType = OGR_STR;
3272 pattValTmp->value = pAVS;
3275 pb = (
unsigned char *)aval;
3276 unsigned char nl = *pb++;
3279 for (
int i = 0; i < nl; i++) {
3280 sprintf(vi,
"%d,", *pb++);
3283 if (strlen(val)) val[strlen(val) - 1] = 0;
3286 pattValTmp->valType = OGR_STR;
3287 pattValTmp->value = pAVS;
3291 pAVR = (
double *)malloc(
sizeof(
double));
3295 float __attribute__((aligned(16))) tf1;
3296 unsigned char *pucf = (
unsigned char *)pf;
3298 memcpy(&tf1, pucf, sizeof(
float));
3304 pattValTmp->valType = OGR_REAL;
3305 pattValTmp->value = pAVR;
3313 if (sattr.IsSameAs(
"COLMAR")) {
3314 translate_colmar(sclass, pattValTmp);
3319 if (pattValTmp->valType == OGR_INT &&
3320 (sattr.IsSameAs(
"QUASOU") || sattr.IsSameAs(
"CATLIT"))) {
3321 int v = *(
int *)pattValTmp->value;
3322 free(pattValTmp->value);
3323 sprintf(val,
"%d", v);
3325 pattValTmp->valType = OGR_STR;
3326 pattValTmp->value = pAVS;
3330 if (sclass.IsSameAs(
"$AREAS") && (vtype ==
'S') &&
3331 sattr.IsSameAs(
"$SCODE")) {
3332 if (!strcmp((
char *)pattValTmp->value,
"II25")) {
3333 free(pattValTmp->value);
3334 pattValTmp->value = strdup(
"BACKGROUND");
3339 if (sattr.IsSameAs(
"RECDAT") || sattr.IsSameAs(
"_dgdat")) {
3340 if (sclass_sub.IsSameAs(
"M_COVR") && (vtype ==
'S')) {
3341 wxString pub_date((
char *)pattValTmp->value, wxConvUTF8);
3344 upd.ParseFormat(pub_date,
"%Y%m%d");
3345 if (!upd.IsValid()) upd.ParseFormat(
"20000101",
"%Y%m%d");
3348 pub_date.Truncate(4);
3351 pub_date.ToLong(&nyear);
3357 if (sclass_sub.IsSameAs(
"M_COVR") && (vtype ==
'R')) {
3358 if (sattr.IsSameAs(
"_wgsox")) {
3359 tmp_transform_x = *(
double *)pattValTmp->value;
3360 if (fabs(tmp_transform_x) > 1.0)
3361 m_CIB.b_have_offsets =
true;
3362 }
else if (sattr.IsSameAs(
"_wgsoy")) {
3363 tmp_transform_y = *(
double *)pattValTmp->value;
3364 if (fabs(tmp_transform_y) > 1.0) m_CIB.b_have_offsets =
true;
3369 wxASSERT(sattr.Len() == 6);
3370 wxCharBuffer dbuffer = sattr.ToUTF8();
3371 if (dbuffer.data()) {
3373 (
char *)realloc(pobj->att_array, 6 * (pobj->n_attr + 1));
3375 strncpy(pobj->att_array + (6 *
sizeof(
char) * pobj->n_attr),
3379 pobj->attVal->Add(pattValTmp);
3393 if (1 == geomtype) {
3394 if ((!strncmp(pobj->FeatureName,
"LIT", 3)) ||
3395 (!strncmp(pobj->FeatureName,
"LIGHTS", 6)) ||
3396 (!strncmp(pobj->FeatureName,
"BCN", 3)) ||
3397 (!strncmp(pobj->FeatureName,
"_slgto", 6)) ||
3398 (!strncmp(pobj->FeatureName,
"_boygn", 6)) ||
3399 (!strncmp(pobj->FeatureName,
"_bcngn", 6)) ||
3400 (!strncmp(pobj->FeatureName,
"_extgn", 6)) ||
3401 (!strncmp(pobj->FeatureName,
"TOWERS", 6)) ||
3402 (!strncmp(pobj->FeatureName,
"BOY", 3))) {
3403 bool bfound_OBJNAM = (pobj->GetAttributeIndex(
"OBJNAM") != -1);
3404 bool bfound_INFORM = (pobj->GetAttributeIndex(
"INFORM") != -1);
3406 if ((!bfound_OBJNAM) && (bfound_INFORM))
3408 char *patl = pobj->att_array;
3409 for (
int i = 0; i < pobj->n_attr; i++) {
3410 if (!strncmp(patl,
"INFORM", 6)) {
3411 memcpy(patl,
"OBJNAM", 6);
3423 pobj->Primitive_type = GEO_AREA;
3426 if (sclass_sub.IsSameAs(
"M_COVR")) {
3430 GetCoverSet()->Find_MCD(cell_index, iobject, subcell);
3431 if (NULL == pmcd_look)
3438 pmcd->m_cell_index = cell_index;
3439 pmcd->m_object_id = iobject;
3440 pmcd->m_subcell = subcell;
3443 pmcd->user_xoff = 0;
3444 pmcd->user_yoff = 0;
3445 pmcd->m_buser_offsets =
false;
3448 pmcd->m_npub_year = npub_year;
3451 int npta = xgeom->contour_array[0];
3452 float_2Dpt *geoPt =
new float_2Dpt[npta + 2];
3453 float_2Dpt *ppt = geoPt;
3455 pmcd->m_covr_lon_max = -1000.;
3456 pmcd->m_covr_lon_min = 1000.;
3457 pmcd->m_covr_lat_max = -1000.;
3458 pmcd->m_covr_lat_min = 1000.;
3462 for (
int ip = 0; ip < npta; ip++) {
3464 p.x = (int)xgeom->vertex_array[ip + 1].m_x;
3465 p.y = (int)xgeom->vertex_array[ip + 1].m_y;
3467 Transform(&p, 0, 0, &lat,
3472 pmcd->m_covr_lon_max = wxMax(pmcd->m_covr_lon_max, lon);
3473 pmcd->m_covr_lon_min = wxMin(pmcd->m_covr_lon_min, lon);
3474 pmcd->m_covr_lat_max = wxMax(pmcd->m_covr_lat_max, lat);
3475 pmcd->m_covr_lat_min = wxMin(pmcd->m_covr_lat_min, lat);
3479 pmcd->m_nvertices = npta;
3480 pmcd->pvertices = geoPt;
3482 pmcd->m_covr_bbox.Set(pmcd->m_covr_lat_min, pmcd->m_covr_lon_min,
3483 pmcd->m_covr_lat_max, pmcd->m_covr_lon_max);
3487 pmcd->transform_WGS84_offset_x = tmp_transform_x;
3488 pmcd->transform_WGS84_offset_y = tmp_transform_y;
3490 pmcd->m_centerlat_cos = cos(
3491 ((pmcd->m_covr_lat_min + pmcd->m_covr_lat_max) / 2.) * PI / 180.);
3494 GetCoverSet()->Add_Update_MCD(pmcd);
3499 if (pmcd_look->m_buser_offsets) {
3500 m_CIB.b_have_user_offsets =
true;
3502 m_CIB.user_xoff = pmcd_look->user_xoff;
3503 m_CIB.user_yoff = pmcd_look->user_yoff;
3510 m_pcovr_array_loaded.Add(pmcd);
3513 unsigned int n = pmcd->m_nvertices;
3514 double *pts =
new double[2 * n];
3517 for (
size_t i = 0; i < 2 * n; i++)
3518 pts[i] = ((
float *)pmcd->pvertices)[i];
3522 if (LLRegion::PointsCCW(n, pts))
3523 for (
size_t i = 0; i < n; i++)
3524 if (pts[2 * i + 1] < 0) pts[2 * i + 1] += 360;
3527 LLRegion rgn_covr(n, pts);
3528 m_region.Union(rgn_covr);
3536 m_CIB.m_cell_mcovr_list.Append(pmcd);
3540 pobj->x = (xgeom->xmin + xgeom->xmax) / 2.;
3541 pobj->y = (xgeom->ymin + xgeom->ymax) / 2.;
3544 pobj->m_n_lsindex = xgeom->n_vector_indices;
3545 pobj->m_lsindex_array =
3546 xgeom->pvector_index;
3547 pobj->m_n_edge_max_points = 0;
3550 if (m_CIB.b_have_offsets || m_CIB.b_have_user_offsets) {
3553 pc.x = (
short unsigned int)pobj->x;
3554 pc.y = (
short unsigned int)pobj->y;
3555 Transform(&pc, 0., 0., &latc, &lonc);
3557 M_COVR_Desc *pmcd = FindM_COVR_InWorkingSet(latc, lonc);
3559 trans_WGS84_offset_x = pmcd->user_xoff;
3560 trans_WGS84_offset_y = pmcd->user_yoff;
3565 double lat1, lon1, lat2, lon2;
3568 p.x = (int)xgeom->xmin;
3569 p.y = (int)xgeom->ymin;
3570 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat1, &lon1);
3571 xgeom->ref_lat = lat1;
3572 xgeom->ref_lon = lon1;
3574 p.x = (int)xgeom->xmax;
3575 p.y = (int)xgeom->ymax;
3576 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat2, &lon2);
3577 pobj->BBObj.Set(lat1, lon1, lat2, lon2);
3582 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat1, &lon1);
3590 xgeom->x_rate = m_CIB.transform_x_rate;
3591 xgeom->x_offset = m_CIB.transform_x_origin - trans_WGS84_offset_x;
3592 xgeom->y_rate = m_CIB.transform_y_rate;
3593 xgeom->y_offset = m_CIB.transform_y_origin - trans_WGS84_offset_y;
3595 pobj->pPolyTessGeo =
new PolyTessGeo(xgeom);
3602 pobj->Primitive_type = GEO_POINT;
3605 pobj->x = xgeom->pointx;
3606 pobj->y = xgeom->pointy;
3610 p.x = xgeom->pointx;
3611 p.y = xgeom->pointy;
3612 Transform(&p, 0., 0., &lat, &lon);
3615 if (m_CIB.b_have_offsets || m_CIB.b_have_user_offsets) {
3616 M_COVR_Desc *pmcd = FindM_COVR_InWorkingSet(lat, lon);
3618 trans_WGS84_offset_x = pmcd->user_xoff;
3619 trans_WGS84_offset_y = pmcd->user_yoff;
3624 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat, &lon);
3634 double llsize = 1e-3 / view_scale_ppm;
3636 pobj->BBObj.Set(lat, lon, lat, lon);
3637 pobj->BBObj.EnLarge(llsize);
3644 pobj->Primitive_type = GEO_POINT;
3647 double lat1, lon1, lat2, lon2;
3650 p.x = (int)xgeom->xmin;
3651 p.y = (int)xgeom->ymin;
3652 Transform(&p, 0., 0., &lat1, &lon1);
3654 p.x = (int)xgeom->xmax;
3655 p.y = (int)xgeom->ymax;
3656 Transform(&p, 0., 0., &lat2, &lon2);
3657 pobj->BBObj.Set(lat1, lon1, lat2, lon2);
3660 pobj->x = (xgeom->xmin + xgeom->xmax) / 2.;
3661 pobj->y = (xgeom->ymin + xgeom->ymax) / 2.;
3663 OGRMultiPoint *pGeo = (OGRMultiPoint *)xgeom->pogrGeom;
3664 pobj->npt = pGeo->getNumGeometries();
3666 pobj->geoPtz = (
double *)malloc(pobj->npt * 3 *
sizeof(
double));
3667 pobj->geoPtMulti = (
double *)malloc(pobj->npt * 2 *
sizeof(
double));
3669 double *pdd = pobj->geoPtz;
3670 double *pdl = pobj->geoPtMulti;
3672 for (
int ip = 0; ip < pobj->npt; ip++) {
3673 OGRPoint *ppt = (OGRPoint *)(pGeo->getGeometryRef(ip));
3676 p.x = (int)ppt->getX();
3677 p.y = (int)ppt->getY();
3678 double depth = ppt->getZ();
3683 double snd_trans_x = 0.;
3684 double snd_trans_y = 0.;
3687 if (m_CIB.b_have_user_offsets) {
3689 Transform(&p, 0., 0., &lats, &lons);
3691 M_COVR_Desc *pmcd = FindM_COVR_InWorkingSet(lats, lons);
3694 snd_trans_x = pmcd->user_xoff;
3695 snd_trans_y = pmcd->user_yoff;
3699 east -= pmcd->user_xoff / m_CIB.transform_x_rate;
3700 north -= pmcd->user_yoff / m_CIB.transform_y_rate;
3710 Transform(&p, snd_trans_x, snd_trans_y, &lat1, &lon1);
3718 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat1, &lon1);
3728 pobj->Primitive_type = GEO_LINE;
3730 pobj->npt = xgeom->n_max_vertex;
3731 pobj->geoPt = (pt *)xgeom->vertex_array;
3732 xgeom->vertex_array = NULL;
3735 pobj->x = (xgeom->xmin + xgeom->xmax) / 2.;
3736 pobj->y = (xgeom->ymin + xgeom->ymax) / 2.;
3739 pobj->m_n_lsindex = xgeom->n_vector_indices;
3740 pobj->m_lsindex_array =
3741 xgeom->pvector_index;
3742 pobj->m_n_edge_max_points = 0;
3745 if (m_CIB.b_have_offsets || m_CIB.b_have_user_offsets) {
3748 pc.x = (
short unsigned int)pobj->x;
3749 pc.y = (
short unsigned int)pobj->y;
3750 Transform(&pc, 0., 0., &latc, &lonc);
3752 M_COVR_Desc *pmcd = FindM_COVR_InWorkingSet(latc, lonc);
3754 trans_WGS84_offset_x = pmcd->user_xoff;
3755 trans_WGS84_offset_y = pmcd->user_yoff;
3760 double lat1, lon1, lat2, lon2;
3763 p.x = (int)xgeom->xmin;
3764 p.y = (int)xgeom->ymin;
3765 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat1, &lon1);
3767 p.x = (int)xgeom->xmax;
3768 p.y = (int)xgeom->ymax;
3769 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat2, &lon2);
3770 pobj->BBObj.Set(lat1, lon1, lat2, lon2);
3775 Transform(&p, trans_WGS84_offset_x, trans_WGS84_offset_y, &lat1, &lon1);
3784 pobj->Primitive_type = GEO_PRIM;
3791 if (!strncmp(pobj->FeatureName,
"OBSTRN", 6) ||
3792 !strncmp(pobj->FeatureName,
"WRECKS", 6) ||
3793 !strncmp(pobj->FeatureName,
"DEPCNT", 6) ||
3794 !strncmp(pobj->FeatureName,
"UWTROC", 6)) {
3795 pobj->m_bcategory_mutable =
true;
3797 pobj->m_bcategory_mutable =
false;
3810 if (geomtype != 4)
delete xgeom;
3814 m_CIB.transform_x_rate *
3815 (mercator_k0 * WGS84_semimajor_axis_meters / CM93_semimajor_axis_meters);
3817 m_CIB.transform_y_rate *
3818 (mercator_k0 * WGS84_semimajor_axis_meters / CM93_semimajor_axis_meters);
3820 m_CIB.transform_x_origin *
3821 (mercator_k0 * WGS84_semimajor_axis_meters / CM93_semimajor_axis_meters);
3823 m_CIB.transform_y_origin *
3824 (mercator_k0 * WGS84_semimajor_axis_meters / CM93_semimajor_axis_meters);
3828 pobj->x_origin -= trans_WGS84_offset_x;
3829 pobj->y_origin -= trans_WGS84_offset_y;
3832 pobj->auxParm3 = CHART_TYPE_CM93;
3838M_COVR_Desc *cm93chart::FindM_COVR_InWorkingSet(
double lat,
double lon) {
3841 if (m_CIB.m_cell_mcovr_list.GetCount() == 1) {
3842 wxList_Of_M_COVR_DescNode *node0 = m_CIB.m_cell_mcovr_list.GetFirst();
3843 if (node0) ret = node0->GetData();
3845 wxList_Of_M_COVR_DescNode *node = m_CIB.m_cell_mcovr_list.GetFirst();
3849 if (G_PtInPolygon_FL(pmcd->pvertices, pmcd->m_nvertices, lon, lat)) {
3854 node = node->GetNext();
3862wxPoint2DDouble cm93chart::FindM_COVROffset(
double lat,
double lon) {
3863 wxPoint2DDouble ret(0., 0.);
3866 wxList_Of_M_COVR_DescNode *node0 = m_CIB.m_cell_mcovr_list.GetFirst();
3869 ret.m_x = pmcd0->transform_WGS84_offset_x;
3870 ret.m_y = pmcd0->transform_WGS84_offset_y;
3874 if (m_CIB.m_cell_mcovr_list.GetCount() > 1) {
3875 wxList_Of_M_COVR_DescNode *node = m_CIB.m_cell_mcovr_list.GetFirst();
3879 if (G_PtInPolygon_FL(pmcd->pvertices, pmcd->m_nvertices, lon, lat)) {
3880 ret.m_x = pmcd->transform_WGS84_offset_x;
3881 ret.m_y = pmcd->transform_WGS84_offset_y;
3885 node = node->GetNext();
3893InitReturn cm93chart::CreateHeaderDataFromCM93Cell(
void) {
3895 wxFileName fn(m_FullPath);
3896 wxString ext = fn.GetExt();
3899 switch ((ext.mb_str())[(
size_t)0]) {
3929 m_Chart_Scale =
scale;
3935 switch (m_Chart_Scale) {
3937 bproc = m_pManager->m_bfoundZ;
3940 bproc = m_pManager->m_bfoundA;
3943 bproc = m_pManager->m_bfoundB;
3946 bproc = m_pManager->m_bfoundC;
3949 bproc = m_pManager->m_bfoundD;
3952 bproc = m_pManager->m_bfoundE;
3955 bproc = m_pManager->m_bfoundF;
3958 bproc = m_pManager->m_bfoundG;
3962 if (bproc)
return INIT_FAIL_NOERROR;
3965 switch (m_Chart_Scale) {
3967 m_pManager->m_bfoundZ =
true;
3970 m_pManager->m_bfoundA =
true;
3973 m_pManager->m_bfoundB =
true;
3976 m_pManager->m_bfoundC =
true;
3979 m_pManager->m_bfoundD =
true;
3982 m_pManager->m_bfoundE =
true;
3985 m_pManager->m_bfoundF =
true;
3988 m_pManager->m_bfoundG =
true;
3994 m_FullExtent.ELON = 179.0;
3995 m_FullExtent.WLON = -179.0;
3996 m_FullExtent.NLAT = 80.0;
3997 m_FullExtent.SLAT = -80.0;
3998 m_bExtentSet =
true;
4002 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
4003 *m_pCOVRTablePoints = 4;
4004 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
4005 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
4009 *pfe++ = m_FullExtent.NLAT;
4010 *pfe++ = m_FullExtent.WLON;
4012 *pfe++ = m_FullExtent.NLAT;
4013 *pfe++ = m_FullExtent.ELON;
4015 *pfe++ = m_FullExtent.SLAT;
4016 *pfe++ = m_FullExtent.ELON;
4018 *pfe++ = m_FullExtent.SLAT;
4019 *pfe++ = m_FullExtent.WLON;
4024void cm93chart::ProcessMCOVRObjects(
int cell_index,
char subcell) {
4027 Object *pobject = m_CIB.pobject_block;
4030 while (iObj < m_CIB.m_nfeature_records) {
4031 if ((pobject != NULL)) {
4033 int iclass = pobject->otype;
4035 wxString sclass = m_pDict->GetClassName(iclass);
4037 if (sclass.IsSameAs(
"_m_sor")) {
4039 m_pcovr_set->Find_MCD(cell_index, iObj, (
int)subcell);
4041 Extended_Geometry *xgeom = BuildGeom(pobject, NULL, iObj);
4045 double tmp_transform_x = 0.;
4046 double tmp_transform_y = 0.;
4049 for (
int jattr = 0; jattr < pobject->n_attributes; jattr++) {
4050 unsigned char *curr_attr = pab.GetNextAttr();
4051 unsigned char iattr = *curr_attr;
4052 wxString sattr = m_pDict->GetAttrName(iattr);
4053 char vtype = m_pDict->GetAttrType(iattr);
4054 unsigned char *aval = curr_attr + 1;
4057 float *pf = (
float *)aval;
4059 float __attribute__((aligned(16))) tf1;
4060 unsigned char *pucf = (
unsigned char *)pf;
4061 memcpy(&tf1, pucf, sizeof(
float));
4062 if (sattr.IsSameAs("_wgsox"))
4063 tmp_transform_x = tf1;
4064 else if (sattr.IsSameAs("_wgsoy"))
4065 tmp_transform_y = tf1;
4067 if (sattr.IsSameAs(
"_wgsox"))
4068 tmp_transform_x = *pf;
4069 else if (sattr.IsSameAs(
"_wgsoy"))
4070 tmp_transform_y = *pf;
4076 if (NULL != xgeom) {
4082 pmcd->m_cell_index = cell_index;
4083 pmcd->m_object_id = iObj;
4084 pmcd->m_subcell = (int)subcell;
4087 int npta = xgeom->contour_array[0];
4088 float_2Dpt *geoPt =
new float_2Dpt[npta + 2];
4089 float_2Dpt *ppt = geoPt;
4093 pmcd->m_covr_lon_max = -1000.;
4094 pmcd->m_covr_lon_min = 1000.;
4095 pmcd->m_covr_lat_max = -1000.;
4096 pmcd->m_covr_lat_min = 1000.;
4098 for (
int ip = 0; ip < npta; ip++) {
4100 p.x = (int)xgeom->vertex_array[ip + 1].m_x;
4101 p.y = (int)xgeom->vertex_array[ip + 1].m_y;
4103 Transform(&p, 0., 0., &lat, &lon);
4107 pmcd->m_covr_lon_max = wxMax(pmcd->m_covr_lon_max, lon);
4108 pmcd->m_covr_lon_min = wxMin(pmcd->m_covr_lon_min, lon);
4109 pmcd->m_covr_lat_max = wxMax(pmcd->m_covr_lat_max, lat);
4110 pmcd->m_covr_lat_min = wxMin(pmcd->m_covr_lat_min, lat);
4114 pmcd->m_nvertices = npta;
4115 pmcd->pvertices = geoPt;
4117 pmcd->m_covr_bbox.Set(pmcd->m_covr_lat_min, pmcd->m_covr_lon_min,
4118 pmcd->m_covr_lat_max, pmcd->m_covr_lon_max);
4122 pmcd->transform_WGS84_offset_x = tmp_transform_x;
4123 pmcd->transform_WGS84_offset_y = tmp_transform_y;
4125 pmcd->m_centerlat_cos =
4126 cos(((pmcd->m_covr_lat_min + pmcd->m_covr_lat_max) / 2.) * PI /
4130 m_pcovr_set->Add_Update_MCD(pmcd);
4133 free(xgeom->pvector_index);
4149bool cm93chart::UpdateCovrSet(
ViewPort *vpt) {
4151 std::vector<int> vpcells = GetVPCellArray(*vpt);
4156 for (
unsigned int i = 0; i < vpcells.size(); i++) {
4159 if (!m_pcovr_set->IsCovrLoaded(vpcells[i])) {
4160 if (loadcell_in_sequence(vpcells[i],
'0')) {
4161 ProcessMCOVRObjects(vpcells[i],
'0');
4164 m_pcovr_set->m_cell_hash[vpcells[i]] = 1;
4166 char loadcell_key =
'A';
4170 while (loadcell_in_sequence(vpcells[i], loadcell_key)) {
4173 ProcessMCOVRObjects(vpcells[i], loadcell_key);
4186bool cm93chart::IsPointInLoadedM_COVR(
double xc,
double yc) {
4189 return m_region.Contains(yc, xc);
4191 for (
unsigned int im = 0; im < m_pcovr_array_loaded.GetCount(); im++) {
4192 if (G_PtInPolygon_FL(m_pcovr_array_loaded[im]->pvertices,
4193 m_pcovr_array_loaded[im]->m_nvertices, xc, yc))
4200LLRegion cm93chart::GetValidRegion() {
return m_region; }
4202int cm93chart::loadcell_in_sequence(
int cellindex,
char subcell) {
4203 int rv = loadsubcell(cellindex, subcell);
4208int cm93chart::loadsubcell(
int cellindex, wxChar sub_char) {
4211 int ilat = cellindex / 10000;
4212 int ilon = cellindex % 10000;
4215 double dlat = m_dval / 3.;
4216 double dlon = m_dval / 3.;
4218 Get_CM93_Cell_Origin(cellindex, GetNativeScale(), &lat, &lon);
4220 "\n Attempting loadcell %d scale %lc, sub_char %lc at lat: %g/%g "
4222 cellindex, wxChar(m_scalechar[0]), sub_char, lat, lat + dlat, lon,
4226 int jlat = (int)(((ilat - 30) / m_dval) * m_dval) + 30;
4227 int jlon = (int)((ilon / m_dval) * m_dval);
4229 int ilatroot = (((ilat - 30) / 60) * 60) + 30;
4230 int ilonroot = (ilon / 60) * 60;
4233 file.Printf(
"%04d%04d.", jlat, jlon);
4234 file += m_scalechar;
4243 bool b_useNoFind =
true;
4244 if (m_noFindArray.GetCount() > 500) b_useNoFind =
false;
4247 fileroot.Printf(
"%04d%04d", ilatroot, ilonroot);
4248 appendOSDirSep(&fileroot);
4249 fileroot.append(m_scalechar);
4250 appendOSDirSep(&fileroot);
4251 wxString key = fileroot;
4253 fileroot.Prepend(m_prefix);
4255 file.Prepend(fileroot);
4259 strncpy(sfile, file.mb_str(), 199);
4261 printf(
" filename: %s\n", sfile);
4264 bool bfound =
false;
4267 if (m_noFindArray.Index(key) == wxNOT_FOUND) {
4268 if (::wxFileExists(file))
4271 m_noFindArray.Add(key);
4274 if (::wxFileExists(file)) bfound =
true;
4280 if (m_noFindArray.Index(key +
".xz") == wxNOT_FOUND) {
4281 if (::wxFileExists(file +
".xz")) {
4282 compfile = file +
".xz";
4285 m_noFindArray.Add(key +
".xz");
4288 if (::wxFileExists(file +
".xz")) compfile = file +
".xz";
4293 if (!bfound && !compfile.Length()) {
4295 wxString new_scalechar = m_scalechar.Lower();
4298 file1.Printf(
"%04d%04d.", jlat, jlon);
4299 file1 += new_scalechar;
4300 file1[0] = sub_char;
4302 fileroot.Printf(
"%04d%04d", ilatroot, ilonroot);
4303 appendOSDirSep(&fileroot);
4304 fileroot.append(new_scalechar);
4305 appendOSDirSep(&fileroot);
4309 fileroot.Prepend(m_prefix);
4311 file1.Prepend(fileroot);
4314 if (m_noFindArray.Index(key) == wxNOT_FOUND) {
4315 if (::wxFileExists(file1)) {
4319 m_noFindArray.Add(key);
4323 if (::wxFileExists(file1)) {
4331 if (m_noFindArray.Index(key +
".xz") == wxNOT_FOUND) {
4332 if (::wxFileExists(file1 +
".xz"))
4333 compfile = file1 +
".xz";
4335 m_noFindArray.Add(key +
".xz");
4338 if (::wxFileExists(file1 +
".xz")) compfile = file1 +
".xz";
4344 printf(
"noFind count: %d\n", (
int)m_noFindArray.GetCount());
4347 if (!bfound && !compfile.Length())
return 0;
4351 wxString msg(
"Loading CM93 cell ");
4357 m_LastFileName = file;
4360 if (compfile.Length()) {
4361 file = wxFileName::CreateTempFileName(wxFileName(compfile).GetFullName());
4362 if (!DecompressXZFile(compfile, file)) {
4370 strncpy(str, msg.mb_str(), 255);
4372 printf(
" %s\n", str);
4376 if (!Ingest_CM93_Cell((
const char *)file.mb_str(), &m_CIB)) {
4377 wxString msg(
" cm93chart Error ingesting ");
4381 if (compfile.Length()) wxRemoveFile(file);
4385 if (compfile.Length()) wxRemoveFile(file);
4390void cm93chart::SetUserOffsets(
int cell_index,
int object_id,
int subcell,
4391 int xoff,
int yoff) {
4392 M_COVR_Desc *pmcd = GetCoverSet()->Find_MCD(cell_index, object_id, subcell);
4394 pmcd->user_xoff = xoff;
4395 pmcd->user_yoff = yoff;
4396 pmcd->m_buser_offsets =
true;
4400wxPoint *cm93chart::GetDrawBuffer(
int nSize) {
4402 if (nSize > m_nDrawBufferSize) {
4403 wxPoint *tmp = m_pDrawBuffer;
4405 (wxPoint *)realloc(m_pDrawBuffer,
sizeof(wxPoint) * (nSize + 1));
4406 if (NULL == m_pDrawBuffer) {
4410 m_nDrawBufferSize = nSize + 1;
4412 return m_pDrawBuffer;
4419cm93manager::cm93manager(
void) {
4432cm93manager::~cm93manager(
void) {
delete m_pcm93Dict; }
4434bool cm93manager::Loadcm93Dictionary(
const wxString &name) {
4437 m_pcm93Dict = FindAndLoadDict(name);
4440 wxLogMessage(
" Cannot load CM93 Dictionary.");
4444 if (!m_pcm93Dict->IsOk()) {
4445 wxLogMessage(
" Error in loading CM93 Dictionary.");
4451 }
else if (!m_pcm93Dict->IsOk()) {
4452 wxLogMessage(
" CM93 Dictionary is not OK.");
4466 wxFileName fn(file);
4467 wxString path = fn.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
4471 while (i < path.Len()) {
4472 target.Append(path[i]);
4473 if (path[i] == fn.GetPathSeparator()) {
4474 if (pdict->LoadDictionary(target)) {
4478 if (pdict->LoadDictionary(target +
"CM93ATTR")) {
4487 strncpy(t, target.mb_str(), 99);
4489 if (retval == NULL)
delete pdict;
4497cm93compchart::cm93compchart() {
4498 m_ChartType = CHART_TYPE_CM93COMP;
4499 m_pDictComposite = NULL;
4502 m_FullPath =
"CM93";
4505 m_Description =
"CM93Composite";
4508 m_datum_str =
"WGS84";
4509 m_SoundingsDatum =
"Unknown";
4511 for (
int i = 0; i < 8; i++) m_pcm93chart_array[i] = NULL;
4513 m_pcm93chart_current = NULL;
4520 SetSpecialOutlineCellIndex(0, 0, 0);
4521 m_last_cell_adjustvp = NULL;
4526cm93compchart::~cm93compchart() {
4531 for (
int i = 0; i < 8; i++)
delete m_pcm93chart_array[i];
4533 delete m_pDictComposite;
4538InitReturn cm93compchart::Init(
const wxString &name, ChartInitFlag flags) {
4541 wxFileName fn(name);
4547 if (!fn.FileExists()) {
4549 if (wxDir::Exists(name)) {
4551 appendOSDirSep(&target);
4553 appendOSDirSep(&path);
4555 wxString msg(
" CM93Composite Chart Init cannot find ");
4558 return INIT_FAIL_REMOVE;
4563 path = fn.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
4567 wxFileName file_path(path);
4568 file_path.RemoveLastDir();
4569 file_path.RemoveLastDir();
4571 target = file_path.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
4574 m_prefixComposite = target;
4576 wxString msg(
"CM93Composite Chart Root is ");
4577 msg.Append(m_prefixComposite);
4580 if (flags == THUMB_ONLY) {
4586 if (flags == HEADER_ONLY)
return CreateHeaderData();
4589 if (!m_pDictComposite) {
4590 if (!m_pDictComposite)
4591 m_pDictComposite = FindAndLoadDictFromDir(path);
4593 if (!m_pDictComposite) {
4595 " CM93Composite Chart Init cannot locate CM93 dictionary.");
4596 return INIT_FAIL_REMOVE;
4601 SetColorScheme(m_global_color_scheme,
false);
4603 bReadyToRender =
true;
4608void cm93compchart::Activate(
void) {
4635void cm93compchart::Deactivate(
void) {
4642double scale_breaks[] = {
4657int cm93compchart::GetCMScaleFromVP(
const ViewPort &vpt) {
4660 double scale_mpp_adj = scale_mpp;
4662 double scale_breaks_adj[7];
4664 for (
int i = 0; i < 7; i++) scale_breaks_adj[i] = scale_breaks[i];
4666 if (g_cm93_zoom_factor) {
4669 double efactor = ( double ) ( g_cm93_zoom_factor ) * ( .176 / 7. );
4670 for (
int i=0 ; i < 7 ; i++ )
4672 double efr = efactor * ( 7 - i );
4673 scale_breaks_adj[i] = scale_breaks[i] * pow ( 10., efr );
4675 printf (
"g_cm93_zoom_factor: %2d efactor: %6g efr:%6g, scale_breaks[i]:%6g scale_breaks_adj[i]: %6g\n",
4676 g_cm93_zoom_factor, efactor, efr, scale_breaks[i], scale_breaks_adj[i] );
4680 double efr = (double)g_cm93_zoom_factor * pow(scale_mpp, -.05);
4681 scale_mpp_adj *= pow(.6, efr);
4685 int cmscale_calc = 7;
4687 while (cmscale_calc > 0) {
4688 if (scale_mpp_adj < scale_breaks_adj[brk_index])
break;
4695 double zoom_factor = scale_breaks[7 - cmscale_calc] / vpt.
chart_scale;
4696 if (zoom_factor > 4.0) {
4697 if (cmscale_calc < 7) cmscale_calc++;
4700 return cmscale_calc;
4703void cm93compchart::SetVPParms(
const ViewPort &vpt) {
4706 int cmscale = GetCMScaleFromVP(vpt);
4707 m_cmscale = PrepareChartScale(vpt, cmscale,
false);
4711 if (m_pcm93chart_array[cmscale]) {
4712 if (!m_EdDate.IsValid() ||
4713 !m_pcm93chart_array[cmscale]->GetEditionDate().IsValid() ||
4714 m_pcm93chart_array[cmscale]->GetEditionDate().IsLaterThan(m_EdDate))
4715 m_EdDate = m_pcm93chart_array[cmscale]->GetEditionDate();
4719int cm93compchart::PrepareChartScale(
const ViewPort &vpt,
int cmscale,
4722 printf(
"\non SetVPParms, cmscale:%d, %c\n", cmscale,
4723 (
char)(
'A' + cmscale - 1));
4726 bool cellscale_is_useable =
false;
4727 bool b_nochart =
false;
4729 while (!cellscale_is_useable) {
4731 while (NULL == m_pcm93chart_array[cmscale]) {
4732 if (Is_CM93Cell_Present(m_prefixComposite, vpt.
clat, vpt.
clon, cmscale)) {
4734 printf(
" chart %c at VP clat/clon is present\n",
4735 (
char)(
'A' + cmscale - 1));
4737 m_pcm93chart_array[cmscale] =
new cm93chart();
4739 ext = (wxChar)(
'A' + cmscale - 1);
4740 if (cmscale == 0) ext =
'Z';
4742 wxString file_dummy =
"CM93.";
4745 m_pcm93chart_array[cmscale]->SetCM93Dict(m_pDictComposite);
4746 m_pcm93chart_array[cmscale]->SetCM93Prefix(m_prefixComposite);
4747 m_pcm93chart_array[cmscale]->SetCM93Manager(m_pcm93mgr);
4749 m_pcm93chart_array[cmscale]->SetColorScheme(m_global_color_scheme);
4750 m_pcm93chart_array[cmscale]->Init(file_dummy, FULL_INIT);
4751 }
else if (cmscale == 0) {
4758 " CM93 finds no chart of any scale present at Lat/Lon %g %g\n",
4768 printf(
" no %c scale chart present, adjusting cmscale to %c\n",
4769 (
char)(
'A' + cmscale), (
char)(
'A' + cmscale - 1));
4773 m_pcm93chart_current = m_pcm93chart_array[cmscale];
4776 if (g_bDebugCM93) printf(
" b_nochart return\n");
4778 m_pcm93chart_current = NULL;
4779 for (
int i = 0; i < 8; i++) {
4780 delete m_pcm93chart_array[i];
4781 m_pcm93chart_array[i] = NULL;
4787 if (m_pcm93chart_current) {
4790 m_pcm93chart_current->SetVPParms(vpt);
4794 float yc = vpt.
clat;
4795 float xc = vpt.
clon;
4797 if (!m_pcm93chart_current->GetCoverSet()->GetCoverCount()) {
4799 printf(
" chart %c has no M_COVR\n", (
char)(
'A' + cmscale - 1));
4802 if (m_pcm93chart_current->IsPointInLoadedM_COVR(xc, yc)) {
4804 printf(
" chart %c contains clat/clon\n", (
char)(
'A' + cmscale - 1));
4806 cellscale_is_useable =
true;
4820 else if (vpt.b_quilt && vpt.b_FullScreenQuilt) {
4823 covr_set *pcover = m_pcm93chart_current->GetCoverSet();
4825 bool boverlap =
false;
4826 for (
unsigned int im = 0; im < pcover->GetCoverCount(); im++) {
4829 if (!(vp.GetBBox().IntersectOut(mcd->m_covr_bbox))) {
4834 if (boverlap) cellscale_is_useable =
true;
4838 if (!cellscale_is_useable) {
4846 printf(
" VP is not in M_COVR, adjusting cmscale to %c\n",
4847 (
char)(
'A' + cmscale - 1));
4854 double zoom_factor = scale_breaks[7 - cmscale] / vpt.
chart_scale;
4856 if (zoom_factor > 4.0) {
4859 float yc = vpt.
clat;
4860 float xc = vpt.
clon;
4863 FillScaleArray(vpt.
clat, vpt.
clon);
4864 int new_scale = cmscale;
4865 bool b_found =
false;
4866 while (new_scale <= 7) {
4867 if (m_bScale_Array[new_scale]) {
4868 double new_zoom_factor =
4872 if (new_zoom_factor < 1.0) {
4874 new_scale = cmscale;
4878 if (new_zoom_factor < 4.0) {
4879 if (NULL == m_pcm93chart_array[new_scale]) {
4880 m_pcm93chart_array[new_scale] =
new cm93chart();
4882 ext = (wxChar)(
'A' + new_scale - 1);
4883 if (new_scale == 0) ext =
'Z';
4885 wxString file_dummy =
"CM93.";
4888 m_pcm93chart_array[new_scale]->SetCM93Dict(m_pDictComposite);
4889 m_pcm93chart_array[new_scale]->SetCM93Prefix(m_prefixComposite);
4890 m_pcm93chart_array[new_scale]->SetCM93Manager(m_pcm93mgr);
4892 m_pcm93chart_array[new_scale]->SetColorScheme(
4893 m_global_color_scheme);
4894 m_pcm93chart_array[new_scale]->Init(file_dummy, FULL_INIT);
4897 m_pcm93chart_array[new_scale]->SetVPParms(vpt);
4898 if (m_pcm93chart_array[new_scale]->IsPointInLoadedM_COVR(xc, yc)) {
4907 cmscale = new_scale;
4908 m_pcm93chart_current = m_pcm93chart_array[cmscale];
4918void cm93compchart::FillScaleArray(
double lat,
double lon) {
4919 for (
int cmscale = 0; cmscale < 8; cmscale++)
4920 m_bScale_Array[cmscale] =
4921 Is_CM93Cell_Present(m_prefixComposite, lat, lon, cmscale);
4927wxString cm93compchart::GetPubDate() {
4930 if (NULL != m_pcm93chart_current)
4932 data.Printf(
"%4d", m_current_cell_pub_date);
4938int cm93compchart::GetNativeScale() {
4939 if (m_pcm93chart_current)
4940 return m_pcm93chart_current->GetNativeScale();
4945double cm93compchart::GetNormalScaleMin(
double canvas_scale_factor,
4946 bool b_allow_overzoom) {
4950 if (m_pcm93chart_current) {
4952 if (m_pcm93chart_current->m_last_vp.IsValid()) {
4953 FillScaleArray(m_pcm93chart_current->m_last_vp.clat,
4954 m_pcm93chart_current->m_last_vp.clon);
4958 while (cmscale > 0) {
4959 if (m_bScale_Array[cmscale])
break;
4967 return 20000000. / oz_factor;
4969 return 3000000. / oz_factor;
4971 return 1000000. / oz_factor;
4973 return 200000. / oz_factor;
4975 return 100000. / oz_factor;
4977 return 50000. / oz_factor;
4979 return 20000. / oz_factor;
4983 return 500. / oz_factor;
4989double cm93compchart::GetNormalScaleMax(
double canvas_scale_factor,
4991 return (180. / 360.) * PI * 2 *
4992 (WGS84_semimajor_axis_meters / (canvas_width / canvas_scale_factor));
4996wxPoint GetPixFromLLVP(
double lat,
double lon,
const ViewPort &VPoint) {
4998 double easting, northing;
5000 double s, y3, s0, y30;
5001 double z = WGS84_semimajor_axis_meters * mercator_k0;
5006 if (lon * VPoint.
clon < 0.) {
5014 if (fabs(xlon - VPoint.
clon) > 180.) {
5015 if (xlon > VPoint.
clon)
5020 easting = (xlon - VPoint.
clon) * DEGREE * z;
5022 s = sin(lat * DEGREE);
5023 y3 = (.5 * log((1 + s) / (1 - s))) * z;
5025 s0 = sin(VPoint.
clat * DEGREE);
5026 y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
5027 northing = y3 - y30;
5033 r.x = (int)round((VPoint.
pix_width / 2) + epix);
5034 r.y = (int)round((VPoint.
pix_height / 2) - npix);
5041void cm93compchart::GetValidCanvasRegion(
const ViewPort &VPoint,
5045 VPoint, g_bopengl ? VPoint.rv_rect : screen_region);
5046 *pValidRegion = ret;
5049OCPNRegion cm93compchart::GetValidScreenCanvasRegion(
5057 if (m_pcm93chart_current) {
5058 int chart_native_scale = m_pcm93chart_current->GetNativeScale();
5060 for (
unsigned int im = 0;
5061 im < m_pcm93chart_current->m_pcovr_array_loaded.GetCount(); im++) {
5062 M_COVR_Desc *pmcd = (m_pcm93chart_current->m_pcovr_array_loaded[im]);
5067 if (vp.GetBBox().IntersectOut(pmcd->m_covr_bbox))
continue;
5069 wxPoint *DrawBuf = m_pcm93chart_current->GetDrawBuffer(pmcd->m_nvertices);
5072 ScreenRegion, pmcd->m_nvertices, (
float *)pmcd->pvertices,
5073 chart_native_scale, DrawBuf);
5075 if (rgn_covr.IsOk())
5076 ret_region.Union(rgn_covr);
5085LLRegion cm93compchart::GetValidRegion() {
5086 if (m_pcm93chart_current)
return m_pcm93chart_current->GetValidRegion();
5091bool cm93compchart::RenderRegionViewOnGL(
const wxGLContext &glc,
5094 const LLRegion &Region) {
5100 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region);
5103bool cm93compchart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
5106 const LLRegion &Region) {
5113 bool render_return =
false;
5114 if (m_pcm93chart_current == 0)
return render_return;
5122 if (VPoint.b_quilt) {
5123 LLRegion vpr_empty = Region;
5124 LLRegion chart_region = GetValidRegion();
5143 if (!chart_region.Empty()) vpr_empty.Subtract(chart_region);
5145 if (!vpr_empty.Empty() &&
5149 int cmscale_save = m_cmscale;
5151 LLRegion region_vect[8];
5155 while (!vpr_empty.Empty() && m_cmscale) {
5157 m_cmscale = PrepareChartScale(vp, m_cmscale - 1,
false);
5159 if (m_pcm93chart_current) {
5160 LLRegion sscale_region = GetValidRegion();
5163 region_vect[m_cmscale] = sscale_region;
5164 region_vect[m_cmscale].Intersect(vpr_empty);
5167 vpr_empty.Subtract(sscale_region);
5174 for (
int i = 0; i < 8; i++) {
5175 if (!region_vect[i].Empty()) {
5176 m_cmscale = PrepareChartScale(vp, i,
false);
5177 if (m_pcm93chart_current)
5178 render_return |= m_pcm93chart_current->RenderRegionViewOnGL(
5179 glc, vp, RectRegion, region_vect[i]);
5184 m_cmscale = cmscale_save;
5185 m_pcm93chart_current = m_pcm93chart_array[m_cmscale];
5189 if (m_pcm93chart_current) {
5190 render_return |= m_pcm93chart_current->RenderRegionViewOnGL(
5191 glc, vp, RectRegion, Region);
5192 m_Name = m_pcm93chart_current->GetName();
5197 if (m_pcm93chart_current) {
5198 render_return = m_pcm93chart_current->RenderRegionViewOnGL(
5199 glc, vp, RectRegion, Region);
5200 m_Name = m_pcm93chart_current->GetLastFileName();
5205 if (VPoint.m_projection_type != PROJECTION_MERCATOR)
5206 return render_return;
5208 if (!m_pcm93chart_current)
return render_return;
5211 if (m_cell_index_special_outline) {
5213 glChartCanvas *glc = gFrame->GetPrimaryCanvas()->GetglCanvas();
5220 covr_set *pcover = m_pcm93chart_current->GetCoverSet();
5222 for (
unsigned int im = 0; im < pcover->GetCoverCount(); im++) {
5224 if ((pmcd->m_cell_index == m_cell_index_special_outline) &&
5225 (pmcd->m_object_id == m_object_id_special_outline) &&
5226 (pmcd->m_subcell == m_subcell_special_outline))
5236 float_2Dpt *p = pmcd->pvertices;
5237 wxPoint *pwp = m_pcm93chart_current->GetDrawBuffer(pmcd->m_nvertices);
5239 for (
int ip = 0; ip < pmcd->m_nvertices; ip++) {
5241 if (fabs(plon - VPoint.
clon) > 180.) {
5242 if (plon > VPoint.
clon)
5248 double easting, northing, epix, npix;
5249 toSM(p->y, plon + 360., VPoint.
clat, VPoint.
clon + 360, &easting,
5255 easting -= pmcd->user_xoff;
5258 northing -= pmcd->user_yoff;
5263 pwp[ip].x = (int)round((VPoint.
pix_width / 2) + epix);
5264 pwp[ip].y = (int)round((VPoint.
pix_height / 2) - npix);
5271 wxPen pen(wxTheColourDatabase->Find(
"YELLOW"), 3);
5275 pen.SetStyle(wxPENSTYLE_USER_DASH);
5276 pen.SetDashes(2, dash1);
5280 for (
int iseg = 0; iseg < pmcd->m_nvertices - 1; iseg++) {
5281 int x0 = pwp[iseg].x;
5282 int y0 = pwp[iseg].y;
5283 int x1 = pwp[iseg + 1].x;
5284 int y1 = pwp[iseg + 1].y;
5286 ClipResult res = cohen_sutherland_line_clip_i(
5287 &x0, &y0, &x1, &y1, 0, VPoint.
pix_width, 0,
5302 return render_return;
5305bool cm93compchart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
5312 return DoRenderRegionViewOnDC(dc, VPoint, Region);
5315bool cm93compchart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
5320 return DoRenderRegionViewOnDC(dc, VPoint, vpr);
5323bool cm93compchart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
5330 printf(
"\nOn DoRenderRegionViewOnDC Ref scale is %d, %c\n", m_cmscale,
5331 (
char)(
'A' + m_cmscale - 1));
5333 while (upd.HaveRects()) {
5334 wxRect rect = upd.GetRect();
5335 printf(
" Region Rect: %d %d %d %d\n", rect.x, rect.y, rect.width,
5344 bool render_return =
false;
5345 if (m_pcm93chart_current) {
5346 m_pcm93chart_current->SetVPParms(vp);
5350 if (VPoint.b_quilt) {
5353 OCPNRegion chart_region = GetValidScreenCanvasRegion(vp, Region);
5357 "On DoRenderRegionViewOnDC : Intersecting Ref region rectangles\n");
5359 while (upd.HaveRects()) {
5360 wxRect rect = upd.GetRect();
5361 printf(
" Region Rect: %d %d %d %d\n", rect.x, rect.y, rect.width,
5367 if (!chart_region.IsEmpty()) vpr_empty.Subtract(chart_region);
5369 if (!vpr_empty.Empty() &&
5373#ifdef ocpnUSE_DIBSECTION
5378 if (!chart_region.IsEmpty())
5379 render_return = m_pcm93chart_current->RenderRegionViewOnDC(
5380 temp_dc, vp, chart_region);
5382 render_return =
false;
5385 cm93chart *m_pcm93chart_save = m_pcm93chart_current;
5391 if ((m_pDummyBM->GetWidth() != VPoint.rv_rect.width) ||
5392 (m_pDummyBM->GetHeight() != VPoint.rv_rect.height)) {
5397 if (NULL == m_pDummyBM)
5399 new wxBitmap(VPoint.rv_rect.width, VPoint.rv_rect.height, -1);
5401#ifdef ocpnUSE_DIBSECTION
5406 dumm_dc.SelectObject(*m_pDummyBM);
5407 dumm_dc.SetBackground(*wxBLACK_BRUSH);
5410 int cmscale_next = m_cmscale;
5414 while (!vpr_empty.Empty() && cmscale_next) {
5417 m_cmscale = PrepareChartScale(vp, cmscale_next,
false);
5418#ifdef ocpnUSE_DIBSECTION
5421 wxMemoryDC build_dc;
5424 if (m_pcm93chart_current) {
5426 printf(
" In DRRVOD, add quilt patch at %d, %c\n", m_cmscale,
5427 (
char)(
'A' + m_cmscale - 1));
5429 m_pcm93chart_current->RenderRegionViewOnDC(build_dc, vp, Region);
5431 OCPNRegion sscale_region = GetValidScreenCanvasRegion(vp, Region);
5434 sscale_region.Intersect(vpr_empty);
5438 while (upd.HaveRects()) {
5439 wxRect rect = upd.GetRect();
5440 dumm_dc.Blit(rect.x, rect.y, rect.width, rect.height, &build_dc,
5444 build_dc.SelectObject(wxNullBitmap);
5447 if (!sscale_region.IsEmpty()) vpr_empty.Subtract(sscale_region);
5455 while (updt.HaveRects()) {
5456 wxRect rect = updt.GetRect();
5457 dumm_dc.Blit(rect.x, rect.y, rect.width, rect.height, &temp_dc,
5461 temp_dc.SelectObject(wxNullBitmap);
5464 m_pcm93chart_current = m_pcm93chart_save;
5468 dumm_dc.SelectObject(wxNullBitmap);
5471 dc.SelectObject(*m_pDummyBM);
5473 render_return =
true;
5475 m_pcm93chart_current->RenderRegionViewOnDC(dc, vp, Region);
5476 render_return =
true;
5478 m_Name = m_pcm93chart_current->GetName();
5483 m_pcm93chart_current->RenderRegionViewOnDC(dc, vp, Region);
5484 m_Name = m_pcm93chart_current->GetLastFileName();
5492 if ((m_pDummyBM->GetWidth() != VPoint.
pix_width) ||
5493 (m_pDummyBM->GetHeight() != VPoint.
pix_height)) {
5499 if (NULL == m_pDummyBM)
5504 mdc.SelectObject(*m_pDummyBM);
5505 mdc.SetBackground(*wxBLACK_BRUSH);
5507 mdc.SelectObject(wxNullBitmap);
5509 dc.SelectObject(*m_pDummyBM);
5515 if (m_cell_index_special_outline && m_pcm93chart_current) {
5516 covr_set *pcover = m_pcm93chart_current->GetCoverSet();
5518 for (
unsigned int im = 0; im < pcover->GetCoverCount(); im++) {
5520 if ((pmcd->m_cell_index == m_cell_index_special_outline) &&
5521 (pmcd->m_object_id == m_object_id_special_outline) &&
5522 (pmcd->m_subcell == m_subcell_special_outline))
5532 float_2Dpt *p = pmcd->pvertices;
5533 wxPoint *pwp = m_pcm93chart_current->GetDrawBuffer(pmcd->m_nvertices);
5535 for (
int ip = 0; ip < pmcd->m_nvertices; ip++) {
5537 if (fabs(plon - VPoint.
clon) > 180.) {
5538 if (plon > VPoint.
clon)
5544 double easting, northing, epix, npix;
5545 toSM(p->y, plon + 360., VPoint.
clat, VPoint.
clon + 360, &easting,
5551 easting -= pmcd->user_xoff;
5554 northing -= pmcd->user_yoff;
5559 pwp[ip].x = (int)round((VPoint.
pix_width / 2) + epix);
5560 pwp[ip].y = (int)round((VPoint.
pix_height / 2) - npix);
5583 dc.SetPen(wxPen(wxTheColourDatabase->Find(
"YELLOW"), 4,
5584 wxPENSTYLE_LONG_DASH));
5586 for (
int iseg = 0; iseg < pmcd->m_nvertices - 1; iseg++) {
5587 int x0 = pwp[iseg].x;
5588 int y0 = pwp[iseg].y;
5589 int x1 = pwp[iseg + 1].x;
5590 int y1 = pwp[iseg + 1].y;
5592 ClipResult res = cohen_sutherland_line_clip_i(
5593 &x0, &y0, &x1, &y1, 0, VPoint.
pix_width, 0,
5600 dc.DrawLine(x0, y0, x1, y1);
5608 return render_return;
5611void cm93compchart::UpdateRenderRegions(
const ViewPort &VPoint) {
5612 OCPNRegion full_screen_region(0, 0, VPoint.rv_rect.width,
5613 VPoint.rv_rect.height);
5619 if (m_pcm93chart_current) {
5620 m_pcm93chart_current->SetVPParms(vp);
5624 if (VPoint.b_quilt) {
5626 for (
int i = 0; i < 8; i++) {
5627 if (m_pcm93chart_array[i])
5628 m_pcm93chart_array[i]->m_render_region.Clear();
5634 GetValidScreenCanvasRegion(vp, full_screen_region);
5635 m_pcm93chart_current->m_render_region = chart_region;
5637 if (!chart_region.IsEmpty()) vpr_empty.Subtract(chart_region);
5639 if (!vpr_empty.Empty() &&
5643 cm93chart *m_pcm93chart_save = m_pcm93chart_current;
5645 int cmscale_next = m_cmscale;
5647 while (!vpr_empty.Empty() && cmscale_next) {
5650 m_cmscale = PrepareChartScale(vp, cmscale_next,
false);
5652 if (m_pcm93chart_current) {
5654 GetValidScreenCanvasRegion(vp, full_screen_region);
5655 sscale_region.Intersect(vpr_empty);
5656 m_pcm93chart_current->m_render_region = sscale_region;
5659 if (!sscale_region.IsEmpty()) vpr_empty.Subtract(sscale_region);
5665 m_pcm93chart_current = m_pcm93chart_save;
5671void cm93compchart::SetSpecialCellIndexOffset(
int cell_index,
int object_id,
5672 int subcell,
int xoff,
int yoff) {
5673 m_special_offset_x = xoff;
5674 m_special_offset_y = yoff;
5676 if (m_pcm93chart_current)
5677 m_pcm93chart_current->SetUserOffsets(cell_index, object_id, subcell, xoff,
5681bool cm93compchart::RenderNextSmallerCellOutlines(
ocpnDC &dc,
ViewPort &vp,
5683 if (m_cmscale >= 7)
return false;
5686 if (!glcc)
return false;
5693 int nss = m_cmscale + 1;
5702 bool bdrawn =
false;
5711 if(nss_max > m_cmscale+3)
5712 nss_max = m_cmscale+3;
5715 while (nss <= nss_max && (!bdrawn || (vp.
chart_scale < 3e6))) {
5716 cm93chart *psc = m_pcm93chart_array[nss];
5719 m_pcm93chart_array[nss] =
new cm93chart();
5720 psc = m_pcm93chart_array[nss];
5722 wxChar ext = (wxChar)(
'A' + nss - 1);
5723 if (nss == 0) ext =
'Z';
5725 wxString file_dummy =
"CM93.";
5728 psc->SetCM93Dict(m_pDictComposite);
5729 psc->SetCM93Prefix(m_prefixComposite);
5730 psc->SetCM93Manager(m_pcm93mgr);
5732 psc->SetColorScheme(m_global_color_scheme);
5733 psc->Init(file_dummy, FULL_INIT);
5739 psc->UpdateCovrSet(&vp);
5742 covr_set *pcover = psc->GetCoverSet();
5744 for (
unsigned int im = 0; im < pcover->GetCoverCount(); im++) {
5747 if (vp.GetBBox().IntersectOut(mcd->m_covr_bbox))
continue;
5749 wxPoint *pwp = psc->GetDrawBuffer(mcd->m_nvertices);
5750 bdrawn = RenderCellOutlines(dc, vp, pwp, mcd);
5758 glDisable(GL_LINE_STIPPLE);
5759 glDisable(GL_LINE_SMOOTH);
5760 glDisable(GL_BLEND);
5766bool cm93compchart::RenderCellOutlines(
ocpnDC &dc,
ViewPort &vp, wxPoint *pwp,
5768 float_2Dpt *p = mcd->pvertices;
5769 int np = mcd->m_nvertices;
5771 for (
int ip = 0; ip < np; ip++, p++) {
5781 wxPoint p0 = pwp[0];
5782 for (
int ip = 1; ip < np; ip++) {
5783 if (((p0.x > vp.
pix_width) && (pwp[ip].x < 0)) ||
5784 ((p0.x < 0) && (pwp[ip].x > vp.
pix_width)))
5790 dc.DrawLines(mcd->m_nvertices, pwp, 0, 0,
false);
5794void cm93compchart::GetPointPix(ObjRazRules *rzRules,
float rlat,
float rlon,
5796 m_pcm93chart_current->GetPointPix(rzRules, rlat, rlon, r);
5799void cm93compchart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
5800 wxPoint *r,
int nPoints) {
5801 m_pcm93chart_current->GetPointPix(rzRules, en, r, nPoints);
5804void cm93compchart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
5806 m_pcm93chart_current->GetPixPoint(pixx, pixy, plat, plon, vpt);
5809void cm93compchart::UpdateLUPs(
s57chart *pOwner) {
5810 for (
int i = 0; i < 8; i++) {
5811 if (m_pcm93chart_array[i]) m_pcm93chart_array[i]->UpdateLUPs(pOwner);
5815std::list<S57Obj *> *cm93compchart::GetAssociatedObjects(S57Obj *obj) {
5816 if (m_pcm93chart_current)
5817 return m_pcm93chart_current->GetAssociatedObjects(obj);
5822void cm93compchart::InvalidateCache() {
5823 for (
int i = 0; i < 8; i++) {
5824 if (m_pcm93chart_array[i]) m_pcm93chart_array[i]->InvalidateCache();
5828void cm93compchart::ForceEdgePriorityEvaluate(
void) {
5829 for (
int i = 0; i < 8; i++) {
5830 if (m_pcm93chart_array[i])
5831 m_pcm93chart_array[i]->ForceEdgePriorityEvaluate();
5835void cm93compchart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
5836 m_global_color_scheme = cs;
5838 for (
int i = 0; i < 8; i++) {
5839 if (m_pcm93chart_array[i])
5840 m_pcm93chart_array[i]->SetColorScheme(cs, bApplyImmediate);
5844ListOfObjRazRules *cm93compchart::GetObjRuleListAtLatLon(
float lat,
float lon,
5845 float select_radius,
5847 int selection_mask) {
5853 if (!VPoint->b_quilt)
5854 if (m_pcm93chart_current)
5855 return m_pcm93chart_current->GetObjRuleListAtLatLon(lat, alon,
5856 select_radius, &vp);
5859 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
5863 UpdateRenderRegions(*VPoint);
5869 for (
int i = 0; i < 8; i++) {
5870 if (m_pcm93chart_array[i]) {
5871 if (!m_pcm93chart_array[i]->m_render_region.IsEmpty()) {
5872 if (wxInRegion == m_pcm93chart_array[i]->m_render_region.Contains(p))
5873 return m_pcm93chart_array[i]->GetObjRuleListAtLatLon(
5874 lat, alon, select_radius, &vp, selection_mask);
5880 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
5886std::unordered_map<unsigned, VE_Element *> &cm93compchart::Get_ve_hash(
void) {
5887 return m_pcm93chart_current->Get_ve_hash();
5890std::unordered_map<unsigned, VC_Element *> &cm93compchart::Get_vc_hash(
void) {
5891 return m_pcm93chart_current->Get_vc_hash();
5902 m_last_cell_adjustvp = m_pcm93chart_current;
5910 if (m_pcm93chart_current)
return false;
5919 int cmscale = GetCMScaleFromVP(
5922 int cmscale_actual = PrepareChartScale(
5923 vp_proposed, cmscale,
5927 printf(
" In AdjustVP, adjustment subchart scale is %c\n",
5928 (
char)(
'A' + cmscale_actual - 1));
5934 bool single_adjust =
false;
5935 if (m_pcm93chart_array[cmscale_actual])
5937 m_pcm93chart_array[cmscale_actual]->AdjustVP(vp_last, vp_proposed);
5939 if (m_cmscale != cmscale_actual)
return false;
5943 if (vp_last.b_quilt)
return false;
5945 return single_adjust;
5948ThumbData *cm93compchart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
5952InitReturn cm93compchart::CreateHeaderData() {
5953 m_Chart_Scale = 20000000;
5959 wxDir dirt(m_prefixComposite);
5961 wxRegEx test(
"[0-9]+");
5963 bool b_cont = dirt.GetFirst(&candidate);
5966 if (test.Matches(candidate) && (candidate.Len() == 8)) {
5967 wxString dir = m_prefixComposite;
5969 if (wxDir::Exists(dir)) {
5970 wxFileName name(dir);
5971 wxString num_name = name.GetName();
5973 if (num_name.ToLong(&number)) {
5974 int ilat = number / 10000;
5975 int ilon = number % 10000;
5977 int lat_base = (ilat - 270) / 3.;
5978 int lon_base = ilon / 3.;
5979 extent_rect.Union(wxRect(lon_base, lat_base, 20, 20));
5983 b_cont = dirt.GetNext(&candidate);
5987 m_FullExtent.ELON = ((double)extent_rect.x + (
double)extent_rect.width);
5988 m_FullExtent.WLON = ((double)extent_rect.x);
5989 m_FullExtent.NLAT = ((double)extent_rect.y + (
double)extent_rect.height);
5990 m_FullExtent.SLAT = ((double)extent_rect.y);
5991 m_bExtentSet =
true;
5995 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
5996 *m_pCOVRTablePoints = 4;
5997 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
5998 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
6002 *pfe++ = m_FullExtent.NLAT;
6003 *pfe++ = m_FullExtent.WLON;
6005 *pfe++ = m_FullExtent.NLAT;
6006 *pfe++ = m_FullExtent.ELON;
6008 *pfe++ = m_FullExtent.SLAT;
6009 *pfe++ = m_FullExtent.ELON;
6011 *pfe++ = m_FullExtent.SLAT;
6012 *pfe++ = m_FullExtent.WLON;
6017cm93_dictionary *cm93compchart::FindAndLoadDictFromDir(
const wxString &dir) {
6022 if (pdict->LoadDictionary(dir))
return pdict;
6027 wxString path = dir;
6031 while (i < path.Len()) {
6032 target.Append(path[i]);
6033 if (path[i] == wxFileName::GetPathSeparator()) {
6037 if (pdict->LoadDictionary(target)) {
6051 wxFileName fnc(dir);
6052 wxString found_dict_file_name;
6056 path = fnc.GetPath(wxPATH_GET_VOLUME);
6058 wxString msg =
" Looking harder for CM93 dictionary in ";
6062 if ((path.Len() == 0) || path.IsSameAs(fnc.GetPathSeparator())) {
6064 wxLogMessage(
"Early break1");
6070 if ((wxNOT_FOUND == path.Lower().Find(
"cm93"))) {
6072 wxLogMessage(
"Early break2");
6080 if (dir.IsOpened()) {
6083 dir.Traverse(cm93Dictionary);
6084 bdone = found_dict_file_name.Len() != 0;
6090 if (found_dict_file_name.Len()) {
6091 wxFileName fnd(found_dict_file_name);
6093 fnd.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
6095 if (pdict->LoadDictionary(dpath)) retval = pdict;
6098 if (NULL == retval)
delete pdict;
6103void cm93compchart::CloseandReopenCurrentSubchart(
void) {
6104 delete m_pcm93chart_current;
6105 m_pcm93chart_current = NULL;
6106 m_pcm93chart_array[m_cmscale] = NULL;
6130 const wxPoint &pos,
const wxSize &size,
long style);
6133 wxString OnGetItemText(
long item,
long column)
const;
6134 int OnGetItemColumnImage(
long item,
long column)
const;
6139OCPNOffsetListCtrl::OCPNOffsetListCtrl(
CM93OffsetDialog *parent, wxWindowID
id,
6140 const wxPoint &pos,
const wxSize &size,
6142 : wxListCtrl(parent, id, pos, size, style) {
6146OCPNOffsetListCtrl::~OCPNOffsetListCtrl() {}
6148wxString OCPNOffsetListCtrl::OnGetItemText(
long item,
long column)
const {
6150 M_COVR_Desc *pmcd = m_parent->m_pcovr_array[item];
6154 ret.Printf(
"%d", pmcd->m_cell_index);
6155 if (((
int)
'0') == pmcd->m_subcell)
6158 char t = (char)pmcd->m_subcell;
6167 ret.Printf(
"%d", pmcd->m_object_id);
6171 ret = m_parent->m_selected_chart_scale_char;
6175 ret.Printf(
"%g", pmcd->transform_WGS84_offset_x);
6179 ret.Printf(
"%g", pmcd->transform_WGS84_offset_y);
6183 ret.Printf(
"%6.0f", pmcd->user_xoff * pmcd->m_centerlat_cos);
6187 ret.Printf(
"%6.0f", pmcd->user_yoff * pmcd->m_centerlat_cos);
6196int OCPNOffsetListCtrl::OnGetItemColumnImage(
long item,
long column)
const {
6207EVT_CLOSE(CM93OffsetDialog::OnClose)
6212 m_pcompchart = NULL;
6217 m_selected_list_index = -1;
6218 m_selected_cell_index = 0;
6220 long wstyle = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER;
6221 wxDialog::Create(parent, -1, _(
"OpenCPN CM93 Cell Offset Adjustments"),
6222 wxPoint(0, 0), wxSize(800, 200), wstyle);
6228 wxBoxSizer *topSizer =
new wxBoxSizer(wxHORIZONTAL);
6233 long flags = wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES |
6236 flags |= wxLC_VIRTUAL;
6242 m_pListCtrlMCOVRs->Connect(
6243 wxEVT_COMMAND_LIST_ITEM_SELECTED,
6244 wxListEventHandler(CM93OffsetDialog::OnCellSelected), NULL,
this);
6246 int dx = GetCharWidth();
6247 int dy = GetCharHeight();
6250 m_pListCtrlMCOVRs->InsertColumn(tlCELL, _(
"Cell"), wxLIST_FORMAT_LEFT, width);
6253 m_pListCtrlMCOVRs->InsertColumn(tlMCOVR, _(
"M_COVR ID"), wxLIST_FORMAT_CENTER,
6257 m_pListCtrlMCOVRs->InsertColumn(tlSCALE, _(
"Cell Scale"),
6258 wxLIST_FORMAT_CENTER, width);
6261 m_pListCtrlMCOVRs->InsertColumn(tlXOFF, _(
"wgsox"), wxLIST_FORMAT_CENTER,
6265 m_pListCtrlMCOVRs->InsertColumn(tlYOFF, _(
"wgsoy"), wxLIST_FORMAT_CENTER,
6269 m_pListCtrlMCOVRs->InsertColumn(tlUXOFF, _(
"User X Offset"),
6270 wxLIST_FORMAT_CENTER, width);
6273 m_pListCtrlMCOVRs->InsertColumn(tlUYOFF, _(
"User Y Offset"),
6274 wxLIST_FORMAT_CENTER, width);
6276 topSizer->Add(m_pListCtrlMCOVRs, 1, wxEXPAND | wxALL, 0);
6278 wxBoxSizer *boxSizer02 =
new wxBoxSizer(wxVERTICAL);
6279 boxSizer02->AddSpacer(22);
6281 wxStaticText *pStaticTextXoff =
new wxStaticText(
6283 wxString::Format(
"%s (%s)", _(
"User X Offset"), _(
"meters")),
6284 wxDefaultPosition, wxDefaultSize, 0);
6285 boxSizer02->Add(pStaticTextXoff, 0, wxALL, 0);
6288 new wxSpinCtrl(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
6289 wxSize(50, -1), wxSP_ARROW_KEYS, -10000, 10000, 0);
6290 m_pSpinCtrlXoff->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,
6291 wxCommandEventHandler(CM93OffsetDialog::OnOffSetSet),
6293 boxSizer02->Add(m_pSpinCtrlXoff, 0, wxEXPAND | wxALL, 0);
6295 wxStaticText *pStaticTextYoff =
new wxStaticText(
6297 wxString::Format(
"%s (%s)", _(
"User Y Offset"), _(
"meters")),
6298 wxDefaultPosition, wxDefaultSize, 0);
6299 boxSizer02->Add(pStaticTextYoff, 0, wxALL, 0);
6302 new wxSpinCtrl(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
6303 wxSize(50, -1), wxSP_ARROW_KEYS, -10000, 10000, 0);
6304 m_pSpinCtrlYoff->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,
6305 wxCommandEventHandler(CM93OffsetDialog::OnOffSetSet),
6307 boxSizer02->Add(m_pSpinCtrlYoff, 0, wxEXPAND | wxALL, 0);
6309 m_OKButton =
new wxButton(
this, wxID_ANY, _(
"OK"), wxDefaultPosition,
6311 m_OKButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
6312 wxCommandEventHandler(CM93OffsetDialog::OnOK), NULL,
6314 boxSizer02->Add(m_OKButton, 0, wxALL, 5);
6315 m_OKButton->SetDefault();
6317 topSizer->Add(boxSizer02, 0, wxEXPAND | wxALL, 2);
6319 wxSize sz(800, dy * 8);
6321 sz = wxGetDisplaySize();
6331 SetSize(GetSize().x, GetSize().y - 1);
6345void CM93OffsetDialog::OnClose(wxCloseEvent &event) {
6347 m_pcompchart->SetSpecialOutlineCellIndex(0, 0, 0);
6349 m_pcompchart->InvalidateCache();
6352 m_pparent->Refresh(
true);
6353 gFrame->InvalidateAllGL();
6357 if (m_pListCtrlMCOVRs->GetItemCount() > m_selected_list_index)
6358 m_pListCtrlMCOVRs->SetItemState(m_selected_list_index, 0,
6359 wxLIST_STATE_SELECTED);
6364void CM93OffsetDialog::OnOK(wxCommandEvent &event) {
6372 m_pcompchart = pchart;
6375void CM93OffsetDialog::OnOffSetSet(wxCommandEvent &event) {
6376 m_xoff = m_pSpinCtrlXoff->GetValue() / m_centerlat_cos;
6377 m_yoff = m_pSpinCtrlYoff->GetValue() / m_centerlat_cos;
6384void CM93OffsetDialog::UpdateOffsets(
void) {
6385 if (m_pcompchart && m_selected_cell_index) {
6387 m_pcompchart->SetSpecialCellIndexOffset(m_selected_cell_index,
6388 m_selected_object_id,
6389 m_selected_subcell, m_xoff, m_yoff);
6393 AbstractPlatform::ShowBusySpinner();
6394 m_pcompchart->CloseandReopenCurrentSubchart();
6395 AbstractPlatform::HideBusySpinner();
6398 m_pparent->Refresh(
true);
6399 gFrame->InvalidateAllGL();
6404void CM93OffsetDialog::SetColorScheme() { DimeControl(
this); }
6406void CM93OffsetDialog::OnCellSelected(wxListEvent &event) {
6408 m_selected_list_index =
event.GetIndex();
6410 M_COVR_Desc *mcd = m_pcovr_array.Item(event.GetIndex());
6412 if (m_selected_list_index > m_pListCtrlMCOVRs->GetItemCount())
6415 cm93chart *pchart = m_pcompchart->GetCurrentSingleScaleChart();
6417 M_COVR_Desc *cached_mcd = pchart->GetCoverSet()->Find_MCD(
6418 mcd->m_cell_index, mcd->m_object_id, mcd->m_subcell);
6420 m_pSpinCtrlXoff->SetValue(
6421 wxRound(cached_mcd->user_xoff * cached_mcd->m_centerlat_cos));
6422 m_pSpinCtrlYoff->SetValue(
6423 wxRound(cached_mcd->user_yoff * cached_mcd->m_centerlat_cos));
6427 m_pcompchart->SetSpecialOutlineCellIndex(mcd->m_cell_index,
6428 mcd->m_object_id, mcd->m_subcell);
6430 m_selected_cell_index = mcd->m_cell_index;
6431 m_selected_object_id = mcd->m_object_id;
6432 m_selected_subcell = mcd->m_subcell;
6433 m_centerlat_cos = mcd->m_centerlat_cos;
6435 m_pcompchart->InvalidateCache();
6438 m_pparent->Refresh(
true);
6439 gFrame->InvalidateAllGL();
6444void CM93OffsetDialog::UpdateMCOVRList(
const ViewPort &vpt) {
6448 cm93chart *pchart = m_pcompchart->GetCurrentSingleScaleChart();
6451 m_selected_chart_scale_char = pchart->GetScaleChar();
6453 m_pcovr_array.Clear();
6456 std::vector<int> cell_array = pchart->GetVPCellArray(vpt);
6464 covr_set *pcover = pchart->GetCoverSet();
6466 for (
unsigned int im = 0; im < pcover->GetCoverCount(); im++) {
6469 for (
unsigned int icell = 0; icell < cell_array.size(); icell++) {
6470 if (cell_array[icell] == mcd->m_cell_index) {
6471 wxPoint *pwp = pchart->GetDrawBuffer(mcd->m_nvertices);
6478 m_pcovr_array.Add(mcd);
6486 for (
unsigned int im = 0; im < m_pcovr_array.size(); im++) {
6488 if ((m_selected_cell_index == mcd->m_cell_index) &&
6489 (m_selected_object_id == mcd->m_object_id) &&
6490 (m_selected_subcell == mcd->m_subcell)) {
6496 if (!m_pListCtrlMCOVRs->IsVirtual()) {
6497 if (m_pListCtrlMCOVRs->GetItemCount())
6498 m_pListCtrlMCOVRs->DeleteAllItems();
6500 for (
unsigned int i = 0; i < m_pcovr_array.GetCount(); i++) {
6503 m_pListCtrlMCOVRs->InsertItem(item);
6504 for (
int j = 0; j < tlUYOFF + 1; j++) {
6506 item.SetText(m_pListCtrlMCOVRs->OnGetItemText(i, j));
6507 m_pListCtrlMCOVRs->SetItem(item);
6511 m_pListCtrlMCOVRs->SetItemCount(m_pcovr_array.GetCount());
6514 if (-1 != sel_index)
6515 m_pListCtrlMCOVRs->SetItemState(sel_index, wxLIST_STATE_SELECTED,
6516 wxLIST_STATE_SELECTED);
6518 m_pListCtrlMCOVRs->SetItemState(sel_index, 0,
6519 wxLIST_STATE_SELECTED);
6521 m_pListCtrlMCOVRs->Refresh(
true);
6524 m_pListCtrlMCOVRs->Refresh(
false);
Generic Chart canvas base.
Dialog for managing CM93 chart offsets.
ChartCanvas - Main chart display and interaction component.
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.
double rotation
Rotation angle of the viewport in radians.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
OCPNRegion GetVPRegionIntersect(const OCPNRegion ®ion, const LLRegion &llregion, int chart_native_scale)
Get the intersection of the viewport with a given region.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents a single CM93 chart at a specific scale.
Represents a composite CM93 chart covering multiple scales.
OpenGL chart rendering canvas.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
CM93OffsetDialog * g_pCM93OffsetDialog
Global instance.
Class cm93chart and helpers – CM93 chart state.
CM93OffsetDialog * g_pCM93OffsetDialog
Global instance.
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
General purpose GUI support.
@ PI_PRIO_NUM
Number of priority levels.
@ PI_LUPNAME_NUM
Total number of lookup table types.
Tools to send data to plugins.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Runtime representation of a plugin block.