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"
83#include "s57class_registrar.h"
87#include "user_colors.h"
98#define S57_THUMB_SIZE 200
100#include <wx/arrimpl.cpp>
102WX_DEFINE_OBJARRAY(ArrayOfS57Obj);
104WX_DEFINE_LIST(ListOfPI_S57Obj);
106WX_DEFINE_LIST(ListOfObjRazRules);
108static wxCriticalSection GDALcriticalSection;
115static jmp_buf env_ogrf;
117static void OpenCPN_OGRErrorHandler(
118 CPLErr eErrClass,
int nError,
119 const char *pszErrorMsg);
121static uint64_t hash_fast64(
const void *buf,
size_t len, uint64_t seed) {
122 const uint64_t m = 0x880355f21e6d1965ULL;
123 const uint64_t *pos = (
const uint64_t *)buf;
124 const uint64_t *end = pos + (len >> 3);
125 const unsigned char *pc;
126 uint64_t h = len * m ^ seed;
131 v *= 0x2127599bf4325c37ULL;
135 pc = (
const unsigned char *)pos;
139 v ^= (uint64_t)pc[6] << 48;
141 v ^= (uint64_t)pc[5] << 40;
143 v ^= (uint64_t)pc[4] << 32;
145 v ^= (uint64_t)pc[3] << 24;
147 v ^= (uint64_t)pc[2] << 16;
149 v ^= (uint64_t)pc[1] << 8;
151 v ^= (uint64_t)pc[0];
153 v *= 0x2127599bf4325c37ULL;
159 h *= 0x2127599bf4325c37ULL;
164static unsigned int hash_fast32(
const void *buf,
size_t len,
166 uint64_t h = hash_fast64(buf, len, seed);
171 return h - (h >> 32);
174unsigned long connector_key::hash()
const {
175 return hash_fast32(k,
sizeof k, 0);
182render_canvas_parms::render_canvas_parms() { pix_buff = NULL; }
184render_canvas_parms::~render_canvas_parms() {}
186static void PrepareForRender(
ViewPort *pvp, s52plib *plib) {
191 pvp->rv_rect, pvp->GetBBox(), pvp->
ref_scale,
193 plib->PrepareForRender();
200s57chart::s57chart() {
201 m_ChartType = CHART_TYPE_S57;
202 m_ChartFamily = CHART_FAMILY_VECTOR;
204 for (
int i = 0; i < PRIO_NUM; i++)
205 for (
int j = 0; j < LUPNAME_NUM; j++) razRules[i][j] = NULL;
214 pFloatingATONArray =
new wxArrayPtrVoid;
215 pRigidATONArray =
new wxArrayPtrVoid;
217 m_tmpup_array = NULL;
219 m_DepthUnits =
"METERS";
220 m_depth_unit_id = DEPTH_UNIT_METERS;
222 bGLUWarningSent =
false;
228 m_pvaldco_array = NULL;
230 m_bExtentSet =
false;
232 m_pDIBThumbDay = NULL;
233 m_pDIBThumbDim = NULL;
234 m_pDIBThumbOrphan = NULL;
235 m_bbase_file_attr_known =
false;
237 m_bLinePrioritySet =
false;
238 m_plib_state_hash = 0;
245 m_b2pointLUPS =
false;
246 m_b2lineLUPS =
false;
248 m_next_safe_cnt = 1e6;
250 m_line_vertex_buffer = 0;
251 m_this_chart_context = 0;
253 m_vbo_byte_length = 0;
254 bReadyToRender =
false;
256 m_disableBackgroundSENC =
false;
259s57chart::~s57chart() {
260 FreeObjectsAndRules();
267 delete pFloatingATONArray;
268 delete pRigidATONArray;
272 free(m_pvaldco_array);
274 free(m_line_vertex_buffer);
276 delete m_pDIBThumbOrphan;
278 for (
unsigned i = 0; i < m_pcs_vector.size(); i++)
delete m_pcs_vector.at(i);
280 for (
unsigned i = 0; i < m_pve_vector.size(); i++)
delete m_pve_vector.at(i);
282 m_pcs_vector.clear();
283 m_pve_vector.clear();
285 for (
const auto &it : m_ve_hash) {
286 VE_Element *pedge = it.second;
288 free(pedge->pPoints);
294 for (
const auto &it : m_vc_hash) {
295 VC_Element *pcs = it.second;
304 if ((m_LineVBO_name > 0)) glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
306 free(m_this_chart_context);
308 if (m_TempFilePath.Length() && (m_FullPath != m_TempFilePath)) {
309 if (::wxFileExists(m_TempFilePath)) wxRemoveFile(m_TempFilePath);
316void s57chart::GetValidCanvasRegion(
const ViewPort &VPoint,
320 double easting, northing;
323 toSM(m_FullExtent.SLAT, m_FullExtent.WLON, VPoint.
clat, VPoint.
clon, &easting,
328 rxl = (int)round((VPoint.
pix_width / 2) + epix);
329 ryb = (int)round((VPoint.
pix_height / 2) - npix);
331 toSM(m_FullExtent.NLAT, m_FullExtent.ELON, VPoint.
clat, VPoint.
clon, &easting,
336 rxr = (int)round((VPoint.
pix_width / 2) + epix);
337 ryt = (int)round((VPoint.
pix_height / 2) - npix);
339 pValidRegion->Clear();
340 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
343LLRegion s57chart::GetValidRegion() {
344 double ll[8] = {m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.SLAT,
345 m_FullExtent.ELON, m_FullExtent.NLAT, m_FullExtent.ELON,
346 m_FullExtent.NLAT, m_FullExtent.WLON};
347 return LLRegion(4, ll);
350void s57chart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
351 if (!ps52plib)
return;
356 case GLOBAL_COLOR_SCHEME_DAY:
357 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
359 case GLOBAL_COLOR_SCHEME_DUSK:
360 ps52plib->SetPLIBColorScheme(
"DUSK", ChartCtxFactory());
362 case GLOBAL_COLOR_SCHEME_NIGHT:
363 ps52plib->SetPLIBColorScheme(
"NIGHT", ChartCtxFactory());
366 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
370 m_global_color_scheme = cs;
372 if (bApplyImmediate) {
378 ClearRenderedTextCache();
381 ChangeThumbColor(cs);
384void s57chart::ChangeThumbColor(ColorScheme cs) {
385 if (0 == m_pDIBThumbDay)
return;
389 case GLOBAL_COLOR_SCHEME_DAY:
390 pThumbData->pDIBThumb = m_pDIBThumbDay;
391 m_pDIBThumbOrphan = m_pDIBThumbDim;
393 case GLOBAL_COLOR_SCHEME_DUSK:
394 case GLOBAL_COLOR_SCHEME_NIGHT: {
395 if (NULL == m_pDIBThumbDim) {
396 wxImage img = m_pDIBThumbDay->ConvertToImage();
398#if wxCHECK_VERSION(2, 8, 0)
399 wxImage gimg = img.ConvertToGreyscale(
409 wxBitmap *pBMP =
new wxBitmap(gimg);
411 m_pDIBThumbDim = pBMP;
412 m_pDIBThumbOrphan = m_pDIBThumbDay;
415 pThumbData->pDIBThumb = m_pDIBThumbDim;
421bool s57chart::GetChartExtent(
Extent *pext) {
423 *pext = m_FullExtent;
429static void free_mps(mps_container *mps) {
430 if (mps == 0)
return;
431 if (ps52plib && mps->cs_rules) {
432 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
433 Rules *rule_chain_top = mps->cs_rules->Item(i);
434 ps52plib->DestroyRulesChain(rule_chain_top);
436 delete mps->cs_rules;
441void s57chart::FreeObjectsAndRules() {
450 for (
int i = 0; i < PRIO_NUM; ++i) {
451 for (
int j = 0; j < LUPNAME_NUM; j++) {
452 top = razRules[i][j];
453 while (top != NULL) {
455 if (0 == top->obj->nRef)
delete top->obj;
458 ObjRazRules *ctop = top->child;
462 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
464 ObjRazRules *cnxx = ctop->next;
479void s57chart::ClearRenderedTextCache() {
481 for (
int i = 0; i < PRIO_NUM; ++i) {
482 for (
int j = 0; j < LUPNAME_NUM; j++) {
483 top = razRules[i][j];
484 while (top != NULL) {
485 if (top->obj->bFText_Added) {
486 top->obj->bFText_Added =
false;
487 delete top->obj->FText;
488 top->obj->FText = NULL;
492 ObjRazRules *ctop = top->child;
494 if (ctop->obj->bFText_Added) {
495 ctop->obj->bFText_Added =
false;
496 delete ctop->obj->FText;
497 ctop->obj->FText = NULL;
509double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
510 bool b_allow_overzoom) {
512 return m_Chart_Scale * 0.125;
516double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
518 return m_Chart_Scale * 4.0;
525void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
527 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
529 r->y = roundint(m_pixy_vp_center -
530 ((north - m_northing_vp_center) * m_view_scale_ppm));
533void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
534 wxPoint *r,
int nPoints) {
535 for (
int i = 0; i < nPoints; i++) {
536 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
538 r[i].y = roundint(m_pixy_vp_center -
539 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
543void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
545 if (vpt->m_projection_type != PROJECTION_MERCATOR)
546 printf(
"s57chart unhandled projection\n");
552 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
553 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
559 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
569void s57chart::SetVPParms(
const ViewPort &vpt) {
575 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
576 &m_northing_vp_center);
578 vp_transform.easting_vp_center = m_easting_vp_center;
579 vp_transform.northing_vp_center = m_northing_vp_center;
583 if (IsCacheValid()) {
586 double prev_easting_c, prev_northing_c;
587 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
590 double easting_c, northing_c;
591 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
599 int dpix_x = (int)round(delta_pix_x);
604 int dpix_y = (int)round(delta_pix_y);
607 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
608 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
611 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
613 vp_proposed.
clon = xlon;
614 vp_proposed.
clat = xlat;
641void s57chart::LoadThumb() {
642 wxFileName fn(m_FullPath);
643 wxString SENCdir = g_SENCPrefix;
645 if (SENCdir.Last() != fn.GetPathSeparator())
646 SENCdir.Append(fn.GetPathSeparator());
648 wxFileName tsfn(SENCdir);
649 tsfn.SetFullName(fn.GetFullName());
651 wxFileName ThumbFileNameLook(tsfn);
652 ThumbFileNameLook.SetExt(
"BMP");
655 if (ThumbFileNameLook.FileExists()) {
658 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
659 m_pDIBThumbDay = pBMP;
660 m_pDIBThumbOrphan = 0;
665ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
668 if (pThumbData->pDIBThumb == 0) {
670 ChangeThumbColor(m_global_color_scheme);
673 UpdateThumbData(lat, lon);
678bool s57chart::UpdateThumbData(
double lat,
double lon) {
682 if (pThumbData->pDIBThumb) {
683 double lat_top = m_FullExtent.NLAT;
684 double lat_bot = m_FullExtent.SLAT;
685 double lon_left = m_FullExtent.WLON;
686 double lon_right = m_FullExtent.ELON;
689 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
691 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
693 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
696 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
697 (int)(east * thumb_view_scale_ppm);
698 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
699 (int)(north * thumb_view_scale_ppm);
706 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
707 pThumbData->ShipX = test_x;
708 pThumbData->ShipY = test_y;
714void s57chart::SetFullExtent(
Extent &ext) {
715 m_FullExtent.NLAT = ext.NLAT;
716 m_FullExtent.SLAT = ext.SLAT;
717 m_FullExtent.WLON = ext.WLON;
718 m_FullExtent.ELON = ext.ELON;
723void s57chart::ForceEdgePriorityEvaluate() { m_bLinePrioritySet =
false; }
725void s57chart::SetLinePriorities() {
726 if (!ps52plib)
return;
731 if (!m_bLinePrioritySet) {
735 for (
int i = 0; i < PRIO_NUM; ++i) {
736 top = razRules[i][2];
737 while (top != NULL) {
738 ObjRazRules *crnt = top;
740 ps52plib->SetLineFeaturePriority(crnt, i);
746 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
751 top = razRules[i][j];
752 while (top != NULL) {
755 ps52plib->SetLineFeaturePriority(crnt, i);
761 for (
int i = 0; i < PRIO_NUM; ++i) {
762 for (
int j = 0; j < LUPNAME_NUM; j++) {
763 ObjRazRules *top = razRules[i][j];
764 while (top != NULL) {
765 S57Obj *obj = top->obj;
768 connector_segment *pcs;
769 line_segment_element *list = obj->m_ls_list;
771 switch (list->ls_type) {
775 if (pedge) list->priority = pedge->max_priority;
780 if (pcs) list->priority = pcs->max_priority_cs;
795 m_bLinePrioritySet =
true;
799void s57chart::SetLinePriorities(
void )
801 if( !ps52plib )
return;
806 if( !m_bLinePrioritySet ) {
810 for(
int i = 0; i < PRIO_NUM; ++i ) {
812 top = razRules[i][2];
813 while( top != NULL ) {
814 ObjRazRules *crnt = top;
816 ps52plib->SetLineFeaturePriority( crnt, i );
821 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
826 top = razRules[i][j];
827 while( top != NULL ) {
830 ps52plib->SetLineFeaturePriority( crnt, i );
838 for(
int i = 0; i < PRIO_NUM; ++i ) {
839 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
840 ObjRazRules *top = razRules[i][j];
841 while( top != NULL ) {
842 S57Obj *obj = top->obj;
845 connector_segment *pcs;
846 line_segment_element *list = obj->m_ls_list;
851 pedge = (VE_Element *)list->private0;
853 list->priority = pedge->max_priority;
857 pcs = (connector_segment *)list->private0;
859 list->priority = pcs->max_priority;
874 m_bLinePrioritySet =
true;
878int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
882 line_segment_element *ls_list = obj->m_ls_list;
884 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
885 nPoints += ls_list->pedge->nCount;
888 ls_list = ls_list->next;
897 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
901 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
902 ls_list = obj->m_ls_list;
904 size_t vbo_offset = 0;
906 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
907 vbo_offset = ls_list->pedge->vbo_offset;
908 count = ls_list->pedge->nCount;
910 vbo_offset = ls_list->pcs->vbo_offset;
914 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
916 ls_list = ls_list->next;
923int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
928 line_segment_element *ls_list = obj->m_ls_list;
930 nPoints += ls_list->n_points;
931 ls_list = ls_list->next;
940 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
944 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
945 ls_list = obj->m_ls_list;
947 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
948 br += ls_list->n_points * 2;
949 ls_list = ls_list->next;
958 float e0, n0, e1, n1;
961void s57chart::AssembleLineGeometry() {
966 for (
const auto &it : m_ve_hash) {
967 VE_Element *pedge = it.second;
969 nPoints += pedge->nCount;
975 std::map<long long, connector_segment *> ce_connector_hash;
976 std::map<long long, connector_segment *> ec_connector_hash;
977 std::map<long long, connector_segment *> cc_connector_hash;
979 std::map<long long, connector_segment *>::iterator csit;
986 std::vector<segment_pair> connector_segment_vector;
987 size_t seg_pair_index = 0;
992 for (
int i = 0; i < PRIO_NUM; ++i) {
993 for (
int j = 0; j < LUPNAME_NUM; j++) {
994 ObjRazRules *top = razRules[i][j];
995 while (top != NULL) {
996 S57Obj *obj = top->obj;
998 if ((!obj->m_ls_list) &&
1001 line_segment_element list_top;
1004 line_segment_element *le_current = &list_top;
1006 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1007 if (!obj->m_lsindex_array)
continue;
1009 int seg_index = iseg * 3;
1010 int *index_run = &obj->m_lsindex_array[seg_index];
1013 unsigned int inode = *index_run++;
1016 bool edge_dir =
true;
1017 int venode = *index_run++;
1023 VE_Element *pedge = 0;
1025 if (m_ve_hash.find(venode) != m_ve_hash.end())
1026 pedge = m_ve_hash[venode];
1030 unsigned int enode = *index_run++;
1033 VC_Element *ipnode = 0;
1034 ipnode = m_vc_hash[inode];
1037 VC_Element *epnode = 0;
1038 epnode = m_vc_hash[enode];
1041 if (pedge && pedge->nCount) {
1045 long long key = ((
unsigned long long)inode << 32) + venode;
1047 connector_segment *pcs = NULL;
1048 csit = ce_connector_hash.find(key);
1049 if (csit == ce_connector_hash.end()) {
1051 pcs =
new connector_segment;
1052 ce_connector_hash[key] = pcs;
1056 float *ppt = ipnode->pPoint;
1061 pair.e1 = pedge->pPoints[0];
1062 pair.n1 = pedge->pPoints[1];
1064 int last_point_index = (pedge->nCount - 1) * 2;
1065 pair.e1 = pedge->pPoints[last_point_index];
1066 pair.n1 = pedge->pPoints[last_point_index + 1];
1069 connector_segment_vector.push_back(pair);
1070 pcs->vbo_offset = seg_pair_index;
1077 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1079 pcs->cs_lat_avg = lat;
1080 pcs->cs_lon_avg = lon;
1085 line_segment_element *pls =
new line_segment_element;
1090 pls->ls_type = TYPE_CE;
1092 le_current->next = pls;
1097 if (pedge && pedge->nCount) {
1098 line_segment_element *pls =
new line_segment_element;
1103 pls->ls_type = TYPE_EE;
1104 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1106 le_current->next = pls;
1114 if (pedge && pedge->nCount) {
1115 long long key = ((
unsigned long long)venode << 32) + enode;
1117 connector_segment *pcs = NULL;
1118 csit = ec_connector_hash.find(key);
1119 if (csit == ec_connector_hash.end()) {
1121 pcs =
new connector_segment;
1122 ec_connector_hash[key] = pcs;
1128 pair.e0 = pedge->pPoints[0];
1129 pair.n0 = pedge->pPoints[1];
1131 int last_point_index = (pedge->nCount - 1) * 2;
1132 pair.e0 = pedge->pPoints[last_point_index];
1133 pair.n0 = pedge->pPoints[last_point_index + 1];
1136 float *ppt = epnode->pPoint;
1140 connector_segment_vector.push_back(pair);
1141 pcs->vbo_offset = seg_pair_index;
1148 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1150 pcs->cs_lat_avg = lat;
1151 pcs->cs_lon_avg = lon;
1156 line_segment_element *pls =
new line_segment_element;
1160 pls->ls_type = TYPE_EC;
1162 le_current->next = pls;
1166 long long key = ((
unsigned long long)inode << 32) + enode;
1168 connector_segment *pcs = NULL;
1169 csit = cc_connector_hash.find(key);
1170 if (csit == cc_connector_hash.end()) {
1172 pcs =
new connector_segment;
1173 cc_connector_hash[key] = pcs;
1178 float *ppt = ipnode->pPoint;
1182 ppt = epnode->pPoint;
1186 connector_segment_vector.push_back(pair);
1187 pcs->vbo_offset = seg_pair_index;
1194 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1196 pcs->cs_lat_avg = lat;
1197 pcs->cs_lon_avg = lon;
1202 line_segment_element *pls =
new line_segment_element;
1206 pls->ls_type = TYPE_CC;
1208 le_current->next = pls;
1222 if (obj->m_ls_list == NULL) {
1223 obj->m_n_lsindex = 0;
1227 free(obj->m_lsindex_array);
1228 obj->m_lsindex_array = NULL;
1241 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1243 unsigned char *buffer_offset;
1246 bool grow_buffer =
false;
1248 if (0 == m_vbo_byte_length) {
1249 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1250 m_vbo_byte_length = vbo_byte_length;
1251 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1254 m_line_vertex_buffer = (
float *)realloc(
1255 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1256 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1257 offset = m_vbo_byte_length;
1258 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1262 float *lvr = (
float *)buffer_offset;
1266 for (
const auto &it : m_ve_hash) {
1267 VE_Element *pedge = it.second;
1269 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1270 lvr += pedge->nCount * 2;
1272 pedge->vbo_offset = offset;
1273 offset += pedge->nCount * 2 *
sizeof(float);
1286 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1288 connector_segment *pcs = csit->second;
1289 m_pcs_vector.push_back(pcs);
1291 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1297 pcs->vbo_offset = offset;
1298 offset += 4 *
sizeof(float);
1301 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1303 connector_segment *pcs = csit->second;
1304 m_pcs_vector.push_back(pcs);
1306 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1312 pcs->vbo_offset = offset;
1313 offset += 4 *
sizeof(float);
1316 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1318 connector_segment *pcs = csit->second;
1319 m_pcs_vector.push_back(pcs);
1321 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1327 pcs->vbo_offset = offset;
1328 offset += 4 *
sizeof(float);
1332 connector_segment_vector.clear();
1337 for (
const auto &it : m_ve_hash) {
1338 VE_Element *pedge = it.second;
1340 m_pve_vector.push_back(pedge);
1341 free(pedge->pPoints);
1349 for (
const auto &it : m_vc_hash) {
1350 VC_Element *pcs = it.second;
1351 if (pcs) free(pcs->pPoint);
1357 if (g_b_EnableVBO) {
1359 if (m_LineVBO_name > 0) {
1360 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1361 m_LineVBO_name = -1;
1368void s57chart::BuildLineVBO() {
1370 if (!g_b_EnableVBO)
return;
1372 if (m_LineVBO_name == -1) {
1375 glGenBuffers(1, &vboId);
1378 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1384#ifndef USE_ANDROID_GLES2
1385 glEnableClientState(GL_VERTEX_ARRAY);
1387 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1392 ObjRazRules *top, *crnt;
1393 int vbo_area_size_bytes = 0;
1394 for (
int i = 0; i < PRIO_NUM; ++i) {
1395 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1396 top = razRules[i][4];
1398 top = razRules[i][3];
1400 while (top != NULL) {
1405 PolyTriGroup *ppg_vbo =
1406 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1408 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1415 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes, NULL,
1418 GLenum err = glGetError();
1421 msg.Printf(
"S57 VBO Error 1: %d", err);
1423 printf(
"S57 VBO Error 1: %d", err);
1427 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length,
1428 m_line_vertex_buffer);
1433 msg.Printf(
"S57 VBO Error 2: %d", err);
1435 printf(
"S57 VBO Error 2: %d", err);
1439 int vbo_load_offset = m_vbo_byte_length;
1441 for (
int i = 0; i < PRIO_NUM; ++i) {
1442 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1443 top = razRules[i][4];
1445 top = razRules[i][3];
1447 while (top != NULL) {
1452 PolyTriGroup *ppg_vbo =
1453 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1456 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1457 ppg_vbo->single_buffer_size, ppg_vbo->single_buffer);
1459 crnt->obj->vboAreaOffset = vbo_load_offset;
1460 vbo_load_offset += ppg_vbo->single_buffer_size;
1467 msg.Printf(
"S57 VBO Error 3: %d", err);
1469 printf(
"S57 VBO Error 3: %d", err);
1474#ifndef USE_ANDROID_GLES2
1475 glDisableClientState(GL_VERTEX_ARRAY);
1477 glBindBuffer(GL_ARRAY_BUFFER, 0);
1481 for (
int i = 0; i < PRIO_NUM; ++i) {
1482 for (
int j = 0; j < LUPNAME_NUM; j++) {
1483 ObjRazRules *top = razRules[i][j];
1484 while (top != NULL) {
1485 S57Obj *obj = top->obj;
1486 obj->auxParm2 = vboId;
1492 m_LineVBO_name = vboId;
1493 m_this_chart_context->vboID = vboId;
1512bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1515 const LLRegion &Region) {
1516 if (!m_RAZBuilt)
return false;
1518 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1521bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1524 const LLRegion &Region) {
1525 if (!m_RAZBuilt)
return false;
1527 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1530bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1533 const LLRegion &Region) {
1534 if (!m_RAZBuilt)
return false;
1536 bool b_text = ps52plib->GetShowS57Text();
1537 ps52plib->m_bShowS57Text =
false;
1538 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1539 ps52plib->m_bShowS57Text = b_text;
1544bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1546 if (!m_RAZBuilt)
return false;
1550 if (!ps52plib)
return false;
1553 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1555 glChartCanvas::DisableClipRegion();
1556 DoRenderOnGLText(glc, VPoint);
1562bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1565 const LLRegion &Region,
bool b_overlay) {
1566 if (!m_RAZBuilt)
return false;
1570 if (!ps52plib)
return false;
1572 if (g_bDebugS57) printf(
"\n");
1576 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1578 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1579 m_bLinePrioritySet =
false;
1581 ClearRenderedTextCache();
1583 ResetPointBBoxes(m_last_vp, VPoint);
1586 m_plib_state_hash = ps52plib->GetStateHash();
1590 ResetPointBBoxes(m_last_vp, VPoint);
1594 SetLinePriorities();
1597 ps52plib->ClearTextList();
1605 wxRect upr = upd.GetRect();
1608 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1609 chart_region.Intersect(Region);
1611 if (!chart_region.Empty()) {
1615 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1622 if (CHART_TYPE_CM93 == GetChartType()) {
1626 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1629#ifdef OPT_USE_ANDROID_GLES2
1637 wxRect r = upd.GetRect();
1639 glViewport(r.x, vp->
pix_height - (r.y + r.height), r.width, r.height);
1647 float yp = vp->
pix_height - (r.y + r.height);
1649 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1650 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1653 I[0][0] *= 2.0 / (float)r.width;
1654 I[1][1] *= -2.0 / (float)r.height;
1658 mat4x4_rotate_Z(Q, I, angle);
1660 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1663 ps52plib->SetReducedBBox(cvp.GetBBox());
1664 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1669 DoRenderOnGL(glc, cvp);
1671 glChartCanvas::DisableClipRegion();
1684bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1697 for (i = 0; i < PRIO_NUM; ++i) {
1698 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1699 top = razRules[i][4];
1701 top = razRules[i][3];
1703 while (top != NULL) {
1706 crnt->sm_transform_parms = &vp_transform;
1707 ps52plib->RenderAreaToGL(glc, crnt);
1713 for (i = 0; i < PRIO_NUM; ++i) {
1715 top = razRules[i][4];
1717 top = razRules[i][3];
1719 while (top != NULL) {
1722 crnt->sm_transform_parms = &vp_transform;
1727 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1728 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1729 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1730 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1733 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1740 for (i = 0; i < PRIO_NUM; ++i) {
1741 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1742 top = razRules[i][4];
1744 top = razRules[i][3];
1745 while (top != NULL) {
1748 crnt->sm_transform_parms = &vp_transform;
1749 ps52plib->RenderObjectToGL(glc, crnt);
1754 for (i = 0; i < PRIO_NUM; ++i) {
1755 top = razRules[i][2];
1756 while (top != NULL) {
1759 crnt->sm_transform_parms = &vp_transform;
1760 ps52plib->RenderObjectToGL(glc, crnt);
1766 for (i = 0; i < PRIO_NUM; ++i) {
1767 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1768 top = razRules[i][0];
1770 top = razRules[i][1];
1772 while (top != NULL) {
1775 crnt->sm_transform_parms = &vp_transform;
1776 ps52plib->RenderObjectToGL(glc, crnt);
1786bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1797 for( i = 0; i < PRIO_NUM; ++i ) {
1798 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1799 top = razRules[i][4];
1801 top = razRules[i][3];
1803 while( top != NULL ) {
1806 crnt->sm_transform_parms = &vp_transform;
1813 for (i = 0; i < PRIO_NUM; ++i) {
1814 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1815 top = razRules[i][4];
1817 top = razRules[i][3];
1819 while (top != NULL) {
1822 crnt->sm_transform_parms = &vp_transform;
1823 ps52plib->RenderObjectToGLText(glc, crnt);
1826 top = razRules[i][2];
1827 while (top != NULL) {
1830 crnt->sm_transform_parms = &vp_transform;
1831 ps52plib->RenderObjectToGLText(glc, crnt);
1834 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1835 top = razRules[i][0];
1837 top = razRules[i][1];
1839 while (top != NULL) {
1842 crnt->sm_transform_parms = &vp_transform;
1843 ps52plib->RenderObjectToGLText(glc, crnt);
1852bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1855 if (!m_RAZBuilt)
return false;
1857 bool b_text = ps52plib->GetShowS57Text();
1858 ps52plib->m_bShowS57Text =
false;
1859 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1860 ps52plib->m_bShowS57Text = b_text;
1865bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1868 if (!dc.IsOk())
return false;
1871 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1876 DCRenderText(dc, VPoint);
1879 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1883 while (upd.HaveRects()) {
1884 wxRect rect = upd.GetRect();
1890 temp_vp.
GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1894 temp_vp.
GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1896 if (temp_lon_right < temp_lon_left)
1897 temp_lon_right += 360.;
1899 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1902 wxDCClipper clip(dc, rect);
1903 DCRenderText(dc, temp_vp);
1912bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1914 if (!m_RAZBuilt)
return false;
1916 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1919bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1922 if (!m_RAZBuilt)
return false;
1923 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1926bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1931 bool force_new_view =
false;
1933 if (Region != m_last_Region) force_new_view =
true;
1935 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1937 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1938 m_bLinePrioritySet =
false;
1940 ClearRenderedTextCache();
1942 ResetPointBBoxes(m_last_vp, VPoint);
1947 ResetPointBBoxes(m_last_vp, VPoint);
1950 SetLinePriorities();
1952 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1956 if (VPoint.b_quilt) {
1958 if ((m_pCloneBM->GetWidth() != VPoint.
pix_width) ||
1959 (m_pCloneBM->GetHeight() != VPoint.
pix_height)) {
1964 if (NULL == m_pCloneBM)
1967 wxMemoryDC dc_clone;
1968 dc_clone.SelectObject(*m_pCloneBM);
1970#ifdef ocpnUSE_DIBSECTION
1973 wxMemoryDC memdc, dc_org;
1976 pDIB->SelectIntoDC(dc_org);
1981 while (upd.HaveRects()) {
1982 wxRect rect = upd.GetRect();
1983 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
1988 dc_clone.SelectObject(wxNullBitmap);
1989 dc_org.SelectObject(wxNullBitmap);
1993 wxColour nodat = GetGlobalColor(
"NODTA");
1994 wxColour nodat_sub = nodat;
1996#ifdef ocpnUSE_ocpnBitmap
1997 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
1999 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
2000 m_pCloneBM->SetMask(m_pMask);
2003 dc.SelectObject(*m_pCloneBM);
2005 pDIB->SelectIntoDC(dc);
2007 m_last_Region = Region;
2012bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2017 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2019 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2020 m_bLinePrioritySet =
false;
2022 ClearRenderedTextCache();
2026 SetLinePriorities();
2028 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2030 pDIB->SelectIntoDC(dc);
2037bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2038 RenderTypeEnum option,
bool force_new_view) {
2039 bool bnewview =
false;
2041 bool bNewVP =
false;
2043 bool bReallyNew =
false;
2045 double easting_ul, northing_ul;
2046 double easting_lr, northing_lr;
2047 double prev_easting_ul = 0., prev_northing_ul = 0.;
2049 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2050 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2059 if (m_last_vprect != dest) bReallyNew =
true;
2060 m_last_vprect = dest;
2062 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2064 m_plib_state_hash = ps52plib->GetStateHash();
2075 if (m_last_vp.IsValid()) {
2077 m_easting_vp_center - ((VPoint.
pix_width / 2) / m_view_scale_ppm);
2079 m_northing_vp_center + ((VPoint.
pix_height / 2) / m_view_scale_ppm);
2080 easting_lr = easting_ul + (VPoint.
pix_width / m_view_scale_ppm);
2081 northing_lr = northing_ul - (VPoint.
pix_height / m_view_scale_ppm);
2083 double last_easting_vp_center, last_northing_vp_center;
2084 toSM(m_last_vp.
clat, m_last_vp.
clon, ref_lat, ref_lon,
2085 &last_easting_vp_center, &last_northing_vp_center);
2088 last_easting_vp_center - ((m_last_vp.
pix_width / 2) / m_view_scale_ppm);
2089 prev_northing_ul = last_northing_vp_center +
2090 ((m_last_vp.
pix_height / 2) / m_view_scale_ppm);
2092 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2093 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2095 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2096 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2098 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2099 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2101 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2104 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2113 else if ((rul.x != 0) || (rul.y != 0)) {
2114 if (g_bDebugS57) printf(
"newvp due to rul\n");
2125 if (force_new_view) bNewVP =
true;
2130 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2131 rgn_last.Intersect(rgn_new);
2133 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2135 rgn_last.GetBox(xu, yu, wu, hu);
2152 pDIB->SelectIntoDC(dc_last);
2157 pDIBNew->SelectIntoDC(dc_new);
2161 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2166 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.
pix_width,
2169 dc_new.SelectObject(wxNullBitmap);
2170 dc_last.SelectObject(wxNullBitmap);
2178 pDIB->SelectIntoDC(dc);
2182 rgn_delta.Subtract(rgn_reused);
2185 while (upd.HaveRects()) {
2186 wxRect rect = upd.GetRect();
2191 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2193 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2194 (rect.y / m_view_scale_ppm);
2195 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2196 (rect.x / m_view_scale_ppm);
2197 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2200 double temp_northing_lr =
2201 temp_northing_ul - (rect.height / m_view_scale_ppm);
2202 double temp_easting_lr =
2203 temp_easting_ul + (rect.width / m_view_scale_ppm);
2204 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2207 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2212 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2213 temp_vp.GetBBox().GetLatRange()) *
2215 temp_vp.GetBBox().EnLarge(margin);
2221 DCRenderRect(dc, temp_vp, &rect);
2226 dc.SelectObject(wxNullBitmap);
2235 else if (bNewVP || (NULL == pDIB)) {
2241 pDIB->SelectIntoDC(dc);
2244 ps52plib->ClearTextList();
2246 DCRenderRect(dc, VPoint, &full_rect);
2248 dc.SelectObject(wxNullBitmap);
2259int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2272 render_canvas_parms pb_spec;
2274 pb_spec.depth = BPP;
2275 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2276 pb_spec.lclip = rect->x;
2277 pb_spec.rclip = rect->x + rect->width - 1;
2278 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2279 pb_spec.width = rect->width;
2280 pb_spec.height = rect->height;
2281 pb_spec.x = rect->x;
2282 pb_spec.y = rect->y;
2284#ifdef ocpnUSE_ocpnBitmap
2285 pb_spec.b_revrgb =
true;
2287 pb_spec.b_revrgb =
false;
2291 wxColour color = GetGlobalColor(
"NODTA");
2292 unsigned char r, g, b;
2300 if (pb_spec.depth == 24) {
2301 for (
int i = 0; i < pb_spec.height; i++) {
2302 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2303 for (
int j = 0; j < pb_spec.width; j++) {
2310 int color_int = ((r) << 16) + ((g) << 8) + (b);
2312 for (
int i = 0; i < pb_spec.height; i++) {
2313 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2314 for (
int j = 0; j < pb_spec.width; j++) {
2321 for (i = 0; i < PRIO_NUM; ++i) {
2322 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2323 top = razRules[i][4];
2325 top = razRules[i][3];
2327 while (top != NULL) {
2330 crnt->sm_transform_parms = &vp_transform;
2331 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2336#ifdef ocpnUSE_ocpnBitmap
2337 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2338 pb_spec.height, pb_spec.depth);
2340 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2341 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2342 wxBitmap *pREN =
new wxBitmap(*prender_image);
2348 dc_ren.SelectObject(*pREN);
2351 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2352 (wxDC *)&dc_ren, 0, 0);
2355 dc_ren.SelectObject(wxNullBitmap);
2357#ifdef ocpnUSE_ocpnBitmap
2358 free(pb_spec.pix_buff);
2360 delete prender_image;
2367 DCRenderLPB(dcinput, vp, rect);
2372bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2379 for (i = 0; i < PRIO_NUM; ++i) {
2381 wxDCClipper *pdcc = NULL;
2387 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2388 top = razRules[i][4];
2390 top = razRules[i][3];
2391 while (top != NULL) {
2394 crnt->sm_transform_parms = &vp_transform;
2395 ps52plib->RenderObjectToDC(&dcinput, crnt);
2398 top = razRules[i][2];
2399 while (top != NULL) {
2402 crnt->sm_transform_parms = &vp_transform;
2403 ps52plib->RenderObjectToDC(&dcinput, crnt);
2406 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2407 top = razRules[i][0];
2409 top = razRules[i][1];
2411 while (top != NULL) {
2414 crnt->sm_transform_parms = &vp_transform;
2415 ps52plib->RenderObjectToDC(&dcinput, crnt);
2419 if (pdcc)
delete pdcc;
2432bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2438 for (i = 0; i < PRIO_NUM; ++i) {
2439 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2440 top = razRules[i][4];
2442 top = razRules[i][3];
2444 while (top != NULL) {
2447 crnt->sm_transform_parms = &vp_transform;
2448 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2451 top = razRules[i][2];
2452 while (top != NULL) {
2455 crnt->sm_transform_parms = &vp_transform;
2456 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2459 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2460 top = razRules[i][0];
2462 top = razRules[i][1];
2464 while (top != NULL) {
2467 crnt->sm_transform_parms = &vp_transform;
2468 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2475bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2476 wxFileName fn(FullPath);
2478 wxString cname = fn.GetName();
2479 if (cname.Length() >= 3)
2480 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2485InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2488 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2491 if (name.Upper().EndsWith(
".XZ")) {
2492 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2495 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2496 wxFileName(name).GetName();
2498 if (!wxFileExists(m_TempFilePath) &&
2499 !DecompressXZFile(name, m_TempFilePath)) {
2500 wxRemoveFile(m_TempFilePath);
2501 return INIT_FAIL_REMOVE;
2504 m_TempFilePath = name;
2505 ext = wxFileName(name).GetExt();
2510 firebase::crashlytics::SetCustomKey(
"s57chartInit",
2511 name.ToStdString().c_str());
2523 InitReturn ret_value = INIT_OK;
2525 m_Description = name;
2527 wxFileName fn(m_TempFilePath);
2530 wxString cname = fn.GetName();
2531 m_usage_char = cname[2];
2534 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2535 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2537 if (flags == THUMB_ONLY) {
2545 if (flags == HEADER_ONLY) {
2547 if (!GetBaseFileAttr(fn.GetFullPath()))
2548 ret_value = INIT_FAIL_REMOVE;
2550 if (!CreateHeaderDataFromENC())
2551 ret_value = INIT_FAIL_REMOVE;
2553 ret_value = INIT_OK;
2555 }
else if (ext ==
"S57") {
2556 m_SENCFileName = m_TempFilePath;
2557 if (!CreateHeaderDataFromSENC())
2558 ret_value = INIT_FAIL_REMOVE;
2560 ret_value = INIT_OK;
2569 if (!m_bbase_file_attr_known) {
2570 if (!GetBaseFileAttr(m_TempFilePath))
2571 ret_value = INIT_FAIL_REMOVE;
2573 m_bbase_file_attr_known =
true;
2577 if (m_bbase_file_attr_known) {
2578 int sret = FindOrCreateSenc(m_FullPath);
2579 if (sret == BUILD_SENC_PENDING) {
2584 if (sret != BUILD_SENC_OK) {
2585 if (sret == BUILD_SENC_NOK_RETRY)
2586 ret_value = INIT_FAIL_RETRY;
2588 ret_value = INIT_FAIL_REMOVE;
2590 ret_value = PostInit(flags, m_global_color_scheme);
2595 else if (ext ==
"S57") {
2596 m_SENCFileName = m_TempFilePath;
2597 ret_value = PostInit(flags, m_global_color_scheme);
2604wxString s57chart::buildSENCName(
const wxString &name) {
2605 wxFileName fn(name);
2607 wxString file_name = fn.GetFullName();
2610 wxString SENCdir = g_SENCPrefix;
2612 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2613 SENCdir.Append(wxFileName::GetPathSeparator());
2616 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2617 wxCharBuffer buf = source_dir.ToUTF8();
2618 unsigned char sha1_out[20];
2619 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2622 for (
unsigned int i = 0; i < 6; i++) {
2624 s.Printf(
"%02X", sha1_out[i]);
2628 file_name.Prepend(sha1);
2631 wxFileName tsfn(SENCdir);
2632 tsfn.SetFullName(file_name);
2634 return tsfn.GetFullPath();
2641int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2645 if (name.Upper().EndsWith(
".XZ")) {
2646 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2649 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2650 wxFileName(name).GetName();
2652 if (!wxFileExists(m_TempFilePath) &&
2653 !DecompressXZFile(name, m_TempFilePath)) {
2654 wxRemoveFile(m_TempFilePath);
2655 return INIT_FAIL_REMOVE;
2658 m_TempFilePath = name;
2659 ext = wxFileName(name).GetExt();
2663 if (!m_bbase_file_attr_known) {
2664 if (!GetBaseFileAttr(m_TempFilePath))
2665 return INIT_FAIL_REMOVE;
2667 m_bbase_file_attr_known =
true;
2671 m_SENCFileName = buildSENCName(name);
2673 int build_ret_val = 1;
2675 bool bbuild_new_senc =
false;
2676 m_bneed_new_thumbnail =
false;
2678 wxFileName FileName000(m_TempFilePath);
2682 wxString msg(
"S57chart::Checking SENC file: ");
2683 msg.Append(m_SENCFileName);
2687 int force_make_senc = 0;
2689 if (::wxFileExists(m_SENCFileName)) {
2692 if (senc.ingestHeader(m_SENCFileName)) {
2693 bbuild_new_senc =
true;
2694 wxLogMessage(
" Rebuilding SENC due to ingestHeader failure.");
2696 int senc_file_version = senc.getSencReadVersion();
2698 int last_update = senc.getSENCReadLastUpdate();
2700 wxString str = senc.getSENCFileCreateDate();
2701 wxDateTime SENCCreateDate;
2702 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
2704 if (SENCCreateDate.IsValid())
2705 SENCCreateDate.ResetTime();
2710 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2712 senc_base_edtn.ToLong(&isenc_edition);
2714 m_edtn000.ToLong(&ifile_edition);
2719 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2720 bbuild_new_senc =
true;
2721 wxLogMessage(
" Rebuilding SENC due to SENC format update.");
2728 else if (ifile_edition > isenc_edition) {
2729 bbuild_new_senc =
true;
2730 wxLogMessage(
" Rebuilding SENC due to cell edition update.");
2732 msg =
" Last edition recorded in SENC: ";
2733 msg += senc_base_edtn;
2734 msg +=
" most recent edition cell file: ";
2739 int most_recent_update_file =
2740 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2742 if (ifile_edition == isenc_edition) {
2743 if (most_recent_update_file > last_update) {
2744 bbuild_new_senc =
true;
2746 " Rebuilding SENC due to incremental cell update.");
2749 " Last update recorded in SENC: %d most recent "
2751 last_update, most_recent_update_file);
2759 wxDateTime OModTime000;
2760 FileName000.GetTimes(NULL, &OModTime000, NULL);
2761 OModTime000.ResetTime();
2762 if (SENCCreateDate.IsValid()) {
2763 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2765 " Rebuilding SENC due to Senc vs cell file time "
2767 bbuild_new_senc =
true;
2770 bbuild_new_senc =
true;
2772 " Rebuilding SENC due to SENC create time invalid.");
2783 if (force_make_senc) bbuild_new_senc =
true;
2785 }
else if (!::wxFileExists(m_SENCFileName))
2787 wxLogMessage(
" Rebuilding SENC due to missing SENC file.");
2788 bbuild_new_senc =
true;
2792 if (bbuild_new_senc) {
2793 m_bneed_new_thumbnail =
2795 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2797 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2798 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2799 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2805InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2807 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2808 wxString msg(
" Cannot load SENC file ");
2809 msg.Append(m_SENCFileName);
2812 return INIT_FAIL_RETRY;
2818 wxString SENCdir = g_SENCPrefix;
2819 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2820 SENCdir.Append(wxFileName::GetPathSeparator());
2822 wxFileName s57File(m_SENCFileName);
2823 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13),
"BMP");
2825 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2826 BuildThumbnail(ThumbFileName.GetFullPath());
2829 if (ThumbFileName.FileExists()) {
2831#ifdef ocpnUSE_ocpnBitmap
2832 pBMP_NEW =
new ocpnBitmap;
2834 pBMP_NEW =
new wxBitmap;
2836 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2839 m_pDIBThumbDay = pBMP_NEW;
2847 m_global_color_scheme = cs;
2848 SetColorScheme(cs,
false);
2851 BuildDepthContourArray();
2853 CreateChartContext();
2854 PopulateObjectsWithContext();
2857 bReadyToRender =
true;
2862void s57chart::ClearDepthContourArray() {
2863 if (m_nvaldco_alloc) {
2864 free(m_pvaldco_array);
2866 m_nvaldco_alloc = 5;
2868 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2871void s57chart::BuildDepthContourArray() {
2874 if (0 == m_nvaldco_alloc) {
2875 m_nvaldco_alloc = 5;
2876 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2882 double prev_valdco = 0.0;
2884 for (
int i = 0; i < PRIO_NUM; ++i) {
2885 for (
int j = 0; j < LUPNAME_NUM; j++) {
2886 top = razRules[i][j];
2887 while (top != NULL) {
2888 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2889 double valdco = 0.0;
2890 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2891 if (valdco != prev_valdco) {
2892 prev_valdco = valdco;
2894 if (m_nvaldco > m_nvaldco_alloc) {
2895 void *tr = realloc((
void *)m_pvaldco_array,
2896 m_nvaldco_alloc * 2 *
sizeof(
double));
2897 m_pvaldco_array = (
double *)tr;
2898 m_nvaldco_alloc *= 2;
2900 m_pvaldco_array[m_nvaldco - 1] = valdco;
2904 ObjRazRules *nxx = top->next;
2909 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2913void s57chart::SetSafetyContour() {
2921 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2924 if (NULL != m_pvaldco_array) {
2925 for (i = 0; i < m_nvaldco; i++) {
2926 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2930 m_next_safe_cnt = m_pvaldco_array[i];
2932 m_next_safe_cnt = (double)1e6;
2934 m_next_safe_cnt = (double)1e6;
2939 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2940 m_next_safe_cnt = (
double)1e6;
2943void s57chart::CreateChartContext() {
2945 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2948void s57chart::PopulateObjectsWithContext() {
2949 m_this_chart_context->chart =
this;
2950 m_this_chart_context->chart_type = GetChartType();
2951 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2952 m_this_chart_context->chart_scale = GetNativeScale();
2953 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2954 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2955 m_this_chart_context->safety_contour = m_next_safe_cnt;
2956 m_this_chart_context->pt2GetAssociatedObjects =
2957 &s57chart::GetAssociatedObjects;
2961 for (
int i = 0; i < PRIO_NUM; ++i) {
2962 for (
int j = 0; j < LUPNAME_NUM; j++) {
2963 top = razRules[i][j];
2964 while (top != NULL) {
2965 S57Obj *obj = top->obj;
2966 obj->m_chart_context = m_this_chart_context;
2973void s57chart::InvalidateCache() {
2978bool s57chart::BuildThumbnail(
const wxString &bmpname) {
2981 wxFileName ThumbFileName(bmpname);
2984 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
2985 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
2986 wxLogMessage(
" Cannot create BMP file directory for " +
2987 ThumbFileName.GetFullPath());
2995 vp.
clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
2996 vp.
clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2998 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
2999 (m_FullExtent.ELON - m_FullExtent.WLON));
3006 vp.m_projection_type = PROJECTION_MERCATOR;
3008 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3025 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3027 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3029 int *psvr = psave_viz;
3033 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3034 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3035 *psvr++ = pOLE->nViz;
3040 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3041 bool bsave_text = ps52plib->m_bShowS57Text;
3044 ps52plib->SaveObjNoshow();
3047 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3048 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3049 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3050 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3053 ps52plib->m_bShowSoundg =
false;
3054 ps52plib->m_bShowS57Text =
false;
3057 DisCat dsave = ps52plib->GetDisplayCategory();
3058 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3060 ps52plib->AddObjNoshow(
"BRIDGE");
3061 ps52plib->AddObjNoshow(
"GATCON");
3063 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3064 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3065 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3066 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3068#ifdef ocpnUSE_DIBSECTION
3071 wxMemoryDC memdc, dc_org;
3075 ps52plib->SaveColorScheme();
3076 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3078 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3081 memdc.SelectObject(wxNullBitmap);
3085 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3086 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3087 pOLE->nViz = *psvr++;
3090 ps52plib->SetDisplayCategory(dsave);
3091 ps52plib->RestoreObjNoshow();
3093 ps52plib->RemoveObjNoshow(
"BRIDGE");
3094 ps52plib->RemoveObjNoshow(
"GATCON");
3096 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3097 ps52plib->m_bShowS57Text = bsave_text;
3099 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3100 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3103 ps52plib->RestoreColorScheme();
3113 wxMemoryDC dc_clone;
3114 dc_clone.SelectObject(*pBMP);
3116 pDIB->SelectIntoDC(dc_org);
3120 dc_clone.SelectObject(wxNullBitmap);
3121 dc_org.SelectObject(wxNullBitmap);
3124 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3131WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3132static int depth = 0;
3133static bool isProcessing =
false;
3136bool s57chart::CreateHeaderDataFromENC() {
3139 float LatMax, LatMin, LonMax, LonMin;
3145 m_pCOVRTablePoints = NULL;
3146 m_pCOVRTable = NULL;
3148 if (!InitENCMinimal(m_TempFilePath)) {
3149 wxString msg(
" Cannot initialize ENC file ");
3150 msg.Append(m_TempFilePath);
3157 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3158 std::vector<int> auxCntArray, noCovrCntArray;
3159 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3162 wxCriticalSectionLocker enter(GDALcriticalSection);
3163 if (isProcessing)
int yyp = 4;
3164 isProcessing =
true;
3172 pFeat = GetChartFirstM_COVR(catcov);
3177 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3178 OGRLinearRing *xring = poly->getExteriorRing();
3180 int npt = xring->getNumPoints();
3191 for (
int i = 0; i < npt; i++) {
3192 xring->getPoint(i, &p);
3196 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3198 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3199 if (xdelta < 0.001 &&
3207 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3208 pfr = &pf[2 * (usedpts - 1)];
3211 LatMax = fmax(LatMax, p.getY());
3212 LatMin = fmin(LatMin, p.getY());
3213 LonMax = fmax(LonMax, p.getX());
3214 LonMin = fmin(LonMin, p.getX());
3222 pAuxPtrArray->Add(pf);
3223 auxCntArray.push_back(usedpts);
3224 }
else if (catcov == 2) {
3225 pNoCovrPtrArray->Add(pf);
3226 noCovrCntArray.push_back(usedpts);
3231 pFeat = GetChartNextM_COVR(catcov);
3232 DEBUG_LOG <<
"used " << usedpts <<
" points";
3238 isProcessing =
false;
3243 m_nCOVREntries = auxCntArray.size();
3247 if (m_nCOVREntries >= 1) {
3248 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3249 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3251 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3252 m_pCOVRTablePoints[j] = auxCntArray[j];
3253 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3259 wxString msg(
" ENC contains no useable M_COVR, CATCOV=1 features: ");
3260 msg.Append(m_TempFilePath);
3265 m_nNoCOVREntries = noCovrCntArray.size();
3267 if (m_nNoCOVREntries) {
3269 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3270 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3272 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3273 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3274 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3277 m_pNoCOVRTablePoints = NULL;
3278 m_pNoCOVRTable = NULL;
3281 delete pAuxPtrArray;
3282 delete pNoCovrPtrArray;
3284 if (0 == m_nCOVREntries) {
3285 wxString msg(
" ENC contains no M_COVR features: ");
3286 msg.Append(m_TempFilePath);
3289 msg =
" Calculating Chart Extents as fallback.";
3295 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3297 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3304 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3305 *m_pCOVRTablePoints = 4;
3306 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3307 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3324 wxString msg(
" Cannot calculate Extents for ENC: ");
3325 msg.Append(m_TempFilePath);
3333 m_FullExtent.NLAT = LatMax;
3334 m_FullExtent.SLAT = LatMin;
3335 m_FullExtent.ELON = LonMax;
3336 m_FullExtent.WLON = LonMin;
3337 m_bExtentSet =
true;
3340 m_Chart_Scale = GetENCScale();
3351bool s57chart::CreateHeaderDataFromoSENC() {
3352 bool ret_val =
true;
3354 wxFFileInputStream fpx(m_SENCFileName);
3356 if (!::wxFileExists(m_SENCFileName)) {
3357 wxString msg(
" Cannot open SENC file ");
3358 msg.Append(m_SENCFileName);
3365 if (senc.ingestHeader(m_SENCFileName)) {
3371 m_Chart_Scale = senc.getSENCReadScale();
3374 m_Name = senc.getReadName();
3377 m_ID = senc.getReadID();
3380 Extent &ext = senc.getReadExtent();
3382 m_FullExtent.ELON = ext.ELON;
3383 m_FullExtent.WLON = ext.WLON;
3384 m_FullExtent.NLAT = ext.NLAT;
3385 m_FullExtent.SLAT = ext.SLAT;
3386 m_bExtentSet =
true;
3389 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3390 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3392 m_nCOVREntries = AuxCntArray.size();
3394 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3395 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3397 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3398 m_pCOVRTablePoints[j] = AuxCntArray[j];
3399 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3400 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3401 AuxCntArray[j] * 2 *
sizeof(
float));
3405 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3406 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3408 m_nNoCOVREntries = NoCovrCntArray.size();
3410 if (m_nNoCOVREntries) {
3412 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3413 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3415 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3416 int npoints = NoCovrCntArray[j];
3417 m_pNoCOVRTablePoints[j] = npoints;
3418 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3419 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3420 npoints * 2 *
sizeof(
float));
3426 m_datum_str =
"WGS84";
3427 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
3429 int senc_file_version = senc.getSencReadVersion();
3431 int last_update = senc.getSENCReadLastUpdate();
3433 wxString str = senc.getSENCFileCreateDate();
3434 wxDateTime SENCCreateDate;
3435 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
3437 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3439 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3446bool s57chart::CreateHeaderDataFromSENC() {
3447 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3455bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3457 if (NULL != m_pvaldco_array) {
3458 for (i = 0; i < m_nvaldco; i++) {
3459 if (m_pvaldco_array[i] >= safe_cnt)
break;
3463 next_safe_cnt = m_pvaldco_array[i];
3465 next_safe_cnt = (double)1e6;
3468 next_safe_cnt = (double)1e6;
3482std::list<S57Obj *> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3486 std::list<S57Obj *> *pobj_list =
new std::list<S57Obj *>();
3489 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3490 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3493 switch (obj->Primitive_type) {
3506 top = razRules[disPrioIdx][3];
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);
3518 ObjRazRules *nxx = top->next;
3523 top = razRules[disPrioIdx][4];
3524 while (top != NULL) {
3525 if (top->obj->bIsAssociable) {
3526 if (top->obj->BBObj.Contains(lat, lon)) {
3527 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3528 pobj_list->push_back(top->obj);
3534 ObjRazRules *nxx = top->next;
3548void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3549 wxFileName fn(FullPath);
3551 wxString target_name = fn.GetName();
3552 target_name.RemoveLast();
3554 wxString dir_name = fn.GetPath();
3556 wxDir dir(dir_name);
3558 wxArrayString FileList;
3560 dir.GetAllFiles(fn.GetPath(), &FileList);
3564 bool found_name =
false;
3568 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3569 wxFileName file(FileList[j]);
3570 if (((file.GetExt()).MakeUpper()) ==
"TXT") {
3572 wxTextFile text_file(file.GetFullPath());
3574 bool file_ok =
true;
3578 if (!text_file.Open()) {
3579 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3584 wxString str = text_file.GetFirstLine();
3585 while (!text_file.Eof()) {
3586 if (0 == target_name.CmpNoCase(
3587 str.Mid(0, target_name.Len()))) {
3588 wxString tname = str.AfterFirst(
'-');
3589 name = tname.AfterFirst(
' ');
3593 str = text_file.GetNextLine();
3597 wxString msg(
" Error Reading ENC .TXT file: ");
3598 msg.Append(file.GetFullPath());
3604 if (found_name)
break;
3621const char *s57chart::getName(OGRFeature *feature) {
3622 return feature->GetDefnRef()->GetName();
3625static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3626 wxFileName fn1(first);
3627 wxFileName fn2(second);
3628 wxString ext1(fn1.GetExt());
3629 wxString ext2(fn2.GetExt());
3631 return ext1.Cmp(ext2);
3634int s57chart::GetUpdateFileArray(
const wxFileName file000,
3635 wxArrayString *UpFiles, wxDateTime date000,
3637 wxString DirName000 =
3638 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3639 wxDir dir(DirName000);
3640 if (!dir.IsOpened()) {
3641 DirName000.Prepend(wxFileName::GetPathSeparator());
3642 DirName000.Prepend(
".");
3643 dir.Open(DirName000);
3644 if (!dir.IsOpened()) {
3649 int flags = wxDIR_DEFAULT;
3656 wxFileName fnDir(DirName000);
3657 fnDir.RemoveLastDir();
3658 wxString sdir = fnDir.GetPath();
3659 wxFileName fnTest(sdir);
3660 wxString sname = fnTest.GetName();
3662 if (sname.ToLong(&tmps)) {
3665 flags |= wxDIR_DIRS;
3669 wxArrayString *dummy_array;
3672 if (UpFiles == NULL)
3673 dummy_array =
new wxArrayString;
3675 dummy_array = UpFiles;
3677 wxArrayString possibleFiles;
3678 wxDir::GetAllFiles(DirName000, &possibleFiles,
"", flags);
3680 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3681 wxString filename(possibleFiles[i]);
3683 wxFileName file(filename);
3684 ext = file.GetExt();
3689 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3690 wxString FileToAdd = filename;
3692 wxCharBuffer buffer =
3695 if (buffer.data() && !filename.IsSameAs(
"CATALOG.031",
3707 DDFModule *poModule =
new DDFModule();
3708 if (!poModule->Open(FileToAdd.mb_str())) {
3710 " s57chart::BuildS57File Unable to open update file ");
3711 msg.Append(FileToAdd);
3720 DDFRecord *pr = poModule->ReadRecord();
3726 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3729 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3733 " s57chart::BuildS57File DDFRecord 0 does not contain "
3734 "DSID:ISDT in update file ");
3735 msg.Append(FileToAdd);
3738 sumdate =
"20000101";
3741 umdate.ParseFormat(sumdate,
"%Y%m%d");
3742 if (!umdate.IsValid()) umdate.ParseFormat(
"20000101",
"%Y%m%d");
3745 if (!umdate.IsValid())
int yyp = 4;
3750 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3752 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3756 " s57chart::BuildS57File DDFRecord 0 does not contain "
3757 "DSID:EDTN in update file ");
3758 msg.Append(FileToAdd);
3767 if ((!umdate.IsEarlierThan(date000)) &&
3768 (umedtn.IsSameAs(edtn000)))
3769 dummy_array->Add(FileToAdd);
3775 dummy_array->Sort(ExtensionCompare);
3778 if (dummy_array->GetCount()) {
3779 wxString Last = dummy_array->Last();
3780 wxFileName fnl(Last);
3782 wxCharBuffer buffer = ext.ToUTF8();
3783 if (buffer.data()) retval = atoi(buffer.data());
3786 if (UpFiles == NULL)
delete dummy_array;
3791int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3792 const wxString CopyDir,
3793 wxString &LastUpdateDate,
3799 wxArrayString *UpFiles =
new wxArrayString;
3800 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3802 if (UpFiles->GetCount()) {
3822 for (
int iff = 0; iff < retval + 1; iff++) {
3823 wxFileName ufile(m_TempFilePath);
3825 sext.Printf(
"%03d", iff);
3829 wxString cp_ufile = CopyDir;
3830 if (cp_ufile.Last() != ufile.GetPathSeparator())
3831 cp_ufile.Append(ufile.GetPathSeparator());
3833 cp_ufile.Append(ufile.GetFullName());
3838 if (ufile.FileExists()) {
3839 wxFile uf(ufile.GetFullPath());
3840 if (uf.IsOpened()) {
3846 if (ufile.FileExists() &&
3850 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3852 wxString msg(
" Cannot copy temporary working ENC file ");
3853 msg.Append(ufile.GetFullPath());
3855 msg.Append(cp_ufile);
3868 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3869 "incomplete or inaccurate.\nCheck the logfile for details."),
3870 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3876 "WARNING---ENC Update chain incomplete. Substituting NULL "
3878 msg += ufile.GetFullName();
3880 wxLogMessage(
" Subsequent ENC updates may produce errors.");
3882 " This ENC exchange set should be updated and SENCs "
3886 DDFModule *dupdate =
new DDFModule;
3887 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3888 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3892 wxString msg(
" Error creating dummy update file: ");
3893 msg.Append(cp_ufile);
3898 m_tmpup_array->Add(cp_ufile);
3905 wxFileName lastfile(m_TempFilePath);
3907 last_sext.Printf(
"%03d", retval);
3908 lastfile.SetExt(last_sext);
3911 DDFModule oUpdateModule;
3916 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3920 oUpdateModule.Rewind();
3921 DDFRecord *pr = oUpdateModule.ReadRecord();
3927 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3931 LastUpdateDate = wxString(u, wxConvUTF8);
3934 wxDateTime now = wxDateTime::Now();
3935 LastUpdateDate = now.Format(
"%Y%m%d");
3944wxString s57chart::GetISDT() {
3945 if (m_date000.IsValid())
3946 return m_date000.Format(
"%Y%m%d");
3951bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3952 if (!wxFileName::FileExists(file000))
return false;
3954 wxString FullPath000 = file000;
3955 DDFModule *poModule =
new DDFModule();
3956 if (!poModule->Open(FullPath000.mb_str())) {
3957 wxString msg(
" s57chart::BuildS57File Unable to open ");
3958 msg.Append(FullPath000);
3970 DDFRecord *pr = poModule->ReadRecord();
3974 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3975 if (!m_nGeoRecords) {
3977 " s57chart::BuildS57File DDFRecord 0 does not contain "
3987 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3989 date000 = wxString(u, wxConvUTF8);
3992 " s57chart::BuildS57File DDFRecord 0 does not contain "
3999 m_date000.ParseFormat(date000,
"%Y%m%d");
4000 if (!m_date000.IsValid()) m_date000.ParseFormat(
"20000101",
"%Y%m%d");
4002 m_date000.ResetTime();
4005 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
4007 m_edtn000 = wxString(u, wxConvUTF8);
4010 " s57chart::BuildS57File DDFRecord 0 does not contain "
4021 for (; pr != NULL; pr = poModule->ReadRecord()) {
4022 if (pr->FindField(
"DSPM") != NULL) {
4023 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4027 if (!m_native_scale) {
4028 wxString msg(
" s57chart::BuildS57File ENC not contain DSPM:CSCL ");
4031 m_native_scale = 1000;
4039int s57chart::BuildSENCFile(
const wxString &FullPath000,
4040 const wxString &SENCFileName,
bool b_progress) {
4042 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4043 double meters_per_pixel_max_scale =
4045 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4048 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4049 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4051 if (!m_disableBackgroundSENC) {
4054 ticket->m_LOD_meters = m_LOD_meters;
4055 ticket->ref_lat = ref_lat;
4056 ticket->ref_lon = ref_lon;
4057 ticket->m_FullPath000 = FullPath000;
4058 ticket->m_SENCFileName = SENCFileName;
4059 ticket->m_chart =
this;
4062 bReadyToRender =
true;
4063 return BUILD_SENC_PENDING;
4066 return BUILD_SENC_NOK_RETRY;
4071 senc.setRegistrar(g_poRegistrar);
4072 senc.setRefLocn(ref_lat, ref_lon);
4073 senc.SetLODMeters(m_LOD_meters);
4075 AbstractPlatform::ShowBusySpinner();
4077 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4079 AbstractPlatform::HideBusySpinner();
4081 if (ret == ERROR_INGESTING000)
4082 return BUILD_SENC_NOK_PERMANENT;
4088int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4095 S57ObjVector Objects;
4096 VE_ElementVector VEs;
4097 VC_ElementVector VCs;
4099 sencfile.setRefLocn(ref_lat, ref_lon);
4101 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4103 if (srv != SENC_NO_ERROR) {
4104 wxLogMessage(sencfile.getLastError());
4110 Extent ext = sencfile.getReadExtent();
4112 m_FullExtent.ELON = ext.ELON;
4113 m_FullExtent.WLON = ext.WLON;
4114 m_FullExtent.NLAT = ext.NLAT;
4115 m_FullExtent.SLAT = ext.SLAT;
4116 m_bExtentSet =
true;
4118 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4119 ref_lon = (ext.ELON + ext.WLON) / 2.;
4124 int n_ve_elements = VEs.size();
4126 double scale = top_frame::Get()->GetBestVPScale(
this);
4127 int nativescale = GetNativeScale();
4129 for (
int i = 0; i < n_ve_elements; i++) {
4130 VE_Element *vep = VEs.at(i);
4131 if (vep && vep->nCount) {
4133 double east_max = -1e7;
4134 double east_min = 1e7;
4135 double north_max = -1e7;
4136 double north_min = 1e7;
4138 float *vrun = vep->pPoints;
4139 for (
size_t i = 0; i < vep->nCount; i++) {
4140 east_max = wxMax(east_max, *vrun);
4141 east_min = wxMin(east_min, *vrun);
4144 north_max = wxMax(north_max, *vrun);
4145 north_min = wxMin(north_min, *vrun);
4149 double lat1, lon1, lat2, lon2;
4150 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4151 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4152 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4155 m_ve_hash[vep->index] = vep;
4159 int n_vc_elements = VCs.size();
4161 for (
int i = 0; i < n_vc_elements; i++) {
4162 VC_Element *vcp = VCs.at(i);
4163 m_vc_hash[vcp->index] = vcp;
4171 for (
unsigned int i = 0; i < Objects.size(); i++) {
4172 S57Obj *obj = Objects[i];
4176 LUPname LUP_Name = PAPER_CHART;
4178 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4179 if (objnam.Len() > 0) {
4180 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4181 SendVectorChartObjectInfo(FullPath, fe_name, objnam, obj->m_lat,
4182 obj->m_lon,
scale, nativescale);
4186 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4187 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4188 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4189 SendVectorChartObjectInfo(FullPath, fe_name, nobjnam, obj->m_lat,
4190 obj->m_lon,
scale, nativescale);
4193 switch (obj->Primitive_type) {
4198 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4199 LUP_Name = PAPER_CHART;
4201 LUP_Name = SIMPLIFIED;
4210 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4211 LUP_Name = PLAIN_BOUNDARIES;
4213 LUP_Name = SYMBOLIZED_BOUNDARIES;
4218 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4222 wxString msg(obj->FeatureName, wxConvUTF8);
4223 msg.Prepend(
" Could not find LUP for ");
4224 LogMessageOnce(msg);
4231 ps52plib->_LUP2rules(LUP, obj);
4234 _insertRules(obj, LUP,
this);
4237 obj->m_DisplayCat = LUP->DISC;
4240 obj->m_DPRI = LUP->DPRI -
'0';
4243 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4244 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4245 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4246 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4247 obj->m_bcategory_mutable =
true;
4249 obj->m_bcategory_mutable =
false;
4254 if (obj && (GEO_POINT == obj->Primitive_type)) {
4256 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4257 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4258 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4259 pFloatingATONArray->Add(obj);
4263 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4264 pRigidATONArray->Add(obj);
4268 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4269 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4270 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4271 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4272 obj->bIsAton =
true;
4281 d000.ParseFormat(sencfile.getBaseDate(),
"%Y%m%d");
4282 if (!d000.IsValid()) d000.ParseFormat(
"20000101",
"%Y%m%d");
4285 updt.ParseFormat(sencfile.getUpdateDate(),
"%Y%m%d");
4286 if (!updt.IsValid()) updt.ParseFormat(
"20000101",
"%Y%m%d");
4288 if (updt.IsLaterThan(d000))
4289 m_PubYear.Printf(
"%4d", updt.GetYear());
4291 m_PubYear.Printf(
"%4d", d000.GetYear());
4294 wxDateTime upd = updt;
4295 if (!upd.IsValid()) upd.ParseFormat(
"20000101",
"%Y%m%d");
4300 m_SE = sencfile.getSENCReadBaseEdition();
4303 supdate.Printf(
" / %d", sencfile.getSENCReadLastUpdate());
4306 m_datum_str =
"WGS84";
4308 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
4309 m_ID = sencfile.getReadID();
4310 m_Name = sencfile.getReadName();
4314 AssembleLineGeometry();
4319int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4320 ObjRazRules *rzRules = NULL;
4330 switch (LUP->DPRI) {
4343 case PRIO_SYMB_POINT:
4346 case PRIO_SYMB_LINE:
4349 case PRIO_SYMB_AREA:
4362 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4366 switch (LUP->TNAM) {
4376 case PLAIN_BOUNDARIES:
4379 case SYMBOLIZED_BOUNDARIES:
4383 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4387 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4391 rzRules->child = NULL;
4392 rzRules->mps = NULL;
4395 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4396 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4401 ObjRazRules *rNext = NULL;
4402 ObjRazRules *rPrevious = NULL;
4403 if (razRules[disPrioIdx][LUPtypeIdx]) {
4404 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4405 rNext = rPrevious->next;
4409 rNext = rPrevious->next;
4412 rzRules->next = NULL;
4414 rPrevious->next = rzRules;
4416 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4423void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4433 for (
int i = 0; i < PRIO_NUM; ++i) {
4434 for (
int j = 0; j < 2; ++j) {
4435 top = razRules[i][j];
4437 while (top != NULL) {
4438 if (!top->obj->geoPtMulti)
4440 if (top->obj->BBObj.GetValid()) {
4441 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4443 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4444 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4446 double minlon = top->obj->BBObj.GetMinLon();
4447 double maxlon = top->obj->BBObj.GetMaxLon();
4449 double lon1 = (lon - minlon) * d;
4450 double lon2 = (lon - maxlon) * d;
4452 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4455 top->obj->BBObj.Invalidate();
4476void s57chart::UpdateLUPs(
s57chart *pOwner) {
4480 for (
int i = 0; i < PRIO_NUM; ++i) {
4482 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4483 m_b2pointLUPS =
true;
4484 top = razRules[i][0];
4486 while (top != NULL) {
4487 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4493 if (top->obj->nRef < 2) {
4494 ps52plib->_LUP2rules(LUP, top->obj);
4495 _insertRules(top->obj, LUP, pOwner);
4496 top->obj->m_DisplayCat = LUP->DISC;
4506 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4507 m_b2pointLUPS =
true;
4508 top = razRules[i][1];
4510 while (top != NULL) {
4511 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4514 if (top->obj->nRef < 2) {
4515 ps52plib->_LUP2rules(LUP, top->obj);
4516 _insertRules(top->obj, LUP, pOwner);
4517 top->obj->m_DisplayCat = LUP->DISC;
4527 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4528 m_b2lineLUPS =
true;
4529 top = razRules[i][3];
4531 while (top != NULL) {
4532 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4533 top->obj->FeatureName, top->obj);
4535 ps52plib->_LUP2rules(LUP, top->obj);
4536 _insertRules(top->obj, LUP, pOwner);
4537 top->obj->m_DisplayCat = LUP->DISC;
4546 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4547 m_b2lineLUPS =
true;
4548 top = razRules[i][4];
4550 while (top != NULL) {
4551 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4554 ps52plib->_LUP2rules(LUP, top->obj);
4555 _insertRules(top->obj, LUP, pOwner);
4556 top->obj->m_DisplayCat = LUP->DISC;
4568 for (
int j = 0; j < LUPNAME_NUM; j++) {
4569 top = razRules[i][j];
4570 while (top != NULL) {
4571 top->obj->bCS_Added = 0;
4574 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4585 for (
int j = 0; j < LUPNAME_NUM; j++) {
4586 top = razRules[i][j];
4587 while (top != NULL) {
4589 ObjRazRules *ctop = top->child;
4590 while (NULL != ctop) {
4591 ctop->obj->bCS_Added = 0;
4592 free_mps(ctop->mps);
4595 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4612ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4613 float lat,
float lon,
ViewPort *VPoint) {
4614 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4615 std::vector<ObjRazRules *> selected_rules;
4620 char *curr_att = NULL;
4622 wxArrayOfS57attVal *attValArray = NULL;
4623 bool bleading_attribute =
false;
4625 for (
int i = 0; i < PRIO_NUM; ++i) {
4629 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4630 top = razRules[i][point_type];
4632 while (top != NULL) {
4633 if (top->obj->npt == 1) {
4634 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4636 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4638 if (ps52plib->ObjectRenderCheckCat(top)) {
4641 wxString curAttrName;
4642 curr_att = top->obj->att_array;
4643 n_attr = top->obj->n_attr;
4644 attValArray = top->obj->attVal;
4652 bleading_attribute =
false;
4654 while (attrCounter < n_attr) {
4655 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4658 S57attVal *pAttrVal = NULL;
4661 pAttrVal = attValArray->Item(attrCounter);
4665 wxString value = s57chart::GetAttributeValueAsString(
4666 pAttrVal, curAttrName);
4668 if (curAttrName ==
"LITVIS") {
4669 if (value.StartsWith(
"obsc")) bviz =
false;
4670 }
else if (curAttrName ==
"VALNMR")
4671 value.ToDouble(&valnmr);
4677 if (bviz && (valnmr > 0.1)) {
4681 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4682 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4683 ref_lat, ref_lon, &olat, &olon);
4685 double dlat = lat - olat;
4686 double dy = dlat * 60 / cos(olat * PI / 180.);
4687 double dlon = lon - olon;
4688 double dx = dlon * 60;
4689 double manhat = abs(dy) + abs(dx);
4693 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4695 selected_rules.push_back(top);
4712 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4713 ret_ptr->Append(selected_rules[i]);
4719ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4720 float select_radius,
4722 int selection_mask) {
4723 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4724 std::vector<ObjRazRules *> selected_rules;
4726 PrepareForRender(VPoint, ps52plib);
4732 for (
int i = 0; i < PRIO_NUM; ++i) {
4733 if (selection_mask & MASK_POINT) {
4736 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4737 top = razRules[i][point_type];
4739 while (top != NULL) {
4740 if (top->obj->npt ==
4743 if (ps52plib->ObjectRenderCheck(top)) {
4744 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4745 selected_rules.push_back(top);
4752 ObjRazRules *child_item = top->child;
4753 while (child_item != NULL) {
4754 if (ps52plib->ObjectRenderCheck(child_item)) {
4755 if (DoesLatLonSelectObject(lat, lon, select_radius,
4757 selected_rules.push_back(child_item);
4760 child_item = child_item->next;
4768 if (selection_mask & MASK_AREA) {
4771 int area_boundary_type =
4772 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4773 top = razRules[i][area_boundary_type];
4774 while (top != NULL) {
4775 if (ps52plib->ObjectRenderCheck(top)) {
4776 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4777 selected_rules.push_back(top);
4784 if (selection_mask & MASK_LINE) {
4786 top = razRules[i][2];
4788 while (top != NULL) {
4789 if (ps52plib->ObjectRenderCheck(top)) {
4790 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4791 selected_rules.push_back(top);
4802 auto sortObjs = [lat, lon,
this](
const ObjRazRules *obj1,
4803 const ObjRazRules *obj2) ->
bool {
4804 double br1, dd1, br2, dd2;
4806 if (obj1->obj->Primitive_type == GEO_POINT &&
4807 obj2->obj->Primitive_type == GEO_POINT) {
4808 double lat1, lat2, lon1, lon2;
4809 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4810 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin, ref_lat,
4811 ref_lon, &lat1, &lon1);
4813 if (lon1 > 180.0) lon1 -= 360.;
4815 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4816 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin, ref_lat,
4817 ref_lon, &lat2, &lon2);
4819 if (lon2 > 180.0) lon2 -= 360.;
4821 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4822 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4829 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4833 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4834 ret_ptr->Append(selected_rules[i]);
4840bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4842 switch (obj->Primitive_type) {
4846 if (!obj->BBObj.GetValid())
return false;
4848 if (1 == obj->npt) {
4853 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4855 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4858 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4859 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4866 sbox.Set(olat, olon, olat, olon);
4868 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4869 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4874 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4881 if (!obj->BBObj.GetValid())
return false;
4884 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4886 double *pdl = obj->geoPtMulti;
4887 for (
int ip = 0; ip < obj->npt; ip++) {
4888 double lon_point = *pdl++;
4889 double lat_point = *pdl++;
4891 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4892 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4903 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4906 return IsPointInObjArea(lat, lon, select_radius, obj);
4911 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4913 float sel_rad_meters = select_radius * 1852 * 60;
4914 double easting, northing;
4915 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4922 pt *ppt = obj->geoPt;
4925 double xr = obj->x_rate;
4926 double xo = obj->x_origin;
4927 double yr = obj->y_rate;
4928 double yo = obj->y_origin;
4930 double north0 = (ppt->y * yr) + yo;
4931 double east0 = (ppt->x * xr) + xo;
4934 for (
int ip = 1; ip < npt; ip++) {
4935 double north = (ppt->y * yr) + yo;
4936 double east = (ppt->x * xr) + xo;
4939 if (northing >= (fmin(north, north0) - sel_rad_meters))
4940 if (northing <= (fmax(north, north0) + sel_rad_meters))
4941 if (easting >= (fmin(east, east0) - sel_rad_meters))
4942 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4952 if (obj->m_ls_list) {
4954 unsigned char *vbo_point =
4955 (
unsigned char *)obj->m_chart_context
4957 line_segment_element *ls = obj->m_ls_list;
4959 while (ls && vbo_point) {
4961 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4962 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4963 nPoints = ls->pedge->nCount;
4965 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4969 float north0 = ppt[1];
4970 float east0 = ppt[0];
4974 for (
int ip = 0; ip < nPoints - 1; ip++) {
4975 float north = ppt[1];
4976 float east = ppt[0];
4978 if (northing >= (fmin(north, north0) - sel_rad_meters))
4979 if (northing <= (fmax(north, north0) + sel_rad_meters))
4980 if (easting >= (fmin(east, east0) - sel_rad_meters))
4981 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
5008wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
5009 wxString ret_val =
"";
5012 const char *att_code;
5014 wxString file(g_csv_locn);
5015 file.Append(
"/s57attributes.csv");
5017 if (!wxFileName::FileExists(file)) {
5018 wxString msg(
" Could not open ");
5025 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5027 CC_ExactString,
"Code");
5033 wxString ei_file(g_csv_locn);
5034 ei_file.Append(
"/s57expectedinput.csv");
5036 if (!wxFileName::FileExists(ei_file)) {
5037 wxString msg(
" Could not open ");
5038 msg.Append(ei_file);
5044 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5045 CSVIngest(ei_file.mb_str());
5047 char **papszFields = NULL;
5048 int bSelected = FALSE;
5054 while (!bSelected && iline + 1 < psTable->nLineCount) {
5056 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5058 if (!strcmp(papszFields[0], att_code)) {
5059 if (atoi(papszFields[1]) == ival) {
5060 ret_val = wxString(papszFields[2], wxConvUTF8);
5065 CSLDestroy(papszFields);
5073bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5077 if (obj->pPolyTessGeo) {
5078 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5080 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5082 TriPrim *pTP = ppg->tri_prim_head;
5084 MyPoint pvert_list[3];
5088 double easting, northing;
5089 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5093 if (!ppg->m_bSMSENC) {
5094 double y_rate = obj->y_rate;
5095 double y_origin = obj->y_origin;
5096 double x_rate = obj->x_rate;
5097 double x_origin = obj->x_origin;
5099 double northing_scaled = (northing - y_origin) / y_rate;
5100 double easting_scaled = (easting - x_origin) / x_rate;
5101 northing = northing_scaled;
5102 easting = easting_scaled;
5107 if (pTP->tri_box.Contains(lat, lon)) {
5108 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5109 double *p_vertex = pTP->p_vertex;
5111 switch (pTP->type) {
5112 case PTG_TRIANGLE_FAN: {
5113 for (
int it = 0; it < pTP->nVert - 2; it++) {
5114 pvert_list[0].x = p_vertex[0];
5115 pvert_list[0].y = p_vertex[1];
5117 pvert_list[1].x = p_vertex[(it * 2) + 2];
5118 pvert_list[1].y = p_vertex[(it * 2) + 3];
5120 pvert_list[2].x = p_vertex[(it * 2) + 4];
5121 pvert_list[2].y = p_vertex[(it * 2) + 5];
5123 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5131 case PTG_TRIANGLE_STRIP: {
5132 for (
int it = 0; it < pTP->nVert - 2; it++) {
5133 pvert_list[0].x = p_vertex[(it * 2)];
5134 pvert_list[0].y = p_vertex[(it * 2) + 1];
5136 pvert_list[1].x = p_vertex[(it * 2) + 2];
5137 pvert_list[1].y = p_vertex[(it * 2) + 3];
5139 pvert_list[2].x = p_vertex[(it * 2) + 4];
5140 pvert_list[2].y = p_vertex[(it * 2) + 5];
5142 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5150 case PTG_TRIANGLES: {
5151 for (
int it = 0; it < pTP->nVert; it += 3) {
5152 pvert_list[0].x = p_vertex[(it * 2)];
5153 pvert_list[0].y = p_vertex[(it * 2) + 1];
5155 pvert_list[1].x = p_vertex[(it * 2) + 2];
5156 pvert_list[1].y = p_vertex[(it * 2) + 3];
5158 pvert_list[2].x = p_vertex[(it * 2) + 4];
5159 pvert_list[2].y = p_vertex[(it * 2) + 5];
5161 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5170 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5171 float *p_vertex = (
float *)pTP->p_vertex;
5173 switch (pTP->type) {
5174 case PTG_TRIANGLE_FAN: {
5175 for (
int it = 0; it < pTP->nVert - 2; it++) {
5176 pvert_list[0].x = p_vertex[0];
5177 pvert_list[0].y = p_vertex[1];
5179 pvert_list[1].x = p_vertex[(it * 2) + 2];
5180 pvert_list[1].y = p_vertex[(it * 2) + 3];
5182 pvert_list[2].x = p_vertex[(it * 2) + 4];
5183 pvert_list[2].y = p_vertex[(it * 2) + 5];
5185 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5193 case PTG_TRIANGLE_STRIP: {
5194 for (
int it = 0; it < pTP->nVert - 2; it++) {
5195 pvert_list[0].x = p_vertex[(it * 2)];
5196 pvert_list[0].y = p_vertex[(it * 2) + 1];
5198 pvert_list[1].x = p_vertex[(it * 2) + 2];
5199 pvert_list[1].y = p_vertex[(it * 2) + 3];
5201 pvert_list[2].x = p_vertex[(it * 2) + 4];
5202 pvert_list[2].y = p_vertex[(it * 2) + 5];
5204 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5212 case PTG_TRIANGLES: {
5213 for (
int it = 0; it < pTP->nVert; it += 3) {
5214 pvert_list[0].x = p_vertex[(it * 2)];
5215 pvert_list[0].y = p_vertex[(it * 2) + 1];
5217 pvert_list[1].x = p_vertex[(it * 2) + 2];
5218 pvert_list[1].y = p_vertex[(it * 2) + 3];
5220 pvert_list[2].x = p_vertex[(it * 2) + 4];
5221 pvert_list[2].y = p_vertex[(it * 2) + 5];
5223 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5246wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5247 wxString curAttrName) {
5251 pval = obj->attVal->Item(iatt);
5252 switch (pval->valType) {
5255 wxString val_str((
char *)(pval->value), wxConvUTF8);
5257 if (val_str.ToLong(&ival)) {
5261 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5262 if (!decode_val.IsEmpty()) {
5265 iv.Printf(
" (%d)", (
int)ival);
5268 value.Printf(
"%d", (
int)ival);
5272 else if (val_str.IsEmpty())
5277 wxString value_increment;
5278 wxStringTokenizer tk(val_str,
",");
5280 if (tk.HasMoreTokens()) {
5281 while (tk.HasMoreTokens()) {
5282 wxString token = tk.GetNextToken();
5284 if (token.ToLong(&ival)) {
5285 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5287 value_increment.Printf(
" (%d)", (
int)ival);
5289 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5291 if (iv) value_increment.Prepend(
", ");
5292 value.Append(value_increment);
5295 if (iv) value.Append(
",");
5296 value.Append(token);
5302 value.Append(val_str);
5305 value =
"[NULL VALUE]";
5311 int ival = *((
int *)pval->value);
5312 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5314 if (!decode_val.IsEmpty()) {
5317 iv.Printf(
"(%d)", ival);
5320 value.Printf(
"(%d)", ival);
5328 double dval = *((
double *)pval->value);
5329 wxString val_suffix =
" m";
5330 bool has_preformatted =
false;
5331 wxString preformatted;
5342 if ((curAttrName ==
"VERCLR") || (curAttrName ==
"VERCCL") ||
5343 (curAttrName ==
"VERCOP") || (curAttrName ==
"HEIGHT") ||
5344 (curAttrName ==
"ELEVAT") || (curAttrName ==
"VERCSA")) {
5349 val_suffix = wxString::Format(
" %s",
unit.c_str());
5350 }
else if (curAttrName ==
"HORCLR") {
5353 double nm = dval / 1852.0;
5355 has_preformatted =
true;
5358 else if ((curAttrName ==
"VALSOU") || (curAttrName ==
"DRVAL1") ||
5359 (curAttrName ==
"DRVAL2") || (curAttrName ==
"VALDCO")) {
5366 wxString
unit = getUsrDepthUnit(-1);
5367 val_suffix = wxString::Format(
" %s",
unit.c_str());
5370 else if (curAttrName ==
"SECTR1")
5371 val_suffix =
"°";
5372 else if (curAttrName ==
"SECTR2")
5373 val_suffix =
"°";
5374 else if (curAttrName ==
"ORIENT")
5375 val_suffix =
"°";
5376 else if (curAttrName ==
"VALNMR")
5378 else if (curAttrName ==
"SIGPER")
5380 else if (curAttrName ==
"VALACM")
5381 val_suffix =
" Minutes/year";
5382 else if (curAttrName ==
"VALMAG")
5383 val_suffix =
"°";
5384 else if (curAttrName ==
"CURVEL")
5387 if (has_preformatted) {
5388 value = preformatted;
5390 if (dval - floor(dval) < 0.01)
5391 value.Printf(
"%2.0f", dval);
5393 value.Printf(
"%4.1f", dval);
5394 value << val_suffix;
5400 case OGR_REAL_LST: {
5407wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5408 wxString AttrName) {
5409 if (NULL == pAttrVal)
return "";
5412 switch (pAttrVal->valType) {
5414 if (pAttrVal->value) {
5415 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5417 if (val_str.ToLong(&ival)) {
5421 wxString decode_val = GetAttributeDecode(AttrName, ival);
5422 if (!decode_val.IsEmpty()) {
5425 iv.Printf(
"(%d)", (
int)ival);
5428 value.Printf(
"%d", (
int)ival);
5432 else if (val_str.IsEmpty())
5437 wxString value_increment;
5438 wxStringTokenizer tk(val_str,
",");
5440 while (tk.HasMoreTokens()) {
5441 wxString token = tk.GetNextToken();
5443 if (token.ToLong(&ival)) {
5444 wxString decode_val = GetAttributeDecode(AttrName, ival);
5445 if (!decode_val.IsEmpty())
5446 value_increment = decode_val;
5448 value_increment.Printf(
" %d", (
int)ival);
5450 if (iv) value_increment.Prepend(
", ");
5452 value.Append(value_increment);
5456 value.Append(val_str);
5459 value =
"[NULL VALUE]";
5465 int ival = *((
int *)pAttrVal->value);
5466 wxString decode_val = GetAttributeDecode(AttrName, ival);
5468 if (!decode_val.IsEmpty()) {
5471 iv.Printf(
"(%d)", ival);
5474 value.Printf(
"(%d)", ival);
5482 double dval = *((
double *)pAttrVal->value);
5483 wxString val_suffix =
" m";
5484 bool has_preformatted =
false;
5485 wxString preformatted;
5488 if ((AttrName ==
"VERCLR") || (AttrName ==
"VERCCL") ||
5489 (AttrName ==
"VERCOP") || (AttrName ==
"HEIGHT") ||
5490 (AttrName ==
"ELEVAT")) {
5495 val_suffix = wxString::Format(
" %s",
unit.c_str());
5496 }
else if (AttrName ==
"HORCLR") {
5498 double nm = dval / 1852.0;
5500 has_preformatted =
true;
5503 else if ((AttrName ==
"VALSOU") || (AttrName ==
"DRVAL1") ||
5504 (AttrName ==
"DRVAL2")) {
5507 wxString
unit = getUsrDepthUnit(-1);
5508 val_suffix = wxString::Format(
" %s",
unit.c_str());
5511 else if (AttrName ==
"SECTR1")
5512 val_suffix =
"°";
5513 else if (AttrName ==
"SECTR2")
5514 val_suffix =
"°";
5515 else if (AttrName ==
"ORIENT")
5516 val_suffix =
"°";
5517 else if (AttrName ==
"VALNMR")
5519 else if (AttrName ==
"SIGPER")
5521 else if (AttrName ==
"VALACM")
5522 val_suffix =
" Minutes/year";
5523 else if (AttrName ==
"VALMAG")
5524 val_suffix =
"°";
5525 else if (AttrName ==
"CURVEL")
5528 if (has_preformatted) {
5529 value = preformatted;
5531 if (dval - floor(dval) < 0.01)
5532 value.Printf(
"%2.0f", dval);
5534 value.Printf(
"%4.1f", dval);
5535 value << val_suffix;
5541 case OGR_REAL_LST: {
5549 int positionDiff = l1->position.Cmp(l2->position);
5550 if (positionDiff < 0)
return false;
5552 int attrIndex1 = l1->attributeNames.Index(
"SECTR1");
5553 int attrIndex2 = l2->attributeNames.Index(
"SECTR1");
5556 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5557 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5558 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5560 double angle1, angle2;
5561 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5562 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5564 return angle1 < angle2;
5567static const char *type2str(GeoPrim_t type) {
5568 const char *r =
"Unknown";
5589wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5592 wxString curAttrName, value;
5593 bool isLight =
false;
5596 wxString classAttributes;
5598 wxString lightsHtml;
5599 wxString positionString;
5600 std::vector<S57Light *> lights;
5604 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5605 node = node->GetPrevious()) {
5606 ObjRazRules *current = node->GetData();
5607 positionString.Clear();
5611 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5613 if (current->obj->Primitive_type == GEO_META)
continue;
5614 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5616 className = wxString(current->obj->FeatureName, wxConvUTF8);
5619 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5624 const char *name_desc;
5625 if (g_csv_locn.Len()) {
5626 wxString oc_file(g_csv_locn);
5627 oc_file.Append(
"/s57objectclasses.csv");
5628 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5629 current->obj->FeatureName,
5630 CC_ExactString,
"ObjectClass");
5636 if (0 == strlen(name_desc)) {
5637 name_desc = current->obj->FeatureName;
5638 classDesc = wxString(name_desc, wxConvUTF8, 1);
5639 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5641 classDesc = wxString(name_desc, wxConvUTF8);
5648 classAttributes =
"";
5649 index.Printf(
"Feature Index: %d<br>", current->obj->Index);
5650 classAttributes << index;
5653 LUPstring.Printf(
"LUP RCID: %d<br>", current->LUP->RCID);
5654 classAttributes << LUPstring;
5657 LLBBox bbox = current->obj->BBObj;
5658 Bbox.Printf(
"Lat/Lon box: %g %g %g %g<br>", bbox.GetMinLat(),
5659 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5660 classAttributes << Bbox;
5663 Type.Printf(
" Type: %s<br>", type2str(current->obj->Primitive_type));
5664 classAttributes << Type;
5666 LUPstring =
" LUP ATTC: ";
5667 if (current->LUP->ATTArray.size())
5668 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5669 LUPstring +=
"<br>";
5670 classAttributes << LUPstring;
5672 LUPstring =
" LUP INST: ";
5673 LUPstring += current->LUP->INST;
5674 LUPstring +=
"<br><br>";
5675 classAttributes << LUPstring;
5678 if (GEO_POINT == current->obj->Primitive_type) {
5680 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5681 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5682 ref_lat, ref_lon, &lat, &lon);
5684 if (lon > 180.0) lon -= 360.;
5686 positionString.Clear();
5687 positionString += toSDMM(1, lat);
5688 positionString <<
" ";
5689 positionString += toSDMM(2, lon);
5693 curLight->position = positionString;
5694 curLight->hasSectors =
false;
5695 lights.push_back(curLight);
5701 if (current->obj->att_array) {
5702 char *curr_att = current->obj->att_array;
5708 attribStr <<
"<table border=0 cellspacing=0 cellpadding=0>";
5711 ret_val <<
"<p>" << classAttributes;
5714 bool inDepthRange =
false;
5716 while (attrCounter < current->obj->n_attr) {
5718 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5725 assert(curLight !=
nullptr);
5726 curLight->attributeNames.Add(curAttrName);
5727 if (curAttrName.StartsWith(
"SECTR")) curLight->hasSectors =
true;
5729 if (curAttrName ==
"DRVAL1") {
5730 attribStr <<
"<tr><td><font size=-1>";
5731 inDepthRange =
true;
5732 }
else if (curAttrName ==
"DRVAL2") {
5734 inDepthRange =
false;
5737 attribStr <<
"</font></td></tr>\n";
5738 inDepthRange =
false;
5740 attribStr <<
"<tr><td valign=top><font size=-2>";
5741 if (curAttrName ==
"catgeo")
5742 attribStr <<
"CATGEO";
5744 attribStr << curAttrName;
5745 attribStr <<
"</font></td><td> </td><td "
5746 "valign=top><font size=-1>";
5757 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5762 wxString AttrNamesFiles =
5763 "PICREP,TXTDSC,NTXTDS";
5765 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5766 if (value.Find(
".XML") == wxNOT_FOUND) {
5767 file.Assign(GetFullPath());
5768 file.Assign(file.GetPath(), value);
5771 if (file.IsCaseSensitive()) {
5772 wxDir dir(file.GetPath());
5774 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
5776 if (filename.IsSameAs(value,
false)) {
5778 file.Assign(file.GetPath(), value);
5781 cont = dir.GetNext(&filename);
5788 wxString::Format(
"<a href=\"%s\">%s</a>",
5789 file.GetFullPath(), file.GetFullName());
5791 value = value +
" <font color=\"red\">[ " +
5792 _(
"this file is not available") +
" ]</font>";
5796 "DATEND,DATSTA,PEREND,PERSTA";
5797 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5800 wxString ts = value;
5804 if (ts.Length() < 5) {
5808 if (ts.Length() < 7) {
5812 wxString::const_iterator end;
5814 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5816 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5817 if (d) ts.Append(wxString::Format(
" %d", dt.GetDay()));
5818 if (dt.GetYear() > 0)
5819 ts.Append(wxString::Format(
", %i", dt.GetYear()));
5820 if (curAttrName ==
"PEREND")
5821 ts = _(
"Period ends: ") + ts +
" (" + value +
")";
5822 if (curAttrName ==
"PERSTA")
5823 ts = _(
"Period starts: ") + ts +
" (" + value +
")";
5824 if (curAttrName ==
"DATEND")
5825 ts = _(
"Date ending: ") + ts +
" (" + value +
")";
5826 if (curAttrName ==
"DATSTA")
5827 ts = _(
"Date starting: ") + ts +
" (" + value +
")";
5831 if (curAttrName ==
"TS_TSP") {
5838 wxStringTokenizer tk(value,
",");
5843 ts1 = tk.GetNextToken().Trim(
false);
5846 }
while ((ts1.Left(2).ToLong(&l)));
5847 ts =
"Tidal Streams referred to<br><b>";
5848 ts.Append(tk.GetNextToken()).Append(
"</b> at <b>").Append(ts1);
5849 ts.Append(
"</b><br><table >");
5851 while (tk.HasMoreTokens()) {
5852 ts.Append(
"<tr><td>");
5853 wxString s1(wxString::Format(
"%+dh ", i));
5855 ts.Append(
"</td><td>");
5856 s1 = tk.GetNextToken();
5858 s1 =
"°</td><td>";
5860 s1 = tk.GetNextToken();
5863 ts.Append(
"</td></tr>");
5866 ts.Append(
"</table>");
5871 assert(curLight !=
nullptr);
5872 curLight->attributeValues.Add(value);
5874 if (curAttrName ==
"INFORM" || curAttrName ==
"NINFOM")
5875 value.Replace(
"|",
"<br>");
5877 if (curAttrName ==
"catgeo")
5878 attribStr << type2str(current->obj->Primitive_type);
5882 if (!(curAttrName ==
"DRVAL1")) {
5883 attribStr <<
"</font></td></tr>\n";
5893 attribStr <<
"</table>\n";
5895 objText +=
"<b>" + classDesc +
"</b> <font size=-2>(" + className +
5896 ")</font>" +
"<br>";
5898 if (positionString.Length())
5899 objText <<
"<font size=-2>" << positionString <<
"</font><br>\n";
5901 if (noAttr > 0) objText << attribStr;
5903 if (node != rule_list->GetFirst()) objText +=
"<hr noshade>";
5910 if (!lights.empty()) {
5911 assert(curLight !=
nullptr);
5916 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5920 for (
auto const &thisLight : lights) {
5923 if (thisLight->position != lastPos) {
5924 lastPos = thisLight->position;
5926 if (thisLight != *lights.begin())
5927 lightsHtml <<
"</table>\n<hr noshade>\n";
5929 lightsHtml <<
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>";
5930 lightsHtml <<
"<font size=-2>" << thisLight->position
5933 if (curLight->hasSectors)
5935 "<font size=-2>(Sector angles are True Bearings from "
5936 "Seaward)</font><br>");
5938 lightsHtml <<
"<table>";
5941 lightsHtml <<
"<tr>";
5942 lightsHtml <<
"<td><font size=-1>";
5945 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
5946 if (attrIndex != wxNOT_FOUND) {
5947 wxString color = thisLight->attributeValues.Item(attrIndex);
5948 if (color ==
"red (3)" || color ==
"red(3)")
5950 "<table border=0><tr><td "
5951 "bgcolor=red> </td></tr></table> ";
5952 else if (color ==
"green (4)" || color ==
"green(4)")
5954 "<table border=0><tr><td "
5955 "bgcolor=green> </td></tr></table> ";
5956 else if (color ==
"white (1)" || color ==
"white(1)")
5958 "<table border=0><tr><td "
5959 "bgcolor=white> </td></tr></table> ";
5960 else if (color ==
"yellow (6)" || color ==
"yellow(6)")
5962 "<table border=0><tr><td "
5963 "bgcolor=yellow> </td></tr></table> ";
5964 else if (color ==
"blue (5)" || color ==
"blue(5)")
5966 "<table border=0><tr><td "
5967 "bgcolor=blue> </td></tr></table> ";
5968 else if (color ==
"magenta (12)" || color ==
"magenta(12)")
5970 "<table border=0><tr><td "
5971 "bgcolor=magenta> </td></tr></table> ";
5974 "<table border=0><tr><td "
5975 "bgcolor=grey> ? </td></tr></table> ";
5978 int visIndex = thisLight->attributeNames.Index(
"LITVIS");
5979 if (visIndex != wxNOT_FOUND) {
5980 wxString vis = thisLight->attributeValues.Item(visIndex);
5981 if (vis.Contains(
"8")) {
5982 if (attrIndex != wxNOT_FOUND) {
5983 wxString color = thisLight->attributeValues.Item(attrIndex);
5984 if ((color ==
"red (3)" || color ==
"red(3)"))
5986 "<table border=0><tr><td "
5987 "bgcolor=DarkRed> </td></tr></table> ";
5988 if ((color ==
"green (4)" || color ==
"green(4)"))
5990 "<table border=0><tr><td "
5991 "bgcolor=DarkGreen> </td></tr></table> ";
5992 if ((color ==
"white (1)" || color ==
"white(1)"))
5994 "<table border=0><tr><td "
5995 "bgcolor=GoldenRod> </td></tr></table> ";
6000 lightsHtml << colorStr;
6002 lightsHtml <<
"</font></td><td><font size=-1><nobr><b>";
6004 attrIndex = thisLight->attributeNames.Index(
"LITCHR");
6005 if (attrIndex != wxNOT_FOUND) {
6006 wxString character = thisLight->attributeValues[attrIndex];
6007 lightsHtml << character.BeforeFirst(wxChar(
'(')) <<
" ";
6010 attrIndex = thisLight->attributeNames.Index(
"SIGGRP");
6011 if (attrIndex != wxNOT_FOUND) {
6012 lightsHtml << thisLight->attributeValues[attrIndex];
6016 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
6017 if (attrIndex != wxNOT_FOUND) {
6019 << thisLight->attributeValues.Item(attrIndex).Upper()[0];
6023 attrIndex = thisLight->attributeNames.Index(
"SIGPER");
6024 if (attrIndex != wxNOT_FOUND) {
6025 lightsHtml << thisLight->attributeValues[attrIndex];
6029 attrIndex = thisLight->attributeNames.Index(
"HEIGHT");
6030 if (attrIndex != wxNOT_FOUND) {
6031 lightsHtml << thisLight->attributeValues[attrIndex];
6035 attrIndex = thisLight->attributeNames.Index(
"VALNMR");
6036 if (attrIndex != wxNOT_FOUND) {
6037 lightsHtml << thisLight->attributeValues[attrIndex];
6041 lightsHtml <<
"</b>";
6043 attrIndex = thisLight->attributeNames.Index(
"SECTR1");
6044 if (attrIndex != wxNOT_FOUND) {
6045 lightsHtml <<
"(" << thisLight->attributeValues[attrIndex];
6046 lightsHtml <<
" - ";
6047 attrIndex = thisLight->attributeNames.Index(
"SECTR2");
6048 lightsHtml << thisLight->attributeValues[attrIndex] <<
") ";
6051 lightsHtml <<
"</nobr>";
6053 attrIndex = thisLight->attributeNames.Index(
"CATLIT");
6054 if (attrIndex != wxNOT_FOUND) {
6055 lightsHtml <<
"<nobr>";
6056 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6058 lightsHtml <<
"</nobr> ";
6061 attrIndex = thisLight->attributeNames.Index(
"EXCLIT");
6062 if (attrIndex != wxNOT_FOUND) {
6063 lightsHtml <<
"<nobr>";
6064 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6066 lightsHtml <<
"</nobr> ";
6069 attrIndex = thisLight->attributeNames.Index(
"OBJNAM");
6070 if (attrIndex != wxNOT_FOUND) {
6071 lightsHtml <<
"<br><nobr>";
6072 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6073 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6074 lightsHtml <<
"</nobr> ";
6077 lightsHtml <<
"</font></td>";
6078 lightsHtml <<
"</tr>";
6080 thisLight->attributeNames.Clear();
6081 thisLight->attributeValues.Clear();
6084 lightsHtml <<
"</table><hr noshade>\n";
6085 ret_val = lightsHtml << ret_val;
6099bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6100 if (NULL == g_poRegistrar) {
6101 wxLogMessage(
" Error: No ClassRegistrar in InitENCMinimal.");
6105 m_pENCDS =
new OGRS57DataSource;
6107 m_pENCDS->SetS57Registrar(g_poRegistrar);
6109 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6112 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6113 pENCReader->SetClassBased(g_poRegistrar);
6115 int rc = pENCReader->Ingest();
6119OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6121 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6123 if ((NULL != pENCReader) && (NULL != g_poRegistrar)) {
6125 g_poRegistrar->SelectClass(
"M_COVR");
6132 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefnM_COVR(302);
6135 pENCReader->AddFeatureDefn(poDefn);
6138 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6141 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6144 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6155OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6159 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6162 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6165 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6168 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6177int s57chart::GetENCScale() {
6178 if (NULL == m_pENCDS)
return 0;
6185 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6188 return pENCReader->GetCSCL();
6198static void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6199 const char *pszErrorMsg) {
6200#define ERR_BUF_LEN 2000
6202 char buf[ERR_BUF_LEN + 1];
6204 if (eErrClass == CE_Debug)
6205 sprintf(buf,
" %s", pszErrorMsg);
6206 else if (eErrClass == CE_Warning)
6207 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6209 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6211 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6212 wxString msg(buf, wxConvUTF8);
6218 if (eErrClass == CE_Fatal) {
6219 longjmp(env_ogrf, 1);
6230const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6231 const char *pszKeyFieldValue,
6232 CSVCompareCriteria eCriteria,
6233 const char *pszTargetField)
6242 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6243 pszKeyFieldValue, eCriteria);
6245 if (papszRecord == NULL)
return "";
6250 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6251 if (iTargetField < 0)
return "";
6253 if (iTargetField >= CSLCount(papszRecord))
return "";
6255 return (papszRecord[iTargetField]);
6269static bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6293 std::vector<s57Sector_t> §orlegs) {
6294 float rangeScale = 0.0;
6296 if (sectorlegs.size() > 0) {
6297 std::vector<int> sectorangles;
6298 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6299 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6302 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6303 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6308 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6309 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6315 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6318 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6319 powf((
float)(lightPos.y - end1.y), 2));
6321 if (rangeScale == 0.0) {
6324 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6328 rangePx = rangePx * rangeScale;
6330 int penWidth = rangePx / 8;
6331 penWidth = wxMin(20, penWidth);
6332 penWidth = wxMax(5, penWidth);
6335 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
6336 penWidth, wxPENSTYLE_SOLID);
6337 arcpen->SetCap(wxCAP_BUTT);
6340 float angle1, angle2;
6341 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6342 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6343 if (angle1 > angle2) {
6346 int lpx = lightPos.x;
6347 int lpy = lightPos.y;
6349 wxPoint arcpoints[150];
6352 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6356 int narc = (angle2 - angle1) / step;
6358 step = (angle2 - angle1) / (
float)narc;
6360 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6361 wxPoint yellowCone[3];
6362 yellowCone[0] = lightPos;
6363 yellowCone[1] = end1;
6364 yellowCone[2] = end2;
6365 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6368 wxColor c = sectorlegs[i].color;
6369 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6370 dc.SetBrush(wxBrush(c));
6371 dc.StrokePolygon(3, yellowCone, 0, 0);
6374 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6375 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6376 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6377 arcpoints[npoints].x = x;
6378 arcpoints[npoints].y = y;
6381 dc.StrokeLines(npoints, arcpoints);
6385 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6391 bool haveAngle1 =
false;
6392 bool haveAngle2 =
false;
6393 int sec1 = (int)sectorlegs[i].sector1;
6394 int sec2 = (int)sectorlegs[i].sector2;
6395 if (sec1 > 360) sec1 -= 360;
6396 if (sec2 > 360) sec2 -= 360;
6398 if ((sec2 == 360) && (sec1 == 0))
6401 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6402 if (sectorangles[j] == sec1) haveAngle1 =
true;
6403 if (sectorangles[j] == sec2) haveAngle2 =
true;
6407 dc.StrokeLine(lightPos, end1);
6408 sectorangles.push_back(sec1);
6412 dc.StrokeLine(lightPos, end2);
6413 sectorangles.push_back(sec2);
6420void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6421 std::vector<s57Sector_t> §orlegs) {
6422 float rangeScale = 0.0;
6424 if (sectorlegs.size() > 0) {
6425 std::vector<int> sectorangles;
6426 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6427 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6430 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6431 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6436 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6437 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6443 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6446 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6447 powf((
float)(lightPos.y - end1.y), 2));
6449 if (rangeScale == 0.0) {
6452 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6456 rangePx = rangePx * rangeScale;
6458 float arcw = rangePx / 10;
6459 arcw = wxMin(20, arcw);
6460 arcw = wxMax(5, arcw);
6464 float angle1, angle2;
6465 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6466 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6467 if (angle1 > angle2) {
6470 int lpx = lightPos.x;
6471 int lpy = lightPos.y;
6473 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6474 wxPoint yellowCone[3];
6475 yellowCone[0] = lightPos;
6476 yellowCone[1] = end1;
6477 yellowCone[2] = end2;
6478 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6481 wxColor c = sectorlegs[i].color;
6482 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6483 dc.SetBrush(wxBrush(c));
6484 dc.StrokePolygon(3, yellowCone, 0, 0);
6488 wxPoint r(lpx, lpy);
6491 float rad = rangePx;
6515 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6518 glBindBuffer(GL_ARRAY_BUFFER, 0);
6519 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6521 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6522 glEnableVertexAttribArray(mPosAttrib);
6526 glGetUniformLocation(shader->programId(),
"circle_radius");
6527 glUniform1f(radiusloc, rad);
6531 glGetUniformLocation(shader->programId(),
"circle_center");
6535 glUniform2fv(centerloc, 1, ctrv);
6538 wxColour colorb = sectorlegs[i].color;
6540 colorv[0] = colorb.Red() / float(256);
6541 colorv[1] = colorb.Green() / float(256);
6542 colorv[2] = colorb.Blue() / float(256);
6543 colorv[3] = colorb.Alpha() / float(256);
6546 glGetUniformLocation(shader->programId(),
"circle_color");
6547 glUniform4fv(colloc, 1, colorv);
6557 glGetUniformLocation(shader->programId(),
"border_color");
6558 glUniform4fv(bcolloc, 1, bcolorv);
6561 GLint borderWidthloc =
6562 glGetUniformLocation(shader->programId(),
"border_width");
6563 glUniform1f(borderWidthloc, 2);
6566 GLint ringWidthloc =
6567 glGetUniformLocation(shader->programId(),
"ring_width");
6568 glUniform1f(ringWidthloc, arcw);
6572 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
6573 if (sr1 > 360.) sr1 -= 360.;
6575 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
6576 if (sr2 > 360.) sr2 -= 360.;
6588 if ((sb < 0) || (se < 0)) {
6594 glGetUniformLocation(shader->programId(),
"sector_1");
6595 glUniform1f(sector1loc, (sb * PI / 180.));
6597 glGetUniformLocation(shader->programId(),
"sector_2");
6598 glUniform1f(sector2loc, (se * PI / 180.));
6603 mat4x4_translate_in_place(I, r.x, r.y, 0);
6606 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6607 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6610 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6614 mat4x4_identity(IM);
6616 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6617 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6619 glDisableVertexAttribArray(mPosAttrib);
6625 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6630 bool haveAngle1 =
false;
6631 bool haveAngle2 =
false;
6632 int sec1 = (int)sectorlegs[i].sector1;
6633 int sec2 = (int)sectorlegs[i].sector2;
6634 if (sec1 > 360) sec1 -= 360;
6635 if (sec2 > 360) sec2 -= 360;
6637 if ((sec2 == 360) && (sec1 == 0))
6640 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6641 if (sectorangles[j] == sec1) haveAngle1 =
true;
6642 if (sectorangles[j] == sec2) haveAngle2 =
true;
6646 dc.StrokeLine(lightPos, end1);
6647 sectorangles.push_back(sec1);
6651 dc.StrokeLine(lightPos, end2);
6652 sectorangles.push_back(sec2);
6660bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6663 ListOfObjRazRules *rule_list,
6664 ListOfPI_S57Obj *pi_rule_list,
6665 std::vector<s57Sector_t> §orlegs) {
6666 bool newSectorsNeedDrawing =
false;
6668 bool bhas_red_green =
false;
6669 bool bleading_attribute =
false;
6672 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6673 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6675 int yOpacity = (float)opacity *
6678 if (target_plugin_chart || Chs57) {
6681 wxPoint2DDouble objPos;
6683 char *curr_att = NULL;
6685 wxArrayOfS57attVal *attValArray = NULL;
6687 ListOfObjRazRules::Node *snode = NULL;
6688 ListOfPI_S57Obj::Node *pnode = NULL;
6690 if (Chs57 && rule_list)
6691 snode = rule_list->GetLast();
6692 else if (target_plugin_chart && pi_rule_list)
6693 pnode = pi_rule_list->GetLast();
6696 wxPoint2DDouble lightPosD(0, 0);
6697 bool is_light =
false;
6701 ObjRazRules *current = snode->GetData();
6702 S57Obj *light = current->obj;
6703 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6704 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6705 curr_att = light->att_array;
6706 n_attr = light->n_attr;
6707 attValArray = light->attVal;
6710 }
else if (target_plugin_chart) {
6714 objPos = wxPoint2DDouble(light->
m_lat, light->
m_lon);
6717 attValArray = light->
attVal;
6727 wxString curAttrName;
6730 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6732 if (is_light && (lightPosD == objPos)) {
6740 bleading_attribute =
false;
6742 while (attrCounter < n_attr) {
6743 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6746 S57attVal *pAttrVal = NULL;
6749 pAttrVal = attValArray->Item(attrCounter);
6750 else if (target_plugin_chart)
6751 pAttrVal = attValArray->Item(attrCounter);
6755 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6757 if (curAttrName ==
"LITVIS") {
6758 if (value.StartsWith(
"obsc")) bviz =
false;
6760 if (curAttrName ==
"SECTR1") value.ToDouble(§r1);
6761 if (curAttrName ==
"SECTR2") value.ToDouble(§r2);
6762 if (curAttrName ==
"VALNMR") value.ToDouble(&valnmr);
6763 if (curAttrName ==
"COLOUR") {
6764 if (value ==
"red(3)") {
6765 color = wxColor(255, 0, 0, opacity);
6766 sector.iswhite =
false;
6767 bhas_red_green =
true;
6770 if (value ==
"green(4)") {
6771 color = wxColor(0, 255, 0, opacity);
6772 sector.iswhite =
false;
6773 bhas_red_green =
true;
6777 if (curAttrName ==
"EXCLIT") {
6778 if (value.Find(
"(3)")) valnmr = 1.0;
6781 if (curAttrName ==
"CATLIT") {
6782 if (value.Upper().StartsWith(
"DIRECT") ||
6783 value.Upper().StartsWith(
"LEAD"))
6784 bleading_attribute =
true;
6791 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6792 if (sectr1 > sectr2) {
6796 sector.pos.m_x = objPos.m_y;
6797 sector.pos.m_y = objPos.m_x;
6800 (valnmr > 0.0) ? valnmr : 2.5;
6801 sector.sector1 = sectr1;
6802 sector.sector2 = sectr2;
6804 if (!color.IsOk()) {
6805 color = wxColor(255, 255, 0, yOpacity);
6806 sector.iswhite =
true;
6808 sector.color = color;
6809 sector.isleading =
false;
6811 if (bleading_attribute) sector.isleading =
true;
6813 bool newsector =
true;
6814 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6815 if (sectorlegs[i].pos == sector.pos &&
6816 sectorlegs[i].sector1 == sector.sector1 &&
6817 sectorlegs[i].sector2 == sector.sector2) {
6823 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6827 if (!bviz) newsector =
false;
6829 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6833 sectorlegs.push_back(sector);
6834 newSectorsNeedDrawing =
true;
6841 snode = snode->GetPrevious();
6842 else if (target_plugin_chart)
6843 pnode = pnode->GetPrevious();
6851 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6852 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6853 if (sectorlegs[i].iswhite && bhas_red_green)
6854 sectorlegs[i].isleading =
true;
6858 return newSectorsNeedDrawing;
6861bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6863 std::vector<s57Sector_t> §orlegs) {
6864 if (!cc)
return false;
6866 static float lastLat, lastLon;
6868 if (!ps52plib)
return false;
6876 if (cc->m_singleChart &&
6877 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6878 target_chart = cc->m_singleChart;
6879 else if (viewport.b_quilt)
6880 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6882 target_chart = NULL;
6885 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6886 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6889 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6892 bool newSectorsNeedDrawing =
false;
6894 if (target_plugin_chart || Chs57) {
6895 ListOfObjRazRules *rule_list = NULL;
6896 ListOfPI_S57Obj *pi_rule_list = NULL;
6903 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6904 else if (target_plugin_chart)
6905 pi_rule_list =
g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6906 target_plugin_chart, lat, lon, viewport);
6908 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6909 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6917 pi_rule_list->Clear();
6918 delete pi_rule_list;
6922 return newSectorsNeedDrawing;
6925bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6927 std::vector<s57Sector_t> §orlegs) {
6928 if (!cc)
return false;
6930 double cursor_lat, cursor_lon;
6931 static float lastLat, lastLon;
6933 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6938 ChartBase *target_chart = cc->GetChartAtCursor();
6940 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6941 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6944 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6949 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6951 lastLat = cursor_lat;
6952 lastLon = cursor_lon;
6953 bool newSectorsNeedDrawing =
false;
6955 if (target_plugin_chart || Chs57) {
6956 ListOfObjRazRules *rule_list = NULL;
6957 ListOfPI_S57Obj *pi_rule_list = NULL;
6963 rule_list = Chs57->GetObjRuleListAtLatLon(
6964 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6965 else if (target_plugin_chart)
6966 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
6967 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6969 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6970 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6978 pi_rule_list->Clear();
6979 delete pi_rule_list;
6983 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.
Abstract gFrame/MyFrame interface.