34#include "wx/tokenzr.h"
35#include <wx/textfile.h>
36#include <wx/filename.h>
39#include "OCPNPlatform.h"
47#include "model/cutil.h"
48#include "model/georef.h"
50#include "model/navutil_base.h"
52#include "ocpn_pixel.h"
55#include "model/wx28compat.h"
58#include "gdal/cpl_csv.h"
67#include "SencManager.h"
71#include "ocpn_frame.h"
74#include <wx/msw/msvcrt.h>
78#include "glChartCanvas.h"
92#define strncasecmp(x, y, z) _strnicmp(x, y, z)
96#include "crashlytics.h"
99extern bool GetDoubleAttr(S57Obj *obj,
const char *AttrName,
102void OpenCPN_OGRErrorHandler(
103 CPLErr eErrClass,
int nError,
104 const char *pszErrorMsg);
106extern s52plib *ps52plib;
107extern S57ClassRegistrar *g_poRegistrar;
108extern wxString g_csv_locn;
109extern wxString g_SENCPrefix;
110extern bool g_bGDAL_Debug;
111extern bool g_bDebugS57;
115extern bool g_b_EnableVBO;
119static jmp_buf env_ogrf;
121#include <wx/arrimpl.cpp>
122WX_DEFINE_OBJARRAY(ArrayOfS57Obj);
124#include <wx/listimpl.cpp>
125WX_DEFINE_LIST(ListOfPI_S57Obj);
127WX_DEFINE_LIST(ListOfObjRazRules);
129#define S57_THUMB_SIZE 200
136static uint64_t hash_fast64(
const void *buf,
size_t len, uint64_t seed) {
137 const uint64_t m = 0x880355f21e6d1965ULL;
138 const uint64_t *pos = (
const uint64_t *)buf;
139 const uint64_t *end = pos + (len >> 3);
140 const unsigned char *pc;
141 uint64_t h = len * m ^ seed;
146 v *= 0x2127599bf4325c37ULL;
150 pc = (
const unsigned char *)pos;
154 v ^= (uint64_t)pc[6] << 48;
156 v ^= (uint64_t)pc[5] << 40;
158 v ^= (uint64_t)pc[4] << 32;
160 v ^= (uint64_t)pc[3] << 24;
162 v ^= (uint64_t)pc[2] << 16;
164 v ^= (uint64_t)pc[1] << 8;
166 v ^= (uint64_t)pc[0];
168 v *= 0x2127599bf4325c37ULL;
174 h *= 0x2127599bf4325c37ULL;
179static unsigned int hash_fast32(
const void *buf,
size_t len,
181 uint64_t h = hash_fast64(buf, len, seed);
186 return h - (h >> 32);
189unsigned long connector_key::hash()
const {
190 return hash_fast32(k,
sizeof k, 0);
197render_canvas_parms::render_canvas_parms() { pix_buff = NULL; }
199render_canvas_parms::~render_canvas_parms(
void) {}
201static void PrepareForRender(
ViewPort *pvp, s52plib *plib) {
206 pvp->rv_rect, pvp->GetBBox(), pvp->
ref_scale,
208 plib->PrepareForRender();
215s57chart::s57chart() {
216 m_ChartType = CHART_TYPE_S57;
217 m_ChartFamily = CHART_FAMILY_VECTOR;
219 for (
int i = 0; i < PRIO_NUM; i++)
220 for (
int j = 0; j < LUPNAME_NUM; j++) razRules[i][j] = NULL;
229 pFloatingATONArray =
new wxArrayPtrVoid;
230 pRigidATONArray =
new wxArrayPtrVoid;
232 m_tmpup_array = NULL;
234 m_DepthUnits =
"METERS";
235 m_depth_unit_id = DEPTH_UNIT_METERS;
237 bGLUWarningSent =
false;
243 m_pvaldco_array = NULL;
245 m_bExtentSet =
false;
247 m_pDIBThumbDay = NULL;
248 m_pDIBThumbDim = NULL;
249 m_pDIBThumbOrphan = NULL;
250 m_bbase_file_attr_known =
false;
252 m_bLinePrioritySet =
false;
253 m_plib_state_hash = 0;
260 m_b2pointLUPS =
false;
261 m_b2lineLUPS =
false;
263 m_next_safe_cnt = 1e6;
265 m_line_vertex_buffer = 0;
266 m_this_chart_context = 0;
268 m_vbo_byte_length = 0;
269 bReadyToRender =
false;
271 m_disableBackgroundSENC =
false;
274s57chart::~s57chart() {
275 FreeObjectsAndRules();
282 delete pFloatingATONArray;
283 delete pRigidATONArray;
287 free(m_pvaldco_array);
289 free(m_line_vertex_buffer);
291 delete m_pDIBThumbOrphan;
293 for (
unsigned i = 0; i < m_pcs_vector.size(); i++)
delete m_pcs_vector.at(i);
295 for (
unsigned i = 0; i < m_pve_vector.size(); i++)
delete m_pve_vector.at(i);
297 m_pcs_vector.clear();
298 m_pve_vector.clear();
300 for (
const auto &it : m_ve_hash) {
301 VE_Element *pedge = it.second;
303 free(pedge->pPoints);
309 for (
const auto &it : m_vc_hash) {
310 VC_Element *pcs = it.second;
319 if ((m_LineVBO_name > 0)) glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
321 free(m_this_chart_context);
323 if (m_TempFilePath.Length() && (m_FullPath != m_TempFilePath)) {
324 if (::wxFileExists(m_TempFilePath)) wxRemoveFile(m_TempFilePath);
328 if (g_SencThreadManager) {
329 if (g_SencThreadManager->IsChartInTicketlist(
this)) {
330 g_SencThreadManager->SetChartPointer(
this, NULL);
335void s57chart::GetValidCanvasRegion(
const ViewPort &VPoint,
339 double easting, northing;
342 toSM(m_FullExtent.SLAT, m_FullExtent.WLON, VPoint.
clat, VPoint.
clon, &easting,
347 rxl = (int)round((VPoint.
pix_width / 2) + epix);
348 ryb = (int)round((VPoint.
pix_height / 2) - npix);
350 toSM(m_FullExtent.NLAT, m_FullExtent.ELON, VPoint.
clat, VPoint.
clon, &easting,
355 rxr = (int)round((VPoint.
pix_width / 2) + epix);
356 ryt = (int)round((VPoint.
pix_height / 2) - npix);
358 pValidRegion->Clear();
359 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
362LLRegion s57chart::GetValidRegion() {
363 double ll[8] = {m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.SLAT,
364 m_FullExtent.ELON, m_FullExtent.NLAT, m_FullExtent.ELON,
365 m_FullExtent.NLAT, m_FullExtent.WLON};
366 return LLRegion(4, ll);
369void s57chart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
370 if (!ps52plib)
return;
375 case GLOBAL_COLOR_SCHEME_DAY:
376 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
378 case GLOBAL_COLOR_SCHEME_DUSK:
379 ps52plib->SetPLIBColorScheme(
"DUSK", ChartCtxFactory());
381 case GLOBAL_COLOR_SCHEME_NIGHT:
382 ps52plib->SetPLIBColorScheme(
"NIGHT", ChartCtxFactory());
385 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
389 m_global_color_scheme = cs;
391 if (bApplyImmediate) {
397 ClearRenderedTextCache();
400 ChangeThumbColor(cs);
403void s57chart::ChangeThumbColor(ColorScheme cs) {
404 if (0 == m_pDIBThumbDay)
return;
408 case GLOBAL_COLOR_SCHEME_DAY:
409 pThumbData->pDIBThumb = m_pDIBThumbDay;
410 m_pDIBThumbOrphan = m_pDIBThumbDim;
412 case GLOBAL_COLOR_SCHEME_DUSK:
413 case GLOBAL_COLOR_SCHEME_NIGHT: {
414 if (NULL == m_pDIBThumbDim) {
415 wxImage img = m_pDIBThumbDay->ConvertToImage();
417#if wxCHECK_VERSION(2, 8, 0)
418 wxImage gimg = img.ConvertToGreyscale(
428 wxBitmap *pBMP =
new wxBitmap(gimg);
430 m_pDIBThumbDim = pBMP;
431 m_pDIBThumbOrphan = m_pDIBThumbDay;
434 pThumbData->pDIBThumb = m_pDIBThumbDim;
440bool s57chart::GetChartExtent(
Extent *pext) {
442 *pext = m_FullExtent;
448static void free_mps(mps_container *mps) {
449 if (mps == 0)
return;
450 if (ps52plib && mps->cs_rules) {
451 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
452 Rules *rule_chain_top = mps->cs_rules->Item(i);
453 ps52plib->DestroyRulesChain(rule_chain_top);
455 delete mps->cs_rules;
460void s57chart::FreeObjectsAndRules() {
469 for (
int i = 0; i < PRIO_NUM; ++i) {
470 for (
int j = 0; j < LUPNAME_NUM; j++) {
471 top = razRules[i][j];
472 while (top != NULL) {
474 if (0 == top->obj->nRef)
delete top->obj;
477 ObjRazRules *ctop = top->child;
481 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
483 ObjRazRules *cnxx = ctop->next;
498void s57chart::ClearRenderedTextCache() {
500 for (
int i = 0; i < PRIO_NUM; ++i) {
501 for (
int j = 0; j < LUPNAME_NUM; j++) {
502 top = razRules[i][j];
503 while (top != NULL) {
504 if (top->obj->bFText_Added) {
505 top->obj->bFText_Added =
false;
506 delete top->obj->FText;
507 top->obj->FText = NULL;
511 ObjRazRules *ctop = top->child;
513 if (ctop->obj->bFText_Added) {
514 ctop->obj->bFText_Added =
false;
515 delete ctop->obj->FText;
516 ctop->obj->FText = NULL;
528double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
529 bool b_allow_overzoom) {
531 return m_Chart_Scale * 0.125;
535double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
537 return m_Chart_Scale * 4.0;
544void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
546 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
548 r->y = roundint(m_pixy_vp_center -
549 ((north - m_northing_vp_center) * m_view_scale_ppm));
552void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
553 wxPoint *r,
int nPoints) {
554 for (
int i = 0; i < nPoints; i++) {
555 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
557 r[i].y = roundint(m_pixy_vp_center -
558 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
562void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
564 if (vpt->m_projection_type != PROJECTION_MERCATOR)
565 printf(
"s57chart unhandled projection\n");
571 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
572 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
578 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
588void s57chart::SetVPParms(
const ViewPort &vpt) {
594 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
595 &m_northing_vp_center);
597 vp_transform.easting_vp_center = m_easting_vp_center;
598 vp_transform.northing_vp_center = m_northing_vp_center;
602 if (IsCacheValid()) {
605 double prev_easting_c, prev_northing_c;
606 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
609 double easting_c, northing_c;
610 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
618 int dpix_x = (int)round(delta_pix_x);
623 int dpix_y = (int)round(delta_pix_y);
626 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
627 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
630 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
632 vp_proposed.
clon = xlon;
633 vp_proposed.
clat = xlat;
660void s57chart::LoadThumb() {
661 wxFileName fn(m_FullPath);
662 wxString SENCdir = g_SENCPrefix;
664 if (SENCdir.Last() != fn.GetPathSeparator())
665 SENCdir.Append(fn.GetPathSeparator());
667 wxFileName tsfn(SENCdir);
668 tsfn.SetFullName(fn.GetFullName());
670 wxFileName ThumbFileNameLook(tsfn);
671 ThumbFileNameLook.SetExt(
"BMP");
674 if (ThumbFileNameLook.FileExists()) {
677 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
678 m_pDIBThumbDay = pBMP;
679 m_pDIBThumbOrphan = 0;
684ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
687 if (pThumbData->pDIBThumb == 0) {
689 ChangeThumbColor(m_global_color_scheme);
692 UpdateThumbData(lat, lon);
697bool s57chart::UpdateThumbData(
double lat,
double lon) {
701 if (pThumbData->pDIBThumb) {
702 double lat_top = m_FullExtent.NLAT;
703 double lat_bot = m_FullExtent.SLAT;
704 double lon_left = m_FullExtent.WLON;
705 double lon_right = m_FullExtent.ELON;
708 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
710 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
712 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
715 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
716 (int)(east * thumb_view_scale_ppm);
717 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
718 (int)(north * thumb_view_scale_ppm);
725 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
726 pThumbData->ShipX = test_x;
727 pThumbData->ShipY = test_y;
733void s57chart::SetFullExtent(
Extent &ext) {
734 m_FullExtent.NLAT = ext.NLAT;
735 m_FullExtent.SLAT = ext.SLAT;
736 m_FullExtent.WLON = ext.WLON;
737 m_FullExtent.ELON = ext.ELON;
742void s57chart::ForceEdgePriorityEvaluate(
void) { m_bLinePrioritySet =
false; }
744void s57chart::SetLinePriorities(
void) {
745 if (!ps52plib)
return;
750 if (!m_bLinePrioritySet) {
754 for (
int i = 0; i < PRIO_NUM; ++i) {
755 top = razRules[i][2];
756 while (top != NULL) {
757 ObjRazRules *crnt = top;
759 ps52plib->SetLineFeaturePriority(crnt, i);
765 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
770 top = razRules[i][j];
771 while (top != NULL) {
774 ps52plib->SetLineFeaturePriority(crnt, i);
780 for (
int i = 0; i < PRIO_NUM; ++i) {
781 for (
int j = 0; j < LUPNAME_NUM; j++) {
782 ObjRazRules *top = razRules[i][j];
783 while (top != NULL) {
784 S57Obj *obj = top->obj;
787 connector_segment *pcs;
788 line_segment_element *list = obj->m_ls_list;
790 switch (list->ls_type) {
794 if (pedge) list->priority = pedge->max_priority;
799 if (pcs) list->priority = pcs->max_priority_cs;
814 m_bLinePrioritySet =
true;
818void s57chart::SetLinePriorities(
void )
820 if( !ps52plib )
return;
825 if( !m_bLinePrioritySet ) {
829 for(
int i = 0; i < PRIO_NUM; ++i ) {
831 top = razRules[i][2];
832 while( top != NULL ) {
833 ObjRazRules *crnt = top;
835 ps52plib->SetLineFeaturePriority( crnt, i );
840 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
845 top = razRules[i][j];
846 while( top != NULL ) {
849 ps52plib->SetLineFeaturePriority( crnt, i );
857 for(
int i = 0; i < PRIO_NUM; ++i ) {
858 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
859 ObjRazRules *top = razRules[i][j];
860 while( top != NULL ) {
861 S57Obj *obj = top->obj;
864 connector_segment *pcs;
865 line_segment_element *list = obj->m_ls_list;
870 pedge = (VE_Element *)list->private0;
872 list->priority = pedge->max_priority;
876 pcs = (connector_segment *)list->private0;
878 list->priority = pcs->max_priority;
893 m_bLinePrioritySet =
true;
897int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
901 line_segment_element *ls_list = obj->m_ls_list;
903 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
904 nPoints += ls_list->pedge->nCount;
907 ls_list = ls_list->next;
916 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
920 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
921 ls_list = obj->m_ls_list;
923 size_t vbo_offset = 0;
925 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
926 vbo_offset = ls_list->pedge->vbo_offset;
927 count = ls_list->pedge->nCount;
929 vbo_offset = ls_list->pcs->vbo_offset;
933 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
935 ls_list = ls_list->next;
942int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
947 line_segment_element *ls_list = obj->m_ls_list;
949 nPoints += ls_list->n_points;
950 ls_list = ls_list->next;
959 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
963 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
964 ls_list = obj->m_ls_list;
966 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
967 br += ls_list->n_points * 2;
968 ls_list = ls_list->next;
977 float e0, n0, e1, n1;
980void s57chart::AssembleLineGeometry(
void) {
985 for (
const auto &it : m_ve_hash) {
986 VE_Element *pedge = it.second;
988 nPoints += pedge->nCount;
994 std::map<long long, connector_segment *> ce_connector_hash;
995 std::map<long long, connector_segment *> ec_connector_hash;
996 std::map<long long, connector_segment *> cc_connector_hash;
998 std::map<long long, connector_segment *>::iterator csit;
1005 std::vector<segment_pair> connector_segment_vector;
1006 size_t seg_pair_index = 0;
1011 for (
int i = 0; i < PRIO_NUM; ++i) {
1012 for (
int j = 0; j < LUPNAME_NUM; j++) {
1013 ObjRazRules *top = razRules[i][j];
1014 while (top != NULL) {
1015 S57Obj *obj = top->obj;
1017 if ((!obj->m_ls_list) &&
1020 line_segment_element list_top;
1023 line_segment_element *le_current = &list_top;
1025 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1026 if (!obj->m_lsindex_array)
continue;
1028 int seg_index = iseg * 3;
1029 int *index_run = &obj->m_lsindex_array[seg_index];
1032 unsigned int inode = *index_run++;
1035 bool edge_dir =
true;
1036 int venode = *index_run++;
1042 VE_Element *pedge = 0;
1044 if (m_ve_hash.find(venode) != m_ve_hash.end())
1045 pedge = m_ve_hash[venode];
1049 unsigned int enode = *index_run++;
1052 VC_Element *ipnode = 0;
1053 ipnode = m_vc_hash[inode];
1056 VC_Element *epnode = 0;
1057 epnode = m_vc_hash[enode];
1060 if (pedge && pedge->nCount) {
1064 long long key = ((
unsigned long long)inode << 32) + venode;
1066 connector_segment *pcs = NULL;
1067 csit = ce_connector_hash.find(key);
1068 if (csit == ce_connector_hash.end()) {
1070 pcs =
new connector_segment;
1071 ce_connector_hash[key] = pcs;
1075 float *ppt = ipnode->pPoint;
1080 pair.e1 = pedge->pPoints[0];
1081 pair.n1 = pedge->pPoints[1];
1083 int last_point_index = (pedge->nCount - 1) * 2;
1084 pair.e1 = pedge->pPoints[last_point_index];
1085 pair.n1 = pedge->pPoints[last_point_index + 1];
1088 connector_segment_vector.push_back(pair);
1089 pcs->vbo_offset = seg_pair_index;
1096 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1098 pcs->cs_lat_avg = lat;
1099 pcs->cs_lon_avg = lon;
1104 line_segment_element *pls =
new line_segment_element;
1109 pls->ls_type = TYPE_CE;
1111 le_current->next = pls;
1116 if (pedge && pedge->nCount) {
1117 line_segment_element *pls =
new line_segment_element;
1122 pls->ls_type = TYPE_EE;
1123 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1125 le_current->next = pls;
1133 if (pedge && pedge->nCount) {
1134 long long key = ((
unsigned long long)venode << 32) + enode;
1136 connector_segment *pcs = NULL;
1137 csit = ec_connector_hash.find(key);
1138 if (csit == ec_connector_hash.end()) {
1140 pcs =
new connector_segment;
1141 ec_connector_hash[key] = pcs;
1147 pair.e0 = pedge->pPoints[0];
1148 pair.n0 = pedge->pPoints[1];
1150 int last_point_index = (pedge->nCount - 1) * 2;
1151 pair.e0 = pedge->pPoints[last_point_index];
1152 pair.n0 = pedge->pPoints[last_point_index + 1];
1155 float *ppt = epnode->pPoint;
1159 connector_segment_vector.push_back(pair);
1160 pcs->vbo_offset = seg_pair_index;
1167 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1169 pcs->cs_lat_avg = lat;
1170 pcs->cs_lon_avg = lon;
1175 line_segment_element *pls =
new line_segment_element;
1179 pls->ls_type = TYPE_EC;
1181 le_current->next = pls;
1185 long long key = ((
unsigned long long)inode << 32) + enode;
1187 connector_segment *pcs = NULL;
1188 csit = cc_connector_hash.find(key);
1189 if (csit == cc_connector_hash.end()) {
1191 pcs =
new connector_segment;
1192 cc_connector_hash[key] = pcs;
1197 float *ppt = ipnode->pPoint;
1201 ppt = epnode->pPoint;
1205 connector_segment_vector.push_back(pair);
1206 pcs->vbo_offset = seg_pair_index;
1213 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1215 pcs->cs_lat_avg = lat;
1216 pcs->cs_lon_avg = lon;
1221 line_segment_element *pls =
new line_segment_element;
1225 pls->ls_type = TYPE_CC;
1227 le_current->next = pls;
1241 if (obj->m_ls_list == NULL) {
1242 obj->m_n_lsindex = 0;
1246 free(obj->m_lsindex_array);
1247 obj->m_lsindex_array = NULL;
1260 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1262 unsigned char *buffer_offset;
1265 bool grow_buffer =
false;
1267 if (0 == m_vbo_byte_length) {
1268 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1269 m_vbo_byte_length = vbo_byte_length;
1270 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1273 m_line_vertex_buffer = (
float *)realloc(
1274 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1275 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1276 offset = m_vbo_byte_length;
1277 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1281 float *lvr = (
float *)buffer_offset;
1285 for (
const auto &it : m_ve_hash) {
1286 VE_Element *pedge = it.second;
1288 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1289 lvr += pedge->nCount * 2;
1291 pedge->vbo_offset = offset;
1292 offset += pedge->nCount * 2 *
sizeof(float);
1305 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1307 connector_segment *pcs = csit->second;
1308 m_pcs_vector.push_back(pcs);
1310 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1316 pcs->vbo_offset = offset;
1317 offset += 4 *
sizeof(float);
1320 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1322 connector_segment *pcs = csit->second;
1323 m_pcs_vector.push_back(pcs);
1325 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1331 pcs->vbo_offset = offset;
1332 offset += 4 *
sizeof(float);
1335 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1337 connector_segment *pcs = csit->second;
1338 m_pcs_vector.push_back(pcs);
1340 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1346 pcs->vbo_offset = offset;
1347 offset += 4 *
sizeof(float);
1351 connector_segment_vector.clear();
1356 for (
const auto &it : m_ve_hash) {
1357 VE_Element *pedge = it.second;
1359 m_pve_vector.push_back(pedge);
1360 free(pedge->pPoints);
1368 for (
const auto &it : m_vc_hash) {
1369 VC_Element *pcs = it.second;
1370 if (pcs) free(pcs->pPoint);
1376 if (g_b_EnableVBO) {
1378 if (m_LineVBO_name > 0) {
1379 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1380 m_LineVBO_name = -1;
1387void s57chart::BuildLineVBO(
void) {
1389 if (!g_b_EnableVBO)
return;
1391 if (m_LineVBO_name == -1) {
1394 glGenBuffers(1, &vboId);
1397 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1403#ifndef USE_ANDROID_GLES2
1404 glEnableClientState(GL_VERTEX_ARRAY);
1406 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1411 ObjRazRules *top, *crnt;
1412 int vbo_area_size_bytes = 0;
1413 for (
int i = 0; i < PRIO_NUM; ++i) {
1414 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1415 top = razRules[i][4];
1417 top = razRules[i][3];
1419 while (top != NULL) {
1424 PolyTriGroup *ppg_vbo =
1425 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1427 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1434 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes, NULL,
1437 GLenum err = glGetError();
1440 msg.Printf(
"S57 VBO Error 1: %d", err);
1442 printf(
"S57 VBO Error 1: %d", err);
1446 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length,
1447 m_line_vertex_buffer);
1452 msg.Printf(
"S57 VBO Error 2: %d", err);
1454 printf(
"S57 VBO Error 2: %d", err);
1458 int vbo_load_offset = m_vbo_byte_length;
1460 for (
int i = 0; i < PRIO_NUM; ++i) {
1461 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1462 top = razRules[i][4];
1464 top = razRules[i][3];
1466 while (top != NULL) {
1471 PolyTriGroup *ppg_vbo =
1472 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1475 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1476 ppg_vbo->single_buffer_size, ppg_vbo->single_buffer);
1478 crnt->obj->vboAreaOffset = vbo_load_offset;
1479 vbo_load_offset += ppg_vbo->single_buffer_size;
1486 msg.Printf(
"S57 VBO Error 3: %d", err);
1488 printf(
"S57 VBO Error 3: %d", err);
1493#ifndef USE_ANDROID_GLES2
1494 glDisableClientState(GL_VERTEX_ARRAY);
1496 glBindBuffer(GL_ARRAY_BUFFER, 0);
1500 for (
int i = 0; i < PRIO_NUM; ++i) {
1501 for (
int j = 0; j < LUPNAME_NUM; j++) {
1502 ObjRazRules *top = razRules[i][j];
1503 while (top != NULL) {
1504 S57Obj *obj = top->obj;
1505 obj->auxParm2 = vboId;
1511 m_LineVBO_name = vboId;
1512 m_this_chart_context->vboID = vboId;
1531bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1534 const LLRegion &Region) {
1535 if (!m_RAZBuilt)
return false;
1537 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1540bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1543 const LLRegion &Region) {
1544 if (!m_RAZBuilt)
return false;
1546 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1549bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1552 const LLRegion &Region) {
1553 if (!m_RAZBuilt)
return false;
1555 bool b_text = ps52plib->GetShowS57Text();
1556 ps52plib->m_bShowS57Text =
false;
1557 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1558 ps52plib->m_bShowS57Text = b_text;
1563bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1565 if (!m_RAZBuilt)
return false;
1569 if (!ps52plib)
return false;
1572 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1574 glChartCanvas::DisableClipRegion();
1575 DoRenderOnGLText(glc, VPoint);
1581bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1584 const LLRegion &Region,
bool b_overlay) {
1585 if (!m_RAZBuilt)
return false;
1589 if (!ps52plib)
return false;
1591 if (g_bDebugS57) printf(
"\n");
1595 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1597 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1598 m_bLinePrioritySet =
false;
1600 ClearRenderedTextCache();
1602 ResetPointBBoxes(m_last_vp, VPoint);
1605 m_plib_state_hash = ps52plib->GetStateHash();
1609 ResetPointBBoxes(m_last_vp, VPoint);
1613 SetLinePriorities();
1616 ps52plib->ClearTextList();
1624 wxRect upr = upd.GetRect();
1627 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1628 chart_region.Intersect(Region);
1630 if (!chart_region.Empty()) {
1634 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1641 if (CHART_TYPE_CM93 == GetChartType()) {
1645 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1648#ifdef OPT_USE_ANDROID_GLES2
1656 wxRect r = upd.GetRect();
1658 glViewport(r.x, vp->
pix_height - (r.y + r.height), r.width, r.height);
1666 float yp = vp->
pix_height - (r.y + r.height);
1668 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1669 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1672 I[0][0] *= 2.0 / (float)r.width;
1673 I[1][1] *= -2.0 / (float)r.height;
1677 mat4x4_rotate_Z(Q, I, angle);
1679 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1682 ps52plib->SetReducedBBox(cvp.GetBBox());
1683 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1688 DoRenderOnGL(glc, cvp);
1690 glChartCanvas::DisableClipRegion();
1703bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1716 for (i = 0; i < PRIO_NUM; ++i) {
1717 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1718 top = razRules[i][4];
1720 top = razRules[i][3];
1722 while (top != NULL) {
1725 crnt->sm_transform_parms = &vp_transform;
1726 ps52plib->RenderAreaToGL(glc, crnt);
1732 for (i = 0; i < PRIO_NUM; ++i) {
1734 top = razRules[i][4];
1736 top = razRules[i][3];
1738 while (top != NULL) {
1741 crnt->sm_transform_parms = &vp_transform;
1746 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1747 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1748 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1749 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1752 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1759 for (i = 0; i < PRIO_NUM; ++i) {
1760 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1761 top = razRules[i][4];
1763 top = razRules[i][3];
1764 while (top != NULL) {
1767 crnt->sm_transform_parms = &vp_transform;
1768 ps52plib->RenderObjectToGL(glc, crnt);
1773 for (i = 0; i < PRIO_NUM; ++i) {
1774 top = razRules[i][2];
1775 while (top != NULL) {
1778 crnt->sm_transform_parms = &vp_transform;
1779 ps52plib->RenderObjectToGL(glc, crnt);
1785 for (i = 0; i < PRIO_NUM; ++i) {
1786 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1787 top = razRules[i][0];
1789 top = razRules[i][1];
1791 while (top != NULL) {
1794 crnt->sm_transform_parms = &vp_transform;
1795 ps52plib->RenderObjectToGL(glc, crnt);
1805bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1816 for( i = 0; i < PRIO_NUM; ++i ) {
1817 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1818 top = razRules[i][4];
1820 top = razRules[i][3];
1822 while( top != NULL ) {
1825 crnt->sm_transform_parms = &vp_transform;
1832 for (i = 0; i < PRIO_NUM; ++i) {
1833 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1834 top = razRules[i][4];
1836 top = razRules[i][3];
1838 while (top != NULL) {
1841 crnt->sm_transform_parms = &vp_transform;
1842 ps52plib->RenderObjectToGLText(glc, crnt);
1845 top = razRules[i][2];
1846 while (top != NULL) {
1849 crnt->sm_transform_parms = &vp_transform;
1850 ps52plib->RenderObjectToGLText(glc, crnt);
1853 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1854 top = razRules[i][0];
1856 top = razRules[i][1];
1858 while (top != NULL) {
1861 crnt->sm_transform_parms = &vp_transform;
1862 ps52plib->RenderObjectToGLText(glc, crnt);
1871bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1874 if (!m_RAZBuilt)
return false;
1876 bool b_text = ps52plib->GetShowS57Text();
1877 ps52plib->m_bShowS57Text =
false;
1878 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1879 ps52plib->m_bShowS57Text = b_text;
1884bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1887 if (!dc.IsOk())
return false;
1890 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1895 DCRenderText(dc, VPoint);
1898 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1902 while (upd.HaveRects()) {
1903 wxRect rect = upd.GetRect();
1909 temp_vp.
GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1913 temp_vp.
GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1915 if (temp_lon_right < temp_lon_left)
1916 temp_lon_right += 360.;
1918 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1921 wxDCClipper clip(dc, rect);
1922 DCRenderText(dc, temp_vp);
1931bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1933 if (!m_RAZBuilt)
return false;
1935 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1938bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1941 if (!m_RAZBuilt)
return false;
1942 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1945bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1950 bool force_new_view =
false;
1952 if (Region != m_last_Region) force_new_view =
true;
1954 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1956 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1957 m_bLinePrioritySet =
false;
1959 ClearRenderedTextCache();
1961 ResetPointBBoxes(m_last_vp, VPoint);
1966 ResetPointBBoxes(m_last_vp, VPoint);
1969 SetLinePriorities();
1971 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1975 if (VPoint.b_quilt) {
1977 if ((m_pCloneBM->GetWidth() != VPoint.
pix_width) ||
1978 (m_pCloneBM->GetHeight() != VPoint.
pix_height)) {
1983 if (NULL == m_pCloneBM)
1986 wxMemoryDC dc_clone;
1987 dc_clone.SelectObject(*m_pCloneBM);
1989#ifdef ocpnUSE_DIBSECTION
1992 wxMemoryDC memdc, dc_org;
1995 pDIB->SelectIntoDC(dc_org);
2000 while (upd.HaveRects()) {
2001 wxRect rect = upd.GetRect();
2002 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
2007 dc_clone.SelectObject(wxNullBitmap);
2008 dc_org.SelectObject(wxNullBitmap);
2012 wxColour nodat = GetGlobalColor(_T (
"NODTA" ));
2013 wxColour nodat_sub = nodat;
2015#ifdef ocpnUSE_ocpnBitmap
2016 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
2018 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
2019 m_pCloneBM->SetMask(m_pMask);
2022 dc.SelectObject(*m_pCloneBM);
2024 pDIB->SelectIntoDC(dc);
2026 m_last_Region = Region;
2031bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2036 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2038 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2039 m_bLinePrioritySet =
false;
2041 ClearRenderedTextCache();
2045 SetLinePriorities();
2047 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2049 pDIB->SelectIntoDC(dc);
2056bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2057 RenderTypeEnum option,
bool force_new_view) {
2058 bool bnewview =
false;
2060 bool bNewVP =
false;
2062 bool bReallyNew =
false;
2064 double easting_ul, northing_ul;
2065 double easting_lr, northing_lr;
2066 double prev_easting_ul = 0., prev_northing_ul = 0.;
2068 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2069 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2078 if (m_last_vprect != dest) bReallyNew =
true;
2079 m_last_vprect = dest;
2081 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2083 m_plib_state_hash = ps52plib->GetStateHash();
2094 if (m_last_vp.IsValid()) {
2096 m_easting_vp_center - ((VPoint.
pix_width / 2) / m_view_scale_ppm);
2098 m_northing_vp_center + ((VPoint.
pix_height / 2) / m_view_scale_ppm);
2099 easting_lr = easting_ul + (VPoint.
pix_width / m_view_scale_ppm);
2100 northing_lr = northing_ul - (VPoint.
pix_height / m_view_scale_ppm);
2102 double last_easting_vp_center, last_northing_vp_center;
2103 toSM(m_last_vp.
clat, m_last_vp.
clon, ref_lat, ref_lon,
2104 &last_easting_vp_center, &last_northing_vp_center);
2107 last_easting_vp_center - ((m_last_vp.
pix_width / 2) / m_view_scale_ppm);
2108 prev_northing_ul = last_northing_vp_center +
2109 ((m_last_vp.
pix_height / 2) / m_view_scale_ppm);
2111 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2112 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2114 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2115 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2117 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2118 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2120 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2123 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2132 else if ((rul.x != 0) || (rul.y != 0)) {
2133 if (g_bDebugS57) printf(
"newvp due to rul\n");
2144 if (force_new_view) bNewVP =
true;
2149 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2150 rgn_last.Intersect(rgn_new);
2152 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2154 rgn_last.GetBox(xu, yu, wu, hu);
2171 pDIB->SelectIntoDC(dc_last);
2176 pDIBNew->SelectIntoDC(dc_new);
2180 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2185 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.
pix_width,
2188 dc_new.SelectObject(wxNullBitmap);
2189 dc_last.SelectObject(wxNullBitmap);
2197 pDIB->SelectIntoDC(dc);
2201 rgn_delta.Subtract(rgn_reused);
2204 while (upd.HaveRects()) {
2205 wxRect rect = upd.GetRect();
2210 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2212 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2213 (rect.y / m_view_scale_ppm);
2214 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2215 (rect.x / m_view_scale_ppm);
2216 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2219 double temp_northing_lr =
2220 temp_northing_ul - (rect.height / m_view_scale_ppm);
2221 double temp_easting_lr =
2222 temp_easting_ul + (rect.width / m_view_scale_ppm);
2223 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2226 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2231 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2232 temp_vp.GetBBox().GetLatRange()) *
2234 temp_vp.GetBBox().EnLarge(margin);
2240 DCRenderRect(dc, temp_vp, &rect);
2245 dc.SelectObject(wxNullBitmap);
2254 else if (bNewVP || (NULL == pDIB)) {
2260 pDIB->SelectIntoDC(dc);
2263 ps52plib->ClearTextList();
2265 DCRenderRect(dc, VPoint, &full_rect);
2267 dc.SelectObject(wxNullBitmap);
2278int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2291 render_canvas_parms pb_spec;
2293 pb_spec.depth = BPP;
2294 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2295 pb_spec.lclip = rect->x;
2296 pb_spec.rclip = rect->x + rect->width - 1;
2297 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2298 pb_spec.width = rect->width;
2299 pb_spec.height = rect->height;
2300 pb_spec.x = rect->x;
2301 pb_spec.y = rect->y;
2303#ifdef ocpnUSE_ocpnBitmap
2304 pb_spec.b_revrgb =
true;
2306 pb_spec.b_revrgb =
false;
2310 wxColour color = GetGlobalColor(_T (
"NODTA" ));
2311 unsigned char r, g, b;
2319 if (pb_spec.depth == 24) {
2320 for (
int i = 0; i < pb_spec.height; i++) {
2321 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2322 for (
int j = 0; j < pb_spec.width; j++) {
2329 int color_int = ((r) << 16) + ((g) << 8) + (b);
2331 for (
int i = 0; i < pb_spec.height; i++) {
2332 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2333 for (
int j = 0; j < pb_spec.width; j++) {
2340 for (i = 0; i < PRIO_NUM; ++i) {
2341 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2342 top = razRules[i][4];
2344 top = razRules[i][3];
2346 while (top != NULL) {
2349 crnt->sm_transform_parms = &vp_transform;
2350 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2355#ifdef ocpnUSE_ocpnBitmap
2356 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2357 pb_spec.height, pb_spec.depth);
2359 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2360 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2361 wxBitmap *pREN =
new wxBitmap(*prender_image);
2367 dc_ren.SelectObject(*pREN);
2370 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2371 (wxDC *)&dc_ren, 0, 0);
2374 dc_ren.SelectObject(wxNullBitmap);
2376#ifdef ocpnUSE_ocpnBitmap
2377 free(pb_spec.pix_buff);
2379 delete prender_image;
2386 DCRenderLPB(dcinput, vp, rect);
2391bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2398 for (i = 0; i < PRIO_NUM; ++i) {
2400 wxDCClipper *pdcc = NULL;
2406 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2407 top = razRules[i][4];
2409 top = razRules[i][3];
2410 while (top != NULL) {
2413 crnt->sm_transform_parms = &vp_transform;
2414 ps52plib->RenderObjectToDC(&dcinput, crnt);
2417 top = razRules[i][2];
2418 while (top != NULL) {
2421 crnt->sm_transform_parms = &vp_transform;
2422 ps52plib->RenderObjectToDC(&dcinput, crnt);
2425 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2426 top = razRules[i][0];
2428 top = razRules[i][1];
2430 while (top != NULL) {
2433 crnt->sm_transform_parms = &vp_transform;
2434 ps52plib->RenderObjectToDC(&dcinput, crnt);
2438 if (pdcc)
delete pdcc;
2451bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2457 for (i = 0; i < PRIO_NUM; ++i) {
2458 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2459 top = razRules[i][4];
2461 top = razRules[i][3];
2463 while (top != NULL) {
2466 crnt->sm_transform_parms = &vp_transform;
2467 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2470 top = razRules[i][2];
2471 while (top != NULL) {
2474 crnt->sm_transform_parms = &vp_transform;
2475 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2478 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2479 top = razRules[i][0];
2481 top = razRules[i][1];
2483 while (top != NULL) {
2486 crnt->sm_transform_parms = &vp_transform;
2487 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2494bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2495 wxFileName fn(FullPath);
2497 wxString cname = fn.GetName();
2498 if (cname.Length() >= 3)
2499 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2504InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2507 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2510 if (name.Upper().EndsWith(
".XZ")) {
2511 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2514 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2515 wxFileName(name).GetName();
2517 if (!wxFileExists(m_TempFilePath) &&
2518 !DecompressXZFile(name, m_TempFilePath)) {
2519 wxRemoveFile(m_TempFilePath);
2520 return INIT_FAIL_REMOVE;
2523 m_TempFilePath = name;
2524 ext = wxFileName(name).GetExt();
2529 firebase::crashlytics::SetCustomKey(
"s57chartInit",
2530 name.ToStdString().c_str());
2537 return INIT_FAIL_NOERROR;
2542 InitReturn ret_value = INIT_OK;
2544 m_Description = name;
2546 wxFileName fn(m_TempFilePath);
2549 wxString cname = fn.GetName();
2550 m_usage_char = cname[2];
2553 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2554 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2556 if (flags == THUMB_ONLY) {
2564 if (flags == HEADER_ONLY) {
2566 if (!GetBaseFileAttr(fn.GetFullPath()))
2567 ret_value = INIT_FAIL_REMOVE;
2569 if (!CreateHeaderDataFromENC())
2570 ret_value = INIT_FAIL_REMOVE;
2572 ret_value = INIT_OK;
2574 }
else if (ext ==
"S57") {
2575 m_SENCFileName = m_TempFilePath;
2576 if (!CreateHeaderDataFromSENC())
2577 ret_value = INIT_FAIL_REMOVE;
2579 ret_value = INIT_OK;
2588 if (!m_bbase_file_attr_known) {
2589 if (!GetBaseFileAttr(m_TempFilePath))
2590 ret_value = INIT_FAIL_REMOVE;
2592 m_bbase_file_attr_known =
true;
2596 if (m_bbase_file_attr_known) {
2597 int sret = FindOrCreateSenc(m_FullPath);
2598 if (sret == BUILD_SENC_PENDING) {
2603 if (sret != BUILD_SENC_OK) {
2604 if (sret == BUILD_SENC_NOK_RETRY)
2605 ret_value = INIT_FAIL_RETRY;
2607 ret_value = INIT_FAIL_REMOVE;
2609 ret_value = PostInit(flags, m_global_color_scheme);
2614 else if (ext ==
"S57") {
2615 m_SENCFileName = m_TempFilePath;
2616 ret_value = PostInit(flags, m_global_color_scheme);
2623wxString s57chart::buildSENCName(
const wxString &name) {
2624 wxFileName fn(name);
2626 wxString file_name = fn.GetFullName();
2629 wxString SENCdir = g_SENCPrefix;
2631 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2632 SENCdir.Append(wxFileName::GetPathSeparator());
2635 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2636 wxCharBuffer buf = source_dir.ToUTF8();
2637 unsigned char sha1_out[20];
2638 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2641 for (
unsigned int i = 0; i < 6; i++) {
2643 s.Printf(
"%02X", sha1_out[i]);
2647 file_name.Prepend(sha1);
2650 wxFileName tsfn(SENCdir);
2651 tsfn.SetFullName(file_name);
2653 return tsfn.GetFullPath();
2660int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2664 if (name.Upper().EndsWith(
".XZ")) {
2665 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2668 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2669 wxFileName(name).GetName();
2671 if (!wxFileExists(m_TempFilePath) &&
2672 !DecompressXZFile(name, m_TempFilePath)) {
2673 wxRemoveFile(m_TempFilePath);
2674 return INIT_FAIL_REMOVE;
2677 m_TempFilePath = name;
2678 ext = wxFileName(name).GetExt();
2682 if (!m_bbase_file_attr_known) {
2683 if (!GetBaseFileAttr(m_TempFilePath))
2684 return INIT_FAIL_REMOVE;
2686 m_bbase_file_attr_known =
true;
2690 m_SENCFileName = buildSENCName(name);
2692 int build_ret_val = 1;
2694 bool bbuild_new_senc =
false;
2695 m_bneed_new_thumbnail =
false;
2697 wxFileName FileName000(m_TempFilePath);
2701 wxString msg(
"S57chart::Checking SENC file: ");
2702 msg.Append(m_SENCFileName);
2706 int force_make_senc = 0;
2708 if (::wxFileExists(m_SENCFileName)) {
2711 if (senc.ingestHeader(m_SENCFileName)) {
2712 bbuild_new_senc =
true;
2713 wxLogMessage(
" Rebuilding SENC due to ingestHeader failure.");
2715 int senc_file_version = senc.getSencReadVersion();
2717 int last_update = senc.getSENCReadLastUpdate();
2719 wxString str = senc.getSENCFileCreateDate();
2720 wxDateTime SENCCreateDate;
2721 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
2723 if (SENCCreateDate.IsValid())
2724 SENCCreateDate.ResetTime();
2729 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2731 senc_base_edtn.ToLong(&isenc_edition);
2733 m_edtn000.ToLong(&ifile_edition);
2738 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2739 bbuild_new_senc =
true;
2740 wxLogMessage(
" Rebuilding SENC due to SENC format update.");
2747 else if (ifile_edition > isenc_edition) {
2748 bbuild_new_senc =
true;
2749 wxLogMessage(
" Rebuilding SENC due to cell edition update.");
2751 msg =
" Last edition recorded in SENC: ";
2752 msg += senc_base_edtn;
2753 msg +=
" most recent edition cell file: ";
2758 int most_recent_update_file =
2759 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2761 if (ifile_edition == isenc_edition) {
2762 if (most_recent_update_file > last_update) {
2763 bbuild_new_senc =
true;
2765 " Rebuilding SENC due to incremental cell update.");
2768 " Last update recorded in SENC: %d most recent "
2770 last_update, most_recent_update_file);
2778 wxDateTime OModTime000;
2779 FileName000.GetTimes(NULL, &OModTime000, NULL);
2780 OModTime000.ResetTime();
2781 if (SENCCreateDate.IsValid()) {
2782 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2784 " Rebuilding SENC due to Senc vs cell file time "
2786 bbuild_new_senc =
true;
2789 bbuild_new_senc =
true;
2791 " Rebuilding SENC due to SENC create time invalid.");
2802 if (force_make_senc) bbuild_new_senc =
true;
2804 }
else if (!::wxFileExists(m_SENCFileName))
2806 wxLogMessage(
" Rebuilding SENC due to missing SENC file.");
2807 bbuild_new_senc =
true;
2811 if (bbuild_new_senc) {
2812 m_bneed_new_thumbnail =
2814 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2816 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2817 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2818 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2824InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2826 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2827 wxString msg(
" Cannot load SENC file ");
2828 msg.Append(m_SENCFileName);
2831 return INIT_FAIL_RETRY;
2837 wxString SENCdir = g_SENCPrefix;
2838 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2839 SENCdir.Append(wxFileName::GetPathSeparator());
2841 wxFileName s57File(m_SENCFileName);
2842 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13),
"BMP");
2844 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2845 BuildThumbnail(ThumbFileName.GetFullPath());
2848 if (ThumbFileName.FileExists()) {
2850#ifdef ocpnUSE_ocpnBitmap
2851 pBMP_NEW =
new ocpnBitmap;
2853 pBMP_NEW =
new wxBitmap;
2855 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2858 m_pDIBThumbDay = pBMP_NEW;
2866 m_global_color_scheme = cs;
2867 SetColorScheme(cs,
false);
2870 BuildDepthContourArray();
2872 CreateChartContext();
2873 PopulateObjectsWithContext();
2876 bReadyToRender =
true;
2881void s57chart::ClearDepthContourArray(
void) {
2882 if (m_nvaldco_alloc) {
2883 free(m_pvaldco_array);
2885 m_nvaldco_alloc = 5;
2887 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2890void s57chart::BuildDepthContourArray(
void) {
2893 if (0 == m_nvaldco_alloc) {
2894 m_nvaldco_alloc = 5;
2895 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2901 double prev_valdco = 0.0;
2903 for (
int i = 0; i < PRIO_NUM; ++i) {
2904 for (
int j = 0; j < LUPNAME_NUM; j++) {
2905 top = razRules[i][j];
2906 while (top != NULL) {
2907 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2908 double valdco = 0.0;
2909 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2910 if (valdco != prev_valdco) {
2911 prev_valdco = valdco;
2913 if (m_nvaldco > m_nvaldco_alloc) {
2914 void *tr = realloc((
void *)m_pvaldco_array,
2915 m_nvaldco_alloc * 2 *
sizeof(
double));
2916 m_pvaldco_array = (
double *)tr;
2917 m_nvaldco_alloc *= 2;
2919 m_pvaldco_array[m_nvaldco - 1] = valdco;
2923 ObjRazRules *nxx = top->next;
2928 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2932void s57chart::SetSafetyContour(
void) {
2940 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2943 if (NULL != m_pvaldco_array) {
2944 for (i = 0; i < m_nvaldco; i++) {
2945 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2949 m_next_safe_cnt = m_pvaldco_array[i];
2951 m_next_safe_cnt = (double)1e6;
2953 m_next_safe_cnt = (double)1e6;
2958 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2959 m_next_safe_cnt = (
double)1e6;
2962void s57chart::CreateChartContext() {
2964 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2967void s57chart::PopulateObjectsWithContext() {
2968 m_this_chart_context->chart =
this;
2969 m_this_chart_context->chart_type = GetChartType();
2970 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2971 m_this_chart_context->chart_scale = GetNativeScale();
2972 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2973 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2974 m_this_chart_context->safety_contour = m_next_safe_cnt;
2975 m_this_chart_context->pt2GetAssociatedObjects =
2976 &s57chart::GetAssociatedObjects;
2980 for (
int i = 0; i < PRIO_NUM; ++i) {
2981 for (
int j = 0; j < LUPNAME_NUM; j++) {
2982 top = razRules[i][j];
2983 while (top != NULL) {
2984 S57Obj *obj = top->obj;
2985 obj->m_chart_context = m_this_chart_context;
2992void s57chart::InvalidateCache() {
2997bool s57chart::BuildThumbnail(
const wxString &bmpname) {
3000 wxFileName ThumbFileName(bmpname);
3003 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
3004 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
3005 wxLogMessage(
" Cannot create BMP file directory for " +
3006 ThumbFileName.GetFullPath());
3014 vp.
clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
3015 vp.
clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
3017 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
3018 (m_FullExtent.ELON - m_FullExtent.WLON));
3025 vp.m_projection_type = PROJECTION_MERCATOR;
3027 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3044 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3046 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3048 int *psvr = psave_viz;
3052 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3053 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3054 *psvr++ = pOLE->nViz;
3059 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3060 bool bsave_text = ps52plib->m_bShowS57Text;
3063 ps52plib->SaveObjNoshow();
3066 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3067 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3068 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3069 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3072 ps52plib->m_bShowSoundg =
false;
3073 ps52plib->m_bShowS57Text =
false;
3076 DisCat dsave = ps52plib->GetDisplayCategory();
3077 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3079 ps52plib->AddObjNoshow(
"BRIDGE");
3080 ps52plib->AddObjNoshow(
"GATCON");
3082 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3083 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3084 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3085 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3087#ifdef ocpnUSE_DIBSECTION
3090 wxMemoryDC memdc, dc_org;
3094 ps52plib->SaveColorScheme();
3095 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3097 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3100 memdc.SelectObject(wxNullBitmap);
3104 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3105 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3106 pOLE->nViz = *psvr++;
3109 ps52plib->SetDisplayCategory(dsave);
3110 ps52plib->RestoreObjNoshow();
3112 ps52plib->RemoveObjNoshow(
"BRIDGE");
3113 ps52plib->RemoveObjNoshow(
"GATCON");
3115 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3116 ps52plib->m_bShowS57Text = bsave_text;
3118 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3119 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3122 ps52plib->RestoreColorScheme();
3132 wxMemoryDC dc_clone;
3133 dc_clone.SelectObject(*pBMP);
3135 pDIB->SelectIntoDC(dc_org);
3139 dc_clone.SelectObject(wxNullBitmap);
3140 dc_org.SelectObject(wxNullBitmap);
3143 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3150#include <wx/arrimpl.cpp>
3151WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3154bool s57chart::CreateHeaderDataFromENC(
void) {
3155 if (!InitENCMinimal(m_TempFilePath)) {
3156 wxString msg(
" Cannot initialize ENC file ");
3157 msg.Append(m_TempFilePath);
3165 float LatMax, LatMin, LonMax, LonMin;
3171 m_pCOVRTablePoints = NULL;
3172 m_pCOVRTable = NULL;
3175 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3176 std::vector<int> auxCntArray, noCovrCntArray;
3178 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3181 pFeat = GetChartFirstM_COVR(catcov);
3186 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3187 OGRLinearRing *xring = poly->getExteriorRing();
3189 int npt = xring->getNumPoints();
3200 for (
int i = 0; i < npt; i++) {
3201 xring->getPoint(i, &p);
3205 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3207 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3208 if (xdelta < 0.001 &&
3216 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3217 pfr = &pf[2 * (usedpts - 1)];
3220 LatMax = fmax(LatMax, p.getY());
3221 LatMin = fmin(LatMin, p.getY());
3222 LonMax = fmax(LonMax, p.getX());
3223 LonMin = fmin(LonMin, p.getX());
3231 pAuxPtrArray->Add(pf);
3232 auxCntArray.push_back(usedpts);
3233 }
else if (catcov == 2) {
3234 pNoCovrPtrArray->Add(pf);
3235 noCovrCntArray.push_back(usedpts);
3240 pFeat = GetChartNextM_COVR(catcov);
3241 DEBUG_LOG <<
"used " << usedpts <<
" points";
3246 m_nCOVREntries = auxCntArray.size();
3250 if (m_nCOVREntries >= 1) {
3251 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3252 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3254 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3255 m_pCOVRTablePoints[j] = auxCntArray[j];
3256 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3262 wxString msg(
" ENC contains no useable M_COVR, CATCOV=1 features: ");
3263 msg.Append(m_TempFilePath);
3268 m_nNoCOVREntries = noCovrCntArray.size();
3270 if (m_nNoCOVREntries) {
3272 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3273 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3275 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3276 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3277 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3280 m_pNoCOVRTablePoints = NULL;
3281 m_pNoCOVRTable = NULL;
3284 delete pAuxPtrArray;
3285 delete pNoCovrPtrArray;
3287 if (0 == m_nCOVREntries) {
3288 wxString msg(
" ENC contains no M_COVR features: ");
3289 msg.Append(m_TempFilePath);
3292 msg =
" Calculating Chart Extents as fallback.";
3298 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3300 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3307 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3308 *m_pCOVRTablePoints = 4;
3309 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3310 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3327 wxString msg(
" Cannot calculate Extents for ENC: ");
3328 msg.Append(m_TempFilePath);
3336 m_FullExtent.NLAT = LatMax;
3337 m_FullExtent.SLAT = LatMin;
3338 m_FullExtent.ELON = LonMax;
3339 m_FullExtent.WLON = LonMin;
3340 m_bExtentSet =
true;
3343 m_Chart_Scale = GetENCScale();
3346 GetChartNameFromTXT(m_TempFilePath, nice_name);
3354bool s57chart::CreateHeaderDataFromoSENC(
void) {
3355 bool ret_val =
true;
3357 wxFFileInputStream fpx(m_SENCFileName);
3359 if (!::wxFileExists(m_SENCFileName)) {
3360 wxString msg(
" Cannot open SENC file ");
3361 msg.Append(m_SENCFileName);
3368 if (senc.ingestHeader(m_SENCFileName)) {
3374 m_Chart_Scale = senc.getSENCReadScale();
3377 m_Name = senc.getReadName();
3380 m_ID = senc.getReadID();
3383 Extent &ext = senc.getReadExtent();
3385 m_FullExtent.ELON = ext.ELON;
3386 m_FullExtent.WLON = ext.WLON;
3387 m_FullExtent.NLAT = ext.NLAT;
3388 m_FullExtent.SLAT = ext.SLAT;
3389 m_bExtentSet =
true;
3392 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3393 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3395 m_nCOVREntries = AuxCntArray.size();
3397 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3398 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3400 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3401 m_pCOVRTablePoints[j] = AuxCntArray[j];
3402 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3403 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3404 AuxCntArray[j] * 2 *
sizeof(
float));
3408 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3409 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3411 m_nNoCOVREntries = NoCovrCntArray.size();
3413 if (m_nNoCOVREntries) {
3415 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3416 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3418 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3419 int npoints = NoCovrCntArray[j];
3420 m_pNoCOVRTablePoints[j] = npoints;
3421 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3422 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3423 npoints * 2 *
sizeof(
float));
3429 m_datum_str =
"WGS84";
3430 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
3432 int senc_file_version = senc.getSencReadVersion();
3434 int last_update = senc.getSENCReadLastUpdate();
3436 wxString str = senc.getSENCFileCreateDate();
3437 wxDateTime SENCCreateDate;
3438 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
3440 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3442 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3449bool s57chart::CreateHeaderDataFromSENC(
void) {
3450 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3458bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3460 if (NULL != m_pvaldco_array) {
3461 for (i = 0; i < m_nvaldco; i++) {
3462 if (m_pvaldco_array[i] >= safe_cnt)
break;
3466 next_safe_cnt = m_pvaldco_array[i];
3468 next_safe_cnt = (double)1e6;
3471 next_safe_cnt = (double)1e6;
3485std::list<S57Obj *> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3489 std::list<S57Obj *> *pobj_list =
new std::list<S57Obj *>();
3492 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3493 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3496 switch (obj->Primitive_type) {
3509 top = razRules[disPrioIdx][3];
3510 while (top != NULL) {
3511 if (top->obj->bIsAssociable) {
3512 if (top->obj->BBObj.Contains(lat, lon)) {
3513 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3514 pobj_list->push_back(top->obj);
3521 ObjRazRules *nxx = top->next;
3526 top = razRules[disPrioIdx][4];
3527 while (top != NULL) {
3528 if (top->obj->bIsAssociable) {
3529 if (top->obj->BBObj.Contains(lat, lon)) {
3530 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3531 pobj_list->push_back(top->obj);
3537 ObjRazRules *nxx = top->next;
3551void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3552 wxFileName fn(FullPath);
3554 wxString target_name = fn.GetName();
3555 target_name.RemoveLast();
3557 wxString dir_name = fn.GetPath();
3559 wxDir dir(dir_name);
3561 wxArrayString FileList;
3563 dir.GetAllFiles(fn.GetPath(), &FileList);
3567 bool found_name =
false;
3571 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3572 wxFileName file(FileList[j]);
3573 if (((file.GetExt()).MakeUpper()) ==
"TXT") {
3575 wxTextFile text_file(file.GetFullPath());
3577 bool file_ok =
true;
3581 if (!text_file.Open()) {
3582 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3587 wxString str = text_file.GetFirstLine();
3588 while (!text_file.Eof()) {
3589 if (0 == target_name.CmpNoCase(
3590 str.Mid(0, target_name.Len()))) {
3591 wxString tname = str.AfterFirst(
'-');
3592 name = tname.AfterFirst(
' ');
3596 str = text_file.GetNextLine();
3600 wxString msg(
" Error Reading ENC .TXT file: ");
3601 msg.Append(file.GetFullPath());
3607 if (found_name)
break;
3624const char *s57chart::getName(OGRFeature *feature) {
3625 return feature->GetDefnRef()->GetName();
3628static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3629 wxFileName fn1(first);
3630 wxFileName fn2(second);
3631 wxString ext1(fn1.GetExt());
3632 wxString ext2(fn2.GetExt());
3634 return ext1.Cmp(ext2);
3637int s57chart::GetUpdateFileArray(
const wxFileName file000,
3638 wxArrayString *UpFiles, wxDateTime date000,
3640 wxString DirName000 =
3641 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3642 wxDir dir(DirName000);
3643 if (!dir.IsOpened()) {
3644 DirName000.Prepend(wxFileName::GetPathSeparator());
3645 DirName000.Prepend(
".");
3646 dir.Open(DirName000);
3647 if (!dir.IsOpened()) {
3652 int flags = wxDIR_DEFAULT;
3659 wxFileName fnDir(DirName000);
3660 fnDir.RemoveLastDir();
3661 wxString sdir = fnDir.GetPath();
3662 wxFileName fnTest(sdir);
3663 wxString sname = fnTest.GetName();
3665 if (sname.ToLong(&tmps)) {
3668 flags |= wxDIR_DIRS;
3672 wxArrayString *dummy_array;
3675 if (UpFiles == NULL)
3676 dummy_array =
new wxArrayString;
3678 dummy_array = UpFiles;
3680 wxArrayString possibleFiles;
3681 wxDir::GetAllFiles(DirName000, &possibleFiles, wxEmptyString, flags);
3683 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3684 wxString filename(possibleFiles[i]);
3686 wxFileName file(filename);
3687 ext = file.GetExt();
3692 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3693 wxString FileToAdd = filename;
3695 wxCharBuffer buffer =
3698 if (buffer.data() && !filename.IsSameAs(
"CATALOG.031",
3710 DDFModule *poModule =
new DDFModule();
3711 if (!poModule->Open(FileToAdd.mb_str())) {
3713 " s57chart::BuildS57File Unable to open update file ");
3714 msg.Append(FileToAdd);
3723 DDFRecord *pr = poModule->ReadRecord();
3729 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3732 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3736 " s57chart::BuildS57File DDFRecord 0 does not contain "
3737 "DSID:ISDT in update file ");
3738 msg.Append(FileToAdd);
3741 sumdate =
"20000101";
3744 umdate.ParseFormat(sumdate,
"%Y%m%d");
3745 if (!umdate.IsValid()) umdate.ParseFormat(
"20000101",
"%Y%m%d");
3748 if (!umdate.IsValid())
int yyp = 4;
3753 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3755 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3759 " s57chart::BuildS57File DDFRecord 0 does not contain "
3760 "DSID:EDTN in update file ");
3761 msg.Append(FileToAdd);
3770 if ((!umdate.IsEarlierThan(date000)) &&
3771 (umedtn.IsSameAs(edtn000)))
3772 dummy_array->Add(FileToAdd);
3778 dummy_array->Sort(ExtensionCompare);
3781 if (dummy_array->GetCount()) {
3782 wxString Last = dummy_array->Last();
3783 wxFileName fnl(Last);
3785 wxCharBuffer buffer = ext.ToUTF8();
3786 if (buffer.data()) retval = atoi(buffer.data());
3789 if (UpFiles == NULL)
delete dummy_array;
3794int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3795 const wxString CopyDir,
3796 wxString &LastUpdateDate,
3802 wxArrayString *UpFiles =
new wxArrayString;
3803 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3805 if (UpFiles->GetCount()) {
3819 bool chain_broken_mssage_shown =
false;
3825 for (
int iff = 0; iff < retval + 1; iff++) {
3826 wxFileName ufile(m_TempFilePath);
3828 sext.Printf(
"%03d", iff);
3832 wxString cp_ufile = CopyDir;
3833 if (cp_ufile.Last() != ufile.GetPathSeparator())
3834 cp_ufile.Append(ufile.GetPathSeparator());
3836 cp_ufile.Append(ufile.GetFullName());
3841 if (ufile.FileExists()) {
3842 wxFile uf(ufile.GetFullPath());
3843 if (uf.IsOpened()) {
3849 if (ufile.FileExists() &&
3853 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3855 wxString msg(
" Cannot copy temporary working ENC file ");
3856 msg.Append(ufile.GetFullPath());
3858 msg.Append(cp_ufile);
3868 if (!chain_broken_mssage_shown) {
3871 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3872 "incomplete or inaccurate.\nCheck the logfile for details."),
3873 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3875 chain_broken_mssage_shown =
true;
3879 "WARNING---ENC Update chain incomplete. Substituting NULL "
3881 msg += ufile.GetFullName();
3883 wxLogMessage(
" Subsequent ENC updates may produce errors.");
3885 " This ENC exchange set should be updated and SENCs "
3889 DDFModule *dupdate =
new DDFModule;
3890 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3891 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3895 wxString msg(
" Error creating dummy update file: ");
3896 msg.Append(cp_ufile);
3901 m_tmpup_array->Add(cp_ufile);
3908 wxFileName lastfile(m_TempFilePath);
3910 last_sext.Printf(
"%03d", retval);
3911 lastfile.SetExt(last_sext);
3914 DDFModule oUpdateModule;
3919 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3923 oUpdateModule.Rewind();
3924 DDFRecord *pr = oUpdateModule.ReadRecord();
3930 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3934 LastUpdateDate = wxString(u, wxConvUTF8);
3937 wxDateTime now = wxDateTime::Now();
3938 LastUpdateDate = now.Format(
"%Y%m%d");
3947wxString s57chart::GetISDT(
void) {
3948 if (m_date000.IsValid())
3949 return m_date000.Format(
"%Y%m%d");
3954bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3955 if (!wxFileName::FileExists(file000))
return false;
3957 wxString FullPath000 = file000;
3958 DDFModule *poModule =
new DDFModule();
3959 if (!poModule->Open(FullPath000.mb_str())) {
3960 wxString msg(
" s57chart::BuildS57File Unable to open ");
3961 msg.Append(FullPath000);
3973 DDFRecord *pr = poModule->ReadRecord();
3977 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3978 if (!m_nGeoRecords) {
3980 " s57chart::BuildS57File DDFRecord 0 does not contain "
3990 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3992 date000 = wxString(u, wxConvUTF8);
3995 " s57chart::BuildS57File DDFRecord 0 does not contain "
4002 m_date000.ParseFormat(date000,
"%Y%m%d");
4003 if (!m_date000.IsValid()) m_date000.ParseFormat(
"20000101",
"%Y%m%d");
4005 m_date000.ResetTime();
4008 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
4010 m_edtn000 = wxString(u, wxConvUTF8);
4013 " s57chart::BuildS57File DDFRecord 0 does not contain "
4024 for (; pr != NULL; pr = poModule->ReadRecord()) {
4025 if (pr->FindField(
"DSPM") != NULL) {
4026 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4030 if (!m_native_scale) {
4031 wxString msg(
" s57chart::BuildS57File ENC not contain DSPM:CSCL ");
4034 m_native_scale = 1000;
4042int s57chart::BuildSENCFile(
const wxString &FullPath000,
4043 const wxString &SENCFileName,
bool b_progress) {
4045 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4046 double meters_per_pixel_max_scale =
4048 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4051 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4052 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4054 if (!m_disableBackgroundSENC) {
4055 if (g_SencThreadManager) {
4057 ticket->m_LOD_meters = m_LOD_meters;
4058 ticket->ref_lat = ref_lat;
4059 ticket->ref_lon = ref_lon;
4060 ticket->m_FullPath000 = FullPath000;
4061 ticket->m_SENCFileName = SENCFileName;
4062 ticket->m_chart =
this;
4064 g_SencThreadManager->ScheduleJob(ticket);
4065 bReadyToRender =
true;
4066 return BUILD_SENC_PENDING;
4069 return BUILD_SENC_NOK_RETRY;
4074 senc.setRegistrar(g_poRegistrar);
4075 senc.setRefLocn(ref_lat, ref_lon);
4076 senc.SetLODMeters(m_LOD_meters);
4078 AbstractPlatform::ShowBusySpinner();
4080 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4082 AbstractPlatform::HideBusySpinner();
4084 if (ret == ERROR_INGESTING000)
4085 return BUILD_SENC_NOK_PERMANENT;
4091int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4098 S57ObjVector Objects;
4099 VE_ElementVector VEs;
4100 VC_ElementVector VCs;
4102 sencfile.setRefLocn(ref_lat, ref_lon);
4104 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4106 if (srv != SENC_NO_ERROR) {
4107 wxLogMessage(sencfile.getLastError());
4113 Extent ext = sencfile.getReadExtent();
4115 m_FullExtent.ELON = ext.ELON;
4116 m_FullExtent.WLON = ext.WLON;
4117 m_FullExtent.NLAT = ext.NLAT;
4118 m_FullExtent.SLAT = ext.SLAT;
4119 m_bExtentSet =
true;
4121 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4122 ref_lon = (ext.ELON + ext.WLON) / 2.;
4127 int n_ve_elements = VEs.size();
4129 double scale = gFrame->GetBestVPScale(
this);
4130 int nativescale = GetNativeScale();
4132 for (
int i = 0; i < n_ve_elements; i++) {
4133 VE_Element *vep = VEs.at(i);
4134 if (vep && vep->nCount) {
4136 double east_max = -1e7;
4137 double east_min = 1e7;
4138 double north_max = -1e7;
4139 double north_min = 1e7;
4141 float *vrun = vep->pPoints;
4142 for (
size_t i = 0; i < vep->nCount; i++) {
4143 east_max = wxMax(east_max, *vrun);
4144 east_min = wxMin(east_min, *vrun);
4147 north_max = wxMax(north_max, *vrun);
4148 north_min = wxMin(north_min, *vrun);
4152 double lat1, lon1, lat2, lon2;
4153 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4154 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4155 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4158 m_ve_hash[vep->index] = vep;
4162 int n_vc_elements = VCs.size();
4164 for (
int i = 0; i < n_vc_elements; i++) {
4165 VC_Element *vcp = VCs.at(i);
4166 m_vc_hash[vcp->index] = vcp;
4174 for (
unsigned int i = 0; i < Objects.size(); i++) {
4175 S57Obj *obj = Objects[i];
4179 LUPname LUP_Name = PAPER_CHART;
4181 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4182 if (objnam.Len() > 0) {
4183 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4184 SendVectorChartObjectInfo(FullPath, fe_name, objnam, obj->m_lat,
4185 obj->m_lon,
scale, nativescale);
4189 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4190 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4191 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4192 SendVectorChartObjectInfo(FullPath, fe_name, nobjnam, obj->m_lat,
4193 obj->m_lon,
scale, nativescale);
4196 switch (obj->Primitive_type) {
4201 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4202 LUP_Name = PAPER_CHART;
4204 LUP_Name = SIMPLIFIED;
4213 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4214 LUP_Name = PLAIN_BOUNDARIES;
4216 LUP_Name = SYMBOLIZED_BOUNDARIES;
4221 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4225 wxString msg(obj->FeatureName, wxConvUTF8);
4226 msg.Prepend(
" Could not find LUP for ");
4227 LogMessageOnce(msg);
4234 ps52plib->_LUP2rules(LUP, obj);
4237 _insertRules(obj, LUP,
this);
4240 obj->m_DisplayCat = LUP->DISC;
4243 obj->m_DPRI = LUP->DPRI -
'0';
4246 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4247 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4248 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4249 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4250 obj->m_bcategory_mutable =
true;
4252 obj->m_bcategory_mutable =
false;
4257 if (obj && (GEO_POINT == obj->Primitive_type)) {
4259 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4260 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4261 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4262 pFloatingATONArray->Add(obj);
4266 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4267 pRigidATONArray->Add(obj);
4271 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4272 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4273 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4274 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4275 obj->bIsAton =
true;
4284 d000.ParseFormat(sencfile.getBaseDate(),
"%Y%m%d");
4285 if (!d000.IsValid()) d000.ParseFormat(
"20000101",
"%Y%m%d");
4288 updt.ParseFormat(sencfile.getUpdateDate(),
"%Y%m%d");
4289 if (!updt.IsValid()) updt.ParseFormat(
"20000101",
"%Y%m%d");
4291 if (updt.IsLaterThan(d000))
4292 m_PubYear.Printf(
"%4d", updt.GetYear());
4294 m_PubYear.Printf(
"%4d", d000.GetYear());
4297 wxDateTime upd = updt;
4298 if (!upd.IsValid()) upd.ParseFormat(
"20000101",
"%Y%m%d");
4303 m_SE = sencfile.getSENCReadBaseEdition();
4306 supdate.Printf(
" / %d", sencfile.getSENCReadLastUpdate());
4309 m_datum_str =
"WGS84";
4311 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
4312 m_ID = sencfile.getReadID();
4313 m_Name = sencfile.getReadName();
4317 AssembleLineGeometry();
4322int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4323 ObjRazRules *rzRules = NULL;
4333 switch (LUP->DPRI) {
4346 case PRIO_SYMB_POINT:
4349 case PRIO_SYMB_LINE:
4352 case PRIO_SYMB_AREA:
4365 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4369 switch (LUP->TNAM) {
4379 case PLAIN_BOUNDARIES:
4382 case SYMBOLIZED_BOUNDARIES:
4386 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4390 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4394 rzRules->child = NULL;
4395 rzRules->mps = NULL;
4398 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4399 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4404 ObjRazRules *rNext = NULL;
4405 ObjRazRules *rPrevious = NULL;
4406 if (razRules[disPrioIdx][LUPtypeIdx]) {
4407 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4408 rNext = rPrevious->next;
4412 rNext = rPrevious->next;
4415 rzRules->next = NULL;
4417 rPrevious->next = rzRules;
4419 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4426void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4436 for (
int i = 0; i < PRIO_NUM; ++i) {
4437 for (
int j = 0; j < 2; ++j) {
4438 top = razRules[i][j];
4440 while (top != NULL) {
4441 if (!top->obj->geoPtMulti)
4443 if (top->obj->BBObj.GetValid()) {
4444 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4446 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4447 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4449 double minlon = top->obj->BBObj.GetMinLon();
4450 double maxlon = top->obj->BBObj.GetMaxLon();
4452 double lon1 = (lon - minlon) * d;
4453 double lon2 = (lon - maxlon) * d;
4455 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4458 top->obj->BBObj.Invalidate();
4479void s57chart::UpdateLUPs(
s57chart *pOwner) {
4483 for (
int i = 0; i < PRIO_NUM; ++i) {
4485 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4486 m_b2pointLUPS =
true;
4487 top = razRules[i][0];
4489 while (top != NULL) {
4490 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4496 if (top->obj->nRef < 2) {
4497 ps52plib->_LUP2rules(LUP, top->obj);
4498 _insertRules(top->obj, LUP, pOwner);
4499 top->obj->m_DisplayCat = LUP->DISC;
4509 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4510 m_b2pointLUPS =
true;
4511 top = razRules[i][1];
4513 while (top != NULL) {
4514 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4517 if (top->obj->nRef < 2) {
4518 ps52plib->_LUP2rules(LUP, top->obj);
4519 _insertRules(top->obj, LUP, pOwner);
4520 top->obj->m_DisplayCat = LUP->DISC;
4530 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4531 m_b2lineLUPS =
true;
4532 top = razRules[i][3];
4534 while (top != NULL) {
4535 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4536 top->obj->FeatureName, top->obj);
4538 ps52plib->_LUP2rules(LUP, top->obj);
4539 _insertRules(top->obj, LUP, pOwner);
4540 top->obj->m_DisplayCat = LUP->DISC;
4549 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4550 m_b2lineLUPS =
true;
4551 top = razRules[i][4];
4553 while (top != NULL) {
4554 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4557 ps52plib->_LUP2rules(LUP, top->obj);
4558 _insertRules(top->obj, LUP, pOwner);
4559 top->obj->m_DisplayCat = LUP->DISC;
4571 for (
int j = 0; j < LUPNAME_NUM; j++) {
4572 top = razRules[i][j];
4573 while (top != NULL) {
4574 top->obj->bCS_Added = 0;
4577 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4588 for (
int j = 0; j < LUPNAME_NUM; j++) {
4589 top = razRules[i][j];
4590 while (top != NULL) {
4592 ObjRazRules *ctop = top->child;
4593 while (NULL != ctop) {
4594 ctop->obj->bCS_Added = 0;
4595 free_mps(ctop->mps);
4598 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4615ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4616 float lat,
float lon,
ViewPort *VPoint) {
4617 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4618 std::vector<ObjRazRules *> selected_rules;
4623 char *curr_att = NULL;
4625 wxArrayOfS57attVal *attValArray = NULL;
4626 bool bleading_attribute =
false;
4628 for (
int i = 0; i < PRIO_NUM; ++i) {
4632 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4633 top = razRules[i][point_type];
4635 while (top != NULL) {
4636 if (top->obj->npt == 1) {
4637 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4639 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4641 if (ps52plib->ObjectRenderCheckCat(top)) {
4644 wxString curAttrName;
4645 curr_att = top->obj->att_array;
4646 n_attr = top->obj->n_attr;
4647 attValArray = top->obj->attVal;
4655 bleading_attribute =
false;
4657 while (attrCounter < n_attr) {
4658 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4661 S57attVal *pAttrVal = NULL;
4664 pAttrVal = attValArray->Item(attrCounter);
4668 wxString value = s57chart::GetAttributeValueAsString(
4669 pAttrVal, curAttrName);
4671 if (curAttrName ==
"LITVIS") {
4672 if (value.StartsWith(
"obsc")) bviz =
false;
4673 }
else if (curAttrName ==
"VALNMR")
4674 value.ToDouble(&valnmr);
4680 if (bviz && (valnmr > 0.1)) {
4684 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4685 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4686 ref_lat, ref_lon, &olat, &olon);
4688 double dlat = lat - olat;
4689 double dy = dlat * 60 / cos(olat * PI / 180.);
4690 double dlon = lon - olon;
4691 double dx = dlon * 60;
4692 double manhat = abs(dy) + abs(dx);
4696 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4698 selected_rules.push_back(top);
4715 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4716 ret_ptr->Append(selected_rules[i]);
4722ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4723 float select_radius,
4725 int selection_mask) {
4726 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4727 std::vector<ObjRazRules *> selected_rules;
4729 PrepareForRender(VPoint, ps52plib);
4735 for (
int i = 0; i < PRIO_NUM; ++i) {
4736 if (selection_mask & MASK_POINT) {
4739 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4740 top = razRules[i][point_type];
4742 while (top != NULL) {
4743 if (top->obj->npt ==
4746 if (ps52plib->ObjectRenderCheck(top)) {
4747 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4748 selected_rules.push_back(top);
4755 ObjRazRules *child_item = top->child;
4756 while (child_item != NULL) {
4757 if (ps52plib->ObjectRenderCheck(child_item)) {
4758 if (DoesLatLonSelectObject(lat, lon, select_radius,
4760 selected_rules.push_back(child_item);
4763 child_item = child_item->next;
4771 if (selection_mask & MASK_AREA) {
4774 int area_boundary_type =
4775 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4776 top = razRules[i][area_boundary_type];
4777 while (top != NULL) {
4778 if (ps52plib->ObjectRenderCheck(top)) {
4779 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4780 selected_rules.push_back(top);
4787 if (selection_mask & MASK_LINE) {
4789 top = razRules[i][2];
4791 while (top != NULL) {
4792 if (ps52plib->ObjectRenderCheck(top)) {
4793 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4794 selected_rules.push_back(top);
4805 auto sortObjs = [lat, lon,
this](
const ObjRazRules *obj1,
4806 const ObjRazRules *obj2) ->
bool {
4807 double br1, dd1, br2, dd2;
4809 if (obj1->obj->Primitive_type == GEO_POINT &&
4810 obj2->obj->Primitive_type == GEO_POINT) {
4811 double lat1, lat2, lon1, lon2;
4812 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4813 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin, ref_lat,
4814 ref_lon, &lat1, &lon1);
4816 if (lon1 > 180.0) lon1 -= 360.;
4818 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4819 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin, ref_lat,
4820 ref_lon, &lat2, &lon2);
4822 if (lon2 > 180.0) lon2 -= 360.;
4824 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4825 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4832 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4836 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4837 ret_ptr->Append(selected_rules[i]);
4843bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4845 switch (obj->Primitive_type) {
4849 if (!obj->BBObj.GetValid())
return false;
4851 if (1 == obj->npt) {
4856 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4858 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4861 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4862 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4869 sbox.Set(olat, olon, olat, olon);
4871 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4872 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4877 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4884 if (!obj->BBObj.GetValid())
return false;
4887 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4889 double *pdl = obj->geoPtMulti;
4890 for (
int ip = 0; ip < obj->npt; ip++) {
4891 double lon_point = *pdl++;
4892 double lat_point = *pdl++;
4894 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4895 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4906 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4909 return IsPointInObjArea(lat, lon, select_radius, obj);
4914 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4916 float sel_rad_meters = select_radius * 1852 * 60;
4917 double easting, northing;
4918 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4925 pt *ppt = obj->geoPt;
4928 double xr = obj->x_rate;
4929 double xo = obj->x_origin;
4930 double yr = obj->y_rate;
4931 double yo = obj->y_origin;
4933 double north0 = (ppt->y * yr) + yo;
4934 double east0 = (ppt->x * xr) + xo;
4937 for (
int ip = 1; ip < npt; ip++) {
4938 double north = (ppt->y * yr) + yo;
4939 double east = (ppt->x * xr) + xo;
4942 if (northing >= (fmin(north, north0) - sel_rad_meters))
4943 if (northing <= (fmax(north, north0) + sel_rad_meters))
4944 if (easting >= (fmin(east, east0) - sel_rad_meters))
4945 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4955 if (obj->m_ls_list) {
4957 unsigned char *vbo_point =
4958 (
unsigned char *)obj->m_chart_context
4960 line_segment_element *ls = obj->m_ls_list;
4962 while (ls && vbo_point) {
4964 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4965 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4966 nPoints = ls->pedge->nCount;
4968 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4972 float north0 = ppt[1];
4973 float east0 = ppt[0];
4977 for (
int ip = 0; ip < nPoints - 1; ip++) {
4978 float north = ppt[1];
4979 float east = ppt[0];
4981 if (northing >= (fmin(north, north0) - sel_rad_meters))
4982 if (northing <= (fmax(north, north0) + sel_rad_meters))
4983 if (easting >= (fmin(east, east0) - sel_rad_meters))
4984 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
5011wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
5012 wxString ret_val =
"";
5015 const char *att_code;
5017 wxString file(g_csv_locn);
5018 file.Append(
"/s57attributes.csv");
5020 if (!wxFileName::FileExists(file)) {
5021 wxString msg(
" Could not open ");
5028 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5030 CC_ExactString,
"Code");
5036 wxString ei_file(g_csv_locn);
5037 ei_file.Append(
"/s57expectedinput.csv");
5039 if (!wxFileName::FileExists(ei_file)) {
5040 wxString msg(
" Could not open ");
5041 msg.Append(ei_file);
5047 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5048 CSVIngest(ei_file.mb_str());
5050 char **papszFields = NULL;
5051 int bSelected = FALSE;
5057 while (!bSelected && iline + 1 < psTable->nLineCount) {
5059 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5061 if (!strcmp(papszFields[0], att_code)) {
5062 if (atoi(papszFields[1]) == ival) {
5063 ret_val = wxString(papszFields[2], wxConvUTF8);
5068 CSLDestroy(papszFields);
5076bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5080 if (obj->pPolyTessGeo) {
5081 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5083 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5085 TriPrim *pTP = ppg->tri_prim_head;
5087 MyPoint pvert_list[3];
5091 double easting, northing;
5092 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5096 if (!ppg->m_bSMSENC) {
5097 double y_rate = obj->y_rate;
5098 double y_origin = obj->y_origin;
5099 double x_rate = obj->x_rate;
5100 double x_origin = obj->x_origin;
5102 double northing_scaled = (northing - y_origin) / y_rate;
5103 double easting_scaled = (easting - x_origin) / x_rate;
5104 northing = northing_scaled;
5105 easting = easting_scaled;
5110 if (pTP->tri_box.Contains(lat, lon)) {
5111 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5112 double *p_vertex = pTP->p_vertex;
5114 switch (pTP->type) {
5115 case PTG_TRIANGLE_FAN: {
5116 for (
int it = 0; it < pTP->nVert - 2; it++) {
5117 pvert_list[0].x = p_vertex[0];
5118 pvert_list[0].y = p_vertex[1];
5120 pvert_list[1].x = p_vertex[(it * 2) + 2];
5121 pvert_list[1].y = p_vertex[(it * 2) + 3];
5123 pvert_list[2].x = p_vertex[(it * 2) + 4];
5124 pvert_list[2].y = p_vertex[(it * 2) + 5];
5126 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5134 case PTG_TRIANGLE_STRIP: {
5135 for (
int it = 0; it < pTP->nVert - 2; it++) {
5136 pvert_list[0].x = p_vertex[(it * 2)];
5137 pvert_list[0].y = p_vertex[(it * 2) + 1];
5139 pvert_list[1].x = p_vertex[(it * 2) + 2];
5140 pvert_list[1].y = p_vertex[(it * 2) + 3];
5142 pvert_list[2].x = p_vertex[(it * 2) + 4];
5143 pvert_list[2].y = p_vertex[(it * 2) + 5];
5145 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5153 case PTG_TRIANGLES: {
5154 for (
int it = 0; it < pTP->nVert; it += 3) {
5155 pvert_list[0].x = p_vertex[(it * 2)];
5156 pvert_list[0].y = p_vertex[(it * 2) + 1];
5158 pvert_list[1].x = p_vertex[(it * 2) + 2];
5159 pvert_list[1].y = p_vertex[(it * 2) + 3];
5161 pvert_list[2].x = p_vertex[(it * 2) + 4];
5162 pvert_list[2].y = p_vertex[(it * 2) + 5];
5164 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5173 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5174 float *p_vertex = (
float *)pTP->p_vertex;
5176 switch (pTP->type) {
5177 case PTG_TRIANGLE_FAN: {
5178 for (
int it = 0; it < pTP->nVert - 2; it++) {
5179 pvert_list[0].x = p_vertex[0];
5180 pvert_list[0].y = p_vertex[1];
5182 pvert_list[1].x = p_vertex[(it * 2) + 2];
5183 pvert_list[1].y = p_vertex[(it * 2) + 3];
5185 pvert_list[2].x = p_vertex[(it * 2) + 4];
5186 pvert_list[2].y = p_vertex[(it * 2) + 5];
5188 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5196 case PTG_TRIANGLE_STRIP: {
5197 for (
int it = 0; it < pTP->nVert - 2; it++) {
5198 pvert_list[0].x = p_vertex[(it * 2)];
5199 pvert_list[0].y = p_vertex[(it * 2) + 1];
5201 pvert_list[1].x = p_vertex[(it * 2) + 2];
5202 pvert_list[1].y = p_vertex[(it * 2) + 3];
5204 pvert_list[2].x = p_vertex[(it * 2) + 4];
5205 pvert_list[2].y = p_vertex[(it * 2) + 5];
5207 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5215 case PTG_TRIANGLES: {
5216 for (
int it = 0; it < pTP->nVert; it += 3) {
5217 pvert_list[0].x = p_vertex[(it * 2)];
5218 pvert_list[0].y = p_vertex[(it * 2) + 1];
5220 pvert_list[1].x = p_vertex[(it * 2) + 2];
5221 pvert_list[1].y = p_vertex[(it * 2) + 3];
5223 pvert_list[2].x = p_vertex[(it * 2) + 4];
5224 pvert_list[2].y = p_vertex[(it * 2) + 5];
5226 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5249wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5250 wxString curAttrName) {
5254 pval = obj->attVal->Item(iatt);
5255 switch (pval->valType) {
5258 wxString val_str((
char *)(pval->value), wxConvUTF8);
5260 if (val_str.ToLong(&ival)) {
5264 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5265 if (!decode_val.IsEmpty()) {
5268 iv.Printf(
" (%d)", (
int)ival);
5271 value.Printf(
"%d", (
int)ival);
5275 else if (val_str.IsEmpty())
5280 wxString value_increment;
5281 wxStringTokenizer tk(val_str,
",");
5283 if (tk.HasMoreTokens()) {
5284 while (tk.HasMoreTokens()) {
5285 wxString token = tk.GetNextToken();
5287 if (token.ToLong(&ival)) {
5288 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5290 value_increment.Printf(
" (%d)", (
int)ival);
5292 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5294 if (iv) value_increment.Prepend(
", ");
5295 value.Append(value_increment);
5298 if (iv) value.Append(
",");
5299 value.Append(token);
5305 value.Append(val_str);
5308 value =
"[NULL VALUE]";
5314 int ival = *((
int *)pval->value);
5315 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5317 if (!decode_val.IsEmpty()) {
5320 iv.Printf(
"(%d)", ival);
5323 value.Printf(
"(%d)", ival);
5331 double dval = *((
double *)pval->value);
5332 wxString val_suffix =
" m";
5335 if ((curAttrName ==
"VERCLR") || (curAttrName ==
"VERCCL") ||
5336 (curAttrName ==
"VERCOP") || (curAttrName ==
"HEIGHT") ||
5337 (curAttrName ==
"HORCLR") || (curAttrName ==
"ELEVAT")) {
5338 switch (ps52plib->m_nDepthUnitDisplay) {
5341 dval = dval * 3 * 39.37 / 36;
5349 else if ((curAttrName ==
"VALSOU") || (curAttrName ==
"DRVAL1") ||
5350 (curAttrName ==
"DRVAL2") || (curAttrName ==
"VALDCO")) {
5351 switch (ps52plib->m_nDepthUnitDisplay) {
5353 dval = dval * 3 * 39.37 / 36;
5357 dval = dval * 3 * 39.37 / 36;
5359 val_suffix =
" fathoms";
5366 else if (curAttrName ==
"SECTR1")
5367 val_suffix =
"°";
5368 else if (curAttrName ==
"SECTR2")
5369 val_suffix =
"°";
5370 else if (curAttrName ==
"ORIENT")
5371 val_suffix =
"°";
5372 else if (curAttrName ==
"VALNMR")
5374 else if (curAttrName ==
"SIGPER")
5376 else if (curAttrName ==
"VALACM")
5377 val_suffix =
" Minutes/year";
5378 else if (curAttrName ==
"VALMAG")
5379 val_suffix =
"°";
5380 else if (curAttrName ==
"CURVEL")
5383 if (dval - floor(dval) < 0.01)
5384 value.Printf(
"%2.0f", dval);
5386 value.Printf(
"%4.1f", dval);
5388 value << val_suffix;
5393 case OGR_REAL_LST: {
5400wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5401 wxString AttrName) {
5402 if (NULL == pAttrVal)
return "";
5405 switch (pAttrVal->valType) {
5407 if (pAttrVal->value) {
5408 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5410 if (val_str.ToLong(&ival)) {
5414 wxString decode_val = GetAttributeDecode(AttrName, ival);
5415 if (!decode_val.IsEmpty()) {
5418 iv.Printf(
"(%d)", (
int)ival);
5421 value.Printf(
"%d", (
int)ival);
5425 else if (val_str.IsEmpty())
5430 wxString value_increment;
5431 wxStringTokenizer tk(val_str,
",");
5433 while (tk.HasMoreTokens()) {
5434 wxString token = tk.GetNextToken();
5436 if (token.ToLong(&ival)) {
5437 wxString decode_val = GetAttributeDecode(AttrName, ival);
5438 if (!decode_val.IsEmpty())
5439 value_increment = decode_val;
5441 value_increment.Printf(
" %d", (
int)ival);
5443 if (iv) value_increment.Prepend(
", ");
5445 value.Append(value_increment);
5449 value.Append(val_str);
5452 value =
"[NULL VALUE]";
5458 int ival = *((
int *)pAttrVal->value);
5459 wxString decode_val = GetAttributeDecode(AttrName, ival);
5461 if (!decode_val.IsEmpty()) {
5464 iv.Printf(
"(%d)", ival);
5467 value.Printf(
"(%d)", ival);
5475 double dval = *((
double *)pAttrVal->value);
5476 wxString val_suffix =
" m";
5479 if ((AttrName ==
"VERCLR") || (AttrName ==
"VERCCL") ||
5480 (AttrName ==
"VERCOP") || (AttrName ==
"HEIGHT") ||
5481 (AttrName ==
"HORCLR") || (AttrName ==
"ELEVAT")) {
5482 switch (ps52plib->m_nDepthUnitDisplay) {
5485 dval = dval * 3 * 39.37 / 36;
5493 else if ((AttrName ==
"VALSOU") || (AttrName ==
"DRVAL1") ||
5494 (AttrName ==
"DRVAL2")) {
5495 switch (ps52plib->m_nDepthUnitDisplay) {
5497 dval = dval * 3 * 39.37 / 36;
5501 dval = dval * 3 * 39.37 / 36;
5503 val_suffix =
" fathoms";
5510 else if (AttrName ==
"SECTR1")
5511 val_suffix =
"°";
5512 else if (AttrName ==
"SECTR2")
5513 val_suffix =
"°";
5514 else if (AttrName ==
"ORIENT")
5515 val_suffix =
"°";
5516 else if (AttrName ==
"VALNMR")
5518 else if (AttrName ==
"SIGPER")
5520 else if (AttrName ==
"VALACM")
5521 val_suffix =
" Minutes/year";
5522 else if (AttrName ==
"VALMAG")
5523 val_suffix =
"°";
5524 else if (AttrName ==
"CURVEL")
5527 if (dval - floor(dval) < 0.01)
5528 value.Printf(
"%2.0f", dval);
5530 value.Printf(
"%4.1f", dval);
5532 value << val_suffix;
5537 case OGR_REAL_LST: {
5545 int positionDiff = l1->position.Cmp(l2->position);
5546 if (positionDiff < 0)
return false;
5548 int attrIndex1 = l1->attributeNames.Index(
"SECTR1");
5549 int attrIndex2 = l2->attributeNames.Index(
"SECTR1");
5552 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5553 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5554 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5556 double angle1, angle2;
5557 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5558 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5560 return angle1 < angle2;
5563static const char *type2str(GeoPrim_t type) {
5564 const char *r =
"Unknown";
5585wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5588 wxString curAttrName, value;
5589 bool isLight =
false;
5592 wxString classAttributes;
5594 wxString lightsHtml;
5595 wxString positionString;
5596 std::vector<S57Light *> lights;
5600 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5601 node = node->GetPrevious()) {
5602 ObjRazRules *current = node->GetData();
5603 positionString.Clear();
5607 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5609 if (current->obj->Primitive_type == GEO_META)
continue;
5610 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5612 className = wxString(current->obj->FeatureName, wxConvUTF8);
5615 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5620 const char *name_desc;
5621 if (g_csv_locn.Len()) {
5622 wxString oc_file(g_csv_locn);
5623 oc_file.Append(
"/s57objectclasses.csv");
5624 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5625 current->obj->FeatureName,
5626 CC_ExactString,
"ObjectClass");
5632 if (0 == strlen(name_desc)) {
5633 name_desc = current->obj->FeatureName;
5634 classDesc = wxString(name_desc, wxConvUTF8, 1);
5635 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5637 classDesc = wxString(name_desc, wxConvUTF8);
5644 classAttributes =
"";
5645 index.Printf(
"Feature Index: %d<br>", current->obj->Index);
5646 classAttributes << index;
5649 LUPstring.Printf(
"LUP RCID: %d<br>", current->LUP->RCID);
5650 classAttributes << LUPstring;
5653 LLBBox bbox = current->obj->BBObj;
5654 Bbox.Printf(
"Lat/Lon box: %g %g %g %g<br>", bbox.GetMinLat(),
5655 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5656 classAttributes << Bbox;
5659 Type.Printf(
" Type: %s<br>", type2str(current->obj->Primitive_type));
5660 classAttributes << Type;
5662 LUPstring =
" LUP ATTC: ";
5663 if (current->LUP->ATTArray.size())
5664 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5665 LUPstring +=
"<br>";
5666 classAttributes << LUPstring;
5668 LUPstring =
" LUP INST: ";
5669 LUPstring += current->LUP->INST;
5670 LUPstring +=
"<br><br>";
5671 classAttributes << LUPstring;
5674 if (GEO_POINT == current->obj->Primitive_type) {
5676 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5677 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5678 ref_lat, ref_lon, &lat, &lon);
5680 if (lon > 180.0) lon -= 360.;
5682 positionString.Clear();
5683 positionString += toSDMM(1, lat);
5684 positionString <<
" ";
5685 positionString += toSDMM(2, lon);
5689 curLight->position = positionString;
5690 curLight->hasSectors =
false;
5691 lights.push_back(curLight);
5697 if (current->obj->att_array) {
5698 char *curr_att = current->obj->att_array;
5704 attribStr <<
"<table border=0 cellspacing=0 cellpadding=0>";
5707 ret_val <<
"<p>" << classAttributes;
5710 bool inDepthRange =
false;
5712 while (attrCounter < current->obj->n_attr) {
5714 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5721 assert(curLight !=
nullptr);
5722 curLight->attributeNames.Add(curAttrName);
5723 if (curAttrName.StartsWith(
"SECTR")) curLight->hasSectors =
true;
5725 if (curAttrName ==
"DRVAL1") {
5726 attribStr <<
"<tr><td><font size=-1>";
5727 inDepthRange =
true;
5728 }
else if (curAttrName ==
"DRVAL2") {
5730 inDepthRange =
false;
5733 attribStr <<
"</font></td></tr>\n";
5734 inDepthRange =
false;
5736 attribStr <<
"<tr><td valign=top><font size=-2>";
5737 if (curAttrName ==
"catgeo")
5738 attribStr <<
"CATGEO";
5740 attribStr << curAttrName;
5741 attribStr <<
"</font></td><td> </td><td "
5742 "valign=top><font size=-1>";
5753 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5758 wxString AttrNamesFiles =
5759 "PICREP,TXTDSC,NTXTDS";
5761 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5762 if (value.Find(
".XML") == wxNOT_FOUND) {
5763 file.Assign(GetFullPath());
5764 file.Assign(file.GetPath(), value);
5767 if (file.IsCaseSensitive()) {
5768 wxDir dir(file.GetPath());
5770 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
5772 if (filename.IsSameAs(value,
false)) {
5774 file.Assign(file.GetPath(), value);
5777 cont = dir.GetNext(&filename);
5784 wxString::Format(
"<a href=\"%s\">%s</a>",
5785 file.GetFullPath(), file.GetFullName());
5787 value = value +
" <font color=\"red\">[ " +
5788 _(
"this file is not available") +
" ]</font>";
5792 "DATEND,DATSTA,PEREND,PERSTA";
5793 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5796 wxString ts = value;
5800 if (ts.Length() < 5) {
5804 if (ts.Length() < 7) {
5808 wxString::const_iterator end;
5810 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5812 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5813 if (d) ts.Append(wxString::Format(
" %d", dt.GetDay()));
5814 if (dt.GetYear() > 0)
5815 ts.Append(wxString::Format(
", %i", dt.GetYear()));
5816 if (curAttrName ==
"PEREND")
5817 ts = _(
"Period ends: ") + ts +
" (" + value +
")";
5818 if (curAttrName ==
"PERSTA")
5819 ts = _(
"Period starts: ") + ts +
" (" + value +
")";
5820 if (curAttrName ==
"DATEND")
5821 ts = _(
"Date ending: ") + ts +
" (" + value +
")";
5822 if (curAttrName ==
"DATSTA")
5823 ts = _(
"Date starting: ") + ts +
" (" + value +
")";
5827 if (curAttrName ==
"TS_TSP") {
5834 wxStringTokenizer tk(value,
",");
5839 ts1 = tk.GetNextToken().Trim(
false);
5842 }
while ((ts1.Left(2).ToLong(&l)));
5843 ts =
"Tidal Streams referred to<br><b>";
5844 ts.Append(tk.GetNextToken()).Append(
"</b> at <b>").Append(ts1);
5845 ts.Append(
"</b><br><table >");
5847 while (tk.HasMoreTokens()) {
5848 ts.Append(
"<tr><td>");
5849 wxString s1(wxString::Format(
"%+dh ", i));
5851 ts.Append(
"</td><td>");
5852 s1 = tk.GetNextToken();
5854 s1 =
"°</td><td>";
5856 s1 = tk.GetNextToken();
5859 ts.Append(
"</td></tr>");
5862 ts.Append(
"</table>");
5867 assert(curLight !=
nullptr);
5868 curLight->attributeValues.Add(value);
5870 if (curAttrName ==
"INFORM" || curAttrName ==
"NINFOM")
5871 value.Replace(
"|",
"<br>");
5873 if (curAttrName ==
"catgeo")
5874 attribStr << type2str(current->obj->Primitive_type);
5878 if (!(curAttrName ==
"DRVAL1")) {
5879 attribStr <<
"</font></td></tr>\n";
5889 attribStr <<
"</table>\n";
5891 objText +=
"<b>" + classDesc +
"</b> <font size=-2>(" + className +
5892 ")</font>" +
"<br>";
5894 if (positionString.Length())
5895 objText <<
"<font size=-2>" << positionString <<
"</font><br>\n";
5897 if (noAttr > 0) objText << attribStr;
5899 if (node != rule_list->GetFirst()) objText +=
"<hr noshade>";
5906 if (!lights.empty()) {
5907 assert(curLight !=
nullptr);
5912 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5916 for (
auto const &thisLight : lights) {
5919 if (thisLight->position != lastPos) {
5920 lastPos = thisLight->position;
5922 if (thisLight != *lights.begin())
5923 lightsHtml <<
"</table>\n<hr noshade>\n";
5925 lightsHtml <<
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>";
5926 lightsHtml <<
"<font size=-2>" << thisLight->position
5929 if (curLight->hasSectors)
5931 "<font size=-2>(Sector angles are True Bearings from "
5932 "Seaward)</font><br>");
5934 lightsHtml <<
"<table>";
5937 lightsHtml <<
"<tr>";
5938 lightsHtml <<
"<td><font size=-1>";
5941 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
5942 if (attrIndex != wxNOT_FOUND) {
5943 wxString color = thisLight->attributeValues.Item(attrIndex);
5944 if (color ==
"red (3)" || color ==
"red(3)")
5946 "<table border=0><tr><td "
5947 "bgcolor=red> </td></tr></table> ";
5948 else if (color ==
"green (4)" || color ==
"green(4)")
5950 "<table border=0><tr><td "
5951 "bgcolor=green> </td></tr></table> ";
5952 else if (color ==
"white (1)" || color ==
"white(1)")
5954 "<table border=0><tr><td "
5955 "bgcolor=white> </td></tr></table> ";
5956 else if (color ==
"yellow (6)" || color ==
"yellow(6)")
5958 "<table border=0><tr><td "
5959 "bgcolor=yellow> </td></tr></table> ";
5960 else if (color ==
"blue (5)" || color ==
"blue(5)")
5962 "<table border=0><tr><td "
5963 "bgcolor=blue> </td></tr></table> ";
5964 else if (color ==
"magenta (12)" || color ==
"magenta(12)")
5966 "<table border=0><tr><td "
5967 "bgcolor=magenta> </td></tr></table> ";
5970 "<table border=0><tr><td "
5971 "bgcolor=grey> ? </td></tr></table> ";
5974 int visIndex = thisLight->attributeNames.Index(
"LITVIS");
5975 if (visIndex != wxNOT_FOUND) {
5976 wxString vis = thisLight->attributeValues.Item(visIndex);
5977 if (vis.Contains(
"8")) {
5978 if (attrIndex != wxNOT_FOUND) {
5979 wxString color = thisLight->attributeValues.Item(attrIndex);
5980 if ((color ==
"red (3)" || color ==
"red(3)"))
5982 "<table border=0><tr><td "
5983 "bgcolor=DarkRed> </td></tr></table> ";
5984 if ((color ==
"green (4)" || color ==
"green(4)"))
5986 "<table border=0><tr><td "
5987 "bgcolor=DarkGreen> </td></tr></table> ";
5988 if ((color ==
"white (1)" || color ==
"white(1)"))
5990 "<table border=0><tr><td "
5991 "bgcolor=GoldenRod> </td></tr></table> ";
5996 lightsHtml << colorStr;
5998 lightsHtml <<
"</font></td><td><font size=-1><nobr><b>";
6000 attrIndex = thisLight->attributeNames.Index(
"LITCHR");
6001 if (attrIndex != wxNOT_FOUND) {
6002 wxString character = thisLight->attributeValues[attrIndex];
6003 lightsHtml << character.BeforeFirst(wxChar(
'(')) <<
" ";
6006 attrIndex = thisLight->attributeNames.Index(
"SIGGRP");
6007 if (attrIndex != wxNOT_FOUND) {
6008 lightsHtml << thisLight->attributeValues[attrIndex];
6012 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
6013 if (attrIndex != wxNOT_FOUND) {
6015 << thisLight->attributeValues.Item(attrIndex).Upper()[0];
6019 attrIndex = thisLight->attributeNames.Index(
"SIGPER");
6020 if (attrIndex != wxNOT_FOUND) {
6021 lightsHtml << thisLight->attributeValues[attrIndex];
6025 attrIndex = thisLight->attributeNames.Index(
"HEIGHT");
6026 if (attrIndex != wxNOT_FOUND) {
6027 lightsHtml << thisLight->attributeValues[attrIndex];
6031 attrIndex = thisLight->attributeNames.Index(
"VALNMR");
6032 if (attrIndex != wxNOT_FOUND) {
6033 lightsHtml << thisLight->attributeValues[attrIndex];
6037 lightsHtml <<
"</b>";
6039 attrIndex = thisLight->attributeNames.Index(
"SECTR1");
6040 if (attrIndex != wxNOT_FOUND) {
6041 lightsHtml <<
"(" << thisLight->attributeValues[attrIndex];
6042 lightsHtml <<
" - ";
6043 attrIndex = thisLight->attributeNames.Index(
"SECTR2");
6044 lightsHtml << thisLight->attributeValues[attrIndex] <<
") ";
6047 lightsHtml <<
"</nobr>";
6049 attrIndex = thisLight->attributeNames.Index(
"CATLIT");
6050 if (attrIndex != wxNOT_FOUND) {
6051 lightsHtml <<
"<nobr>";
6052 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6054 lightsHtml <<
"</nobr> ";
6057 attrIndex = thisLight->attributeNames.Index(
"EXCLIT");
6058 if (attrIndex != wxNOT_FOUND) {
6059 lightsHtml <<
"<nobr>";
6060 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6062 lightsHtml <<
"</nobr> ";
6065 attrIndex = thisLight->attributeNames.Index(
"OBJNAM");
6066 if (attrIndex != wxNOT_FOUND) {
6067 lightsHtml <<
"<br><nobr>";
6068 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6069 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6070 lightsHtml <<
"</nobr> ";
6073 lightsHtml <<
"</font></td>";
6074 lightsHtml <<
"</tr>";
6076 thisLight->attributeNames.Clear();
6077 thisLight->attributeValues.Clear();
6080 lightsHtml <<
"</table><hr noshade>\n";
6081 ret_val = lightsHtml << ret_val;
6095bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6096 if (NULL == g_poRegistrar) {
6097 wxLogMessage(
" Error: No ClassRegistrar in InitENCMinimal.");
6101 m_pENCDS =
new OGRS57DataSource;
6103 m_pENCDS->SetS57Registrar(g_poRegistrar);
6105 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6108 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6109 pENCReader->SetClassBased(g_poRegistrar);
6111 pENCReader->Ingest();
6116OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6118 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6120 if ((NULL != pENCReader) && (NULL != g_poRegistrar)) {
6122 g_poRegistrar->SelectClass(
"M_COVR");
6125 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefn(
6126 g_poRegistrar, g_poRegistrar->GetOBJL(), pENCReader->GetOptionFlags());
6129 pENCReader->AddFeatureDefn(poDefn);
6132 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6135 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6138 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6149OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6153 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6156 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6159 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6162 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6171int s57chart::GetENCScale(
void) {
6172 if (NULL == m_pENCDS)
return 0;
6179 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6182 return pENCReader->GetCSCL();
6192void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6193 const char *pszErrorMsg) {
6194#define ERR_BUF_LEN 2000
6196 char buf[ERR_BUF_LEN + 1];
6198 if (eErrClass == CE_Debug)
6199 sprintf(buf,
" %s", pszErrorMsg);
6200 else if (eErrClass == CE_Warning)
6201 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6203 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6205 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6206 wxString msg(buf, wxConvUTF8);
6212 if (eErrClass == CE_Fatal) {
6213 longjmp(env_ogrf, 1);
6224const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6225 const char *pszKeyFieldValue,
6226 CSVCompareCriteria eCriteria,
6227 const char *pszTargetField)
6236 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6237 pszKeyFieldValue, eCriteria);
6239 if (papszRecord == NULL)
return "";
6244 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6245 if (iTargetField < 0)
return "";
6247 if (iTargetField >= CSLCount(papszRecord))
return "";
6249 return (papszRecord[iTargetField]);
6263bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6287 std::vector<s57Sector_t> §orlegs) {
6288 float rangeScale = 0.0;
6290 if (sectorlegs.size() > 0) {
6291 std::vector<int> sectorangles;
6292 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6293 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6296 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6297 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6302 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6303 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6309 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6312 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6313 powf((
float)(lightPos.y - end1.y), 2));
6315 if (rangeScale == 0.0) {
6318 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6322 rangePx = rangePx * rangeScale;
6324 int penWidth = rangePx / 8;
6325 penWidth = wxMin(20, penWidth);
6326 penWidth = wxMax(5, penWidth);
6329 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
6330 penWidth, wxPENSTYLE_SOLID);
6331 arcpen->SetCap(wxCAP_BUTT);
6334 float angle1, angle2;
6335 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6336 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6337 if (angle1 > angle2) {
6340 int lpx = lightPos.x;
6341 int lpy = lightPos.y;
6343 wxPoint arcpoints[150];
6346 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6350 int narc = (angle2 - angle1) / step;
6352 step = (angle2 - angle1) / (
float)narc;
6354 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6355 wxPoint yellowCone[3];
6356 yellowCone[0] = lightPos;
6357 yellowCone[1] = end1;
6358 yellowCone[2] = end2;
6359 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6362 wxColor c = sectorlegs[i].color;
6363 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6364 dc.SetBrush(wxBrush(c));
6365 dc.StrokePolygon(3, yellowCone, 0, 0);
6368 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6369 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6370 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6371 arcpoints[npoints].x = x;
6372 arcpoints[npoints].y = y;
6375 dc.StrokeLines(npoints, arcpoints);
6379 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6385 bool haveAngle1 =
false;
6386 bool haveAngle2 =
false;
6387 int sec1 = (int)sectorlegs[i].sector1;
6388 int sec2 = (int)sectorlegs[i].sector2;
6389 if (sec1 > 360) sec1 -= 360;
6390 if (sec2 > 360) sec2 -= 360;
6392 if ((sec2 == 360) && (sec1 == 0))
6395 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6396 if (sectorangles[j] == sec1) haveAngle1 =
true;
6397 if (sectorangles[j] == sec2) haveAngle2 =
true;
6401 dc.StrokeLine(lightPos, end1);
6402 sectorangles.push_back(sec1);
6406 dc.StrokeLine(lightPos, end2);
6407 sectorangles.push_back(sec2);
6414void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6415 std::vector<s57Sector_t> §orlegs) {
6416 float rangeScale = 0.0;
6418 if (sectorlegs.size() > 0) {
6419 std::vector<int> sectorangles;
6420 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6421 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6424 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6425 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6430 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6431 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6437 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6440 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6441 powf((
float)(lightPos.y - end1.y), 2));
6443 if (rangeScale == 0.0) {
6446 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6450 rangePx = rangePx * rangeScale;
6452 float arcw = rangePx / 10;
6453 arcw = wxMin(20, arcw);
6454 arcw = wxMax(5, arcw);
6458 float angle1, angle2;
6459 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6460 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6461 if (angle1 > angle2) {
6464 int lpx = lightPos.x;
6465 int lpy = lightPos.y;
6467 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6468 wxPoint yellowCone[3];
6469 yellowCone[0] = lightPos;
6470 yellowCone[1] = end1;
6471 yellowCone[2] = end2;
6472 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6475 wxColor c = sectorlegs[i].color;
6476 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6477 dc.SetBrush(wxBrush(c));
6478 dc.StrokePolygon(3, yellowCone, 0, 0);
6482 wxPoint r(lpx, lpy);
6485 float rad = rangePx;
6509 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6512 glBindBuffer(GL_ARRAY_BUFFER, 0);
6513 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6515 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6516 glEnableVertexAttribArray(mPosAttrib);
6520 glGetUniformLocation(shader->programId(),
"circle_radius");
6521 glUniform1f(radiusloc, rad);
6525 glGetUniformLocation(shader->programId(),
"circle_center");
6529 glUniform2fv(centerloc, 1, ctrv);
6532 wxColour colorb = sectorlegs[i].color;
6534 colorv[0] = colorb.Red() / float(256);
6535 colorv[1] = colorb.Green() / float(256);
6536 colorv[2] = colorb.Blue() / float(256);
6537 colorv[3] = colorb.Alpha() / float(256);
6540 glGetUniformLocation(shader->programId(),
"circle_color");
6541 glUniform4fv(colloc, 1, colorv);
6551 glGetUniformLocation(shader->programId(),
"border_color");
6552 glUniform4fv(bcolloc, 1, bcolorv);
6555 GLint borderWidthloc =
6556 glGetUniformLocation(shader->programId(),
"border_width");
6557 glUniform1f(borderWidthloc, 2);
6560 GLint ringWidthloc =
6561 glGetUniformLocation(shader->programId(),
"ring_width");
6562 glUniform1f(ringWidthloc, arcw);
6566 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
6567 if (sr1 > 360.) sr1 -= 360.;
6569 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
6570 if (sr2 > 360.) sr2 -= 360.;
6582 if ((sb < 0) || (se < 0)) {
6588 glGetUniformLocation(shader->programId(),
"sector_1");
6589 glUniform1f(sector1loc, (sb * PI / 180.));
6591 glGetUniformLocation(shader->programId(),
"sector_2");
6592 glUniform1f(sector2loc, (se * PI / 180.));
6597 mat4x4_translate_in_place(I, r.x, r.y, 0);
6600 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6601 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6604 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6608 mat4x4_identity(IM);
6610 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6611 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6613 glDisableVertexAttribArray(mPosAttrib);
6619 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6624 bool haveAngle1 =
false;
6625 bool haveAngle2 =
false;
6626 int sec1 = (int)sectorlegs[i].sector1;
6627 int sec2 = (int)sectorlegs[i].sector2;
6628 if (sec1 > 360) sec1 -= 360;
6629 if (sec2 > 360) sec2 -= 360;
6631 if ((sec2 == 360) && (sec1 == 0))
6634 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6635 if (sectorangles[j] == sec1) haveAngle1 =
true;
6636 if (sectorangles[j] == sec2) haveAngle2 =
true;
6640 dc.StrokeLine(lightPos, end1);
6641 sectorangles.push_back(sec1);
6645 dc.StrokeLine(lightPos, end2);
6646 sectorangles.push_back(sec2);
6654bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6657 ListOfObjRazRules *rule_list,
6658 ListOfPI_S57Obj *pi_rule_list,
6659 std::vector<s57Sector_t> §orlegs) {
6660 bool newSectorsNeedDrawing =
false;
6662 bool bhas_red_green =
false;
6663 bool bleading_attribute =
false;
6666 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6667 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6669 int yOpacity = (float)opacity *
6672 if (target_plugin_chart || Chs57) {
6675 wxPoint2DDouble objPos;
6677 char *curr_att = NULL;
6679 wxArrayOfS57attVal *attValArray = NULL;
6681 ListOfObjRazRules::Node *snode = NULL;
6682 ListOfPI_S57Obj::Node *pnode = NULL;
6684 if (Chs57 && rule_list)
6685 snode = rule_list->GetLast();
6686 else if (target_plugin_chart && pi_rule_list)
6687 pnode = pi_rule_list->GetLast();
6690 wxPoint2DDouble lightPosD(0, 0);
6691 bool is_light =
false;
6695 ObjRazRules *current = snode->GetData();
6696 S57Obj *light = current->obj;
6697 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6698 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6699 curr_att = light->att_array;
6700 n_attr = light->n_attr;
6701 attValArray = light->attVal;
6704 }
else if (target_plugin_chart) {
6708 objPos = wxPoint2DDouble(light->
m_lat, light->
m_lon);
6711 attValArray = light->
attVal;
6721 wxString curAttrName;
6724 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6726 if (is_light && (lightPosD == objPos)) {
6734 bleading_attribute =
false;
6736 while (attrCounter < n_attr) {
6737 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6740 S57attVal *pAttrVal = NULL;
6743 pAttrVal = attValArray->Item(attrCounter);
6744 else if (target_plugin_chart)
6745 pAttrVal = attValArray->Item(attrCounter);
6749 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6751 if (curAttrName ==
"LITVIS") {
6752 if (value.StartsWith(
"obsc")) bviz =
false;
6754 if (curAttrName ==
"SECTR1") value.ToDouble(§r1);
6755 if (curAttrName ==
"SECTR2") value.ToDouble(§r2);
6756 if (curAttrName ==
"VALNMR") value.ToDouble(&valnmr);
6757 if (curAttrName ==
"COLOUR") {
6758 if (value ==
"red(3)") {
6759 color = wxColor(255, 0, 0, opacity);
6760 sector.iswhite =
false;
6761 bhas_red_green =
true;
6764 if (value ==
"green(4)") {
6765 color = wxColor(0, 255, 0, opacity);
6766 sector.iswhite =
false;
6767 bhas_red_green =
true;
6771 if (curAttrName ==
"EXCLIT") {
6772 if (value.Find(
"(3)")) valnmr = 1.0;
6775 if (curAttrName ==
"CATLIT") {
6776 if (value.Upper().StartsWith(
"DIRECT") ||
6777 value.Upper().StartsWith(
"LEAD"))
6778 bleading_attribute =
true;
6785 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6786 if (sectr1 > sectr2) {
6790 sector.pos.m_x = objPos.m_y;
6791 sector.pos.m_y = objPos.m_x;
6794 (valnmr > 0.0) ? valnmr : 2.5;
6795 sector.sector1 = sectr1;
6796 sector.sector2 = sectr2;
6798 if (!color.IsOk()) {
6799 color = wxColor(255, 255, 0, yOpacity);
6800 sector.iswhite =
true;
6802 sector.color = color;
6803 sector.isleading =
false;
6805 if (bleading_attribute) sector.isleading =
true;
6807 bool newsector =
true;
6808 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6809 if (sectorlegs[i].pos == sector.pos &&
6810 sectorlegs[i].sector1 == sector.sector1 &&
6811 sectorlegs[i].sector2 == sector.sector2) {
6817 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6821 if (!bviz) newsector =
false;
6823 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6827 sectorlegs.push_back(sector);
6828 newSectorsNeedDrawing =
true;
6835 snode = snode->GetPrevious();
6836 else if (target_plugin_chart)
6837 pnode = pnode->GetPrevious();
6845 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6846 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6847 if (sectorlegs[i].iswhite && bhas_red_green)
6848 sectorlegs[i].isleading =
true;
6852 return newSectorsNeedDrawing;
6855bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6857 std::vector<s57Sector_t> §orlegs) {
6858 if (!cc)
return false;
6860 static float lastLat, lastLon;
6862 if (!ps52plib)
return false;
6870 if (cc->m_singleChart &&
6871 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6872 target_chart = cc->m_singleChart;
6873 else if (viewport.b_quilt)
6874 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6876 target_chart = NULL;
6879 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6880 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6883 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6886 bool newSectorsNeedDrawing =
false;
6888 if (target_plugin_chart || Chs57) {
6889 ListOfObjRazRules *rule_list = NULL;
6890 ListOfPI_S57Obj *pi_rule_list = NULL;
6897 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6898 else if (target_plugin_chart)
6899 pi_rule_list = g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6900 target_plugin_chart, lat, lon, viewport);
6902 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6903 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6911 pi_rule_list->Clear();
6912 delete pi_rule_list;
6916 return newSectorsNeedDrawing;
6919bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6921 std::vector<s57Sector_t> §orlegs) {
6922 if (!cc)
return false;
6924 double cursor_lat, cursor_lon;
6925 static float lastLat, lastLon;
6927 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6932 ChartBase *target_chart = cc->GetChartAtCursor();
6934 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6935 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6938 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6943 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6945 lastLat = cursor_lat;
6946 lastLon = cursor_lon;
6947 bool newSectorsNeedDrawing =
false;
6949 if (target_plugin_chart || Chs57) {
6950 ListOfObjRazRules *rule_list = NULL;
6951 ListOfPI_S57Obj *pi_rule_list = NULL;
6957 rule_list = Chs57->GetObjRuleListAtLatLon(
6958 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6959 else if (target_plugin_chart)
6960 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
6961 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6963 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6964 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6972 pi_rule_list->Clear();
6973 delete pi_rule_list;
6977 return newSectorsNeedDrawing;
Wrapper for creating a ChartCtx based on global vars.
Generic Chart canvas base.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Wrapper class for plugin-based charts.
Wrapper class for OpenGL shader programs.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
Class representing an S-57 chart object.
double m_lon
Reference longitude.
int n_attr
Number of attributes.
char * att_array
Array of attribute types.
double m_lat
Reference latitude.
char FeatureName[8]
S-57 feature type code (e.g., "DEPARE")
wxArrayOfS57attVal * attVal
Array of attribute values.
Represents a light feature in an S57 chart.
Manager for S57 chart SENC creation threads.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
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.
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.
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).
Device context class that can use either wxDC or OpenGL for drawing.
Represents an S57 format electronic navigational chart in OpenCPN.
General purpose GUI support.
bool g_b_overzoom_x
Allow high overzoom.
Enhanced logging interface on top of wx/log.h.
void fromSM_Plugin(double x, double y, double lat0, double lon0, double *lat, double *lon)
Converts Simple Mercator coordinates to geographic.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
Tools to send data to plugins.
int PI_GetPLIBBoundaryStyle()
Gets configured S52 boundary style.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Represents a sector of a light in an S57 chart.