1 /******************************************************************************
2 * $Id: ogrs57datasource.cpp 28348 2015-01-23 15:27:13Z rouault $
3 *
4 * Project: S-57 Translator
5 * Purpose: Implements OGRS57DataSource class
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 1999, Frank Warmerdam
10 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "ogr_s57.h"
32 #include "cpl_conv.h"
33 #include "cpl_string.h"
34
35 CPL_CVSID("$Id: ogrs57datasource.cpp 28348 2015-01-23 15:27:13Z rouault $");
36
37 /************************************************************************/
38 /* OGRS57DataSource() */
39 /************************************************************************/
40
OGRS57DataSource(char ** papszOpenOptions)41 OGRS57DataSource::OGRS57DataSource(char** papszOpenOptions)
42
43 {
44 nLayers = 0;
45 papoLayers = NULL;
46
47 nModules = 0;
48 papoModules = NULL;
49 poClassContentExplorer = NULL;
50 poWriter = NULL;
51
52 pszName = NULL;
53
54 poSpatialRef = new OGRSpatialReference();
55 poSpatialRef->SetWellKnownGeogCS( "WGS84" );
56
57 bExtentsSet = FALSE;
58
59
60 /* -------------------------------------------------------------------- */
61 /* Allow initialization of options from the environment. */
62 /* -------------------------------------------------------------------- */
63 if( papszOpenOptions != NULL )
64 {
65 papszOptions = CSLDuplicate(papszOpenOptions);
66 }
67 else
68 {
69 const char *pszOptString = CPLGetConfigOption( "OGR_S57_OPTIONS", NULL );
70 papszOptions = NULL;
71
72 if ( pszOptString )
73 {
74 char **papszCurOption;
75
76 papszOptions =
77 CSLTokenizeStringComplex( pszOptString, ",", FALSE, FALSE );
78
79 if ( papszOptions && *papszOptions )
80 {
81 CPLDebug( "S57", "The following S57 options are being set:" );
82 papszCurOption = papszOptions;
83 while( *papszCurOption )
84 CPLDebug( "S57", " %s", *papszCurOption++ );
85 }
86 }
87 }
88 }
89
90 /************************************************************************/
91 /* ~OGRS57DataSource() */
92 /************************************************************************/
93
~OGRS57DataSource()94 OGRS57DataSource::~OGRS57DataSource()
95
96 {
97 int i;
98
99 for( i = 0; i < nLayers; i++ )
100 delete papoLayers[i];
101
102 CPLFree( papoLayers );
103
104 for( i = 0; i < nModules; i++ )
105 delete papoModules[i];
106 CPLFree( papoModules );
107
108 CPLFree( pszName );
109
110 CSLDestroy( papszOptions );
111
112 poSpatialRef->Release();
113
114 if( poWriter != NULL )
115 {
116 poWriter->Close();
117 delete poWriter;
118 }
119 delete poClassContentExplorer;
120 }
121
122 /************************************************************************/
123 /* SetOptionList() */
124 /************************************************************************/
125
SetOptionList(char ** papszNewOptions)126 void OGRS57DataSource::SetOptionList( char ** papszNewOptions )
127
128 {
129 CSLDestroy( papszOptions );
130 papszOptions = CSLDuplicate( papszNewOptions );
131 }
132
133 /************************************************************************/
134 /* GetOption() */
135 /************************************************************************/
136
GetOption(const char * pszOption)137 const char *OGRS57DataSource::GetOption( const char * pszOption )
138
139 {
140 return CSLFetchNameValue( papszOptions, pszOption );
141 }
142
143 /************************************************************************/
144 /* TestCapability() */
145 /************************************************************************/
146
TestCapability(const char *)147 int OGRS57DataSource::TestCapability( const char * )
148
149 {
150 return FALSE;
151 }
152
153 /************************************************************************/
154 /* Open() */
155 /************************************************************************/
156
Open(const char * pszFilename)157 int OGRS57DataSource::Open( const char * pszFilename )
158
159 {
160 int iModule;
161
162 pszName = CPLStrdup( pszFilename );
163
164 /* -------------------------------------------------------------------- */
165 /* Setup reader options. */
166 /* -------------------------------------------------------------------- */
167 char **papszReaderOptions = NULL;
168 S57Reader *poModule;
169
170 poModule = new S57Reader( pszFilename );
171
172 if( GetOption(S57O_LNAM_REFS) == NULL )
173 papszReaderOptions = CSLSetNameValue(papszReaderOptions,
174 S57O_LNAM_REFS, "ON" );
175 else
176 papszReaderOptions =
177 CSLSetNameValue( papszReaderOptions, S57O_LNAM_REFS,
178 GetOption(S57O_LNAM_REFS));
179
180 if( GetOption(S57O_UPDATES) != NULL )
181 papszReaderOptions =
182 CSLSetNameValue( papszReaderOptions, S57O_UPDATES,
183 GetOption(S57O_UPDATES));
184
185 if( GetOption(S57O_SPLIT_MULTIPOINT) != NULL )
186 papszReaderOptions =
187 CSLSetNameValue( papszReaderOptions, S57O_SPLIT_MULTIPOINT,
188 GetOption(S57O_SPLIT_MULTIPOINT) );
189
190 if( GetOption(S57O_ADD_SOUNDG_DEPTH) != NULL )
191 papszReaderOptions =
192 CSLSetNameValue( papszReaderOptions, S57O_ADD_SOUNDG_DEPTH,
193 GetOption(S57O_ADD_SOUNDG_DEPTH));
194
195 if( GetOption(S57O_PRESERVE_EMPTY_NUMBERS) != NULL )
196 papszReaderOptions =
197 CSLSetNameValue( papszReaderOptions, S57O_PRESERVE_EMPTY_NUMBERS,
198 GetOption(S57O_PRESERVE_EMPTY_NUMBERS) );
199
200 if( GetOption(S57O_RETURN_PRIMITIVES) != NULL )
201 papszReaderOptions =
202 CSLSetNameValue( papszReaderOptions, S57O_RETURN_PRIMITIVES,
203 GetOption(S57O_RETURN_PRIMITIVES) );
204
205 if( GetOption(S57O_RETURN_LINKAGES) != NULL )
206 papszReaderOptions =
207 CSLSetNameValue( papszReaderOptions, S57O_RETURN_LINKAGES,
208 GetOption(S57O_RETURN_LINKAGES) );
209
210 if( GetOption(S57O_RETURN_DSID) != NULL )
211 papszReaderOptions =
212 CSLSetNameValue( papszReaderOptions, S57O_RETURN_DSID,
213 GetOption(S57O_RETURN_DSID) );
214
215 if( GetOption(S57O_RECODE_BY_DSSI) != NULL )
216 papszReaderOptions =
217 CSLSetNameValue( papszReaderOptions, S57O_RECODE_BY_DSSI,
218 GetOption(S57O_RECODE_BY_DSSI) );
219
220 int bRet = poModule->SetOptions( papszReaderOptions );
221 CSLDestroy( papszReaderOptions );
222
223 if( !bRet )
224 {
225 delete poModule;
226 return FALSE;
227 }
228
229 /* -------------------------------------------------------------------- */
230 /* Try opening. */
231 /* */
232 /* Eventually this should check for catalogs, and if found */
233 /* instantiate a whole series of modules. */
234 /* -------------------------------------------------------------------- */
235 if( !poModule->Open( TRUE ) )
236 {
237 delete poModule;
238
239 return FALSE;
240 }
241
242 int bSuccess = TRUE;
243
244 nModules = 1;
245 papoModules = (S57Reader **) CPLMalloc(sizeof(void*));
246 papoModules[0] = poModule;
247
248 /* -------------------------------------------------------------------- */
249 /* Add the header layers if they are called for. */
250 /* -------------------------------------------------------------------- */
251 if( GetOption( S57O_RETURN_DSID ) == NULL
252 || CSLTestBoolean(GetOption( S57O_RETURN_DSID )) )
253 {
254 OGRFeatureDefn *poDefn;
255
256 poDefn = S57GenerateDSIDFeatureDefn();
257 AddLayer( new OGRS57Layer( this, poDefn ) );
258 }
259
260 /* -------------------------------------------------------------------- */
261 /* Add the primitive layers if they are called for. */
262 /* -------------------------------------------------------------------- */
263 if( GetOption( S57O_RETURN_PRIMITIVES ) != NULL )
264 {
265 OGRFeatureDefn *poDefn;
266
267 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VI, poModule->GetOptionFlags());
268 AddLayer( new OGRS57Layer( this, poDefn ) );
269
270 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VC, poModule->GetOptionFlags());
271 AddLayer( new OGRS57Layer( this, poDefn ) );
272
273 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VE, poModule->GetOptionFlags());
274 AddLayer( new OGRS57Layer( this, poDefn ) );
275
276 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VF, poModule->GetOptionFlags());
277 AddLayer( new OGRS57Layer( this, poDefn ) );
278 }
279
280 /* -------------------------------------------------------------------- */
281 /* Initialize a layer for each type of geometry. Eventually */
282 /* we will do this by object class. */
283 /* -------------------------------------------------------------------- */
284 if( OGRS57Driver::GetS57Registrar() == NULL )
285 {
286 OGRFeatureDefn *poDefn;
287
288 poDefn = S57GenerateGeomFeatureDefn( wkbPoint,
289 poModule->GetOptionFlags() );
290 AddLayer( new OGRS57Layer( this, poDefn ) );
291
292 poDefn = S57GenerateGeomFeatureDefn( wkbLineString,
293 poModule->GetOptionFlags() );
294 AddLayer( new OGRS57Layer( this, poDefn ) );
295
296 poDefn = S57GenerateGeomFeatureDefn( wkbPolygon,
297 poModule->GetOptionFlags() );
298 AddLayer( new OGRS57Layer( this, poDefn ) );
299
300 poDefn = S57GenerateGeomFeatureDefn( wkbNone,
301 poModule->GetOptionFlags() );
302 AddLayer( new OGRS57Layer( this, poDefn ) );
303 }
304
305 /* -------------------------------------------------------------------- */
306 /* Initialize a feature definition for each class that actually */
307 /* occurs in the dataset. */
308 /* -------------------------------------------------------------------- */
309 else
310 {
311 OGRFeatureDefn *poDefn;
312 std::vector<int> anClassCount;
313 int bGeneric = FALSE;
314 unsigned int iClass;
315
316 poClassContentExplorer =
317 new S57ClassContentExplorer( OGRS57Driver::GetS57Registrar() );
318
319 for( iModule = 0; iModule < nModules; iModule++ )
320 papoModules[iModule]->SetClassBased( OGRS57Driver::GetS57Registrar(),
321 poClassContentExplorer );
322
323 for( iModule = 0; iModule < nModules; iModule++ )
324 {
325 bSuccess &=
326 papoModules[iModule]->CollectClassList(anClassCount);
327 }
328
329 for( iClass = 0; iClass < anClassCount.size(); iClass++ )
330 {
331 if( anClassCount[iClass] > 0 )
332 {
333 poDefn =
334 S57GenerateObjectClassDefn( OGRS57Driver::GetS57Registrar(),
335 poClassContentExplorer,
336 iClass,
337 poModule->GetOptionFlags() );
338
339 if( poDefn != NULL )
340 AddLayer( new OGRS57Layer( this, poDefn,
341 anClassCount[iClass] ) );
342 else
343 {
344 bGeneric = TRUE;
345 CPLDebug( "S57",
346 "Unable to find definition for OBJL=%d\n",
347 iClass );
348 }
349 }
350 }
351
352 if( bGeneric )
353 {
354 poDefn = S57GenerateGeomFeatureDefn( wkbUnknown,
355 poModule->GetOptionFlags() );
356 AddLayer( new OGRS57Layer( this, poDefn ) );
357 }
358 }
359
360 /* -------------------------------------------------------------------- */
361 /* Attach the layer definitions to each of the readers. */
362 /* -------------------------------------------------------------------- */
363 for( iModule = 0; iModule < nModules; iModule++ )
364 {
365 for( int iLayer = 0; iLayer < nLayers; iLayer++ )
366 {
367 papoModules[iModule]->AddFeatureDefn(
368 papoLayers[iLayer]->GetLayerDefn() );
369 }
370 }
371
372 return bSuccess;
373 }
374
375 /************************************************************************/
376 /* GetLayer() */
377 /************************************************************************/
378
GetLayer(int iLayer)379 OGRLayer *OGRS57DataSource::GetLayer( int iLayer )
380
381 {
382 if( iLayer < 0 || iLayer >= nLayers )
383 return NULL;
384 else
385 return papoLayers[iLayer];
386 }
387
388 /************************************************************************/
389 /* AddLayer() */
390 /************************************************************************/
391
AddLayer(OGRS57Layer * poNewLayer)392 void OGRS57DataSource::AddLayer( OGRS57Layer * poNewLayer )
393
394 {
395 papoLayers = (OGRS57Layer **)
396 CPLRealloc( papoLayers, sizeof(void*) * ++nLayers );
397
398 papoLayers[nLayers-1] = poNewLayer;
399 }
400
401 /************************************************************************/
402 /* GetModule() */
403 /************************************************************************/
404
GetModule(int i)405 S57Reader * OGRS57DataSource::GetModule( int i )
406
407 {
408 if( i < 0 || i >= nModules )
409 return NULL;
410 else
411 return papoModules[i];
412 }
413
414 /************************************************************************/
415 /* GetDSExtent() */
416 /************************************************************************/
417
GetDSExtent(OGREnvelope * psExtent,int bForce)418 OGRErr OGRS57DataSource::GetDSExtent( OGREnvelope *psExtent, int bForce )
419
420 {
421 /* -------------------------------------------------------------------- */
422 /* If we have it, return it immediately. */
423 /* -------------------------------------------------------------------- */
424 if( bExtentsSet )
425 {
426 *psExtent = oExtents;
427 return OGRERR_NONE;
428 }
429
430 if( nModules == 0 )
431 return OGRERR_FAILURE;
432
433 /* -------------------------------------------------------------------- */
434 /* Otherwise try asking each of the readers for it. */
435 /* -------------------------------------------------------------------- */
436 for( int iModule=0; iModule < nModules; iModule++ )
437 {
438 OGREnvelope oModuleEnvelope;
439 OGRErr eErr;
440
441 eErr = papoModules[iModule]->GetExtent( &oModuleEnvelope, bForce );
442 if( eErr != OGRERR_NONE )
443 return eErr;
444
445 if( iModule == 0 )
446 oExtents = oModuleEnvelope;
447 else
448 {
449 oExtents.MinX = MIN(oExtents.MinX,oModuleEnvelope.MinX);
450 oExtents.MaxX = MAX(oExtents.MaxX,oModuleEnvelope.MaxX);
451 oExtents.MinY = MIN(oExtents.MinY,oModuleEnvelope.MinY);
452 oExtents.MaxX = MAX(oExtents.MaxY,oModuleEnvelope.MaxY);
453 }
454 }
455
456 *psExtent = oExtents;
457 bExtentsSet = TRUE;
458
459 return OGRERR_NONE;
460 }
461
462 /************************************************************************/
463 /* Create() */
464 /* */
465 /* Create a new S57 file, and represent it as a datasource. */
466 /************************************************************************/
467
Create(const char * pszFilename,char ** papszOptions)468 int OGRS57DataSource::Create( const char *pszFilename,
469 char **papszOptions )
470 {
471 /* -------------------------------------------------------------------- */
472 /* Instantiate the class registrar if possible. */
473 /* -------------------------------------------------------------------- */
474 if( OGRS57Driver::GetS57Registrar() == NULL )
475 {
476 CPLError( CE_Failure, CPLE_AppDefined,
477 "Unable to load s57objectclasses.csv, unable to continue." );
478 return FALSE;
479 }
480
481 /* -------------------------------------------------------------------- */
482 /* Create the S-57 file with definition record. */
483 /* -------------------------------------------------------------------- */
484 poWriter = new S57Writer();
485
486 if( !poWriter->CreateS57File( pszFilename ) )
487 return FALSE;
488
489 poClassContentExplorer =
490 new S57ClassContentExplorer( OGRS57Driver::GetS57Registrar() );
491
492 poWriter->SetClassBased( OGRS57Driver::GetS57Registrar(),
493 poClassContentExplorer );
494 pszName = CPLStrdup( pszFilename );
495
496 /* -------------------------------------------------------------------- */
497 /* Add the primitive layers if they are called for. */
498 /* -------------------------------------------------------------------- */
499 OGRFeatureDefn *poDefn;
500 int nOptionFlags = S57M_RETURN_LINKAGES | S57M_LNAM_REFS;
501
502 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VI, nOptionFlags );
503 AddLayer( new OGRS57Layer( this, poDefn ) );
504
505 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VC, nOptionFlags );
506 AddLayer( new OGRS57Layer( this, poDefn ) );
507
508 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VE, nOptionFlags );
509 AddLayer( new OGRS57Layer( this, poDefn ) );
510
511 poDefn = S57GenerateVectorPrimitiveFeatureDefn( RCNM_VF, nOptionFlags );
512 AddLayer( new OGRS57Layer( this, poDefn ) );
513
514 /* -------------------------------------------------------------------- */
515 /* Initialize a feature definition for each object class. */
516 /* -------------------------------------------------------------------- */
517 poClassContentExplorer->Rewind();
518 while( poClassContentExplorer->NextClass() )
519 {
520 poDefn =
521 S57GenerateObjectClassDefn( OGRS57Driver::GetS57Registrar(),
522 poClassContentExplorer,
523 poClassContentExplorer->GetOBJL(),
524 nOptionFlags );
525
526 AddLayer( new OGRS57Layer( this, poDefn, 0,
527 poClassContentExplorer->GetOBJL() ) );
528 }
529
530 /* -------------------------------------------------------------------- */
531 /* Write out "header" records. */
532 /* -------------------------------------------------------------------- */
533 int nEXPP = 1, nINTU = 4, nAGEN = 540, nNOMR = 0, nNOGR = 0,
534 nNOLR = 0, nNOIN = 0, nNOCN = 0, nNOED = 0;
535 const char
536 *pszEXPP = CSLFetchNameValue(papszOptions, "S57_EXPP"),
537 *pszINTU = CSLFetchNameValue(papszOptions, "S57_INTU"),
538 *pszEDTN = CSLFetchNameValue(papszOptions, "S57_EDTN"),
539 *pszUPDN = CSLFetchNameValue(papszOptions, "S57_UPDN"),
540 *pszUADT = CSLFetchNameValue(papszOptions, "S57_UADT"),
541 *pszISDT = CSLFetchNameValue(papszOptions, "S57_ISDT"),
542 *pszSTED = CSLFetchNameValue(papszOptions, "S57_STED"),
543 *pszAGEN = CSLFetchNameValue(papszOptions, "S57_AGEN"),
544 *pszCOMT = CSLFetchNameValue(papszOptions, "S57_COMT"),
545 *pszNOMR = CSLFetchNameValue(papszOptions, "S57_NOMR"),
546 *pszNOGR = CSLFetchNameValue(papszOptions, "S57_NOGR"),
547 *pszNOLR = CSLFetchNameValue(papszOptions, "S57_NOLR"),
548 *pszNOIN = CSLFetchNameValue(papszOptions, "S57_NOIN"),
549 *pszNOCN = CSLFetchNameValue(papszOptions, "S57_NOCN"),
550 *pszNOED = CSLFetchNameValue(papszOptions, "S57_NOED");
551 if (pszEXPP) nEXPP = atoi(pszEXPP);
552 if (pszINTU) nINTU = atoi(pszINTU);
553 if (pszAGEN) nAGEN = atoi(pszAGEN);
554 if (pszNOMR) nNOMR = atoi(pszNOMR);
555 if (pszNOGR) nNOGR = atoi(pszNOGR);
556 if (pszNOLR) nNOLR = atoi(pszNOLR);
557 if (pszNOIN) nNOIN = atoi(pszNOIN);
558 if (pszNOCN) nNOCN = atoi(pszNOCN);
559 if (pszNOED) nNOED = atoi(pszNOED);
560 poWriter->WriteDSID( nEXPP, nINTU, CPLGetFilename( pszFilename ),
561 pszEDTN, pszUPDN, pszUADT, pszISDT, pszSTED, nAGEN,
562 pszCOMT, nNOMR, nNOGR, nNOLR, nNOIN, nNOCN, nNOED );
563
564 int nHDAT = 2, nVDAT = 17, nSDAT = 23, nCSCL = 52000;
565 const char
566 *pszHDAT = CSLFetchNameValue(papszOptions, "S57_HDAT"),
567 *pszVDAT = CSLFetchNameValue(papszOptions, "S57_VDAT"),
568 *pszSDAT = CSLFetchNameValue(papszOptions, "S57_SDAT"),
569 *pszCSCL = CSLFetchNameValue(papszOptions, "S57_CSCL");
570 if (pszHDAT)
571 nHDAT = atoi(pszHDAT);
572 if (pszVDAT)
573 nVDAT = atoi(pszVDAT);
574 if (pszSDAT)
575 nSDAT = atoi(pszSDAT);
576 if (pszCSCL)
577 nCSCL = atoi(pszCSCL);
578 poWriter->WriteDSPM(nHDAT, nVDAT, nSDAT, nCSCL);
579
580
581 return TRUE;
582 }
583