1 /***************************************************************************
2  *
3  * Project:  OpenCPN
4  * Purpose:  S57 Chart Object
5  * Author:   David Register
6  *
7  ***************************************************************************
8  *   Copyright (C) 2010 by David S. Register                               *
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program; if not, write to the                         *
22  *   Free Software Foundation, Inc.,                                       *
23  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
24  **************************************************************************/
25 
26 // For compilers that support precompilation, includes "wx.h".
27 #include "wx/wxprec.h"
28 
29 #ifndef  WX_PRECOMP
30   #include "wx/wx.h"
31 #endif //precompiled headers
32 
33 #include "wx/image.h"                           // for some reason, needed for msvc???
34 #include "wx/tokenzr.h"
35 #include <wx/textfile.h>
36 
37 #include "dychart.h"
38 #include "OCPNPlatform.h"
39 
40 #include "s52s57.h"
41 #include "s52plib.h"
42 
43 #include "s57chart.h"
44 
45 #include "mygeom.h"
46 #include "cutil.h"
47 #include "georef.h"
48 #include "navutil.h"                            // for LogMessageOnce
49 #include "ocpn_pixel.h"
50 #include "ocpndc.h"
51 #include "s52utils.h"
52 #include "wx28compat.h"
53 
54 #include "gdal/cpl_csv.h"
55 #include "setjmp.h"
56 
57 #include "ogr_s57.h"
58 
59 #include "pluginmanager.h"                      // for S57 lights overlay
60 
61 #include "Osenc.h"
62 
63 #ifdef __MSVC__
64 #define _CRTDBG_MAP_ALLOC
65 #include <stdlib.h>
66 #include <crtdbg.h>
67 #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__ )
68 #define new DEBUG_NEW
69 #endif
70 
71 #ifdef ocpnUSE_GL
72 #include "glChartCanvas.h"
73 #endif
74 
75 #include <algorithm>          // for std::sort
76 #include <map>
77 
78 #ifdef __MSVC__
79 #define strncasecmp(x,y,z) _strnicmp(x,y,z)
80 #endif
81 
82 
83 extern bool              g_b_EnableVBO;
84 
85 #ifdef ocpnUSE_GL
86 extern PFNGLDELETEBUFFERSPROC              s_glDeleteBuffers;
87 #endif
88 
89 //----------------------------------------------------------------------------------
90 //      S57Obj CTOR
91 //----------------------------------------------------------------------------------
92 
S57Obj()93 S57Obj::S57Obj()
94 {
95     Init();
96 }
97 
98 //----------------------------------------------------------------------------------
99 //      S57Obj DTOR
100 //----------------------------------------------------------------------------------
101 
~S57Obj()102 S57Obj::~S57Obj()
103 {
104     //  Don't delete any allocated records of simple copy clones
105     if( !bIsClone ) {
106         if( attVal ) {
107             for( unsigned int iv = 0; iv < attVal->GetCount(); iv++ ) {
108                 S57attVal *vv = attVal->Item( iv );
109                 void *v2 = vv->value;
110                 free( v2 );
111                 delete vv;
112             }
113             delete attVal;
114         }
115         free( att_array );
116 
117         if( pPolyTessGeo ) {
118 #ifdef ocpnUSE_GL
119             bool b_useVBO = g_b_EnableVBO  && !auxParm1;    // VBO allowed?
120 
121             PolyTriGroup *ppg_vbo = pPolyTessGeo->Get_PolyTriGroup_head();
122             if (b_useVBO && ppg_vbo && auxParm0 > 0 && ppg_vbo->single_buffer && s_glDeleteBuffers) {
123                 s_glDeleteBuffers(1, (GLuint *)&auxParm0);
124             }
125 #endif
126             delete pPolyTessGeo;
127         }
128 
129         if( FText ) delete FText;
130 
131         if( geoPt ) free( geoPt );
132         if( geoPtz ) free( geoPtz );
133         if( geoPtMulti ) free( geoPtMulti );
134 
135         if( m_lsindex_array ) free( m_lsindex_array );
136 
137         if(m_ls_list){
138             line_segment_element *element = m_ls_list;
139             while(element){
140                 line_segment_element *next = element->next;
141                 delete element;
142                 element = next;
143             }
144         }
145     }
146 }
147 
148 
Init()149 void S57Obj::Init()
150 {
151     att_array = NULL;
152     attVal = NULL;
153     n_attr = 0;
154 
155     pPolyTessGeo = NULL;
156 
157 
158     bCS_Added = 0;
159     CSrules = NULL;
160     FText = NULL;
161     bFText_Added = 0;
162     geoPtMulti = NULL;
163     geoPtz = NULL;
164     geoPt = NULL;
165     bIsClone = false;
166     Scamin = 10000000;                              // ten million enough?
167     nRef = 0;
168 
169     bIsAton = false;
170     bIsAssociable = false;
171     m_n_lsindex = 0;
172     m_lsindex_array = NULL;
173     m_n_edge_max_points = 0;
174     m_ls_list = 0;
175     m_ls_list_legacy = 0;
176 
177     iOBJL = -1; // deferred, done by OBJL filtering in the PLIB as needed
178     bBBObj_valid = false;
179 
180     //        Set default (unity) auxiliary transform coefficients
181     x_rate = 1.0;
182     y_rate = 1.0;
183     x_origin = 0.0;
184     y_origin = 0.0;
185 
186     auxParm0 = 0;
187     auxParm1 = 0;
188     auxParm2 = 0;
189     auxParm3 = 0;
190 }
191 
192 //----------------------------------------------------------------------------------
193 //      S57Obj CTOR from FeatureName
194 //----------------------------------------------------------------------------------
S57Obj(const char * featureName)195 S57Obj::S57Obj( const char* featureName )
196 {
197     Init();
198 
199     attVal = new wxArrayOfS57attVal();
200 
201     strncpy( FeatureName, featureName, 6 );
202     FeatureName[6] = 0;
203 
204     if( !strncmp( FeatureName, "DEPARE", 6 )
205         || !strncmp( FeatureName, "DRGARE", 6 ) ) bIsAssociable = true;
206 
207 }
208 
209 
AddIntegerAttribute(const char * acronym,int val)210 bool S57Obj::AddIntegerAttribute( const char *acronym, int val ){
211 
212     S57attVal *pattValTmp = new S57attVal;
213 
214     int *pAVI = (int *) malloc( sizeof(int) );         //new int;
215     *pAVI = val;
216 
217     pattValTmp->valType = OGR_INT;
218     pattValTmp->value = pAVI;
219 
220     att_array = (char *)realloc(att_array, 6*(n_attr + 1));
221     strncpy(att_array + (6 * sizeof(char) * n_attr), acronym, 6);
222     n_attr++;
223 
224     attVal->Add( pattValTmp );
225 
226     if(!strncmp(acronym, "SCAMIN", 6))
227         Scamin = val;
228 
229     return true;
230 }
231 
AddIntegerListAttribute(const char * acronym,int * pval,int nValue)232 bool S57Obj::AddIntegerListAttribute( const char *acronym, int *pval, int nValue ){
233 
234     return true;
235 }
236 
AddDoubleAttribute(const char * acronym,double val)237 bool S57Obj::AddDoubleAttribute( const char *acronym, double val ){
238 
239     S57attVal *pattValTmp = new S57attVal;
240 
241     double *pAVI = (double *) malloc( sizeof(double) );         //new double;
242     *pAVI = val;
243 
244     pattValTmp->valType = OGR_REAL;
245     pattValTmp->value = pAVI;
246 
247     att_array = (char *)realloc(att_array, 6*(n_attr + 1));
248     strncpy(att_array + (6 * sizeof(char) * n_attr), acronym, 6);
249     n_attr++;
250 
251     attVal->Add( pattValTmp );
252 
253     return true;
254 }
255 
AddDoubleListAttribute(const char * acronym,double * pval,int nValue)256 bool S57Obj::AddDoubleListAttribute( const char *acronym, double *pval, int nValue ){
257 
258     return true;
259 }
260 
AddStringAttribute(const char * acronym,char * val)261 bool S57Obj::AddStringAttribute( const char *acronym, char *val ){
262 
263     S57attVal *pattValTmp = new S57attVal;
264 
265     char *pAVS = (char *)malloc(strlen(val) + 1);   //new string
266     strcpy(pAVS, val);
267 
268     pattValTmp->valType = OGR_STR;
269     pattValTmp->value = pAVS;
270 
271     att_array = (char *)realloc(att_array, 6*(n_attr + 1));
272     strncpy(att_array + (6 * sizeof(char) * n_attr), acronym, 6);
273     n_attr++;
274 
275     attVal->Add( pattValTmp );
276 
277     return true;
278 }
279 
SetPointGeometry(double lat,double lon,double ref_lat,double ref_lon)280 bool S57Obj::SetPointGeometry( double lat, double lon, double ref_lat, double ref_lon)
281 {
282     Primitive_type = GEO_POINT;
283 
284     m_lon = lon;
285     m_lat = lat;
286 
287     //  Set initial BoundingBox limits fairly large...
288     BBObj.Set(m_lat - .25, m_lon - .25, m_lat + .25, m_lon + .25);
289     bBBObj_valid = false;
290 
291     //  Calculate SM from chart common reference point
292     double easting, northing;
293     toSM( lat, lon, ref_lat, ref_lon, &easting, &northing );
294 
295     x = easting;
296     y = northing;
297 
298     npt = 1;
299 
300     return true;
301 }
302 
303 
SetLineGeometry(LineGeometryDescriptor * pGeo,GeoPrim_t geoType,double ref_lat,double ref_lon)304 bool S57Obj::SetLineGeometry( LineGeometryDescriptor *pGeo, GeoPrim_t geoType, double ref_lat, double ref_lon)
305 {
306     Primitive_type = geoType;
307 
308     // set s57obj bbox as lat/lon
309     BBObj.Set(pGeo->extent_s_lat, pGeo->extent_w_lon, pGeo->extent_n_lat, pGeo->extent_e_lon);
310     bBBObj_valid = true;
311 
312     //  and declare x/y of the object to be average east/north of all points
313     double e1, e2, n1, n2;
314     toSM( pGeo->extent_n_lat, pGeo->extent_e_lon, ref_lat, ref_lon, &e1, &n1 );
315     toSM( pGeo->extent_s_lat, pGeo->extent_w_lon, ref_lat, ref_lon, &e2, &n2 );
316 
317     x = ( e1 + e2 ) / 2.;
318     y = ( n1 + n2 ) / 2.;
319 
320     //  Set the object base point
321     double xll, yll;
322     fromSM( x, y, ref_lat, ref_lon, &yll, &xll );
323     m_lon = xll;
324     m_lat = yll;
325 
326     //  Set the edge and connected node table indices
327     m_n_lsindex = pGeo->indexCount;
328     m_lsindex_array = pGeo->indexTable;
329 
330     m_n_edge_max_points = 0; //TODO this could be precalulated and added to next SENC format
331 
332     return true;
333 }
334 
335 
SetAreaGeometry(PolyTessGeo * ppg,double ref_lat,double ref_lon)336 bool S57Obj::SetAreaGeometry( PolyTessGeo *ppg, double ref_lat, double ref_lon)
337 {
338     Primitive_type = GEO_AREA;
339     pPolyTessGeo = ppg;
340 
341     //  Set the s57obj bounding box as lat/lon
342     BBObj.Set(ppg->Get_ymin(), ppg->Get_xmin(), ppg->Get_ymax(), ppg->Get_xmax());
343     bBBObj_valid = true;
344 
345     //  and declare x/y of the object to be average east/north of all points
346     double e1, e2, n1, n2;
347     toSM( ppg->Get_ymax(), ppg->Get_xmax(), ref_lat, ref_lon, &e1,&n1 );
348     toSM( ppg->Get_ymin(), ppg->Get_xmin(), ref_lat, ref_lon, &e2,&n2 );
349 
350     x = ( e1 + e2 ) / 2.;
351     y = ( n1 + n2 ) / 2.;
352 
353     //  Set the object base point
354     double xll, yll;
355     fromSM( x, y, ref_lat, ref_lon, &yll, &xll );
356     m_lon = xll;
357     m_lat = yll;
358 
359 
360     return true;
361 }
362 
SetMultipointGeometry(MultipointGeometryDescriptor * pGeo,double ref_lat,double ref_lon)363 bool S57Obj::SetMultipointGeometry( MultipointGeometryDescriptor *pGeo, double ref_lat, double ref_lon)
364 {
365     Primitive_type = GEO_POINT;
366 
367     npt = pGeo->pointCount;
368 
369     geoPtz = (double *) malloc( npt * 3 * sizeof(double) );
370     geoPtMulti = (double *) malloc( npt * 2 * sizeof(double) );
371 
372     double *pdd = geoPtz;
373     double *pdl = geoPtMulti;
374 
375     float *pfs = (float *) ( pGeo->pointTable);                 // start of point data
376     for( int ip = 0; ip < npt; ip++ ) {
377         float easting, northing;
378         easting = *pfs++;
379         northing = *pfs++;
380         float depth = *pfs++;
381 
382         *pdd++ = easting;
383         *pdd++ = northing;
384         *pdd++ = depth;
385 
386         //  Convert point from SM to lat/lon for later use in decomposed bboxes
387         double xll, yll;
388         fromSM( easting, northing, ref_lat, ref_lon, &yll, &xll );
389 
390         *pdl++ = xll;
391         *pdl++ = yll;
392     }
393 
394     // set s57obj bbox as lat/lon
395     BBObj.Set(pGeo->extent_s_lat, pGeo->extent_w_lon, pGeo->extent_n_lat, pGeo->extent_e_lon);
396     bBBObj_valid = true;
397 
398     return true;
399 }
400 
401 
GetAttributeIndex(const char * AttrSeek)402 int S57Obj::GetAttributeIndex( const char *AttrSeek ) {
403     char *patl = att_array;
404 
405     for(int i=0 ; i < n_attr ; i++) {
406         if(!strncmp(patl, AttrSeek, 6)){
407             return i;
408             break;
409         }
410 
411         patl += 6;
412     }
413 
414     return -1;
415 }
416 
417 
GetAttrValueAsString(const char * AttrName)418 wxString S57Obj::GetAttrValueAsString( const char *AttrName )
419 {
420     wxString str;
421 
422     int idx = GetAttributeIndex(AttrName);
423 
424     if(idx >= 0) {
425 
426 //      using idx to get the attribute value
427 
428         S57attVal *v = attVal->Item( idx );
429 
430         switch( v->valType ){
431             case OGR_STR: {
432                 char *val = (char *) ( v->value );
433                 str.Append( wxString( val, wxConvUTF8 ) );
434                 break;
435             }
436             case OGR_REAL: {
437                 double dval = *(double*) ( v->value );
438                 str.Printf( _T("%g"), dval );
439                 break;
440             }
441             case OGR_INT: {
442                 int ival = *( (int *) v->value );
443                 str.Printf( _T("%d"), ival );
444                 break;
445             }
446             default: {
447                 str.Printf( _T("Unknown attribute type") );
448                 break;
449             }
450         }
451     }
452     return str;
453 }
454