1 : /******************************************************************************
2 : * $Id: s57reader.cpp 23595 2011-12-18 22:58:47Z rouault $
3 : *
4 : * Project: S-57 Translator
5 : * Purpose: Implements S57Reader class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, 2001, 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 "s57.h"
31 : #include "ogr_api.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 :
35 : #include <string>
36 : #include <fstream>
37 :
38 : CPL_CVSID("$Id: s57reader.cpp 23595 2011-12-18 22:58:47Z rouault $");
39 :
40 : #ifndef PI
41 : #define PI 3.14159265358979323846
42 : #endif
43 :
44 : /************************************************************************/
45 : /* S57Reader() */
46 : /************************************************************************/
47 :
48 12 : S57Reader::S57Reader( const char * pszFilename )
49 :
50 : {
51 12 : pszModuleName = CPLStrdup( pszFilename );
52 12 : pszDSNM = NULL;
53 :
54 12 : poModule = NULL;
55 :
56 12 : nFDefnCount = 0;
57 12 : papoFDefnList = NULL;
58 :
59 12 : nCOMF = 1000000;
60 12 : nSOMF = 10;
61 :
62 12 : poRegistrar = NULL;
63 12 : bFileIngested = FALSE;
64 :
65 12 : nNextFEIndex = 0;
66 12 : nNextVIIndex = 0;
67 12 : nNextVCIndex = 0;
68 12 : nNextVEIndex = 0;
69 12 : nNextVFIndex = 0;
70 12 : nNextDSIDIndex = 0;
71 :
72 12 : poDSIDRecord = NULL;
73 12 : poDSPMRecord = NULL;
74 12 : szUPDNUpdate[0] = '\0';
75 :
76 12 : iPointOffset = 0;
77 12 : poMultiPoint = NULL;
78 :
79 12 : papszOptions = NULL;
80 :
81 12 : nOptionFlags = S57M_UPDATES;
82 :
83 12 : bMissingWarningIssued = FALSE;
84 12 : bAttrWarningIssued = FALSE;
85 :
86 12 : memset( apoFDefnByOBJL, 0, sizeof(apoFDefnByOBJL) );
87 12 : }
88 :
89 : /************************************************************************/
90 : /* ~S57Reader() */
91 : /************************************************************************/
92 :
93 12 : S57Reader::~S57Reader()
94 :
95 : {
96 12 : Close();
97 :
98 12 : CPLFree( pszModuleName );
99 12 : CSLDestroy( papszOptions );
100 :
101 12 : CPLFree( papoFDefnList );
102 12 : }
103 :
104 : /************************************************************************/
105 : /* Open() */
106 : /************************************************************************/
107 :
108 12 : int S57Reader::Open( int bTestOpen )
109 :
110 : {
111 12 : if( poModule != NULL )
112 : {
113 0 : Rewind();
114 0 : return TRUE;
115 : }
116 :
117 12 : poModule = new DDFModule();
118 12 : if( !poModule->Open( pszModuleName ) )
119 : {
120 : // notdef: test bTestOpen.
121 0 : delete poModule;
122 0 : poModule = NULL;
123 0 : return FALSE;
124 : }
125 :
126 : // note that the following won't work for catalogs.
127 12 : if( poModule->FindFieldDefn("DSID") == NULL )
128 : {
129 0 : if( !bTestOpen )
130 : {
131 : CPLError( CE_Failure, CPLE_AppDefined,
132 : "%s is an ISO8211 file, but not an S-57 data file.\n",
133 0 : pszModuleName );
134 : }
135 0 : delete poModule;
136 0 : poModule = NULL;
137 0 : return FALSE;
138 : }
139 :
140 : // Make sure the FSPT field is marked as repeating.
141 12 : DDFFieldDefn *poFSPT = poModule->FindFieldDefn( "FSPT" );
142 12 : if( poFSPT != NULL && !poFSPT->IsRepeating() )
143 : {
144 0 : CPLDebug( "S57", "Forcing FSPT field to be repeating." );
145 0 : poFSPT->SetRepeatingFlag( TRUE );
146 : }
147 :
148 12 : nNextFEIndex = 0;
149 12 : nNextVIIndex = 0;
150 12 : nNextVCIndex = 0;
151 12 : nNextVEIndex = 0;
152 12 : nNextVFIndex = 0;
153 12 : nNextDSIDIndex = 0;
154 :
155 12 : return TRUE;
156 : }
157 :
158 : /************************************************************************/
159 : /* Close() */
160 : /************************************************************************/
161 :
162 12 : void S57Reader::Close()
163 :
164 : {
165 12 : if( poModule != NULL )
166 : {
167 12 : oVI_Index.Clear();
168 12 : oVC_Index.Clear();
169 12 : oVE_Index.Clear();
170 12 : oVF_Index.Clear();
171 12 : oFE_Index.Clear();
172 :
173 12 : if( poDSIDRecord != NULL )
174 : {
175 12 : delete poDSIDRecord;
176 12 : poDSIDRecord = NULL;
177 : }
178 12 : if( poDSPMRecord != NULL )
179 : {
180 10 : delete poDSPMRecord;
181 10 : poDSPMRecord = NULL;
182 : }
183 :
184 12 : ClearPendingMultiPoint();
185 :
186 12 : delete poModule;
187 12 : poModule = NULL;
188 :
189 12 : bFileIngested = FALSE;
190 :
191 12 : CPLFree( pszDSNM );
192 12 : pszDSNM = NULL;
193 : }
194 12 : }
195 :
196 : /************************************************************************/
197 : /* ClearPendingMultiPoint() */
198 : /************************************************************************/
199 :
200 18 : void S57Reader::ClearPendingMultiPoint()
201 :
202 : {
203 18 : if( poMultiPoint != NULL )
204 : {
205 0 : delete poMultiPoint;
206 0 : poMultiPoint = NULL;
207 : }
208 18 : }
209 :
210 : /************************************************************************/
211 : /* NextPendingMultiPoint() */
212 : /************************************************************************/
213 :
214 0 : OGRFeature *S57Reader::NextPendingMultiPoint()
215 :
216 : {
217 0 : CPLAssert( poMultiPoint != NULL );
218 0 : CPLAssert( wkbFlatten(poMultiPoint->GetGeometryRef()->getGeometryType())
219 0 : == wkbMultiPoint );
220 :
221 0 : OGRFeatureDefn *poDefn = poMultiPoint->GetDefnRef();
222 0 : OGRFeature *poPoint = new OGRFeature( poDefn );
223 0 : OGRMultiPoint *poMPGeom = (OGRMultiPoint *) poMultiPoint->GetGeometryRef();
224 : OGRPoint *poSrcPoint;
225 :
226 0 : poPoint->SetFID( poMultiPoint->GetFID() );
227 :
228 0 : for( int i = 0; i < poDefn->GetFieldCount(); i++ )
229 : {
230 0 : poPoint->SetField( i, poMultiPoint->GetRawFieldRef(i) );
231 : }
232 :
233 0 : poSrcPoint = (OGRPoint *) poMPGeom->getGeometryRef( iPointOffset++ );
234 0 : poPoint->SetGeometry( poSrcPoint );
235 :
236 0 : if( poPoint != NULL && (nOptionFlags & S57M_ADD_SOUNDG_DEPTH) )
237 0 : poPoint->SetField( "DEPTH", poSrcPoint->getZ() );
238 :
239 0 : if( iPointOffset >= poMPGeom->getNumGeometries() )
240 0 : ClearPendingMultiPoint();
241 :
242 0 : return poPoint;
243 : }
244 :
245 : /************************************************************************/
246 : /* SetOptions() */
247 : /************************************************************************/
248 :
249 12 : void S57Reader::SetOptions( char ** papszOptionsIn )
250 :
251 : {
252 : const char * pszOptionValue;
253 :
254 12 : CSLDestroy( papszOptions );
255 12 : papszOptions = CSLDuplicate( papszOptionsIn );
256 :
257 12 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_SPLIT_MULTIPOINT );
258 12 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
259 0 : nOptionFlags |= S57M_SPLIT_MULTIPOINT;
260 : else
261 12 : nOptionFlags &= ~S57M_SPLIT_MULTIPOINT;
262 :
263 12 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_ADD_SOUNDG_DEPTH );
264 12 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
265 0 : nOptionFlags |= S57M_ADD_SOUNDG_DEPTH;
266 : else
267 12 : nOptionFlags &= ~S57M_ADD_SOUNDG_DEPTH;
268 :
269 : CPLAssert( ! (nOptionFlags & S57M_ADD_SOUNDG_DEPTH)
270 12 : || (nOptionFlags & S57M_SPLIT_MULTIPOINT) );
271 :
272 12 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_LNAM_REFS );
273 24 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
274 12 : nOptionFlags |= S57M_LNAM_REFS;
275 : else
276 0 : nOptionFlags &= ~S57M_LNAM_REFS;
277 :
278 12 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_UPDATES );
279 12 : if( pszOptionValue == NULL )
280 : /* no change */;
281 0 : else if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"APPLY") )
282 0 : nOptionFlags &= ~S57M_UPDATES;
283 : else
284 0 : nOptionFlags |= S57M_UPDATES;
285 :
286 : pszOptionValue = CSLFetchNameValue(papszOptions,
287 12 : S57O_PRESERVE_EMPTY_NUMBERS);
288 12 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
289 0 : nOptionFlags |= S57M_PRESERVE_EMPTY_NUMBERS;
290 : else
291 12 : nOptionFlags &= ~S57M_PRESERVE_EMPTY_NUMBERS;
292 :
293 12 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_PRIMITIVES );
294 12 : if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
295 0 : nOptionFlags |= S57M_RETURN_PRIMITIVES;
296 : else
297 12 : nOptionFlags &= ~S57M_RETURN_PRIMITIVES;
298 :
299 12 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_LINKAGES );
300 12 : if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
301 0 : nOptionFlags |= S57M_RETURN_LINKAGES;
302 : else
303 12 : nOptionFlags &= ~S57M_RETURN_LINKAGES;
304 :
305 12 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_DSID );
306 12 : if( pszOptionValue == NULL || CSLTestBoolean(pszOptionValue) )
307 12 : nOptionFlags |= S57M_RETURN_DSID;
308 : else
309 0 : nOptionFlags &= ~S57M_RETURN_DSID;
310 12 : }
311 :
312 : /************************************************************************/
313 : /* SetClassBased() */
314 : /************************************************************************/
315 :
316 12 : void S57Reader::SetClassBased( S57ClassRegistrar * poReg )
317 :
318 : {
319 12 : poRegistrar = poReg;
320 12 : }
321 :
322 : /************************************************************************/
323 : /* Rewind() */
324 : /************************************************************************/
325 :
326 0 : void S57Reader::Rewind()
327 :
328 : {
329 0 : ClearPendingMultiPoint();
330 0 : nNextFEIndex = 0;
331 0 : nNextVIIndex = 0;
332 0 : nNextVCIndex = 0;
333 0 : nNextVEIndex = 0;
334 0 : nNextVFIndex = 0;
335 0 : nNextDSIDIndex = 0;
336 0 : }
337 :
338 : /************************************************************************/
339 : /* Ingest() */
340 : /* */
341 : /* Read all the records into memory, adding to the appropriate */
342 : /* indexes. */
343 : /************************************************************************/
344 :
345 12 : int S57Reader::Ingest()
346 :
347 : {
348 : DDFRecord *poRecord;
349 :
350 12 : if( poModule == NULL || bFileIngested )
351 0 : return TRUE;
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Read all the records in the module, and place them in */
355 : /* appropriate indexes. */
356 : /* -------------------------------------------------------------------- */
357 12 : CPLErrorReset();
358 47180 : while( (poRecord = poModule->ReadRecord()) != NULL )
359 : {
360 47156 : DDFField *poKeyField = poRecord->GetField(1);
361 47156 : if (poKeyField == NULL)
362 0 : return FALSE;
363 :
364 47156 : if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"VRID") )
365 : {
366 32740 : int nRCNM = poRecord->GetIntSubfield( "VRID",0, "RCNM",0);
367 32740 : int nRCID = poRecord->GetIntSubfield( "VRID",0, "RCID",0);
368 :
369 32740 : switch( nRCNM )
370 : {
371 : case RCNM_VI:
372 1132 : oVI_Index.AddRecord( nRCID, poRecord->Clone() );
373 1132 : break;
374 :
375 : case RCNM_VC:
376 14776 : oVC_Index.AddRecord( nRCID, poRecord->Clone() );
377 14776 : break;
378 :
379 : case RCNM_VE:
380 16832 : oVE_Index.AddRecord( nRCID, poRecord->Clone() );
381 16832 : break;
382 :
383 : case RCNM_VF:
384 0 : oVF_Index.AddRecord( nRCID, poRecord->Clone() );
385 0 : break;
386 :
387 : default:
388 : CPLError(CE_Failure, CPLE_AppDefined,
389 0 : "Unhandled value for RCNM ; %d", nRCNM);
390 : break;
391 : }
392 : }
393 :
394 14416 : else if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"FRID") )
395 : {
396 14394 : int nRCID = poRecord->GetIntSubfield( "FRID",0, "RCID",0);
397 :
398 14394 : oFE_Index.AddRecord( nRCID, poRecord->Clone() );
399 : }
400 :
401 22 : else if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"DSID") )
402 : {
403 12 : CPLFree( pszDSNM );
404 : pszDSNM =
405 12 : CPLStrdup(poRecord->GetStringSubfield( "DSID", 0, "DSNM", 0 ));
406 :
407 12 : if( nOptionFlags & S57M_RETURN_DSID )
408 : {
409 12 : if( poDSIDRecord != NULL )
410 0 : delete poDSIDRecord;
411 :
412 12 : poDSIDRecord = poRecord->Clone();
413 : }
414 : }
415 :
416 10 : else if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"DSPM") )
417 : {
418 10 : nCOMF = MAX(1,poRecord->GetIntSubfield( "DSPM",0, "COMF",0));
419 10 : nSOMF = MAX(1,poRecord->GetIntSubfield( "DSPM",0, "SOMF",0));
420 :
421 10 : if( nOptionFlags & S57M_RETURN_DSID )
422 : {
423 10 : if( poDSPMRecord != NULL )
424 0 : delete poDSPMRecord;
425 :
426 10 : poDSPMRecord = poRecord->Clone();
427 : }
428 : }
429 :
430 : else
431 : {
432 : CPLDebug( "S57",
433 : "Skipping %s record in S57Reader::Ingest().\n",
434 0 : poKeyField->GetFieldDefn()->GetName() );
435 : }
436 : }
437 :
438 12 : if( CPLGetLastErrorType() == CE_Failure )
439 0 : return FALSE;
440 :
441 12 : bFileIngested = TRUE;
442 :
443 : /* -------------------------------------------------------------------- */
444 : /* If update support is enabled, read and apply them. */
445 : /* -------------------------------------------------------------------- */
446 12 : if( nOptionFlags & S57M_UPDATES )
447 12 : return FindAndApplyUpdates();
448 : else
449 0 : return TRUE;
450 : }
451 :
452 : /************************************************************************/
453 : /* SetNextFEIndex() */
454 : /************************************************************************/
455 :
456 16 : void S57Reader::SetNextFEIndex( int nNewIndex, int nRCNM )
457 :
458 : {
459 16 : if( nRCNM == RCNM_VI )
460 0 : nNextVIIndex = nNewIndex;
461 16 : else if( nRCNM == RCNM_VC )
462 0 : nNextVCIndex = nNewIndex;
463 16 : else if( nRCNM == RCNM_VE )
464 0 : nNextVEIndex = nNewIndex;
465 16 : else if( nRCNM == RCNM_VF )
466 0 : nNextVFIndex = nNewIndex;
467 16 : else if( nRCNM == RCNM_DSID )
468 4 : nNextDSIDIndex = nNewIndex;
469 : else
470 : {
471 12 : if( nNextFEIndex != nNewIndex )
472 6 : ClearPendingMultiPoint();
473 :
474 12 : nNextFEIndex = nNewIndex;
475 : }
476 16 : }
477 :
478 : /************************************************************************/
479 : /* GetNextFEIndex() */
480 : /************************************************************************/
481 :
482 16 : int S57Reader::GetNextFEIndex( int nRCNM )
483 :
484 : {
485 16 : if( nRCNM == RCNM_VI )
486 0 : return nNextVIIndex;
487 16 : else if( nRCNM == RCNM_VC )
488 0 : return nNextVCIndex;
489 16 : else if( nRCNM == RCNM_VE )
490 0 : return nNextVEIndex;
491 16 : else if( nRCNM == RCNM_VF )
492 0 : return nNextVFIndex;
493 16 : else if( nRCNM == RCNM_DSID )
494 4 : return nNextDSIDIndex;
495 : else
496 12 : return nNextFEIndex;
497 : }
498 :
499 : /************************************************************************/
500 : /* ReadNextFeature() */
501 : /************************************************************************/
502 :
503 16 : OGRFeature * S57Reader::ReadNextFeature( OGRFeatureDefn * poTarget )
504 :
505 : {
506 16 : if( !bFileIngested && !Ingest() )
507 0 : return NULL;
508 :
509 : /* -------------------------------------------------------------------- */
510 : /* Special case for "in progress" multipoints being split up. */
511 : /* -------------------------------------------------------------------- */
512 16 : if( poMultiPoint != NULL )
513 : {
514 0 : if( poTarget == NULL || poTarget == poMultiPoint->GetDefnRef() )
515 : {
516 0 : return NextPendingMultiPoint();
517 : }
518 : else
519 : {
520 0 : ClearPendingMultiPoint();
521 : }
522 : }
523 :
524 : /* -------------------------------------------------------------------- */
525 : /* Next vector feature? */
526 : /* -------------------------------------------------------------------- */
527 16 : if( (nOptionFlags & S57M_RETURN_DSID)
528 : && nNextDSIDIndex == 0
529 : && (poTarget == NULL || EQUAL(poTarget->GetName(),"DSID")) )
530 : {
531 2 : return ReadDSID();
532 : }
533 :
534 : /* -------------------------------------------------------------------- */
535 : /* Next vector feature? */
536 : /* -------------------------------------------------------------------- */
537 14 : if( nOptionFlags & S57M_RETURN_PRIMITIVES )
538 : {
539 0 : int nRCNM = 0;
540 0 : int *pnCounter = NULL;
541 :
542 0 : if( poTarget == NULL )
543 : {
544 0 : if( nNextVIIndex < oVI_Index.GetCount() )
545 : {
546 0 : nRCNM = RCNM_VI;
547 0 : pnCounter = &nNextVIIndex;
548 : }
549 0 : else if( nNextVCIndex < oVC_Index.GetCount() )
550 : {
551 0 : nRCNM = RCNM_VC;
552 0 : pnCounter = &nNextVCIndex;
553 : }
554 0 : else if( nNextVEIndex < oVE_Index.GetCount() )
555 : {
556 0 : nRCNM = RCNM_VE;
557 0 : pnCounter = &nNextVEIndex;
558 : }
559 0 : else if( nNextVFIndex < oVF_Index.GetCount() )
560 : {
561 0 : nRCNM = RCNM_VF;
562 0 : pnCounter = &nNextVFIndex;
563 : }
564 : }
565 : else
566 : {
567 0 : if( EQUAL(poTarget->GetName(),OGRN_VI) )
568 : {
569 0 : nRCNM = RCNM_VI;
570 0 : pnCounter = &nNextVIIndex;
571 : }
572 0 : else if( EQUAL(poTarget->GetName(),OGRN_VC) )
573 : {
574 0 : nRCNM = RCNM_VC;
575 0 : pnCounter = &nNextVCIndex;
576 : }
577 0 : else if( EQUAL(poTarget->GetName(),OGRN_VE) )
578 : {
579 0 : nRCNM = RCNM_VE;
580 0 : pnCounter = &nNextVEIndex;
581 : }
582 0 : else if( EQUAL(poTarget->GetName(),OGRN_VF) )
583 : {
584 0 : nRCNM = RCNM_VF;
585 0 : pnCounter = &nNextVFIndex;
586 : }
587 : }
588 :
589 0 : if( nRCNM != 0 )
590 : {
591 0 : OGRFeature *poFeature = ReadVector( *pnCounter, nRCNM );
592 0 : if( poFeature != NULL )
593 : {
594 0 : *pnCounter += 1;
595 0 : return poFeature;
596 : }
597 : }
598 : }
599 :
600 : /* -------------------------------------------------------------------- */
601 : /* Next feature. */
602 : /* -------------------------------------------------------------------- */
603 2444 : while( nNextFEIndex < oFE_Index.GetCount() )
604 : {
605 : OGRFeature *poFeature;
606 : OGRFeatureDefn *poFeatureDefn;
607 :
608 : poFeatureDefn = (OGRFeatureDefn *)
609 2428 : oFE_Index.GetClientInfoByIndex( nNextFEIndex );
610 :
611 2428 : if( poFeatureDefn == NULL )
612 : {
613 2356 : poFeatureDefn = FindFDefn( oFE_Index.GetByIndex( nNextFEIndex ) );
614 2356 : oFE_Index.SetClientInfoByIndex( nNextFEIndex, poFeatureDefn );
615 : }
616 :
617 2428 : if( poFeatureDefn != poTarget && poTarget != NULL )
618 : {
619 2416 : nNextFEIndex++;
620 2416 : continue;
621 : }
622 :
623 12 : poFeature = ReadFeature( nNextFEIndex++, poTarget );
624 12 : if( poFeature != NULL )
625 : {
626 12 : if( (nOptionFlags & S57M_SPLIT_MULTIPOINT)
627 : && poFeature->GetGeometryRef() != NULL
628 0 : && wkbFlatten(poFeature->GetGeometryRef()->getGeometryType())
629 : == wkbMultiPoint)
630 : {
631 0 : poMultiPoint = poFeature;
632 0 : iPointOffset = 0;
633 0 : return NextPendingMultiPoint();
634 : }
635 :
636 12 : return poFeature;
637 : }
638 : }
639 :
640 2 : return NULL;
641 : }
642 :
643 : /************************************************************************/
644 : /* ReadFeature() */
645 : /* */
646 : /* Read the features who's id is provided. */
647 : /************************************************************************/
648 :
649 20 : OGRFeature *S57Reader::ReadFeature( int nFeatureId, OGRFeatureDefn *poTarget )
650 :
651 : {
652 : OGRFeature *poFeature;
653 :
654 20 : if( nFeatureId < 0 || nFeatureId >= oFE_Index.GetCount() )
655 2 : return NULL;
656 :
657 : poFeature = AssembleFeature( oFE_Index.GetByIndex(nFeatureId),
658 18 : poTarget );
659 18 : if( poFeature != NULL )
660 18 : poFeature->SetFID( nFeatureId );
661 :
662 18 : return poFeature;
663 : }
664 :
665 :
666 : /************************************************************************/
667 : /* AssembleFeature() */
668 : /* */
669 : /* Assemble an OGR feature based on a feature record. */
670 : /************************************************************************/
671 :
672 18 : OGRFeature *S57Reader::AssembleFeature( DDFRecord * poRecord,
673 : OGRFeatureDefn * poTarget )
674 :
675 : {
676 : int nPRIM, nOBJL;
677 : OGRFeatureDefn *poFDefn;
678 :
679 : /* -------------------------------------------------------------------- */
680 : /* Find the feature definition to use. Currently this is based */
681 : /* on the primitive, but eventually this should be based on the */
682 : /* object class (FRID.OBJL) in some cases, and the primitive in */
683 : /* others. */
684 : /* -------------------------------------------------------------------- */
685 18 : poFDefn = FindFDefn( poRecord );
686 18 : if( poFDefn == NULL )
687 0 : return NULL;
688 :
689 : /* -------------------------------------------------------------------- */
690 : /* Does this match our target feature definition? If not skip */
691 : /* this feature. */
692 : /* -------------------------------------------------------------------- */
693 18 : if( poTarget != NULL && poFDefn != poTarget )
694 0 : return NULL;
695 :
696 : /* -------------------------------------------------------------------- */
697 : /* Create the new feature object. */
698 : /* -------------------------------------------------------------------- */
699 : OGRFeature *poFeature;
700 :
701 18 : poFeature = new OGRFeature( poFDefn );
702 :
703 : /* -------------------------------------------------------------------- */
704 : /* Assign a few standard feature attribues. */
705 : /* -------------------------------------------------------------------- */
706 18 : nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
707 18 : poFeature->SetField( "OBJL", nOBJL );
708 :
709 : poFeature->SetField( "RCID",
710 18 : poRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ));
711 : poFeature->SetField( "PRIM",
712 18 : poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 ));
713 : poFeature->SetField( "GRUP",
714 18 : poRecord->GetIntSubfield( "FRID", 0, "GRUP", 0 ));
715 : poFeature->SetField( "RVER",
716 18 : poRecord->GetIntSubfield( "FRID", 0, "RVER", 0 ));
717 : poFeature->SetField( "AGEN",
718 18 : poRecord->GetIntSubfield( "FOID", 0, "AGEN", 0 ));
719 : poFeature->SetField( "FIDN",
720 18 : poRecord->GetIntSubfield( "FOID", 0, "FIDN", 0 ));
721 : poFeature->SetField( "FIDS",
722 18 : poRecord->GetIntSubfield( "FOID", 0, "FIDS", 0 ));
723 :
724 : /* -------------------------------------------------------------------- */
725 : /* Generate long name, if requested. */
726 : /* -------------------------------------------------------------------- */
727 18 : if( nOptionFlags & S57M_LNAM_REFS )
728 : {
729 18 : GenerateLNAMAndRefs( poRecord, poFeature );
730 : }
731 :
732 : /* -------------------------------------------------------------------- */
733 : /* Generate primitive references if requested. */
734 : /* -------------------------------------------------------------------- */
735 18 : if( nOptionFlags & S57M_RETURN_LINKAGES )
736 0 : GenerateFSPTAttributes( poRecord, poFeature );
737 :
738 : /* -------------------------------------------------------------------- */
739 : /* Apply object class specific attributes, if supported. */
740 : /* -------------------------------------------------------------------- */
741 18 : if( poRegistrar != NULL )
742 18 : ApplyObjectClassAttributes( poRecord, poFeature );
743 :
744 : /* -------------------------------------------------------------------- */
745 : /* Find and assign spatial component. */
746 : /* -------------------------------------------------------------------- */
747 18 : nPRIM = poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 );
748 :
749 18 : if( nPRIM == PRIM_P )
750 : {
751 10 : if( nOBJL == 129 ) /* SOUNDG */
752 2 : AssembleSoundingGeometry( poRecord, poFeature );
753 : else
754 8 : AssemblePointGeometry( poRecord, poFeature );
755 : }
756 8 : else if( nPRIM == PRIM_L )
757 : {
758 4 : AssembleLineGeometry( poRecord, poFeature );
759 : }
760 4 : else if( nPRIM == PRIM_A )
761 : {
762 4 : AssembleAreaGeometry( poRecord, poFeature );
763 : }
764 :
765 18 : return poFeature;
766 : }
767 :
768 : /************************************************************************/
769 : /* ApplyObjectClassAttributes() */
770 : /************************************************************************/
771 :
772 18 : void S57Reader::ApplyObjectClassAttributes( DDFRecord * poRecord,
773 : OGRFeature * poFeature )
774 :
775 : {
776 : /* -------------------------------------------------------------------- */
777 : /* ATTF Attributes */
778 : /* -------------------------------------------------------------------- */
779 18 : DDFField *poATTF = poRecord->FindField( "ATTF" );
780 : int nAttrCount, iAttr;
781 :
782 18 : if( poATTF == NULL )
783 6 : return;
784 :
785 12 : nAttrCount = poATTF->GetRepeatCount();
786 42 : for( iAttr = 0; iAttr < nAttrCount; iAttr++ )
787 : {
788 30 : int nAttrId = poRecord->GetIntSubfield("ATTF",0,"ATTL",iAttr);
789 : const char *pszAcronym;
790 :
791 30 : if( nAttrId < 1 || nAttrId > poRegistrar->GetMaxAttrIndex()
792 : || (pszAcronym = poRegistrar->GetAttrAcronym(nAttrId)) == NULL )
793 : {
794 0 : if( !bAttrWarningIssued )
795 : {
796 0 : bAttrWarningIssued = TRUE;
797 : CPLError( CE_Warning, CPLE_AppDefined,
798 : "Illegal feature attribute id (ATTF:ATTL[%d]) of %d\n"
799 : "on feature FIDN=%d, FIDS=%d.\n"
800 : "Skipping attribute, no more warnings will be issued.",
801 : iAttr, nAttrId,
802 : poFeature->GetFieldAsInteger( "FIDN" ),
803 0 : poFeature->GetFieldAsInteger( "FIDS" ) );
804 : }
805 :
806 0 : continue;
807 : }
808 :
809 : /* Fetch the attribute value */
810 : const char *pszValue;
811 30 : pszValue = poRecord->GetStringSubfield("ATTF",0,"ATVL",iAttr);
812 :
813 : /* Apply to feature in an appropriate way */
814 : int iField;
815 : OGRFieldDefn *poFldDefn;
816 :
817 30 : iField = poFeature->GetDefnRef()->GetFieldIndex(pszAcronym);
818 30 : if( iField < 0 )
819 : {
820 0 : if( !bMissingWarningIssued )
821 : {
822 0 : bMissingWarningIssued = TRUE;
823 : CPLError( CE_Warning, CPLE_AppDefined,
824 : "Attributes %s ignored, not in expected schema.\n"
825 : "No more warnings will be issued for this dataset.",
826 0 : pszAcronym );
827 : }
828 0 : continue;
829 : }
830 :
831 30 : poFldDefn = poFeature->GetDefnRef()->GetFieldDefn( iField );
832 30 : if( poFldDefn->GetType() == OFTInteger
833 : || poFldDefn->GetType() == OFTReal )
834 : {
835 14 : if( strlen(pszValue) == 0 )
836 : {
837 2 : if( nOptionFlags & S57M_PRESERVE_EMPTY_NUMBERS )
838 0 : poFeature->SetField( iField, EMPTY_NUMBER_MARKER );
839 : else
840 : /* leave as null if value was empty string */;
841 : }
842 : else
843 12 : poFeature->SetField( iField, pszValue );
844 : }
845 : else
846 16 : poFeature->SetField( iField, pszValue );
847 : }
848 :
849 : /* -------------------------------------------------------------------- */
850 : /* NATF (national) attributes */
851 : /* -------------------------------------------------------------------- */
852 12 : DDFField *poNATF = poRecord->FindField( "NATF" );
853 :
854 12 : if( poNATF == NULL )
855 10 : return;
856 :
857 2 : nAttrCount = poNATF->GetRepeatCount();
858 4 : for( iAttr = 0; iAttr < nAttrCount; iAttr++ )
859 : {
860 2 : int nAttrId = poRecord->GetIntSubfield("NATF",0,"ATTL",iAttr);
861 : const char *pszAcronym;
862 :
863 2 : if( nAttrId < 1 || nAttrId >= poRegistrar->GetMaxAttrIndex()
864 : || (pszAcronym = poRegistrar->GetAttrAcronym(nAttrId)) == NULL )
865 : {
866 : static int bAttrWarningIssued = FALSE;
867 :
868 0 : if( !bAttrWarningIssued )
869 : {
870 0 : bAttrWarningIssued = TRUE;
871 : CPLError( CE_Warning, CPLE_AppDefined,
872 : "Illegal feature attribute id (NATF:ATTL[%d]) of %d\n"
873 : "on feature FIDN=%d, FIDS=%d.\n"
874 : "Skipping attribute, no more warnings will be issued.",
875 : iAttr, nAttrId,
876 : poFeature->GetFieldAsInteger( "FIDN" ),
877 0 : poFeature->GetFieldAsInteger( "FIDS" ) );
878 : }
879 :
880 0 : continue;
881 : }
882 :
883 : poFeature->SetField( pszAcronym,
884 2 : poRecord->GetStringSubfield("NATF",0,"ATVL",iAttr) );
885 : }
886 : }
887 :
888 : /************************************************************************/
889 : /* GenerateLNAMAndRefs() */
890 : /************************************************************************/
891 :
892 18 : void S57Reader::GenerateLNAMAndRefs( DDFRecord * poRecord,
893 : OGRFeature * poFeature )
894 :
895 : {
896 : char szLNAM[32];
897 :
898 : /* -------------------------------------------------------------------- */
899 : /* Apply the LNAM to the object. */
900 : /* -------------------------------------------------------------------- */
901 : sprintf( szLNAM, "%04X%08X%04X",
902 : poFeature->GetFieldAsInteger( "AGEN" ),
903 : poFeature->GetFieldAsInteger( "FIDN" ),
904 18 : poFeature->GetFieldAsInteger( "FIDS" ) );
905 18 : poFeature->SetField( "LNAM", szLNAM );
906 :
907 : /* -------------------------------------------------------------------- */
908 : /* Do we have references to other features. */
909 : /* -------------------------------------------------------------------- */
910 : DDFField *poFFPT;
911 :
912 18 : poFFPT = poRecord->FindField( "FFPT" );
913 :
914 18 : if( poFFPT == NULL )
915 16 : return;
916 :
917 : /* -------------------------------------------------------------------- */
918 : /* Apply references. */
919 : /* -------------------------------------------------------------------- */
920 2 : int nRefCount = poFFPT->GetRepeatCount();
921 : DDFSubfieldDefn *poLNAM;
922 2 : char **papszRefs = NULL;
923 2 : int *panRIND = (int *) CPLMalloc(sizeof(int) * nRefCount);
924 :
925 2 : poLNAM = poFFPT->GetFieldDefn()->FindSubfieldDefn( "LNAM" );
926 2 : if( poLNAM == NULL )
927 0 : return;
928 :
929 6 : for( int iRef = 0; iRef < nRefCount; iRef++ )
930 : {
931 : unsigned char *pabyData;
932 :
933 : pabyData = (unsigned char *)
934 4 : poFFPT->GetSubfieldData( poLNAM, NULL, iRef );
935 :
936 : sprintf( szLNAM, "%02X%02X%02X%02X%02X%02X%02X%02X",
937 8 : pabyData[1], pabyData[0], /* AGEN */
938 16 : pabyData[5], pabyData[4], pabyData[3], pabyData[2], /* FIDN */
939 28 : pabyData[7], pabyData[6] );
940 :
941 4 : papszRefs = CSLAddString( papszRefs, szLNAM );
942 :
943 4 : panRIND[iRef] = pabyData[8];
944 : }
945 :
946 2 : poFeature->SetField( "LNAM_REFS", papszRefs );
947 2 : CSLDestroy( papszRefs );
948 :
949 2 : poFeature->SetField( "FFPT_RIND", nRefCount, panRIND );
950 2 : CPLFree( panRIND );
951 : }
952 :
953 : /************************************************************************/
954 : /* GenerateFSPTAttributes() */
955 : /************************************************************************/
956 :
957 0 : void S57Reader::GenerateFSPTAttributes( DDFRecord * poRecord,
958 : OGRFeature * poFeature )
959 :
960 : {
961 : /* -------------------------------------------------------------------- */
962 : /* Feature the spatial record containing the point. */
963 : /* -------------------------------------------------------------------- */
964 : DDFField *poFSPT;
965 : int nCount, i;
966 :
967 0 : poFSPT = poRecord->FindField( "FSPT" );
968 0 : if( poFSPT == NULL )
969 0 : return;
970 :
971 0 : nCount = poFSPT->GetRepeatCount();
972 :
973 : /* -------------------------------------------------------------------- */
974 : /* Allocate working lists of the attributes. */
975 : /* -------------------------------------------------------------------- */
976 : int *panORNT, *panUSAG, *panMASK, *panRCNM, *panRCID;
977 :
978 0 : panORNT = (int *) CPLMalloc( sizeof(int) * nCount );
979 0 : panUSAG = (int *) CPLMalloc( sizeof(int) * nCount );
980 0 : panMASK = (int *) CPLMalloc( sizeof(int) * nCount );
981 0 : panRCNM = (int *) CPLMalloc( sizeof(int) * nCount );
982 0 : panRCID = (int *) CPLMalloc( sizeof(int) * nCount );
983 :
984 : /* -------------------------------------------------------------------- */
985 : /* loop over all entries, decoding them. */
986 : /* -------------------------------------------------------------------- */
987 0 : for( i = 0; i < nCount; i++ )
988 : {
989 0 : panRCID[i] = ParseName( poFSPT, i, panRCNM + i );
990 0 : panORNT[i] = poRecord->GetIntSubfield( "FSPT", 0, "ORNT",i);
991 0 : panUSAG[i] = poRecord->GetIntSubfield( "FSPT", 0, "USAG",i);
992 0 : panMASK[i] = poRecord->GetIntSubfield( "FSPT", 0, "MASK",i);
993 : }
994 :
995 : /* -------------------------------------------------------------------- */
996 : /* Assign to feature. */
997 : /* -------------------------------------------------------------------- */
998 0 : poFeature->SetField( "NAME_RCNM", nCount, panRCNM );
999 0 : poFeature->SetField( "NAME_RCID", nCount, panRCID );
1000 0 : poFeature->SetField( "ORNT", nCount, panORNT );
1001 0 : poFeature->SetField( "USAG", nCount, panUSAG );
1002 0 : poFeature->SetField( "MASK", nCount, panMASK );
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Cleanup. */
1006 : /* -------------------------------------------------------------------- */
1007 0 : CPLFree( panRCNM );
1008 0 : CPLFree( panRCID );
1009 0 : CPLFree( panORNT );
1010 0 : CPLFree( panUSAG );
1011 0 : CPLFree( panMASK );
1012 : }
1013 :
1014 : /************************************************************************/
1015 : /* ReadDSID() */
1016 : /************************************************************************/
1017 :
1018 2 : OGRFeature *S57Reader::ReadDSID()
1019 :
1020 : {
1021 2 : if( poDSIDRecord == NULL && poDSPMRecord == NULL )
1022 0 : return NULL;
1023 :
1024 : /* -------------------------------------------------------------------- */
1025 : /* Find the feature definition to use. */
1026 : /* -------------------------------------------------------------------- */
1027 2 : OGRFeatureDefn *poFDefn = NULL;
1028 :
1029 2 : for( int i = 0; i < nFDefnCount; i++ )
1030 : {
1031 2 : if( EQUAL(papoFDefnList[i]->GetName(),"DSID") )
1032 : {
1033 2 : poFDefn = papoFDefnList[i];
1034 2 : break;
1035 : }
1036 : }
1037 :
1038 2 : if( poFDefn == NULL )
1039 : {
1040 0 : CPLAssert( FALSE );
1041 0 : return NULL;
1042 : }
1043 :
1044 : /* -------------------------------------------------------------------- */
1045 : /* Create feature. */
1046 : /* -------------------------------------------------------------------- */
1047 2 : OGRFeature *poFeature = new OGRFeature( poFDefn );
1048 :
1049 : /* -------------------------------------------------------------------- */
1050 : /* Apply DSID values. */
1051 : /* -------------------------------------------------------------------- */
1052 2 : if( poDSIDRecord != NULL )
1053 : {
1054 : poFeature->SetField( "DSID_EXPP",
1055 2 : poDSIDRecord->GetIntSubfield( "DSID", 0, "EXPP", 0 ));
1056 : poFeature->SetField( "DSID_INTU",
1057 2 : poDSIDRecord->GetIntSubfield( "DSID", 0, "INTU", 0 ));
1058 : poFeature->SetField( "DSID_DSNM",
1059 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "DSNM", 0 ));
1060 : poFeature->SetField( "DSID_EDTN",
1061 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "EDTN", 0 ));
1062 2 : if( strlen(szUPDNUpdate) > 0 )
1063 0 : poFeature->SetField( "DSID_UPDN", szUPDNUpdate );
1064 : else
1065 : poFeature->SetField( "DSID_UPDN",
1066 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "UPDN", 0 ));
1067 :
1068 : poFeature->SetField( "DSID_UADT",
1069 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "UADT", 0 ));
1070 : poFeature->SetField( "DSID_ISDT",
1071 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "ISDT", 0 ));
1072 : poFeature->SetField( "DSID_STED",
1073 2 : poDSIDRecord->GetFloatSubfield( "DSID", 0, "STED", 0 ));
1074 : poFeature->SetField( "DSID_PRSP",
1075 2 : poDSIDRecord->GetIntSubfield( "DSID", 0, "PRSP", 0 ));
1076 : poFeature->SetField( "DSID_PSDN",
1077 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "PSDN", 0 ));
1078 : poFeature->SetField( "DSID_PRED",
1079 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "PRED", 0 ));
1080 : poFeature->SetField( "DSID_PROF",
1081 2 : poDSIDRecord->GetIntSubfield( "DSID", 0, "PROF", 0 ));
1082 : poFeature->SetField( "DSID_AGEN",
1083 2 : poDSIDRecord->GetIntSubfield( "DSID", 0, "AGEN", 0 ));
1084 : poFeature->SetField( "DSID_COMT",
1085 2 : poDSIDRecord->GetStringSubfield( "DSID", 0, "COMT", 0 ));
1086 :
1087 : /* -------------------------------------------------------------------- */
1088 : /* Apply DSSI values. */
1089 : /* -------------------------------------------------------------------- */
1090 : poFeature->SetField( "DSSI_DSTR",
1091 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "DSTR", 0 ));
1092 : poFeature->SetField( "DSSI_AALL",
1093 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "AALL", 0 ));
1094 : poFeature->SetField( "DSSI_NALL",
1095 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NALL", 0 ));
1096 : poFeature->SetField( "DSSI_NOMR",
1097 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOMR", 0 ));
1098 : poFeature->SetField( "DSSI_NOCR",
1099 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOCR", 0 ));
1100 : poFeature->SetField( "DSSI_NOGR",
1101 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOGR", 0 ));
1102 : poFeature->SetField( "DSSI_NOLR",
1103 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOLR", 0 ));
1104 : poFeature->SetField( "DSSI_NOIN",
1105 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOIN", 0 ));
1106 : poFeature->SetField( "DSSI_NOCN",
1107 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOCN", 0 ));
1108 : poFeature->SetField( "DSSI_NOED",
1109 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOED", 0 ));
1110 : poFeature->SetField( "DSSI_NOFA",
1111 2 : poDSIDRecord->GetIntSubfield( "DSSI", 0, "NOFA", 0 ));
1112 : }
1113 :
1114 : /* -------------------------------------------------------------------- */
1115 : /* Apply DSPM record. */
1116 : /* -------------------------------------------------------------------- */
1117 2 : if( poDSPMRecord != NULL )
1118 : {
1119 : poFeature->SetField( "DSPM_HDAT",
1120 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "HDAT", 0 ));
1121 : poFeature->SetField( "DSPM_VDAT",
1122 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "VDAT", 0 ));
1123 : poFeature->SetField( "DSPM_SDAT",
1124 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "SDAT", 0 ));
1125 : poFeature->SetField( "DSPM_CSCL",
1126 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "CSCL", 0 ));
1127 : poFeature->SetField( "DSPM_DUNI",
1128 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "DUNI", 0 ));
1129 : poFeature->SetField( "DSPM_HUNI",
1130 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "HUNI", 0 ));
1131 : poFeature->SetField( "DSPM_PUNI",
1132 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "PUNI", 0 ));
1133 : poFeature->SetField( "DSPM_COUN",
1134 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "COUN", 0 ));
1135 : poFeature->SetField( "DSPM_COMF",
1136 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "COMF", 0 ));
1137 : poFeature->SetField( "DSPM_SOMF",
1138 2 : poDSPMRecord->GetIntSubfield( "DSPM", 0, "SOMF", 0 ));
1139 : poFeature->SetField( "DSPM_COMT",
1140 2 : poDSPMRecord->GetStringSubfield( "DSPM", 0, "COMT", 0 ));
1141 : }
1142 :
1143 2 : poFeature->SetFID( nNextDSIDIndex++ );
1144 :
1145 2 : return poFeature;
1146 : }
1147 :
1148 :
1149 : /************************************************************************/
1150 : /* ReadVector() */
1151 : /* */
1152 : /* Read a vector primitive objects based on the type (RCNM_) */
1153 : /* and index within the related index. */
1154 : /************************************************************************/
1155 :
1156 0 : OGRFeature *S57Reader::ReadVector( int nFeatureId, int nRCNM )
1157 :
1158 : {
1159 : DDFRecordIndex *poIndex;
1160 0 : const char *pszFDName = NULL;
1161 :
1162 : /* -------------------------------------------------------------------- */
1163 : /* What type of vector are we fetching. */
1164 : /* -------------------------------------------------------------------- */
1165 0 : switch( nRCNM )
1166 : {
1167 : case RCNM_VI:
1168 0 : poIndex = &oVI_Index;
1169 0 : pszFDName = OGRN_VI;
1170 0 : break;
1171 :
1172 : case RCNM_VC:
1173 0 : poIndex = &oVC_Index;
1174 0 : pszFDName = OGRN_VC;
1175 0 : break;
1176 :
1177 : case RCNM_VE:
1178 0 : poIndex = &oVE_Index;
1179 0 : pszFDName = OGRN_VE;
1180 0 : break;
1181 :
1182 : case RCNM_VF:
1183 0 : poIndex = &oVF_Index;
1184 0 : pszFDName = OGRN_VF;
1185 0 : break;
1186 :
1187 : default:
1188 0 : CPLAssert( FALSE );
1189 0 : return NULL;
1190 : }
1191 :
1192 0 : if( nFeatureId < 0 || nFeatureId >= poIndex->GetCount() )
1193 0 : return NULL;
1194 :
1195 0 : DDFRecord *poRecord = poIndex->GetByIndex( nFeatureId );
1196 :
1197 : /* -------------------------------------------------------------------- */
1198 : /* Find the feature definition to use. */
1199 : /* -------------------------------------------------------------------- */
1200 0 : OGRFeatureDefn *poFDefn = NULL;
1201 :
1202 0 : for( int i = 0; i < nFDefnCount; i++ )
1203 : {
1204 0 : if( EQUAL(papoFDefnList[i]->GetName(),pszFDName) )
1205 : {
1206 0 : poFDefn = papoFDefnList[i];
1207 0 : break;
1208 : }
1209 : }
1210 :
1211 0 : if( poFDefn == NULL )
1212 : {
1213 0 : CPLAssert( FALSE );
1214 0 : return NULL;
1215 : }
1216 :
1217 : /* -------------------------------------------------------------------- */
1218 : /* Create feature, and assign standard fields. */
1219 : /* -------------------------------------------------------------------- */
1220 0 : OGRFeature *poFeature = new OGRFeature( poFDefn );
1221 :
1222 0 : poFeature->SetFID( nFeatureId );
1223 :
1224 : poFeature->SetField( "RCNM",
1225 0 : poRecord->GetIntSubfield( "VRID", 0, "RCNM",0) );
1226 : poFeature->SetField( "RCID",
1227 0 : poRecord->GetIntSubfield( "VRID", 0, "RCID",0) );
1228 : poFeature->SetField( "RVER",
1229 0 : poRecord->GetIntSubfield( "VRID", 0, "RVER",0) );
1230 : poFeature->SetField( "RUIN",
1231 0 : poRecord->GetIntSubfield( "VRID", 0, "RUIN",0) );
1232 :
1233 : /* -------------------------------------------------------------------- */
1234 : /* Collect point geometries. */
1235 : /* -------------------------------------------------------------------- */
1236 0 : if( nRCNM == RCNM_VI || nRCNM == RCNM_VC )
1237 : {
1238 0 : double dfX=0.0, dfY=0.0, dfZ=0.0;
1239 :
1240 0 : if( poRecord->FindField( "SG2D" ) != NULL )
1241 : {
1242 0 : dfX = poRecord->GetIntSubfield("SG2D",0,"XCOO",0) / (double)nCOMF;
1243 0 : dfY = poRecord->GetIntSubfield("SG2D",0,"YCOO",0) / (double)nCOMF;
1244 0 : poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY ) );
1245 : }
1246 :
1247 0 : else if( poRecord->FindField( "SG3D" ) != NULL ) /* presume sounding*/
1248 : {
1249 0 : int i, nVCount = poRecord->FindField("SG3D")->GetRepeatCount();
1250 0 : if( nVCount == 1 )
1251 : {
1252 0 : dfX =poRecord->GetIntSubfield("SG3D",0,"XCOO",0)/(double)nCOMF;
1253 0 : dfY =poRecord->GetIntSubfield("SG3D",0,"YCOO",0)/(double)nCOMF;
1254 0 : dfZ =poRecord->GetIntSubfield("SG3D",0,"VE3D",0)/(double)nSOMF;
1255 0 : poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ));
1256 : }
1257 : else
1258 : {
1259 0 : OGRMultiPoint *poMP = new OGRMultiPoint();
1260 :
1261 0 : for( i = 0; i < nVCount; i++ )
1262 : {
1263 : dfX = poRecord->GetIntSubfield("SG3D",0,"XCOO",i)
1264 0 : / (double)nCOMF;
1265 : dfY = poRecord->GetIntSubfield("SG3D",0,"YCOO",i)
1266 0 : / (double)nCOMF;
1267 : dfZ = poRecord->GetIntSubfield("SG3D",0,"VE3D",i)
1268 0 : / (double)nSOMF;
1269 :
1270 0 : poMP->addGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1271 : }
1272 :
1273 0 : poFeature->SetGeometryDirectly( poMP );
1274 : }
1275 : }
1276 :
1277 : }
1278 :
1279 : /* -------------------------------------------------------------------- */
1280 : /* Collect an edge geometry. */
1281 : /* -------------------------------------------------------------------- */
1282 0 : else if( nRCNM == RCNM_VE )
1283 : {
1284 0 : int nPoints = 0;
1285 : DDFField *poSG2D;
1286 0 : OGRLineString *poLine = new OGRLineString();
1287 :
1288 0 : for( int iField = 0; iField < poRecord->GetFieldCount(); ++iField )
1289 : {
1290 0 : poSG2D = poRecord->GetField( iField );
1291 :
1292 0 : if( EQUAL(poSG2D->GetFieldDefn()->GetName(), "SG2D") )
1293 : {
1294 0 : int nVCount = poSG2D->GetRepeatCount();
1295 :
1296 0 : poLine->setNumPoints( nPoints + nVCount );
1297 :
1298 0 : for( int i = 0; i < nVCount; ++i )
1299 : {
1300 : poLine->setPoint
1301 : (nPoints++,
1302 : poRecord->GetIntSubfield("SG2D",0,"XCOO",i) / (double)nCOMF,
1303 0 : poRecord->GetIntSubfield("SG2D",0,"YCOO",i) / (double)nCOMF );
1304 : }
1305 : }
1306 : }
1307 :
1308 0 : poFeature->SetGeometryDirectly( poLine );
1309 : }
1310 :
1311 : /* -------------------------------------------------------------------- */
1312 : /* Special edge fields. */
1313 : /* Allow either 2 VRPT fields or one VRPT field with 2 rows */
1314 : /* -------------------------------------------------------------------- */
1315 : DDFField *poVRPT;
1316 :
1317 0 : if( nRCNM == RCNM_VE
1318 : && (poVRPT = poRecord->FindField( "VRPT" )) != NULL )
1319 : {
1320 0 : int iField = 0, iSubField = 1;
1321 :
1322 0 : poFeature->SetField( "NAME_RCNM_0", RCNM_VC );
1323 0 : poFeature->SetField( "NAME_RCID_0", ParseName( poVRPT ) );
1324 : poFeature->SetField( "ORNT_0",
1325 0 : poRecord->GetIntSubfield("VRPT",0,"ORNT",0) );
1326 : poFeature->SetField( "USAG_0",
1327 0 : poRecord->GetIntSubfield("VRPT",0,"USAG",0) );
1328 : poFeature->SetField( "TOPI_0",
1329 0 : poRecord->GetIntSubfield("VRPT",0,"TOPI",0) );
1330 : poFeature->SetField( "MASK_0",
1331 0 : poRecord->GetIntSubfield("VRPT",0,"MASK",0) );
1332 :
1333 0 : if( poVRPT->GetRepeatCount() == 1 )
1334 : {
1335 : // Only one row, need a second VRPT field
1336 0 : iField = 1; iSubField = 0;
1337 :
1338 0 : if( (poVRPT = poRecord->FindField( "VRPT", iField )) == NULL )
1339 : {
1340 : CPLError( CE_Warning, CPLE_AppDefined,
1341 : "Unable to fetch last edge node.\n"
1342 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1343 : " missing geometry.",
1344 : poFeature->GetDefnRef()->GetName(),
1345 0 : poFeature->GetFieldAsInteger( "RCID" ) );
1346 :
1347 0 : return poFeature;
1348 : }
1349 : }
1350 :
1351 0 : poFeature->SetField( "NAME_RCID_1", ParseName( poVRPT, iSubField ) );
1352 0 : poFeature->SetField( "NAME_RCNM_1", RCNM_VC );
1353 : poFeature->SetField( "ORNT_1",
1354 : poRecord->GetIntSubfield("VRPT",iField,
1355 0 : "ORNT",iSubField) );
1356 : poFeature->SetField( "USAG_1",
1357 : poRecord->GetIntSubfield("VRPT",iField,
1358 0 : "USAG",iSubField) );
1359 : poFeature->SetField( "TOPI_1",
1360 : poRecord->GetIntSubfield("VRPT",iField,
1361 0 : "TOPI",iSubField) );
1362 : poFeature->SetField( "MASK_1",
1363 : poRecord->GetIntSubfield("VRPT",iField,
1364 0 : "MASK",iSubField) );
1365 : }
1366 :
1367 0 : return poFeature;
1368 : }
1369 :
1370 : /************************************************************************/
1371 : /* FetchPoint() */
1372 : /* */
1373 : /* Fetch the location of a spatial point object. */
1374 : /************************************************************************/
1375 :
1376 114 : int S57Reader::FetchPoint( int nRCNM, int nRCID,
1377 : double * pdfX, double * pdfY, double * pdfZ )
1378 :
1379 : {
1380 : DDFRecord *poSRecord;
1381 :
1382 114 : if( nRCNM == RCNM_VI )
1383 6 : poSRecord = oVI_Index.FindRecord( nRCID );
1384 : else
1385 108 : poSRecord = oVC_Index.FindRecord( nRCID );
1386 :
1387 114 : if( poSRecord == NULL )
1388 0 : return FALSE;
1389 :
1390 114 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1391 :
1392 114 : if( poSRecord->FindField( "SG2D" ) != NULL )
1393 : {
1394 114 : dfX = poSRecord->GetIntSubfield("SG2D",0,"XCOO",0) / (double)nCOMF;
1395 114 : dfY = poSRecord->GetIntSubfield("SG2D",0,"YCOO",0) / (double)nCOMF;
1396 : }
1397 0 : else if( poSRecord->FindField( "SG3D" ) != NULL )
1398 : {
1399 0 : dfX = poSRecord->GetIntSubfield("SG3D",0,"XCOO",0) / (double)nCOMF;
1400 0 : dfY = poSRecord->GetIntSubfield("SG3D",0,"YCOO",0) / (double)nCOMF;
1401 0 : dfZ = poSRecord->GetIntSubfield("SG3D",0,"VE3D",0) / (double)nSOMF;
1402 : }
1403 : else
1404 0 : return FALSE;
1405 :
1406 114 : if( pdfX != NULL )
1407 114 : *pdfX = dfX;
1408 114 : if( pdfY != NULL )
1409 114 : *pdfY = dfY;
1410 114 : if( pdfZ != NULL )
1411 6 : *pdfZ = dfZ;
1412 :
1413 114 : return TRUE;
1414 : }
1415 :
1416 : /************************************************************************/
1417 : /* S57StrokeArcToOGRGeometry_Angles() */
1418 : /************************************************************************/
1419 :
1420 : static OGRLineString *
1421 0 : S57StrokeArcToOGRGeometry_Angles( double dfCenterX, double dfCenterY,
1422 : double dfRadius,
1423 : double dfStartAngle, double dfEndAngle,
1424 : int nVertexCount )
1425 :
1426 : {
1427 0 : OGRLineString *poLine = new OGRLineString;
1428 : double dfArcX, dfArcY, dfSlice;
1429 : int iPoint;
1430 :
1431 0 : nVertexCount = MAX(2,nVertexCount);
1432 0 : dfSlice = (dfEndAngle-dfStartAngle)/(nVertexCount-1);
1433 :
1434 0 : poLine->setNumPoints( nVertexCount );
1435 :
1436 0 : for( iPoint=0; iPoint < nVertexCount; iPoint++ )
1437 : {
1438 : double dfAngle;
1439 :
1440 0 : dfAngle = (dfStartAngle + iPoint * dfSlice) * PI / 180.0;
1441 :
1442 0 : dfArcX = dfCenterX + cos(dfAngle) * dfRadius;
1443 0 : dfArcY = dfCenterY + sin(dfAngle) * dfRadius;
1444 :
1445 0 : poLine->setPoint( iPoint, dfArcX, dfArcY );
1446 : }
1447 :
1448 0 : return poLine;
1449 : }
1450 :
1451 :
1452 : /************************************************************************/
1453 : /* S57StrokeArcToOGRGeometry_Points() */
1454 : /************************************************************************/
1455 :
1456 : static OGRLineString *
1457 0 : S57StrokeArcToOGRGeometry_Points( double dfStartX, double dfStartY,
1458 : double dfCenterX, double dfCenterY,
1459 : double dfEndX, double dfEndY,
1460 : int nVertexCount )
1461 :
1462 : {
1463 : double dfStartAngle, dfEndAngle;
1464 : double dfRadius;
1465 :
1466 0 : if( dfStartX == dfEndX && dfStartY == dfEndY )
1467 : {
1468 0 : dfStartAngle = 0.0;
1469 0 : dfEndAngle = 360.0;
1470 : }
1471 : else
1472 : {
1473 : double dfDeltaX, dfDeltaY;
1474 :
1475 0 : dfDeltaX = dfStartX - dfCenterX;
1476 0 : dfDeltaY = dfStartY - dfCenterY;
1477 0 : dfStartAngle = atan2(dfDeltaY,dfDeltaX) * 180.0 / PI;
1478 :
1479 0 : dfDeltaX = dfEndX - dfCenterX;
1480 0 : dfDeltaY = dfEndY - dfCenterY;
1481 0 : dfEndAngle = atan2(dfDeltaY,dfDeltaX) * 180.0 / PI;
1482 :
1483 : #ifdef notdef
1484 : if( dfStartAngle > dfAlongAngle && dfAlongAngle > dfEndAngle )
1485 : {
1486 : double dfTempAngle;
1487 :
1488 : dfTempAngle = dfStartAngle;
1489 : dfStartAngle = dfEndAngle;
1490 : dfEndAngle = dfTempAngle;
1491 : }
1492 : #endif
1493 :
1494 0 : while( dfStartAngle < dfEndAngle )
1495 0 : dfStartAngle += 360.0;
1496 :
1497 : // while( dfAlongAngle < dfStartAngle )
1498 : // dfAlongAngle += 360.0;
1499 :
1500 : // while( dfEndAngle < dfAlongAngle )
1501 : // dfEndAngle += 360.0;
1502 :
1503 0 : if( dfEndAngle - dfStartAngle > 360.0 )
1504 : {
1505 : double dfTempAngle;
1506 :
1507 0 : dfTempAngle = dfStartAngle;
1508 0 : dfStartAngle = dfEndAngle;
1509 0 : dfEndAngle = dfTempAngle;
1510 :
1511 0 : while( dfEndAngle < dfStartAngle )
1512 0 : dfStartAngle -= 360.0;
1513 : }
1514 : }
1515 :
1516 : dfRadius = sqrt( (dfCenterX - dfStartX) * (dfCenterX - dfStartX)
1517 0 : + (dfCenterY - dfStartY) * (dfCenterY - dfStartY) );
1518 :
1519 : return S57StrokeArcToOGRGeometry_Angles( dfCenterX, dfCenterY,
1520 : dfRadius,
1521 : dfStartAngle, dfEndAngle,
1522 0 : nVertexCount );
1523 : }
1524 :
1525 : /************************************************************************/
1526 : /* FetchLine() */
1527 : /************************************************************************/
1528 :
1529 30 : int S57Reader::FetchLine( DDFRecord *poSRecord,
1530 : int iStartVertex, int iDirection,
1531 : OGRLineString *poLine )
1532 :
1533 : {
1534 30 : int nPoints = 0;
1535 : DDFField *poSG2D, *poAR2D;
1536 30 : DDFSubfieldDefn *poXCOO=NULL, *poYCOO=NULL;
1537 30 : int bStandardFormat = TRUE;
1538 :
1539 : /* -------------------------------------------------------------------- */
1540 : /* Points may be multiple rows in one SG2D/AR2D field or */
1541 : /* multiple SG2D/AR2D fields (or a combination of both) */
1542 : /* Iterate over all the SG2D/AR2D fields in the record */
1543 : /* -------------------------------------------------------------------- */
1544 :
1545 134 : for( int iField = 0; iField < poSRecord->GetFieldCount(); ++iField )
1546 : {
1547 104 : poSG2D = poSRecord->GetField( iField );
1548 :
1549 104 : if( EQUAL(poSG2D->GetFieldDefn()->GetName(), "SG2D") )
1550 : {
1551 10 : poAR2D = NULL;
1552 : }
1553 94 : else if( EQUAL(poSG2D->GetFieldDefn()->GetName(), "AR2D") )
1554 : {
1555 0 : poAR2D = poSG2D;
1556 : }
1557 : else
1558 : {
1559 : /* Other types of fields are skipped */
1560 94 : continue;
1561 : }
1562 :
1563 : /* -------------------------------------------------------------------- */
1564 : /* Get some basic definitions. */
1565 : /* -------------------------------------------------------------------- */
1566 :
1567 10 : poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
1568 10 : poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
1569 :
1570 10 : if( poXCOO == NULL || poYCOO == NULL )
1571 : {
1572 0 : CPLDebug( "S57", "XCOO or YCOO are NULL" );
1573 0 : return FALSE;
1574 : }
1575 :
1576 10 : int nVCount = poSG2D->GetRepeatCount();
1577 :
1578 : /* -------------------------------------------------------------------- */
1579 : /* It is legitimate to have zero vertices for line segments */
1580 : /* that just have the start and end node (bug 840). */
1581 : /* */
1582 : /* This is bogus! nVCount != 0, because poXCOO != 0 here */
1583 : /* In case of zero vertices, there will not be any SG2D fields */
1584 : /* -------------------------------------------------------------------- */
1585 10 : if( nVCount == 0 )
1586 0 : continue;
1587 :
1588 : /* -------------------------------------------------------------------- */
1589 : /* Make sure out line is long enough to hold all the vertices */
1590 : /* we will apply. */
1591 : /* -------------------------------------------------------------------- */
1592 : int nVBase;
1593 :
1594 10 : if( iDirection < 0 )
1595 0 : nVBase = iStartVertex + nPoints + nVCount;
1596 : else
1597 10 : nVBase = iStartVertex + nPoints;
1598 :
1599 10 : if( poLine->getNumPoints() < iStartVertex + nPoints + nVCount )
1600 10 : poLine->setNumPoints( iStartVertex + nPoints + nVCount );
1601 :
1602 10 : nPoints += nVCount;
1603 : /* -------------------------------------------------------------------- */
1604 : /* Are the SG2D and XCOO/YCOO definitions in the form we expect? */
1605 : /* -------------------------------------------------------------------- */
1606 : bStandardFormat =
1607 : (poSG2D->GetFieldDefn()->GetSubfieldCount() == 2) &&
1608 : EQUAL(poXCOO->GetFormat(),"b24") &&
1609 10 : EQUAL(poYCOO->GetFormat(),"b24");
1610 :
1611 : /* -------------------------------------------------------------------- */
1612 : /* Collect the vertices: */
1613 : /* */
1614 : /* This approach assumes that the data is LSB organized int32 */
1615 : /* binary data as per the specification. We avoid lots of */
1616 : /* extra calls to low level DDF methods as they are quite */
1617 : /* expensive. */
1618 : /* -------------------------------------------------------------------- */
1619 10 : if( bStandardFormat )
1620 : {
1621 : const char *pachData;
1622 : int nBytesRemaining;
1623 :
1624 10 : pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,0);
1625 :
1626 38 : for( int i = 0; i < nVCount; i++ )
1627 : {
1628 : double dfX, dfY;
1629 : GInt32 nXCOO, nYCOO;
1630 :
1631 28 : memcpy( &nYCOO, pachData, 4 );
1632 28 : pachData += 4;
1633 28 : memcpy( &nXCOO, pachData, 4 );
1634 28 : pachData += 4;
1635 :
1636 : #ifdef CPL_MSB
1637 : CPL_SWAP32PTR( &nXCOO );
1638 : CPL_SWAP32PTR( &nYCOO );
1639 : #endif
1640 28 : dfX = nXCOO / (double) nCOMF;
1641 28 : dfY = nYCOO / (double) nCOMF;
1642 :
1643 28 : poLine->setPoint( nVBase, dfX, dfY );
1644 :
1645 28 : nVBase += iDirection;
1646 : }
1647 : }
1648 :
1649 : /* -------------------------------------------------------------------- */
1650 : /* Collect the vertices: */
1651 : /* */
1652 : /* The generic case where we use low level but expensive DDF */
1653 : /* methods to get the data. This should work even if some */
1654 : /* things are changed about the SG2D fields such as making them */
1655 : /* floating point or a different byte order. */
1656 : /* -------------------------------------------------------------------- */
1657 : else
1658 : {
1659 0 : for( int i = 0; i < nVCount; i++ )
1660 : {
1661 : double dfX, dfY;
1662 : const char *pachData;
1663 : int nBytesRemaining;
1664 :
1665 0 : pachData = poSG2D->GetSubfieldData(poXCOO,&nBytesRemaining,i);
1666 :
1667 : dfX = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1668 0 : / (double) nCOMF;
1669 :
1670 0 : pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,i);
1671 :
1672 : dfY = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1673 0 : / (double) nCOMF;
1674 :
1675 0 : poLine->setPoint( nVBase, dfX, dfY );
1676 :
1677 0 : nVBase += iDirection;
1678 : }
1679 : }
1680 :
1681 : /* -------------------------------------------------------------------- */
1682 : /* If this is actually an arc, turn the start, end and center */
1683 : /* of rotation into a "stroked" arc linestring. */
1684 : /* -------------------------------------------------------------------- */
1685 10 : if( poAR2D != NULL && poLine->getNumPoints() >= 3 )
1686 : {
1687 : OGRLineString *poArc;
1688 0 : int i, iLast = poLine->getNumPoints() - 1;
1689 :
1690 : poArc = S57StrokeArcToOGRGeometry_Points(
1691 : poLine->getX(iLast-0), poLine->getY(iLast-0),
1692 : poLine->getX(iLast-1), poLine->getY(iLast-1),
1693 : poLine->getX(iLast-2), poLine->getY(iLast-2),
1694 0 : 30 );
1695 :
1696 0 : if( poArc != NULL )
1697 : {
1698 0 : for( i = 0; i < poArc->getNumPoints(); i++ )
1699 0 : poLine->setPoint( iLast-2+i, poArc->getX(i), poArc->getY(i) );
1700 :
1701 0 : delete poArc;
1702 : }
1703 : }
1704 : }
1705 :
1706 30 : return TRUE;
1707 : }
1708 :
1709 : /************************************************************************/
1710 : /* AssemblePointGeometry() */
1711 : /************************************************************************/
1712 :
1713 8 : void S57Reader::AssemblePointGeometry( DDFRecord * poFRecord,
1714 : OGRFeature * poFeature )
1715 :
1716 : {
1717 : DDFField *poFSPT;
1718 : int nRCNM, nRCID;
1719 :
1720 : /* -------------------------------------------------------------------- */
1721 : /* Feature the spatial record containing the point. */
1722 : /* -------------------------------------------------------------------- */
1723 8 : poFSPT = poFRecord->FindField( "FSPT" );
1724 8 : if( poFSPT == NULL )
1725 2 : return;
1726 :
1727 6 : if( poFSPT->GetRepeatCount() != 1 )
1728 : {
1729 : #ifdef DEBUG
1730 : fprintf( stderr,
1731 0 : "Point features with other than one spatial linkage.\n" );
1732 0 : poFRecord->Dump( stderr );
1733 : #endif
1734 : CPLDebug( "S57",
1735 0 : "Point feature encountered with other than one spatial linkage." );
1736 : }
1737 :
1738 6 : nRCID = ParseName( poFSPT, 0, &nRCNM );
1739 :
1740 6 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1741 :
1742 6 : if( nRCID == -1 || !FetchPoint( nRCNM, nRCID, &dfX, &dfY, &dfZ ) )
1743 : {
1744 : CPLError( CE_Warning, CPLE_AppDefined,
1745 : "Failed to fetch %d/%d point geometry for point feature.\n"
1746 : "Feature will have empty geometry.",
1747 0 : nRCNM, nRCID );
1748 0 : return;
1749 : }
1750 :
1751 6 : if( dfZ == 0.0 )
1752 6 : poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY ) );
1753 : else
1754 0 : poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1755 : }
1756 :
1757 : /************************************************************************/
1758 : /* AssembleSoundingGeometry() */
1759 : /************************************************************************/
1760 :
1761 2 : void S57Reader::AssembleSoundingGeometry( DDFRecord * poFRecord,
1762 : OGRFeature * poFeature )
1763 :
1764 : {
1765 : DDFField *poFSPT;
1766 : int nRCNM, nRCID;
1767 : DDFRecord *poSRecord;
1768 :
1769 :
1770 : /* -------------------------------------------------------------------- */
1771 : /* Feature the spatial record containing the point. */
1772 : /* -------------------------------------------------------------------- */
1773 2 : poFSPT = poFRecord->FindField( "FSPT" );
1774 2 : if( poFSPT == NULL )
1775 0 : return;
1776 :
1777 2 : CPLAssert( poFSPT->GetRepeatCount() == 1 );
1778 :
1779 2 : nRCID = ParseName( poFSPT, 0, &nRCNM );
1780 :
1781 2 : if( nRCNM == RCNM_VI )
1782 2 : poSRecord = oVI_Index.FindRecord( nRCID );
1783 : else
1784 0 : poSRecord = oVC_Index.FindRecord( nRCID );
1785 :
1786 2 : if( poSRecord == NULL )
1787 0 : return;
1788 :
1789 : /* -------------------------------------------------------------------- */
1790 : /* Extract vertices. */
1791 : /* -------------------------------------------------------------------- */
1792 2 : OGRMultiPoint *poMP = new OGRMultiPoint();
1793 : DDFField *poField;
1794 : int nPointCount, i, nBytesLeft;
1795 : DDFSubfieldDefn *poXCOO, *poYCOO, *poVE3D;
1796 : const char *pachData;
1797 :
1798 2 : poField = poSRecord->FindField( "SG2D" );
1799 2 : if( poField == NULL )
1800 2 : poField = poSRecord->FindField( "SG3D" );
1801 2 : if( poField == NULL )
1802 0 : return;
1803 :
1804 2 : poXCOO = poField->GetFieldDefn()->FindSubfieldDefn( "XCOO" );
1805 2 : poYCOO = poField->GetFieldDefn()->FindSubfieldDefn( "YCOO" );
1806 2 : poVE3D = poField->GetFieldDefn()->FindSubfieldDefn( "VE3D" );
1807 :
1808 2 : nPointCount = poField->GetRepeatCount();
1809 :
1810 2 : pachData = poField->GetData();
1811 2 : nBytesLeft = poField->GetDataSize();
1812 :
1813 20 : for( i = 0; i < nPointCount; i++ )
1814 : {
1815 8 : double dfX, dfY, dfZ = 0.0;
1816 : int nBytesConsumed;
1817 :
1818 : dfY = poYCOO->ExtractIntData( pachData, nBytesLeft,
1819 8 : &nBytesConsumed ) / (double) nCOMF;
1820 8 : nBytesLeft -= nBytesConsumed;
1821 8 : pachData += nBytesConsumed;
1822 :
1823 : dfX = poXCOO->ExtractIntData( pachData, nBytesLeft,
1824 8 : &nBytesConsumed ) / (double) nCOMF;
1825 8 : nBytesLeft -= nBytesConsumed;
1826 8 : pachData += nBytesConsumed;
1827 :
1828 8 : if( poVE3D != NULL )
1829 : {
1830 : dfZ = poYCOO->ExtractIntData( pachData, nBytesLeft,
1831 8 : &nBytesConsumed ) / (double) nSOMF;
1832 8 : nBytesLeft -= nBytesConsumed;
1833 8 : pachData += nBytesConsumed;
1834 : }
1835 :
1836 8 : poMP->addGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1837 : }
1838 :
1839 2 : poFeature->SetGeometryDirectly( poMP );
1840 : }
1841 :
1842 : /************************************************************************/
1843 : /* GetIntSubfield() */
1844 : /************************************************************************/
1845 :
1846 : static int
1847 24 : GetIntSubfield( DDFField *poField,
1848 : const char * pszSubfield,
1849 : int iSubfieldIndex)
1850 : {
1851 : DDFSubfieldDefn *poSFDefn =
1852 24 : poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
1853 :
1854 24 : if( poSFDefn == NULL )
1855 0 : return 0;
1856 :
1857 : /* -------------------------------------------------------------------- */
1858 : /* Get a pointer to the data. */
1859 : /* -------------------------------------------------------------------- */
1860 : int nBytesRemaining;
1861 :
1862 : const char *pachData = poField->GetSubfieldData( poSFDefn,
1863 : &nBytesRemaining,
1864 24 : iSubfieldIndex );
1865 :
1866 24 : return( poSFDefn->ExtractIntData( pachData, nBytesRemaining, NULL ) );
1867 : }
1868 :
1869 : /************************************************************************/
1870 : /* AssembleLineGeometry() */
1871 : /************************************************************************/
1872 :
1873 4 : void S57Reader::AssembleLineGeometry( DDFRecord * poFRecord,
1874 : OGRFeature * poFeature )
1875 :
1876 : {
1877 : DDFField *poFSPT;
1878 4 : OGRLineString *poLine = new OGRLineString();
1879 8 : OGRMultiLineString *poMLS = new OGRMultiLineString();
1880 4 : double dlastfX( 0.0 ), dlastfY( 0.0 ), dfX, dfY;
1881 :
1882 : /* -------------------------------------------------------------------- */
1883 : /* Loop collecting edges. */
1884 : /* Iterate over the FSPT fields. */
1885 : /* -------------------------------------------------------------------- */
1886 4 : const int nFieldCount = poFRecord->GetFieldCount();
1887 :
1888 20 : for( int iField = 0; iField < nFieldCount; ++iField )
1889 : {
1890 16 : poFSPT = poFRecord->GetField( iField );
1891 :
1892 16 : if( !EQUAL(poFSPT->GetFieldDefn()->GetName(), "FSPT") )
1893 12 : continue;
1894 :
1895 : /* -------------------------------------------------------------------- */
1896 : /* Loop over the rows of each FSPT field */
1897 : /* -------------------------------------------------------------------- */
1898 4 : const int nEdgeCount = poFSPT->GetRepeatCount();
1899 :
1900 28 : for( int iEdge = 0; iEdge < nEdgeCount; ++iEdge )
1901 : {
1902 : int nVC_RCID_firstnode, nVC_RCID_lastnode;
1903 24 : bool bReverse = (GetIntSubfield( poFSPT, "ORNT", iEdge ) == 2);
1904 :
1905 : /* -------------------------------------------------------------------- */
1906 : /* Find the spatial record for this edge. */
1907 : /* -------------------------------------------------------------------- */
1908 24 : int nRCID = ParseName( poFSPT, iEdge );
1909 :
1910 24 : DDFRecord *poSRecord = oVE_Index.FindRecord( nRCID );
1911 24 : if( poSRecord == NULL )
1912 : {
1913 : CPLError( CE_Warning, CPLE_AppDefined,
1914 : "Couldn't find spatial record %d.\n"
1915 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1916 : "missing geometry.",
1917 : nRCID,
1918 : poFeature->GetDefnRef()->GetName(),
1919 0 : GetIntSubfield( poFSPT, "RCID", 0 ) );
1920 0 : continue;
1921 : }
1922 :
1923 : /* -------------------------------------------------------------------- */
1924 : /* Get the first and last nodes */
1925 : /* -------------------------------------------------------------------- */
1926 24 : DDFField *poVRPT = poSRecord->FindField( "VRPT" );
1927 24 : if( poVRPT == NULL )
1928 : {
1929 : CPLError( CE_Warning, CPLE_AppDefined,
1930 : "Unable to fetch start node for RCID %d.\n"
1931 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1932 : "missing geometry.",
1933 : nRCID,
1934 : poFeature->GetDefnRef()->GetName(),
1935 0 : GetIntSubfield( poFSPT, "RCID", 0 ) );
1936 0 : continue;
1937 : }
1938 :
1939 : // The "VRPT" field has only one row
1940 : // Get the next row from a second "VRPT" field
1941 24 : if( poVRPT->GetRepeatCount() == 1 )
1942 : {
1943 0 : nVC_RCID_firstnode = ParseName( poVRPT );
1944 0 : poVRPT = poSRecord->FindField( "VRPT", 1 );
1945 :
1946 0 : if( poVRPT == NULL )
1947 : {
1948 : CPLError( CE_Warning, CPLE_AppDefined,
1949 : "Unable to fetch end node for RCID %d.\n"
1950 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1951 : "missing geometry.",
1952 : nRCID,
1953 : poFeature->GetDefnRef()->GetName(),
1954 0 : GetIntSubfield( poFSPT, "RCID", 0 ) );
1955 0 : continue;
1956 : }
1957 :
1958 0 : nVC_RCID_lastnode = ParseName( poVRPT );
1959 :
1960 0 : if( bReverse )
1961 : {
1962 0 : int tmp = nVC_RCID_lastnode;
1963 0 : nVC_RCID_lastnode = nVC_RCID_firstnode;
1964 0 : nVC_RCID_firstnode = tmp;
1965 : }
1966 : }
1967 24 : else if( bReverse )
1968 : {
1969 0 : nVC_RCID_lastnode = ParseName( poVRPT );
1970 0 : nVC_RCID_firstnode = ParseName( poVRPT, 1 );
1971 : }
1972 : else
1973 : {
1974 24 : nVC_RCID_firstnode = ParseName( poVRPT );
1975 24 : nVC_RCID_lastnode = ParseName( poVRPT, 1 );
1976 : }
1977 :
1978 24 : if( nVC_RCID_firstnode == -1 ||
1979 : ! FetchPoint( RCNM_VC, nVC_RCID_firstnode, &dfX, &dfY ) )
1980 : {
1981 : CPLError( CE_Warning, CPLE_AppDefined,
1982 : "Unable to fetch start node RCID=%d.\n"
1983 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1984 : " missing geometry.",
1985 : nVC_RCID_firstnode,
1986 : poFeature->GetDefnRef()->GetName(),
1987 : poFRecord->GetIntSubfield( "FRID", 0,
1988 0 : "RCID", 0 ) );
1989 :
1990 0 : continue;
1991 : }
1992 :
1993 : /* -------------------------------------------------------------------- */
1994 : /* Does the first node match the trailing node on the existing */
1995 : /* line string? If so, skip it, otherwise if the existing */
1996 : /* linestring is not empty we need to push it out and start a */
1997 : /* new one as it means things are not connected. */
1998 : /* -------------------------------------------------------------------- */
1999 24 : if( poLine->getNumPoints() == 0 )
2000 : {
2001 4 : poLine->addPoint( dfX, dfY );
2002 : }
2003 20 : else if( ABS(dlastfX - dfX) > 0.00000001 ||
2004 : ABS(dlastfY - dfY) > 0.00000001 )
2005 : {
2006 : // we need to start a new linestring.
2007 14 : poMLS->addGeometryDirectly( poLine );
2008 14 : poLine = new OGRLineString();
2009 14 : poLine->addPoint( dfX, dfY );
2010 : }
2011 : else
2012 : /* omit point, already present */;
2013 :
2014 : // remember the coordinates of the last point
2015 24 : dlastfX = dfX; dlastfY = dfY;
2016 :
2017 : /* -------------------------------------------------------------------- */
2018 : /* Collect the vertices. */
2019 : /* Iterate over all the SG2D fields in the Spatial record */
2020 : /* -------------------------------------------------------------------- */
2021 : int nVBase, nVCount;
2022 : int nStart, nEnd, nInc;
2023 : DDFField *poSG2D;
2024 24 : DDFSubfieldDefn *poXCOO=NULL, *poYCOO=NULL;
2025 :
2026 124 : for( int iSField = 0; iSField < poSRecord->GetFieldCount();
2027 : ++iSField )
2028 : {
2029 100 : poSG2D = poSRecord->GetField( iSField );
2030 :
2031 100 : if( EQUAL(poSG2D->GetFieldDefn()->GetName(), "SG2D") ||
2032 : EQUAL(poSG2D->GetFieldDefn()->GetName(), "AR2D") )
2033 : {
2034 24 : poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
2035 24 : poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
2036 :
2037 24 : nVCount = poSG2D->GetRepeatCount();
2038 :
2039 24 : if( bReverse )
2040 : {
2041 0 : nStart = nVCount-1;
2042 0 : nEnd = 0;
2043 0 : nInc = -1;
2044 : }
2045 : else
2046 : {
2047 24 : nStart = 0;
2048 24 : nEnd = nVCount-1;
2049 24 : nInc = 1;
2050 : }
2051 :
2052 24 : nVBase = poLine->getNumPoints();
2053 24 : poLine->setNumPoints( nVBase + nVCount );
2054 :
2055 : const char *pachData;
2056 : int nBytesRemaining;
2057 :
2058 142 : for( int i = nStart; i != nEnd+nInc; i += nInc )
2059 : {
2060 118 : pachData = poSG2D->GetSubfieldData(poXCOO,&nBytesRemaining,i);
2061 :
2062 : dfX = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
2063 118 : / (double) nCOMF;
2064 :
2065 118 : pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,i);
2066 :
2067 : dfY = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
2068 118 : / (double) nCOMF;
2069 :
2070 118 : poLine->setPoint( nVBase++, dfX, dfY );
2071 : }
2072 : }
2073 : }
2074 24 : dlastfX = dfX; dlastfY = dfY;
2075 :
2076 : /* -------------------------------------------------------------------- */
2077 : /* Add the end node. */
2078 : /* -------------------------------------------------------------------- */
2079 24 : if( nVC_RCID_lastnode != -1 &&
2080 : FetchPoint( RCNM_VC, nVC_RCID_lastnode, &dfX, &dfY ) )
2081 : {
2082 24 : poLine->addPoint( dfX, dfY );
2083 24 : dlastfX = dfX; dlastfY = dfY;
2084 : }
2085 : else
2086 : {
2087 : CPLError( CE_Warning, CPLE_AppDefined,
2088 : "Unable to fetch end node RCID=%d.\n"
2089 : "Feature OBJL=%s, RCID=%d may have corrupt or"
2090 : " missing geometry.",
2091 : nVC_RCID_lastnode,
2092 : poFeature->GetDefnRef()->GetName(),
2093 0 : poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
2094 0 : continue;
2095 : }
2096 : }
2097 : }
2098 :
2099 : /* -------------------------------------------------------------------- */
2100 : /* Set either the line or multilinestring as the geometry. We */
2101 : /* are careful to just produce a linestring if there are no */
2102 : /* disconnections. */
2103 : /* -------------------------------------------------------------------- */
2104 4 : if( poMLS->getNumGeometries() > 0 )
2105 : {
2106 2 : poMLS->addGeometryDirectly( poLine );
2107 2 : poFeature->SetGeometryDirectly( poMLS );
2108 : }
2109 2 : else if( poLine->getNumPoints() >= 2 )
2110 : {
2111 2 : poFeature->SetGeometryDirectly( poLine );
2112 2 : delete poMLS;
2113 : }
2114 : else
2115 : {
2116 0 : delete poLine;
2117 0 : delete poMLS;
2118 : }
2119 4 : }
2120 :
2121 : /************************************************************************/
2122 : /* AssembleAreaGeometry() */
2123 : /************************************************************************/
2124 :
2125 4 : void S57Reader::AssembleAreaGeometry( DDFRecord * poFRecord,
2126 : OGRFeature * poFeature )
2127 :
2128 : {
2129 : DDFField *poFSPT;
2130 4 : OGRGeometryCollection * poLines = new OGRGeometryCollection();
2131 :
2132 : /* -------------------------------------------------------------------- */
2133 : /* Find the FSPT fields. */
2134 : /* -------------------------------------------------------------------- */
2135 4 : const int nFieldCount = poFRecord->GetFieldCount();
2136 :
2137 22 : for( int iFSPT = 0; iFSPT < nFieldCount; ++iFSPT )
2138 : {
2139 18 : poFSPT = poFRecord->GetField(iFSPT);
2140 :
2141 18 : if ( !EQUAL(poFSPT->GetFieldDefn()->GetName(), "FSPT") )
2142 14 : continue;
2143 :
2144 : int nEdgeCount;
2145 :
2146 4 : nEdgeCount = poFSPT->GetRepeatCount();
2147 :
2148 : /* ==================================================================== */
2149 : /* Loop collecting edges. */
2150 : /* ==================================================================== */
2151 34 : for( int iEdge = 0; iEdge < nEdgeCount; iEdge++ )
2152 : {
2153 : DDFRecord *poSRecord;
2154 : int nRCID;
2155 :
2156 : /* -------------------------------------------------------------------- */
2157 : /* Find the spatial record for this edge. */
2158 : /* -------------------------------------------------------------------- */
2159 30 : nRCID = ParseName( poFSPT, iEdge );
2160 :
2161 30 : poSRecord = oVE_Index.FindRecord( nRCID );
2162 30 : if( poSRecord == NULL )
2163 : {
2164 : CPLError( CE_Warning, CPLE_AppDefined,
2165 : "Couldn't find spatial record %d.\n"
2166 : "Feature OBJL=%s, RCID=%d may have corrupt or"
2167 : "missing geometry.",
2168 : nRCID,
2169 : poFeature->GetDefnRef()->GetName(),
2170 0 : GetIntSubfield( poFSPT, "RCID", 0 ) );
2171 0 : continue;
2172 : }
2173 :
2174 : /* -------------------------------------------------------------------- */
2175 : /* Create the line string. */
2176 : /* -------------------------------------------------------------------- */
2177 30 : OGRLineString *poLine = new OGRLineString();
2178 :
2179 : /* -------------------------------------------------------------------- */
2180 : /* Add the start node. */
2181 : /* -------------------------------------------------------------------- */
2182 30 : DDFField *poVRPT = poSRecord->FindField( "VRPT" );
2183 30 : if( poVRPT != NULL )
2184 : {
2185 30 : int nVC_RCID = ParseName( poVRPT );
2186 : double dfX, dfY;
2187 :
2188 30 : if( nVC_RCID != -1 && FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
2189 30 : poLine->addPoint( dfX, dfY );
2190 : }
2191 :
2192 : /* -------------------------------------------------------------------- */
2193 : /* Collect the vertices. */
2194 : /* -------------------------------------------------------------------- */
2195 30 : if( !FetchLine( poSRecord, poLine->getNumPoints(), 1, poLine ) )
2196 : {
2197 0 : CPLDebug( "S57", "FetchLine() failed in AssembleAreaGeometry()!" );
2198 : }
2199 :
2200 :
2201 : /* -------------------------------------------------------------------- */
2202 : /* Add the end node. */
2203 : /* -------------------------------------------------------------------- */
2204 30 : if( poVRPT->GetRepeatCount() > 1 )
2205 : {
2206 30 : int nVC_RCID = ParseName( poVRPT, 1 );
2207 : double dfX, dfY;
2208 :
2209 30 : if( nVC_RCID != -1 && FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
2210 30 : poLine->addPoint( dfX, dfY );
2211 : }
2212 0 : else if( (poVRPT = poSRecord->FindField( "VRPT", 1 )) != NULL )
2213 : {
2214 0 : int nVC_RCID = ParseName( poVRPT );
2215 : double dfX, dfY;
2216 :
2217 0 : if( nVC_RCID != -1 && FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
2218 0 : poLine->addPoint( dfX, dfY );
2219 : }
2220 :
2221 30 : poLines->addGeometryDirectly( poLine );
2222 : }
2223 : }
2224 :
2225 : /* -------------------------------------------------------------------- */
2226 : /* Build lines into a polygon. */
2227 : /* -------------------------------------------------------------------- */
2228 : OGRPolygon *poPolygon;
2229 : OGRErr eErr;
2230 :
2231 : poPolygon = (OGRPolygon *)
2232 : OGRBuildPolygonFromEdges( (OGRGeometryH) poLines,
2233 4 : TRUE, FALSE, 0.0, &eErr );
2234 4 : if( eErr != OGRERR_NONE )
2235 : {
2236 : CPLError( CE_Warning, CPLE_AppDefined,
2237 : "Polygon assembly has failed for feature FIDN=%d,FIDS=%d.\n"
2238 : "Geometry may be missing or incomplete.",
2239 : poFeature->GetFieldAsInteger( "FIDN" ),
2240 0 : poFeature->GetFieldAsInteger( "FIDS" ) );
2241 : }
2242 :
2243 4 : delete poLines;
2244 :
2245 4 : if( poPolygon != NULL )
2246 4 : poFeature->SetGeometryDirectly( poPolygon );
2247 4 : }
2248 :
2249 : /************************************************************************/
2250 : /* FindFDefn() */
2251 : /* */
2252 : /* Find the OGRFeatureDefn corresponding to the passed feature */
2253 : /* record. It will search based on geometry class, or object */
2254 : /* class depending on the bClassBased setting. */
2255 : /************************************************************************/
2256 :
2257 2374 : OGRFeatureDefn * S57Reader::FindFDefn( DDFRecord * poRecord )
2258 :
2259 : {
2260 2374 : if( poRegistrar != NULL )
2261 : {
2262 2374 : int nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
2263 :
2264 2374 : if( apoFDefnByOBJL[nOBJL] != NULL )
2265 2046 : return apoFDefnByOBJL[nOBJL];
2266 :
2267 328 : if( !poRegistrar->SelectClass( nOBJL ) )
2268 : {
2269 4304 : for( int i = 0; i < nFDefnCount; i++ )
2270 : {
2271 4304 : if( EQUAL(papoFDefnList[i]->GetName(),"Generic") )
2272 328 : return papoFDefnList[i];
2273 : }
2274 0 : return NULL;
2275 : }
2276 :
2277 0 : for( int i = 0; i < nFDefnCount; i++ )
2278 : {
2279 0 : if( EQUAL(papoFDefnList[i]->GetName(),
2280 : poRegistrar->GetAcronym()) )
2281 0 : return papoFDefnList[i];
2282 : }
2283 :
2284 0 : return NULL;
2285 : }
2286 : else
2287 : {
2288 0 : int nPRIM = poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 );
2289 : OGRwkbGeometryType eGType;
2290 :
2291 0 : if( nPRIM == PRIM_P )
2292 0 : eGType = wkbPoint;
2293 0 : else if( nPRIM == PRIM_L )
2294 0 : eGType = wkbLineString;
2295 0 : else if( nPRIM == PRIM_A )
2296 0 : eGType = wkbPolygon;
2297 : else
2298 0 : eGType = wkbNone;
2299 :
2300 0 : for( int i = 0; i < nFDefnCount; i++ )
2301 : {
2302 0 : if( papoFDefnList[i]->GetGeomType() == eGType )
2303 0 : return papoFDefnList[i];
2304 : }
2305 : }
2306 :
2307 0 : return NULL;
2308 : }
2309 :
2310 : /************************************************************************/
2311 : /* ParseName() */
2312 : /* */
2313 : /* Pull the RCNM and RCID values from a NAME field. The RCID */
2314 : /* is returned and the RCNM can be gotten via the pnRCNM argument. */
2315 : /* Note: nIndex is the index of the requested 'NAME' instance */
2316 : /************************************************************************/
2317 :
2318 170 : int S57Reader::ParseName( DDFField * poField, int nIndex, int * pnRCNM )
2319 :
2320 : {
2321 : unsigned char *pabyData;
2322 :
2323 170 : if( poField == NULL )
2324 : {
2325 : CPLError( CE_Failure, CPLE_AppDefined,
2326 0 : "Missing field in ParseName()." );
2327 0 : return -1;
2328 : }
2329 :
2330 : pabyData = (unsigned char *)
2331 : poField->GetSubfieldData(
2332 : poField->GetFieldDefn()->FindSubfieldDefn( "NAME" ),
2333 170 : NULL, nIndex );
2334 :
2335 170 : if( pnRCNM != NULL )
2336 8 : *pnRCNM = pabyData[0];
2337 :
2338 170 : return pabyData[1]
2339 170 : + pabyData[2] * 256
2340 170 : + pabyData[3] * 256 * 256
2341 510 : + pabyData[4] * 256 * 256 * 256;
2342 : }
2343 :
2344 : /************************************************************************/
2345 : /* AddFeatureDefn() */
2346 : /************************************************************************/
2347 :
2348 356 : void S57Reader::AddFeatureDefn( OGRFeatureDefn * poFDefn )
2349 :
2350 : {
2351 356 : nFDefnCount++;
2352 : papoFDefnList = (OGRFeatureDefn **)
2353 356 : CPLRealloc(papoFDefnList, sizeof(OGRFeatureDefn*)*nFDefnCount );
2354 :
2355 356 : papoFDefnList[nFDefnCount-1] = poFDefn;
2356 :
2357 356 : if( poRegistrar != NULL )
2358 : {
2359 356 : if( poRegistrar->SelectClass( poFDefn->GetName() ) )
2360 340 : apoFDefnByOBJL[poRegistrar->GetOBJL()] = poFDefn;
2361 : }
2362 356 : }
2363 :
2364 : /************************************************************************/
2365 : /* CollectClassList() */
2366 : /* */
2367 : /* Establish the list of classes (unique OBJL values) that */
2368 : /* occur in this dataset. */
2369 : /************************************************************************/
2370 :
2371 12 : int S57Reader::CollectClassList(int *panClassCount, int nMaxClass )
2372 :
2373 : {
2374 12 : int bSuccess = TRUE;
2375 :
2376 12 : if( !bFileIngested && !Ingest() )
2377 0 : return FALSE;
2378 :
2379 14420 : for( int iFEIndex = 0; iFEIndex < oFE_Index.GetCount(); iFEIndex++ )
2380 : {
2381 14408 : DDFRecord *poRecord = oFE_Index.GetByIndex( iFEIndex );
2382 14408 : int nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
2383 :
2384 14408 : if( nOBJL >= nMaxClass )
2385 0 : bSuccess = FALSE;
2386 : else
2387 14408 : panClassCount[nOBJL]++;
2388 :
2389 : }
2390 :
2391 12 : return bSuccess;
2392 : }
2393 :
2394 : /************************************************************************/
2395 : /* ApplyRecordUpdate() */
2396 : /* */
2397 : /* Update one target record based on an S-57 update record */
2398 : /* (RUIN=3). */
2399 : /************************************************************************/
2400 :
2401 16 : int S57Reader::ApplyRecordUpdate( DDFRecord *poTarget, DDFRecord *poUpdate )
2402 :
2403 : {
2404 16 : const char *pszKey = poUpdate->GetField(1)->GetFieldDefn()->GetName();
2405 :
2406 : /* -------------------------------------------------------------------- */
2407 : /* Validate versioning. */
2408 : /* -------------------------------------------------------------------- */
2409 16 : if( poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 ) + 1
2410 : != poUpdate->GetIntSubfield( pszKey, 0, "RVER", 0 ) )
2411 : {
2412 : CPLDebug( "S57",
2413 : "Mismatched RVER value on RCNM=%d,RCID=%d.\n",
2414 : poTarget->GetIntSubfield( pszKey, 0, "RCNM", 0 ),
2415 0 : poTarget->GetIntSubfield( pszKey, 0, "RCID", 0 ) );
2416 :
2417 0 : CPLAssert( FALSE );
2418 0 : return FALSE;
2419 : }
2420 :
2421 : /* -------------------------------------------------------------------- */
2422 : /* Update the target version. */
2423 : /* -------------------------------------------------------------------- */
2424 : unsigned char *pnRVER;
2425 16 : DDFField *poKey = poTarget->FindField( pszKey );
2426 : DDFSubfieldDefn *poRVER_SFD;
2427 :
2428 16 : if( poKey == NULL )
2429 : {
2430 0 : CPLAssert( FALSE );
2431 0 : return FALSE;
2432 : }
2433 :
2434 16 : poRVER_SFD = poKey->GetFieldDefn()->FindSubfieldDefn( "RVER" );
2435 16 : if( poRVER_SFD == NULL )
2436 0 : return FALSE;
2437 :
2438 16 : pnRVER = (unsigned char *) poKey->GetSubfieldData( poRVER_SFD, NULL, 0 );
2439 :
2440 16 : *pnRVER += 1;
2441 :
2442 : /* -------------------------------------------------------------------- */
2443 : /* Check for, and apply record record to spatial record pointer */
2444 : /* updates. */
2445 : /* -------------------------------------------------------------------- */
2446 16 : if( poUpdate->FindField( "FSPC" ) != NULL )
2447 : {
2448 16 : int nFSUI = poUpdate->GetIntSubfield( "FSPC", 0, "FSUI", 0 );
2449 16 : int nFSIX = poUpdate->GetIntSubfield( "FSPC", 0, "FSIX", 0 );
2450 16 : int nNSPT = poUpdate->GetIntSubfield( "FSPC", 0, "NSPT", 0 );
2451 16 : DDFField *poSrcFSPT = poUpdate->FindField( "FSPT" );
2452 16 : DDFField *poDstFSPT = poTarget->FindField( "FSPT" );
2453 : int nPtrSize;
2454 :
2455 16 : if( (poSrcFSPT == NULL && nFSUI != 2) || poDstFSPT == NULL )
2456 : {
2457 0 : CPLAssert( FALSE );
2458 0 : return FALSE;
2459 : }
2460 :
2461 16 : nPtrSize = poDstFSPT->GetFieldDefn()->GetFixedWidth();
2462 :
2463 16 : if( nFSUI == 1 ) /* INSERT */
2464 : {
2465 : char *pachInsertion;
2466 0 : int nInsertionBytes = nPtrSize * nNSPT;
2467 :
2468 0 : pachInsertion = (char *) CPLMalloc(nInsertionBytes + nPtrSize);
2469 0 : memcpy( pachInsertion, poSrcFSPT->GetData(), nInsertionBytes );
2470 :
2471 : /*
2472 : ** If we are inserting before an instance that already
2473 : ** exists, we must add it to the end of the data being
2474 : ** inserted.
2475 : */
2476 0 : if( nFSIX <= poDstFSPT->GetRepeatCount() )
2477 : {
2478 : memcpy( pachInsertion + nInsertionBytes,
2479 : poDstFSPT->GetData() + nPtrSize * (nFSIX-1),
2480 0 : nPtrSize );
2481 0 : nInsertionBytes += nPtrSize;
2482 : }
2483 :
2484 : poTarget->SetFieldRaw( poDstFSPT, nFSIX - 1,
2485 0 : pachInsertion, nInsertionBytes );
2486 0 : CPLFree( pachInsertion );
2487 : }
2488 16 : else if( nFSUI == 2 ) /* DELETE */
2489 : {
2490 : /* Wipe each deleted coordinate */
2491 0 : for( int i = nNSPT-1; i >= 0; i-- )
2492 : {
2493 0 : poTarget->SetFieldRaw( poDstFSPT, i + nFSIX - 1, NULL, 0 );
2494 : }
2495 : }
2496 16 : else if( nFSUI == 3 ) /* MODIFY */
2497 : {
2498 : /* copy over each ptr */
2499 32 : for( int i = 0; i < nNSPT; i++ )
2500 : {
2501 : const char *pachRawData;
2502 :
2503 16 : pachRawData = poSrcFSPT->GetData() + nPtrSize * i;
2504 : poTarget->SetFieldRaw( poDstFSPT, i + nFSIX - 1,
2505 16 : pachRawData, nPtrSize );
2506 : }
2507 : }
2508 : }
2509 :
2510 : /* -------------------------------------------------------------------- */
2511 : /* Check for, and apply vector record to vector record pointer */
2512 : /* updates. */
2513 : /* -------------------------------------------------------------------- */
2514 16 : if( poUpdate->FindField( "VRPC" ) != NULL )
2515 : {
2516 0 : int nVPUI = poUpdate->GetIntSubfield( "VRPC", 0, "VPUI", 0 );
2517 0 : int nVPIX = poUpdate->GetIntSubfield( "VRPC", 0, "VPIX", 0 );
2518 0 : int nNVPT = poUpdate->GetIntSubfield( "VRPC", 0, "NVPT", 0 );
2519 0 : DDFField *poSrcVRPT = poUpdate->FindField( "VRPT" );
2520 0 : DDFField *poDstVRPT = poTarget->FindField( "VRPT" );
2521 : int nPtrSize;
2522 :
2523 0 : if( (poSrcVRPT == NULL && nVPUI != 2) || poDstVRPT == NULL )
2524 : {
2525 0 : CPLAssert( FALSE );
2526 0 : return FALSE;
2527 : }
2528 :
2529 0 : nPtrSize = poDstVRPT->GetFieldDefn()->GetFixedWidth();
2530 :
2531 0 : if( nVPUI == 1 ) /* INSERT */
2532 : {
2533 : char *pachInsertion;
2534 0 : int nInsertionBytes = nPtrSize * nNVPT;
2535 :
2536 0 : pachInsertion = (char *) CPLMalloc(nInsertionBytes + nPtrSize);
2537 0 : memcpy( pachInsertion, poSrcVRPT->GetData(), nInsertionBytes );
2538 :
2539 : /*
2540 : ** If we are inserting before an instance that already
2541 : ** exists, we must add it to the end of the data being
2542 : ** inserted.
2543 : */
2544 0 : if( nVPIX <= poDstVRPT->GetRepeatCount() )
2545 : {
2546 : memcpy( pachInsertion + nInsertionBytes,
2547 : poDstVRPT->GetData() + nPtrSize * (nVPIX-1),
2548 0 : nPtrSize );
2549 0 : nInsertionBytes += nPtrSize;
2550 : }
2551 :
2552 : poTarget->SetFieldRaw( poDstVRPT, nVPIX - 1,
2553 0 : pachInsertion, nInsertionBytes );
2554 0 : CPLFree( pachInsertion );
2555 : }
2556 0 : else if( nVPUI == 2 ) /* DELETE */
2557 : {
2558 : /* Wipe each deleted coordinate */
2559 0 : for( int i = nNVPT-1; i >= 0; i-- )
2560 : {
2561 0 : poTarget->SetFieldRaw( poDstVRPT, i + nVPIX - 1, NULL, 0 );
2562 : }
2563 : }
2564 0 : else if( nVPUI == 3 ) /* MODIFY */
2565 : {
2566 : /* copy over each ptr */
2567 0 : for( int i = 0; i < nNVPT; i++ )
2568 : {
2569 : const char *pachRawData;
2570 :
2571 0 : pachRawData = poSrcVRPT->GetData() + nPtrSize * i;
2572 :
2573 : poTarget->SetFieldRaw( poDstVRPT, i + nVPIX - 1,
2574 0 : pachRawData, nPtrSize );
2575 : }
2576 : }
2577 : }
2578 :
2579 : /* -------------------------------------------------------------------- */
2580 : /* Check for, and apply record update to coordinates. */
2581 : /* -------------------------------------------------------------------- */
2582 16 : if( poUpdate->FindField( "SGCC" ) != NULL )
2583 : {
2584 0 : int nCCUI = poUpdate->GetIntSubfield( "SGCC", 0, "CCUI", 0 );
2585 0 : int nCCIX = poUpdate->GetIntSubfield( "SGCC", 0, "CCIX", 0 );
2586 0 : int nCCNC = poUpdate->GetIntSubfield( "SGCC", 0, "CCNC", 0 );
2587 0 : DDFField *poSrcSG2D = poUpdate->FindField( "SG2D" );
2588 0 : DDFField *poDstSG2D = poTarget->FindField( "SG2D" );
2589 : int nCoordSize;
2590 :
2591 : /* If we don't have SG2D, check for SG3D */
2592 0 : if( poDstSG2D == NULL )
2593 : {
2594 0 : poDstSG2D = poTarget->FindField( "SG3D" );
2595 0 : if (poDstSG2D != NULL)
2596 : {
2597 0 : poSrcSG2D = poUpdate->FindField("SG3D");
2598 : }
2599 : }
2600 :
2601 0 : if( (poSrcSG2D == NULL && nCCUI != 2)
2602 : || (poDstSG2D == NULL && nCCUI != 1) )
2603 : {
2604 0 : CPLAssert( FALSE );
2605 0 : return FALSE;
2606 : }
2607 :
2608 0 : if (poDstSG2D == NULL)
2609 : {
2610 0 : poTarget->AddField(poTarget->GetModule()->FindFieldDefn("SG2D"));
2611 0 : poDstSG2D = poTarget->FindField("SG2D");
2612 0 : if (poDstSG2D == NULL) {
2613 0 : CPLAssert( FALSE );
2614 0 : return FALSE;
2615 : }
2616 :
2617 : // Delete null default data that was created
2618 0 : poTarget->SetFieldRaw( poDstSG2D, 0, NULL, 0 );
2619 : }
2620 :
2621 0 : nCoordSize = poDstSG2D->GetFieldDefn()->GetFixedWidth();
2622 :
2623 0 : if( nCCUI == 1 ) /* INSERT */
2624 : {
2625 : char *pachInsertion;
2626 0 : int nInsertionBytes = nCoordSize * nCCNC;
2627 :
2628 0 : pachInsertion = (char *) CPLMalloc(nInsertionBytes + nCoordSize);
2629 0 : memcpy( pachInsertion, poSrcSG2D->GetData(), nInsertionBytes );
2630 :
2631 : /*
2632 : ** If we are inserting before an instance that already
2633 : ** exists, we must add it to the end of the data being
2634 : ** inserted.
2635 : */
2636 0 : if( nCCIX <= poDstSG2D->GetRepeatCount() )
2637 : {
2638 : memcpy( pachInsertion + nInsertionBytes,
2639 : poDstSG2D->GetData() + nCoordSize * (nCCIX-1),
2640 0 : nCoordSize );
2641 0 : nInsertionBytes += nCoordSize;
2642 : }
2643 :
2644 : poTarget->SetFieldRaw( poDstSG2D, nCCIX - 1,
2645 0 : pachInsertion, nInsertionBytes );
2646 0 : CPLFree( pachInsertion );
2647 :
2648 : }
2649 0 : else if( nCCUI == 2 ) /* DELETE */
2650 : {
2651 : /* Wipe each deleted coordinate */
2652 0 : for( int i = nCCNC-1; i >= 0; i-- )
2653 : {
2654 0 : poTarget->SetFieldRaw( poDstSG2D, i + nCCIX - 1, NULL, 0 );
2655 : }
2656 : }
2657 0 : else if( nCCUI == 3 ) /* MODIFY */
2658 : {
2659 : /* copy over each ptr */
2660 0 : for( int i = 0; i < nCCNC; i++ )
2661 : {
2662 : const char *pachRawData;
2663 :
2664 0 : pachRawData = poSrcSG2D->GetData() + nCoordSize * i;
2665 :
2666 : poTarget->SetFieldRaw( poDstSG2D, i + nCCIX - 1,
2667 0 : pachRawData, nCoordSize );
2668 : }
2669 : }
2670 : }
2671 :
2672 : /* -------------------------------------------------------------------- */
2673 : /* We don't currently handle FFPC (feature to feature linkage) */
2674 : /* issues, but we will at least report them when debugging. */
2675 : /* -------------------------------------------------------------------- */
2676 16 : if( poUpdate->FindField( "FFPC" ) != NULL )
2677 : {
2678 0 : CPLDebug( "S57", "Found FFPC, but not applying it." );
2679 : }
2680 :
2681 : /* -------------------------------------------------------------------- */
2682 : /* Check for and apply changes to attribute lists. */
2683 : /* -------------------------------------------------------------------- */
2684 16 : if( poUpdate->FindField( "ATTF" ) != NULL )
2685 : {
2686 : DDFSubfieldDefn *poSrcATVLDefn;
2687 0 : DDFField *poSrcATTF = poUpdate->FindField( "ATTF" );
2688 0 : DDFField *poDstATTF = poTarget->FindField( "ATTF" );
2689 0 : int nRepeatCount = poSrcATTF->GetRepeatCount();
2690 :
2691 0 : if( poDstATTF == NULL )
2692 : {
2693 : CPLError( CE_Warning, CPLE_AppDefined,
2694 0 : "Unable to apply ATTF change to target record without an ATTF field (see GDAL/OGR Bug #1648)" );
2695 0 : return FALSE;
2696 : }
2697 :
2698 0 : poSrcATVLDefn = poSrcATTF->GetFieldDefn()->FindSubfieldDefn( "ATVL" );
2699 :
2700 0 : for( int iAtt = 0; iAtt < nRepeatCount; iAtt++ )
2701 : {
2702 0 : int nATTL = poUpdate->GetIntSubfield( "ATTF", 0, "ATTL", iAtt );
2703 : int iTAtt, nDataBytes;
2704 : const char *pszRawData;
2705 :
2706 0 : for( iTAtt = poDstATTF->GetRepeatCount()-1; iTAtt >= 0; iTAtt-- )
2707 : {
2708 0 : if( poTarget->GetIntSubfield( "ATTF", 0, "ATTL", iTAtt )
2709 : == nATTL )
2710 0 : break;
2711 : }
2712 0 : if( iTAtt == -1 )
2713 0 : iTAtt = poDstATTF->GetRepeatCount();
2714 :
2715 0 : pszRawData = poSrcATTF->GetInstanceData( iAtt, &nDataBytes );
2716 0 : if( pszRawData[2] == 0x7f /* delete marker */ )
2717 : {
2718 0 : poTarget->SetFieldRaw( poDstATTF, iTAtt, NULL, 0 );
2719 : }
2720 : else
2721 : {
2722 : poTarget->SetFieldRaw( poDstATTF, iTAtt, pszRawData,
2723 0 : nDataBytes );
2724 : }
2725 : }
2726 : }
2727 :
2728 16 : return TRUE;
2729 : }
2730 :
2731 :
2732 : /************************************************************************/
2733 : /* ApplyUpdates() */
2734 : /* */
2735 : /* Read records from an update file, and apply them to the */
2736 : /* currently loaded index of features. */
2737 : /************************************************************************/
2738 :
2739 2 : int S57Reader::ApplyUpdates( DDFModule *poUpdateModule )
2740 :
2741 : {
2742 : DDFRecord *poRecord;
2743 :
2744 : /* -------------------------------------------------------------------- */
2745 : /* Ensure base file is loaded. */
2746 : /* -------------------------------------------------------------------- */
2747 2 : if( !bFileIngested && !Ingest() )
2748 0 : return FALSE;
2749 :
2750 : /* -------------------------------------------------------------------- */
2751 : /* Read records, and apply as updates. */
2752 : /* -------------------------------------------------------------------- */
2753 2 : CPLErrorReset();
2754 74 : while( (poRecord = poUpdateModule->ReadRecord()) != NULL )
2755 : {
2756 70 : DDFField *poKeyField = poRecord->GetField(1);
2757 70 : const char *pszKey = poKeyField->GetFieldDefn()->GetName();
2758 :
2759 138 : if( EQUAL(pszKey,"VRID") || EQUAL(pszKey,"FRID"))
2760 : {
2761 68 : int nRCNM = poRecord->GetIntSubfield( pszKey,0, "RCNM",0 );
2762 68 : int nRCID = poRecord->GetIntSubfield( pszKey,0, "RCID",0 );
2763 68 : int nRVER = poRecord->GetIntSubfield( pszKey,0, "RVER",0 );
2764 68 : int nRUIN = poRecord->GetIntSubfield( pszKey,0, "RUIN",0 );
2765 68 : DDFRecordIndex *poIndex = NULL;
2766 :
2767 68 : if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"VRID") )
2768 : {
2769 38 : switch( nRCNM )
2770 : {
2771 : case RCNM_VI:
2772 38 : poIndex = &oVI_Index;
2773 38 : break;
2774 :
2775 : case RCNM_VC:
2776 0 : poIndex = &oVC_Index;
2777 0 : break;
2778 :
2779 : case RCNM_VE:
2780 0 : poIndex = &oVE_Index;
2781 0 : break;
2782 :
2783 : case RCNM_VF:
2784 0 : poIndex = &oVF_Index;
2785 0 : break;
2786 :
2787 : default:
2788 0 : CPLAssert( FALSE );
2789 : break;
2790 : }
2791 : }
2792 : else
2793 : {
2794 30 : poIndex = &oFE_Index;
2795 : }
2796 :
2797 68 : if( poIndex != NULL )
2798 : {
2799 68 : if( nRUIN == 1 ) /* insert */
2800 : {
2801 36 : poIndex->AddRecord( nRCID, poRecord->CloneOn(poModule) );
2802 : }
2803 32 : else if( nRUIN == 2 ) /* delete */
2804 : {
2805 : DDFRecord *poTarget;
2806 :
2807 16 : poTarget = poIndex->FindRecord( nRCID );
2808 16 : if( poTarget == NULL )
2809 : {
2810 : CPLError( CE_Warning, CPLE_AppDefined,
2811 : "Can't find RCNM=%d,RCID=%d for delete.\n",
2812 0 : nRCNM, nRCID );
2813 : }
2814 16 : else if( poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 )
2815 : != nRVER - 1 )
2816 : {
2817 : CPLError( CE_Warning, CPLE_AppDefined,
2818 : "Mismatched RVER value on RCNM=%d,RCID=%d.\n",
2819 0 : nRCNM, nRCID );
2820 : }
2821 : else
2822 : {
2823 16 : poIndex->RemoveRecord( nRCID );
2824 : }
2825 : }
2826 :
2827 16 : else if( nRUIN == 3 ) /* modify in place */
2828 : {
2829 : DDFRecord *poTarget;
2830 :
2831 16 : poTarget = poIndex->FindRecord( nRCID );
2832 16 : if( poTarget == NULL )
2833 : {
2834 : CPLError( CE_Warning, CPLE_AppDefined,
2835 : "Can't find RCNM=%d,RCID=%d for update.\n",
2836 0 : nRCNM, nRCID );
2837 : }
2838 : else
2839 : {
2840 16 : if( !ApplyRecordUpdate( poTarget, poRecord ) )
2841 : {
2842 : CPLError( CE_Warning, CPLE_AppDefined,
2843 : "An update to RCNM=%d,RCID=%d failed.\n",
2844 0 : nRCNM, nRCID );
2845 : }
2846 : }
2847 : }
2848 : }
2849 : }
2850 :
2851 2 : else if( EQUAL(pszKey,"DSID") )
2852 : {
2853 2 : if( poDSIDRecord != NULL )
2854 : {
2855 : strcpy( szUPDNUpdate,
2856 2 : poRecord->GetStringSubfield( "DSID", 0, "UPDN", 0 ) );
2857 : }
2858 : }
2859 :
2860 : else
2861 : {
2862 : CPLDebug( "S57",
2863 : "Skipping %s record in S57Reader::ApplyUpdates().\n",
2864 0 : pszKey );
2865 : }
2866 : }
2867 :
2868 2 : return CPLGetLastErrorType() != CE_Failure;
2869 : }
2870 :
2871 : /************************************************************************/
2872 : /* FindAndApplyUpdates() */
2873 : /* */
2874 : /* Find all update files that would appear to apply to this */
2875 : /* base file. */
2876 : /************************************************************************/
2877 :
2878 12 : int S57Reader::FindAndApplyUpdates( const char * pszPath )
2879 :
2880 : {
2881 : int iUpdate;
2882 12 : int bSuccess = TRUE;
2883 :
2884 12 : if( pszPath == NULL )
2885 12 : pszPath = pszModuleName;
2886 :
2887 12 : if( !EQUAL(CPLGetExtension(pszPath),"000") )
2888 : {
2889 : CPLError( CE_Failure, CPLE_AppDefined,
2890 : "Can't apply updates to a base file with a different\n"
2891 0 : "extension than .000.\n" );
2892 0 : return FALSE;
2893 : }
2894 :
2895 12 : for( iUpdate = 1; bSuccess; iUpdate++ )
2896 : {
2897 : //Creaing file extension
2898 14 : CPLString extension;
2899 14 : CPLString dirname;
2900 28 : if( 1 <= iUpdate && iUpdate < 10 )
2901 : {
2902 : char buf[2];
2903 14 : sprintf( buf, "%i", iUpdate );
2904 14 : extension.append("00");
2905 14 : extension.append(buf);
2906 14 : dirname.append(buf);
2907 : }
2908 0 : else if( 10 <= iUpdate && iUpdate < 100 )
2909 : {
2910 : char buf[3];
2911 0 : sprintf( buf, "%i", iUpdate );
2912 0 : extension.append("0");
2913 0 : extension.append(buf);
2914 0 : dirname.append(buf);
2915 : }
2916 0 : else if( 100 <= iUpdate && iUpdate < 1000 )
2917 : {
2918 : char buf[4];
2919 0 : sprintf( buf, "%i", iUpdate );
2920 0 : extension.append(buf);
2921 0 : dirname.append(buf);
2922 : }
2923 :
2924 14 : DDFModule oUpdateModule;
2925 :
2926 : //trying current dir first
2927 : char *pszUpdateFilename =
2928 14 : CPLStrdup(CPLResetExtension(pszPath,extension.c_str()));
2929 :
2930 14 : FILE *file = VSIFOpen( pszUpdateFilename, "r" );
2931 14 : if( file )
2932 : {
2933 2 : VSIFClose( file );
2934 2 : bSuccess = oUpdateModule.Open( pszUpdateFilename, TRUE );
2935 2 : if( bSuccess )
2936 : CPLDebug( "S57", "Applying feature updates from %s.",
2937 2 : pszUpdateFilename );
2938 2 : if( bSuccess )
2939 : {
2940 2 : if( !ApplyUpdates( &oUpdateModule ) )
2941 0 : return FALSE;
2942 : }
2943 : }
2944 : else // file is store on Primar generated cd
2945 : {
2946 12 : char* pszBaseFileDir = CPLStrdup(CPLGetDirname(pszPath));
2947 12 : char* pszFileDir = CPLStrdup(CPLGetDirname(pszBaseFileDir));
2948 :
2949 12 : CPLString remotefile(pszFileDir);
2950 12 : remotefile.append( "/" );
2951 12 : remotefile.append( dirname );
2952 12 : remotefile.append( "/" );
2953 12 : remotefile.append( CPLGetBasename(pszPath) );
2954 12 : remotefile.append( "." );
2955 12 : remotefile.append( extension );
2956 12 : bSuccess = oUpdateModule.Open( remotefile.c_str(), TRUE );
2957 :
2958 12 : if( bSuccess )
2959 : CPLDebug( "S57", "Applying feature updates from %s.",
2960 0 : remotefile.c_str() );
2961 12 : CPLFree( pszBaseFileDir );
2962 12 : CPLFree( pszFileDir );
2963 12 : if( bSuccess )
2964 : {
2965 0 : if( !ApplyUpdates( &oUpdateModule ) )
2966 0 : return FALSE;
2967 0 : }
2968 : }//end for if-else
2969 14 : CPLFree( pszUpdateFilename );
2970 : }
2971 :
2972 12 : return TRUE;
2973 : }
2974 :
2975 : /************************************************************************/
2976 : /* GetExtent() */
2977 : /* */
2978 : /* Scan all the cached records collecting spatial bounds as */
2979 : /* efficiently as possible for this transfer. */
2980 : /************************************************************************/
2981 :
2982 0 : OGRErr S57Reader::GetExtent( OGREnvelope *psExtent, int bForce )
2983 :
2984 : {
2985 : #define INDEX_COUNT 4
2986 :
2987 : DDFRecordIndex *apoIndex[INDEX_COUNT];
2988 :
2989 : /* -------------------------------------------------------------------- */
2990 : /* If we aren't forced to get the extent say no if we haven't */
2991 : /* already indexed the iso8211 records. */
2992 : /* -------------------------------------------------------------------- */
2993 0 : if( !bForce && !bFileIngested )
2994 0 : return OGRERR_FAILURE;
2995 :
2996 0 : if( !Ingest() )
2997 0 : return OGRERR_FAILURE;
2998 :
2999 : /* -------------------------------------------------------------------- */
3000 : /* We will scan all the low level vector elements for extents */
3001 : /* coordinates. */
3002 : /* -------------------------------------------------------------------- */
3003 0 : int bGotExtents = FALSE;
3004 0 : int nXMin=0, nXMax=0, nYMin=0, nYMax=0;
3005 :
3006 0 : apoIndex[0] = &oVI_Index;
3007 0 : apoIndex[1] = &oVC_Index;
3008 0 : apoIndex[2] = &oVE_Index;
3009 0 : apoIndex[3] = &oVF_Index;
3010 :
3011 0 : for( int iIndex = 0; iIndex < INDEX_COUNT; iIndex++ )
3012 : {
3013 0 : DDFRecordIndex *poIndex = apoIndex[iIndex];
3014 :
3015 0 : for( int iVIndex = 0; iVIndex < poIndex->GetCount(); iVIndex++ )
3016 : {
3017 0 : DDFRecord *poRecord = poIndex->GetByIndex( iVIndex );
3018 0 : DDFField *poSG3D = poRecord->FindField( "SG3D" );
3019 0 : DDFField *poSG2D = poRecord->FindField( "SG2D" );
3020 :
3021 0 : if( poSG3D != NULL )
3022 : {
3023 0 : int i, nVCount = poSG3D->GetRepeatCount();
3024 : GInt32 *panData, nX, nY;
3025 :
3026 0 : panData = (GInt32 *) poSG3D->GetData();
3027 0 : for( i = 0; i < nVCount; i++ )
3028 : {
3029 0 : nX = CPL_LSBWORD32(panData[i*3+1]);
3030 0 : nY = CPL_LSBWORD32(panData[i*3+0]);
3031 :
3032 0 : if( bGotExtents )
3033 : {
3034 0 : nXMin = MIN(nXMin,nX);
3035 0 : nXMax = MAX(nXMax,nX);
3036 0 : nYMin = MIN(nYMin,nY);
3037 0 : nYMax = MAX(nYMax,nY);
3038 : }
3039 : else
3040 : {
3041 0 : nXMin = nXMax = nX;
3042 0 : nYMin = nYMax = nY;
3043 0 : bGotExtents = TRUE;
3044 : }
3045 : }
3046 : }
3047 0 : else if( poSG2D != NULL )
3048 : {
3049 0 : int i, nVCount = poSG2D->GetRepeatCount();
3050 : GInt32 *panData, nX, nY;
3051 :
3052 0 : panData = (GInt32 *) poSG2D->GetData();
3053 0 : for( i = 0; i < nVCount; i++ )
3054 : {
3055 0 : nX = CPL_LSBWORD32(panData[i*2+1]);
3056 0 : nY = CPL_LSBWORD32(panData[i*2+0]);
3057 :
3058 0 : if( bGotExtents )
3059 : {
3060 0 : nXMin = MIN(nXMin,nX);
3061 0 : nXMax = MAX(nXMax,nX);
3062 0 : nYMin = MIN(nYMin,nY);
3063 0 : nYMax = MAX(nYMax,nY);
3064 : }
3065 : else
3066 : {
3067 0 : nXMin = nXMax = nX;
3068 0 : nYMin = nYMax = nY;
3069 0 : bGotExtents = TRUE;
3070 : }
3071 : }
3072 : }
3073 : }
3074 : }
3075 :
3076 0 : if( !bGotExtents )
3077 0 : return OGRERR_FAILURE;
3078 : else
3079 : {
3080 0 : psExtent->MinX = nXMin / (double) nCOMF;
3081 0 : psExtent->MaxX = nXMax / (double) nCOMF;
3082 0 : psExtent->MinY = nYMin / (double) nCOMF;
3083 0 : psExtent->MaxY = nYMax / (double) nCOMF;
3084 :
3085 0 : return OGRERR_NONE;
3086 : }
3087 : }
3088 :
|