34#include "wx/tokenzr.h"
35#include <wx/textfile.h>
36#include <wx/filename.h>
39#include "OCPNPlatform.h"
50#include "navutil_base.h"
51#include "ocpn_pixel.h"
54#include "wx28compat.h"
55#include "chartdata_input_stream.h"
57#include "gdal/cpl_csv.h"
62#include "pluginmanager.h"
66#include "SencManager.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#define strncasecmp(x, y, z) _strnicmp(x, y, z)
95extern bool GetDoubleAttr(S57Obj *obj,
const char *AttrName,
98void OpenCPN_OGRErrorHandler(
99 CPLErr eErrClass,
int nError,
100 const char *pszErrorMsg);
103extern s52plib *ps52plib;
105extern wxString g_csv_locn;
106extern wxString g_SENCPrefix;
107extern bool g_bGDAL_Debug;
108extern bool g_bDebugS57;
111extern bool g_b_overzoom_x;
112extern bool g_b_EnableVBO;
116int g_SENC_LOD_pixels;
118static jmp_buf env_ogrf;
120#include <wx/arrimpl.cpp>
121WX_DEFINE_OBJARRAY(ArrayOfS57Obj);
123#include <wx/listimpl.cpp>
124WX_DEFINE_LIST(ListOfPI_S57Obj);
126WX_DEFINE_LIST(ListOfObjRazRules);
128#define S57_THUMB_SIZE 200
135static uint64_t hash_fast64(
const void *buf,
size_t len, uint64_t seed) {
136 const uint64_t m = 0x880355f21e6d1965ULL;
137 const uint64_t *pos = (
const uint64_t *)buf;
138 const uint64_t *end = pos + (len >> 3);
139 const unsigned char *pc;
140 uint64_t h = len * m ^ seed;
145 v *= 0x2127599bf4325c37ULL;
149 pc = (
const unsigned char *)pos;
153 v ^= (uint64_t)pc[6] << 48;
155 v ^= (uint64_t)pc[5] << 40;
157 v ^= (uint64_t)pc[4] << 32;
159 v ^= (uint64_t)pc[3] << 24;
161 v ^= (uint64_t)pc[2] << 16;
163 v ^= (uint64_t)pc[1] << 8;
165 v ^= (uint64_t)pc[0];
167 v *= 0x2127599bf4325c37ULL;
173 h *= 0x2127599bf4325c37ULL;
178static unsigned int hash_fast32(
const void *buf,
size_t len,
180 uint64_t h = hash_fast64(buf, len, seed);
185 return h - (h >> 32);
188unsigned long connector_key::hash()
const {
189 return hash_fast32(k,
sizeof k, 0);
196render_canvas_parms::render_canvas_parms() { pix_buff = NULL; }
198render_canvas_parms::~render_canvas_parms(
void) {}
200static void PrepareForRender(
ViewPort *pvp, s52plib *plib) {
204 plib->SetVPointCompat(
215 GetOCPNCanvasWindow()->GetContentScaleFactor()
217 plib->PrepareForRender();
225s57chart::s57chart() {
226 m_ChartType = CHART_TYPE_S57;
227 m_ChartFamily = CHART_FAMILY_VECTOR;
229 for (
int i = 0; i < PRIO_NUM; i++)
230 for (
int j = 0; j < LUPNAME_NUM; j++) razRules[i][j] = NULL;
239 pFloatingATONArray =
new wxArrayPtrVoid;
240 pRigidATONArray =
new wxArrayPtrVoid;
242 m_tmpup_array = NULL;
244 m_DepthUnits = _T(
"METERS");
245 m_depth_unit_id = DEPTH_UNIT_METERS;
247 bGLUWarningSent =
false;
253 m_pvaldco_array = NULL;
255 m_bExtentSet =
false;
257 m_pDIBThumbDay = NULL;
258 m_pDIBThumbDim = NULL;
259 m_pDIBThumbOrphan = NULL;
260 m_bbase_file_attr_known =
false;
262 m_bLinePrioritySet =
false;
263 m_plib_state_hash = 0;
270 m_b2pointLUPS =
false;
271 m_b2lineLUPS =
false;
273 m_next_safe_cnt = 1e6;
275 m_line_vertex_buffer = 0;
276 m_this_chart_context = 0;
278 m_vbo_byte_length = 0;
279 m_SENCthreadStatus = THREAD_INACTIVE;
280 bReadyToRender =
false;
282 m_disableBackgroundSENC =
false;
285s57chart::~s57chart() {
286 FreeObjectsAndRules();
293 delete pFloatingATONArray;
294 delete pRigidATONArray;
298 free(m_pvaldco_array);
300 free(m_line_vertex_buffer);
302 delete m_pDIBThumbOrphan;
304 for (
unsigned i = 0; i < m_pcs_vector.size(); i++)
delete m_pcs_vector.at(i);
306 for (
unsigned i = 0; i < m_pve_vector.size(); i++)
delete m_pve_vector.at(i);
308 m_pcs_vector.clear();
309 m_pve_vector.clear();
311 for (
const auto &it : m_ve_hash) {
312 VE_Element *pedge = it.second;
314 free(pedge->pPoints);
320 for (
const auto &it : m_vc_hash) {
321 VC_Element *pcs = it.second;
330 if ((m_LineVBO_name > 0))
331 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
333 free(m_this_chart_context);
335 if (m_TempFilePath.Length() && (m_FullPath != m_TempFilePath)) {
336 if (::wxFileExists(m_TempFilePath)) wxRemoveFile(m_TempFilePath);
340 if (g_SencThreadManager) {
341 if (g_SencThreadManager->IsChartInTicketlist(
this)) {
342 g_SencThreadManager->SetChartPointer(
this, NULL);
347void s57chart::GetValidCanvasRegion(
const ViewPort &VPoint,
351 double easting, northing;
354 toSM(m_FullExtent.SLAT, m_FullExtent.WLON, VPoint.clat, VPoint.clon, &easting,
356 epix = easting * VPoint.view_scale_ppm;
357 npix = northing * VPoint.view_scale_ppm;
359 rxl = (int)round((VPoint.pix_width / 2) + epix);
360 ryb = (int)round((VPoint.pix_height / 2) - npix);
362 toSM(m_FullExtent.NLAT, m_FullExtent.ELON, VPoint.clat, VPoint.clon, &easting,
364 epix = easting * VPoint.view_scale_ppm;
365 npix = northing * VPoint.view_scale_ppm;
367 rxr = (int)round((VPoint.pix_width / 2) + epix);
368 ryt = (int)round((VPoint.pix_height / 2) - npix);
370 pValidRegion->Clear();
371 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
374LLRegion s57chart::GetValidRegion() {
375 double ll[8] = {m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.SLAT,
376 m_FullExtent.ELON, m_FullExtent.NLAT, m_FullExtent.ELON,
377 m_FullExtent.NLAT, m_FullExtent.WLON};
378 return LLRegion(4, ll);
381void s57chart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
382 if (!ps52plib)
return;
387 case GLOBAL_COLOR_SCHEME_DAY:
388 ps52plib->SetPLIBColorScheme(_T(
"DAY"));
390 case GLOBAL_COLOR_SCHEME_DUSK:
391 ps52plib->SetPLIBColorScheme(_T(
"DUSK"));
393 case GLOBAL_COLOR_SCHEME_NIGHT:
394 ps52plib->SetPLIBColorScheme(_T(
"NIGHT"));
397 ps52plib->SetPLIBColorScheme(_T(
"DAY"));
401 m_global_color_scheme = cs;
403 if (bApplyImmediate) {
409 ClearRenderedTextCache();
412 ChangeThumbColor(cs);
415void s57chart::ChangeThumbColor(ColorScheme cs) {
416 if (0 == m_pDIBThumbDay)
return;
420 case GLOBAL_COLOR_SCHEME_DAY:
421 pThumbData->pDIBThumb = m_pDIBThumbDay;
422 m_pDIBThumbOrphan = m_pDIBThumbDim;
424 case GLOBAL_COLOR_SCHEME_DUSK:
425 case GLOBAL_COLOR_SCHEME_NIGHT: {
426 if (NULL == m_pDIBThumbDim) {
427 wxImage img = m_pDIBThumbDay->ConvertToImage();
429#if wxCHECK_VERSION(2, 8, 0)
430 wxImage gimg = img.ConvertToGreyscale(
440 wxBitmap *pBMP =
new wxBitmap(gimg);
442 m_pDIBThumbDim = pBMP;
443 m_pDIBThumbOrphan = m_pDIBThumbDay;
446 pThumbData->pDIBThumb = m_pDIBThumbDim;
452bool s57chart::GetChartExtent(
Extent *pext) {
454 *pext = m_FullExtent;
460static void free_mps(mps_container *mps) {
461 if (mps == 0)
return;
462 if (ps52plib && mps->cs_rules) {
463 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
464 Rules *rule_chain_top = mps->cs_rules->Item(i);
465 ps52plib->DestroyRulesChain(rule_chain_top);
467 delete mps->cs_rules;
472void s57chart::FreeObjectsAndRules() {
481 for (
int i = 0; i < PRIO_NUM; ++i) {
482 for (
int j = 0; j < LUPNAME_NUM; j++) {
483 top = razRules[i][j];
484 while (top != NULL) {
486 if (0 == top->obj->nRef)
delete top->obj;
489 ObjRazRules *ctop = top->child;
493 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
496 ObjRazRules *cnxx = ctop->next;
511void s57chart::ClearRenderedTextCache() {
513 for (
int i = 0; i < PRIO_NUM; ++i) {
514 for (
int j = 0; j < LUPNAME_NUM; j++) {
515 top = razRules[i][j];
516 while (top != NULL) {
517 if (top->obj->bFText_Added) {
518 top->obj->bFText_Added =
false;
519 delete top->obj->FText;
520 top->obj->FText = NULL;
524 ObjRazRules *ctop = top->child;
526 if (ctop->obj->bFText_Added) {
527 ctop->obj->bFText_Added =
false;
528 delete ctop->obj->FText;
529 ctop->obj->FText = NULL;
541double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
542 bool b_allow_overzoom) {
544 return m_Chart_Scale * 0.125;
548double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
550 return m_Chart_Scale * 4.0;
557void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
559 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
561 r->y = roundint(m_pixy_vp_center -
562 ((north - m_northing_vp_center) * m_view_scale_ppm));
565void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
566 wxPoint *r,
int nPoints) {
567 for (
int i = 0; i < nPoints; i++) {
568 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
570 r[i].y = roundint(m_pixy_vp_center -
571 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
575void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
577 if (vpt->m_projection_type != PROJECTION_MERCATOR)
578 printf(
"s57chart unhandled projection\n");
581 int dx = pixx - (vpt->pix_width / 2);
582 int dy = (vpt->pix_height / 2) - pixy;
584 double xp = (dx * cos(vpt->skew)) - (dy * sin(vpt->skew));
585 double yp = (dy * cos(vpt->skew)) + (dx * sin(vpt->skew));
587 double d_east = xp / vpt->view_scale_ppm;
588 double d_north = yp / vpt->view_scale_ppm;
591 fromSM(d_east, d_north, vpt->clat, vpt->clon, &slat, &slon);
601void s57chart::SetVPParms(
const ViewPort &vpt) {
603 m_pixx_vp_center = vpt.pix_width / 2.0;
604 m_pixy_vp_center = vpt.pix_height / 2.0;
605 m_view_scale_ppm = vpt.view_scale_ppm;
607 toSM(vpt.clat, vpt.clon, ref_lat, ref_lon, &m_easting_vp_center,
608 &m_northing_vp_center);
610 vp_transform.easting_vp_center = m_easting_vp_center;
611 vp_transform.northing_vp_center = m_northing_vp_center;
615 if (IsCacheValid()) {
617 if (vp_last.view_scale_ppm == vp_proposed.view_scale_ppm) {
618 double prev_easting_c, prev_northing_c;
619 toSM(vp_last.clat, vp_last.clon, ref_lat, ref_lon, &prev_easting_c,
622 double easting_c, northing_c;
623 toSM(vp_proposed.clat, vp_proposed.clon, ref_lat, ref_lon, &easting_c,
630 (easting_c - prev_easting_c) * vp_proposed.view_scale_ppm;
631 int dpix_x = (
int)round(delta_pix_x);
635 (northing_c - prev_northing_c) * vp_proposed.view_scale_ppm;
636 int dpix_y = (
int)round(delta_pix_y);
639 double c_east_d = (dpx / vp_proposed.view_scale_ppm) + prev_easting_c;
640 double c_north_d = (dpy / vp_proposed.view_scale_ppm) + prev_northing_c;
643 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
645 vp_proposed.clon = xlon;
646 vp_proposed.clat = xlat;
673void s57chart::LoadThumb() {
674 wxFileName fn(m_FullPath);
675 wxString SENCdir = g_SENCPrefix;
677 if (SENCdir.Last() != fn.GetPathSeparator())
678 SENCdir.Append(fn.GetPathSeparator());
680 wxFileName tsfn(SENCdir);
681 tsfn.SetFullName(fn.GetFullName());
683 wxFileName ThumbFileNameLook(tsfn);
684 ThumbFileNameLook.SetExt(_T(
"BMP"));
687 if (ThumbFileNameLook.FileExists()) {
690 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
691 m_pDIBThumbDay = pBMP;
692 m_pDIBThumbOrphan = 0;
697ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
700 if (pThumbData->pDIBThumb == 0) {
702 ChangeThumbColor(m_global_color_scheme);
705 UpdateThumbData(lat, lon);
710bool s57chart::UpdateThumbData(
double lat,
double lon) {
714 if (pThumbData->pDIBThumb) {
715 double lat_top = m_FullExtent.NLAT;
716 double lat_bot = m_FullExtent.SLAT;
717 double lon_left = m_FullExtent.WLON;
718 double lon_right = m_FullExtent.ELON;
721 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
723 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
725 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
728 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
729 (int)(east * thumb_view_scale_ppm);
730 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
731 (int)(north * thumb_view_scale_ppm);
738 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
739 pThumbData->ShipX = test_x;
740 pThumbData->ShipY = test_y;
746void s57chart::SetFullExtent(
Extent &ext) {
747 m_FullExtent.NLAT = ext.NLAT;
748 m_FullExtent.SLAT = ext.SLAT;
749 m_FullExtent.WLON = ext.WLON;
750 m_FullExtent.ELON = ext.ELON;
755void s57chart::ForceEdgePriorityEvaluate(
void) { m_bLinePrioritySet =
false; }
757void s57chart::SetLinePriorities(
void) {
758 if (!ps52plib)
return;
763 if (!m_bLinePrioritySet) {
767 for (
int i = 0; i < PRIO_NUM; ++i) {
768 top = razRules[i][2];
769 while (top != NULL) {
770 ObjRazRules *crnt = top;
772 ps52plib->SetLineFeaturePriority(crnt, i);
778 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
783 top = razRules[i][j];
784 while (top != NULL) {
787 ps52plib->SetLineFeaturePriority(crnt, i);
793 for (
int i = 0; i < PRIO_NUM; ++i) {
794 for (
int j = 0; j < LUPNAME_NUM; j++) {
795 ObjRazRules *top = razRules[i][j];
796 while (top != NULL) {
797 S57Obj *obj = top->obj;
800 connector_segment *pcs;
801 line_segment_element *list = obj->m_ls_list;
803 switch (list->ls_type) {
807 if (pedge) list->priority = pedge->max_priority;
812 if (pcs) list->priority = pcs->max_priority_cs;
827 m_bLinePrioritySet =
true;
831void s57chart::SetLinePriorities(
void )
833 if( !ps52plib )
return;
838 if( !m_bLinePrioritySet ) {
842 for(
int i = 0; i < PRIO_NUM; ++i ) {
844 top = razRules[i][2];
845 while( top != NULL ) {
846 ObjRazRules *crnt = top;
848 ps52plib->SetLineFeaturePriority( crnt, i );
853 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
858 top = razRules[i][j];
859 while( top != NULL ) {
862 ps52plib->SetLineFeaturePriority( crnt, i );
870 for(
int i = 0; i < PRIO_NUM; ++i ) {
871 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
872 ObjRazRules *top = razRules[i][j];
873 while( top != NULL ) {
874 S57Obj *obj = top->obj;
877 connector_segment *pcs;
878 line_segment_element *list = obj->m_ls_list;
883 pedge = (VE_Element *)list->private0;
885 list->priority = pedge->max_priority;
889 pcs = (connector_segment *)list->private0;
891 list->priority = pcs->max_priority;
906 m_bLinePrioritySet =
true;
910int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
914 line_segment_element *ls_list = obj->m_ls_list;
916 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
917 nPoints += ls_list->pedge->nCount;
920 ls_list = ls_list->next;
929 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
933 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
934 ls_list = obj->m_ls_list;
936 size_t vbo_offset = 0;
938 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
939 vbo_offset = ls_list->pedge->vbo_offset;
940 count = ls_list->pedge->nCount;
942 vbo_offset = ls_list->pcs->vbo_offset;
946 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
948 ls_list = ls_list->next;
955int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
960 line_segment_element *ls_list = obj->m_ls_list;
962 nPoints += ls_list->n_points;
963 ls_list = ls_list->next;
972 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
976 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
977 ls_list = obj->m_ls_list;
979 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
980 br += ls_list->n_points * 2;
981 ls_list = ls_list->next;
990 float e0, n0, e1, n1;
993void s57chart::AssembleLineGeometry(
void) {
998 for (
const auto &it : m_ve_hash) {
999 VE_Element *pedge = it.second;
1001 nPoints += pedge->nCount;
1007 std::map<long long, connector_segment *> ce_connector_hash;
1008 std::map<long long, connector_segment *> ec_connector_hash;
1009 std::map<long long, connector_segment *> cc_connector_hash;
1011 std::map<long long, connector_segment *>::iterator csit;
1018 std::vector<segment_pair> connector_segment_vector;
1019 size_t seg_pair_index = 0;
1024 for (
int i = 0; i < PRIO_NUM; ++i) {
1025 for (
int j = 0; j < LUPNAME_NUM; j++) {
1026 ObjRazRules *top = razRules[i][j];
1027 while (top != NULL) {
1028 S57Obj *obj = top->obj;
1030 if ((!obj->m_ls_list) &&
1033 line_segment_element list_top;
1036 line_segment_element *le_current = &list_top;
1038 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1039 if (!obj->m_lsindex_array)
continue;
1041 int seg_index = iseg * 3;
1042 int *index_run = &obj->m_lsindex_array[seg_index];
1045 unsigned int inode = *index_run++;
1048 bool edge_dir =
true;
1049 int venode = *index_run++;
1055 VE_Element *pedge = 0;
1057 if (m_ve_hash.find(venode) != m_ve_hash.end())
1058 pedge = m_ve_hash[venode];
1062 unsigned int enode = *index_run++;
1065 VC_Element *ipnode = 0;
1066 ipnode = m_vc_hash[inode];
1069 VC_Element *epnode = 0;
1070 epnode = m_vc_hash[enode];
1073 if (pedge && pedge->nCount) {
1077 long long key = ((
unsigned long long)inode << 32) + venode;
1079 connector_segment *pcs = NULL;
1080 csit = ce_connector_hash.find(key);
1081 if (csit == ce_connector_hash.end()) {
1083 pcs =
new connector_segment;
1084 ce_connector_hash[key] = pcs;
1088 float *ppt = ipnode->pPoint;
1093 pair.e1 = pedge->pPoints[0];
1094 pair.n1 = pedge->pPoints[1];
1096 int last_point_index = (pedge->nCount - 1) * 2;
1097 pair.e1 = pedge->pPoints[last_point_index];
1098 pair.n1 = pedge->pPoints[last_point_index + 1];
1101 connector_segment_vector.push_back(pair);
1102 pcs->vbo_offset = seg_pair_index;
1108 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1109 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1111 pcs->cs_lat_avg = lat;
1112 pcs->cs_lon_avg = lon;
1117 line_segment_element *pls =
new line_segment_element;
1122 pls->ls_type = TYPE_CE;
1124 le_current->next = pls;
1129 if (pedge && pedge->nCount) {
1130 line_segment_element *pls =
new line_segment_element;
1135 pls->ls_type = TYPE_EE;
1136 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1138 le_current->next = pls;
1146 if (pedge && pedge->nCount) {
1147 long long key = ((
unsigned long long)venode << 32) + enode;
1149 connector_segment *pcs = NULL;
1150 csit = ec_connector_hash.find(key);
1151 if (csit == ec_connector_hash.end()) {
1153 pcs =
new connector_segment;
1154 ec_connector_hash[key] = pcs;
1160 pair.e0 = pedge->pPoints[0];
1161 pair.n0 = pedge->pPoints[1];
1163 int last_point_index = (pedge->nCount - 1) * 2;
1164 pair.e0 = pedge->pPoints[last_point_index];
1165 pair.n0 = pedge->pPoints[last_point_index + 1];
1168 float *ppt = epnode->pPoint;
1172 connector_segment_vector.push_back(pair);
1173 pcs->vbo_offset = seg_pair_index;
1179 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1180 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1182 pcs->cs_lat_avg = lat;
1183 pcs->cs_lon_avg = lon;
1188 line_segment_element *pls =
new line_segment_element;
1192 pls->ls_type = TYPE_EC;
1194 le_current->next = pls;
1198 long long key = ((
unsigned long long)inode << 32) + enode;
1200 connector_segment *pcs = NULL;
1201 csit = cc_connector_hash.find(key);
1202 if (csit == cc_connector_hash.end()) {
1204 pcs =
new connector_segment;
1205 cc_connector_hash[key] = pcs;
1210 float *ppt = ipnode->pPoint;
1214 ppt = epnode->pPoint;
1218 connector_segment_vector.push_back(pair);
1219 pcs->vbo_offset = seg_pair_index;
1225 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1226 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1228 pcs->cs_lat_avg = lat;
1229 pcs->cs_lon_avg = lon;
1234 line_segment_element *pls =
new line_segment_element;
1238 pls->ls_type = TYPE_CC;
1240 le_current->next = pls;
1254 if (obj->m_ls_list == NULL) {
1255 obj->m_n_lsindex = 0;
1259 free(obj->m_lsindex_array);
1260 obj->m_lsindex_array = NULL;
1273 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1275 unsigned char *buffer_offset;
1278 if (0 == m_vbo_byte_length) {
1279 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1280 m_vbo_byte_length = vbo_byte_length;
1281 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1284 m_line_vertex_buffer = (
float *)realloc(
1285 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1286 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1287 offset = m_vbo_byte_length;
1288 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1291 float *lvr = (
float *)buffer_offset;
1295 for (
const auto &it : m_ve_hash) {
1296 VE_Element *pedge = it.second;
1298 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1299 lvr += pedge->nCount * 2;
1301 pedge->vbo_offset = offset;
1302 offset += pedge->nCount * 2 *
sizeof(float);
1315 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1317 connector_segment *pcs = csit->second;
1318 m_pcs_vector.push_back(pcs);
1320 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1326 pcs->vbo_offset = offset;
1327 offset += 4 *
sizeof(float);
1330 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1332 connector_segment *pcs = csit->second;
1333 m_pcs_vector.push_back(pcs);
1335 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1341 pcs->vbo_offset = offset;
1342 offset += 4 *
sizeof(float);
1345 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1347 connector_segment *pcs = csit->second;
1348 m_pcs_vector.push_back(pcs);
1350 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1356 pcs->vbo_offset = offset;
1357 offset += 4 *
sizeof(float);
1361 connector_segment_vector.clear();
1366 for (
const auto &it : m_ve_hash) {
1367 VE_Element *pedge = it.second;
1369 m_pve_vector.push_back(pedge);
1370 free(pedge->pPoints);
1378 for (
const auto &it : m_vc_hash) {
1379 VC_Element *pcs = it.second;
1380 if (pcs) free(pcs->pPoint);
1386void s57chart::BuildLineVBO(
void) {
1392 if (CHART_TYPE_CM93 == GetChartType())
return;
1394 if (!g_b_EnableVBO)
return;
1396 if (m_LineVBO_name == -1) {
1399 glGenBuffers(1, &vboId);
1402 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1405#ifndef USE_ANDROID_GLES2
1406 glEnableClientState(GL_VERTEX_ARRAY);
1408 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1411#ifndef USE_ANDROID_GLES2
1412 glDisableClientState(GL_VERTEX_ARRAY);
1414 glBindBuffer(GL_ARRAY_BUFFER, 0);
1417 for (
int i = 0; i < PRIO_NUM; ++i) {
1418 for (
int j = 0; j < LUPNAME_NUM; j++) {
1419 ObjRazRules *top = razRules[i][j];
1420 while (top != NULL) {
1421 S57Obj *obj = top->obj;
1422 obj->auxParm2 = vboId;
1428 m_LineVBO_name = vboId;
1446bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1449 const LLRegion &Region) {
1450 if (!m_RAZBuilt)
return false;
1452 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1455bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1458 const LLRegion &Region) {
1459 if (!m_RAZBuilt)
return false;
1461 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1464bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1467 const LLRegion &Region) {
1468 if (!m_RAZBuilt)
return false;
1470 bool b_text = ps52plib->GetShowS57Text();
1471 ps52plib->m_bShowS57Text =
false;
1472 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1473 ps52plib->m_bShowS57Text = b_text;
1478bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1480 if (!m_RAZBuilt)
return false;
1484 if (!ps52plib)
return false;
1487 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1489 glChartCanvas::DisableClipRegion();
1490 DoRenderOnGLText(glc, VPoint);
1496bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1499 const LLRegion &Region,
bool b_overlay) {
1500 if (!m_RAZBuilt)
return false;
1504 if (!ps52plib)
return false;
1506 if (g_bDebugS57) printf(
"\n");
1510 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1512 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1513 m_bLinePrioritySet =
false;
1515 ClearRenderedTextCache();
1517 ResetPointBBoxes(m_last_vp, VPoint);
1520 m_plib_state_hash = ps52plib->GetStateHash();
1523 if (VPoint.view_scale_ppm != m_last_vp.view_scale_ppm) {
1524 ResetPointBBoxes(m_last_vp, VPoint);
1528 SetLinePriorities();
1531 ps52plib->ClearTextList();
1538 wxRect upr = upd.GetRect();
1541 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1542 chart_region.Intersect(Region);
1544 if (!chart_region.Empty()) {
1548 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1550 if (CHART_TYPE_CM93 == GetChartType()) {
1554 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1557#ifdef OPT_USE_ANDROID_GLES2
1565 wxRect r = upd.GetRect();
1567 glViewport(r.x, vp->pix_height - (r.y + r.height), r.width, r.height);
1575 float yp = vp->pix_height - (r.y + r.height);
1577 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1578 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1581 I[0][0] *= 2.0 / (float)r.width;
1582 I[1][1] *= -2.0 / (
float)r.height;
1586 mat4x4_rotate_Z(Q, I, angle);
1588 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1591 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1597 DoRenderOnGL(glc, cvp);
1599 glChartCanvas::DisableClipRegion();
1612bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1622 for (i = 0; i < PRIO_NUM; ++i) {
1623 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1624 top = razRules[i][4];
1626 top = razRules[i][3];
1628 while (top != NULL) {
1631 crnt->sm_transform_parms = &vp_transform;
1632 ps52plib->RenderAreaToGL(glc, crnt);
1638 for (i = 0; i < PRIO_NUM; ++i) {
1639 if (PI_GetPLIBBoundaryStyle() == SYMBOLIZED_BOUNDARIES)
1640 top = razRules[i][4];
1642 top = razRules[i][3];
1644 while (top != NULL) {
1647 crnt->sm_transform_parms = &vp_transform;
1652 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1653 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1654 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1655 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1658 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1665 for (i = 0; i < PRIO_NUM; ++i) {
1666 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1667 top = razRules[i][4];
1669 top = razRules[i][3];
1670 while (top != NULL) {
1673 crnt->sm_transform_parms = &vp_transform;
1674 ps52plib->RenderObjectToGL(glc, crnt);
1679 for (i = 0; i < PRIO_NUM; ++i) {
1680 top = razRules[i][2];
1681 while (top != NULL) {
1684 crnt->sm_transform_parms = &vp_transform;
1685 ps52plib->RenderObjectToGL(glc, crnt);
1691 for (i = 0; i < PRIO_NUM; ++i) {
1692 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1693 top = razRules[i][0];
1695 top = razRules[i][1];
1697 while (top != NULL) {
1700 crnt->sm_transform_parms = &vp_transform;
1701 ps52plib->RenderObjectToGL(glc, crnt);
1711bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1722 for( i = 0; i < PRIO_NUM; ++i ) {
1723 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1724 top = razRules[i][4];
1726 top = razRules[i][3];
1728 while( top != NULL ) {
1731 crnt->sm_transform_parms = &vp_transform;
1738 for (i = 0; i < PRIO_NUM; ++i) {
1739 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1740 top = razRules[i][4];
1742 top = razRules[i][3];
1744 while (top != NULL) {
1747 crnt->sm_transform_parms = &vp_transform;
1748 ps52plib->RenderObjectToGLText(glc, crnt);
1751 top = razRules[i][2];
1752 while (top != NULL) {
1755 crnt->sm_transform_parms = &vp_transform;
1756 ps52plib->RenderObjectToGLText(glc, crnt);
1759 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1760 top = razRules[i][0];
1762 top = razRules[i][1];
1764 while (top != NULL) {
1767 crnt->sm_transform_parms = &vp_transform;
1768 ps52plib->RenderObjectToGLText(glc, crnt);
1777bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1780 if (!m_RAZBuilt)
return false;
1782 bool b_text = ps52plib->GetShowS57Text();
1783 ps52plib->m_bShowS57Text =
false;
1784 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1785 ps52plib->m_bShowS57Text = b_text;
1790bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1793 if (!dc.IsOk())
return false;
1796 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1800 if (fabs(VPoint.rotation) > .01) {
1801 DCRenderText(dc, VPoint);
1804 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1808 while (upd.HaveRects()) {
1809 wxRect rect = upd.GetRect();
1815 temp_vp.GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1819 temp_vp.GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1821 if (temp_lon_right < temp_lon_left)
1822 temp_lon_right += 360.;
1824 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1827 wxDCClipper clip(dc, rect);
1828 DCRenderText(dc, temp_vp);
1837bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1839 if (!m_RAZBuilt)
return false;
1841 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1844bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1847 if (!m_RAZBuilt)
return false;
1848 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1851bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1856 bool force_new_view =
false;
1858 if (Region != m_last_Region) force_new_view =
true;
1860 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1862 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1863 m_bLinePrioritySet =
false;
1865 ClearRenderedTextCache();
1867 ResetPointBBoxes(m_last_vp, VPoint);
1871 if (VPoint.view_scale_ppm != m_last_vp.view_scale_ppm) {
1872 ResetPointBBoxes(m_last_vp, VPoint);
1875 SetLinePriorities();
1877 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1881 if (VPoint.b_quilt) {
1883 if ((m_pCloneBM->GetWidth() != VPoint.pix_width) ||
1884 (m_pCloneBM->GetHeight() != VPoint.pix_height)) {
1889 if (NULL == m_pCloneBM)
1890 m_pCloneBM =
new wxBitmap(VPoint.pix_width, VPoint.pix_height, -1);
1892 wxMemoryDC dc_clone;
1893 dc_clone.SelectObject(*m_pCloneBM);
1895#ifdef ocpnUSE_DIBSECTION
1898 wxMemoryDC memdc, dc_org;
1901 pDIB->SelectIntoDC(dc_org);
1906 while (upd.HaveRects()) {
1907 wxRect rect = upd.GetRect();
1908 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
1913 dc_clone.SelectObject(wxNullBitmap);
1914 dc_org.SelectObject(wxNullBitmap);
1918 wxColour nodat = GetGlobalColor(_T (
"NODTA" ));
1919 wxColour nodat_sub = nodat;
1921#ifdef ocpnUSE_ocpnBitmap
1922 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
1924 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
1925 m_pCloneBM->SetMask(m_pMask);
1928 dc.SelectObject(*m_pCloneBM);
1930 pDIB->SelectIntoDC(dc);
1932 m_last_Region = Region;
1937bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
1942 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1944 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1945 m_bLinePrioritySet =
false;
1947 ClearRenderedTextCache();
1951 SetLinePriorities();
1953 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
1955 pDIB->SelectIntoDC(dc);
1962bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1963 RenderTypeEnum option,
bool force_new_view) {
1964 bool bnewview =
false;
1966 bool bNewVP =
false;
1968 bool bReallyNew =
false;
1970 double easting_ul, northing_ul;
1971 double easting_lr, northing_lr;
1972 double prev_easting_ul = 0., prev_northing_ul = 0.;
1974 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
1975 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
1977 if (VPoint.view_scale_ppm != m_last_vp.view_scale_ppm) bReallyNew =
true;
1981 if (VPoint.chart_scale > 1e8) bReallyNew =
true;
1983 wxRect dest(0, 0, VPoint.pix_width, VPoint.pix_height);
1984 if (m_last_vprect != dest) bReallyNew =
true;
1985 m_last_vprect = dest;
1987 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1989 m_plib_state_hash = ps52plib->GetStateHash();
2000 if (m_last_vp.IsValid()) {
2002 m_easting_vp_center - ((VPoint.pix_width / 2) / m_view_scale_ppm);
2004 m_northing_vp_center + ((VPoint.pix_height / 2) / m_view_scale_ppm);
2005 easting_lr = easting_ul + (VPoint.pix_width / m_view_scale_ppm);
2006 northing_lr = northing_ul - (VPoint.pix_height / m_view_scale_ppm);
2008 double last_easting_vp_center, last_northing_vp_center;
2009 toSM(m_last_vp.clat, m_last_vp.clon, ref_lat, ref_lon,
2010 &last_easting_vp_center, &last_northing_vp_center);
2013 last_easting_vp_center - ((m_last_vp.pix_width / 2) / m_view_scale_ppm);
2014 prev_northing_ul = last_northing_vp_center +
2015 ((m_last_vp.pix_height / 2) / m_view_scale_ppm);
2017 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2018 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2020 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2021 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2023 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2024 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2026 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2029 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2038 else if ((rul.x != 0) || (rul.y != 0)) {
2039 if (g_bDebugS57) printf(
"newvp due to rul\n");
2050 if (force_new_view) bNewVP =
true;
2054 OCPNRegion rgn_last(0, 0, VPoint.pix_width, VPoint.pix_height);
2055 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2056 rgn_last.Intersect(rgn_new);
2058 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2060 rgn_last.GetBox(xu, yu, wu, hu);
2077 pDIB->SelectIntoDC(dc_last);
2081 new PixelCache(VPoint.pix_width, VPoint.pix_height, BPP);
2082 pDIBNew->SelectIntoDC(dc_new);
2086 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2091 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.pix_width,
2094 dc_new.SelectObject(wxNullBitmap);
2095 dc_last.SelectObject(wxNullBitmap);
2103 pDIB->SelectIntoDC(dc);
2105 OCPNRegion rgn_delta(0, 0, VPoint.pix_width, VPoint.pix_height);
2107 rgn_delta.Subtract(rgn_reused);
2110 while (upd.HaveRects()) {
2111 wxRect rect = upd.GetRect();
2116 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2118 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2119 (rect.y / m_view_scale_ppm);
2120 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2121 (rect.x / m_view_scale_ppm);
2122 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2125 double temp_northing_lr =
2126 temp_northing_ul - (rect.height / m_view_scale_ppm);
2127 double temp_easting_lr =
2128 temp_easting_ul + (rect.width / m_view_scale_ppm);
2129 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2132 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2137 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2138 temp_vp.GetBBox().GetLatRange()) *
2140 temp_vp.GetBBox().EnLarge(margin);
2146 DCRenderRect(dc, temp_vp, &rect);
2151 dc.SelectObject(wxNullBitmap);
2160 else if (bNewVP || (NULL == pDIB)) {
2162 pDIB =
new PixelCache(VPoint.pix_width, VPoint.pix_height,
2165 wxRect full_rect(0, 0, VPoint.pix_width, VPoint.pix_height);
2166 pDIB->SelectIntoDC(dc);
2169 ps52plib->ClearTextList();
2171 DCRenderRect(dc, VPoint, &full_rect);
2173 dc.SelectObject(wxNullBitmap);
2184int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2197 render_canvas_parms pb_spec;
2199 pb_spec.depth = BPP;
2200 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2201 pb_spec.lclip = rect->x;
2202 pb_spec.rclip = rect->x + rect->width - 1;
2203 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2204 pb_spec.width = rect->width;
2205 pb_spec.height = rect->height;
2206 pb_spec.x = rect->x;
2207 pb_spec.y = rect->y;
2209#ifdef ocpnUSE_ocpnBitmap
2210 pb_spec.b_revrgb =
true;
2212 pb_spec.b_revrgb =
false;
2216 wxColour color = GetGlobalColor(_T (
"NODTA" ));
2217 unsigned char r, g, b;
2225 if (pb_spec.depth == 24) {
2226 for (
int i = 0; i < pb_spec.height; i++) {
2227 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2228 for (
int j = 0; j < pb_spec.width; j++) {
2235 int color_int = ((r) << 16) + ((g) << 8) + (b);
2237 for (
int i = 0; i < pb_spec.height; i++) {
2238 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2239 for (
int j = 0; j < pb_spec.width; j++) {
2246 for (i = 0; i < PRIO_NUM; ++i) {
2247 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2248 top = razRules[i][4];
2250 top = razRules[i][3];
2252 while (top != NULL) {
2255 crnt->sm_transform_parms = &vp_transform;
2256 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2261#ifdef ocpnUSE_ocpnBitmap
2262 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2263 pb_spec.height, pb_spec.depth);
2265 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2266 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2267 wxBitmap *pREN =
new wxBitmap(*prender_image);
2273 dc_ren.SelectObject(*pREN);
2276 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2277 (wxDC *)&dc_ren, 0, 0);
2280 dc_ren.SelectObject(wxNullBitmap);
2282#ifdef ocpnUSE_ocpnBitmap
2283 free(pb_spec.pix_buff);
2285 delete prender_image;
2292 DCRenderLPB(dcinput, vp, rect);
2297bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2304 for (i = 0; i < PRIO_NUM; ++i) {
2306 wxDCClipper *pdcc = NULL;
2312 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2313 top = razRules[i][4];
2315 top = razRules[i][3];
2316 while (top != NULL) {
2319 crnt->sm_transform_parms = &vp_transform;
2320 ps52plib->RenderObjectToDC(&dcinput, crnt);
2323 top = razRules[i][2];
2324 while (top != NULL) {
2327 crnt->sm_transform_parms = &vp_transform;
2328 ps52plib->RenderObjectToDC(&dcinput, crnt);
2331 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2332 top = razRules[i][0];
2334 top = razRules[i][1];
2336 while (top != NULL) {
2339 crnt->sm_transform_parms = &vp_transform;
2340 ps52plib->RenderObjectToDC(&dcinput, crnt);
2344 if (pdcc)
delete pdcc;
2357bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2363 for (i = 0; i < PRIO_NUM; ++i) {
2364 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2365 top = razRules[i][4];
2367 top = razRules[i][3];
2369 while (top != NULL) {
2372 crnt->sm_transform_parms = &vp_transform;
2373 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2376 top = razRules[i][2];
2377 while (top != NULL) {
2380 crnt->sm_transform_parms = &vp_transform;
2381 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2384 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2385 top = razRules[i][0];
2387 top = razRules[i][1];
2389 while (top != NULL) {
2392 crnt->sm_transform_parms = &vp_transform;
2393 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2400bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2401 wxFileName fn(FullPath);
2403 wxString cname = fn.GetName();
2404 if (cname.Length() >= 3)
2405 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2410InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2413 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2416 if (name.Upper().EndsWith(
".XZ")) {
2417 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2420 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2421 wxFileName(name).GetName();
2423 if (!wxFileExists(m_TempFilePath) &&
2424 !DecompressXZFile(name, m_TempFilePath)) {
2425 wxRemoveFile(m_TempFilePath);
2426 return INIT_FAIL_REMOVE;
2429 m_TempFilePath = name;
2430 ext = wxFileName(name).GetExt();
2438 return INIT_FAIL_NOERROR;
2443 InitReturn ret_value = INIT_OK;
2445 m_Description = name;
2447 wxFileName fn(m_TempFilePath);
2450 wxString cname = fn.GetName();
2451 m_usage_char = cname[2];
2454 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2455 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2457 if (flags == THUMB_ONLY) {
2465 if (flags == HEADER_ONLY) {
2466 if (ext == _T(
"000")) {
2467 if (!GetBaseFileAttr(fn.GetFullPath()))
2468 ret_value = INIT_FAIL_REMOVE;
2470 if (!CreateHeaderDataFromENC())
2471 ret_value = INIT_FAIL_REMOVE;
2473 ret_value = INIT_OK;
2475 }
else if (ext == _T(
"S57")) {
2476 m_SENCFileName = m_TempFilePath;
2477 if (!CreateHeaderDataFromSENC())
2478 ret_value = INIT_FAIL_REMOVE;
2480 ret_value = INIT_OK;
2489 if (!m_bbase_file_attr_known) {
2490 if (!GetBaseFileAttr(m_TempFilePath))
2491 ret_value = INIT_FAIL_REMOVE;
2493 m_bbase_file_attr_known =
true;
2496 if (ext == _T(
"000")) {
2497 if (m_bbase_file_attr_known) {
2498 int sret = FindOrCreateSenc(m_FullPath);
2499 if (sret == BUILD_SENC_PENDING) {
2504 if (sret != BUILD_SENC_OK) {
2505 if (sret == BUILD_SENC_NOK_RETRY)
2506 ret_value = INIT_FAIL_RETRY;
2508 ret_value = INIT_FAIL_REMOVE;
2510 ret_value = PostInit(flags, m_global_color_scheme);
2515 else if (ext == _T(
"S57")) {
2516 m_SENCFileName = m_TempFilePath;
2517 ret_value = PostInit(flags, m_global_color_scheme);
2524wxString s57chart::buildSENCName(
const wxString &name) {
2525 wxFileName fn(name);
2526 fn.SetExt(_T(
"S57"));
2527 wxString file_name = fn.GetFullName();
2530 wxString SENCdir = g_SENCPrefix;
2532 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2533 SENCdir.Append(wxFileName::GetPathSeparator());
2536 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2537 wxCharBuffer buf = source_dir.ToUTF8();
2538 unsigned char sha1_out[20];
2539 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2542 for (
unsigned int i = 0; i < 6; i++) {
2544 s.Printf(_T(
"%02X"), sha1_out[i]);
2548 file_name.Prepend(sha1);
2551 wxFileName tsfn(SENCdir);
2552 tsfn.SetFullName(file_name);
2554 return tsfn.GetFullPath();
2561int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2565 if (name.Upper().EndsWith(
".XZ")) {
2566 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2569 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2570 wxFileName(name).GetName();
2572 if (!wxFileExists(m_TempFilePath) &&
2573 !DecompressXZFile(name, m_TempFilePath)) {
2574 wxRemoveFile(m_TempFilePath);
2575 return INIT_FAIL_REMOVE;
2578 m_TempFilePath = name;
2579 ext = wxFileName(name).GetExt();
2583 if (!m_bbase_file_attr_known) {
2584 if (!GetBaseFileAttr(m_TempFilePath))
2585 return INIT_FAIL_REMOVE;
2587 m_bbase_file_attr_known =
true;
2591 m_SENCFileName = buildSENCName(name);
2593 int build_ret_val = 1;
2595 bool bbuild_new_senc =
false;
2596 m_bneed_new_thumbnail =
false;
2598 wxFileName FileName000(m_TempFilePath);
2602 wxString msg(_T(
"S57chart::Checking SENC file: "));
2603 msg.Append(m_SENCFileName);
2607 int force_make_senc = 0;
2609 if (::wxFileExists(m_SENCFileName)) {
2612 if (senc.ingestHeader(m_SENCFileName)) {
2613 bbuild_new_senc =
true;
2614 wxLogMessage(_T(
" Rebuilding SENC due to ingestHeader failure."));
2616 int senc_file_version = senc.getSencReadVersion();
2618 int last_update = senc.getSENCReadLastUpdate();
2620 wxString str = senc.getSENCFileCreateDate();
2621 wxDateTime SENCCreateDate;
2622 SENCCreateDate.ParseFormat(str, _T(
"%Y%m%d"));
2624 if (SENCCreateDate.IsValid())
2625 SENCCreateDate.ResetTime();
2630 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2632 senc_base_edtn.ToLong(&isenc_edition);
2634 m_edtn000.ToLong(&ifile_edition);
2639 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2640 bbuild_new_senc =
true;
2641 wxLogMessage(_T(
" Rebuilding SENC due to SENC format update."));
2648 else if (ifile_edition > isenc_edition) {
2649 bbuild_new_senc =
true;
2650 wxLogMessage(_T(
" Rebuilding SENC due to cell edition update."));
2652 msg = _T(
" Last edition recorded in SENC: ");
2653 msg += senc_base_edtn;
2654 msg += _T(
" most recent edition cell file: ");
2659 int most_recent_update_file =
2660 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2662 if (ifile_edition == isenc_edition) {
2663 if (most_recent_update_file > last_update) {
2664 bbuild_new_senc =
true;
2666 _T(
" Rebuilding SENC due to incremental cell update."));
2669 _T(
" Last update recorded in SENC: %d most recent ")
2670 _T(
"update file: %d"),
2671 last_update, most_recent_update_file);
2679 wxDateTime OModTime000;
2680 FileName000.GetTimes(NULL, &OModTime000, NULL);
2681 OModTime000.ResetTime();
2682 if (SENCCreateDate.IsValid()) {
2683 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2685 _T(
" Rebuilding SENC due to Senc vs cell file time ")
2687 bbuild_new_senc =
true;
2690 bbuild_new_senc =
true;
2692 _T(
" Rebuilding SENC due to SENC create time invalid."));
2703 if (force_make_senc) bbuild_new_senc =
true;
2705 }
else if (!::wxFileExists(m_SENCFileName))
2707 wxLogMessage(_T(
" Rebuilding SENC due to missing SENC file."));
2708 bbuild_new_senc =
true;
2712 if (bbuild_new_senc) {
2713 m_bneed_new_thumbnail =
2715 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2717 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2718 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2719 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2725InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2727 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2728 wxString msg(_T(
" Cannot load SENC file "));
2729 msg.Append(m_SENCFileName);
2732 return INIT_FAIL_RETRY;
2738 wxString SENCdir = g_SENCPrefix;
2739 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2740 SENCdir.Append(wxFileName::GetPathSeparator());
2742 wxFileName s57File(m_SENCFileName);
2743 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13), _T(
"BMP"));
2745 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2746 BuildThumbnail(ThumbFileName.GetFullPath());
2749 if (ThumbFileName.FileExists()) {
2751#ifdef ocpnUSE_ocpnBitmap
2752 pBMP_NEW =
new ocpnBitmap;
2754 pBMP_NEW =
new wxBitmap;
2756 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2759 m_pDIBThumbDay = pBMP_NEW;
2767 m_global_color_scheme = cs;
2768 SetColorScheme(cs,
false);
2772 BuildDepthContourArray();
2774 bReadyToRender =
true;
2779void s57chart::ClearDepthContourArray(
void) {
2780 if (m_nvaldco_alloc) {
2781 free(m_pvaldco_array);
2783 m_nvaldco_alloc = 5;
2785 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2788void s57chart::BuildDepthContourArray(
void) {
2791 if (0 == m_nvaldco_alloc) {
2792 m_nvaldco_alloc = 5;
2793 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2799 double prev_valdco = 0.0;
2801 for (
int i = 0; i < PRIO_NUM; ++i) {
2802 for (
int j = 0; j < LUPNAME_NUM; j++) {
2803 top = razRules[i][j];
2804 while (top != NULL) {
2805 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2806 double valdco = 0.0;
2807 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2808 if (valdco != prev_valdco) {
2809 prev_valdco = valdco;
2811 if (m_nvaldco > m_nvaldco_alloc) {
2812 void *tr = realloc((
void *)m_pvaldco_array,
2813 m_nvaldco_alloc * 2 *
sizeof(
double));
2814 m_pvaldco_array = (
double *)tr;
2815 m_nvaldco_alloc *= 2;
2817 m_pvaldco_array[m_nvaldco - 1] = valdco;
2821 ObjRazRules *nxx = top->next;
2826 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2830void s57chart::SetSafetyContour(
void) {
2838 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2841 if (NULL != m_pvaldco_array) {
2842 for (i = 0; i < m_nvaldco; i++) {
2843 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2847 m_next_safe_cnt = m_pvaldco_array[i];
2849 m_next_safe_cnt = (double)1e6;
2851 m_next_safe_cnt = (double)1e6;
2856 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2857 m_next_safe_cnt = (
double)1e6;
2860void s57chart::InvalidateCache() {
2865bool s57chart::BuildThumbnail(
const wxString &bmpname) {
2868 wxFileName ThumbFileName(bmpname);
2871 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
2872 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
2873 wxLogMessage(_T(
" Cannot create BMP file directory for ") +
2874 ThumbFileName.GetFullPath());
2882 vp.clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
2883 vp.clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2885 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
2886 (m_FullExtent.ELON - m_FullExtent.WLON));
2888 vp.view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
2890 vp.pix_height = S57_THUMB_SIZE;
2891 vp.pix_width = S57_THUMB_SIZE;
2893 vp.m_projection_type = PROJECTION_MERCATOR;
2895 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
2898 vp.chart_scale = 10000000 - 1;
2899 vp.ref_scale = vp.chart_scale;
2912 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
2914 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
2916 int *psvr = psave_viz;
2920 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
2921 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
2922 *psvr++ = pOLE->nViz;
2927 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
2928 bool bsave_text = ps52plib->m_bShowS57Text;
2931 ps52plib->SaveObjNoshow();
2934 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
2935 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
2936 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
2937 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
2940 ps52plib->m_bShowSoundg =
false;
2941 ps52plib->m_bShowS57Text =
false;
2944 DisCat dsave = ps52plib->GetDisplayCategory();
2945 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
2947 ps52plib->AddObjNoshow(
"BRIDGE");
2948 ps52plib->AddObjNoshow(
"GATCON");
2950 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
2951 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
2952 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2953 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
2955#ifdef ocpnUSE_DIBSECTION
2958 wxMemoryDC memdc, dc_org;
2962 ps52plib->SaveColorScheme();
2963 ps52plib->SetPLIBColorScheme(_T(
"DAY"));
2965 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
2968 memdc.SelectObject(wxNullBitmap);
2972 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
2973 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
2974 pOLE->nViz = *psvr++;
2977 ps52plib->SetDisplayCategory(dsave);
2978 ps52plib->RestoreObjNoshow();
2980 ps52plib->RemoveObjNoshow(
"BRIDGE");
2981 ps52plib->RemoveObjNoshow(
"GATCON");
2983 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
2984 ps52plib->m_bShowS57Text = bsave_text;
2986 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
2987 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
2990 ps52plib->RestoreColorScheme();
2998 pBMP =
new wxBitmap(vp.pix_width, vp.pix_height );
3000 wxMemoryDC dc_clone;
3001 dc_clone.SelectObject(*pBMP);
3003 pDIB->SelectIntoDC(dc_org);
3005 dc_clone.Blit(0, 0, vp.pix_width, vp.pix_height, (wxDC *)&dc_org, 0, 0);
3007 dc_clone.SelectObject(wxNullBitmap);
3008 dc_org.SelectObject(wxNullBitmap);
3011 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3018#include <wx/arrimpl.cpp>
3019WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3022bool s57chart::CreateHeaderDataFromENC(
void) {
3023 if (!InitENCMinimal(m_TempFilePath)) {
3024 wxString msg(_T(
" Cannot initialize ENC file "));
3025 msg.Append(m_TempFilePath);
3033 float LatMax, LatMin, LonMax, LonMin;
3039 m_pCOVRTablePoints = NULL;
3040 m_pCOVRTable = NULL;
3043 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3044 std::vector<int> auxCntArray, noCovrCntArray;
3046 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3049 pFeat = GetChartFirstM_COVR(catcov);
3054 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3055 OGRLinearRing *xring = poly->getExteriorRing();
3057 int npt = xring->getNumPoints();
3068 for (
int i = 0; i < npt; i++) {
3069 xring->getPoint(i, &p);
3073 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3075 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3076 if (xdelta < 0.001 &&
3084 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3085 pfr = &pf[2 * (usedpts - 1)];
3088 LatMax = fmax(LatMax, p.getY());
3089 LatMin = fmin(LatMin, p.getY());
3090 LonMax = fmax(LonMax, p.getX());
3091 LonMin = fmin(LonMin, p.getX());
3099 pAuxPtrArray->Add(pf);
3100 auxCntArray.push_back(usedpts);
3101 }
else if (catcov == 2) {
3102 pNoCovrPtrArray->Add(pf);
3103 noCovrCntArray.push_back(usedpts);
3108 pFeat = GetChartNextM_COVR(catcov);
3109 DEBUG_LOG <<
"used " << usedpts <<
" points";
3114 m_nCOVREntries = auxCntArray.size();
3118 if (m_nCOVREntries >= 1) {
3119 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3120 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3122 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3123 m_pCOVRTablePoints[j] = auxCntArray[j];
3124 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3130 wxString msg(_T(
" ENC contains no useable M_COVR, CATCOV=1 features: "));
3131 msg.Append(m_TempFilePath);
3136 m_nNoCOVREntries = noCovrCntArray.size();
3138 if (m_nNoCOVREntries) {
3140 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3141 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3143 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3144 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3145 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3148 m_pNoCOVRTablePoints = NULL;
3149 m_pNoCOVRTable = NULL;
3152 delete pAuxPtrArray;
3153 delete pNoCovrPtrArray;
3155 if (0 == m_nCOVREntries) {
3156 wxString msg(_T(
" ENC contains no M_COVR features: "));
3157 msg.Append(m_TempFilePath);
3160 msg = _T(
" Calculating Chart Extents as fallback.");
3166 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3168 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3175 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3176 *m_pCOVRTablePoints = 4;
3177 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3178 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3195 wxString msg(_T(
" Cannot calculate Extents for ENC: "));
3196 msg.Append(m_TempFilePath);
3204 m_FullExtent.NLAT = LatMax;
3205 m_FullExtent.SLAT = LatMin;
3206 m_FullExtent.ELON = LonMax;
3207 m_FullExtent.WLON = LonMin;
3208 m_bExtentSet =
true;
3211 m_Chart_Scale = GetENCScale();
3214 GetChartNameFromTXT(m_TempFilePath, nice_name);
3222bool s57chart::CreateHeaderDataFromoSENC(
void) {
3223 bool ret_val =
true;
3225 wxFFileInputStream fpx(m_SENCFileName);
3227 if (!::wxFileExists(m_SENCFileName)) {
3228 wxString msg(_T(
" Cannot open SENC file "));
3229 msg.Append(m_SENCFileName);
3236 if (senc.ingestHeader(m_SENCFileName)) {
3242 m_Chart_Scale = senc.getSENCReadScale();
3245 m_Name = senc.getReadName();
3248 m_ID = senc.getReadID();
3251 Extent &ext = senc.getReadExtent();
3253 m_FullExtent.ELON = ext.ELON;
3254 m_FullExtent.WLON = ext.WLON;
3255 m_FullExtent.NLAT = ext.NLAT;
3256 m_FullExtent.SLAT = ext.SLAT;
3257 m_bExtentSet =
true;
3260 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3261 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3263 m_nCOVREntries = AuxCntArray.size();
3265 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3266 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3268 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3269 m_pCOVRTablePoints[j] = AuxCntArray[j];
3270 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3271 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3272 AuxCntArray[j] * 2 *
sizeof(
float));
3276 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3277 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3279 m_nNoCOVREntries = NoCovrCntArray.size();
3281 if (m_nNoCOVREntries) {
3283 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3284 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3286 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3287 int npoints = NoCovrCntArray[j];
3288 m_pNoCOVRTablePoints[j] = npoints;
3289 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3290 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3291 npoints * 2 *
sizeof(
float));
3297 m_datum_str = _T(
"WGS84");
3298 m_SoundingsDatum = _T(
"MEAN LOWER LOW WATER");
3300 int senc_file_version = senc.getSencReadVersion();
3302 int last_update = senc.getSENCReadLastUpdate();
3304 wxString str = senc.getSENCFileCreateDate();
3305 wxDateTime SENCCreateDate;
3306 SENCCreateDate.ParseFormat(str, _T(
"%Y%m%d"));
3308 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3310 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3317bool s57chart::CreateHeaderDataFromSENC(
void) {
3318 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3326bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3328 if (NULL != m_pvaldco_array) {
3329 for (i = 0; i < m_nvaldco; i++) {
3330 if (m_pvaldco_array[i] >= safe_cnt)
break;
3334 next_safe_cnt = m_pvaldco_array[i];
3336 next_safe_cnt = (double)1e6;
3339 next_safe_cnt = (double)1e6;
3353std::list<S57Obj*> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3357 std::list<S57Obj*> *pobj_list =
new std::list<S57Obj*>();
3360 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3361 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3364 switch (obj->Primitive_type) {
3377 top = razRules[disPrioIdx][3];
3378 while (top != NULL) {
3379 if (top->obj->bIsAssociable) {
3380 if (top->obj->BBObj.Contains(lat, lon)) {
3381 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3382 pobj_list->push_back(top->obj);
3389 ObjRazRules *nxx = top->next;
3394 top = razRules[disPrioIdx][4];
3395 while (top != NULL) {
3396 if (top->obj->bIsAssociable) {
3397 if (top->obj->BBObj.Contains(lat, lon)) {
3398 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3399 pobj_list->push_back(top->obj);
3405 ObjRazRules *nxx = top->next;
3419void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3420 wxFileName fn(FullPath);
3422 wxString target_name = fn.GetName();
3423 target_name.RemoveLast();
3425 wxString dir_name = fn.GetPath();
3427 wxDir dir(dir_name);
3429 wxArrayString FileList;
3431 dir.GetAllFiles(fn.GetPath(), &FileList);
3435 bool found_name =
false;
3439 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3440 wxFileName file(FileList[j]);
3441 if (((file.GetExt()).MakeUpper()) == _T(
"TXT")) {
3443 wxTextFile text_file(file.GetFullPath());
3445 bool file_ok =
true;
3449 if (!text_file.Open()) {
3450 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3455 wxString str = text_file.GetFirstLine();
3456 while (!text_file.Eof()) {
3457 if (0 == target_name.CmpNoCase(
3458 str.Mid(0, target_name.Len()))) {
3459 wxString tname = str.AfterFirst(
'-');
3460 name = tname.AfterFirst(
' ');
3464 str = text_file.GetNextLine();
3468 wxString msg(_T(
" Error Reading ENC .TXT file: "));
3469 msg.Append(file.GetFullPath());
3475 if (found_name)
break;
3492const char *s57chart::getName(OGRFeature *feature) {
3493 return feature->GetDefnRef()->GetName();
3496static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3497 wxFileName fn1(first);
3498 wxFileName fn2(second);
3499 wxString ext1(fn1.GetExt());
3500 wxString ext2(fn2.GetExt());
3502 return ext1.Cmp(ext2);
3505int s57chart::GetUpdateFileArray(
const wxFileName file000,
3506 wxArrayString *UpFiles, wxDateTime date000,
3508 wxString DirName000 =
3509 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3510 wxDir dir(DirName000);
3511 if (!dir.IsOpened()) {
3512 DirName000.Prepend(wxFileName::GetPathSeparator());
3513 DirName000.Prepend(_T(
"."));
3514 dir.Open(DirName000);
3515 if (!dir.IsOpened()) {
3520 int flags = wxDIR_DEFAULT;
3527 wxFileName fnDir(DirName000);
3528 fnDir.RemoveLastDir();
3529 wxString sdir = fnDir.GetPath();
3530 wxFileName fnTest(sdir);
3531 wxString sname = fnTest.GetName();
3533 if (sname.ToLong(&tmps)) {
3536 flags |= wxDIR_DIRS;
3540 wxArrayString *dummy_array;
3543 if (UpFiles == NULL)
3544 dummy_array =
new wxArrayString;
3546 dummy_array = UpFiles;
3548 wxArrayString possibleFiles;
3549 wxDir::GetAllFiles(DirName000, &possibleFiles, wxEmptyString, flags);
3551 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3552 wxString filename(possibleFiles[i]);
3554 wxFileName file(filename);
3555 ext = file.GetExt();
3560 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3561 wxString FileToAdd = filename;
3563 wxCharBuffer buffer =
3566 if (buffer.data() && !filename.IsSameAs(_T(
"CATALOG.031"),
3578 DDFModule *poModule =
new DDFModule();
3579 if (!poModule->Open(FileToAdd.mb_str())) {
3581 _T(
" s57chart::BuildS57File Unable to open update file "));
3582 msg.Append(FileToAdd);
3591 DDFRecord *pr = poModule->ReadRecord();
3597 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3600 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3604 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3605 _T(
"DSID:ISDT in update file "));
3606 msg.Append(FileToAdd);
3609 sumdate = _T(
"20000101");
3612 umdate.ParseFormat(sumdate, _T(
"%Y%m%d"));
3613 if (!umdate.IsValid())
3614 umdate.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
3617 if (!umdate.IsValid())
3623 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3625 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3629 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3630 _T(
"DSID:EDTN in update file "));
3631 msg.Append(FileToAdd);
3640 if ((!umdate.IsEarlierThan(date000)) &&
3641 (umedtn.IsSameAs(edtn000)))
3642 dummy_array->Add(FileToAdd);
3648 dummy_array->Sort(ExtensionCompare);
3651 if (dummy_array->GetCount()) {
3652 wxString Last = dummy_array->Last();
3653 wxFileName fnl(Last);
3655 wxCharBuffer buffer = ext.ToUTF8();
3656 if (buffer.data()) retval = atoi(buffer.data());
3659 if (UpFiles == NULL)
delete dummy_array;
3664int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3665 const wxString CopyDir,
3666 wxString &LastUpdateDate,
3672 wxArrayString *UpFiles =
new wxArrayString;
3673 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3675 if (UpFiles->GetCount()) {
3689 bool chain_broken_mssage_shown =
false;
3695 for (
int iff = 0; iff < retval + 1; iff++) {
3696 wxFileName ufile(m_TempFilePath);
3698 sext.Printf(_T(
"%03d"), iff);
3702 wxString cp_ufile = CopyDir;
3703 if (cp_ufile.Last() != ufile.GetPathSeparator())
3704 cp_ufile.Append(ufile.GetPathSeparator());
3706 cp_ufile.Append(ufile.GetFullName());
3711 if (ufile.FileExists()) {
3712 wxFile uf(ufile.GetFullPath());
3713 if (uf.IsOpened()) {
3719 if (ufile.FileExists() &&
3723 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3725 wxString msg(_T(
" Cannot copy temporary working ENC file "));
3726 msg.Append(ufile.GetFullPath());
3727 msg.Append(_T(
" to "));
3728 msg.Append(cp_ufile);
3738 if (!chain_broken_mssage_shown) {
3741 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3742 "incomplete or inaccurate.\nCheck the logfile for details."),
3743 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3745 chain_broken_mssage_shown =
true;
3749 _T(
"WARNING---ENC Update chain incomplete. Substituting NULL ")
3750 _T(
"update file: "));
3751 msg += ufile.GetFullName();
3753 wxLogMessage(_T(
" Subsequent ENC updates may produce errors."));
3755 _T(
" This ENC exchange set should be updated and SENCs ")
3759 DDFModule *dupdate =
new DDFModule;
3760 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3761 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3765 wxString msg(_T(
" Error creating dummy update file: "));
3766 msg.Append(cp_ufile);
3771 m_tmpup_array->Add(cp_ufile);
3778 wxFileName lastfile(m_TempFilePath);
3780 last_sext.Printf(_T(
"%03d"), retval);
3781 lastfile.SetExt(last_sext);
3784 DDFModule oUpdateModule;
3789 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3793 oUpdateModule.Rewind();
3794 DDFRecord *pr = oUpdateModule.ReadRecord();
3800 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3804 LastUpdateDate = wxString(u, wxConvUTF8);
3807 wxDateTime now = wxDateTime::Now();
3808 LastUpdateDate = now.Format(_T(
"%Y%m%d"));
3817wxString s57chart::GetISDT(
void) {
3818 if (m_date000.IsValid())
3819 return m_date000.Format(_T(
"%Y%m%d"));
3821 return _T(
"Unknown");
3824bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3825 if (!wxFileName::FileExists(file000))
return false;
3827 wxString FullPath000 = file000;
3828 DDFModule *poModule =
new DDFModule();
3829 if (!poModule->Open(FullPath000.mb_str())) {
3830 wxString msg(_T(
" s57chart::BuildS57File Unable to open "));
3831 msg.Append(FullPath000);
3843 DDFRecord *pr = poModule->ReadRecord();
3847 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3848 if (!m_nGeoRecords) {
3850 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3860 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3862 date000 = wxString(u, wxConvUTF8);
3865 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3872 m_date000.ParseFormat(date000, _T(
"%Y%m%d"));
3873 if (!m_date000.IsValid()) m_date000.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
3875 m_date000.ResetTime();
3878 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3880 m_edtn000 = wxString(u, wxConvUTF8);
3883 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3887 m_edtn000 = _T(
"1");
3894 for (; pr != NULL; pr = poModule->ReadRecord()) {
3895 if (pr->FindField(
"DSPM") != NULL) {
3896 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
3900 if (!m_native_scale) {
3901 wxString msg(_T(
" s57chart::BuildS57File ENC not contain DSPM:CSCL "));
3904 m_native_scale = 1000;
3912int s57chart::BuildSENCFile(
const wxString &FullPath000,
3913 const wxString &SENCFileName,
bool b_progress) {
3915 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
3916 double meters_per_pixel_max_scale =
3917 GetNormalScaleMin(0, g_b_overzoom_x) / display_pix_per_meter;
3918 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
3921 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
3922 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
3924 if (!m_disableBackgroundSENC) {
3925 if (g_SencThreadManager) {
3927 ticket->m_LOD_meters = m_LOD_meters;
3928 ticket->ref_lat = ref_lat;
3929 ticket->ref_lon = ref_lon;
3930 ticket->m_FullPath000 = FullPath000;
3931 ticket->m_SENCFileName = SENCFileName;
3932 ticket->m_chart =
this;
3934 m_SENCthreadStatus = g_SencThreadManager->ScheduleJob(ticket);
3935 bReadyToRender =
true;
3936 return BUILD_SENC_PENDING;
3939 return BUILD_SENC_NOK_RETRY;
3944 senc.setRegistrar(g_poRegistrar);
3945 senc.setRefLocn(ref_lat, ref_lon);
3946 senc.SetLODMeters(m_LOD_meters);
3948 OCPNPlatform::ShowBusySpinner();
3950 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
3952 OCPNPlatform::HideBusySpinner();
3954 if (ret == ERROR_INGESTING000)
3955 return BUILD_SENC_NOK_PERMANENT;
3961int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
3968 S57ObjVector Objects;
3969 VE_ElementVector VEs;
3970 VC_ElementVector VCs;
3972 sencfile.setRefLocn(ref_lat, ref_lon);
3974 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
3976 if (srv != SENC_NO_ERROR) {
3977 wxLogMessage(sencfile.getLastError());
3983 Extent ext = sencfile.getReadExtent();
3985 m_FullExtent.ELON = ext.ELON;
3986 m_FullExtent.WLON = ext.WLON;
3987 m_FullExtent.NLAT = ext.NLAT;
3988 m_FullExtent.SLAT = ext.SLAT;
3989 m_bExtentSet =
true;
3991 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
3992 ref_lon = (ext.ELON + ext.WLON) / 2.;
3997 int n_ve_elements = VEs.size();
3999 double scale = gFrame->GetBestVPScale(
this);
4000 int nativescale = GetNativeScale();
4002 for (
int i = 0; i < n_ve_elements; i++) {
4003 VE_Element *vep = VEs.at(i);
4004 if (vep && vep->nCount) {
4006 double east_max = -1e7;
4007 double east_min = 1e7;
4008 double north_max = -1e7;
4009 double north_min = 1e7;
4011 float *vrun = vep->pPoints;
4012 for (
size_t i = 0; i < vep->nCount; i++) {
4013 east_max = wxMax(east_max, *vrun);
4014 east_min = wxMin(east_min, *vrun);
4017 north_max = wxMax(north_max, *vrun);
4018 north_min = wxMin(north_min, *vrun);
4022 double lat1, lon1, lat2, lon2;
4023 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4024 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4025 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4028 m_ve_hash[vep->index] = vep;
4032 int n_vc_elements = VCs.size();
4034 for (
int i = 0; i < n_vc_elements; i++) {
4035 VC_Element *vcp = VCs.at(i);
4036 m_vc_hash[vcp->index] = vcp;
4044 for (
unsigned int i = 0; i < Objects.size(); i++) {
4045 S57Obj *obj = Objects[i];
4049 LUPname LUP_Name = PAPER_CHART;
4051 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4052 if (objnam.Len() > 0) {
4053 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4054 g_pi_manager->SendVectorChartObjectInfo(FullPath, fe_name, objnam,
4055 obj->m_lat, obj->m_lon,
scale,
4060 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4061 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4062 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4063 g_pi_manager->SendVectorChartObjectInfo(FullPath, fe_name, nobjnam,
4064 obj->m_lat, obj->m_lon,
scale,
4068 switch (obj->Primitive_type) {
4073 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4074 LUP_Name = PAPER_CHART;
4076 LUP_Name = SIMPLIFIED;
4085 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4086 LUP_Name = PLAIN_BOUNDARIES;
4088 LUP_Name = SYMBOLIZED_BOUNDARIES;
4093 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4097 wxString msg(obj->FeatureName, wxConvUTF8);
4098 msg.Prepend(_T(
" Could not find LUP for "));
4099 LogMessageOnce(msg);
4106 ps52plib->_LUP2rules(LUP, obj);
4109 _insertRules(obj, LUP,
this);
4112 obj->m_DisplayCat = LUP->DISC;
4115 obj->m_DPRI = LUP->DPRI -
'0';
4118 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4119 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4120 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4121 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4122 obj->m_bcategory_mutable =
true;
4124 obj->m_bcategory_mutable =
false;
4129 if (obj && (GEO_POINT == obj->Primitive_type)) {
4131 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4132 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4133 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4134 pFloatingATONArray->Add(obj);
4138 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4139 pRigidATONArray->Add(obj);
4143 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4144 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4145 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4146 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4147 obj->bIsAton =
true;
4156 d000.ParseFormat(sencfile.getBaseDate(), _T(
"%Y%m%d"));
4157 if (!d000.IsValid()) d000.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4160 updt.ParseFormat(sencfile.getUpdateDate(), _T(
"%Y%m%d"));
4161 if (!updt.IsValid()) updt.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4163 if (updt.IsLaterThan(d000))
4164 m_PubYear.Printf(_T(
"%4d"), updt.GetYear());
4166 m_PubYear.Printf(_T(
"%4d"), d000.GetYear());
4169 wxDateTime upd = updt;
4170 if (!upd.IsValid()) upd.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4175 m_SE = sencfile.getSENCReadBaseEdition();
4178 supdate.Printf(_T(
" / %d"), sencfile.getSENCReadLastUpdate());
4181 m_datum_str = _T(
"WGS84");
4183 m_SoundingsDatum = _T(
"MEAN LOWER LOW WATER");
4184 m_ID = sencfile.getReadID();
4185 m_Name = sencfile.getReadName();
4189 AssembleLineGeometry();
4192 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
4193 m_this_chart_context->chart =
this;
4194 m_this_chart_context->chart_type = GetChartType();
4195 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
4196 m_this_chart_context->chart_scale = GetNativeScale();
4199 for (
int i = 0; i < PRIO_NUM; ++i) {
4200 for (
int j = 0; j < LUPNAME_NUM; j++) {
4201 top = razRules[i][j];
4202 while (top != NULL) {
4203 S57Obj *obj = top->obj;
4204 obj->m_chart_context = m_this_chart_context;
4213int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4214 ObjRazRules *rzRules = NULL;
4224 switch (LUP->DPRI) {
4237 case PRIO_SYMB_POINT:
4240 case PRIO_SYMB_LINE:
4243 case PRIO_SYMB_AREA:
4256 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4260 switch (LUP->TNAM) {
4270 case PLAIN_BOUNDARIES:
4273 case SYMBOLIZED_BOUNDARIES:
4277 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4281 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4285 rzRules->child = NULL;
4286 rzRules->mps = NULL;
4289 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4290 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4295 ObjRazRules *rNext = NULL;
4296 ObjRazRules *rPrevious = NULL;
4297 if (razRules[disPrioIdx][LUPtypeIdx]) {
4298 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4299 rNext = rPrevious->next;
4303 rNext = rPrevious->next;
4306 rzRules->next = NULL;
4308 rPrevious->next = rzRules;
4310 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4317void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4322 if (vp_last.view_scale_ppm == 1.0)
4325 double d = vp_last.view_scale_ppm / vp_this.view_scale_ppm;
4327 for (
int i = 0; i < PRIO_NUM; ++i) {
4328 for (
int j = 0; j < 2; ++j) {
4329 top = razRules[i][j];
4331 while (top != NULL) {
4332 if (!top->obj->geoPtMulti)
4334 if (top->obj->BBObj.GetValid()) {
4335 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4337 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4338 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4340 double minlon = top->obj->BBObj.GetMinLon();
4341 double maxlon = top->obj->BBObj.GetMaxLon();
4343 double lon1 = (lon - minlon) * d;
4344 double lon2 = (lon - maxlon) * d;
4346 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4349 top->obj->BBObj.Invalidate();
4370void s57chart::UpdateLUPs(
s57chart *pOwner) {
4374 for (
int i = 0; i < PRIO_NUM; ++i) {
4376 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4377 m_b2pointLUPS =
true;
4378 top = razRules[i][0];
4380 while (top != NULL) {
4381 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4387 if (top->obj->nRef < 2) {
4388 ps52plib->_LUP2rules(LUP, top->obj);
4389 _insertRules(top->obj, LUP, pOwner);
4390 top->obj->m_DisplayCat = LUP->DISC;
4400 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4401 m_b2pointLUPS =
true;
4402 top = razRules[i][1];
4404 while (top != NULL) {
4405 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4408 if (top->obj->nRef < 2) {
4409 ps52plib->_LUP2rules(LUP, top->obj);
4410 _insertRules(top->obj, LUP, pOwner);
4411 top->obj->m_DisplayCat = LUP->DISC;
4421 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4422 m_b2lineLUPS =
true;
4423 top = razRules[i][3];
4425 while (top != NULL) {
4426 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4427 top->obj->FeatureName, top->obj);
4429 ps52plib->_LUP2rules(LUP, top->obj);
4430 _insertRules(top->obj, LUP, pOwner);
4431 top->obj->m_DisplayCat = LUP->DISC;
4440 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4441 m_b2lineLUPS =
true;
4442 top = razRules[i][4];
4444 while (top != NULL) {
4445 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4448 ps52plib->_LUP2rules(LUP, top->obj);
4449 _insertRules(top->obj, LUP, pOwner);
4450 top->obj->m_DisplayCat = LUP->DISC;
4462 for (
int j = 0; j < LUPNAME_NUM; j++) {
4463 top = razRules[i][j];
4464 while (top != NULL) {
4465 top->obj->bCS_Added = 0;
4468 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4479 for (
int j = 0; j < LUPNAME_NUM; j++) {
4480 top = razRules[i][j];
4481 while (top != NULL) {
4483 ObjRazRules *ctop = top->child;
4484 while (NULL != ctop) {
4485 ctop->obj->bCS_Added = 0;
4486 free_mps(ctop->mps);
4489 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4506ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4507 float lat,
float lon,
ViewPort *VPoint) {
4508 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4509 std::vector<ObjRazRules *> selected_rules;
4514 char *curr_att = NULL;
4516 wxArrayOfS57attVal *attValArray = NULL;
4517 bool bleading_attribute =
false;
4519 for (
int i = 0; i < PRIO_NUM; ++i) {
4523 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4524 top = razRules[i][point_type];
4526 while (top != NULL) {
4527 if (top->obj->npt == 1) {
4528 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4530 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4532 if (ps52plib->ObjectRenderCheckCat(top)) {
4535 wxString curAttrName;
4536 curr_att = top->obj->att_array;
4537 n_attr = top->obj->n_attr;
4538 attValArray = top->obj->attVal;
4546 bleading_attribute =
false;
4548 while (attrCounter < n_attr) {
4549 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4552 S57attVal *pAttrVal = NULL;
4555 pAttrVal = attValArray->Item(attrCounter);
4559 wxString value = s57chart::GetAttributeValueAsString(
4560 pAttrVal, curAttrName);
4562 if (curAttrName == _T(
"LITVIS")) {
4563 if (value.StartsWith(_T(
"obsc"))) bviz =
false;
4564 }
else if (curAttrName == _T(
"VALNMR"))
4565 value.ToDouble(&valnmr);
4571 if (bviz && (valnmr > 0.1)) {
4575 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4576 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4577 ref_lat, ref_lon, &olat, &olon);
4579 double dlat = lat - olat;
4580 double dy = dlat * 60 / cos(olat * PI / 180.);
4581 double dlon = lon - olon;
4582 double dx = dlon * 60;
4583 double manhat = abs(dy) + abs(dx);
4587 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4589 selected_rules.push_back(top);
4605 for(std::size_t i = 0; i < selected_rules.size(); ++i) {
4606 ret_ptr->Append(selected_rules[i]);
4612ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4613 float select_radius,
4615 int selection_mask) {
4617 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4618 std::vector<ObjRazRules *> selected_rules;
4624 for (
int i = 0; i < PRIO_NUM; ++i) {
4625 if (selection_mask & MASK_POINT) {
4628 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4629 top = razRules[i][point_type];
4631 while (top != NULL) {
4632 if (top->obj->npt ==
4635 if (ps52plib->ObjectRenderCheck(top)) {
4636 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4637 selected_rules.push_back(top);
4646 ObjRazRules *child_item = top->child;
4647 while (child_item != NULL) {
4648 if (ps52plib->ObjectRenderCheck(child_item)) {
4649 if (DoesLatLonSelectObject(lat, lon, select_radius,
4651 selected_rules.push_back(child_item);
4654 child_item = child_item->next;
4662 if (selection_mask & MASK_AREA) {
4665 int area_boundary_type =
4666 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4667 top = razRules[i][area_boundary_type];
4668 while (top != NULL) {
4669 if (ps52plib->ObjectRenderCheck(top)) {
4670 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4671 selected_rules.push_back(top);
4678 if (selection_mask & MASK_LINE) {
4680 top = razRules[i][2];
4682 while (top != NULL) {
4683 if (ps52plib->ObjectRenderCheck(top)) {
4684 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4685 selected_rules.push_back(top);
4696 auto sortObjs = [lat, lon,
this] (
const ObjRazRules* obj1,
const ObjRazRules* obj2) ->
bool
4698 double br1, dd1, br2, dd2;
4700 if(obj1->obj->Primitive_type == GEO_POINT && obj2->obj->Primitive_type == GEO_POINT){
4701 double lat1, lat2, lon1, lon2;
4702 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4703 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin,
4704 ref_lat, ref_lon, &lat1, &lon1);
4706 if (lon1 > 180.0) lon1 -= 360.;
4708 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4709 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin,
4710 ref_lat, ref_lon, &lat2, &lon2);
4712 if (lon2 > 180.0) lon2 -= 360.;
4714 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4715 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4723 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4726 for(std::size_t i = 0; i < selected_rules.size(); ++i) {
4727 ret_ptr->Append(selected_rules[i]);
4733bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4735 switch (obj->Primitive_type) {
4739 if (!obj->BBObj.GetValid())
return false;
4741 if (1 == obj->npt) {
4746 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4748 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4751 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4752 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4759 sbox.Set(olat, olon, olat, olon);
4761 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4762 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4767 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4774 if (!obj->BBObj.GetValid())
return false;
4777 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4779 double *pdl = obj->geoPtMulti;
4780 for (
int ip = 0; ip < obj->npt; ip++) {
4781 double lon_point = *pdl++;
4782 double lat_point = *pdl++;
4784 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4785 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4796 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4799 return IsPointInObjArea(lat, lon, select_radius, obj);
4804 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4806 float sel_rad_meters = select_radius * 1852 * 60;
4807 double easting, northing;
4808 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4815 pt *ppt = obj->geoPt;
4818 double xr = obj->x_rate;
4819 double xo = obj->x_origin;
4820 double yr = obj->y_rate;
4821 double yo = obj->y_origin;
4823 double north0 = (ppt->y * yr) + yo;
4824 double east0 = (ppt->x * xr) + xo;
4827 for (
int ip = 1; ip < npt; ip++) {
4828 double north = (ppt->y * yr) + yo;
4829 double east = (ppt->x * xr) + xo;
4832 if (northing >= (fmin(north, north0) - sel_rad_meters))
4833 if (northing <= (fmax(north, north0) + sel_rad_meters))
4834 if (easting >= (fmin(east, east0) - sel_rad_meters))
4835 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4845 if (obj->m_ls_list) {
4847 unsigned char *vbo_point =
4849 obj->m_chart_context->vertex_buffer;
4850 line_segment_element *ls = obj->m_ls_list;
4852 while (ls && vbo_point) {
4854 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4855 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4856 nPoints = ls->pedge->nCount;
4858 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4862 float north0 = ppt[1];
4863 float east0 = ppt[0];
4867 for (
int ip = 0; ip < nPoints - 1; ip++) {
4868 float north = ppt[1];
4869 float east = ppt[0];
4871 if (northing >= (fmin(north, north0) - sel_rad_meters))
4872 if (northing <= (fmax(north, north0) + sel_rad_meters))
4873 if (easting >= (fmin(east, east0) - sel_rad_meters))
4874 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4901wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
4902 wxString ret_val = _T(
"");
4905 const char *att_code;
4907 wxString file(g_csv_locn);
4908 file.Append(_T(
"/s57attributes.csv"));
4910 if (!wxFileName::FileExists(file)) {
4911 wxString msg(_T(
" Could not open "));
4918 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
4920 CC_ExactString,
"Code");
4926 wxString ei_file(g_csv_locn);
4927 ei_file.Append(_T(
"/s57expectedinput.csv"));
4929 if (!wxFileName::FileExists(ei_file)) {
4930 wxString msg(_T(
" Could not open "));
4931 msg.Append(ei_file);
4937 CSVTable *psTable = CSVAccess(ei_file.mb_str());
4938 CSVIngest(ei_file.mb_str());
4940 char **papszFields = NULL;
4941 int bSelected = FALSE;
4947 while (!bSelected && iline + 1 < psTable->nLineCount) {
4949 papszFields = CSVSplitLine(psTable->papszLines[iline]);
4951 if (!strcmp(papszFields[0], att_code)) {
4952 if (atoi(papszFields[1]) == ival) {
4953 ret_val = wxString(papszFields[2], wxConvUTF8);
4958 CSLDestroy(papszFields);
4966bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
4970 if (obj->pPolyTessGeo) {
4971 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
4973 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
4975 TriPrim *pTP = ppg->tri_prim_head;
4977 MyPoint pvert_list[3];
4981 double easting, northing;
4982 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4986 if (!ppg->m_bSMSENC) {
4987 double y_rate = obj->y_rate;
4988 double y_origin = obj->y_origin;
4989 double x_rate = obj->x_rate;
4990 double x_origin = obj->x_origin;
4992 double northing_scaled = (northing - y_origin) / y_rate;
4993 double easting_scaled = (easting - x_origin) / x_rate;
4994 northing = northing_scaled;
4995 easting = easting_scaled;
5000 if (pTP->tri_box.Contains(lat, lon)) {
5001 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5002 double *p_vertex = pTP->p_vertex;
5004 switch (pTP->type) {
5005 case PTG_TRIANGLE_FAN: {
5006 for (
int it = 0; it < pTP->nVert - 2; it++) {
5007 pvert_list[0].x = p_vertex[0];
5008 pvert_list[0].y = p_vertex[1];
5010 pvert_list[1].x = p_vertex[(it * 2) + 2];
5011 pvert_list[1].y = p_vertex[(it * 2) + 3];
5013 pvert_list[2].x = p_vertex[(it * 2) + 4];
5014 pvert_list[2].y = p_vertex[(it * 2) + 5];
5016 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5024 case PTG_TRIANGLE_STRIP: {
5025 for (
int it = 0; it < pTP->nVert - 2; it++) {
5026 pvert_list[0].x = p_vertex[(it * 2)];
5027 pvert_list[0].y = p_vertex[(it * 2) + 1];
5029 pvert_list[1].x = p_vertex[(it * 2) + 2];
5030 pvert_list[1].y = p_vertex[(it * 2) + 3];
5032 pvert_list[2].x = p_vertex[(it * 2) + 4];
5033 pvert_list[2].y = p_vertex[(it * 2) + 5];
5035 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5043 case PTG_TRIANGLES: {
5044 for (
int it = 0; it < pTP->nVert; it += 3) {
5045 pvert_list[0].x = p_vertex[(it * 2)];
5046 pvert_list[0].y = p_vertex[(it * 2) + 1];
5048 pvert_list[1].x = p_vertex[(it * 2) + 2];
5049 pvert_list[1].y = p_vertex[(it * 2) + 3];
5051 pvert_list[2].x = p_vertex[(it * 2) + 4];
5052 pvert_list[2].y = p_vertex[(it * 2) + 5];
5054 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5063 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5064 float *p_vertex = (
float *)pTP->p_vertex;
5066 switch (pTP->type) {
5067 case PTG_TRIANGLE_FAN: {
5068 for (
int it = 0; it < pTP->nVert - 2; it++) {
5069 pvert_list[0].x = p_vertex[0];
5070 pvert_list[0].y = p_vertex[1];
5072 pvert_list[1].x = p_vertex[(it * 2) + 2];
5073 pvert_list[1].y = p_vertex[(it * 2) + 3];
5075 pvert_list[2].x = p_vertex[(it * 2) + 4];
5076 pvert_list[2].y = p_vertex[(it * 2) + 5];
5078 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5086 case PTG_TRIANGLE_STRIP: {
5087 for (
int it = 0; it < pTP->nVert - 2; it++) {
5088 pvert_list[0].x = p_vertex[(it * 2)];
5089 pvert_list[0].y = p_vertex[(it * 2) + 1];
5091 pvert_list[1].x = p_vertex[(it * 2) + 2];
5092 pvert_list[1].y = p_vertex[(it * 2) + 3];
5094 pvert_list[2].x = p_vertex[(it * 2) + 4];
5095 pvert_list[2].y = p_vertex[(it * 2) + 5];
5097 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5105 case PTG_TRIANGLES: {
5106 for (
int it = 0; it < pTP->nVert; it += 3) {
5107 pvert_list[0].x = p_vertex[(it * 2)];
5108 pvert_list[0].y = p_vertex[(it * 2) + 1];
5110 pvert_list[1].x = p_vertex[(it * 2) + 2];
5111 pvert_list[1].y = p_vertex[(it * 2) + 3];
5113 pvert_list[2].x = p_vertex[(it * 2) + 4];
5114 pvert_list[2].y = p_vertex[(it * 2) + 5];
5116 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5139wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5140 wxString curAttrName) {
5144 pval = obj->attVal->Item(iatt);
5145 switch (pval->valType) {
5148 wxString val_str((
char *)(pval->value), wxConvUTF8);
5150 if (val_str.ToLong(&ival)) {
5152 value = _T(
"Unknown");
5154 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5155 if (!decode_val.IsEmpty()) {
5158 iv.Printf(_T(
" (%d)"), (
int)ival);
5161 value.Printf(_T(
"%d"), (
int)ival);
5165 else if (val_str.IsEmpty())
5166 value = _T(
"Unknown");
5170 wxString value_increment;
5171 wxStringTokenizer tk(val_str, wxT(
","));
5173 if (tk.HasMoreTokens()) {
5174 while (tk.HasMoreTokens()) {
5175 wxString token = tk.GetNextToken();
5177 if (token.ToLong(&ival)) {
5178 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5180 value_increment.Printf(_T(
" (%d)"), (
int)ival);
5182 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5184 if (iv) value_increment.Prepend(wxT(
", "));
5185 value.Append(value_increment);
5188 if (iv) value.Append(_T(
","));
5189 value.Append(token);
5195 value.Append(val_str);
5198 value = _T(
"[NULL VALUE]");
5204 int ival = *((
int *)pval->value);
5205 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5207 if (!decode_val.IsEmpty()) {
5210 iv.Printf(_T(
"(%d)"), ival);
5213 value.Printf(_T(
"(%d)"), ival);
5221 double dval = *((
double *)pval->value);
5222 wxString val_suffix = _T(
" m");
5225 if ((curAttrName == _T(
"VERCLR")) || (curAttrName == _T(
"VERCCL")) ||
5226 (curAttrName == _T(
"VERCOP")) || (curAttrName == _T(
"HEIGHT")) ||
5227 (curAttrName == _T(
"HORCLR"))) {
5228 switch (ps52plib->m_nDepthUnitDisplay) {
5231 dval = dval * 3 * 39.37 / 36;
5232 val_suffix = _T(
" ft");
5239 else if ((curAttrName == _T(
"VALSOU")) || (curAttrName == _T(
"DRVAL1")) ||
5240 (curAttrName == _T(
"DRVAL2")) || (curAttrName == _T(
"VALDCO"))) {
5241 switch (ps52plib->m_nDepthUnitDisplay) {
5243 dval = dval * 3 * 39.37 / 36;
5244 val_suffix = _T(
" ft");
5247 dval = dval * 3 * 39.37 / 36;
5249 val_suffix = _T(
" fathoms");
5256 else if (curAttrName == _T(
"SECTR1"))
5257 val_suffix = _T(
"°");
5258 else if (curAttrName == _T(
"SECTR2"))
5259 val_suffix = _T(
"°");
5260 else if (curAttrName == _T(
"ORIENT"))
5261 val_suffix = _T(
"°");
5262 else if (curAttrName == _T(
"VALNMR"))
5263 val_suffix = _T(
" Nm");
5264 else if (curAttrName == _T(
"SIGPER"))
5265 val_suffix = _T(
"s");
5266 else if (curAttrName == _T(
"VALACM"))
5267 val_suffix = _T(
" Minutes/year");
5268 else if (curAttrName == _T(
"VALMAG"))
5269 val_suffix = _T(
"°");
5270 else if (curAttrName == _T(
"CURVEL"))
5271 val_suffix = _T(
" kt");
5273 if (dval - floor(dval) < 0.01)
5274 value.Printf(_T(
"%2.0f"), dval);
5276 value.Printf(_T(
"%4.1f"), dval);
5278 value << val_suffix;
5283 case OGR_REAL_LST: {
5290wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5291 wxString AttrName) {
5292 if (NULL == pAttrVal)
return _T(
"");
5295 switch (pAttrVal->valType) {
5297 if (pAttrVal->value) {
5298 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5300 if (val_str.ToLong(&ival)) {
5302 value = _T(
"Unknown");
5304 wxString decode_val = GetAttributeDecode(AttrName, ival);
5305 if (!decode_val.IsEmpty()) {
5308 iv.Printf(_T(
"(%d)"), (
int)ival);
5311 value.Printf(_T(
"%d"), (
int)ival);
5315 else if (val_str.IsEmpty())
5316 value = _T(
"Unknown");
5320 wxString value_increment;
5321 wxStringTokenizer tk(val_str, wxT(
","));
5323 while (tk.HasMoreTokens()) {
5324 wxString token = tk.GetNextToken();
5326 if (token.ToLong(&ival)) {
5327 wxString decode_val = GetAttributeDecode(AttrName, ival);
5328 if (!decode_val.IsEmpty())
5329 value_increment = decode_val;
5331 value_increment.Printf(_T(
" %d"), (
int)ival);
5333 if (iv) value_increment.Prepend(wxT(
", "));
5335 value.Append(value_increment);
5339 value.Append(val_str);
5342 value = _T(
"[NULL VALUE]");
5348 int ival = *((
int *)pAttrVal->value);
5349 wxString decode_val = GetAttributeDecode(AttrName, ival);
5351 if (!decode_val.IsEmpty()) {
5354 iv.Printf(_T(
"(%d)"), ival);
5357 value.Printf(_T(
"(%d)"), ival);
5365 double dval = *((
double *)pAttrVal->value);
5366 wxString val_suffix = _T(
" m");
5369 if ((AttrName == _T(
"VERCLR")) || (AttrName == _T(
"VERCCL")) ||
5370 (AttrName == _T(
"VERCOP")) || (AttrName == _T(
"HEIGHT")) ||
5371 (AttrName == _T(
"HORCLR"))) {
5372 switch (ps52plib->m_nDepthUnitDisplay) {
5375 dval = dval * 3 * 39.37 / 36;
5376 val_suffix = _T(
" ft");
5383 else if ((AttrName == _T(
"VALSOU")) || (AttrName == _T(
"DRVAL1")) ||
5384 (AttrName == _T(
"DRVAL2"))) {
5385 switch (ps52plib->m_nDepthUnitDisplay) {
5387 dval = dval * 3 * 39.37 / 36;
5388 val_suffix = _T(
" ft");
5391 dval = dval * 3 * 39.37 / 36;
5393 val_suffix = _T(
" fathoms");
5400 else if (AttrName == _T(
"SECTR1"))
5401 val_suffix = _T(
"°");
5402 else if (AttrName == _T(
"SECTR2"))
5403 val_suffix = _T(
"°");
5404 else if (AttrName == _T(
"ORIENT"))
5405 val_suffix = _T(
"°");
5406 else if (AttrName == _T(
"VALNMR"))
5407 val_suffix = _T(
" Nm");
5408 else if (AttrName == _T(
"SIGPER"))
5409 val_suffix = _T(
"s");
5410 else if (AttrName == _T(
"VALACM"))
5411 val_suffix = _T(
" Minutes/year");
5412 else if (AttrName == _T(
"VALMAG"))
5413 val_suffix = _T(
"°");
5414 else if (AttrName == _T(
"CURVEL"))
5415 val_suffix = _T(
" kt");
5417 if (dval - floor(dval) < 0.01)
5418 value.Printf(_T(
"%2.0f"), dval);
5420 value.Printf(_T(
"%4.1f"), dval);
5422 value << val_suffix;
5427 case OGR_REAL_LST: {
5435 int positionDiff = l1->position.Cmp(l2->position);
5436 if (positionDiff < 0)
return false;
5438 int attrIndex1 = l1->attributeNames.Index(_T(
"SECTR1"));
5439 int attrIndex2 = l2->attributeNames.Index(_T(
"SECTR1"));
5442 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5443 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5444 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5446 double angle1, angle2;
5447 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5448 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5450 return angle1 < angle2;
5453static const char *type2str(GeoPrim_t type) {
5454 const char *r =
"Unknown";
5475wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5478 wxString curAttrName, value;
5479 bool isLight =
false;
5482 wxString classAttributes;
5484 wxString lightsHtml;
5485 wxString positionString;
5486 std::vector<S57Light *> lights;
5490 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5491 node = node->GetPrevious()) {
5492 ObjRazRules *current = node->GetData();
5493 positionString.Clear();
5497 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5499 if (current->obj->Primitive_type == GEO_META)
continue;
5500 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5502 className = wxString(current->obj->FeatureName, wxConvUTF8);
5505 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5510 const char *name_desc;
5511 if (g_csv_locn.Len()) {
5512 wxString oc_file(g_csv_locn);
5513 oc_file.Append(_T(
"/s57objectclasses.csv"));
5514 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5515 current->obj->FeatureName,
5516 CC_ExactString,
"ObjectClass");
5522 if (0 == strlen(name_desc)) {
5523 name_desc = current->obj->FeatureName;
5524 classDesc = wxString(name_desc, wxConvUTF8, 1);
5525 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5527 classDesc = wxString(name_desc, wxConvUTF8);
5534 classAttributes = _T(
"");
5535 index.Printf(_T(
"Feature Index: %d<br>"), current->obj->Index);
5536 classAttributes << index;
5539 LUPstring.Printf(_T(
"LUP RCID: %d<br>"), current->LUP->RCID);
5540 classAttributes << LUPstring;
5543 LLBBox bbox = current->obj->BBObj;
5544 Bbox.Printf(_T(
"Lat/Lon box: %g %g %g %g<br>"), bbox.GetMinLat(),
5545 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5546 classAttributes << Bbox;
5549 Type.Printf(_T(
" Type: %s<br>"), type2str(current->obj->Primitive_type));
5550 classAttributes << Type;
5552 LUPstring = _T(
" LUP ATTC: ");
5553 if (current->LUP->ATTArray.size())
5554 LUPstring += wxString(current->LUP->ATTArray[0], wxConvUTF8);
5555 LUPstring += _T(
"<br>");
5556 classAttributes << LUPstring;
5558 LUPstring = _T(
" LUP INST: ");
5559 if (current->LUP->INST) LUPstring += *(current->LUP->INST);
5560 LUPstring += _T(
"<br><br>");
5561 classAttributes << LUPstring;
5564 if (GEO_POINT == current->obj->Primitive_type) {
5566 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5567 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5568 ref_lat, ref_lon, &lat, &lon);
5570 if (lon > 180.0) lon -= 360.;
5572 positionString.Clear();
5573 positionString += toSDMM(1, lat);
5574 positionString << _T(
" ");
5575 positionString += toSDMM(2, lon);
5579 curLight->position = positionString;
5580 curLight->hasSectors =
false;
5581 lights.push_back(curLight);
5587 if (current->obj->att_array) {
5588 char *curr_att = current->obj->att_array;
5594 attribStr << _T(
"<table border=0 cellspacing=0 cellpadding=0>");
5597 ret_val << _T(
"<p>") << classAttributes;
5600 bool inDepthRange =
false;
5602 while (attrCounter < current->obj->n_attr) {
5604 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5611 assert(curLight !=
nullptr);
5612 curLight->attributeNames.Add(curAttrName);
5613 if (curAttrName.StartsWith(_T(
"SECTR"))) curLight->hasSectors =
true;
5615 if (curAttrName == _T(
"DRVAL1")) {
5616 attribStr << _T(
"<tr><td><font size=-1>");
5617 inDepthRange =
true;
5618 }
else if (curAttrName == _T(
"DRVAL2")) {
5619 attribStr << _T(
" - ");
5620 inDepthRange =
false;
5623 attribStr << _T(
"</font></td></tr>\n");
5624 inDepthRange =
false;
5626 attribStr << _T(
"<tr><td valign=top><font size=-2>");
5627 if (curAttrName == _T(
"catgeo"))
5628 attribStr << _T(
"CATGEO");
5630 attribStr << curAttrName;
5631 attribStr << _T(
"</font></td><td> </td><td ")
5632 _T("valign=top><font size=-1>");
5643 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5648 wxString AttrNamesFiles =
5649 _T("PICREP,TXTDSC,NTXTDS");
5651 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5652 if (value.Find(_T(".XML")) == wxNOT_FOUND) {
5653 file.Assign(GetFullPath());
5654 file.Assign(file.GetPath(), value);
5659 wxString::Format(_T(
"<a href=\"%s\">%s</a>"),
5660 file.GetFullPath(), file.GetFullName());
5662 value = value + _T(
" <font color=\"red\">[ ") +
5663 _(
"this file is not available") + _T(
" ]</font>");
5667 _T(
"DATEND,DATSTA,PEREND,PERSTA");
5668 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5671 wxString ts = value;
5673 ts.Replace(wxT(
"--"),
5675 if (ts.Length() < 5) {
5680 if (ts.Length() < 7) {
5685 wxString::const_iterator end;
5687 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5689 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5690 if (d) ts.Append(wxString::Format(wxT(
" %d"), dt.GetDay()));
5691 if (dt.GetYear() > 0)
5692 ts.Append(wxString::Format(wxT(
", %i"), dt.GetYear()));
5693 if (curAttrName == _T(
"PEREND"))
5694 ts = _(
"Period ends: ") + ts + wxT(
" (") + value + wxT(
")");
5695 if (curAttrName == _T(
"PERSTA"))
5696 ts = _(
"Period starts: ") + ts + wxT(
" (") + value + wxT(
")");
5697 if (curAttrName == _T(
"DATEND"))
5698 ts = _(
"Date ending: ") + ts + wxT(
" (") + value + wxT(
")");
5699 if (curAttrName == _T(
"DATSTA"))
5700 ts = _(
"Date starting: ") + ts + wxT(
" (") + value + wxT(
")");
5704 if (curAttrName == _T(
"TS_TSP")) {
5707 wxStringTokenizer tk(value, wxT(
","));
5708 ts = tk.GetNextToken();
5710 ts1 = tk.GetNextToken();
5711 ts = _T(
"Tidal Streams referred to<br><b>");
5712 ts.Append(tk.GetNextToken()).Append(_T(
"</b> at <b>")).Append(ts1);
5713 ts.Append( _T(
"</b><br><table >"));
5715 while (tk.HasMoreTokens()) {
5716 ts.Append(_T(
"<tr><td>"));
5717 wxString s1; s1.Format(wxT(
"%i"), i);
5719 ts.Append(_T(
"</td><td>"));
5720 s1 = tk.GetNextToken();
5722 s1 =
"°</td><td>";
5724 s1 = tk.GetNextToken();
5726 ts.Append(_T(
"</td></tr>"));
5729 ts.Append(_T(
"</table>"));
5734 assert(curLight !=
nullptr);
5735 curLight->attributeValues.Add(value);
5737 if (curAttrName == _T(
"INFORM") || curAttrName == _T(
"NINFOM"))
5738 value.Replace(_T(
"|"), _T(
"<br>"));
5740 if (curAttrName == _T(
"catgeo"))
5741 attribStr << type2str(current->obj->Primitive_type);
5745 if (!(curAttrName == _T(
"DRVAL1"))) {
5746 attribStr << _T(
"</font></td></tr>\n");
5756 attribStr << _T(
"</table>\n");
5758 objText += _T(
"<b>") + classDesc + _T(
"</b> <font size=-2>(") +
5759 className + _T(
")</font>") + _T(
"<br>");
5761 if (positionString.Length())
5762 objText << _T(
"<font size=-2>") << positionString
5763 << _T(
"</font><br>\n");
5765 if (noAttr > 0) objText << attribStr;
5767 if (node != rule_list->GetFirst()) objText += _T(
"<hr noshade>");
5768 objText += _T(
"<br>");
5774 if (!lights.empty()) {
5775 assert(curLight !=
nullptr);
5780 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5784 for (
auto const &thisLight : lights) {
5787 if (thisLight->position != lastPos) {
5788 lastPos = thisLight->position;
5790 if (thisLight != *lights.begin())
5791 lightsHtml << _T(
"</table>\n<hr noshade>\n");
5793 lightsHtml << _T(
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>");
5794 lightsHtml << _T(
"<font size=-2>") << thisLight->position
5795 << _T(
"</font><br>\n");
5797 if (curLight->hasSectors)
5799 "<font size=-2>(Sector angles are True Bearings from "
5800 "Seaward)</font><br>");
5802 lightsHtml << _T(
"<table>");
5805 lightsHtml << _T(
"<tr>");
5806 lightsHtml << _T(
"<td><font size=-1>");
5809 attrIndex = thisLight->attributeNames.Index(_T(
"COLOUR"));
5810 if (attrIndex != wxNOT_FOUND) {
5811 wxString color = thisLight->attributeValues.Item(attrIndex);
5812 if (color == _T(
"red (3)"))
5814 _T(
"<table border=0><tr><td ")
5815 _T("bgcolor=red> </td></tr></table> ");
5816 else if (color == _T("green (4)"))
5818 _T("<table border=0><tr><td ")
5819 _T("bgcolor=green> </td></tr></table> ");
5820 else if (color == _T("white (1)"))
5822 _T("<table border=0><tr><td ")
5823 _T("bgcolor=white> </td></tr></table> ");
5824 else if (color == _T("yellow (6)"))
5826 _T("<table border=0><tr><td ")
5827 _T("bgcolor=yellow> </td></tr></table> ");
5828 else if (color == _T("blue (5)"))
5830 _T("<table border=0><tr><td ")
5831 _T("bgcolor=blue> </td></tr></table> ");
5834 _T("<table border=0><tr><td ")
5835 _T("bgcolor=grey> ? </td></tr></table> ");
5838 int visIndex = thisLight->attributeNames.Index(_T("LITVIS"));
5839 if (visIndex != wxNOT_FOUND) {
5840 wxString vis = thisLight->attributeValues.Item(visIndex);
5841 if (vis.Contains(_T(
"8"))) {
5842 if (attrIndex != wxNOT_FOUND) {
5843 wxString color = thisLight->attributeValues.Item(attrIndex);
5844 if (color == _T(
"red (3)"))
5846 _T(
"<table border=0><tr><td ")
5847 _T("bgcolor=DarkRed> </td></tr></table> ");
5848 if (color == _T("green (4)"))
5850 _T("<table border=0><tr><td ")
5851 _T("bgcolor=DarkGreen> </td></tr></table> ");
5852 if (color == _T("white (1)"))
5854 _T("<table border=0><tr><td ")
5855 _T("bgcolor=GoldenRod> </td></tr></table> ");
5860 lightsHtml << colorStr;
5862 lightsHtml << _T("</font></td><td><font size=-1><nobr><b>");
5864 attrIndex = thisLight->attributeNames.Index(_T("LITCHR"));
5865 if (attrIndex != wxNOT_FOUND) {
5866 wxString character = thisLight->attributeValues[attrIndex];
5867 lightsHtml << character.BeforeFirst(wxChar(
'(')) << _T(
" ");
5870 attrIndex = thisLight->attributeNames.Index(_T(
"SIGGRP"));
5871 if (attrIndex != wxNOT_FOUND) {
5872 lightsHtml << thisLight->attributeValues[attrIndex];
5873 lightsHtml << _T(
" ");
5876 attrIndex = thisLight->attributeNames.Index(_T(
"SIGPER"));
5877 if (attrIndex != wxNOT_FOUND) {
5878 lightsHtml << thisLight->attributeValues[attrIndex];
5879 lightsHtml << _T(
" ");
5882 attrIndex = thisLight->attributeNames.Index(_T(
"HEIGHT"));
5883 if (attrIndex != wxNOT_FOUND) {
5884 lightsHtml << thisLight->attributeValues[attrIndex];
5885 lightsHtml << _T(
" ");
5888 attrIndex = thisLight->attributeNames.Index(_T(
"VALNMR"));
5889 if (attrIndex != wxNOT_FOUND) {
5890 lightsHtml << thisLight->attributeValues[attrIndex];
5891 lightsHtml << _T(
" ");
5894 lightsHtml << _T(
"</b>");
5896 attrIndex = thisLight->attributeNames.Index(_T(
"SECTR1"));
5897 if (attrIndex != wxNOT_FOUND) {
5898 lightsHtml << _T(
"(") << thisLight->attributeValues[attrIndex];
5899 lightsHtml << _T(
" - ");
5900 attrIndex = thisLight->attributeNames.Index(_T(
"SECTR2"));
5901 lightsHtml << thisLight->attributeValues[attrIndex] << _T(
") ");
5904 lightsHtml << _T(
"</nobr>");
5906 attrIndex = thisLight->attributeNames.Index(_T(
"CATLIT"));
5907 if (attrIndex != wxNOT_FOUND) {
5908 lightsHtml << _T(
"<nobr>");
5909 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
5911 lightsHtml << _T(
"</nobr> ");
5914 attrIndex = thisLight->attributeNames.Index(_T(
"EXCLIT"));
5915 if (attrIndex != wxNOT_FOUND) {
5916 lightsHtml << _T(
"<nobr>");
5917 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
5919 lightsHtml << _T(
"</nobr> ");
5922 attrIndex = thisLight->attributeNames.Index(_T(
"OBJNAM"));
5923 if (attrIndex != wxNOT_FOUND) {
5924 lightsHtml << _T(
"<br><nobr>");
5925 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
5926 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
5927 lightsHtml << _T(
"</nobr> ");
5930 lightsHtml << _T(
"</font></td>");
5931 lightsHtml << _T(
"</tr>");
5933 thisLight->attributeNames.Clear();
5934 thisLight->attributeValues.Clear();
5937 lightsHtml << _T(
"</table><hr noshade>\n");
5938 ret_val = lightsHtml << ret_val;
5952bool s57chart::InitENCMinimal(
const wxString &FullPath) {
5953 if (NULL == g_poRegistrar) {
5954 wxLogMessage(_T(
" Error: No ClassRegistrar in InitENCMinimal."));
5960 m_pENCDS->SetS57Registrar(g_poRegistrar);
5962 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
5965 S57Reader *pENCReader = m_pENCDS->GetModule(0);
5966 pENCReader->SetClassBased(g_poRegistrar);
5968 pENCReader->Ingest();
5973OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
5975 S57Reader *pENCReader = m_pENCDS->GetModule(0);
5977 if ((NULL != pENCReader) && (NULL != g_poRegistrar)) {
5979 g_poRegistrar->SelectClass(
"M_COVR");
5982 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefn(
5983 g_poRegistrar, g_poRegistrar->GetOBJL(), pENCReader->GetOptionFlags());
5986 pENCReader->AddFeatureDefn(poDefn);
5989 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
5992 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
5995 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6006OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6010 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6013 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6016 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6019 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6028int s57chart::GetENCScale(
void) {
6029 if (NULL == m_pENCDS)
return 0;
6036 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6039 return pENCReader->GetCSCL();
6049void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6050 const char *pszErrorMsg) {
6051#define ERR_BUF_LEN 2000
6053 char buf[ERR_BUF_LEN + 1];
6055 if (eErrClass == CE_Debug)
6056 sprintf(buf,
" %s", pszErrorMsg);
6057 else if (eErrClass == CE_Warning)
6058 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6060 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6062 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6063 wxString msg(buf, wxConvUTF8);
6069 if (eErrClass == CE_Fatal) {
6070 longjmp(env_ogrf, 1);
6081const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6082 const char *pszKeyFieldValue,
6083 CSVCompareCriteria eCriteria,
6084 const char *pszTargetField)
6093 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6094 pszKeyFieldValue, eCriteria);
6096 if (papszRecord == NULL)
return "";
6101 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6102 if (iTargetField < 0)
return "";
6104 if (iTargetField >= CSLCount(papszRecord))
return "";
6106 return (papszRecord[iTargetField]);
6120bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6144 std::vector<s57Sector_t> §orlegs) {
6145 float rangeScale = 0.0;
6147 if (sectorlegs.size() > 0) {
6148 std::vector<int> sectorangles;
6149 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6150 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6153 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6154 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6157 wxPoint end1 = viewport.GetPixFromLL(endy, endx);
6159 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6160 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6163 wxPoint end2 = viewport.GetPixFromLL(endy, endx);
6166 viewport.GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6169 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6170 powf((
float)(lightPos.y - end1.y), 2));
6172 if (rangeScale == 0.0) {
6174 if (rangePx > viewport.pix_height / 3) {
6175 rangeScale *= (viewport.pix_height / 3) / rangePx;
6179 rangePx = rangePx * rangeScale;
6181 int penWidth = rangePx / 8;
6182 penWidth = wxMin(20, penWidth);
6183 penWidth = wxMax(5, penWidth);
6187 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color, penWidth,
6189 arcpen->SetCap(wxCAP_BUTT);
6192 float angle1, angle2;
6193 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.rotation * 180.0 / PI;
6194 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.rotation * 180.0 / PI;
6195 if (angle1 > angle2) {
6198 int lpx = lightPos.x;
6199 int lpy = lightPos.y;
6201 wxPoint arcpoints[150];
6204 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6208 int narc = (angle2 - angle1) / step;
6210 step = (angle2 - angle1) / (
float)narc;
6212 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6213 wxPoint yellowCone[3];
6214 yellowCone[0] = lightPos;
6215 yellowCone[1] = end1;
6216 yellowCone[2] = end2;
6217 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6220 wxColor c = sectorlegs[i].color;
6221 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6222 dc.SetBrush(wxBrush(c));
6223 dc.StrokePolygon(3, yellowCone, 0, 0);
6226 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6227 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6228 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6229 arcpoints[npoints].x = x;
6230 arcpoints[npoints].y = y;
6233 dc.StrokeLines(npoints, arcpoints);
6237 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6243 bool haveAngle1 =
false;
6244 bool haveAngle2 =
false;
6245 int sec1 = (int)sectorlegs[i].sector1;
6246 int sec2 = (int)sectorlegs[i].sector2;
6247 if (sec1 > 360) sec1 -= 360;
6248 if (sec2 > 360) sec2 -= 360;
6250 if ((sec2 == 360) && (sec1 == 0))
6253 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6254 if (sectorangles[j] == sec1) haveAngle1 =
true;
6255 if (sectorangles[j] == sec2) haveAngle2 =
true;
6259 dc.StrokeLine(lightPos, end1);
6260 sectorangles.push_back(sec1);
6264 dc.StrokeLine(lightPos, end2);
6265 sectorangles.push_back(sec2);
6271void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6272 std::vector<s57Sector_t> §orlegs) {
6273 float rangeScale = 0.0;
6275 if (sectorlegs.size() > 0) {
6276 std::vector<int> sectorangles;
6277 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6278 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6281 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6282 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6285 wxPoint end1 = viewport.GetPixFromLL(endy, endx);
6287 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6288 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6291 wxPoint end2 = viewport.GetPixFromLL(endy, endx);
6294 viewport.GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6298 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6299 powf((
float)(lightPos.y - end1.y), 2));
6301 if (rangeScale == 0.0) {
6303 if (rangePx > viewport.pix_height / 3) {
6304 rangeScale *= (viewport.pix_height / 3) / rangePx;
6308 rangePx = rangePx * rangeScale;
6310 float arcw = rangePx / 10;
6311 arcw = wxMin(20, arcw);
6312 arcw = wxMax(5, arcw);
6316 float angle1, angle2;
6317 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.rotation * 180.0 / PI;
6318 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.rotation * 180.0 / PI;
6319 if (angle1 > angle2) {
6322 int lpx = lightPos.x;
6323 int lpy = lightPos.y;
6325 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6326 wxPoint yellowCone[3];
6327 yellowCone[0] = lightPos;
6328 yellowCone[1] = end1;
6329 yellowCone[2] = end2;
6330 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6333 wxColor c = sectorlegs[i].color;
6334 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6335 dc.SetBrush(wxBrush(c));
6336 dc.StrokePolygon(3, yellowCone, 0, 0);
6340 wxPoint r(lpx, lpy);
6343 float rad = rangePx;
6368 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6371 glBindBuffer(GL_ARRAY_BUFFER, 0);
6372 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6374 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6375 glEnableVertexAttribArray(mPosAttrib);
6379 glGetUniformLocation(shader->programId(),
"circle_radius");
6380 glUniform1f(radiusloc, rad);
6384 glGetUniformLocation(shader->programId(),
"circle_center");
6387 ctrv[1] = viewport.pix_height - r.y;
6388 glUniform2fv(centerloc, 1, ctrv);
6391 wxColour colorb = sectorlegs[i].color;
6393 colorv[0] = colorb.Red() / float(256);
6394 colorv[1] = colorb.Green() / float(256);
6395 colorv[2] = colorb.Blue() / float(256);
6396 colorv[3] = colorb.Alpha() / float(256);
6398 GLint colloc = glGetUniformLocation(shader->programId(),
"circle_color");
6399 glUniform4fv(colloc, 1, colorv);
6408 GLint bcolloc = glGetUniformLocation(shader->programId(),
"border_color");
6409 glUniform4fv(bcolloc, 1, bcolorv);
6412 GLint borderWidthloc =
6413 glGetUniformLocation(shader->programId(),
"border_width");
6414 glUniform1f(borderWidthloc, 2);
6417 GLint ringWidthloc =
6418 glGetUniformLocation(shader->programId(),
"ring_width");
6419 glUniform1f(ringWidthloc, arcw);
6422 float sr1 = sectorlegs[i].sector1 + (viewport.rotation * 180 / PI) + 180;
6423 if (sr1 > 360.) sr1 -= 360.;
6424 float sr2 = sectorlegs[i].sector2 + (viewport.rotation * 180 / PI) + 180;
6425 if (sr2 > 360.) sr2 -= 360.;
6437 if ((sb < 0) || (se < 0)) {
6442 GLint sector1loc = glGetUniformLocation(shader->programId(),
"sector_1");
6443 glUniform1f(sector1loc, (sb * PI / 180.));
6444 GLint sector2loc = glGetUniformLocation(shader->programId(),
"sector_2");
6445 glUniform1f(sector2loc, (se * PI / 180.));
6450 mat4x4_translate_in_place(I, r.x, r.y, 0);
6453 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6454 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6457 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6461 mat4x4_identity(IM);
6463 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6464 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6466 glDisableVertexAttribArray(mPosAttrib);
6473 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6478 bool haveAngle1 =
false;
6479 bool haveAngle2 =
false;
6480 int sec1 = (int)sectorlegs[i].sector1;
6481 int sec2 = (int)sectorlegs[i].sector2;
6482 if (sec1 > 360) sec1 -= 360;
6483 if (sec2 > 360) sec2 -= 360;
6485 if ((sec2 == 360) && (sec1 == 0))
6488 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6489 if (sectorangles[j] == sec1) haveAngle1 =
true;
6490 if (sectorangles[j] == sec2) haveAngle2 =
true;
6494 dc.StrokeLine(lightPos, end1);
6495 sectorangles.push_back(sec1);
6499 dc.StrokeLine(lightPos, end2);
6500 sectorangles.push_back(sec2);
6507bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6510 ListOfObjRazRules *rule_list,
6511 ListOfPI_S57Obj *pi_rule_list,
6512 std::vector<s57Sector_t> §orlegs) {
6513 bool newSectorsNeedDrawing =
false;
6515 bool bhas_red_green =
false;
6516 bool bleading_attribute =
false;
6519 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6520 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6522 int yOpacity = (float)opacity *
6525 if (target_plugin_chart || Chs57) {
6528 wxPoint2DDouble objPos;
6530 char *curr_att = NULL;
6532 wxArrayOfS57attVal *attValArray = NULL;
6534 ListOfObjRazRules::Node *snode = NULL;
6535 ListOfPI_S57Obj::Node *pnode = NULL;
6537 if (Chs57 && rule_list)
6538 snode = rule_list->GetLast();
6539 else if (target_plugin_chart && pi_rule_list)
6540 pnode = pi_rule_list->GetLast();
6543 wxPoint2DDouble lightPosD(0, 0);
6544 bool is_light =
false;
6548 ObjRazRules *current = snode->GetData();
6549 S57Obj *light = current->obj;
6550 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6551 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6552 curr_att = light->att_array;
6553 n_attr = light->n_attr;
6554 attValArray = light->attVal;
6557 }
else if (target_plugin_chart) {
6560 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6561 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6562 curr_att = light->att_array;
6563 n_attr = light->n_attr;
6564 attValArray = light->attVal;
6574 wxString curAttrName;
6577 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6579 if (is_light && (lightPosD == objPos)) {
6587 bleading_attribute =
false;
6589 while (attrCounter < n_attr) {
6590 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6593 S57attVal *pAttrVal = NULL;
6596 pAttrVal = attValArray->Item(attrCounter);
6597 else if (target_plugin_chart)
6598 pAttrVal = attValArray->Item(attrCounter);
6602 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6604 if (curAttrName == _T(
"LITVIS")) {
6605 if (value.StartsWith(_T(
"obsc"))) bviz =
false;
6607 if (curAttrName == _T(
"SECTR1")) value.ToDouble(§r1);
6608 if (curAttrName == _T(
"SECTR2")) value.ToDouble(§r2);
6609 if (curAttrName == _T(
"VALNMR")) value.ToDouble(&valnmr);
6610 if (curAttrName == _T(
"COLOUR")) {
6611 if (value == _T(
"red(3)")) {
6612 color = wxColor(255, 0, 0, opacity);
6613 sector.iswhite =
false;
6614 bhas_red_green =
true;
6617 if (value == _T(
"green(4)")) {
6618 color = wxColor(0, 255, 0, opacity);
6619 sector.iswhite =
false;
6620 bhas_red_green =
true;
6624 if (curAttrName == _T(
"EXCLIT")) {
6625 if (value.Find(_T(
"(3)"))) valnmr = 1.0;
6628 if (curAttrName == _T(
"CATLIT")) {
6629 if (value.Upper().StartsWith(_T(
"DIRECT")) ||
6630 value.Upper().StartsWith(_T(
"LEAD")))
6631 bleading_attribute =
true;
6638 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6639 if (sectr1 > sectr2) {
6643 sector.pos.m_x = objPos.m_y;
6644 sector.pos.m_y = objPos.m_x;
6647 (valnmr > 0.0) ? valnmr : 2.5;
6648 sector.sector1 = sectr1;
6649 sector.sector2 = sectr2;
6651 if (!color.IsOk()) {
6652 color = wxColor(255, 255, 0, yOpacity);
6653 sector.iswhite =
true;
6655 sector.color = color;
6656 sector.isleading =
false;
6658 if (bleading_attribute) sector.isleading =
true;
6660 bool newsector =
true;
6661 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6662 if (sectorlegs[i].pos == sector.pos &&
6663 sectorlegs[i].sector1 == sector.sector1 &&
6664 sectorlegs[i].sector2 == sector.sector2) {
6670 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6674 if (!bviz) newsector =
false;
6676 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6680 sectorlegs.push_back(sector);
6681 newSectorsNeedDrawing =
true;
6688 snode = snode->GetPrevious();
6689 else if (target_plugin_chart)
6690 pnode = pnode->GetPrevious();
6698 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6699 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6700 if (sectorlegs[i].iswhite && bhas_red_green)
6701 sectorlegs[i].isleading =
true;
6705 return newSectorsNeedDrawing;
6708bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6710 std::vector<s57Sector_t> §orlegs) {
6711 if (!cc)
return false;
6713 static float lastLat, lastLon;
6715 if (!ps52plib)
return false;
6721 wxPoint calcPoint = viewport.GetPixFromLL(lat, lon);
6723 if (cc->m_singleChart && (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6724 target_chart = cc->m_singleChart;
6725 else if (viewport.b_quilt)
6726 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6728 target_chart = NULL;
6731 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6732 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6735 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6738 bool newSectorsNeedDrawing =
false;
6740 if (target_plugin_chart || Chs57) {
6741 ListOfObjRazRules *rule_list = NULL;
6742 ListOfPI_S57Obj *pi_rule_list = NULL;
6745 float selectRadius = 16 / (viewport.view_scale_ppm * 1852 * 60);
6749 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6750 else if (target_plugin_chart)
6751 pi_rule_list = g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6752 target_plugin_chart, lat, lon, viewport);
6754 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6755 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6763 pi_rule_list->Clear();
6764 delete pi_rule_list;
6768 return newSectorsNeedDrawing;
6771bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6773 std::vector<s57Sector_t> §orlegs) {
6774 if (!cc)
return false;
6776 double cursor_lat, cursor_lon;
6777 static float lastLat, lastLon;
6779 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6784 ChartBase *target_chart = cc->GetChartAtCursor();
6786 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6787 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6790 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6793 cc->GetCanvasPixPoint(mx, my, cursor_lat, cursor_lon);
6795 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6797 lastLat = cursor_lat;
6798 lastLon = cursor_lon;
6799 bool newSectorsNeedDrawing =
false;
6801 if (target_plugin_chart || Chs57) {
6802 ListOfObjRazRules *rule_list = NULL;
6803 ListOfPI_S57Obj *pi_rule_list = NULL;
6806 float selectRadius = 16 / (viewport.view_scale_ppm * 1852 * 60);
6809 rule_list = Chs57->GetObjRuleListAtLatLon(
6810 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6811 else if (target_plugin_chart)
6812 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
6813 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6815 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6816 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6824 pi_rule_list->Clear();
6825 delete pi_rule_list;
6829 return newSectorsNeedDrawing;