34#include "wx/tokenzr.h"
35#include <wx/textfile.h>
36#include <wx/filename.h>
39#include "OCPNPlatform.h"
47#include "model/cutil.h"
48#include "model/georef.h"
50#include "model/navutil_base.h"
52#include "ocpn_pixel.h"
55#include "model/wx28compat.h"
56#include "model/chartdata_input_stream.h"
58#include "gdal/cpl_csv.h"
63#include "pluginmanager.h"
67#include "SencManager.h"
71#include "ocpn_frame.h"
74#include <wx/msw/msvcrt.h>
78#include "glChartCanvas.h"
89#include "chart_ctx_factory.h"
92#define strncasecmp(x, y, z) _strnicmp(x, y, z)
96#include "crashlytics.h"
99extern bool GetDoubleAttr(S57Obj *obj,
const char *AttrName,
102void OpenCPN_OGRErrorHandler(
103 CPLErr eErrClass,
int nError,
104 const char *pszErrorMsg);
106extern s52plib *ps52plib;
107extern S57ClassRegistrar *g_poRegistrar;
108extern wxString g_csv_locn;
109extern wxString g_SENCPrefix;
110extern bool g_bGDAL_Debug;
111extern bool g_bDebugS57;
114extern bool g_b_overzoom_x;
115extern bool g_b_EnableVBO;
119int g_SENC_LOD_pixels;
121static jmp_buf env_ogrf;
123#include <wx/arrimpl.cpp>
124WX_DEFINE_OBJARRAY(ArrayOfS57Obj);
126#include <wx/listimpl.cpp>
127WX_DEFINE_LIST(ListOfPI_S57Obj);
129WX_DEFINE_LIST(ListOfObjRazRules);
131#define S57_THUMB_SIZE 200
138static uint64_t hash_fast64(
const void *buf,
size_t len, uint64_t seed) {
139 const uint64_t m = 0x880355f21e6d1965ULL;
140 const uint64_t *pos = (
const uint64_t *)buf;
141 const uint64_t *end = pos + (len >> 3);
142 const unsigned char *pc;
143 uint64_t h = len * m ^ seed;
148 v *= 0x2127599bf4325c37ULL;
152 pc = (
const unsigned char *)pos;
156 v ^= (uint64_t)pc[6] << 48;
158 v ^= (uint64_t)pc[5] << 40;
160 v ^= (uint64_t)pc[4] << 32;
162 v ^= (uint64_t)pc[3] << 24;
164 v ^= (uint64_t)pc[2] << 16;
166 v ^= (uint64_t)pc[1] << 8;
168 v ^= (uint64_t)pc[0];
170 v *= 0x2127599bf4325c37ULL;
176 h *= 0x2127599bf4325c37ULL;
181static unsigned int hash_fast32(
const void *buf,
size_t len,
183 uint64_t h = hash_fast64(buf, len, seed);
188 return h - (h >> 32);
191unsigned long connector_key::hash()
const {
192 return hash_fast32(k,
sizeof k, 0);
199render_canvas_parms::render_canvas_parms() { pix_buff = NULL; }
201render_canvas_parms::~render_canvas_parms(
void) {}
203static void PrepareForRender(
ViewPort *pvp, s52plib *plib) {
208 pvp->rv_rect, pvp->GetBBox(), pvp->
ref_scale,
209 GetOCPNCanvasWindow()->GetContentScaleFactor());
210 plib->PrepareForRender();
217s57chart::s57chart() {
218 m_ChartType = CHART_TYPE_S57;
219 m_ChartFamily = CHART_FAMILY_VECTOR;
221 for (
int i = 0; i < PRIO_NUM; i++)
222 for (
int j = 0; j < LUPNAME_NUM; j++) razRules[i][j] = NULL;
231 pFloatingATONArray =
new wxArrayPtrVoid;
232 pRigidATONArray =
new wxArrayPtrVoid;
234 m_tmpup_array = NULL;
236 m_DepthUnits = _T(
"METERS");
237 m_depth_unit_id = DEPTH_UNIT_METERS;
239 bGLUWarningSent =
false;
245 m_pvaldco_array = NULL;
247 m_bExtentSet =
false;
249 m_pDIBThumbDay = NULL;
250 m_pDIBThumbDim = NULL;
251 m_pDIBThumbOrphan = NULL;
252 m_bbase_file_attr_known =
false;
254 m_bLinePrioritySet =
false;
255 m_plib_state_hash = 0;
262 m_b2pointLUPS =
false;
263 m_b2lineLUPS =
false;
265 m_next_safe_cnt = 1e6;
267 m_line_vertex_buffer = 0;
268 m_this_chart_context = 0;
270 m_vbo_byte_length = 0;
271 bReadyToRender =
false;
273 m_disableBackgroundSENC =
false;
276s57chart::~s57chart() {
277 FreeObjectsAndRules();
284 delete pFloatingATONArray;
285 delete pRigidATONArray;
289 free(m_pvaldco_array);
291 free(m_line_vertex_buffer);
293 delete m_pDIBThumbOrphan;
295 for (
unsigned i = 0; i < m_pcs_vector.size(); i++)
delete m_pcs_vector.at(i);
297 for (
unsigned i = 0; i < m_pve_vector.size(); i++)
delete m_pve_vector.at(i);
299 m_pcs_vector.clear();
300 m_pve_vector.clear();
302 for (
const auto &it : m_ve_hash) {
303 VE_Element *pedge = it.second;
305 free(pedge->pPoints);
311 for (
const auto &it : m_vc_hash) {
312 VC_Element *pcs = it.second;
321 if ((m_LineVBO_name > 0)) glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
323 free(m_this_chart_context);
325 if (m_TempFilePath.Length() && (m_FullPath != m_TempFilePath)) {
326 if (::wxFileExists(m_TempFilePath)) wxRemoveFile(m_TempFilePath);
330 if (g_SencThreadManager) {
331 if (g_SencThreadManager->IsChartInTicketlist(
this)) {
332 g_SencThreadManager->SetChartPointer(
this, NULL);
337void s57chart::GetValidCanvasRegion(
const ViewPort &VPoint,
341 double easting, northing;
344 toSM(m_FullExtent.SLAT, m_FullExtent.WLON, VPoint.
clat, VPoint.
clon, &easting,
349 rxl = (int)round((VPoint.
pix_width / 2) + epix);
350 ryb = (int)round((VPoint.
pix_height / 2) - npix);
352 toSM(m_FullExtent.NLAT, m_FullExtent.ELON, VPoint.
clat, VPoint.
clon, &easting,
357 rxr = (int)round((VPoint.
pix_width / 2) + epix);
358 ryt = (int)round((VPoint.
pix_height / 2) - npix);
360 pValidRegion->Clear();
361 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
364LLRegion s57chart::GetValidRegion() {
365 double ll[8] = {m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.SLAT,
366 m_FullExtent.ELON, m_FullExtent.NLAT, m_FullExtent.ELON,
367 m_FullExtent.NLAT, m_FullExtent.WLON};
368 return LLRegion(4, ll);
371void s57chart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
372 if (!ps52plib)
return;
377 case GLOBAL_COLOR_SCHEME_DAY:
378 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
380 case GLOBAL_COLOR_SCHEME_DUSK:
381 ps52plib->SetPLIBColorScheme(
"DUSK", ChartCtxFactory());
383 case GLOBAL_COLOR_SCHEME_NIGHT:
384 ps52plib->SetPLIBColorScheme(
"NIGHT", ChartCtxFactory());
387 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
391 m_global_color_scheme = cs;
393 if (bApplyImmediate) {
399 ClearRenderedTextCache();
402 ChangeThumbColor(cs);
405void s57chart::ChangeThumbColor(ColorScheme cs) {
406 if (0 == m_pDIBThumbDay)
return;
410 case GLOBAL_COLOR_SCHEME_DAY:
411 pThumbData->pDIBThumb = m_pDIBThumbDay;
412 m_pDIBThumbOrphan = m_pDIBThumbDim;
414 case GLOBAL_COLOR_SCHEME_DUSK:
415 case GLOBAL_COLOR_SCHEME_NIGHT: {
416 if (NULL == m_pDIBThumbDim) {
417 wxImage img = m_pDIBThumbDay->ConvertToImage();
419#if wxCHECK_VERSION(2, 8, 0)
420 wxImage gimg = img.ConvertToGreyscale(
430 wxBitmap *pBMP =
new wxBitmap(gimg);
432 m_pDIBThumbDim = pBMP;
433 m_pDIBThumbOrphan = m_pDIBThumbDay;
436 pThumbData->pDIBThumb = m_pDIBThumbDim;
442bool s57chart::GetChartExtent(
Extent *pext) {
444 *pext = m_FullExtent;
450static void free_mps(mps_container *mps) {
451 if (mps == 0)
return;
452 if (ps52plib && mps->cs_rules) {
453 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
454 Rules *rule_chain_top = mps->cs_rules->Item(i);
455 ps52plib->DestroyRulesChain(rule_chain_top);
457 delete mps->cs_rules;
462void s57chart::FreeObjectsAndRules() {
471 for (
int i = 0; i < PRIO_NUM; ++i) {
472 for (
int j = 0; j < LUPNAME_NUM; j++) {
473 top = razRules[i][j];
474 while (top != NULL) {
476 if (0 == top->obj->nRef)
delete top->obj;
479 ObjRazRules *ctop = top->child;
483 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
485 ObjRazRules *cnxx = ctop->next;
500void s57chart::ClearRenderedTextCache() {
502 for (
int i = 0; i < PRIO_NUM; ++i) {
503 for (
int j = 0; j < LUPNAME_NUM; j++) {
504 top = razRules[i][j];
505 while (top != NULL) {
506 if (top->obj->bFText_Added) {
507 top->obj->bFText_Added =
false;
508 delete top->obj->FText;
509 top->obj->FText = NULL;
513 ObjRazRules *ctop = top->child;
515 if (ctop->obj->bFText_Added) {
516 ctop->obj->bFText_Added =
false;
517 delete ctop->obj->FText;
518 ctop->obj->FText = NULL;
530double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
531 bool b_allow_overzoom) {
533 return m_Chart_Scale * 0.125;
537double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
539 return m_Chart_Scale * 4.0;
546void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
548 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
550 r->y = roundint(m_pixy_vp_center -
551 ((north - m_northing_vp_center) * m_view_scale_ppm));
554void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
555 wxPoint *r,
int nPoints) {
556 for (
int i = 0; i < nPoints; i++) {
557 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
559 r[i].y = roundint(m_pixy_vp_center -
560 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
564void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
566 if (vpt->m_projection_type != PROJECTION_MERCATOR)
567 printf(
"s57chart unhandled projection\n");
573 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
574 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
580 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
590void s57chart::SetVPParms(
const ViewPort &vpt) {
596 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
597 &m_northing_vp_center);
599 vp_transform.easting_vp_center = m_easting_vp_center;
600 vp_transform.northing_vp_center = m_northing_vp_center;
604 if (IsCacheValid()) {
607 double prev_easting_c, prev_northing_c;
608 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
611 double easting_c, northing_c;
612 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
620 int dpix_x = (int)round(delta_pix_x);
625 int dpix_y = (int)round(delta_pix_y);
628 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
629 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
632 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
634 vp_proposed.
clon = xlon;
635 vp_proposed.
clat = xlat;
662void s57chart::LoadThumb() {
663 wxFileName fn(m_FullPath);
664 wxString SENCdir = g_SENCPrefix;
666 if (SENCdir.Last() != fn.GetPathSeparator())
667 SENCdir.Append(fn.GetPathSeparator());
669 wxFileName tsfn(SENCdir);
670 tsfn.SetFullName(fn.GetFullName());
672 wxFileName ThumbFileNameLook(tsfn);
673 ThumbFileNameLook.SetExt(_T(
"BMP"));
676 if (ThumbFileNameLook.FileExists()) {
679 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
680 m_pDIBThumbDay = pBMP;
681 m_pDIBThumbOrphan = 0;
686ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
689 if (pThumbData->pDIBThumb == 0) {
691 ChangeThumbColor(m_global_color_scheme);
694 UpdateThumbData(lat, lon);
699bool s57chart::UpdateThumbData(
double lat,
double lon) {
703 if (pThumbData->pDIBThumb) {
704 double lat_top = m_FullExtent.NLAT;
705 double lat_bot = m_FullExtent.SLAT;
706 double lon_left = m_FullExtent.WLON;
707 double lon_right = m_FullExtent.ELON;
710 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
712 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
714 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
717 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
718 (int)(east * thumb_view_scale_ppm);
719 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
720 (int)(north * thumb_view_scale_ppm);
727 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
728 pThumbData->ShipX = test_x;
729 pThumbData->ShipY = test_y;
735void s57chart::SetFullExtent(
Extent &ext) {
736 m_FullExtent.NLAT = ext.NLAT;
737 m_FullExtent.SLAT = ext.SLAT;
738 m_FullExtent.WLON = ext.WLON;
739 m_FullExtent.ELON = ext.ELON;
744void s57chart::ForceEdgePriorityEvaluate(
void) { m_bLinePrioritySet =
false; }
746void s57chart::SetLinePriorities(
void) {
747 if (!ps52plib)
return;
752 if (!m_bLinePrioritySet) {
756 for (
int i = 0; i < PRIO_NUM; ++i) {
757 top = razRules[i][2];
758 while (top != NULL) {
759 ObjRazRules *crnt = top;
761 ps52plib->SetLineFeaturePriority(crnt, i);
767 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
772 top = razRules[i][j];
773 while (top != NULL) {
776 ps52plib->SetLineFeaturePriority(crnt, i);
782 for (
int i = 0; i < PRIO_NUM; ++i) {
783 for (
int j = 0; j < LUPNAME_NUM; j++) {
784 ObjRazRules *top = razRules[i][j];
785 while (top != NULL) {
786 S57Obj *obj = top->obj;
789 connector_segment *pcs;
790 line_segment_element *list = obj->m_ls_list;
792 switch (list->ls_type) {
796 if (pedge) list->priority = pedge->max_priority;
801 if (pcs) list->priority = pcs->max_priority_cs;
816 m_bLinePrioritySet =
true;
820void s57chart::SetLinePriorities(
void )
822 if( !ps52plib )
return;
827 if( !m_bLinePrioritySet ) {
831 for(
int i = 0; i < PRIO_NUM; ++i ) {
833 top = razRules[i][2];
834 while( top != NULL ) {
835 ObjRazRules *crnt = top;
837 ps52plib->SetLineFeaturePriority( crnt, i );
842 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
847 top = razRules[i][j];
848 while( top != NULL ) {
851 ps52plib->SetLineFeaturePriority( crnt, i );
859 for(
int i = 0; i < PRIO_NUM; ++i ) {
860 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
861 ObjRazRules *top = razRules[i][j];
862 while( top != NULL ) {
863 S57Obj *obj = top->obj;
866 connector_segment *pcs;
867 line_segment_element *list = obj->m_ls_list;
872 pedge = (VE_Element *)list->private0;
874 list->priority = pedge->max_priority;
878 pcs = (connector_segment *)list->private0;
880 list->priority = pcs->max_priority;
895 m_bLinePrioritySet =
true;
899int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
903 line_segment_element *ls_list = obj->m_ls_list;
905 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
906 nPoints += ls_list->pedge->nCount;
909 ls_list = ls_list->next;
918 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
922 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
923 ls_list = obj->m_ls_list;
925 size_t vbo_offset = 0;
927 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
928 vbo_offset = ls_list->pedge->vbo_offset;
929 count = ls_list->pedge->nCount;
931 vbo_offset = ls_list->pcs->vbo_offset;
935 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
937 ls_list = ls_list->next;
944int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
949 line_segment_element *ls_list = obj->m_ls_list;
951 nPoints += ls_list->n_points;
952 ls_list = ls_list->next;
961 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
965 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
966 ls_list = obj->m_ls_list;
968 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
969 br += ls_list->n_points * 2;
970 ls_list = ls_list->next;
979 float e0, n0, e1, n1;
982void s57chart::AssembleLineGeometry(
void) {
987 for (
const auto &it : m_ve_hash) {
988 VE_Element *pedge = it.second;
990 nPoints += pedge->nCount;
996 std::map<long long, connector_segment *> ce_connector_hash;
997 std::map<long long, connector_segment *> ec_connector_hash;
998 std::map<long long, connector_segment *> cc_connector_hash;
1000 std::map<long long, connector_segment *>::iterator csit;
1007 std::vector<segment_pair> connector_segment_vector;
1008 size_t seg_pair_index = 0;
1013 for (
int i = 0; i < PRIO_NUM; ++i) {
1014 for (
int j = 0; j < LUPNAME_NUM; j++) {
1015 ObjRazRules *top = razRules[i][j];
1016 while (top != NULL) {
1017 S57Obj *obj = top->obj;
1019 if ((!obj->m_ls_list) &&
1022 line_segment_element list_top;
1025 line_segment_element *le_current = &list_top;
1027 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1028 if (!obj->m_lsindex_array)
continue;
1030 int seg_index = iseg * 3;
1031 int *index_run = &obj->m_lsindex_array[seg_index];
1034 unsigned int inode = *index_run++;
1037 bool edge_dir =
true;
1038 int venode = *index_run++;
1044 VE_Element *pedge = 0;
1046 if (m_ve_hash.find(venode) != m_ve_hash.end())
1047 pedge = m_ve_hash[venode];
1051 unsigned int enode = *index_run++;
1054 VC_Element *ipnode = 0;
1055 ipnode = m_vc_hash[inode];
1058 VC_Element *epnode = 0;
1059 epnode = m_vc_hash[enode];
1062 if (pedge && pedge->nCount) {
1066 long long key = ((
unsigned long long)inode << 32) + venode;
1068 connector_segment *pcs = NULL;
1069 csit = ce_connector_hash.find(key);
1070 if (csit == ce_connector_hash.end()) {
1072 pcs =
new connector_segment;
1073 ce_connector_hash[key] = pcs;
1077 float *ppt = ipnode->pPoint;
1082 pair.e1 = pedge->pPoints[0];
1083 pair.n1 = pedge->pPoints[1];
1085 int last_point_index = (pedge->nCount - 1) * 2;
1086 pair.e1 = pedge->pPoints[last_point_index];
1087 pair.n1 = pedge->pPoints[last_point_index + 1];
1090 connector_segment_vector.push_back(pair);
1091 pcs->vbo_offset = seg_pair_index;
1097 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1098 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1100 pcs->cs_lat_avg = lat;
1101 pcs->cs_lon_avg = lon;
1106 line_segment_element *pls =
new line_segment_element;
1111 pls->ls_type = TYPE_CE;
1113 le_current->next = pls;
1118 if (pedge && pedge->nCount) {
1119 line_segment_element *pls =
new line_segment_element;
1124 pls->ls_type = TYPE_EE;
1125 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1127 le_current->next = pls;
1135 if (pedge && pedge->nCount) {
1136 long long key = ((
unsigned long long)venode << 32) + enode;
1138 connector_segment *pcs = NULL;
1139 csit = ec_connector_hash.find(key);
1140 if (csit == ec_connector_hash.end()) {
1142 pcs =
new connector_segment;
1143 ec_connector_hash[key] = pcs;
1149 pair.e0 = pedge->pPoints[0];
1150 pair.n0 = pedge->pPoints[1];
1152 int last_point_index = (pedge->nCount - 1) * 2;
1153 pair.e0 = pedge->pPoints[last_point_index];
1154 pair.n0 = pedge->pPoints[last_point_index + 1];
1157 float *ppt = epnode->pPoint;
1161 connector_segment_vector.push_back(pair);
1162 pcs->vbo_offset = seg_pair_index;
1168 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1169 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1171 pcs->cs_lat_avg = lat;
1172 pcs->cs_lon_avg = lon;
1177 line_segment_element *pls =
new line_segment_element;
1181 pls->ls_type = TYPE_EC;
1183 le_current->next = pls;
1187 long long key = ((
unsigned long long)inode << 32) + enode;
1189 connector_segment *pcs = NULL;
1190 csit = cc_connector_hash.find(key);
1191 if (csit == cc_connector_hash.end()) {
1193 pcs =
new connector_segment;
1194 cc_connector_hash[key] = pcs;
1199 float *ppt = ipnode->pPoint;
1203 ppt = epnode->pPoint;
1207 connector_segment_vector.push_back(pair);
1208 pcs->vbo_offset = seg_pair_index;
1214 fromSM_Plugin((pair.e0 + pair.e1) / 2,
1215 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1217 pcs->cs_lat_avg = lat;
1218 pcs->cs_lon_avg = lon;
1223 line_segment_element *pls =
new line_segment_element;
1227 pls->ls_type = TYPE_CC;
1229 le_current->next = pls;
1243 if (obj->m_ls_list == NULL) {
1244 obj->m_n_lsindex = 0;
1248 free(obj->m_lsindex_array);
1249 obj->m_lsindex_array = NULL;
1262 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1264 unsigned char *buffer_offset;
1267 bool grow_buffer =
false;
1269 if (0 == m_vbo_byte_length) {
1270 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1271 m_vbo_byte_length = vbo_byte_length;
1272 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1275 m_line_vertex_buffer = (
float *)realloc(
1276 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1277 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1278 offset = m_vbo_byte_length;
1279 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1283 float *lvr = (
float *)buffer_offset;
1287 for (
const auto &it : m_ve_hash) {
1288 VE_Element *pedge = it.second;
1290 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1291 lvr += pedge->nCount * 2;
1293 pedge->vbo_offset = offset;
1294 offset += pedge->nCount * 2 *
sizeof(float);
1307 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1309 connector_segment *pcs = csit->second;
1310 m_pcs_vector.push_back(pcs);
1312 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1318 pcs->vbo_offset = offset;
1319 offset += 4 *
sizeof(float);
1322 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1324 connector_segment *pcs = csit->second;
1325 m_pcs_vector.push_back(pcs);
1327 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1333 pcs->vbo_offset = offset;
1334 offset += 4 *
sizeof(float);
1337 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1339 connector_segment *pcs = csit->second;
1340 m_pcs_vector.push_back(pcs);
1342 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1348 pcs->vbo_offset = offset;
1349 offset += 4 *
sizeof(float);
1353 connector_segment_vector.clear();
1358 for (
const auto &it : m_ve_hash) {
1359 VE_Element *pedge = it.second;
1361 m_pve_vector.push_back(pedge);
1362 free(pedge->pPoints);
1370 for (
const auto &it : m_vc_hash) {
1371 VC_Element *pcs = it.second;
1372 if (pcs) free(pcs->pPoint);
1378 if (g_b_EnableVBO) {
1380 if (m_LineVBO_name > 0) {
1381 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1382 m_LineVBO_name = -1;
1389void s57chart::BuildLineVBO(
void) {
1391 if (!g_b_EnableVBO)
return;
1393 if (m_LineVBO_name == -1) {
1396 glGenBuffers(1, &vboId);
1399 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,
1413 ObjRazRules *top, *crnt;
1414 int vbo_area_size_bytes = 0;
1415 for (
int i = 0; i < PRIO_NUM; ++i) {
1416 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1417 top = razRules[i][4];
1419 top = razRules[i][3];
1421 while (top != NULL) {
1426 PolyTriGroup *ppg_vbo =
1427 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1429 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1436 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes, NULL,
1439 GLenum err = glGetError();
1442 msg.Printf(_T(
"S57 VBO Error 1: %d"), err);
1444 printf(
"S57 VBO Error 1: %d", err);
1448 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length,
1449 m_line_vertex_buffer);
1454 msg.Printf(_T(
"S57 VBO Error 2: %d"), err);
1456 printf(
"S57 VBO Error 2: %d", err);
1460 int vbo_load_offset = m_vbo_byte_length;
1462 for (
int i = 0; i < PRIO_NUM; ++i) {
1463 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1464 top = razRules[i][4];
1466 top = razRules[i][3];
1468 while (top != NULL) {
1473 PolyTriGroup *ppg_vbo =
1474 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1477 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1478 ppg_vbo->single_buffer_size, ppg_vbo->single_buffer);
1480 crnt->obj->vboAreaOffset = vbo_load_offset;
1481 vbo_load_offset += ppg_vbo->single_buffer_size;
1488 msg.Printf(_T(
"S57 VBO Error 3: %d"), err);
1490 printf(
"S57 VBO Error 3: %d", err);
1495#ifndef USE_ANDROID_GLES2
1496 glDisableClientState(GL_VERTEX_ARRAY);
1498 glBindBuffer(GL_ARRAY_BUFFER, 0);
1502 for (
int i = 0; i < PRIO_NUM; ++i) {
1503 for (
int j = 0; j < LUPNAME_NUM; j++) {
1504 ObjRazRules *top = razRules[i][j];
1505 while (top != NULL) {
1506 S57Obj *obj = top->obj;
1507 obj->auxParm2 = vboId;
1513 m_LineVBO_name = vboId;
1514 m_this_chart_context->vboID = vboId;
1533bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1536 const LLRegion &Region) {
1537 if (!m_RAZBuilt)
return false;
1539 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1542bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1545 const LLRegion &Region) {
1546 if (!m_RAZBuilt)
return false;
1548 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1551bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1554 const LLRegion &Region) {
1555 if (!m_RAZBuilt)
return false;
1557 bool b_text = ps52plib->GetShowS57Text();
1558 ps52plib->m_bShowS57Text =
false;
1559 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1560 ps52plib->m_bShowS57Text = b_text;
1565bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1567 if (!m_RAZBuilt)
return false;
1571 if (!ps52plib)
return false;
1574 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1576 glChartCanvas::DisableClipRegion();
1577 DoRenderOnGLText(glc, VPoint);
1583bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1586 const LLRegion &Region,
bool b_overlay) {
1587 if (!m_RAZBuilt)
return false;
1591 if (!ps52plib)
return false;
1593 if (g_bDebugS57) printf(
"\n");
1597 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1599 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1600 m_bLinePrioritySet =
false;
1602 ClearRenderedTextCache();
1604 ResetPointBBoxes(m_last_vp, VPoint);
1607 m_plib_state_hash = ps52plib->GetStateHash();
1611 ResetPointBBoxes(m_last_vp, VPoint);
1615 SetLinePriorities();
1618 ps52plib->ClearTextList();
1626 wxRect upr = upd.GetRect();
1629 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1630 chart_region.Intersect(Region);
1632 if (!chart_region.Empty()) {
1636 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1643 if (CHART_TYPE_CM93 == GetChartType()) {
1647 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1650#ifdef OPT_USE_ANDROID_GLES2
1658 wxRect r = upd.GetRect();
1660 glViewport(r.x, vp->
pix_height - (r.y + r.height), r.width, r.height);
1668 float yp = vp->
pix_height - (r.y + r.height);
1670 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1671 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1674 I[0][0] *= 2.0 / (float)r.width;
1675 I[1][1] *= -2.0 / (float)r.height;
1679 mat4x4_rotate_Z(Q, I, angle);
1681 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1684 ps52plib->SetReducedBBox(cvp.GetBBox());
1685 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1690 DoRenderOnGL(glc, cvp);
1692 glChartCanvas::DisableClipRegion();
1705bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1718 for (i = 0; i < PRIO_NUM; ++i) {
1719 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1720 top = razRules[i][4];
1722 top = razRules[i][3];
1724 while (top != NULL) {
1727 crnt->sm_transform_parms = &vp_transform;
1728 ps52plib->RenderAreaToGL(glc, crnt);
1734 for (i = 0; i < PRIO_NUM; ++i) {
1735 if (PI_GetPLIBBoundaryStyle() == SYMBOLIZED_BOUNDARIES)
1736 top = razRules[i][4];
1738 top = razRules[i][3];
1740 while (top != NULL) {
1743 crnt->sm_transform_parms = &vp_transform;
1748 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1749 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1750 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1751 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1754 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1761 for (i = 0; i < PRIO_NUM; ++i) {
1762 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1763 top = razRules[i][4];
1765 top = razRules[i][3];
1766 while (top != NULL) {
1769 crnt->sm_transform_parms = &vp_transform;
1770 ps52plib->RenderObjectToGL(glc, crnt);
1775 for (i = 0; i < PRIO_NUM; ++i) {
1776 top = razRules[i][2];
1777 while (top != NULL) {
1780 crnt->sm_transform_parms = &vp_transform;
1781 ps52plib->RenderObjectToGL(glc, crnt);
1787 for (i = 0; i < PRIO_NUM; ++i) {
1788 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1789 top = razRules[i][0];
1791 top = razRules[i][1];
1793 while (top != NULL) {
1796 crnt->sm_transform_parms = &vp_transform;
1797 ps52plib->RenderObjectToGL(glc, crnt);
1807bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1818 for( i = 0; i < PRIO_NUM; ++i ) {
1819 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1820 top = razRules[i][4];
1822 top = razRules[i][3];
1824 while( top != NULL ) {
1827 crnt->sm_transform_parms = &vp_transform;
1834 for (i = 0; i < PRIO_NUM; ++i) {
1835 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1836 top = razRules[i][4];
1838 top = razRules[i][3];
1840 while (top != NULL) {
1843 crnt->sm_transform_parms = &vp_transform;
1844 ps52plib->RenderObjectToGLText(glc, crnt);
1847 top = razRules[i][2];
1848 while (top != NULL) {
1851 crnt->sm_transform_parms = &vp_transform;
1852 ps52plib->RenderObjectToGLText(glc, crnt);
1855 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1856 top = razRules[i][0];
1858 top = razRules[i][1];
1860 while (top != NULL) {
1863 crnt->sm_transform_parms = &vp_transform;
1864 ps52plib->RenderObjectToGLText(glc, crnt);
1873bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1876 if (!m_RAZBuilt)
return false;
1878 bool b_text = ps52plib->GetShowS57Text();
1879 ps52plib->m_bShowS57Text =
false;
1880 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1881 ps52plib->m_bShowS57Text = b_text;
1886bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1889 if (!dc.IsOk())
return false;
1892 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1897 DCRenderText(dc, VPoint);
1900 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1904 while (upd.HaveRects()) {
1905 wxRect rect = upd.GetRect();
1911 temp_vp.
GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1915 temp_vp.
GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1917 if (temp_lon_right < temp_lon_left)
1918 temp_lon_right += 360.;
1920 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1923 wxDCClipper clip(dc, rect);
1924 DCRenderText(dc, temp_vp);
1933bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1935 if (!m_RAZBuilt)
return false;
1937 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1940bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1943 if (!m_RAZBuilt)
return false;
1944 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1947bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1952 bool force_new_view =
false;
1954 if (Region != m_last_Region) force_new_view =
true;
1956 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1958 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1959 m_bLinePrioritySet =
false;
1961 ClearRenderedTextCache();
1963 ResetPointBBoxes(m_last_vp, VPoint);
1968 ResetPointBBoxes(m_last_vp, VPoint);
1971 SetLinePriorities();
1973 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1977 if (VPoint.b_quilt) {
1979 if ((m_pCloneBM->GetWidth() != VPoint.
pix_width) ||
1980 (m_pCloneBM->GetHeight() != VPoint.
pix_height)) {
1985 if (NULL == m_pCloneBM)
1988 wxMemoryDC dc_clone;
1989 dc_clone.SelectObject(*m_pCloneBM);
1991#ifdef ocpnUSE_DIBSECTION
1994 wxMemoryDC memdc, dc_org;
1997 pDIB->SelectIntoDC(dc_org);
2002 while (upd.HaveRects()) {
2003 wxRect rect = upd.GetRect();
2004 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
2009 dc_clone.SelectObject(wxNullBitmap);
2010 dc_org.SelectObject(wxNullBitmap);
2014 wxColour nodat = GetGlobalColor(_T (
"NODTA" ));
2015 wxColour nodat_sub = nodat;
2017#ifdef ocpnUSE_ocpnBitmap
2018 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
2020 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
2021 m_pCloneBM->SetMask(m_pMask);
2024 dc.SelectObject(*m_pCloneBM);
2026 pDIB->SelectIntoDC(dc);
2028 m_last_Region = Region;
2033bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2038 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2040 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2041 m_bLinePrioritySet =
false;
2043 ClearRenderedTextCache();
2047 SetLinePriorities();
2049 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2051 pDIB->SelectIntoDC(dc);
2058bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2059 RenderTypeEnum option,
bool force_new_view) {
2060 bool bnewview =
false;
2062 bool bNewVP =
false;
2064 bool bReallyNew =
false;
2066 double easting_ul, northing_ul;
2067 double easting_lr, northing_lr;
2068 double prev_easting_ul = 0., prev_northing_ul = 0.;
2070 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2071 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2080 if (m_last_vprect != dest) bReallyNew =
true;
2081 m_last_vprect = dest;
2083 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2085 m_plib_state_hash = ps52plib->GetStateHash();
2096 if (m_last_vp.IsValid()) {
2098 m_easting_vp_center - ((VPoint.
pix_width / 2) / m_view_scale_ppm);
2100 m_northing_vp_center + ((VPoint.
pix_height / 2) / m_view_scale_ppm);
2101 easting_lr = easting_ul + (VPoint.
pix_width / m_view_scale_ppm);
2102 northing_lr = northing_ul - (VPoint.
pix_height / m_view_scale_ppm);
2104 double last_easting_vp_center, last_northing_vp_center;
2105 toSM(m_last_vp.
clat, m_last_vp.
clon, ref_lat, ref_lon,
2106 &last_easting_vp_center, &last_northing_vp_center);
2109 last_easting_vp_center - ((m_last_vp.
pix_width / 2) / m_view_scale_ppm);
2110 prev_northing_ul = last_northing_vp_center +
2111 ((m_last_vp.
pix_height / 2) / m_view_scale_ppm);
2113 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2114 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2116 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2117 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2119 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2120 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2122 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2125 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2134 else if ((rul.x != 0) || (rul.y != 0)) {
2135 if (g_bDebugS57) printf(
"newvp due to rul\n");
2146 if (force_new_view) bNewVP =
true;
2151 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2152 rgn_last.Intersect(rgn_new);
2154 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2156 rgn_last.GetBox(xu, yu, wu, hu);
2173 pDIB->SelectIntoDC(dc_last);
2178 pDIBNew->SelectIntoDC(dc_new);
2182 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2187 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.
pix_width,
2190 dc_new.SelectObject(wxNullBitmap);
2191 dc_last.SelectObject(wxNullBitmap);
2199 pDIB->SelectIntoDC(dc);
2203 rgn_delta.Subtract(rgn_reused);
2206 while (upd.HaveRects()) {
2207 wxRect rect = upd.GetRect();
2212 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2214 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2215 (rect.y / m_view_scale_ppm);
2216 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2217 (rect.x / m_view_scale_ppm);
2218 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2221 double temp_northing_lr =
2222 temp_northing_ul - (rect.height / m_view_scale_ppm);
2223 double temp_easting_lr =
2224 temp_easting_ul + (rect.width / m_view_scale_ppm);
2225 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2228 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2233 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2234 temp_vp.GetBBox().GetLatRange()) *
2236 temp_vp.GetBBox().EnLarge(margin);
2242 DCRenderRect(dc, temp_vp, &rect);
2247 dc.SelectObject(wxNullBitmap);
2256 else if (bNewVP || (NULL == pDIB)) {
2262 pDIB->SelectIntoDC(dc);
2265 ps52plib->ClearTextList();
2267 DCRenderRect(dc, VPoint, &full_rect);
2269 dc.SelectObject(wxNullBitmap);
2280int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2293 render_canvas_parms pb_spec;
2295 pb_spec.depth = BPP;
2296 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2297 pb_spec.lclip = rect->x;
2298 pb_spec.rclip = rect->x + rect->width - 1;
2299 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2300 pb_spec.width = rect->width;
2301 pb_spec.height = rect->height;
2302 pb_spec.x = rect->x;
2303 pb_spec.y = rect->y;
2305#ifdef ocpnUSE_ocpnBitmap
2306 pb_spec.b_revrgb =
true;
2308 pb_spec.b_revrgb =
false;
2312 wxColour color = GetGlobalColor(_T (
"NODTA" ));
2313 unsigned char r, g, b;
2321 if (pb_spec.depth == 24) {
2322 for (
int i = 0; i < pb_spec.height; i++) {
2323 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2324 for (
int j = 0; j < pb_spec.width; j++) {
2331 int color_int = ((r) << 16) + ((g) << 8) + (b);
2333 for (
int i = 0; i < pb_spec.height; i++) {
2334 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2335 for (
int j = 0; j < pb_spec.width; j++) {
2342 for (i = 0; i < PRIO_NUM; ++i) {
2343 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2344 top = razRules[i][4];
2346 top = razRules[i][3];
2348 while (top != NULL) {
2351 crnt->sm_transform_parms = &vp_transform;
2352 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2357#ifdef ocpnUSE_ocpnBitmap
2358 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2359 pb_spec.height, pb_spec.depth);
2361 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2362 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2363 wxBitmap *pREN =
new wxBitmap(*prender_image);
2369 dc_ren.SelectObject(*pREN);
2372 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2373 (wxDC *)&dc_ren, 0, 0);
2376 dc_ren.SelectObject(wxNullBitmap);
2378#ifdef ocpnUSE_ocpnBitmap
2379 free(pb_spec.pix_buff);
2381 delete prender_image;
2388 DCRenderLPB(dcinput, vp, rect);
2393bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2400 for (i = 0; i < PRIO_NUM; ++i) {
2402 wxDCClipper *pdcc = NULL;
2408 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2409 top = razRules[i][4];
2411 top = razRules[i][3];
2412 while (top != NULL) {
2415 crnt->sm_transform_parms = &vp_transform;
2416 ps52plib->RenderObjectToDC(&dcinput, crnt);
2419 top = razRules[i][2];
2420 while (top != NULL) {
2423 crnt->sm_transform_parms = &vp_transform;
2424 ps52plib->RenderObjectToDC(&dcinput, crnt);
2427 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2428 top = razRules[i][0];
2430 top = razRules[i][1];
2432 while (top != NULL) {
2435 crnt->sm_transform_parms = &vp_transform;
2436 ps52plib->RenderObjectToDC(&dcinput, crnt);
2440 if (pdcc)
delete pdcc;
2453bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2459 for (i = 0; i < PRIO_NUM; ++i) {
2460 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2461 top = razRules[i][4];
2463 top = razRules[i][3];
2465 while (top != NULL) {
2468 crnt->sm_transform_parms = &vp_transform;
2469 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2472 top = razRules[i][2];
2473 while (top != NULL) {
2476 crnt->sm_transform_parms = &vp_transform;
2477 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2480 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2481 top = razRules[i][0];
2483 top = razRules[i][1];
2485 while (top != NULL) {
2488 crnt->sm_transform_parms = &vp_transform;
2489 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2496bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2497 wxFileName fn(FullPath);
2499 wxString cname = fn.GetName();
2500 if (cname.Length() >= 3)
2501 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2506InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2509 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2512 if (name.Upper().EndsWith(
".XZ")) {
2513 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2516 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2517 wxFileName(name).GetName();
2519 if (!wxFileExists(m_TempFilePath) &&
2520 !DecompressXZFile(name, m_TempFilePath)) {
2521 wxRemoveFile(m_TempFilePath);
2522 return INIT_FAIL_REMOVE;
2525 m_TempFilePath = name;
2526 ext = wxFileName(name).GetExt();
2531 firebase::crashlytics::SetCustomKey(
"s57chartInit",
2532 name.ToStdString().c_str());
2539 return INIT_FAIL_NOERROR;
2544 InitReturn ret_value = INIT_OK;
2546 m_Description = name;
2548 wxFileName fn(m_TempFilePath);
2551 wxString cname = fn.GetName();
2552 m_usage_char = cname[2];
2555 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2556 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2558 if (flags == THUMB_ONLY) {
2566 if (flags == HEADER_ONLY) {
2567 if (ext == _T(
"000")) {
2568 if (!GetBaseFileAttr(fn.GetFullPath()))
2569 ret_value = INIT_FAIL_REMOVE;
2571 if (!CreateHeaderDataFromENC())
2572 ret_value = INIT_FAIL_REMOVE;
2574 ret_value = INIT_OK;
2576 }
else if (ext == _T(
"S57")) {
2577 m_SENCFileName = m_TempFilePath;
2578 if (!CreateHeaderDataFromSENC())
2579 ret_value = INIT_FAIL_REMOVE;
2581 ret_value = INIT_OK;
2590 if (!m_bbase_file_attr_known) {
2591 if (!GetBaseFileAttr(m_TempFilePath))
2592 ret_value = INIT_FAIL_REMOVE;
2594 m_bbase_file_attr_known =
true;
2597 if (ext == _T(
"000")) {
2598 if (m_bbase_file_attr_known) {
2599 int sret = FindOrCreateSenc(m_FullPath);
2600 if (sret == BUILD_SENC_PENDING) {
2605 if (sret != BUILD_SENC_OK) {
2606 if (sret == BUILD_SENC_NOK_RETRY)
2607 ret_value = INIT_FAIL_RETRY;
2609 ret_value = INIT_FAIL_REMOVE;
2611 ret_value = PostInit(flags, m_global_color_scheme);
2616 else if (ext == _T(
"S57")) {
2617 m_SENCFileName = m_TempFilePath;
2618 ret_value = PostInit(flags, m_global_color_scheme);
2625wxString s57chart::buildSENCName(
const wxString &name) {
2626 wxFileName fn(name);
2627 fn.SetExt(_T(
"S57"));
2628 wxString file_name = fn.GetFullName();
2631 wxString SENCdir = g_SENCPrefix;
2633 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2634 SENCdir.Append(wxFileName::GetPathSeparator());
2637 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2638 wxCharBuffer buf = source_dir.ToUTF8();
2639 unsigned char sha1_out[20];
2640 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2643 for (
unsigned int i = 0; i < 6; i++) {
2645 s.Printf(_T(
"%02X"), sha1_out[i]);
2649 file_name.Prepend(sha1);
2652 wxFileName tsfn(SENCdir);
2653 tsfn.SetFullName(file_name);
2655 return tsfn.GetFullPath();
2662int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2666 if (name.Upper().EndsWith(
".XZ")) {
2667 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2670 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2671 wxFileName(name).GetName();
2673 if (!wxFileExists(m_TempFilePath) &&
2674 !DecompressXZFile(name, m_TempFilePath)) {
2675 wxRemoveFile(m_TempFilePath);
2676 return INIT_FAIL_REMOVE;
2679 m_TempFilePath = name;
2680 ext = wxFileName(name).GetExt();
2684 if (!m_bbase_file_attr_known) {
2685 if (!GetBaseFileAttr(m_TempFilePath))
2686 return INIT_FAIL_REMOVE;
2688 m_bbase_file_attr_known =
true;
2692 m_SENCFileName = buildSENCName(name);
2694 int build_ret_val = 1;
2696 bool bbuild_new_senc =
false;
2697 m_bneed_new_thumbnail =
false;
2699 wxFileName FileName000(m_TempFilePath);
2703 wxString msg(_T(
"S57chart::Checking SENC file: "));
2704 msg.Append(m_SENCFileName);
2708 int force_make_senc = 0;
2710 if (::wxFileExists(m_SENCFileName)) {
2713 if (senc.ingestHeader(m_SENCFileName)) {
2714 bbuild_new_senc =
true;
2715 wxLogMessage(_T(
" Rebuilding SENC due to ingestHeader failure."));
2717 int senc_file_version = senc.getSencReadVersion();
2719 int last_update = senc.getSENCReadLastUpdate();
2721 wxString str = senc.getSENCFileCreateDate();
2722 wxDateTime SENCCreateDate;
2723 SENCCreateDate.ParseFormat(str, _T(
"%Y%m%d"));
2725 if (SENCCreateDate.IsValid())
2726 SENCCreateDate.ResetTime();
2731 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2733 senc_base_edtn.ToLong(&isenc_edition);
2735 m_edtn000.ToLong(&ifile_edition);
2740 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2741 bbuild_new_senc =
true;
2742 wxLogMessage(_T(
" Rebuilding SENC due to SENC format update."));
2749 else if (ifile_edition > isenc_edition) {
2750 bbuild_new_senc =
true;
2751 wxLogMessage(_T(
" Rebuilding SENC due to cell edition update."));
2753 msg = _T(
" Last edition recorded in SENC: ");
2754 msg += senc_base_edtn;
2755 msg += _T(
" most recent edition cell file: ");
2760 int most_recent_update_file =
2761 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2763 if (ifile_edition == isenc_edition) {
2764 if (most_recent_update_file > last_update) {
2765 bbuild_new_senc =
true;
2767 _T(
" Rebuilding SENC due to incremental cell update."));
2770 _T(
" Last update recorded in SENC: %d most recent ")
2771 _T(
"update file: %d"),
2772 last_update, most_recent_update_file);
2780 wxDateTime OModTime000;
2781 FileName000.GetTimes(NULL, &OModTime000, NULL);
2782 OModTime000.ResetTime();
2783 if (SENCCreateDate.IsValid()) {
2784 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2786 _T(
" Rebuilding SENC due to Senc vs cell file time ")
2788 bbuild_new_senc =
true;
2791 bbuild_new_senc =
true;
2793 _T(
" Rebuilding SENC due to SENC create time invalid."));
2804 if (force_make_senc) bbuild_new_senc =
true;
2806 }
else if (!::wxFileExists(m_SENCFileName))
2808 wxLogMessage(_T(
" Rebuilding SENC due to missing SENC file."));
2809 bbuild_new_senc =
true;
2813 if (bbuild_new_senc) {
2814 m_bneed_new_thumbnail =
2816 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2818 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2819 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2820 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2826InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2828 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2829 wxString msg(_T(
" Cannot load SENC file "));
2830 msg.Append(m_SENCFileName);
2833 return INIT_FAIL_RETRY;
2839 wxString SENCdir = g_SENCPrefix;
2840 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2841 SENCdir.Append(wxFileName::GetPathSeparator());
2843 wxFileName s57File(m_SENCFileName);
2844 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13), _T(
"BMP"));
2846 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2847 BuildThumbnail(ThumbFileName.GetFullPath());
2850 if (ThumbFileName.FileExists()) {
2852#ifdef ocpnUSE_ocpnBitmap
2853 pBMP_NEW =
new ocpnBitmap;
2855 pBMP_NEW =
new wxBitmap;
2857 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2860 m_pDIBThumbDay = pBMP_NEW;
2868 m_global_color_scheme = cs;
2869 SetColorScheme(cs,
false);
2872 BuildDepthContourArray();
2874 CreateChartContext();
2875 PopulateObjectsWithContext();
2878 bReadyToRender =
true;
2883void s57chart::ClearDepthContourArray(
void) {
2884 if (m_nvaldco_alloc) {
2885 free(m_pvaldco_array);
2887 m_nvaldco_alloc = 5;
2889 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2892void s57chart::BuildDepthContourArray(
void) {
2895 if (0 == m_nvaldco_alloc) {
2896 m_nvaldco_alloc = 5;
2897 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2903 double prev_valdco = 0.0;
2905 for (
int i = 0; i < PRIO_NUM; ++i) {
2906 for (
int j = 0; j < LUPNAME_NUM; j++) {
2907 top = razRules[i][j];
2908 while (top != NULL) {
2909 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2910 double valdco = 0.0;
2911 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2912 if (valdco != prev_valdco) {
2913 prev_valdco = valdco;
2915 if (m_nvaldco > m_nvaldco_alloc) {
2916 void *tr = realloc((
void *)m_pvaldco_array,
2917 m_nvaldco_alloc * 2 *
sizeof(
double));
2918 m_pvaldco_array = (
double *)tr;
2919 m_nvaldco_alloc *= 2;
2921 m_pvaldco_array[m_nvaldco - 1] = valdco;
2925 ObjRazRules *nxx = top->next;
2930 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2934void s57chart::SetSafetyContour(
void) {
2942 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2945 if (NULL != m_pvaldco_array) {
2946 for (i = 0; i < m_nvaldco; i++) {
2947 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2951 m_next_safe_cnt = m_pvaldco_array[i];
2953 m_next_safe_cnt = (double)1e6;
2955 m_next_safe_cnt = (double)1e6;
2960 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2961 m_next_safe_cnt = (
double)1e6;
2964void s57chart::CreateChartContext() {
2966 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2969void s57chart::PopulateObjectsWithContext() {
2970 m_this_chart_context->chart =
this;
2971 m_this_chart_context->chart_type = GetChartType();
2972 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2973 m_this_chart_context->chart_scale = GetNativeScale();
2974 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2975 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2976 m_this_chart_context->safety_contour = m_next_safe_cnt;
2977 m_this_chart_context->pt2GetAssociatedObjects =
2978 &s57chart::GetAssociatedObjects;
2982 for (
int i = 0; i < PRIO_NUM; ++i) {
2983 for (
int j = 0; j < LUPNAME_NUM; j++) {
2984 top = razRules[i][j];
2985 while (top != NULL) {
2986 S57Obj *obj = top->obj;
2987 obj->m_chart_context = m_this_chart_context;
2994void s57chart::InvalidateCache() {
2999bool s57chart::BuildThumbnail(
const wxString &bmpname) {
3002 wxFileName ThumbFileName(bmpname);
3005 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
3006 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
3007 wxLogMessage(_T(
" Cannot create BMP file directory for ") +
3008 ThumbFileName.GetFullPath());
3016 vp.
clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
3017 vp.
clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
3019 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
3020 (m_FullExtent.ELON - m_FullExtent.WLON));
3027 vp.m_projection_type = PROJECTION_MERCATOR;
3029 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3046 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3048 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3050 int *psvr = psave_viz;
3054 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3055 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3056 *psvr++ = pOLE->nViz;
3061 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3062 bool bsave_text = ps52plib->m_bShowS57Text;
3065 ps52plib->SaveObjNoshow();
3068 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3069 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3070 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3071 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3074 ps52plib->m_bShowSoundg =
false;
3075 ps52plib->m_bShowS57Text =
false;
3078 DisCat dsave = ps52plib->GetDisplayCategory();
3079 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3081 ps52plib->AddObjNoshow(
"BRIDGE");
3082 ps52plib->AddObjNoshow(
"GATCON");
3084 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3085 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3086 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3087 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3089#ifdef ocpnUSE_DIBSECTION
3092 wxMemoryDC memdc, dc_org;
3096 ps52plib->SaveColorScheme();
3097 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3099 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3102 memdc.SelectObject(wxNullBitmap);
3106 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3107 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3108 pOLE->nViz = *psvr++;
3111 ps52plib->SetDisplayCategory(dsave);
3112 ps52plib->RestoreObjNoshow();
3114 ps52plib->RemoveObjNoshow(
"BRIDGE");
3115 ps52plib->RemoveObjNoshow(
"GATCON");
3117 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3118 ps52plib->m_bShowS57Text = bsave_text;
3120 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3121 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3124 ps52plib->RestoreColorScheme();
3134 wxMemoryDC dc_clone;
3135 dc_clone.SelectObject(*pBMP);
3137 pDIB->SelectIntoDC(dc_org);
3141 dc_clone.SelectObject(wxNullBitmap);
3142 dc_org.SelectObject(wxNullBitmap);
3145 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3152#include <wx/arrimpl.cpp>
3153WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3156bool s57chart::CreateHeaderDataFromENC(
void) {
3157 if (!InitENCMinimal(m_TempFilePath)) {
3158 wxString msg(_T(
" Cannot initialize ENC file "));
3159 msg.Append(m_TempFilePath);
3167 float LatMax, LatMin, LonMax, LonMin;
3173 m_pCOVRTablePoints = NULL;
3174 m_pCOVRTable = NULL;
3177 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3178 std::vector<int> auxCntArray, noCovrCntArray;
3180 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3183 pFeat = GetChartFirstM_COVR(catcov);
3188 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3189 OGRLinearRing *xring = poly->getExteriorRing();
3191 int npt = xring->getNumPoints();
3202 for (
int i = 0; i < npt; i++) {
3203 xring->getPoint(i, &p);
3207 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3209 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3210 if (xdelta < 0.001 &&
3218 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3219 pfr = &pf[2 * (usedpts - 1)];
3222 LatMax = fmax(LatMax, p.getY());
3223 LatMin = fmin(LatMin, p.getY());
3224 LonMax = fmax(LonMax, p.getX());
3225 LonMin = fmin(LonMin, p.getX());
3233 pAuxPtrArray->Add(pf);
3234 auxCntArray.push_back(usedpts);
3235 }
else if (catcov == 2) {
3236 pNoCovrPtrArray->Add(pf);
3237 noCovrCntArray.push_back(usedpts);
3242 pFeat = GetChartNextM_COVR(catcov);
3243 DEBUG_LOG <<
"used " << usedpts <<
" points";
3248 m_nCOVREntries = auxCntArray.size();
3252 if (m_nCOVREntries >= 1) {
3253 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3254 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3256 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3257 m_pCOVRTablePoints[j] = auxCntArray[j];
3258 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3264 wxString msg(_T(
" ENC contains no useable M_COVR, CATCOV=1 features: "));
3265 msg.Append(m_TempFilePath);
3270 m_nNoCOVREntries = noCovrCntArray.size();
3272 if (m_nNoCOVREntries) {
3274 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3275 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3277 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3278 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3279 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3282 m_pNoCOVRTablePoints = NULL;
3283 m_pNoCOVRTable = NULL;
3286 delete pAuxPtrArray;
3287 delete pNoCovrPtrArray;
3289 if (0 == m_nCOVREntries) {
3290 wxString msg(_T(
" ENC contains no M_COVR features: "));
3291 msg.Append(m_TempFilePath);
3294 msg = _T(
" Calculating Chart Extents as fallback.");
3300 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3302 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3309 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3310 *m_pCOVRTablePoints = 4;
3311 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3312 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3329 wxString msg(_T(
" Cannot calculate Extents for ENC: "));
3330 msg.Append(m_TempFilePath);
3338 m_FullExtent.NLAT = LatMax;
3339 m_FullExtent.SLAT = LatMin;
3340 m_FullExtent.ELON = LonMax;
3341 m_FullExtent.WLON = LonMin;
3342 m_bExtentSet =
true;
3345 m_Chart_Scale = GetENCScale();
3348 GetChartNameFromTXT(m_TempFilePath, nice_name);
3356bool s57chart::CreateHeaderDataFromoSENC(
void) {
3357 bool ret_val =
true;
3359 wxFFileInputStream fpx(m_SENCFileName);
3361 if (!::wxFileExists(m_SENCFileName)) {
3362 wxString msg(_T(
" Cannot open SENC file "));
3363 msg.Append(m_SENCFileName);
3370 if (senc.ingestHeader(m_SENCFileName)) {
3376 m_Chart_Scale = senc.getSENCReadScale();
3379 m_Name = senc.getReadName();
3382 m_ID = senc.getReadID();
3385 Extent &ext = senc.getReadExtent();
3387 m_FullExtent.ELON = ext.ELON;
3388 m_FullExtent.WLON = ext.WLON;
3389 m_FullExtent.NLAT = ext.NLAT;
3390 m_FullExtent.SLAT = ext.SLAT;
3391 m_bExtentSet =
true;
3394 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3395 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3397 m_nCOVREntries = AuxCntArray.size();
3399 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3400 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3402 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3403 m_pCOVRTablePoints[j] = AuxCntArray[j];
3404 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3405 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3406 AuxCntArray[j] * 2 *
sizeof(
float));
3410 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3411 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3413 m_nNoCOVREntries = NoCovrCntArray.size();
3415 if (m_nNoCOVREntries) {
3417 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3418 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3420 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3421 int npoints = NoCovrCntArray[j];
3422 m_pNoCOVRTablePoints[j] = npoints;
3423 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3424 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3425 npoints * 2 *
sizeof(
float));
3431 m_datum_str = _T(
"WGS84");
3432 m_SoundingsDatum = _T(
"MEAN LOWER LOW WATER");
3434 int senc_file_version = senc.getSencReadVersion();
3436 int last_update = senc.getSENCReadLastUpdate();
3438 wxString str = senc.getSENCFileCreateDate();
3439 wxDateTime SENCCreateDate;
3440 SENCCreateDate.ParseFormat(str, _T(
"%Y%m%d"));
3442 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3444 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3451bool s57chart::CreateHeaderDataFromSENC(
void) {
3452 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3460bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3462 if (NULL != m_pvaldco_array) {
3463 for (i = 0; i < m_nvaldco; i++) {
3464 if (m_pvaldco_array[i] >= safe_cnt)
break;
3468 next_safe_cnt = m_pvaldco_array[i];
3470 next_safe_cnt = (double)1e6;
3473 next_safe_cnt = (double)1e6;
3487std::list<S57Obj *> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3491 std::list<S57Obj *> *pobj_list =
new std::list<S57Obj *>();
3494 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3495 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3498 switch (obj->Primitive_type) {
3511 top = razRules[disPrioIdx][3];
3512 while (top != NULL) {
3513 if (top->obj->bIsAssociable) {
3514 if (top->obj->BBObj.Contains(lat, lon)) {
3515 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3516 pobj_list->push_back(top->obj);
3523 ObjRazRules *nxx = top->next;
3528 top = razRules[disPrioIdx][4];
3529 while (top != NULL) {
3530 if (top->obj->bIsAssociable) {
3531 if (top->obj->BBObj.Contains(lat, lon)) {
3532 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3533 pobj_list->push_back(top->obj);
3539 ObjRazRules *nxx = top->next;
3553void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3554 wxFileName fn(FullPath);
3556 wxString target_name = fn.GetName();
3557 target_name.RemoveLast();
3559 wxString dir_name = fn.GetPath();
3561 wxDir dir(dir_name);
3563 wxArrayString FileList;
3565 dir.GetAllFiles(fn.GetPath(), &FileList);
3569 bool found_name =
false;
3573 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3574 wxFileName file(FileList[j]);
3575 if (((file.GetExt()).MakeUpper()) == _T(
"TXT")) {
3577 wxTextFile text_file(file.GetFullPath());
3579 bool file_ok =
true;
3583 if (!text_file.Open()) {
3584 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3589 wxString str = text_file.GetFirstLine();
3590 while (!text_file.Eof()) {
3591 if (0 == target_name.CmpNoCase(
3592 str.Mid(0, target_name.Len()))) {
3593 wxString tname = str.AfterFirst(
'-');
3594 name = tname.AfterFirst(
' ');
3598 str = text_file.GetNextLine();
3602 wxString msg(_T(
" Error Reading ENC .TXT file: "));
3603 msg.Append(file.GetFullPath());
3609 if (found_name)
break;
3626const char *s57chart::getName(OGRFeature *feature) {
3627 return feature->GetDefnRef()->GetName();
3630static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3631 wxFileName fn1(first);
3632 wxFileName fn2(second);
3633 wxString ext1(fn1.GetExt());
3634 wxString ext2(fn2.GetExt());
3636 return ext1.Cmp(ext2);
3639int s57chart::GetUpdateFileArray(
const wxFileName file000,
3640 wxArrayString *UpFiles, wxDateTime date000,
3642 wxString DirName000 =
3643 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3644 wxDir dir(DirName000);
3645 if (!dir.IsOpened()) {
3646 DirName000.Prepend(wxFileName::GetPathSeparator());
3647 DirName000.Prepend(_T(
"."));
3648 dir.Open(DirName000);
3649 if (!dir.IsOpened()) {
3654 int flags = wxDIR_DEFAULT;
3661 wxFileName fnDir(DirName000);
3662 fnDir.RemoveLastDir();
3663 wxString sdir = fnDir.GetPath();
3664 wxFileName fnTest(sdir);
3665 wxString sname = fnTest.GetName();
3667 if (sname.ToLong(&tmps)) {
3670 flags |= wxDIR_DIRS;
3674 wxArrayString *dummy_array;
3677 if (UpFiles == NULL)
3678 dummy_array =
new wxArrayString;
3680 dummy_array = UpFiles;
3682 wxArrayString possibleFiles;
3683 wxDir::GetAllFiles(DirName000, &possibleFiles, wxEmptyString, flags);
3685 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3686 wxString filename(possibleFiles[i]);
3688 wxFileName file(filename);
3689 ext = file.GetExt();
3694 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3695 wxString FileToAdd = filename;
3697 wxCharBuffer buffer =
3700 if (buffer.data() && !filename.IsSameAs(_T(
"CATALOG.031"),
3712 DDFModule *poModule =
new DDFModule();
3713 if (!poModule->Open(FileToAdd.mb_str())) {
3715 _T(
" s57chart::BuildS57File Unable to open update file "));
3716 msg.Append(FileToAdd);
3725 DDFRecord *pr = poModule->ReadRecord();
3731 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3734 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3738 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3739 _T(
"DSID:ISDT in update file "));
3740 msg.Append(FileToAdd);
3743 sumdate = _T(
"20000101");
3746 umdate.ParseFormat(sumdate, _T(
"%Y%m%d"));
3747 if (!umdate.IsValid())
3748 umdate.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
3751 if (!umdate.IsValid())
int yyp = 4;
3756 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3758 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3762 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3763 _T(
"DSID:EDTN in update file "));
3764 msg.Append(FileToAdd);
3773 if ((!umdate.IsEarlierThan(date000)) &&
3774 (umedtn.IsSameAs(edtn000)))
3775 dummy_array->Add(FileToAdd);
3781 dummy_array->Sort(ExtensionCompare);
3784 if (dummy_array->GetCount()) {
3785 wxString Last = dummy_array->Last();
3786 wxFileName fnl(Last);
3788 wxCharBuffer buffer = ext.ToUTF8();
3789 if (buffer.data()) retval = atoi(buffer.data());
3792 if (UpFiles == NULL)
delete dummy_array;
3797int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3798 const wxString CopyDir,
3799 wxString &LastUpdateDate,
3805 wxArrayString *UpFiles =
new wxArrayString;
3806 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3808 if (UpFiles->GetCount()) {
3822 bool chain_broken_mssage_shown =
false;
3828 for (
int iff = 0; iff < retval + 1; iff++) {
3829 wxFileName ufile(m_TempFilePath);
3831 sext.Printf(_T(
"%03d"), iff);
3835 wxString cp_ufile = CopyDir;
3836 if (cp_ufile.Last() != ufile.GetPathSeparator())
3837 cp_ufile.Append(ufile.GetPathSeparator());
3839 cp_ufile.Append(ufile.GetFullName());
3844 if (ufile.FileExists()) {
3845 wxFile uf(ufile.GetFullPath());
3846 if (uf.IsOpened()) {
3852 if (ufile.FileExists() &&
3856 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3858 wxString msg(_T(
" Cannot copy temporary working ENC file "));
3859 msg.Append(ufile.GetFullPath());
3860 msg.Append(_T(
" to "));
3861 msg.Append(cp_ufile);
3871 if (!chain_broken_mssage_shown) {
3874 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3875 "incomplete or inaccurate.\nCheck the logfile for details."),
3876 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3878 chain_broken_mssage_shown =
true;
3882 _T(
"WARNING---ENC Update chain incomplete. Substituting NULL ")
3883 _T(
"update file: "));
3884 msg += ufile.GetFullName();
3886 wxLogMessage(_T(
" Subsequent ENC updates may produce errors."));
3888 _T(
" This ENC exchange set should be updated and SENCs ")
3892 DDFModule *dupdate =
new DDFModule;
3893 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3894 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3898 wxString msg(_T(
" Error creating dummy update file: "));
3899 msg.Append(cp_ufile);
3904 m_tmpup_array->Add(cp_ufile);
3911 wxFileName lastfile(m_TempFilePath);
3913 last_sext.Printf(_T(
"%03d"), retval);
3914 lastfile.SetExt(last_sext);
3917 DDFModule oUpdateModule;
3922 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3926 oUpdateModule.Rewind();
3927 DDFRecord *pr = oUpdateModule.ReadRecord();
3933 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3937 LastUpdateDate = wxString(u, wxConvUTF8);
3940 wxDateTime now = wxDateTime::Now();
3941 LastUpdateDate = now.Format(_T(
"%Y%m%d"));
3950wxString s57chart::GetISDT(
void) {
3951 if (m_date000.IsValid())
3952 return m_date000.Format(_T(
"%Y%m%d"));
3954 return _T(
"Unknown");
3957bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3958 if (!wxFileName::FileExists(file000))
return false;
3960 wxString FullPath000 = file000;
3961 DDFModule *poModule =
new DDFModule();
3962 if (!poModule->Open(FullPath000.mb_str())) {
3963 wxString msg(_T(
" s57chart::BuildS57File Unable to open "));
3964 msg.Append(FullPath000);
3976 DDFRecord *pr = poModule->ReadRecord();
3980 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3981 if (!m_nGeoRecords) {
3983 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
3993 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3995 date000 = wxString(u, wxConvUTF8);
3998 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
4005 m_date000.ParseFormat(date000, _T(
"%Y%m%d"));
4006 if (!m_date000.IsValid()) m_date000.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4008 m_date000.ResetTime();
4011 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
4013 m_edtn000 = wxString(u, wxConvUTF8);
4016 _T(
" s57chart::BuildS57File DDFRecord 0 does not contain ")
4020 m_edtn000 = _T(
"1");
4027 for (; pr != NULL; pr = poModule->ReadRecord()) {
4028 if (pr->FindField(
"DSPM") != NULL) {
4029 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4033 if (!m_native_scale) {
4034 wxString msg(_T(
" s57chart::BuildS57File ENC not contain DSPM:CSCL "));
4037 m_native_scale = 1000;
4045int s57chart::BuildSENCFile(
const wxString &FullPath000,
4046 const wxString &SENCFileName,
bool b_progress) {
4048 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4049 double meters_per_pixel_max_scale =
4050 GetNormalScaleMin(0, g_b_overzoom_x) / display_pix_per_meter;
4051 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4054 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4055 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4057 if (!m_disableBackgroundSENC) {
4058 if (g_SencThreadManager) {
4060 ticket->m_LOD_meters = m_LOD_meters;
4061 ticket->ref_lat = ref_lat;
4062 ticket->ref_lon = ref_lon;
4063 ticket->m_FullPath000 = FullPath000;
4064 ticket->m_SENCFileName = SENCFileName;
4065 ticket->m_chart =
this;
4067 g_SencThreadManager->ScheduleJob(ticket);
4068 bReadyToRender =
true;
4069 return BUILD_SENC_PENDING;
4072 return BUILD_SENC_NOK_RETRY;
4077 senc.setRegistrar(g_poRegistrar);
4078 senc.setRefLocn(ref_lat, ref_lon);
4079 senc.SetLODMeters(m_LOD_meters);
4081 AbstractPlatform::ShowBusySpinner();
4083 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4085 AbstractPlatform::HideBusySpinner();
4087 if (ret == ERROR_INGESTING000)
4088 return BUILD_SENC_NOK_PERMANENT;
4094int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4101 S57ObjVector Objects;
4102 VE_ElementVector VEs;
4103 VC_ElementVector VCs;
4105 sencfile.setRefLocn(ref_lat, ref_lon);
4107 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4109 if (srv != SENC_NO_ERROR) {
4110 wxLogMessage(sencfile.getLastError());
4116 Extent ext = sencfile.getReadExtent();
4118 m_FullExtent.ELON = ext.ELON;
4119 m_FullExtent.WLON = ext.WLON;
4120 m_FullExtent.NLAT = ext.NLAT;
4121 m_FullExtent.SLAT = ext.SLAT;
4122 m_bExtentSet =
true;
4124 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4125 ref_lon = (ext.ELON + ext.WLON) / 2.;
4130 int n_ve_elements = VEs.size();
4132 double scale = gFrame->GetBestVPScale(
this);
4133 int nativescale = GetNativeScale();
4135 for (
int i = 0; i < n_ve_elements; i++) {
4136 VE_Element *vep = VEs.at(i);
4137 if (vep && vep->nCount) {
4139 double east_max = -1e7;
4140 double east_min = 1e7;
4141 double north_max = -1e7;
4142 double north_min = 1e7;
4144 float *vrun = vep->pPoints;
4145 for (
size_t i = 0; i < vep->nCount; i++) {
4146 east_max = wxMax(east_max, *vrun);
4147 east_min = wxMin(east_min, *vrun);
4150 north_max = wxMax(north_max, *vrun);
4151 north_min = wxMin(north_min, *vrun);
4155 double lat1, lon1, lat2, lon2;
4156 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4157 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4158 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4161 m_ve_hash[vep->index] = vep;
4165 int n_vc_elements = VCs.size();
4167 for (
int i = 0; i < n_vc_elements; i++) {
4168 VC_Element *vcp = VCs.at(i);
4169 m_vc_hash[vcp->index] = vcp;
4177 for (
unsigned int i = 0; i < Objects.size(); i++) {
4178 S57Obj *obj = Objects[i];
4182 LUPname LUP_Name = PAPER_CHART;
4184 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4185 if (objnam.Len() > 0) {
4186 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4187 SendVectorChartObjectInfo(FullPath, fe_name, objnam, obj->m_lat,
4188 obj->m_lon,
scale, nativescale);
4192 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4193 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4194 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4195 SendVectorChartObjectInfo(FullPath, fe_name, nobjnam, obj->m_lat,
4196 obj->m_lon,
scale, nativescale);
4199 switch (obj->Primitive_type) {
4204 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4205 LUP_Name = PAPER_CHART;
4207 LUP_Name = SIMPLIFIED;
4216 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4217 LUP_Name = PLAIN_BOUNDARIES;
4219 LUP_Name = SYMBOLIZED_BOUNDARIES;
4224 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4228 wxString msg(obj->FeatureName, wxConvUTF8);
4229 msg.Prepend(_T(
" Could not find LUP for "));
4230 LogMessageOnce(msg);
4237 ps52plib->_LUP2rules(LUP, obj);
4240 _insertRules(obj, LUP,
this);
4243 obj->m_DisplayCat = LUP->DISC;
4246 obj->m_DPRI = LUP->DPRI -
'0';
4249 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4250 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4251 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4252 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4253 obj->m_bcategory_mutable =
true;
4255 obj->m_bcategory_mutable =
false;
4260 if (obj && (GEO_POINT == obj->Primitive_type)) {
4262 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4263 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4264 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4265 pFloatingATONArray->Add(obj);
4269 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4270 pRigidATONArray->Add(obj);
4274 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4275 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4276 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4277 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4278 obj->bIsAton =
true;
4287 d000.ParseFormat(sencfile.getBaseDate(), _T(
"%Y%m%d"));
4288 if (!d000.IsValid()) d000.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4291 updt.ParseFormat(sencfile.getUpdateDate(), _T(
"%Y%m%d"));
4292 if (!updt.IsValid()) updt.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4294 if (updt.IsLaterThan(d000))
4295 m_PubYear.Printf(_T(
"%4d"), updt.GetYear());
4297 m_PubYear.Printf(_T(
"%4d"), d000.GetYear());
4300 wxDateTime upd = updt;
4301 if (!upd.IsValid()) upd.ParseFormat(_T(
"20000101"), _T(
"%Y%m%d"));
4306 m_SE = sencfile.getSENCReadBaseEdition();
4309 supdate.Printf(_T(
" / %d"), sencfile.getSENCReadLastUpdate());
4312 m_datum_str = _T(
"WGS84");
4314 m_SoundingsDatum = _T(
"MEAN LOWER LOW WATER");
4315 m_ID = sencfile.getReadID();
4316 m_Name = sencfile.getReadName();
4320 AssembleLineGeometry();
4325int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4326 ObjRazRules *rzRules = NULL;
4336 switch (LUP->DPRI) {
4349 case PRIO_SYMB_POINT:
4352 case PRIO_SYMB_LINE:
4355 case PRIO_SYMB_AREA:
4368 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4372 switch (LUP->TNAM) {
4382 case PLAIN_BOUNDARIES:
4385 case SYMBOLIZED_BOUNDARIES:
4389 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4393 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4397 rzRules->child = NULL;
4398 rzRules->mps = NULL;
4401 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4402 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4407 ObjRazRules *rNext = NULL;
4408 ObjRazRules *rPrevious = NULL;
4409 if (razRules[disPrioIdx][LUPtypeIdx]) {
4410 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4411 rNext = rPrevious->next;
4415 rNext = rPrevious->next;
4418 rzRules->next = NULL;
4420 rPrevious->next = rzRules;
4422 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4429void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4439 for (
int i = 0; i < PRIO_NUM; ++i) {
4440 for (
int j = 0; j < 2; ++j) {
4441 top = razRules[i][j];
4443 while (top != NULL) {
4444 if (!top->obj->geoPtMulti)
4446 if (top->obj->BBObj.GetValid()) {
4447 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4449 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4450 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4452 double minlon = top->obj->BBObj.GetMinLon();
4453 double maxlon = top->obj->BBObj.GetMaxLon();
4455 double lon1 = (lon - minlon) * d;
4456 double lon2 = (lon - maxlon) * d;
4458 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4461 top->obj->BBObj.Invalidate();
4482void s57chart::UpdateLUPs(
s57chart *pOwner) {
4486 for (
int i = 0; i < PRIO_NUM; ++i) {
4488 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4489 m_b2pointLUPS =
true;
4490 top = razRules[i][0];
4492 while (top != NULL) {
4493 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4499 if (top->obj->nRef < 2) {
4500 ps52plib->_LUP2rules(LUP, top->obj);
4501 _insertRules(top->obj, LUP, pOwner);
4502 top->obj->m_DisplayCat = LUP->DISC;
4512 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4513 m_b2pointLUPS =
true;
4514 top = razRules[i][1];
4516 while (top != NULL) {
4517 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4520 if (top->obj->nRef < 2) {
4521 ps52plib->_LUP2rules(LUP, top->obj);
4522 _insertRules(top->obj, LUP, pOwner);
4523 top->obj->m_DisplayCat = LUP->DISC;
4533 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4534 m_b2lineLUPS =
true;
4535 top = razRules[i][3];
4537 while (top != NULL) {
4538 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4539 top->obj->FeatureName, top->obj);
4541 ps52plib->_LUP2rules(LUP, top->obj);
4542 _insertRules(top->obj, LUP, pOwner);
4543 top->obj->m_DisplayCat = LUP->DISC;
4552 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4553 m_b2lineLUPS =
true;
4554 top = razRules[i][4];
4556 while (top != NULL) {
4557 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4560 ps52plib->_LUP2rules(LUP, top->obj);
4561 _insertRules(top->obj, LUP, pOwner);
4562 top->obj->m_DisplayCat = LUP->DISC;
4574 for (
int j = 0; j < LUPNAME_NUM; j++) {
4575 top = razRules[i][j];
4576 while (top != NULL) {
4577 top->obj->bCS_Added = 0;
4580 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4591 for (
int j = 0; j < LUPNAME_NUM; j++) {
4592 top = razRules[i][j];
4593 while (top != NULL) {
4595 ObjRazRules *ctop = top->child;
4596 while (NULL != ctop) {
4597 ctop->obj->bCS_Added = 0;
4598 free_mps(ctop->mps);
4601 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4618ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4619 float lat,
float lon,
ViewPort *VPoint) {
4620 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4621 std::vector<ObjRazRules *> selected_rules;
4626 char *curr_att = NULL;
4628 wxArrayOfS57attVal *attValArray = NULL;
4629 bool bleading_attribute =
false;
4631 for (
int i = 0; i < PRIO_NUM; ++i) {
4635 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4636 top = razRules[i][point_type];
4638 while (top != NULL) {
4639 if (top->obj->npt == 1) {
4640 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4642 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4644 if (ps52plib->ObjectRenderCheckCat(top)) {
4647 wxString curAttrName;
4648 curr_att = top->obj->att_array;
4649 n_attr = top->obj->n_attr;
4650 attValArray = top->obj->attVal;
4658 bleading_attribute =
false;
4660 while (attrCounter < n_attr) {
4661 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4664 S57attVal *pAttrVal = NULL;
4667 pAttrVal = attValArray->Item(attrCounter);
4671 wxString value = s57chart::GetAttributeValueAsString(
4672 pAttrVal, curAttrName);
4674 if (curAttrName == _T(
"LITVIS")) {
4675 if (value.StartsWith(_T(
"obsc"))) bviz =
false;
4676 }
else if (curAttrName == _T(
"VALNMR"))
4677 value.ToDouble(&valnmr);
4683 if (bviz && (valnmr > 0.1)) {
4687 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4688 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4689 ref_lat, ref_lon, &olat, &olon);
4691 double dlat = lat - olat;
4692 double dy = dlat * 60 / cos(olat * PI / 180.);
4693 double dlon = lon - olon;
4694 double dx = dlon * 60;
4695 double manhat = abs(dy) + abs(dx);
4699 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4701 selected_rules.push_back(top);
4718 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4719 ret_ptr->Append(selected_rules[i]);
4725ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4726 float select_radius,
4728 int selection_mask) {
4729 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4730 std::vector<ObjRazRules *> selected_rules;
4732 PrepareForRender(VPoint, ps52plib);
4738 for (
int i = 0; i < PRIO_NUM; ++i) {
4739 if (selection_mask & MASK_POINT) {
4742 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4743 top = razRules[i][point_type];
4745 while (top != NULL) {
4746 if (top->obj->npt ==
4749 if (ps52plib->ObjectRenderCheck(top)) {
4750 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4751 selected_rules.push_back(top);
4758 ObjRazRules *child_item = top->child;
4759 while (child_item != NULL) {
4760 if (ps52plib->ObjectRenderCheck(child_item)) {
4761 if (DoesLatLonSelectObject(lat, lon, select_radius,
4763 selected_rules.push_back(child_item);
4766 child_item = child_item->next;
4774 if (selection_mask & MASK_AREA) {
4777 int area_boundary_type =
4778 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4779 top = razRules[i][area_boundary_type];
4780 while (top != NULL) {
4781 if (ps52plib->ObjectRenderCheck(top)) {
4782 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4783 selected_rules.push_back(top);
4790 if (selection_mask & MASK_LINE) {
4792 top = razRules[i][2];
4794 while (top != NULL) {
4795 if (ps52plib->ObjectRenderCheck(top)) {
4796 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4797 selected_rules.push_back(top);
4808 auto sortObjs = [lat, lon,
this](
const ObjRazRules *obj1,
4809 const ObjRazRules *obj2) ->
bool {
4810 double br1, dd1, br2, dd2;
4812 if (obj1->obj->Primitive_type == GEO_POINT &&
4813 obj2->obj->Primitive_type == GEO_POINT) {
4814 double lat1, lat2, lon1, lon2;
4815 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4816 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin, ref_lat,
4817 ref_lon, &lat1, &lon1);
4819 if (lon1 > 180.0) lon1 -= 360.;
4821 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4822 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin, ref_lat,
4823 ref_lon, &lat2, &lon2);
4825 if (lon2 > 180.0) lon2 -= 360.;
4827 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4828 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4835 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4839 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4840 ret_ptr->Append(selected_rules[i]);
4846bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4848 switch (obj->Primitive_type) {
4852 if (!obj->BBObj.GetValid())
return false;
4854 if (1 == obj->npt) {
4859 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4861 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4864 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4865 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4872 sbox.Set(olat, olon, olat, olon);
4874 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4875 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4880 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4887 if (!obj->BBObj.GetValid())
return false;
4890 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4892 double *pdl = obj->geoPtMulti;
4893 for (
int ip = 0; ip < obj->npt; ip++) {
4894 double lon_point = *pdl++;
4895 double lat_point = *pdl++;
4897 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4898 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4909 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4912 return IsPointInObjArea(lat, lon, select_radius, obj);
4917 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4919 float sel_rad_meters = select_radius * 1852 * 60;
4920 double easting, northing;
4921 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4928 pt *ppt = obj->geoPt;
4931 double xr = obj->x_rate;
4932 double xo = obj->x_origin;
4933 double yr = obj->y_rate;
4934 double yo = obj->y_origin;
4936 double north0 = (ppt->y * yr) + yo;
4937 double east0 = (ppt->x * xr) + xo;
4940 for (
int ip = 1; ip < npt; ip++) {
4941 double north = (ppt->y * yr) + yo;
4942 double east = (ppt->x * xr) + xo;
4945 if (northing >= (fmin(north, north0) - sel_rad_meters))
4946 if (northing <= (fmax(north, north0) + sel_rad_meters))
4947 if (easting >= (fmin(east, east0) - sel_rad_meters))
4948 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4958 if (obj->m_ls_list) {
4960 unsigned char *vbo_point =
4961 (
unsigned char *)obj->m_chart_context
4963 line_segment_element *ls = obj->m_ls_list;
4965 while (ls && vbo_point) {
4967 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4968 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4969 nPoints = ls->pedge->nCount;
4971 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4975 float north0 = ppt[1];
4976 float east0 = ppt[0];
4980 for (
int ip = 0; ip < nPoints - 1; ip++) {
4981 float north = ppt[1];
4982 float east = ppt[0];
4984 if (northing >= (fmin(north, north0) - sel_rad_meters))
4985 if (northing <= (fmax(north, north0) + sel_rad_meters))
4986 if (easting >= (fmin(east, east0) - sel_rad_meters))
4987 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
5014wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
5015 wxString ret_val = _T(
"");
5018 const char *att_code;
5020 wxString file(g_csv_locn);
5021 file.Append(_T(
"/s57attributes.csv"));
5023 if (!wxFileName::FileExists(file)) {
5024 wxString msg(_T(
" Could not open "));
5031 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5033 CC_ExactString,
"Code");
5039 wxString ei_file(g_csv_locn);
5040 ei_file.Append(_T(
"/s57expectedinput.csv"));
5042 if (!wxFileName::FileExists(ei_file)) {
5043 wxString msg(_T(
" Could not open "));
5044 msg.Append(ei_file);
5050 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5051 CSVIngest(ei_file.mb_str());
5053 char **papszFields = NULL;
5054 int bSelected = FALSE;
5060 while (!bSelected && iline + 1 < psTable->nLineCount) {
5062 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5064 if (!strcmp(papszFields[0], att_code)) {
5065 if (atoi(papszFields[1]) == ival) {
5066 ret_val = wxString(papszFields[2], wxConvUTF8);
5071 CSLDestroy(papszFields);
5079bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5083 if (obj->pPolyTessGeo) {
5084 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5086 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5088 TriPrim *pTP = ppg->tri_prim_head;
5090 MyPoint pvert_list[3];
5094 double easting, northing;
5095 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5099 if (!ppg->m_bSMSENC) {
5100 double y_rate = obj->y_rate;
5101 double y_origin = obj->y_origin;
5102 double x_rate = obj->x_rate;
5103 double x_origin = obj->x_origin;
5105 double northing_scaled = (northing - y_origin) / y_rate;
5106 double easting_scaled = (easting - x_origin) / x_rate;
5107 northing = northing_scaled;
5108 easting = easting_scaled;
5113 if (pTP->tri_box.Contains(lat, lon)) {
5114 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5115 double *p_vertex = pTP->p_vertex;
5117 switch (pTP->type) {
5118 case PTG_TRIANGLE_FAN: {
5119 for (
int it = 0; it < pTP->nVert - 2; it++) {
5120 pvert_list[0].x = p_vertex[0];
5121 pvert_list[0].y = p_vertex[1];
5123 pvert_list[1].x = p_vertex[(it * 2) + 2];
5124 pvert_list[1].y = p_vertex[(it * 2) + 3];
5126 pvert_list[2].x = p_vertex[(it * 2) + 4];
5127 pvert_list[2].y = p_vertex[(it * 2) + 5];
5129 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5137 case PTG_TRIANGLE_STRIP: {
5138 for (
int it = 0; it < pTP->nVert - 2; it++) {
5139 pvert_list[0].x = p_vertex[(it * 2)];
5140 pvert_list[0].y = p_vertex[(it * 2) + 1];
5142 pvert_list[1].x = p_vertex[(it * 2) + 2];
5143 pvert_list[1].y = p_vertex[(it * 2) + 3];
5145 pvert_list[2].x = p_vertex[(it * 2) + 4];
5146 pvert_list[2].y = p_vertex[(it * 2) + 5];
5148 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5156 case PTG_TRIANGLES: {
5157 for (
int it = 0; it < pTP->nVert; it += 3) {
5158 pvert_list[0].x = p_vertex[(it * 2)];
5159 pvert_list[0].y = p_vertex[(it * 2) + 1];
5161 pvert_list[1].x = p_vertex[(it * 2) + 2];
5162 pvert_list[1].y = p_vertex[(it * 2) + 3];
5164 pvert_list[2].x = p_vertex[(it * 2) + 4];
5165 pvert_list[2].y = p_vertex[(it * 2) + 5];
5167 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5176 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5177 float *p_vertex = (
float *)pTP->p_vertex;
5179 switch (pTP->type) {
5180 case PTG_TRIANGLE_FAN: {
5181 for (
int it = 0; it < pTP->nVert - 2; it++) {
5182 pvert_list[0].x = p_vertex[0];
5183 pvert_list[0].y = p_vertex[1];
5185 pvert_list[1].x = p_vertex[(it * 2) + 2];
5186 pvert_list[1].y = p_vertex[(it * 2) + 3];
5188 pvert_list[2].x = p_vertex[(it * 2) + 4];
5189 pvert_list[2].y = p_vertex[(it * 2) + 5];
5191 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5199 case PTG_TRIANGLE_STRIP: {
5200 for (
int it = 0; it < pTP->nVert - 2; it++) {
5201 pvert_list[0].x = p_vertex[(it * 2)];
5202 pvert_list[0].y = p_vertex[(it * 2) + 1];
5204 pvert_list[1].x = p_vertex[(it * 2) + 2];
5205 pvert_list[1].y = p_vertex[(it * 2) + 3];
5207 pvert_list[2].x = p_vertex[(it * 2) + 4];
5208 pvert_list[2].y = p_vertex[(it * 2) + 5];
5210 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5218 case PTG_TRIANGLES: {
5219 for (
int it = 0; it < pTP->nVert; it += 3) {
5220 pvert_list[0].x = p_vertex[(it * 2)];
5221 pvert_list[0].y = p_vertex[(it * 2) + 1];
5223 pvert_list[1].x = p_vertex[(it * 2) + 2];
5224 pvert_list[1].y = p_vertex[(it * 2) + 3];
5226 pvert_list[2].x = p_vertex[(it * 2) + 4];
5227 pvert_list[2].y = p_vertex[(it * 2) + 5];
5229 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5252wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5253 wxString curAttrName) {
5257 pval = obj->attVal->Item(iatt);
5258 switch (pval->valType) {
5261 wxString val_str((
char *)(pval->value), wxConvUTF8);
5263 if (val_str.ToLong(&ival)) {
5265 value = _T(
"Unknown");
5267 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5268 if (!decode_val.IsEmpty()) {
5271 iv.Printf(_T(
" (%d)"), (
int)ival);
5274 value.Printf(_T(
"%d"), (
int)ival);
5278 else if (val_str.IsEmpty())
5279 value = _T(
"Unknown");
5283 wxString value_increment;
5284 wxStringTokenizer tk(val_str, wxT(
","));
5286 if (tk.HasMoreTokens()) {
5287 while (tk.HasMoreTokens()) {
5288 wxString token = tk.GetNextToken();
5290 if (token.ToLong(&ival)) {
5291 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5293 value_increment.Printf(_T(
" (%d)"), (
int)ival);
5295 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5297 if (iv) value_increment.Prepend(wxT(
", "));
5298 value.Append(value_increment);
5301 if (iv) value.Append(_T(
","));
5302 value.Append(token);
5308 value.Append(val_str);
5311 value = _T(
"[NULL VALUE]");
5317 int ival = *((
int *)pval->value);
5318 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5320 if (!decode_val.IsEmpty()) {
5323 iv.Printf(_T(
"(%d)"), ival);
5326 value.Printf(_T(
"(%d)"), ival);
5334 double dval = *((
double *)pval->value);
5335 wxString val_suffix = _T(
" m");
5338 if ((curAttrName == _T(
"VERCLR")) || (curAttrName == _T(
"VERCCL")) ||
5339 (curAttrName == _T(
"VERCOP")) || (curAttrName == _T(
"HEIGHT")) ||
5340 (curAttrName == _T(
"HORCLR"))) {
5341 switch (ps52plib->m_nDepthUnitDisplay) {
5344 dval = dval * 3 * 39.37 / 36;
5345 val_suffix = _T(
" ft");
5352 else if ((curAttrName == _T(
"VALSOU")) || (curAttrName == _T(
"DRVAL1")) ||
5353 (curAttrName == _T(
"DRVAL2")) || (curAttrName == _T(
"VALDCO"))) {
5354 switch (ps52plib->m_nDepthUnitDisplay) {
5356 dval = dval * 3 * 39.37 / 36;
5357 val_suffix = _T(
" ft");
5360 dval = dval * 3 * 39.37 / 36;
5362 val_suffix = _T(
" fathoms");
5369 else if (curAttrName == _T(
"SECTR1"))
5370 val_suffix = _T(
"°");
5371 else if (curAttrName == _T(
"SECTR2"))
5372 val_suffix = _T(
"°");
5373 else if (curAttrName == _T(
"ORIENT"))
5374 val_suffix = _T(
"°");
5375 else if (curAttrName == _T(
"VALNMR"))
5376 val_suffix = _T(
" Nm");
5377 else if (curAttrName == _T(
"SIGPER"))
5378 val_suffix = _T(
"s");
5379 else if (curAttrName == _T(
"VALACM"))
5380 val_suffix = _T(
" Minutes/year");
5381 else if (curAttrName == _T(
"VALMAG"))
5382 val_suffix = _T(
"°");
5383 else if (curAttrName == _T(
"CURVEL"))
5384 val_suffix = _T(
" kt");
5386 if (dval - floor(dval) < 0.01)
5387 value.Printf(_T(
"%2.0f"), dval);
5389 value.Printf(_T(
"%4.1f"), dval);
5391 value << val_suffix;
5396 case OGR_REAL_LST: {
5403wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5404 wxString AttrName) {
5405 if (NULL == pAttrVal)
return _T(
"");
5408 switch (pAttrVal->valType) {
5410 if (pAttrVal->value) {
5411 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5413 if (val_str.ToLong(&ival)) {
5415 value = _T(
"Unknown");
5417 wxString decode_val = GetAttributeDecode(AttrName, ival);
5418 if (!decode_val.IsEmpty()) {
5421 iv.Printf(_T(
"(%d)"), (
int)ival);
5424 value.Printf(_T(
"%d"), (
int)ival);
5428 else if (val_str.IsEmpty())
5429 value = _T(
"Unknown");
5433 wxString value_increment;
5434 wxStringTokenizer tk(val_str, wxT(
","));
5436 while (tk.HasMoreTokens()) {
5437 wxString token = tk.GetNextToken();
5439 if (token.ToLong(&ival)) {
5440 wxString decode_val = GetAttributeDecode(AttrName, ival);
5441 if (!decode_val.IsEmpty())
5442 value_increment = decode_val;
5444 value_increment.Printf(_T(
" %d"), (
int)ival);
5446 if (iv) value_increment.Prepend(wxT(
", "));
5448 value.Append(value_increment);
5452 value.Append(val_str);
5455 value = _T(
"[NULL VALUE]");
5461 int ival = *((
int *)pAttrVal->value);
5462 wxString decode_val = GetAttributeDecode(AttrName, ival);
5464 if (!decode_val.IsEmpty()) {
5467 iv.Printf(_T(
"(%d)"), ival);
5470 value.Printf(_T(
"(%d)"), ival);
5478 double dval = *((
double *)pAttrVal->value);
5479 wxString val_suffix = _T(
" m");
5482 if ((AttrName == _T(
"VERCLR")) || (AttrName == _T(
"VERCCL")) ||
5483 (AttrName == _T(
"VERCOP")) || (AttrName == _T(
"HEIGHT")) ||
5484 (AttrName == _T(
"HORCLR"))) {
5485 switch (ps52plib->m_nDepthUnitDisplay) {
5488 dval = dval * 3 * 39.37 / 36;
5489 val_suffix = _T(
" ft");
5496 else if ((AttrName == _T(
"VALSOU")) || (AttrName == _T(
"DRVAL1")) ||
5497 (AttrName == _T(
"DRVAL2"))) {
5498 switch (ps52plib->m_nDepthUnitDisplay) {
5500 dval = dval * 3 * 39.37 / 36;
5501 val_suffix = _T(
" ft");
5504 dval = dval * 3 * 39.37 / 36;
5506 val_suffix = _T(
" fathoms");
5513 else if (AttrName == _T(
"SECTR1"))
5514 val_suffix = _T(
"°");
5515 else if (AttrName == _T(
"SECTR2"))
5516 val_suffix = _T(
"°");
5517 else if (AttrName == _T(
"ORIENT"))
5518 val_suffix = _T(
"°");
5519 else if (AttrName == _T(
"VALNMR"))
5520 val_suffix = _T(
" Nm");
5521 else if (AttrName == _T(
"SIGPER"))
5522 val_suffix = _T(
"s");
5523 else if (AttrName == _T(
"VALACM"))
5524 val_suffix = _T(
" Minutes/year");
5525 else if (AttrName == _T(
"VALMAG"))
5526 val_suffix = _T(
"°");
5527 else if (AttrName == _T(
"CURVEL"))
5528 val_suffix = _T(
" kt");
5530 if (dval - floor(dval) < 0.01)
5531 value.Printf(_T(
"%2.0f"), dval);
5533 value.Printf(_T(
"%4.1f"), dval);
5535 value << val_suffix;
5540 case OGR_REAL_LST: {
5548 int positionDiff = l1->position.Cmp(l2->position);
5549 if (positionDiff < 0)
return false;
5551 int attrIndex1 = l1->attributeNames.Index(_T(
"SECTR1"));
5552 int attrIndex2 = l2->attributeNames.Index(_T(
"SECTR1"));
5555 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5556 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5557 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5559 double angle1, angle2;
5560 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5561 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5563 return angle1 < angle2;
5566static const char *type2str(GeoPrim_t type) {
5567 const char *r =
"Unknown";
5588wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5591 wxString curAttrName, value;
5592 bool isLight =
false;
5595 wxString classAttributes;
5597 wxString lightsHtml;
5598 wxString positionString;
5599 std::vector<S57Light *> lights;
5603 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5604 node = node->GetPrevious()) {
5605 ObjRazRules *current = node->GetData();
5606 positionString.Clear();
5610 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5612 if (current->obj->Primitive_type == GEO_META)
continue;
5613 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5615 className = wxString(current->obj->FeatureName, wxConvUTF8);
5618 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5623 const char *name_desc;
5624 if (g_csv_locn.Len()) {
5625 wxString oc_file(g_csv_locn);
5626 oc_file.Append(_T(
"/s57objectclasses.csv"));
5627 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5628 current->obj->FeatureName,
5629 CC_ExactString,
"ObjectClass");
5635 if (0 == strlen(name_desc)) {
5636 name_desc = current->obj->FeatureName;
5637 classDesc = wxString(name_desc, wxConvUTF8, 1);
5638 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5640 classDesc = wxString(name_desc, wxConvUTF8);
5647 classAttributes = _T(
"");
5648 index.Printf(_T(
"Feature Index: %d<br>"), current->obj->Index);
5649 classAttributes << index;
5652 LUPstring.Printf(_T(
"LUP RCID: %d<br>"), current->LUP->RCID);
5653 classAttributes << LUPstring;
5656 LLBBox bbox = current->obj->BBObj;
5657 Bbox.Printf(_T(
"Lat/Lon box: %g %g %g %g<br>"), bbox.GetMinLat(),
5658 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5659 classAttributes << Bbox;
5662 Type.Printf(_T(
" Type: %s<br>"), type2str(current->obj->Primitive_type));
5663 classAttributes << Type;
5665 LUPstring = _T(
" LUP ATTC: ");
5666 if (current->LUP->ATTArray.size())
5667 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5668 LUPstring += _T(
"<br>");
5669 classAttributes << LUPstring;
5671 LUPstring = _T(
" LUP INST: ");
5672 LUPstring += current->LUP->INST;
5673 LUPstring += _T(
"<br><br>");
5674 classAttributes << LUPstring;
5677 if (GEO_POINT == current->obj->Primitive_type) {
5679 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5680 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5681 ref_lat, ref_lon, &lat, &lon);
5683 if (lon > 180.0) lon -= 360.;
5685 positionString.Clear();
5686 positionString += toSDMM(1, lat);
5687 positionString << _T(
" ");
5688 positionString += toSDMM(2, lon);
5692 curLight->position = positionString;
5693 curLight->hasSectors =
false;
5694 lights.push_back(curLight);
5700 if (current->obj->att_array) {
5701 char *curr_att = current->obj->att_array;
5707 attribStr << _T(
"<table border=0 cellspacing=0 cellpadding=0>");
5710 ret_val << _T(
"<p>") << classAttributes;
5713 bool inDepthRange =
false;
5715 while (attrCounter < current->obj->n_attr) {
5717 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5724 assert(curLight !=
nullptr);
5725 curLight->attributeNames.Add(curAttrName);
5726 if (curAttrName.StartsWith(_T(
"SECTR"))) curLight->hasSectors =
true;
5728 if (curAttrName == _T(
"DRVAL1")) {
5729 attribStr << _T(
"<tr><td><font size=-1>");
5730 inDepthRange =
true;
5731 }
else if (curAttrName == _T(
"DRVAL2")) {
5732 attribStr << _T(
" - ");
5733 inDepthRange =
false;
5736 attribStr << _T(
"</font></td></tr>\n");
5737 inDepthRange =
false;
5739 attribStr << _T(
"<tr><td valign=top><font size=-2>");
5740 if (curAttrName == _T(
"catgeo"))
5741 attribStr << _T(
"CATGEO");
5743 attribStr << curAttrName;
5744 attribStr << _T(
"</font></td><td> </td><td ")
5745 _T("valign=top><font size=-1>");
5756 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5761 wxString AttrNamesFiles =
5762 _T("PICREP,TXTDSC,NTXTDS");
5764 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5765 if (value.Find(_T(".XML")) == wxNOT_FOUND) {
5766 file.Assign(GetFullPath());
5767 file.Assign(file.GetPath(), value);
5770 if (file.IsCaseSensitive()) {
5771 wxDir dir(file.GetPath());
5773 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
5775 if (filename.IsSameAs(value,
false)) {
5777 file.Assign(file.GetPath(), value);
5780 cont = dir.GetNext(&filename);
5787 wxString::Format(_T(
"<a href=\"%s\">%s</a>"),
5788 file.GetFullPath(), file.GetFullName());
5790 value = value + _T(
" <font color=\"red\">[ ") +
5791 _(
"this file is not available") + _T(
" ]</font>");
5795 _T(
"DATEND,DATSTA,PEREND,PERSTA");
5796 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5799 wxString ts = value;
5801 ts.Replace(wxT(
"--"),
5803 if (ts.Length() < 5) {
5808 if (ts.Length() < 7) {
5813 wxString::const_iterator end;
5815 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5817 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5818 if (d) ts.Append(wxString::Format(wxT(
" %d"), dt.GetDay()));
5819 if (dt.GetYear() > 0)
5820 ts.Append(wxString::Format(wxT(
", %i"), dt.GetYear()));
5821 if (curAttrName == _T(
"PEREND"))
5822 ts = _(
"Period ends: ") + ts + wxT(
" (") + value + wxT(
")");
5823 if (curAttrName == _T(
"PERSTA"))
5824 ts = _(
"Period starts: ") + ts + wxT(
" (") + value + wxT(
")");
5825 if (curAttrName == _T(
"DATEND"))
5826 ts = _(
"Date ending: ") + ts + wxT(
" (") + value + wxT(
")");
5827 if (curAttrName == _T(
"DATSTA"))
5828 ts = _(
"Date starting: ") + ts + wxT(
" (") + value + wxT(
")");
5832 if (curAttrName == _T(
"TS_TSP")) {
5839 wxStringTokenizer tk(value, wxT(
","));
5844 ts1 = tk.GetNextToken().Trim(
false);
5847 }
while ((ts1.Left(2).ToLong(&l)));
5848 ts = _T(
"Tidal Streams referred to<br><b>");
5849 ts.Append(tk.GetNextToken()).Append(_T(
"</b> at <b>")).Append(ts1);
5850 ts.Append(_T(
"</b><br><table >"));
5852 while (tk.HasMoreTokens()) {
5853 ts.Append(_T(
"<tr><td>"));
5854 wxString s1(wxString::Format(_T(
"%+dh "), i));
5856 ts.Append(_T(
"</td><td>"));
5857 s1 = tk.GetNextToken();
5859 s1 =
"°</td><td>";
5861 s1 = tk.GetNextToken();
5864 ts.Append(_T(
"</td></tr>"));
5867 ts.Append(_T(
"</table>"));
5872 assert(curLight !=
nullptr);
5873 curLight->attributeValues.Add(value);
5875 if (curAttrName == _T(
"INFORM") || curAttrName == _T(
"NINFOM"))
5876 value.Replace(_T(
"|"), _T(
"<br>"));
5878 if (curAttrName == _T(
"catgeo"))
5879 attribStr << type2str(current->obj->Primitive_type);
5883 if (!(curAttrName == _T(
"DRVAL1"))) {
5884 attribStr << _T(
"</font></td></tr>\n");
5894 attribStr << _T(
"</table>\n");
5896 objText += _T(
"<b>") + classDesc + _T(
"</b> <font size=-2>(") +
5897 className + _T(
")</font>") + _T(
"<br>");
5899 if (positionString.Length())
5900 objText << _T(
"<font size=-2>") << positionString
5901 << _T(
"</font><br>\n");
5903 if (noAttr > 0) objText << attribStr;
5905 if (node != rule_list->GetFirst()) objText += _T(
"<hr noshade>");
5906 objText += _T(
"<br>");
5912 if (!lights.empty()) {
5913 assert(curLight !=
nullptr);
5918 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5922 for (
auto const &thisLight : lights) {
5925 if (thisLight->position != lastPos) {
5926 lastPos = thisLight->position;
5928 if (thisLight != *lights.begin())
5929 lightsHtml << _T(
"</table>\n<hr noshade>\n");
5931 lightsHtml << _T(
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>");
5932 lightsHtml << _T(
"<font size=-2>") << thisLight->position
5933 << _T(
"</font><br>\n");
5935 if (curLight->hasSectors)
5937 "<font size=-2>(Sector angles are True Bearings from "
5938 "Seaward)</font><br>");
5940 lightsHtml << _T(
"<table>");
5943 lightsHtml << _T(
"<tr>");
5944 lightsHtml << _T(
"<td><font size=-1>");
5947 attrIndex = thisLight->attributeNames.Index(_T(
"COLOUR"));
5948 if (attrIndex != wxNOT_FOUND) {
5949 wxString color = thisLight->attributeValues.Item(attrIndex);
5950 if (color == _T(
"red (3)") || color == _T(
"red(3)"))
5952 _T(
"<table border=0><tr><td ")
5953 _T("bgcolor=red> </td></tr></table> ");
5954 else if (color == _T("green (4)") || color == _T("green(4)"))
5956 _T("<table border=0><tr><td ")
5957 _T("bgcolor=green> </td></tr></table> ");
5958 else if (color == _T("white (1)") || color == _T("white(1)"))
5960 _T("<table border=0><tr><td ")
5961 _T("bgcolor=white> </td></tr></table> ");
5962 else if (color == _T("yellow (6)") || color == _T("yellow(6)"))
5964 _T("<table border=0><tr><td ")
5965 _T("bgcolor=yellow> </td></tr></table> ");
5966 else if (color == _T("blue (5)") || color == _T("blue(5)"))
5968 _T("<table border=0><tr><td ")
5969 _T("bgcolor=blue> </td></tr></table> ");
5970 else if (color == _T("magenta (12)") || color == _T("magenta(12)"))
5972 _T("<table border=0><tr><td ")
5973 _T("bgcolor=magenta> </td></tr></table> ");
5976 _T("<table border=0><tr><td ")
5977 _T("bgcolor=grey> ? </td></tr></table> ");
5980 int visIndex = thisLight->attributeNames.Index(_T("LITVIS"));
5981 if (visIndex != wxNOT_FOUND) {
5982 wxString vis = thisLight->attributeValues.Item(visIndex);
5983 if (vis.Contains(_T(
"8"))) {
5984 if (attrIndex != wxNOT_FOUND) {
5985 wxString color = thisLight->attributeValues.Item(attrIndex);
5986 if ((color == _T(
"red (3)") || color == _T(
"red(3)")))
5988 _T(
"<table border=0><tr><td ")
5989 _T("bgcolor=DarkRed> </td></tr></table> ");
5990 if ((color == _T("green (4)") || color == _T("green(4)")))
5992 _T("<table border=0><tr><td ")
5993 _T("bgcolor=DarkGreen> </td></tr></table> ");
5994 if ((color == _T("white (1)") || color == _T("white(1)")))
5996 _T("<table border=0><tr><td ")
5997 _T("bgcolor=GoldenRod> </td></tr></table> ");
6002 lightsHtml << colorStr;
6004 lightsHtml << _T("</font></td><td><font size=-1><nobr><b>");
6006 attrIndex = thisLight->attributeNames.Index(_T("LITCHR"));
6007 if (attrIndex != wxNOT_FOUND) {
6008 wxString character = thisLight->attributeValues[attrIndex];
6009 lightsHtml << character.BeforeFirst(wxChar(
'(')) << _T(
" ");
6012 attrIndex = thisLight->attributeNames.Index(_T(
"SIGGRP"));
6013 if (attrIndex != wxNOT_FOUND) {
6014 lightsHtml << thisLight->attributeValues[attrIndex];
6015 lightsHtml << _T(
" ");
6018 attrIndex = thisLight->attributeNames.Index(_T(
"COLOUR"));
6019 if (attrIndex != wxNOT_FOUND) {
6020 lightsHtml << _T(
" ")
6021 << thisLight->attributeValues.Item(attrIndex).Upper()[0];
6022 lightsHtml << _T(
" ");
6025 attrIndex = thisLight->attributeNames.Index(_T(
"SIGPER"));
6026 if (attrIndex != wxNOT_FOUND) {
6027 lightsHtml << thisLight->attributeValues[attrIndex];
6028 lightsHtml << _T(
" ");
6031 attrIndex = thisLight->attributeNames.Index(_T(
"HEIGHT"));
6032 if (attrIndex != wxNOT_FOUND) {
6033 lightsHtml << thisLight->attributeValues[attrIndex];
6034 lightsHtml << _T(
" ");
6037 attrIndex = thisLight->attributeNames.Index(_T(
"VALNMR"));
6038 if (attrIndex != wxNOT_FOUND) {
6039 lightsHtml << thisLight->attributeValues[attrIndex];
6040 lightsHtml << _T(
" ");
6043 lightsHtml << _T(
"</b>");
6045 attrIndex = thisLight->attributeNames.Index(_T(
"SECTR1"));
6046 if (attrIndex != wxNOT_FOUND) {
6047 lightsHtml << _T(
"(") << thisLight->attributeValues[attrIndex];
6048 lightsHtml << _T(
" - ");
6049 attrIndex = thisLight->attributeNames.Index(_T(
"SECTR2"));
6050 lightsHtml << thisLight->attributeValues[attrIndex] << _T(
") ");
6053 lightsHtml << _T(
"</nobr>");
6055 attrIndex = thisLight->attributeNames.Index(_T(
"CATLIT"));
6056 if (attrIndex != wxNOT_FOUND) {
6057 lightsHtml << _T(
"<nobr>");
6058 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6060 lightsHtml << _T(
"</nobr> ");
6063 attrIndex = thisLight->attributeNames.Index(_T(
"EXCLIT"));
6064 if (attrIndex != wxNOT_FOUND) {
6065 lightsHtml << _T(
"<nobr>");
6066 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6068 lightsHtml << _T(
"</nobr> ");
6071 attrIndex = thisLight->attributeNames.Index(_T(
"OBJNAM"));
6072 if (attrIndex != wxNOT_FOUND) {
6073 lightsHtml << _T(
"<br><nobr>");
6074 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6075 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6076 lightsHtml << _T(
"</nobr> ");
6079 lightsHtml << _T(
"</font></td>");
6080 lightsHtml << _T(
"</tr>");
6082 thisLight->attributeNames.Clear();
6083 thisLight->attributeValues.Clear();
6086 lightsHtml << _T(
"</table><hr noshade>\n");
6087 ret_val = lightsHtml << ret_val;
6101bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6102 if (NULL == g_poRegistrar) {
6103 wxLogMessage(_T(
" Error: No ClassRegistrar in InitENCMinimal."));
6107 m_pENCDS =
new OGRS57DataSource;
6109 m_pENCDS->SetS57Registrar(g_poRegistrar);
6111 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6114 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6115 pENCReader->SetClassBased(g_poRegistrar);
6117 pENCReader->Ingest();
6122OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6124 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6126 if ((NULL != pENCReader) && (NULL != g_poRegistrar)) {
6128 g_poRegistrar->SelectClass(
"M_COVR");
6131 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefn(
6132 g_poRegistrar, g_poRegistrar->GetOBJL(), pENCReader->GetOptionFlags());
6135 pENCReader->AddFeatureDefn(poDefn);
6138 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6141 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6144 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6155OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6159 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6162 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6165 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6168 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6177int s57chart::GetENCScale(
void) {
6178 if (NULL == m_pENCDS)
return 0;
6185 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6188 return pENCReader->GetCSCL();
6198void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6199 const char *pszErrorMsg) {
6200#define ERR_BUF_LEN 2000
6202 char buf[ERR_BUF_LEN + 1];
6204 if (eErrClass == CE_Debug)
6205 sprintf(buf,
" %s", pszErrorMsg);
6206 else if (eErrClass == CE_Warning)
6207 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6209 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6211 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6212 wxString msg(buf, wxConvUTF8);
6218 if (eErrClass == CE_Fatal) {
6219 longjmp(env_ogrf, 1);
6230const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6231 const char *pszKeyFieldValue,
6232 CSVCompareCriteria eCriteria,
6233 const char *pszTargetField)
6242 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6243 pszKeyFieldValue, eCriteria);
6245 if (papszRecord == NULL)
return "";
6250 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6251 if (iTargetField < 0)
return "";
6253 if (iTargetField >= CSLCount(papszRecord))
return "";
6255 return (papszRecord[iTargetField]);
6269bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6293 std::vector<s57Sector_t> §orlegs) {
6294 float rangeScale = 0.0;
6296 if (sectorlegs.size() > 0) {
6297 std::vector<int> sectorangles;
6298 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6299 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6302 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6303 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6308 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6309 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6315 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6318 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6319 powf((
float)(lightPos.y - end1.y), 2));
6321 if (rangeScale == 0.0) {
6324 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6328 rangePx = rangePx * rangeScale;
6330 int penWidth = rangePx / 8;
6331 penWidth = wxMin(20, penWidth);
6332 penWidth = wxMax(5, penWidth);
6335 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
6336 penWidth, wxPENSTYLE_SOLID);
6337 arcpen->SetCap(wxCAP_BUTT);
6340 float angle1, angle2;
6341 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6342 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6343 if (angle1 > angle2) {
6346 int lpx = lightPos.x;
6347 int lpy = lightPos.y;
6349 wxPoint arcpoints[150];
6352 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6356 int narc = (angle2 - angle1) / step;
6358 step = (angle2 - angle1) / (
float)narc;
6360 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6361 wxPoint yellowCone[3];
6362 yellowCone[0] = lightPos;
6363 yellowCone[1] = end1;
6364 yellowCone[2] = end2;
6365 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6368 wxColor c = sectorlegs[i].color;
6369 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6370 dc.SetBrush(wxBrush(c));
6371 dc.StrokePolygon(3, yellowCone, 0, 0);
6374 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6375 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6376 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6377 arcpoints[npoints].x = x;
6378 arcpoints[npoints].y = y;
6381 dc.StrokeLines(npoints, arcpoints);
6385 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6391 bool haveAngle1 =
false;
6392 bool haveAngle2 =
false;
6393 int sec1 = (int)sectorlegs[i].sector1;
6394 int sec2 = (int)sectorlegs[i].sector2;
6395 if (sec1 > 360) sec1 -= 360;
6396 if (sec2 > 360) sec2 -= 360;
6398 if ((sec2 == 360) && (sec1 == 0))
6401 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6402 if (sectorangles[j] == sec1) haveAngle1 =
true;
6403 if (sectorangles[j] == sec2) haveAngle2 =
true;
6407 dc.StrokeLine(lightPos, end1);
6408 sectorangles.push_back(sec1);
6412 dc.StrokeLine(lightPos, end2);
6413 sectorangles.push_back(sec2);
6420void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6421 std::vector<s57Sector_t> §orlegs) {
6422 float rangeScale = 0.0;
6424 if (sectorlegs.size() > 0) {
6425 std::vector<int> sectorangles;
6426 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6427 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6430 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6431 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6436 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6437 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6443 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6446 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6447 powf((
float)(lightPos.y - end1.y), 2));
6449 if (rangeScale == 0.0) {
6452 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6456 rangePx = rangePx * rangeScale;
6458 float arcw = rangePx / 10;
6459 arcw = wxMin(20, arcw);
6460 arcw = wxMax(5, arcw);
6464 float angle1, angle2;
6465 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6466 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6467 if (angle1 > angle2) {
6470 int lpx = lightPos.x;
6471 int lpy = lightPos.y;
6473 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6474 wxPoint yellowCone[3];
6475 yellowCone[0] = lightPos;
6476 yellowCone[1] = end1;
6477 yellowCone[2] = end2;
6478 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6481 wxColor c = sectorlegs[i].color;
6482 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6483 dc.SetBrush(wxBrush(c));
6484 dc.StrokePolygon(3, yellowCone, 0, 0);
6488 wxPoint r(lpx, lpy);
6491 float rad = rangePx;
6515 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6518 glBindBuffer(GL_ARRAY_BUFFER, 0);
6519 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6521 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6522 glEnableVertexAttribArray(mPosAttrib);
6526 glGetUniformLocation(shader->programId(),
"circle_radius");
6527 glUniform1f(radiusloc, rad);
6531 glGetUniformLocation(shader->programId(),
"circle_center");
6535 glUniform2fv(centerloc, 1, ctrv);
6538 wxColour colorb = sectorlegs[i].color;
6540 colorv[0] = colorb.Red() / float(256);
6541 colorv[1] = colorb.Green() / float(256);
6542 colorv[2] = colorb.Blue() / float(256);
6543 colorv[3] = colorb.Alpha() / float(256);
6546 glGetUniformLocation(shader->programId(),
"circle_color");
6547 glUniform4fv(colloc, 1, colorv);
6557 glGetUniformLocation(shader->programId(),
"border_color");
6558 glUniform4fv(bcolloc, 1, bcolorv);
6561 GLint borderWidthloc =
6562 glGetUniformLocation(shader->programId(),
"border_width");
6563 glUniform1f(borderWidthloc, 2);
6566 GLint ringWidthloc =
6567 glGetUniformLocation(shader->programId(),
"ring_width");
6568 glUniform1f(ringWidthloc, arcw);
6572 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
6573 if (sr1 > 360.) sr1 -= 360.;
6575 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
6576 if (sr2 > 360.) sr2 -= 360.;
6588 if ((sb < 0) || (se < 0)) {
6594 glGetUniformLocation(shader->programId(),
"sector_1");
6595 glUniform1f(sector1loc, (sb * PI / 180.));
6597 glGetUniformLocation(shader->programId(),
"sector_2");
6598 glUniform1f(sector2loc, (se * PI / 180.));
6603 mat4x4_translate_in_place(I, r.x, r.y, 0);
6606 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6607 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6610 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6614 mat4x4_identity(IM);
6616 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6617 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6619 glDisableVertexAttribArray(mPosAttrib);
6625 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6630 bool haveAngle1 =
false;
6631 bool haveAngle2 =
false;
6632 int sec1 = (int)sectorlegs[i].sector1;
6633 int sec2 = (int)sectorlegs[i].sector2;
6634 if (sec1 > 360) sec1 -= 360;
6635 if (sec2 > 360) sec2 -= 360;
6637 if ((sec2 == 360) && (sec1 == 0))
6640 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6641 if (sectorangles[j] == sec1) haveAngle1 =
true;
6642 if (sectorangles[j] == sec2) haveAngle2 =
true;
6646 dc.StrokeLine(lightPos, end1);
6647 sectorangles.push_back(sec1);
6651 dc.StrokeLine(lightPos, end2);
6652 sectorangles.push_back(sec2);
6660bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6663 ListOfObjRazRules *rule_list,
6664 ListOfPI_S57Obj *pi_rule_list,
6665 std::vector<s57Sector_t> §orlegs) {
6666 bool newSectorsNeedDrawing =
false;
6668 bool bhas_red_green =
false;
6669 bool bleading_attribute =
false;
6672 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6673 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6675 int yOpacity = (float)opacity *
6678 if (target_plugin_chart || Chs57) {
6681 wxPoint2DDouble objPos;
6683 char *curr_att = NULL;
6685 wxArrayOfS57attVal *attValArray = NULL;
6687 ListOfObjRazRules::Node *snode = NULL;
6688 ListOfPI_S57Obj::Node *pnode = NULL;
6690 if (Chs57 && rule_list)
6691 snode = rule_list->GetLast();
6692 else if (target_plugin_chart && pi_rule_list)
6693 pnode = pi_rule_list->GetLast();
6696 wxPoint2DDouble lightPosD(0, 0);
6697 bool is_light =
false;
6701 ObjRazRules *current = snode->GetData();
6702 S57Obj *light = current->obj;
6703 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6704 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6705 curr_att = light->att_array;
6706 n_attr = light->n_attr;
6707 attValArray = light->attVal;
6710 }
else if (target_plugin_chart) {
6713 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6714 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6715 curr_att = light->att_array;
6716 n_attr = light->n_attr;
6717 attValArray = light->attVal;
6727 wxString curAttrName;
6730 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6732 if (is_light && (lightPosD == objPos)) {
6740 bleading_attribute =
false;
6742 while (attrCounter < n_attr) {
6743 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6746 S57attVal *pAttrVal = NULL;
6749 pAttrVal = attValArray->Item(attrCounter);
6750 else if (target_plugin_chart)
6751 pAttrVal = attValArray->Item(attrCounter);
6755 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6757 if (curAttrName == _T(
"LITVIS")) {
6758 if (value.StartsWith(_T(
"obsc"))) bviz =
false;
6760 if (curAttrName == _T(
"SECTR1")) value.ToDouble(§r1);
6761 if (curAttrName == _T(
"SECTR2")) value.ToDouble(§r2);
6762 if (curAttrName == _T(
"VALNMR")) value.ToDouble(&valnmr);
6763 if (curAttrName == _T(
"COLOUR")) {
6764 if (value == _T(
"red(3)")) {
6765 color = wxColor(255, 0, 0, opacity);
6766 sector.iswhite =
false;
6767 bhas_red_green =
true;
6770 if (value == _T(
"green(4)")) {
6771 color = wxColor(0, 255, 0, opacity);
6772 sector.iswhite =
false;
6773 bhas_red_green =
true;
6777 if (curAttrName == _T(
"EXCLIT")) {
6778 if (value.Find(_T(
"(3)"))) valnmr = 1.0;
6781 if (curAttrName == _T(
"CATLIT")) {
6782 if (value.Upper().StartsWith(_T(
"DIRECT")) ||
6783 value.Upper().StartsWith(_T(
"LEAD")))
6784 bleading_attribute =
true;
6791 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6792 if (sectr1 > sectr2) {
6796 sector.pos.m_x = objPos.m_y;
6797 sector.pos.m_y = objPos.m_x;
6800 (valnmr > 0.0) ? valnmr : 2.5;
6801 sector.sector1 = sectr1;
6802 sector.sector2 = sectr2;
6804 if (!color.IsOk()) {
6805 color = wxColor(255, 255, 0, yOpacity);
6806 sector.iswhite =
true;
6808 sector.color = color;
6809 sector.isleading =
false;
6811 if (bleading_attribute) sector.isleading =
true;
6813 bool newsector =
true;
6814 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6815 if (sectorlegs[i].pos == sector.pos &&
6816 sectorlegs[i].sector1 == sector.sector1 &&
6817 sectorlegs[i].sector2 == sector.sector2) {
6823 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6827 if (!bviz) newsector =
false;
6829 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6833 sectorlegs.push_back(sector);
6834 newSectorsNeedDrawing =
true;
6841 snode = snode->GetPrevious();
6842 else if (target_plugin_chart)
6843 pnode = pnode->GetPrevious();
6851 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6852 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6853 if (sectorlegs[i].iswhite && bhas_red_green)
6854 sectorlegs[i].isleading =
true;
6858 return newSectorsNeedDrawing;
6861bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6863 std::vector<s57Sector_t> §orlegs) {
6864 if (!cc)
return false;
6866 static float lastLat, lastLon;
6868 if (!ps52plib)
return false;
6876 if (cc->m_singleChart &&
6877 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6878 target_chart = cc->m_singleChart;
6879 else if (viewport.b_quilt)
6880 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6882 target_chart = NULL;
6885 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6886 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6889 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6892 bool newSectorsNeedDrawing =
false;
6894 if (target_plugin_chart || Chs57) {
6895 ListOfObjRazRules *rule_list = NULL;
6896 ListOfPI_S57Obj *pi_rule_list = NULL;
6903 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6904 else if (target_plugin_chart)
6905 pi_rule_list = g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6906 target_plugin_chart, lat, lon, viewport);
6908 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6909 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6917 pi_rule_list->Clear();
6918 delete pi_rule_list;
6922 return newSectorsNeedDrawing;
6925bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6927 std::vector<s57Sector_t> §orlegs) {
6928 if (!cc)
return false;
6930 double cursor_lat, cursor_lon;
6931 static float lastLat, lastLon;
6933 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6938 ChartBase *target_chart = cc->GetChartAtCursor();
6940 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6941 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6944 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6949 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6951 lastLat = cursor_lat;
6952 lastLon = cursor_lon;
6953 bool newSectorsNeedDrawing =
false;
6955 if (target_plugin_chart || Chs57) {
6956 ListOfObjRazRules *rule_list = NULL;
6957 ListOfPI_S57Obj *pi_rule_list = NULL;
6963 rule_list = Chs57->GetObjRuleListAtLatLon(
6964 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6965 else if (target_plugin_chart)
6966 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
6967 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6969 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6970 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6978 pi_rule_list->Clear();
6979 delete pi_rule_list;
6983 return newSectorsNeedDrawing;
Base class for all chart types.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Wrapper class for plugin-based charts.
Wrapper class for OpenGL shader programs.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
Represents a light feature in an S57 chart.
Manager for S57 chart SENC creation threads.
Represents the view port for chart display in OpenCPN.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
int pix_width
Width of the viewport in physical pixels.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Device context class that can use either wxDC or OpenGL for drawing.
Represents an S57 format electronic navigational chart in OpenCPN.
General purpose GUI support.
Enhanced logging interface on top of wx/log.h.
Tools to send data to plugins.
Represents a sector of a light in an S57 chart.