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"
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());
365 case GLOBAL_COLOR_SCHEME_DAY_HICON:
366 ps52plib->SetPLIBColorScheme(
"DAY_HICON", ChartCtxFactory());
368 case GLOBAL_COLOR_SCHEME_NIGHT_HICON:
369 ps52plib->SetPLIBColorScheme(
"NIGHT_HICON", ChartCtxFactory());
373 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
377 m_global_color_scheme = cs;
379 if (bApplyImmediate) {
385 ClearRenderedTextCache();
388 ChangeThumbColor(cs);
391void s57chart::ChangeThumbColor(ColorScheme cs) {
392 if (0 == m_pDIBThumbDay)
return;
396 case GLOBAL_COLOR_SCHEME_DAY:
397 pThumbData->pDIBThumb = m_pDIBThumbDay;
398 m_pDIBThumbOrphan = m_pDIBThumbDim;
400 case GLOBAL_COLOR_SCHEME_DUSK:
401 case GLOBAL_COLOR_SCHEME_NIGHT: {
402 if (NULL == m_pDIBThumbDim) {
403 wxImage img = m_pDIBThumbDay->ConvertToImage();
405#if wxCHECK_VERSION(2, 8, 0)
406 wxImage gimg = img.ConvertToGreyscale(
416 wxBitmap *pBMP =
new wxBitmap(gimg);
418 m_pDIBThumbDim = pBMP;
419 m_pDIBThumbOrphan = m_pDIBThumbDay;
422 pThumbData->pDIBThumb = m_pDIBThumbDim;
428bool s57chart::GetChartExtent(
Extent *pext) {
430 *pext = m_FullExtent;
436static void free_mps(mps_container *mps) {
437 if (mps == 0)
return;
438 if (ps52plib && mps->cs_rules) {
439 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
440 Rules *rule_chain_top = mps->cs_rules->Item(i);
441 ps52plib->DestroyRulesChain(rule_chain_top);
443 delete mps->cs_rules;
448void s57chart::FreeObjectsAndRules() {
457 for (
int i = 0; i < PRIO_NUM; ++i) {
458 for (
int j = 0; j < LUPNAME_NUM; j++) {
459 top = razRules[i][j];
460 while (top != NULL) {
462 if (0 == top->obj->nRef)
delete top->obj;
465 ObjRazRules *ctop = top->child;
469 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
471 ObjRazRules *cnxx = ctop->next;
486void s57chart::ClearRenderedTextCache() {
488 for (
int i = 0; i < PRIO_NUM; ++i) {
489 for (
int j = 0; j < LUPNAME_NUM; j++) {
490 top = razRules[i][j];
491 while (top != NULL) {
492 if (top->obj->bFText_Added) {
493 top->obj->bFText_Added =
false;
494 delete top->obj->FText;
495 top->obj->FText = NULL;
499 ObjRazRules *ctop = top->child;
501 if (ctop->obj->bFText_Added) {
502 ctop->obj->bFText_Added =
false;
503 delete ctop->obj->FText;
504 ctop->obj->FText = NULL;
516double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
517 bool b_allow_overzoom) {
519 return m_Chart_Scale * 0.125;
523double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
525 return m_Chart_Scale * 4.0;
532void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
534 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
536 r->y = roundint(m_pixy_vp_center -
537 ((north - m_northing_vp_center) * m_view_scale_ppm));
540void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
541 wxPoint *r,
int nPoints) {
542 for (
int i = 0; i < nPoints; i++) {
543 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
545 r[i].y = roundint(m_pixy_vp_center -
546 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
550void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
552 if (vpt->m_projection_type != PROJECTION_MERCATOR)
553 printf(
"s57chart unhandled projection\n");
559 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
560 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
566 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
576void s57chart::SetVPParms(
const ViewPort &vpt) {
582 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
583 &m_northing_vp_center);
585 vp_transform.easting_vp_center = m_easting_vp_center;
586 vp_transform.northing_vp_center = m_northing_vp_center;
590 if (IsCacheValid()) {
593 double prev_easting_c, prev_northing_c;
594 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
597 double easting_c, northing_c;
598 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
606 int dpix_x = (int)round(delta_pix_x);
611 int dpix_y = (int)round(delta_pix_y);
614 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
615 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
618 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
620 vp_proposed.
clon = xlon;
621 vp_proposed.
clat = xlat;
648void s57chart::LoadThumb() {
649 wxFileName fn(m_FullPath);
650 wxString SENCdir = g_SENCPrefix;
652 if (SENCdir.Last() != fn.GetPathSeparator())
653 SENCdir.Append(fn.GetPathSeparator());
655 wxFileName tsfn(SENCdir);
656 tsfn.SetFullName(fn.GetFullName());
658 wxFileName ThumbFileNameLook(tsfn);
659 ThumbFileNameLook.SetExt(
"BMP");
662 if (ThumbFileNameLook.FileExists()) {
665 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
666 m_pDIBThumbDay = pBMP;
667 m_pDIBThumbOrphan = 0;
672ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
675 if (pThumbData->pDIBThumb == 0) {
677 ChangeThumbColor(m_global_color_scheme);
680 UpdateThumbData(lat, lon);
685bool s57chart::UpdateThumbData(
double lat,
double lon) {
689 if (pThumbData->pDIBThumb) {
690 double lat_top = m_FullExtent.NLAT;
691 double lat_bot = m_FullExtent.SLAT;
692 double lon_left = m_FullExtent.WLON;
693 double lon_right = m_FullExtent.ELON;
696 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
698 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
700 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
703 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
704 (int)(east * thumb_view_scale_ppm);
705 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
706 (int)(north * thumb_view_scale_ppm);
713 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
714 pThumbData->ShipX = test_x;
715 pThumbData->ShipY = test_y;
721void s57chart::SetFullExtent(
Extent &ext) {
722 m_FullExtent.NLAT = ext.NLAT;
723 m_FullExtent.SLAT = ext.SLAT;
724 m_FullExtent.WLON = ext.WLON;
725 m_FullExtent.ELON = ext.ELON;
730void s57chart::ForceEdgePriorityEvaluate() { m_bLinePrioritySet =
false; }
732void s57chart::SetLinePriorities() {
733 if (!ps52plib)
return;
738 if (!m_bLinePrioritySet) {
742 for (
int i = 0; i < PRIO_NUM; ++i) {
743 top = razRules[i][2];
744 while (top != NULL) {
745 ObjRazRules *crnt = top;
747 ps52plib->SetLineFeaturePriority(crnt, i);
753 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
758 top = razRules[i][j];
759 while (top != NULL) {
762 ps52plib->SetLineFeaturePriority(crnt, i);
768 for (
int i = 0; i < PRIO_NUM; ++i) {
769 for (
int j = 0; j < LUPNAME_NUM; j++) {
770 ObjRazRules *top = razRules[i][j];
771 while (top != NULL) {
772 S57Obj *obj = top->obj;
775 connector_segment *pcs;
776 line_segment_element *list = obj->m_ls_list;
778 switch (list->ls_type) {
782 if (pedge) list->priority = pedge->max_priority;
787 if (pcs) list->priority = pcs->max_priority_cs;
802 m_bLinePrioritySet =
true;
806void s57chart::SetLinePriorities(
void )
808 if( !ps52plib )
return;
813 if( !m_bLinePrioritySet ) {
817 for(
int i = 0; i < PRIO_NUM; ++i ) {
819 top = razRules[i][2];
820 while( top != NULL ) {
821 ObjRazRules *crnt = top;
823 ps52plib->SetLineFeaturePriority( crnt, i );
828 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
833 top = razRules[i][j];
834 while( top != NULL ) {
837 ps52plib->SetLineFeaturePriority( crnt, i );
845 for(
int i = 0; i < PRIO_NUM; ++i ) {
846 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
847 ObjRazRules *top = razRules[i][j];
848 while( top != NULL ) {
849 S57Obj *obj = top->obj;
852 connector_segment *pcs;
853 line_segment_element *list = obj->m_ls_list;
858 pedge = (VE_Element *)list->private0;
860 list->priority = pedge->max_priority;
864 pcs = (connector_segment *)list->private0;
866 list->priority = pcs->max_priority;
881 m_bLinePrioritySet =
true;
885int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
889 line_segment_element *ls_list = obj->m_ls_list;
891 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
892 nPoints += ls_list->pedge->nCount;
895 ls_list = ls_list->next;
904 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
908 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
909 ls_list = obj->m_ls_list;
911 size_t vbo_offset = 0;
913 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
914 vbo_offset = ls_list->pedge->vbo_offset;
915 count = ls_list->pedge->nCount;
917 vbo_offset = ls_list->pcs->vbo_offset;
921 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
923 ls_list = ls_list->next;
930int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
935 line_segment_element *ls_list = obj->m_ls_list;
937 nPoints += ls_list->n_points;
938 ls_list = ls_list->next;
947 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
951 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
952 ls_list = obj->m_ls_list;
954 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
955 br += ls_list->n_points * 2;
956 ls_list = ls_list->next;
965 float e0, n0, e1, n1;
968void s57chart::AssembleLineGeometry() {
973 for (
const auto &it : m_ve_hash) {
974 VE_Element *pedge = it.second;
976 nPoints += pedge->nCount;
982 std::map<long long, connector_segment *> ce_connector_hash;
983 std::map<long long, connector_segment *> ec_connector_hash;
984 std::map<long long, connector_segment *> cc_connector_hash;
986 std::map<long long, connector_segment *>::iterator csit;
993 std::vector<segment_pair> connector_segment_vector;
994 size_t seg_pair_index = 0;
999 for (
int i = 0; i < PRIO_NUM; ++i) {
1000 for (
int j = 0; j < LUPNAME_NUM; j++) {
1001 ObjRazRules *top = razRules[i][j];
1002 while (top != NULL) {
1003 S57Obj *obj = top->obj;
1005 if ((!obj->m_ls_list) &&
1008 line_segment_element list_top;
1011 line_segment_element *le_current = &list_top;
1013 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1014 if (!obj->m_lsindex_array)
continue;
1016 int seg_index = iseg * 3;
1017 int *index_run = &obj->m_lsindex_array[seg_index];
1020 unsigned int inode = *index_run++;
1023 bool edge_dir =
true;
1024 int venode = *index_run++;
1030 VE_Element *pedge = 0;
1032 if (m_ve_hash.find(venode) != m_ve_hash.end())
1033 pedge = m_ve_hash[venode];
1037 unsigned int enode = *index_run++;
1040 VC_Element *ipnode = 0;
1041 ipnode = m_vc_hash[inode];
1044 VC_Element *epnode = 0;
1045 epnode = m_vc_hash[enode];
1048 if (pedge && pedge->nCount) {
1052 long long key = ((
unsigned long long)inode << 32) + venode;
1054 connector_segment *pcs = NULL;
1055 csit = ce_connector_hash.find(key);
1056 if (csit == ce_connector_hash.end()) {
1058 pcs =
new connector_segment;
1059 ce_connector_hash[key] = pcs;
1063 float *ppt = ipnode->pPoint;
1068 pair.e1 = pedge->pPoints[0];
1069 pair.n1 = pedge->pPoints[1];
1071 int last_point_index = (pedge->nCount - 1) * 2;
1072 pair.e1 = pedge->pPoints[last_point_index];
1073 pair.n1 = pedge->pPoints[last_point_index + 1];
1076 connector_segment_vector.push_back(pair);
1077 pcs->vbo_offset = seg_pair_index;
1084 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1086 pcs->cs_lat_avg = lat;
1087 pcs->cs_lon_avg = lon;
1092 line_segment_element *pls =
new line_segment_element;
1097 pls->ls_type = TYPE_CE;
1099 le_current->next = pls;
1104 if (pedge && pedge->nCount) {
1105 line_segment_element *pls =
new line_segment_element;
1110 pls->ls_type = TYPE_EE;
1111 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1113 le_current->next = pls;
1121 if (pedge && pedge->nCount) {
1122 long long key = ((
unsigned long long)venode << 32) + enode;
1124 connector_segment *pcs = NULL;
1125 csit = ec_connector_hash.find(key);
1126 if (csit == ec_connector_hash.end()) {
1128 pcs =
new connector_segment;
1129 ec_connector_hash[key] = pcs;
1135 pair.e0 = pedge->pPoints[0];
1136 pair.n0 = pedge->pPoints[1];
1138 int last_point_index = (pedge->nCount - 1) * 2;
1139 pair.e0 = pedge->pPoints[last_point_index];
1140 pair.n0 = pedge->pPoints[last_point_index + 1];
1143 float *ppt = epnode->pPoint;
1147 connector_segment_vector.push_back(pair);
1148 pcs->vbo_offset = seg_pair_index;
1155 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1157 pcs->cs_lat_avg = lat;
1158 pcs->cs_lon_avg = lon;
1163 line_segment_element *pls =
new line_segment_element;
1167 pls->ls_type = TYPE_EC;
1169 le_current->next = pls;
1173 long long key = ((
unsigned long long)inode << 32) + enode;
1175 connector_segment *pcs = NULL;
1176 csit = cc_connector_hash.find(key);
1177 if (csit == cc_connector_hash.end()) {
1179 pcs =
new connector_segment;
1180 cc_connector_hash[key] = pcs;
1185 float *ppt = ipnode->pPoint;
1189 ppt = epnode->pPoint;
1193 connector_segment_vector.push_back(pair);
1194 pcs->vbo_offset = seg_pair_index;
1201 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1203 pcs->cs_lat_avg = lat;
1204 pcs->cs_lon_avg = lon;
1209 line_segment_element *pls =
new line_segment_element;
1213 pls->ls_type = TYPE_CC;
1215 le_current->next = pls;
1229 if (obj->m_ls_list == NULL) {
1230 obj->m_n_lsindex = 0;
1234 free(obj->m_lsindex_array);
1235 obj->m_lsindex_array = NULL;
1248 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1250 unsigned char *buffer_offset;
1253 bool grow_buffer =
false;
1255 if (0 == m_vbo_byte_length) {
1256 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1257 m_vbo_byte_length = vbo_byte_length;
1258 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1261 m_line_vertex_buffer = (
float *)realloc(
1262 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1263 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1264 offset = m_vbo_byte_length;
1265 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1269 float *lvr = (
float *)buffer_offset;
1273 for (
const auto &it : m_ve_hash) {
1274 VE_Element *pedge = it.second;
1276 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1277 lvr += pedge->nCount * 2;
1279 pedge->vbo_offset = offset;
1280 offset += pedge->nCount * 2 *
sizeof(float);
1293 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1295 connector_segment *pcs = csit->second;
1296 m_pcs_vector.push_back(pcs);
1298 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1304 pcs->vbo_offset = offset;
1305 offset += 4 *
sizeof(float);
1308 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1310 connector_segment *pcs = csit->second;
1311 m_pcs_vector.push_back(pcs);
1313 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1319 pcs->vbo_offset = offset;
1320 offset += 4 *
sizeof(float);
1323 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1325 connector_segment *pcs = csit->second;
1326 m_pcs_vector.push_back(pcs);
1328 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1334 pcs->vbo_offset = offset;
1335 offset += 4 *
sizeof(float);
1339 connector_segment_vector.clear();
1344 for (
const auto &it : m_ve_hash) {
1345 VE_Element *pedge = it.second;
1347 m_pve_vector.push_back(pedge);
1348 free(pedge->pPoints);
1356 for (
const auto &it : m_vc_hash) {
1357 VC_Element *pcs = it.second;
1358 if (pcs) free(pcs->pPoint);
1364 if (g_b_EnableVBO) {
1366 if (m_LineVBO_name > 0) {
1367 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1368 m_LineVBO_name = -1;
1375void s57chart::BuildLineVBO() {
1377 if (!g_b_EnableVBO)
return;
1379 if (m_LineVBO_name == -1) {
1382 glGenBuffers(1, &vboId);
1385 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1391#ifndef USE_ANDROID_GLES2
1392 glEnableClientState(GL_VERTEX_ARRAY);
1394 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1399 ObjRazRules *top, *crnt;
1400 int vbo_area_size_bytes = 0;
1401 for (
int i = 0; i < PRIO_NUM; ++i) {
1402 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1403 top = razRules[i][4];
1405 top = razRules[i][3];
1407 while (top != NULL) {
1412 PolyTriGroup *ppg_vbo =
1413 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1415 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1422 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes, NULL,
1425 GLenum err = glGetError();
1428 msg.Printf(
"S57 VBO Error 1: %d", err);
1430 printf(
"S57 VBO Error 1: %d", err);
1434 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length,
1435 m_line_vertex_buffer);
1440 msg.Printf(
"S57 VBO Error 2: %d", err);
1442 printf(
"S57 VBO Error 2: %d", err);
1446 int vbo_load_offset = m_vbo_byte_length;
1448 for (
int i = 0; i < PRIO_NUM; ++i) {
1449 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1450 top = razRules[i][4];
1452 top = razRules[i][3];
1454 while (top != NULL) {
1459 PolyTriGroup *ppg_vbo =
1460 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1463 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1464 ppg_vbo->single_buffer_size, ppg_vbo->single_buffer);
1466 crnt->obj->vboAreaOffset = vbo_load_offset;
1467 vbo_load_offset += ppg_vbo->single_buffer_size;
1474 msg.Printf(
"S57 VBO Error 3: %d", err);
1476 printf(
"S57 VBO Error 3: %d", err);
1481#ifndef USE_ANDROID_GLES2
1482 glDisableClientState(GL_VERTEX_ARRAY);
1484 glBindBuffer(GL_ARRAY_BUFFER, 0);
1488 for (
int i = 0; i < PRIO_NUM; ++i) {
1489 for (
int j = 0; j < LUPNAME_NUM; j++) {
1490 ObjRazRules *top = razRules[i][j];
1491 while (top != NULL) {
1492 S57Obj *obj = top->obj;
1493 obj->auxParm2 = vboId;
1499 m_LineVBO_name = vboId;
1500 m_this_chart_context->vboID = vboId;
1519bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1522 const LLRegion &Region) {
1523 if (!m_RAZBuilt)
return false;
1525 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1528bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1531 const LLRegion &Region) {
1532 if (!m_RAZBuilt)
return false;
1534 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1537bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1540 const LLRegion &Region) {
1541 if (!m_RAZBuilt)
return false;
1543 bool b_text = ps52plib->GetShowS57Text();
1544 ps52plib->m_bShowS57Text =
false;
1545 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1546 ps52plib->m_bShowS57Text = b_text;
1551bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1553 if (!m_RAZBuilt)
return false;
1557 if (!ps52plib)
return false;
1560 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1562 glChartCanvas::DisableClipRegion();
1563 DoRenderOnGLText(glc, VPoint);
1569bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1572 const LLRegion &Region,
bool b_overlay) {
1573 if (!m_RAZBuilt)
return false;
1577 if (!ps52plib)
return false;
1579 if (g_bDebugS57) printf(
"\n");
1583 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1585 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1586 m_bLinePrioritySet =
false;
1588 ClearRenderedTextCache();
1590 ResetPointBBoxes(m_last_vp, VPoint);
1593 m_plib_state_hash = ps52plib->GetStateHash();
1597 ResetPointBBoxes(m_last_vp, VPoint);
1601 SetLinePriorities();
1604 ps52plib->ClearTextList();
1612 wxRect upr = upd.GetRect();
1615 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1616 chart_region.Intersect(Region);
1618 if (!chart_region.Empty()) {
1622 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1629 if (CHART_TYPE_CM93 == GetChartType()) {
1633 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1636#ifdef OPT_USE_ANDROID_GLES2
1644 wxRect r = upd.GetRect();
1646 glViewport(r.x, vp->
pix_height - (r.y + r.height), r.width, r.height);
1654 float yp = vp->
pix_height - (r.y + r.height);
1656 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1657 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1660 I[0][0] *= 2.0 / (float)r.width;
1661 I[1][1] *= -2.0 / (float)r.height;
1665 mat4x4_rotate_Z(Q, I, angle);
1667 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1670 ps52plib->SetReducedBBox(cvp.GetBBox());
1671 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1676 DoRenderOnGL(glc, cvp);
1678 glChartCanvas::DisableClipRegion();
1691bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1704 for (i = 0; i < PRIO_NUM; ++i) {
1705 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1706 top = razRules[i][4];
1708 top = razRules[i][3];
1710 while (top != NULL) {
1713 crnt->sm_transform_parms = &vp_transform;
1714 ps52plib->RenderAreaToGL(glc, crnt);
1720 for (i = 0; i < PRIO_NUM; ++i) {
1722 top = razRules[i][4];
1724 top = razRules[i][3];
1726 while (top != NULL) {
1729 crnt->sm_transform_parms = &vp_transform;
1734 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1735 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1736 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1737 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1740 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1747 for (i = 0; i < PRIO_NUM; ++i) {
1748 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1749 top = razRules[i][4];
1751 top = razRules[i][3];
1752 while (top != NULL) {
1755 crnt->sm_transform_parms = &vp_transform;
1756 ps52plib->RenderObjectToGL(glc, crnt);
1761 for (i = 0; i < PRIO_NUM; ++i) {
1762 top = razRules[i][2];
1763 while (top != NULL) {
1766 crnt->sm_transform_parms = &vp_transform;
1767 ps52plib->RenderObjectToGL(glc, crnt);
1773 for (i = 0; i < PRIO_NUM; ++i) {
1774 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1775 top = razRules[i][0];
1777 top = razRules[i][1];
1779 while (top != NULL) {
1782 crnt->sm_transform_parms = &vp_transform;
1783 ps52plib->RenderObjectToGL(glc, crnt);
1793bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1804 for( i = 0; i < PRIO_NUM; ++i ) {
1805 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1806 top = razRules[i][4];
1808 top = razRules[i][3];
1810 while( top != NULL ) {
1813 crnt->sm_transform_parms = &vp_transform;
1820 for (i = 0; i < PRIO_NUM; ++i) {
1821 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1822 top = razRules[i][4];
1824 top = razRules[i][3];
1826 while (top != NULL) {
1829 crnt->sm_transform_parms = &vp_transform;
1830 ps52plib->RenderObjectToGLText(glc, crnt);
1833 top = razRules[i][2];
1834 while (top != NULL) {
1837 crnt->sm_transform_parms = &vp_transform;
1838 ps52plib->RenderObjectToGLText(glc, crnt);
1841 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1842 top = razRules[i][0];
1844 top = razRules[i][1];
1846 while (top != NULL) {
1849 crnt->sm_transform_parms = &vp_transform;
1850 ps52plib->RenderObjectToGLText(glc, crnt);
1859bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1862 if (!m_RAZBuilt)
return false;
1864 bool b_text = ps52plib->GetShowS57Text();
1865 ps52plib->m_bShowS57Text =
false;
1866 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1867 ps52plib->m_bShowS57Text = b_text;
1872bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1875 if (!dc.IsOk())
return false;
1878 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1883 DCRenderText(dc, VPoint);
1886 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1890 while (upd.HaveRects()) {
1891 wxRect rect = upd.GetRect();
1897 temp_vp.
GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1901 temp_vp.
GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1903 if (temp_lon_right < temp_lon_left)
1904 temp_lon_right += 360.;
1906 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1909 wxDCClipper clip(dc, rect);
1910 DCRenderText(dc, temp_vp);
1919bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1921 if (!m_RAZBuilt)
return false;
1923 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1926bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1929 if (!m_RAZBuilt)
return false;
1930 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1933bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1938 bool force_new_view =
false;
1940 if (Region != m_last_Region) force_new_view =
true;
1942 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1944 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1945 m_bLinePrioritySet =
false;
1947 ClearRenderedTextCache();
1949 ResetPointBBoxes(m_last_vp, VPoint);
1954 ResetPointBBoxes(m_last_vp, VPoint);
1957 SetLinePriorities();
1959 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1963 if (VPoint.b_quilt) {
1965 if ((m_pCloneBM->GetWidth() != VPoint.
pix_width) ||
1966 (m_pCloneBM->GetHeight() != VPoint.
pix_height)) {
1971 if (NULL == m_pCloneBM)
1974 wxMemoryDC dc_clone;
1975 dc_clone.SelectObject(*m_pCloneBM);
1977#ifdef ocpnUSE_DIBSECTION
1980 wxMemoryDC memdc, dc_org;
1983 pDIB->SelectIntoDC(dc_org);
1988 while (upd.HaveRects()) {
1989 wxRect rect = upd.GetRect();
1990 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
1995 dc_clone.SelectObject(wxNullBitmap);
1996 dc_org.SelectObject(wxNullBitmap);
2000 wxColour nodat = GetGlobalColor(
"NODTA");
2001 wxColour nodat_sub = nodat;
2003#ifdef ocpnUSE_ocpnBitmap
2004 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
2006 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
2007 m_pCloneBM->SetMask(m_pMask);
2010 dc.SelectObject(*m_pCloneBM);
2012 pDIB->SelectIntoDC(dc);
2014 m_last_Region = Region;
2019bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2024 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2026 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2027 m_bLinePrioritySet =
false;
2029 ClearRenderedTextCache();
2033 SetLinePriorities();
2035 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2037 pDIB->SelectIntoDC(dc);
2044bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2045 RenderTypeEnum option,
bool force_new_view) {
2046 bool bnewview =
false;
2048 bool bNewVP =
false;
2050 bool bReallyNew =
false;
2052 double easting_ul, northing_ul;
2053 double easting_lr, northing_lr;
2054 double prev_easting_ul = 0., prev_northing_ul = 0.;
2056 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2057 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2066 if (m_last_vprect != dest) bReallyNew =
true;
2067 m_last_vprect = dest;
2069 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2071 m_plib_state_hash = ps52plib->GetStateHash();
2082 if (m_last_vp.IsValid()) {
2084 m_easting_vp_center - ((VPoint.
pix_width / 2) / m_view_scale_ppm);
2086 m_northing_vp_center + ((VPoint.
pix_height / 2) / m_view_scale_ppm);
2087 easting_lr = easting_ul + (VPoint.
pix_width / m_view_scale_ppm);
2088 northing_lr = northing_ul - (VPoint.
pix_height / m_view_scale_ppm);
2090 double last_easting_vp_center, last_northing_vp_center;
2091 toSM(m_last_vp.
clat, m_last_vp.
clon, ref_lat, ref_lon,
2092 &last_easting_vp_center, &last_northing_vp_center);
2095 last_easting_vp_center - ((m_last_vp.
pix_width / 2) / m_view_scale_ppm);
2096 prev_northing_ul = last_northing_vp_center +
2097 ((m_last_vp.
pix_height / 2) / m_view_scale_ppm);
2099 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2100 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2102 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2103 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2105 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2106 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2108 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2111 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2120 else if ((rul.x != 0) || (rul.y != 0)) {
2121 if (g_bDebugS57) printf(
"newvp due to rul\n");
2132 if (force_new_view) bNewVP =
true;
2137 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2138 rgn_last.Intersect(rgn_new);
2140 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2142 rgn_last.GetBox(xu, yu, wu, hu);
2159 pDIB->SelectIntoDC(dc_last);
2164 pDIBNew->SelectIntoDC(dc_new);
2168 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2173 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.
pix_width,
2176 dc_new.SelectObject(wxNullBitmap);
2177 dc_last.SelectObject(wxNullBitmap);
2185 pDIB->SelectIntoDC(dc);
2189 rgn_delta.Subtract(rgn_reused);
2192 while (upd.HaveRects()) {
2193 wxRect rect = upd.GetRect();
2198 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2200 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2201 (rect.y / m_view_scale_ppm);
2202 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2203 (rect.x / m_view_scale_ppm);
2204 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2207 double temp_northing_lr =
2208 temp_northing_ul - (rect.height / m_view_scale_ppm);
2209 double temp_easting_lr =
2210 temp_easting_ul + (rect.width / m_view_scale_ppm);
2211 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2214 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2219 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2220 temp_vp.GetBBox().GetLatRange()) *
2222 temp_vp.GetBBox().EnLarge(margin);
2228 DCRenderRect(dc, temp_vp, &rect);
2233 dc.SelectObject(wxNullBitmap);
2242 else if (bNewVP || (NULL == pDIB)) {
2248 pDIB->SelectIntoDC(dc);
2251 ps52plib->ClearTextList();
2253 DCRenderRect(dc, VPoint, &full_rect);
2255 dc.SelectObject(wxNullBitmap);
2266int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2279 render_canvas_parms pb_spec;
2281 pb_spec.depth = BPP;
2282 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2283 pb_spec.lclip = rect->x;
2284 pb_spec.rclip = rect->x + rect->width - 1;
2285 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2286 pb_spec.width = rect->width;
2287 pb_spec.height = rect->height;
2288 pb_spec.x = rect->x;
2289 pb_spec.y = rect->y;
2291#ifdef ocpnUSE_ocpnBitmap
2292 pb_spec.b_revrgb =
true;
2294 pb_spec.b_revrgb =
false;
2298 wxColour color = GetGlobalColor(
"NODTA");
2299 unsigned char r, g, b;
2307 if (pb_spec.depth == 24) {
2308 for (
int i = 0; i < pb_spec.height; i++) {
2309 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2310 for (
int j = 0; j < pb_spec.width; j++) {
2317 int color_int = ((r) << 16) + ((g) << 8) + (b);
2319 for (
int i = 0; i < pb_spec.height; i++) {
2320 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2321 for (
int j = 0; j < pb_spec.width; j++) {
2328 for (i = 0; i < PRIO_NUM; ++i) {
2329 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2330 top = razRules[i][4];
2332 top = razRules[i][3];
2334 while (top != NULL) {
2337 crnt->sm_transform_parms = &vp_transform;
2338 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2343#ifdef ocpnUSE_ocpnBitmap
2344 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2345 pb_spec.height, pb_spec.depth);
2347 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2348 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2349 wxBitmap *pREN =
new wxBitmap(*prender_image);
2355 dc_ren.SelectObject(*pREN);
2358 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2359 (wxDC *)&dc_ren, 0, 0);
2362 dc_ren.SelectObject(wxNullBitmap);
2364#ifdef ocpnUSE_ocpnBitmap
2365 free(pb_spec.pix_buff);
2367 delete prender_image;
2374 DCRenderLPB(dcinput, vp, rect);
2379bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2386 for (i = 0; i < PRIO_NUM; ++i) {
2388 wxDCClipper *pdcc = NULL;
2394 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2395 top = razRules[i][4];
2397 top = razRules[i][3];
2398 while (top != NULL) {
2401 crnt->sm_transform_parms = &vp_transform;
2402 ps52plib->RenderObjectToDC(&dcinput, crnt);
2405 top = razRules[i][2];
2406 while (top != NULL) {
2409 crnt->sm_transform_parms = &vp_transform;
2410 ps52plib->RenderObjectToDC(&dcinput, crnt);
2413 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2414 top = razRules[i][0];
2416 top = razRules[i][1];
2418 while (top != NULL) {
2421 crnt->sm_transform_parms = &vp_transform;
2422 ps52plib->RenderObjectToDC(&dcinput, crnt);
2426 if (pdcc)
delete pdcc;
2439bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2445 for (i = 0; i < PRIO_NUM; ++i) {
2446 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2447 top = razRules[i][4];
2449 top = razRules[i][3];
2451 while (top != NULL) {
2454 crnt->sm_transform_parms = &vp_transform;
2455 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2458 top = razRules[i][2];
2459 while (top != NULL) {
2462 crnt->sm_transform_parms = &vp_transform;
2463 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2466 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2467 top = razRules[i][0];
2469 top = razRules[i][1];
2471 while (top != NULL) {
2474 crnt->sm_transform_parms = &vp_transform;
2475 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2482bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2483 wxFileName fn(FullPath);
2485 wxString cname = fn.GetName();
2486 if (cname.Length() >= 3)
2487 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2492InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2495 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2498 if (name.Upper().EndsWith(
".XZ")) {
2499 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2502 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2503 wxFileName(name).GetName();
2505 if (!wxFileExists(m_TempFilePath) &&
2506 !DecompressXZFile(name, m_TempFilePath)) {
2507 wxRemoveFile(m_TempFilePath);
2508 return INIT_FAIL_REMOVE;
2511 m_TempFilePath = name;
2512 ext = wxFileName(name).GetExt();
2517 firebase::crashlytics::SetCustomKey(
"s57chartInit",
2518 name.ToStdString().c_str());
2530 InitReturn ret_value = INIT_OK;
2532 m_Description = name;
2534 wxFileName fn(m_TempFilePath);
2537 wxString cname = fn.GetName();
2538 m_usage_char = cname[2];
2541 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2542 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2544 if (flags == THUMB_ONLY) {
2552 if (flags == HEADER_ONLY) {
2554 if (!GetBaseFileAttr(fn.GetFullPath()))
2555 ret_value = INIT_FAIL_REMOVE;
2557 if (!CreateHeaderDataFromENC())
2558 ret_value = INIT_FAIL_REMOVE;
2560 ret_value = INIT_OK;
2562 }
else if (ext ==
"S57") {
2563 m_SENCFileName = m_TempFilePath;
2564 if (!CreateHeaderDataFromSENC())
2565 ret_value = INIT_FAIL_REMOVE;
2567 ret_value = INIT_OK;
2576 if (!m_bbase_file_attr_known) {
2577 if (!GetBaseFileAttr(m_TempFilePath))
2578 ret_value = INIT_FAIL_REMOVE;
2580 m_bbase_file_attr_known =
true;
2584 if (m_bbase_file_attr_known) {
2585 int sret = FindOrCreateSenc(m_FullPath);
2586 if (sret == BUILD_SENC_PENDING) {
2591 if (sret != BUILD_SENC_OK) {
2592 if (sret == BUILD_SENC_NOK_RETRY)
2593 ret_value = INIT_FAIL_RETRY;
2595 ret_value = INIT_FAIL_REMOVE;
2597 ret_value = PostInit(flags, m_global_color_scheme);
2602 else if (ext ==
"S57") {
2603 m_SENCFileName = m_TempFilePath;
2604 ret_value = PostInit(flags, m_global_color_scheme);
2611wxString s57chart::buildSENCName(
const wxString &name) {
2612 wxFileName fn(name);
2614 wxString file_name = fn.GetFullName();
2617 wxString SENCdir = g_SENCPrefix;
2619 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2620 SENCdir.Append(wxFileName::GetPathSeparator());
2623 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2624 wxCharBuffer buf = source_dir.ToUTF8();
2625 unsigned char sha1_out[20];
2626 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2629 for (
unsigned int i = 0; i < 6; i++) {
2631 s.Printf(
"%02X", sha1_out[i]);
2635 file_name.Prepend(sha1);
2638 wxFileName tsfn(SENCdir);
2639 tsfn.SetFullName(file_name);
2641 return tsfn.GetFullPath();
2648int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2652 if (name.Upper().EndsWith(
".XZ")) {
2653 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2656 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2657 wxFileName(name).GetName();
2659 if (!wxFileExists(m_TempFilePath) &&
2660 !DecompressXZFile(name, m_TempFilePath)) {
2661 wxRemoveFile(m_TempFilePath);
2662 return INIT_FAIL_REMOVE;
2665 m_TempFilePath = name;
2666 ext = wxFileName(name).GetExt();
2670 if (!m_bbase_file_attr_known) {
2671 if (!GetBaseFileAttr(m_TempFilePath))
2672 return INIT_FAIL_REMOVE;
2674 m_bbase_file_attr_known =
true;
2678 m_SENCFileName = buildSENCName(name);
2680 int build_ret_val = 1;
2682 bool bbuild_new_senc =
false;
2683 m_bneed_new_thumbnail =
false;
2685 wxFileName FileName000(m_TempFilePath);
2689 wxString msg(
"S57chart::Checking SENC file: ");
2690 msg.Append(m_SENCFileName);
2694 int force_make_senc = 0;
2696 if (::wxFileExists(m_SENCFileName)) {
2699 if (senc.ingestHeader(m_SENCFileName)) {
2700 bbuild_new_senc =
true;
2701 wxLogMessage(
" Rebuilding SENC due to ingestHeader failure.");
2703 int senc_file_version = senc.getSencReadVersion();
2705 int last_update = senc.getSENCReadLastUpdate();
2707 wxString str = senc.getSENCFileCreateDate();
2708 wxDateTime SENCCreateDate;
2709 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
2711 if (SENCCreateDate.IsValid())
2712 SENCCreateDate.ResetTime();
2717 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2719 senc_base_edtn.ToLong(&isenc_edition);
2721 m_edtn000.ToLong(&ifile_edition);
2726 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2727 bbuild_new_senc =
true;
2728 wxLogMessage(
" Rebuilding SENC due to SENC format update.");
2735 else if (ifile_edition > isenc_edition) {
2736 bbuild_new_senc =
true;
2737 wxLogMessage(
" Rebuilding SENC due to cell edition update.");
2739 msg =
" Last edition recorded in SENC: ";
2740 msg += senc_base_edtn;
2741 msg +=
" most recent edition cell file: ";
2746 int most_recent_update_file =
2747 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2749 if (ifile_edition == isenc_edition) {
2750 if (most_recent_update_file > last_update) {
2751 bbuild_new_senc =
true;
2753 " Rebuilding SENC due to incremental cell update.");
2756 " Last update recorded in SENC: %d most recent "
2758 last_update, most_recent_update_file);
2766 wxDateTime OModTime000;
2767 FileName000.GetTimes(NULL, &OModTime000, NULL);
2768 OModTime000.ResetTime();
2769 if (SENCCreateDate.IsValid()) {
2770 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2772 " Rebuilding SENC due to Senc vs cell file time "
2774 bbuild_new_senc =
true;
2777 bbuild_new_senc =
true;
2779 " Rebuilding SENC due to SENC create time invalid.");
2790 if (force_make_senc) bbuild_new_senc =
true;
2792 }
else if (!::wxFileExists(m_SENCFileName))
2794 wxLogMessage(
" Rebuilding SENC due to missing SENC file.");
2795 bbuild_new_senc =
true;
2799 if (bbuild_new_senc) {
2800 m_bneed_new_thumbnail =
2802 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2804 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2805 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2806 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2812InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2814 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2815 wxString msg(
" Cannot load SENC file ");
2816 msg.Append(m_SENCFileName);
2819 return INIT_FAIL_RETRY;
2825 wxString SENCdir = g_SENCPrefix;
2826 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2827 SENCdir.Append(wxFileName::GetPathSeparator());
2829 wxFileName s57File(m_SENCFileName);
2830 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13),
"BMP");
2832 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2833 BuildThumbnail(ThumbFileName.GetFullPath());
2836 if (ThumbFileName.FileExists()) {
2838#ifdef ocpnUSE_ocpnBitmap
2839 pBMP_NEW =
new ocpnBitmap;
2841 pBMP_NEW =
new wxBitmap;
2843 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2846 m_pDIBThumbDay = pBMP_NEW;
2854 m_global_color_scheme = cs;
2855 SetColorScheme(cs,
false);
2858 BuildDepthContourArray();
2860 CreateChartContext();
2861 PopulateObjectsWithContext();
2864 bReadyToRender =
true;
2869void s57chart::ClearDepthContourArray() {
2870 if (m_nvaldco_alloc) {
2871 free(m_pvaldco_array);
2873 m_nvaldco_alloc = 5;
2875 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2878void s57chart::BuildDepthContourArray() {
2881 if (0 == m_nvaldco_alloc) {
2882 m_nvaldco_alloc = 5;
2883 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2889 double prev_valdco = 0.0;
2891 for (
int i = 0; i < PRIO_NUM; ++i) {
2892 for (
int j = 0; j < LUPNAME_NUM; j++) {
2893 top = razRules[i][j];
2894 while (top != NULL) {
2895 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2896 double valdco = 0.0;
2897 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2898 if (valdco != prev_valdco) {
2899 prev_valdco = valdco;
2901 if (m_nvaldco > m_nvaldco_alloc) {
2902 void *tr = realloc((
void *)m_pvaldco_array,
2903 m_nvaldco_alloc * 2 *
sizeof(
double));
2904 m_pvaldco_array = (
double *)tr;
2905 m_nvaldco_alloc *= 2;
2907 m_pvaldco_array[m_nvaldco - 1] = valdco;
2911 ObjRazRules *nxx = top->next;
2916 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2920void s57chart::SetSafetyContour() {
2928 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2931 if (NULL != m_pvaldco_array) {
2932 for (i = 0; i < m_nvaldco; i++) {
2933 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2937 m_next_safe_cnt = m_pvaldco_array[i];
2939 m_next_safe_cnt = (double)1e6;
2941 m_next_safe_cnt = (double)1e6;
2946 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2947 m_next_safe_cnt = (
double)1e6;
2950void s57chart::CreateChartContext() {
2952 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2955void s57chart::PopulateObjectsWithContext() {
2956 m_this_chart_context->chart =
this;
2957 m_this_chart_context->chart_type = GetChartType();
2958 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2959 m_this_chart_context->chart_scale = GetNativeScale();
2960 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2961 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2962 m_this_chart_context->safety_contour = m_next_safe_cnt;
2963 m_this_chart_context->pt2GetAssociatedObjects =
2964 &s57chart::GetAssociatedObjects;
2968 for (
int i = 0; i < PRIO_NUM; ++i) {
2969 for (
int j = 0; j < LUPNAME_NUM; j++) {
2970 top = razRules[i][j];
2971 while (top != NULL) {
2972 S57Obj *obj = top->obj;
2973 obj->m_chart_context = m_this_chart_context;
2980void s57chart::InvalidateCache() {
2985bool s57chart::BuildThumbnail(
const wxString &bmpname) {
2988 wxFileName ThumbFileName(bmpname);
2991 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
2992 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
2993 wxLogMessage(
" Cannot create BMP file directory for " +
2994 ThumbFileName.GetFullPath());
3002 vp.
clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
3003 vp.
clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
3005 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
3006 (m_FullExtent.ELON - m_FullExtent.WLON));
3013 vp.m_projection_type = PROJECTION_MERCATOR;
3015 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3032 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3034 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3036 int *psvr = psave_viz;
3040 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3041 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3042 *psvr++ = pOLE->nViz;
3047 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3048 bool bsave_text = ps52plib->m_bShowS57Text;
3051 ps52plib->SaveObjNoshow();
3054 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3055 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3056 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3057 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3060 ps52plib->m_bShowSoundg =
false;
3061 ps52plib->m_bShowS57Text =
false;
3064 DisCat dsave = ps52plib->GetDisplayCategory();
3065 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3067 ps52plib->AddObjNoshow(
"BRIDGE");
3068 ps52plib->AddObjNoshow(
"GATCON");
3070 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3071 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3072 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3073 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3075#ifdef ocpnUSE_DIBSECTION
3078 wxMemoryDC memdc, dc_org;
3082 ps52plib->SaveColorScheme();
3083 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3085 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3088 memdc.SelectObject(wxNullBitmap);
3092 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3093 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3094 pOLE->nViz = *psvr++;
3097 ps52plib->SetDisplayCategory(dsave);
3098 ps52plib->RestoreObjNoshow();
3100 ps52plib->RemoveObjNoshow(
"BRIDGE");
3101 ps52plib->RemoveObjNoshow(
"GATCON");
3103 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3104 ps52plib->m_bShowS57Text = bsave_text;
3106 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3107 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3110 ps52plib->RestoreColorScheme();
3120 wxMemoryDC dc_clone;
3121 dc_clone.SelectObject(*pBMP);
3123 pDIB->SelectIntoDC(dc_org);
3127 dc_clone.SelectObject(wxNullBitmap);
3128 dc_org.SelectObject(wxNullBitmap);
3131 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3138WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3139static int depth = 0;
3140static bool isProcessing =
false;
3143bool s57chart::CreateHeaderDataFromENC() {
3146 float LatMax, LatMin, LonMax, LonMin;
3152 m_pCOVRTablePoints = NULL;
3153 m_pCOVRTable = NULL;
3155 if (!InitENCMinimal(m_TempFilePath)) {
3156 wxString msg(
" Cannot initialize ENC file ");
3157 msg.Append(m_TempFilePath);
3164 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3165 std::vector<int> auxCntArray, noCovrCntArray;
3166 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3169 wxCriticalSectionLocker enter(GDALcriticalSection);
3170 if (isProcessing)
int yyp = 4;
3171 isProcessing =
true;
3179 pFeat = GetChartFirstM_COVR(catcov);
3184 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3185 OGRLinearRing *xring = poly->getExteriorRing();
3187 int npt = xring->getNumPoints();
3198 for (
int i = 0; i < npt; i++) {
3199 xring->getPoint(i, &p);
3203 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3205 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3206 if (xdelta < 0.001 &&
3214 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3215 pfr = &pf[2 * (usedpts - 1)];
3218 LatMax = fmax(LatMax, p.getY());
3219 LatMin = fmin(LatMin, p.getY());
3220 LonMax = fmax(LonMax, p.getX());
3221 LonMin = fmin(LonMin, p.getX());
3229 pAuxPtrArray->Add(pf);
3230 auxCntArray.push_back(usedpts);
3231 }
else if (catcov == 2) {
3232 pNoCovrPtrArray->Add(pf);
3233 noCovrCntArray.push_back(usedpts);
3238 pFeat = GetChartNextM_COVR(catcov);
3239 DEBUG_LOG <<
"used " << usedpts <<
" points";
3245 isProcessing =
false;
3250 m_nCOVREntries = auxCntArray.size();
3254 if (m_nCOVREntries >= 1) {
3255 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3256 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3258 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3259 m_pCOVRTablePoints[j] = auxCntArray[j];
3260 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3266 wxString msg(
" ENC contains no useable M_COVR, CATCOV=1 features: ");
3267 msg.Append(m_TempFilePath);
3272 m_nNoCOVREntries = noCovrCntArray.size();
3274 if (m_nNoCOVREntries) {
3276 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3277 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3279 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3280 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3281 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3284 m_pNoCOVRTablePoints = NULL;
3285 m_pNoCOVRTable = NULL;
3288 delete pAuxPtrArray;
3289 delete pNoCovrPtrArray;
3291 if (0 == m_nCOVREntries) {
3292 wxString msg(
" ENC contains no M_COVR features: ");
3293 msg.Append(m_TempFilePath);
3296 msg =
" Calculating Chart Extents as fallback.";
3302 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3304 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3311 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3312 *m_pCOVRTablePoints = 4;
3313 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3314 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3331 wxString msg(
" Cannot calculate Extents for ENC: ");
3332 msg.Append(m_TempFilePath);
3340 m_FullExtent.NLAT = LatMax;
3341 m_FullExtent.SLAT = LatMin;
3342 m_FullExtent.ELON = LonMax;
3343 m_FullExtent.WLON = LonMin;
3344 m_bExtentSet =
true;
3347 m_Chart_Scale = GetENCScale();
3358bool s57chart::CreateHeaderDataFromoSENC() {
3359 bool ret_val =
true;
3361 wxFFileInputStream fpx(m_SENCFileName);
3363 if (!::wxFileExists(m_SENCFileName)) {
3364 wxString msg(
" Cannot open SENC file ");
3365 msg.Append(m_SENCFileName);
3372 if (senc.ingestHeader(m_SENCFileName)) {
3378 m_Chart_Scale = senc.getSENCReadScale();
3381 m_Name = senc.getReadName();
3384 m_ID = senc.getReadID();
3387 Extent &ext = senc.getReadExtent();
3389 m_FullExtent.ELON = ext.ELON;
3390 m_FullExtent.WLON = ext.WLON;
3391 m_FullExtent.NLAT = ext.NLAT;
3392 m_FullExtent.SLAT = ext.SLAT;
3393 m_bExtentSet =
true;
3396 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3397 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3399 m_nCOVREntries = AuxCntArray.size();
3401 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3402 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3404 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3405 m_pCOVRTablePoints[j] = AuxCntArray[j];
3406 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3407 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3408 AuxCntArray[j] * 2 *
sizeof(
float));
3412 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3413 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3415 m_nNoCOVREntries = NoCovrCntArray.size();
3417 if (m_nNoCOVREntries) {
3419 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3420 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3422 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3423 int npoints = NoCovrCntArray[j];
3424 m_pNoCOVRTablePoints[j] = npoints;
3425 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3426 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3427 npoints * 2 *
sizeof(
float));
3433 m_datum_str =
"WGS84";
3434 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
3436 int senc_file_version = senc.getSencReadVersion();
3438 int last_update = senc.getSENCReadLastUpdate();
3440 wxString str = senc.getSENCFileCreateDate();
3441 wxDateTime SENCCreateDate;
3442 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
3444 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3446 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3453bool s57chart::CreateHeaderDataFromSENC() {
3454 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3462bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3464 if (NULL != m_pvaldco_array) {
3465 for (i = 0; i < m_nvaldco; i++) {
3466 if (m_pvaldco_array[i] >= safe_cnt)
break;
3470 next_safe_cnt = m_pvaldco_array[i];
3472 next_safe_cnt = (double)1e6;
3475 next_safe_cnt = (double)1e6;
3489std::list<S57Obj *> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3493 std::list<S57Obj *> *pobj_list =
new std::list<S57Obj *>();
3496 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3497 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3500 switch (obj->Primitive_type) {
3513 top = razRules[disPrioIdx][3];
3514 while (top != NULL) {
3515 if (top->obj->bIsAssociable) {
3516 if (top->obj->BBObj.Contains(lat, lon)) {
3517 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3518 pobj_list->push_back(top->obj);
3525 ObjRazRules *nxx = top->next;
3530 top = razRules[disPrioIdx][4];
3531 while (top != NULL) {
3532 if (top->obj->bIsAssociable) {
3533 if (top->obj->BBObj.Contains(lat, lon)) {
3534 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3535 pobj_list->push_back(top->obj);
3541 ObjRazRules *nxx = top->next;
3555void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3556 wxFileName fn(FullPath);
3558 wxString target_name = fn.GetName();
3559 target_name.RemoveLast();
3561 wxString dir_name = fn.GetPath();
3563 wxDir dir(dir_name);
3565 wxArrayString FileList;
3567 dir.GetAllFiles(fn.GetPath(), &FileList);
3571 bool found_name =
false;
3575 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3576 wxFileName file(FileList[j]);
3577 if (((file.GetExt()).MakeUpper()) ==
"TXT") {
3579 wxTextFile text_file(file.GetFullPath());
3581 bool file_ok =
true;
3585 if (!text_file.Open()) {
3586 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3591 wxString str = text_file.GetFirstLine();
3592 while (!text_file.Eof()) {
3593 if (0 == target_name.CmpNoCase(
3594 str.Mid(0, target_name.Len()))) {
3595 wxString tname = str.AfterFirst(
'-');
3596 name = tname.AfterFirst(
' ');
3600 str = text_file.GetNextLine();
3604 wxString msg(
" Error Reading ENC .TXT file: ");
3605 msg.Append(file.GetFullPath());
3611 if (found_name)
break;
3628const char *s57chart::getName(OGRFeature *feature) {
3629 return feature->GetDefnRef()->GetName();
3632static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3633 wxFileName fn1(first);
3634 wxFileName fn2(second);
3635 wxString ext1(fn1.GetExt());
3636 wxString ext2(fn2.GetExt());
3638 return ext1.Cmp(ext2);
3641int s57chart::GetUpdateFileArray(
const wxFileName file000,
3642 wxArrayString *UpFiles, wxDateTime date000,
3644 wxString DirName000 =
3645 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3646 wxDir dir(DirName000);
3647 if (!dir.IsOpened()) {
3648 DirName000.Prepend(wxFileName::GetPathSeparator());
3649 DirName000.Prepend(
".");
3650 dir.Open(DirName000);
3651 if (!dir.IsOpened()) {
3656 int flags = wxDIR_DEFAULT;
3663 wxFileName fnDir(DirName000);
3664 fnDir.RemoveLastDir();
3665 wxString sdir = fnDir.GetPath();
3666 wxFileName fnTest(sdir);
3667 wxString sname = fnTest.GetName();
3669 if (sname.ToLong(&tmps)) {
3672 flags |= wxDIR_DIRS;
3676 wxArrayString *dummy_array;
3679 if (UpFiles == NULL)
3680 dummy_array =
new wxArrayString;
3682 dummy_array = UpFiles;
3684 wxArrayString possibleFiles;
3685 wxDir::GetAllFiles(DirName000, &possibleFiles,
"", flags);
3687 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3688 wxString filename(possibleFiles[i]);
3690 wxFileName file(filename);
3691 ext = file.GetExt();
3696 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3697 wxString FileToAdd = filename;
3699 wxCharBuffer buffer =
3702 if (buffer.data() && !filename.IsSameAs(
"CATALOG.031",
3714 DDFModule *poModule =
new DDFModule();
3715 if (!poModule->Open(FileToAdd.mb_str())) {
3717 " s57chart::BuildS57File Unable to open update file ");
3718 msg.Append(FileToAdd);
3727 DDFRecord *pr = poModule->ReadRecord();
3733 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3736 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3740 " s57chart::BuildS57File DDFRecord 0 does not contain "
3741 "DSID:ISDT in update file ");
3742 msg.Append(FileToAdd);
3745 sumdate =
"20000101";
3748 umdate.ParseFormat(sumdate,
"%Y%m%d");
3749 if (!umdate.IsValid()) umdate.ParseFormat(
"20000101",
"%Y%m%d");
3752 if (!umdate.IsValid())
int yyp = 4;
3757 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3759 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3763 " s57chart::BuildS57File DDFRecord 0 does not contain "
3764 "DSID:EDTN in update file ");
3765 msg.Append(FileToAdd);
3774 if ((!umdate.IsEarlierThan(date000)) &&
3775 (umedtn.IsSameAs(edtn000)))
3776 dummy_array->Add(FileToAdd);
3782 dummy_array->Sort(ExtensionCompare);
3785 if (dummy_array->GetCount()) {
3786 wxString Last = dummy_array->Last();
3787 wxFileName fnl(Last);
3789 wxCharBuffer buffer = ext.ToUTF8();
3790 if (buffer.data()) retval = atoi(buffer.data());
3793 if (UpFiles == NULL)
delete dummy_array;
3798int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3799 const wxString CopyDir,
3800 wxString &LastUpdateDate,
3806 wxArrayString *UpFiles =
new wxArrayString;
3807 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3809 if (UpFiles->GetCount()) {
3829 for (
int iff = 0; iff < retval + 1; iff++) {
3830 wxFileName ufile(m_TempFilePath);
3832 sext.Printf(
"%03d", iff);
3836 wxString cp_ufile = CopyDir;
3837 if (cp_ufile.Last() != ufile.GetPathSeparator())
3838 cp_ufile.Append(ufile.GetPathSeparator());
3840 cp_ufile.Append(ufile.GetFullName());
3845 if (ufile.FileExists()) {
3846 wxFile uf(ufile.GetFullPath());
3847 if (uf.IsOpened()) {
3853 if (ufile.FileExists() &&
3857 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3859 wxString msg(
" Cannot copy temporary working ENC file ");
3860 msg.Append(ufile.GetFullPath());
3862 msg.Append(cp_ufile);
3875 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3876 "incomplete or inaccurate.\nCheck the logfile for details."),
3877 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3883 "WARNING---ENC Update chain incomplete. Substituting NULL "
3885 msg += ufile.GetFullName();
3887 wxLogMessage(
" Subsequent ENC updates may produce errors.");
3889 " This ENC exchange set should be updated and SENCs "
3893 DDFModule *dupdate =
new DDFModule;
3894 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3895 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3899 wxString msg(
" Error creating dummy update file: ");
3900 msg.Append(cp_ufile);
3905 m_tmpup_array->Add(cp_ufile);
3912 wxFileName lastfile(m_TempFilePath);
3914 last_sext.Printf(
"%03d", retval);
3915 lastfile.SetExt(last_sext);
3918 DDFModule oUpdateModule;
3923 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3927 oUpdateModule.Rewind();
3928 DDFRecord *pr = oUpdateModule.ReadRecord();
3934 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3938 LastUpdateDate = wxString(u, wxConvUTF8);
3941 wxDateTime now = wxDateTime::Now();
3942 LastUpdateDate = now.Format(
"%Y%m%d");
3951wxString s57chart::GetISDT() {
3952 if (m_date000.IsValid())
3953 return m_date000.Format(
"%Y%m%d");
3958bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3959 if (!wxFileName::FileExists(file000))
return false;
3961 wxString FullPath000 = file000;
3962 DDFModule *poModule =
new DDFModule();
3963 if (!poModule->Open(FullPath000.mb_str())) {
3964 wxString msg(
" s57chart::BuildS57File Unable to open ");
3965 msg.Append(FullPath000);
3977 DDFRecord *pr = poModule->ReadRecord();
3981 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3982 if (!m_nGeoRecords) {
3984 " s57chart::BuildS57File DDFRecord 0 does not contain "
3994 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3996 date000 = wxString(u, wxConvUTF8);
3999 " s57chart::BuildS57File DDFRecord 0 does not contain "
4006 m_date000.ParseFormat(date000,
"%Y%m%d");
4007 if (!m_date000.IsValid()) m_date000.ParseFormat(
"20000101",
"%Y%m%d");
4009 m_date000.ResetTime();
4012 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
4014 m_edtn000 = wxString(u, wxConvUTF8);
4017 " s57chart::BuildS57File DDFRecord 0 does not contain "
4028 for (; pr != NULL; pr = poModule->ReadRecord()) {
4029 if (pr->FindField(
"DSPM") != NULL) {
4030 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4034 if (!m_native_scale) {
4035 wxString msg(
" s57chart::BuildS57File ENC not contain DSPM:CSCL ");
4038 m_native_scale = 1000;
4046int s57chart::BuildSENCFile(
const wxString &FullPath000,
4047 const wxString &SENCFileName,
bool b_progress) {
4049 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4050 double meters_per_pixel_max_scale =
4052 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4055 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4056 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4058 if (!m_disableBackgroundSENC) {
4061 ticket->m_LOD_meters = m_LOD_meters;
4062 ticket->ref_lat = ref_lat;
4063 ticket->ref_lon = ref_lon;
4064 ticket->m_FullPath000 = FullPath000;
4065 ticket->m_SENCFileName = SENCFileName;
4066 ticket->m_chart =
this;
4069 bReadyToRender =
true;
4070 return BUILD_SENC_PENDING;
4073 return BUILD_SENC_NOK_RETRY;
4079 senc.setRefLocn(ref_lat, ref_lon);
4080 senc.SetLODMeters(m_LOD_meters);
4082 AbstractPlatform::ShowBusySpinner();
4084 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4086 AbstractPlatform::HideBusySpinner();
4088 if (ret == ERROR_INGESTING000)
4089 return BUILD_SENC_NOK_PERMANENT;
4095int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4102 S57ObjVector Objects;
4103 VE_ElementVector VEs;
4104 VC_ElementVector VCs;
4106 sencfile.setRefLocn(ref_lat, ref_lon);
4108 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4110 if (srv != SENC_NO_ERROR) {
4111 wxLogMessage(sencfile.getLastError());
4117 Extent ext = sencfile.getReadExtent();
4119 m_FullExtent.ELON = ext.ELON;
4120 m_FullExtent.WLON = ext.WLON;
4121 m_FullExtent.NLAT = ext.NLAT;
4122 m_FullExtent.SLAT = ext.SLAT;
4123 m_bExtentSet =
true;
4125 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4126 ref_lon = (ext.ELON + ext.WLON) / 2.;
4131 int n_ve_elements = VEs.size();
4133 double scale = top_frame::Get()->GetBestVPScale(
this);
4134 int nativescale = GetNativeScale();
4136 for (
int i = 0; i < n_ve_elements; i++) {
4137 VE_Element *vep = VEs.at(i);
4138 if (vep && vep->nCount) {
4140 double east_max = -1e7;
4141 double east_min = 1e7;
4142 double north_max = -1e7;
4143 double north_min = 1e7;
4145 float *vrun = vep->pPoints;
4146 for (
size_t i = 0; i < vep->nCount; i++) {
4147 east_max = wxMax(east_max, *vrun);
4148 east_min = wxMin(east_min, *vrun);
4151 north_max = wxMax(north_max, *vrun);
4152 north_min = wxMin(north_min, *vrun);
4156 double lat1, lon1, lat2, lon2;
4157 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4158 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4159 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4162 m_ve_hash[vep->index] = vep;
4166 int n_vc_elements = VCs.size();
4168 for (
int i = 0; i < n_vc_elements; i++) {
4169 VC_Element *vcp = VCs.at(i);
4170 m_vc_hash[vcp->index] = vcp;
4178 for (
unsigned int i = 0; i < Objects.size(); i++) {
4179 S57Obj *obj = Objects[i];
4183 LUPname LUP_Name = PAPER_CHART;
4185 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4186 if (objnam.Len() > 0) {
4187 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4188 SendVectorChartObjectInfo(FullPath, fe_name, objnam, obj->m_lat,
4189 obj->m_lon,
scale, nativescale);
4193 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4194 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4195 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4196 SendVectorChartObjectInfo(FullPath, fe_name, nobjnam, obj->m_lat,
4197 obj->m_lon,
scale, nativescale);
4200 switch (obj->Primitive_type) {
4205 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4206 LUP_Name = PAPER_CHART;
4208 LUP_Name = SIMPLIFIED;
4217 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4218 LUP_Name = PLAIN_BOUNDARIES;
4220 LUP_Name = SYMBOLIZED_BOUNDARIES;
4225 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4229 wxString msg(obj->FeatureName, wxConvUTF8);
4230 msg.Prepend(
" Could not find LUP for ");
4231 LogMessageOnce(msg);
4238 ps52plib->_LUP2rules(LUP, obj);
4241 _insertRules(obj, LUP,
this);
4244 obj->m_DisplayCat = LUP->DISC;
4247 obj->m_DPRI = LUP->DPRI -
'0';
4250 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4251 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4252 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4253 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4254 obj->m_bcategory_mutable =
true;
4256 obj->m_bcategory_mutable =
false;
4261 if (obj && (GEO_POINT == obj->Primitive_type)) {
4263 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4264 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4265 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4266 pFloatingATONArray->Add(obj);
4270 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4271 pRigidATONArray->Add(obj);
4275 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4276 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4277 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4278 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4279 obj->bIsAton =
true;
4288 d000.ParseFormat(sencfile.getBaseDate(),
"%Y%m%d");
4289 if (!d000.IsValid()) d000.ParseFormat(
"20000101",
"%Y%m%d");
4292 updt.ParseFormat(sencfile.getUpdateDate(),
"%Y%m%d");
4293 if (!updt.IsValid()) updt.ParseFormat(
"20000101",
"%Y%m%d");
4295 if (updt.IsLaterThan(d000))
4296 m_PubYear.Printf(
"%4d", updt.GetYear());
4298 m_PubYear.Printf(
"%4d", d000.GetYear());
4301 wxDateTime upd = updt;
4302 if (!upd.IsValid()) upd.ParseFormat(
"20000101",
"%Y%m%d");
4307 m_SE = sencfile.getSENCReadBaseEdition();
4310 supdate.Printf(
" / %d", sencfile.getSENCReadLastUpdate());
4313 m_datum_str =
"WGS84";
4315 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
4316 m_ID = sencfile.getReadID();
4317 m_Name = sencfile.getReadName();
4321 AssembleLineGeometry();
4326int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4327 ObjRazRules *rzRules = NULL;
4337 switch (LUP->DPRI) {
4350 case PRIO_SYMB_POINT:
4353 case PRIO_SYMB_LINE:
4356 case PRIO_SYMB_AREA:
4369 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4373 switch (LUP->TNAM) {
4383 case PLAIN_BOUNDARIES:
4386 case SYMBOLIZED_BOUNDARIES:
4390 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4394 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4398 rzRules->child = NULL;
4399 rzRules->mps = NULL;
4402 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4403 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4408 ObjRazRules *rNext = NULL;
4409 ObjRazRules *rPrevious = NULL;
4410 if (razRules[disPrioIdx][LUPtypeIdx]) {
4411 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4412 rNext = rPrevious->next;
4416 rNext = rPrevious->next;
4419 rzRules->next = NULL;
4421 rPrevious->next = rzRules;
4423 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4430void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4440 for (
int i = 0; i < PRIO_NUM; ++i) {
4441 for (
int j = 0; j < 2; ++j) {
4442 top = razRules[i][j];
4444 while (top != NULL) {
4445 if (!top->obj->geoPtMulti)
4447 if (top->obj->BBObj.GetValid()) {
4448 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4450 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4451 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4453 double minlon = top->obj->BBObj.GetMinLon();
4454 double maxlon = top->obj->BBObj.GetMaxLon();
4456 double lon1 = (lon - minlon) * d;
4457 double lon2 = (lon - maxlon) * d;
4459 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4462 top->obj->BBObj.Invalidate();
4483void s57chart::UpdateLUPs(
s57chart *pOwner) {
4487 for (
int i = 0; i < PRIO_NUM; ++i) {
4489 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4490 m_b2pointLUPS =
true;
4491 top = razRules[i][0];
4493 while (top != NULL) {
4494 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4500 if (top->obj->nRef < 2) {
4501 ps52plib->_LUP2rules(LUP, top->obj);
4502 _insertRules(top->obj, LUP, pOwner);
4503 top->obj->m_DisplayCat = LUP->DISC;
4513 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4514 m_b2pointLUPS =
true;
4515 top = razRules[i][1];
4517 while (top != NULL) {
4518 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4521 if (top->obj->nRef < 2) {
4522 ps52plib->_LUP2rules(LUP, top->obj);
4523 _insertRules(top->obj, LUP, pOwner);
4524 top->obj->m_DisplayCat = LUP->DISC;
4534 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4535 m_b2lineLUPS =
true;
4536 top = razRules[i][3];
4538 while (top != NULL) {
4539 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4540 top->obj->FeatureName, top->obj);
4542 ps52plib->_LUP2rules(LUP, top->obj);
4543 _insertRules(top->obj, LUP, pOwner);
4544 top->obj->m_DisplayCat = LUP->DISC;
4553 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4554 m_b2lineLUPS =
true;
4555 top = razRules[i][4];
4557 while (top != NULL) {
4558 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4561 ps52plib->_LUP2rules(LUP, top->obj);
4562 _insertRules(top->obj, LUP, pOwner);
4563 top->obj->m_DisplayCat = LUP->DISC;
4575 for (
int j = 0; j < LUPNAME_NUM; j++) {
4576 top = razRules[i][j];
4577 while (top != NULL) {
4578 top->obj->bCS_Added = 0;
4581 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4592 for (
int j = 0; j < LUPNAME_NUM; j++) {
4593 top = razRules[i][j];
4594 while (top != NULL) {
4596 ObjRazRules *ctop = top->child;
4597 while (NULL != ctop) {
4598 ctop->obj->bCS_Added = 0;
4599 free_mps(ctop->mps);
4602 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4619ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4620 float lat,
float lon,
ViewPort *VPoint) {
4621 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4622 std::vector<ObjRazRules *> selected_rules;
4627 char *curr_att = NULL;
4629 wxArrayOfS57attVal *attValArray = NULL;
4630 bool bleading_attribute =
false;
4632 for (
int i = 0; i < PRIO_NUM; ++i) {
4636 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4637 top = razRules[i][point_type];
4639 while (top != NULL) {
4640 if (top->obj->npt == 1) {
4641 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4643 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4645 if (ps52plib->ObjectRenderCheckCat(top)) {
4648 wxString curAttrName;
4649 curr_att = top->obj->att_array;
4650 n_attr = top->obj->n_attr;
4651 attValArray = top->obj->attVal;
4659 bleading_attribute =
false;
4661 while (attrCounter < n_attr) {
4662 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4665 S57attVal *pAttrVal = NULL;
4668 pAttrVal = attValArray->Item(attrCounter);
4672 wxString value = s57chart::GetAttributeValueAsString(
4673 pAttrVal, curAttrName);
4675 if (curAttrName ==
"LITVIS") {
4676 if (value.StartsWith(
"obsc")) bviz =
false;
4677 }
else if (curAttrName ==
"VALNMR")
4678 value.ToDouble(&valnmr);
4684 if (bviz && (valnmr > 0.1)) {
4688 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4689 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4690 ref_lat, ref_lon, &olat, &olon);
4692 double dlat = lat - olat;
4693 double dy = dlat * 60 / cos(olat * PI / 180.);
4694 double dlon = lon - olon;
4695 double dx = dlon * 60;
4696 double manhat = abs(dy) + abs(dx);
4700 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4702 selected_rules.push_back(top);
4719 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4720 ret_ptr->Append(selected_rules[i]);
4726ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4727 float select_radius,
4729 int selection_mask) {
4730 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4731 std::vector<ObjRazRules *> selected_rules;
4733 PrepareForRender(VPoint, ps52plib);
4739 for (
int i = 0; i < PRIO_NUM; ++i) {
4740 if (selection_mask & MASK_POINT) {
4743 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4744 top = razRules[i][point_type];
4746 while (top != NULL) {
4747 if (top->obj->npt ==
4750 if (ps52plib->ObjectRenderCheck(top)) {
4751 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4752 selected_rules.push_back(top);
4759 ObjRazRules *child_item = top->child;
4760 while (child_item != NULL) {
4761 if (ps52plib->ObjectRenderCheck(child_item)) {
4762 if (DoesLatLonSelectObject(lat, lon, select_radius,
4764 selected_rules.push_back(child_item);
4767 child_item = child_item->next;
4775 if (selection_mask & MASK_AREA) {
4778 int area_boundary_type =
4779 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4780 top = razRules[i][area_boundary_type];
4781 while (top != NULL) {
4782 if (ps52plib->ObjectRenderCheck(top)) {
4783 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4784 selected_rules.push_back(top);
4791 if (selection_mask & MASK_LINE) {
4793 top = razRules[i][2];
4795 while (top != NULL) {
4796 if (ps52plib->ObjectRenderCheck(top)) {
4797 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4798 selected_rules.push_back(top);
4809 auto sortObjs = [lat, lon,
this](
const ObjRazRules *obj1,
4810 const ObjRazRules *obj2) ->
bool {
4811 double br1, dd1, br2, dd2;
4813 if (obj1->obj->Primitive_type == GEO_POINT &&
4814 obj2->obj->Primitive_type == GEO_POINT) {
4815 double lat1, lat2, lon1, lon2;
4816 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4817 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin, ref_lat,
4818 ref_lon, &lat1, &lon1);
4820 if (lon1 > 180.0) lon1 -= 360.;
4822 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4823 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin, ref_lat,
4824 ref_lon, &lat2, &lon2);
4826 if (lon2 > 180.0) lon2 -= 360.;
4828 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4829 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4836 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4840 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4841 ret_ptr->Append(selected_rules[i]);
4847bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4849 switch (obj->Primitive_type) {
4853 if (!obj->BBObj.GetValid())
return false;
4855 if (1 == obj->npt) {
4860 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4862 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4865 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4866 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4873 sbox.Set(olat, olon, olat, olon);
4875 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4876 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4881 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4888 if (!obj->BBObj.GetValid())
return false;
4891 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4893 double *pdl = obj->geoPtMulti;
4894 for (
int ip = 0; ip < obj->npt; ip++) {
4895 double lon_point = *pdl++;
4896 double lat_point = *pdl++;
4898 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4899 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4910 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4913 return IsPointInObjArea(lat, lon, select_radius, obj);
4918 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4920 float sel_rad_meters = select_radius * 1852 * 60;
4921 double easting, northing;
4922 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4929 pt *ppt = obj->geoPt;
4932 double xr = obj->x_rate;
4933 double xo = obj->x_origin;
4934 double yr = obj->y_rate;
4935 double yo = obj->y_origin;
4937 double north0 = (ppt->y * yr) + yo;
4938 double east0 = (ppt->x * xr) + xo;
4941 for (
int ip = 1; ip < npt; ip++) {
4942 double north = (ppt->y * yr) + yo;
4943 double east = (ppt->x * xr) + xo;
4946 if (northing >= (fmin(north, north0) - sel_rad_meters))
4947 if (northing <= (fmax(north, north0) + sel_rad_meters))
4948 if (easting >= (fmin(east, east0) - sel_rad_meters))
4949 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4959 if (obj->m_ls_list) {
4961 unsigned char *vbo_point =
4962 (
unsigned char *)obj->m_chart_context
4964 line_segment_element *ls = obj->m_ls_list;
4966 while (ls && vbo_point) {
4968 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4969 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4970 nPoints = ls->pedge->nCount;
4972 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4976 float north0 = ppt[1];
4977 float east0 = ppt[0];
4981 for (
int ip = 0; ip < nPoints - 1; ip++) {
4982 float north = ppt[1];
4983 float east = ppt[0];
4985 if (northing >= (fmin(north, north0) - sel_rad_meters))
4986 if (northing <= (fmax(north, north0) + sel_rad_meters))
4987 if (easting >= (fmin(east, east0) - sel_rad_meters))
4988 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
5015wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
5016 wxString ret_val =
"";
5019 const char *att_code;
5021 wxString file(g_csv_locn);
5022 file.Append(
"/s57attributes.csv");
5024 if (!wxFileName::FileExists(file)) {
5025 wxString msg(
" Could not open ");
5032 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5034 CC_ExactString,
"Code");
5040 wxString ei_file(g_csv_locn);
5041 ei_file.Append(
"/s57expectedinput.csv");
5043 if (!wxFileName::FileExists(ei_file)) {
5044 wxString msg(
" Could not open ");
5045 msg.Append(ei_file);
5051 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5052 CSVIngest(ei_file.mb_str());
5054 char **papszFields = NULL;
5055 int bSelected = FALSE;
5061 while (!bSelected && iline + 1 < psTable->nLineCount) {
5063 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5065 if (!strcmp(papszFields[0], att_code)) {
5066 if (atoi(papszFields[1]) == ival) {
5067 ret_val = wxString(papszFields[2], wxConvUTF8);
5072 CSLDestroy(papszFields);
5080bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5084 if (obj->pPolyTessGeo) {
5085 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5087 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5089 TriPrim *pTP = ppg->tri_prim_head;
5091 MyPoint pvert_list[3];
5095 double easting, northing;
5096 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5100 if (!ppg->m_bSMSENC) {
5101 double y_rate = obj->y_rate;
5102 double y_origin = obj->y_origin;
5103 double x_rate = obj->x_rate;
5104 double x_origin = obj->x_origin;
5106 double northing_scaled = (northing - y_origin) / y_rate;
5107 double easting_scaled = (easting - x_origin) / x_rate;
5108 northing = northing_scaled;
5109 easting = easting_scaled;
5114 if (pTP->tri_box.Contains(lat, lon)) {
5115 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5116 double *p_vertex = pTP->p_vertex;
5118 switch (pTP->type) {
5119 case PTG_TRIANGLE_FAN: {
5120 for (
int it = 0; it < pTP->nVert - 2; it++) {
5121 pvert_list[0].x = p_vertex[0];
5122 pvert_list[0].y = p_vertex[1];
5124 pvert_list[1].x = p_vertex[(it * 2) + 2];
5125 pvert_list[1].y = p_vertex[(it * 2) + 3];
5127 pvert_list[2].x = p_vertex[(it * 2) + 4];
5128 pvert_list[2].y = p_vertex[(it * 2) + 5];
5130 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5138 case PTG_TRIANGLE_STRIP: {
5139 for (
int it = 0; it < pTP->nVert - 2; it++) {
5140 pvert_list[0].x = p_vertex[(it * 2)];
5141 pvert_list[0].y = p_vertex[(it * 2) + 1];
5143 pvert_list[1].x = p_vertex[(it * 2) + 2];
5144 pvert_list[1].y = p_vertex[(it * 2) + 3];
5146 pvert_list[2].x = p_vertex[(it * 2) + 4];
5147 pvert_list[2].y = p_vertex[(it * 2) + 5];
5149 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5157 case PTG_TRIANGLES: {
5158 for (
int it = 0; it < pTP->nVert; it += 3) {
5159 pvert_list[0].x = p_vertex[(it * 2)];
5160 pvert_list[0].y = p_vertex[(it * 2) + 1];
5162 pvert_list[1].x = p_vertex[(it * 2) + 2];
5163 pvert_list[1].y = p_vertex[(it * 2) + 3];
5165 pvert_list[2].x = p_vertex[(it * 2) + 4];
5166 pvert_list[2].y = p_vertex[(it * 2) + 5];
5168 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5177 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5178 float *p_vertex = (
float *)pTP->p_vertex;
5180 switch (pTP->type) {
5181 case PTG_TRIANGLE_FAN: {
5182 for (
int it = 0; it < pTP->nVert - 2; it++) {
5183 pvert_list[0].x = p_vertex[0];
5184 pvert_list[0].y = p_vertex[1];
5186 pvert_list[1].x = p_vertex[(it * 2) + 2];
5187 pvert_list[1].y = p_vertex[(it * 2) + 3];
5189 pvert_list[2].x = p_vertex[(it * 2) + 4];
5190 pvert_list[2].y = p_vertex[(it * 2) + 5];
5192 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5200 case PTG_TRIANGLE_STRIP: {
5201 for (
int it = 0; it < pTP->nVert - 2; it++) {
5202 pvert_list[0].x = p_vertex[(it * 2)];
5203 pvert_list[0].y = p_vertex[(it * 2) + 1];
5205 pvert_list[1].x = p_vertex[(it * 2) + 2];
5206 pvert_list[1].y = p_vertex[(it * 2) + 3];
5208 pvert_list[2].x = p_vertex[(it * 2) + 4];
5209 pvert_list[2].y = p_vertex[(it * 2) + 5];
5211 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5219 case PTG_TRIANGLES: {
5220 for (
int it = 0; it < pTP->nVert; it += 3) {
5221 pvert_list[0].x = p_vertex[(it * 2)];
5222 pvert_list[0].y = p_vertex[(it * 2) + 1];
5224 pvert_list[1].x = p_vertex[(it * 2) + 2];
5225 pvert_list[1].y = p_vertex[(it * 2) + 3];
5227 pvert_list[2].x = p_vertex[(it * 2) + 4];
5228 pvert_list[2].y = p_vertex[(it * 2) + 5];
5230 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5253wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5254 wxString curAttrName) {
5258 pval = obj->attVal->Item(iatt);
5259 switch (pval->valType) {
5262 wxString val_str((
char *)(pval->value), wxConvUTF8);
5264 if (val_str.ToLong(&ival)) {
5268 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5269 if (!decode_val.IsEmpty()) {
5272 iv.Printf(
" (%d)", (
int)ival);
5275 value.Printf(
"%d", (
int)ival);
5279 else if (val_str.IsEmpty())
5284 wxString value_increment;
5285 wxStringTokenizer tk(val_str,
",");
5287 if (tk.HasMoreTokens()) {
5288 while (tk.HasMoreTokens()) {
5289 wxString token = tk.GetNextToken();
5291 if (token.ToLong(&ival)) {
5292 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5294 value_increment.Printf(
" (%d)", (
int)ival);
5296 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5298 if (iv) value_increment.Prepend(
", ");
5299 value.Append(value_increment);
5302 if (iv) value.Append(
",");
5303 value.Append(token);
5309 value.Append(val_str);
5312 value =
"[NULL VALUE]";
5318 int ival = *((
int *)pval->value);
5319 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5321 if (!decode_val.IsEmpty()) {
5324 iv.Printf(
"(%d)", ival);
5327 value.Printf(
"(%d)", ival);
5335 double dval = *((
double *)pval->value);
5336 wxString val_suffix =
" m";
5337 bool has_preformatted =
false;
5338 wxString preformatted;
5349 if ((curAttrName ==
"VERCLR") || (curAttrName ==
"VERCCL") ||
5350 (curAttrName ==
"VERCOP") || (curAttrName ==
"HEIGHT") ||
5351 (curAttrName ==
"ELEVAT") || (curAttrName ==
"VERCSA")) {
5356 val_suffix = wxString::Format(
" %s",
unit.c_str());
5357 }
else if (curAttrName ==
"HORCLR") {
5360 double nm = dval / 1852.0;
5362 has_preformatted =
true;
5365 else if ((curAttrName ==
"VALSOU") || (curAttrName ==
"DRVAL1") ||
5366 (curAttrName ==
"DRVAL2") || (curAttrName ==
"VALDCO")) {
5373 wxString
unit = getUsrDepthUnit(-1);
5374 val_suffix = wxString::Format(
" %s",
unit.c_str());
5377 else if (curAttrName ==
"SECTR1")
5378 val_suffix =
"°";
5379 else if (curAttrName ==
"SECTR2")
5380 val_suffix =
"°";
5381 else if (curAttrName ==
"ORIENT")
5382 val_suffix =
"°";
5383 else if (curAttrName ==
"VALNMR")
5385 else if (curAttrName ==
"SIGPER")
5387 else if (curAttrName ==
"VALACM")
5388 val_suffix =
" Minutes/year";
5389 else if (curAttrName ==
"VALMAG")
5390 val_suffix =
"°";
5391 else if (curAttrName ==
"CURVEL")
5394 if (has_preformatted) {
5395 value = preformatted;
5397 if (dval - floor(dval) < 0.01)
5398 value.Printf(
"%2.0f", dval);
5400 value.Printf(
"%4.1f", dval);
5401 value << val_suffix;
5407 case OGR_REAL_LST: {
5414wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5415 wxString AttrName) {
5416 if (NULL == pAttrVal)
return "";
5419 switch (pAttrVal->valType) {
5421 if (pAttrVal->value) {
5422 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5424 if (val_str.ToLong(&ival)) {
5428 wxString decode_val = GetAttributeDecode(AttrName, ival);
5429 if (!decode_val.IsEmpty()) {
5432 iv.Printf(
"(%d)", (
int)ival);
5435 value.Printf(
"%d", (
int)ival);
5439 else if (val_str.IsEmpty())
5444 wxString value_increment;
5445 wxStringTokenizer tk(val_str,
",");
5447 while (tk.HasMoreTokens()) {
5448 wxString token = tk.GetNextToken();
5450 if (token.ToLong(&ival)) {
5451 wxString decode_val = GetAttributeDecode(AttrName, ival);
5452 if (!decode_val.IsEmpty())
5453 value_increment = decode_val;
5455 value_increment.Printf(
" %d", (
int)ival);
5457 if (iv) value_increment.Prepend(
", ");
5459 value.Append(value_increment);
5463 value.Append(val_str);
5466 value =
"[NULL VALUE]";
5472 int ival = *((
int *)pAttrVal->value);
5473 wxString decode_val = GetAttributeDecode(AttrName, ival);
5475 if (!decode_val.IsEmpty()) {
5478 iv.Printf(
"(%d)", ival);
5481 value.Printf(
"(%d)", ival);
5489 double dval = *((
double *)pAttrVal->value);
5490 wxString val_suffix =
" m";
5491 bool has_preformatted =
false;
5492 wxString preformatted;
5495 if ((AttrName ==
"VERCLR") || (AttrName ==
"VERCCL") ||
5496 (AttrName ==
"VERCOP") || (AttrName ==
"HEIGHT") ||
5497 (AttrName ==
"ELEVAT")) {
5502 val_suffix = wxString::Format(
" %s",
unit.c_str());
5503 }
else if (AttrName ==
"HORCLR") {
5505 double nm = dval / 1852.0;
5507 has_preformatted =
true;
5510 else if ((AttrName ==
"VALSOU") || (AttrName ==
"DRVAL1") ||
5511 (AttrName ==
"DRVAL2")) {
5514 wxString
unit = getUsrDepthUnit(-1);
5515 val_suffix = wxString::Format(
" %s",
unit.c_str());
5518 else if (AttrName ==
"SECTR1")
5519 val_suffix =
"°";
5520 else if (AttrName ==
"SECTR2")
5521 val_suffix =
"°";
5522 else if (AttrName ==
"ORIENT")
5523 val_suffix =
"°";
5524 else if (AttrName ==
"VALNMR")
5526 else if (AttrName ==
"SIGPER")
5528 else if (AttrName ==
"VALACM")
5529 val_suffix =
" Minutes/year";
5530 else if (AttrName ==
"VALMAG")
5531 val_suffix =
"°";
5532 else if (AttrName ==
"CURVEL")
5535 if (has_preformatted) {
5536 value = preformatted;
5538 if (dval - floor(dval) < 0.01)
5539 value.Printf(
"%2.0f", dval);
5541 value.Printf(
"%4.1f", dval);
5542 value << val_suffix;
5548 case OGR_REAL_LST: {
5556 int positionDiff = l1->position.Cmp(l2->position);
5557 if (positionDiff < 0)
return false;
5559 int attrIndex1 = l1->attributeNames.Index(
"SECTR1");
5560 int attrIndex2 = l2->attributeNames.Index(
"SECTR1");
5563 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5564 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5565 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5567 double angle1, angle2;
5568 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5569 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5571 return angle1 < angle2;
5574static const char *type2str(GeoPrim_t type) {
5575 const char *r =
"Unknown";
5596wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5599 wxString curAttrName, value;
5600 bool isLight =
false;
5603 wxString classAttributes;
5605 wxString lightsHtml;
5606 wxString positionString;
5607 std::vector<S57Light *> lights;
5611 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5612 node = node->GetPrevious()) {
5613 ObjRazRules *current = node->GetData();
5614 positionString.Clear();
5618 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5620 if (current->obj->Primitive_type == GEO_META)
continue;
5621 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5623 className = wxString(current->obj->FeatureName, wxConvUTF8);
5626 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5631 const char *name_desc;
5632 if (g_csv_locn.Len()) {
5633 wxString oc_file(g_csv_locn);
5634 oc_file.Append(
"/s57objectclasses.csv");
5635 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5636 current->obj->FeatureName,
5637 CC_ExactString,
"ObjectClass");
5643 if (0 == strlen(name_desc)) {
5644 name_desc = current->obj->FeatureName;
5645 classDesc = wxString(name_desc, wxConvUTF8, 1);
5646 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5648 classDesc = wxString(name_desc, wxConvUTF8);
5655 classAttributes =
"";
5656 index.Printf(
"Feature Index: %d<br>", current->obj->Index);
5657 classAttributes << index;
5660 LUPstring.Printf(
"LUP RCID: %d<br>", current->LUP->RCID);
5661 classAttributes << LUPstring;
5664 LLBBox bbox = current->obj->BBObj;
5665 Bbox.Printf(
"Lat/Lon box: %g %g %g %g<br>", bbox.GetMinLat(),
5666 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5667 classAttributes << Bbox;
5670 Type.Printf(
" Type: %s<br>", type2str(current->obj->Primitive_type));
5671 classAttributes << Type;
5673 LUPstring =
" LUP ATTC: ";
5674 if (current->LUP->ATTArray.size())
5675 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5676 LUPstring +=
"<br>";
5677 classAttributes << LUPstring;
5679 LUPstring =
" LUP INST: ";
5680 LUPstring += current->LUP->INST;
5681 LUPstring +=
"<br><br>";
5682 classAttributes << LUPstring;
5685 if (GEO_POINT == current->obj->Primitive_type) {
5687 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5688 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5689 ref_lat, ref_lon, &lat, &lon);
5691 if (lon > 180.0) lon -= 360.;
5693 positionString.Clear();
5694 positionString += toSDMM(1, lat);
5695 positionString <<
" ";
5696 positionString += toSDMM(2, lon);
5700 curLight->position = positionString;
5701 curLight->hasSectors =
false;
5702 lights.push_back(curLight);
5708 if (current->obj->att_array) {
5709 char *curr_att = current->obj->att_array;
5715 attribStr <<
"<table border=0 cellspacing=0 cellpadding=0>";
5718 ret_val <<
"<p>" << classAttributes;
5721 bool inDepthRange =
false;
5723 while (attrCounter < current->obj->n_attr) {
5725 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5732 assert(curLight !=
nullptr);
5733 curLight->attributeNames.Add(curAttrName);
5734 if (curAttrName.StartsWith(
"SECTR")) curLight->hasSectors =
true;
5736 if (curAttrName ==
"DRVAL1") {
5737 attribStr <<
"<tr><td><font size=-1>";
5738 inDepthRange =
true;
5739 }
else if (curAttrName ==
"DRVAL2") {
5741 inDepthRange =
false;
5744 attribStr <<
"</font></td></tr>\n";
5745 inDepthRange =
false;
5747 attribStr <<
"<tr><td valign=top><font size=-2>";
5748 if (curAttrName ==
"catgeo")
5749 attribStr <<
"CATGEO";
5751 attribStr << curAttrName;
5752 attribStr <<
"</font></td><td> </td><td "
5753 "valign=top><font size=-1>";
5764 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5769 wxString AttrNamesFiles =
5770 "PICREP,TXTDSC,NTXTDS";
5772 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5773 if (value.Find(
".XML") == wxNOT_FOUND) {
5774 file.Assign(GetFullPath());
5775 file.Assign(file.GetPath(), value);
5778 if (file.IsCaseSensitive()) {
5779 wxDir dir(file.GetPath());
5781 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
5783 if (filename.IsSameAs(value,
false)) {
5785 file.Assign(file.GetPath(), value);
5788 cont = dir.GetNext(&filename);
5795 wxString::Format(
"<a href=\"%s\">%s</a>",
5796 file.GetFullPath(), file.GetFullName());
5798 value = value +
" <font color=\"red\">[ " +
5799 _(
"this file is not available") +
" ]</font>";
5803 "DATEND,DATSTA,PEREND,PERSTA";
5804 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5807 wxString ts = value;
5811 if (ts.Length() < 5) {
5815 if (ts.Length() < 7) {
5819 wxString::const_iterator end;
5821 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5823 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5824 if (d) ts.Append(wxString::Format(
" %d", dt.GetDay()));
5825 if (dt.GetYear() > 0)
5826 ts.Append(wxString::Format(
", %i", dt.GetYear()));
5827 if (curAttrName ==
"PEREND")
5828 ts = _(
"Period ends: ") + ts +
" (" + value +
")";
5829 if (curAttrName ==
"PERSTA")
5830 ts = _(
"Period starts: ") + ts +
" (" + value +
")";
5831 if (curAttrName ==
"DATEND")
5832 ts = _(
"Date ending: ") + ts +
" (" + value +
")";
5833 if (curAttrName ==
"DATSTA")
5834 ts = _(
"Date starting: ") + ts +
" (" + value +
")";
5838 if (curAttrName ==
"TS_TSP") {
5845 wxStringTokenizer tk(value,
",");
5850 ts1 = tk.GetNextToken().Trim(
false);
5853 }
while ((ts1.Left(2).ToLong(&l)));
5854 ts =
"Tidal Streams referred to<br><b>";
5855 ts.Append(tk.GetNextToken()).Append(
"</b> at <b>").Append(ts1);
5856 ts.Append(
"</b><br><table >");
5858 while (tk.HasMoreTokens()) {
5859 ts.Append(
"<tr><td>");
5860 wxString s1(wxString::Format(
"%+dh ", i));
5862 ts.Append(
"</td><td>");
5863 s1 = tk.GetNextToken();
5865 s1 =
"°</td><td>";
5867 s1 = tk.GetNextToken();
5870 ts.Append(
"</td></tr>");
5873 ts.Append(
"</table>");
5878 assert(curLight !=
nullptr);
5879 curLight->attributeValues.Add(value);
5881 if (curAttrName ==
"INFORM" || curAttrName ==
"NINFOM")
5882 value.Replace(
"|",
"<br>");
5884 if (curAttrName ==
"catgeo")
5885 attribStr << type2str(current->obj->Primitive_type);
5889 if (!(curAttrName ==
"DRVAL1")) {
5890 attribStr <<
"</font></td></tr>\n";
5900 attribStr <<
"</table>\n";
5902 objText +=
"<b>" + classDesc +
"</b> <font size=-2>(" + className +
5903 ")</font>" +
"<br>";
5905 if (positionString.Length())
5906 objText <<
"<font size=-2>" << positionString <<
"</font><br>\n";
5908 if (noAttr > 0) objText << attribStr;
5910 if (node != rule_list->GetFirst()) objText +=
"<hr noshade>";
5917 if (!lights.empty()) {
5918 assert(curLight !=
nullptr);
5923 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5927 for (
auto const &thisLight : lights) {
5930 if (thisLight->position != lastPos) {
5931 lastPos = thisLight->position;
5933 if (thisLight != *lights.begin())
5934 lightsHtml <<
"</table>\n<hr noshade>\n";
5936 lightsHtml <<
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>";
5937 lightsHtml <<
"<font size=-2>" << thisLight->position
5940 if (curLight->hasSectors)
5942 "<font size=-2>(Sector angles are True Bearings from "
5943 "Seaward)</font><br>");
5945 lightsHtml <<
"<table>";
5948 lightsHtml <<
"<tr>";
5949 lightsHtml <<
"<td><font size=-1>";
5952 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
5953 if (attrIndex != wxNOT_FOUND) {
5954 wxString color = thisLight->attributeValues.Item(attrIndex);
5955 if (color ==
"red (3)" || color ==
"red(3)")
5957 "<table border=0><tr><td "
5958 "bgcolor=red> </td></tr></table> ";
5959 else if (color ==
"green (4)" || color ==
"green(4)")
5961 "<table border=0><tr><td "
5962 "bgcolor=green> </td></tr></table> ";
5963 else if (color ==
"white (1)" || color ==
"white(1)")
5965 "<table border=0><tr><td "
5966 "bgcolor=white> </td></tr></table> ";
5967 else if (color ==
"yellow (6)" || color ==
"yellow(6)")
5969 "<table border=0><tr><td "
5970 "bgcolor=yellow> </td></tr></table> ";
5971 else if (color ==
"blue (5)" || color ==
"blue(5)")
5973 "<table border=0><tr><td "
5974 "bgcolor=blue> </td></tr></table> ";
5975 else if (color ==
"magenta (12)" || color ==
"magenta(12)")
5977 "<table border=0><tr><td "
5978 "bgcolor=magenta> </td></tr></table> ";
5981 "<table border=0><tr><td "
5982 "bgcolor=grey> ? </td></tr></table> ";
5985 int visIndex = thisLight->attributeNames.Index(
"LITVIS");
5986 if (visIndex != wxNOT_FOUND) {
5987 wxString vis = thisLight->attributeValues.Item(visIndex);
5988 if (vis.Contains(
"8")) {
5989 if (attrIndex != wxNOT_FOUND) {
5990 wxString color = thisLight->attributeValues.Item(attrIndex);
5991 if ((color ==
"red (3)" || color ==
"red(3)"))
5993 "<table border=0><tr><td "
5994 "bgcolor=DarkRed> </td></tr></table> ";
5995 if ((color ==
"green (4)" || color ==
"green(4)"))
5997 "<table border=0><tr><td "
5998 "bgcolor=DarkGreen> </td></tr></table> ";
5999 if ((color ==
"white (1)" || color ==
"white(1)"))
6001 "<table border=0><tr><td "
6002 "bgcolor=GoldenRod> </td></tr></table> ";
6007 lightsHtml << colorStr;
6009 lightsHtml <<
"</font></td><td><font size=-1><nobr><b>";
6011 attrIndex = thisLight->attributeNames.Index(
"LITCHR");
6012 if (attrIndex != wxNOT_FOUND) {
6013 wxString character = thisLight->attributeValues[attrIndex];
6014 lightsHtml << character.BeforeFirst(wxChar(
'(')) <<
" ";
6017 attrIndex = thisLight->attributeNames.Index(
"SIGGRP");
6018 if (attrIndex != wxNOT_FOUND) {
6019 lightsHtml << thisLight->attributeValues[attrIndex];
6023 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
6024 if (attrIndex != wxNOT_FOUND) {
6026 << thisLight->attributeValues.Item(attrIndex).Upper()[0];
6030 attrIndex = thisLight->attributeNames.Index(
"SIGPER");
6031 if (attrIndex != wxNOT_FOUND) {
6032 lightsHtml << thisLight->attributeValues[attrIndex];
6036 attrIndex = thisLight->attributeNames.Index(
"HEIGHT");
6037 if (attrIndex != wxNOT_FOUND) {
6038 lightsHtml << thisLight->attributeValues[attrIndex];
6042 attrIndex = thisLight->attributeNames.Index(
"VALNMR");
6043 if (attrIndex != wxNOT_FOUND) {
6044 lightsHtml << thisLight->attributeValues[attrIndex];
6048 lightsHtml <<
"</b>";
6050 attrIndex = thisLight->attributeNames.Index(
"SECTR1");
6051 if (attrIndex != wxNOT_FOUND) {
6052 lightsHtml <<
"(" << thisLight->attributeValues[attrIndex];
6053 lightsHtml <<
" - ";
6054 attrIndex = thisLight->attributeNames.Index(
"SECTR2");
6055 lightsHtml << thisLight->attributeValues[attrIndex] <<
") ";
6058 lightsHtml <<
"</nobr>";
6060 attrIndex = thisLight->attributeNames.Index(
"CATLIT");
6061 if (attrIndex != wxNOT_FOUND) {
6062 lightsHtml <<
"<nobr>";
6063 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6065 lightsHtml <<
"</nobr> ";
6068 attrIndex = thisLight->attributeNames.Index(
"EXCLIT");
6069 if (attrIndex != wxNOT_FOUND) {
6070 lightsHtml <<
"<nobr>";
6071 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6073 lightsHtml <<
"</nobr> ";
6076 attrIndex = thisLight->attributeNames.Index(
"OBJNAM");
6077 if (attrIndex != wxNOT_FOUND) {
6078 lightsHtml <<
"<br><nobr>";
6079 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6080 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6081 lightsHtml <<
"</nobr> ";
6084 lightsHtml <<
"</font></td>";
6085 lightsHtml <<
"</tr>";
6087 thisLight->attributeNames.Clear();
6088 thisLight->attributeValues.Clear();
6091 lightsHtml <<
"</table><hr noshade>\n";
6092 ret_val = lightsHtml << ret_val;
6106bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6108 wxLogMessage(
" Error: No ClassRegistrar in InitENCMinimal.");
6116 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6119 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6122 int rc = pENCReader->Ingest();
6126OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6128 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6139 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefnM_COVR(302);
6142 pENCReader->AddFeatureDefn(poDefn);
6145 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6148 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6151 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6162OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6166 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6169 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6172 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6175 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6184int s57chart::GetENCScale() {
6185 if (NULL == m_pENCDS)
return 0;
6192 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6195 return pENCReader->GetCSCL();
6205static void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6206 const char *pszErrorMsg) {
6207#define ERR_BUF_LEN 2000
6209 char buf[ERR_BUF_LEN + 1];
6211 if (eErrClass == CE_Debug)
6212 sprintf(buf,
" %s", pszErrorMsg);
6213 else if (eErrClass == CE_Warning)
6214 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6216 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6218 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6219 wxString msg(buf, wxConvUTF8);
6225 if (eErrClass == CE_Fatal) {
6226 longjmp(env_ogrf, 1);
6237const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6238 const char *pszKeyFieldValue,
6239 CSVCompareCriteria eCriteria,
6240 const char *pszTargetField)
6249 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6250 pszKeyFieldValue, eCriteria);
6252 if (papszRecord == NULL)
return "";
6257 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6258 if (iTargetField < 0)
return "";
6260 if (iTargetField >= CSLCount(papszRecord))
return "";
6262 return (papszRecord[iTargetField]);
6276static bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6300 std::vector<s57Sector_t> §orlegs) {
6301 float rangeScale = 0.0;
6303 if (sectorlegs.size() > 0) {
6304 std::vector<int> sectorangles;
6305 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6306 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6309 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6310 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6315 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6316 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6322 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6325 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6326 powf((
float)(lightPos.y - end1.y), 2));
6328 if (rangeScale == 0.0) {
6331 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6335 rangePx = rangePx * rangeScale;
6337 int penWidth = rangePx / 8;
6338 penWidth = wxMin(20, penWidth);
6339 penWidth = wxMax(5, penWidth);
6342 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
6343 penWidth, wxPENSTYLE_SOLID);
6344 arcpen->SetCap(wxCAP_BUTT);
6347 float angle1, angle2;
6348 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6349 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6350 if (angle1 > angle2) {
6353 int lpx = lightPos.x;
6354 int lpy = lightPos.y;
6356 wxPoint arcpoints[150];
6359 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6363 int narc = (angle2 - angle1) / step;
6365 step = (angle2 - angle1) / (
float)narc;
6367 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6368 wxPoint yellowCone[3];
6369 yellowCone[0] = lightPos;
6370 yellowCone[1] = end1;
6371 yellowCone[2] = end2;
6372 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6375 wxColor c = sectorlegs[i].color;
6376 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6377 dc.SetBrush(wxBrush(c));
6378 dc.StrokePolygon(3, yellowCone, 0, 0);
6381 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6382 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6383 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6384 arcpoints[npoints].x = x;
6385 arcpoints[npoints].y = y;
6388 dc.StrokeLines(npoints, arcpoints);
6392 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6398 bool haveAngle1 =
false;
6399 bool haveAngle2 =
false;
6400 int sec1 = (int)sectorlegs[i].sector1;
6401 int sec2 = (int)sectorlegs[i].sector2;
6402 if (sec1 > 360) sec1 -= 360;
6403 if (sec2 > 360) sec2 -= 360;
6405 if ((sec2 == 360) && (sec1 == 0))
6408 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6409 if (sectorangles[j] == sec1) haveAngle1 =
true;
6410 if (sectorangles[j] == sec2) haveAngle2 =
true;
6414 dc.StrokeLine(lightPos, end1);
6415 sectorangles.push_back(sec1);
6419 dc.StrokeLine(lightPos, end2);
6420 sectorangles.push_back(sec2);
6427void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6428 std::vector<s57Sector_t> §orlegs) {
6429 float rangeScale = 0.0;
6431 if (sectorlegs.size() > 0) {
6432 std::vector<int> sectorangles;
6433 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6434 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6437 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6438 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6443 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6444 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6450 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6453 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6454 powf((
float)(lightPos.y - end1.y), 2));
6456 if (rangeScale == 0.0) {
6459 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6463 rangePx = rangePx * rangeScale;
6465 float arcw = rangePx / 10;
6466 arcw = wxMin(20, arcw);
6467 arcw = wxMax(5, arcw);
6471 float angle1, angle2;
6472 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6473 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6474 if (angle1 > angle2) {
6477 int lpx = lightPos.x;
6478 int lpy = lightPos.y;
6480 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6481 wxPoint yellowCone[3];
6482 yellowCone[0] = lightPos;
6483 yellowCone[1] = end1;
6484 yellowCone[2] = end2;
6485 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6488 wxColor c = sectorlegs[i].color;
6489 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6490 dc.SetBrush(wxBrush(c));
6491 dc.StrokePolygon(3, yellowCone, 0, 0);
6495 wxPoint r(lpx, lpy);
6498 float rad = rangePx;
6522 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6525 glBindBuffer(GL_ARRAY_BUFFER, 0);
6526 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6528 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6529 glEnableVertexAttribArray(mPosAttrib);
6533 glGetUniformLocation(shader->programId(),
"circle_radius");
6534 glUniform1f(radiusloc, rad);
6538 glGetUniformLocation(shader->programId(),
"circle_center");
6542 glUniform2fv(centerloc, 1, ctrv);
6545 wxColour colorb = sectorlegs[i].color;
6547 colorv[0] = colorb.Red() / float(256);
6548 colorv[1] = colorb.Green() / float(256);
6549 colorv[2] = colorb.Blue() / float(256);
6550 colorv[3] = colorb.Alpha() / float(256);
6553 glGetUniformLocation(shader->programId(),
"circle_color");
6554 glUniform4fv(colloc, 1, colorv);
6564 glGetUniformLocation(shader->programId(),
"border_color");
6565 glUniform4fv(bcolloc, 1, bcolorv);
6568 GLint borderWidthloc =
6569 glGetUniformLocation(shader->programId(),
"border_width");
6570 glUniform1f(borderWidthloc, 2);
6573 GLint ringWidthloc =
6574 glGetUniformLocation(shader->programId(),
"ring_width");
6575 glUniform1f(ringWidthloc, arcw);
6579 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
6580 if (sr1 > 360.) sr1 -= 360.;
6582 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
6583 if (sr2 > 360.) sr2 -= 360.;
6595 if ((sb < 0) || (se < 0)) {
6601 glGetUniformLocation(shader->programId(),
"sector_1");
6602 glUniform1f(sector1loc, (sb * PI / 180.));
6604 glGetUniformLocation(shader->programId(),
"sector_2");
6605 glUniform1f(sector2loc, (se * PI / 180.));
6610 mat4x4_translate_in_place(I, r.x, r.y, 0);
6613 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6614 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6617 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6621 mat4x4_identity(IM);
6623 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6624 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6626 glDisableVertexAttribArray(mPosAttrib);
6632 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6637 bool haveAngle1 =
false;
6638 bool haveAngle2 =
false;
6639 int sec1 = (int)sectorlegs[i].sector1;
6640 int sec2 = (int)sectorlegs[i].sector2;
6641 if (sec1 > 360) sec1 -= 360;
6642 if (sec2 > 360) sec2 -= 360;
6644 if ((sec2 == 360) && (sec1 == 0))
6647 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6648 if (sectorangles[j] == sec1) haveAngle1 =
true;
6649 if (sectorangles[j] == sec2) haveAngle2 =
true;
6653 dc.StrokeLine(lightPos, end1);
6654 sectorangles.push_back(sec1);
6658 dc.StrokeLine(lightPos, end2);
6659 sectorangles.push_back(sec2);
6667bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6670 ListOfObjRazRules *rule_list,
6671 ListOfPI_S57Obj *pi_rule_list,
6672 std::vector<s57Sector_t> §orlegs) {
6673 bool newSectorsNeedDrawing =
false;
6675 bool bhas_red_green =
false;
6676 bool bleading_attribute =
false;
6679 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6680 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6682 int yOpacity = (float)opacity *
6685 if (target_plugin_chart || Chs57) {
6688 wxPoint2DDouble objPos;
6690 char *curr_att = NULL;
6692 wxArrayOfS57attVal *attValArray = NULL;
6694 ListOfObjRazRules::Node *snode = NULL;
6695 ListOfPI_S57Obj::Node *pnode = NULL;
6697 if (Chs57 && rule_list)
6698 snode = rule_list->GetLast();
6699 else if (target_plugin_chart && pi_rule_list)
6700 pnode = pi_rule_list->GetLast();
6703 wxPoint2DDouble lightPosD(0, 0);
6704 bool is_light =
false;
6708 ObjRazRules *current = snode->GetData();
6709 S57Obj *light = current->obj;
6710 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6711 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6712 curr_att = light->att_array;
6713 n_attr = light->n_attr;
6714 attValArray = light->attVal;
6717 }
else if (target_plugin_chart) {
6721 objPos = wxPoint2DDouble(light->
m_lat, light->
m_lon);
6724 attValArray = light->
attVal;
6734 wxString curAttrName;
6737 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6739 if (is_light && (lightPosD == objPos)) {
6747 bleading_attribute =
false;
6749 while (attrCounter < n_attr) {
6750 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6753 S57attVal *pAttrVal = NULL;
6756 pAttrVal = attValArray->Item(attrCounter);
6757 else if (target_plugin_chart)
6758 pAttrVal = attValArray->Item(attrCounter);
6762 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6764 if (curAttrName ==
"LITVIS") {
6765 if (value.StartsWith(
"obsc")) bviz =
false;
6767 if (curAttrName ==
"SECTR1") value.ToDouble(§r1);
6768 if (curAttrName ==
"SECTR2") value.ToDouble(§r2);
6769 if (curAttrName ==
"VALNMR") value.ToDouble(&valnmr);
6770 if (curAttrName ==
"COLOUR") {
6771 if (value ==
"red(3)") {
6772 color = wxColor(255, 0, 0, opacity);
6773 sector.iswhite =
false;
6774 bhas_red_green =
true;
6777 if (value ==
"green(4)") {
6778 color = wxColor(0, 255, 0, opacity);
6779 sector.iswhite =
false;
6780 bhas_red_green =
true;
6784 if (curAttrName ==
"EXCLIT") {
6785 if (value.Find(
"(3)")) valnmr = 1.0;
6788 if (curAttrName ==
"CATLIT") {
6789 if (value.Upper().StartsWith(
"DIRECT") ||
6790 value.Upper().StartsWith(
"LEAD"))
6791 bleading_attribute =
true;
6798 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6799 if (sectr1 > sectr2) {
6803 sector.pos.m_x = objPos.m_y;
6804 sector.pos.m_y = objPos.m_x;
6807 (valnmr > 0.0) ? valnmr : 2.5;
6808 sector.sector1 = sectr1;
6809 sector.sector2 = sectr2;
6811 if (!color.IsOk()) {
6812 color = wxColor(255, 255, 0, yOpacity);
6813 sector.iswhite =
true;
6815 sector.color = color;
6816 sector.isleading =
false;
6818 if (bleading_attribute) sector.isleading =
true;
6820 bool newsector =
true;
6821 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6822 if (sectorlegs[i].pos == sector.pos &&
6823 sectorlegs[i].sector1 == sector.sector1 &&
6824 sectorlegs[i].sector2 == sector.sector2) {
6830 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6834 if (!bviz) newsector =
false;
6836 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6840 sectorlegs.push_back(sector);
6841 newSectorsNeedDrawing =
true;
6848 snode = snode->GetPrevious();
6849 else if (target_plugin_chart)
6850 pnode = pnode->GetPrevious();
6858 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6859 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6860 if (sectorlegs[i].iswhite && bhas_red_green)
6861 sectorlegs[i].isleading =
true;
6865 return newSectorsNeedDrawing;
6868bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6870 std::vector<s57Sector_t> §orlegs) {
6871 if (!cc)
return false;
6873 static float lastLat, lastLon;
6875 if (!ps52plib)
return false;
6883 if (cc->m_singleChart &&
6884 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6885 target_chart = cc->m_singleChart;
6886 else if (viewport.b_quilt)
6887 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6889 target_chart = NULL;
6892 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6893 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6896 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6899 bool newSectorsNeedDrawing =
false;
6901 if (target_plugin_chart || Chs57) {
6902 ListOfObjRazRules *rule_list = NULL;
6903 ListOfPI_S57Obj *pi_rule_list = NULL;
6910 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6911 else if (target_plugin_chart)
6912 pi_rule_list =
g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6913 target_plugin_chart, lat, lon, viewport);
6915 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6916 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6924 pi_rule_list->Clear();
6925 delete pi_rule_list;
6929 return newSectorsNeedDrawing;
6932bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6934 std::vector<s57Sector_t> §orlegs) {
6935 if (!cc)
return false;
6937 double cursor_lat, cursor_lon;
6938 static float lastLat, lastLon;
6940 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6945 ChartBase *target_chart = cc->GetChartAtCursor();
6947 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6948 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6951 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6956 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6958 lastLat = cursor_lat;
6959 lastLon = cursor_lon;
6960 bool newSectorsNeedDrawing =
false;
6962 if (target_plugin_chart || Chs57) {
6963 ListOfObjRazRules *rule_list = NULL;
6964 ListOfPI_S57Obj *pi_rule_list = NULL;
6970 rule_list = Chs57->GetObjRuleListAtLatLon(
6971 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6972 else if (target_plugin_chart)
6973 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
6974 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6976 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6977 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6985 pi_rule_list->Clear();
6986 delete pi_rule_list;
6990 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.
Declarations for classes binding S57 support onto OGRLayer, OGRDataSource and OGRDriver.
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.
An s57 class registry container.
S57ClassRegistrar * g_poRegistrar
Global instance.
SENCThreadManager * g_SencThreadManager
Global instance.
Represents a sector of a light in an S57 chart.
Abstract gFrame/MyFrame interface.