30#include "crashlytics.h"
34#define strncasecmp(x, y, z) _strnicmp(x, y, z)
45#include <wx/tokenzr.h>
46#include <wx/textfile.h>
47#include <wx/filename.h>
49#include <wx/listimpl.cpp>
52#include <wx/msw/msvcrt.h>
64#include "gdal/cpl_csv.h"
83#include "s57class_registrar.h"
87#include "user_colors.h"
98#define S57_THUMB_SIZE 200
100#include <wx/arrimpl.cpp>
102WX_DEFINE_OBJARRAY(ArrayOfS57Obj);
104WX_DEFINE_LIST(ListOfPI_S57Obj);
106WX_DEFINE_LIST(ListOfObjRazRules);
108static wxCriticalSection GDALcriticalSection;
115static jmp_buf env_ogrf;
117static void OpenCPN_OGRErrorHandler(
118 CPLErr eErrClass,
int nError,
119 const char *pszErrorMsg);
121static uint64_t hash_fast64(
const void *buf,
size_t len, uint64_t seed) {
122 const uint64_t m = 0x880355f21e6d1965ULL;
123 const uint64_t *pos = (
const uint64_t *)buf;
124 const uint64_t *end = pos + (len >> 3);
125 const unsigned char *pc;
126 uint64_t h = len * m ^ seed;
131 v *= 0x2127599bf4325c37ULL;
135 pc = (
const unsigned char *)pos;
139 v ^= (uint64_t)pc[6] << 48;
141 v ^= (uint64_t)pc[5] << 40;
143 v ^= (uint64_t)pc[4] << 32;
145 v ^= (uint64_t)pc[3] << 24;
147 v ^= (uint64_t)pc[2] << 16;
149 v ^= (uint64_t)pc[1] << 8;
151 v ^= (uint64_t)pc[0];
153 v *= 0x2127599bf4325c37ULL;
159 h *= 0x2127599bf4325c37ULL;
164static unsigned int hash_fast32(
const void *buf,
size_t len,
166 uint64_t h = hash_fast64(buf, len, seed);
171 return h - (h >> 32);
174unsigned long connector_key::hash()
const {
175 return hash_fast32(k,
sizeof k, 0);
182render_canvas_parms::render_canvas_parms() { pix_buff = NULL; }
184render_canvas_parms::~render_canvas_parms() {}
186static void PrepareForRender(
ViewPort *pvp, s52plib *plib) {
191 pvp->rv_rect, pvp->GetBBox(), pvp->
ref_scale,
193 plib->PrepareForRender();
200s57chart::s57chart() {
201 m_ChartType = CHART_TYPE_S57;
202 m_ChartFamily = CHART_FAMILY_VECTOR;
204 for (
int i = 0; i < PRIO_NUM; i++)
205 for (
int j = 0; j < LUPNAME_NUM; j++) razRules[i][j] = NULL;
214 pFloatingATONArray =
new wxArrayPtrVoid;
215 pRigidATONArray =
new wxArrayPtrVoid;
217 m_tmpup_array = NULL;
219 m_DepthUnits =
"METERS";
220 m_depth_unit_id = DEPTH_UNIT_METERS;
222 bGLUWarningSent =
false;
228 m_pvaldco_array = NULL;
230 m_bExtentSet =
false;
232 m_pDIBThumbDay = NULL;
233 m_pDIBThumbDim = NULL;
234 m_pDIBThumbOrphan = NULL;
235 m_bbase_file_attr_known =
false;
237 m_bLinePrioritySet =
false;
238 m_plib_state_hash = 0;
245 m_b2pointLUPS =
false;
246 m_b2lineLUPS =
false;
248 m_next_safe_cnt = 1e6;
250 m_line_vertex_buffer = 0;
251 m_this_chart_context = 0;
253 m_vbo_byte_length = 0;
254 bReadyToRender =
false;
256 m_disableBackgroundSENC =
false;
259s57chart::~s57chart() {
260 FreeObjectsAndRules();
267 delete pFloatingATONArray;
268 delete pRigidATONArray;
272 free(m_pvaldco_array);
274 free(m_line_vertex_buffer);
276 delete m_pDIBThumbOrphan;
278 for (
unsigned i = 0; i < m_pcs_vector.size(); i++)
delete m_pcs_vector.at(i);
280 for (
unsigned i = 0; i < m_pve_vector.size(); i++)
delete m_pve_vector.at(i);
282 m_pcs_vector.clear();
283 m_pve_vector.clear();
285 for (
const auto &it : m_ve_hash) {
286 VE_Element *pedge = it.second;
288 free(pedge->pPoints);
294 for (
const auto &it : m_vc_hash) {
295 VC_Element *pcs = it.second;
304 if ((m_LineVBO_name > 0)) glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
306 free(m_this_chart_context);
308 if (m_TempFilePath.Length() && (m_FullPath != m_TempFilePath)) {
309 if (::wxFileExists(m_TempFilePath)) wxRemoveFile(m_TempFilePath);
320void s57chart::GetValidCanvasRegion(
const ViewPort &VPoint,
324 double easting, northing;
327 toSM(m_FullExtent.SLAT, m_FullExtent.WLON, VPoint.
clat, VPoint.
clon, &easting,
332 rxl = (int)round((VPoint.
pix_width / 2) + epix);
333 ryb = (int)round((VPoint.
pix_height / 2) - npix);
335 toSM(m_FullExtent.NLAT, m_FullExtent.ELON, VPoint.
clat, VPoint.
clon, &easting,
340 rxr = (int)round((VPoint.
pix_width / 2) + epix);
341 ryt = (int)round((VPoint.
pix_height / 2) - npix);
343 pValidRegion->Clear();
344 pValidRegion->Union(rxl, ryt, rxr - rxl, ryb - ryt);
347LLRegion s57chart::GetValidRegion() {
348 double ll[8] = {m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.SLAT,
349 m_FullExtent.ELON, m_FullExtent.NLAT, m_FullExtent.ELON,
350 m_FullExtent.NLAT, m_FullExtent.WLON};
351 return LLRegion(4, ll);
354void s57chart::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
355 if (!ps52plib)
return;
360 case GLOBAL_COLOR_SCHEME_DAY:
361 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
363 case GLOBAL_COLOR_SCHEME_DUSK:
364 ps52plib->SetPLIBColorScheme(
"DUSK", ChartCtxFactory());
366 case GLOBAL_COLOR_SCHEME_NIGHT:
367 ps52plib->SetPLIBColorScheme(
"NIGHT", ChartCtxFactory());
370 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
374 m_global_color_scheme = cs;
376 if (bApplyImmediate) {
382 ClearRenderedTextCache();
385 ChangeThumbColor(cs);
388void s57chart::ChangeThumbColor(ColorScheme cs) {
389 if (0 == m_pDIBThumbDay)
return;
393 case GLOBAL_COLOR_SCHEME_DAY:
394 pThumbData->pDIBThumb = m_pDIBThumbDay;
395 m_pDIBThumbOrphan = m_pDIBThumbDim;
397 case GLOBAL_COLOR_SCHEME_DUSK:
398 case GLOBAL_COLOR_SCHEME_NIGHT: {
399 if (NULL == m_pDIBThumbDim) {
400 wxImage img = m_pDIBThumbDay->ConvertToImage();
402#if wxCHECK_VERSION(2, 8, 0)
403 wxImage gimg = img.ConvertToGreyscale(
413 wxBitmap *pBMP =
new wxBitmap(gimg);
415 m_pDIBThumbDim = pBMP;
416 m_pDIBThumbOrphan = m_pDIBThumbDay;
419 pThumbData->pDIBThumb = m_pDIBThumbDim;
425bool s57chart::GetChartExtent(
Extent *pext) {
427 *pext = m_FullExtent;
433static void free_mps(mps_container *mps) {
434 if (mps == 0)
return;
435 if (ps52plib && mps->cs_rules) {
436 for (
unsigned int i = 0; i < mps->cs_rules->GetCount(); i++) {
437 Rules *rule_chain_top = mps->cs_rules->Item(i);
438 ps52plib->DestroyRulesChain(rule_chain_top);
440 delete mps->cs_rules;
445void s57chart::FreeObjectsAndRules() {
454 for (
int i = 0; i < PRIO_NUM; ++i) {
455 for (
int j = 0; j < LUPNAME_NUM; j++) {
456 top = razRules[i][j];
457 while (top != NULL) {
459 if (0 == top->obj->nRef)
delete top->obj;
462 ObjRazRules *ctop = top->child;
466 if (ps52plib) ps52plib->DestroyLUP(ctop->LUP);
468 ObjRazRules *cnxx = ctop->next;
483void s57chart::ClearRenderedTextCache() {
485 for (
int i = 0; i < PRIO_NUM; ++i) {
486 for (
int j = 0; j < LUPNAME_NUM; j++) {
487 top = razRules[i][j];
488 while (top != NULL) {
489 if (top->obj->bFText_Added) {
490 top->obj->bFText_Added =
false;
491 delete top->obj->FText;
492 top->obj->FText = NULL;
496 ObjRazRules *ctop = top->child;
498 if (ctop->obj->bFText_Added) {
499 ctop->obj->bFText_Added =
false;
500 delete ctop->obj->FText;
501 ctop->obj->FText = NULL;
513double s57chart::GetNormalScaleMin(
double canvas_scale_factor,
514 bool b_allow_overzoom) {
516 return m_Chart_Scale * 0.125;
520double s57chart::GetNormalScaleMax(
double canvas_scale_factor,
522 return m_Chart_Scale * 4.0;
529void s57chart::GetPointPix(ObjRazRules *rzRules,
float north,
float east,
531 r->x = roundint(((east - m_easting_vp_center) * m_view_scale_ppm) +
533 r->y = roundint(m_pixy_vp_center -
534 ((north - m_northing_vp_center) * m_view_scale_ppm));
537void s57chart::GetPointPix(ObjRazRules *rzRules, wxPoint2DDouble *en,
538 wxPoint *r,
int nPoints) {
539 for (
int i = 0; i < nPoints; i++) {
540 r[i].x = roundint(((en[i].m_x - m_easting_vp_center) * m_view_scale_ppm) +
542 r[i].y = roundint(m_pixy_vp_center -
543 ((en[i].m_y - m_northing_vp_center) * m_view_scale_ppm));
547void s57chart::GetPixPoint(
int pixx,
int pixy,
double *plat,
double *plon,
549 if (vpt->m_projection_type != PROJECTION_MERCATOR)
550 printf(
"s57chart unhandled projection\n");
556 double xp = (dx * cos(vpt->
skew)) - (dy * sin(vpt->
skew));
557 double yp = (dy * cos(vpt->
skew)) + (dx * sin(vpt->
skew));
563 fromSM(d_east, d_north, vpt->
clat, vpt->
clon, &slat, &slon);
573void s57chart::SetVPParms(
const ViewPort &vpt) {
579 toSM(vpt.
clat, vpt.
clon, ref_lat, ref_lon, &m_easting_vp_center,
580 &m_northing_vp_center);
582 vp_transform.easting_vp_center = m_easting_vp_center;
583 vp_transform.northing_vp_center = m_northing_vp_center;
587 if (IsCacheValid()) {
590 double prev_easting_c, prev_northing_c;
591 toSM(vp_last.
clat, vp_last.
clon, ref_lat, ref_lon, &prev_easting_c,
594 double easting_c, northing_c;
595 toSM(vp_proposed.
clat, vp_proposed.
clon, ref_lat, ref_lon, &easting_c,
603 int dpix_x = (int)round(delta_pix_x);
608 int dpix_y = (int)round(delta_pix_y);
611 double c_east_d = (dpx / vp_proposed.
view_scale_ppm) + prev_easting_c;
612 double c_north_d = (dpy / vp_proposed.
view_scale_ppm) + prev_northing_c;
615 fromSM(c_east_d, c_north_d, ref_lat, ref_lon, &xlat, &xlon);
617 vp_proposed.
clon = xlon;
618 vp_proposed.
clat = xlat;
645void s57chart::LoadThumb() {
646 wxFileName fn(m_FullPath);
647 wxString SENCdir = g_SENCPrefix;
649 if (SENCdir.Last() != fn.GetPathSeparator())
650 SENCdir.Append(fn.GetPathSeparator());
652 wxFileName tsfn(SENCdir);
653 tsfn.SetFullName(fn.GetFullName());
655 wxFileName ThumbFileNameLook(tsfn);
656 ThumbFileNameLook.SetExt(
"BMP");
659 if (ThumbFileNameLook.FileExists()) {
662 pBMP->LoadFile(ThumbFileNameLook.GetFullPath(), wxBITMAP_TYPE_BMP);
663 m_pDIBThumbDay = pBMP;
664 m_pDIBThumbOrphan = 0;
669ThumbData *s57chart::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
672 if (pThumbData->pDIBThumb == 0) {
674 ChangeThumbColor(m_global_color_scheme);
677 UpdateThumbData(lat, lon);
682bool s57chart::UpdateThumbData(
double lat,
double lon) {
686 if (pThumbData->pDIBThumb) {
687 double lat_top = m_FullExtent.NLAT;
688 double lat_bot = m_FullExtent.SLAT;
689 double lon_left = m_FullExtent.WLON;
690 double lon_right = m_FullExtent.ELON;
693 double ext_max = fmax((lat_top - lat_bot), (lon_right - lon_left));
695 double thumb_view_scale_ppm = (S57_THUMB_SIZE / ext_max) / (1852 * 60);
697 toSM(lat, lon, (lat_top + lat_bot) / 2., (lon_left + lon_right) / 2., &east,
700 test_x = pThumbData->pDIBThumb->GetWidth() / 2 +
701 (int)(east * thumb_view_scale_ppm);
702 test_y = pThumbData->pDIBThumb->GetHeight() / 2 -
703 (int)(north * thumb_view_scale_ppm);
710 if ((test_x != pThumbData->ShipX) || (test_y != pThumbData->ShipY)) {
711 pThumbData->ShipX = test_x;
712 pThumbData->ShipY = test_y;
718void s57chart::SetFullExtent(
Extent &ext) {
719 m_FullExtent.NLAT = ext.NLAT;
720 m_FullExtent.SLAT = ext.SLAT;
721 m_FullExtent.WLON = ext.WLON;
722 m_FullExtent.ELON = ext.ELON;
727void s57chart::ForceEdgePriorityEvaluate() { m_bLinePrioritySet =
false; }
729void s57chart::SetLinePriorities() {
730 if (!ps52plib)
return;
735 if (!m_bLinePrioritySet) {
739 for (
int i = 0; i < PRIO_NUM; ++i) {
740 top = razRules[i][2];
741 while (top != NULL) {
742 ObjRazRules *crnt = top;
744 ps52plib->SetLineFeaturePriority(crnt, i);
750 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
755 top = razRules[i][j];
756 while (top != NULL) {
759 ps52plib->SetLineFeaturePriority(crnt, i);
765 for (
int i = 0; i < PRIO_NUM; ++i) {
766 for (
int j = 0; j < LUPNAME_NUM; j++) {
767 ObjRazRules *top = razRules[i][j];
768 while (top != NULL) {
769 S57Obj *obj = top->obj;
772 connector_segment *pcs;
773 line_segment_element *list = obj->m_ls_list;
775 switch (list->ls_type) {
779 if (pedge) list->priority = pedge->max_priority;
784 if (pcs) list->priority = pcs->max_priority_cs;
799 m_bLinePrioritySet =
true;
803void s57chart::SetLinePriorities(
void )
805 if( !ps52plib )
return;
810 if( !m_bLinePrioritySet ) {
814 for(
int i = 0; i < PRIO_NUM; ++i ) {
816 top = razRules[i][2];
817 while( top != NULL ) {
818 ObjRazRules *crnt = top;
820 ps52plib->SetLineFeaturePriority( crnt, i );
825 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
830 top = razRules[i][j];
831 while( top != NULL ) {
834 ps52plib->SetLineFeaturePriority( crnt, i );
842 for(
int i = 0; i < PRIO_NUM; ++i ) {
843 for(
int j = 0; j < LUPNAME_NUM; j++ ) {
844 ObjRazRules *top = razRules[i][j];
845 while( top != NULL ) {
846 S57Obj *obj = top->obj;
849 connector_segment *pcs;
850 line_segment_element *list = obj->m_ls_list;
855 pedge = (VE_Element *)list->private0;
857 list->priority = pedge->max_priority;
861 pcs = (connector_segment *)list->private0;
863 list->priority = pcs->max_priority;
878 m_bLinePrioritySet =
true;
882int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array) {
886 line_segment_element *ls_list = obj->m_ls_list;
888 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV))
889 nPoints += ls_list->pedge->nCount;
892 ls_list = ls_list->next;
901 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
905 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
906 ls_list = obj->m_ls_list;
908 size_t vbo_offset = 0;
910 if ((ls_list->ls_type == TYPE_EE) || (ls_list->ls_type == TYPE_EE_REV)) {
911 vbo_offset = ls_list->pedge->vbo_offset;
912 count = ls_list->pedge->nCount;
914 vbo_offset = ls_list->pcs->vbo_offset;
918 memcpy(br, source_buffer + vbo_offset, count * 2 *
sizeof(
float));
920 ls_list = ls_list->next;
927int s57chart::GetLineFeaturePointArray(S57Obj *obj,
void **ret_array)
932 line_segment_element *ls_list = obj->m_ls_list;
934 nPoints += ls_list->n_points;
935 ls_list = ls_list->next;
944 float *br = (
float *)malloc(nPoints * 2 *
sizeof(
float));
948 unsigned char *source_buffer = (
unsigned char *)GetLineVertexBuffer();
949 ls_list = obj->m_ls_list;
951 memcpy(br, source_buffer + ls_list->vbo_offset, ls_list->n_points * 2 *
sizeof(
float));
952 br += ls_list->n_points * 2;
953 ls_list = ls_list->next;
962 float e0, n0, e1, n1;
965void s57chart::AssembleLineGeometry() {
970 for (
const auto &it : m_ve_hash) {
971 VE_Element *pedge = it.second;
973 nPoints += pedge->nCount;
979 std::map<long long, connector_segment *> ce_connector_hash;
980 std::map<long long, connector_segment *> ec_connector_hash;
981 std::map<long long, connector_segment *> cc_connector_hash;
983 std::map<long long, connector_segment *>::iterator csit;
990 std::vector<segment_pair> connector_segment_vector;
991 size_t seg_pair_index = 0;
996 for (
int i = 0; i < PRIO_NUM; ++i) {
997 for (
int j = 0; j < LUPNAME_NUM; j++) {
998 ObjRazRules *top = razRules[i][j];
999 while (top != NULL) {
1000 S57Obj *obj = top->obj;
1002 if ((!obj->m_ls_list) &&
1005 line_segment_element list_top;
1008 line_segment_element *le_current = &list_top;
1010 for (
int iseg = 0; iseg < obj->m_n_lsindex; iseg++) {
1011 if (!obj->m_lsindex_array)
continue;
1013 int seg_index = iseg * 3;
1014 int *index_run = &obj->m_lsindex_array[seg_index];
1017 unsigned int inode = *index_run++;
1020 bool edge_dir =
true;
1021 int venode = *index_run++;
1027 VE_Element *pedge = 0;
1029 if (m_ve_hash.find(venode) != m_ve_hash.end())
1030 pedge = m_ve_hash[venode];
1034 unsigned int enode = *index_run++;
1037 VC_Element *ipnode = 0;
1038 ipnode = m_vc_hash[inode];
1041 VC_Element *epnode = 0;
1042 epnode = m_vc_hash[enode];
1045 if (pedge && pedge->nCount) {
1049 long long key = ((
unsigned long long)inode << 32) + venode;
1051 connector_segment *pcs = NULL;
1052 csit = ce_connector_hash.find(key);
1053 if (csit == ce_connector_hash.end()) {
1055 pcs =
new connector_segment;
1056 ce_connector_hash[key] = pcs;
1060 float *ppt = ipnode->pPoint;
1065 pair.e1 = pedge->pPoints[0];
1066 pair.n1 = pedge->pPoints[1];
1068 int last_point_index = (pedge->nCount - 1) * 2;
1069 pair.e1 = pedge->pPoints[last_point_index];
1070 pair.n1 = pedge->pPoints[last_point_index + 1];
1073 connector_segment_vector.push_back(pair);
1074 pcs->vbo_offset = seg_pair_index;
1081 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon, &lat,
1083 pcs->cs_lat_avg = lat;
1084 pcs->cs_lon_avg = lon;
1089 line_segment_element *pls =
new line_segment_element;
1094 pls->ls_type = TYPE_CE;
1096 le_current->next = pls;
1101 if (pedge && pedge->nCount) {
1102 line_segment_element *pls =
new line_segment_element;
1107 pls->ls_type = TYPE_EE;
1108 if (!edge_dir) pls->ls_type = TYPE_EE_REV;
1110 le_current->next = pls;
1118 if (pedge && pedge->nCount) {
1119 long long key = ((
unsigned long long)venode << 32) + enode;
1121 connector_segment *pcs = NULL;
1122 csit = ec_connector_hash.find(key);
1123 if (csit == ec_connector_hash.end()) {
1125 pcs =
new connector_segment;
1126 ec_connector_hash[key] = pcs;
1132 pair.e0 = pedge->pPoints[0];
1133 pair.n0 = pedge->pPoints[1];
1135 int last_point_index = (pedge->nCount - 1) * 2;
1136 pair.e0 = pedge->pPoints[last_point_index];
1137 pair.n0 = pedge->pPoints[last_point_index + 1];
1140 float *ppt = epnode->pPoint;
1144 connector_segment_vector.push_back(pair);
1145 pcs->vbo_offset = seg_pair_index;
1152 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1154 pcs->cs_lat_avg = lat;
1155 pcs->cs_lon_avg = lon;
1160 line_segment_element *pls =
new line_segment_element;
1164 pls->ls_type = TYPE_EC;
1166 le_current->next = pls;
1170 long long key = ((
unsigned long long)inode << 32) + enode;
1172 connector_segment *pcs = NULL;
1173 csit = cc_connector_hash.find(key);
1174 if (csit == cc_connector_hash.end()) {
1176 pcs =
new connector_segment;
1177 cc_connector_hash[key] = pcs;
1182 float *ppt = ipnode->pPoint;
1186 ppt = epnode->pPoint;
1190 connector_segment_vector.push_back(pair);
1191 pcs->vbo_offset = seg_pair_index;
1198 (pair.n0 + pair.n1) / 2, ref_lat, ref_lon,
1200 pcs->cs_lat_avg = lat;
1201 pcs->cs_lon_avg = lon;
1206 line_segment_element *pls =
new line_segment_element;
1210 pls->ls_type = TYPE_CC;
1212 le_current->next = pls;
1226 if (obj->m_ls_list == NULL) {
1227 obj->m_n_lsindex = 0;
1231 free(obj->m_lsindex_array);
1232 obj->m_lsindex_array = NULL;
1245 size_t vbo_byte_length = 2 * nPoints *
sizeof(float);
1247 unsigned char *buffer_offset;
1250 bool grow_buffer =
false;
1252 if (0 == m_vbo_byte_length) {
1253 m_line_vertex_buffer = (
float *)malloc(vbo_byte_length);
1254 m_vbo_byte_length = vbo_byte_length;
1255 buffer_offset = (
unsigned char *)m_line_vertex_buffer;
1258 m_line_vertex_buffer = (
float *)realloc(
1259 m_line_vertex_buffer, m_vbo_byte_length + vbo_byte_length);
1260 buffer_offset = (
unsigned char *)m_line_vertex_buffer + m_vbo_byte_length;
1261 offset = m_vbo_byte_length;
1262 m_vbo_byte_length = m_vbo_byte_length + vbo_byte_length;
1266 float *lvr = (
float *)buffer_offset;
1270 for (
const auto &it : m_ve_hash) {
1271 VE_Element *pedge = it.second;
1273 memcpy(lvr, pedge->pPoints, pedge->nCount * 2 *
sizeof(
float));
1274 lvr += pedge->nCount * 2;
1276 pedge->vbo_offset = offset;
1277 offset += pedge->nCount * 2 *
sizeof(float);
1290 for (csit = ce_connector_hash.begin(); csit != ce_connector_hash.end();
1292 connector_segment *pcs = csit->second;
1293 m_pcs_vector.push_back(pcs);
1295 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1301 pcs->vbo_offset = offset;
1302 offset += 4 *
sizeof(float);
1305 for (csit = ec_connector_hash.begin(); csit != ec_connector_hash.end();
1307 connector_segment *pcs = csit->second;
1308 m_pcs_vector.push_back(pcs);
1310 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1316 pcs->vbo_offset = offset;
1317 offset += 4 *
sizeof(float);
1320 for (csit = cc_connector_hash.begin(); csit != cc_connector_hash.end();
1322 connector_segment *pcs = csit->second;
1323 m_pcs_vector.push_back(pcs);
1325 segment_pair pair = connector_segment_vector.at(pcs->vbo_offset);
1331 pcs->vbo_offset = offset;
1332 offset += 4 *
sizeof(float);
1336 connector_segment_vector.clear();
1341 for (
const auto &it : m_ve_hash) {
1342 VE_Element *pedge = it.second;
1344 m_pve_vector.push_back(pedge);
1345 free(pedge->pPoints);
1353 for (
const auto &it : m_vc_hash) {
1354 VC_Element *pcs = it.second;
1355 if (pcs) free(pcs->pPoint);
1361 if (g_b_EnableVBO) {
1363 if (m_LineVBO_name > 0) {
1364 glDeleteBuffers(1, (GLuint *)&m_LineVBO_name);
1365 m_LineVBO_name = -1;
1372void s57chart::BuildLineVBO() {
1374 if (!g_b_EnableVBO)
return;
1376 if (m_LineVBO_name == -1) {
1379 glGenBuffers(1, &vboId);
1382 glBindBuffer(GL_ARRAY_BUFFER, vboId);
1388#ifndef USE_ANDROID_GLES2
1389 glEnableClientState(GL_VERTEX_ARRAY);
1391 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length, m_line_vertex_buffer,
1396 ObjRazRules *top, *crnt;
1397 int vbo_area_size_bytes = 0;
1398 for (
int i = 0; i < PRIO_NUM; ++i) {
1399 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1400 top = razRules[i][4];
1402 top = razRules[i][3];
1404 while (top != NULL) {
1409 PolyTriGroup *ppg_vbo =
1410 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1412 vbo_area_size_bytes += ppg_vbo->single_buffer_size;
1419 glBufferData(GL_ARRAY_BUFFER, m_vbo_byte_length + vbo_area_size_bytes, NULL,
1422 GLenum err = glGetError();
1425 msg.Printf(
"S57 VBO Error 1: %d", err);
1427 printf(
"S57 VBO Error 1: %d", err);
1431 glBufferSubData(GL_ARRAY_BUFFER, 0, m_vbo_byte_length,
1432 m_line_vertex_buffer);
1437 msg.Printf(
"S57 VBO Error 2: %d", err);
1439 printf(
"S57 VBO Error 2: %d", err);
1443 int vbo_load_offset = m_vbo_byte_length;
1445 for (
int i = 0; i < PRIO_NUM; ++i) {
1446 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1447 top = razRules[i][4];
1449 top = razRules[i][3];
1451 while (top != NULL) {
1456 PolyTriGroup *ppg_vbo =
1457 crnt->obj->pPolyTessGeo->Get_PolyTriGroup_head();
1460 glBufferSubData(GL_ARRAY_BUFFER, vbo_load_offset,
1461 ppg_vbo->single_buffer_size, ppg_vbo->single_buffer);
1463 crnt->obj->vboAreaOffset = vbo_load_offset;
1464 vbo_load_offset += ppg_vbo->single_buffer_size;
1471 msg.Printf(
"S57 VBO Error 3: %d", err);
1473 printf(
"S57 VBO Error 3: %d", err);
1478#ifndef USE_ANDROID_GLES2
1479 glDisableClientState(GL_VERTEX_ARRAY);
1481 glBindBuffer(GL_ARRAY_BUFFER, 0);
1485 for (
int i = 0; i < PRIO_NUM; ++i) {
1486 for (
int j = 0; j < LUPNAME_NUM; j++) {
1487 ObjRazRules *top = razRules[i][j];
1488 while (top != NULL) {
1489 S57Obj *obj = top->obj;
1490 obj->auxParm2 = vboId;
1496 m_LineVBO_name = vboId;
1497 m_this_chart_context->vboID = vboId;
1516bool s57chart::RenderRegionViewOnGL(
const wxGLContext &glc,
1519 const LLRegion &Region) {
1520 if (!m_RAZBuilt)
return false;
1522 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1525bool s57chart::RenderOverlayRegionViewOnGL(
const wxGLContext &glc,
1528 const LLRegion &Region) {
1529 if (!m_RAZBuilt)
return false;
1531 return DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
true);
1534bool s57chart::RenderRegionViewOnGLNoText(
const wxGLContext &glc,
1537 const LLRegion &Region) {
1538 if (!m_RAZBuilt)
return false;
1540 bool b_text = ps52plib->GetShowS57Text();
1541 ps52plib->m_bShowS57Text =
false;
1542 bool b_ret = DoRenderRegionViewOnGL(glc, VPoint, RectRegion, Region,
false);
1543 ps52plib->m_bShowS57Text = b_text;
1548bool s57chart::RenderViewOnGLTextOnly(
const wxGLContext &glc,
1550 if (!m_RAZBuilt)
return false;
1554 if (!ps52plib)
return false;
1557 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1559 glChartCanvas::DisableClipRegion();
1560 DoRenderOnGLText(glc, VPoint);
1566bool s57chart::DoRenderRegionViewOnGL(
const wxGLContext &glc,
1569 const LLRegion &Region,
bool b_overlay) {
1570 if (!m_RAZBuilt)
return false;
1574 if (!ps52plib)
return false;
1576 if (g_bDebugS57) printf(
"\n");
1580 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1582 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1583 m_bLinePrioritySet =
false;
1585 ClearRenderedTextCache();
1587 ResetPointBBoxes(m_last_vp, VPoint);
1590 m_plib_state_hash = ps52plib->GetStateHash();
1594 ResetPointBBoxes(m_last_vp, VPoint);
1598 SetLinePriorities();
1601 ps52plib->ClearTextList();
1609 wxRect upr = upd.GetRect();
1612 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
1613 chart_region.Intersect(Region);
1615 if (!chart_region.Empty()) {
1619 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
1626 if (CHART_TYPE_CM93 == GetChartType()) {
1630 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1633#ifdef OPT_USE_ANDROID_GLES2
1641 wxRect r = upd.GetRect();
1643 glViewport(r.x, vp->
pix_height - (r.y + r.height), r.width, r.height);
1651 float yp = vp->
pix_height - (r.y + r.height);
1653 I[3][0] = (-r.x - (float)r.width / 2) * (2.0 / (float)r.width);
1654 I[3][1] = (r.y + (float)r.height / 2) * (2.0 / (float)r.height);
1657 I[0][0] *= 2.0 / (float)r.width;
1658 I[1][1] *= -2.0 / (float)r.height;
1662 mat4x4_rotate_Z(Q, I, angle);
1664 mat4x4_dup((
float(*)[4])vp->vp_transform, Q);
1667 ps52plib->SetReducedBBox(cvp.GetBBox());
1668 glChartCanvas::SetClipRect(cvp, upd.GetRect(),
false);
1673 DoRenderOnGL(glc, cvp);
1675 glChartCanvas::DisableClipRegion();
1688bool s57chart::DoRenderOnGL(
const wxGLContext &glc,
const ViewPort &VPoint) {
1701 for (i = 0; i < PRIO_NUM; ++i) {
1702 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1703 top = razRules[i][4];
1705 top = razRules[i][3];
1707 while (top != NULL) {
1710 crnt->sm_transform_parms = &vp_transform;
1711 ps52plib->RenderAreaToGL(glc, crnt);
1717 for (i = 0; i < PRIO_NUM; ++i) {
1719 top = razRules[i][4];
1721 top = razRules[i][3];
1723 while (top != NULL) {
1726 crnt->sm_transform_parms = &vp_transform;
1731 if (!crnt->obj->pPolyTessGeo->IsOk()) {
1732 if (ps52plib->ObjectRenderCheckRules(crnt, &tvp,
true)) {
1733 if (!crnt->obj->pPolyTessGeo->m_pxgeom)
1734 crnt->obj->pPolyTessGeo->m_pxgeom = buildExtendedGeom(crnt->obj);
1737 ps52plib->RenderAreaToGL(glc, crnt, &tvp);
1744 for (i = 0; i < PRIO_NUM; ++i) {
1745 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1746 top = razRules[i][4];
1748 top = razRules[i][3];
1749 while (top != NULL) {
1752 crnt->sm_transform_parms = &vp_transform;
1753 ps52plib->RenderObjectToGL(glc, crnt);
1758 for (i = 0; i < PRIO_NUM; ++i) {
1759 top = razRules[i][2];
1760 while (top != NULL) {
1763 crnt->sm_transform_parms = &vp_transform;
1764 ps52plib->RenderObjectToGL(glc, crnt);
1770 for (i = 0; i < PRIO_NUM; ++i) {
1771 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1772 top = razRules[i][0];
1774 top = razRules[i][1];
1776 while (top != NULL) {
1779 crnt->sm_transform_parms = &vp_transform;
1780 ps52plib->RenderObjectToGL(glc, crnt);
1790bool s57chart::DoRenderOnGLText(
const wxGLContext &glc,
1801 for( i = 0; i < PRIO_NUM; ++i ) {
1802 if( ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES )
1803 top = razRules[i][4];
1805 top = razRules[i][3];
1807 while( top != NULL ) {
1810 crnt->sm_transform_parms = &vp_transform;
1817 for (i = 0; i < PRIO_NUM; ++i) {
1818 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
1819 top = razRules[i][4];
1821 top = razRules[i][3];
1823 while (top != NULL) {
1826 crnt->sm_transform_parms = &vp_transform;
1827 ps52plib->RenderObjectToGLText(glc, crnt);
1830 top = razRules[i][2];
1831 while (top != NULL) {
1834 crnt->sm_transform_parms = &vp_transform;
1835 ps52plib->RenderObjectToGLText(glc, crnt);
1838 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
1839 top = razRules[i][0];
1841 top = razRules[i][1];
1843 while (top != NULL) {
1846 crnt->sm_transform_parms = &vp_transform;
1847 ps52plib->RenderObjectToGLText(glc, crnt);
1856bool s57chart::RenderRegionViewOnDCNoText(wxMemoryDC &dc,
1859 if (!m_RAZBuilt)
return false;
1861 bool b_text = ps52plib->GetShowS57Text();
1862 ps52plib->m_bShowS57Text =
false;
1863 bool b_ret = DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1864 ps52plib->m_bShowS57Text = b_text;
1869bool s57chart::RenderRegionViewOnDCTextOnly(wxMemoryDC &dc,
1872 if (!dc.IsOk())
return false;
1875 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1880 DCRenderText(dc, VPoint);
1883 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
1887 while (upd.HaveRects()) {
1888 wxRect rect = upd.GetRect();
1894 temp_vp.
GetLLFromPix(p, &temp_lat_top, &temp_lon_left);
1898 temp_vp.
GetLLFromPix(p, &temp_lat_bot, &temp_lon_right);
1900 if (temp_lon_right < temp_lon_left)
1901 temp_lon_right += 360.;
1903 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
1906 wxDCClipper clip(dc, rect);
1907 DCRenderText(dc, temp_vp);
1916bool s57chart::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1918 if (!m_RAZBuilt)
return false;
1920 return DoRenderRegionViewOnDC(dc, VPoint, Region,
false);
1923bool s57chart::RenderOverlayRegionViewOnDC(wxMemoryDC &dc,
1926 if (!m_RAZBuilt)
return false;
1927 return DoRenderRegionViewOnDC(dc, VPoint, Region,
true);
1930bool s57chart::DoRenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1935 bool force_new_view =
false;
1937 if (Region != m_last_Region) force_new_view =
true;
1939 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
1941 if (m_plib_state_hash != ps52plib->GetStateHash()) {
1942 m_bLinePrioritySet =
false;
1944 ClearRenderedTextCache();
1946 ResetPointBBoxes(m_last_vp, VPoint);
1951 ResetPointBBoxes(m_last_vp, VPoint);
1954 SetLinePriorities();
1956 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY, force_new_view);
1960 if (VPoint.b_quilt) {
1962 if ((m_pCloneBM->GetWidth() != VPoint.
pix_width) ||
1963 (m_pCloneBM->GetHeight() != VPoint.
pix_height)) {
1968 if (NULL == m_pCloneBM)
1971 wxMemoryDC dc_clone;
1972 dc_clone.SelectObject(*m_pCloneBM);
1974#ifdef ocpnUSE_DIBSECTION
1977 wxMemoryDC memdc, dc_org;
1980 pDIB->SelectIntoDC(dc_org);
1985 while (upd.HaveRects()) {
1986 wxRect rect = upd.GetRect();
1987 dc_clone.Blit(rect.x, rect.y, rect.width, rect.height, &dc_org, rect.x,
1992 dc_clone.SelectObject(wxNullBitmap);
1993 dc_org.SelectObject(wxNullBitmap);
1997 wxColour nodat = GetGlobalColor(
"NODTA");
1998 wxColour nodat_sub = nodat;
2000#ifdef ocpnUSE_ocpnBitmap
2001 nodat_sub = wxColour(nodat.Blue(), nodat.Green(), nodat.Red());
2003 m_pMask =
new wxMask(*m_pCloneBM, nodat_sub);
2004 m_pCloneBM->SetMask(m_pMask);
2007 dc.SelectObject(*m_pCloneBM);
2009 pDIB->SelectIntoDC(dc);
2011 m_last_Region = Region;
2016bool s57chart::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
2021 PrepareForRender((
ViewPort *)&VPoint, ps52plib);
2023 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2024 m_bLinePrioritySet =
false;
2026 ClearRenderedTextCache();
2030 SetLinePriorities();
2032 bool bnew_view = DoRenderViewOnDC(dc, VPoint, DC_RENDER_ONLY,
false);
2034 pDIB->SelectIntoDC(dc);
2041bool s57chart::DoRenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
2042 RenderTypeEnum option,
bool force_new_view) {
2043 bool bnewview =
false;
2045 bool bNewVP =
false;
2047 bool bReallyNew =
false;
2049 double easting_ul, northing_ul;
2050 double easting_lr, northing_lr;
2051 double prev_easting_ul = 0., prev_northing_ul = 0.;
2053 if (ps52plib->GetPLIBColorScheme() != m_lastColorScheme) bReallyNew =
true;
2054 m_lastColorScheme = ps52plib->GetPLIBColorScheme();
2063 if (m_last_vprect != dest) bReallyNew =
true;
2064 m_last_vprect = dest;
2066 if (m_plib_state_hash != ps52plib->GetStateHash()) {
2068 m_plib_state_hash = ps52plib->GetStateHash();
2079 if (m_last_vp.IsValid()) {
2081 m_easting_vp_center - ((VPoint.
pix_width / 2) / m_view_scale_ppm);
2083 m_northing_vp_center + ((VPoint.
pix_height / 2) / m_view_scale_ppm);
2084 easting_lr = easting_ul + (VPoint.
pix_width / m_view_scale_ppm);
2085 northing_lr = northing_ul - (VPoint.
pix_height / m_view_scale_ppm);
2087 double last_easting_vp_center, last_northing_vp_center;
2088 toSM(m_last_vp.
clat, m_last_vp.
clon, ref_lat, ref_lon,
2089 &last_easting_vp_center, &last_northing_vp_center);
2092 last_easting_vp_center - ((m_last_vp.
pix_width / 2) / m_view_scale_ppm);
2093 prev_northing_ul = last_northing_vp_center +
2094 ((m_last_vp.
pix_height / 2) / m_view_scale_ppm);
2096 double dx = (easting_ul - prev_easting_ul) * m_view_scale_ppm;
2097 double dy = (prev_northing_ul - northing_ul) * m_view_scale_ppm;
2099 rul.x = (int)round((easting_ul - prev_easting_ul) * m_view_scale_ppm);
2100 rul.y = (int)round((prev_northing_ul - northing_ul) * m_view_scale_ppm);
2102 rlr.x = (int)round((easting_lr - prev_easting_ul) * m_view_scale_ppm);
2103 rlr.y = (int)round((prev_northing_ul - northing_lr) * m_view_scale_ppm);
2105 if ((fabs(dx - wxRound(dx)) > 1e-5) || (fabs(dy - wxRound(dy)) > 1e-5)) {
2108 "s57chart::DoRender Cache miss on non-integer pixel delta %g %g\n",
2117 else if ((rul.x != 0) || (rul.y != 0)) {
2118 if (g_bDebugS57) printf(
"newvp due to rul\n");
2129 if (force_new_view) bNewVP =
true;
2134 OCPNRegion rgn_new(rul.x, rul.y, rlr.x - rul.x, rlr.y - rul.y);
2135 rgn_last.Intersect(rgn_new);
2137 if (bNewVP && (NULL != pDIB) && !rgn_last.IsEmpty()) {
2139 rgn_last.GetBox(xu, yu, wu, hu);
2156 pDIB->SelectIntoDC(dc_last);
2161 pDIBNew->SelectIntoDC(dc_new);
2165 dc_new.Blit(desx, desy, wu, hu, (wxDC *)&dc_last, srcx, srcy, wxCOPY);
2170 ps52plib->AdjustTextList(desx - srcx, desy - srcy, VPoint.
pix_width,
2173 dc_new.SelectObject(wxNullBitmap);
2174 dc_last.SelectObject(wxNullBitmap);
2182 pDIB->SelectIntoDC(dc);
2186 rgn_delta.Subtract(rgn_reused);
2189 while (upd.HaveRects()) {
2190 wxRect rect = upd.GetRect();
2195 double temp_lon_left, temp_lat_bot, temp_lon_right, temp_lat_top;
2197 double temp_northing_ul = prev_northing_ul - (rul.y / m_view_scale_ppm) -
2198 (rect.y / m_view_scale_ppm);
2199 double temp_easting_ul = prev_easting_ul + (rul.x / m_view_scale_ppm) +
2200 (rect.x / m_view_scale_ppm);
2201 fromSM(temp_easting_ul, temp_northing_ul, ref_lat, ref_lon, &temp_lat_top,
2204 double temp_northing_lr =
2205 temp_northing_ul - (rect.height / m_view_scale_ppm);
2206 double temp_easting_lr =
2207 temp_easting_ul + (rect.width / m_view_scale_ppm);
2208 fromSM(temp_easting_lr, temp_northing_lr, ref_lat, ref_lon, &temp_lat_bot,
2211 temp_vp.GetBBox().Set(temp_lat_bot, temp_lon_left, temp_lat_top,
2216 double margin = wxMin(temp_vp.GetBBox().GetLonRange(),
2217 temp_vp.GetBBox().GetLatRange()) *
2219 temp_vp.GetBBox().EnLarge(margin);
2225 DCRenderRect(dc, temp_vp, &rect);
2230 dc.SelectObject(wxNullBitmap);
2239 else if (bNewVP || (NULL == pDIB)) {
2245 pDIB->SelectIntoDC(dc);
2248 ps52plib->ClearTextList();
2250 DCRenderRect(dc, VPoint, &full_rect);
2252 dc.SelectObject(wxNullBitmap);
2263int s57chart::DCRenderRect(wxMemoryDC &dcinput,
const ViewPort &vp,
2276 render_canvas_parms pb_spec;
2278 pb_spec.depth = BPP;
2279 pb_spec.pb_pitch = ((rect->width * pb_spec.depth / 8));
2280 pb_spec.lclip = rect->x;
2281 pb_spec.rclip = rect->x + rect->width - 1;
2282 pb_spec.pix_buff = (
unsigned char *)malloc(rect->height * pb_spec.pb_pitch);
2283 pb_spec.width = rect->width;
2284 pb_spec.height = rect->height;
2285 pb_spec.x = rect->x;
2286 pb_spec.y = rect->y;
2288#ifdef ocpnUSE_ocpnBitmap
2289 pb_spec.b_revrgb =
true;
2291 pb_spec.b_revrgb =
false;
2295 wxColour color = GetGlobalColor(
"NODTA");
2296 unsigned char r, g, b;
2304 if (pb_spec.depth == 24) {
2305 for (
int i = 0; i < pb_spec.height; i++) {
2306 unsigned char *p = pb_spec.pix_buff + (i * pb_spec.pb_pitch);
2307 for (
int j = 0; j < pb_spec.width; j++) {
2314 int color_int = ((r) << 16) + ((g) << 8) + (b);
2316 for (
int i = 0; i < pb_spec.height; i++) {
2317 int *p = (
int *)(pb_spec.pix_buff + (i * pb_spec.pb_pitch));
2318 for (
int j = 0; j < pb_spec.width; j++) {
2325 for (i = 0; i < PRIO_NUM; ++i) {
2326 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2327 top = razRules[i][4];
2329 top = razRules[i][3];
2331 while (top != NULL) {
2334 crnt->sm_transform_parms = &vp_transform;
2335 ps52plib->RenderAreaToDC(&dcinput, crnt, &pb_spec);
2340#ifdef ocpnUSE_ocpnBitmap
2341 ocpnBitmap *pREN =
new ocpnBitmap(pb_spec.pix_buff, pb_spec.width,
2342 pb_spec.height, pb_spec.depth);
2344 wxImage *prender_image =
new wxImage(pb_spec.width, pb_spec.height,
false);
2345 prender_image->SetData((
unsigned char *)pb_spec.pix_buff);
2346 wxBitmap *pREN =
new wxBitmap(*prender_image);
2352 dc_ren.SelectObject(*pREN);
2355 dcinput.Blit(pb_spec.x, pb_spec.y, pb_spec.width, pb_spec.height,
2356 (wxDC *)&dc_ren, 0, 0);
2359 dc_ren.SelectObject(wxNullBitmap);
2361#ifdef ocpnUSE_ocpnBitmap
2362 free(pb_spec.pix_buff);
2364 delete prender_image;
2371 DCRenderLPB(dcinput, vp, rect);
2376bool s57chart::DCRenderLPB(wxMemoryDC &dcinput,
const ViewPort &vp,
2383 for (i = 0; i < PRIO_NUM; ++i) {
2385 wxDCClipper *pdcc = NULL;
2391 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2392 top = razRules[i][4];
2394 top = razRules[i][3];
2395 while (top != NULL) {
2398 crnt->sm_transform_parms = &vp_transform;
2399 ps52plib->RenderObjectToDC(&dcinput, crnt);
2402 top = razRules[i][2];
2403 while (top != NULL) {
2406 crnt->sm_transform_parms = &vp_transform;
2407 ps52plib->RenderObjectToDC(&dcinput, crnt);
2410 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2411 top = razRules[i][0];
2413 top = razRules[i][1];
2415 while (top != NULL) {
2418 crnt->sm_transform_parms = &vp_transform;
2419 ps52plib->RenderObjectToDC(&dcinput, crnt);
2423 if (pdcc)
delete pdcc;
2436bool s57chart::DCRenderText(wxMemoryDC &dcinput,
const ViewPort &vp) {
2442 for (i = 0; i < PRIO_NUM; ++i) {
2443 if (ps52plib->m_nBoundaryStyle == SYMBOLIZED_BOUNDARIES)
2444 top = razRules[i][4];
2446 top = razRules[i][3];
2448 while (top != NULL) {
2451 crnt->sm_transform_parms = &vp_transform;
2452 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2455 top = razRules[i][2];
2456 while (top != NULL) {
2459 crnt->sm_transform_parms = &vp_transform;
2460 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2463 if (ps52plib->m_nSymbolStyle == SIMPLIFIED)
2464 top = razRules[i][0];
2466 top = razRules[i][1];
2468 while (top != NULL) {
2471 crnt->sm_transform_parms = &vp_transform;
2472 ps52plib->RenderObjectToDCText(&dcinput, crnt);
2479bool s57chart::IsCellOverlayType(
const wxString &FullPath) {
2480 wxFileName fn(FullPath);
2482 wxString cname = fn.GetName();
2483 if (cname.Length() >= 3)
2484 return ((cname[2] ==
'L') || (cname[2] ==
'A'));
2489InitReturn s57chart::Init(
const wxString &name, ChartInitFlag flags) {
2492 if ((NULL == ps52plib) || !(ps52plib->m_bOK))
return INIT_FAIL_REMOVE;
2495 if (name.Upper().EndsWith(
".XZ")) {
2496 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2499 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2500 wxFileName(name).GetName();
2502 if (!wxFileExists(m_TempFilePath) &&
2503 !DecompressXZFile(name, m_TempFilePath)) {
2504 wxRemoveFile(m_TempFilePath);
2505 return INIT_FAIL_REMOVE;
2508 m_TempFilePath = name;
2509 ext = wxFileName(name).GetExt();
2514 firebase::crashlytics::SetCustomKey(
"s57chartInit",
2515 name.ToStdString().c_str());
2527 InitReturn ret_value = INIT_OK;
2529 m_Description = name;
2531 wxFileName fn(m_TempFilePath);
2534 wxString cname = fn.GetName();
2535 m_usage_char = cname[2];
2538 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
2539 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
2541 if (flags == THUMB_ONLY) {
2549 if (flags == HEADER_ONLY) {
2551 if (!GetBaseFileAttr(fn.GetFullPath()))
2552 ret_value = INIT_FAIL_REMOVE;
2554 if (!CreateHeaderDataFromENC())
2555 ret_value = INIT_FAIL_REMOVE;
2557 ret_value = INIT_OK;
2559 }
else if (ext ==
"S57") {
2560 m_SENCFileName = m_TempFilePath;
2561 if (!CreateHeaderDataFromSENC())
2562 ret_value = INIT_FAIL_REMOVE;
2564 ret_value = INIT_OK;
2573 if (!m_bbase_file_attr_known) {
2574 if (!GetBaseFileAttr(m_TempFilePath))
2575 ret_value = INIT_FAIL_REMOVE;
2577 m_bbase_file_attr_known =
true;
2581 if (m_bbase_file_attr_known) {
2582 int sret = FindOrCreateSenc(m_FullPath);
2583 if (sret == BUILD_SENC_PENDING) {
2588 if (sret != BUILD_SENC_OK) {
2589 if (sret == BUILD_SENC_NOK_RETRY)
2590 ret_value = INIT_FAIL_RETRY;
2592 ret_value = INIT_FAIL_REMOVE;
2594 ret_value = PostInit(flags, m_global_color_scheme);
2599 else if (ext ==
"S57") {
2600 m_SENCFileName = m_TempFilePath;
2601 ret_value = PostInit(flags, m_global_color_scheme);
2608wxString s57chart::buildSENCName(
const wxString &name) {
2609 wxFileName fn(name);
2611 wxString file_name = fn.GetFullName();
2614 wxString SENCdir = g_SENCPrefix;
2616 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2617 SENCdir.Append(wxFileName::GetPathSeparator());
2620 wxString source_dir = fn.GetPath(wxPATH_GET_SEPARATOR);
2621 wxCharBuffer buf = source_dir.ToUTF8();
2622 unsigned char sha1_out[20];
2623 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
2626 for (
unsigned int i = 0; i < 6; i++) {
2628 s.Printf(
"%02X", sha1_out[i]);
2632 file_name.Prepend(sha1);
2635 wxFileName tsfn(SENCdir);
2636 tsfn.SetFullName(file_name);
2638 return tsfn.GetFullPath();
2645int s57chart::FindOrCreateSenc(
const wxString &name,
bool b_progress) {
2649 if (name.Upper().EndsWith(
".XZ")) {
2650 ext = wxFileName(name.Left(name.Length() - 3)).GetExt();
2653 m_TempFilePath = wxFileName::GetTempDir() + wxFileName::GetPathSeparator() +
2654 wxFileName(name).GetName();
2656 if (!wxFileExists(m_TempFilePath) &&
2657 !DecompressXZFile(name, m_TempFilePath)) {
2658 wxRemoveFile(m_TempFilePath);
2659 return INIT_FAIL_REMOVE;
2662 m_TempFilePath = name;
2663 ext = wxFileName(name).GetExt();
2667 if (!m_bbase_file_attr_known) {
2668 if (!GetBaseFileAttr(m_TempFilePath))
2669 return INIT_FAIL_REMOVE;
2671 m_bbase_file_attr_known =
true;
2675 m_SENCFileName = buildSENCName(name);
2677 int build_ret_val = 1;
2679 bool bbuild_new_senc =
false;
2680 m_bneed_new_thumbnail =
false;
2682 wxFileName FileName000(m_TempFilePath);
2686 wxString msg(
"S57chart::Checking SENC file: ");
2687 msg.Append(m_SENCFileName);
2691 int force_make_senc = 0;
2693 if (::wxFileExists(m_SENCFileName)) {
2696 if (senc.ingestHeader(m_SENCFileName)) {
2697 bbuild_new_senc =
true;
2698 wxLogMessage(
" Rebuilding SENC due to ingestHeader failure.");
2700 int senc_file_version = senc.getSencReadVersion();
2702 int last_update = senc.getSENCReadLastUpdate();
2704 wxString str = senc.getSENCFileCreateDate();
2705 wxDateTime SENCCreateDate;
2706 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
2708 if (SENCCreateDate.IsValid())
2709 SENCCreateDate.ResetTime();
2714 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
2716 senc_base_edtn.ToLong(&isenc_edition);
2718 m_edtn000.ToLong(&ifile_edition);
2723 if (senc_file_version != CURRENT_SENC_FORMAT_VERSION) {
2724 bbuild_new_senc =
true;
2725 wxLogMessage(
" Rebuilding SENC due to SENC format update.");
2732 else if (ifile_edition > isenc_edition) {
2733 bbuild_new_senc =
true;
2734 wxLogMessage(
" Rebuilding SENC due to cell edition update.");
2736 msg =
" Last edition recorded in SENC: ";
2737 msg += senc_base_edtn;
2738 msg +=
" most recent edition cell file: ";
2743 int most_recent_update_file =
2744 GetUpdateFileArray(FileName000, NULL, m_date000, m_edtn000);
2746 if (ifile_edition == isenc_edition) {
2747 if (most_recent_update_file > last_update) {
2748 bbuild_new_senc =
true;
2750 " Rebuilding SENC due to incremental cell update.");
2753 " Last update recorded in SENC: %d most recent "
2755 last_update, most_recent_update_file);
2763 wxDateTime OModTime000;
2764 FileName000.GetTimes(NULL, &OModTime000, NULL);
2765 OModTime000.ResetTime();
2766 if (SENCCreateDate.IsValid()) {
2767 if (OModTime000.IsLaterThan(SENCCreateDate)) {
2769 " Rebuilding SENC due to Senc vs cell file time "
2771 bbuild_new_senc =
true;
2774 bbuild_new_senc =
true;
2776 " Rebuilding SENC due to SENC create time invalid.");
2787 if (force_make_senc) bbuild_new_senc =
true;
2789 }
else if (!::wxFileExists(m_SENCFileName))
2791 wxLogMessage(
" Rebuilding SENC due to missing SENC file.");
2792 bbuild_new_senc =
true;
2796 if (bbuild_new_senc) {
2797 m_bneed_new_thumbnail =
2799 build_ret_val = BuildSENCFile(m_TempFilePath, m_SENCFileName, b_progress);
2801 if (BUILD_SENC_PENDING == build_ret_val)
return BUILD_SENC_PENDING;
2802 if (BUILD_SENC_NOK_PERMANENT == build_ret_val)
return INIT_FAIL_REMOVE;
2803 if (BUILD_SENC_NOK_RETRY == build_ret_val)
return INIT_FAIL_RETRY;
2809InitReturn s57chart::PostInit(ChartInitFlag flags, ColorScheme cs) {
2811 if (0 != BuildRAZFromSENCFile(m_SENCFileName)) {
2812 wxString msg(
" Cannot load SENC file ");
2813 msg.Append(m_SENCFileName);
2816 return INIT_FAIL_RETRY;
2822 wxString SENCdir = g_SENCPrefix;
2823 if (SENCdir.Last() != wxFileName::GetPathSeparator())
2824 SENCdir.Append(wxFileName::GetPathSeparator());
2826 wxFileName s57File(m_SENCFileName);
2827 wxFileName ThumbFileName(SENCdir, s57File.GetName().Mid(13),
"BMP");
2829 if (!ThumbFileName.FileExists() || m_bneed_new_thumbnail) {
2830 BuildThumbnail(ThumbFileName.GetFullPath());
2833 if (ThumbFileName.FileExists()) {
2835#ifdef ocpnUSE_ocpnBitmap
2836 pBMP_NEW =
new ocpnBitmap;
2838 pBMP_NEW =
new wxBitmap;
2840 if (pBMP_NEW->LoadFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP)) {
2843 m_pDIBThumbDay = pBMP_NEW;
2851 m_global_color_scheme = cs;
2852 SetColorScheme(cs,
false);
2855 BuildDepthContourArray();
2857 CreateChartContext();
2858 PopulateObjectsWithContext();
2861 bReadyToRender =
true;
2866void s57chart::ClearDepthContourArray() {
2867 if (m_nvaldco_alloc) {
2868 free(m_pvaldco_array);
2870 m_nvaldco_alloc = 5;
2872 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2875void s57chart::BuildDepthContourArray() {
2878 if (0 == m_nvaldco_alloc) {
2879 m_nvaldco_alloc = 5;
2880 m_pvaldco_array = (
double *)calloc(m_nvaldco_alloc,
sizeof(
double));
2886 double prev_valdco = 0.0;
2888 for (
int i = 0; i < PRIO_NUM; ++i) {
2889 for (
int j = 0; j < LUPNAME_NUM; j++) {
2890 top = razRules[i][j];
2891 while (top != NULL) {
2892 if (!strncmp(top->obj->FeatureName,
"DEPCNT", 6)) {
2893 double valdco = 0.0;
2894 if (GetDoubleAttr(top->obj,
"VALDCO", valdco)) {
2895 if (valdco != prev_valdco) {
2896 prev_valdco = valdco;
2898 if (m_nvaldco > m_nvaldco_alloc) {
2899 void *tr = realloc((
void *)m_pvaldco_array,
2900 m_nvaldco_alloc * 2 *
sizeof(
double));
2901 m_pvaldco_array = (
double *)tr;
2902 m_nvaldco_alloc *= 2;
2904 m_pvaldco_array[m_nvaldco - 1] = valdco;
2908 ObjRazRules *nxx = top->next;
2913 std::sort(m_pvaldco_array, m_pvaldco_array + m_nvaldco);
2917void s57chart::SetSafetyContour() {
2925 double mar_safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
2928 if (NULL != m_pvaldco_array) {
2929 for (i = 0; i < m_nvaldco; i++) {
2930 if (m_pvaldco_array[i] >= mar_safety_contour)
break;
2934 m_next_safe_cnt = m_pvaldco_array[i];
2936 m_next_safe_cnt = (double)1e6;
2938 m_next_safe_cnt = (double)1e6;
2943 if (m_next_safe_cnt > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
2944 m_next_safe_cnt = (
double)1e6;
2947void s57chart::CreateChartContext() {
2949 m_this_chart_context = (chart_context *)calloc(
sizeof(chart_context), 1);
2952void s57chart::PopulateObjectsWithContext() {
2953 m_this_chart_context->chart =
this;
2954 m_this_chart_context->chart_type = GetChartType();
2955 m_this_chart_context->vertex_buffer = GetLineVertexBuffer();
2956 m_this_chart_context->chart_scale = GetNativeScale();
2957 m_this_chart_context->pFloatingATONArray = pFloatingATONArray;
2958 m_this_chart_context->pRigidATONArray = pRigidATONArray;
2959 m_this_chart_context->safety_contour = m_next_safe_cnt;
2960 m_this_chart_context->pt2GetAssociatedObjects =
2961 &s57chart::GetAssociatedObjects;
2965 for (
int i = 0; i < PRIO_NUM; ++i) {
2966 for (
int j = 0; j < LUPNAME_NUM; j++) {
2967 top = razRules[i][j];
2968 while (top != NULL) {
2969 S57Obj *obj = top->obj;
2970 obj->m_chart_context = m_this_chart_context;
2977void s57chart::InvalidateCache() {
2982bool s57chart::BuildThumbnail(
const wxString &bmpname) {
2985 wxFileName ThumbFileName(bmpname);
2988 if (
true != ThumbFileName.DirExists(ThumbFileName.GetPath())) {
2989 if (!ThumbFileName.Mkdir(ThumbFileName.GetPath())) {
2990 wxLogMessage(
" Cannot create BMP file directory for " +
2991 ThumbFileName.GetFullPath());
2999 vp.
clon = (m_FullExtent.ELON + m_FullExtent.WLON) / 2.;
3000 vp.
clat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
3002 float ext_max = fmax((m_FullExtent.NLAT - m_FullExtent.SLAT),
3003 (m_FullExtent.ELON - m_FullExtent.WLON));
3010 vp.m_projection_type = PROJECTION_MERCATOR;
3012 vp.GetBBox().Set(m_FullExtent.SLAT, m_FullExtent.WLON, m_FullExtent.NLAT,
3029 unsigned int OBJLCount = ps52plib->pOBJLArray->GetCount();
3031 int *psave_viz = (
int *)malloc(OBJLCount *
sizeof(
int));
3033 int *psvr = psave_viz;
3037 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3038 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3039 *psvr++ = pOLE->nViz;
3044 bool bsavem_bShowSoundgp = ps52plib->m_bShowSoundg;
3045 bool bsave_text = ps52plib->m_bShowS57Text;
3048 ps52plib->SaveObjNoshow();
3051 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3052 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3053 if (!strncmp(pOLE->OBJLName,
"LNDARE", 6)) pOLE->nViz = 1;
3054 if (!strncmp(pOLE->OBJLName,
"DEPARE", 6)) pOLE->nViz = 1;
3057 ps52plib->m_bShowSoundg =
false;
3058 ps52plib->m_bShowS57Text =
false;
3061 DisCat dsave = ps52plib->GetDisplayCategory();
3062 ps52plib->SetDisplayCategory(MARINERS_STANDARD);
3064 ps52plib->AddObjNoshow(
"BRIDGE");
3065 ps52plib->AddObjNoshow(
"GATCON");
3067 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
3068 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, -100);
3069 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3070 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, -100);
3072#ifdef ocpnUSE_DIBSECTION
3075 wxMemoryDC memdc, dc_org;
3079 ps52plib->SaveColorScheme();
3080 ps52plib->SetPLIBColorScheme(
"DAY", ChartCtxFactory());
3082 DoRenderViewOnDC(memdc, vp, DC_RENDER_ONLY,
true);
3085 memdc.SelectObject(wxNullBitmap);
3089 for (iPtr = 0; iPtr < OBJLCount; iPtr++) {
3090 pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3091 pOLE->nViz = *psvr++;
3094 ps52plib->SetDisplayCategory(dsave);
3095 ps52plib->RestoreObjNoshow();
3097 ps52plib->RemoveObjNoshow(
"BRIDGE");
3098 ps52plib->RemoveObjNoshow(
"GATCON");
3100 ps52plib->m_bShowSoundg = bsavem_bShowSoundgp;
3101 ps52plib->m_bShowS57Text = bsave_text;
3103 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, safety_depth);
3104 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, safety_contour);
3107 ps52plib->RestoreColorScheme();
3117 wxMemoryDC dc_clone;
3118 dc_clone.SelectObject(*pBMP);
3120 pDIB->SelectIntoDC(dc_org);
3124 dc_clone.SelectObject(wxNullBitmap);
3125 dc_org.SelectObject(wxNullBitmap);
3128 ret_code = pBMP->SaveFile(ThumbFileName.GetFullPath(), wxBITMAP_TYPE_BMP);
3135WX_DEFINE_ARRAY_PTR(
float *, MyFloatPtrArray);
3136static int depth = 0;
3137static bool isProcessing =
false;
3140bool s57chart::CreateHeaderDataFromENC() {
3143 float LatMax, LatMin, LonMax, LonMin;
3149 m_pCOVRTablePoints = NULL;
3150 m_pCOVRTable = NULL;
3152 if (!InitENCMinimal(m_TempFilePath)) {
3153 wxString msg(
" Cannot initialize ENC file ");
3154 msg.Append(m_TempFilePath);
3161 MyFloatPtrArray *pAuxPtrArray =
new MyFloatPtrArray;
3162 std::vector<int> auxCntArray, noCovrCntArray;
3163 MyFloatPtrArray *pNoCovrPtrArray =
new MyFloatPtrArray;
3166 wxCriticalSectionLocker enter(GDALcriticalSection);
3167 if (isProcessing)
int yyp = 4;
3168 isProcessing =
true;
3176 pFeat = GetChartFirstM_COVR(catcov);
3181 OGRPolygon *poly = (OGRPolygon *)(pFeat->GetGeometryRef());
3182 OGRLinearRing *xring = poly->getExteriorRing();
3184 int npt = xring->getNumPoints();
3195 for (
int i = 0; i < npt; i++) {
3196 xring->getPoint(i, &p);
3200 fmax(last_p.getX(), p.getX()) - fmin(last_p.getX(), p.getX());
3202 fmax(last_p.getY(), p.getY()) - fmin(last_p.getY(), p.getY());
3203 if (xdelta < 0.001 &&
3211 pf = (
float *)realloc(pf, 2 * usedpts *
sizeof(
float));
3212 pfr = &pf[2 * (usedpts - 1)];
3215 LatMax = fmax(LatMax, p.getY());
3216 LatMin = fmin(LatMin, p.getY());
3217 LonMax = fmax(LonMax, p.getX());
3218 LonMin = fmin(LonMin, p.getX());
3226 pAuxPtrArray->Add(pf);
3227 auxCntArray.push_back(usedpts);
3228 }
else if (catcov == 2) {
3229 pNoCovrPtrArray->Add(pf);
3230 noCovrCntArray.push_back(usedpts);
3235 pFeat = GetChartNextM_COVR(catcov);
3236 DEBUG_LOG <<
"used " << usedpts <<
" points";
3242 isProcessing =
false;
3247 m_nCOVREntries = auxCntArray.size();
3251 if (m_nCOVREntries >= 1) {
3252 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3253 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3255 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3256 m_pCOVRTablePoints[j] = auxCntArray[j];
3257 m_pCOVRTable[j] = pAuxPtrArray->Item(j);
3263 wxString msg(
" ENC contains no useable M_COVR, CATCOV=1 features: ");
3264 msg.Append(m_TempFilePath);
3269 m_nNoCOVREntries = noCovrCntArray.size();
3271 if (m_nNoCOVREntries) {
3273 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3274 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3276 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3277 m_pNoCOVRTablePoints[j] = noCovrCntArray[j];
3278 m_pNoCOVRTable[j] = pNoCovrPtrArray->Item(j);
3281 m_pNoCOVRTablePoints = NULL;
3282 m_pNoCOVRTable = NULL;
3285 delete pAuxPtrArray;
3286 delete pNoCovrPtrArray;
3288 if (0 == m_nCOVREntries) {
3289 wxString msg(
" ENC contains no M_COVR features: ");
3290 msg.Append(m_TempFilePath);
3293 msg =
" Calculating Chart Extents as fallback.";
3299 S57Reader *pENCReader = m_pENCDS->GetModule(0);
3301 if (pENCReader->GetExtent(&Env,
true) == OGRERR_NONE) {
3308 m_pCOVRTablePoints = (
int *)malloc(
sizeof(
int));
3309 *m_pCOVRTablePoints = 4;
3310 m_pCOVRTable = (
float **)malloc(
sizeof(
float *));
3311 float *pf = (
float *)malloc(2 * 4 *
sizeof(
float));
3328 wxString msg(
" Cannot calculate Extents for ENC: ");
3329 msg.Append(m_TempFilePath);
3337 m_FullExtent.NLAT = LatMax;
3338 m_FullExtent.SLAT = LatMin;
3339 m_FullExtent.ELON = LonMax;
3340 m_FullExtent.WLON = LonMin;
3341 m_bExtentSet =
true;
3344 m_Chart_Scale = GetENCScale();
3355bool s57chart::CreateHeaderDataFromoSENC() {
3356 bool ret_val =
true;
3358 wxFFileInputStream fpx(m_SENCFileName);
3360 if (!::wxFileExists(m_SENCFileName)) {
3361 wxString msg(
" Cannot open SENC file ");
3362 msg.Append(m_SENCFileName);
3369 if (senc.ingestHeader(m_SENCFileName)) {
3375 m_Chart_Scale = senc.getSENCReadScale();
3378 m_Name = senc.getReadName();
3381 m_ID = senc.getReadID();
3384 Extent &ext = senc.getReadExtent();
3386 m_FullExtent.ELON = ext.ELON;
3387 m_FullExtent.WLON = ext.WLON;
3388 m_FullExtent.NLAT = ext.NLAT;
3389 m_FullExtent.SLAT = ext.SLAT;
3390 m_bExtentSet =
true;
3393 SENCFloatPtrArray &AuxPtrArray = senc.getSENCReadAuxPointArray();
3394 std::vector<int> &AuxCntArray = senc.getSENCReadAuxPointCountArray();
3396 m_nCOVREntries = AuxCntArray.size();
3398 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
3399 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
3401 for (
unsigned int j = 0; j < (
unsigned int)m_nCOVREntries; j++) {
3402 m_pCOVRTablePoints[j] = AuxCntArray[j];
3403 m_pCOVRTable[j] = (
float *)malloc(AuxCntArray[j] * 2 *
sizeof(
float));
3404 memcpy(m_pCOVRTable[j], AuxPtrArray[j],
3405 AuxCntArray[j] * 2 *
sizeof(
float));
3409 SENCFloatPtrArray &NoCovrPtrArray = senc.getSENCReadNOCOVRPointArray();
3410 std::vector<int> &NoCovrCntArray = senc.getSENCReadNOCOVRPointCountArray();
3412 m_nNoCOVREntries = NoCovrCntArray.size();
3414 if (m_nNoCOVREntries) {
3416 m_pNoCOVRTablePoints = (
int *)malloc(m_nNoCOVREntries *
sizeof(
int));
3417 m_pNoCOVRTable = (
float **)malloc(m_nNoCOVREntries *
sizeof(
float *));
3419 for (
unsigned int j = 0; j < (
unsigned int)m_nNoCOVREntries; j++) {
3420 int npoints = NoCovrCntArray[j];
3421 m_pNoCOVRTablePoints[j] = npoints;
3422 m_pNoCOVRTable[j] = (
float *)malloc(npoints * 2 *
sizeof(
float));
3423 memcpy(m_pNoCOVRTable[j], NoCovrPtrArray[j],
3424 npoints * 2 *
sizeof(
float));
3430 m_datum_str =
"WGS84";
3431 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
3433 int senc_file_version = senc.getSencReadVersion();
3435 int last_update = senc.getSENCReadLastUpdate();
3437 wxString str = senc.getSENCFileCreateDate();
3438 wxDateTime SENCCreateDate;
3439 SENCCreateDate.ParseFormat(str,
"%Y%m%d");
3441 if (SENCCreateDate.IsValid()) SENCCreateDate.ResetTime();
3443 wxString senc_base_edtn = senc.getSENCReadBaseEdition();
3450bool s57chart::CreateHeaderDataFromSENC() {
3451 if (CURRENT_SENC_FORMAT_VERSION >= 200)
return CreateHeaderDataFromoSENC();
3459bool s57chart::GetNearestSafeContour(
double safe_cnt,
double &next_safe_cnt) {
3461 if (NULL != m_pvaldco_array) {
3462 for (i = 0; i < m_nvaldco; i++) {
3463 if (m_pvaldco_array[i] >= safe_cnt)
break;
3467 next_safe_cnt = m_pvaldco_array[i];
3469 next_safe_cnt = (double)1e6;
3472 next_safe_cnt = (double)1e6;
3486std::list<S57Obj *> *s57chart::GetAssociatedObjects(S57Obj *obj) {
3490 std::list<S57Obj *> *pobj_list =
new std::list<S57Obj *>();
3493 fromSM((obj->x * obj->x_rate) + obj->x_origin,
3494 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon, &lat, &lon);
3497 switch (obj->Primitive_type) {
3510 top = razRules[disPrioIdx][3];
3511 while (top != NULL) {
3512 if (top->obj->bIsAssociable) {
3513 if (top->obj->BBObj.Contains(lat, lon)) {
3514 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3515 pobj_list->push_back(top->obj);
3522 ObjRazRules *nxx = top->next;
3527 top = razRules[disPrioIdx][4];
3528 while (top != NULL) {
3529 if (top->obj->bIsAssociable) {
3530 if (top->obj->BBObj.Contains(lat, lon)) {
3531 if (IsPointInObjArea(lat, lon, 0.0, top->obj)) {
3532 pobj_list->push_back(top->obj);
3538 ObjRazRules *nxx = top->next;
3552void s57chart::GetChartNameFromTXT(
const wxString &FullPath, wxString &Name) {
3553 wxFileName fn(FullPath);
3555 wxString target_name = fn.GetName();
3556 target_name.RemoveLast();
3558 wxString dir_name = fn.GetPath();
3560 wxDir dir(dir_name);
3562 wxArrayString FileList;
3564 dir.GetAllFiles(fn.GetPath(), &FileList);
3568 bool found_name =
false;
3572 for (
unsigned int j = 0; j < FileList.GetCount(); j++) {
3573 wxFileName file(FileList[j]);
3574 if (((file.GetExt()).MakeUpper()) ==
"TXT") {
3576 wxTextFile text_file(file.GetFullPath());
3578 bool file_ok =
true;
3582 if (!text_file.Open()) {
3583 if (!text_file.Open(wxConvISO8859_1)) file_ok =
false;
3588 wxString str = text_file.GetFirstLine();
3589 while (!text_file.Eof()) {
3590 if (0 == target_name.CmpNoCase(
3591 str.Mid(0, target_name.Len()))) {
3592 wxString tname = str.AfterFirst(
'-');
3593 name = tname.AfterFirst(
' ');
3597 str = text_file.GetNextLine();
3601 wxString msg(
" Error Reading ENC .TXT file: ");
3602 msg.Append(file.GetFullPath());
3608 if (found_name)
break;
3625const char *s57chart::getName(OGRFeature *feature) {
3626 return feature->GetDefnRef()->GetName();
3629static int ExtensionCompare(
const wxString &first,
const wxString &second) {
3630 wxFileName fn1(first);
3631 wxFileName fn2(second);
3632 wxString ext1(fn1.GetExt());
3633 wxString ext2(fn2.GetExt());
3635 return ext1.Cmp(ext2);
3638int s57chart::GetUpdateFileArray(
const wxFileName file000,
3639 wxArrayString *UpFiles, wxDateTime date000,
3641 wxString DirName000 =
3642 file000.GetPath((
int)(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME));
3643 wxDir dir(DirName000);
3644 if (!dir.IsOpened()) {
3645 DirName000.Prepend(wxFileName::GetPathSeparator());
3646 DirName000.Prepend(
".");
3647 dir.Open(DirName000);
3648 if (!dir.IsOpened()) {
3653 int flags = wxDIR_DEFAULT;
3660 wxFileName fnDir(DirName000);
3661 fnDir.RemoveLastDir();
3662 wxString sdir = fnDir.GetPath();
3663 wxFileName fnTest(sdir);
3664 wxString sname = fnTest.GetName();
3666 if (sname.ToLong(&tmps)) {
3669 flags |= wxDIR_DIRS;
3673 wxArrayString *dummy_array;
3676 if (UpFiles == NULL)
3677 dummy_array =
new wxArrayString;
3679 dummy_array = UpFiles;
3681 wxArrayString possibleFiles;
3682 wxDir::GetAllFiles(DirName000, &possibleFiles,
"", flags);
3684 for (
unsigned int i = 0; i < possibleFiles.GetCount(); i++) {
3685 wxString filename(possibleFiles[i]);
3687 wxFileName file(filename);
3688 ext = file.GetExt();
3693 if (ext.ToLong(&tmp) && (file.GetName() == file000.GetName())) {
3694 wxString FileToAdd = filename;
3696 wxCharBuffer buffer =
3699 if (buffer.data() && !filename.IsSameAs(
"CATALOG.031",
3711 DDFModule *poModule =
new DDFModule();
3712 if (!poModule->Open(FileToAdd.mb_str())) {
3714 " s57chart::BuildS57File Unable to open update file ");
3715 msg.Append(FileToAdd);
3724 DDFRecord *pr = poModule->ReadRecord();
3730 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3733 if (strlen(u)) sumdate = wxString(u, wxConvUTF8);
3737 " s57chart::BuildS57File DDFRecord 0 does not contain "
3738 "DSID:ISDT in update file ");
3739 msg.Append(FileToAdd);
3742 sumdate =
"20000101";
3745 umdate.ParseFormat(sumdate,
"%Y%m%d");
3746 if (!umdate.IsValid()) umdate.ParseFormat(
"20000101",
"%Y%m%d");
3749 if (!umdate.IsValid())
int yyp = 4;
3754 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
3756 if (strlen(u)) umedtn = wxString(u, wxConvUTF8);
3760 " s57chart::BuildS57File DDFRecord 0 does not contain "
3761 "DSID:EDTN in update file ");
3762 msg.Append(FileToAdd);
3771 if ((!umdate.IsEarlierThan(date000)) &&
3772 (umedtn.IsSameAs(edtn000)))
3773 dummy_array->Add(FileToAdd);
3779 dummy_array->Sort(ExtensionCompare);
3782 if (dummy_array->GetCount()) {
3783 wxString Last = dummy_array->Last();
3784 wxFileName fnl(Last);
3786 wxCharBuffer buffer = ext.ToUTF8();
3787 if (buffer.data()) retval = atoi(buffer.data());
3790 if (UpFiles == NULL)
delete dummy_array;
3795int s57chart::ValidateAndCountUpdates(
const wxFileName file000,
3796 const wxString CopyDir,
3797 wxString &LastUpdateDate,
3803 wxArrayString *UpFiles =
new wxArrayString;
3804 retval = GetUpdateFileArray(file000, UpFiles, m_date000, m_edtn000);
3806 if (UpFiles->GetCount()) {
3826 for (
int iff = 0; iff < retval + 1; iff++) {
3827 wxFileName ufile(m_TempFilePath);
3829 sext.Printf(
"%03d", iff);
3833 wxString cp_ufile = CopyDir;
3834 if (cp_ufile.Last() != ufile.GetPathSeparator())
3835 cp_ufile.Append(ufile.GetPathSeparator());
3837 cp_ufile.Append(ufile.GetFullName());
3842 if (ufile.FileExists()) {
3843 wxFile uf(ufile.GetFullPath());
3844 if (uf.IsOpened()) {
3850 if (ufile.FileExists() &&
3854 bool cpok = wxCopyFile(ufile.GetFullPath(), cp_ufile);
3856 wxString msg(
" Cannot copy temporary working ENC file ");
3857 msg.Append(ufile.GetFullPath());
3859 msg.Append(cp_ufile);
3872 _(
"S57 Cell Update chain incomplete.\nENC features may be "
3873 "incomplete or inaccurate.\nCheck the logfile for details."),
3874 _(
"OpenCPN Create SENC Warning"), wxOK | wxICON_EXCLAMATION,
3880 "WARNING---ENC Update chain incomplete. Substituting NULL "
3882 msg += ufile.GetFullName();
3884 wxLogMessage(
" Subsequent ENC updates may produce errors.");
3886 " This ENC exchange set should be updated and SENCs "
3890 DDFModule *dupdate =
new DDFModule;
3891 dupdate->Initialize(
'3',
'L',
'E',
'1',
'0',
"!!!", 3, 4, 4);
3892 bstat = !(dupdate->Create(cp_ufile.mb_str()) == 0);
3896 wxString msg(
" Error creating dummy update file: ");
3897 msg.Append(cp_ufile);
3902 m_tmpup_array->Add(cp_ufile);
3909 wxFileName lastfile(m_TempFilePath);
3911 last_sext.Printf(
"%03d", retval);
3912 lastfile.SetExt(last_sext);
3915 DDFModule oUpdateModule;
3920 !(oUpdateModule.Open(lastfile.GetFullPath().mb_str(), TRUE) == 0);
3924 oUpdateModule.Rewind();
3925 DDFRecord *pr = oUpdateModule.ReadRecord();
3931 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0, &nSuccess));
3935 LastUpdateDate = wxString(u, wxConvUTF8);
3938 wxDateTime now = wxDateTime::Now();
3939 LastUpdateDate = now.Format(
"%Y%m%d");
3948wxString s57chart::GetISDT() {
3949 if (m_date000.IsValid())
3950 return m_date000.Format(
"%Y%m%d");
3955bool s57chart::GetBaseFileAttr(
const wxString &file000) {
3956 if (!wxFileName::FileExists(file000))
return false;
3958 wxString FullPath000 = file000;
3959 DDFModule *poModule =
new DDFModule();
3960 if (!poModule->Open(FullPath000.mb_str())) {
3961 wxString msg(
" s57chart::BuildS57File Unable to open ");
3962 msg.Append(FullPath000);
3974 DDFRecord *pr = poModule->ReadRecord();
3978 m_nGeoRecords = pr->GetIntSubfield(
"DSSI", 0,
"NOGR", 0);
3979 if (!m_nGeoRecords) {
3981 " s57chart::BuildS57File DDFRecord 0 does not contain "
3991 char *u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"ISDT", 0));
3993 date000 = wxString(u, wxConvUTF8);
3996 " s57chart::BuildS57File DDFRecord 0 does not contain "
4003 m_date000.ParseFormat(date000,
"%Y%m%d");
4004 if (!m_date000.IsValid()) m_date000.ParseFormat(
"20000101",
"%Y%m%d");
4006 m_date000.ResetTime();
4009 u = (
char *)(pr->GetStringSubfield(
"DSID", 0,
"EDTN", 0));
4011 m_edtn000 = wxString(u, wxConvUTF8);
4014 " s57chart::BuildS57File DDFRecord 0 does not contain "
4025 for (; pr != NULL; pr = poModule->ReadRecord()) {
4026 if (pr->FindField(
"DSPM") != NULL) {
4027 m_native_scale = pr->GetIntSubfield(
"DSPM", 0,
"CSCL", 0);
4031 if (!m_native_scale) {
4032 wxString msg(
" s57chart::BuildS57File ENC not contain DSPM:CSCL ");
4035 m_native_scale = 1000;
4043int s57chart::BuildSENCFile(
const wxString &FullPath000,
4044 const wxString &SENCFileName,
bool b_progress) {
4046 double display_pix_per_meter = g_Platform->GetDisplayDPmm() * 1000;
4047 double meters_per_pixel_max_scale =
4049 m_LOD_meters = meters_per_pixel_max_scale * g_SENC_LOD_pixels;
4052 ref_lat = (m_FullExtent.NLAT + m_FullExtent.SLAT) / 2.;
4053 ref_lon = (m_FullExtent.WLON + m_FullExtent.ELON) / 2.;
4055 if (!m_disableBackgroundSENC) {
4058 ticket->m_LOD_meters = m_LOD_meters;
4059 ticket->ref_lat = ref_lat;
4060 ticket->ref_lon = ref_lon;
4061 ticket->m_FullPath000 = FullPath000;
4062 ticket->m_SENCFileName = SENCFileName;
4063 ticket->m_chart =
this;
4066 bReadyToRender =
true;
4067 return BUILD_SENC_PENDING;
4070 return BUILD_SENC_NOK_RETRY;
4075 senc.setRegistrar(g_poRegistrar);
4076 senc.setRefLocn(ref_lat, ref_lon);
4077 senc.SetLODMeters(m_LOD_meters);
4079 AbstractPlatform::ShowBusySpinner();
4081 int ret = senc.createSenc200(FullPath000, SENCFileName, b_progress);
4083 AbstractPlatform::HideBusySpinner();
4085 if (ret == ERROR_INGESTING000)
4086 return BUILD_SENC_NOK_PERMANENT;
4092int s57chart::BuildRAZFromSENCFile(
const wxString &FullPath) {
4099 S57ObjVector Objects;
4100 VE_ElementVector VEs;
4101 VC_ElementVector VCs;
4103 sencfile.setRefLocn(ref_lat, ref_lon);
4105 int srv = sencfile.ingest200(FullPath, &Objects, &VEs, &VCs);
4107 if (srv != SENC_NO_ERROR) {
4108 wxLogMessage(sencfile.getLastError());
4114 Extent ext = sencfile.getReadExtent();
4116 m_FullExtent.ELON = ext.ELON;
4117 m_FullExtent.WLON = ext.WLON;
4118 m_FullExtent.NLAT = ext.NLAT;
4119 m_FullExtent.SLAT = ext.SLAT;
4120 m_bExtentSet =
true;
4122 ref_lat = (ext.NLAT + ext.SLAT) / 2.;
4123 ref_lon = (ext.ELON + ext.WLON) / 2.;
4128 int n_ve_elements = VEs.size();
4130 double scale = top_frame::Get()->GetBestVPScale(
this);
4131 int nativescale = GetNativeScale();
4133 for (
int i = 0; i < n_ve_elements; i++) {
4134 VE_Element *vep = VEs.at(i);
4135 if (vep && vep->nCount) {
4137 double east_max = -1e7;
4138 double east_min = 1e7;
4139 double north_max = -1e7;
4140 double north_min = 1e7;
4142 float *vrun = vep->pPoints;
4143 for (
size_t i = 0; i < vep->nCount; i++) {
4144 east_max = wxMax(east_max, *vrun);
4145 east_min = wxMin(east_min, *vrun);
4148 north_max = wxMax(north_max, *vrun);
4149 north_min = wxMin(north_min, *vrun);
4153 double lat1, lon1, lat2, lon2;
4154 fromSM(east_min, north_min, ref_lat, ref_lon, &lat1, &lon1);
4155 fromSM(east_max, north_max, ref_lat, ref_lon, &lat2, &lon2);
4156 vep->edgeBBox.Set(lat1, lon1, lat2, lon2);
4159 m_ve_hash[vep->index] = vep;
4163 int n_vc_elements = VCs.size();
4165 for (
int i = 0; i < n_vc_elements; i++) {
4166 VC_Element *vcp = VCs.at(i);
4167 m_vc_hash[vcp->index] = vcp;
4175 for (
unsigned int i = 0; i < Objects.size(); i++) {
4176 S57Obj *obj = Objects[i];
4180 LUPname LUP_Name = PAPER_CHART;
4182 const wxString objnam = obj->GetAttrValueAsString(
"OBJNAM");
4183 if (objnam.Len() > 0) {
4184 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4185 SendVectorChartObjectInfo(FullPath, fe_name, objnam, obj->m_lat,
4186 obj->m_lon,
scale, nativescale);
4190 const wxString nobjnam = obj->GetAttrValueAsString(
"NOBJNM");
4191 if (nobjnam.Len() > 0 && nobjnam != objnam) {
4192 const wxString fe_name = wxString(obj->FeatureName, wxConvUTF8);
4193 SendVectorChartObjectInfo(FullPath, fe_name, nobjnam, obj->m_lat,
4194 obj->m_lon,
scale, nativescale);
4197 switch (obj->Primitive_type) {
4202 if (PAPER_CHART == ps52plib->m_nSymbolStyle)
4203 LUP_Name = PAPER_CHART;
4205 LUP_Name = SIMPLIFIED;
4214 if (PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle)
4215 LUP_Name = PLAIN_BOUNDARIES;
4217 LUP_Name = SYMBOLIZED_BOUNDARIES;
4222 LUP = ps52plib->S52_LUPLookup(LUP_Name, obj->FeatureName, obj);
4226 wxString msg(obj->FeatureName, wxConvUTF8);
4227 msg.Prepend(
" Could not find LUP for ");
4228 LogMessageOnce(msg);
4235 ps52plib->_LUP2rules(LUP, obj);
4238 _insertRules(obj, LUP,
this);
4241 obj->m_DisplayCat = LUP->DISC;
4244 obj->m_DPRI = LUP->DPRI -
'0';
4247 if (!strncmp(obj->FeatureName,
"OBSTRN", 6) ||
4248 !strncmp(obj->FeatureName,
"WRECKS", 6) ||
4249 !strncmp(obj->FeatureName,
"DEPCNT", 6) ||
4250 !strncmp(obj->FeatureName,
"UWTROC", 6)) {
4251 obj->m_bcategory_mutable =
true;
4253 obj->m_bcategory_mutable =
false;
4258 if (obj && (GEO_POINT == obj->Primitive_type)) {
4260 if ((!strncmp(obj->FeatureName,
"LITFLT", 6)) ||
4261 (!strncmp(obj->FeatureName,
"LITVES", 6)) ||
4262 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4263 pFloatingATONArray->Add(obj);
4267 if (!strncasecmp(obj->FeatureName,
"BCN", 3)) {
4268 pRigidATONArray->Add(obj);
4272 if ((!strncmp(obj->FeatureName,
"LIT", 3)) ||
4273 (!strncmp(obj->FeatureName,
"LIGHTS", 6)) ||
4274 (!strncasecmp(obj->FeatureName,
"BCN", 3)) ||
4275 (!strncasecmp(obj->FeatureName,
"BOY", 3))) {
4276 obj->bIsAton =
true;
4285 d000.ParseFormat(sencfile.getBaseDate(),
"%Y%m%d");
4286 if (!d000.IsValid()) d000.ParseFormat(
"20000101",
"%Y%m%d");
4289 updt.ParseFormat(sencfile.getUpdateDate(),
"%Y%m%d");
4290 if (!updt.IsValid()) updt.ParseFormat(
"20000101",
"%Y%m%d");
4292 if (updt.IsLaterThan(d000))
4293 m_PubYear.Printf(
"%4d", updt.GetYear());
4295 m_PubYear.Printf(
"%4d", d000.GetYear());
4298 wxDateTime upd = updt;
4299 if (!upd.IsValid()) upd.ParseFormat(
"20000101",
"%Y%m%d");
4304 m_SE = sencfile.getSENCReadBaseEdition();
4307 supdate.Printf(
" / %d", sencfile.getSENCReadLastUpdate());
4310 m_datum_str =
"WGS84";
4312 m_SoundingsDatum =
"MEAN LOWER LOW WATER";
4313 m_ID = sencfile.getReadID();
4314 m_Name = sencfile.getReadName();
4318 AssembleLineGeometry();
4323int s57chart::_insertRules(S57Obj *obj, LUPrec *LUP,
s57chart *pOwner) {
4324 ObjRazRules *rzRules = NULL;
4334 switch (LUP->DPRI) {
4347 case PRIO_SYMB_POINT:
4350 case PRIO_SYMB_LINE:
4353 case PRIO_SYMB_AREA:
4366 printf(
"SEQuencer:_insertRules():ERROR no display priority!!!\n");
4370 switch (LUP->TNAM) {
4380 case PLAIN_BOUNDARIES:
4383 case SYMBOLIZED_BOUNDARIES:
4387 printf(
"SEQuencer:_insertRules():ERROR no look up type !!!\n");
4391 rzRules = (ObjRazRules *)malloc(
sizeof(ObjRazRules));
4395 rzRules->child = NULL;
4396 rzRules->mps = NULL;
4399 rzRules->next = razRules[disPrioIdx][LUPtypeIdx];
4400 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4405 ObjRazRules *rNext = NULL;
4406 ObjRazRules *rPrevious = NULL;
4407 if (razRules[disPrioIdx][LUPtypeIdx]) {
4408 rPrevious = razRules[disPrioIdx][LUPtypeIdx];
4409 rNext = rPrevious->next;
4413 rNext = rPrevious->next;
4416 rzRules->next = NULL;
4418 rPrevious->next = rzRules;
4420 razRules[disPrioIdx][LUPtypeIdx] = rzRules;
4427void s57chart::ResetPointBBoxes(
const ViewPort &vp_last,
4437 for (
int i = 0; i < PRIO_NUM; ++i) {
4438 for (
int j = 0; j < 2; ++j) {
4439 top = razRules[i][j];
4441 while (top != NULL) {
4442 if (!top->obj->geoPtMulti)
4444 if (top->obj->BBObj.GetValid()) {
4445 double lat = top->obj->m_lat, lon = top->obj->m_lon;
4447 double lat1 = (lat - top->obj->BBObj.GetMinLat()) * d;
4448 double lat2 = (lat - top->obj->BBObj.GetMaxLat()) * d;
4450 double minlon = top->obj->BBObj.GetMinLon();
4451 double maxlon = top->obj->BBObj.GetMaxLon();
4453 double lon1 = (lon - minlon) * d;
4454 double lon2 = (lon - maxlon) * d;
4456 top->obj->BBObj.Set(lat - lat1, lon - lon1, lat - lat2, lon - lon2);
4459 top->obj->BBObj.Invalidate();
4480void s57chart::UpdateLUPs(
s57chart *pOwner) {
4484 for (
int i = 0; i < PRIO_NUM; ++i) {
4486 if ((razRules[i][0]) && (NULL == razRules[i][1])) {
4487 m_b2pointLUPS =
true;
4488 top = razRules[i][0];
4490 while (top != NULL) {
4491 LUP = ps52plib->S52_LUPLookup(PAPER_CHART, top->obj->FeatureName,
4497 if (top->obj->nRef < 2) {
4498 ps52plib->_LUP2rules(LUP, top->obj);
4499 _insertRules(top->obj, LUP, pOwner);
4500 top->obj->m_DisplayCat = LUP->DISC;
4510 if ((razRules[i][1]) && (NULL == razRules[i][0])) {
4511 m_b2pointLUPS =
true;
4512 top = razRules[i][1];
4514 while (top != NULL) {
4515 LUP = ps52plib->S52_LUPLookup(SIMPLIFIED, top->obj->FeatureName,
4518 if (top->obj->nRef < 2) {
4519 ps52plib->_LUP2rules(LUP, top->obj);
4520 _insertRules(top->obj, LUP, pOwner);
4521 top->obj->m_DisplayCat = LUP->DISC;
4531 if ((razRules[i][3]) && (NULL == razRules[i][4])) {
4532 m_b2lineLUPS =
true;
4533 top = razRules[i][3];
4535 while (top != NULL) {
4536 LUP = ps52plib->S52_LUPLookup(SYMBOLIZED_BOUNDARIES,
4537 top->obj->FeatureName, top->obj);
4539 ps52plib->_LUP2rules(LUP, top->obj);
4540 _insertRules(top->obj, LUP, pOwner);
4541 top->obj->m_DisplayCat = LUP->DISC;
4550 if ((razRules[i][4]) && (NULL == razRules[i][3])) {
4551 m_b2lineLUPS =
true;
4552 top = razRules[i][4];
4554 while (top != NULL) {
4555 LUP = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, top->obj->FeatureName,
4558 ps52plib->_LUP2rules(LUP, top->obj);
4559 _insertRules(top->obj, LUP, pOwner);
4560 top->obj->m_DisplayCat = LUP->DISC;
4572 for (
int j = 0; j < LUPNAME_NUM; j++) {
4573 top = razRules[i][j];
4574 while (top != NULL) {
4575 top->obj->bCS_Added = 0;
4578 if (top->LUP) top->obj->m_DisplayCat = top->LUP->DISC;
4589 for (
int j = 0; j < LUPNAME_NUM; j++) {
4590 top = razRules[i][j];
4591 while (top != NULL) {
4593 ObjRazRules *ctop = top->child;
4594 while (NULL != ctop) {
4595 ctop->obj->bCS_Added = 0;
4596 free_mps(ctop->mps);
4599 if (ctop->LUP) ctop->obj->m_DisplayCat = ctop->LUP->DISC;
4616ListOfObjRazRules *s57chart::GetLightsObjRuleListVisibleAtLatLon(
4617 float lat,
float lon,
ViewPort *VPoint) {
4618 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4619 std::vector<ObjRazRules *> selected_rules;
4624 char *curr_att = NULL;
4626 wxArrayOfS57attVal *attValArray = NULL;
4627 bool bleading_attribute =
false;
4629 for (
int i = 0; i < PRIO_NUM; ++i) {
4633 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4634 top = razRules[i][point_type];
4636 while (top != NULL) {
4637 if (top->obj->npt == 1) {
4638 if (!strncmp(top->obj->FeatureName,
"LIGHTS", 6)) {
4640 bool hasSectors = GetDoubleAttr(top->obj,
"SECTR1", sectrTest);
4642 if (ps52plib->ObjectRenderCheckCat(top)) {
4645 wxString curAttrName;
4646 curr_att = top->obj->att_array;
4647 n_attr = top->obj->n_attr;
4648 attValArray = top->obj->attVal;
4656 bleading_attribute =
false;
4658 while (attrCounter < n_attr) {
4659 curAttrName = wxString(curr_att, wxConvUTF8, 6);
4662 S57attVal *pAttrVal = NULL;
4665 pAttrVal = attValArray->Item(attrCounter);
4669 wxString value = s57chart::GetAttributeValueAsString(
4670 pAttrVal, curAttrName);
4672 if (curAttrName ==
"LITVIS") {
4673 if (value.StartsWith(
"obsc")) bviz =
false;
4674 }
else if (curAttrName ==
"VALNMR")
4675 value.ToDouble(&valnmr);
4681 if (bviz && (valnmr > 0.1)) {
4685 (top->obj->x * top->obj->x_rate) + top->obj->x_origin,
4686 (top->obj->y * top->obj->y_rate) + top->obj->y_origin,
4687 ref_lat, ref_lon, &olat, &olon);
4689 double dlat = lat - olat;
4690 double dy = dlat * 60 / cos(olat * PI / 180.);
4691 double dlon = lon - olon;
4692 double dx = dlon * 60;
4693 double manhat = abs(dy) + abs(dx);
4697 DistanceBearingMercator(lat, lon, olat, olon, &br, &dd);
4699 selected_rules.push_back(top);
4716 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4717 ret_ptr->Append(selected_rules[i]);
4723ListOfObjRazRules *s57chart::GetObjRuleListAtLatLon(
float lat,
float lon,
4724 float select_radius,
4726 int selection_mask) {
4727 ListOfObjRazRules *ret_ptr =
new ListOfObjRazRules;
4728 std::vector<ObjRazRules *> selected_rules;
4730 PrepareForRender(VPoint, ps52plib);
4736 for (
int i = 0; i < PRIO_NUM; ++i) {
4737 if (selection_mask & MASK_POINT) {
4740 int point_type = (ps52plib->m_nSymbolStyle == SIMPLIFIED) ? 0 : 1;
4741 top = razRules[i][point_type];
4743 while (top != NULL) {
4744 if (top->obj->npt ==
4747 if (ps52plib->ObjectRenderCheck(top)) {
4748 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4749 selected_rules.push_back(top);
4756 ObjRazRules *child_item = top->child;
4757 while (child_item != NULL) {
4758 if (ps52plib->ObjectRenderCheck(child_item)) {
4759 if (DoesLatLonSelectObject(lat, lon, select_radius,
4761 selected_rules.push_back(child_item);
4764 child_item = child_item->next;
4772 if (selection_mask & MASK_AREA) {
4775 int area_boundary_type =
4776 (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES) ? 3 : 4;
4777 top = razRules[i][area_boundary_type];
4778 while (top != NULL) {
4779 if (ps52plib->ObjectRenderCheck(top)) {
4780 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4781 selected_rules.push_back(top);
4788 if (selection_mask & MASK_LINE) {
4790 top = razRules[i][2];
4792 while (top != NULL) {
4793 if (ps52plib->ObjectRenderCheck(top)) {
4794 if (DoesLatLonSelectObject(lat, lon, select_radius, top->obj))
4795 selected_rules.push_back(top);
4806 auto sortObjs = [lat, lon,
this](
const ObjRazRules *obj1,
4807 const ObjRazRules *obj2) ->
bool {
4808 double br1, dd1, br2, dd2;
4810 if (obj1->obj->Primitive_type == GEO_POINT &&
4811 obj2->obj->Primitive_type == GEO_POINT) {
4812 double lat1, lat2, lon1, lon2;
4813 fromSM((obj1->obj->x * obj1->obj->x_rate) + obj1->obj->x_origin,
4814 (obj1->obj->y * obj1->obj->y_rate) + obj1->obj->y_origin, ref_lat,
4815 ref_lon, &lat1, &lon1);
4817 if (lon1 > 180.0) lon1 -= 360.;
4819 fromSM((obj2->obj->x * obj2->obj->x_rate) + obj2->obj->x_origin,
4820 (obj2->obj->y * obj2->obj->y_rate) + obj2->obj->y_origin, ref_lat,
4821 ref_lon, &lat2, &lon2);
4823 if (lon2 > 180.0) lon2 -= 360.;
4825 DistanceBearingMercator(lat, lon, lat1, lon1, &br1, &dd1);
4826 DistanceBearingMercator(lat, lon, lat2, lon2, &br2, &dd2);
4833 std::sort(selected_rules.begin(), selected_rules.end(), sortObjs);
4837 for (std::size_t i = 0; i < selected_rules.size(); ++i) {
4838 ret_ptr->Append(selected_rules[i]);
4844bool s57chart::DoesLatLonSelectObject(
float lat,
float lon,
float select_radius,
4846 switch (obj->Primitive_type) {
4850 if (!obj->BBObj.GetValid())
return false;
4852 if (1 == obj->npt) {
4857 if (!strncmp(obj->FeatureName,
"LIGHTS", 6)) {
4859 bool hasSectors = GetDoubleAttr(obj,
"SECTR1", sectrTest);
4862 fromSM((obj->x * obj->x_rate) + obj->x_origin,
4863 (obj->y * obj->y_rate) + obj->y_origin, ref_lat, ref_lon,
4870 sbox.Set(olat, olon, olat, olon);
4872 if (sbox.ContainsMarge(lat, lon, select_radius))
return true;
4873 }
else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4878 else if (obj->BBObj.ContainsMarge(lat, lon, select_radius))
4885 if (!obj->BBObj.GetValid())
return false;
4888 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4890 double *pdl = obj->geoPtMulti;
4891 for (
int ip = 0; ip < obj->npt; ip++) {
4892 double lon_point = *pdl++;
4893 double lat_point = *pdl++;
4895 BB_point.Set(lat_point, lon_point, lat_point, lon_point);
4896 if (BB_point.ContainsMarge(lat, lon, select_radius)) {
4907 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
4910 return IsPointInObjArea(lat, lon, select_radius, obj);
4915 if (!obj->BBObj.ContainsMarge(lat, lon, select_radius))
return false;
4917 float sel_rad_meters = select_radius * 1852 * 60;
4918 double easting, northing;
4919 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
4926 pt *ppt = obj->geoPt;
4929 double xr = obj->x_rate;
4930 double xo = obj->x_origin;
4931 double yr = obj->y_rate;
4932 double yo = obj->y_origin;
4934 double north0 = (ppt->y * yr) + yo;
4935 double east0 = (ppt->x * xr) + xo;
4938 for (
int ip = 1; ip < npt; ip++) {
4939 double north = (ppt->y * yr) + yo;
4940 double east = (ppt->x * xr) + xo;
4943 if (northing >= (fmin(north, north0) - sel_rad_meters))
4944 if (northing <= (fmax(north, north0) + sel_rad_meters))
4945 if (easting >= (fmin(east, east0) - sel_rad_meters))
4946 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
4956 if (obj->m_ls_list) {
4958 unsigned char *vbo_point =
4959 (
unsigned char *)obj->m_chart_context
4961 line_segment_element *ls = obj->m_ls_list;
4963 while (ls && vbo_point) {
4965 if ((ls->ls_type == TYPE_EE) || (ls->ls_type == TYPE_EE_REV)) {
4966 ppt = (
float *)(vbo_point + ls->pedge->vbo_offset);
4967 nPoints = ls->pedge->nCount;
4969 ppt = (
float *)(vbo_point + ls->pcs->vbo_offset);
4973 float north0 = ppt[1];
4974 float east0 = ppt[0];
4978 for (
int ip = 0; ip < nPoints - 1; ip++) {
4979 float north = ppt[1];
4980 float east = ppt[0];
4982 if (northing >= (fmin(north, north0) - sel_rad_meters))
4983 if (northing <= (fmax(north, north0) + sel_rad_meters))
4984 if (easting >= (fmin(east, east0) - sel_rad_meters))
4985 if (easting <= (fmax(east, east0) + sel_rad_meters)) {
5012wxString s57chart::GetAttributeDecode(wxString &att,
int ival) {
5013 wxString ret_val =
"";
5016 const char *att_code;
5018 wxString file(g_csv_locn);
5019 file.Append(
"/s57attributes.csv");
5021 if (!wxFileName::FileExists(file)) {
5022 wxString msg(
" Could not open ");
5029 att_code = MyCSVGetField(file.mb_str(),
"Acronym",
5031 CC_ExactString,
"Code");
5037 wxString ei_file(g_csv_locn);
5038 ei_file.Append(
"/s57expectedinput.csv");
5040 if (!wxFileName::FileExists(ei_file)) {
5041 wxString msg(
" Could not open ");
5042 msg.Append(ei_file);
5048 CSVTable *psTable = CSVAccess(ei_file.mb_str());
5049 CSVIngest(ei_file.mb_str());
5051 char **papszFields = NULL;
5052 int bSelected = FALSE;
5058 while (!bSelected && iline + 1 < psTable->nLineCount) {
5060 papszFields = CSVSplitLine(psTable->papszLines[iline]);
5062 if (!strcmp(papszFields[0], att_code)) {
5063 if (atoi(papszFields[1]) == ival) {
5064 ret_val = wxString(papszFields[2], wxConvUTF8);
5069 CSLDestroy(papszFields);
5077bool s57chart::IsPointInObjArea(
float lat,
float lon,
float select_radius,
5081 if (obj->pPolyTessGeo) {
5082 if (!obj->pPolyTessGeo->IsOk()) obj->pPolyTessGeo->BuildDeferredTess();
5084 PolyTriGroup *ppg = obj->pPolyTessGeo->Get_PolyTriGroup_head();
5086 TriPrim *pTP = ppg->tri_prim_head;
5088 MyPoint pvert_list[3];
5092 double easting, northing;
5093 toSM(lat, lon, ref_lat, ref_lon, &easting, &northing);
5097 if (!ppg->m_bSMSENC) {
5098 double y_rate = obj->y_rate;
5099 double y_origin = obj->y_origin;
5100 double x_rate = obj->x_rate;
5101 double x_origin = obj->x_origin;
5103 double northing_scaled = (northing - y_origin) / y_rate;
5104 double easting_scaled = (easting - x_origin) / x_rate;
5105 northing = northing_scaled;
5106 easting = easting_scaled;
5111 if (pTP->tri_box.Contains(lat, lon)) {
5112 if (ppg->data_type == DATA_TYPE_DOUBLE) {
5113 double *p_vertex = pTP->p_vertex;
5115 switch (pTP->type) {
5116 case PTG_TRIANGLE_FAN: {
5117 for (
int it = 0; it < pTP->nVert - 2; it++) {
5118 pvert_list[0].x = p_vertex[0];
5119 pvert_list[0].y = p_vertex[1];
5121 pvert_list[1].x = p_vertex[(it * 2) + 2];
5122 pvert_list[1].y = p_vertex[(it * 2) + 3];
5124 pvert_list[2].x = p_vertex[(it * 2) + 4];
5125 pvert_list[2].y = p_vertex[(it * 2) + 5];
5127 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5135 case PTG_TRIANGLE_STRIP: {
5136 for (
int it = 0; it < pTP->nVert - 2; it++) {
5137 pvert_list[0].x = p_vertex[(it * 2)];
5138 pvert_list[0].y = p_vertex[(it * 2) + 1];
5140 pvert_list[1].x = p_vertex[(it * 2) + 2];
5141 pvert_list[1].y = p_vertex[(it * 2) + 3];
5143 pvert_list[2].x = p_vertex[(it * 2) + 4];
5144 pvert_list[2].y = p_vertex[(it * 2) + 5];
5146 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5154 case PTG_TRIANGLES: {
5155 for (
int it = 0; it < pTP->nVert; it += 3) {
5156 pvert_list[0].x = p_vertex[(it * 2)];
5157 pvert_list[0].y = p_vertex[(it * 2) + 1];
5159 pvert_list[1].x = p_vertex[(it * 2) + 2];
5160 pvert_list[1].y = p_vertex[(it * 2) + 3];
5162 pvert_list[2].x = p_vertex[(it * 2) + 4];
5163 pvert_list[2].y = p_vertex[(it * 2) + 5];
5165 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5174 }
else if (ppg->data_type == DATA_TYPE_FLOAT) {
5175 float *p_vertex = (
float *)pTP->p_vertex;
5177 switch (pTP->type) {
5178 case PTG_TRIANGLE_FAN: {
5179 for (
int it = 0; it < pTP->nVert - 2; it++) {
5180 pvert_list[0].x = p_vertex[0];
5181 pvert_list[0].y = p_vertex[1];
5183 pvert_list[1].x = p_vertex[(it * 2) + 2];
5184 pvert_list[1].y = p_vertex[(it * 2) + 3];
5186 pvert_list[2].x = p_vertex[(it * 2) + 4];
5187 pvert_list[2].y = p_vertex[(it * 2) + 5];
5189 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5197 case PTG_TRIANGLE_STRIP: {
5198 for (
int it = 0; it < pTP->nVert - 2; it++) {
5199 pvert_list[0].x = p_vertex[(it * 2)];
5200 pvert_list[0].y = p_vertex[(it * 2) + 1];
5202 pvert_list[1].x = p_vertex[(it * 2) + 2];
5203 pvert_list[1].y = p_vertex[(it * 2) + 3];
5205 pvert_list[2].x = p_vertex[(it * 2) + 4];
5206 pvert_list[2].y = p_vertex[(it * 2) + 5];
5208 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5216 case PTG_TRIANGLES: {
5217 for (
int it = 0; it < pTP->nVert; it += 3) {
5218 pvert_list[0].x = p_vertex[(it * 2)];
5219 pvert_list[0].y = p_vertex[(it * 2) + 1];
5221 pvert_list[1].x = p_vertex[(it * 2) + 2];
5222 pvert_list[1].y = p_vertex[(it * 2) + 3];
5224 pvert_list[2].x = p_vertex[(it * 2) + 4];
5225 pvert_list[2].y = p_vertex[(it * 2) + 5];
5227 if (G_PtInPolygon((MyPoint *)pvert_list, 3, easting,
5250wxString s57chart::GetObjectAttributeValueAsString(S57Obj *obj,
int iatt,
5251 wxString curAttrName) {
5255 pval = obj->attVal->Item(iatt);
5256 switch (pval->valType) {
5259 wxString val_str((
char *)(pval->value), wxConvUTF8);
5261 if (val_str.ToLong(&ival)) {
5265 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5266 if (!decode_val.IsEmpty()) {
5269 iv.Printf(
" (%d)", (
int)ival);
5272 value.Printf(
"%d", (
int)ival);
5276 else if (val_str.IsEmpty())
5281 wxString value_increment;
5282 wxStringTokenizer tk(val_str,
",");
5284 if (tk.HasMoreTokens()) {
5285 while (tk.HasMoreTokens()) {
5286 wxString token = tk.GetNextToken();
5288 if (token.ToLong(&ival)) {
5289 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5291 value_increment.Printf(
" (%d)", (
int)ival);
5293 if (!decode_val.IsEmpty()) value_increment.Prepend(decode_val);
5295 if (iv) value_increment.Prepend(
", ");
5296 value.Append(value_increment);
5299 if (iv) value.Append(
",");
5300 value.Append(token);
5306 value.Append(val_str);
5309 value =
"[NULL VALUE]";
5315 int ival = *((
int *)pval->value);
5316 wxString decode_val = GetAttributeDecode(curAttrName, ival);
5318 if (!decode_val.IsEmpty()) {
5321 iv.Printf(
"(%d)", ival);
5324 value.Printf(
"(%d)", ival);
5332 double dval = *((
double *)pval->value);
5333 wxString val_suffix =
" m";
5334 bool has_preformatted =
false;
5335 wxString preformatted;
5346 if ((curAttrName ==
"VERCLR") || (curAttrName ==
"VERCCL") ||
5347 (curAttrName ==
"VERCOP") || (curAttrName ==
"HEIGHT") ||
5348 (curAttrName ==
"ELEVAT") || (curAttrName ==
"VERCSA")) {
5353 val_suffix = wxString::Format(
" %s",
unit.c_str());
5354 }
else if (curAttrName ==
"HORCLR") {
5357 double nm = dval / 1852.0;
5359 has_preformatted =
true;
5362 else if ((curAttrName ==
"VALSOU") || (curAttrName ==
"DRVAL1") ||
5363 (curAttrName ==
"DRVAL2") || (curAttrName ==
"VALDCO")) {
5370 wxString
unit = getUsrDepthUnit(-1);
5371 val_suffix = wxString::Format(
" %s",
unit.c_str());
5374 else if (curAttrName ==
"SECTR1")
5375 val_suffix =
"°";
5376 else if (curAttrName ==
"SECTR2")
5377 val_suffix =
"°";
5378 else if (curAttrName ==
"ORIENT")
5379 val_suffix =
"°";
5380 else if (curAttrName ==
"VALNMR")
5382 else if (curAttrName ==
"SIGPER")
5384 else if (curAttrName ==
"VALACM")
5385 val_suffix =
" Minutes/year";
5386 else if (curAttrName ==
"VALMAG")
5387 val_suffix =
"°";
5388 else if (curAttrName ==
"CURVEL")
5391 if (has_preformatted) {
5392 value = preformatted;
5394 if (dval - floor(dval) < 0.01)
5395 value.Printf(
"%2.0f", dval);
5397 value.Printf(
"%4.1f", dval);
5398 value << val_suffix;
5404 case OGR_REAL_LST: {
5411wxString s57chart::GetAttributeValueAsString(S57attVal *pAttrVal,
5412 wxString AttrName) {
5413 if (NULL == pAttrVal)
return "";
5416 switch (pAttrVal->valType) {
5418 if (pAttrVal->value) {
5419 wxString val_str((
char *)(pAttrVal->value), wxConvUTF8);
5421 if (val_str.ToLong(&ival)) {
5425 wxString decode_val = GetAttributeDecode(AttrName, ival);
5426 if (!decode_val.IsEmpty()) {
5429 iv.Printf(
"(%d)", (
int)ival);
5432 value.Printf(
"%d", (
int)ival);
5436 else if (val_str.IsEmpty())
5441 wxString value_increment;
5442 wxStringTokenizer tk(val_str,
",");
5444 while (tk.HasMoreTokens()) {
5445 wxString token = tk.GetNextToken();
5447 if (token.ToLong(&ival)) {
5448 wxString decode_val = GetAttributeDecode(AttrName, ival);
5449 if (!decode_val.IsEmpty())
5450 value_increment = decode_val;
5452 value_increment.Printf(
" %d", (
int)ival);
5454 if (iv) value_increment.Prepend(
", ");
5456 value.Append(value_increment);
5460 value.Append(val_str);
5463 value =
"[NULL VALUE]";
5469 int ival = *((
int *)pAttrVal->value);
5470 wxString decode_val = GetAttributeDecode(AttrName, ival);
5472 if (!decode_val.IsEmpty()) {
5475 iv.Printf(
"(%d)", ival);
5478 value.Printf(
"(%d)", ival);
5486 double dval = *((
double *)pAttrVal->value);
5487 wxString val_suffix =
" m";
5488 bool has_preformatted =
false;
5489 wxString preformatted;
5492 if ((AttrName ==
"VERCLR") || (AttrName ==
"VERCCL") ||
5493 (AttrName ==
"VERCOP") || (AttrName ==
"HEIGHT") ||
5494 (AttrName ==
"ELEVAT")) {
5499 val_suffix = wxString::Format(
" %s",
unit.c_str());
5500 }
else if (AttrName ==
"HORCLR") {
5502 double nm = dval / 1852.0;
5504 has_preformatted =
true;
5507 else if ((AttrName ==
"VALSOU") || (AttrName ==
"DRVAL1") ||
5508 (AttrName ==
"DRVAL2")) {
5511 wxString
unit = getUsrDepthUnit(-1);
5512 val_suffix = wxString::Format(
" %s",
unit.c_str());
5515 else if (AttrName ==
"SECTR1")
5516 val_suffix =
"°";
5517 else if (AttrName ==
"SECTR2")
5518 val_suffix =
"°";
5519 else if (AttrName ==
"ORIENT")
5520 val_suffix =
"°";
5521 else if (AttrName ==
"VALNMR")
5523 else if (AttrName ==
"SIGPER")
5525 else if (AttrName ==
"VALACM")
5526 val_suffix =
" Minutes/year";
5527 else if (AttrName ==
"VALMAG")
5528 val_suffix =
"°";
5529 else if (AttrName ==
"CURVEL")
5532 if (has_preformatted) {
5533 value = preformatted;
5535 if (dval - floor(dval) < 0.01)
5536 value.Printf(
"%2.0f", dval);
5538 value.Printf(
"%4.1f", dval);
5539 value << val_suffix;
5545 case OGR_REAL_LST: {
5553 int positionDiff = l1->position.Cmp(l2->position);
5554 if (positionDiff < 0)
return false;
5556 int attrIndex1 = l1->attributeNames.Index(
"SECTR1");
5557 int attrIndex2 = l2->attributeNames.Index(
"SECTR1");
5560 if (attrIndex1 == wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return false;
5561 if (attrIndex1 != wxNOT_FOUND && attrIndex2 == wxNOT_FOUND)
return true;
5562 if (attrIndex1 == wxNOT_FOUND && attrIndex2 != wxNOT_FOUND)
return false;
5564 double angle1, angle2;
5565 l1->attributeValues.Item(attrIndex1).ToDouble(&angle1);
5566 l2->attributeValues.Item(attrIndex2).ToDouble(&angle2);
5568 return angle1 < angle2;
5571static const char *type2str(GeoPrim_t type) {
5572 const char *r =
"Unknown";
5593wxString s57chart::CreateObjDescriptions(ListOfObjRazRules *rule_list) {
5596 wxString curAttrName, value;
5597 bool isLight =
false;
5600 wxString classAttributes;
5602 wxString lightsHtml;
5603 wxString positionString;
5604 std::vector<S57Light *> lights;
5608 for (ListOfObjRazRules::Node *node = rule_list->GetLast(); node;
5609 node = node->GetPrevious()) {
5610 ObjRazRules *current = node->GetData();
5611 positionString.Clear();
5615 if (0 == strncmp(current->LUP->OBCL,
"SOUND", 5))
continue;
5617 if (current->obj->Primitive_type == GEO_META)
continue;
5618 if (current->obj->Primitive_type == GEO_PRIM)
continue;
5620 className = wxString(current->obj->FeatureName, wxConvUTF8);
5623 isLight = !strcmp(current->obj->FeatureName,
"LIGHTS");
5628 const char *name_desc;
5629 if (g_csv_locn.Len()) {
5630 wxString oc_file(g_csv_locn);
5631 oc_file.Append(
"/s57objectclasses.csv");
5632 name_desc = MyCSVGetField(oc_file.mb_str(),
"Acronym",
5633 current->obj->FeatureName,
5634 CC_ExactString,
"ObjectClass");
5640 if (0 == strlen(name_desc)) {
5641 name_desc = current->obj->FeatureName;
5642 classDesc = wxString(name_desc, wxConvUTF8, 1);
5643 classDesc << wxString(name_desc + 1, wxConvUTF8).MakeLower();
5645 classDesc = wxString(name_desc, wxConvUTF8);
5652 classAttributes =
"";
5653 index.Printf(
"Feature Index: %d<br>", current->obj->Index);
5654 classAttributes << index;
5657 LUPstring.Printf(
"LUP RCID: %d<br>", current->LUP->RCID);
5658 classAttributes << LUPstring;
5661 LLBBox bbox = current->obj->BBObj;
5662 Bbox.Printf(
"Lat/Lon box: %g %g %g %g<br>", bbox.GetMinLat(),
5663 bbox.GetMaxLat(), bbox.GetMinLon(), bbox.GetMaxLon());
5664 classAttributes << Bbox;
5667 Type.Printf(
" Type: %s<br>", type2str(current->obj->Primitive_type));
5668 classAttributes << Type;
5670 LUPstring =
" LUP ATTC: ";
5671 if (current->LUP->ATTArray.size())
5672 LUPstring += wxString(current->LUP->ATTArray[0].c_str(), wxConvUTF8);
5673 LUPstring +=
"<br>";
5674 classAttributes << LUPstring;
5676 LUPstring =
" LUP INST: ";
5677 LUPstring += current->LUP->INST;
5678 LUPstring +=
"<br><br>";
5679 classAttributes << LUPstring;
5682 if (GEO_POINT == current->obj->Primitive_type) {
5684 fromSM((current->obj->x * current->obj->x_rate) + current->obj->x_origin,
5685 (current->obj->y * current->obj->y_rate) + current->obj->y_origin,
5686 ref_lat, ref_lon, &lat, &lon);
5688 if (lon > 180.0) lon -= 360.;
5690 positionString.Clear();
5691 positionString += toSDMM(1, lat);
5692 positionString <<
" ";
5693 positionString += toSDMM(2, lon);
5697 curLight->position = positionString;
5698 curLight->hasSectors =
false;
5699 lights.push_back(curLight);
5705 if (current->obj->att_array) {
5706 char *curr_att = current->obj->att_array;
5712 attribStr <<
"<table border=0 cellspacing=0 cellpadding=0>";
5715 ret_val <<
"<p>" << classAttributes;
5718 bool inDepthRange =
false;
5720 while (attrCounter < current->obj->n_attr) {
5722 curAttrName = wxString(curr_att, wxConvUTF8, 6);
5729 assert(curLight !=
nullptr);
5730 curLight->attributeNames.Add(curAttrName);
5731 if (curAttrName.StartsWith(
"SECTR")) curLight->hasSectors =
true;
5733 if (curAttrName ==
"DRVAL1") {
5734 attribStr <<
"<tr><td><font size=-1>";
5735 inDepthRange =
true;
5736 }
else if (curAttrName ==
"DRVAL2") {
5738 inDepthRange =
false;
5741 attribStr <<
"</font></td></tr>\n";
5742 inDepthRange =
false;
5744 attribStr <<
"<tr><td valign=top><font size=-2>";
5745 if (curAttrName ==
"catgeo")
5746 attribStr <<
"CATGEO";
5748 attribStr << curAttrName;
5749 attribStr <<
"</font></td><td> </td><td "
5750 "valign=top><font size=-1>";
5761 value = GetObjectAttributeValueAsString(current->obj, attrCounter,
5766 wxString AttrNamesFiles =
5767 "PICREP,TXTDSC,NTXTDS";
5769 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND)
5770 if (value.Find(
".XML") == wxNOT_FOUND) {
5771 file.Assign(GetFullPath());
5772 file.Assign(file.GetPath(), value);
5775 if (file.IsCaseSensitive()) {
5776 wxDir dir(file.GetPath());
5778 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
5780 if (filename.IsSameAs(value,
false)) {
5782 file.Assign(file.GetPath(), value);
5785 cont = dir.GetNext(&filename);
5792 wxString::Format(
"<a href=\"%s\">%s</a>",
5793 file.GetFullPath(), file.GetFullName());
5795 value = value +
" <font color=\"red\">[ " +
5796 _(
"this file is not available") +
" ]</font>";
5800 "DATEND,DATSTA,PEREND,PERSTA";
5801 if (AttrNamesFiles.Find(curAttrName) != wxNOT_FOUND) {
5804 wxString ts = value;
5808 if (ts.Length() < 5) {
5812 if (ts.Length() < 7) {
5816 wxString::const_iterator end;
5818 if (dt.ParseFormat(ts,
"%Y%m%d", &end)) {
5820 if (m) ts = wxDateTime::GetMonthName(dt.GetMonth());
5821 if (d) ts.Append(wxString::Format(
" %d", dt.GetDay()));
5822 if (dt.GetYear() > 0)
5823 ts.Append(wxString::Format(
", %i", dt.GetYear()));
5824 if (curAttrName ==
"PEREND")
5825 ts = _(
"Period ends: ") + ts +
" (" + value +
")";
5826 if (curAttrName ==
"PERSTA")
5827 ts = _(
"Period starts: ") + ts +
" (" + value +
")";
5828 if (curAttrName ==
"DATEND")
5829 ts = _(
"Date ending: ") + ts +
" (" + value +
")";
5830 if (curAttrName ==
"DATSTA")
5831 ts = _(
"Date starting: ") + ts +
" (" + value +
")";
5835 if (curAttrName ==
"TS_TSP") {
5842 wxStringTokenizer tk(value,
",");
5847 ts1 = tk.GetNextToken().Trim(
false);
5850 }
while ((ts1.Left(2).ToLong(&l)));
5851 ts =
"Tidal Streams referred to<br><b>";
5852 ts.Append(tk.GetNextToken()).Append(
"</b> at <b>").Append(ts1);
5853 ts.Append(
"</b><br><table >");
5855 while (tk.HasMoreTokens()) {
5856 ts.Append(
"<tr><td>");
5857 wxString s1(wxString::Format(
"%+dh ", i));
5859 ts.Append(
"</td><td>");
5860 s1 = tk.GetNextToken();
5862 s1 =
"°</td><td>";
5864 s1 = tk.GetNextToken();
5867 ts.Append(
"</td></tr>");
5870 ts.Append(
"</table>");
5875 assert(curLight !=
nullptr);
5876 curLight->attributeValues.Add(value);
5878 if (curAttrName ==
"INFORM" || curAttrName ==
"NINFOM")
5879 value.Replace(
"|",
"<br>");
5881 if (curAttrName ==
"catgeo")
5882 attribStr << type2str(current->obj->Primitive_type);
5886 if (!(curAttrName ==
"DRVAL1")) {
5887 attribStr <<
"</font></td></tr>\n";
5897 attribStr <<
"</table>\n";
5899 objText +=
"<b>" + classDesc +
"</b> <font size=-2>(" + className +
5900 ")</font>" +
"<br>";
5902 if (positionString.Length())
5903 objText <<
"<font size=-2>" << positionString <<
"</font><br>\n";
5905 if (noAttr > 0) objText << attribStr;
5907 if (node != rule_list->GetFirst()) objText +=
"<hr noshade>";
5914 if (!lights.empty()) {
5915 assert(curLight !=
nullptr);
5920 std::sort(lights.begin(), lights.end(), s57chart::CompareLights);
5924 for (
auto const &thisLight : lights) {
5927 if (thisLight->position != lastPos) {
5928 lastPos = thisLight->position;
5930 if (thisLight != *lights.begin())
5931 lightsHtml <<
"</table>\n<hr noshade>\n";
5933 lightsHtml <<
"<b>Light</b> <font size=-2>(LIGHTS)</font><br>";
5934 lightsHtml <<
"<font size=-2>" << thisLight->position
5937 if (curLight->hasSectors)
5939 "<font size=-2>(Sector angles are True Bearings from "
5940 "Seaward)</font><br>");
5942 lightsHtml <<
"<table>";
5945 lightsHtml <<
"<tr>";
5946 lightsHtml <<
"<td><font size=-1>";
5949 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
5950 if (attrIndex != wxNOT_FOUND) {
5951 wxString color = thisLight->attributeValues.Item(attrIndex);
5952 if (color ==
"red (3)" || color ==
"red(3)")
5954 "<table border=0><tr><td "
5955 "bgcolor=red> </td></tr></table> ";
5956 else if (color ==
"green (4)" || color ==
"green(4)")
5958 "<table border=0><tr><td "
5959 "bgcolor=green> </td></tr></table> ";
5960 else if (color ==
"white (1)" || color ==
"white(1)")
5962 "<table border=0><tr><td "
5963 "bgcolor=white> </td></tr></table> ";
5964 else if (color ==
"yellow (6)" || color ==
"yellow(6)")
5966 "<table border=0><tr><td "
5967 "bgcolor=yellow> </td></tr></table> ";
5968 else if (color ==
"blue (5)" || color ==
"blue(5)")
5970 "<table border=0><tr><td "
5971 "bgcolor=blue> </td></tr></table> ";
5972 else if (color ==
"magenta (12)" || color ==
"magenta(12)")
5974 "<table border=0><tr><td "
5975 "bgcolor=magenta> </td></tr></table> ";
5978 "<table border=0><tr><td "
5979 "bgcolor=grey> ? </td></tr></table> ";
5982 int visIndex = thisLight->attributeNames.Index(
"LITVIS");
5983 if (visIndex != wxNOT_FOUND) {
5984 wxString vis = thisLight->attributeValues.Item(visIndex);
5985 if (vis.Contains(
"8")) {
5986 if (attrIndex != wxNOT_FOUND) {
5987 wxString color = thisLight->attributeValues.Item(attrIndex);
5988 if ((color ==
"red (3)" || color ==
"red(3)"))
5990 "<table border=0><tr><td "
5991 "bgcolor=DarkRed> </td></tr></table> ";
5992 if ((color ==
"green (4)" || color ==
"green(4)"))
5994 "<table border=0><tr><td "
5995 "bgcolor=DarkGreen> </td></tr></table> ";
5996 if ((color ==
"white (1)" || color ==
"white(1)"))
5998 "<table border=0><tr><td "
5999 "bgcolor=GoldenRod> </td></tr></table> ";
6004 lightsHtml << colorStr;
6006 lightsHtml <<
"</font></td><td><font size=-1><nobr><b>";
6008 attrIndex = thisLight->attributeNames.Index(
"LITCHR");
6009 if (attrIndex != wxNOT_FOUND) {
6010 wxString character = thisLight->attributeValues[attrIndex];
6011 lightsHtml << character.BeforeFirst(wxChar(
'(')) <<
" ";
6014 attrIndex = thisLight->attributeNames.Index(
"SIGGRP");
6015 if (attrIndex != wxNOT_FOUND) {
6016 lightsHtml << thisLight->attributeValues[attrIndex];
6020 attrIndex = thisLight->attributeNames.Index(
"COLOUR");
6021 if (attrIndex != wxNOT_FOUND) {
6023 << thisLight->attributeValues.Item(attrIndex).Upper()[0];
6027 attrIndex = thisLight->attributeNames.Index(
"SIGPER");
6028 if (attrIndex != wxNOT_FOUND) {
6029 lightsHtml << thisLight->attributeValues[attrIndex];
6033 attrIndex = thisLight->attributeNames.Index(
"HEIGHT");
6034 if (attrIndex != wxNOT_FOUND) {
6035 lightsHtml << thisLight->attributeValues[attrIndex];
6039 attrIndex = thisLight->attributeNames.Index(
"VALNMR");
6040 if (attrIndex != wxNOT_FOUND) {
6041 lightsHtml << thisLight->attributeValues[attrIndex];
6045 lightsHtml <<
"</b>";
6047 attrIndex = thisLight->attributeNames.Index(
"SECTR1");
6048 if (attrIndex != wxNOT_FOUND) {
6049 lightsHtml <<
"(" << thisLight->attributeValues[attrIndex];
6050 lightsHtml <<
" - ";
6051 attrIndex = thisLight->attributeNames.Index(
"SECTR2");
6052 lightsHtml << thisLight->attributeValues[attrIndex] <<
") ";
6055 lightsHtml <<
"</nobr>";
6057 attrIndex = thisLight->attributeNames.Index(
"CATLIT");
6058 if (attrIndex != wxNOT_FOUND) {
6059 lightsHtml <<
"<nobr>";
6060 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6062 lightsHtml <<
"</nobr> ";
6065 attrIndex = thisLight->attributeNames.Index(
"EXCLIT");
6066 if (attrIndex != wxNOT_FOUND) {
6067 lightsHtml <<
"<nobr>";
6068 lightsHtml << thisLight->attributeValues[attrIndex].BeforeFirst(
6070 lightsHtml <<
"</nobr> ";
6073 attrIndex = thisLight->attributeNames.Index(
"OBJNAM");
6074 if (attrIndex != wxNOT_FOUND) {
6075 lightsHtml <<
"<br><nobr>";
6076 lightsHtml << thisLight->attributeValues[attrIndex].Left(1).Upper();
6077 lightsHtml << thisLight->attributeValues[attrIndex].Mid(1);
6078 lightsHtml <<
"</nobr> ";
6081 lightsHtml <<
"</font></td>";
6082 lightsHtml <<
"</tr>";
6084 thisLight->attributeNames.Clear();
6085 thisLight->attributeValues.Clear();
6088 lightsHtml <<
"</table><hr noshade>\n";
6089 ret_val = lightsHtml << ret_val;
6103bool s57chart::InitENCMinimal(
const wxString &FullPath) {
6104 if (NULL == g_poRegistrar) {
6105 wxLogMessage(
" Error: No ClassRegistrar in InitENCMinimal.");
6109 m_pENCDS =
new OGRS57DataSource;
6111 m_pENCDS->SetS57Registrar(g_poRegistrar);
6113 if (!m_pENCDS->OpenMin(FullPath.mb_str(), TRUE))
6116 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6117 pENCReader->SetClassBased(g_poRegistrar);
6119 int rc = pENCReader->Ingest();
6123OGRFeature *s57chart::GetChartFirstM_COVR(
int &catcov) {
6125 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6127 if ((NULL != pENCReader) && (NULL != g_poRegistrar)) {
6129 g_poRegistrar->SelectClass(
"M_COVR");
6136 OGRFeatureDefn *poDefn = S57GenerateObjectClassDefnM_COVR(302);
6139 pENCReader->AddFeatureDefn(poDefn);
6142 m_pENCDS->AddLayer(
new OGRS57Layer(m_pENCDS, poDefn, 1));
6145 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6148 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6159OGRFeature *s57chart::GetChartNextM_COVR(
int &catcov) {
6163 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6166 OGRFeatureDefn *poDefn = m_pENCDS->GetLayer(0)->GetLayerDefn();
6169 OGRFeature *pobjectDef = pENCReader->ReadNextFeature(poDefn);
6172 catcov = pobjectDef->GetFieldAsInteger(
"CATCOV");
6181int s57chart::GetENCScale() {
6182 if (NULL == m_pENCDS)
return 0;
6189 S57Reader *pENCReader = m_pENCDS->GetModule(0);
6192 return pENCReader->GetCSCL();
6202static void OpenCPN_OGRErrorHandler(CPLErr eErrClass,
int nError,
6203 const char *pszErrorMsg) {
6204#define ERR_BUF_LEN 2000
6206 char buf[ERR_BUF_LEN + 1];
6208 if (eErrClass == CE_Debug)
6209 sprintf(buf,
" %s", pszErrorMsg);
6210 else if (eErrClass == CE_Warning)
6211 sprintf(buf,
" Warning %d: %s\n", nError, pszErrorMsg);
6213 sprintf(buf,
" ERROR %d: %s\n", nError, pszErrorMsg);
6215 if (g_bGDAL_Debug || (CE_Debug != eErrClass)) {
6216 wxString msg(buf, wxConvUTF8);
6222 if (eErrClass == CE_Fatal) {
6223 longjmp(env_ogrf, 1);
6234const char *MyCSVGetField(
const char *pszFilename,
const char *pszKeyFieldName,
6235 const char *pszKeyFieldValue,
6236 CSVCompareCriteria eCriteria,
6237 const char *pszTargetField)
6246 papszRecord = CSVScanFileByName(pszFilename, pszKeyFieldName,
6247 pszKeyFieldValue, eCriteria);
6249 if (papszRecord == NULL)
return "";
6254 iTargetField = CSVGetFileFieldId(pszFilename, pszTargetField);
6255 if (iTargetField < 0)
return "";
6257 if (iTargetField >= CSLCount(papszRecord))
return "";
6259 return (papszRecord[iTargetField]);
6273static bool s57_GetChartExtent(
const wxString &FullPath,
Extent *pext) {
6297 std::vector<s57Sector_t> §orlegs) {
6298 float rangeScale = 0.0;
6300 if (sectorlegs.size() > 0) {
6301 std::vector<int> sectorangles;
6302 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6303 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6306 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6307 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6312 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6313 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6319 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6322 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6323 powf((
float)(lightPos.y - end1.y), 2));
6325 if (rangeScale == 0.0) {
6328 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6332 rangePx = rangePx * rangeScale;
6334 int penWidth = rangePx / 8;
6335 penWidth = wxMin(20, penWidth);
6336 penWidth = wxMax(5, penWidth);
6339 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
6340 penWidth, wxPENSTYLE_SOLID);
6341 arcpen->SetCap(wxCAP_BUTT);
6344 float angle1, angle2;
6345 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6346 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6347 if (angle1 > angle2) {
6350 int lpx = lightPos.x;
6351 int lpy = lightPos.y;
6353 wxPoint arcpoints[150];
6356 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
6360 int narc = (angle2 - angle1) / step;
6362 step = (angle2 - angle1) / (
float)narc;
6364 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6365 wxPoint yellowCone[3];
6366 yellowCone[0] = lightPos;
6367 yellowCone[1] = end1;
6368 yellowCone[2] = end2;
6369 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6372 wxColor c = sectorlegs[i].color;
6373 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6374 dc.SetBrush(wxBrush(c));
6375 dc.StrokePolygon(3, yellowCone, 0, 0);
6378 for (
float a = angle1; a <= angle2 + 0.1; a += step) {
6379 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
6380 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
6381 arcpoints[npoints].x = x;
6382 arcpoints[npoints].y = y;
6385 dc.StrokeLines(npoints, arcpoints);
6389 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
6395 bool haveAngle1 =
false;
6396 bool haveAngle2 =
false;
6397 int sec1 = (int)sectorlegs[i].sector1;
6398 int sec2 = (int)sectorlegs[i].sector2;
6399 if (sec1 > 360) sec1 -= 360;
6400 if (sec2 > 360) sec2 -= 360;
6402 if ((sec2 == 360) && (sec1 == 0))
6405 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6406 if (sectorangles[j] == sec1) haveAngle1 =
true;
6407 if (sectorangles[j] == sec2) haveAngle2 =
true;
6411 dc.StrokeLine(lightPos, end1);
6412 sectorangles.push_back(sec1);
6416 dc.StrokeLine(lightPos, end2);
6417 sectorangles.push_back(sec2);
6424void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
6425 std::vector<s57Sector_t> §orlegs) {
6426 float rangeScale = 0.0;
6428 if (sectorlegs.size() > 0) {
6429 std::vector<int> sectorangles;
6430 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6431 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3)
continue;
6434 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6435 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
6440 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
6441 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
6447 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
6450 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
6451 powf((
float)(lightPos.y - end1.y), 2));
6453 if (rangeScale == 0.0) {
6456 rangeScale *= (viewport.
pix_height / 3) / rangePx;
6460 rangePx = rangePx * rangeScale;
6462 float arcw = rangePx / 10;
6463 arcw = wxMin(20, arcw);
6464 arcw = wxMax(5, arcw);
6468 float angle1, angle2;
6469 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.
rotation * 180.0 / PI;
6470 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.
rotation * 180.0 / PI;
6471 if (angle1 > angle2) {
6474 int lpx = lightPos.x;
6475 int lpy = lightPos.y;
6477 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
6478 wxPoint yellowCone[3];
6479 yellowCone[0] = lightPos;
6480 yellowCone[1] = end1;
6481 yellowCone[2] = end2;
6482 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
6485 wxColor c = sectorlegs[i].color;
6486 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
6487 dc.SetBrush(wxBrush(c));
6488 dc.StrokePolygon(3, yellowCone, 0, 0);
6492 wxPoint r(lpx, lpy);
6495 float rad = rangePx;
6519 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
6522 glBindBuffer(GL_ARRAY_BUFFER, 0);
6523 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6525 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
6526 glEnableVertexAttribArray(mPosAttrib);
6530 glGetUniformLocation(shader->programId(),
"circle_radius");
6531 glUniform1f(radiusloc, rad);
6535 glGetUniformLocation(shader->programId(),
"circle_center");
6539 glUniform2fv(centerloc, 1, ctrv);
6542 wxColour colorb = sectorlegs[i].color;
6544 colorv[0] = colorb.Red() / float(256);
6545 colorv[1] = colorb.Green() / float(256);
6546 colorv[2] = colorb.Blue() / float(256);
6547 colorv[3] = colorb.Alpha() / float(256);
6550 glGetUniformLocation(shader->programId(),
"circle_color");
6551 glUniform4fv(colloc, 1, colorv);
6561 glGetUniformLocation(shader->programId(),
"border_color");
6562 glUniform4fv(bcolloc, 1, bcolorv);
6565 GLint borderWidthloc =
6566 glGetUniformLocation(shader->programId(),
"border_width");
6567 glUniform1f(borderWidthloc, 2);
6570 GLint ringWidthloc =
6571 glGetUniformLocation(shader->programId(),
"ring_width");
6572 glUniform1f(ringWidthloc, arcw);
6576 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
6577 if (sr1 > 360.) sr1 -= 360.;
6579 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
6580 if (sr2 > 360.) sr2 -= 360.;
6592 if ((sb < 0) || (se < 0)) {
6598 glGetUniformLocation(shader->programId(),
"sector_1");
6599 glUniform1f(sector1loc, (sb * PI / 180.));
6601 glGetUniformLocation(shader->programId(),
"sector_2");
6602 glUniform1f(sector2loc, (se * PI / 180.));
6607 mat4x4_translate_in_place(I, r.x, r.y, 0);
6610 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6611 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
6614 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
6618 mat4x4_identity(IM);
6620 glGetUniformLocation(shader->programId(),
"TransformMatrix");
6621 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
6623 glDisableVertexAttribArray(mPosAttrib);
6629 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
6634 bool haveAngle1 =
false;
6635 bool haveAngle2 =
false;
6636 int sec1 = (int)sectorlegs[i].sector1;
6637 int sec2 = (int)sectorlegs[i].sector2;
6638 if (sec1 > 360) sec1 -= 360;
6639 if (sec2 > 360) sec2 -= 360;
6641 if ((sec2 == 360) && (sec1 == 0))
6644 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
6645 if (sectorangles[j] == sec1) haveAngle1 =
true;
6646 if (sectorangles[j] == sec2) haveAngle2 =
true;
6650 dc.StrokeLine(lightPos, end1);
6651 sectorangles.push_back(sec1);
6655 dc.StrokeLine(lightPos, end2);
6656 sectorangles.push_back(sec2);
6664bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
6667 ListOfObjRazRules *rule_list,
6668 ListOfPI_S57Obj *pi_rule_list,
6669 std::vector<s57Sector_t> §orlegs) {
6670 bool newSectorsNeedDrawing =
false;
6672 bool bhas_red_green =
false;
6673 bool bleading_attribute =
false;
6676 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
6677 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
6679 int yOpacity = (float)opacity *
6682 if (target_plugin_chart || Chs57) {
6685 wxPoint2DDouble objPos;
6687 char *curr_att = NULL;
6689 wxArrayOfS57attVal *attValArray = NULL;
6691 ListOfObjRazRules::Node *snode = NULL;
6692 ListOfPI_S57Obj::Node *pnode = NULL;
6694 if (Chs57 && rule_list)
6695 snode = rule_list->GetLast();
6696 else if (target_plugin_chart && pi_rule_list)
6697 pnode = pi_rule_list->GetLast();
6700 wxPoint2DDouble lightPosD(0, 0);
6701 bool is_light =
false;
6705 ObjRazRules *current = snode->GetData();
6706 S57Obj *light = current->obj;
6707 if (!strcmp(light->FeatureName,
"LIGHTS")) {
6708 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
6709 curr_att = light->att_array;
6710 n_attr = light->n_attr;
6711 attValArray = light->attVal;
6714 }
else if (target_plugin_chart) {
6718 objPos = wxPoint2DDouble(light->
m_lat, light->
m_lon);
6721 attValArray = light->
attVal;
6731 wxString curAttrName;
6734 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
6736 if (is_light && (lightPosD == objPos)) {
6744 bleading_attribute =
false;
6746 while (attrCounter < n_attr) {
6747 curAttrName = wxString(curr_att, wxConvUTF8, 6);
6750 S57attVal *pAttrVal = NULL;
6753 pAttrVal = attValArray->Item(attrCounter);
6754 else if (target_plugin_chart)
6755 pAttrVal = attValArray->Item(attrCounter);
6759 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
6761 if (curAttrName ==
"LITVIS") {
6762 if (value.StartsWith(
"obsc")) bviz =
false;
6764 if (curAttrName ==
"SECTR1") value.ToDouble(§r1);
6765 if (curAttrName ==
"SECTR2") value.ToDouble(§r2);
6766 if (curAttrName ==
"VALNMR") value.ToDouble(&valnmr);
6767 if (curAttrName ==
"COLOUR") {
6768 if (value ==
"red(3)") {
6769 color = wxColor(255, 0, 0, opacity);
6770 sector.iswhite =
false;
6771 bhas_red_green =
true;
6774 if (value ==
"green(4)") {
6775 color = wxColor(0, 255, 0, opacity);
6776 sector.iswhite =
false;
6777 bhas_red_green =
true;
6781 if (curAttrName ==
"EXCLIT") {
6782 if (value.Find(
"(3)")) valnmr = 1.0;
6785 if (curAttrName ==
"CATLIT") {
6786 if (value.Upper().StartsWith(
"DIRECT") ||
6787 value.Upper().StartsWith(
"LEAD"))
6788 bleading_attribute =
true;
6795 if ((sectr1 >= 0) && (sectr2 >= 0)) {
6796 if (sectr1 > sectr2) {
6800 sector.pos.m_x = objPos.m_y;
6801 sector.pos.m_y = objPos.m_x;
6804 (valnmr > 0.0) ? valnmr : 2.5;
6805 sector.sector1 = sectr1;
6806 sector.sector2 = sectr2;
6808 if (!color.IsOk()) {
6809 color = wxColor(255, 255, 0, yOpacity);
6810 sector.iswhite =
true;
6812 sector.color = color;
6813 sector.isleading =
false;
6815 if (bleading_attribute) sector.isleading =
true;
6817 bool newsector =
true;
6818 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6819 if (sectorlegs[i].pos == sector.pos &&
6820 sectorlegs[i].sector1 == sector.sector1 &&
6821 sectorlegs[i].sector2 == sector.sector2) {
6827 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
6831 if (!bviz) newsector =
false;
6833 if ((sector.sector2 == 360) && (sector.sector1 == 0))
6837 sectorlegs.push_back(sector);
6838 newSectorsNeedDrawing =
true;
6845 snode = snode->GetPrevious();
6846 else if (target_plugin_chart)
6847 pnode = pnode->GetPrevious();
6855 for (
unsigned int i = 0; i < sectorlegs.size(); i++) {
6856 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
6857 if (sectorlegs[i].iswhite && bhas_red_green)
6858 sectorlegs[i].isleading =
true;
6862 return newSectorsNeedDrawing;
6865bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
6867 std::vector<s57Sector_t> §orlegs) {
6868 if (!cc)
return false;
6870 static float lastLat, lastLon;
6872 if (!ps52plib)
return false;
6880 if (cc->m_singleChart &&
6881 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
6882 target_chart = cc->m_singleChart;
6883 else if (viewport.b_quilt)
6884 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
6886 target_chart = NULL;
6889 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6890 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6893 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6896 bool newSectorsNeedDrawing =
false;
6898 if (target_plugin_chart || Chs57) {
6899 ListOfObjRazRules *rule_list = NULL;
6900 ListOfPI_S57Obj *pi_rule_list = NULL;
6907 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
6908 else if (target_plugin_chart)
6909 pi_rule_list =
g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
6910 target_plugin_chart, lat, lon, viewport);
6912 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6913 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6921 pi_rule_list->Clear();
6922 delete pi_rule_list;
6926 return newSectorsNeedDrawing;
6929bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
6931 std::vector<s57Sector_t> §orlegs) {
6932 if (!cc)
return false;
6934 double cursor_lat, cursor_lon;
6935 static float lastLat, lastLon;
6937 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
6942 ChartBase *target_chart = cc->GetChartAtCursor();
6944 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
6945 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
6948 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
6953 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
6955 lastLat = cursor_lat;
6956 lastLon = cursor_lon;
6957 bool newSectorsNeedDrawing =
false;
6959 if (target_plugin_chart || Chs57) {
6960 ListOfObjRazRules *rule_list = NULL;
6961 ListOfPI_S57Obj *pi_rule_list = NULL;
6967 rule_list = Chs57->GetObjRuleListAtLatLon(
6968 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
6969 else if (target_plugin_chart)
6970 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
6971 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
6973 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
6974 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
6982 pi_rule_list->Clear();
6983 delete pi_rule_list;
6987 return newSectorsNeedDrawing;
Wrapper for creating a ChartCtx based on global vars.
Generic Chart canvas base.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Wrapper class for plugin-based charts.
Wrapper class for OpenGL shader programs.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
Class representing an S-57 chart object.
double m_lon
Reference longitude.
int n_attr
Number of attributes.
char * att_array
Array of attribute types.
double m_lat
Reference latitude.
char FeatureName[8]
S-57 feature type code (e.g., "DEPARE")
wxArrayOfS57attVal * attVal
Array of attribute values.
Represents a light feature in an S57 chart.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
int pix_width
Width of the viewport in physical pixels.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Device context class that can use either wxDC or OpenGL for drawing.
Represents an S57 format electronic navigational chart in OpenCPN.
Extern C linked utilities.
OpenGL chart rendering canvas.
General purpose GUI support.
bool g_b_overzoom_x
Allow high overzoom.
Enhanced logging interface on top of wx/log.h.
wxString getUsrHeightUnit(int unit)
Get the abbreviation for the preferred height unit.
double toUsrHeight(double m_height, int unit)
Convert height from meters to preferred height units.
double toUsrDepth(double m_depth, int unit)
Convert a depth from meters to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
Optimized wxBitmap Object.
void fromSM_Plugin(double x, double y, double lat0, double lon0, double *lat, double *lon)
Converts Simple Mercator coordinates to geographic.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
Layer to use wxDC or opengl.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
int PI_GetPLIBBoundaryStyle()
Gets configured S52 boundary style.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
bool chain_broken_mssage_shown
Global instance.
SENCThreadManager * g_SencThreadManager
Global instance.
Represents a sector of a light in an S57 chart.
Abstract gFrame/MyFrame interface.