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