1 : /******************************************************************************
2 : * $Id: s57reader.cpp 17953 2009-11-02 21:13:56Z rouault $
3 : *
4 : * Project: S-57 Translator
5 : * Purpose: Implements S57Reader class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, 2001, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "s57.h"
31 : #include "ogr_api.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 :
35 : #include <string>
36 : #include <fstream>
37 :
38 : CPL_CVSID("$Id: s57reader.cpp 17953 2009-11-02 21:13:56Z rouault $");
39 :
40 : #ifndef PI
41 : #define PI 3.14159265358979323846
42 : #endif
43 :
44 : /************************************************************************/
45 : /* S57Reader() */
46 : /************************************************************************/
47 :
48 2 : S57Reader::S57Reader( const char * pszFilename )
49 :
50 : {
51 2 : pszModuleName = CPLStrdup( pszFilename );
52 2 : pszDSNM = NULL;
53 :
54 2 : poModule = NULL;
55 :
56 2 : nFDefnCount = 0;
57 2 : papoFDefnList = NULL;
58 :
59 2 : nCOMF = 1000000;
60 2 : nSOMF = 10;
61 :
62 2 : poRegistrar = NULL;
63 2 : bFileIngested = FALSE;
64 :
65 2 : nNextFEIndex = 0;
66 2 : nNextVIIndex = 0;
67 2 : nNextVCIndex = 0;
68 2 : nNextVEIndex = 0;
69 2 : nNextVFIndex = 0;
70 2 : nNextDSIDIndex = 0;
71 :
72 2 : poDSIDRecord = NULL;
73 2 : poDSPMRecord = NULL;
74 2 : szUPDNUpdate[0] = '\0';
75 :
76 2 : iPointOffset = 0;
77 2 : poMultiPoint = NULL;
78 :
79 2 : papszOptions = NULL;
80 :
81 2 : nOptionFlags = S57M_UPDATES;
82 :
83 2 : bMissingWarningIssued = FALSE;
84 2 : bAttrWarningIssued = FALSE;
85 :
86 2 : memset( apoFDefnByOBJL, 0, sizeof(apoFDefnByOBJL) );
87 2 : }
88 :
89 : /************************************************************************/
90 : /* ~S57Reader() */
91 : /************************************************************************/
92 :
93 2 : S57Reader::~S57Reader()
94 :
95 : {
96 2 : Close();
97 :
98 2 : CPLFree( pszModuleName );
99 2 : CSLDestroy( papszOptions );
100 :
101 2 : CPLFree( papoFDefnList );
102 2 : }
103 :
104 : /************************************************************************/
105 : /* Open() */
106 : /************************************************************************/
107 :
108 2 : int S57Reader::Open( int bTestOpen )
109 :
110 : {
111 2 : if( poModule != NULL )
112 : {
113 0 : Rewind();
114 0 : return TRUE;
115 : }
116 :
117 2 : poModule = new DDFModule();
118 2 : 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 2 : 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 2 : DDFFieldDefn *poFSPT = poModule->FindFieldDefn( "FSPT" );
142 2 : if( poFSPT != NULL && !poFSPT->IsRepeating() )
143 : {
144 0 : CPLDebug( "S57", "Forcing FSPT field to be repeating." );
145 0 : poFSPT->SetRepeatingFlag( TRUE );
146 : }
147 :
148 2 : nNextFEIndex = 0;
149 2 : nNextVIIndex = 0;
150 2 : nNextVCIndex = 0;
151 2 : nNextVEIndex = 0;
152 2 : nNextVFIndex = 0;
153 2 : nNextDSIDIndex = 0;
154 :
155 2 : return TRUE;
156 : }
157 :
158 : /************************************************************************/
159 : /* Close() */
160 : /************************************************************************/
161 :
162 2 : void S57Reader::Close()
163 :
164 : {
165 2 : if( poModule != NULL )
166 : {
167 2 : oVI_Index.Clear();
168 2 : oVC_Index.Clear();
169 2 : oVE_Index.Clear();
170 2 : oVF_Index.Clear();
171 2 : oFE_Index.Clear();
172 :
173 2 : if( poDSIDRecord != NULL )
174 : {
175 2 : delete poDSIDRecord;
176 2 : poDSIDRecord = NULL;
177 : }
178 2 : if( poDSPMRecord != NULL )
179 : {
180 1 : delete poDSPMRecord;
181 1 : poDSPMRecord = NULL;
182 : }
183 :
184 2 : ClearPendingMultiPoint();
185 :
186 2 : delete poModule;
187 2 : poModule = NULL;
188 :
189 2 : bFileIngested = FALSE;
190 :
191 2 : CPLFree( pszDSNM );
192 2 : pszDSNM = NULL;
193 : }
194 2 : }
195 :
196 : /************************************************************************/
197 : /* ClearPendingMultiPoint() */
198 : /************************************************************************/
199 :
200 5 : void S57Reader::ClearPendingMultiPoint()
201 :
202 : {
203 5 : if( poMultiPoint != NULL )
204 : {
205 0 : delete poMultiPoint;
206 0 : poMultiPoint = NULL;
207 : }
208 5 : }
209 :
210 : /************************************************************************/
211 : /* NextPendingMultiPoint() */
212 : /************************************************************************/
213 :
214 0 : OGRFeature *S57Reader::NextPendingMultiPoint()
215 :
216 : {
217 : CPLAssert( poMultiPoint != NULL );
218 : CPLAssert( wkbFlatten(poMultiPoint->GetGeometryRef()->getGeometryType())
219 : == 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 2 : void S57Reader::SetOptions( char ** papszOptionsIn )
250 :
251 : {
252 : const char * pszOptionValue;
253 :
254 2 : CSLDestroy( papszOptions );
255 2 : papszOptions = CSLDuplicate( papszOptionsIn );
256 :
257 2 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_SPLIT_MULTIPOINT );
258 2 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
259 0 : nOptionFlags |= S57M_SPLIT_MULTIPOINT;
260 : else
261 2 : nOptionFlags &= ~S57M_SPLIT_MULTIPOINT;
262 :
263 2 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_ADD_SOUNDG_DEPTH );
264 2 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
265 0 : nOptionFlags |= S57M_ADD_SOUNDG_DEPTH;
266 : else
267 2 : nOptionFlags &= ~S57M_ADD_SOUNDG_DEPTH;
268 :
269 : CPLAssert( ! (nOptionFlags & S57M_ADD_SOUNDG_DEPTH)
270 : || (nOptionFlags & S57M_SPLIT_MULTIPOINT) );
271 :
272 2 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_LNAM_REFS );
273 4 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
274 2 : nOptionFlags |= S57M_LNAM_REFS;
275 : else
276 0 : nOptionFlags &= ~S57M_LNAM_REFS;
277 :
278 2 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_UPDATES );
279 2 : 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 2 : S57O_PRESERVE_EMPTY_NUMBERS);
288 2 : if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
289 0 : nOptionFlags |= S57M_PRESERVE_EMPTY_NUMBERS;
290 : else
291 2 : nOptionFlags &= ~S57M_PRESERVE_EMPTY_NUMBERS;
292 :
293 2 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_PRIMITIVES );
294 2 : if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
295 0 : nOptionFlags |= S57M_RETURN_PRIMITIVES;
296 : else
297 2 : nOptionFlags &= ~S57M_RETURN_PRIMITIVES;
298 :
299 2 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_LINKAGES );
300 2 : if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
301 0 : nOptionFlags |= S57M_RETURN_LINKAGES;
302 : else
303 2 : nOptionFlags &= ~S57M_RETURN_LINKAGES;
304 :
305 2 : pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RETURN_DSID );
306 2 : if( pszOptionValue == NULL || CSLTestBoolean(pszOptionValue) )
307 2 : nOptionFlags |= S57M_RETURN_DSID;
308 : else
309 0 : nOptionFlags &= ~S57M_RETURN_DSID;
310 2 : }
311 :
312 : /************************************************************************/
313 : /* SetClassBased() */
314 : /************************************************************************/
315 :
316 2 : void S57Reader::SetClassBased( S57ClassRegistrar * poReg )
317 :
318 : {
319 2 : poRegistrar = poReg;
320 2 : }
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 2 : int S57Reader::Ingest()
346 :
347 : {
348 : DDFRecord *poRecord;
349 :
350 2 : 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 2 : CPLErrorReset();
358 150 : while( (poRecord = poModule->ReadRecord()) != NULL )
359 : {
360 146 : DDFField *poKeyField = poRecord->GetField(1);
361 :
362 146 : if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"VRID") )
363 : {
364 55 : int nRCNM = poRecord->GetIntSubfield( "VRID",0, "RCNM",0);
365 55 : int nRCID = poRecord->GetIntSubfield( "VRID",0, "RCID",0);
366 :
367 55 : switch( nRCNM )
368 : {
369 : case RCNM_VI:
370 11 : oVI_Index.AddRecord( nRCID, poRecord->Clone() );
371 11 : break;
372 :
373 : case RCNM_VC:
374 19 : oVC_Index.AddRecord( nRCID, poRecord->Clone() );
375 19 : break;
376 :
377 : case RCNM_VE:
378 25 : oVE_Index.AddRecord( nRCID, poRecord->Clone() );
379 25 : break;
380 :
381 : case RCNM_VF:
382 0 : oVF_Index.AddRecord( nRCID, poRecord->Clone() );
383 : break;
384 :
385 : default:
386 : CPLAssert( FALSE );
387 : break;
388 : }
389 : }
390 :
391 91 : else if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"FRID") )
392 : {
393 88 : int nRCID = poRecord->GetIntSubfield( "FRID",0, "RCID",0);
394 :
395 88 : oFE_Index.AddRecord( nRCID, poRecord->Clone() );
396 : }
397 :
398 3 : else if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"DSID") )
399 : {
400 2 : CPLFree( pszDSNM );
401 : pszDSNM =
402 2 : CPLStrdup(poRecord->GetStringSubfield( "DSID", 0, "DSNM", 0 ));
403 :
404 2 : if( nOptionFlags & S57M_RETURN_DSID )
405 : {
406 2 : if( poDSIDRecord != NULL )
407 0 : delete poDSIDRecord;
408 :
409 2 : poDSIDRecord = poRecord->Clone();
410 : }
411 : }
412 :
413 1 : else if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"DSPM") )
414 : {
415 1 : nCOMF = MAX(1,poRecord->GetIntSubfield( "DSPM",0, "COMF",0));
416 1 : nSOMF = MAX(1,poRecord->GetIntSubfield( "DSPM",0, "SOMF",0));
417 :
418 1 : if( nOptionFlags & S57M_RETURN_DSID )
419 : {
420 1 : if( poDSPMRecord != NULL )
421 0 : delete poDSPMRecord;
422 :
423 1 : 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 2 : if( CPLGetLastErrorType() == CE_Failure )
436 0 : return FALSE;
437 :
438 2 : bFileIngested = TRUE;
439 :
440 : /* -------------------------------------------------------------------- */
441 : /* If update support is enabled, read and apply them. */
442 : /* -------------------------------------------------------------------- */
443 2 : if( nOptionFlags & S57M_UPDATES )
444 2 : return FindAndApplyUpdates();
445 : else
446 0 : return TRUE;
447 : }
448 :
449 : /************************************************************************/
450 : /* SetNextFEIndex() */
451 : /************************************************************************/
452 :
453 6 : void S57Reader::SetNextFEIndex( int nNewIndex, int nRCNM )
454 :
455 : {
456 6 : if( nRCNM == RCNM_VI )
457 0 : nNextVIIndex = nNewIndex;
458 6 : else if( nRCNM == RCNM_VC )
459 0 : nNextVCIndex = nNewIndex;
460 6 : else if( nRCNM == RCNM_VE )
461 0 : nNextVEIndex = nNewIndex;
462 6 : else if( nRCNM == RCNM_VF )
463 0 : nNextVFIndex = nNewIndex;
464 6 : else if( nRCNM == RCNM_DSID )
465 2 : nNextDSIDIndex = nNewIndex;
466 : else
467 : {
468 4 : if( nNextFEIndex != nNewIndex )
469 3 : ClearPendingMultiPoint();
470 :
471 4 : nNextFEIndex = nNewIndex;
472 : }
473 6 : }
474 :
475 : /************************************************************************/
476 : /* GetNextFEIndex() */
477 : /************************************************************************/
478 :
479 6 : int S57Reader::GetNextFEIndex( int nRCNM )
480 :
481 : {
482 6 : if( nRCNM == RCNM_VI )
483 0 : return nNextVIIndex;
484 6 : else if( nRCNM == RCNM_VC )
485 0 : return nNextVCIndex;
486 6 : else if( nRCNM == RCNM_VE )
487 0 : return nNextVEIndex;
488 6 : else if( nRCNM == RCNM_VF )
489 0 : return nNextVFIndex;
490 6 : else if( nRCNM == RCNM_DSID )
491 2 : return nNextDSIDIndex;
492 : else
493 4 : return nNextFEIndex;
494 : }
495 :
496 : /************************************************************************/
497 : /* ReadNextFeature() */
498 : /************************************************************************/
499 :
500 6 : OGRFeature * S57Reader::ReadNextFeature( OGRFeatureDefn * poTarget )
501 :
502 : {
503 6 : if( !bFileIngested && !Ingest() )
504 0 : return NULL;
505 :
506 : /* -------------------------------------------------------------------- */
507 : /* Special case for "in progress" multipoints being split up. */
508 : /* -------------------------------------------------------------------- */
509 6 : 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 6 : 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 5 : 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 128 : while( nNextFEIndex < oFE_Index.GetCount() )
601 : {
602 : OGRFeature *poFeature;
603 : OGRFeatureDefn *poFeatureDefn;
604 :
605 : poFeatureDefn = (OGRFeatureDefn *)
606 122 : oFE_Index.GetClientInfoByIndex( nNextFEIndex );
607 :
608 122 : if( poFeatureDefn == NULL )
609 : {
610 86 : poFeatureDefn = FindFDefn( oFE_Index.GetByIndex( nNextFEIndex ) );
611 86 : oFE_Index.SetClientInfoByIndex( nNextFEIndex, poFeatureDefn );
612 : }
613 :
614 122 : if( poFeatureDefn != poTarget && poTarget != NULL )
615 : {
616 118 : nNextFEIndex++;
617 118 : continue;
618 : }
619 :
620 4 : poFeature = ReadFeature( nNextFEIndex++, poTarget );
621 4 : if( poFeature != NULL )
622 : {
623 4 : 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 4 : 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 4 : OGRFeature *S57Reader::ReadFeature( int nFeatureId, OGRFeatureDefn *poTarget )
647 :
648 : {
649 : OGRFeature *poFeature;
650 :
651 4 : if( nFeatureId < 0 || nFeatureId >= oFE_Index.GetCount() )
652 0 : return NULL;
653 :
654 : poFeature = AssembleFeature( oFE_Index.GetByIndex(nFeatureId),
655 4 : poTarget );
656 4 : if( poFeature != NULL )
657 4 : poFeature->SetFID( nFeatureId );
658 :
659 4 : return poFeature;
660 : }
661 :
662 :
663 : /************************************************************************/
664 : /* AssembleFeature() */
665 : /* */
666 : /* Assemble an OGR feature based on a feature record. */
667 : /************************************************************************/
668 :
669 4 : 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 4 : poFDefn = FindFDefn( poRecord );
683 4 : 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 4 : if( poTarget != NULL && poFDefn != poTarget )
691 0 : return NULL;
692 :
693 : /* -------------------------------------------------------------------- */
694 : /* Create the new feature object. */
695 : /* -------------------------------------------------------------------- */
696 : OGRFeature *poFeature;
697 :
698 4 : poFeature = new OGRFeature( poFDefn );
699 :
700 : /* -------------------------------------------------------------------- */
701 : /* Assign a few standard feature attribues. */
702 : /* -------------------------------------------------------------------- */
703 4 : nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
704 4 : poFeature->SetField( "OBJL", nOBJL );
705 :
706 : poFeature->SetField( "RCID",
707 4 : poRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ));
708 : poFeature->SetField( "PRIM",
709 4 : poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 ));
710 : poFeature->SetField( "GRUP",
711 4 : poRecord->GetIntSubfield( "FRID", 0, "GRUP", 0 ));
712 : poFeature->SetField( "RVER",
713 4 : poRecord->GetIntSubfield( "FRID", 0, "RVER", 0 ));
714 : poFeature->SetField( "AGEN",
715 4 : poRecord->GetIntSubfield( "FOID", 0, "AGEN", 0 ));
716 : poFeature->SetField( "FIDN",
717 4 : poRecord->GetIntSubfield( "FOID", 0, "FIDN", 0 ));
718 : poFeature->SetField( "FIDS",
719 4 : poRecord->GetIntSubfield( "FOID", 0, "FIDS", 0 ));
720 :
721 : /* -------------------------------------------------------------------- */
722 : /* Generate long name, if requested. */
723 : /* -------------------------------------------------------------------- */
724 4 : if( nOptionFlags & S57M_LNAM_REFS )
725 : {
726 4 : GenerateLNAMAndRefs( poRecord, poFeature );
727 : }
728 :
729 : /* -------------------------------------------------------------------- */
730 : /* Generate primitive references if requested. */
731 : /* -------------------------------------------------------------------- */
732 4 : if( nOptionFlags & S57M_RETURN_LINKAGES )
733 0 : GenerateFSPTAttributes( poRecord, poFeature );
734 :
735 : /* -------------------------------------------------------------------- */
736 : /* Apply object class specific attributes, if supported. */
737 : /* -------------------------------------------------------------------- */
738 4 : if( poRegistrar != NULL )
739 4 : ApplyObjectClassAttributes( poRecord, poFeature );
740 :
741 : /* -------------------------------------------------------------------- */
742 : /* Find and assign spatial component. */
743 : /* -------------------------------------------------------------------- */
744 4 : nPRIM = poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 );
745 :
746 4 : if( nPRIM == PRIM_P )
747 : {
748 2 : if( nOBJL == 129 ) /* SOUNDG */
749 1 : AssembleSoundingGeometry( poRecord, poFeature );
750 : else
751 1 : AssemblePointGeometry( poRecord, poFeature );
752 : }
753 2 : else if( nPRIM == PRIM_L )
754 : {
755 1 : AssembleLineGeometry( poRecord, poFeature );
756 : }
757 1 : else if( nPRIM == PRIM_A )
758 : {
759 1 : AssembleAreaGeometry( poRecord, poFeature );
760 : }
761 :
762 4 : return poFeature;
763 : }
764 :
765 : /************************************************************************/
766 : /* ApplyObjectClassAttributes() */
767 : /************************************************************************/
768 :
769 4 : void S57Reader::ApplyObjectClassAttributes( DDFRecord * poRecord,
770 : OGRFeature * poFeature )
771 :
772 : {
773 : /* -------------------------------------------------------------------- */
774 : /* ATTF Attributes */
775 : /* -------------------------------------------------------------------- */
776 4 : DDFField *poATTF = poRecord->FindField( "ATTF" );
777 : int nAttrCount, iAttr;
778 :
779 4 : if( poATTF == NULL )
780 1 : return;
781 :
782 3 : nAttrCount = poATTF->GetRepeatCount();
783 6 : for( iAttr = 0; iAttr < nAttrCount; iAttr++ )
784 : {
785 3 : int nAttrId = poRecord->GetIntSubfield("ATTF",0,"ATTL",iAttr);
786 : const char *pszAcronym;
787 :
788 3 : 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 3 : pszValue = poRecord->GetStringSubfield("ATTF",0,"ATVL",iAttr);
809 :
810 : /* Apply to feature in an appropriate way */
811 : int iField;
812 : OGRFieldDefn *poFldDefn;
813 :
814 3 : iField = poFeature->GetDefnRef()->GetFieldIndex(pszAcronym);
815 3 : 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 3 : poFldDefn = poFeature->GetDefnRef()->GetFieldDefn( iField );
829 3 : if( poFldDefn->GetType() == OFTInteger
830 : || poFldDefn->GetType() == OFTReal )
831 : {
832 1 : 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 0 : poFeature->SetField( iField, pszValue );
841 : }
842 : else
843 2 : poFeature->SetField( iField, pszValue );
844 : }
845 :
846 : /* -------------------------------------------------------------------- */
847 : /* NATF (national) attributes */
848 : /* -------------------------------------------------------------------- */
849 3 : DDFField *poNATF = poRecord->FindField( "NATF" );
850 :
851 3 : if( poNATF == NULL )
852 2 : 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 4 : 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 4 : poFeature->GetFieldAsInteger( "FIDS" ) );
902 4 : poFeature->SetField( "LNAM", szLNAM );
903 :
904 : /* -------------------------------------------------------------------- */
905 : /* Do we have references to other features. */
906 : /* -------------------------------------------------------------------- */
907 : DDFField *poFFPT;
908 :
909 4 : poFFPT = poRecord->FindField( "FFPT" );
910 :
911 4 : if( poFFPT == NULL )
912 4 : return;
913 :
914 : /* -------------------------------------------------------------------- */
915 : /* Apply references. */
916 : /* -------------------------------------------------------------------- */
917 0 : int nRefCount = poFFPT->GetRepeatCount();
918 : DDFSubfieldDefn *poLNAM;
919 0 : char **papszRefs = NULL;
920 0 : int *panRIND = (int *) CPLMalloc(sizeof(int) * nRefCount);
921 :
922 0 : poLNAM = poFFPT->GetFieldDefn()->FindSubfieldDefn( "LNAM" );
923 0 : if( poLNAM == NULL )
924 0 : return;
925 :
926 0 : for( int iRef = 0; iRef < nRefCount; iRef++ )
927 : {
928 : unsigned char *pabyData;
929 :
930 : pabyData = (unsigned char *)
931 0 : poFFPT->GetSubfieldData( poLNAM, NULL, iRef );
932 :
933 : sprintf( szLNAM, "%02X%02X%02X%02X%02X%02X%02X%02X",
934 0 : pabyData[1], pabyData[0], /* AGEN */
935 0 : pabyData[5], pabyData[4], pabyData[3], pabyData[2], /* FIDN */
936 0 : pabyData[7], pabyData[6] );
937 :
938 0 : papszRefs = CSLAddString( papszRefs, szLNAM );
939 :
940 0 : panRIND[iRef] = pabyData[8];
941 : }
942 :
943 0 : poFeature->SetField( "LNAM_REFS", papszRefs );
944 0 : CSLDestroy( papszRefs );
945 :
946 0 : poFeature->SetField( "FFPT_RIND", nRefCount, panRIND );
947 0 : 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 : 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 : 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 : 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 && poRecord->FindField( "SG2D" ) != NULL )
1280 : {
1281 0 : int i, nVCount = poRecord->FindField("SG2D")->GetRepeatCount();
1282 0 : OGRLineString *poLine = new OGRLineString();
1283 :
1284 0 : poLine->setNumPoints( nVCount );
1285 :
1286 0 : for( i = 0; i < nVCount; i++ )
1287 : {
1288 : poLine->setPoint(
1289 : i,
1290 : poRecord->GetIntSubfield("SG2D",0,"XCOO",i) / (double)nCOMF,
1291 0 : poRecord->GetIntSubfield("SG2D",0,"YCOO",i) / (double)nCOMF );
1292 : }
1293 0 : poFeature->SetGeometryDirectly( poLine );
1294 : }
1295 :
1296 : /* -------------------------------------------------------------------- */
1297 : /* Special edge fields. */
1298 : /* -------------------------------------------------------------------- */
1299 : DDFField *poVRPT;
1300 :
1301 0 : if( nRCNM == RCNM_VE
1302 : && (poVRPT = poRecord->FindField( "VRPT" )) != NULL )
1303 : {
1304 0 : poFeature->SetField( "NAME_RCNM_0", RCNM_VC );
1305 0 : poFeature->SetField( "NAME_RCID_0", ParseName( poVRPT, 0 ) );
1306 : poFeature->SetField( "ORNT_0",
1307 0 : poRecord->GetIntSubfield("VRPT",0,"ORNT",0) );
1308 : poFeature->SetField( "USAG_0",
1309 0 : poRecord->GetIntSubfield("VRPT",0,"USAG",0) );
1310 : poFeature->SetField( "TOPI_0",
1311 0 : poRecord->GetIntSubfield("VRPT",0,"TOPI",0) );
1312 : poFeature->SetField( "MASK_0",
1313 0 : poRecord->GetIntSubfield("VRPT",0,"MASK",0) );
1314 :
1315 :
1316 0 : poFeature->SetField( "NAME_RCNM_1", RCNM_VC );
1317 0 : poFeature->SetField( "NAME_RCID_1", ParseName( poVRPT, 1 ) );
1318 : poFeature->SetField( "ORNT_1",
1319 0 : poRecord->GetIntSubfield("VRPT",0,"ORNT",1) );
1320 : poFeature->SetField( "USAG_1",
1321 0 : poRecord->GetIntSubfield("VRPT",0,"USAG",1) );
1322 : poFeature->SetField( "TOPI_1",
1323 0 : poRecord->GetIntSubfield("VRPT",0,"TOPI",1) );
1324 : poFeature->SetField( "MASK_1",
1325 0 : poRecord->GetIntSubfield("VRPT",0,"MASK",1) );
1326 : }
1327 :
1328 0 : return poFeature;
1329 : }
1330 :
1331 : /************************************************************************/
1332 : /* FetchPoint() */
1333 : /* */
1334 : /* Fetch the location of a spatial point object. */
1335 : /************************************************************************/
1336 :
1337 29 : int S57Reader::FetchPoint( int nRCNM, int nRCID,
1338 : double * pdfX, double * pdfY, double * pdfZ )
1339 :
1340 : {
1341 : DDFRecord *poSRecord;
1342 :
1343 29 : if( nRCNM == RCNM_VI )
1344 0 : poSRecord = oVI_Index.FindRecord( nRCID );
1345 : else
1346 29 : poSRecord = oVC_Index.FindRecord( nRCID );
1347 :
1348 29 : if( poSRecord == NULL )
1349 0 : return FALSE;
1350 :
1351 29 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1352 :
1353 29 : if( poSRecord->FindField( "SG2D" ) != NULL )
1354 : {
1355 29 : dfX = poSRecord->GetIntSubfield("SG2D",0,"XCOO",0) / (double)nCOMF;
1356 29 : dfY = poSRecord->GetIntSubfield("SG2D",0,"YCOO",0) / (double)nCOMF;
1357 : }
1358 0 : else if( poSRecord->FindField( "SG3D" ) != NULL )
1359 : {
1360 0 : dfX = poSRecord->GetIntSubfield("SG3D",0,"XCOO",0) / (double)nCOMF;
1361 0 : dfY = poSRecord->GetIntSubfield("SG3D",0,"YCOO",0) / (double)nCOMF;
1362 0 : dfZ = poSRecord->GetIntSubfield("SG3D",0,"VE3D",0) / (double)nSOMF;
1363 : }
1364 : else
1365 0 : return FALSE;
1366 :
1367 29 : if( pdfX != NULL )
1368 29 : *pdfX = dfX;
1369 29 : if( pdfY != NULL )
1370 29 : *pdfY = dfY;
1371 29 : if( pdfZ != NULL )
1372 0 : *pdfZ = dfZ;
1373 :
1374 29 : return TRUE;
1375 : }
1376 :
1377 : /************************************************************************/
1378 : /* S57StrokeArcToOGRGeometry_Angles() */
1379 : /************************************************************************/
1380 :
1381 : static OGRLineString *
1382 0 : S57StrokeArcToOGRGeometry_Angles( double dfCenterX, double dfCenterY,
1383 : double dfRadius,
1384 : double dfStartAngle, double dfEndAngle,
1385 : int nVertexCount )
1386 :
1387 : {
1388 0 : OGRLineString *poLine = new OGRLineString;
1389 : double dfArcX, dfArcY, dfSlice;
1390 : int iPoint;
1391 :
1392 0 : nVertexCount = MAX(2,nVertexCount);
1393 0 : dfSlice = (dfEndAngle-dfStartAngle)/(nVertexCount-1);
1394 :
1395 0 : poLine->setNumPoints( nVertexCount );
1396 :
1397 0 : for( iPoint=0; iPoint < nVertexCount; iPoint++ )
1398 : {
1399 : double dfAngle;
1400 :
1401 0 : dfAngle = (dfStartAngle + iPoint * dfSlice) * PI / 180.0;
1402 :
1403 0 : dfArcX = dfCenterX + cos(dfAngle) * dfRadius;
1404 0 : dfArcY = dfCenterY + sin(dfAngle) * dfRadius;
1405 :
1406 0 : poLine->setPoint( iPoint, dfArcX, dfArcY );
1407 : }
1408 :
1409 0 : return poLine;
1410 : }
1411 :
1412 :
1413 : /************************************************************************/
1414 : /* S57StrokeArcToOGRGeometry_Points() */
1415 : /************************************************************************/
1416 :
1417 : static OGRLineString *
1418 0 : S57StrokeArcToOGRGeometry_Points( double dfStartX, double dfStartY,
1419 : double dfCenterX, double dfCenterY,
1420 : double dfEndX, double dfEndY,
1421 : int nVertexCount )
1422 :
1423 : {
1424 : double dfStartAngle, dfEndAngle;
1425 : double dfRadius;
1426 :
1427 0 : if( dfStartX == dfEndX && dfStartY == dfEndY )
1428 : {
1429 0 : dfStartAngle = 0.0;
1430 0 : dfEndAngle = 360.0;
1431 : }
1432 : else
1433 : {
1434 : double dfDeltaX, dfDeltaY;
1435 :
1436 0 : dfDeltaX = dfStartX - dfCenterX;
1437 0 : dfDeltaY = dfStartY - dfCenterY;
1438 0 : dfStartAngle = atan2(dfDeltaY,dfDeltaX) * 180.0 / PI;
1439 :
1440 0 : dfDeltaX = dfEndX - dfCenterX;
1441 0 : dfDeltaY = dfEndY - dfCenterY;
1442 0 : dfEndAngle = atan2(dfDeltaY,dfDeltaX) * 180.0 / PI;
1443 :
1444 : #ifdef notdef
1445 : if( dfStartAngle > dfAlongAngle && dfAlongAngle > dfEndAngle )
1446 : {
1447 : double dfTempAngle;
1448 :
1449 : dfTempAngle = dfStartAngle;
1450 : dfStartAngle = dfEndAngle;
1451 : dfEndAngle = dfTempAngle;
1452 : }
1453 : #endif
1454 :
1455 0 : while( dfStartAngle < dfEndAngle )
1456 0 : dfStartAngle += 360.0;
1457 :
1458 : // while( dfAlongAngle < dfStartAngle )
1459 : // dfAlongAngle += 360.0;
1460 :
1461 : // while( dfEndAngle < dfAlongAngle )
1462 : // dfEndAngle += 360.0;
1463 :
1464 0 : if( dfEndAngle - dfStartAngle > 360.0 )
1465 : {
1466 : double dfTempAngle;
1467 :
1468 0 : dfTempAngle = dfStartAngle;
1469 0 : dfStartAngle = dfEndAngle;
1470 0 : dfEndAngle = dfTempAngle;
1471 :
1472 0 : while( dfEndAngle < dfStartAngle )
1473 0 : dfStartAngle -= 360.0;
1474 : }
1475 : }
1476 :
1477 : dfRadius = sqrt( (dfCenterX - dfStartX) * (dfCenterX - dfStartX)
1478 0 : + (dfCenterY - dfStartY) * (dfCenterY - dfStartY) );
1479 :
1480 : return S57StrokeArcToOGRGeometry_Angles( dfCenterX, dfCenterY,
1481 : dfRadius,
1482 : dfStartAngle, dfEndAngle,
1483 0 : nVertexCount );
1484 : }
1485 :
1486 : /************************************************************************/
1487 : /* FetchLine() */
1488 : /************************************************************************/
1489 :
1490 13 : int S57Reader::FetchLine( DDFRecord *poSRecord,
1491 : int iStartVertex, int iDirection,
1492 : OGRLineString *poLine )
1493 :
1494 : {
1495 : int nVCount;
1496 13 : DDFField *poSG2D = poSRecord->FindField( "SG2D" );
1497 13 : DDFField *poAR2D = poSRecord->FindField( "AR2D" );
1498 13 : DDFSubfieldDefn *poXCOO=NULL, *poYCOO=NULL;
1499 13 : int bStandardFormat = TRUE;
1500 :
1501 13 : if( poSG2D == NULL && poAR2D != NULL )
1502 0 : poSG2D = poAR2D;
1503 :
1504 : /* -------------------------------------------------------------------- */
1505 : /* Get some basic definitions. */
1506 : /* -------------------------------------------------------------------- */
1507 13 : if( poSG2D != NULL )
1508 : {
1509 4 : poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
1510 4 : poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
1511 :
1512 4 : if( poXCOO == NULL || poYCOO == NULL )
1513 : {
1514 0 : CPLDebug( "S57", "XCOO or YCOO are NULL" );
1515 0 : return FALSE;
1516 : }
1517 :
1518 4 : nVCount = poSG2D->GetRepeatCount();
1519 : }
1520 : else
1521 : {
1522 9 : return TRUE;
1523 : }
1524 :
1525 : /* -------------------------------------------------------------------- */
1526 : /* It is legitimate to have zero vertices for line segments */
1527 : /* that just have the start and end node (bug 840). */
1528 : /* -------------------------------------------------------------------- */
1529 4 : if( nVCount == 0 )
1530 0 : return TRUE;
1531 :
1532 : /* -------------------------------------------------------------------- */
1533 : /* Make sure out line is long enough to hold all the vertices */
1534 : /* we will apply. */
1535 : /* -------------------------------------------------------------------- */
1536 : int nVBase;
1537 :
1538 4 : if( iDirection < 0 )
1539 0 : nVBase = iStartVertex + nVCount;
1540 : else
1541 4 : nVBase = iStartVertex;
1542 :
1543 4 : if( poLine->getNumPoints() < iStartVertex + nVCount )
1544 4 : poLine->setNumPoints( iStartVertex + nVCount );
1545 :
1546 : /* -------------------------------------------------------------------- */
1547 : /* Are the SG2D and XCOO/YCOO definitions in the form we expect? */
1548 : /* -------------------------------------------------------------------- */
1549 4 : if( poSG2D->GetFieldDefn()->GetSubfieldCount() != 2 )
1550 0 : bStandardFormat = FALSE;
1551 :
1552 4 : if( !EQUAL(poXCOO->GetFormat(),"b24")
1553 : || !EQUAL(poYCOO->GetFormat(),"b24") )
1554 0 : bStandardFormat = FALSE;
1555 :
1556 : /* -------------------------------------------------------------------- */
1557 : /* Collect the vertices: */
1558 : /* */
1559 : /* This approach assumes that the data is LSB organized int32 */
1560 : /* binary data as per the specification. We avoid lots of */
1561 : /* extra calls to low level DDF methods as they are quite */
1562 : /* expensive. */
1563 : /* -------------------------------------------------------------------- */
1564 4 : if( bStandardFormat )
1565 : {
1566 : const char *pachData;
1567 : int nBytesRemaining;
1568 :
1569 4 : pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,0);
1570 :
1571 8 : for( int i = 0; i < nVCount; i++ )
1572 : {
1573 : double dfX, dfY;
1574 : GInt32 nXCOO, nYCOO;
1575 :
1576 4 : memcpy( &nYCOO, pachData, 4 );
1577 4 : pachData += 4;
1578 4 : memcpy( &nXCOO, pachData, 4 );
1579 4 : pachData += 4;
1580 :
1581 : #ifdef CPL_MSB
1582 : CPL_SWAP32PTR( &nXCOO );
1583 : CPL_SWAP32PTR( &nYCOO );
1584 : #endif
1585 4 : dfX = nXCOO / (double) nCOMF;
1586 4 : dfY = nYCOO / (double) nCOMF;
1587 :
1588 4 : poLine->setPoint( nVBase, dfX, dfY );
1589 :
1590 4 : nVBase += iDirection;
1591 : }
1592 : }
1593 :
1594 : /* -------------------------------------------------------------------- */
1595 : /* Collect the vertices: */
1596 : /* */
1597 : /* The generic case where we use low level but expensive DDF */
1598 : /* methods to get the data. This should work even if some */
1599 : /* things are changed about the SG2D fields such as making them */
1600 : /* floating point or a different byte order. */
1601 : /* -------------------------------------------------------------------- */
1602 : else
1603 : {
1604 0 : for( int i = 0; i < nVCount; i++ )
1605 : {
1606 : double dfX, dfY;
1607 : const char *pachData;
1608 : int nBytesRemaining;
1609 :
1610 0 : pachData = poSG2D->GetSubfieldData(poXCOO,&nBytesRemaining,i);
1611 :
1612 : dfX = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1613 0 : / (double) nCOMF;
1614 :
1615 0 : pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,i);
1616 :
1617 : dfY = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1618 0 : / (double) nCOMF;
1619 :
1620 0 : poLine->setPoint( nVBase, dfX, dfY );
1621 :
1622 0 : nVBase += iDirection;
1623 : }
1624 : }
1625 :
1626 : /* -------------------------------------------------------------------- */
1627 : /* If this is actually an arc, turn the start, end and center */
1628 : /* of rotation into a "stroked" arc linestring. */
1629 : /* -------------------------------------------------------------------- */
1630 4 : if( poAR2D != NULL && poLine->getNumPoints() >= 3 )
1631 : {
1632 : OGRLineString *poArc;
1633 0 : int i, iLast = poLine->getNumPoints() - 1;
1634 :
1635 : poArc = S57StrokeArcToOGRGeometry_Points(
1636 : poLine->getX(iLast-0), poLine->getY(iLast-0),
1637 : poLine->getX(iLast-1), poLine->getY(iLast-1),
1638 : poLine->getX(iLast-2), poLine->getY(iLast-2),
1639 0 : 30 );
1640 :
1641 0 : if( poArc != NULL )
1642 : {
1643 0 : for( i = 0; i < poArc->getNumPoints(); i++ )
1644 0 : poLine->setPoint( iLast-2+i, poArc->getX(i), poArc->getY(i) );
1645 :
1646 0 : delete poArc;
1647 : }
1648 : }
1649 :
1650 4 : return TRUE;
1651 : }
1652 :
1653 : /************************************************************************/
1654 : /* AssemblePointGeometry() */
1655 : /************************************************************************/
1656 :
1657 1 : void S57Reader::AssemblePointGeometry( DDFRecord * poFRecord,
1658 : OGRFeature * poFeature )
1659 :
1660 : {
1661 : DDFField *poFSPT;
1662 : int nRCNM, nRCID;
1663 :
1664 : /* -------------------------------------------------------------------- */
1665 : /* Feature the spatial record containing the point. */
1666 : /* -------------------------------------------------------------------- */
1667 1 : poFSPT = poFRecord->FindField( "FSPT" );
1668 1 : if( poFSPT == NULL )
1669 1 : return;
1670 :
1671 0 : if( poFSPT->GetRepeatCount() != 1 )
1672 : {
1673 : #ifdef DEBUG
1674 : fprintf( stderr,
1675 : "Point features with other than one spatial linkage.\n" );
1676 : poFRecord->Dump( stderr );
1677 : #endif
1678 : CPLDebug( "S57",
1679 0 : "Point feature encountered with other than one spatial linkage." );
1680 : }
1681 :
1682 0 : nRCID = ParseName( poFSPT, 0, &nRCNM );
1683 :
1684 0 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1685 :
1686 0 : if( !FetchPoint( nRCNM, nRCID, &dfX, &dfY, &dfZ ) )
1687 : {
1688 : CPLAssert( FALSE );
1689 0 : return;
1690 : }
1691 :
1692 0 : if( dfZ == 0.0 )
1693 0 : poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY ) );
1694 : else
1695 0 : poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1696 : }
1697 :
1698 : /************************************************************************/
1699 : /* AssembleSoundingGeometry() */
1700 : /************************************************************************/
1701 :
1702 1 : void S57Reader::AssembleSoundingGeometry( DDFRecord * poFRecord,
1703 : OGRFeature * poFeature )
1704 :
1705 : {
1706 : DDFField *poFSPT;
1707 : int nRCNM, nRCID;
1708 : DDFRecord *poSRecord;
1709 :
1710 :
1711 : /* -------------------------------------------------------------------- */
1712 : /* Feature the spatial record containing the point. */
1713 : /* -------------------------------------------------------------------- */
1714 1 : poFSPT = poFRecord->FindField( "FSPT" );
1715 1 : if( poFSPT == NULL )
1716 0 : return;
1717 :
1718 : CPLAssert( poFSPT->GetRepeatCount() == 1 );
1719 :
1720 1 : nRCID = ParseName( poFSPT, 0, &nRCNM );
1721 :
1722 1 : if( nRCNM == RCNM_VI )
1723 1 : poSRecord = oVI_Index.FindRecord( nRCID );
1724 : else
1725 0 : poSRecord = oVC_Index.FindRecord( nRCID );
1726 :
1727 1 : if( poSRecord == NULL )
1728 0 : return;
1729 :
1730 : /* -------------------------------------------------------------------- */
1731 : /* Extract vertices. */
1732 : /* -------------------------------------------------------------------- */
1733 1 : OGRMultiPoint *poMP = new OGRMultiPoint();
1734 : DDFField *poField;
1735 : int nPointCount, i, nBytesLeft;
1736 : DDFSubfieldDefn *poXCOO, *poYCOO, *poVE3D;
1737 : const char *pachData;
1738 :
1739 1 : poField = poSRecord->FindField( "SG2D" );
1740 1 : if( poField == NULL )
1741 1 : poField = poSRecord->FindField( "SG3D" );
1742 1 : if( poField == NULL )
1743 0 : return;
1744 :
1745 1 : poXCOO = poField->GetFieldDefn()->FindSubfieldDefn( "XCOO" );
1746 1 : poYCOO = poField->GetFieldDefn()->FindSubfieldDefn( "YCOO" );
1747 1 : poVE3D = poField->GetFieldDefn()->FindSubfieldDefn( "VE3D" );
1748 :
1749 1 : nPointCount = poField->GetRepeatCount();
1750 :
1751 1 : pachData = poField->GetData();
1752 1 : nBytesLeft = poField->GetDataSize();
1753 :
1754 10 : for( i = 0; i < nPointCount; i++ )
1755 : {
1756 4 : double dfX, dfY, dfZ = 0.0;
1757 : int nBytesConsumed;
1758 :
1759 : dfY = poYCOO->ExtractIntData( pachData, nBytesLeft,
1760 4 : &nBytesConsumed ) / (double) nCOMF;
1761 4 : nBytesLeft -= nBytesConsumed;
1762 4 : pachData += nBytesConsumed;
1763 :
1764 : dfX = poXCOO->ExtractIntData( pachData, nBytesLeft,
1765 4 : &nBytesConsumed ) / (double) nCOMF;
1766 4 : nBytesLeft -= nBytesConsumed;
1767 4 : pachData += nBytesConsumed;
1768 :
1769 4 : if( poVE3D != NULL )
1770 : {
1771 : dfZ = poYCOO->ExtractIntData( pachData, nBytesLeft,
1772 4 : &nBytesConsumed ) / (double) nSOMF;
1773 4 : nBytesLeft -= nBytesConsumed;
1774 4 : pachData += nBytesConsumed;
1775 : }
1776 :
1777 4 : poMP->addGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
1778 : }
1779 :
1780 1 : poFeature->SetGeometryDirectly( poMP );
1781 : }
1782 :
1783 : /************************************************************************/
1784 : /* AssembleLineGeometry() */
1785 : /************************************************************************/
1786 :
1787 1 : void S57Reader::AssembleLineGeometry( DDFRecord * poFRecord,
1788 : OGRFeature * poFeature )
1789 :
1790 : {
1791 : DDFField *poFSPT;
1792 : int nEdgeCount;
1793 1 : OGRLineString *poLine = new OGRLineString();
1794 :
1795 : /* -------------------------------------------------------------------- */
1796 : /* Find the FSPT field. */
1797 : /* -------------------------------------------------------------------- */
1798 1 : poFSPT = poFRecord->FindField( "FSPT" );
1799 1 : if( poFSPT == NULL )
1800 0 : return;
1801 :
1802 1 : nEdgeCount = poFSPT->GetRepeatCount();
1803 :
1804 : /* ==================================================================== */
1805 : /* Loop collecting edges. */
1806 : /* ==================================================================== */
1807 3 : for( int iEdge = 0; iEdge < nEdgeCount; iEdge++ )
1808 : {
1809 : DDFRecord *poSRecord;
1810 : int nRCID;
1811 :
1812 : /* -------------------------------------------------------------------- */
1813 : /* Find the spatial record for this edge. */
1814 : /* -------------------------------------------------------------------- */
1815 2 : nRCID = ParseName( poFSPT, iEdge );
1816 :
1817 2 : poSRecord = oVE_Index.FindRecord( nRCID );
1818 2 : if( poSRecord == NULL )
1819 : {
1820 : CPLError( CE_Warning, CPLE_AppDefined,
1821 : "Couldn't find spatial record %d.\n"
1822 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1823 : "missing geometry.",
1824 : nRCID,
1825 : poFeature->GetDefnRef()->GetName(),
1826 0 : poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
1827 0 : continue;
1828 : }
1829 :
1830 : /* -------------------------------------------------------------------- */
1831 : /* Establish the number of vertices, and whether we need to */
1832 : /* reverse or not. */
1833 : /* -------------------------------------------------------------------- */
1834 : int nVCount;
1835 : int nStart, nEnd, nInc;
1836 2 : DDFField *poSG2D = poSRecord->FindField( "SG2D" );
1837 2 : DDFField *poAR2D = poSRecord->FindField( "AR2D" );
1838 2 : DDFSubfieldDefn *poXCOO=NULL, *poYCOO=NULL;
1839 :
1840 2 : if( poSG2D == NULL && poAR2D != NULL )
1841 0 : poSG2D = poAR2D;
1842 :
1843 2 : if( poSG2D != NULL )
1844 : {
1845 2 : poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
1846 2 : poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
1847 :
1848 2 : nVCount = poSG2D->GetRepeatCount();
1849 : }
1850 : else
1851 0 : nVCount = 0;
1852 :
1853 2 : if( poFRecord->GetIntSubfield( "FSPT", 0, "ORNT", iEdge ) == 2 )
1854 : {
1855 0 : nStart = nVCount-1;
1856 0 : nEnd = 0;
1857 0 : nInc = -1;
1858 : }
1859 : else
1860 : {
1861 2 : nStart = 0;
1862 2 : nEnd = nVCount-1;
1863 2 : nInc = 1;
1864 : }
1865 :
1866 : /* -------------------------------------------------------------------- */
1867 : /* Add the start node, if this is the first edge. */
1868 : /* -------------------------------------------------------------------- */
1869 2 : if( iEdge == 0 )
1870 : {
1871 : int nVC_RCID;
1872 : double dfX, dfY;
1873 :
1874 1 : if( nInc == 1 )
1875 1 : nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 0 );
1876 : else
1877 0 : nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 1 );
1878 :
1879 1 : if( FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
1880 1 : poLine->addPoint( dfX, dfY );
1881 : else
1882 : CPLError( CE_Warning, CPLE_AppDefined,
1883 : "Unable to fetch start node RCID%d.\n"
1884 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1885 : " missing geometry.",
1886 : nVC_RCID,
1887 : poFeature->GetDefnRef()->GetName(),
1888 0 : poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
1889 : }
1890 :
1891 : /* -------------------------------------------------------------------- */
1892 : /* Collect the vertices. */
1893 : /* -------------------------------------------------------------------- */
1894 2 : int nVBase = poLine->getNumPoints();
1895 :
1896 2 : poLine->setNumPoints( nVCount+nVBase );
1897 :
1898 14 : for( int i = nStart; i != nEnd+nInc; i += nInc )
1899 : {
1900 : double dfX, dfY;
1901 : const char *pachData;
1902 : int nBytesRemaining;
1903 :
1904 12 : pachData = poSG2D->GetSubfieldData(poXCOO,&nBytesRemaining,i);
1905 :
1906 : dfX = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1907 12 : / (double) nCOMF;
1908 :
1909 12 : pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,i);
1910 :
1911 : dfY = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
1912 12 : / (double) nCOMF;
1913 :
1914 12 : poLine->setPoint( nVBase++, dfX, dfY );
1915 : }
1916 :
1917 : /* -------------------------------------------------------------------- */
1918 : /* Add the end node. */
1919 : /* -------------------------------------------------------------------- */
1920 : {
1921 : int nVC_RCID;
1922 : double dfX, dfY;
1923 :
1924 2 : if( nInc == 1 )
1925 2 : nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 1 );
1926 : else
1927 0 : nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 0 );
1928 :
1929 2 : if( FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
1930 2 : poLine->addPoint( dfX, dfY );
1931 : else
1932 : CPLError( CE_Warning, CPLE_AppDefined,
1933 : "Unable to fetch end node RCID=%d.\n"
1934 : "Feature OBJL=%s, RCID=%d may have corrupt or"
1935 : " missing geometry.",
1936 : nVC_RCID,
1937 : poFeature->GetDefnRef()->GetName(),
1938 0 : poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
1939 : }
1940 : }
1941 :
1942 1 : if( poLine->getNumPoints() >= 2 )
1943 1 : poFeature->SetGeometryDirectly( poLine );
1944 : else
1945 0 : delete poLine;
1946 : }
1947 :
1948 : /************************************************************************/
1949 : /* AssembleAreaGeometry() */
1950 : /************************************************************************/
1951 :
1952 1 : void S57Reader::AssembleAreaGeometry( DDFRecord * poFRecord,
1953 : OGRFeature * poFeature )
1954 :
1955 : {
1956 : DDFField *poFSPT;
1957 1 : OGRGeometryCollection * poLines = new OGRGeometryCollection();
1958 :
1959 : /* -------------------------------------------------------------------- */
1960 : /* Find the FSPT fields. */
1961 : /* -------------------------------------------------------------------- */
1962 2 : for( int iFSPT = 0;
1963 : (poFSPT = poFRecord->FindField( "FSPT", iFSPT )) != NULL;
1964 : iFSPT++ )
1965 : {
1966 : int nEdgeCount;
1967 :
1968 1 : nEdgeCount = poFSPT->GetRepeatCount();
1969 :
1970 : /* ==================================================================== */
1971 : /* Loop collecting edges. */
1972 : /* ==================================================================== */
1973 14 : for( int iEdge = 0; iEdge < nEdgeCount; iEdge++ )
1974 : {
1975 : DDFRecord *poSRecord;
1976 : int nRCID;
1977 :
1978 : /* -------------------------------------------------------------------- */
1979 : /* Find the spatial record for this edge. */
1980 : /* -------------------------------------------------------------------- */
1981 13 : nRCID = ParseName( poFSPT, iEdge );
1982 :
1983 13 : poSRecord = oVE_Index.FindRecord( nRCID );
1984 13 : if( poSRecord == NULL )
1985 : {
1986 : CPLError( CE_Warning, CPLE_AppDefined,
1987 0 : "Couldn't find spatial record %d.\n", nRCID );
1988 0 : continue;
1989 : }
1990 :
1991 : /* -------------------------------------------------------------------- */
1992 : /* Create the line string. */
1993 : /* -------------------------------------------------------------------- */
1994 13 : OGRLineString *poLine = new OGRLineString();
1995 :
1996 : /* -------------------------------------------------------------------- */
1997 : /* Add the start node. */
1998 : /* -------------------------------------------------------------------- */
1999 : {
2000 : int nVC_RCID;
2001 : double dfX, dfY;
2002 :
2003 13 : nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 0 );
2004 :
2005 13 : if( FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
2006 13 : poLine->addPoint( dfX, dfY );
2007 : }
2008 :
2009 : /* -------------------------------------------------------------------- */
2010 : /* Collect the vertices. */
2011 : /* -------------------------------------------------------------------- */
2012 13 : if( !FetchLine( poSRecord, poLine->getNumPoints(), 1, poLine ) )
2013 : {
2014 0 : CPLDebug( "S57", "FetchLine() failed in AssembleAreaGeometry()!" );
2015 : }
2016 :
2017 :
2018 : /* -------------------------------------------------------------------- */
2019 : /* Add the end node. */
2020 : /* -------------------------------------------------------------------- */
2021 : {
2022 : int nVC_RCID;
2023 : double dfX, dfY;
2024 :
2025 13 : nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 1 );
2026 :
2027 13 : if( FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
2028 13 : poLine->addPoint( dfX, dfY );
2029 : }
2030 :
2031 13 : poLines->addGeometryDirectly( poLine );
2032 : }
2033 : }
2034 :
2035 : /* -------------------------------------------------------------------- */
2036 : /* Build lines into a polygon. */
2037 : /* -------------------------------------------------------------------- */
2038 : OGRPolygon *poPolygon;
2039 : OGRErr eErr;
2040 :
2041 : poPolygon = (OGRPolygon *)
2042 : OGRBuildPolygonFromEdges( (OGRGeometryH) poLines,
2043 1 : TRUE, FALSE, 0.0, &eErr );
2044 1 : if( eErr != OGRERR_NONE )
2045 : {
2046 : CPLError( CE_Warning, CPLE_AppDefined,
2047 : "Polygon assembly has failed for feature FIDN=%d,FIDS=%d.\n"
2048 : "Geometry may be missing or incomplete.",
2049 : poFeature->GetFieldAsInteger( "FIDN" ),
2050 0 : poFeature->GetFieldAsInteger( "FIDS" ) );
2051 : }
2052 :
2053 1 : delete poLines;
2054 :
2055 1 : if( poPolygon != NULL )
2056 1 : poFeature->SetGeometryDirectly( poPolygon );
2057 1 : }
2058 :
2059 : /************************************************************************/
2060 : /* FindFDefn() */
2061 : /* */
2062 : /* Find the OGRFeatureDefn corresponding to the passed feature */
2063 : /* record. It will search based on geometry class, or object */
2064 : /* class depending on the bClassBased setting. */
2065 : /************************************************************************/
2066 :
2067 90 : OGRFeatureDefn * S57Reader::FindFDefn( DDFRecord * poRecord )
2068 :
2069 : {
2070 90 : if( poRegistrar != NULL )
2071 : {
2072 90 : int nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
2073 :
2074 90 : if( apoFDefnByOBJL[nOBJL] != NULL )
2075 90 : return apoFDefnByOBJL[nOBJL];
2076 :
2077 0 : if( !poRegistrar->SelectClass( nOBJL ) )
2078 : {
2079 0 : for( int i = 0; i < nFDefnCount; i++ )
2080 : {
2081 0 : if( EQUAL(papoFDefnList[i]->GetName(),"Generic") )
2082 0 : return papoFDefnList[i];
2083 : }
2084 0 : return NULL;
2085 : }
2086 :
2087 0 : for( int i = 0; i < nFDefnCount; i++ )
2088 : {
2089 0 : if( EQUAL(papoFDefnList[i]->GetName(),
2090 : poRegistrar->GetAcronym()) )
2091 0 : return papoFDefnList[i];
2092 : }
2093 :
2094 0 : return NULL;
2095 : }
2096 : else
2097 : {
2098 0 : int nPRIM = poRecord->GetIntSubfield( "FRID", 0, "PRIM", 0 );
2099 : OGRwkbGeometryType eGType;
2100 :
2101 0 : if( nPRIM == PRIM_P )
2102 0 : eGType = wkbPoint;
2103 0 : else if( nPRIM == PRIM_L )
2104 0 : eGType = wkbLineString;
2105 0 : else if( nPRIM == PRIM_A )
2106 0 : eGType = wkbPolygon;
2107 : else
2108 0 : eGType = wkbNone;
2109 :
2110 0 : for( int i = 0; i < nFDefnCount; i++ )
2111 : {
2112 0 : if( papoFDefnList[i]->GetGeomType() == eGType )
2113 0 : return papoFDefnList[i];
2114 : }
2115 : }
2116 :
2117 0 : return NULL;
2118 : }
2119 :
2120 : /************************************************************************/
2121 : /* ParseName() */
2122 : /* */
2123 : /* Pull the RCNM and RCID values from a NAME field. The RCID */
2124 : /* is returned and the RCNM can be gotten via the pnRCNM argument. */
2125 : /************************************************************************/
2126 :
2127 45 : int S57Reader::ParseName( DDFField * poField, int nIndex, int * pnRCNM )
2128 :
2129 : {
2130 : unsigned char *pabyData;
2131 :
2132 : pabyData = (unsigned char *)
2133 : poField->GetSubfieldData(
2134 : poField->GetFieldDefn()->FindSubfieldDefn( "NAME" ),
2135 45 : NULL, nIndex );
2136 :
2137 45 : if( pnRCNM != NULL )
2138 1 : *pnRCNM = pabyData[0];
2139 :
2140 45 : return pabyData[1]
2141 45 : + pabyData[2] * 256
2142 45 : + pabyData[3] * 256 * 256
2143 135 : + pabyData[4] * 256 * 256 * 256;
2144 : }
2145 :
2146 : /************************************************************************/
2147 : /* AddFeatureDefn() */
2148 : /************************************************************************/
2149 :
2150 23 : void S57Reader::AddFeatureDefn( OGRFeatureDefn * poFDefn )
2151 :
2152 : {
2153 23 : nFDefnCount++;
2154 : papoFDefnList = (OGRFeatureDefn **)
2155 23 : CPLRealloc(papoFDefnList, sizeof(OGRFeatureDefn*)*nFDefnCount );
2156 :
2157 23 : papoFDefnList[nFDefnCount-1] = poFDefn;
2158 :
2159 23 : if( poRegistrar != NULL )
2160 : {
2161 23 : if( poRegistrar->SelectClass( poFDefn->GetName() ) )
2162 21 : apoFDefnByOBJL[poRegistrar->GetOBJL()] = poFDefn;
2163 : }
2164 23 : }
2165 :
2166 : /************************************************************************/
2167 : /* CollectClassList() */
2168 : /* */
2169 : /* Establish the list of classes (unique OBJL values) that */
2170 : /* occur in this dataset. */
2171 : /************************************************************************/
2172 :
2173 2 : int S57Reader::CollectClassList(int *panClassCount, int nMaxClass )
2174 :
2175 : {
2176 2 : int bSuccess = TRUE;
2177 :
2178 2 : if( !bFileIngested && !Ingest() )
2179 0 : return FALSE;
2180 :
2181 90 : for( int iFEIndex = 0; iFEIndex < oFE_Index.GetCount(); iFEIndex++ )
2182 : {
2183 88 : DDFRecord *poRecord = oFE_Index.GetByIndex( iFEIndex );
2184 88 : int nOBJL = poRecord->GetIntSubfield( "FRID", 0, "OBJL", 0 );
2185 :
2186 88 : if( nOBJL >= nMaxClass )
2187 0 : bSuccess = FALSE;
2188 : else
2189 88 : panClassCount[nOBJL]++;
2190 :
2191 : }
2192 :
2193 2 : return bSuccess;
2194 : }
2195 :
2196 : /************************************************************************/
2197 : /* ApplyRecordUpdate() */
2198 : /* */
2199 : /* Update one target record based on an S-57 update record */
2200 : /* (RUIN=3). */
2201 : /************************************************************************/
2202 :
2203 0 : int S57Reader::ApplyRecordUpdate( DDFRecord *poTarget, DDFRecord *poUpdate )
2204 :
2205 : {
2206 0 : const char *pszKey = poUpdate->GetField(1)->GetFieldDefn()->GetName();
2207 :
2208 : /* -------------------------------------------------------------------- */
2209 : /* Validate versioning. */
2210 : /* -------------------------------------------------------------------- */
2211 0 : if( poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 ) + 1
2212 : != poUpdate->GetIntSubfield( pszKey, 0, "RVER", 0 ) )
2213 : {
2214 : CPLDebug( "S57",
2215 : "Mismatched RVER value on RCNM=%d,RCID=%d.\n",
2216 : poTarget->GetIntSubfield( pszKey, 0, "RCNM", 0 ),
2217 0 : poTarget->GetIntSubfield( pszKey, 0, "RCID", 0 ) );
2218 :
2219 : CPLAssert( FALSE );
2220 0 : return FALSE;
2221 : }
2222 :
2223 : /* -------------------------------------------------------------------- */
2224 : /* Update the target version. */
2225 : /* -------------------------------------------------------------------- */
2226 : unsigned char *pnRVER;
2227 0 : DDFField *poKey = poTarget->FindField( pszKey );
2228 : DDFSubfieldDefn *poRVER_SFD;
2229 :
2230 0 : if( poKey == NULL )
2231 : {
2232 : CPLAssert( FALSE );
2233 0 : return FALSE;
2234 : }
2235 :
2236 0 : poRVER_SFD = poKey->GetFieldDefn()->FindSubfieldDefn( "RVER" );
2237 0 : if( poRVER_SFD == NULL )
2238 0 : return FALSE;
2239 :
2240 0 : pnRVER = (unsigned char *) poKey->GetSubfieldData( poRVER_SFD, NULL, 0 );
2241 :
2242 0 : *pnRVER += 1;
2243 :
2244 : /* -------------------------------------------------------------------- */
2245 : /* Check for, and apply record record to spatial record pointer */
2246 : /* updates. */
2247 : /* -------------------------------------------------------------------- */
2248 0 : if( poUpdate->FindField( "FSPC" ) != NULL )
2249 : {
2250 0 : int nFSUI = poUpdate->GetIntSubfield( "FSPC", 0, "FSUI", 0 );
2251 0 : int nFSIX = poUpdate->GetIntSubfield( "FSPC", 0, "FSIX", 0 );
2252 0 : int nNSPT = poUpdate->GetIntSubfield( "FSPC", 0, "NSPT", 0 );
2253 0 : DDFField *poSrcFSPT = poUpdate->FindField( "FSPT" );
2254 0 : DDFField *poDstFSPT = poTarget->FindField( "FSPT" );
2255 : int nPtrSize;
2256 :
2257 0 : if( (poSrcFSPT == NULL && nFSUI != 2) || poDstFSPT == NULL )
2258 : {
2259 : CPLAssert( FALSE );
2260 0 : return FALSE;
2261 : }
2262 :
2263 0 : nPtrSize = poDstFSPT->GetFieldDefn()->GetFixedWidth();
2264 :
2265 0 : if( nFSUI == 1 ) /* INSERT */
2266 : {
2267 : char *pachInsertion;
2268 0 : int nInsertionBytes = nPtrSize * nNSPT;
2269 :
2270 0 : pachInsertion = (char *) CPLMalloc(nInsertionBytes + nPtrSize);
2271 0 : memcpy( pachInsertion, poSrcFSPT->GetData(), nInsertionBytes );
2272 :
2273 : /*
2274 : ** If we are inserting before an instance that already
2275 : ** exists, we must add it to the end of the data being
2276 : ** inserted.
2277 : */
2278 0 : if( nFSIX <= poDstFSPT->GetRepeatCount() )
2279 : {
2280 : memcpy( pachInsertion + nInsertionBytes,
2281 : poDstFSPT->GetData() + nPtrSize * (nFSIX-1),
2282 0 : nPtrSize );
2283 0 : nInsertionBytes += nPtrSize;
2284 : }
2285 :
2286 : poTarget->SetFieldRaw( poDstFSPT, nFSIX - 1,
2287 0 : pachInsertion, nInsertionBytes );
2288 0 : CPLFree( pachInsertion );
2289 : }
2290 0 : else if( nFSUI == 2 ) /* DELETE */
2291 : {
2292 : /* Wipe each deleted coordinate */
2293 0 : for( int i = nNSPT-1; i >= 0; i-- )
2294 : {
2295 0 : poTarget->SetFieldRaw( poDstFSPT, i + nFSIX - 1, NULL, 0 );
2296 : }
2297 : }
2298 0 : else if( nFSUI == 3 ) /* MODIFY */
2299 : {
2300 : /* copy over each ptr */
2301 0 : for( int i = 0; i < nNSPT; i++ )
2302 : {
2303 : const char *pachRawData;
2304 :
2305 0 : pachRawData = poSrcFSPT->GetData() + nPtrSize * i;
2306 : poTarget->SetFieldRaw( poDstFSPT, i + nFSIX - 1,
2307 0 : pachRawData, nPtrSize );
2308 : }
2309 : }
2310 : }
2311 :
2312 : /* -------------------------------------------------------------------- */
2313 : /* Check for, and apply vector record to vector record pointer */
2314 : /* updates. */
2315 : /* -------------------------------------------------------------------- */
2316 0 : if( poUpdate->FindField( "VRPC" ) != NULL )
2317 : {
2318 0 : int nVPUI = poUpdate->GetIntSubfield( "VRPC", 0, "VPUI", 0 );
2319 0 : int nVPIX = poUpdate->GetIntSubfield( "VRPC", 0, "VPIX", 0 );
2320 0 : int nNVPT = poUpdate->GetIntSubfield( "VRPC", 0, "NVPT", 0 );
2321 0 : DDFField *poSrcVRPT = poUpdate->FindField( "VRPT" );
2322 0 : DDFField *poDstVRPT = poTarget->FindField( "VRPT" );
2323 : int nPtrSize;
2324 :
2325 0 : if( (poSrcVRPT == NULL && nVPUI != 2) || poDstVRPT == NULL )
2326 : {
2327 : CPLAssert( FALSE );
2328 0 : return FALSE;
2329 : }
2330 :
2331 0 : nPtrSize = poDstVRPT->GetFieldDefn()->GetFixedWidth();
2332 :
2333 0 : if( nVPUI == 1 ) /* INSERT */
2334 : {
2335 : char *pachInsertion;
2336 0 : int nInsertionBytes = nPtrSize * nNVPT;
2337 :
2338 0 : pachInsertion = (char *) CPLMalloc(nInsertionBytes + nPtrSize);
2339 0 : memcpy( pachInsertion, poSrcVRPT->GetData(), nInsertionBytes );
2340 :
2341 : /*
2342 : ** If we are inserting before an instance that already
2343 : ** exists, we must add it to the end of the data being
2344 : ** inserted.
2345 : */
2346 0 : if( nVPIX <= poDstVRPT->GetRepeatCount() )
2347 : {
2348 : memcpy( pachInsertion + nInsertionBytes,
2349 : poDstVRPT->GetData() + nPtrSize * (nVPIX-1),
2350 0 : nPtrSize );
2351 0 : nInsertionBytes += nPtrSize;
2352 : }
2353 :
2354 : poTarget->SetFieldRaw( poDstVRPT, nVPIX - 1,
2355 0 : pachInsertion, nInsertionBytes );
2356 0 : CPLFree( pachInsertion );
2357 : }
2358 0 : else if( nVPUI == 2 ) /* DELETE */
2359 : {
2360 : /* Wipe each deleted coordinate */
2361 0 : for( int i = nNVPT-1; i >= 0; i-- )
2362 : {
2363 0 : poTarget->SetFieldRaw( poDstVRPT, i + nVPIX - 1, NULL, 0 );
2364 : }
2365 : }
2366 0 : else if( nVPUI == 3 ) /* MODIFY */
2367 : {
2368 : /* copy over each ptr */
2369 0 : for( int i = 0; i < nNVPT; i++ )
2370 : {
2371 : const char *pachRawData;
2372 :
2373 0 : pachRawData = poSrcVRPT->GetData() + nPtrSize * i;
2374 :
2375 : poTarget->SetFieldRaw( poDstVRPT, i + nVPIX - 1,
2376 0 : pachRawData, nPtrSize );
2377 : }
2378 : }
2379 : }
2380 :
2381 : /* -------------------------------------------------------------------- */
2382 : /* Check for, and apply record update to coordinates. */
2383 : /* -------------------------------------------------------------------- */
2384 0 : if( poUpdate->FindField( "SGCC" ) != NULL )
2385 : {
2386 0 : int nCCUI = poUpdate->GetIntSubfield( "SGCC", 0, "CCUI", 0 );
2387 0 : int nCCIX = poUpdate->GetIntSubfield( "SGCC", 0, "CCIX", 0 );
2388 0 : int nCCNC = poUpdate->GetIntSubfield( "SGCC", 0, "CCNC", 0 );
2389 0 : DDFField *poSrcSG2D = poUpdate->FindField( "SG2D" );
2390 0 : DDFField *poDstSG2D = poTarget->FindField( "SG2D" );
2391 : int nCoordSize;
2392 :
2393 : /* If we don't have SG2D, check for SG3D */
2394 0 : if( poDstSG2D == NULL )
2395 : {
2396 0 : poSrcSG2D = poUpdate->FindField( "SG3D" );
2397 0 : poDstSG2D = poTarget->FindField( "SG3D" );
2398 : }
2399 :
2400 0 : if( (poSrcSG2D == NULL && nCCUI != 2) || poDstSG2D == NULL )
2401 : {
2402 : CPLAssert( FALSE );
2403 0 : return FALSE;
2404 : }
2405 :
2406 0 : nCoordSize = poDstSG2D->GetFieldDefn()->GetFixedWidth();
2407 :
2408 0 : if( nCCUI == 1 ) /* INSERT */
2409 : {
2410 : char *pachInsertion;
2411 0 : int nInsertionBytes = nCoordSize * nCCNC;
2412 :
2413 0 : pachInsertion = (char *) CPLMalloc(nInsertionBytes + nCoordSize);
2414 0 : memcpy( pachInsertion, poSrcSG2D->GetData(), nInsertionBytes );
2415 :
2416 : /*
2417 : ** If we are inserting before an instance that already
2418 : ** exists, we must add it to the end of the data being
2419 : ** inserted.
2420 : */
2421 0 : if( nCCIX <= poDstSG2D->GetRepeatCount() )
2422 : {
2423 : memcpy( pachInsertion + nInsertionBytes,
2424 : poDstSG2D->GetData() + nCoordSize * (nCCIX-1),
2425 0 : nCoordSize );
2426 0 : nInsertionBytes += nCoordSize;
2427 : }
2428 :
2429 : poTarget->SetFieldRaw( poDstSG2D, nCCIX - 1,
2430 0 : pachInsertion, nInsertionBytes );
2431 0 : CPLFree( pachInsertion );
2432 :
2433 : }
2434 0 : else if( nCCUI == 2 ) /* DELETE */
2435 : {
2436 : /* Wipe each deleted coordinate */
2437 0 : for( int i = nCCNC-1; i >= 0; i-- )
2438 : {
2439 0 : poTarget->SetFieldRaw( poDstSG2D, i + nCCIX - 1, NULL, 0 );
2440 : }
2441 : }
2442 0 : else if( nCCUI == 3 ) /* MODIFY */
2443 : {
2444 : /* copy over each ptr */
2445 0 : for( int i = 0; i < nCCNC; i++ )
2446 : {
2447 : const char *pachRawData;
2448 :
2449 0 : pachRawData = poSrcSG2D->GetData() + nCoordSize * i;
2450 :
2451 : poTarget->SetFieldRaw( poDstSG2D, i + nCCIX - 1,
2452 0 : pachRawData, nCoordSize );
2453 : }
2454 : }
2455 : }
2456 :
2457 : /* -------------------------------------------------------------------- */
2458 : /* We don't currently handle FFPC (feature to feature linkage) */
2459 : /* issues, but we will at least report them when debugging. */
2460 : /* -------------------------------------------------------------------- */
2461 0 : if( poUpdate->FindField( "FFPC" ) != NULL )
2462 : {
2463 0 : CPLDebug( "S57", "Found FFPC, but not applying it." );
2464 : }
2465 :
2466 : /* -------------------------------------------------------------------- */
2467 : /* Check for and apply changes to attribute lists. */
2468 : /* -------------------------------------------------------------------- */
2469 0 : if( poUpdate->FindField( "ATTF" ) != NULL )
2470 : {
2471 : DDFSubfieldDefn *poSrcATVLDefn;
2472 0 : DDFField *poSrcATTF = poUpdate->FindField( "ATTF" );
2473 0 : DDFField *poDstATTF = poTarget->FindField( "ATTF" );
2474 0 : int nRepeatCount = poSrcATTF->GetRepeatCount();
2475 :
2476 0 : if( poDstATTF == NULL )
2477 : {
2478 : CPLError( CE_Warning, CPLE_AppDefined,
2479 0 : "Unable to apply ATTF change to target record without an ATTF field (see GDAL/OGR Bug #1648)" );
2480 0 : return FALSE;
2481 : }
2482 :
2483 0 : poSrcATVLDefn = poSrcATTF->GetFieldDefn()->FindSubfieldDefn( "ATVL" );
2484 :
2485 0 : for( int iAtt = 0; iAtt < nRepeatCount; iAtt++ )
2486 : {
2487 0 : int nATTL = poUpdate->GetIntSubfield( "ATTF", 0, "ATTL", iAtt );
2488 : int iTAtt, nDataBytes;
2489 : const char *pszRawData;
2490 :
2491 0 : for( iTAtt = poDstATTF->GetRepeatCount()-1; iTAtt >= 0; iTAtt-- )
2492 : {
2493 0 : if( poTarget->GetIntSubfield( "ATTF", 0, "ATTL", iTAtt )
2494 : == nATTL )
2495 0 : break;
2496 : }
2497 0 : if( iTAtt == -1 )
2498 0 : iTAtt = poDstATTF->GetRepeatCount();
2499 :
2500 0 : pszRawData = poSrcATTF->GetInstanceData( iAtt, &nDataBytes );
2501 0 : if( pszRawData[2] == 0x7f /* delete marker */ )
2502 : {
2503 0 : poTarget->SetFieldRaw( poDstATTF, iTAtt, NULL, 0 );
2504 : }
2505 : else
2506 : {
2507 : poTarget->SetFieldRaw( poDstATTF, iTAtt, pszRawData,
2508 0 : nDataBytes );
2509 : }
2510 : }
2511 : }
2512 :
2513 0 : return TRUE;
2514 : }
2515 :
2516 :
2517 : /************************************************************************/
2518 : /* ApplyUpdates() */
2519 : /* */
2520 : /* Read records from an update file, and apply them to the */
2521 : /* currently loaded index of features. */
2522 : /************************************************************************/
2523 :
2524 0 : int S57Reader::ApplyUpdates( DDFModule *poUpdateModule )
2525 :
2526 : {
2527 : DDFRecord *poRecord;
2528 :
2529 : /* -------------------------------------------------------------------- */
2530 : /* Ensure base file is loaded. */
2531 : /* -------------------------------------------------------------------- */
2532 0 : if( !bFileIngested && !Ingest() )
2533 0 : return FALSE;
2534 :
2535 : /* -------------------------------------------------------------------- */
2536 : /* Read records, and apply as updates. */
2537 : /* -------------------------------------------------------------------- */
2538 0 : CPLErrorReset();
2539 0 : while( (poRecord = poUpdateModule->ReadRecord()) != NULL )
2540 : {
2541 0 : DDFField *poKeyField = poRecord->GetField(1);
2542 0 : const char *pszKey = poKeyField->GetFieldDefn()->GetName();
2543 :
2544 0 : if( EQUAL(pszKey,"VRID") || EQUAL(pszKey,"FRID"))
2545 : {
2546 0 : int nRCNM = poRecord->GetIntSubfield( pszKey,0, "RCNM",0 );
2547 0 : int nRCID = poRecord->GetIntSubfield( pszKey,0, "RCID",0 );
2548 0 : int nRVER = poRecord->GetIntSubfield( pszKey,0, "RVER",0 );
2549 0 : int nRUIN = poRecord->GetIntSubfield( pszKey,0, "RUIN",0 );
2550 0 : DDFRecordIndex *poIndex = NULL;
2551 :
2552 0 : if( EQUAL(poKeyField->GetFieldDefn()->GetName(),"VRID") )
2553 : {
2554 0 : switch( nRCNM )
2555 : {
2556 : case RCNM_VI:
2557 0 : poIndex = &oVI_Index;
2558 0 : break;
2559 :
2560 : case RCNM_VC:
2561 0 : poIndex = &oVC_Index;
2562 0 : break;
2563 :
2564 : case RCNM_VE:
2565 0 : poIndex = &oVE_Index;
2566 0 : break;
2567 :
2568 : case RCNM_VF:
2569 0 : poIndex = &oVF_Index;
2570 : break;
2571 :
2572 : default:
2573 : CPLAssert( FALSE );
2574 : break;
2575 : }
2576 : }
2577 : else
2578 : {
2579 0 : poIndex = &oFE_Index;
2580 : }
2581 :
2582 0 : if( poIndex != NULL )
2583 : {
2584 0 : if( nRUIN == 1 ) /* insert */
2585 : {
2586 0 : poIndex->AddRecord( nRCID, poRecord->CloneOn(poModule) );
2587 : }
2588 0 : else if( nRUIN == 2 ) /* delete */
2589 : {
2590 : DDFRecord *poTarget;
2591 :
2592 0 : poTarget = poIndex->FindRecord( nRCID );
2593 0 : if( poTarget == NULL )
2594 : {
2595 : CPLError( CE_Warning, CPLE_AppDefined,
2596 : "Can't find RCNM=%d,RCID=%d for delete.\n",
2597 0 : nRCNM, nRCID );
2598 : }
2599 0 : else if( poTarget->GetIntSubfield( pszKey, 0, "RVER", 0 )
2600 : != nRVER - 1 )
2601 : {
2602 : CPLError( CE_Warning, CPLE_AppDefined,
2603 : "Mismatched RVER value on RCNM=%d,RCID=%d.\n",
2604 0 : nRCNM, nRCID );
2605 : }
2606 : else
2607 : {
2608 0 : poIndex->RemoveRecord( nRCID );
2609 : }
2610 : }
2611 :
2612 0 : else if( nRUIN == 3 ) /* modify in place */
2613 : {
2614 : DDFRecord *poTarget;
2615 :
2616 0 : poTarget = poIndex->FindRecord( nRCID );
2617 0 : if( poTarget == NULL )
2618 : {
2619 : CPLError( CE_Warning, CPLE_AppDefined,
2620 : "Can't find RCNM=%d,RCID=%d for update.\n",
2621 0 : nRCNM, nRCID );
2622 : }
2623 : else
2624 : {
2625 0 : if( !ApplyRecordUpdate( poTarget, poRecord ) )
2626 : {
2627 : CPLError( CE_Warning, CPLE_AppDefined,
2628 : "An update to RCNM=%d,RCID=%d failed.\n",
2629 0 : nRCNM, nRCID );
2630 : }
2631 : }
2632 : }
2633 : }
2634 : }
2635 :
2636 0 : else if( EQUAL(pszKey,"DSID") )
2637 : {
2638 0 : if( poDSIDRecord != NULL )
2639 : {
2640 : strcpy( szUPDNUpdate,
2641 0 : poRecord->GetStringSubfield( "DSID", 0, "UPDN", 0 ) );
2642 : }
2643 : }
2644 :
2645 : else
2646 : {
2647 : CPLDebug( "S57",
2648 : "Skipping %s record in S57Reader::ApplyUpdates().\n",
2649 0 : pszKey );
2650 : }
2651 : }
2652 :
2653 0 : return CPLGetLastErrorType() != CE_Failure;
2654 : }
2655 :
2656 : /************************************************************************/
2657 : /* FindAndApplyUpdates() */
2658 : /* */
2659 : /* Find all update files that would appear to apply to this */
2660 : /* base file. */
2661 : /************************************************************************/
2662 :
2663 2 : int S57Reader::FindAndApplyUpdates( const char * pszPath )
2664 :
2665 : {
2666 : int iUpdate;
2667 2 : int bSuccess = TRUE;
2668 :
2669 2 : if( pszPath == NULL )
2670 2 : pszPath = pszModuleName;
2671 :
2672 2 : if( !EQUAL(CPLGetExtension(pszPath),"000") )
2673 : {
2674 : CPLError( CE_Failure, CPLE_AppDefined,
2675 : "Can't apply updates to a base file with a different\n"
2676 0 : "extension than .000.\n" );
2677 0 : return FALSE;
2678 : }
2679 :
2680 2 : for( iUpdate = 1; bSuccess; iUpdate++ )
2681 : {
2682 : //Creaing file extension
2683 2 : CPLString extension;
2684 2 : CPLString dirname;
2685 4 : if( 1 <= iUpdate && iUpdate < 10 )
2686 : {
2687 : char buf[2];
2688 2 : sprintf( buf, "%i", iUpdate );
2689 2 : extension.append("00");
2690 2 : extension.append(buf);
2691 2 : dirname.append(buf);
2692 : }
2693 0 : else if( 10 <= iUpdate && iUpdate < 100 )
2694 : {
2695 : char buf[3];
2696 0 : sprintf( buf, "%i", iUpdate );
2697 0 : extension.append("0");
2698 0 : extension.append(buf);
2699 0 : dirname.append(buf);
2700 : }
2701 0 : else if( 100 <= iUpdate && iUpdate < 1000 )
2702 : {
2703 : char buf[4];
2704 0 : sprintf( buf, "%i", iUpdate );
2705 0 : extension.append(buf);
2706 0 : dirname.append(buf);
2707 : }
2708 :
2709 2 : DDFModule oUpdateModule;
2710 :
2711 : //trying current dir first
2712 : char *pszUpdateFilename =
2713 2 : CPLStrdup(CPLResetExtension(pszPath,extension.c_str()));
2714 :
2715 2 : FILE *file = VSIFOpen( pszUpdateFilename, "r" );
2716 2 : if( file )
2717 : {
2718 0 : VSIFClose( file );
2719 0 : bSuccess = oUpdateModule.Open( pszUpdateFilename, TRUE );
2720 0 : if( bSuccess )
2721 : CPLDebug( "S57", "Applying feature updates from %s.",
2722 0 : pszUpdateFilename );
2723 0 : if( bSuccess )
2724 : {
2725 0 : if( !ApplyUpdates( &oUpdateModule ) )
2726 0 : return FALSE;
2727 : }
2728 : }
2729 : else // file is store on Primar generated cd
2730 : {
2731 2 : char* pszBaseFileDir = CPLStrdup(CPLGetDirname(pszPath));
2732 2 : char* pszFileDir = CPLStrdup(CPLGetDirname(pszBaseFileDir));
2733 :
2734 2 : CPLString remotefile(pszFileDir);
2735 2 : remotefile.append( "/" );
2736 2 : remotefile.append( dirname );
2737 2 : remotefile.append( "/" );
2738 2 : remotefile.append( CPLGetBasename(pszPath) );
2739 2 : remotefile.append( "." );
2740 2 : remotefile.append( extension );
2741 2 : bSuccess = oUpdateModule.Open( remotefile.c_str(), TRUE );
2742 :
2743 2 : if( bSuccess )
2744 : CPLDebug( "S57", "Applying feature updates from %s.",
2745 0 : remotefile.c_str() );
2746 2 : CPLFree( pszBaseFileDir );
2747 2 : CPLFree( pszFileDir );
2748 2 : if( bSuccess )
2749 : {
2750 0 : if( !ApplyUpdates( &oUpdateModule ) )
2751 0 : return FALSE;
2752 0 : }
2753 : }//end for if-else
2754 2 : CPLFree( pszUpdateFilename );
2755 : }
2756 :
2757 2 : return TRUE;
2758 : }
2759 :
2760 : /************************************************************************/
2761 : /* GetExtent() */
2762 : /* */
2763 : /* Scan all the cached records collecting spatial bounds as */
2764 : /* efficiently as possible for this transfer. */
2765 : /************************************************************************/
2766 :
2767 0 : OGRErr S57Reader::GetExtent( OGREnvelope *psExtent, int bForce )
2768 :
2769 : {
2770 : #define INDEX_COUNT 4
2771 :
2772 : DDFRecordIndex *apoIndex[INDEX_COUNT];
2773 :
2774 : /* -------------------------------------------------------------------- */
2775 : /* If we aren't forced to get the extent say no if we haven't */
2776 : /* already indexed the iso8211 records. */
2777 : /* -------------------------------------------------------------------- */
2778 0 : if( !bForce && !bFileIngested )
2779 0 : return OGRERR_FAILURE;
2780 :
2781 0 : if( !Ingest() )
2782 0 : return OGRERR_FAILURE;
2783 :
2784 : /* -------------------------------------------------------------------- */
2785 : /* We will scan all the low level vector elements for extents */
2786 : /* coordinates. */
2787 : /* -------------------------------------------------------------------- */
2788 0 : int bGotExtents = FALSE;
2789 0 : int nXMin=0, nXMax=0, nYMin=0, nYMax=0;
2790 :
2791 0 : apoIndex[0] = &oVI_Index;
2792 0 : apoIndex[1] = &oVC_Index;
2793 0 : apoIndex[2] = &oVE_Index;
2794 0 : apoIndex[3] = &oVF_Index;
2795 :
2796 0 : for( int iIndex = 0; iIndex < INDEX_COUNT; iIndex++ )
2797 : {
2798 0 : DDFRecordIndex *poIndex = apoIndex[iIndex];
2799 :
2800 0 : for( int iVIndex = 0; iVIndex < poIndex->GetCount(); iVIndex++ )
2801 : {
2802 0 : DDFRecord *poRecord = poIndex->GetByIndex( iVIndex );
2803 0 : DDFField *poSG3D = poRecord->FindField( "SG3D" );
2804 0 : DDFField *poSG2D = poRecord->FindField( "SG2D" );
2805 :
2806 0 : if( poSG3D != NULL )
2807 : {
2808 0 : int i, nVCount = poSG3D->GetRepeatCount();
2809 : GInt32 *panData, nX, nY;
2810 :
2811 0 : panData = (GInt32 *) poSG3D->GetData();
2812 0 : for( i = 0; i < nVCount; i++ )
2813 : {
2814 0 : nX = CPL_LSBWORD32(panData[i*3+1]);
2815 0 : nY = CPL_LSBWORD32(panData[i*3+0]);
2816 :
2817 0 : if( bGotExtents )
2818 : {
2819 0 : nXMin = MIN(nXMin,nX);
2820 0 : nXMax = MAX(nXMax,nX);
2821 0 : nYMin = MIN(nYMin,nY);
2822 0 : nYMax = MAX(nYMax,nY);
2823 : }
2824 : else
2825 : {
2826 0 : nXMin = nXMax = nX;
2827 0 : nYMin = nYMax = nY;
2828 0 : bGotExtents = TRUE;
2829 : }
2830 : }
2831 : }
2832 0 : else if( poSG2D != NULL )
2833 : {
2834 0 : int i, nVCount = poSG2D->GetRepeatCount();
2835 : GInt32 *panData, nX, nY;
2836 :
2837 0 : panData = (GInt32 *) poSG2D->GetData();
2838 0 : for( i = 0; i < nVCount; i++ )
2839 : {
2840 0 : nX = CPL_LSBWORD32(panData[i*2+1]);
2841 0 : nY = CPL_LSBWORD32(panData[i*2+0]);
2842 :
2843 0 : if( bGotExtents )
2844 : {
2845 0 : nXMin = MIN(nXMin,nX);
2846 0 : nXMax = MAX(nXMax,nX);
2847 0 : nYMin = MIN(nYMin,nY);
2848 0 : nYMax = MAX(nYMax,nY);
2849 : }
2850 : else
2851 : {
2852 0 : nXMin = nXMax = nX;
2853 0 : nYMin = nYMax = nY;
2854 0 : bGotExtents = TRUE;
2855 : }
2856 : }
2857 : }
2858 : }
2859 : }
2860 :
2861 0 : if( !bGotExtents )
2862 0 : return OGRERR_FAILURE;
2863 : else
2864 : {
2865 0 : psExtent->MinX = nXMin / (double) nCOMF;
2866 0 : psExtent->MaxX = nXMax / (double) nCOMF;
2867 0 : psExtent->MinY = nYMin / (double) nCOMF;
2868 0 : psExtent->MaxY = nYMax / (double) nCOMF;
2869 :
2870 0 : return OGRERR_NONE;
2871 : }
2872 : }
2873 :
|