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