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 case GLOBAL_COLOR_SCHEME_DAY_HICON:
398 pThumbData->pDIBThumb = m_pDIBThumbDay;
399 m_pDIBThumbOrphan = m_pDIBThumbDim;
401 case GLOBAL_COLOR_SCHEME_DUSK:
402 case GLOBAL_COLOR_SCHEME_NIGHT_HICON:
403 case GLOBAL_COLOR_SCHEME_NIGHT: {
404 if (NULL == m_pDIBThumbDim) {
405 wxImage img = m_pDIBThumbDay->ConvertToImage();
407#if wxCHECK_VERSION(2, 8, 0)
408 wxImage gimg = img.ConvertToGreyscale(
418 wxBitmap *pBMP =
new wxBitmap(gimg);
420 m_pDIBThumbDim = pBMP;
421 m_pDIBThumbOrphan = m_pDIBThumbDay;
424 pThumbData->pDIBThumb = m_pDIBThumbDim;
430bool s57chart::GetChartExtent(
Extent *pext) {
432 *pext = m_FullExtent;
438static void free_mps(mps_container *mps) {
439 if (mps == 0)
return;
440 if (ps52plib && mps->cs_rules) {
441 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
442 Rules *rule_chain_top = mps->cs_rules->Item(i);
443 ps52plib->DestroyRulesChain(rule_chain_top);
445 delete mps->cs_rules;
450void s57chart::FreeObjectsAndRules() {
459 for (
int i = 0; i < PRIO_NUM; ++i) {
460 for (
int j = 0; j < LUPNAME_NUM; j++) {
461 top = razRules[i][j];
462 while (top != NULL) {
464 if (0 == top->obj->nRef)
delete top->obj;
467 ObjRazRules *ctop = top->child;
471 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
473 ObjRazRules *cnxx = ctop->next;
488void s57chart::ClearRenderedTextCache() {
490 for (
int i = 0; i < PRIO_NUM; ++i) {
491 for (
int j = 0; j < LUPNAME_NUM; j++) {
492 top = razRules[i][j];
493 while (top != NULL) {
494 if (top->obj->bFText_Added) {
495 top->obj->bFText_Added =
false;
496 delete top->obj->FText;
497 top->obj->FText = NULL;
501 ObjRazRules *ctop = top->child;
503 if (ctop->obj->bFText_Added) {
504 ctop->obj->bFText_Added =
false;
505 delete ctop->obj->FText;
506 ctop->obj->FText = NULL;
518double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
519 bool b_allow_overzoom) {
521 return m_Chart_Scale * 0.125;
525double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
527 return m_Chart_Scale * 4.0;
534void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
536 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
538 r->y = roundint(m_pixy_vp_center -
539 ((north - m_northing_vp_center) * m_view_scale_ppm));
542void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
543 wxPoint *r,
int nPoints) {
544 for (
int i = 0; i < nPoints; i++) {
545 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
547 r[i].y = roundint(m_pixy_vp_center -
548 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
552void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
554 if (vpt->m_projection_type != PROJECTION_MERCATOR)
555 printf(
"s57chart unhandled projection\n");
561 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
562 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
568 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
578void s57chart::SetVPParms(
const ViewPort &vpt) {
584 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
585 &m_northing_vp_center);
587 vp_transform.easting_vp_center = m_easting_vp_center;
588 vp_transform.northing_vp_center = m_northing_vp_center;
592 if (IsCacheValid()) {
595 double prev_easting_c, prev_northing_c;
596 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
599 double easting_c, northing_c;
600 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
608 int dpix_x = (int)round(delta_pix_x);
613 int dpix_y = (int)round(delta_pix_y);
616 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
617 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
620 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
622 vp_proposed.
clon = xlon;
623 vp_proposed.
clat = xlat;
650void s57chart::LoadThumb() {
651 wxFileName fn(m_FullPath);
652 wxString SENCdir = g_SENCPrefix;
654 if (SENCdir.Last() != fn.GetPathSeparator())
655 SENCdir.Append(fn.GetPathSeparator());
657 wxFileName tsfn(SENCdir);
658 tsfn.SetFullName(fn.GetFullName());
660 wxFileName ThumbFileNameLook(tsfn);
661 ThumbFileNameLook.SetExt(
"BMP");
664 if (ThumbFileNameLook.FileExists()) {
667 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
668 m_pDIBThumbDay = pBMP;
669 m_pDIBThumbOrphan = 0;
674ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
677 if (pThumbData->pDIBThumb == 0) {
679 ChangeThumbColor(m_global_color_scheme);
682 UpdateThumbData(lat, lon);
687bool s57chart::UpdateThumbData(
double lat,
double lon) {
691 if (pThumbData->pDIBThumb) {
692 double lat_top = m_FullExtent.NLAT;
693 double lat_bot = m_FullExtent.SLAT;
694 double lon_left = m_FullExtent.WLON;
695 double lon_right = m_FullExtent.ELON;
698 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
700 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
702 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
705 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
706 (int)(east * thumb_view_scale_ppm);
707 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
708 (int)(north * thumb_view_scale_ppm);
715 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
716 pThumbData->ShipX = test_x;
717 pThumbData->ShipY = test_y;
723void s57chart::SetFullExtent(
Extent &ext) {
724 m_FullExtent.NLAT = ext.NLAT;
725 m_FullExtent.SLAT = ext.SLAT;
726 m_FullExtent.WLON = ext.WLON;
727 m_FullExtent.ELON = ext.ELON;
732void s57chart::ForceEdgePriorityEvaluate() { m_bLinePrioritySet =
false; }
734void s57chart::SetLinePriorities() {
735 if (!ps52plib)
return;
740 if (!m_bLinePrioritySet) {
744 for (
int i = 0; i < PRIO_NUM; ++i) {
745 top = razRules[i][2];
746 while (top != NULL) {
747 ObjRazRules *crnt = top;
749 ps52plib->SetLineFeaturePriority(crnt, i);
755 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
760 top = razRules[i][j];
761 while (top != NULL) {
764 ps52plib->SetLineFeaturePriority(crnt, i);
770 for (
int i = 0; i < PRIO_NUM; ++i) {
771 for (
int j = 0; j < LUPNAME_NUM; j++) {
772 ObjRazRules *top = razRules[i][j];
773 while (top != NULL) {
774 S57Obj *obj = top->obj;
777 connector_segment *pcs;
778 line_segment_element *list = obj->m_ls_list;
780 switch (list->ls_type) {
784 if (pedge) list->priority = pedge->max_priority;
789 if (pcs) list->priority = pcs->max_priority_cs;
804 m_bLinePrioritySet =
true;
808void s57chart::SetLinePriorities(
void )
810 if( !ps52plib )
return;
815 if( !m_bLinePrioritySet ) {
819 for(
int i = 0; i < PRIO_NUM; ++i ) {
821 top = razRules[i][2];
822 while( top != NULL ) {
823 ObjRazRules *crnt = top;
825 ps52plib->SetLineFeaturePriority( crnt, i );
830 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
835 top = razRules[i][j];
836 while( top != NULL ) {
839 ps52plib->SetLineFeaturePriority( crnt, i );
847 for(
int i = 0; i < PRIO_NUM; ++i ) {
848 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
849 ObjRazRules *top = razRules[i][j];
850 while( top != NULL ) {
851 S57Obj *obj = top->obj;
854 connector_segment *pcs;
855 line_segment_element *list = obj->m_ls_list;
860 pedge = (VE_Element *)list->private0;
862 list->priority = pedge->max_priority;
866 pcs = (connector_segment *)list->private0;
868 list->priority = pcs->max_priority;
883 m_bLinePrioritySet =
true;
887int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
891 line_segment_element *ls_list = obj->m_ls_list;
893 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
894 nPoints += ls_list->pedge->nCount;
897 ls_list = ls_list->next;
906 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
910 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
911 ls_list = obj->m_ls_list;
913 size_t vbo_offset = 0;
915 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
916 vbo_offset = ls_list->pedge->vbo_offset;
917 count = ls_list->pedge->nCount;
919 vbo_offset = ls_list->pcs->vbo_offset;
923 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
925 ls_list = ls_list->next;
932int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
937 line_segment_element *ls_list = obj->m_ls_list;
939 nPoints += ls_list->n_points;
940 ls_list = ls_list->next;
949 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
953 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
954 ls_list = obj->m_ls_list;
956 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
957 br += ls_list->n_points * 2;
958 ls_list = ls_list->next;
967 float e0, n0, e1, n1;
970void s57chart::AssembleLineGeometry() {
975 for (
const auto &it : m_ve_hash) {
976 VE_Element *pedge = it.second;
978 nPoints += pedge->nCount;
984 std::map<long long, connector_segment *> ce_connector_hash;
985 std::map<long long, connector_segment *> ec_connector_hash;
986 std::map<long long, connector_segment *> cc_connector_hash;
988 std::map<long long, connector_segment *>::iterator csit;
995 std::vector<segment_pair> connector_segment_vector;
996 size_t seg_pair_index = 0;
1001 for (
int i = 0; i < PRIO_NUM; ++i) {
1002 for (
int j = 0; j < LUPNAME_NUM; j++) {
1003 ObjRazRules *top = razRules[i][j];
1004 while (top != NULL) {
1005 S57Obj *obj = top->obj;
1007 if ((!obj->m_ls_list) &&
1010 line_segment_element list_top;
1013 line_segment_element *le_current = &list_top;
1015 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1016 if (!obj->m_lsindex_array)
continue;
1018 int seg_index = iseg * 3;
1019 int *index_run = &obj->m_lsindex_array[seg_index];
1022 unsigned int inode = *index_run++;
1025 bool edge_dir =
true;
1026 int venode = *index_run++;
1032 VE_Element *pedge = 0;
1034 if (m_ve_hash.find(venode) != m_ve_hash.end())
1035 pedge = m_ve_hash[venode];
1039 unsigned int enode = *index_run++;
1042 VC_Element *ipnode = 0;
1043 ipnode = m_vc_hash[inode];
1046 VC_Element *epnode = 0;
1047 epnode = m_vc_hash[enode];
1050 if (pedge && pedge->nCount) {
1054 long long key = ((
unsigned long long)inode << 32) + venode;
1056 connector_segment *pcs = NULL;
1057 csit = ce_connector_hash.find(key);
1058 if (csit == ce_connector_hash.end()) {
1060 pcs =
new connector_segment;
1061 ce_connector_hash[key] = pcs;
1065 float *ppt = ipnode->pPoint;
1070 pair.e1 = pedge->pPoints[0];
1071 pair.n1 = pedge->pPoints[1];
1073 int last_point_index = (pedge->nCount - 1) * 2;
1074 pair.e1 = pedge->pPoints[last_point_index];
1075 pair.n1 = pedge->pPoints[last_point_index + 1];
1078 connector_segment_vector.push_back(pair);
1079 pcs->vbo_offset = seg_pair_index;
1086 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1088 pcs->cs_lat_avg = lat;
1089 pcs->cs_lon_avg = lon;
1094 line_segment_element *pls =
new line_segment_element;
1099 pls->ls_type = TYPE_CE;
1101 le_current->next = pls;
1106 if (pedge && pedge->nCount) {
1107 line_segment_element *pls =
new line_segment_element;
1112 pls->ls_type = TYPE_EE;
1113 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1115 le_current->next = pls;
1123 if (pedge && pedge->nCount) {
1124 long long key = ((
unsigned long long)venode << 32) + enode;
1126 connector_segment *pcs = NULL;
1127 csit = ec_connector_hash.find(key);
1128 if (csit == ec_connector_hash.end()) {
1130 pcs =
new connector_segment;
1131 ec_connector_hash[key] = pcs;
1137 pair.e0 = pedge->pPoints[0];
1138 pair.n0 = pedge->pPoints[1];
1140 int last_point_index = (pedge->nCount - 1) * 2;
1141 pair.e0 = pedge->pPoints[last_point_index];
1142 pair.n0 = pedge->pPoints[last_point_index + 1];
1145 float *ppt = epnode->pPoint;
1149 connector_segment_vector.push_back(pair);
1150 pcs->vbo_offset = seg_pair_index;
1157 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1159 pcs->cs_lat_avg = lat;
1160 pcs->cs_lon_avg = lon;
1165 line_segment_element *pls =
new line_segment_element;
1169 pls->ls_type = TYPE_EC;
1171 le_current->next = pls;
1175 long long key = ((
unsigned long long)inode << 32) + enode;
1177 connector_segment *pcs = NULL;
1178 csit = cc_connector_hash.find(key);
1179 if (csit == cc_connector_hash.end()) {
1181 pcs =
new connector_segment;
1182 cc_connector_hash[key] = pcs;
1187 float *ppt = ipnode->pPoint;
1191 ppt = epnode->pPoint;
1195 connector_segment_vector.push_back(pair);
1196 pcs->vbo_offset = seg_pair_index;
1203 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1205 pcs->cs_lat_avg = lat;
1206 pcs->cs_lon_avg = lon;
1211 line_segment_element *pls =
new line_segment_element;
1215 pls->ls_type = TYPE_CC;
1217 le_current->next = pls;
1231 if (obj->m_ls_list == NULL) {
1232 obj->m_n_lsindex = 0;
1236 free(obj->m_lsindex_array);
1237 obj->m_lsindex_array = NULL;
1250 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1252 unsigned char *buffer_offset;
1255 bool grow_buffer =
false;
1257 if (0 == m_vbo_byte_length) {
1258 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1259 m_vbo_byte_length = vbo_byte_length;
1260 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1263 m_line_vertex_buffer = (
float *)realloc(
1264 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1265 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1266 offset = m_vbo_byte_length;
1267 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1271 float *lvr = (
float *)buffer_offset;
1275 for (
const auto &it : m_ve_hash) {
1276 VE_Element *pedge = it.second;
1278 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1279 lvr += pedge->nCount * 2;
1281 pedge->vbo_offset = offset;
1282 offset += pedge->nCount * 2 *
sizeof(float);
1295 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1297 connector_segment *pcs = csit->second;
1298 m_pcs_vector.push_back(pcs);
1300 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1306 pcs->vbo_offset = offset;
1307 offset += 4 *
sizeof(float);
1310 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1312 connector_segment *pcs = csit->second;
1313 m_pcs_vector.push_back(pcs);
1315 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1321 pcs->vbo_offset = offset;
1322 offset += 4 *
sizeof(float);
1325 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1327 connector_segment *pcs = csit->second;
1328 m_pcs_vector.push_back(pcs);
1330 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1336 pcs->vbo_offset = offset;
1337 offset += 4 *
sizeof(float);
1341 connector_segment_vector.clear();
1346 for (
const auto &it : m_ve_hash) {
1347 VE_Element *pedge = it.second;
1349 m_pve_vector.push_back(pedge);
1350 free(pedge->pPoints);
1358 for (
const auto &it : m_vc_hash) {
1359 VC_Element *pcs = it.second;
1360 if (pcs) free(pcs->pPoint);
1366 if (g_b_EnableVBO) {
1368 if (m_LineVBO_name > 0) {
1369 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1370 m_LineVBO_name = -1;
1377void s57chart::BuildLineVBO() {
1379 if (!g_b_EnableVBO)
return;
1381 if (m_LineVBO_name == -1) {
1384 glGenBuffers(1, &vboId);
1387 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1393#ifndef USE_ANDROID_GLES2
1394 glEnableClientState(GL_VERTEX_ARRAY);
1396 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1401 ObjRazRules *top, *crnt;
1402 int vbo_area_size_bytes = 0;
1403 for (
int i = 0; i < PRIO_NUM; ++i) {
1404 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1405 top = razRules[i][4];
1407 top = razRules[i][3];
1409 while (top != NULL) {
1414 PolyTriGroup *ppg_vbo =
1415 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1417 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1424 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes, NULL,
1427 GLenum err = glGetError();
1430 msg.Printf(
"S57 VBO Error 1: %d", err);
1432 printf(
"S57 VBO Error 1: %d", err);
1436 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length,
1437 m_line_vertex_buffer);
1442 msg.Printf(
"S57 VBO Error 2: %d", err);
1444 printf(
"S57 VBO Error 2: %d", err);
1448 int vbo_load_offset = m_vbo_byte_length;
1450 for (
int i = 0; i < PRIO_NUM; ++i) {
1451 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1452 top = razRules[i][4];
1454 top = razRules[i][3];
1456 while (top != NULL) {
1461 PolyTriGroup *ppg_vbo =
1462 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1465 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1466 ppg_vbo->single_buffer_size, ppg_vbo->single_buffer);
1468 crnt->obj->vboAreaOffset = vbo_load_offset;
1469 vbo_load_offset += ppg_vbo->single_buffer_size;
1476 msg.Printf(
"S57 VBO Error 3: %d", err);
1478 printf(
"S57 VBO Error 3: %d", err);
1483#ifndef USE_ANDROID_GLES2
1484 glDisableClientState(GL_VERTEX_ARRAY);
1486 glBindBuffer(GL_ARRAY_BUFFER, 0);
1490 for (
int i = 0; i < PRIO_NUM; ++i) {
1491 for (
int j = 0; j < LUPNAME_NUM; j++) {
1492 ObjRazRules *top = razRules[i][j];
1493 while (top != NULL) {
1494 S57Obj *obj = top->obj;
1495 obj->auxParm2 = vboId;
1501 m_LineVBO_name = vboId;
1502 m_this_chart_context->vboID = vboId;
1521bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1524 const LLRegion &Region) {
1525 if (!m_RAZBuilt)
return false;
1527 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1530bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1533 const LLRegion &Region) {
1534 if (!m_RAZBuilt)
return false;
1536 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1539bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1542 const LLRegion &Region) {
1543 if (!m_RAZBuilt)
return false;
1545 bool b_text = ps52plib->GetShowS57Text();
1546 ps52plib->m_bShowS57Text =
false;
1547 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1548 ps52plib->m_bShowS57Text = b_text;
1553bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1555 if (!m_RAZBuilt)
return false;
1559 if (!ps52plib)
return false;
1562 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1564 glChartCanvas::DisableClipRegion();
1565 DoRenderOnGLText(glc, VPoint);
1571bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1574 const LLRegion &Region,
bool b_overlay) {
1575 if (!m_RAZBuilt)
return false;
1579 if (!ps52plib)
return false;
1581 if (g_bDebugS57) printf(
"\n");
1585 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1587 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1588 m_bLinePrioritySet =
false;
1590 ClearRenderedTextCache();
1592 ResetPointBBoxes(m_last_vp, VPoint);
1595 m_plib_state_hash = ps52plib->GetStateHash();
1599 ResetPointBBoxes(m_last_vp, VPoint);
1603 SetLinePriorities();
1606 ps52plib->ClearTextList();
1614 wxRect upr = upd.GetRect();
1617 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1618 chart_region.Intersect(Region);
1620 if (!chart_region.Empty()) {
1624 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1631 if (CHART_TYPE_CM93 == GetChartType()) {
1635 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1638#ifdef OPT_USE_ANDROID_GLES2
1646 wxRect r = upd.GetRect();
1648 glViewport(r.x, vp->
pix_height - (r.y + r.height), r.width, r.height);
1656 float yp = vp->
pix_height - (r.y + r.height);
1658 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1659 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1662 I[0][0] *= 2.0 / (float)r.width;
1663 I[1][1] *= -2.0 / (float)r.height;
1667 mat4x4_rotate_Z(Q, I, angle);
1669 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1672 ps52plib->SetReducedBBox(cvp.GetBBox());
1673 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1678 DoRenderOnGL(glc, cvp);
1680 glChartCanvas::DisableClipRegion();
1693bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1706 for (i = 0; i < PRIO_NUM; ++i) {
1707 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1708 top = razRules[i][4];
1710 top = razRules[i][3];
1712 while (top != NULL) {
1715 crnt->sm_transform_parms = &vp_transform;
1716 ps52plib->RenderAreaToGL(glc, crnt);
1722 for (i = 0; i < PRIO_NUM; ++i) {
1724 top = razRules[i][4];
1726 top = razRules[i][3];
1728 while (top != NULL) {
1731 crnt->sm_transform_parms = &vp_transform;
1736 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1737 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1738 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1739 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1742 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1749 for (i = 0; i < PRIO_NUM; ++i) {
1750 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1751 top = razRules[i][4];
1753 top = razRules[i][3];
1754 while (top != NULL) {
1757 crnt->sm_transform_parms = &vp_transform;
1758 ps52plib->RenderObjectToGL(glc, crnt);
1763 for (i = 0; i < PRIO_NUM; ++i) {
1764 top = razRules[i][2];
1765 while (top != NULL) {
1768 crnt->sm_transform_parms = &vp_transform;
1769 ps52plib->RenderObjectToGL(glc, crnt);
1775 for (i = 0; i < PRIO_NUM; ++i) {
1776 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1777 top = razRules[i][0];
1779 top = razRules[i][1];
1781 while (top != NULL) {
1784 crnt->sm_transform_parms = &vp_transform;
1785 ps52plib->RenderObjectToGL(glc, crnt);
1795bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1806 for( i = 0; i < PRIO_NUM; ++i ) {
1807 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1808 top = razRules[i][4];
1810 top = razRules[i][3];
1812 while( top != NULL ) {
1815 crnt->sm_transform_parms = &vp_transform;
1822 for (i = 0; i < PRIO_NUM; ++i) {
1823 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1824 top = razRules[i][4];
1826 top = razRules[i][3];
1828 while (top != NULL) {
1831 crnt->sm_transform_parms = &vp_transform;
1832 ps52plib->RenderObjectToGLText(glc, crnt);
1835 top = razRules[i][2];
1836 while (top != NULL) {
1839 crnt->sm_transform_parms = &vp_transform;
1840 ps52plib->RenderObjectToGLText(glc, crnt);
1843 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1844 top = razRules[i][0];
1846 top = razRules[i][1];
1848 while (top != NULL) {
1851 crnt->sm_transform_parms = &vp_transform;
1852 ps52plib->RenderObjectToGLText(glc, crnt);
1861bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1864 if (!m_RAZBuilt)
return false;
1866 bool b_text = ps52plib->GetShowS57Text();
1867 ps52plib->m_bShowS57Text =
false;
1868 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1869 ps52plib->m_bShowS57Text = b_text;
1874bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1877 if (!dc.IsOk())
return false;
1880 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1885 DCRenderText(dc, VPoint);
1888 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1892 while (upd.HaveRects()) {
1893 wxRect rect = upd.GetRect();
1899 temp_vp.
GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1903 temp_vp.
GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1905 if (temp_lon_right < temp_lon_left)
1906 temp_lon_right += 360.;
1908 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1911 wxDCClipper clip(dc, rect);
1912 DCRenderText(dc, temp_vp);
1921bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1923 if (!m_RAZBuilt)
return false;
1925 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1928bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1931 if (!m_RAZBuilt)
return false;
1932 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1935bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1940 bool force_new_view =
false;
1942 if (Region != m_last_Region) force_new_view =
true;
1944 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1946 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1947 m_bLinePrioritySet =
false;
1949 ClearRenderedTextCache();
1951 ResetPointBBoxes(m_last_vp, VPoint);
1956 ResetPointBBoxes(m_last_vp, VPoint);
1959 SetLinePriorities();
1961 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1965 if (VPoint.b_quilt) {
1967 if ((m_pCloneBM->GetWidth() != VPoint.
pix_width) ||
1968 (m_pCloneBM->GetHeight() != VPoint.
pix_height)) {
1973 if (NULL == m_pCloneBM)
1976 wxMemoryDC dc_clone;
1977 dc_clone.SelectObject(*m_pCloneBM);
1979#ifdef ocpnUSE_DIBSECTION
1982 wxMemoryDC memdc, dc_org;
1985 pDIB->SelectIntoDC(dc_org);
1990 while (upd.HaveRects()) {
1991 wxRect rect = upd.GetRect();
1992 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
1997 dc_clone.SelectObject(wxNullBitmap);
1998 dc_org.SelectObject(wxNullBitmap);
2002 wxColour nodat = GetGlobalColor(
"NODTA");
2003 wxColour nodat_sub = nodat;
2005#ifdef ocpnUSE_ocpnBitmap
2006 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
2008 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
2009 m_pCloneBM->SetMask(m_pMask);
2012 dc.SelectObject(*m_pCloneBM);
2014 pDIB->SelectIntoDC(dc);
2016 m_last_Region = Region;
2021bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2026 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2028 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2029 m_bLinePrioritySet =
false;
2031 ClearRenderedTextCache();
2035 SetLinePriorities();
2037 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2039 pDIB->SelectIntoDC(dc);
2046bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2047 RenderTypeEnum option,
bool force_new_view) {
2048 bool bnewview =
false;
2050 bool bNewVP =
false;
2052 bool bReallyNew =
false;
2054 double easting_ul, northing_ul;
2055 double easting_lr, northing_lr;
2056 double prev_easting_ul = 0., prev_northing_ul = 0.;
2058 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2059 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2068 if (m_last_vprect != dest) bReallyNew =
true;
2069 m_last_vprect = dest;
2071 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2073 m_plib_state_hash = ps52plib->GetStateHash();
2084 if (m_last_vp.IsValid()) {
2086 m_easting_vp_center - ((VPoint.
pix_width / 2) / m_view_scale_ppm);
2088 m_northing_vp_center + ((VPoint.
pix_height / 2) / m_view_scale_ppm);
2089 easting_lr = easting_ul + (VPoint.
pix_width / m_view_scale_ppm);
2090 northing_lr = northing_ul - (VPoint.
pix_height / m_view_scale_ppm);
2092 double last_easting_vp_center, last_northing_vp_center;
2093 toSM(m_last_vp.
clat, m_last_vp.
clon, ref_lat, ref_lon,
2094 &last_easting_vp_center, &last_northing_vp_center);
2097 last_easting_vp_center - ((m_last_vp.
pix_width / 2) / m_view_scale_ppm);
2098 prev_northing_ul = last_northing_vp_center +
2099 ((m_last_vp.
pix_height / 2) / m_view_scale_ppm);
2101 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2102 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2104 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2105 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2107 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2108 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2110 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2113 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2122 else if ((rul.x != 0) || (rul.y != 0)) {
2123 if (g_bDebugS57) printf(
"newvp due to rul\n");
2134 if (force_new_view) bNewVP =
true;
2139 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2140 rgn_last.Intersect(rgn_new);
2142 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2144 rgn_last.GetBox(xu, yu, wu, hu);
2161 pDIB->SelectIntoDC(dc_last);
2166 pDIBNew->SelectIntoDC(dc_new);
2170 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2175 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.
pix_width,
2178 dc_new.SelectObject(wxNullBitmap);
2179 dc_last.SelectObject(wxNullBitmap);
2187 pDIB->SelectIntoDC(dc);
2191 rgn_delta.Subtract(rgn_reused);
2194 while (upd.HaveRects()) {
2195 wxRect rect = upd.GetRect();
2200 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2202 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2203 (rect.y / m_view_scale_ppm);
2204 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2205 (rect.x / m_view_scale_ppm);
2206 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2209 double temp_northing_lr =
2210 temp_northing_ul - (rect.height / m_view_scale_ppm);
2211 double temp_easting_lr =
2212 temp_easting_ul + (rect.width / m_view_scale_ppm);
2213 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2216 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2221 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2222 temp_vp.GetBBox().GetLatRange()) *
2224 temp_vp.GetBBox().EnLarge(margin);
2230 DCRenderRect(dc, temp_vp, &rect);
2235 dc.SelectObject(wxNullBitmap);
2244 else if (bNewVP || (NULL == pDIB)) {
2250 pDIB->SelectIntoDC(dc);
2253 ps52plib->ClearTextList();
2255 DCRenderRect(dc, VPoint, &full_rect);
2257 dc.SelectObject(wxNullBitmap);
2268int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2281 render_canvas_parms pb_spec;
2283 pb_spec.depth = BPP;
2284 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2285 pb_spec.lclip = rect->x;
2286 pb_spec.rclip = rect->x + rect->width - 1;
2287 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2288 pb_spec.width = rect->width;
2289 pb_spec.height = rect->height;
2290 pb_spec.x = rect->x;
2291 pb_spec.y = rect->y;
2293#ifdef ocpnUSE_ocpnBitmap
2294 pb_spec.b_revrgb =
true;
2296 pb_spec.b_revrgb =
false;
2300 wxColour color = GetGlobalColor(
"NODTA");
2301 unsigned char r, g, b;
2309 if (pb_spec.depth == 24) {
2310 for (
int i = 0; i < pb_spec.height; i++) {
2311 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2312 for (
int j = 0; j < pb_spec.width; j++) {
2319 int color_int = ((r) << 16) + ((g) << 8) + (b);
2321 for (
int i = 0; i < pb_spec.height; i++) {
2322 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2323 for (
int j = 0; j < pb_spec.width; j++) {
2330 for (i = 0; i < PRIO_NUM; ++i) {
2331 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2332 top = razRules[i][4];
2334 top = razRules[i][3];
2336 while (top != NULL) {
2339 crnt->sm_transform_parms = &vp_transform;
2340 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2345#ifdef ocpnUSE_ocpnBitmap
2346 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2347 pb_spec.height, pb_spec.depth);
2349 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2350 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2351 wxBitmap *pREN =
new wxBitmap(*prender_image);
2357 dc_ren.SelectObject(*pREN);
2360 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2361 (wxDC *)&dc_ren, 0, 0);
2364 dc_ren.SelectObject(wxNullBitmap);
2366#ifdef ocpnUSE_ocpnBitmap
2367 free(pb_spec.pix_buff);
2369 delete prender_image;
2376 DCRenderLPB(dcinput, vp, rect);
2381bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2388 for (i = 0; i < PRIO_NUM; ++i) {
2390 wxDCClipper *pdcc = NULL;
2396 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2397 top = razRules[i][4];
2399 top = razRules[i][3];
2400 while (top != NULL) {
2403 crnt->sm_transform_parms = &vp_transform;
2404 ps52plib->RenderObjectToDC(&dcinput, crnt);
2407 top = razRules[i][2];
2408 while (top != NULL) {
2411 crnt->sm_transform_parms = &vp_transform;
2412 ps52plib->RenderObjectToDC(&dcinput, crnt);
2415 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2416 top = razRules[i][0];
2418 top = razRules[i][1];
2420 while (top != NULL) {
2423 crnt->sm_transform_parms = &vp_transform;
2424 ps52plib->RenderObjectToDC(&dcinput, crnt);
2428 if (pdcc)
delete pdcc;
2441bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2447 for (i = 0; i < PRIO_NUM; ++i) {
2448 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2449 top = razRules[i][4];
2451 top = razRules[i][3];
2453 while (top != NULL) {
2456 crnt->sm_transform_parms = &vp_transform;
2457 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2460 top = razRules[i][2];
2461 while (top != NULL) {
2464 crnt->sm_transform_parms = &vp_transform;
2465 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2468 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2469 top = razRules[i][0];
2471 top = razRules[i][1];
2473 while (top != NULL) {
2476 crnt->sm_transform_parms = &vp_transform;
2477 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2484bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2485 wxFileName fn(FullPath);
2487 wxString cname = fn.GetName();
2488 if (cname.Length() >= 3)
2489 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2494InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2497 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2500 if (name.Upper().EndsWith(
".XZ")) {
2501 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2504 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2505 wxFileName(name).GetName();
2507 if (!wxFileExists(m_TempFilePath) &&
2508 !DecompressXZFile(name, m_TempFilePath)) {
2509 wxRemoveFile(m_TempFilePath);
2510 return INIT_FAIL_REMOVE;
2513 m_TempFilePath = name;
2514 ext = wxFileName(name).GetExt();
2519 firebase::crashlytics::SetCustomKey(
"s57chartInit",
2520 name.ToStdString().c_str());
2532 InitReturn ret_value = INIT_OK;
2534 m_Description = name;
2536 wxFileName fn(m_TempFilePath);
2539 wxString cname = fn.GetName();
2540 m_usage_char = cname[2];
2543 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2544 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2546 if (flags == THUMB_ONLY) {
2554 if (flags == HEADER_ONLY) {
2556 if (!GetBaseFileAttr(fn.GetFullPath()))
2557 ret_value = INIT_FAIL_REMOVE;
2559 if (!CreateHeaderDataFromENC())
2560 ret_value = INIT_FAIL_REMOVE;
2562 ret_value = INIT_OK;
2564 }
else if (ext ==
"S57") {
2565 m_SENCFileName = m_TempFilePath;
2566 if (!CreateHeaderDataFromSENC())
2567 ret_value = INIT_FAIL_REMOVE;
2569 ret_value = INIT_OK;
2578 if (!m_bbase_file_attr_known) {
2579 if (!GetBaseFileAttr(m_TempFilePath))
2580 ret_value = INIT_FAIL_REMOVE;
2582 m_bbase_file_attr_known =
true;
2586 if (m_bbase_file_attr_known) {
2587 int sret = FindOrCreateSenc(m_FullPath);
2588 if (sret == BUILD_SENC_PENDING) {
2593 if (sret != BUILD_SENC_OK) {
2594 if (sret == BUILD_SENC_NOK_RETRY)
2595 ret_value = INIT_FAIL_RETRY;
2597 ret_value = INIT_FAIL_REMOVE;
2599 ret_value = PostInit(flags, m_global_color_scheme);
2604 else if (ext ==
"S57") {
2605 m_SENCFileName = m_TempFilePath;
2606 ret_value = PostInit(flags, m_global_color_scheme);
2613wxString s57chart::buildSENCName(
const wxString &name) {
2614 wxFileName fn(name);
2616 wxString file_name = fn.GetFullName();
2619 wxString SENCdir = g_SENCPrefix;
2621 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2622 SENCdir.Append(wxFileName::GetPathSeparator());
2625 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2626 wxCharBuffer buf = source_dir.ToUTF8();
2627 unsigned char sha1_out[20];
2628 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2631 for (
unsigned int i = 0; i < 6; i++) {
2633 s.Printf(
"%02X", sha1_out[i]);
2637 file_name.Prepend(sha1);
2640 wxFileName tsfn(SENCdir);
2641 tsfn.SetFullName(file_name);
2643 return tsfn.GetFullPath();
2650int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2654 if (name.Upper().EndsWith(
".XZ")) {
2655 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2658 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2659 wxFileName(name).GetName();
2661 if (!wxFileExists(m_TempFilePath) &&
2662 !DecompressXZFile(name, m_TempFilePath)) {
2663 wxRemoveFile(m_TempFilePath);
2664 return INIT_FAIL_REMOVE;
2667 m_TempFilePath = name;
2668 ext = wxFileName(name).GetExt();
2672 if (!m_bbase_file_attr_known) {
2673 if (!GetBaseFileAttr(m_TempFilePath))
2674 return INIT_FAIL_REMOVE;
2676 m_bbase_file_attr_known =
true;
2680 m_SENCFileName = buildSENCName(name);
2682 int build_ret_val = 1;
2684 bool bbuild_new_senc =
false;
2685 m_bneed_new_thumbnail =
false;
2687 wxFileName FileName000(m_TempFilePath);
2691 wxString msg(
"S57chart::Checking SENC file: ");
2692 msg.Append(m_SENCFileName);
2696 int force_make_senc = 0;
2698 if (::wxFileExists(m_SENCFileName)) {
2701 if (senc.ingestHeader(m_SENCFileName)) {
2702 bbuild_new_senc =
true;
2703 wxLogMessage(
" Rebuilding SENC due to ingestHeader failure.");
2705 int senc_file_version = senc.getSencReadVersion();
2707 int last_update = senc.getSENCReadLastUpdate();
2709 wxString str = senc.getSENCFileCreateDate();
2710 wxDateTime SENCCreateDate;
2711 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
2713 if (SENCCreateDate.IsValid())
2714 SENCCreateDate.ResetTime();
2719 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2721 senc_base_edtn.ToLong(&isenc_edition);
2723 m_edtn000.ToLong(&ifile_edition);
2728 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2729 bbuild_new_senc =
true;
2730 wxLogMessage(
" Rebuilding SENC due to SENC format update.");
2737 else if (ifile_edition > isenc_edition) {
2738 bbuild_new_senc =
true;
2739 wxLogMessage(
" Rebuilding SENC due to cell edition update.");
2741 msg =
" Last edition recorded in SENC: ";
2742 msg += senc_base_edtn;
2743 msg +=
" most recent edition cell file: ";
2748 int most_recent_update_file =
2749 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2751 if (ifile_edition == isenc_edition) {
2752 if (most_recent_update_file > last_update) {
2753 bbuild_new_senc =
true;
2755 " Rebuilding SENC due to incremental cell update.");
2758 " Last update recorded in SENC: %d most recent "
2760 last_update, most_recent_update_file);
2768 wxDateTime OModTime000;
2769 FileName000.GetTimes(NULL, &OModTime000, NULL);
2770 OModTime000.ResetTime();
2771 if (SENCCreateDate.IsValid()) {
2772 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2774 " Rebuilding SENC due to Senc vs cell file time "
2776 bbuild_new_senc =
true;
2779 bbuild_new_senc =
true;
2781 " Rebuilding SENC due to SENC create time invalid.");
2792 if (force_make_senc) bbuild_new_senc =
true;
2794 }
else if (!::wxFileExists(m_SENCFileName))
2796 wxLogMessage(
" Rebuilding SENC due to missing SENC file.");
2797 bbuild_new_senc =
true;
2801 if (bbuild_new_senc) {
2802 m_bneed_new_thumbnail =
2804 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2806 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2807 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2808 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2814InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2816 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2817 wxString msg(
" Cannot load SENC file ");
2818 msg.Append(m_SENCFileName);
2821 return INIT_FAIL_RETRY;
2827 wxString SENCdir = g_SENCPrefix;
2828 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2829 SENCdir.Append(wxFileName::GetPathSeparator());
2831 wxFileName s57File(m_SENCFileName);
2832 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13),
"BMP");
2834 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2835 BuildThumbnail(ThumbFileName.GetFullPath());
2838 if (ThumbFileName.FileExists()) {
2840#ifdef ocpnUSE_ocpnBitmap
2841 pBMP_NEW =
new ocpnBitmap;
2843 pBMP_NEW =
new wxBitmap;
2845 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2848 m_pDIBThumbDay = pBMP_NEW;
2856 m_global_color_scheme = cs;
2857 SetColorScheme(cs,
false);
2860 BuildDepthContourArray();
2862 CreateChartContext();
2863 PopulateObjectsWithContext();
2866 bReadyToRender =
true;
2871void s57chart::ClearDepthContourArray() {
2872 if (m_nvaldco_alloc) {
2873 free(m_pvaldco_array);
2875 m_nvaldco_alloc = 5;
2877 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2880void s57chart::BuildDepthContourArray() {
2883 if (0 == m_nvaldco_alloc) {
2884 m_nvaldco_alloc = 5;
2885 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2891 double prev_valdco = 0.0;
2893 for (
int i = 0; i < PRIO_NUM; ++i) {
2894 for (
int j = 0; j < LUPNAME_NUM; j++) {
2895 top = razRules[i][j];
2896 while (top != NULL) {
2897 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2898 double valdco = 0.0;
2899 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2900 if (valdco != prev_valdco) {
2901 prev_valdco = valdco;
2903 if (m_nvaldco > m_nvaldco_alloc) {
2904 void *tr = realloc((
void *)m_pvaldco_array,
2905 m_nvaldco_alloc * 2 *
sizeof(
double));
2906 m_pvaldco_array = (
double *)tr;
2907 m_nvaldco_alloc *= 2;
2909 m_pvaldco_array[m_nvaldco - 1] = valdco;
2913 ObjRazRules *nxx = top->next;
2918 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2922void s57chart::SetSafetyContour() {
2930 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2933 if (NULL != m_pvaldco_array) {
2934 for (i = 0; i < m_nvaldco; i++) {
2935 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2939 m_next_safe_cnt = m_pvaldco_array[i];
2941 m_next_safe_cnt = (double)1e6;
2943 m_next_safe_cnt = (double)1e6;
2948 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2949 m_next_safe_cnt = (
double)1e6;
2952void s57chart::CreateChartContext() {
2954 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2957void s57chart::PopulateObjectsWithContext() {
2958 m_this_chart_context->chart =
this;
2959 m_this_chart_context->chart_type = GetChartType();
2960 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2961 m_this_chart_context->chart_scale = GetNativeScale();
2962 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2963 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2964 m_this_chart_context->safety_contour = m_next_safe_cnt;
2965 m_this_chart_context->pt2GetAssociatedObjects =
2966 &s57chart::GetAssociatedObjects;
2970 for (
int i = 0; i < PRIO_NUM; ++i) {
2971 for (
int j = 0; j < LUPNAME_NUM; j++) {
2972 top = razRules[i][j];
2973 while (top != NULL) {
2974 S57Obj *obj = top->obj;
2975 obj->m_chart_context = m_this_chart_context;
2982void s57chart::InvalidateCache() {
2987bool s57chart::BuildThumbnail(
const wxString &bmpname) {
2990 wxFileName ThumbFileName(bmpname);
2993 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
2994 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
2995 wxLogMessage(
" Cannot create BMP file directory for " +
2996 ThumbFileName.GetFullPath());
3004 vp.
clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
3005 vp.
clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
3007 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
3008 (m_FullExtent.ELON - m_FullExtent.WLON));
3015 vp.m_projection_type = PROJECTION_MERCATOR;
3017 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3034 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3036 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3038 int *psvr = psave_viz;
3042 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3043 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3044 *psvr++ = pOLE->nViz;
3049 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3050 bool bsave_text = ps52plib->m_bShowS57Text;
3053 ps52plib->SaveObjNoshow();
3056 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3057 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3058 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3059 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3062 ps52plib->m_bShowSoundg =
false;
3063 ps52plib->m_bShowS57Text =
false;
3066 DisCat dsave = ps52plib->GetDisplayCategory();
3067 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3069 ps52plib->AddObjNoshow(
"BRIDGE");
3070 ps52plib->AddObjNoshow(
"GATCON");
3072 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3073 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3074 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3075 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3077#ifdef ocpnUSE_DIBSECTION
3080 wxMemoryDC memdc, dc_org;
3084 ps52plib->SaveColorScheme();
3085 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3087 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3090 memdc.SelectObject(wxNullBitmap);
3094 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3095 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3096 pOLE->nViz = *psvr++;
3099 ps52plib->SetDisplayCategory(dsave);
3100 ps52plib->RestoreObjNoshow();
3102 ps52plib->RemoveObjNoshow(
"BRIDGE");
3103 ps52plib->RemoveObjNoshow(
"GATCON");
3105 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3106 ps52plib->m_bShowS57Text = bsave_text;
3108 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3109 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3112 ps52plib->RestoreColorScheme();
3122 wxMemoryDC dc_clone;
3123 dc_clone.SelectObject(*pBMP);
3125 pDIB->SelectIntoDC(dc_org);
3129 dc_clone.SelectObject(wxNullBitmap);
3130 dc_org.SelectObject(wxNullBitmap);
3133 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3140WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3141static int depth = 0;
3142static bool isProcessing =
false;
3145bool s57chart::CreateHeaderDataFromENC() {
3148 float LatMax, LatMin, LonMax, LonMin;
3154 m_pCOVRTablePoints = NULL;
3155 m_pCOVRTable = NULL;
3157 if (!InitENCMinimal(m_TempFilePath)) {
3158 wxString msg(
" Cannot initialize ENC file ");
3159 msg.Append(m_TempFilePath);
3166 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3167 std::vector<int> auxCntArray, noCovrCntArray;
3168 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3171 wxCriticalSectionLocker enter(GDALcriticalSection);
3172 if (isProcessing)
int yyp = 4;
3173 isProcessing =
true;
3181 pFeat = GetChartFirstM_COVR(catcov);
3186 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3187 OGRLinearRing *xring = poly->getExteriorRing();
3189 int npt = xring->getNumPoints();
3200 for (
int i = 0; i < npt; i++) {
3201 xring->getPoint(i, &p);
3205 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3207 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3208 if (xdelta < 0.001 &&
3216 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3217 pfr = &pf[2 * (usedpts - 1)];
3220 LatMax = fmax(LatMax, p.getY());
3221 LatMin = fmin(LatMin, p.getY());
3222 LonMax = fmax(LonMax, p.getX());
3223 LonMin = fmin(LonMin, p.getX());
3231 pAuxPtrArray->Add(pf);
3232 auxCntArray.push_back(usedpts);
3233 }
else if (catcov == 2) {
3234 pNoCovrPtrArray->Add(pf);
3235 noCovrCntArray.push_back(usedpts);
3240 pFeat = GetChartNextM_COVR(catcov);
3241 DEBUG_LOG <<
"used " << usedpts <<
" points";
3247 isProcessing =
false;
3252 m_nCOVREntries = auxCntArray.size();
3256 if (m_nCOVREntries >= 1) {
3257 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3258 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3260 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3261 m_pCOVRTablePoints[j] = auxCntArray[j];
3262 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3268 wxString msg(
" ENC contains no useable M_COVR, CATCOV=1 features: ");
3269 msg.Append(m_TempFilePath);
3274 m_nNoCOVREntries = noCovrCntArray.size();
3276 if (m_nNoCOVREntries) {
3278 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3279 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3281 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3282 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3283 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3286 m_pNoCOVRTablePoints = NULL;
3287 m_pNoCOVRTable = NULL;
3290 delete pAuxPtrArray;
3291 delete pNoCovrPtrArray;
3293 if (0 == m_nCOVREntries) {
3294 wxString msg(
" ENC contains no M_COVR features: ");
3295 msg.Append(m_TempFilePath);
3298 msg =
" Calculating Chart Extents as fallback.";
3304 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3306 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3313 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3314 *m_pCOVRTablePoints = 4;
3315 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3316 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3333 wxString msg(
" Cannot calculate Extents for ENC: ");
3334 msg.Append(m_TempFilePath);
3342 m_FullExtent.NLAT = LatMax;
3343 m_FullExtent.SLAT = LatMin;
3344 m_FullExtent.ELON = LonMax;
3345 m_FullExtent.WLON = LonMin;
3346 m_bExtentSet =
true;
3349 m_Chart_Scale = GetENCScale();
3360bool s57chart::CreateHeaderDataFromoSENC() {
3361 bool ret_val =
true;
3363 wxFFileInputStream fpx(m_SENCFileName);
3365 if (!::wxFileExists(m_SENCFileName)) {
3366 wxString msg(
" Cannot open SENC file ");
3367 msg.Append(m_SENCFileName);
3374 if (senc.ingestHeader(m_SENCFileName)) {
3380 m_Chart_Scale = senc.getSENCReadScale();
3383 m_Name = senc.getReadName();
3386 m_ID = senc.getReadID();
3389 Extent &ext = senc.getReadExtent();
3391 m_FullExtent.ELON = ext.ELON;
3392 m_FullExtent.WLON = ext.WLON;
3393 m_FullExtent.NLAT = ext.NLAT;
3394 m_FullExtent.SLAT = ext.SLAT;
3395 m_bExtentSet =
true;
3398 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3399 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3401 m_nCOVREntries = AuxCntArray.size();
3403 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3404 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3406 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3407 m_pCOVRTablePoints[j] = AuxCntArray[j];
3408 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3409 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3410 AuxCntArray[j] * 2 *
sizeof(
float));
3414 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3415 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3417 m_nNoCOVREntries = NoCovrCntArray.size();
3419 if (m_nNoCOVREntries) {
3421 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3422 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3424 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3425 int npoints = NoCovrCntArray[j];
3426 m_pNoCOVRTablePoints[j] = npoints;
3427 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3428 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3429 npoints * 2 *
sizeof(
float));
3435 m_datum_str =
"WGS84";
3436 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
3438 int senc_file_version = senc.getSencReadVersion();
3440 int last_update = senc.getSENCReadLastUpdate();
3442 wxString str = senc.getSENCFileCreateDate();
3443 wxDateTime SENCCreateDate;
3444 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
3446 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3448 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3455bool s57chart::CreateHeaderDataFromSENC() {
3456 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3464bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3466 if (NULL != m_pvaldco_array) {
3467 for (i = 0; i < m_nvaldco; i++) {
3468 if (m_pvaldco_array[i] >= safe_cnt)
break;
3472 next_safe_cnt = m_pvaldco_array[i];
3474 next_safe_cnt = (double)1e6;
3477 next_safe_cnt = (double)1e6;
3491std::list<S57Obj *> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3495 std::list<S57Obj *> *pobj_list =
new std::list<S57Obj *>();
3498 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3499 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3502 switch (obj->Primitive_type) {
3515 top = razRules[disPrioIdx][3];
3516 while (top != NULL) {
3517 if (top->obj->bIsAssociable) {
3518 if (top->obj->BBObj.Contains(lat, lon)) {
3519 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3520 pobj_list->push_back(top->obj);
3527 ObjRazRules *nxx = top->next;
3532 top = razRules[disPrioIdx][4];
3533 while (top != NULL) {
3534 if (top->obj->bIsAssociable) {
3535 if (top->obj->BBObj.Contains(lat, lon)) {
3536 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3537 pobj_list->push_back(top->obj);
3543 ObjRazRules *nxx = top->next;
3557void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3558 wxFileName fn(FullPath);
3560 wxString target_name = fn.GetName();
3561 target_name.RemoveLast();
3563 wxString dir_name = fn.GetPath();
3565 wxDir dir(dir_name);
3567 wxArrayString FileList;
3569 dir.GetAllFiles(fn.GetPath(), &FileList);
3573 bool found_name =
false;
3577 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3578 wxFileName file(FileList[j]);
3579 if (((file.GetExt()).MakeUpper()) ==
"TXT") {
3581 wxTextFile text_file(file.GetFullPath());
3583 bool file_ok =
true;
3587 if (!text_file.Open()) {
3588 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3593 wxString str = text_file.GetFirstLine();
3594 while (!text_file.Eof()) {
3595 if (0 == target_name.CmpNoCase(
3596 str.Mid(0, target_name.Len()))) {
3597 wxString tname = str.AfterFirst(
'-');
3598 name = tname.AfterFirst(
' ');
3602 str = text_file.GetNextLine();
3606 wxString msg(
" Error Reading ENC .TXT file: ");
3607 msg.Append(file.GetFullPath());
3613 if (found_name)
break;
3630const char *s57chart::getName(OGRFeature *feature) {
3631 return feature->GetDefnRef()->GetName();
3634static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3635 wxFileName fn1(first);
3636 wxFileName fn2(second);
3637 wxString ext1(fn1.GetExt());
3638 wxString ext2(fn2.GetExt());
3640 return ext1.Cmp(ext2);
3643int s57chart::GetUpdateFileArray(
const wxFileName file000,
3644 wxArrayString *UpFiles, wxDateTime date000,
3646 wxString DirName000 =
3647 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3648 wxDir dir(DirName000);
3649 if (!dir.IsOpened()) {
3650 DirName000.Prepend(wxFileName::GetPathSeparator());
3651 DirName000.Prepend(
".");
3652 dir.Open(DirName000);
3653 if (!dir.IsOpened()) {
3658 int flags = wxDIR_DEFAULT;
3665 wxFileName fnDir(DirName000);
3666 fnDir.RemoveLastDir();
3667 wxString sdir = fnDir.GetPath();
3668 wxFileName fnTest(sdir);
3669 wxString sname = fnTest.GetName();
3671 if (sname.ToLong(&tmps)) {
3674 flags |= wxDIR_DIRS;
3678 wxArrayString *dummy_array;
3681 if (UpFiles == NULL)
3682 dummy_array =
new wxArrayString;
3684 dummy_array = UpFiles;
3686 wxArrayString possibleFiles;
3687 wxDir::GetAllFiles(DirName000, &possibleFiles,
"", flags);
3689 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3690 wxString filename(possibleFiles[i]);
3692 wxFileName file(filename);
3693 ext = file.GetExt();
3698 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3699 wxString FileToAdd = filename;
3701 wxCharBuffer buffer =
3704 if (buffer.data() && !filename.IsSameAs(
"CATALOG.031",
3716 DDFModule *poModule =
new DDFModule();
3717 if (!poModule->Open(FileToAdd.mb_str())) {
3719 " s57chart::BuildS57File Unable to open update file ");
3720 msg.Append(FileToAdd);
3729 DDFRecord *pr = poModule->ReadRecord();
3735 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3738 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3742 " s57chart::BuildS57File DDFRecord 0 does not contain "
3743 "DSID:ISDT in update file ");
3744 msg.Append(FileToAdd);
3747 sumdate =
"20000101";
3750 umdate.ParseFormat(sumdate,
"%Y%m%d");
3751 if (!umdate.IsValid()) umdate.ParseFormat(
"20000101",
"%Y%m%d");
3754 if (!umdate.IsValid())
int yyp = 4;
3759 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3761 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3765 " s57chart::BuildS57File DDFRecord 0 does not contain "
3766 "DSID:EDTN in update file ");
3767 msg.Append(FileToAdd);
3776 if ((!umdate.IsEarlierThan(date000)) &&
3777 (umedtn.IsSameAs(edtn000)))
3778 dummy_array->Add(FileToAdd);
3784 dummy_array->Sort(ExtensionCompare);
3787 if (dummy_array->GetCount()) {
3788 wxString Last = dummy_array->Last();
3789 wxFileName fnl(Last);
3791 wxCharBuffer buffer = ext.ToUTF8();
3792 if (buffer.data()) retval = atoi(buffer.data());
3795 if (UpFiles == NULL)
delete dummy_array;
3800int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3801 const wxString CopyDir,
3802 wxString &LastUpdateDate,
3808 wxArrayString *UpFiles =
new wxArrayString;
3809 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3811 if (UpFiles->GetCount()) {
3831 for (
int iff = 0; iff < retval + 1; iff++) {
3832 wxFileName ufile(m_TempFilePath);
3834 sext.Printf(
"%03d", iff);
3838 wxString cp_ufile = CopyDir;
3839 if (cp_ufile.Last() != ufile.GetPathSeparator())
3840 cp_ufile.Append(ufile.GetPathSeparator());
3842 cp_ufile.Append(ufile.GetFullName());
3847 if (ufile.FileExists()) {
3848 wxFile uf(ufile.GetFullPath());
3849 if (uf.IsOpened()) {
3855 if (ufile.FileExists() &&
3859 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3861 wxString msg(
" Cannot copy temporary working ENC file ");
3862 msg.Append(ufile.GetFullPath());
3864 msg.Append(cp_ufile);
3877 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3878 "incomplete or inaccurate.\nCheck the logfile for details."),
3879 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3885 "WARNING---ENC Update chain incomplete. Substituting NULL "
3887 msg += ufile.GetFullName();
3889 wxLogMessage(
" Subsequent ENC updates may produce errors.");
3891 " This ENC exchange set should be updated and SENCs "
3895 DDFModule *dupdate =
new DDFModule;
3896 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3897 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3901 wxString msg(
" Error creating dummy update file: ");
3902 msg.Append(cp_ufile);
3907 m_tmpup_array->Add(cp_ufile);
3914 wxFileName lastfile(m_TempFilePath);
3916 last_sext.Printf(
"%03d", retval);
3917 lastfile.SetExt(last_sext);
3920 DDFModule oUpdateModule;
3925 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3929 oUpdateModule.Rewind();
3930 DDFRecord *pr = oUpdateModule.ReadRecord();
3936 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3940 LastUpdateDate = wxString(u, wxConvUTF8);
3943 wxDateTime now = wxDateTime::Now();
3944 LastUpdateDate = now.Format(
"%Y%m%d");
3953wxString s57chart::GetISDT() {
3954 if (m_date000.IsValid())
3955 return m_date000.Format(
"%Y%m%d");
3960bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3961 if (!wxFileName::FileExists(file000))
return false;
3963 wxString FullPath000 = file000;
3964 DDFModule *poModule =
new DDFModule();
3965 if (!poModule->Open(FullPath000.mb_str())) {
3966 wxString msg(
" s57chart::BuildS57File Unable to open ");
3967 msg.Append(FullPath000);
3979 DDFRecord *pr = poModule->ReadRecord();
3983 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3984 if (!m_nGeoRecords) {
3986 " s57chart::BuildS57File DDFRecord 0 does not contain "
3996 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3998 date000 = wxString(u, wxConvUTF8);
4001 " s57chart::BuildS57File DDFRecord 0 does not contain "
4008 m_date000.ParseFormat(date000,
"%Y%m%d");
4009 if (!m_date000.IsValid()) m_date000.ParseFormat(
"20000101",
"%Y%m%d");
4011 m_date000.ResetTime();
4014 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
4016 m_edtn000 = wxString(u, wxConvUTF8);
4019 " s57chart::BuildS57File DDFRecord 0 does not contain "
4030 for (; pr != NULL; pr = poModule->ReadRecord()) {
4031 if (pr->FindField(
"DSPM") != NULL) {
4032 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4036 if (!m_native_scale) {
4037 wxString msg(
" s57chart::BuildS57File ENC not contain DSPM:CSCL ");
4040 m_native_scale = 1000;
4048int s57chart::BuildSENCFile(
const wxString &FullPath000,
4049 const wxString &SENCFileName,
bool b_progress) {
4051 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4052 double meters_per_pixel_max_scale =
4054 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4057 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4058 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4060 if (!m_disableBackgroundSENC) {
4063 ticket->m_LOD_meters = m_LOD_meters;
4064 ticket->ref_lat = ref_lat;
4065 ticket->ref_lon = ref_lon;
4066 ticket->m_FullPath000 = FullPath000;
4067 ticket->m_SENCFileName = SENCFileName;
4068 ticket->m_chart =
this;
4071 bReadyToRender =
true;
4072 return BUILD_SENC_PENDING;
4075 return BUILD_SENC_NOK_RETRY;
4081 senc.setRefLocn(ref_lat, ref_lon);
4082 senc.SetLODMeters(m_LOD_meters);
4084 AbstractPlatform::ShowBusySpinner();
4086 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4088 AbstractPlatform::HideBusySpinner();
4090 if (ret == ERROR_INGESTING000)
4091 return BUILD_SENC_NOK_PERMANENT;
4097int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4104 S57ObjVector Objects;
4105 VE_ElementVector VEs;
4106 VC_ElementVector VCs;
4108 sencfile.setRefLocn(ref_lat, ref_lon);
4110 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4112 if (srv != SENC_NO_ERROR) {
4113 wxLogMessage(sencfile.getLastError());
4119 Extent ext = sencfile.getReadExtent();
4121 m_FullExtent.ELON = ext.ELON;
4122 m_FullExtent.WLON = ext.WLON;
4123 m_FullExtent.NLAT = ext.NLAT;
4124 m_FullExtent.SLAT = ext.SLAT;
4125 m_bExtentSet =
true;
4127 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4128 ref_lon = (ext.ELON + ext.WLON) / 2.;
4133 int n_ve_elements = VEs.size();
4135 double scale = top_frame::Get()->GetBestVPScale(
this);
4136 int nativescale = GetNativeScale();
4138 for (
int i = 0; i < n_ve_elements; i++) {
4139 VE_Element *vep = VEs.at(i);
4140 if (vep && vep->nCount) {
4142 double east_max = -1e7;
4143 double east_min = 1e7;
4144 double north_max = -1e7;
4145 double north_min = 1e7;
4147 float *vrun = vep->pPoints;
4148 for (
size_t i = 0; i < vep->nCount; i++) {
4149 east_max = wxMax(east_max, *vrun);
4150 east_min = wxMin(east_min, *vrun);
4153 north_max = wxMax(north_max, *vrun);
4154 north_min = wxMin(north_min, *vrun);
4158 double lat1, lon1, lat2, lon2;
4159 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4160 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4161 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4164 m_ve_hash[vep->index] = vep;
4168 int n_vc_elements = VCs.size();
4170 for (
int i = 0; i < n_vc_elements; i++) {
4171 VC_Element *vcp = VCs.at(i);
4172 m_vc_hash[vcp->index] = vcp;
4180 for (
unsigned int i = 0; i < Objects.size(); i++) {
4181 S57Obj *obj = Objects[i];
4185 LUPname LUP_Name = PAPER_CHART;
4187 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4188 if (objnam.Len() > 0) {
4189 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4190 SendVectorChartObjectInfo(FullPath, fe_name, objnam, obj->m_lat,
4191 obj->m_lon,
scale, nativescale);
4195 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4196 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4197 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4198 SendVectorChartObjectInfo(FullPath, fe_name, nobjnam, obj->m_lat,
4199 obj->m_lon,
scale, nativescale);
4202 switch (obj->Primitive_type) {
4207 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4208 LUP_Name = PAPER_CHART;
4210 LUP_Name = SIMPLIFIED;
4219 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4220 LUP_Name = PLAIN_BOUNDARIES;
4222 LUP_Name = SYMBOLIZED_BOUNDARIES;
4227 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4231 wxString msg(obj->FeatureName, wxConvUTF8);
4232 msg.Prepend(
" Could not find LUP for ");
4233 LogMessageOnce(msg);
4240 ps52plib->_LUP2rules(LUP, obj);
4243 _insertRules(obj, LUP,
this);
4246 obj->m_DisplayCat = LUP->DISC;
4249 obj->m_DPRI = LUP->DPRI -
'0';
4252 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4253 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4254 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4255 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4256 obj->m_bcategory_mutable =
true;
4258 obj->m_bcategory_mutable =
false;
4263 if (obj && (GEO_POINT == obj->Primitive_type)) {
4265 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4266 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4267 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4268 pFloatingATONArray->Add(obj);
4272 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4273 pRigidATONArray->Add(obj);
4277 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4278 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4279 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4280 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4281 obj->bIsAton =
true;
4290 d000.ParseFormat(sencfile.getBaseDate(),
"%Y%m%d");
4291 if (!d000.IsValid()) d000.ParseFormat(
"20000101",
"%Y%m%d");
4294 updt.ParseFormat(sencfile.getUpdateDate(),
"%Y%m%d");
4295 if (!updt.IsValid()) updt.ParseFormat(
"20000101",
"%Y%m%d");
4297 if (updt.IsLaterThan(d000))
4298 m_PubYear.Printf(
"%4d", updt.GetYear());
4300 m_PubYear.Printf(
"%4d", d000.GetYear());
4303 wxDateTime upd = updt;
4304 if (!upd.IsValid()) upd.ParseFormat(
"20000101",
"%Y%m%d");
4309 m_SE = sencfile.getSENCReadBaseEdition();
4312 supdate.Printf(
" / %d", sencfile.getSENCReadLastUpdate());
4315 m_datum_str =
"WGS84";
4317 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
4318 m_ID = sencfile.getReadID();
4319 m_Name = sencfile.getReadName();
4323 AssembleLineGeometry();
4328int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4329 ObjRazRules *rzRules = NULL;
4339 switch (LUP->DPRI) {
4352 case PRIO_SYMB_POINT:
4355 case PRIO_SYMB_LINE:
4358 case PRIO_SYMB_AREA:
4371 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4375 switch (LUP->TNAM) {
4385 case PLAIN_BOUNDARIES:
4388 case SYMBOLIZED_BOUNDARIES:
4392 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4396 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4400 rzRules->child = NULL;
4401 rzRules->mps = NULL;
4404 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4405 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4410 ObjRazRules *rNext = NULL;
4411 ObjRazRules *rPrevious = NULL;
4412 if (razRules[disPrioIdx][LUPtypeIdx]) {
4413 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4414 rNext = rPrevious->next;
4418 rNext = rPrevious->next;
4421 rzRules->next = NULL;
4423 rPrevious->next = rzRules;
4425 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4432void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4442 for (
int i = 0; i < PRIO_NUM; ++i) {
4443 for (
int j = 0; j < 2; ++j) {
4444 top = razRules[i][j];
4446 while (top != NULL) {
4447 if (!top->obj->geoPtMulti)
4449 if (top->obj->BBObj.GetValid()) {
4450 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4452 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4453 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4455 double minlon = top->obj->BBObj.GetMinLon();
4456 double maxlon = top->obj->BBObj.GetMaxLon();
4458 double lon1 = (lon - minlon) * d;
4459 double lon2 = (lon - maxlon) * d;
4461 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4464 top->obj->BBObj.Invalidate();
4485void s57chart::UpdateLUPs(
s57chart *pOwner) {
4489 for (
int i = 0; i < PRIO_NUM; ++i) {
4491 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4492 m_b2pointLUPS =
true;
4493 top = razRules[i][0];
4495 while (top != NULL) {
4496 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4502 if (top->obj->nRef < 2) {
4503 ps52plib->_LUP2rules(LUP, top->obj);
4504 _insertRules(top->obj, LUP, pOwner);
4505 top->obj->m_DisplayCat = LUP->DISC;
4515 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4516 m_b2pointLUPS =
true;
4517 top = razRules[i][1];
4519 while (top != NULL) {
4520 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4523 if (top->obj->nRef < 2) {
4524 ps52plib->_LUP2rules(LUP, top->obj);
4525 _insertRules(top->obj, LUP, pOwner);
4526 top->obj->m_DisplayCat = LUP->DISC;
4536 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4537 m_b2lineLUPS =
true;
4538 top = razRules[i][3];
4540 while (top != NULL) {
4541 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4542 top->obj->FeatureName, top->obj);
4544 ps52plib->_LUP2rules(LUP, top->obj);
4545 _insertRules(top->obj, LUP, pOwner);
4546 top->obj->m_DisplayCat = LUP->DISC;
4555 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4556 m_b2lineLUPS =
true;
4557 top = razRules[i][4];
4559 while (top != NULL) {
4560 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4563 ps52plib->_LUP2rules(LUP, top->obj);
4564 _insertRules(top->obj, LUP, pOwner);
4565 top->obj->m_DisplayCat = LUP->DISC;
4577 for (
int j = 0; j < LUPNAME_NUM; j++) {
4578 top = razRules[i][j];
4579 while (top != NULL) {
4580 top->obj->bCS_Added = 0;
4583 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4594 for (
int j = 0; j < LUPNAME_NUM; j++) {
4595 top = razRules[i][j];
4596 while (top != NULL) {
4598 ObjRazRules *ctop = top->child;
4599 while (NULL != ctop) {
4600 ctop->obj->bCS_Added = 0;
4601 free_mps(ctop->mps);
4604 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4621ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4622 float lat,
float lon,
ViewPort *VPoint) {
4623 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4624 std::vector<ObjRazRules *> selected_rules;
4629 char *curr_att = NULL;
4631 wxArrayOfS57attVal *attValArray = NULL;
4632 bool bleading_attribute =
false;
4634 for (
int i = 0; i < PRIO_NUM; ++i) {
4638 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4639 top = razRules[i][point_type];
4641 while (top != NULL) {
4642 if (top->obj->npt == 1) {
4643 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4645 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4647 if (ps52plib->ObjectRenderCheckCat(top)) {
4650 wxString curAttrName;
4651 curr_att = top->obj->att_array;
4652 n_attr = top->obj->n_attr;
4653 attValArray = top->obj->attVal;
4661 bleading_attribute =
false;
4663 while (attrCounter < n_attr) {
4664 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4667 S57attVal *pAttrVal = NULL;
4670 pAttrVal = attValArray->Item(attrCounter);
4674 wxString value = s57chart::GetAttributeValueAsString(
4675 pAttrVal, curAttrName);
4677 if (curAttrName ==
"LITVIS") {
4678 if (value.StartsWith(
"obsc")) bviz =
false;
4679 }
else if (curAttrName ==
"VALNMR")
4680 value.ToDouble(&valnmr);
4686 if (bviz && (valnmr > 0.1)) {
4690 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4691 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4692 ref_lat, ref_lon, &olat, &olon);
4694 double dlat = lat - olat;
4695 double dy = dlat * 60 / cos(olat * PI / 180.);
4696 double dlon = lon - olon;
4697 double dx = dlon * 60;
4698 double manhat = abs(dy) + abs(dx);
4702 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4704 selected_rules.push_back(top);
4721 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4722 ret_ptr->Append(selected_rules[i]);
4728ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4729 float select_radius,
4731 int selection_mask) {
4732 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4733 std::vector<ObjRazRules *> selected_rules;
4735 PrepareForRender(VPoint, ps52plib);
4741 for (
int i = 0; i < PRIO_NUM; ++i) {
4742 if (selection_mask & MASK_POINT) {
4745 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4746 top = razRules[i][point_type];
4748 while (top != NULL) {
4749 if (top->obj->npt ==
4752 if (ps52plib->ObjectRenderCheck(top)) {
4753 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4754 selected_rules.push_back(top);
4761 ObjRazRules *child_item = top->child;
4762 while (child_item != NULL) {
4763 if (ps52plib->ObjectRenderCheck(child_item)) {
4764 if (DoesLatLonSelectObject(lat, lon, select_radius,
4766 selected_rules.push_back(child_item);
4769 child_item = child_item->next;
4777 if (selection_mask & MASK_AREA) {
4780 int area_boundary_type =
4781 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4782 top = razRules[i][area_boundary_type];
4783 while (top != NULL) {
4784 if (ps52plib->ObjectRenderCheck(top)) {
4785 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4786 selected_rules.push_back(top);
4793 if (selection_mask & MASK_LINE) {
4795 top = razRules[i][2];
4797 while (top != NULL) {
4798 if (ps52plib->ObjectRenderCheck(top)) {
4799 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4800 selected_rules.push_back(top);
4811 auto sortObjs = [lat, lon,
this](
const ObjRazRules *obj1,
4812 const ObjRazRules *obj2) ->
bool {
4813 double br1, dd1, br2, dd2;
4815 if (obj1->obj->Primitive_type == GEO_POINT &&
4816 obj2->obj->Primitive_type == GEO_POINT) {
4817 double lat1, lat2, lon1, lon2;
4818 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4819 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin, ref_lat,
4820 ref_lon, &lat1, &lon1);
4822 if (lon1 > 180.0) lon1 -= 360.;
4824 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4825 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin, ref_lat,
4826 ref_lon, &lat2, &lon2);
4828 if (lon2 > 180.0) lon2 -= 360.;
4830 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4831 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4838 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4842 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4843 ret_ptr->Append(selected_rules[i]);
4849bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4851 switch (obj->Primitive_type) {
4855 if (!obj->BBObj.GetValid())
return false;
4857 if (1 == obj->npt) {
4862 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4864 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4867 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4868 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4875 sbox.Set(olat, olon, olat, olon);
4877 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4878 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4883 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4890 if (!obj->BBObj.GetValid())
return false;
4893 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4895 double *pdl = obj->geoPtMulti;
4896 for (
int ip = 0; ip < obj->npt; ip++) {
4897 double lon_point = *pdl++;
4898 double lat_point = *pdl++;
4900 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4901 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4912 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4915 return IsPointInObjArea(lat, lon, select_radius, obj);
4920 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4922 float sel_rad_meters = select_radius * 1852 * 60;
4923 double easting, northing;
4924 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4931 pt *ppt = obj->geoPt;
4934 double xr = obj->x_rate;
4935 double xo = obj->x_origin;
4936 double yr = obj->y_rate;
4937 double yo = obj->y_origin;
4939 double north0 = (ppt->y * yr) + yo;
4940 double east0 = (ppt->x * xr) + xo;
4943 for (
int ip = 1; ip < npt; ip++) {
4944 double north = (ppt->y * yr) + yo;
4945 double east = (ppt->x * xr) + xo;
4948 if (northing >= (fmin(north, north0) - sel_rad_meters))
4949 if (northing <= (fmax(north, north0) + sel_rad_meters))
4950 if (easting >= (fmin(east, east0) - sel_rad_meters))
4951 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4961 if (obj->m_ls_list) {
4963 unsigned char *vbo_point =
4964 (
unsigned char *)obj->m_chart_context
4966 line_segment_element *ls = obj->m_ls_list;
4968 while (ls && vbo_point) {
4970 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4971 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4972 nPoints = ls->pedge->nCount;
4974 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4978 float north0 = ppt[1];
4979 float east0 = ppt[0];
4983 for (
int ip = 0; ip < nPoints - 1; ip++) {
4984 float north = ppt[1];
4985 float east = ppt[0];
4987 if (northing >= (fmin(north, north0) - sel_rad_meters))
4988 if (northing <= (fmax(north, north0) + sel_rad_meters))
4989 if (easting >= (fmin(east, east0) - sel_rad_meters))
4990 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
5017wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
5018 wxString ret_val =
"";
5021 const char *att_code;
5023 wxString file(g_csv_locn);
5024 file.Append(
"/s57attributes.csv");
5026 if (!wxFileName::FileExists(file)) {
5027 wxString msg(
" Could not open ");
5034 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5036 CC_ExactString,
"Code");
5042 wxString ei_file(g_csv_locn);
5043 ei_file.Append(
"/s57expectedinput.csv");
5045 if (!wxFileName::FileExists(ei_file)) {
5046 wxString msg(
" Could not open ");
5047 msg.Append(ei_file);
5053 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5054 CSVIngest(ei_file.mb_str());
5056 char **papszFields = NULL;
5057 int bSelected = FALSE;
5063 while (!bSelected && iline + 1 < psTable->nLineCount) {
5065 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5067 if (!strcmp(papszFields[0], att_code)) {
5068 if (atoi(papszFields[1]) == ival) {
5069 ret_val = wxString(papszFields[2], wxConvUTF8);
5074 CSLDestroy(papszFields);
5082bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5086 if (obj->pPolyTessGeo) {
5087 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5089 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5091 TriPrim *pTP = ppg->tri_prim_head;
5093 MyPoint pvert_list[3];
5097 double easting, northing;
5098 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5102 if (!ppg->m_bSMSENC) {
5103 double y_rate = obj->y_rate;
5104 double y_origin = obj->y_origin;
5105 double x_rate = obj->x_rate;
5106 double x_origin = obj->x_origin;
5108 double northing_scaled = (northing - y_origin) / y_rate;
5109 double easting_scaled = (easting - x_origin) / x_rate;
5110 northing = northing_scaled;
5111 easting = easting_scaled;
5116 if (pTP->tri_box.Contains(lat, lon)) {
5117 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5118 double *p_vertex = pTP->p_vertex;
5120 switch (pTP->type) {
5121 case PTG_TRIANGLE_FAN: {
5122 for (
int it = 0; it < pTP->nVert - 2; it++) {
5123 pvert_list[0].x = p_vertex[0];
5124 pvert_list[0].y = p_vertex[1];
5126 pvert_list[1].x = p_vertex[(it * 2) + 2];
5127 pvert_list[1].y = p_vertex[(it * 2) + 3];
5129 pvert_list[2].x = p_vertex[(it * 2) + 4];
5130 pvert_list[2].y = p_vertex[(it * 2) + 5];
5132 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5140 case PTG_TRIANGLE_STRIP: {
5141 for (
int it = 0; it < pTP->nVert - 2; it++) {
5142 pvert_list[0].x = p_vertex[(it * 2)];
5143 pvert_list[0].y = p_vertex[(it * 2) + 1];
5145 pvert_list[1].x = p_vertex[(it * 2) + 2];
5146 pvert_list[1].y = p_vertex[(it * 2) + 3];
5148 pvert_list[2].x = p_vertex[(it * 2) + 4];
5149 pvert_list[2].y = p_vertex[(it * 2) + 5];
5151 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5159 case PTG_TRIANGLES: {
5160 for (
int it = 0; it < pTP->nVert; it += 3) {
5161 pvert_list[0].x = p_vertex[(it * 2)];
5162 pvert_list[0].y = p_vertex[(it * 2) + 1];
5164 pvert_list[1].x = p_vertex[(it * 2) + 2];
5165 pvert_list[1].y = p_vertex[(it * 2) + 3];
5167 pvert_list[2].x = p_vertex[(it * 2) + 4];
5168 pvert_list[2].y = p_vertex[(it * 2) + 5];
5170 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5179 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5180 float *p_vertex = (
float *)pTP->p_vertex;
5182 switch (pTP->type) {
5183 case PTG_TRIANGLE_FAN: {
5184 for (
int it = 0; it < pTP->nVert - 2; it++) {
5185 pvert_list[0].x = p_vertex[0];
5186 pvert_list[0].y = p_vertex[1];
5188 pvert_list[1].x = p_vertex[(it * 2) + 2];
5189 pvert_list[1].y = p_vertex[(it * 2) + 3];
5191 pvert_list[2].x = p_vertex[(it * 2) + 4];
5192 pvert_list[2].y = p_vertex[(it * 2) + 5];
5194 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5202 case PTG_TRIANGLE_STRIP: {
5203 for (
int it = 0; it < pTP->nVert - 2; it++) {
5204 pvert_list[0].x = p_vertex[(it * 2)];
5205 pvert_list[0].y = p_vertex[(it * 2) + 1];
5207 pvert_list[1].x = p_vertex[(it * 2) + 2];
5208 pvert_list[1].y = p_vertex[(it * 2) + 3];
5210 pvert_list[2].x = p_vertex[(it * 2) + 4];
5211 pvert_list[2].y = p_vertex[(it * 2) + 5];
5213 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5221 case PTG_TRIANGLES: {
5222 for (
int it = 0; it < pTP->nVert; it += 3) {
5223 pvert_list[0].x = p_vertex[(it * 2)];
5224 pvert_list[0].y = p_vertex[(it * 2) + 1];
5226 pvert_list[1].x = p_vertex[(it * 2) + 2];
5227 pvert_list[1].y = p_vertex[(it * 2) + 3];
5229 pvert_list[2].x = p_vertex[(it * 2) + 4];
5230 pvert_list[2].y = p_vertex[(it * 2) + 5];
5232 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5255wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5256 wxString curAttrName) {
5260 pval = obj->attVal->Item(iatt);
5261 switch (pval->valType) {
5264 wxString val_str((
char *)(pval->value), wxConvUTF8);
5266 if (val_str.ToLong(&ival)) {
5270 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5271 if (!decode_val.IsEmpty()) {
5274 iv.Printf(
" (%d)", (
int)ival);
5277 value.Printf(
"%d", (
int)ival);
5281 else if (val_str.IsEmpty())
5286 wxString value_increment;
5287 wxStringTokenizer tk(val_str,
",");
5289 if (tk.HasMoreTokens()) {
5290 while (tk.HasMoreTokens()) {
5291 wxString token = tk.GetNextToken();
5293 if (token.ToLong(&ival)) {
5294 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5296 value_increment.Printf(
" (%d)", (
int)ival);
5298 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5300 if (iv) value_increment.Prepend(
", ");
5301 value.Append(value_increment);
5304 if (iv) value.Append(
",");
5305 value.Append(token);
5311 value.Append(val_str);
5314 value =
"[NULL VALUE]";
5320 int ival = *((
int *)pval->value);
5321 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5323 if (!decode_val.IsEmpty()) {
5326 iv.Printf(
"(%d)", ival);
5329 value.Printf(
"(%d)", ival);
5337 double dval = *((
double *)pval->value);
5338 wxString val_suffix =
" m";
5339 bool has_preformatted =
false;
5340 wxString preformatted;
5351 if ((curAttrName ==
"VERCLR") || (curAttrName ==
"VERCCL") ||
5352 (curAttrName ==
"VERCOP") || (curAttrName ==
"HEIGHT") ||
5353 (curAttrName ==
"ELEVAT") || (curAttrName ==
"VERCSA")) {
5358 val_suffix = wxString::Format(
" %s",
unit.c_str());
5359 }
else if (curAttrName ==
"HORCLR") {
5362 double nm = dval / 1852.0;
5364 has_preformatted =
true;
5367 else if ((curAttrName ==
"VALSOU") || (curAttrName ==
"DRVAL1") ||
5368 (curAttrName ==
"DRVAL2") || (curAttrName ==
"VALDCO")) {
5375 wxString
unit = getUsrDepthUnit(-1);
5376 val_suffix = wxString::Format(
" %s",
unit.c_str());
5379 else if (curAttrName ==
"SECTR1")
5380 val_suffix =
"°";
5381 else if (curAttrName ==
"SECTR2")
5382 val_suffix =
"°";
5383 else if (curAttrName ==
"ORIENT")
5384 val_suffix =
"°";
5385 else if (curAttrName ==
"VALNMR")
5387 else if (curAttrName ==
"SIGPER")
5389 else if (curAttrName ==
"VALACM")
5390 val_suffix =
" Minutes/year";
5391 else if (curAttrName ==
"VALMAG")
5392 val_suffix =
"°";
5393 else if (curAttrName ==
"CURVEL")
5396 if (has_preformatted) {
5397 value = preformatted;
5399 if (dval - floor(dval) < 0.01)
5400 value.Printf(
"%2.0f", dval);
5402 value.Printf(
"%4.1f", dval);
5403 value << val_suffix;
5409 case OGR_REAL_LST: {
5416wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5417 wxString AttrName) {
5418 if (NULL == pAttrVal)
return "";
5421 switch (pAttrVal->valType) {
5423 if (pAttrVal->value) {
5424 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5426 if (val_str.ToLong(&ival)) {
5430 wxString decode_val = GetAttributeDecode(AttrName, ival);
5431 if (!decode_val.IsEmpty()) {
5434 iv.Printf(
"(%d)", (
int)ival);
5437 value.Printf(
"%d", (
int)ival);
5441 else if (val_str.IsEmpty())
5446 wxString value_increment;
5447 wxStringTokenizer tk(val_str,
",");
5449 while (tk.HasMoreTokens()) {
5450 wxString token = tk.GetNextToken();
5452 if (token.ToLong(&ival)) {
5453 wxString decode_val = GetAttributeDecode(AttrName, ival);
5454 if (!decode_val.IsEmpty())
5455 value_increment = decode_val;
5457 value_increment.Printf(
" %d", (
int)ival);
5459 if (iv) value_increment.Prepend(
", ");
5461 value.Append(value_increment);
5465 value.Append(val_str);
5468 value =
"[NULL VALUE]";
5474 int ival = *((
int *)pAttrVal->value);
5475 wxString decode_val = GetAttributeDecode(AttrName, ival);
5477 if (!decode_val.IsEmpty()) {
5480 iv.Printf(
"(%d)", ival);
5483 value.Printf(
"(%d)", ival);
5491 double dval = *((
double *)pAttrVal->value);
5492 wxString val_suffix =
" m";
5493 bool has_preformatted =
false;
5494 wxString preformatted;
5497 if ((AttrName ==
"VERCLR") || (AttrName ==
"VERCCL") ||
5498 (AttrName ==
"VERCOP") || (AttrName ==
"HEIGHT") ||
5499 (AttrName ==
"ELEVAT")) {
5504 val_suffix = wxString::Format(
" %s",
unit.c_str());
5505 }
else if (AttrName ==
"HORCLR") {
5507 double nm = dval / 1852.0;
5509 has_preformatted =
true;
5512 else if ((AttrName ==
"VALSOU") || (AttrName ==
"DRVAL1") ||
5513 (AttrName ==
"DRVAL2")) {
5516 wxString
unit = getUsrDepthUnit(-1);
5517 val_suffix = wxString::Format(
" %s",
unit.c_str());
5520 else if (AttrName ==
"SECTR1")
5521 val_suffix =
"°";
5522 else if (AttrName ==
"SECTR2")
5523 val_suffix =
"°";
5524 else if (AttrName ==
"ORIENT")
5525 val_suffix =
"°";
5526 else if (AttrName ==
"VALNMR")
5528 else if (AttrName ==
"SIGPER")
5530 else if (AttrName ==
"VALACM")
5531 val_suffix =
" Minutes/year";
5532 else if (AttrName ==
"VALMAG")
5533 val_suffix =
"°";
5534 else if (AttrName ==
"CURVEL")
5537 if (has_preformatted) {
5538 value = preformatted;
5540 if (dval - floor(dval) < 0.01)
5541 value.Printf(
"%2.0f", dval);
5543 value.Printf(
"%4.1f", dval);
5544 value << val_suffix;
5550 case OGR_REAL_LST: {
5558 int positionDiff = l1->position.Cmp(l2->position);
5559 if (positionDiff < 0)
return false;
5561 int attrIndex1 = l1->attributeNames.Index(
"SECTR1");
5562 int attrIndex2 = l2->attributeNames.Index(
"SECTR1");
5565 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5566 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5567 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5569 double angle1, angle2;
5570 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5571 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5573 return angle1 < angle2;
5576static const char *type2str(GeoPrim_t type) {
5577 const char *r =
"Unknown";
5598wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5601 wxString curAttrName, value;
5602 bool isLight =
false;
5605 wxString classAttributes;
5607 wxString lightsHtml;
5608 wxString positionString;
5609 std::vector<S57Light *> lights;
5613 for (ListOfObjRazRules::compatibility_iterator node = rule_list->GetLast();
5614 node; node = node->GetPrevious()) {
5615 ObjRazRules *current = node->GetData();
5616 positionString.Clear();
5620 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5622 if (current->obj->Primitive_type == GEO_META)
continue;
5623 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5625 className = wxString(current->obj->FeatureName, wxConvUTF8);
5628 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5633 const char *name_desc;
5634 if (g_csv_locn.Len()) {
5635 wxString oc_file(g_csv_locn);
5636 oc_file.Append(
"/s57objectclasses.csv");
5637 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5638 current->obj->FeatureName,
5639 CC_ExactString,
"ObjectClass");
5645 if (0 == strlen(name_desc)) {
5646 name_desc = current->obj->FeatureName;
5647 classDesc = wxString(name_desc, wxConvUTF8, 1);
5648 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5650 classDesc = wxString(name_desc, wxConvUTF8);
5657 classAttributes =
"";
5658 index.Printf(
"Feature Index: %d<br>", current->obj->Index);
5659 classAttributes << index;
5662 LUPstring.Printf(
"LUP RCID: %d<br>", current->LUP->RCID);
5663 classAttributes << LUPstring;
5666 LLBBox bbox = current->obj->BBObj;
5667 Bbox.Printf(
"Lat/Lon box: %g %g %g %g<br>", bbox.GetMinLat(),
5668 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5669 classAttributes << Bbox;
5672 Type.Printf(
" Type: %s<br>", type2str(current->obj->Primitive_type));
5673 classAttributes << Type;
5675 LUPstring =
" LUP ATTC: ";
5676 if (current->LUP->ATTArray.size())
5677 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5678 LUPstring +=
"<br>";
5679 classAttributes << LUPstring;
5681 LUPstring =
" LUP INST: ";
5682 LUPstring += current->LUP->INST;
5683 LUPstring +=
"<br><br>";
5684 classAttributes << LUPstring;
5687 if (GEO_POINT == current->obj->Primitive_type) {
5689 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5690 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5691 ref_lat, ref_lon, &lat, &lon);
5693 if (lon > 180.0) lon -= 360.;
5695 positionString.Clear();
5696 positionString += toSDMM(1, lat);
5697 positionString <<
" ";
5698 positionString += toSDMM(2, lon);
5702 curLight->position = positionString;
5703 curLight->hasSectors =
false;
5704 lights.push_back(curLight);
5710 if (current->obj->att_array) {
5711 char *curr_att = current->obj->att_array;
5717 attribStr <<
"<table border=0 cellspacing=0 cellpadding=0>";
5720 ret_val <<
"<p>" << classAttributes;
5723 bool inDepthRange =
false;
5725 while (attrCounter < current->obj->n_attr) {
5727 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5734 assert(curLight !=
nullptr);
5735 curLight->attributeNames.Add(curAttrName);
5736 if (curAttrName.StartsWith(
"SECTR")) curLight->hasSectors =
true;
5738 if (curAttrName ==
"DRVAL1") {
5739 attribStr <<
"<tr><td><font size=-1>";
5740 inDepthRange =
true;
5741 }
else if (curAttrName ==
"DRVAL2") {
5743 inDepthRange =
false;
5746 attribStr <<
"</font></td></tr>\n";
5747 inDepthRange =
false;
5749 attribStr <<
"<tr><td valign=top><font size=-2>";
5750 if (curAttrName ==
"catgeo")
5751 attribStr <<
"CATGEO";
5753 attribStr << curAttrName;
5754 attribStr <<
"</font></td><td> </td><td "
5755 "valign=top><font size=-1>";
5766 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5771 wxString AttrNamesFiles =
5772 "PICREP,TXTDSC,NTXTDS";
5774 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5775 if (value.Find(
".XML") == wxNOT_FOUND) {
5776 file.Assign(GetFullPath());
5777 file.Assign(file.GetPath(), value);
5780 if (file.IsCaseSensitive()) {
5781 wxDir dir(file.GetPath());
5783 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
5785 if (filename.IsSameAs(value,
false)) {
5787 file.Assign(file.GetPath(), value);
5790 cont = dir.GetNext(&filename);
5797 wxString::Format(
"<a href=\"%s\">%s</a>",
5798 file.GetFullPath(), file.GetFullName());
5800 value = value +
" <font color=\"red\">[ " +
5801 _(
"this file is not available") +
" ]</font>";
5805 "DATEND,DATSTA,PEREND,PERSTA";
5806 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5809 wxString ts = value;
5813 if (ts.Length() < 5) {
5817 if (ts.Length() < 7) {
5821 wxString::const_iterator end;
5823 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5825 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5826 if (d) ts.Append(wxString::Format(
" %d", dt.GetDay()));
5827 if (dt.GetYear() > 0)
5828 ts.Append(wxString::Format(
", %i", dt.GetYear()));
5829 if (curAttrName ==
"PEREND")
5830 ts = _(
"Period ends: ") + ts +
" (" + value +
")";
5831 if (curAttrName ==
"PERSTA")
5832 ts = _(
"Period starts: ") + ts +
" (" + value +
")";
5833 if (curAttrName ==
"DATEND")
5834 ts = _(
"Date ending: ") + ts +
" (" + value +
")";
5835 if (curAttrName ==
"DATSTA")
5836 ts = _(
"Date starting: ") + ts +
" (" + value +
")";
5840 if (curAttrName ==
"TS_TSP") {
5847 wxStringTokenizer tk(value,
",");
5852 ts1 = tk.GetNextToken().Trim(
false);
5855 }
while ((ts1.Left(2).ToLong(&l)));
5856 ts =
"Tidal Streams referred to<br><b>";
5857 ts.Append(tk.GetNextToken()).Append(
"</b> at <b>").Append(ts1);
5858 ts.Append(
"</b><br><table >");
5860 while (tk.HasMoreTokens()) {
5861 ts.Append(
"<tr><td>");
5862 wxString s1(wxString::Format(
"%+dh ", i));
5864 ts.Append(
"</td><td>");
5865 s1 = tk.GetNextToken();
5867 s1 =
"°</td><td>";
5869 s1 = tk.GetNextToken();
5872 ts.Append(
"</td></tr>");
5875 ts.Append(
"</table>");
5880 assert(curLight !=
nullptr);
5881 curLight->attributeValues.Add(value);
5883 if (curAttrName ==
"INFORM" || curAttrName ==
"NINFOM")
5884 value.Replace(
"|",
"<br>");
5886 if (curAttrName ==
"catgeo")
5887 attribStr << type2str(current->obj->Primitive_type);
5891 if (!(curAttrName ==
"DRVAL1")) {
5892 attribStr <<
"</font></td></tr>\n";
5902 attribStr <<
"</table>\n";
5904 objText +=
"<b>" + classDesc +
"</b> <font size=-2>(" + className +
5905 ")</font>" +
"<br>";
5907 if (positionString.Length())
5908 objText <<
"<font size=-2>" << positionString <<
"</font><br>\n";
5910 if (noAttr > 0) objText << attribStr;
5912 if (node != rule_list->GetFirst()) objText +=
"<hr noshade>";
5919 if (!lights.empty()) {
5920 assert(curLight !=
nullptr);
5925 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5929 for (
auto const &thisLight : lights) {
5932 if (thisLight->position != lastPos) {
5933 lastPos = thisLight->position;
5935 if (thisLight != *lights.begin())
5936 lightsHtml <<
"</table>\n<hr noshade>\n";
5938 lightsHtml <<
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>";
5939 lightsHtml <<
"<font size=-2>" << thisLight->position
5942 if (curLight->hasSectors)
5944 "<font size=-2>(Sector angles are True Bearings from "
5945 "Seaward)</font><br>");
5947 lightsHtml <<
"<table>";
5950 lightsHtml <<
"<tr>";
5951 lightsHtml <<
"<td><font size=-1>";
5954 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
5955 if (attrIndex != wxNOT_FOUND) {
5956 wxString color = thisLight->attributeValues.Item(attrIndex);
5957 if (color ==
"red (3)" || color ==
"red(3)")
5959 "<table border=0><tr><td "
5960 "bgcolor=red> </td></tr></table> ";
5961 else if (color ==
"green (4)" || color ==
"green(4)")
5963 "<table border=0><tr><td "
5964 "bgcolor=green> </td></tr></table> ";
5965 else if (color ==
"white (1)" || color ==
"white(1)")
5967 "<table border=0><tr><td "
5968 "bgcolor=white> </td></tr></table> ";
5969 else if (color ==
"yellow (6)" || color ==
"yellow(6)")
5971 "<table border=0><tr><td "
5972 "bgcolor=yellow> </td></tr></table> ";
5973 else if (color ==
"blue (5)" || color ==
"blue(5)")
5975 "<table border=0><tr><td "
5976 "bgcolor=blue> </td></tr></table> ";
5977 else if (color ==
"magenta (12)" || color ==
"magenta(12)")
5979 "<table border=0><tr><td "
5980 "bgcolor=magenta> </td></tr></table> ";
5983 "<table border=0><tr><td "
5984 "bgcolor=grey> ? </td></tr></table> ";
5987 int visIndex = thisLight->attributeNames.Index(
"LITVIS");
5988 if (visIndex != wxNOT_FOUND) {
5989 wxString vis = thisLight->attributeValues.Item(visIndex);
5990 if (vis.Contains(
"8")) {
5991 if (attrIndex != wxNOT_FOUND) {
5992 wxString color = thisLight->attributeValues.Item(attrIndex);
5993 if ((color ==
"red (3)" || color ==
"red(3)"))
5995 "<table border=0><tr><td "
5996 "bgcolor=DarkRed> </td></tr></table> ";
5997 if ((color ==
"green (4)" || color ==
"green(4)"))
5999 "<table border=0><tr><td "
6000 "bgcolor=DarkGreen> </td></tr></table> ";
6001 if ((color ==
"white (1)" || color ==
"white(1)"))
6003 "<table border=0><tr><td "
6004 "bgcolor=GoldenRod> </td></tr></table> ";
6009 lightsHtml << colorStr;
6011 lightsHtml <<
"</font></td><td><font size=-1><nobr><b>";
6013 attrIndex = thisLight->attributeNames.Index(
"LITCHR");
6014 if (attrIndex != wxNOT_FOUND) {
6015 wxString character = thisLight->attributeValues[attrIndex];
6016 lightsHtml << character.BeforeFirst(wxChar(
'(')) <<
" ";
6019 attrIndex = thisLight->attributeNames.Index(
"SIGGRP");
6020 if (attrIndex != wxNOT_FOUND) {
6021 lightsHtml << thisLight->attributeValues[attrIndex];
6025 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
6026 if (attrIndex != wxNOT_FOUND) {
6028 << thisLight->attributeValues.Item(attrIndex).Upper()[0];
6032 attrIndex = thisLight->attributeNames.Index(
"SIGPER");
6033 if (attrIndex != wxNOT_FOUND) {
6034 lightsHtml << thisLight->attributeValues[attrIndex];
6038 attrIndex = thisLight->attributeNames.Index(
"HEIGHT");
6039 if (attrIndex != wxNOT_FOUND) {
6040 lightsHtml << thisLight->attributeValues[attrIndex];
6044 attrIndex = thisLight->attributeNames.Index(
"VALNMR");
6045 if (attrIndex != wxNOT_FOUND) {
6046 lightsHtml << thisLight->attributeValues[attrIndex];
6050 lightsHtml <<
"</b>";
6052 attrIndex = thisLight->attributeNames.Index(
"SECTR1");
6053 if (attrIndex != wxNOT_FOUND) {
6054 lightsHtml <<
"(" << thisLight->attributeValues[attrIndex];
6055 lightsHtml <<
" - ";
6056 attrIndex = thisLight->attributeNames.Index(
"SECTR2");
6057 lightsHtml << thisLight->attributeValues[attrIndex] <<
") ";
6060 lightsHtml <<
"</nobr>";
6062 attrIndex = thisLight->attributeNames.Index(
"CATLIT");
6063 if (attrIndex != wxNOT_FOUND) {
6064 lightsHtml <<
"<nobr>";
6065 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6067 lightsHtml <<
"</nobr> ";
6070 attrIndex = thisLight->attributeNames.Index(
"EXCLIT");
6071 if (attrIndex != wxNOT_FOUND) {
6072 lightsHtml <<
"<nobr>";
6073 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6075 lightsHtml <<
"</nobr> ";
6078 attrIndex = thisLight->attributeNames.Index(
"OBJNAM");
6079 if (attrIndex != wxNOT_FOUND) {
6080 lightsHtml <<
"<br><nobr>";
6081 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6082 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6083 lightsHtml <<
"</nobr> ";
6086 lightsHtml <<
"</font></td>";
6087 lightsHtml <<
"</tr>";
6089 thisLight->attributeNames.Clear();
6090 thisLight->attributeValues.Clear();
6093 lightsHtml <<
"</table><hr noshade>\n";
6094 ret_val = lightsHtml << ret_val;
6108bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6110 wxLogMessage(
" Error: No ClassRegistrar in InitENCMinimal.");
6118 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6121 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6124 int rc = pENCReader->Ingest();
6128OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6130 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6141 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefnM_COVR(302);
6144 pENCReader->AddFeatureDefn(poDefn);
6147 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6150 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6153 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6164OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6168 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6171 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6174 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6177 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6186int s57chart::GetENCScale() {
6187 if (NULL == m_pENCDS)
return 0;
6194 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6197 return pENCReader->GetCSCL();
6207static void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6208 const char *pszErrorMsg) {
6209#define ERR_BUF_LEN 2000
6211 char buf[ERR_BUF_LEN + 1];
6213 if (eErrClass == CE_Debug)
6214 sprintf(buf,
" %s", pszErrorMsg);
6215 else if (eErrClass == CE_Warning)
6216 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6218 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6220 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6221 wxString msg(buf, wxConvUTF8);
6227 if (eErrClass == CE_Fatal) {
6228 longjmp(env_ogrf, 1);
6239const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6240 const char *pszKeyFieldValue,
6241 CSVCompareCriteria eCriteria,
6242 const char *pszTargetField)
6251 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6252 pszKeyFieldValue, eCriteria);
6254 if (papszRecord == NULL)
return "";
6259 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6260 if (iTargetField < 0)
return "";
6262 if (iTargetField >= CSLCount(papszRecord))
return "";
6264 return (papszRecord[iTargetField]);
6278static bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6302 std::vector<s57Sector_t> §orlegs) {
6303 float rangeScale = 0.0;
6305 if (sectorlegs.size() > 0) {
6306 std::vector<int> sectorangles;
6307 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6308 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6311 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6312 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6317 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6318 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6324 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6327 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6328 powf((
float)(lightPos.y - end1.y), 2));
6330 if (rangeScale == 0.0) {
6333 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6337 rangePx = rangePx * rangeScale;
6339 int penWidth = rangePx / 8;
6340 penWidth = wxMin(20, penWidth);
6341 penWidth = wxMax(5, penWidth);
6344 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
6345 penWidth, wxPENSTYLE_SOLID);
6346 arcpen->SetCap(wxCAP_BUTT);
6349 float angle1, angle2;
6350 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6351 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6352 if (angle1 > angle2) {
6355 int lpx = lightPos.x;
6356 int lpy = lightPos.y;
6358 wxPoint arcpoints[150];
6361 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6365 int narc = (angle2 - angle1) / step;
6367 step = (angle2 - angle1) / (
float)narc;
6369 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6370 wxPoint yellowCone[3];
6371 yellowCone[0] = lightPos;
6372 yellowCone[1] = end1;
6373 yellowCone[2] = end2;
6374 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6377 wxColor c = sectorlegs[i].color;
6378 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6379 dc.SetBrush(wxBrush(c));
6380 dc.StrokePolygon(3, yellowCone, 0, 0);
6383 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6384 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6385 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6386 arcpoints[npoints].x = x;
6387 arcpoints[npoints].y = y;
6390 dc.StrokeLines(npoints, arcpoints);
6394 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6400 bool haveAngle1 =
false;
6401 bool haveAngle2 =
false;
6402 int sec1 = (int)sectorlegs[i].sector1;
6403 int sec2 = (int)sectorlegs[i].sector2;
6404 if (sec1 > 360) sec1 -= 360;
6405 if (sec2 > 360) sec2 -= 360;
6407 if ((sec2 == 360) && (sec1 == 0))
6410 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6411 if (sectorangles[j] == sec1) haveAngle1 =
true;
6412 if (sectorangles[j] == sec2) haveAngle2 =
true;
6416 dc.StrokeLine(lightPos, end1);
6417 sectorangles.push_back(sec1);
6421 dc.StrokeLine(lightPos, end2);
6422 sectorangles.push_back(sec2);
6429void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6430 std::vector<s57Sector_t> §orlegs) {
6431 float rangeScale = 0.0;
6433 if (sectorlegs.size() > 0) {
6434 std::vector<int> sectorangles;
6435 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6436 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6439 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6440 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6445 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6446 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6452 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6455 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6456 powf((
float)(lightPos.y - end1.y), 2));
6458 if (rangeScale == 0.0) {
6461 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6465 rangePx = rangePx * rangeScale;
6467 float arcw = rangePx / 10;
6468 arcw = wxMin(20, arcw);
6469 arcw = wxMax(5, arcw);
6473 float angle1, angle2;
6474 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6475 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6476 if (angle1 > angle2) {
6479 int lpx = lightPos.x;
6480 int lpy = lightPos.y;
6482 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6483 wxPoint yellowCone[3];
6484 yellowCone[0] = lightPos;
6485 yellowCone[1] = end1;
6486 yellowCone[2] = end2;
6487 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6490 wxColor c = sectorlegs[i].color;
6491 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6492 dc.SetBrush(wxBrush(c));
6493 dc.StrokePolygon(3, yellowCone, 0, 0);
6497 wxPoint r(lpx, lpy);
6500 float rad = rangePx;
6524 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6527 glBindBuffer(GL_ARRAY_BUFFER, 0);
6528 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6530 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6531 glEnableVertexAttribArray(mPosAttrib);
6535 glGetUniformLocation(shader->programId(),
"circle_radius");
6536 glUniform1f(radiusloc, rad);
6540 glGetUniformLocation(shader->programId(),
"circle_center");
6544 glUniform2fv(centerloc, 1, ctrv);
6547 wxColour colorb = sectorlegs[i].color;
6549 colorv[0] = colorb.Red() / float(256);
6550 colorv[1] = colorb.Green() / float(256);
6551 colorv[2] = colorb.Blue() / float(256);
6552 colorv[3] = colorb.Alpha() / float(256);
6555 glGetUniformLocation(shader->programId(),
"circle_color");
6556 glUniform4fv(colloc, 1, colorv);
6566 glGetUniformLocation(shader->programId(),
"border_color");
6567 glUniform4fv(bcolloc, 1, bcolorv);
6570 GLint borderWidthloc =
6571 glGetUniformLocation(shader->programId(),
"border_width");
6572 glUniform1f(borderWidthloc, 2);
6575 GLint ringWidthloc =
6576 glGetUniformLocation(shader->programId(),
"ring_width");
6577 glUniform1f(ringWidthloc, arcw);
6581 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
6582 if (sr1 > 360.) sr1 -= 360.;
6584 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
6585 if (sr2 > 360.) sr2 -= 360.;
6597 if ((sb < 0) || (se < 0)) {
6603 glGetUniformLocation(shader->programId(),
"sector_1");
6604 glUniform1f(sector1loc, (sb * PI / 180.));
6606 glGetUniformLocation(shader->programId(),
"sector_2");
6607 glUniform1f(sector2loc, (se * PI / 180.));
6612 mat4x4_translate_in_place(I, r.x, r.y, 0);
6615 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6616 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6619 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6623 mat4x4_identity(IM);
6625 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6626 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6628 glDisableVertexAttribArray(mPosAttrib);
6634 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6639 bool haveAngle1 =
false;
6640 bool haveAngle2 =
false;
6641 int sec1 = (int)sectorlegs[i].sector1;
6642 int sec2 = (int)sectorlegs[i].sector2;
6643 if (sec1 > 360) sec1 -= 360;
6644 if (sec2 > 360) sec2 -= 360;
6646 if ((sec2 == 360) && (sec1 == 0))
6649 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6650 if (sectorangles[j] == sec1) haveAngle1 =
true;
6651 if (sectorangles[j] == sec2) haveAngle2 =
true;
6655 dc.StrokeLine(lightPos, end1);
6656 sectorangles.push_back(sec1);
6660 dc.StrokeLine(lightPos, end2);
6661 sectorangles.push_back(sec2);
6669bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6672 ListOfObjRazRules *rule_list,
6673 ListOfPI_S57Obj *pi_rule_list,
6674 std::vector<s57Sector_t> §orlegs) {
6675 bool newSectorsNeedDrawing =
false;
6677 bool bhas_red_green =
false;
6678 bool bleading_attribute =
false;
6681 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK ||
6682 cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT_HICON)
6684 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6686 int yOpacity = (float)opacity *
6689 if (target_plugin_chart || Chs57) {
6692 wxPoint2DDouble objPos;
6694 char *curr_att = NULL;
6696 wxArrayOfS57attVal *attValArray = NULL;
6698 ListOfObjRazRules::compatibility_iterator snode;
6699 ListOfPI_S57Obj::compatibility_iterator pnode;
6701 if (Chs57 && rule_list)
6702 snode = rule_list->GetLast();
6703 else if (target_plugin_chart && pi_rule_list)
6704 pnode = pi_rule_list->GetLast();
6707 wxPoint2DDouble lightPosD(0, 0);
6708 bool is_light =
false;
6712 ObjRazRules *current = snode->GetData();
6713 S57Obj *light = current->obj;
6714 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6715 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6716 curr_att = light->att_array;
6717 n_attr = light->n_attr;
6718 attValArray = light->attVal;
6721 }
else if (target_plugin_chart) {
6725 objPos = wxPoint2DDouble(light->
m_lat, light->
m_lon);
6728 attValArray = light->
attVal;
6738 wxString curAttrName;
6741 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6743 if (is_light && (lightPosD == objPos)) {
6751 bleading_attribute =
false;
6753 while (attrCounter < n_attr) {
6754 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6757 S57attVal *pAttrVal = NULL;
6760 pAttrVal = attValArray->Item(attrCounter);
6761 else if (target_plugin_chart)
6762 pAttrVal = attValArray->Item(attrCounter);
6766 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6768 if (curAttrName ==
"LITVIS") {
6769 if (value.StartsWith(
"obsc")) bviz =
false;
6771 if (curAttrName ==
"SECTR1") value.ToDouble(§r1);
6772 if (curAttrName ==
"SECTR2") value.ToDouble(§r2);
6773 if (curAttrName ==
"VALNMR") value.ToDouble(&valnmr);
6774 if (curAttrName ==
"COLOUR") {
6775 if (value ==
"red(3)") {
6776 color = wxColor(255, 0, 0, opacity);
6777 sector.iswhite =
false;
6778 bhas_red_green =
true;
6781 if (value ==
"green(4)") {
6782 color = wxColor(0, 255, 0, opacity);
6783 sector.iswhite =
false;
6784 bhas_red_green =
true;
6788 if (curAttrName ==
"EXCLIT") {
6789 if (value.Find(
"(3)")) valnmr = 1.0;
6792 if (curAttrName ==
"CATLIT") {
6793 if (value.Upper().StartsWith(
"DIRECT") ||
6794 value.Upper().StartsWith(
"LEAD"))
6795 bleading_attribute =
true;
6802 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6803 if (sectr1 > sectr2) {
6807 sector.pos.m_x = objPos.m_y;
6808 sector.pos.m_y = objPos.m_x;
6811 (valnmr > 0.0) ? valnmr : 2.5;
6812 sector.sector1 = sectr1;
6813 sector.sector2 = sectr2;
6815 if (!color.IsOk()) {
6816 color = wxColor(255, 255, 0, yOpacity);
6817 sector.iswhite =
true;
6819 sector.color = color;
6820 sector.isleading =
false;
6822 if (bleading_attribute) sector.isleading =
true;
6824 bool newsector =
true;
6825 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6826 if (sectorlegs[i].pos == sector.pos &&
6827 sectorlegs[i].sector1 == sector.sector1 &&
6828 sectorlegs[i].sector2 == sector.sector2) {
6834 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6838 if (!bviz) newsector =
false;
6840 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6844 sectorlegs.push_back(sector);
6845 newSectorsNeedDrawing =
true;
6852 snode = snode->GetPrevious();
6853 else if (target_plugin_chart)
6854 pnode = pnode->GetPrevious();
6862 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6863 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6864 if (sectorlegs[i].iswhite && bhas_red_green)
6865 sectorlegs[i].isleading =
true;
6869 return newSectorsNeedDrawing;
6872bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6874 std::vector<s57Sector_t> §orlegs) {
6875 if (!cc)
return false;
6877 static float lastLat, lastLon;
6879 if (!ps52plib)
return false;
6887 if (cc->m_singleChart &&
6888 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6889 target_chart = cc->m_singleChart;
6890 else if (viewport.b_quilt)
6891 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6893 target_chart = NULL;
6896 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6897 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6900 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6903 bool newSectorsNeedDrawing =
false;
6905 if (target_plugin_chart || Chs57) {
6906 ListOfObjRazRules *rule_list = NULL;
6907 ListOfPI_S57Obj *pi_rule_list = NULL;
6914 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6915 else if (target_plugin_chart)
6916 pi_rule_list =
g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6917 target_plugin_chart, lat, lon, viewport);
6919 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6920 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6928 pi_rule_list->Clear();
6929 delete pi_rule_list;
6933 return newSectorsNeedDrawing;
6936bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6938 std::vector<s57Sector_t> §orlegs) {
6939 if (!cc)
return false;
6941 double cursor_lat, cursor_lon;
6942 static float lastLat, lastLon;
6944 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6949 ChartBase *target_chart = cc->GetChartAtCursor();
6951 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6952 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6955 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6960 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6962 lastLat = cursor_lat;
6963 lastLon = cursor_lon;
6964 bool newSectorsNeedDrawing =
false;
6966 if (target_plugin_chart || Chs57) {
6967 ListOfObjRazRules *rule_list = NULL;
6968 ListOfPI_S57Obj *pi_rule_list = NULL;
6974 rule_list = Chs57->GetObjRuleListAtLatLon(
6975 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6976 else if (target_plugin_chart)
6977 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
6978 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6980 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6981 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6989 pi_rule_list->Clear();
6990 delete pi_rule_list;
6994 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.