30#include "crashlytics.h"
34#define strncasecmp(x, y, z) _strnicmp(x, y, z)
45#include <wx/tokenzr.h>
46#include <wx/textfile.h>
47#include <wx/filename.h>
49#include <wx/listimpl.cpp>
52#include <wx/msw/msvcrt.h>
64#include "gdal/cpl_csv.h"
84#include "s57class_registrar.h"
97#define S57_THUMB_SIZE 200
99WX_DEFINE_OBJARRAY(ArrayOfS57Obj);
101WX_DEFINE_LIST(ListOfPI_S57Obj);
103WX_DEFINE_LIST(ListOfObjRazRules);
110static jmp_buf env_ogrf;
112static void OpenCPN_OGRErrorHandler(
113 CPLErr eErrClass,
int nError,
114 const char *pszErrorMsg);
116static uint64_t hash_fast64(
const void *buf,
size_t len, uint64_t seed) {
117 const uint64_t m = 0x880355f21e6d1965ULL;
118 const uint64_t *pos = (
const uint64_t *)buf;
119 const uint64_t *end = pos + (len >> 3);
120 const unsigned char *pc;
121 uint64_t h = len * m ^ seed;
126 v *= 0x2127599bf4325c37ULL;
130 pc = (
const unsigned char *)pos;
134 v ^= (uint64_t)pc[6] << 48;
136 v ^= (uint64_t)pc[5] << 40;
138 v ^= (uint64_t)pc[4] << 32;
140 v ^= (uint64_t)pc[3] << 24;
142 v ^= (uint64_t)pc[2] << 16;
144 v ^= (uint64_t)pc[1] << 8;
146 v ^= (uint64_t)pc[0];
148 v *= 0x2127599bf4325c37ULL;
154 h *= 0x2127599bf4325c37ULL;
159static unsigned int hash_fast32(
const void *buf,
size_t len,
161 uint64_t h = hash_fast64(buf, len, seed);
166 return h - (h >> 32);
169unsigned long connector_key::hash()
const {
170 return hash_fast32(k,
sizeof k, 0);
177render_canvas_parms::render_canvas_parms() { pix_buff = NULL; }
179render_canvas_parms::~render_canvas_parms() {}
181static void PrepareForRender(
ViewPort *pvp, s52plib *plib) {
186 pvp->rv_rect, pvp->GetBBox(), pvp->
ref_scale,
188 plib->PrepareForRender();
195s57chart::s57chart() {
196 m_ChartType = CHART_TYPE_S57;
197 m_ChartFamily = CHART_FAMILY_VECTOR;
199 for (
int i = 0; i < PRIO_NUM; i++)
200 for (
int j = 0; j < LUPNAME_NUM; j++) razRules[i][j] = NULL;
209 pFloatingATONArray =
new wxArrayPtrVoid;
210 pRigidATONArray =
new wxArrayPtrVoid;
212 m_tmpup_array = NULL;
214 m_DepthUnits =
"METERS";
215 m_depth_unit_id = DEPTH_UNIT_METERS;
217 bGLUWarningSent =
false;
223 m_pvaldco_array = NULL;
225 m_bExtentSet =
false;
227 m_pDIBThumbDay = NULL;
228 m_pDIBThumbDim = NULL;
229 m_pDIBThumbOrphan = NULL;
230 m_bbase_file_attr_known =
false;
232 m_bLinePrioritySet =
false;
233 m_plib_state_hash = 0;
240 m_b2pointLUPS =
false;
241 m_b2lineLUPS =
false;
243 m_next_safe_cnt = 1e6;
245 m_line_vertex_buffer = 0;
246 m_this_chart_context = 0;
248 m_vbo_byte_length = 0;
249 bReadyToRender =
false;
251 m_disableBackgroundSENC =
false;
254s57chart::~s57chart() {
255 FreeObjectsAndRules();
262 delete pFloatingATONArray;
263 delete pRigidATONArray;
267 free(m_pvaldco_array);
269 free(m_line_vertex_buffer);
271 delete m_pDIBThumbOrphan;
273 for (
unsigned i = 0; i < m_pcs_vector.size(); i++)
delete m_pcs_vector.at(i);
275 for (
unsigned i = 0; i < m_pve_vector.size(); i++)
delete m_pve_vector.at(i);
277 m_pcs_vector.clear();
278 m_pve_vector.clear();
280 for (
const auto &it : m_ve_hash) {
281 VE_Element *pedge = it.second;
283 free(pedge->pPoints);
289 for (
const auto &it : m_vc_hash) {
290 VC_Element *pcs = it.second;
299 if ((m_LineVBO_name > 0)) glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
301 free(m_this_chart_context);
303 if (m_TempFilePath.Length() && (m_FullPath != m_TempFilePath)) {
304 if (::wxFileExists(m_TempFilePath)) wxRemoveFile(m_TempFilePath);
315void s57chart::GetValidCanvasRegion(
const ViewPort &VPoint,
319 double easting, northing;
322 toSM(m_FullExtent.SLAT, m_FullExtent.WLON, VPoint.
clat, VPoint.
clon, &easting,
327 rxl = (int)round((VPoint.
pix_width / 2) + epix);
328 ryb = (int)round((VPoint.
pix_height / 2) - npix);
330 toSM(m_FullExtent.NLAT, m_FullExtent.ELON, VPoint.
clat, VPoint.
clon, &easting,
335 rxr = (int)round((VPoint.
pix_width / 2) + epix);
336 ryt = (int)round((VPoint.
pix_height / 2) - npix);
338 pValidRegion->Clear();
339 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
342LLRegion s57chart::GetValidRegion() {
343 double ll[8] = {m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.SLAT,
344 m_FullExtent.ELON, m_FullExtent.NLAT, m_FullExtent.ELON,
345 m_FullExtent.NLAT, m_FullExtent.WLON};
346 return LLRegion(4, ll);
349void s57chart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
350 if (!ps52plib)
return;
355 case GLOBAL_COLOR_SCHEME_DAY:
356 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
358 case GLOBAL_COLOR_SCHEME_DUSK:
359 ps52plib->SetPLIBColorScheme(
"DUSK", ChartCtxFactory());
361 case GLOBAL_COLOR_SCHEME_NIGHT:
362 ps52plib->SetPLIBColorScheme(
"NIGHT", ChartCtxFactory());
365 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
369 m_global_color_scheme = cs;
371 if (bApplyImmediate) {
377 ClearRenderedTextCache();
380 ChangeThumbColor(cs);
383void s57chart::ChangeThumbColor(ColorScheme cs) {
384 if (0 == m_pDIBThumbDay)
return;
388 case GLOBAL_COLOR_SCHEME_DAY:
389 pThumbData->pDIBThumb = m_pDIBThumbDay;
390 m_pDIBThumbOrphan = m_pDIBThumbDim;
392 case GLOBAL_COLOR_SCHEME_DUSK:
393 case GLOBAL_COLOR_SCHEME_NIGHT: {
394 if (NULL == m_pDIBThumbDim) {
395 wxImage img = m_pDIBThumbDay->ConvertToImage();
397#if wxCHECK_VERSION(2, 8, 0)
398 wxImage gimg = img.ConvertToGreyscale(
408 wxBitmap *pBMP =
new wxBitmap(gimg);
410 m_pDIBThumbDim = pBMP;
411 m_pDIBThumbOrphan = m_pDIBThumbDay;
414 pThumbData->pDIBThumb = m_pDIBThumbDim;
420bool s57chart::GetChartExtent(
Extent *pext) {
422 *pext = m_FullExtent;
428static void free_mps(mps_container *mps) {
429 if (mps == 0)
return;
430 if (ps52plib && mps->cs_rules) {
431 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
432 Rules *rule_chain_top = mps->cs_rules->Item(i);
433 ps52plib->DestroyRulesChain(rule_chain_top);
435 delete mps->cs_rules;
440void s57chart::FreeObjectsAndRules() {
449 for (
int i = 0; i < PRIO_NUM; ++i) {
450 for (
int j = 0; j < LUPNAME_NUM; j++) {
451 top = razRules[i][j];
452 while (top != NULL) {
454 if (0 == top->obj->nRef)
delete top->obj;
457 ObjRazRules *ctop = top->child;
461 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
463 ObjRazRules *cnxx = ctop->next;
478void s57chart::ClearRenderedTextCache() {
480 for (
int i = 0; i < PRIO_NUM; ++i) {
481 for (
int j = 0; j < LUPNAME_NUM; j++) {
482 top = razRules[i][j];
483 while (top != NULL) {
484 if (top->obj->bFText_Added) {
485 top->obj->bFText_Added =
false;
486 delete top->obj->FText;
487 top->obj->FText = NULL;
491 ObjRazRules *ctop = top->child;
493 if (ctop->obj->bFText_Added) {
494 ctop->obj->bFText_Added =
false;
495 delete ctop->obj->FText;
496 ctop->obj->FText = NULL;
508double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
509 bool b_allow_overzoom) {
511 return m_Chart_Scale * 0.125;
515double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
517 return m_Chart_Scale * 4.0;
524void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
526 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
528 r->y = roundint(m_pixy_vp_center -
529 ((north - m_northing_vp_center) * m_view_scale_ppm));
532void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
533 wxPoint *r,
int nPoints) {
534 for (
int i = 0; i < nPoints; i++) {
535 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
537 r[i].y = roundint(m_pixy_vp_center -
538 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
542void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
544 if (vpt->m_projection_type != PROJECTION_MERCATOR)
545 printf(
"s57chart unhandled projection\n");
551 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
552 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
558 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
568void s57chart::SetVPParms(
const ViewPort &vpt) {
574 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
575 &m_northing_vp_center);
577 vp_transform.easting_vp_center = m_easting_vp_center;
578 vp_transform.northing_vp_center = m_northing_vp_center;
582 if (IsCacheValid()) {
585 double prev_easting_c, prev_northing_c;
586 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
589 double easting_c, northing_c;
590 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
598 int dpix_x = (int)round(delta_pix_x);
603 int dpix_y = (int)round(delta_pix_y);
606 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
607 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
610 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
612 vp_proposed.
clon = xlon;
613 vp_proposed.
clat = xlat;
640void s57chart::LoadThumb() {
641 wxFileName fn(m_FullPath);
642 wxString SENCdir = g_SENCPrefix;
644 if (SENCdir.Last() != fn.GetPathSeparator())
645 SENCdir.Append(fn.GetPathSeparator());
647 wxFileName tsfn(SENCdir);
648 tsfn.SetFullName(fn.GetFullName());
650 wxFileName ThumbFileNameLook(tsfn);
651 ThumbFileNameLook.SetExt(
"BMP");
654 if (ThumbFileNameLook.FileExists()) {
657 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
658 m_pDIBThumbDay = pBMP;
659 m_pDIBThumbOrphan = 0;
664ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
667 if (pThumbData->pDIBThumb == 0) {
669 ChangeThumbColor(m_global_color_scheme);
672 UpdateThumbData(lat, lon);
677bool s57chart::UpdateThumbData(
double lat,
double lon) {
681 if (pThumbData->pDIBThumb) {
682 double lat_top = m_FullExtent.NLAT;
683 double lat_bot = m_FullExtent.SLAT;
684 double lon_left = m_FullExtent.WLON;
685 double lon_right = m_FullExtent.ELON;
688 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
690 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
692 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
695 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
696 (int)(east * thumb_view_scale_ppm);
697 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
698 (int)(north * thumb_view_scale_ppm);
705 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
706 pThumbData->ShipX = test_x;
707 pThumbData->ShipY = test_y;
713void s57chart::SetFullExtent(
Extent &ext) {
714 m_FullExtent.NLAT = ext.NLAT;
715 m_FullExtent.SLAT = ext.SLAT;
716 m_FullExtent.WLON = ext.WLON;
717 m_FullExtent.ELON = ext.ELON;
722void s57chart::ForceEdgePriorityEvaluate() { m_bLinePrioritySet =
false; }
724void s57chart::SetLinePriorities() {
725 if (!ps52plib)
return;
730 if (!m_bLinePrioritySet) {
734 for (
int i = 0; i < PRIO_NUM; ++i) {
735 top = razRules[i][2];
736 while (top != NULL) {
737 ObjRazRules *crnt = top;
739 ps52plib->SetLineFeaturePriority(crnt, i);
745 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
750 top = razRules[i][j];
751 while (top != NULL) {
754 ps52plib->SetLineFeaturePriority(crnt, i);
760 for (
int i = 0; i < PRIO_NUM; ++i) {
761 for (
int j = 0; j < LUPNAME_NUM; j++) {
762 ObjRazRules *top = razRules[i][j];
763 while (top != NULL) {
764 S57Obj *obj = top->obj;
767 connector_segment *pcs;
768 line_segment_element *list = obj->m_ls_list;
770 switch (list->ls_type) {
774 if (pedge) list->priority = pedge->max_priority;
779 if (pcs) list->priority = pcs->max_priority_cs;
794 m_bLinePrioritySet =
true;
798void s57chart::SetLinePriorities(
void )
800 if( !ps52plib )
return;
805 if( !m_bLinePrioritySet ) {
809 for(
int i = 0; i < PRIO_NUM; ++i ) {
811 top = razRules[i][2];
812 while( top != NULL ) {
813 ObjRazRules *crnt = top;
815 ps52plib->SetLineFeaturePriority( crnt, i );
820 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
825 top = razRules[i][j];
826 while( top != NULL ) {
829 ps52plib->SetLineFeaturePriority( crnt, i );
837 for(
int i = 0; i < PRIO_NUM; ++i ) {
838 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
839 ObjRazRules *top = razRules[i][j];
840 while( top != NULL ) {
841 S57Obj *obj = top->obj;
844 connector_segment *pcs;
845 line_segment_element *list = obj->m_ls_list;
850 pedge = (VE_Element *)list->private0;
852 list->priority = pedge->max_priority;
856 pcs = (connector_segment *)list->private0;
858 list->priority = pcs->max_priority;
873 m_bLinePrioritySet =
true;
877int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
881 line_segment_element *ls_list = obj->m_ls_list;
883 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
884 nPoints += ls_list->pedge->nCount;
887 ls_list = ls_list->next;
896 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
900 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
901 ls_list = obj->m_ls_list;
903 size_t vbo_offset = 0;
905 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
906 vbo_offset = ls_list->pedge->vbo_offset;
907 count = ls_list->pedge->nCount;
909 vbo_offset = ls_list->pcs->vbo_offset;
913 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
915 ls_list = ls_list->next;
922int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
927 line_segment_element *ls_list = obj->m_ls_list;
929 nPoints += ls_list->n_points;
930 ls_list = ls_list->next;
939 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
943 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
944 ls_list = obj->m_ls_list;
946 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
947 br += ls_list->n_points * 2;
948 ls_list = ls_list->next;
957 float e0, n0, e1, n1;
960void s57chart::AssembleLineGeometry() {
965 for (
const auto &it : m_ve_hash) {
966 VE_Element *pedge = it.second;
968 nPoints += pedge->nCount;
974 std::map<long long, connector_segment *> ce_connector_hash;
975 std::map<long long, connector_segment *> ec_connector_hash;
976 std::map<long long, connector_segment *> cc_connector_hash;
978 std::map<long long, connector_segment *>::iterator csit;
985 std::vector<segment_pair> connector_segment_vector;
986 size_t seg_pair_index = 0;
991 for (
int i = 0; i < PRIO_NUM; ++i) {
992 for (
int j = 0; j < LUPNAME_NUM; j++) {
993 ObjRazRules *top = razRules[i][j];
994 while (top != NULL) {
995 S57Obj *obj = top->obj;
997 if ((!obj->m_ls_list) &&
1000 line_segment_element list_top;
1003 line_segment_element *le_current = &list_top;
1005 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1006 if (!obj->m_lsindex_array)
continue;
1008 int seg_index = iseg * 3;
1009 int *index_run = &obj->m_lsindex_array[seg_index];
1012 unsigned int inode = *index_run++;
1015 bool edge_dir =
true;
1016 int venode = *index_run++;
1022 VE_Element *pedge = 0;
1024 if (m_ve_hash.find(venode) != m_ve_hash.end())
1025 pedge = m_ve_hash[venode];
1029 unsigned int enode = *index_run++;
1032 VC_Element *ipnode = 0;
1033 ipnode = m_vc_hash[inode];
1036 VC_Element *epnode = 0;
1037 epnode = m_vc_hash[enode];
1040 if (pedge && pedge->nCount) {
1044 long long key = ((
unsigned long long)inode << 32) + venode;
1046 connector_segment *pcs = NULL;
1047 csit = ce_connector_hash.find(key);
1048 if (csit == ce_connector_hash.end()) {
1050 pcs =
new connector_segment;
1051 ce_connector_hash[key] = pcs;
1055 float *ppt = ipnode->pPoint;
1060 pair.e1 = pedge->pPoints[0];
1061 pair.n1 = pedge->pPoints[1];
1063 int last_point_index = (pedge->nCount - 1) * 2;
1064 pair.e1 = pedge->pPoints[last_point_index];
1065 pair.n1 = pedge->pPoints[last_point_index + 1];
1068 connector_segment_vector.push_back(pair);
1069 pcs->vbo_offset = seg_pair_index;
1076 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1078 pcs->cs_lat_avg = lat;
1079 pcs->cs_lon_avg = lon;
1084 line_segment_element *pls =
new line_segment_element;
1089 pls->ls_type = TYPE_CE;
1091 le_current->next = pls;
1096 if (pedge && pedge->nCount) {
1097 line_segment_element *pls =
new line_segment_element;
1102 pls->ls_type = TYPE_EE;
1103 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1105 le_current->next = pls;
1113 if (pedge && pedge->nCount) {
1114 long long key = ((
unsigned long long)venode << 32) + enode;
1116 connector_segment *pcs = NULL;
1117 csit = ec_connector_hash.find(key);
1118 if (csit == ec_connector_hash.end()) {
1120 pcs =
new connector_segment;
1121 ec_connector_hash[key] = pcs;
1127 pair.e0 = pedge->pPoints[0];
1128 pair.n0 = pedge->pPoints[1];
1130 int last_point_index = (pedge->nCount - 1) * 2;
1131 pair.e0 = pedge->pPoints[last_point_index];
1132 pair.n0 = pedge->pPoints[last_point_index + 1];
1135 float *ppt = epnode->pPoint;
1139 connector_segment_vector.push_back(pair);
1140 pcs->vbo_offset = seg_pair_index;
1147 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1149 pcs->cs_lat_avg = lat;
1150 pcs->cs_lon_avg = lon;
1155 line_segment_element *pls =
new line_segment_element;
1159 pls->ls_type = TYPE_EC;
1161 le_current->next = pls;
1165 long long key = ((
unsigned long long)inode << 32) + enode;
1167 connector_segment *pcs = NULL;
1168 csit = cc_connector_hash.find(key);
1169 if (csit == cc_connector_hash.end()) {
1171 pcs =
new connector_segment;
1172 cc_connector_hash[key] = pcs;
1177 float *ppt = ipnode->pPoint;
1181 ppt = epnode->pPoint;
1185 connector_segment_vector.push_back(pair);
1186 pcs->vbo_offset = seg_pair_index;
1193 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1195 pcs->cs_lat_avg = lat;
1196 pcs->cs_lon_avg = lon;
1201 line_segment_element *pls =
new line_segment_element;
1205 pls->ls_type = TYPE_CC;
1207 le_current->next = pls;
1221 if (obj->m_ls_list == NULL) {
1222 obj->m_n_lsindex = 0;
1226 free(obj->m_lsindex_array);
1227 obj->m_lsindex_array = NULL;
1240 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1242 unsigned char *buffer_offset;
1245 bool grow_buffer =
false;
1247 if (0 == m_vbo_byte_length) {
1248 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1249 m_vbo_byte_length = vbo_byte_length;
1250 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1253 m_line_vertex_buffer = (
float *)realloc(
1254 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1255 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1256 offset = m_vbo_byte_length;
1257 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1261 float *lvr = (
float *)buffer_offset;
1265 for (
const auto &it : m_ve_hash) {
1266 VE_Element *pedge = it.second;
1268 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1269 lvr += pedge->nCount * 2;
1271 pedge->vbo_offset = offset;
1272 offset += pedge->nCount * 2 *
sizeof(float);
1285 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1287 connector_segment *pcs = csit->second;
1288 m_pcs_vector.push_back(pcs);
1290 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1296 pcs->vbo_offset = offset;
1297 offset += 4 *
sizeof(float);
1300 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1302 connector_segment *pcs = csit->second;
1303 m_pcs_vector.push_back(pcs);
1305 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1311 pcs->vbo_offset = offset;
1312 offset += 4 *
sizeof(float);
1315 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1317 connector_segment *pcs = csit->second;
1318 m_pcs_vector.push_back(pcs);
1320 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1326 pcs->vbo_offset = offset;
1327 offset += 4 *
sizeof(float);
1331 connector_segment_vector.clear();
1336 for (
const auto &it : m_ve_hash) {
1337 VE_Element *pedge = it.second;
1339 m_pve_vector.push_back(pedge);
1340 free(pedge->pPoints);
1348 for (
const auto &it : m_vc_hash) {
1349 VC_Element *pcs = it.second;
1350 if (pcs) free(pcs->pPoint);
1356 if (g_b_EnableVBO) {
1358 if (m_LineVBO_name > 0) {
1359 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1360 m_LineVBO_name = -1;
1367void s57chart::BuildLineVBO() {
1369 if (!g_b_EnableVBO)
return;
1371 if (m_LineVBO_name == -1) {
1374 glGenBuffers(1, &vboId);
1377 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1383#ifndef USE_ANDROID_GLES2
1384 glEnableClientState(GL_VERTEX_ARRAY);
1386 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1391 ObjRazRules *top, *crnt;
1392 int vbo_area_size_bytes = 0;
1393 for (
int i = 0; i < PRIO_NUM; ++i) {
1394 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1395 top = razRules[i][4];
1397 top = razRules[i][3];
1399 while (top != NULL) {
1404 PolyTriGroup *ppg_vbo =
1405 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1407 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1414 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes, NULL,
1417 GLenum err = glGetError();
1420 msg.Printf(
"S57 VBO Error 1: %d", err);
1422 printf(
"S57 VBO Error 1: %d", err);
1426 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length,
1427 m_line_vertex_buffer);
1432 msg.Printf(
"S57 VBO Error 2: %d", err);
1434 printf(
"S57 VBO Error 2: %d", err);
1438 int vbo_load_offset = m_vbo_byte_length;
1440 for (
int i = 0; i < PRIO_NUM; ++i) {
1441 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1442 top = razRules[i][4];
1444 top = razRules[i][3];
1446 while (top != NULL) {
1451 PolyTriGroup *ppg_vbo =
1452 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1455 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1456 ppg_vbo->single_buffer_size, ppg_vbo->single_buffer);
1458 crnt->obj->vboAreaOffset = vbo_load_offset;
1459 vbo_load_offset += ppg_vbo->single_buffer_size;
1466 msg.Printf(
"S57 VBO Error 3: %d", err);
1468 printf(
"S57 VBO Error 3: %d", err);
1473#ifndef USE_ANDROID_GLES2
1474 glDisableClientState(GL_VERTEX_ARRAY);
1476 glBindBuffer(GL_ARRAY_BUFFER, 0);
1480 for (
int i = 0; i < PRIO_NUM; ++i) {
1481 for (
int j = 0; j < LUPNAME_NUM; j++) {
1482 ObjRazRules *top = razRules[i][j];
1483 while (top != NULL) {
1484 S57Obj *obj = top->obj;
1485 obj->auxParm2 = vboId;
1491 m_LineVBO_name = vboId;
1492 m_this_chart_context->vboID = vboId;
1511bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1514 const LLRegion &Region) {
1515 if (!m_RAZBuilt)
return false;
1517 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1520bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1523 const LLRegion &Region) {
1524 if (!m_RAZBuilt)
return false;
1526 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1529bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1532 const LLRegion &Region) {
1533 if (!m_RAZBuilt)
return false;
1535 bool b_text = ps52plib->GetShowS57Text();
1536 ps52plib->m_bShowS57Text =
false;
1537 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1538 ps52plib->m_bShowS57Text = b_text;
1543bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1545 if (!m_RAZBuilt)
return false;
1549 if (!ps52plib)
return false;
1552 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1554 glChartCanvas::DisableClipRegion();
1555 DoRenderOnGLText(glc, VPoint);
1561bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1564 const LLRegion &Region,
bool b_overlay) {
1565 if (!m_RAZBuilt)
return false;
1569 if (!ps52plib)
return false;
1571 if (g_bDebugS57) printf(
"\n");
1575 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1577 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1578 m_bLinePrioritySet =
false;
1580 ClearRenderedTextCache();
1582 ResetPointBBoxes(m_last_vp, VPoint);
1585 m_plib_state_hash = ps52plib->GetStateHash();
1589 ResetPointBBoxes(m_last_vp, VPoint);
1593 SetLinePriorities();
1596 ps52plib->ClearTextList();
1604 wxRect upr = upd.GetRect();
1607 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1608 chart_region.Intersect(Region);
1610 if (!chart_region.Empty()) {
1614 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1621 if (CHART_TYPE_CM93 == GetChartType()) {
1625 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1628#ifdef OPT_USE_ANDROID_GLES2
1636 wxRect r = upd.GetRect();
1638 glViewport(r.x, vp->
pix_height - (r.y + r.height), r.width, r.height);
1646 float yp = vp->
pix_height - (r.y + r.height);
1648 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1649 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1652 I[0][0] *= 2.0 / (float)r.width;
1653 I[1][1] *= -2.0 / (float)r.height;
1657 mat4x4_rotate_Z(Q, I, angle);
1659 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1662 ps52plib->SetReducedBBox(cvp.GetBBox());
1663 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1668 DoRenderOnGL(glc, cvp);
1670 glChartCanvas::DisableClipRegion();
1683bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1696 for (i = 0; i < PRIO_NUM; ++i) {
1697 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1698 top = razRules[i][4];
1700 top = razRules[i][3];
1702 while (top != NULL) {
1705 crnt->sm_transform_parms = &vp_transform;
1706 ps52plib->RenderAreaToGL(glc, crnt);
1712 for (i = 0; i < PRIO_NUM; ++i) {
1714 top = razRules[i][4];
1716 top = razRules[i][3];
1718 while (top != NULL) {
1721 crnt->sm_transform_parms = &vp_transform;
1726 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1727 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1728 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1729 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1732 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1739 for (i = 0; i < PRIO_NUM; ++i) {
1740 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1741 top = razRules[i][4];
1743 top = razRules[i][3];
1744 while (top != NULL) {
1747 crnt->sm_transform_parms = &vp_transform;
1748 ps52plib->RenderObjectToGL(glc, crnt);
1753 for (i = 0; i < PRIO_NUM; ++i) {
1754 top = razRules[i][2];
1755 while (top != NULL) {
1758 crnt->sm_transform_parms = &vp_transform;
1759 ps52plib->RenderObjectToGL(glc, crnt);
1765 for (i = 0; i < PRIO_NUM; ++i) {
1766 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1767 top = razRules[i][0];
1769 top = razRules[i][1];
1771 while (top != NULL) {
1774 crnt->sm_transform_parms = &vp_transform;
1775 ps52plib->RenderObjectToGL(glc, crnt);
1785bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1796 for( i = 0; i < PRIO_NUM; ++i ) {
1797 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1798 top = razRules[i][4];
1800 top = razRules[i][3];
1802 while( top != NULL ) {
1805 crnt->sm_transform_parms = &vp_transform;
1812 for (i = 0; i < PRIO_NUM; ++i) {
1813 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1814 top = razRules[i][4];
1816 top = razRules[i][3];
1818 while (top != NULL) {
1821 crnt->sm_transform_parms = &vp_transform;
1822 ps52plib->RenderObjectToGLText(glc, crnt);
1825 top = razRules[i][2];
1826 while (top != NULL) {
1829 crnt->sm_transform_parms = &vp_transform;
1830 ps52plib->RenderObjectToGLText(glc, crnt);
1833 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1834 top = razRules[i][0];
1836 top = razRules[i][1];
1838 while (top != NULL) {
1841 crnt->sm_transform_parms = &vp_transform;
1842 ps52plib->RenderObjectToGLText(glc, crnt);
1851bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1854 if (!m_RAZBuilt)
return false;
1856 bool b_text = ps52plib->GetShowS57Text();
1857 ps52plib->m_bShowS57Text =
false;
1858 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1859 ps52plib->m_bShowS57Text = b_text;
1864bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1867 if (!dc.IsOk())
return false;
1870 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1875 DCRenderText(dc, VPoint);
1878 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1882 while (upd.HaveRects()) {
1883 wxRect rect = upd.GetRect();
1889 temp_vp.
GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1893 temp_vp.
GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1895 if (temp_lon_right < temp_lon_left)
1896 temp_lon_right += 360.;
1898 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1901 wxDCClipper clip(dc, rect);
1902 DCRenderText(dc, temp_vp);
1911bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1913 if (!m_RAZBuilt)
return false;
1915 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1918bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1921 if (!m_RAZBuilt)
return false;
1922 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1925bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1930 bool force_new_view =
false;
1932 if (Region != m_last_Region) force_new_view =
true;
1934 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1936 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1937 m_bLinePrioritySet =
false;
1939 ClearRenderedTextCache();
1941 ResetPointBBoxes(m_last_vp, VPoint);
1946 ResetPointBBoxes(m_last_vp, VPoint);
1949 SetLinePriorities();
1951 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1955 if (VPoint.b_quilt) {
1957 if ((m_pCloneBM->GetWidth() != VPoint.
pix_width) ||
1958 (m_pCloneBM->GetHeight() != VPoint.
pix_height)) {
1963 if (NULL == m_pCloneBM)
1966 wxMemoryDC dc_clone;
1967 dc_clone.SelectObject(*m_pCloneBM);
1969#ifdef ocpnUSE_DIBSECTION
1972 wxMemoryDC memdc, dc_org;
1975 pDIB->SelectIntoDC(dc_org);
1980 while (upd.HaveRects()) {
1981 wxRect rect = upd.GetRect();
1982 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
1987 dc_clone.SelectObject(wxNullBitmap);
1988 dc_org.SelectObject(wxNullBitmap);
1992 wxColour nodat = GetGlobalColor(
"NODTA");
1993 wxColour nodat_sub = nodat;
1995#ifdef ocpnUSE_ocpnBitmap
1996 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
1998 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
1999 m_pCloneBM->SetMask(m_pMask);
2002 dc.SelectObject(*m_pCloneBM);
2004 pDIB->SelectIntoDC(dc);
2006 m_last_Region = Region;
2011bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2016 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2018 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2019 m_bLinePrioritySet =
false;
2021 ClearRenderedTextCache();
2025 SetLinePriorities();
2027 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2029 pDIB->SelectIntoDC(dc);
2036bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2037 RenderTypeEnum option,
bool force_new_view) {
2038 bool bnewview =
false;
2040 bool bNewVP =
false;
2042 bool bReallyNew =
false;
2044 double easting_ul, northing_ul;
2045 double easting_lr, northing_lr;
2046 double prev_easting_ul = 0., prev_northing_ul = 0.;
2048 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2049 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2058 if (m_last_vprect != dest) bReallyNew =
true;
2059 m_last_vprect = dest;
2061 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2063 m_plib_state_hash = ps52plib->GetStateHash();
2074 if (m_last_vp.IsValid()) {
2076 m_easting_vp_center - ((VPoint.
pix_width / 2) / m_view_scale_ppm);
2078 m_northing_vp_center + ((VPoint.
pix_height / 2) / m_view_scale_ppm);
2079 easting_lr = easting_ul + (VPoint.
pix_width / m_view_scale_ppm);
2080 northing_lr = northing_ul - (VPoint.
pix_height / m_view_scale_ppm);
2082 double last_easting_vp_center, last_northing_vp_center;
2083 toSM(m_last_vp.
clat, m_last_vp.
clon, ref_lat, ref_lon,
2084 &last_easting_vp_center, &last_northing_vp_center);
2087 last_easting_vp_center - ((m_last_vp.
pix_width / 2) / m_view_scale_ppm);
2088 prev_northing_ul = last_northing_vp_center +
2089 ((m_last_vp.
pix_height / 2) / m_view_scale_ppm);
2091 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2092 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2094 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2095 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2097 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2098 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2100 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2103 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2112 else if ((rul.x != 0) || (rul.y != 0)) {
2113 if (g_bDebugS57) printf(
"newvp due to rul\n");
2124 if (force_new_view) bNewVP =
true;
2129 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2130 rgn_last.Intersect(rgn_new);
2132 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2134 rgn_last.GetBox(xu, yu, wu, hu);
2151 pDIB->SelectIntoDC(dc_last);
2156 pDIBNew->SelectIntoDC(dc_new);
2160 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2165 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.
pix_width,
2168 dc_new.SelectObject(wxNullBitmap);
2169 dc_last.SelectObject(wxNullBitmap);
2177 pDIB->SelectIntoDC(dc);
2181 rgn_delta.Subtract(rgn_reused);
2184 while (upd.HaveRects()) {
2185 wxRect rect = upd.GetRect();
2190 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2192 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2193 (rect.y / m_view_scale_ppm);
2194 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2195 (rect.x / m_view_scale_ppm);
2196 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2199 double temp_northing_lr =
2200 temp_northing_ul - (rect.height / m_view_scale_ppm);
2201 double temp_easting_lr =
2202 temp_easting_ul + (rect.width / m_view_scale_ppm);
2203 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2206 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2211 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2212 temp_vp.GetBBox().GetLatRange()) *
2214 temp_vp.GetBBox().EnLarge(margin);
2220 DCRenderRect(dc, temp_vp, &rect);
2225 dc.SelectObject(wxNullBitmap);
2234 else if (bNewVP || (NULL == pDIB)) {
2240 pDIB->SelectIntoDC(dc);
2243 ps52plib->ClearTextList();
2245 DCRenderRect(dc, VPoint, &full_rect);
2247 dc.SelectObject(wxNullBitmap);
2258int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2271 render_canvas_parms pb_spec;
2273 pb_spec.depth = BPP;
2274 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2275 pb_spec.lclip = rect->x;
2276 pb_spec.rclip = rect->x + rect->width - 1;
2277 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2278 pb_spec.width = rect->width;
2279 pb_spec.height = rect->height;
2280 pb_spec.x = rect->x;
2281 pb_spec.y = rect->y;
2283#ifdef ocpnUSE_ocpnBitmap
2284 pb_spec.b_revrgb =
true;
2286 pb_spec.b_revrgb =
false;
2290 wxColour color = GetGlobalColor(
"NODTA");
2291 unsigned char r, g, b;
2299 if (pb_spec.depth == 24) {
2300 for (
int i = 0; i < pb_spec.height; i++) {
2301 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2302 for (
int j = 0; j < pb_spec.width; j++) {
2309 int color_int = ((r) << 16) + ((g) << 8) + (b);
2311 for (
int i = 0; i < pb_spec.height; i++) {
2312 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2313 for (
int j = 0; j < pb_spec.width; j++) {
2320 for (i = 0; i < PRIO_NUM; ++i) {
2321 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2322 top = razRules[i][4];
2324 top = razRules[i][3];
2326 while (top != NULL) {
2329 crnt->sm_transform_parms = &vp_transform;
2330 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2335#ifdef ocpnUSE_ocpnBitmap
2336 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2337 pb_spec.height, pb_spec.depth);
2339 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2340 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2341 wxBitmap *pREN =
new wxBitmap(*prender_image);
2347 dc_ren.SelectObject(*pREN);
2350 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2351 (wxDC *)&dc_ren, 0, 0);
2354 dc_ren.SelectObject(wxNullBitmap);
2356#ifdef ocpnUSE_ocpnBitmap
2357 free(pb_spec.pix_buff);
2359 delete prender_image;
2366 DCRenderLPB(dcinput, vp, rect);
2371bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2378 for (i = 0; i < PRIO_NUM; ++i) {
2380 wxDCClipper *pdcc = NULL;
2386 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2387 top = razRules[i][4];
2389 top = razRules[i][3];
2390 while (top != NULL) {
2393 crnt->sm_transform_parms = &vp_transform;
2394 ps52plib->RenderObjectToDC(&dcinput, crnt);
2397 top = razRules[i][2];
2398 while (top != NULL) {
2401 crnt->sm_transform_parms = &vp_transform;
2402 ps52plib->RenderObjectToDC(&dcinput, crnt);
2405 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2406 top = razRules[i][0];
2408 top = razRules[i][1];
2410 while (top != NULL) {
2413 crnt->sm_transform_parms = &vp_transform;
2414 ps52plib->RenderObjectToDC(&dcinput, crnt);
2418 if (pdcc)
delete pdcc;
2431bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2437 for (i = 0; i < PRIO_NUM; ++i) {
2438 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2439 top = razRules[i][4];
2441 top = razRules[i][3];
2443 while (top != NULL) {
2446 crnt->sm_transform_parms = &vp_transform;
2447 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2450 top = razRules[i][2];
2451 while (top != NULL) {
2454 crnt->sm_transform_parms = &vp_transform;
2455 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2458 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2459 top = razRules[i][0];
2461 top = razRules[i][1];
2463 while (top != NULL) {
2466 crnt->sm_transform_parms = &vp_transform;
2467 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2474bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2475 wxFileName fn(FullPath);
2477 wxString cname = fn.GetName();
2478 if (cname.Length() >= 3)
2479 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2484InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2487 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2490 if (name.Upper().EndsWith(
".XZ")) {
2491 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2494 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2495 wxFileName(name).GetName();
2497 if (!wxFileExists(m_TempFilePath) &&
2498 !DecompressXZFile(name, m_TempFilePath)) {
2499 wxRemoveFile(m_TempFilePath);
2500 return INIT_FAIL_REMOVE;
2503 m_TempFilePath = name;
2504 ext = wxFileName(name).GetExt();
2509 firebase::crashlytics::SetCustomKey(
"s57chartInit",
2510 name.ToStdString().c_str());
2517 return INIT_FAIL_NOERROR;
2522 InitReturn ret_value = INIT_OK;
2524 m_Description = name;
2526 wxFileName fn(m_TempFilePath);
2529 wxString cname = fn.GetName();
2530 m_usage_char = cname[2];
2533 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2534 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2536 if (flags == THUMB_ONLY) {
2544 if (flags == HEADER_ONLY) {
2546 if (!GetBaseFileAttr(fn.GetFullPath()))
2547 ret_value = INIT_FAIL_REMOVE;
2549 if (!CreateHeaderDataFromENC())
2550 ret_value = INIT_FAIL_REMOVE;
2552 ret_value = INIT_OK;
2554 }
else if (ext ==
"S57") {
2555 m_SENCFileName = m_TempFilePath;
2556 if (!CreateHeaderDataFromSENC())
2557 ret_value = INIT_FAIL_REMOVE;
2559 ret_value = INIT_OK;
2568 if (!m_bbase_file_attr_known) {
2569 if (!GetBaseFileAttr(m_TempFilePath))
2570 ret_value = INIT_FAIL_REMOVE;
2572 m_bbase_file_attr_known =
true;
2576 if (m_bbase_file_attr_known) {
2577 int sret = FindOrCreateSenc(m_FullPath);
2578 if (sret == BUILD_SENC_PENDING) {
2583 if (sret != BUILD_SENC_OK) {
2584 if (sret == BUILD_SENC_NOK_RETRY)
2585 ret_value = INIT_FAIL_RETRY;
2587 ret_value = INIT_FAIL_REMOVE;
2589 ret_value = PostInit(flags, m_global_color_scheme);
2594 else if (ext ==
"S57") {
2595 m_SENCFileName = m_TempFilePath;
2596 ret_value = PostInit(flags, m_global_color_scheme);
2603wxString s57chart::buildSENCName(
const wxString &name) {
2604 wxFileName fn(name);
2606 wxString file_name = fn.GetFullName();
2609 wxString SENCdir = g_SENCPrefix;
2611 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2612 SENCdir.Append(wxFileName::GetPathSeparator());
2615 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2616 wxCharBuffer buf = source_dir.ToUTF8();
2617 unsigned char sha1_out[20];
2618 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2621 for (
unsigned int i = 0; i < 6; i++) {
2623 s.Printf(
"%02X", sha1_out[i]);
2627 file_name.Prepend(sha1);
2630 wxFileName tsfn(SENCdir);
2631 tsfn.SetFullName(file_name);
2633 return tsfn.GetFullPath();
2640int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2644 if (name.Upper().EndsWith(
".XZ")) {
2645 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2648 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2649 wxFileName(name).GetName();
2651 if (!wxFileExists(m_TempFilePath) &&
2652 !DecompressXZFile(name, m_TempFilePath)) {
2653 wxRemoveFile(m_TempFilePath);
2654 return INIT_FAIL_REMOVE;
2657 m_TempFilePath = name;
2658 ext = wxFileName(name).GetExt();
2662 if (!m_bbase_file_attr_known) {
2663 if (!GetBaseFileAttr(m_TempFilePath))
2664 return INIT_FAIL_REMOVE;
2666 m_bbase_file_attr_known =
true;
2670 m_SENCFileName = buildSENCName(name);
2672 int build_ret_val = 1;
2674 bool bbuild_new_senc =
false;
2675 m_bneed_new_thumbnail =
false;
2677 wxFileName FileName000(m_TempFilePath);
2681 wxString msg(
"S57chart::Checking SENC file: ");
2682 msg.Append(m_SENCFileName);
2686 int force_make_senc = 0;
2688 if (::wxFileExists(m_SENCFileName)) {
2691 if (senc.ingestHeader(m_SENCFileName)) {
2692 bbuild_new_senc =
true;
2693 wxLogMessage(
" Rebuilding SENC due to ingestHeader failure.");
2695 int senc_file_version = senc.getSencReadVersion();
2697 int last_update = senc.getSENCReadLastUpdate();
2699 wxString str = senc.getSENCFileCreateDate();
2700 wxDateTime SENCCreateDate;
2701 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
2703 if (SENCCreateDate.IsValid())
2704 SENCCreateDate.ResetTime();
2709 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2711 senc_base_edtn.ToLong(&isenc_edition);
2713 m_edtn000.ToLong(&ifile_edition);
2718 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2719 bbuild_new_senc =
true;
2720 wxLogMessage(
" Rebuilding SENC due to SENC format update.");
2727 else if (ifile_edition > isenc_edition) {
2728 bbuild_new_senc =
true;
2729 wxLogMessage(
" Rebuilding SENC due to cell edition update.");
2731 msg =
" Last edition recorded in SENC: ";
2732 msg += senc_base_edtn;
2733 msg +=
" most recent edition cell file: ";
2738 int most_recent_update_file =
2739 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2741 if (ifile_edition == isenc_edition) {
2742 if (most_recent_update_file > last_update) {
2743 bbuild_new_senc =
true;
2745 " Rebuilding SENC due to incremental cell update.");
2748 " Last update recorded in SENC: %d most recent "
2750 last_update, most_recent_update_file);
2758 wxDateTime OModTime000;
2759 FileName000.GetTimes(NULL, &OModTime000, NULL);
2760 OModTime000.ResetTime();
2761 if (SENCCreateDate.IsValid()) {
2762 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2764 " Rebuilding SENC due to Senc vs cell file time "
2766 bbuild_new_senc =
true;
2769 bbuild_new_senc =
true;
2771 " Rebuilding SENC due to SENC create time invalid.");
2782 if (force_make_senc) bbuild_new_senc =
true;
2784 }
else if (!::wxFileExists(m_SENCFileName))
2786 wxLogMessage(
" Rebuilding SENC due to missing SENC file.");
2787 bbuild_new_senc =
true;
2791 if (bbuild_new_senc) {
2792 m_bneed_new_thumbnail =
2794 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2796 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2797 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2798 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2804InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2806 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2807 wxString msg(
" Cannot load SENC file ");
2808 msg.Append(m_SENCFileName);
2811 return INIT_FAIL_RETRY;
2817 wxString SENCdir = g_SENCPrefix;
2818 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2819 SENCdir.Append(wxFileName::GetPathSeparator());
2821 wxFileName s57File(m_SENCFileName);
2822 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13),
"BMP");
2824 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2825 BuildThumbnail(ThumbFileName.GetFullPath());
2828 if (ThumbFileName.FileExists()) {
2830#ifdef ocpnUSE_ocpnBitmap
2831 pBMP_NEW =
new ocpnBitmap;
2833 pBMP_NEW =
new wxBitmap;
2835 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2838 m_pDIBThumbDay = pBMP_NEW;
2846 m_global_color_scheme = cs;
2847 SetColorScheme(cs,
false);
2850 BuildDepthContourArray();
2852 CreateChartContext();
2853 PopulateObjectsWithContext();
2856 bReadyToRender =
true;
2861void s57chart::ClearDepthContourArray() {
2862 if (m_nvaldco_alloc) {
2863 free(m_pvaldco_array);
2865 m_nvaldco_alloc = 5;
2867 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2870void s57chart::BuildDepthContourArray() {
2873 if (0 == m_nvaldco_alloc) {
2874 m_nvaldco_alloc = 5;
2875 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2881 double prev_valdco = 0.0;
2883 for (
int i = 0; i < PRIO_NUM; ++i) {
2884 for (
int j = 0; j < LUPNAME_NUM; j++) {
2885 top = razRules[i][j];
2886 while (top != NULL) {
2887 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2888 double valdco = 0.0;
2889 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2890 if (valdco != prev_valdco) {
2891 prev_valdco = valdco;
2893 if (m_nvaldco > m_nvaldco_alloc) {
2894 void *tr = realloc((
void *)m_pvaldco_array,
2895 m_nvaldco_alloc * 2 *
sizeof(
double));
2896 m_pvaldco_array = (
double *)tr;
2897 m_nvaldco_alloc *= 2;
2899 m_pvaldco_array[m_nvaldco - 1] = valdco;
2903 ObjRazRules *nxx = top->next;
2908 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2912void s57chart::SetSafetyContour() {
2920 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2923 if (NULL != m_pvaldco_array) {
2924 for (i = 0; i < m_nvaldco; i++) {
2925 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2929 m_next_safe_cnt = m_pvaldco_array[i];
2931 m_next_safe_cnt = (double)1e6;
2933 m_next_safe_cnt = (double)1e6;
2938 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2939 m_next_safe_cnt = (
double)1e6;
2942void s57chart::CreateChartContext() {
2944 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2947void s57chart::PopulateObjectsWithContext() {
2948 m_this_chart_context->chart =
this;
2949 m_this_chart_context->chart_type = GetChartType();
2950 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2951 m_this_chart_context->chart_scale = GetNativeScale();
2952 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2953 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2954 m_this_chart_context->safety_contour = m_next_safe_cnt;
2955 m_this_chart_context->pt2GetAssociatedObjects =
2956 &s57chart::GetAssociatedObjects;
2960 for (
int i = 0; i < PRIO_NUM; ++i) {
2961 for (
int j = 0; j < LUPNAME_NUM; j++) {
2962 top = razRules[i][j];
2963 while (top != NULL) {
2964 S57Obj *obj = top->obj;
2965 obj->m_chart_context = m_this_chart_context;
2972void s57chart::InvalidateCache() {
2977bool s57chart::BuildThumbnail(
const wxString &bmpname) {
2980 wxFileName ThumbFileName(bmpname);
2983 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
2984 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
2985 wxLogMessage(
" Cannot create BMP file directory for " +
2986 ThumbFileName.GetFullPath());
2994 vp.
clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
2995 vp.
clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2997 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
2998 (m_FullExtent.ELON - m_FullExtent.WLON));
3005 vp.m_projection_type = PROJECTION_MERCATOR;
3007 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3024 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3026 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3028 int *psvr = psave_viz;
3032 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3033 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3034 *psvr++ = pOLE->nViz;
3039 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3040 bool bsave_text = ps52plib->m_bShowS57Text;
3043 ps52plib->SaveObjNoshow();
3046 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3047 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3048 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3049 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3052 ps52plib->m_bShowSoundg =
false;
3053 ps52plib->m_bShowS57Text =
false;
3056 DisCat dsave = ps52plib->GetDisplayCategory();
3057 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3059 ps52plib->AddObjNoshow(
"BRIDGE");
3060 ps52plib->AddObjNoshow(
"GATCON");
3062 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3063 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3064 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3065 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3067#ifdef ocpnUSE_DIBSECTION
3070 wxMemoryDC memdc, dc_org;
3074 ps52plib->SaveColorScheme();
3075 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3077 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3080 memdc.SelectObject(wxNullBitmap);
3084 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3085 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3086 pOLE->nViz = *psvr++;
3089 ps52plib->SetDisplayCategory(dsave);
3090 ps52plib->RestoreObjNoshow();
3092 ps52plib->RemoveObjNoshow(
"BRIDGE");
3093 ps52plib->RemoveObjNoshow(
"GATCON");
3095 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3096 ps52plib->m_bShowS57Text = bsave_text;
3098 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3099 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3102 ps52plib->RestoreColorScheme();
3112 wxMemoryDC dc_clone;
3113 dc_clone.SelectObject(*pBMP);
3115 pDIB->SelectIntoDC(dc_org);
3119 dc_clone.SelectObject(wxNullBitmap);
3120 dc_org.SelectObject(wxNullBitmap);
3123 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3130#include <wx/arrimpl.cpp>
3131WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3134bool s57chart::CreateHeaderDataFromENC() {
3135 if (!InitENCMinimal(m_TempFilePath)) {
3136 wxString msg(
" Cannot initialize ENC file ");
3137 msg.Append(m_TempFilePath);
3145 float LatMax, LatMin, LonMax, LonMin;
3151 m_pCOVRTablePoints = NULL;
3152 m_pCOVRTable = NULL;
3155 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3156 std::vector<int> auxCntArray, noCovrCntArray;
3158 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3161 pFeat = GetChartFirstM_COVR(catcov);
3166 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3167 OGRLinearRing *xring = poly->getExteriorRing();
3169 int npt = xring->getNumPoints();
3180 for (
int i = 0; i < npt; i++) {
3181 xring->getPoint(i, &p);
3185 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3187 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3188 if (xdelta < 0.001 &&
3196 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3197 pfr = &pf[2 * (usedpts - 1)];
3200 LatMax = fmax(LatMax, p.getY());
3201 LatMin = fmin(LatMin, p.getY());
3202 LonMax = fmax(LonMax, p.getX());
3203 LonMin = fmin(LonMin, p.getX());
3211 pAuxPtrArray->Add(pf);
3212 auxCntArray.push_back(usedpts);
3213 }
else if (catcov == 2) {
3214 pNoCovrPtrArray->Add(pf);
3215 noCovrCntArray.push_back(usedpts);
3220 pFeat = GetChartNextM_COVR(catcov);
3221 DEBUG_LOG <<
"used " << usedpts <<
" points";
3226 m_nCOVREntries = auxCntArray.size();
3230 if (m_nCOVREntries >= 1) {
3231 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3232 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3234 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3235 m_pCOVRTablePoints[j] = auxCntArray[j];
3236 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3242 wxString msg(
" ENC contains no useable M_COVR, CATCOV=1 features: ");
3243 msg.Append(m_TempFilePath);
3248 m_nNoCOVREntries = noCovrCntArray.size();
3250 if (m_nNoCOVREntries) {
3252 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3253 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3255 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3256 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3257 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3260 m_pNoCOVRTablePoints = NULL;
3261 m_pNoCOVRTable = NULL;
3264 delete pAuxPtrArray;
3265 delete pNoCovrPtrArray;
3267 if (0 == m_nCOVREntries) {
3268 wxString msg(
" ENC contains no M_COVR features: ");
3269 msg.Append(m_TempFilePath);
3272 msg =
" Calculating Chart Extents as fallback.";
3278 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3280 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3287 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3288 *m_pCOVRTablePoints = 4;
3289 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3290 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3307 wxString msg(
" Cannot calculate Extents for ENC: ");
3308 msg.Append(m_TempFilePath);
3316 m_FullExtent.NLAT = LatMax;
3317 m_FullExtent.SLAT = LatMin;
3318 m_FullExtent.ELON = LonMax;
3319 m_FullExtent.WLON = LonMin;
3320 m_bExtentSet =
true;
3323 m_Chart_Scale = GetENCScale();
3326 GetChartNameFromTXT(m_TempFilePath, nice_name);
3334bool s57chart::CreateHeaderDataFromoSENC() {
3335 bool ret_val =
true;
3337 wxFFileInputStream fpx(m_SENCFileName);
3339 if (!::wxFileExists(m_SENCFileName)) {
3340 wxString msg(
" Cannot open SENC file ");
3341 msg.Append(m_SENCFileName);
3348 if (senc.ingestHeader(m_SENCFileName)) {
3354 m_Chart_Scale = senc.getSENCReadScale();
3357 m_Name = senc.getReadName();
3360 m_ID = senc.getReadID();
3363 Extent &ext = senc.getReadExtent();
3365 m_FullExtent.ELON = ext.ELON;
3366 m_FullExtent.WLON = ext.WLON;
3367 m_FullExtent.NLAT = ext.NLAT;
3368 m_FullExtent.SLAT = ext.SLAT;
3369 m_bExtentSet =
true;
3372 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3373 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3375 m_nCOVREntries = AuxCntArray.size();
3377 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3378 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3380 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3381 m_pCOVRTablePoints[j] = AuxCntArray[j];
3382 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3383 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3384 AuxCntArray[j] * 2 *
sizeof(
float));
3388 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3389 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3391 m_nNoCOVREntries = NoCovrCntArray.size();
3393 if (m_nNoCOVREntries) {
3395 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3396 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3398 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3399 int npoints = NoCovrCntArray[j];
3400 m_pNoCOVRTablePoints[j] = npoints;
3401 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3402 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3403 npoints * 2 *
sizeof(
float));
3409 m_datum_str =
"WGS84";
3410 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
3412 int senc_file_version = senc.getSencReadVersion();
3414 int last_update = senc.getSENCReadLastUpdate();
3416 wxString str = senc.getSENCFileCreateDate();
3417 wxDateTime SENCCreateDate;
3418 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
3420 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3422 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3429bool s57chart::CreateHeaderDataFromSENC() {
3430 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3438bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3440 if (NULL != m_pvaldco_array) {
3441 for (i = 0; i < m_nvaldco; i++) {
3442 if (m_pvaldco_array[i] >= safe_cnt)
break;
3446 next_safe_cnt = m_pvaldco_array[i];
3448 next_safe_cnt = (double)1e6;
3451 next_safe_cnt = (double)1e6;
3465std::list<S57Obj *> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3469 std::list<S57Obj *> *pobj_list =
new std::list<S57Obj *>();
3472 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3473 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3476 switch (obj->Primitive_type) {
3489 top = razRules[disPrioIdx][3];
3490 while (top != NULL) {
3491 if (top->obj->bIsAssociable) {
3492 if (top->obj->BBObj.Contains(lat, lon)) {
3493 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3494 pobj_list->push_back(top->obj);
3501 ObjRazRules *nxx = top->next;
3506 top = razRules[disPrioIdx][4];
3507 while (top != NULL) {
3508 if (top->obj->bIsAssociable) {
3509 if (top->obj->BBObj.Contains(lat, lon)) {
3510 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3511 pobj_list->push_back(top->obj);
3517 ObjRazRules *nxx = top->next;
3531void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3532 wxFileName fn(FullPath);
3534 wxString target_name = fn.GetName();
3535 target_name.RemoveLast();
3537 wxString dir_name = fn.GetPath();
3539 wxDir dir(dir_name);
3541 wxArrayString FileList;
3543 dir.GetAllFiles(fn.GetPath(), &FileList);
3547 bool found_name =
false;
3551 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3552 wxFileName file(FileList[j]);
3553 if (((file.GetExt()).MakeUpper()) ==
"TXT") {
3555 wxTextFile text_file(file.GetFullPath());
3557 bool file_ok =
true;
3561 if (!text_file.Open()) {
3562 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3567 wxString str = text_file.GetFirstLine();
3568 while (!text_file.Eof()) {
3569 if (0 == target_name.CmpNoCase(
3570 str.Mid(0, target_name.Len()))) {
3571 wxString tname = str.AfterFirst(
'-');
3572 name = tname.AfterFirst(
' ');
3576 str = text_file.GetNextLine();
3580 wxString msg(
" Error Reading ENC .TXT file: ");
3581 msg.Append(file.GetFullPath());
3587 if (found_name)
break;
3604const char *s57chart::getName(OGRFeature *feature) {
3605 return feature->GetDefnRef()->GetName();
3608static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3609 wxFileName fn1(first);
3610 wxFileName fn2(second);
3611 wxString ext1(fn1.GetExt());
3612 wxString ext2(fn2.GetExt());
3614 return ext1.Cmp(ext2);
3617int s57chart::GetUpdateFileArray(
const wxFileName file000,
3618 wxArrayString *UpFiles, wxDateTime date000,
3620 wxString DirName000 =
3621 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3622 wxDir dir(DirName000);
3623 if (!dir.IsOpened()) {
3624 DirName000.Prepend(wxFileName::GetPathSeparator());
3625 DirName000.Prepend(
".");
3626 dir.Open(DirName000);
3627 if (!dir.IsOpened()) {
3632 int flags = wxDIR_DEFAULT;
3639 wxFileName fnDir(DirName000);
3640 fnDir.RemoveLastDir();
3641 wxString sdir = fnDir.GetPath();
3642 wxFileName fnTest(sdir);
3643 wxString sname = fnTest.GetName();
3645 if (sname.ToLong(&tmps)) {
3648 flags |= wxDIR_DIRS;
3652 wxArrayString *dummy_array;
3655 if (UpFiles == NULL)
3656 dummy_array =
new wxArrayString;
3658 dummy_array = UpFiles;
3660 wxArrayString possibleFiles;
3661 wxDir::GetAllFiles(DirName000, &possibleFiles,
"", flags);
3663 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3664 wxString filename(possibleFiles[i]);
3666 wxFileName file(filename);
3667 ext = file.GetExt();
3672 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3673 wxString FileToAdd = filename;
3675 wxCharBuffer buffer =
3678 if (buffer.data() && !filename.IsSameAs(
"CATALOG.031",
3690 DDFModule *poModule =
new DDFModule();
3691 if (!poModule->Open(FileToAdd.mb_str())) {
3693 " s57chart::BuildS57File Unable to open update file ");
3694 msg.Append(FileToAdd);
3703 DDFRecord *pr = poModule->ReadRecord();
3709 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3712 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3716 " s57chart::BuildS57File DDFRecord 0 does not contain "
3717 "DSID:ISDT in update file ");
3718 msg.Append(FileToAdd);
3721 sumdate =
"20000101";
3724 umdate.ParseFormat(sumdate,
"%Y%m%d");
3725 if (!umdate.IsValid()) umdate.ParseFormat(
"20000101",
"%Y%m%d");
3728 if (!umdate.IsValid())
int yyp = 4;
3733 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3735 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3739 " s57chart::BuildS57File DDFRecord 0 does not contain "
3740 "DSID:EDTN in update file ");
3741 msg.Append(FileToAdd);
3750 if ((!umdate.IsEarlierThan(date000)) &&
3751 (umedtn.IsSameAs(edtn000)))
3752 dummy_array->Add(FileToAdd);
3758 dummy_array->Sort(ExtensionCompare);
3761 if (dummy_array->GetCount()) {
3762 wxString Last = dummy_array->Last();
3763 wxFileName fnl(Last);
3765 wxCharBuffer buffer = ext.ToUTF8();
3766 if (buffer.data()) retval = atoi(buffer.data());
3769 if (UpFiles == NULL)
delete dummy_array;
3774int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3775 const wxString CopyDir,
3776 wxString &LastUpdateDate,
3782 wxArrayString *UpFiles =
new wxArrayString;
3783 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3785 if (UpFiles->GetCount()) {
3805 for (
int iff = 0; iff < retval + 1; iff++) {
3806 wxFileName ufile(m_TempFilePath);
3808 sext.Printf(
"%03d", iff);
3812 wxString cp_ufile = CopyDir;
3813 if (cp_ufile.Last() != ufile.GetPathSeparator())
3814 cp_ufile.Append(ufile.GetPathSeparator());
3816 cp_ufile.Append(ufile.GetFullName());
3821 if (ufile.FileExists()) {
3822 wxFile uf(ufile.GetFullPath());
3823 if (uf.IsOpened()) {
3829 if (ufile.FileExists() &&
3833 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3835 wxString msg(
" Cannot copy temporary working ENC file ");
3836 msg.Append(ufile.GetFullPath());
3838 msg.Append(cp_ufile);
3851 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3852 "incomplete or inaccurate.\nCheck the logfile for details."),
3853 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3859 "WARNING---ENC Update chain incomplete. Substituting NULL "
3861 msg += ufile.GetFullName();
3863 wxLogMessage(
" Subsequent ENC updates may produce errors.");
3865 " This ENC exchange set should be updated and SENCs "
3869 DDFModule *dupdate =
new DDFModule;
3870 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3871 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3875 wxString msg(
" Error creating dummy update file: ");
3876 msg.Append(cp_ufile);
3881 m_tmpup_array->Add(cp_ufile);
3888 wxFileName lastfile(m_TempFilePath);
3890 last_sext.Printf(
"%03d", retval);
3891 lastfile.SetExt(last_sext);
3894 DDFModule oUpdateModule;
3899 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3903 oUpdateModule.Rewind();
3904 DDFRecord *pr = oUpdateModule.ReadRecord();
3910 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3914 LastUpdateDate = wxString(u, wxConvUTF8);
3917 wxDateTime now = wxDateTime::Now();
3918 LastUpdateDate = now.Format(
"%Y%m%d");
3927wxString s57chart::GetISDT() {
3928 if (m_date000.IsValid())
3929 return m_date000.Format(
"%Y%m%d");
3934bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3935 if (!wxFileName::FileExists(file000))
return false;
3937 wxString FullPath000 = file000;
3938 DDFModule *poModule =
new DDFModule();
3939 if (!poModule->Open(FullPath000.mb_str())) {
3940 wxString msg(
" s57chart::BuildS57File Unable to open ");
3941 msg.Append(FullPath000);
3953 DDFRecord *pr = poModule->ReadRecord();
3957 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3958 if (!m_nGeoRecords) {
3960 " s57chart::BuildS57File DDFRecord 0 does not contain "
3970 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3972 date000 = wxString(u, wxConvUTF8);
3975 " s57chart::BuildS57File DDFRecord 0 does not contain "
3982 m_date000.ParseFormat(date000,
"%Y%m%d");
3983 if (!m_date000.IsValid()) m_date000.ParseFormat(
"20000101",
"%Y%m%d");
3985 m_date000.ResetTime();
3988 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3990 m_edtn000 = wxString(u, wxConvUTF8);
3993 " s57chart::BuildS57File DDFRecord 0 does not contain "
4004 for (; pr != NULL; pr = poModule->ReadRecord()) {
4005 if (pr->FindField(
"DSPM") != NULL) {
4006 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4010 if (!m_native_scale) {
4011 wxString msg(
" s57chart::BuildS57File ENC not contain DSPM:CSCL ");
4014 m_native_scale = 1000;
4022int s57chart::BuildSENCFile(
const wxString &FullPath000,
4023 const wxString &SENCFileName,
bool b_progress) {
4025 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4026 double meters_per_pixel_max_scale =
4028 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4031 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4032 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4034 if (!m_disableBackgroundSENC) {
4037 ticket->m_LOD_meters = m_LOD_meters;
4038 ticket->ref_lat = ref_lat;
4039 ticket->ref_lon = ref_lon;
4040 ticket->m_FullPath000 = FullPath000;
4041 ticket->m_SENCFileName = SENCFileName;
4042 ticket->m_chart =
this;
4045 bReadyToRender =
true;
4046 return BUILD_SENC_PENDING;
4049 return BUILD_SENC_NOK_RETRY;
4054 senc.setRegistrar(g_poRegistrar);
4055 senc.setRefLocn(ref_lat, ref_lon);
4056 senc.SetLODMeters(m_LOD_meters);
4058 AbstractPlatform::ShowBusySpinner();
4060 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4062 AbstractPlatform::HideBusySpinner();
4064 if (ret == ERROR_INGESTING000)
4065 return BUILD_SENC_NOK_PERMANENT;
4071int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4078 S57ObjVector Objects;
4079 VE_ElementVector VEs;
4080 VC_ElementVector VCs;
4082 sencfile.setRefLocn(ref_lat, ref_lon);
4084 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4086 if (srv != SENC_NO_ERROR) {
4087 wxLogMessage(sencfile.getLastError());
4093 Extent ext = sencfile.getReadExtent();
4095 m_FullExtent.ELON = ext.ELON;
4096 m_FullExtent.WLON = ext.WLON;
4097 m_FullExtent.NLAT = ext.NLAT;
4098 m_FullExtent.SLAT = ext.SLAT;
4099 m_bExtentSet =
true;
4101 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4102 ref_lon = (ext.ELON + ext.WLON) / 2.;
4107 int n_ve_elements = VEs.size();
4109 double scale = gFrame->GetBestVPScale(
this);
4110 int nativescale = GetNativeScale();
4112 for (
int i = 0; i < n_ve_elements; i++) {
4113 VE_Element *vep = VEs.at(i);
4114 if (vep && vep->nCount) {
4116 double east_max = -1e7;
4117 double east_min = 1e7;
4118 double north_max = -1e7;
4119 double north_min = 1e7;
4121 float *vrun = vep->pPoints;
4122 for (
size_t i = 0; i < vep->nCount; i++) {
4123 east_max = wxMax(east_max, *vrun);
4124 east_min = wxMin(east_min, *vrun);
4127 north_max = wxMax(north_max, *vrun);
4128 north_min = wxMin(north_min, *vrun);
4132 double lat1, lon1, lat2, lon2;
4133 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4134 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4135 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4138 m_ve_hash[vep->index] = vep;
4142 int n_vc_elements = VCs.size();
4144 for (
int i = 0; i < n_vc_elements; i++) {
4145 VC_Element *vcp = VCs.at(i);
4146 m_vc_hash[vcp->index] = vcp;
4154 for (
unsigned int i = 0; i < Objects.size(); i++) {
4155 S57Obj *obj = Objects[i];
4159 LUPname LUP_Name = PAPER_CHART;
4161 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4162 if (objnam.Len() > 0) {
4163 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4164 SendVectorChartObjectInfo(FullPath, fe_name, objnam, obj->m_lat,
4165 obj->m_lon,
scale, nativescale);
4169 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4170 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4171 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4172 SendVectorChartObjectInfo(FullPath, fe_name, nobjnam, obj->m_lat,
4173 obj->m_lon,
scale, nativescale);
4176 switch (obj->Primitive_type) {
4181 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4182 LUP_Name = PAPER_CHART;
4184 LUP_Name = SIMPLIFIED;
4193 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4194 LUP_Name = PLAIN_BOUNDARIES;
4196 LUP_Name = SYMBOLIZED_BOUNDARIES;
4201 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4205 wxString msg(obj->FeatureName, wxConvUTF8);
4206 msg.Prepend(
" Could not find LUP for ");
4207 LogMessageOnce(msg);
4214 ps52plib->_LUP2rules(LUP, obj);
4217 _insertRules(obj, LUP,
this);
4220 obj->m_DisplayCat = LUP->DISC;
4223 obj->m_DPRI = LUP->DPRI -
'0';
4226 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4227 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4228 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4229 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4230 obj->m_bcategory_mutable =
true;
4232 obj->m_bcategory_mutable =
false;
4237 if (obj && (GEO_POINT == obj->Primitive_type)) {
4239 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4240 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4241 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4242 pFloatingATONArray->Add(obj);
4246 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4247 pRigidATONArray->Add(obj);
4251 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4252 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4253 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4254 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4255 obj->bIsAton =
true;
4264 d000.ParseFormat(sencfile.getBaseDate(),
"%Y%m%d");
4265 if (!d000.IsValid()) d000.ParseFormat(
"20000101",
"%Y%m%d");
4268 updt.ParseFormat(sencfile.getUpdateDate(),
"%Y%m%d");
4269 if (!updt.IsValid()) updt.ParseFormat(
"20000101",
"%Y%m%d");
4271 if (updt.IsLaterThan(d000))
4272 m_PubYear.Printf(
"%4d", updt.GetYear());
4274 m_PubYear.Printf(
"%4d", d000.GetYear());
4277 wxDateTime upd = updt;
4278 if (!upd.IsValid()) upd.ParseFormat(
"20000101",
"%Y%m%d");
4283 m_SE = sencfile.getSENCReadBaseEdition();
4286 supdate.Printf(
" / %d", sencfile.getSENCReadLastUpdate());
4289 m_datum_str =
"WGS84";
4291 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
4292 m_ID = sencfile.getReadID();
4293 m_Name = sencfile.getReadName();
4297 AssembleLineGeometry();
4302int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4303 ObjRazRules *rzRules = NULL;
4313 switch (LUP->DPRI) {
4326 case PRIO_SYMB_POINT:
4329 case PRIO_SYMB_LINE:
4332 case PRIO_SYMB_AREA:
4345 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4349 switch (LUP->TNAM) {
4359 case PLAIN_BOUNDARIES:
4362 case SYMBOLIZED_BOUNDARIES:
4366 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4370 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4374 rzRules->child = NULL;
4375 rzRules->mps = NULL;
4378 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4379 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4384 ObjRazRules *rNext = NULL;
4385 ObjRazRules *rPrevious = NULL;
4386 if (razRules[disPrioIdx][LUPtypeIdx]) {
4387 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4388 rNext = rPrevious->next;
4392 rNext = rPrevious->next;
4395 rzRules->next = NULL;
4397 rPrevious->next = rzRules;
4399 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4406void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4416 for (
int i = 0; i < PRIO_NUM; ++i) {
4417 for (
int j = 0; j < 2; ++j) {
4418 top = razRules[i][j];
4420 while (top != NULL) {
4421 if (!top->obj->geoPtMulti)
4423 if (top->obj->BBObj.GetValid()) {
4424 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4426 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4427 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4429 double minlon = top->obj->BBObj.GetMinLon();
4430 double maxlon = top->obj->BBObj.GetMaxLon();
4432 double lon1 = (lon - minlon) * d;
4433 double lon2 = (lon - maxlon) * d;
4435 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4438 top->obj->BBObj.Invalidate();
4459void s57chart::UpdateLUPs(
s57chart *pOwner) {
4463 for (
int i = 0; i < PRIO_NUM; ++i) {
4465 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4466 m_b2pointLUPS =
true;
4467 top = razRules[i][0];
4469 while (top != NULL) {
4470 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4476 if (top->obj->nRef < 2) {
4477 ps52plib->_LUP2rules(LUP, top->obj);
4478 _insertRules(top->obj, LUP, pOwner);
4479 top->obj->m_DisplayCat = LUP->DISC;
4489 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4490 m_b2pointLUPS =
true;
4491 top = razRules[i][1];
4493 while (top != NULL) {
4494 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4497 if (top->obj->nRef < 2) {
4498 ps52plib->_LUP2rules(LUP, top->obj);
4499 _insertRules(top->obj, LUP, pOwner);
4500 top->obj->m_DisplayCat = LUP->DISC;
4510 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4511 m_b2lineLUPS =
true;
4512 top = razRules[i][3];
4514 while (top != NULL) {
4515 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4516 top->obj->FeatureName, top->obj);
4518 ps52plib->_LUP2rules(LUP, top->obj);
4519 _insertRules(top->obj, LUP, pOwner);
4520 top->obj->m_DisplayCat = LUP->DISC;
4529 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4530 m_b2lineLUPS =
true;
4531 top = razRules[i][4];
4533 while (top != NULL) {
4534 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4537 ps52plib->_LUP2rules(LUP, top->obj);
4538 _insertRules(top->obj, LUP, pOwner);
4539 top->obj->m_DisplayCat = LUP->DISC;
4551 for (
int j = 0; j < LUPNAME_NUM; j++) {
4552 top = razRules[i][j];
4553 while (top != NULL) {
4554 top->obj->bCS_Added = 0;
4557 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4568 for (
int j = 0; j < LUPNAME_NUM; j++) {
4569 top = razRules[i][j];
4570 while (top != NULL) {
4572 ObjRazRules *ctop = top->child;
4573 while (NULL != ctop) {
4574 ctop->obj->bCS_Added = 0;
4575 free_mps(ctop->mps);
4578 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4595ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4596 float lat,
float lon,
ViewPort *VPoint) {
4597 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4598 std::vector<ObjRazRules *> selected_rules;
4603 char *curr_att = NULL;
4605 wxArrayOfS57attVal *attValArray = NULL;
4606 bool bleading_attribute =
false;
4608 for (
int i = 0; i < PRIO_NUM; ++i) {
4612 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4613 top = razRules[i][point_type];
4615 while (top != NULL) {
4616 if (top->obj->npt == 1) {
4617 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4619 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4621 if (ps52plib->ObjectRenderCheckCat(top)) {
4624 wxString curAttrName;
4625 curr_att = top->obj->att_array;
4626 n_attr = top->obj->n_attr;
4627 attValArray = top->obj->attVal;
4635 bleading_attribute =
false;
4637 while (attrCounter < n_attr) {
4638 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4641 S57attVal *pAttrVal = NULL;
4644 pAttrVal = attValArray->Item(attrCounter);
4648 wxString value = s57chart::GetAttributeValueAsString(
4649 pAttrVal, curAttrName);
4651 if (curAttrName ==
"LITVIS") {
4652 if (value.StartsWith(
"obsc")) bviz =
false;
4653 }
else if (curAttrName ==
"VALNMR")
4654 value.ToDouble(&valnmr);
4660 if (bviz && (valnmr > 0.1)) {
4664 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4665 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4666 ref_lat, ref_lon, &olat, &olon);
4668 double dlat = lat - olat;
4669 double dy = dlat * 60 / cos(olat * PI / 180.);
4670 double dlon = lon - olon;
4671 double dx = dlon * 60;
4672 double manhat = abs(dy) + abs(dx);
4676 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4678 selected_rules.push_back(top);
4695 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4696 ret_ptr->Append(selected_rules[i]);
4702ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4703 float select_radius,
4705 int selection_mask) {
4706 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4707 std::vector<ObjRazRules *> selected_rules;
4709 PrepareForRender(VPoint, ps52plib);
4715 for (
int i = 0; i < PRIO_NUM; ++i) {
4716 if (selection_mask & MASK_POINT) {
4719 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4720 top = razRules[i][point_type];
4722 while (top != NULL) {
4723 if (top->obj->npt ==
4726 if (ps52plib->ObjectRenderCheck(top)) {
4727 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4728 selected_rules.push_back(top);
4735 ObjRazRules *child_item = top->child;
4736 while (child_item != NULL) {
4737 if (ps52plib->ObjectRenderCheck(child_item)) {
4738 if (DoesLatLonSelectObject(lat, lon, select_radius,
4740 selected_rules.push_back(child_item);
4743 child_item = child_item->next;
4751 if (selection_mask & MASK_AREA) {
4754 int area_boundary_type =
4755 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4756 top = razRules[i][area_boundary_type];
4757 while (top != NULL) {
4758 if (ps52plib->ObjectRenderCheck(top)) {
4759 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4760 selected_rules.push_back(top);
4767 if (selection_mask & MASK_LINE) {
4769 top = razRules[i][2];
4771 while (top != NULL) {
4772 if (ps52plib->ObjectRenderCheck(top)) {
4773 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4774 selected_rules.push_back(top);
4785 auto sortObjs = [lat, lon,
this](
const ObjRazRules *obj1,
4786 const ObjRazRules *obj2) ->
bool {
4787 double br1, dd1, br2, dd2;
4789 if (obj1->obj->Primitive_type == GEO_POINT &&
4790 obj2->obj->Primitive_type == GEO_POINT) {
4791 double lat1, lat2, lon1, lon2;
4792 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4793 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin, ref_lat,
4794 ref_lon, &lat1, &lon1);
4796 if (lon1 > 180.0) lon1 -= 360.;
4798 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4799 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin, ref_lat,
4800 ref_lon, &lat2, &lon2);
4802 if (lon2 > 180.0) lon2 -= 360.;
4804 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4805 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4812 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4816 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4817 ret_ptr->Append(selected_rules[i]);
4823bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4825 switch (obj->Primitive_type) {
4829 if (!obj->BBObj.GetValid())
return false;
4831 if (1 == obj->npt) {
4836 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4838 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4841 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4842 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4849 sbox.Set(olat, olon, olat, olon);
4851 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4852 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4857 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4864 if (!obj->BBObj.GetValid())
return false;
4867 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4869 double *pdl = obj->geoPtMulti;
4870 for (
int ip = 0; ip < obj->npt; ip++) {
4871 double lon_point = *pdl++;
4872 double lat_point = *pdl++;
4874 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4875 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4886 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4889 return IsPointInObjArea(lat, lon, select_radius, obj);
4894 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4896 float sel_rad_meters = select_radius * 1852 * 60;
4897 double easting, northing;
4898 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4905 pt *ppt = obj->geoPt;
4908 double xr = obj->x_rate;
4909 double xo = obj->x_origin;
4910 double yr = obj->y_rate;
4911 double yo = obj->y_origin;
4913 double north0 = (ppt->y * yr) + yo;
4914 double east0 = (ppt->x * xr) + xo;
4917 for (
int ip = 1; ip < npt; ip++) {
4918 double north = (ppt->y * yr) + yo;
4919 double east = (ppt->x * xr) + xo;
4922 if (northing >= (fmin(north, north0) - sel_rad_meters))
4923 if (northing <= (fmax(north, north0) + sel_rad_meters))
4924 if (easting >= (fmin(east, east0) - sel_rad_meters))
4925 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4935 if (obj->m_ls_list) {
4937 unsigned char *vbo_point =
4938 (
unsigned char *)obj->m_chart_context
4940 line_segment_element *ls = obj->m_ls_list;
4942 while (ls && vbo_point) {
4944 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4945 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4946 nPoints = ls->pedge->nCount;
4948 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4952 float north0 = ppt[1];
4953 float east0 = ppt[0];
4957 for (
int ip = 0; ip < nPoints - 1; ip++) {
4958 float north = ppt[1];
4959 float east = ppt[0];
4961 if (northing >= (fmin(north, north0) - sel_rad_meters))
4962 if (northing <= (fmax(north, north0) + sel_rad_meters))
4963 if (easting >= (fmin(east, east0) - sel_rad_meters))
4964 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4991wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
4992 wxString ret_val =
"";
4995 const char *att_code;
4997 wxString file(g_csv_locn);
4998 file.Append(
"/s57attributes.csv");
5000 if (!wxFileName::FileExists(file)) {
5001 wxString msg(
" Could not open ");
5008 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5010 CC_ExactString,
"Code");
5016 wxString ei_file(g_csv_locn);
5017 ei_file.Append(
"/s57expectedinput.csv");
5019 if (!wxFileName::FileExists(ei_file)) {
5020 wxString msg(
" Could not open ");
5021 msg.Append(ei_file);
5027 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5028 CSVIngest(ei_file.mb_str());
5030 char **papszFields = NULL;
5031 int bSelected = FALSE;
5037 while (!bSelected && iline + 1 < psTable->nLineCount) {
5039 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5041 if (!strcmp(papszFields[0], att_code)) {
5042 if (atoi(papszFields[1]) == ival) {
5043 ret_val = wxString(papszFields[2], wxConvUTF8);
5048 CSLDestroy(papszFields);
5056bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5060 if (obj->pPolyTessGeo) {
5061 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5063 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5065 TriPrim *pTP = ppg->tri_prim_head;
5067 MyPoint pvert_list[3];
5071 double easting, northing;
5072 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5076 if (!ppg->m_bSMSENC) {
5077 double y_rate = obj->y_rate;
5078 double y_origin = obj->y_origin;
5079 double x_rate = obj->x_rate;
5080 double x_origin = obj->x_origin;
5082 double northing_scaled = (northing - y_origin) / y_rate;
5083 double easting_scaled = (easting - x_origin) / x_rate;
5084 northing = northing_scaled;
5085 easting = easting_scaled;
5090 if (pTP->tri_box.Contains(lat, lon)) {
5091 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5092 double *p_vertex = pTP->p_vertex;
5094 switch (pTP->type) {
5095 case PTG_TRIANGLE_FAN: {
5096 for (
int it = 0; it < pTP->nVert - 2; it++) {
5097 pvert_list[0].x = p_vertex[0];
5098 pvert_list[0].y = p_vertex[1];
5100 pvert_list[1].x = p_vertex[(it * 2) + 2];
5101 pvert_list[1].y = p_vertex[(it * 2) + 3];
5103 pvert_list[2].x = p_vertex[(it * 2) + 4];
5104 pvert_list[2].y = p_vertex[(it * 2) + 5];
5106 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5114 case PTG_TRIANGLE_STRIP: {
5115 for (
int it = 0; it < pTP->nVert - 2; it++) {
5116 pvert_list[0].x = p_vertex[(it * 2)];
5117 pvert_list[0].y = p_vertex[(it * 2) + 1];
5119 pvert_list[1].x = p_vertex[(it * 2) + 2];
5120 pvert_list[1].y = p_vertex[(it * 2) + 3];
5122 pvert_list[2].x = p_vertex[(it * 2) + 4];
5123 pvert_list[2].y = p_vertex[(it * 2) + 5];
5125 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5133 case PTG_TRIANGLES: {
5134 for (
int it = 0; it < pTP->nVert; it += 3) {
5135 pvert_list[0].x = p_vertex[(it * 2)];
5136 pvert_list[0].y = p_vertex[(it * 2) + 1];
5138 pvert_list[1].x = p_vertex[(it * 2) + 2];
5139 pvert_list[1].y = p_vertex[(it * 2) + 3];
5141 pvert_list[2].x = p_vertex[(it * 2) + 4];
5142 pvert_list[2].y = p_vertex[(it * 2) + 5];
5144 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5153 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5154 float *p_vertex = (
float *)pTP->p_vertex;
5156 switch (pTP->type) {
5157 case PTG_TRIANGLE_FAN: {
5158 for (
int it = 0; it < pTP->nVert - 2; it++) {
5159 pvert_list[0].x = p_vertex[0];
5160 pvert_list[0].y = p_vertex[1];
5162 pvert_list[1].x = p_vertex[(it * 2) + 2];
5163 pvert_list[1].y = p_vertex[(it * 2) + 3];
5165 pvert_list[2].x = p_vertex[(it * 2) + 4];
5166 pvert_list[2].y = p_vertex[(it * 2) + 5];
5168 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5176 case PTG_TRIANGLE_STRIP: {
5177 for (
int it = 0; it < pTP->nVert - 2; it++) {
5178 pvert_list[0].x = p_vertex[(it * 2)];
5179 pvert_list[0].y = p_vertex[(it * 2) + 1];
5181 pvert_list[1].x = p_vertex[(it * 2) + 2];
5182 pvert_list[1].y = p_vertex[(it * 2) + 3];
5184 pvert_list[2].x = p_vertex[(it * 2) + 4];
5185 pvert_list[2].y = p_vertex[(it * 2) + 5];
5187 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5195 case PTG_TRIANGLES: {
5196 for (
int it = 0; it < pTP->nVert; it += 3) {
5197 pvert_list[0].x = p_vertex[(it * 2)];
5198 pvert_list[0].y = p_vertex[(it * 2) + 1];
5200 pvert_list[1].x = p_vertex[(it * 2) + 2];
5201 pvert_list[1].y = p_vertex[(it * 2) + 3];
5203 pvert_list[2].x = p_vertex[(it * 2) + 4];
5204 pvert_list[2].y = p_vertex[(it * 2) + 5];
5206 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5229wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5230 wxString curAttrName) {
5234 pval = obj->attVal->Item(iatt);
5235 switch (pval->valType) {
5238 wxString val_str((
char *)(pval->value), wxConvUTF8);
5240 if (val_str.ToLong(&ival)) {
5244 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5245 if (!decode_val.IsEmpty()) {
5248 iv.Printf(
" (%d)", (
int)ival);
5251 value.Printf(
"%d", (
int)ival);
5255 else if (val_str.IsEmpty())
5260 wxString value_increment;
5261 wxStringTokenizer tk(val_str,
",");
5263 if (tk.HasMoreTokens()) {
5264 while (tk.HasMoreTokens()) {
5265 wxString token = tk.GetNextToken();
5267 if (token.ToLong(&ival)) {
5268 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5270 value_increment.Printf(
" (%d)", (
int)ival);
5272 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5274 if (iv) value_increment.Prepend(
", ");
5275 value.Append(value_increment);
5278 if (iv) value.Append(
",");
5279 value.Append(token);
5285 value.Append(val_str);
5288 value =
"[NULL VALUE]";
5294 int ival = *((
int *)pval->value);
5295 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5297 if (!decode_val.IsEmpty()) {
5300 iv.Printf(
"(%d)", ival);
5303 value.Printf(
"(%d)", ival);
5311 double dval = *((
double *)pval->value);
5312 wxString val_suffix =
" m";
5313 bool has_preformatted =
false;
5314 wxString preformatted;
5325 if ((curAttrName ==
"VERCLR") || (curAttrName ==
"VERCCL") ||
5326 (curAttrName ==
"VERCOP") || (curAttrName ==
"HEIGHT") ||
5327 (curAttrName ==
"ELEVAT") || (curAttrName ==
"VERCSA")) {
5332 val_suffix = wxString::Format(
" %s",
unit.c_str());
5333 }
else if (curAttrName ==
"HORCLR") {
5336 double nm = dval / 1852.0;
5338 has_preformatted =
true;
5341 else if ((curAttrName ==
"VALSOU") || (curAttrName ==
"DRVAL1") ||
5342 (curAttrName ==
"DRVAL2") || (curAttrName ==
"VALDCO")) {
5349 wxString
unit = getUsrDepthUnit(-1);
5350 val_suffix = wxString::Format(
" %s",
unit.c_str());
5353 else if (curAttrName ==
"SECTR1")
5354 val_suffix =
"°";
5355 else if (curAttrName ==
"SECTR2")
5356 val_suffix =
"°";
5357 else if (curAttrName ==
"ORIENT")
5358 val_suffix =
"°";
5359 else if (curAttrName ==
"VALNMR")
5361 else if (curAttrName ==
"SIGPER")
5363 else if (curAttrName ==
"VALACM")
5364 val_suffix =
" Minutes/year";
5365 else if (curAttrName ==
"VALMAG")
5366 val_suffix =
"°";
5367 else if (curAttrName ==
"CURVEL")
5370 if (has_preformatted) {
5371 value = preformatted;
5373 if (dval - floor(dval) < 0.01)
5374 value.Printf(
"%2.0f", dval);
5376 value.Printf(
"%4.1f", dval);
5377 value << val_suffix;
5383 case OGR_REAL_LST: {
5390wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5391 wxString AttrName) {
5392 if (NULL == pAttrVal)
return "";
5395 switch (pAttrVal->valType) {
5397 if (pAttrVal->value) {
5398 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5400 if (val_str.ToLong(&ival)) {
5404 wxString decode_val = GetAttributeDecode(AttrName, ival);
5405 if (!decode_val.IsEmpty()) {
5408 iv.Printf(
"(%d)", (
int)ival);
5411 value.Printf(
"%d", (
int)ival);
5415 else if (val_str.IsEmpty())
5420 wxString value_increment;
5421 wxStringTokenizer tk(val_str,
",");
5423 while (tk.HasMoreTokens()) {
5424 wxString token = tk.GetNextToken();
5426 if (token.ToLong(&ival)) {
5427 wxString decode_val = GetAttributeDecode(AttrName, ival);
5428 if (!decode_val.IsEmpty())
5429 value_increment = decode_val;
5431 value_increment.Printf(
" %d", (
int)ival);
5433 if (iv) value_increment.Prepend(
", ");
5435 value.Append(value_increment);
5439 value.Append(val_str);
5442 value =
"[NULL VALUE]";
5448 int ival = *((
int *)pAttrVal->value);
5449 wxString decode_val = GetAttributeDecode(AttrName, ival);
5451 if (!decode_val.IsEmpty()) {
5454 iv.Printf(
"(%d)", ival);
5457 value.Printf(
"(%d)", ival);
5465 double dval = *((
double *)pAttrVal->value);
5466 wxString val_suffix =
" m";
5467 bool has_preformatted =
false;
5468 wxString preformatted;
5471 if ((AttrName ==
"VERCLR") || (AttrName ==
"VERCCL") ||
5472 (AttrName ==
"VERCOP") || (AttrName ==
"HEIGHT") ||
5473 (AttrName ==
"ELEVAT")) {
5478 val_suffix = wxString::Format(
" %s",
unit.c_str());
5479 }
else if (AttrName ==
"HORCLR") {
5481 double nm = dval / 1852.0;
5483 has_preformatted =
true;
5486 else if ((AttrName ==
"VALSOU") || (AttrName ==
"DRVAL1") ||
5487 (AttrName ==
"DRVAL2")) {
5490 wxString
unit = getUsrDepthUnit(-1);
5491 val_suffix = wxString::Format(
" %s",
unit.c_str());
5494 else if (AttrName ==
"SECTR1")
5495 val_suffix =
"°";
5496 else if (AttrName ==
"SECTR2")
5497 val_suffix =
"°";
5498 else if (AttrName ==
"ORIENT")
5499 val_suffix =
"°";
5500 else if (AttrName ==
"VALNMR")
5502 else if (AttrName ==
"SIGPER")
5504 else if (AttrName ==
"VALACM")
5505 val_suffix =
" Minutes/year";
5506 else if (AttrName ==
"VALMAG")
5507 val_suffix =
"°";
5508 else if (AttrName ==
"CURVEL")
5511 if (has_preformatted) {
5512 value = preformatted;
5514 if (dval - floor(dval) < 0.01)
5515 value.Printf(
"%2.0f", dval);
5517 value.Printf(
"%4.1f", dval);
5518 value << val_suffix;
5524 case OGR_REAL_LST: {
5532 int positionDiff = l1->position.Cmp(l2->position);
5533 if (positionDiff < 0)
return false;
5535 int attrIndex1 = l1->attributeNames.Index(
"SECTR1");
5536 int attrIndex2 = l2->attributeNames.Index(
"SECTR1");
5539 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5540 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5541 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5543 double angle1, angle2;
5544 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5545 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5547 return angle1 < angle2;
5550static const char *type2str(GeoPrim_t type) {
5551 const char *r =
"Unknown";
5572wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5575 wxString curAttrName, value;
5576 bool isLight =
false;
5579 wxString classAttributes;
5581 wxString lightsHtml;
5582 wxString positionString;
5583 std::vector<S57Light *> lights;
5587 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5588 node = node->GetPrevious()) {
5589 ObjRazRules *current = node->GetData();
5590 positionString.Clear();
5594 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5596 if (current->obj->Primitive_type == GEO_META)
continue;
5597 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5599 className = wxString(current->obj->FeatureName, wxConvUTF8);
5602 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5607 const char *name_desc;
5608 if (g_csv_locn.Len()) {
5609 wxString oc_file(g_csv_locn);
5610 oc_file.Append(
"/s57objectclasses.csv");
5611 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5612 current->obj->FeatureName,
5613 CC_ExactString,
"ObjectClass");
5619 if (0 == strlen(name_desc)) {
5620 name_desc = current->obj->FeatureName;
5621 classDesc = wxString(name_desc, wxConvUTF8, 1);
5622 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5624 classDesc = wxString(name_desc, wxConvUTF8);
5631 classAttributes =
"";
5632 index.Printf(
"Feature Index: %d<br>", current->obj->Index);
5633 classAttributes << index;
5636 LUPstring.Printf(
"LUP RCID: %d<br>", current->LUP->RCID);
5637 classAttributes << LUPstring;
5640 LLBBox bbox = current->obj->BBObj;
5641 Bbox.Printf(
"Lat/Lon box: %g %g %g %g<br>", bbox.GetMinLat(),
5642 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5643 classAttributes << Bbox;
5646 Type.Printf(
" Type: %s<br>", type2str(current->obj->Primitive_type));
5647 classAttributes << Type;
5649 LUPstring =
" LUP ATTC: ";
5650 if (current->LUP->ATTArray.size())
5651 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5652 LUPstring +=
"<br>";
5653 classAttributes << LUPstring;
5655 LUPstring =
" LUP INST: ";
5656 LUPstring += current->LUP->INST;
5657 LUPstring +=
"<br><br>";
5658 classAttributes << LUPstring;
5661 if (GEO_POINT == current->obj->Primitive_type) {
5663 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5664 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5665 ref_lat, ref_lon, &lat, &lon);
5667 if (lon > 180.0) lon -= 360.;
5669 positionString.Clear();
5670 positionString += toSDMM(1, lat);
5671 positionString <<
" ";
5672 positionString += toSDMM(2, lon);
5676 curLight->position = positionString;
5677 curLight->hasSectors =
false;
5678 lights.push_back(curLight);
5684 if (current->obj->att_array) {
5685 char *curr_att = current->obj->att_array;
5691 attribStr <<
"<table border=0 cellspacing=0 cellpadding=0>";
5694 ret_val <<
"<p>" << classAttributes;
5697 bool inDepthRange =
false;
5699 while (attrCounter < current->obj->n_attr) {
5701 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5708 assert(curLight !=
nullptr);
5709 curLight->attributeNames.Add(curAttrName);
5710 if (curAttrName.StartsWith(
"SECTR")) curLight->hasSectors =
true;
5712 if (curAttrName ==
"DRVAL1") {
5713 attribStr <<
"<tr><td><font size=-1>";
5714 inDepthRange =
true;
5715 }
else if (curAttrName ==
"DRVAL2") {
5717 inDepthRange =
false;
5720 attribStr <<
"</font></td></tr>\n";
5721 inDepthRange =
false;
5723 attribStr <<
"<tr><td valign=top><font size=-2>";
5724 if (curAttrName ==
"catgeo")
5725 attribStr <<
"CATGEO";
5727 attribStr << curAttrName;
5728 attribStr <<
"</font></td><td> </td><td "
5729 "valign=top><font size=-1>";
5740 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5745 wxString AttrNamesFiles =
5746 "PICREP,TXTDSC,NTXTDS";
5748 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5749 if (value.Find(
".XML") == wxNOT_FOUND) {
5750 file.Assign(GetFullPath());
5751 file.Assign(file.GetPath(), value);
5754 if (file.IsCaseSensitive()) {
5755 wxDir dir(file.GetPath());
5757 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
5759 if (filename.IsSameAs(value,
false)) {
5761 file.Assign(file.GetPath(), value);
5764 cont = dir.GetNext(&filename);
5771 wxString::Format(
"<a href=\"%s\">%s</a>",
5772 file.GetFullPath(), file.GetFullName());
5774 value = value +
" <font color=\"red\">[ " +
5775 _(
"this file is not available") +
" ]</font>";
5779 "DATEND,DATSTA,PEREND,PERSTA";
5780 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5783 wxString ts = value;
5787 if (ts.Length() < 5) {
5791 if (ts.Length() < 7) {
5795 wxString::const_iterator end;
5797 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5799 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5800 if (d) ts.Append(wxString::Format(
" %d", dt.GetDay()));
5801 if (dt.GetYear() > 0)
5802 ts.Append(wxString::Format(
", %i", dt.GetYear()));
5803 if (curAttrName ==
"PEREND")
5804 ts = _(
"Period ends: ") + ts +
" (" + value +
")";
5805 if (curAttrName ==
"PERSTA")
5806 ts = _(
"Period starts: ") + ts +
" (" + value +
")";
5807 if (curAttrName ==
"DATEND")
5808 ts = _(
"Date ending: ") + ts +
" (" + value +
")";
5809 if (curAttrName ==
"DATSTA")
5810 ts = _(
"Date starting: ") + ts +
" (" + value +
")";
5814 if (curAttrName ==
"TS_TSP") {
5821 wxStringTokenizer tk(value,
",");
5826 ts1 = tk.GetNextToken().Trim(
false);
5829 }
while ((ts1.Left(2).ToLong(&l)));
5830 ts =
"Tidal Streams referred to<br><b>";
5831 ts.Append(tk.GetNextToken()).Append(
"</b> at <b>").Append(ts1);
5832 ts.Append(
"</b><br><table >");
5834 while (tk.HasMoreTokens()) {
5835 ts.Append(
"<tr><td>");
5836 wxString s1(wxString::Format(
"%+dh ", i));
5838 ts.Append(
"</td><td>");
5839 s1 = tk.GetNextToken();
5841 s1 =
"°</td><td>";
5843 s1 = tk.GetNextToken();
5846 ts.Append(
"</td></tr>");
5849 ts.Append(
"</table>");
5854 assert(curLight !=
nullptr);
5855 curLight->attributeValues.Add(value);
5857 if (curAttrName ==
"INFORM" || curAttrName ==
"NINFOM")
5858 value.Replace(
"|",
"<br>");
5860 if (curAttrName ==
"catgeo")
5861 attribStr << type2str(current->obj->Primitive_type);
5865 if (!(curAttrName ==
"DRVAL1")) {
5866 attribStr <<
"</font></td></tr>\n";
5876 attribStr <<
"</table>\n";
5878 objText +=
"<b>" + classDesc +
"</b> <font size=-2>(" + className +
5879 ")</font>" +
"<br>";
5881 if (positionString.Length())
5882 objText <<
"<font size=-2>" << positionString <<
"</font><br>\n";
5884 if (noAttr > 0) objText << attribStr;
5886 if (node != rule_list->GetFirst()) objText +=
"<hr noshade>";
5893 if (!lights.empty()) {
5894 assert(curLight !=
nullptr);
5899 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5903 for (
auto const &thisLight : lights) {
5906 if (thisLight->position != lastPos) {
5907 lastPos = thisLight->position;
5909 if (thisLight != *lights.begin())
5910 lightsHtml <<
"</table>\n<hr noshade>\n";
5912 lightsHtml <<
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>";
5913 lightsHtml <<
"<font size=-2>" << thisLight->position
5916 if (curLight->hasSectors)
5918 "<font size=-2>(Sector angles are True Bearings from "
5919 "Seaward)</font><br>");
5921 lightsHtml <<
"<table>";
5924 lightsHtml <<
"<tr>";
5925 lightsHtml <<
"<td><font size=-1>";
5928 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
5929 if (attrIndex != wxNOT_FOUND) {
5930 wxString color = thisLight->attributeValues.Item(attrIndex);
5931 if (color ==
"red (3)" || color ==
"red(3)")
5933 "<table border=0><tr><td "
5934 "bgcolor=red> </td></tr></table> ";
5935 else if (color ==
"green (4)" || color ==
"green(4)")
5937 "<table border=0><tr><td "
5938 "bgcolor=green> </td></tr></table> ";
5939 else if (color ==
"white (1)" || color ==
"white(1)")
5941 "<table border=0><tr><td "
5942 "bgcolor=white> </td></tr></table> ";
5943 else if (color ==
"yellow (6)" || color ==
"yellow(6)")
5945 "<table border=0><tr><td "
5946 "bgcolor=yellow> </td></tr></table> ";
5947 else if (color ==
"blue (5)" || color ==
"blue(5)")
5949 "<table border=0><tr><td "
5950 "bgcolor=blue> </td></tr></table> ";
5951 else if (color ==
"magenta (12)" || color ==
"magenta(12)")
5953 "<table border=0><tr><td "
5954 "bgcolor=magenta> </td></tr></table> ";
5957 "<table border=0><tr><td "
5958 "bgcolor=grey> ? </td></tr></table> ";
5961 int visIndex = thisLight->attributeNames.Index(
"LITVIS");
5962 if (visIndex != wxNOT_FOUND) {
5963 wxString vis = thisLight->attributeValues.Item(visIndex);
5964 if (vis.Contains(
"8")) {
5965 if (attrIndex != wxNOT_FOUND) {
5966 wxString color = thisLight->attributeValues.Item(attrIndex);
5967 if ((color ==
"red (3)" || color ==
"red(3)"))
5969 "<table border=0><tr><td "
5970 "bgcolor=DarkRed> </td></tr></table> ";
5971 if ((color ==
"green (4)" || color ==
"green(4)"))
5973 "<table border=0><tr><td "
5974 "bgcolor=DarkGreen> </td></tr></table> ";
5975 if ((color ==
"white (1)" || color ==
"white(1)"))
5977 "<table border=0><tr><td "
5978 "bgcolor=GoldenRod> </td></tr></table> ";
5983 lightsHtml << colorStr;
5985 lightsHtml <<
"</font></td><td><font size=-1><nobr><b>";
5987 attrIndex = thisLight->attributeNames.Index(
"LITCHR");
5988 if (attrIndex != wxNOT_FOUND) {
5989 wxString character = thisLight->attributeValues[attrIndex];
5990 lightsHtml << character.BeforeFirst(wxChar(
'(')) <<
" ";
5993 attrIndex = thisLight->attributeNames.Index(
"SIGGRP");
5994 if (attrIndex != wxNOT_FOUND) {
5995 lightsHtml << thisLight->attributeValues[attrIndex];
5999 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
6000 if (attrIndex != wxNOT_FOUND) {
6002 << thisLight->attributeValues.Item(attrIndex).Upper()[0];
6006 attrIndex = thisLight->attributeNames.Index(
"SIGPER");
6007 if (attrIndex != wxNOT_FOUND) {
6008 lightsHtml << thisLight->attributeValues[attrIndex];
6012 attrIndex = thisLight->attributeNames.Index(
"HEIGHT");
6013 if (attrIndex != wxNOT_FOUND) {
6014 lightsHtml << thisLight->attributeValues[attrIndex];
6018 attrIndex = thisLight->attributeNames.Index(
"VALNMR");
6019 if (attrIndex != wxNOT_FOUND) {
6020 lightsHtml << thisLight->attributeValues[attrIndex];
6024 lightsHtml <<
"</b>";
6026 attrIndex = thisLight->attributeNames.Index(
"SECTR1");
6027 if (attrIndex != wxNOT_FOUND) {
6028 lightsHtml <<
"(" << thisLight->attributeValues[attrIndex];
6029 lightsHtml <<
" - ";
6030 attrIndex = thisLight->attributeNames.Index(
"SECTR2");
6031 lightsHtml << thisLight->attributeValues[attrIndex] <<
") ";
6034 lightsHtml <<
"</nobr>";
6036 attrIndex = thisLight->attributeNames.Index(
"CATLIT");
6037 if (attrIndex != wxNOT_FOUND) {
6038 lightsHtml <<
"<nobr>";
6039 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6041 lightsHtml <<
"</nobr> ";
6044 attrIndex = thisLight->attributeNames.Index(
"EXCLIT");
6045 if (attrIndex != wxNOT_FOUND) {
6046 lightsHtml <<
"<nobr>";
6047 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6049 lightsHtml <<
"</nobr> ";
6052 attrIndex = thisLight->attributeNames.Index(
"OBJNAM");
6053 if (attrIndex != wxNOT_FOUND) {
6054 lightsHtml <<
"<br><nobr>";
6055 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6056 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6057 lightsHtml <<
"</nobr> ";
6060 lightsHtml <<
"</font></td>";
6061 lightsHtml <<
"</tr>";
6063 thisLight->attributeNames.Clear();
6064 thisLight->attributeValues.Clear();
6067 lightsHtml <<
"</table><hr noshade>\n";
6068 ret_val = lightsHtml << ret_val;
6082bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6083 if (NULL == g_poRegistrar) {
6084 wxLogMessage(
" Error: No ClassRegistrar in InitENCMinimal.");
6088 m_pENCDS =
new OGRS57DataSource;
6090 m_pENCDS->SetS57Registrar(g_poRegistrar);
6092 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6095 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6096 pENCReader->SetClassBased(g_poRegistrar);
6098 pENCReader->Ingest();
6103OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6105 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6107 if ((NULL != pENCReader) && (NULL != g_poRegistrar)) {
6109 g_poRegistrar->SelectClass(
"M_COVR");
6112 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefn(
6113 g_poRegistrar, g_poRegistrar->GetOBJL(), pENCReader->GetOptionFlags());
6116 pENCReader->AddFeatureDefn(poDefn);
6119 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6122 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6125 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6136OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6140 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6143 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6146 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6149 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6158int s57chart::GetENCScale() {
6159 if (NULL == m_pENCDS)
return 0;
6166 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6169 return pENCReader->GetCSCL();
6179static void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6180 const char *pszErrorMsg) {
6181#define ERR_BUF_LEN 2000
6183 char buf[ERR_BUF_LEN + 1];
6185 if (eErrClass == CE_Debug)
6186 sprintf(buf,
" %s", pszErrorMsg);
6187 else if (eErrClass == CE_Warning)
6188 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6190 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6192 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6193 wxString msg(buf, wxConvUTF8);
6199 if (eErrClass == CE_Fatal) {
6200 longjmp(env_ogrf, 1);
6211const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6212 const char *pszKeyFieldValue,
6213 CSVCompareCriteria eCriteria,
6214 const char *pszTargetField)
6223 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6224 pszKeyFieldValue, eCriteria);
6226 if (papszRecord == NULL)
return "";
6231 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6232 if (iTargetField < 0)
return "";
6234 if (iTargetField >= CSLCount(papszRecord))
return "";
6236 return (papszRecord[iTargetField]);
6250static bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6274 std::vector<s57Sector_t> §orlegs) {
6275 float rangeScale = 0.0;
6277 if (sectorlegs.size() > 0) {
6278 std::vector<int> sectorangles;
6279 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6280 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6283 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6284 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6289 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6290 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6296 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6299 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6300 powf((
float)(lightPos.y - end1.y), 2));
6302 if (rangeScale == 0.0) {
6305 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6309 rangePx = rangePx * rangeScale;
6311 int penWidth = rangePx / 8;
6312 penWidth = wxMin(20, penWidth);
6313 penWidth = wxMax(5, penWidth);
6316 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
6317 penWidth, wxPENSTYLE_SOLID);
6318 arcpen->SetCap(wxCAP_BUTT);
6321 float angle1, angle2;
6322 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6323 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6324 if (angle1 > angle2) {
6327 int lpx = lightPos.x;
6328 int lpy = lightPos.y;
6330 wxPoint arcpoints[150];
6333 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6337 int narc = (angle2 - angle1) / step;
6339 step = (angle2 - angle1) / (
float)narc;
6341 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6342 wxPoint yellowCone[3];
6343 yellowCone[0] = lightPos;
6344 yellowCone[1] = end1;
6345 yellowCone[2] = end2;
6346 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6349 wxColor c = sectorlegs[i].color;
6350 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6351 dc.SetBrush(wxBrush(c));
6352 dc.StrokePolygon(3, yellowCone, 0, 0);
6355 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6356 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6357 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6358 arcpoints[npoints].x = x;
6359 arcpoints[npoints].y = y;
6362 dc.StrokeLines(npoints, arcpoints);
6366 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6372 bool haveAngle1 =
false;
6373 bool haveAngle2 =
false;
6374 int sec1 = (int)sectorlegs[i].sector1;
6375 int sec2 = (int)sectorlegs[i].sector2;
6376 if (sec1 > 360) sec1 -= 360;
6377 if (sec2 > 360) sec2 -= 360;
6379 if ((sec2 == 360) && (sec1 == 0))
6382 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6383 if (sectorangles[j] == sec1) haveAngle1 =
true;
6384 if (sectorangles[j] == sec2) haveAngle2 =
true;
6388 dc.StrokeLine(lightPos, end1);
6389 sectorangles.push_back(sec1);
6393 dc.StrokeLine(lightPos, end2);
6394 sectorangles.push_back(sec2);
6401void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6402 std::vector<s57Sector_t> §orlegs) {
6403 float rangeScale = 0.0;
6405 if (sectorlegs.size() > 0) {
6406 std::vector<int> sectorangles;
6407 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6408 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6411 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6412 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6417 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6418 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6424 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6427 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6428 powf((
float)(lightPos.y - end1.y), 2));
6430 if (rangeScale == 0.0) {
6433 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6437 rangePx = rangePx * rangeScale;
6439 float arcw = rangePx / 10;
6440 arcw = wxMin(20, arcw);
6441 arcw = wxMax(5, arcw);
6445 float angle1, angle2;
6446 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6447 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6448 if (angle1 > angle2) {
6451 int lpx = lightPos.x;
6452 int lpy = lightPos.y;
6454 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6455 wxPoint yellowCone[3];
6456 yellowCone[0] = lightPos;
6457 yellowCone[1] = end1;
6458 yellowCone[2] = end2;
6459 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6462 wxColor c = sectorlegs[i].color;
6463 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6464 dc.SetBrush(wxBrush(c));
6465 dc.StrokePolygon(3, yellowCone, 0, 0);
6469 wxPoint r(lpx, lpy);
6472 float rad = rangePx;
6496 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6499 glBindBuffer(GL_ARRAY_BUFFER, 0);
6500 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6502 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6503 glEnableVertexAttribArray(mPosAttrib);
6507 glGetUniformLocation(shader->programId(),
"circle_radius");
6508 glUniform1f(radiusloc, rad);
6512 glGetUniformLocation(shader->programId(),
"circle_center");
6516 glUniform2fv(centerloc, 1, ctrv);
6519 wxColour colorb = sectorlegs[i].color;
6521 colorv[0] = colorb.Red() / float(256);
6522 colorv[1] = colorb.Green() / float(256);
6523 colorv[2] = colorb.Blue() / float(256);
6524 colorv[3] = colorb.Alpha() / float(256);
6527 glGetUniformLocation(shader->programId(),
"circle_color");
6528 glUniform4fv(colloc, 1, colorv);
6538 glGetUniformLocation(shader->programId(),
"border_color");
6539 glUniform4fv(bcolloc, 1, bcolorv);
6542 GLint borderWidthloc =
6543 glGetUniformLocation(shader->programId(),
"border_width");
6544 glUniform1f(borderWidthloc, 2);
6547 GLint ringWidthloc =
6548 glGetUniformLocation(shader->programId(),
"ring_width");
6549 glUniform1f(ringWidthloc, arcw);
6553 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
6554 if (sr1 > 360.) sr1 -= 360.;
6556 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
6557 if (sr2 > 360.) sr2 -= 360.;
6569 if ((sb < 0) || (se < 0)) {
6575 glGetUniformLocation(shader->programId(),
"sector_1");
6576 glUniform1f(sector1loc, (sb * PI / 180.));
6578 glGetUniformLocation(shader->programId(),
"sector_2");
6579 glUniform1f(sector2loc, (se * PI / 180.));
6584 mat4x4_translate_in_place(I, r.x, r.y, 0);
6587 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6588 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6591 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6595 mat4x4_identity(IM);
6597 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6598 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6600 glDisableVertexAttribArray(mPosAttrib);
6606 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6611 bool haveAngle1 =
false;
6612 bool haveAngle2 =
false;
6613 int sec1 = (int)sectorlegs[i].sector1;
6614 int sec2 = (int)sectorlegs[i].sector2;
6615 if (sec1 > 360) sec1 -= 360;
6616 if (sec2 > 360) sec2 -= 360;
6618 if ((sec2 == 360) && (sec1 == 0))
6621 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6622 if (sectorangles[j] == sec1) haveAngle1 =
true;
6623 if (sectorangles[j] == sec2) haveAngle2 =
true;
6627 dc.StrokeLine(lightPos, end1);
6628 sectorangles.push_back(sec1);
6632 dc.StrokeLine(lightPos, end2);
6633 sectorangles.push_back(sec2);
6641bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6644 ListOfObjRazRules *rule_list,
6645 ListOfPI_S57Obj *pi_rule_list,
6646 std::vector<s57Sector_t> §orlegs) {
6647 bool newSectorsNeedDrawing =
false;
6649 bool bhas_red_green =
false;
6650 bool bleading_attribute =
false;
6653 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6654 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6656 int yOpacity = (float)opacity *
6659 if (target_plugin_chart || Chs57) {
6662 wxPoint2DDouble objPos;
6664 char *curr_att = NULL;
6666 wxArrayOfS57attVal *attValArray = NULL;
6668 ListOfObjRazRules::Node *snode = NULL;
6669 ListOfPI_S57Obj::Node *pnode = NULL;
6671 if (Chs57 && rule_list)
6672 snode = rule_list->GetLast();
6673 else if (target_plugin_chart && pi_rule_list)
6674 pnode = pi_rule_list->GetLast();
6677 wxPoint2DDouble lightPosD(0, 0);
6678 bool is_light =
false;
6682 ObjRazRules *current = snode->GetData();
6683 S57Obj *light = current->obj;
6684 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6685 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6686 curr_att = light->att_array;
6687 n_attr = light->n_attr;
6688 attValArray = light->attVal;
6691 }
else if (target_plugin_chart) {
6695 objPos = wxPoint2DDouble(light->
m_lat, light->
m_lon);
6698 attValArray = light->
attVal;
6708 wxString curAttrName;
6711 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6713 if (is_light && (lightPosD == objPos)) {
6721 bleading_attribute =
false;
6723 while (attrCounter < n_attr) {
6724 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6727 S57attVal *pAttrVal = NULL;
6730 pAttrVal = attValArray->Item(attrCounter);
6731 else if (target_plugin_chart)
6732 pAttrVal = attValArray->Item(attrCounter);
6736 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6738 if (curAttrName ==
"LITVIS") {
6739 if (value.StartsWith(
"obsc")) bviz =
false;
6741 if (curAttrName ==
"SECTR1") value.ToDouble(§r1);
6742 if (curAttrName ==
"SECTR2") value.ToDouble(§r2);
6743 if (curAttrName ==
"VALNMR") value.ToDouble(&valnmr);
6744 if (curAttrName ==
"COLOUR") {
6745 if (value ==
"red(3)") {
6746 color = wxColor(255, 0, 0, opacity);
6747 sector.iswhite =
false;
6748 bhas_red_green =
true;
6751 if (value ==
"green(4)") {
6752 color = wxColor(0, 255, 0, opacity);
6753 sector.iswhite =
false;
6754 bhas_red_green =
true;
6758 if (curAttrName ==
"EXCLIT") {
6759 if (value.Find(
"(3)")) valnmr = 1.0;
6762 if (curAttrName ==
"CATLIT") {
6763 if (value.Upper().StartsWith(
"DIRECT") ||
6764 value.Upper().StartsWith(
"LEAD"))
6765 bleading_attribute =
true;
6772 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6773 if (sectr1 > sectr2) {
6777 sector.pos.m_x = objPos.m_y;
6778 sector.pos.m_y = objPos.m_x;
6781 (valnmr > 0.0) ? valnmr : 2.5;
6782 sector.sector1 = sectr1;
6783 sector.sector2 = sectr2;
6785 if (!color.IsOk()) {
6786 color = wxColor(255, 255, 0, yOpacity);
6787 sector.iswhite =
true;
6789 sector.color = color;
6790 sector.isleading =
false;
6792 if (bleading_attribute) sector.isleading =
true;
6794 bool newsector =
true;
6795 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6796 if (sectorlegs[i].pos == sector.pos &&
6797 sectorlegs[i].sector1 == sector.sector1 &&
6798 sectorlegs[i].sector2 == sector.sector2) {
6804 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6808 if (!bviz) newsector =
false;
6810 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6814 sectorlegs.push_back(sector);
6815 newSectorsNeedDrawing =
true;
6822 snode = snode->GetPrevious();
6823 else if (target_plugin_chart)
6824 pnode = pnode->GetPrevious();
6832 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6833 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6834 if (sectorlegs[i].iswhite && bhas_red_green)
6835 sectorlegs[i].isleading =
true;
6839 return newSectorsNeedDrawing;
6842bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6844 std::vector<s57Sector_t> §orlegs) {
6845 if (!cc)
return false;
6847 static float lastLat, lastLon;
6849 if (!ps52plib)
return false;
6857 if (cc->m_singleChart &&
6858 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6859 target_chart = cc->m_singleChart;
6860 else if (viewport.b_quilt)
6861 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6863 target_chart = NULL;
6866 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6867 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6870 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6873 bool newSectorsNeedDrawing =
false;
6875 if (target_plugin_chart || Chs57) {
6876 ListOfObjRazRules *rule_list = NULL;
6877 ListOfPI_S57Obj *pi_rule_list = NULL;
6884 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6885 else if (target_plugin_chart)
6886 pi_rule_list =
g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6887 target_plugin_chart, lat, lon, viewport);
6889 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6890 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6898 pi_rule_list->Clear();
6899 delete pi_rule_list;
6903 return newSectorsNeedDrawing;
6906bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6908 std::vector<s57Sector_t> §orlegs) {
6909 if (!cc)
return false;
6911 double cursor_lat, cursor_lon;
6912 static float lastLat, lastLon;
6914 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6919 ChartBase *target_chart = cc->GetChartAtCursor();
6921 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6922 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6925 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6930 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6932 lastLat = cursor_lat;
6933 lastLon = cursor_lon;
6934 bool newSectorsNeedDrawing =
false;
6936 if (target_plugin_chart || Chs57) {
6937 ListOfObjRazRules *rule_list = NULL;
6938 ListOfPI_S57Obj *pi_rule_list = NULL;
6944 rule_list = Chs57->GetObjRuleListAtLatLon(
6945 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6946 else if (target_plugin_chart)
6947 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
6948 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6950 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6951 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6959 pi_rule_list->Clear();
6960 delete pi_rule_list;
6964 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.
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.
Extern C linked utilities.
OpenGL chart rendering canvas.
General purpose GUI support.
bool g_b_overzoom_x
Allow high overzoom.
Enhanced logging interface on top of wx/log.h.
wxString getUsrHeightUnit(int unit)
Get the abbreviation for the preferred height unit.
double toUsrHeight(double m_height, int unit)
Convert height from meters to preferred height units.
double toUsrDepth(double m_depth, int unit)
Convert a depth from meters to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
Optimized wxBitmap Object.
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.
Layer to use wxDC or opengl.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
int PI_GetPLIBBoundaryStyle()
Gets configured S52 boundary style.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
bool chain_broken_mssage_shown
Global instance.
SENCThreadManager * g_SencThreadManager
Global instance.
Represents a sector of a light in an S57 chart.