27 #include "wx/wxprec.h"
34 #include "wx/tokenzr.h"
35 #include <wx/textfile.h>
36 #include <wx/filename.h>
39 #include "OCPNPlatform.h"
47 #include "model/cutil.h"
48 #include "model/georef.h"
50 #include "model/navutil_base.h"
51 #include "ocpn_pixel.h"
54 #include "model/wx28compat.h"
55 #include "model/chartdata_input_stream.h"
57 #include "gdal/cpl_csv.h"
62 #include "pluginmanager.h"
66 #include "SencManager.h"
68 #include "model/logger.h"
70 #include "ocpn_frame.h"
73 #define _CRTDBG_MAP_ALLOC
76 #define DEBUG_NEW new (_NORMAL_BLOCK, __FILE__, __LINE__)
81 #include "glChartCanvas.h"
92 #include "chart_ctx_factory.h"
95 #define strncasecmp(x, y, z) _strnicmp(x, y, z)
98 extern bool GetDoubleAttr(S57Obj *obj,
const char *AttrName,
101 void OpenCPN_OGRErrorHandler(
102 CPLErr eErrClass,
int nError,
103 const char *pszErrorMsg);
106 extern s52plib *ps52plib;
107 extern S57ClassRegistrar *g_poRegistrar;
108 extern wxString g_csv_locn;
109 extern wxString g_SENCPrefix;
110 extern bool g_bGDAL_Debug;
111 extern bool g_bDebugS57;
114 extern bool g_b_overzoom_x;
115 extern bool g_b_EnableVBO;
119 int g_SENC_LOD_pixels;
121 static jmp_buf env_ogrf;
123 #include <wx/arrimpl.cpp>
124 WX_DEFINE_OBJARRAY(ArrayOfS57Obj);
126 #include <wx/listimpl.cpp>
127 WX_DEFINE_LIST(ListOfPI_S57Obj);
129 WX_DEFINE_LIST(ListOfObjRazRules);
131 #define S57_THUMB_SIZE 200
138 static uint64_t hash_fast64(
const void *buf,
size_t len, uint64_t seed) {
139 const uint64_t m = 0x880355f21e6d1965ULL;
140 const uint64_t *pos = (
const uint64_t *)buf;
141 const uint64_t *end = pos + (len >> 3);
142 const unsigned char *pc;
143 uint64_t h = len * m ^ seed;
148 v *= 0x2127599bf4325c37ULL;
152 pc = (
const unsigned char *)pos;
156 v ^= (uint64_t)pc[6] << 48;
158 v ^= (uint64_t)pc[5] << 40;
160 v ^= (uint64_t)pc[4] << 32;
162 v ^= (uint64_t)pc[3] << 24;
164 v ^= (uint64_t)pc[2] << 16;
166 v ^= (uint64_t)pc[1] << 8;
168 v ^= (uint64_t)pc[0];
170 v *= 0x2127599bf4325c37ULL;
176 h *= 0x2127599bf4325c37ULL;
181 static unsigned int hash_fast32(
const void *buf,
size_t len,
183 uint64_t h = hash_fast64(buf, len, seed);
188 return h - (h >> 32);
191 unsigned long connector_key::hash()
const {
192 return hash_fast32(k,
sizeof k, 0);
200 render_canvas_parms::render_canvas_parms() { pix_buff = NULL; }
202 render_canvas_parms::~render_canvas_parms(
void) {}
204 static void PrepareForRender(
ViewPort *pvp, s52plib *plib) {
208 plib->SetVPointCompat(
219 GetOCPNCanvasWindow()->GetContentScaleFactor()
221 plib->PrepareForRender();
229 s57chart::s57chart() {
230 m_ChartType = CHART_TYPE_S57;
231 m_ChartFamily = CHART_FAMILY_VECTOR;
233 for (
int i = 0; i < PRIO_NUM; i++)
234 for (
int j = 0; j < LUPNAME_NUM; j++) razRules[i][j] = NULL;
243 pFloatingATONArray =
new wxArrayPtrVoid;
244 pRigidATONArray =
new wxArrayPtrVoid;
246 m_tmpup_array = NULL;
248 m_DepthUnits = _T(
"METERS");
249 m_depth_unit_id = DEPTH_UNIT_METERS;
251 bGLUWarningSent =
false;
257 m_pvaldco_array = NULL;
259 m_bExtentSet =
false;
261 m_pDIBThumbDay = NULL;
262 m_pDIBThumbDim = NULL;
263 m_pDIBThumbOrphan = NULL;
264 m_bbase_file_attr_known =
false;
266 m_bLinePrioritySet =
false;
267 m_plib_state_hash = 0;
274 m_b2pointLUPS =
false;
275 m_b2lineLUPS =
false;
277 m_next_safe_cnt = 1e6;
279 m_line_vertex_buffer = 0;
280 m_this_chart_context = 0;
282 m_vbo_byte_length = 0;
283 m_SENCthreadStatus = THREAD_INACTIVE;
284 bReadyToRender =
false;
286 m_disableBackgroundSENC =
false;
289 s57chart::~s57chart() {
290 FreeObjectsAndRules();
297 delete pFloatingATONArray;
298 delete pRigidATONArray;
302 free(m_pvaldco_array);
304 free(m_line_vertex_buffer);
306 delete m_pDIBThumbOrphan;
308 for (
unsigned i = 0; i < m_pcs_vector.size(); i++)
delete m_pcs_vector.at(i);
310 for (
unsigned i = 0; i < m_pve_vector.size(); i++)
delete m_pve_vector.at(i);
312 m_pcs_vector.clear();
313 m_pve_vector.clear();
315 for (
const auto &it : m_ve_hash) {
316 VE_Element *pedge = it.second;
318 free(pedge->pPoints);
324 for (
const auto &it : m_vc_hash) {
325 VC_Element *pcs = it.second;
334 if ((m_LineVBO_name > 0))
335 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
337 free(m_this_chart_context);
339 if (m_TempFilePath.Length() && (m_FullPath != m_TempFilePath)) {
340 if (::wxFileExists(m_TempFilePath)) wxRemoveFile(m_TempFilePath);
344 if (g_SencThreadManager) {
345 if (g_SencThreadManager->IsChartInTicketlist(
this)) {
346 g_SencThreadManager->SetChartPointer(
this, NULL);
351 void s57chart::GetValidCanvasRegion(
const ViewPort &VPoint,
355 double easting, northing;
358 toSM(m_FullExtent.SLAT, m_FullExtent.WLON, VPoint.clat, VPoint.clon, &easting,
360 epix = easting * VPoint.view_scale_ppm;
361 npix = northing * VPoint.view_scale_ppm;
363 rxl = (int)round((VPoint.pix_width / 2) + epix);
364 ryb = (int)round((VPoint.pix_height / 2) - npix);
366 toSM(m_FullExtent.NLAT, m_FullExtent.ELON, VPoint.clat, VPoint.clon, &easting,
368 epix = easting * VPoint.view_scale_ppm;
369 npix = northing * VPoint.view_scale_ppm;
371 rxr = (int)round((VPoint.pix_width / 2) + epix);
372 ryt = (int)round((VPoint.pix_height / 2) - npix);
374 pValidRegion->Clear();
375 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
378 LLRegion s57chart::GetValidRegion() {
379 double ll[8] = {m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.SLAT,
380 m_FullExtent.ELON, m_FullExtent.NLAT, m_FullExtent.ELON,
381 m_FullExtent.NLAT, m_FullExtent.WLON};
382 return LLRegion(4, ll);
385 void s57chart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
386 if (!ps52plib)
return;
391 case GLOBAL_COLOR_SCHEME_DAY:
392 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
394 case GLOBAL_COLOR_SCHEME_DUSK:
395 ps52plib->SetPLIBColorScheme(
"DUSK", ChartCtxFactory());
397 case GLOBAL_COLOR_SCHEME_NIGHT:
398 ps52plib->SetPLIBColorScheme(
"NIGHT", ChartCtxFactory());
401 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
405 m_global_color_scheme = cs;
407 if (bApplyImmediate) {
413 ClearRenderedTextCache();
416 ChangeThumbColor(cs);
419 void s57chart::ChangeThumbColor(ColorScheme cs) {
420 if (0 == m_pDIBThumbDay)
return;
424 case GLOBAL_COLOR_SCHEME_DAY:
425 pThumbData->pDIBThumb = m_pDIBThumbDay;
426 m_pDIBThumbOrphan = m_pDIBThumbDim;
428 case GLOBAL_COLOR_SCHEME_DUSK:
429 case GLOBAL_COLOR_SCHEME_NIGHT: {
430 if (NULL == m_pDIBThumbDim) {
431 wxImage img = m_pDIBThumbDay->ConvertToImage();
433 #if wxCHECK_VERSION(2, 8, 0)
434 wxImage gimg = img.ConvertToGreyscale(
444 wxBitmap *pBMP =
new wxBitmap(gimg);
446 m_pDIBThumbDim = pBMP;
447 m_pDIBThumbOrphan = m_pDIBThumbDay;
450 pThumbData->pDIBThumb = m_pDIBThumbDim;
456 bool s57chart::GetChartExtent(
Extent *pext) {
458 *pext = m_FullExtent;
464 static void free_mps(mps_container *mps) {
465 if (mps == 0)
return;
466 if (ps52plib && mps->cs_rules) {
467 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
468 Rules *rule_chain_top = mps->cs_rules->Item(i);
469 ps52plib->DestroyRulesChain(rule_chain_top);
471 delete mps->cs_rules;
476 void s57chart::FreeObjectsAndRules() {
485 for (
int i = 0; i < PRIO_NUM; ++i) {
486 for (
int j = 0; j < LUPNAME_NUM; j++) {
487 top = razRules[i][j];
488 while (top != NULL) {
490 if (0 == top->obj->nRef)
delete top->obj;
493 ObjRazRules *ctop = top->child;
497 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
499 ObjRazRules *cnxx = ctop->next;
514 void s57chart::ClearRenderedTextCache() {
516 for (
int i = 0; i < PRIO_NUM; ++i) {
517 for (
int j = 0; j < LUPNAME_NUM; j++) {
518 top = razRules[i][j];
519 while (top != NULL) {
520 if (top->obj->bFText_Added) {
521 top->obj->bFText_Added =
false;
522 delete top->obj->FText;
523 top->obj->FText = NULL;
527 ObjRazRules *ctop = top->child;
529 if (ctop->obj->bFText_Added) {
530 ctop->obj->bFText_Added =
false;
531 delete ctop->obj->FText;
532 ctop->obj->FText = NULL;
544 double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
545 bool b_allow_overzoom) {
547 return m_Chart_Scale * 0.125;
551 double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
553 return m_Chart_Scale * 4.0;
560 void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
562 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
564 r->y = roundint(m_pixy_vp_center -
565 ((north - m_northing_vp_center) * m_view_scale_ppm));
568 void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
569 wxPoint *r,
int nPoints) {
570 for (
int i = 0; i < nPoints; i++) {
571 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
573 r[i].y = roundint(m_pixy_vp_center -
574 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
578 void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
580 if (vpt->m_projection_type != PROJECTION_MERCATOR)
581 printf(
"s57chart unhandled projection\n");
584 int dx = pixx - (vpt->pix_width / 2);
585 int dy = (vpt->pix_height / 2) - pixy;
587 double xp = (dx * cos(vpt->skew)) - (dy * sin(vpt->skew));
588 double yp = (dy * cos(vpt->skew)) + (dx * sin(vpt->skew));
590 double d_east = xp / vpt->view_scale_ppm;
591 double d_north = yp / vpt->view_scale_ppm;
594 fromSM(d_east, d_north, vpt->clat, vpt->clon, &slat, &slon);
604 void s57chart::SetVPParms(
const ViewPort &vpt) {
606 m_pixx_vp_center = vpt.pix_width / 2.0;
607 m_pixy_vp_center = vpt.pix_height / 2.0;
608 m_view_scale_ppm = vpt.view_scale_ppm;
610 toSM(vpt.clat, vpt.clon, ref_lat, ref_lon, &m_easting_vp_center,
611 &m_northing_vp_center);
613 vp_transform.easting_vp_center = m_easting_vp_center;
614 vp_transform.northing_vp_center = m_northing_vp_center;
618 if (IsCacheValid()) {
620 if (vp_last.view_scale_ppm == vp_proposed.view_scale_ppm) {
621 double prev_easting_c, prev_northing_c;
622 toSM(vp_last.clat, vp_last.clon, ref_lat, ref_lon, &prev_easting_c,
625 double easting_c, northing_c;
626 toSM(vp_proposed.clat, vp_proposed.clon, ref_lat, ref_lon, &easting_c,
633 (easting_c - prev_easting_c) * vp_proposed.view_scale_ppm;
634 int dpix_x = (
int)round(delta_pix_x);
638 (northing_c - prev_northing_c) * vp_proposed.view_scale_ppm;
639 int dpix_y = (
int)round(delta_pix_y);
642 double c_east_d = (dpx / vp_proposed.view_scale_ppm) + prev_easting_c;
643 double c_north_d = (dpy / vp_proposed.view_scale_ppm) + prev_northing_c;
646 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
648 vp_proposed.clon = xlon;
649 vp_proposed.clat = xlat;
676 void s57chart::LoadThumb() {
677 wxFileName fn(m_FullPath);
678 wxString SENCdir = g_SENCPrefix;
680 if (SENCdir.Last() != fn.GetPathSeparator())
681 SENCdir.Append(fn.GetPathSeparator());
683 wxFileName tsfn(SENCdir);
684 tsfn.SetFullName(fn.GetFullName());
686 wxFileName ThumbFileNameLook(tsfn);
687 ThumbFileNameLook.SetExt(_T(
"BMP"));
690 if (ThumbFileNameLook.FileExists()) {
693 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
694 m_pDIBThumbDay = pBMP;
695 m_pDIBThumbOrphan = 0;
700 ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
703 if (pThumbData->pDIBThumb == 0) {
705 ChangeThumbColor(m_global_color_scheme);
708 UpdateThumbData(lat, lon);
713 bool s57chart::UpdateThumbData(
double lat,
double lon) {
717 if (pThumbData->pDIBThumb) {
718 double lat_top = m_FullExtent.NLAT;
719 double lat_bot = m_FullExtent.SLAT;
720 double lon_left = m_FullExtent.WLON;
721 double lon_right = m_FullExtent.ELON;
724 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
726 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
728 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
731 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
732 (int)(east * thumb_view_scale_ppm);
733 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
734 (int)(north * thumb_view_scale_ppm);
741 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
742 pThumbData->ShipX = test_x;
743 pThumbData->ShipY = test_y;
749 void s57chart::SetFullExtent(
Extent &ext) {
750 m_FullExtent.NLAT = ext.NLAT;
751 m_FullExtent.SLAT = ext.SLAT;
752 m_FullExtent.WLON = ext.WLON;
753 m_FullExtent.ELON = ext.ELON;
758 void s57chart::ForceEdgePriorityEvaluate(
void) { m_bLinePrioritySet =
false; }
760 void s57chart::SetLinePriorities(
void) {
761 if (!ps52plib)
return;
766 if (!m_bLinePrioritySet) {
770 for (
int i = 0; i < PRIO_NUM; ++i) {
771 top = razRules[i][2];
772 while (top != NULL) {
773 ObjRazRules *crnt = top;
775 ps52plib->SetLineFeaturePriority(crnt, i);
781 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
786 top = razRules[i][j];
787 while (top != NULL) {
790 ps52plib->SetLineFeaturePriority(crnt, i);
796 for (
int i = 0; i < PRIO_NUM; ++i) {
797 for (
int j = 0; j < LUPNAME_NUM; j++) {
798 ObjRazRules *top = razRules[i][j];
799 while (top != NULL) {
800 S57Obj *obj = top->obj;
803 connector_segment *pcs;
804 line_segment_element *list = obj->m_ls_list;
806 switch (list->ls_type) {
810 if (pedge) list->priority = pedge->max_priority;
815 if (pcs) list->priority = pcs->max_priority_cs;
830 m_bLinePrioritySet =
true;
834 void s57chart::SetLinePriorities(
void )
836 if( !ps52plib )
return;
841 if( !m_bLinePrioritySet ) {
845 for(
int i = 0; i < PRIO_NUM; ++i ) {
847 top = razRules[i][2];
848 while( top != NULL ) {
849 ObjRazRules *crnt = top;
851 ps52plib->SetLineFeaturePriority( crnt, i );
856 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
861 top = razRules[i][j];
862 while( top != NULL ) {
865 ps52plib->SetLineFeaturePriority( crnt, i );
873 for(
int i = 0; i < PRIO_NUM; ++i ) {
874 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
875 ObjRazRules *top = razRules[i][j];
876 while( top != NULL ) {
877 S57Obj *obj = top->obj;
880 connector_segment *pcs;
881 line_segment_element *list = obj->m_ls_list;
886 pedge = (VE_Element *)list->private0;
888 list->priority = pedge->max_priority;
892 pcs = (connector_segment *)list->private0;
894 list->priority = pcs->max_priority;
909 m_bLinePrioritySet =
true;
913 int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
917 line_segment_element *ls_list = obj->m_ls_list;
919 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
920 nPoints += ls_list->pedge->nCount;
923 ls_list = ls_list->next;
932 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
936 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
937 ls_list = obj->m_ls_list;
939 size_t vbo_offset = 0;
941 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
942 vbo_offset = ls_list->pedge->vbo_offset;
943 count = ls_list->pedge->nCount;
945 vbo_offset = ls_list->pcs->vbo_offset;
949 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
951 ls_list = ls_list->next;
958 int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
963 line_segment_element *ls_list = obj->m_ls_list;
965 nPoints += ls_list->n_points;
966 ls_list = ls_list->next;
975 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
979 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
980 ls_list = obj->m_ls_list;
982 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
983 br += ls_list->n_points * 2;
984 ls_list = ls_list->next;
993 float e0, n0, e1, n1;
996 void s57chart::AssembleLineGeometry(
void) {
1001 for (
const auto &it : m_ve_hash) {
1002 VE_Element *pedge = it.second;
1004 nPoints += pedge->nCount;
1010 std::map<long long, connector_segment *> ce_connector_hash;
1011 std::map<long long, connector_segment *> ec_connector_hash;
1012 std::map<long long, connector_segment *> cc_connector_hash;
1014 std::map<long long, connector_segment *>::iterator csit;
1021 std::vector<segment_pair> connector_segment_vector;
1022 size_t seg_pair_index = 0;
1027 for (
int i = 0; i < PRIO_NUM; ++i) {
1028 for (
int j = 0; j < LUPNAME_NUM; j++) {
1029 ObjRazRules *top = razRules[i][j];
1030 while (top != NULL) {
1031 S57Obj *obj = top->obj;
1033 if ((!obj->m_ls_list) &&
1036 line_segment_element list_top;
1039 line_segment_element *le_current = &list_top;
1041 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1042 if (!obj->m_lsindex_array)
continue;
1044 int seg_index = iseg * 3;
1045 int *index_run = &obj->m_lsindex_array[seg_index];
1048 unsigned int inode = *index_run++;
1051 bool edge_dir =
true;
1052 int venode = *index_run++;
1058 VE_Element *pedge = 0;
1060 if (m_ve_hash.find(venode) != m_ve_hash.end())
1061 pedge = m_ve_hash[venode];
1065 unsigned int enode = *index_run++;
1068 VC_Element *ipnode = 0;
1069 ipnode = m_vc_hash[inode];
1072 VC_Element *epnode = 0;
1073 epnode = m_vc_hash[enode];
1076 if (pedge && pedge->nCount) {
1080 long long key = ((
unsigned long long)inode << 32) + venode;
1082 connector_segment *pcs = NULL;
1083 csit = ce_connector_hash.find(key);
1084 if (csit == ce_connector_hash.end()) {
1086 pcs =
new connector_segment;
1087 ce_connector_hash[key] = pcs;
1091 float *ppt = ipnode->pPoint;
1096 pair.e1 = pedge->pPoints[0];
1097 pair.n1 = pedge->pPoints[1];
1099 int last_point_index = (pedge->nCount - 1) * 2;
1100 pair.e1 = pedge->pPoints[last_point_index];
1101 pair.n1 = pedge->pPoints[last_point_index + 1];
1104 connector_segment_vector.push_back(pair);
1105 pcs->vbo_offset = seg_pair_index;
1111 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1112 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1114 pcs->cs_lat_avg = lat;
1115 pcs->cs_lon_avg = lon;
1120 line_segment_element *pls =
new line_segment_element;
1125 pls->ls_type = TYPE_CE;
1127 le_current->next = pls;
1132 if (pedge && pedge->nCount) {
1133 line_segment_element *pls =
new line_segment_element;
1138 pls->ls_type = TYPE_EE;
1139 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1141 le_current->next = pls;
1149 if (pedge && pedge->nCount) {
1150 long long key = ((
unsigned long long)venode << 32) + enode;
1152 connector_segment *pcs = NULL;
1153 csit = ec_connector_hash.find(key);
1154 if (csit == ec_connector_hash.end()) {
1156 pcs =
new connector_segment;
1157 ec_connector_hash[key] = pcs;
1163 pair.e0 = pedge->pPoints[0];
1164 pair.n0 = pedge->pPoints[1];
1166 int last_point_index = (pedge->nCount - 1) * 2;
1167 pair.e0 = pedge->pPoints[last_point_index];
1168 pair.n0 = pedge->pPoints[last_point_index + 1];
1171 float *ppt = epnode->pPoint;
1175 connector_segment_vector.push_back(pair);
1176 pcs->vbo_offset = seg_pair_index;
1182 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1183 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1185 pcs->cs_lat_avg = lat;
1186 pcs->cs_lon_avg = lon;
1191 line_segment_element *pls =
new line_segment_element;
1195 pls->ls_type = TYPE_EC;
1197 le_current->next = pls;
1201 long long key = ((
unsigned long long)inode << 32) + enode;
1203 connector_segment *pcs = NULL;
1204 csit = cc_connector_hash.find(key);
1205 if (csit == cc_connector_hash.end()) {
1207 pcs =
new connector_segment;
1208 cc_connector_hash[key] = pcs;
1213 float *ppt = ipnode->pPoint;
1217 ppt = epnode->pPoint;
1221 connector_segment_vector.push_back(pair);
1222 pcs->vbo_offset = seg_pair_index;
1228 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1229 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1231 pcs->cs_lat_avg = lat;
1232 pcs->cs_lon_avg = lon;
1237 line_segment_element *pls =
new line_segment_element;
1241 pls->ls_type = TYPE_CC;
1243 le_current->next = pls;
1257 if (obj->m_ls_list == NULL) {
1258 obj->m_n_lsindex = 0;
1262 free(obj->m_lsindex_array);
1263 obj->m_lsindex_array = NULL;
1276 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1278 unsigned char *buffer_offset;
1281 bool grow_buffer =
false;
1283 if (0 == m_vbo_byte_length) {
1284 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1285 m_vbo_byte_length = vbo_byte_length;
1286 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1289 m_line_vertex_buffer = (
float *)realloc(
1290 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1291 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1292 offset = m_vbo_byte_length;
1293 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1297 float *lvr = (
float *)buffer_offset;
1301 for (
const auto &it : m_ve_hash) {
1302 VE_Element *pedge = it.second;
1304 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1305 lvr += pedge->nCount * 2;
1307 pedge->vbo_offset = offset;
1308 offset += pedge->nCount * 2 *
sizeof(float);
1321 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1323 connector_segment *pcs = csit->second;
1324 m_pcs_vector.push_back(pcs);
1326 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1332 pcs->vbo_offset = offset;
1333 offset += 4 *
sizeof(float);
1336 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1338 connector_segment *pcs = csit->second;
1339 m_pcs_vector.push_back(pcs);
1341 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1347 pcs->vbo_offset = offset;
1348 offset += 4 *
sizeof(float);
1351 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1353 connector_segment *pcs = csit->second;
1354 m_pcs_vector.push_back(pcs);
1356 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1362 pcs->vbo_offset = offset;
1363 offset += 4 *
sizeof(float);
1367 connector_segment_vector.clear();
1372 for (
const auto &it : m_ve_hash) {
1373 VE_Element *pedge = it.second;
1375 m_pve_vector.push_back(pedge);
1376 free(pedge->pPoints);
1384 for (
const auto &it : m_vc_hash) {
1385 VC_Element *pcs = it.second;
1386 if (pcs) free(pcs->pPoint);
1392 if (g_b_EnableVBO) {
1394 if (m_LineVBO_name > 0){
1395 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1396 m_LineVBO_name = -1;
1405 void s57chart::BuildLineVBO(
void) {
1407 if (!g_b_EnableVBO)
return;
1409 if (m_LineVBO_name == -1) {
1412 glGenBuffers(1, &vboId);
1415 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1421 #ifndef USE_ANDROID_GLES2
1422 glEnableClientState(GL_VERTEX_ARRAY);
1424 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1429 ObjRazRules *top, *crnt;
1430 int vbo_area_size_bytes = 0;
1431 for (
int i = 0; i < PRIO_NUM; ++i) {
1432 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1433 top = razRules[i][4];
1435 top = razRules[i][3];
1437 while (top != NULL) {
1442 PolyTriGroup *ppg_vbo = crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1444 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1451 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes,
1452 NULL, GL_STATIC_DRAW);
1454 GLenum err = glGetError();
1457 msg.Printf(_T(
"S57 VBO Error 1: %d"), err);
1459 printf(
"S57 VBO Error 1: %d", err);
1463 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length, m_line_vertex_buffer);
1468 msg.Printf(_T(
"S57 VBO Error 2: %d"), err);
1470 printf(
"S57 VBO Error 2: %d", err);
1475 int vbo_load_offset = m_vbo_byte_length;
1477 for (
int i = 0; i < PRIO_NUM; ++i) {
1478 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1479 top = razRules[i][4];
1481 top = razRules[i][3];
1483 while (top != NULL) {
1488 PolyTriGroup *ppg_vbo = crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1491 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1492 ppg_vbo->single_buffer_size,
1493 ppg_vbo->single_buffer);
1495 crnt->obj->vboAreaOffset = vbo_load_offset;
1496 vbo_load_offset += ppg_vbo->single_buffer_size;
1503 msg.Printf(_T(
"S57 VBO Error 3: %d"), err);
1505 printf(
"S57 VBO Error 3: %d", err);
1510 #ifndef USE_ANDROID_GLES2
1511 glDisableClientState(GL_VERTEX_ARRAY);
1513 glBindBuffer(GL_ARRAY_BUFFER, 0);
1517 for (
int i = 0; i < PRIO_NUM; ++i) {
1518 for (
int j = 0; j < LUPNAME_NUM; j++) {
1519 ObjRazRules *top = razRules[i][j];
1520 while (top != NULL) {
1521 S57Obj *obj = top->obj;
1522 obj->auxParm2 = vboId;
1528 m_LineVBO_name = vboId;
1529 m_this_chart_context->vboID = vboId;
1548 bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1551 const LLRegion &Region) {
1552 if (!m_RAZBuilt)
return false;
1554 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1557 bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1560 const LLRegion &Region) {
1561 if (!m_RAZBuilt)
return false;
1563 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1566 bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1569 const LLRegion &Region) {
1570 if (!m_RAZBuilt)
return false;
1572 bool b_text = ps52plib->GetShowS57Text();
1573 ps52plib->m_bShowS57Text =
false;
1574 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1575 ps52plib->m_bShowS57Text = b_text;
1580 bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1582 if (!m_RAZBuilt)
return false;
1586 if (!ps52plib)
return false;
1589 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1591 glChartCanvas::DisableClipRegion();
1592 DoRenderOnGLText(glc, VPoint);
1598 bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1601 const LLRegion &Region,
bool b_overlay) {
1602 if (!m_RAZBuilt)
return false;
1606 if (!ps52plib)
return false;
1608 if (g_bDebugS57) printf(
"\n");
1612 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1614 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1615 m_bLinePrioritySet =
false;
1617 ClearRenderedTextCache();
1619 ResetPointBBoxes(m_last_vp, VPoint);
1622 m_plib_state_hash = ps52plib->GetStateHash();
1625 if (VPoint.view_scale_ppm != m_last_vp.view_scale_ppm) {
1626 ResetPointBBoxes(m_last_vp, VPoint);
1630 SetLinePriorities();
1633 ps52plib->ClearTextList();
1641 wxRect upr = upd.GetRect();
1644 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1645 chart_region.Intersect(Region);
1647 if (!chart_region.Empty()) {
1651 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1658 if (CHART_TYPE_CM93 == GetChartType()) {
1662 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1665 #ifdef OPT_USE_ANDROID_GLES2
1673 wxRect r = upd.GetRect();
1675 glViewport(r.x, vp->pix_height - (r.y + r.height), r.width, r.height);
1683 float yp = vp->pix_height - (r.y + r.height);
1685 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1686 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1689 I[0][0] *= 2.0 / (float)r.width;
1690 I[1][1] *= -2.0 / (
float)r.height;
1694 mat4x4_rotate_Z(Q, I, angle);
1696 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1699 ps52plib->SetReducedBBox(cvp.GetBBox());
1700 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1705 DoRenderOnGL(glc, cvp);
1707 glChartCanvas::DisableClipRegion();
1721 bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1734 for (i = 0; i < PRIO_NUM; ++i) {
1735 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1736 top = razRules[i][4];
1738 top = razRules[i][3];
1740 while (top != NULL) {
1743 crnt->sm_transform_parms = &vp_transform;
1744 ps52plib->RenderAreaToGL(glc, crnt);
1750 for (i = 0; i < PRIO_NUM; ++i) {
1751 if (PI_GetPLIBBoundaryStyle() == SYMBOLIZED_BOUNDARIES)
1752 top = razRules[i][4];
1754 top = razRules[i][3];
1756 while (top != NULL) {
1759 crnt->sm_transform_parms = &vp_transform;
1764 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1765 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1766 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1767 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1770 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1777 for (i = 0; i < PRIO_NUM; ++i) {
1778 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1779 top = razRules[i][4];
1781 top = razRules[i][3];
1782 while (top != NULL) {
1785 crnt->sm_transform_parms = &vp_transform;
1786 ps52plib->RenderObjectToGL(glc, crnt);
1791 for (i = 0; i < PRIO_NUM; ++i) {
1792 top = razRules[i][2];
1793 while (top != NULL) {
1796 crnt->sm_transform_parms = &vp_transform;
1797 ps52plib->RenderObjectToGL(glc, crnt);
1803 for (i = 0; i < PRIO_NUM; ++i) {
1804 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1805 top = razRules[i][0];
1807 top = razRules[i][1];
1809 while (top != NULL) {
1812 crnt->sm_transform_parms = &vp_transform;
1813 ps52plib->RenderObjectToGL(glc, crnt);
1823 bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1834 for( i = 0; i < PRIO_NUM; ++i ) {
1835 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1836 top = razRules[i][4];
1838 top = razRules[i][3];
1840 while( top != NULL ) {
1843 crnt->sm_transform_parms = &vp_transform;
1850 for (i = 0; i < PRIO_NUM; ++i) {
1851 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1852 top = razRules[i][4];
1854 top = razRules[i][3];
1856 while (top != NULL) {
1859 crnt->sm_transform_parms = &vp_transform;
1860 ps52plib->RenderObjectToGLText(glc, crnt);
1863 top = razRules[i][2];
1864 while (top != NULL) {
1867 crnt->sm_transform_parms = &vp_transform;
1868 ps52plib->RenderObjectToGLText(glc, crnt);
1871 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1872 top = razRules[i][0];
1874 top = razRules[i][1];
1876 while (top != NULL) {
1879 crnt->sm_transform_parms = &vp_transform;
1880 ps52plib->RenderObjectToGLText(glc, crnt);
1889 bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1892 if (!m_RAZBuilt)
return false;
1894 bool b_text = ps52plib->GetShowS57Text();
1895 ps52plib->m_bShowS57Text =
false;
1896 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1897 ps52plib->m_bShowS57Text = b_text;
1902 bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1905 if (!dc.IsOk())
return false;
1908 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1912 if (fabs(VPoint.rotation) > .01) {
1913 DCRenderText(dc, VPoint);
1916 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1920 while (upd.HaveRects()) {
1921 wxRect rect = upd.GetRect();
1927 temp_vp.GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1931 temp_vp.GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1933 if (temp_lon_right < temp_lon_left)
1934 temp_lon_right += 360.;
1936 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1939 wxDCClipper clip(dc, rect);
1940 DCRenderText(dc, temp_vp);
1949 bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1951 if (!m_RAZBuilt)
return false;
1953 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1956 bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1959 if (!m_RAZBuilt)
return false;
1960 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1963 bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1968 bool force_new_view =
false;
1970 if (Region != m_last_Region) force_new_view =
true;
1972 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1974 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1975 m_bLinePrioritySet =
false;
1977 ClearRenderedTextCache();
1979 ResetPointBBoxes(m_last_vp, VPoint);
1983 if (VPoint.view_scale_ppm != m_last_vp.view_scale_ppm) {
1984 ResetPointBBoxes(m_last_vp, VPoint);
1987 SetLinePriorities();
1989 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1993 if (VPoint.b_quilt) {
1995 if ((m_pCloneBM->GetWidth() != VPoint.pix_width) ||
1996 (m_pCloneBM->GetHeight() != VPoint.pix_height)) {
2001 if (NULL == m_pCloneBM)
2002 m_pCloneBM =
new wxBitmap(VPoint.pix_width, VPoint.pix_height, -1);
2004 wxMemoryDC dc_clone;
2005 dc_clone.SelectObject(*m_pCloneBM);
2007 #ifdef ocpnUSE_DIBSECTION
2010 wxMemoryDC memdc, dc_org;
2013 pDIB->SelectIntoDC(dc_org);
2018 while (upd.HaveRects()) {
2019 wxRect rect = upd.GetRect();
2020 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
2025 dc_clone.SelectObject(wxNullBitmap);
2026 dc_org.SelectObject(wxNullBitmap);
2030 wxColour nodat = GetGlobalColor(_T (
"NODTA" ));
2031 wxColour nodat_sub = nodat;
2033 #ifdef ocpnUSE_ocpnBitmap
2034 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
2036 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
2037 m_pCloneBM->SetMask(m_pMask);
2040 dc.SelectObject(*m_pCloneBM);
2042 pDIB->SelectIntoDC(dc);
2044 m_last_Region = Region;
2049 bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2054 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2056 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2057 m_bLinePrioritySet =
false;
2059 ClearRenderedTextCache();
2063 SetLinePriorities();
2065 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2067 pDIB->SelectIntoDC(dc);
2074 bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2075 RenderTypeEnum option,
bool force_new_view) {
2076 bool bnewview =
false;
2078 bool bNewVP =
false;
2080 bool bReallyNew =
false;
2082 double easting_ul, northing_ul;
2083 double easting_lr, northing_lr;
2084 double prev_easting_ul = 0., prev_northing_ul = 0.;
2086 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2087 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2089 if (VPoint.view_scale_ppm != m_last_vp.view_scale_ppm) bReallyNew =
true;
2093 if (VPoint.chart_scale > 1e8) bReallyNew =
true;
2095 wxRect dest(0, 0, VPoint.pix_width, VPoint.pix_height);
2096 if (m_last_vprect != dest) bReallyNew =
true;
2097 m_last_vprect = dest;
2099 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2101 m_plib_state_hash = ps52plib->GetStateHash();
2112 if (m_last_vp.IsValid()) {
2114 m_easting_vp_center - ((VPoint.pix_width / 2) / m_view_scale_ppm);
2116 m_northing_vp_center + ((VPoint.pix_height / 2) / m_view_scale_ppm);
2117 easting_lr = easting_ul + (VPoint.pix_width / m_view_scale_ppm);
2118 northing_lr = northing_ul - (VPoint.pix_height / m_view_scale_ppm);
2120 double last_easting_vp_center, last_northing_vp_center;
2121 toSM(m_last_vp.clat, m_last_vp.clon, ref_lat, ref_lon,
2122 &last_easting_vp_center, &last_northing_vp_center);
2125 last_easting_vp_center - ((m_last_vp.pix_width / 2) / m_view_scale_ppm);
2126 prev_northing_ul = last_northing_vp_center +
2127 ((m_last_vp.pix_height / 2) / m_view_scale_ppm);
2129 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2130 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2132 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2133 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2135 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2136 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2138 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2141 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2150 else if ((rul.x != 0) || (rul.y != 0)) {
2151 if (g_bDebugS57) printf(
"newvp due to rul\n");
2162 if (force_new_view) bNewVP =
true;
2166 OCPNRegion rgn_last(0, 0, VPoint.pix_width, VPoint.pix_height);
2167 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2168 rgn_last.Intersect(rgn_new);
2170 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2172 rgn_last.GetBox(xu, yu, wu, hu);
2189 pDIB->SelectIntoDC(dc_last);
2193 new PixelCache(VPoint.pix_width, VPoint.pix_height, BPP);
2194 pDIBNew->SelectIntoDC(dc_new);
2198 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2203 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.pix_width,
2206 dc_new.SelectObject(wxNullBitmap);
2207 dc_last.SelectObject(wxNullBitmap);
2215 pDIB->SelectIntoDC(dc);
2217 OCPNRegion rgn_delta(0, 0, VPoint.pix_width, VPoint.pix_height);
2219 rgn_delta.Subtract(rgn_reused);
2222 while (upd.HaveRects()) {
2223 wxRect rect = upd.GetRect();
2228 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2230 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2231 (rect.y / m_view_scale_ppm);
2232 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2233 (rect.x / m_view_scale_ppm);
2234 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2237 double temp_northing_lr =
2238 temp_northing_ul - (rect.height / m_view_scale_ppm);
2239 double temp_easting_lr =
2240 temp_easting_ul + (rect.width / m_view_scale_ppm);
2241 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2244 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2249 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2250 temp_vp.GetBBox().GetLatRange()) *
2252 temp_vp.GetBBox().EnLarge(margin);
2258 DCRenderRect(dc, temp_vp, &rect);
2263 dc.SelectObject(wxNullBitmap);
2272 else if (bNewVP || (NULL == pDIB)) {
2274 pDIB =
new PixelCache(VPoint.pix_width, VPoint.pix_height,
2277 wxRect full_rect(0, 0, VPoint.pix_width, VPoint.pix_height);
2278 pDIB->SelectIntoDC(dc);
2281 ps52plib->ClearTextList();
2283 DCRenderRect(dc, VPoint, &full_rect);
2285 dc.SelectObject(wxNullBitmap);
2296 int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2309 render_canvas_parms pb_spec;
2311 pb_spec.depth = BPP;
2312 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2313 pb_spec.lclip = rect->x;
2314 pb_spec.rclip = rect->x + rect->width - 1;
2315 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2316 pb_spec.width = rect->width;
2317 pb_spec.height = rect->height;
2318 pb_spec.x = rect->x;
2319 pb_spec.y = rect->y;
2321 #ifdef ocpnUSE_ocpnBitmap
2322 pb_spec.b_revrgb =
true;
2324 pb_spec.b_revrgb =
false;
2328 wxColour color = GetGlobalColor(_T (
"NODTA" ));
2329 unsigned char r, g, b;
2337 if (pb_spec.depth == 24) {
2338 for (
int i = 0; i < pb_spec.height; i++) {
2339 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2340 for (
int j = 0; j < pb_spec.width; j++) {
2347 int color_int = ((r) << 16) + ((g) << 8) + (b);
2349 for (
int i = 0; i < pb_spec.height; i++) {
2350 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2351 for (
int j = 0; j < pb_spec.width; j++) {
2358 for (i = 0; i < PRIO_NUM; ++i) {
2359 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2360 top = razRules[i][4];
2362 top = razRules[i][3];
2364 while (top != NULL) {
2367 crnt->sm_transform_parms = &vp_transform;
2368 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2373 #ifdef ocpnUSE_ocpnBitmap
2374 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2375 pb_spec.height, pb_spec.depth);
2377 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2378 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2379 wxBitmap *pREN =
new wxBitmap(*prender_image);
2385 dc_ren.SelectObject(*pREN);
2388 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2389 (wxDC *)&dc_ren, 0, 0);
2392 dc_ren.SelectObject(wxNullBitmap);
2394 #ifdef ocpnUSE_ocpnBitmap
2395 free(pb_spec.pix_buff);
2397 delete prender_image;
2404 DCRenderLPB(dcinput, vp, rect);
2409 bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2416 for (i = 0; i < PRIO_NUM; ++i) {
2418 wxDCClipper *pdcc = NULL;
2424 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2425 top = razRules[i][4];
2427 top = razRules[i][3];
2428 while (top != NULL) {
2431 crnt->sm_transform_parms = &vp_transform;
2432 ps52plib->RenderObjectToDC(&dcinput, crnt);
2435 top = razRules[i][2];
2436 while (top != NULL) {
2439 crnt->sm_transform_parms = &vp_transform;
2440 ps52plib->RenderObjectToDC(&dcinput, crnt);
2443 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2444 top = razRules[i][0];
2446 top = razRules[i][1];
2448 while (top != NULL) {
2451 crnt->sm_transform_parms = &vp_transform;
2452 ps52plib->RenderObjectToDC(&dcinput, crnt);
2456 if (pdcc)
delete pdcc;
2469 bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2475 for (i = 0; i < PRIO_NUM; ++i) {
2476 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2477 top = razRules[i][4];
2479 top = razRules[i][3];
2481 while (top != NULL) {
2484 crnt->sm_transform_parms = &vp_transform;
2485 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2488 top = razRules[i][2];
2489 while (top != NULL) {
2492 crnt->sm_transform_parms = &vp_transform;
2493 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2496 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2497 top = razRules[i][0];
2499 top = razRules[i][1];
2501 while (top != NULL) {
2504 crnt->sm_transform_parms = &vp_transform;
2505 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2512 bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2513 wxFileName fn(FullPath);
2515 wxString cname = fn.GetName();
2516 if (cname.Length() >= 3)
2517 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2522 InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2525 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2528 if (name.Upper().EndsWith(
".XZ")) {
2529 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2532 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2533 wxFileName(name).GetName();
2535 if (!wxFileExists(m_TempFilePath) &&
2536 !DecompressXZFile(name, m_TempFilePath)) {
2537 wxRemoveFile(m_TempFilePath);
2538 return INIT_FAIL_REMOVE;
2541 m_TempFilePath = name;
2542 ext = wxFileName(name).GetExt();
2550 return INIT_FAIL_NOERROR;
2555 InitReturn ret_value = INIT_OK;
2557 m_Description = name;
2559 wxFileName fn(m_TempFilePath);
2562 wxString cname = fn.GetName();
2563 m_usage_char = cname[2];
2566 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2567 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2569 if (flags == THUMB_ONLY) {
2577 if (flags == HEADER_ONLY) {
2578 if (ext == _T(
"000")) {
2579 if (!GetBaseFileAttr(fn.GetFullPath()))
2580 ret_value = INIT_FAIL_REMOVE;
2582 if (!CreateHeaderDataFromENC())
2583 ret_value = INIT_FAIL_REMOVE;
2585 ret_value = INIT_OK;
2587 }
else if (ext == _T(
"S57")) {
2588 m_SENCFileName = m_TempFilePath;
2589 if (!CreateHeaderDataFromSENC())
2590 ret_value = INIT_FAIL_REMOVE;
2592 ret_value = INIT_OK;
2601 if (!m_bbase_file_attr_known) {
2602 if (!GetBaseFileAttr(m_TempFilePath))
2603 ret_value = INIT_FAIL_REMOVE;
2605 m_bbase_file_attr_known =
true;
2608 if (ext == _T(
"000")) {
2609 if (m_bbase_file_attr_known) {
2610 int sret = FindOrCreateSenc(m_FullPath);
2611 if (sret == BUILD_SENC_PENDING) {
2616 if (sret != BUILD_SENC_OK) {
2617 if (sret == BUILD_SENC_NOK_RETRY)
2618 ret_value = INIT_FAIL_RETRY;
2620 ret_value = INIT_FAIL_REMOVE;
2622 ret_value = PostInit(flags, m_global_color_scheme);
2627 else if (ext == _T(
"S57")) {
2628 m_SENCFileName = m_TempFilePath;
2629 ret_value = PostInit(flags, m_global_color_scheme);
2636 wxString s57chart::buildSENCName(
const wxString &name) {
2637 wxFileName fn(name);
2638 fn.SetExt(_T(
"S57"));
2639 wxString file_name = fn.GetFullName();
2642 wxString SENCdir = g_SENCPrefix;
2644 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2645 SENCdir.Append(wxFileName::GetPathSeparator());
2648 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2649 wxCharBuffer buf = source_dir.ToUTF8();
2650 unsigned char sha1_out[20];
2651 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2654 for (
unsigned int i = 0; i < 6; i++) {
2656 s.Printf(_T(
"%02X"), sha1_out[i]);
2660 file_name.Prepend(sha1);
2663 wxFileName tsfn(SENCdir);
2664 tsfn.SetFullName(file_name);
2666 return tsfn.GetFullPath();
2673 int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2677 if (name.Upper().EndsWith(
".XZ")) {
2678 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2681 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2682 wxFileName(name).GetName();
2684 if (!wxFileExists(m_TempFilePath) &&
2685 !DecompressXZFile(name, m_TempFilePath)) {
2686 wxRemoveFile(m_TempFilePath);
2687 return INIT_FAIL_REMOVE;
2690 m_TempFilePath = name;
2691 ext = wxFileName(name).GetExt();
2695 if (!m_bbase_file_attr_known) {
2696 if (!GetBaseFileAttr(m_TempFilePath))
2697 return INIT_FAIL_REMOVE;
2699 m_bbase_file_attr_known =
true;
2703 m_SENCFileName = buildSENCName(name);
2705 int build_ret_val = 1;
2707 bool bbuild_new_senc =
false;
2708 m_bneed_new_thumbnail =
false;
2710 wxFileName FileName000(m_TempFilePath);
2714 wxString msg(_T(
"S57chart::Checking SENC file: "));
2715 msg.Append(m_SENCFileName);
2719 int force_make_senc = 0;
2721 if (::wxFileExists(m_SENCFileName)) {
2724 if (senc.ingestHeader(m_SENCFileName)) {
2725 bbuild_new_senc =
true;
2726 wxLogMessage(_T(
" Rebuilding SENC due to ingestHeader failure."));
2728 int senc_file_version = senc.getSencReadVersion();
2730 int last_update = senc.getSENCReadLastUpdate();
2732 wxString str = senc.getSENCFileCreateDate();
2733 wxDateTime SENCCreateDate;
2734 SENCCreateDate.ParseFormat(str, _T(
"%Y%m%d"));
2736 if (SENCCreateDate.IsValid())
2737 SENCCreateDate.ResetTime();
2742 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2744 senc_base_edtn.ToLong(&isenc_edition);
2746 m_edtn000.ToLong(&ifile_edition);
2751 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2752 bbuild_new_senc =
true;
2753 wxLogMessage(_T(
" Rebuilding SENC due to SENC format update."));
2760 else if (ifile_edition > isenc_edition) {
2761 bbuild_new_senc =
true;
2762 wxLogMessage(_T(
" Rebuilding SENC due to cell edition update."));
2764 msg = _T(
" Last edition recorded in SENC: ");
2765 msg += senc_base_edtn;
2766 msg += _T(
" most recent edition cell file: ");
2771 int most_recent_update_file =
2772 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2774 if (ifile_edition == isenc_edition) {
2775 if (most_recent_update_file > last_update) {
2776 bbuild_new_senc =
true;
2778 _T(
" Rebuilding SENC due to incremental cell update."));
2781 _T(
" Last update recorded in SENC: %d most recent ")
2782 _T(
"update file: %d"),
2783 last_update, most_recent_update_file);
2791 wxDateTime OModTime000;
2792 FileName000.GetTimes(NULL, &OModTime000, NULL);
2793 OModTime000.ResetTime();
2794 if (SENCCreateDate.IsValid()) {
2795 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2797 _T(
" Rebuilding SENC due to Senc vs cell file time ")
2799 bbuild_new_senc =
true;
2802 bbuild_new_senc =
true;
2804 _T(
" Rebuilding SENC due to SENC create time invalid."));
2815 if (force_make_senc) bbuild_new_senc =
true;
2817 }
else if (!::wxFileExists(m_SENCFileName))
2819 wxLogMessage(_T(
" Rebuilding SENC due to missing SENC file."));
2820 bbuild_new_senc =
true;
2824 if (bbuild_new_senc) {
2825 m_bneed_new_thumbnail =
2827 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2829 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2830 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2831 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2837 InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2839 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2840 wxString msg(_T(
" Cannot load SENC file "));
2841 msg.Append(m_SENCFileName);
2844 return INIT_FAIL_RETRY;
2850 wxString SENCdir = g_SENCPrefix;
2851 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2852 SENCdir.Append(wxFileName::GetPathSeparator());
2854 wxFileName s57File(m_SENCFileName);
2855 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13), _T(
"BMP"));
2857 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2858 BuildThumbnail(ThumbFileName.GetFullPath());
2861 if (ThumbFileName.FileExists()) {
2863 #ifdef ocpnUSE_ocpnBitmap
2864 pBMP_NEW =
new ocpnBitmap;
2866 pBMP_NEW =
new wxBitmap;
2868 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2871 m_pDIBThumbDay = pBMP_NEW;
2879 m_global_color_scheme = cs;
2880 SetColorScheme(cs,
false);
2883 BuildDepthContourArray();
2885 CreateChartContext();
2886 PopulateObjectsWithContext();
2889 bReadyToRender =
true;
2894 void s57chart::ClearDepthContourArray(
void) {
2895 if (m_nvaldco_alloc) {
2896 free(m_pvaldco_array);
2898 m_nvaldco_alloc = 5;
2900 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2903 void s57chart::BuildDepthContourArray(
void) {
2906 if (0 == m_nvaldco_alloc) {
2907 m_nvaldco_alloc = 5;
2908 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2914 double prev_valdco = 0.0;
2916 for (
int i = 0; i < PRIO_NUM; ++i) {
2917 for (
int j = 0; j < LUPNAME_NUM; j++) {
2918 top = razRules[i][j];
2919 while (top != NULL) {
2920 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2921 double valdco = 0.0;
2922 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2923 if (valdco != prev_valdco) {
2924 prev_valdco = valdco;
2926 if (m_nvaldco > m_nvaldco_alloc) {
2927 void *tr = realloc((
void *)m_pvaldco_array,
2928 m_nvaldco_alloc * 2 *
sizeof(
double));
2929 m_pvaldco_array = (
double *)tr;
2930 m_nvaldco_alloc *= 2;
2932 m_pvaldco_array[m_nvaldco - 1] = valdco;
2936 ObjRazRules *nxx = top->next;
2941 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2945 void s57chart::SetSafetyContour(
void) {
2953 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2956 if (NULL != m_pvaldco_array) {
2957 for (i = 0; i < m_nvaldco; i++) {
2958 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2962 m_next_safe_cnt = m_pvaldco_array[i];
2964 m_next_safe_cnt = (double)1e6;
2966 m_next_safe_cnt = (double)1e6;
2971 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2972 m_next_safe_cnt = (
double)1e6;
2975 void s57chart::CreateChartContext(){
2977 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2980 void s57chart::PopulateObjectsWithContext(){
2982 m_this_chart_context->chart =
this;
2983 m_this_chart_context->chart_type = GetChartType();
2984 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2985 m_this_chart_context->chart_scale = GetNativeScale();
2986 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2987 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2988 m_this_chart_context->safety_contour = m_next_safe_cnt;
2989 m_this_chart_context->pt2GetAssociatedObjects = &s57chart::GetAssociatedObjects;
2994 for (
int i = 0; i < PRIO_NUM; ++i) {
2995 for (
int j = 0; j < LUPNAME_NUM; j++) {
2996 top = razRules[i][j];
2997 while (top != NULL) {
2998 S57Obj *obj = top->obj;
2999 obj->m_chart_context = m_this_chart_context;
3007 void s57chart::InvalidateCache() {
3012 bool s57chart::BuildThumbnail(
const wxString &bmpname) {
3015 wxFileName ThumbFileName(bmpname);
3018 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
3019 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
3020 wxLogMessage(_T(
" Cannot create BMP file directory for ") +
3021 ThumbFileName.GetFullPath());
3029 vp.clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
3030 vp.clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
3032 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
3033 (m_FullExtent.ELON - m_FullExtent.WLON));
3035 vp.view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
3037 vp.pix_height = S57_THUMB_SIZE;
3038 vp.pix_width = S57_THUMB_SIZE;
3040 vp.m_projection_type = PROJECTION_MERCATOR;
3042 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3045 vp.chart_scale = 10000000 - 1;
3046 vp.ref_scale = vp.chart_scale;
3059 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3061 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3063 int *psvr = psave_viz;
3067 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3068 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3069 *psvr++ = pOLE->nViz;
3074 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3075 bool bsave_text = ps52plib->m_bShowS57Text;
3078 ps52plib->SaveObjNoshow();
3081 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3082 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3083 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3084 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3087 ps52plib->m_bShowSoundg =
false;
3088 ps52plib->m_bShowS57Text =
false;
3091 DisCat dsave = ps52plib->GetDisplayCategory();
3092 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3094 ps52plib->AddObjNoshow(
"BRIDGE");
3095 ps52plib->AddObjNoshow(
"GATCON");
3097 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3098 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3099 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3100 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3102 #ifdef ocpnUSE_DIBSECTION
3105 wxMemoryDC memdc, dc_org;
3109 ps52plib->SaveColorScheme();
3110 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3112 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3115 memdc.SelectObject(wxNullBitmap);
3119 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3120 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3121 pOLE->nViz = *psvr++;
3124 ps52plib->SetDisplayCategory(dsave);
3125 ps52plib->RestoreObjNoshow();
3127 ps52plib->RemoveObjNoshow(
"BRIDGE");
3128 ps52plib->RemoveObjNoshow(
"GATCON");
3130 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3131 ps52plib->m_bShowS57Text = bsave_text;
3133 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3134 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3137 ps52plib->RestoreColorScheme();
3145 pBMP =
new wxBitmap(vp.pix_width, vp.pix_height );
3147 wxMemoryDC dc_clone;
3148 dc_clone.SelectObject(*pBMP);
3150 pDIB->SelectIntoDC(dc_org);
3152 dc_clone.Blit(0, 0, vp.pix_width, vp.pix_height, (wxDC *)&dc_org, 0, 0);
3154 dc_clone.SelectObject(wxNullBitmap);
3155 dc_org.SelectObject(wxNullBitmap);
3158 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3165 #include <wx/arrimpl.cpp>
3166 WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3169 bool s57chart::CreateHeaderDataFromENC(
void) {
3170 if (!InitENCMinimal(m_TempFilePath)) {
3171 wxString msg(_T(
" Cannot initialize ENC file "));
3172 msg.Append(m_TempFilePath);
3180 float LatMax, LatMin, LonMax, LonMin;
3186 m_pCOVRTablePoints = NULL;
3187 m_pCOVRTable = NULL;
3190 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3191 std::vector<int> auxCntArray, noCovrCntArray;
3193 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3196 pFeat = GetChartFirstM_COVR(catcov);
3201 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3202 OGRLinearRing *xring = poly->getExteriorRing();
3204 int npt = xring->getNumPoints();
3215 for (
int i = 0; i < npt; i++) {
3216 xring->getPoint(i, &p);
3220 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3222 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3223 if (xdelta < 0.001 &&
3231 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3232 pfr = &pf[2 * (usedpts - 1)];
3235 LatMax = fmax(LatMax, p.getY());
3236 LatMin = fmin(LatMin, p.getY());
3237 LonMax = fmax(LonMax, p.getX());
3238 LonMin = fmin(LonMin, p.getX());
3246 pAuxPtrArray->Add(pf);
3247 auxCntArray.push_back(usedpts);
3248 }
else if (catcov == 2) {
3249 pNoCovrPtrArray->Add(pf);
3250 noCovrCntArray.push_back(usedpts);
3255 pFeat = GetChartNextM_COVR(catcov);
3256 DEBUG_LOG <<
"used " << usedpts <<
" points";
3261 m_nCOVREntries = auxCntArray.size();
3265 if (m_nCOVREntries >= 1) {
3266 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3267 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3269 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3270 m_pCOVRTablePoints[j] = auxCntArray[j];
3271 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3277 wxString msg(_T(
" ENC contains no useable M_COVR, CATCOV=1 features: "));
3278 msg.Append(m_TempFilePath);
3283 m_nNoCOVREntries = noCovrCntArray.size();
3285 if (m_nNoCOVREntries) {
3287 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3288 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3290 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3291 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3292 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3295 m_pNoCOVRTablePoints = NULL;
3296 m_pNoCOVRTable = NULL;
3299 delete pAuxPtrArray;
3300 delete pNoCovrPtrArray;
3302 if (0 == m_nCOVREntries) {
3303 wxString msg(_T(
" ENC contains no M_COVR features: "));
3304 msg.Append(m_TempFilePath);
3307 msg = _T(
" Calculating Chart Extents as fallback.");
3313 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3315 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3322 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3323 *m_pCOVRTablePoints = 4;
3324 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3325 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3342 wxString msg(_T(
" Cannot calculate Extents for ENC: "));
3343 msg.Append(m_TempFilePath);
3351 m_FullExtent.NLAT = LatMax;
3352 m_FullExtent.SLAT = LatMin;
3353 m_FullExtent.ELON = LonMax;
3354 m_FullExtent.WLON = LonMin;
3355 m_bExtentSet =
true;
3358 m_Chart_Scale = GetENCScale();
3361 GetChartNameFromTXT(m_TempFilePath, nice_name);
3369 bool s57chart::CreateHeaderDataFromoSENC(
void) {
3370 bool ret_val =
true;
3372 wxFFileInputStream fpx(m_SENCFileName);
3374 if (!::wxFileExists(m_SENCFileName)) {
3375 wxString msg(_T(
" Cannot open SENC file "));
3376 msg.Append(m_SENCFileName);
3383 if (senc.ingestHeader(m_SENCFileName)) {
3389 m_Chart_Scale = senc.getSENCReadScale();
3392 m_Name = senc.getReadName();
3395 m_ID = senc.getReadID();
3398 Extent &ext = senc.getReadExtent();
3400 m_FullExtent.ELON = ext.ELON;
3401 m_FullExtent.WLON = ext.WLON;
3402 m_FullExtent.NLAT = ext.NLAT;
3403 m_FullExtent.SLAT = ext.SLAT;
3404 m_bExtentSet =
true;
3407 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3408 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3410 m_nCOVREntries = AuxCntArray.size();
3412 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3413 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3415 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3416 m_pCOVRTablePoints[j] = AuxCntArray[j];
3417 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3418 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3419 AuxCntArray[j] * 2 *
sizeof(
float));
3423 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3424 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3426 m_nNoCOVREntries = NoCovrCntArray.size();
3428 if (m_nNoCOVREntries) {
3430 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3431 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3433 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3434 int npoints = NoCovrCntArray[j];
3435 m_pNoCOVRTablePoints[j] = npoints;
3436 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3437 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3438 npoints * 2 *
sizeof(
float));
3444 m_datum_str = _T(
"WGS84");
3445 m_SoundingsDatum = _T(
"MEAN LOWER LOW WATER");
3447 int senc_file_version = senc.getSencReadVersion();
3449 int last_update = senc.getSENCReadLastUpdate();
3451 wxString str = senc.getSENCFileCreateDate();
3452 wxDateTime SENCCreateDate;
3453 SENCCreateDate.ParseFormat(str, _T(
"%Y%m%d"));
3455 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3457 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3464 bool s57chart::CreateHeaderDataFromSENC(
void) {
3465 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3473 bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3475 if (NULL != m_pvaldco_array) {
3476 for (i = 0; i < m_nvaldco; i++) {
3477 if (m_pvaldco_array[i] >= safe_cnt)
break;
3481 next_safe_cnt = m_pvaldco_array[i];
3483 next_safe_cnt = (double)1e6;
3486 next_safe_cnt = (double)1e6;
3500 std::list<S57Obj*> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3504 std::list<S57Obj*> *pobj_list =
new std::list<S57Obj*>();
3507 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3508 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3511 switch (obj->Primitive_type) {
3524 top = razRules[disPrioIdx][3];
3525 while (top != NULL) {
3526 if (top->obj->bIsAssociable) {
3527 if (top->obj->BBObj.Contains(lat, lon)) {
3528 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3529 pobj_list->push_back(top->obj);
3536 ObjRazRules *nxx = top->next;
3541 top = razRules[disPrioIdx][4];
3542 while (top != NULL) {
3543 if (top->obj->bIsAssociable) {
3544 if (top->obj->BBObj.Contains(lat, lon)) {
3545 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3546 pobj_list->push_back(top->obj);
3552 ObjRazRules *nxx = top->next;
3566 void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3567 wxFileName fn(FullPath);
3569 wxString target_name = fn.GetName();
3570 target_name.RemoveLast();
3572 wxString dir_name = fn.GetPath();
3574 wxDir dir(dir_name);
3576 wxArrayString FileList;
3578 dir.GetAllFiles(fn.GetPath(), &FileList);
3582 bool found_name =
false;
3586 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3587 wxFileName file(FileList[j]);
3588 if (((file.GetExt()).MakeUpper()) == _T(
"TXT")) {
3590 wxTextFile text_file(file.GetFullPath());
3592 bool file_ok =
true;
3596 if (!text_file.Open()) {
3597 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3602 wxString str = text_file.GetFirstLine();
3603 while (!text_file.Eof()) {
3604 if (0 == target_name.CmpNoCase(
3605 str.Mid(0, target_name.Len()))) {
3606 wxString tname = str.AfterFirst(
'-');
3607 name = tname.AfterFirst(
' ');
3611 str = text_file.GetNextLine();
3615 wxString msg(_T(
" Error Reading ENC .TXT file: "));
3616 msg.Append(file.GetFullPath());
3622 if (found_name)
break;
3639 const char *s57chart::getName(OGRFeature *feature) {
3640 return feature->GetDefnRef()->GetName();
3643 static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3644 wxFileName fn1(first);
3645 wxFileName fn2(second);
3646 wxString ext1(fn1.GetExt());
3647 wxString ext2(fn2.GetExt());
3649 return ext1.Cmp(ext2);
3652 int s57chart::GetUpdateFileArray(
const wxFileName file000,
3653 wxArrayString *UpFiles, wxDateTime date000,
3655 wxString DirName000 =
3656 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3657 wxDir dir(DirName000);
3658 if (!dir.IsOpened()) {
3659 DirName000.Prepend(wxFileName::GetPathSeparator());
3660 DirName000.Prepend(_T(
"."));
3661 dir.Open(DirName000);
3662 if (!dir.IsOpened()) {
3667 int flags = wxDIR_DEFAULT;
3674 wxFileName fnDir(DirName000);
3675 fnDir.RemoveLastDir();
3676 wxString sdir = fnDir.GetPath();
3677 wxFileName fnTest(sdir);
3678 wxString sname = fnTest.GetName();
3680 if (sname.ToLong(&tmps)) {
3683 flags |= wxDIR_DIRS;
3687 wxArrayString *dummy_array;
3690 if (UpFiles == NULL)
3691 dummy_array =
new wxArrayString;
3693 dummy_array = UpFiles;
3695 wxArrayString possibleFiles;
3696 wxDir::GetAllFiles(DirName000, &possibleFiles, wxEmptyString, flags);
3698 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3699 wxString filename(possibleFiles[i]);
3701 wxFileName file(filename);
3702 ext = file.GetExt();
3707 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3708 wxString FileToAdd = filename;
3710 wxCharBuffer buffer =
3713 if (buffer.data() && !filename.IsSameAs(_T(
"CATALOG.031"),
3725 DDFModule *poModule =
new DDFModule();
3726 if (!poModule->Open(FileToAdd.mb_str())) {
3728 _T(
" s57chart::BuildS57File Unable to open update file "));
3729 msg.Append(FileToAdd);
3738 DDFRecord *pr = poModule->ReadRecord();
3744 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3747 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3751 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3752 _T(
"DSID:ISDT in update file "));
3753 msg.Append(FileToAdd);
3756 sumdate = _T(
"20000101");
3759 umdate.ParseFormat(sumdate, _T(
"%Y%m%d"));
3760 if (!umdate.IsValid())
3761 umdate.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
3764 if (!umdate.IsValid())
3770 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3772 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3776 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3777 _T(
"DSID:EDTN in update file "));
3778 msg.Append(FileToAdd);
3787 if ((!umdate.IsEarlierThan(date000)) &&
3788 (umedtn.IsSameAs(edtn000)))
3789 dummy_array->Add(FileToAdd);
3795 dummy_array->Sort(ExtensionCompare);
3798 if (dummy_array->GetCount()) {
3799 wxString Last = dummy_array->Last();
3800 wxFileName fnl(Last);
3802 wxCharBuffer buffer = ext.ToUTF8();
3803 if (buffer.data()) retval = atoi(buffer.data());
3806 if (UpFiles == NULL)
delete dummy_array;
3811 int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3812 const wxString CopyDir,
3813 wxString &LastUpdateDate,
3819 wxArrayString *UpFiles =
new wxArrayString;
3820 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3822 if (UpFiles->GetCount()) {
3836 bool chain_broken_mssage_shown =
false;
3842 for (
int iff = 0; iff < retval + 1; iff++) {
3843 wxFileName ufile(m_TempFilePath);
3845 sext.Printf(_T(
"%03d"), iff);
3849 wxString cp_ufile = CopyDir;
3850 if (cp_ufile.Last() != ufile.GetPathSeparator())
3851 cp_ufile.Append(ufile.GetPathSeparator());
3853 cp_ufile.Append(ufile.GetFullName());
3858 if (ufile.FileExists()) {
3859 wxFile uf(ufile.GetFullPath());
3860 if (uf.IsOpened()) {
3866 if (ufile.FileExists() &&
3870 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3872 wxString msg(_T(
" Cannot copy temporary working ENC file "));
3873 msg.Append(ufile.GetFullPath());
3874 msg.Append(_T(
" to "));
3875 msg.Append(cp_ufile);
3885 if (!chain_broken_mssage_shown) {
3888 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3889 "incomplete or inaccurate.\nCheck the logfile for details."),
3890 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3892 chain_broken_mssage_shown =
true;
3896 _T(
"WARNING---ENC Update chain incomplete. Substituting NULL ")
3897 _T(
"update file: "));
3898 msg += ufile.GetFullName();
3900 wxLogMessage(_T(
" Subsequent ENC updates may produce errors."));
3902 _T(
" This ENC exchange set should be updated and SENCs ")
3906 DDFModule *dupdate =
new DDFModule;
3907 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3908 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3912 wxString msg(_T(
" Error creating dummy update file: "));
3913 msg.Append(cp_ufile);
3918 m_tmpup_array->Add(cp_ufile);
3925 wxFileName lastfile(m_TempFilePath);
3927 last_sext.Printf(_T(
"%03d"), retval);
3928 lastfile.SetExt(last_sext);
3931 DDFModule oUpdateModule;
3936 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3940 oUpdateModule.Rewind();
3941 DDFRecord *pr = oUpdateModule.ReadRecord();
3947 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3951 LastUpdateDate = wxString(u, wxConvUTF8);
3954 wxDateTime now = wxDateTime::Now();
3955 LastUpdateDate = now.Format(_T(
"%Y%m%d"));
3964 wxString s57chart::GetISDT(
void) {
3965 if (m_date000.IsValid())
3966 return m_date000.Format(_T(
"%Y%m%d"));
3968 return _T(
"Unknown");
3971 bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3972 if (!wxFileName::FileExists(file000))
return false;
3974 wxString FullPath000 = file000;
3975 DDFModule *poModule =
new DDFModule();
3976 if (!poModule->Open(FullPath000.mb_str())) {
3977 wxString msg(_T(
" s57chart::BuildS57File Unable to open "));
3978 msg.Append(FullPath000);
3990 DDFRecord *pr = poModule->ReadRecord();
3994 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3995 if (!m_nGeoRecords) {
3997 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
4007 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
4009 date000 = wxString(u, wxConvUTF8);
4012 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
4019 m_date000.ParseFormat(date000, _T(
"%Y%m%d"));
4020 if (!m_date000.IsValid()) m_date000.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4022 m_date000.ResetTime();
4025 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
4027 m_edtn000 = wxString(u, wxConvUTF8);
4030 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
4034 m_edtn000 = _T(
"1");
4041 for (; pr != NULL; pr = poModule->ReadRecord()) {
4042 if (pr->FindField(
"DSPM") != NULL) {
4043 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4047 if (!m_native_scale) {
4048 wxString msg(_T(
" s57chart::BuildS57File ENC not contain DSPM:CSCL "));
4051 m_native_scale = 1000;
4059 int s57chart::BuildSENCFile(
const wxString &FullPath000,
4060 const wxString &SENCFileName,
bool b_progress) {
4062 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4063 double meters_per_pixel_max_scale =
4064 GetNormalScaleMin(0, g_b_overzoom_x) / display_pix_per_meter;
4065 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4068 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4069 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4071 if (!m_disableBackgroundSENC) {
4072 if (g_SencThreadManager) {
4074 ticket->m_LOD_meters = m_LOD_meters;
4075 ticket->ref_lat = ref_lat;
4076 ticket->ref_lon = ref_lon;
4077 ticket->m_FullPath000 = FullPath000;
4078 ticket->m_SENCFileName = SENCFileName;
4079 ticket->m_chart =
this;
4081 m_SENCthreadStatus = g_SencThreadManager->ScheduleJob(ticket);
4082 bReadyToRender =
true;
4083 return BUILD_SENC_PENDING;
4086 return BUILD_SENC_NOK_RETRY;
4091 senc.setRegistrar(g_poRegistrar);
4092 senc.setRefLocn(ref_lat, ref_lon);
4093 senc.SetLODMeters(m_LOD_meters);
4095 AbstractPlatform::ShowBusySpinner();
4097 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4099 AbstractPlatform::HideBusySpinner();
4101 if (ret == ERROR_INGESTING000)
4102 return BUILD_SENC_NOK_PERMANENT;
4108 int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4115 S57ObjVector Objects;
4116 VE_ElementVector VEs;
4117 VC_ElementVector VCs;
4119 sencfile.setRefLocn(ref_lat, ref_lon);
4121 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4123 if (srv != SENC_NO_ERROR) {
4124 wxLogMessage(sencfile.getLastError());
4130 Extent ext = sencfile.getReadExtent();
4132 m_FullExtent.ELON = ext.ELON;
4133 m_FullExtent.WLON = ext.WLON;
4134 m_FullExtent.NLAT = ext.NLAT;
4135 m_FullExtent.SLAT = ext.SLAT;
4136 m_bExtentSet =
true;
4138 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4139 ref_lon = (ext.ELON + ext.WLON) / 2.;
4144 int n_ve_elements = VEs.size();
4146 double scale = gFrame->GetBestVPScale(
this);
4147 int nativescale = GetNativeScale();
4149 for (
int i = 0; i < n_ve_elements; i++) {
4150 VE_Element *vep = VEs.at(i);
4151 if (vep && vep->nCount) {
4153 double east_max = -1e7;
4154 double east_min = 1e7;
4155 double north_max = -1e7;
4156 double north_min = 1e7;
4158 float *vrun = vep->pPoints;
4159 for (
size_t i = 0; i < vep->nCount; i++) {
4160 east_max = wxMax(east_max, *vrun);
4161 east_min = wxMin(east_min, *vrun);
4164 north_max = wxMax(north_max, *vrun);
4165 north_min = wxMin(north_min, *vrun);
4169 double lat1, lon1, lat2, lon2;
4170 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4171 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4172 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4175 m_ve_hash[vep->index] = vep;
4179 int n_vc_elements = VCs.size();
4181 for (
int i = 0; i < n_vc_elements; i++) {
4182 VC_Element *vcp = VCs.at(i);
4183 m_vc_hash[vcp->index] = vcp;
4191 for (
unsigned int i = 0; i < Objects.size(); i++) {
4192 S57Obj *obj = Objects[i];
4196 LUPname LUP_Name = PAPER_CHART;
4198 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4199 if (objnam.Len() > 0) {
4200 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4201 g_pi_manager->SendVectorChartObjectInfo(FullPath, fe_name, objnam,
4202 obj->m_lat, obj->m_lon,
scale,
4207 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4208 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4209 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4210 g_pi_manager->SendVectorChartObjectInfo(FullPath, fe_name, nobjnam,
4211 obj->m_lat, obj->m_lon,
scale,
4215 switch (obj->Primitive_type) {
4220 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4221 LUP_Name = PAPER_CHART;
4223 LUP_Name = SIMPLIFIED;
4232 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4233 LUP_Name = PLAIN_BOUNDARIES;
4235 LUP_Name = SYMBOLIZED_BOUNDARIES;
4240 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4244 wxString msg(obj->FeatureName, wxConvUTF8);
4245 msg.Prepend(_T(
" Could not find LUP for "));
4246 LogMessageOnce(msg);
4253 ps52plib->_LUP2rules(LUP, obj);
4256 _insertRules(obj, LUP,
this);
4259 obj->m_DisplayCat = LUP->DISC;
4262 obj->m_DPRI = LUP->DPRI -
'0';
4265 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4266 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4267 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4268 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4269 obj->m_bcategory_mutable =
true;
4271 obj->m_bcategory_mutable =
false;
4276 if (obj && (GEO_POINT == obj->Primitive_type)) {
4278 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4279 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4280 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4281 pFloatingATONArray->Add(obj);
4285 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4286 pRigidATONArray->Add(obj);
4290 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4291 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4292 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4293 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4294 obj->bIsAton =
true;
4303 d000.ParseFormat(sencfile.getBaseDate(), _T(
"%Y%m%d"));
4304 if (!d000.IsValid()) d000.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4307 updt.ParseFormat(sencfile.getUpdateDate(), _T(
"%Y%m%d"));
4308 if (!updt.IsValid()) updt.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4310 if (updt.IsLaterThan(d000))
4311 m_PubYear.Printf(_T(
"%4d"), updt.GetYear());
4313 m_PubYear.Printf(_T(
"%4d"), d000.GetYear());
4316 wxDateTime upd = updt;
4317 if (!upd.IsValid()) upd.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4322 m_SE = sencfile.getSENCReadBaseEdition();
4325 supdate.Printf(_T(
" / %d"), sencfile.getSENCReadLastUpdate());
4328 m_datum_str = _T(
"WGS84");
4330 m_SoundingsDatum = _T(
"MEAN LOWER LOW WATER");
4331 m_ID = sencfile.getReadID();
4332 m_Name = sencfile.getReadName();
4336 AssembleLineGeometry();
4341 int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4342 ObjRazRules *rzRules = NULL;
4352 switch (LUP->DPRI) {
4365 case PRIO_SYMB_POINT:
4368 case PRIO_SYMB_LINE:
4371 case PRIO_SYMB_AREA:
4384 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4388 switch (LUP->TNAM) {
4398 case PLAIN_BOUNDARIES:
4401 case SYMBOLIZED_BOUNDARIES:
4405 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4409 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4413 rzRules->child = NULL;
4414 rzRules->mps = NULL;
4417 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4418 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4423 ObjRazRules *rNext = NULL;
4424 ObjRazRules *rPrevious = NULL;
4425 if (razRules[disPrioIdx][LUPtypeIdx]) {
4426 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4427 rNext = rPrevious->next;
4431 rNext = rPrevious->next;
4434 rzRules->next = NULL;
4436 rPrevious->next = rzRules;
4438 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4445 void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4450 if (vp_last.view_scale_ppm == 1.0)
4453 double d = vp_last.view_scale_ppm / vp_this.view_scale_ppm;
4455 for (
int i = 0; i < PRIO_NUM; ++i) {
4456 for (
int j = 0; j < 2; ++j) {
4457 top = razRules[i][j];
4459 while (top != NULL) {
4460 if (!top->obj->geoPtMulti)
4462 if (top->obj->BBObj.GetValid()) {
4463 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4465 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4466 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4468 double minlon = top->obj->BBObj.GetMinLon();
4469 double maxlon = top->obj->BBObj.GetMaxLon();
4471 double lon1 = (lon - minlon) * d;
4472 double lon2 = (lon - maxlon) * d;
4474 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4477 top->obj->BBObj.Invalidate();
4498 void s57chart::UpdateLUPs(
s57chart *pOwner) {
4502 for (
int i = 0; i < PRIO_NUM; ++i) {
4504 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4505 m_b2pointLUPS =
true;
4506 top = razRules[i][0];
4508 while (top != NULL) {
4509 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4515 if (top->obj->nRef < 2) {
4516 ps52plib->_LUP2rules(LUP, top->obj);
4517 _insertRules(top->obj, LUP, pOwner);
4518 top->obj->m_DisplayCat = LUP->DISC;
4528 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4529 m_b2pointLUPS =
true;
4530 top = razRules[i][1];
4532 while (top != NULL) {
4533 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4536 if (top->obj->nRef < 2) {
4537 ps52plib->_LUP2rules(LUP, top->obj);
4538 _insertRules(top->obj, LUP, pOwner);
4539 top->obj->m_DisplayCat = LUP->DISC;
4549 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4550 m_b2lineLUPS =
true;
4551 top = razRules[i][3];
4553 while (top != NULL) {
4554 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4555 top->obj->FeatureName, top->obj);
4557 ps52plib->_LUP2rules(LUP, top->obj);
4558 _insertRules(top->obj, LUP, pOwner);
4559 top->obj->m_DisplayCat = LUP->DISC;
4568 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4569 m_b2lineLUPS =
true;
4570 top = razRules[i][4];
4572 while (top != NULL) {
4573 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4576 ps52plib->_LUP2rules(LUP, top->obj);
4577 _insertRules(top->obj, LUP, pOwner);
4578 top->obj->m_DisplayCat = LUP->DISC;
4590 for (
int j = 0; j < LUPNAME_NUM; j++) {
4591 top = razRules[i][j];
4592 while (top != NULL) {
4593 top->obj->bCS_Added = 0;
4596 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4607 for (
int j = 0; j < LUPNAME_NUM; j++) {
4608 top = razRules[i][j];
4609 while (top != NULL) {
4611 ObjRazRules *ctop = top->child;
4612 while (NULL != ctop) {
4613 ctop->obj->bCS_Added = 0;
4614 free_mps(ctop->mps);
4617 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4634 ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4635 float lat,
float lon,
ViewPort *VPoint) {
4636 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4637 std::vector<ObjRazRules *> selected_rules;
4642 char *curr_att = NULL;
4644 wxArrayOfS57attVal *attValArray = NULL;
4645 bool bleading_attribute =
false;
4647 for (
int i = 0; i < PRIO_NUM; ++i) {
4651 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4652 top = razRules[i][point_type];
4654 while (top != NULL) {
4655 if (top->obj->npt == 1) {
4656 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4658 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4660 if (ps52plib->ObjectRenderCheckCat(top)) {
4663 wxString curAttrName;
4664 curr_att = top->obj->att_array;
4665 n_attr = top->obj->n_attr;
4666 attValArray = top->obj->attVal;
4674 bleading_attribute =
false;
4676 while (attrCounter < n_attr) {
4677 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4680 S57attVal *pAttrVal = NULL;
4683 pAttrVal = attValArray->Item(attrCounter);
4687 wxString value = s57chart::GetAttributeValueAsString(
4688 pAttrVal, curAttrName);
4690 if (curAttrName == _T(
"LITVIS")) {
4691 if (value.StartsWith(_T(
"obsc"))) bviz =
false;
4692 }
else if (curAttrName == _T(
"VALNMR"))
4693 value.ToDouble(&valnmr);
4699 if (bviz && (valnmr > 0.1)) {
4703 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4704 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4705 ref_lat, ref_lon, &olat, &olon);
4707 double dlat = lat - olat;
4708 double dy = dlat * 60 / cos(olat * PI / 180.);
4709 double dlon = lon - olon;
4710 double dx = dlon * 60;
4711 double manhat = abs(dy) + abs(dx);
4715 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4717 selected_rules.push_back(top);
4733 for(std::size_t i = 0; i < selected_rules.size(); ++i) {
4734 ret_ptr->Append(selected_rules[i]);
4740 ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4741 float select_radius,
4743 int selection_mask) {
4745 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4746 std::vector<ObjRazRules *> selected_rules;
4748 PrepareForRender(VPoint, ps52plib);
4754 for (
int i = 0; i < PRIO_NUM; ++i) {
4755 if (selection_mask & MASK_POINT) {
4758 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4759 top = razRules[i][point_type];
4761 while (top != NULL) {
4762 if (top->obj->npt ==
4765 if (ps52plib->ObjectRenderCheck(top)) {
4766 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4767 selected_rules.push_back(top);
4776 ObjRazRules *child_item = top->child;
4777 while (child_item != NULL) {
4778 if (ps52plib->ObjectRenderCheck(child_item)) {
4779 if (DoesLatLonSelectObject(lat, lon, select_radius,
4781 selected_rules.push_back(child_item);
4784 child_item = child_item->next;
4792 if (selection_mask & MASK_AREA) {
4795 int area_boundary_type =
4796 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4797 top = razRules[i][area_boundary_type];
4798 while (top != NULL) {
4799 if (ps52plib->ObjectRenderCheck(top)) {
4800 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4801 selected_rules.push_back(top);
4808 if (selection_mask & MASK_LINE) {
4810 top = razRules[i][2];
4812 while (top != NULL) {
4813 if (ps52plib->ObjectRenderCheck(top)) {
4814 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4815 selected_rules.push_back(top);
4826 auto sortObjs = [lat, lon,
this] (
const ObjRazRules* obj1,
const ObjRazRules* obj2) ->
bool
4828 double br1, dd1, br2, dd2;
4830 if(obj1->obj->Primitive_type == GEO_POINT && obj2->obj->Primitive_type == GEO_POINT){
4831 double lat1, lat2, lon1, lon2;
4832 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4833 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin,
4834 ref_lat, ref_lon, &lat1, &lon1);
4836 if (lon1 > 180.0) lon1 -= 360.;
4838 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4839 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin,
4840 ref_lat, ref_lon, &lat2, &lon2);
4842 if (lon2 > 180.0) lon2 -= 360.;
4844 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4845 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4853 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4856 for(std::size_t i = 0; i < selected_rules.size(); ++i) {
4857 ret_ptr->Append(selected_rules[i]);
4863 bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4865 switch (obj->Primitive_type) {
4869 if (!obj->BBObj.GetValid())
return false;
4871 if (1 == obj->npt) {
4876 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4878 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4881 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4882 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4889 sbox.Set(olat, olon, olat, olon);
4891 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4892 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4897 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4904 if (!obj->BBObj.GetValid())
return false;
4907 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4909 double *pdl = obj->geoPtMulti;
4910 for (
int ip = 0; ip < obj->npt; ip++) {
4911 double lon_point = *pdl++;
4912 double lat_point = *pdl++;
4914 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4915 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4926 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4929 return IsPointInObjArea(lat, lon, select_radius, obj);
4934 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4936 float sel_rad_meters = select_radius * 1852 * 60;
4937 double easting, northing;
4938 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4945 pt *ppt = obj->geoPt;
4948 double xr = obj->x_rate;
4949 double xo = obj->x_origin;
4950 double yr = obj->y_rate;
4951 double yo = obj->y_origin;
4953 double north0 = (ppt->y * yr) + yo;
4954 double east0 = (ppt->x * xr) + xo;
4957 for (
int ip = 1; ip < npt; ip++) {
4958 double north = (ppt->y * yr) + yo;
4959 double east = (ppt->x * xr) + xo;
4962 if (northing >= (fmin(north, north0) - sel_rad_meters))
4963 if (northing <= (fmax(north, north0) + sel_rad_meters))
4964 if (easting >= (fmin(east, east0) - sel_rad_meters))
4965 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4975 if (obj->m_ls_list) {
4977 unsigned char *vbo_point =
4979 obj->m_chart_context->vertex_buffer;
4980 line_segment_element *ls = obj->m_ls_list;
4982 while (ls && vbo_point) {
4984 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4985 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4986 nPoints = ls->pedge->nCount;
4988 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4992 float north0 = ppt[1];
4993 float east0 = ppt[0];
4997 for (
int ip = 0; ip < nPoints - 1; ip++) {
4998 float north = ppt[1];
4999 float east = ppt[0];
5001 if (northing >= (fmin(north, north0) - sel_rad_meters))
5002 if (northing <= (fmax(north, north0) + sel_rad_meters))
5003 if (easting >= (fmin(east, east0) - sel_rad_meters))
5004 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
5031 wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
5032 wxString ret_val = _T(
"");
5035 const char *att_code;
5037 wxString file(g_csv_locn);
5038 file.Append(_T(
"/s57attributes.csv"));
5040 if (!wxFileName::FileExists(file)) {
5041 wxString msg(_T(
" Could not open "));
5048 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5050 CC_ExactString,
"Code");
5056 wxString ei_file(g_csv_locn);
5057 ei_file.Append(_T(
"/s57expectedinput.csv"));
5059 if (!wxFileName::FileExists(ei_file)) {
5060 wxString msg(_T(
" Could not open "));
5061 msg.Append(ei_file);
5067 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5068 CSVIngest(ei_file.mb_str());
5070 char **papszFields = NULL;
5071 int bSelected = FALSE;
5077 while (!bSelected && iline + 1 < psTable->nLineCount) {
5079 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5081 if (!strcmp(papszFields[0], att_code)) {
5082 if (atoi(papszFields[1]) == ival) {
5083 ret_val = wxString(papszFields[2], wxConvUTF8);
5088 CSLDestroy(papszFields);
5096 bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5100 if (obj->pPolyTessGeo) {
5101 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5103 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5105 TriPrim *pTP = ppg->tri_prim_head;
5107 MyPoint pvert_list[3];
5111 double easting, northing;
5112 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5116 if (!ppg->m_bSMSENC) {
5117 double y_rate = obj->y_rate;
5118 double y_origin = obj->y_origin;
5119 double x_rate = obj->x_rate;
5120 double x_origin = obj->x_origin;
5122 double northing_scaled = (northing - y_origin) / y_rate;
5123 double easting_scaled = (easting - x_origin) / x_rate;
5124 northing = northing_scaled;
5125 easting = easting_scaled;
5130 if (pTP->tri_box.Contains(lat, lon)) {
5131 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5132 double *p_vertex = pTP->p_vertex;
5134 switch (pTP->type) {
5135 case PTG_TRIANGLE_FAN: {
5136 for (
int it = 0; it < pTP->nVert - 2; it++) {
5137 pvert_list[0].x = p_vertex[0];
5138 pvert_list[0].y = p_vertex[1];
5140 pvert_list[1].x = p_vertex[(it * 2) + 2];
5141 pvert_list[1].y = p_vertex[(it * 2) + 3];
5143 pvert_list[2].x = p_vertex[(it * 2) + 4];
5144 pvert_list[2].y = p_vertex[(it * 2) + 5];
5146 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5154 case PTG_TRIANGLE_STRIP: {
5155 for (
int it = 0; it < pTP->nVert - 2; it++) {
5156 pvert_list[0].x = p_vertex[(it * 2)];
5157 pvert_list[0].y = p_vertex[(it * 2) + 1];
5159 pvert_list[1].x = p_vertex[(it * 2) + 2];
5160 pvert_list[1].y = p_vertex[(it * 2) + 3];
5162 pvert_list[2].x = p_vertex[(it * 2) + 4];
5163 pvert_list[2].y = p_vertex[(it * 2) + 5];
5165 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5173 case PTG_TRIANGLES: {
5174 for (
int it = 0; it < pTP->nVert; it += 3) {
5175 pvert_list[0].x = p_vertex[(it * 2)];
5176 pvert_list[0].y = p_vertex[(it * 2) + 1];
5178 pvert_list[1].x = p_vertex[(it * 2) + 2];
5179 pvert_list[1].y = p_vertex[(it * 2) + 3];
5181 pvert_list[2].x = p_vertex[(it * 2) + 4];
5182 pvert_list[2].y = p_vertex[(it * 2) + 5];
5184 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5193 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5194 float *p_vertex = (
float *)pTP->p_vertex;
5196 switch (pTP->type) {
5197 case PTG_TRIANGLE_FAN: {
5198 for (
int it = 0; it < pTP->nVert - 2; it++) {
5199 pvert_list[0].x = p_vertex[0];
5200 pvert_list[0].y = p_vertex[1];
5202 pvert_list[1].x = p_vertex[(it * 2) + 2];
5203 pvert_list[1].y = p_vertex[(it * 2) + 3];
5205 pvert_list[2].x = p_vertex[(it * 2) + 4];
5206 pvert_list[2].y = p_vertex[(it * 2) + 5];
5208 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5216 case PTG_TRIANGLE_STRIP: {
5217 for (
int it = 0; it < pTP->nVert - 2; it++) {
5218 pvert_list[0].x = p_vertex[(it * 2)];
5219 pvert_list[0].y = p_vertex[(it * 2) + 1];
5221 pvert_list[1].x = p_vertex[(it * 2) + 2];
5222 pvert_list[1].y = p_vertex[(it * 2) + 3];
5224 pvert_list[2].x = p_vertex[(it * 2) + 4];
5225 pvert_list[2].y = p_vertex[(it * 2) + 5];
5227 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5235 case PTG_TRIANGLES: {
5236 for (
int it = 0; it < pTP->nVert; it += 3) {
5237 pvert_list[0].x = p_vertex[(it * 2)];
5238 pvert_list[0].y = p_vertex[(it * 2) + 1];
5240 pvert_list[1].x = p_vertex[(it * 2) + 2];
5241 pvert_list[1].y = p_vertex[(it * 2) + 3];
5243 pvert_list[2].x = p_vertex[(it * 2) + 4];
5244 pvert_list[2].y = p_vertex[(it * 2) + 5];
5246 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5269 wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5270 wxString curAttrName) {
5274 pval = obj->attVal->Item(iatt);
5275 switch (pval->valType) {
5278 wxString val_str((
char *)(pval->value), wxConvUTF8);
5280 if (val_str.ToLong(&ival)) {
5282 value = _T(
"Unknown");
5284 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5285 if (!decode_val.IsEmpty()) {
5288 iv.Printf(_T(
" (%d)"), (
int)ival);
5291 value.Printf(_T(
"%d"), (
int)ival);
5295 else if (val_str.IsEmpty())
5296 value = _T(
"Unknown");
5300 wxString value_increment;
5301 wxStringTokenizer tk(val_str, wxT(
","));
5303 if (tk.HasMoreTokens()) {
5304 while (tk.HasMoreTokens()) {
5305 wxString token = tk.GetNextToken();
5307 if (token.ToLong(&ival)) {
5308 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5310 value_increment.Printf(_T(
" (%d)"), (
int)ival);
5312 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5314 if (iv) value_increment.Prepend(wxT(
", "));
5315 value.Append(value_increment);
5318 if (iv) value.Append(_T(
","));
5319 value.Append(token);
5325 value.Append(val_str);
5328 value = _T(
"[NULL VALUE]");
5334 int ival = *((
int *)pval->value);
5335 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5337 if (!decode_val.IsEmpty()) {
5340 iv.Printf(_T(
"(%d)"), ival);
5343 value.Printf(_T(
"(%d)"), ival);
5351 double dval = *((
double *)pval->value);
5352 wxString val_suffix = _T(
" m");
5355 if ((curAttrName == _T(
"VERCLR")) || (curAttrName == _T(
"VERCCL")) ||
5356 (curAttrName == _T(
"VERCOP")) || (curAttrName == _T(
"HEIGHT")) ||
5357 (curAttrName == _T(
"HORCLR"))) {
5358 switch (ps52plib->m_nDepthUnitDisplay) {
5361 dval = dval * 3 * 39.37 / 36;
5362 val_suffix = _T(
" ft");
5369 else if ((curAttrName == _T(
"VALSOU")) || (curAttrName == _T(
"DRVAL1")) ||
5370 (curAttrName == _T(
"DRVAL2")) || (curAttrName == _T(
"VALDCO"))) {
5371 switch (ps52plib->m_nDepthUnitDisplay) {
5373 dval = dval * 3 * 39.37 / 36;
5374 val_suffix = _T(
" ft");
5377 dval = dval * 3 * 39.37 / 36;
5379 val_suffix = _T(
" fathoms");
5386 else if (curAttrName == _T(
"SECTR1"))
5387 val_suffix = _T(
"°");
5388 else if (curAttrName == _T(
"SECTR2"))
5389 val_suffix = _T(
"°");
5390 else if (curAttrName == _T(
"ORIENT"))
5391 val_suffix = _T(
"°");
5392 else if (curAttrName == _T(
"VALNMR"))
5393 val_suffix = _T(
" Nm");
5394 else if (curAttrName == _T(
"SIGPER"))
5395 val_suffix = _T(
"s");
5396 else if (curAttrName == _T(
"VALACM"))
5397 val_suffix = _T(
" Minutes/year");
5398 else if (curAttrName == _T(
"VALMAG"))
5399 val_suffix = _T(
"°");
5400 else if (curAttrName == _T(
"CURVEL"))
5401 val_suffix = _T(
" kt");
5403 if (dval - floor(dval) < 0.01)
5404 value.Printf(_T(
"%2.0f"), dval);
5406 value.Printf(_T(
"%4.1f"), dval);
5408 value << val_suffix;
5413 case OGR_REAL_LST: {
5420 wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5421 wxString AttrName) {
5422 if (NULL == pAttrVal)
return _T(
"");
5425 switch (pAttrVal->valType) {
5427 if (pAttrVal->value) {
5428 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5430 if (val_str.ToLong(&ival)) {
5432 value = _T(
"Unknown");
5434 wxString decode_val = GetAttributeDecode(AttrName, ival);
5435 if (!decode_val.IsEmpty()) {
5438 iv.Printf(_T(
"(%d)"), (
int)ival);
5441 value.Printf(_T(
"%d"), (
int)ival);
5445 else if (val_str.IsEmpty())
5446 value = _T(
"Unknown");
5450 wxString value_increment;
5451 wxStringTokenizer tk(val_str, wxT(
","));
5453 while (tk.HasMoreTokens()) {
5454 wxString token = tk.GetNextToken();
5456 if (token.ToLong(&ival)) {
5457 wxString decode_val = GetAttributeDecode(AttrName, ival);
5458 if (!decode_val.IsEmpty())
5459 value_increment = decode_val;
5461 value_increment.Printf(_T(
" %d"), (
int)ival);
5463 if (iv) value_increment.Prepend(wxT(
", "));
5465 value.Append(value_increment);
5469 value.Append(val_str);
5472 value = _T(
"[NULL VALUE]");
5478 int ival = *((
int *)pAttrVal->value);
5479 wxString decode_val = GetAttributeDecode(AttrName, ival);
5481 if (!decode_val.IsEmpty()) {
5484 iv.Printf(_T(
"(%d)"), ival);
5487 value.Printf(_T(
"(%d)"), ival);
5495 double dval = *((
double *)pAttrVal->value);
5496 wxString val_suffix = _T(
" m");
5499 if ((AttrName == _T(
"VERCLR")) || (AttrName == _T(
"VERCCL")) ||
5500 (AttrName == _T(
"VERCOP")) || (AttrName == _T(
"HEIGHT")) ||
5501 (AttrName == _T(
"HORCLR"))) {
5502 switch (ps52plib->m_nDepthUnitDisplay) {
5505 dval = dval * 3 * 39.37 / 36;
5506 val_suffix = _T(
" ft");
5513 else if ((AttrName == _T(
"VALSOU")) || (AttrName == _T(
"DRVAL1")) ||
5514 (AttrName == _T(
"DRVAL2"))) {
5515 switch (ps52plib->m_nDepthUnitDisplay) {
5517 dval = dval * 3 * 39.37 / 36;
5518 val_suffix = _T(
" ft");
5521 dval = dval * 3 * 39.37 / 36;
5523 val_suffix = _T(
" fathoms");
5530 else if (AttrName == _T(
"SECTR1"))
5531 val_suffix = _T(
"°");
5532 else if (AttrName == _T(
"SECTR2"))
5533 val_suffix = _T(
"°");
5534 else if (AttrName == _T(
"ORIENT"))
5535 val_suffix = _T(
"°");
5536 else if (AttrName == _T(
"VALNMR"))
5537 val_suffix = _T(
" Nm");
5538 else if (AttrName == _T(
"SIGPER"))
5539 val_suffix = _T(
"s");
5540 else if (AttrName == _T(
"VALACM"))
5541 val_suffix = _T(
" Minutes/year");
5542 else if (AttrName == _T(
"VALMAG"))
5543 val_suffix = _T(
"°");
5544 else if (AttrName == _T(
"CURVEL"))
5545 val_suffix = _T(
" kt");
5547 if (dval - floor(dval) < 0.01)
5548 value.Printf(_T(
"%2.0f"), dval);
5550 value.Printf(_T(
"%4.1f"), dval);
5552 value << val_suffix;
5557 case OGR_REAL_LST: {
5565 int positionDiff = l1->position.Cmp(l2->position);
5566 if (positionDiff < 0)
return false;
5568 int attrIndex1 = l1->attributeNames.Index(_T(
"SECTR1"));
5569 int attrIndex2 = l2->attributeNames.Index(_T(
"SECTR1"));
5572 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5573 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5574 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5576 double angle1, angle2;
5577 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5578 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5580 return angle1 < angle2;
5583 static const char *type2str(GeoPrim_t type) {
5584 const char *r =
"Unknown";
5605 wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5608 wxString curAttrName, value;
5609 bool isLight =
false;
5612 wxString classAttributes;
5614 wxString lightsHtml;
5615 wxString positionString;
5616 std::vector<S57Light *> lights;
5620 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5621 node = node->GetPrevious()) {
5622 ObjRazRules *current = node->GetData();
5623 positionString.Clear();
5627 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5629 if (current->obj->Primitive_type == GEO_META)
continue;
5630 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5632 className = wxString(current->obj->FeatureName, wxConvUTF8);
5635 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5640 const char *name_desc;
5641 if (g_csv_locn.Len()) {
5642 wxString oc_file(g_csv_locn);
5643 oc_file.Append(_T(
"/s57objectclasses.csv"));
5644 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5645 current->obj->FeatureName,
5646 CC_ExactString,
"ObjectClass");
5652 if (0 == strlen(name_desc)) {
5653 name_desc = current->obj->FeatureName;
5654 classDesc = wxString(name_desc, wxConvUTF8, 1);
5655 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5657 classDesc = wxString(name_desc, wxConvUTF8);
5664 classAttributes = _T(
"");
5665 index.Printf(_T(
"Feature Index: %d<br>"), current->obj->Index);
5666 classAttributes << index;
5669 LUPstring.Printf(_T(
"LUP RCID: %d<br>"), current->LUP->RCID);
5670 classAttributes << LUPstring;
5673 LLBBox bbox = current->obj->BBObj;
5674 Bbox.Printf(_T(
"Lat/Lon box: %g %g %g %g<br>"), bbox.GetMinLat(),
5675 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5676 classAttributes << Bbox;
5679 Type.Printf(_T(
" Type: %s<br>"), type2str(current->obj->Primitive_type));
5680 classAttributes << Type;
5682 LUPstring = _T(
" LUP ATTC: ");
5683 if (current->LUP->ATTArray.size())
5684 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5685 LUPstring += _T(
"<br>");
5686 classAttributes << LUPstring;
5688 LUPstring = _T(
" LUP INST: ");
5689 LUPstring += current->LUP->INST;
5690 LUPstring += _T(
"<br><br>");
5691 classAttributes << LUPstring;
5694 if (GEO_POINT == current->obj->Primitive_type) {
5696 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5697 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5698 ref_lat, ref_lon, &lat, &lon);
5700 if (lon > 180.0) lon -= 360.;
5702 positionString.Clear();
5703 positionString += toSDMM(1, lat);
5704 positionString << _T(
" ");
5705 positionString += toSDMM(2, lon);
5709 curLight->position = positionString;
5710 curLight->hasSectors =
false;
5711 lights.push_back(curLight);
5717 if (current->obj->att_array) {
5718 char *curr_att = current->obj->att_array;
5724 attribStr << _T(
"<table border=0 cellspacing=0 cellpadding=0>");
5727 ret_val << _T(
"<p>") << classAttributes;
5730 bool inDepthRange =
false;
5732 while (attrCounter < current->obj->n_attr) {
5734 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5741 assert(curLight !=
nullptr);
5742 curLight->attributeNames.Add(curAttrName);
5743 if (curAttrName.StartsWith(_T(
"SECTR"))) curLight->hasSectors =
true;
5745 if (curAttrName == _T(
"DRVAL1")) {
5746 attribStr << _T(
"<tr><td><font size=-1>");
5747 inDepthRange =
true;
5748 }
else if (curAttrName == _T(
"DRVAL2")) {
5749 attribStr << _T(
" - ");
5750 inDepthRange =
false;
5753 attribStr << _T(
"</font></td></tr>\n");
5754 inDepthRange =
false;
5756 attribStr << _T(
"<tr><td valign=top><font size=-2>");
5757 if (curAttrName == _T(
"catgeo"))
5758 attribStr << _T(
"CATGEO");
5760 attribStr << curAttrName;
5761 attribStr << _T(
"</font></td><td> </td><td ")
5762 _T("valign=top><font size=-1>");
5773 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5778 wxString AttrNamesFiles =
5779 _T("PICREP,TXTDSC,NTXTDS");
5781 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5782 if (value.Find(_T(".XML")) == wxNOT_FOUND) {
5783 file.Assign(GetFullPath());
5784 file.Assign(file.GetPath(), value);
5789 wxString::Format(_T(
"<a href=\"%s\">%s</a>"),
5790 file.GetFullPath(), file.GetFullName());
5792 value = value + _T(
" <font color=\"red\">[ ") +
5793 _(
"this file is not available") + _T(
" ]</font>");
5797 _T(
"DATEND,DATSTA,PEREND,PERSTA");
5798 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5801 wxString ts = value;
5803 ts.Replace(wxT(
"--"),
5805 if (ts.Length() < 5) {
5810 if (ts.Length() < 7) {
5815 wxString::const_iterator end;
5817 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5819 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5820 if (d) ts.Append(wxString::Format(wxT(
" %d"), dt.GetDay()));
5821 if (dt.GetYear() > 0)
5822 ts.Append(wxString::Format(wxT(
", %i"), dt.GetYear()));
5823 if (curAttrName == _T(
"PEREND"))
5824 ts = _(
"Period ends: ") + ts + wxT(
" (") + value + wxT(
")");
5825 if (curAttrName == _T(
"PERSTA"))
5826 ts = _(
"Period starts: ") + ts + wxT(
" (") + value + wxT(
")");
5827 if (curAttrName == _T(
"DATEND"))
5828 ts = _(
"Date ending: ") + ts + wxT(
" (") + value + wxT(
")");
5829 if (curAttrName == _T(
"DATSTA"))
5830 ts = _(
"Date starting: ") + ts + wxT(
" (") + value + wxT(
")");
5834 if (curAttrName == _T(
"TS_TSP")) {
5841 wxStringTokenizer tk(value, wxT(
","));
5846 ts1 = tk.GetNextToken().Trim(
false);
5849 }
while ((ts1.Left(2).ToLong(&l)));
5850 ts = _T(
"Tidal Streams referred to<br><b>");
5851 ts.Append(tk.GetNextToken()).Append(_T(
"</b> at <b>")).Append(ts1);
5852 ts.Append(_T(
"</b><br><table >"));
5854 while (tk.HasMoreTokens()) {
5855 ts.Append(_T(
"<tr><td>"));
5856 wxString s1(wxString::Format(_T(
"%+dh "), i));
5858 ts.Append(_T(
"</td><td>"));
5859 s1 = tk.GetNextToken();
5861 s1 =
"°</td><td>";
5863 s1 = tk.GetNextToken();
5866 ts.Append(_T(
"</td></tr>"));
5869 ts.Append(_T(
"</table>"));
5874 assert(curLight !=
nullptr);
5875 curLight->attributeValues.Add(value);
5877 if (curAttrName == _T(
"INFORM") || curAttrName == _T(
"NINFOM"))
5878 value.Replace(_T(
"|"), _T(
"<br>"));
5880 if (curAttrName == _T(
"catgeo"))
5881 attribStr << type2str(current->obj->Primitive_type);
5885 if (!(curAttrName == _T(
"DRVAL1"))) {
5886 attribStr << _T(
"</font></td></tr>\n");
5896 attribStr << _T(
"</table>\n");
5898 objText += _T(
"<b>") + classDesc + _T(
"</b> <font size=-2>(") +
5899 className + _T(
")</font>") + _T(
"<br>");
5901 if (positionString.Length())
5902 objText << _T(
"<font size=-2>") << positionString
5903 << _T(
"</font><br>\n");
5905 if (noAttr > 0) objText << attribStr;
5907 if (node != rule_list->GetFirst()) objText += _T(
"<hr noshade>");
5908 objText += _T(
"<br>");
5914 if (!lights.empty()) {
5915 assert(curLight !=
nullptr);
5920 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5924 for (
auto const &thisLight : lights) {
5927 if (thisLight->position != lastPos) {
5928 lastPos = thisLight->position;
5930 if (thisLight != *lights.begin())
5931 lightsHtml << _T(
"</table>\n<hr noshade>\n");
5933 lightsHtml << _T(
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>");
5934 lightsHtml << _T(
"<font size=-2>") << thisLight->position
5935 << _T(
"</font><br>\n");
5937 if (curLight->hasSectors)
5939 "<font size=-2>(Sector angles are True Bearings from "
5940 "Seaward)</font><br>");
5942 lightsHtml << _T(
"<table>");
5945 lightsHtml << _T(
"<tr>");
5946 lightsHtml << _T(
"<td><font size=-1>");
5949 attrIndex = thisLight->attributeNames.Index(_T(
"COLOUR"));
5950 if (attrIndex != wxNOT_FOUND) {
5951 wxString color = thisLight->attributeValues.Item(attrIndex);
5952 if (color == _T(
"red (3)") || color == _T(
"red(3)"))
5954 _T(
"<table border=0><tr><td ")
5955 _T("bgcolor=red> </td></tr></table> ");
5956 else if (color == _T("green (4)") || color == _T("green(4)"))
5958 _T("<table border=0><tr><td ")
5959 _T("bgcolor=green> </td></tr></table> ");
5960 else if (color == _T("white (1)") || color == _T("white(1)"))
5962 _T("<table border=0><tr><td ")
5963 _T("bgcolor=white> </td></tr></table> ");
5964 else if (color == _T("yellow (6)") || color == _T("yellow(6)"))
5966 _T("<table border=0><tr><td ")
5967 _T("bgcolor=yellow> </td></tr></table> ");
5968 else if (color == _T("blue (5)") || color == _T("blue(5)"))
5970 _T("<table border=0><tr><td ")
5971 _T("bgcolor=blue> </td></tr></table> ");
5972 else if (color == _T("magenta (12)") || color == _T("magenta(12)"))
5974 _T("<table border=0><tr><td ")
5975 _T("bgcolor=magenta> </td></tr></table> ");
5978 _T("<table border=0><tr><td ")
5979 _T("bgcolor=grey> ? </td></tr></table> ");
5982 int visIndex = thisLight->attributeNames.Index(_T("LITVIS"));
5983 if (visIndex != wxNOT_FOUND) {
5984 wxString vis = thisLight->attributeValues.Item(visIndex);
5985 if (vis.Contains(_T(
"8"))) {
5986 if (attrIndex != wxNOT_FOUND) {
5987 wxString color = thisLight->attributeValues.Item(attrIndex);
5988 if (( color == _T(
"red (3)") || color == _T(
"red(3)")))
5990 _T(
"<table border=0><tr><td ")
5991 _T("bgcolor=DarkRed> </td></tr></table> ");
5992 if (( color == _T("green (4)") || color == _T("green(4)")))
5994 _T("<table border=0><tr><td ")
5995 _T("bgcolor=DarkGreen> </td></tr></table> ");
5996 if (( color == _T("white (1)") || color == _T("white(1)")))
5998 _T("<table border=0><tr><td ")
5999 _T("bgcolor=GoldenRod> </td></tr></table> ");
6004 lightsHtml << colorStr;
6006 lightsHtml << _T("</font></td><td><font size=-1><nobr><b>");
6008 attrIndex = thisLight->attributeNames.Index(_T("LITCHR"));
6009 if (attrIndex != wxNOT_FOUND) {
6010 wxString character = thisLight->attributeValues[attrIndex];
6011 lightsHtml << character.BeforeFirst(wxChar(
'(')) << _T(
" ");
6014 attrIndex = thisLight->attributeNames.Index(_T(
"SIGGRP"));
6015 if (attrIndex != wxNOT_FOUND) {
6016 lightsHtml << thisLight->attributeValues[attrIndex];
6017 lightsHtml << _T(
" ");
6020 attrIndex = thisLight->attributeNames.Index( _T(
"COLOUR") );
6021 if( attrIndex != wxNOT_FOUND ) {
6022 lightsHtml << _T(
" ") << thisLight->attributeValues.Item( attrIndex ).Upper()[0];
6023 lightsHtml << _T(
" ");
6026 attrIndex = thisLight->attributeNames.Index(_T(
"SIGPER"));
6027 if (attrIndex != wxNOT_FOUND) {
6028 lightsHtml << thisLight->attributeValues[attrIndex];
6029 lightsHtml << _T(
" ");
6032 attrIndex = thisLight->attributeNames.Index(_T(
"HEIGHT"));
6033 if (attrIndex != wxNOT_FOUND) {
6034 lightsHtml << thisLight->attributeValues[attrIndex];
6035 lightsHtml << _T(
" ");
6038 attrIndex = thisLight->attributeNames.Index(_T(
"VALNMR"));
6039 if (attrIndex != wxNOT_FOUND) {
6040 lightsHtml << thisLight->attributeValues[attrIndex];
6041 lightsHtml << _T(
" ");
6044 lightsHtml << _T(
"</b>");
6046 attrIndex = thisLight->attributeNames.Index(_T(
"SECTR1"));
6047 if (attrIndex != wxNOT_FOUND) {
6048 lightsHtml << _T(
"(") << thisLight->attributeValues[attrIndex];
6049 lightsHtml << _T(
" - ");
6050 attrIndex = thisLight->attributeNames.Index(_T(
"SECTR2"));
6051 lightsHtml << thisLight->attributeValues[attrIndex] << _T(
") ");
6054 lightsHtml << _T(
"</nobr>");
6056 attrIndex = thisLight->attributeNames.Index(_T(
"CATLIT"));
6057 if (attrIndex != wxNOT_FOUND) {
6058 lightsHtml << _T(
"<nobr>");
6059 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6061 lightsHtml << _T(
"</nobr> ");
6064 attrIndex = thisLight->attributeNames.Index(_T(
"EXCLIT"));
6065 if (attrIndex != wxNOT_FOUND) {
6066 lightsHtml << _T(
"<nobr>");
6067 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6069 lightsHtml << _T(
"</nobr> ");
6072 attrIndex = thisLight->attributeNames.Index(_T(
"OBJNAM"));
6073 if (attrIndex != wxNOT_FOUND) {
6074 lightsHtml << _T(
"<br><nobr>");
6075 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6076 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6077 lightsHtml << _T(
"</nobr> ");
6080 lightsHtml << _T(
"</font></td>");
6081 lightsHtml << _T(
"</tr>");
6083 thisLight->attributeNames.Clear();
6084 thisLight->attributeValues.Clear();
6087 lightsHtml << _T(
"</table><hr noshade>\n");
6088 ret_val = lightsHtml << ret_val;
6102 bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6103 if (NULL == g_poRegistrar) {
6104 wxLogMessage(_T(
" Error: No ClassRegistrar in InitENCMinimal."));
6108 m_pENCDS =
new OGRS57DataSource;
6110 m_pENCDS->SetS57Registrar(g_poRegistrar);
6112 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6115 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6116 pENCReader->SetClassBased(g_poRegistrar);
6118 pENCReader->Ingest();
6123 OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6125 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6127 if ((NULL != pENCReader) && (NULL != g_poRegistrar)) {
6129 g_poRegistrar->SelectClass(
"M_COVR");
6132 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefn(
6133 g_poRegistrar, g_poRegistrar->GetOBJL(), pENCReader->GetOptionFlags());
6136 pENCReader->AddFeatureDefn(poDefn);
6139 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6142 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6145 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6156 OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6160 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6163 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6166 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6169 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6178 int s57chart::GetENCScale(
void) {
6179 if (NULL == m_pENCDS)
return 0;
6186 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6189 return pENCReader->GetCSCL();
6199 void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6200 const char *pszErrorMsg) {
6201 #define ERR_BUF_LEN 2000
6203 char buf[ERR_BUF_LEN + 1];
6205 if (eErrClass == CE_Debug)
6206 sprintf(buf,
" %s", pszErrorMsg);
6207 else if (eErrClass == CE_Warning)
6208 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6210 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6212 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6213 wxString msg(buf, wxConvUTF8);
6219 if (eErrClass == CE_Fatal) {
6220 longjmp(env_ogrf, 1);
6231 const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6232 const char *pszKeyFieldValue,
6233 CSVCompareCriteria eCriteria,
6234 const char *pszTargetField)
6243 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6244 pszKeyFieldValue, eCriteria);
6246 if (papszRecord == NULL)
return "";
6251 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6252 if (iTargetField < 0)
return "";
6254 if (iTargetField >= CSLCount(papszRecord))
return "";
6256 return (papszRecord[iTargetField]);
6270 bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6293 void s57_DrawExtendedLightSectors(
ocpnDC &dc,
ViewPort &viewport,
6294 std::vector<s57Sector_t> §orlegs) {
6295 float rangeScale = 0.0;
6297 if (sectorlegs.size() > 0) {
6298 std::vector<int> sectorangles;
6299 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6300 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6303 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6304 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6307 wxPoint end1 = viewport.GetPixFromLL(endy, endx);
6309 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6310 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6313 wxPoint end2 = viewport.GetPixFromLL(endy, endx);
6316 viewport.GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6319 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6320 powf((
float)(lightPos.y - end1.y), 2));
6322 if (rangeScale == 0.0) {
6324 if (rangePx > viewport.pix_height / 3) {
6325 rangeScale *= (viewport.pix_height / 3) / rangePx;
6329 rangePx = rangePx * rangeScale;
6331 int penWidth = rangePx / 8;
6332 penWidth = wxMin(20, penWidth);
6333 penWidth = wxMax(5, penWidth);
6337 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color, penWidth,
6339 arcpen->SetCap(wxCAP_BUTT);
6342 float angle1, angle2;
6343 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.rotation * 180.0 / PI;
6344 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.rotation * 180.0 / PI;
6345 if (angle1 > angle2) {
6348 int lpx = lightPos.x;
6349 int lpy = lightPos.y;
6351 wxPoint arcpoints[150];
6354 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6358 int narc = (angle2 - angle1) / step;
6360 step = (angle2 - angle1) / (
float)narc;
6362 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6363 wxPoint yellowCone[3];
6364 yellowCone[0] = lightPos;
6365 yellowCone[1] = end1;
6366 yellowCone[2] = end2;
6367 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6370 wxColor c = sectorlegs[i].color;
6371 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6372 dc.SetBrush(wxBrush(c));
6373 dc.StrokePolygon(3, yellowCone, 0, 0);
6376 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6377 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6378 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6379 arcpoints[npoints].x = x;
6380 arcpoints[npoints].y = y;
6383 dc.StrokeLines(npoints, arcpoints);
6387 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6393 bool haveAngle1 =
false;
6394 bool haveAngle2 =
false;
6395 int sec1 = (int)sectorlegs[i].sector1;
6396 int sec2 = (int)sectorlegs[i].sector2;
6397 if (sec1 > 360) sec1 -= 360;
6398 if (sec2 > 360) sec2 -= 360;
6400 if ((sec2 == 360) && (sec1 == 0))
6403 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6404 if (sectorangles[j] == sec1) haveAngle1 =
true;
6405 if (sectorangles[j] == sec2) haveAngle2 =
true;
6409 dc.StrokeLine(lightPos, end1);
6410 sectorangles.push_back(sec1);
6414 dc.StrokeLine(lightPos, end2);
6415 sectorangles.push_back(sec2);
6422 void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6423 std::vector<s57Sector_t> §orlegs) {
6424 float rangeScale = 0.0;
6426 if (sectorlegs.size() > 0) {
6427 std::vector<int> sectorangles;
6428 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6429 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6432 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6433 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6436 wxPoint end1 = viewport.GetPixFromLL(endy, endx);
6438 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6439 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6442 wxPoint end2 = viewport.GetPixFromLL(endy, endx);
6445 viewport.GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6449 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6450 powf((
float)(lightPos.y - end1.y), 2));
6452 if (rangeScale == 0.0) {
6454 if (rangePx > viewport.pix_height / 3) {
6455 rangeScale *= (viewport.pix_height / 3) / rangePx;
6459 rangePx = rangePx * rangeScale;
6461 float arcw = rangePx / 10;
6462 arcw = wxMin(20, arcw);
6463 arcw = wxMax(5, arcw);
6467 float angle1, angle2;
6468 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.rotation * 180.0 / PI;
6469 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.rotation * 180.0 / PI;
6470 if (angle1 > angle2) {
6473 int lpx = lightPos.x;
6474 int lpy = lightPos.y;
6476 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6477 wxPoint yellowCone[3];
6478 yellowCone[0] = lightPos;
6479 yellowCone[1] = end1;
6480 yellowCone[2] = end2;
6481 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6484 wxColor c = sectorlegs[i].color;
6485 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6486 dc.SetBrush(wxBrush(c));
6487 dc.StrokePolygon(3, yellowCone, 0, 0);
6491 wxPoint r(lpx, lpy);
6494 float rad = rangePx;
6519 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6522 glBindBuffer(GL_ARRAY_BUFFER, 0);
6523 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6525 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6526 glEnableVertexAttribArray(mPosAttrib);
6530 glGetUniformLocation(shader->programId(),
"circle_radius");
6531 glUniform1f(radiusloc, rad);
6535 glGetUniformLocation(shader->programId(),
"circle_center");
6538 ctrv[1] = viewport.pix_height - r.y;
6539 glUniform2fv(centerloc, 1, ctrv);
6542 wxColour colorb = sectorlegs[i].color;
6544 colorv[0] = colorb.Red() / float(256);
6545 colorv[1] = colorb.Green() / float(256);
6546 colorv[2] = colorb.Blue() / float(256);
6547 colorv[3] = colorb.Alpha() / float(256);
6549 GLint colloc = glGetUniformLocation(shader->programId(),
"circle_color");
6550 glUniform4fv(colloc, 1, colorv);
6559 GLint bcolloc = glGetUniformLocation(shader->programId(),
"border_color");
6560 glUniform4fv(bcolloc, 1, bcolorv);
6563 GLint borderWidthloc =
6564 glGetUniformLocation(shader->programId(),
"border_width");
6565 glUniform1f(borderWidthloc, 2);
6568 GLint ringWidthloc =
6569 glGetUniformLocation(shader->programId(),
"ring_width");
6570 glUniform1f(ringWidthloc, arcw);
6573 float sr1 = sectorlegs[i].sector1 + (viewport.rotation * 180 / PI) + 180;
6574 if (sr1 > 360.) sr1 -= 360.;
6575 float sr2 = sectorlegs[i].sector2 + (viewport.rotation * 180 / PI) + 180;
6576 if (sr2 > 360.) sr2 -= 360.;
6588 if ((sb < 0) || (se < 0)) {
6593 GLint sector1loc = glGetUniformLocation(shader->programId(),
"sector_1");
6594 glUniform1f(sector1loc, (sb * PI / 180.));
6595 GLint sector2loc = glGetUniformLocation(shader->programId(),
"sector_2");
6596 glUniform1f(sector2loc, (se * PI / 180.));
6601 mat4x4_translate_in_place(I, r.x, r.y, 0);
6604 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6605 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6608 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6612 mat4x4_identity(IM);
6614 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6615 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6617 glDisableVertexAttribArray(mPosAttrib);
6624 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6629 bool haveAngle1 =
false;
6630 bool haveAngle2 =
false;
6631 int sec1 = (int)sectorlegs[i].sector1;
6632 int sec2 = (int)sectorlegs[i].sector2;
6633 if (sec1 > 360) sec1 -= 360;
6634 if (sec2 > 360) sec2 -= 360;
6636 if ((sec2 == 360) && (sec1 == 0))
6639 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6640 if (sectorangles[j] == sec1) haveAngle1 =
true;
6641 if (sectorangles[j] == sec2) haveAngle2 =
true;
6645 dc.StrokeLine(lightPos, end1);
6646 sectorangles.push_back(sec1);
6650 dc.StrokeLine(lightPos, end2);
6651 sectorangles.push_back(sec2);
6659 bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6662 ListOfObjRazRules *rule_list,
6663 ListOfPI_S57Obj *pi_rule_list,
6664 std::vector<s57Sector_t> §orlegs) {
6665 bool newSectorsNeedDrawing =
false;
6667 bool bhas_red_green =
false;
6668 bool bleading_attribute =
false;
6671 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6672 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6674 int yOpacity = (float)opacity *
6677 if (target_plugin_chart || Chs57) {
6680 wxPoint2DDouble objPos;
6682 char *curr_att = NULL;
6684 wxArrayOfS57attVal *attValArray = NULL;
6686 ListOfObjRazRules::Node *snode = NULL;
6687 ListOfPI_S57Obj::Node *pnode = NULL;
6689 if (Chs57 && rule_list)
6690 snode = rule_list->GetLast();
6691 else if (target_plugin_chart && pi_rule_list)
6692 pnode = pi_rule_list->GetLast();
6695 wxPoint2DDouble lightPosD(0, 0);
6696 bool is_light =
false;
6700 ObjRazRules *current = snode->GetData();
6701 S57Obj *light = current->obj;
6702 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6703 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6704 curr_att = light->att_array;
6705 n_attr = light->n_attr;
6706 attValArray = light->attVal;
6709 }
else if (target_plugin_chart) {
6712 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6713 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6714 curr_att = light->att_array;
6715 n_attr = light->n_attr;
6716 attValArray = light->attVal;
6726 wxString curAttrName;
6729 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6731 if (is_light && (lightPosD == objPos)) {
6739 bleading_attribute =
false;
6741 while (attrCounter < n_attr) {
6742 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6745 S57attVal *pAttrVal = NULL;
6748 pAttrVal = attValArray->Item(attrCounter);
6749 else if (target_plugin_chart)
6750 pAttrVal = attValArray->Item(attrCounter);
6754 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6756 if (curAttrName == _T(
"LITVIS")) {
6757 if (value.StartsWith(_T(
"obsc"))) bviz =
false;
6759 if (curAttrName == _T(
"SECTR1")) value.ToDouble(§r1);
6760 if (curAttrName == _T(
"SECTR2")) value.ToDouble(§r2);
6761 if (curAttrName == _T(
"VALNMR")) value.ToDouble(&valnmr);
6762 if (curAttrName == _T(
"COLOUR")) {
6763 if (value == _T(
"red(3)")) {
6764 color = wxColor(255, 0, 0, opacity);
6765 sector.iswhite =
false;
6766 bhas_red_green =
true;
6769 if (value == _T(
"green(4)")) {
6770 color = wxColor(0, 255, 0, opacity);
6771 sector.iswhite =
false;
6772 bhas_red_green =
true;
6776 if (curAttrName == _T(
"EXCLIT")) {
6777 if (value.Find(_T(
"(3)"))) valnmr = 1.0;
6780 if (curAttrName == _T(
"CATLIT")) {
6781 if (value.Upper().StartsWith(_T(
"DIRECT")) ||
6782 value.Upper().StartsWith(_T(
"LEAD")))
6783 bleading_attribute =
true;
6790 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6791 if (sectr1 > sectr2) {
6795 sector.pos.m_x = objPos.m_y;
6796 sector.pos.m_y = objPos.m_x;
6799 (valnmr > 0.0) ? valnmr : 2.5;
6800 sector.sector1 = sectr1;
6801 sector.sector2 = sectr2;
6803 if (!color.IsOk()) {
6804 color = wxColor(255, 255, 0, yOpacity);
6805 sector.iswhite =
true;
6807 sector.color = color;
6808 sector.isleading =
false;
6810 if (bleading_attribute) sector.isleading =
true;
6812 bool newsector =
true;
6813 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6814 if (sectorlegs[i].pos == sector.pos &&
6815 sectorlegs[i].sector1 == sector.sector1 &&
6816 sectorlegs[i].sector2 == sector.sector2) {
6822 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6826 if (!bviz) newsector =
false;
6828 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6832 sectorlegs.push_back(sector);
6833 newSectorsNeedDrawing =
true;
6840 snode = snode->GetPrevious();
6841 else if (target_plugin_chart)
6842 pnode = pnode->GetPrevious();
6850 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6851 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6852 if (sectorlegs[i].iswhite && bhas_red_green)
6853 sectorlegs[i].isleading =
true;
6857 return newSectorsNeedDrawing;
6860 bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6862 std::vector<s57Sector_t> §orlegs) {
6863 if (!cc)
return false;
6865 static float lastLat, lastLon;
6867 if (!ps52plib)
return false;
6873 wxPoint calcPoint = viewport.GetPixFromLL(lat, lon);
6875 if (cc->m_singleChart && (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6876 target_chart = cc->m_singleChart;
6877 else if (viewport.b_quilt)
6878 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6880 target_chart = NULL;
6883 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6884 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6887 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6890 bool newSectorsNeedDrawing =
false;
6892 if (target_plugin_chart || Chs57) {
6893 ListOfObjRazRules *rule_list = NULL;
6894 ListOfPI_S57Obj *pi_rule_list = NULL;
6897 float selectRadius = 16 / (viewport.view_scale_ppm * 1852 * 60);
6901 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6902 else if (target_plugin_chart)
6903 pi_rule_list = g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6904 target_plugin_chart, lat, lon, viewport);
6906 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6907 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6915 pi_rule_list->Clear();
6916 delete pi_rule_list;
6920 return newSectorsNeedDrawing;
6923 bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6925 std::vector<s57Sector_t> §orlegs) {
6926 if (!cc)
return false;
6928 double cursor_lat, cursor_lon;
6929 static float lastLat, lastLon;
6931 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6936 ChartBase *target_chart = cc->GetChartAtCursor();
6938 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6939 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6942 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6945 cc->GetCanvasPixPoint(mx, my, cursor_lat, cursor_lon);
6947 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6949 lastLat = cursor_lat;
6950 lastLon = cursor_lon;
6951 bool newSectorsNeedDrawing =
false;
6953 if (target_plugin_chart || Chs57) {
6954 ListOfObjRazRules *rule_list = NULL;
6955 ListOfPI_S57Obj *pi_rule_list = NULL;
6958 float selectRadius = 16 / (viewport.view_scale_ppm * 1852 * 60);
6961 rule_list = Chs57->GetObjRuleListAtLatLon(
6962 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6963 else if (target_plugin_chart)
6964 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
6965 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6967 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6968 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6976 pi_rule_list->Clear();
6977 delete pi_rule_list;
6981 return newSectorsNeedDrawing;
General purpose GUI support.