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