OpenCPN Partial API docs
Loading...
Searching...
No Matches
s57reader.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 * Copyright (c) 1999, 2001, Frank Warmerdam warmerdam@pobox.com
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *****************************************************************************/
22
28#include <assert.h>
29#include "gdal/cpl_conv.h"
30#include "gdal/cpl_string.h"
31#include "gdal/ogr_api.h"
32#include "ogr_s57.h"
33#include "s57.h"
34
35/************************************************************************/
36/* S57Reader() */
37/************************************************************************/
38
39S57Reader::S57Reader(const char *pszFilename)
40
41{
42 pszModuleName = CPLStrdup(pszFilename);
43 pszDSNM = NULL;
44
45 poModule = NULL;
46
47 nFDefnCount = 0;
48 papoFDefnList = NULL;
49
50 nCOMF = 1000000;
51 nSOMF = 10;
52
53 poRegistrar = NULL;
54 bFileIngested = FALSE;
55
56 nNextFEIndex = 0;
57 nNextVIIndex = 0;
58 nNextVCIndex = 0;
59 nNextVEIndex = 0;
60 nNextVFIndex = 0;
61
62 iPointOffset = 0;
63 poMultiPoint = NULL;
64
65 papszOptions = NULL;
66
67 nOptionFlags = S57M_UPDATES;
68
69 bMissingWarningIssued = FALSE;
70 bAttrWarningIssued = FALSE;
71
72 Nall = 0;
73 Aall = 0;
74}
75
76/************************************************************************/
77/* ~S57Reader() */
78/************************************************************************/
79
80S57Reader::~S57Reader()
81
82{
83 Close();
84
85 CPLFree(pszModuleName);
86 CSLDestroy(papszOptions);
87
88 CPLFree(papoFDefnList);
89}
90
91/************************************************************************/
92/* Open() */
93/************************************************************************/
94
95int S57Reader::Open(int bTestOpen)
96
97{
98 if (poModule != NULL) {
99 Rewind();
100 return TRUE;
101 }
102
103 poModule = new DDFModule();
104 if (!poModule->Open(pszModuleName)) {
105 // notdef: test bTestOpen.
106 delete poModule;
107 poModule = NULL;
108 return FALSE;
109 }
110
111 // note that the following won't work for catalogs.
112 if (poModule->FindFieldDefn("DSID") == NULL) {
113 if (!bTestOpen) {
114 CPLError(CE_Failure, CPLE_AppDefined,
115 "%s is an ISO8211 file, but not an S-57 data file.\n",
116 pszModuleName);
117 }
118 delete poModule;
119 poModule = NULL;
120 return FALSE;
121 }
122
123 // Make sure the FSPT field is marked as repeating.
124 DDFFieldDefn *poFSPT = poModule->FindFieldDefn("FSPT");
125 if (poFSPT != NULL && !poFSPT->IsRepeating()) {
126 CPLDebug("S57", "Forcing FSPT field to be repeating.");
127 poFSPT->SetRepeatingFlag(TRUE);
128 }
129
130 nNextFEIndex = 0;
131 nNextVIIndex = 0;
132 nNextVCIndex = 0;
133 nNextVEIndex = 0;
134 nNextVFIndex = 0;
135
136 return TRUE;
137}
138
139/************************************************************************/
140/* Close() */
141/************************************************************************/
142
143void S57Reader::Close()
144
145{
146 if (poModule != NULL) {
147 oVI_Index.Clear();
148 oVC_Index.Clear();
149 oVE_Index.Clear();
150 oVF_Index.Clear();
151 oFE_Index.Clear();
152
153 ClearPendingMultiPoint();
154
155 delete poModule;
156 poModule = NULL;
157
158 bFileIngested = FALSE;
159
160 CPLFreeConfig();
161
162 CPLFree(pszDSNM);
163 pszDSNM = NULL;
164 }
165}
166
167/************************************************************************/
168/* ClearPendingMultiPoint() */
169/************************************************************************/
170
171void S57Reader::ClearPendingMultiPoint()
172
173{
174 if (poMultiPoint != NULL) {
175 delete poMultiPoint;
176 poMultiPoint = NULL;
177 }
178}
179
180/************************************************************************/
181/* NextPendingMultiPoint() */
182/************************************************************************/
183
184OGRFeature *S57Reader::NextPendingMultiPoint()
185
186{
187 CPLAssert(poMultiPoint != NULL);
188 CPLAssert(wkbFlatten(poMultiPoint->GetGeometryRef()->getGeometryType()) ==
189 wkbMultiPoint);
190
191 OGRFeatureDefn *poDefn = poMultiPoint->GetDefnRef();
192 OGRFeature *poPoint = new OGRFeature(poDefn);
193 OGRMultiPoint *poMPGeom = (OGRMultiPoint *)poMultiPoint->GetGeometryRef();
194 OGRPoint *poSrcPoint;
195
196 poPoint->SetFID(poMultiPoint->GetFID());
197
198 for (int i = 0; i < poDefn->GetFieldCount(); i++) {
199 poPoint->SetField(i, poMultiPoint->GetRawFieldRef(i));
200 }
201
202 poSrcPoint = (OGRPoint *)poMPGeom->getGeometryRef(iPointOffset++);
203 poPoint->SetGeometry(poSrcPoint);
204
205 poPoint->SetField("DEPTH", poSrcPoint->getZ());
206
207 if (iPointOffset >= poMPGeom->getNumGeometries()) ClearPendingMultiPoint();
208
209 return poPoint;
210}
211
212/************************************************************************/
213/* SetOptions() */
214/************************************************************************/
215
216void S57Reader::SetOptions(char **papszOptionsIn)
217
218{
219 const char *pszOptionValue;
220
221 CSLDestroy(papszOptions);
222 papszOptions = CSLDuplicate(papszOptionsIn);
223
224 pszOptionValue = CSLFetchNameValue(papszOptions, S57O_SPLIT_MULTIPOINT);
225 if (pszOptionValue != NULL && !EQUAL(pszOptionValue, "OFF"))
226 nOptionFlags |= S57M_SPLIT_MULTIPOINT;
227 else
228 nOptionFlags &= ~S57M_SPLIT_MULTIPOINT;
229
230 pszOptionValue = CSLFetchNameValue(papszOptions, S57O_ADD_SOUNDG_DEPTH);
231 if (pszOptionValue != NULL && !EQUAL(pszOptionValue, "OFF"))
232 nOptionFlags |= S57M_ADD_SOUNDG_DEPTH;
233 else
234 nOptionFlags &= ~S57M_ADD_SOUNDG_DEPTH;
235
236 CPLAssert(!(nOptionFlags & S57M_ADD_SOUNDG_DEPTH) ||
237 (nOptionFlags & S57M_SPLIT_MULTIPOINT));
238
239 pszOptionValue = CSLFetchNameValue(papszOptions, S57O_LNAM_REFS);
240 if (pszOptionValue != NULL && !EQUAL(pszOptionValue, "OFF"))
241 nOptionFlags |= S57M_LNAM_REFS;
242 else
243 nOptionFlags &= ~S57M_LNAM_REFS;
244
245 pszOptionValue = CSLFetchNameValue(papszOptions, S57O_UPDATES);
246 if (pszOptionValue != NULL && !EQUAL(pszOptionValue, "OFF"))
247 nOptionFlags |= S57M_UPDATES;
248 else
249 nOptionFlags &= ~S57M_UPDATES;
250
251 pszOptionValue = CSLFetchNameValue(papszOptions, S57O_PRESERVE_EMPTY_NUMBERS);
252 if (pszOptionValue != NULL && !EQUAL(pszOptionValue, "OFF"))
253 nOptionFlags |= S57M_PRESERVE_EMPTY_NUMBERS;
254 else
255 nOptionFlags &= ~S57M_PRESERVE_EMPTY_NUMBERS;
256
257 pszOptionValue = CSLFetchNameValue(papszOptions, S57O_RETURN_PRIMITIVES);
258 if (pszOptionValue != NULL && !EQUAL(pszOptionValue, "OFF"))
259 nOptionFlags |= S57M_RETURN_PRIMITIVES;
260 else
261 nOptionFlags &= ~S57M_RETURN_PRIMITIVES;
262
263 pszOptionValue = CSLFetchNameValue(papszOptions, S57O_RETURN_LINKAGES);
264 if (pszOptionValue != NULL && !EQUAL(pszOptionValue, "OFF"))
265 nOptionFlags |= S57M_RETURN_LINKAGES;
266 else
267 nOptionFlags &= ~S57M_RETURN_LINKAGES;
268}
269
270/************************************************************************/
271/* SetClassBased() */
272/************************************************************************/
273
274void S57Reader::SetClassBased(S57ClassRegistrar *poReg)
275
276{
277 poRegistrar = poReg;
278}
279
280/************************************************************************/
281/* Rewind() */
282/************************************************************************/
283
284void S57Reader::Rewind()
285
286{
287 ClearPendingMultiPoint();
288 nNextFEIndex = 0;
289 nNextVIIndex = 0;
290 nNextVCIndex = 0;
291 nNextVEIndex = 0;
292 nNextVFIndex = 0;
293}
294
295/************************************************************************/
296/* Ingest() */
297/* */
298/* Read all the records into memory, adding to the appropriate */
299/* indexes. */
300/************************************************************************/
301
302int S57Reader::Ingest(CallBackFunction pcallback) {
303 DDFRecord *poRecord;
304
305 // CPLSetConfigOption("CPL_DEBUG", "S57");
306
307 if (poModule == NULL || bFileIngested) return 0;
308
309 /* -------------------------------------------------------------------- */
310 /* Read all the records in the module, and place them in */
311 /* appropriate indexes. */
312 /* -------------------------------------------------------------------- */
313 while ((poRecord = poModule->ReadRecord()) != NULL) {
314 if (pcallback) {
315 if (!(*pcallback)()) return 0;
316 }
317
318 DDFField *poKeyField = poRecord->GetField(1);
319 const char *pszname = poKeyField->GetFieldDefn()->GetName();
320
321 if (EQUAL(pszname, "VRID")) {
322#if 0
323 int nRCNM = poRecord->GetIntSubfield( "VRID",0, "RCNM",0);
324 int nRCID = poRecord->GetIntSubfield( "VRID",0, "RCID",0);
325#else
326 int nRCNM = 0, nRCID = 0;
327 DDFField *poField = poRecord->FindField("VRID", 0);
328 if (poField) {
329 int nBytesRemaining;
330 DDFSubfieldDefn *poSFDefn;
331 poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn("RCNM");
332 if (poSFDefn) {
333 const char *pachData =
334 poField->GetSubfieldData(poSFDefn, &nBytesRemaining, 0);
335 nRCNM = poSFDefn->ExtractIntData(pachData, nBytesRemaining, NULL);
336 }
337
338 poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn("RCID");
339 if (poSFDefn) {
340 const char *pachData =
341 poField->GetSubfieldData(poSFDefn, &nBytesRemaining, 0);
342 nRCID = poSFDefn->ExtractIntData(pachData, nBytesRemaining, NULL);
343 }
344 }
345#endif
346
347 switch (nRCNM) {
348 case RCNM_VI:
349 oVI_Index.AddRecord(nRCID, poRecord->Copy());
350 break;
351
352 case RCNM_VC:
353 oVC_Index.AddRecord(nRCID, poRecord->Copy());
354 break;
355
356 case RCNM_VE:
357 oVE_Index.AddRecord(nRCID, poRecord->Copy());
358 break;
359
360 case RCNM_VF:
361 oVF_Index.AddRecord(nRCID, poRecord->Copy());
362 break;
363
364 default:
365 CPLAssert(FALSE);
366 break;
367 }
368
369 }
370
371 // Feature records
372 else if (EQUAL(pszname, "FRID")) {
373 // poRecord->Dump(stderr); // for debugging,
374 // try ./opencpn &>test.dbg
375
376 int nRCID = poRecord->GetIntSubfield("FRID", 0, "RCID", 0);
377 oFE_Index.AddRecord(nRCID, poRecord->Copy());
378
379 }
380
381 // Convenience values
382 else if (EQUAL(pszname, "DSPM")) {
383 nCOMF = MAX(1, poRecord->GetIntSubfield("DSPM", 0, "COMF", 0));
384 nSOMF = MAX(1, poRecord->GetIntSubfield("DSPM", 0, "SOMF", 0));
385 nCSCL = MAX(1, poRecord->GetIntSubfield("DSPM", 0, "CSCL", 0));
386
387 }
388
389 else if (EQUAL(pszname, "DSID")) {
390 CPLFree(pszDSNM);
391 pszDSNM = CPLStrdup(poRecord->GetStringSubfield("DSID", 0, "DSNM", 0));
392 Nall = poRecord->GetIntSubfield("DSSI", 0, "NALL", 0);
393 Aall = poRecord->GetIntSubfield("DSSI", 0, "AALL", 0);
394 }
395
396 else {
397 CPLDebug("S57", "Skipping %s record in S57Reader::Ingest().\n",
398 poKeyField->GetFieldDefn()->GetName());
399 }
400 }
401
402 bFileIngested = TRUE;
403
404 /* -------------------------------------------------------------------- */
405 /* If update support is enabled, read and apply them. */
406 /* -------------------------------------------------------------------- */
407 int update_return = 0;
408 if (nOptionFlags & S57M_UPDATES) update_return = FindAndApplyUpdates();
409
410 return update_return;
411}
412
413/************************************************************************/
414/* SetNextFEIndex() */
415/************************************************************************/
416
417void S57Reader::SetNextFEIndex(int nNewIndex, int nRCNM)
418
419{
420 if (nRCNM == RCNM_VI)
421 nNextVIIndex = nNewIndex;
422 else if (nRCNM == RCNM_VC)
423 nNextVCIndex = nNewIndex;
424 else if (nRCNM == RCNM_VE)
425 nNextVEIndex = nNewIndex;
426 else if (nRCNM == RCNM_VF)
427 nNextVFIndex = nNewIndex;
428 else {
429 if (nNextFEIndex != nNewIndex) ClearPendingMultiPoint();
430
431 nNextFEIndex = nNewIndex;
432 }
433}
434
435/************************************************************************/
436/* GetNextFEIndex() */
437/************************************************************************/
438
439int S57Reader::GetNextFEIndex(int nRCNM)
440
441{
442 if (nRCNM == RCNM_VI)
443 return nNextVIIndex;
444 else if (nRCNM == RCNM_VC)
445 return nNextVCIndex;
446 else if (nRCNM == RCNM_VE)
447 return nNextVEIndex;
448 else if (nRCNM == RCNM_VF)
449 return nNextVFIndex;
450 else
451 return nNextFEIndex;
452}
453
454/************************************************************************/
455/* ReadNextFeature() */
456/************************************************************************/
457
458OGRFeature *S57Reader::ReadNextFeature(OGRFeatureDefn *poTarget)
459
460{
461 if (!bFileIngested) Ingest();
462
463 /* -------------------------------------------------------------------- */
464 /* Special case for "in progress" multipoints being split up. */
465 /* -------------------------------------------------------------------- */
466 if (poMultiPoint != NULL) {
467 if (poTarget == NULL || poTarget == poMultiPoint->GetDefnRef()) {
468 return NextPendingMultiPoint();
469 } else {
470 ClearPendingMultiPoint();
471 }
472 }
473
474 /* -------------------------------------------------------------------- */
475 /* Next vector feature? */
476 /* -------------------------------------------------------------------- */
477 if (nOptionFlags & S57M_RETURN_PRIMITIVES) {
478 int nRCNM = 0;
479 int *pnCounter = NULL;
480
481 if (poTarget == NULL) {
482 if (nNextVIIndex < oVI_Index.GetCount()) {
483 nRCNM = RCNM_VI;
484 pnCounter = &nNextVIIndex;
485 } else if (nNextVCIndex < oVC_Index.GetCount()) {
486 nRCNM = RCNM_VC;
487 pnCounter = &nNextVCIndex;
488 } else if (nNextVEIndex < oVE_Index.GetCount()) {
489 nRCNM = RCNM_VE;
490 pnCounter = &nNextVEIndex;
491 } else if (nNextVFIndex < oVF_Index.GetCount()) {
492 nRCNM = RCNM_VF;
493 pnCounter = &nNextVFIndex;
494 }
495 } else {
496 if (EQUAL(poTarget->GetName(), OGRN_VI)) {
497 nRCNM = RCNM_VI;
498 pnCounter = &nNextVIIndex;
499 } else if (EQUAL(poTarget->GetName(), OGRN_VC)) {
500 nRCNM = RCNM_VC;
501 pnCounter = &nNextVCIndex;
502 } else if (EQUAL(poTarget->GetName(), OGRN_VE)) {
503 nRCNM = RCNM_VE;
504 pnCounter = &nNextVEIndex;
505 } else if (EQUAL(poTarget->GetName(), OGRN_VF)) {
506 nRCNM = RCNM_VF;
507 pnCounter = &nNextVFIndex;
508 }
509 }
510
511 if (nRCNM != 0) {
512 OGRFeature *poFeature = ReadVector(*pnCounter, nRCNM);
513 if (poFeature != NULL) {
514 *pnCounter += 1;
515 return poFeature;
516 }
517 }
518 }
519
520 /* -------------------------------------------------------------------- */
521 /* Next feature. */
522 /* -------------------------------------------------------------------- */
523 while (nNextFEIndex < oFE_Index.GetCount()) {
524 OGRFeature *poFeature;
525
526 poFeature = ReadFeature(nNextFEIndex++, poTarget);
527 if (poFeature != NULL) {
528 if ((nOptionFlags & S57M_SPLIT_MULTIPOINT) &&
529 poFeature->GetGeometryRef() != NULL &&
530 wkbFlatten(poFeature->GetGeometryRef()->getGeometryType()) ==
531 wkbMultiPoint) {
532 poMultiPoint = poFeature;
533 iPointOffset = 0;
534 return NextPendingMultiPoint();
535 }
536
537 return poFeature;
538 }
539 }
540
541 return NULL;
542}
543
544/************************************************************************/
545/* ReadFeature() */
546/* */
547/* Read the features who's id is provided. */
548/************************************************************************/
549/*
550OGRFeature *S57Reader::ReadFeature( int nFeatureId, OGRFeatureDefn *poTarget )
551
552{
553 OGRFeature *poFeature;
554
555 if( nFeatureId < 0 || nFeatureId >= oFE_Index.GetCount() )
556 return NULL;
557
558
559 poFeature = AssembleFeature( oFE_Index.GetByIndex(nFeatureId),
560 poTarget );
561 if( poFeature != NULL )
562 poFeature->SetFID( nFeatureId );
563
564 return poFeature;
565}
566
567*/
568/************************************************************************/
569/* ReadFeature() */
570/* */
571/* Read the features who's id is provided. */
572/************************************************************************/
573
574OGRFeature *S57Reader::ReadFeature(int nFeatureId, OGRFeatureDefn *poTarget)
575
576{
577 OGRFeature *poFeature;
578
579 if (nFeatureId < 0 || nFeatureId >= oFE_Index.GetCount()) return NULL;
580
581 DDFRecord *poRecord = oFE_Index.GetByIndex(nFeatureId);
582
583 if (poTarget) {
584 int nRecord_OBJL = poRecord->GetIntSubfield("FRID", 0, "OBJL", 0);
585 int nOBJL = poTarget->GetOBJL();
586
587 if (nRecord_OBJL == nOBJL) // tentative match
588 {
589 poFeature = AssembleFeature(oFE_Index.GetByIndex(nFeatureId), poTarget);
590
591 if (poFeature != NULL) poFeature->SetFID(nFeatureId);
592
593 return poFeature;
594 } else
595 return NULL;
596 } else {
597 poFeature = AssembleFeature(oFE_Index.GetByIndex(nFeatureId), poTarget);
598 if (poFeature != NULL) poFeature->SetFID(nFeatureId);
599
600 return poFeature;
601 }
602}
603
604/************************************************************************/
605/* AssembleFeature() */
606/* */
607/* Assemble an OGR feature based on a feature record. */
608/************************************************************************/
609
610OGRFeature *S57Reader::AssembleFeature(DDFRecord *poRecord,
611 OGRFeatureDefn *poTarget)
612
613{
614 int nPRIM, nOBJL;
615 OGRFeatureDefn *poFDefn;
616
617 /* -------------------------------------------------------------------- */
618 /* Find the feature definition to use. Currently this is based */
619 /* on the primitive, but eventually this should be based on the */
620 /* object class (FRID.OBJL) in some cases, and the primitive in */
621 /* others. */
622 /* -------------------------------------------------------------------- */
623 poFDefn = FindFDefn(poRecord);
624 if (poFDefn == NULL) {
625 // It is possible that a Feature was added by update, whose Class
626 // was not already present in the module before updates.
627 // So, if necessary, try to create and add an OGRFeatureDefn for this
628 // Feature.
629 int nOBJL = poRecord->GetIntSubfield("FRID", 0, "OBJL", 0);
630 poFDefn =
631 S57GenerateObjectClassDefn(poRegistrar, nOBJL, this->GetOptionFlags());
632 if (poFDefn)
633 AddFeatureDefn(poFDefn);
634 else
635 return NULL;
636 }
637
638 /* -------------------------------------------------------------------- */
639 /* Does this match our target feature definition? If not skip */
640 /* this feature. */
641 /* -------------------------------------------------------------------- */
642 if (poTarget != NULL && poFDefn != poTarget) return NULL;
643
644 /* -------------------------------------------------------------------- */
645 /* Create the new feature object. */
646 /* -------------------------------------------------------------------- */
647 OGRFeature *poFeature;
648
649 poFeature = new OGRFeature(poFDefn);
650
651 /* -------------------------------------------------------------------- */
652 /* Assign a few standard feature attribues. */
653 /* -------------------------------------------------------------------- */
654 nOBJL = poRecord->GetIntSubfield("FRID", 0, "OBJL", 0);
655 poFeature->SetField("OBJL", nOBJL);
656
657 poFeature->SetField("RCID", poRecord->GetIntSubfield("FRID", 0, "RCID", 0));
658 poFeature->SetField("PRIM", poRecord->GetIntSubfield("FRID", 0, "PRIM", 0));
659 poFeature->SetField("GRUP", poRecord->GetIntSubfield("FRID", 0, "GRUP", 0));
660 poFeature->SetField("RVER", poRecord->GetIntSubfield("FRID", 0, "RVER", 0));
661 poFeature->SetField("AGEN", poRecord->GetIntSubfield("FOID", 0, "AGEN", 0));
662 poFeature->SetField("FIDN", poRecord->GetIntSubfield("FOID", 0, "FIDN", 0));
663 poFeature->SetField("FIDS", poRecord->GetIntSubfield("FOID", 0, "FIDS", 0));
664
665 /* -------------------------------------------------------------------- */
666 /* Generate long name, if requested. */
667 /* -------------------------------------------------------------------- */
668 if (nOptionFlags & S57M_LNAM_REFS) {
669 GenerateLNAMAndRefs(poRecord, poFeature);
670 }
671
672 /* -------------------------------------------------------------------- */
673 /* Generate primitive references if requested. */
674 /* -------------------------------------------------------------------- */
675 if (nOptionFlags & S57M_RETURN_LINKAGES)
676 GenerateFSPTAttributes(poRecord, poFeature);
677
678 /* -------------------------------------------------------------------- */
679 /* Apply object class specific attributes, if supported. */
680 /* -------------------------------------------------------------------- */
681 if (poRegistrar != NULL) ApplyObjectClassAttributes(poRecord, poFeature);
682
683 /* -------------------------------------------------------------------- */
684 /* Find and assign spatial component. */
685 /* -------------------------------------------------------------------- */
686 nPRIM = poRecord->GetIntSubfield("FRID", 0, "PRIM", 0);
687
688 if (nPRIM == PRIM_P) {
689 if (nOBJL == 129) /* SOUNDG */
690 AssembleSoundingGeometry(poRecord, poFeature);
691 else
692 AssemblePointGeometry(poRecord, poFeature);
693 } else if (nPRIM == PRIM_L) {
694 AssembleLineGeometry(poRecord, poFeature);
695 } else if (nPRIM == PRIM_A) {
696 AssembleAreaGeometry(poRecord, poFeature);
697 }
698
699 return poFeature;
700}
701
702/************************************************************************/
703/* ApplyObjectClassAttributes() */
704/************************************************************************/
705
706void S57Reader::ApplyObjectClassAttributes(DDFRecord *poRecord,
707 OGRFeature *poFeature)
708
709{
710 /* -------------------------------------------------------------------- */
711 /* ATTF Attributes */
712 /* -------------------------------------------------------------------- */
713 DDFField *poATTF = poRecord->FindField("ATTF");
714 int nAttrCount, iAttr;
715
716 if (poATTF == NULL) return;
717
718 DDFFieldDefn *poDefn = poATTF->GetFieldDefn();
719
720 nAttrCount = poATTF->GetRepeatCount();
721 for (iAttr = 0; iAttr < nAttrCount; iAttr++) {
722 int nAttrId = poRecord->GetIntSubfield("ATTF", 0, "ATTL", iAttr);
723 const char *pszAcronym;
724
725 if (nAttrId < 1 || nAttrId > poRegistrar->GetMaxAttrIndex() ||
726 (pszAcronym = poRegistrar->GetAttrAcronym(nAttrId)) == NULL) {
727 if (!bAttrWarningIssued) {
728 bAttrWarningIssued = TRUE;
729 CPLError(CE_Warning, CPLE_AppDefined,
730 "Illegal feature attribute id (ATTF:ATTL[%d]) of %d\n"
731 "on feature FIDN=%d, FIDS=%d.\n"
732 "Skipping attribute, no more warnings will be issued.",
733 iAttr, nAttrId, poFeature->GetFieldAsInteger("FIDN"),
734 poFeature->GetFieldAsInteger("FIDS"));
735 }
736
737 continue;
738 }
739
740 /* Fetch the attribute value */
741 const char *pszValue;
742 pszValue = poRecord->GetStringSubfield("ATTF", 0, "ATVL", iAttr);
743
744 /* Apply to feature in an appropriate way */
745 int iField;
746 OGRFieldDefn *poFldDefn;
747
748 iField = poFeature->GetDefnRef()->GetFieldIndex(pszAcronym);
749 if (iField < 0) {
750 if (!bMissingWarningIssued) {
751 bMissingWarningIssued = TRUE;
752 CPLError(CE_Warning, CPLE_AppDefined,
753 "For feature \"%s\", attribute \"%s\" ignored, not in "
754 "expected schema.\n",
755 poFeature->GetDefnRef()->GetName(), pszAcronym);
756 }
757 continue;
758 }
759
760 // Handle deleted attributes
761 // If the first char of the attribute is 0x7f, then unset this field.
762 // Any later requests for the attribute value will retrun an empty string.
763 if (pszValue[0] == 0x7f) {
764 poFeature->UnsetField(iField);
765 continue;
766 }
767
768 poFldDefn = poFeature->GetDefnRef()->GetFieldDefn(iField);
769 if (poFldDefn->GetType() == OFTInteger || poFldDefn->GetType() == OFTReal) {
770 if (strlen(pszValue) == 0) {
771 if (nOptionFlags & S57M_PRESERVE_EMPTY_NUMBERS) {
772 poFeature->SetField(iField, EMPTY_NUMBER_MARKER);
773 } else {
774 /* leave as null if value was empty string */;
775 }
776 } else {
777 poFeature->SetField(iField, pszValue);
778 }
779 } else {
780 poFeature->SetField(iField, pszValue);
781 }
782 }
783
784 /* -------------------------------------------------------------------- */
785 /* NATF (national) attributes */
786 /* -------------------------------------------------------------------- */
787 DDFField *poNATF = poRecord->FindField("NATF");
788
789 if (poNATF == NULL) return;
790
791 nAttrCount = poNATF->GetRepeatCount();
792 for (iAttr = 0; iAttr < nAttrCount; iAttr++) {
793 int nAttrId = poRecord->GetIntSubfield("NATF", 0, "ATTL", iAttr);
794 const char *pszAcronym;
795
796 if (nAttrId < 1 || nAttrId >= poRegistrar->GetMaxAttrIndex() ||
797 (pszAcronym = poRegistrar->GetAttrAcronym(nAttrId)) == NULL) {
798 // poRecord->Dump(stdout);
799 // int xnAttrId =
800 // poRecord->GetIntSubfield("NATF",0,"ATTL",iAttr);
801 static int bAttrWarningIssued = FALSE;
802
803 if (!bAttrWarningIssued) {
804 bAttrWarningIssued = TRUE;
805 CPLError(CE_Warning, CPLE_AppDefined,
806 "Illegal feature attribute id (NATF:ATTL[%d]) of %d\n"
807 "on feature FIDN=%d, FIDS=%d.\n"
808 "Skipping attribute, no more warnings will be issued.",
809 iAttr, nAttrId, poFeature->GetFieldAsInteger("FIDN"),
810 poFeature->GetFieldAsInteger("FIDS"));
811 }
812
813 continue;
814 }
815
816 // Guard against undefined fields
817 if (poFeature->GetFieldIndex(pszAcronym) < 0) continue;
818
819 const char *pszValue =
820 poRecord->GetStringSubfield("NATF", 0, "ATVL", iAttr);
821 if (pszValue != NULL) {
822 // If National Language strings are encoded as UCS-2 (a.k.a UTF-16)
823 // then we capture and duplicate the attribute string directly,
824 // in order to avoid truncation that would happen if it were
825 // considered a simple char *
826
827 if (Nall ==
828 2) { // national string encoded in UCS-2, determined from DSID record
829
830 // Compute the data size
831 DDFField *poField;
832 int nLength = 0;
833 poField = poRecord->FindField("NATF", 0);
834 if (poField) {
835 DDFSubfieldDefn *poSFDefn;
836
837 poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn("ATVL");
838 if (poSFDefn) {
839 int max_length = 0;
840 const char *pachData =
841 poField->GetSubfieldData(poSFDefn, &max_length, iAttr);
842 nLength = poSFDefn->GetDataLength(pachData, max_length, NULL);
843 }
844 }
845
846 if (nLength) {
847 // Make the new length a multiple of 2, so that
848 // later stages will count chars correctly
849 // Also, be sure that the string ends with 00 00
850 int new_len = ((nLength / 2) + 2) * 2;
851 char *aa = (char *)calloc(new_len, 1);
852 memcpy(aa, pszValue, nLength);
853
854 int index = poFeature->GetFieldIndex(pszAcronym);
855 OGRField *field = poFeature->GetRawFieldRef(index);
856 field->String = aa;
857 }
858 } else { // encoded as ISO8859_1, pass it along
859 poFeature->SetField(pszAcronym, pszValue);
860 }
861 }
862 }
863}
864
865/************************************************************************/
866/* generatelnamandrefs() */
867/************************************************************************/
868
869void S57Reader::GenerateLNAMAndRefs(DDFRecord *poRecord, OGRFeature *poFeature)
870
871{
872 char szLNAM[32];
873
874 /* -------------------------------------------------------------------- */
875 /* Apply the LNAM to the object. */
876 /* -------------------------------------------------------------------- */
877 sprintf(szLNAM, "%04X%08X%04X", poFeature->GetFieldAsInteger("AGEN"),
878 poFeature->GetFieldAsInteger("FIDN"),
879 poFeature->GetFieldAsInteger("FIDS"));
880 poFeature->SetField("LNAM", szLNAM);
881
882 /* -------------------------------------------------------------------- */
883 /* Do we have references to other features. */
884 /* -------------------------------------------------------------------- */
885 DDFField *poFFPT;
886
887 poFFPT = poRecord->FindField("FFPT");
888
889 if (poFFPT == NULL) return;
890
891 /* -------------------------------------------------------------------- */
892 /* Apply references. */
893 /* -------------------------------------------------------------------- */
894 int nRefCount = poFFPT->GetRepeatCount();
895 DDFSubfieldDefn *poLNAM;
896 char **papszRefs = NULL;
897 int *panRIND = (int *)CPLMalloc(sizeof(int) * nRefCount);
898
899 poLNAM = poFFPT->GetFieldDefn()->FindSubfieldDefn("LNAM");
900 if (poLNAM == NULL) return;
901
902 for (int iRef = 0; iRef < nRefCount; iRef++) {
903 unsigned char *pabyData;
904
905 pabyData = (unsigned char *)poFFPT->GetSubfieldData(poLNAM, NULL, iRef);
906
907 sprintf(szLNAM, "%02X%02X%02X%02X%02X%02X%02X%02X", pabyData[1],
908 pabyData[0], /* AGEN */
909 pabyData[5], pabyData[4], pabyData[3], pabyData[2], /* FIDN */
910 pabyData[7], pabyData[6]);
911
912 papszRefs = CSLAddString(papszRefs, szLNAM);
913
914 panRIND[iRef] = pabyData[8];
915 }
916
917 poFeature->SetField("LNAM_REFS", papszRefs);
918 CSLDestroy(papszRefs);
919
920 poFeature->SetField("FFPT_RIND", nRefCount, panRIND);
921 CPLFree(panRIND);
922}
923
924/************************************************************************/
925/* GenerateFSPTAttributes() */
926/************************************************************************/
927
928void S57Reader::GenerateFSPTAttributes(DDFRecord *poRecord,
929 OGRFeature *poFeature)
930
931{
932 /* -------------------------------------------------------------------- */
933 /* Feature the spatial record containing the point. */
934 /* -------------------------------------------------------------------- */
935 DDFField *poFSPT;
936 int nCount, i;
937
938 poFSPT = poRecord->FindField("FSPT");
939 if (poFSPT == NULL) return;
940
941 nCount = poFSPT->GetRepeatCount();
942
943 /* -------------------------------------------------------------------- */
944 /* Allocate working lists of the attributes. */
945 /* -------------------------------------------------------------------- */
946 int *panORNT, *panUSAG, *panMASK, *panRCNM, *panRCID;
947
948 panORNT = (int *)CPLMalloc(sizeof(int) * nCount);
949 panUSAG = (int *)CPLMalloc(sizeof(int) * nCount);
950 panMASK = (int *)CPLMalloc(sizeof(int) * nCount);
951 panRCNM = (int *)CPLMalloc(sizeof(int) * nCount);
952 panRCID = (int *)CPLMalloc(sizeof(int) * nCount);
953
954 /* -------------------------------------------------------------------- */
955 /* loop over all entries, decoding them. */
956 /* -------------------------------------------------------------------- */
957 for (i = 0; i < nCount; i++) {
958 panRCID[i] = ParseName(poFSPT, i, panRCNM + i);
959 panORNT[i] = poRecord->GetIntSubfield("FSPT", 0, "ORNT", i);
960 panUSAG[i] = poRecord->GetIntSubfield("FSPT", 0, "USAG", i);
961 panMASK[i] = poRecord->GetIntSubfield("FSPT", 0, "MASK", i);
962 }
963
964 /* -------------------------------------------------------------------- */
965 /* Assign to feature. */
966 /* -------------------------------------------------------------------- */
967 poFeature->SetField("NAME_RCNM", nCount, panRCNM);
968 poFeature->SetField("NAME_RCID", nCount, panRCID);
969 poFeature->SetField("ORNT", nCount, panORNT);
970 poFeature->SetField("USAG", nCount, panUSAG);
971 poFeature->SetField("MASK", nCount, panMASK);
972
973 /* -------------------------------------------------------------------- */
974 /* Cleanup. */
975 /* -------------------------------------------------------------------- */
976 CPLFree(panRCNM);
977 CPLFree(panRCID);
978 CPLFree(panORNT);
979 CPLFree(panUSAG);
980 CPLFree(panMASK);
981}
982
983/************************************************************************/
984/* ReadVector() */
985/* */
986/* Read a vector primitive objects based on the type (RCNM_) */
987/* and index within the related index. */
988/************************************************************************/
989
990OGRFeature *S57Reader::ReadVector(int nFeatureId, int nRCNM)
991
992{
993 DDFRecordIndex *poIndex;
994 const char *pszFDName = NULL;
995
996 /* -------------------------------------------------------------------- */
997 /* What type of vector are we fetching. */
998 /* -------------------------------------------------------------------- */
999 switch (nRCNM) {
1000 case RCNM_VI:
1001 poIndex = &oVI_Index;
1002 pszFDName = OGRN_VI;
1003 break;
1004
1005 case RCNM_VC:
1006 poIndex = &oVC_Index;
1007 pszFDName = OGRN_VC;
1008 break;
1009
1010 case RCNM_VE:
1011 poIndex = &oVE_Index;
1012 pszFDName = OGRN_VE;
1013 break;
1014
1015 case RCNM_VF:
1016 poIndex = &oVF_Index;
1017 pszFDName = OGRN_VF;
1018 break;
1019
1020 default:
1021 CPLAssert(FALSE);
1022 return NULL;
1023 }
1024
1025 if (nFeatureId < 0 || nFeatureId >= poIndex->GetCount()) return NULL;
1026
1027 DDFRecord *poRecord = poIndex->GetByIndex(nFeatureId);
1028
1029 /* -------------------------------------------------------------------- */
1030 /* Find the feature definition to use. */
1031 /* -------------------------------------------------------------------- */
1032 OGRFeatureDefn *poFDefn = NULL;
1033
1034 for (int i = 0; i < nFDefnCount; i++) {
1035 if (EQUAL(papoFDefnList[i]->GetName(), pszFDName)) {
1036 poFDefn = papoFDefnList[i];
1037 break;
1038 }
1039 }
1040
1041 if (poFDefn == NULL) {
1042 CPLAssert(FALSE);
1043 return NULL;
1044 }
1045
1046 /* -------------------------------------------------------------------- */
1047 /* Create feature, and assign standard fields. */
1048 /* -------------------------------------------------------------------- */
1049 OGRFeature *poFeature = new OGRFeature(poFDefn);
1050
1051 poFeature->SetFID(nFeatureId);
1052
1053 poFeature->SetField("RCNM", poRecord->GetIntSubfield("VRID", 0, "RCNM", 0));
1054 poFeature->SetField("RCID", poRecord->GetIntSubfield("VRID", 0, "RCID", 0));
1055 poFeature->SetField("RVER", poRecord->GetIntSubfield("VRID", 0, "RVER", 0));
1056 poFeature->SetField("RUIN", poRecord->GetIntSubfield("VRID", 0, "RUIN", 0));
1057
1058 /* -------------------------------------------------------------------- */
1059 /* Collect point geometries. */
1060 /* -------------------------------------------------------------------- */
1061 if (nRCNM == RCNM_VI || nRCNM == RCNM_VC) {
1062 double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1063
1064 if (poRecord->FindField("SG2D") != NULL) {
1065 dfX = poRecord->GetIntSubfield("SG2D", 0, "XCOO", 0) / (double)nCOMF;
1066 dfY = poRecord->GetIntSubfield("SG2D", 0, "YCOO", 0) / (double)nCOMF;
1067 poFeature->SetGeometryDirectly(new OGRPoint(dfX, dfY));
1068 }
1069
1070 else if (poRecord->FindField("SG3D") != NULL) /* presume sounding*/
1071 {
1072 int i, nVCount = poRecord->FindField("SG3D")->GetRepeatCount();
1073 if (nVCount == 1) {
1074 dfX = poRecord->GetIntSubfield("SG3D", 0, "XCOO", 0) / (double)nCOMF;
1075 dfY = poRecord->GetIntSubfield("SG3D", 0, "YCOO", 0) / (double)nCOMF;
1076 dfZ = poRecord->GetIntSubfield("SG3D", 0, "VE3D", 0) / (double)nSOMF;
1077 poFeature->SetGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
1078 } else {
1079 OGRMultiPoint *poMP = new OGRMultiPoint();
1080
1081 for (i = 0; i < nVCount; i++) {
1082 dfX = poRecord->GetIntSubfield("SG3D", 0, "XCOO", i) / (double)nCOMF;
1083 dfY = poRecord->GetIntSubfield("SG3D", 0, "YCOO", i) / (double)nCOMF;
1084 dfZ = poRecord->GetIntSubfield("SG3D", 0, "VE3D", i) / (double)nSOMF;
1085
1086 poMP->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
1087 }
1088
1089 poFeature->SetGeometryDirectly(poMP);
1090 }
1091 }
1092
1093 }
1094
1095 /* -------------------------------------------------------------------- */
1096 /* Collect an edge geometry. */
1097 /* -------------------------------------------------------------------- */
1098 else if (nRCNM == RCNM_VE && poRecord->FindField("SG2D") != NULL) {
1099 int i, nVCount = poRecord->FindField("SG2D")->GetRepeatCount();
1100
1101 if (nVCount == 1) {
1102 // poRecord->Dump(stdout);
1103 OGRLineString *poLine = new OGRLineString();
1104
1105 int jpt = 0;
1106 while (poRecord->FindField("SG2D", jpt) != NULL) {
1107 poLine->setPoint(
1108 jpt,
1109 poRecord->GetIntSubfield("SG2D", jpt, "XCOO", 0) / (double)nCOMF,
1110 poRecord->GetIntSubfield("SG2D", jpt, "YCOO", 0) / (double)nCOMF);
1111 jpt++;
1112 }
1113
1114 poLine->setNumPoints(jpt);
1115
1116 poFeature->SetGeometryDirectly(poLine);
1117
1118 } else {
1119 OGRLineString *poLine = new OGRLineString();
1120
1121 // if(nVCount != 1)
1122 // {
1123 // poRecord->Dump(stdout);
1124 // nVCount = poRecord->FindField("SG2D")->GetRepeatCount();
1125 // }
1126
1127 poLine->setNumPoints(nVCount);
1128
1129 for (i = 0; i < nVCount; i++) {
1130 poLine->setPoint(
1131 i, poRecord->GetIntSubfield("SG2D", 0, "XCOO", i) / (double)nCOMF,
1132 poRecord->GetIntSubfield("SG2D", 0, "YCOO", i) / (double)nCOMF);
1133 }
1134 poFeature->SetGeometryDirectly(poLine);
1135 }
1136 }
1137
1138 /* -------------------------------------------------------------------- */
1139 /* Special edge fields. */
1140 /* -------------------------------------------------------------------- */
1141 DDFField *poVRPT;
1142
1143 if (nRCNM == RCNM_VE && (poVRPT = poRecord->FindField("VRPT")) != NULL) {
1144 poFeature->SetField("NAME_RCNM_0", RCNM_VC);
1145 poFeature->SetField("NAME_RCID_0", ParseName(poVRPT, 0));
1146 poFeature->SetField("ORNT_0",
1147 poRecord->GetIntSubfield("VRPT", 0, "ORNT", 0));
1148 poFeature->SetField("USAG_0",
1149 poRecord->GetIntSubfield("VRPT", 0, "USAG", 0));
1150 poFeature->SetField("TOPI_0",
1151 poRecord->GetIntSubfield("VRPT", 0, "TOPI", 0));
1152 poFeature->SetField("MASK_0",
1153 poRecord->GetIntSubfield("VRPT", 0, "MASK", 0));
1154
1155 if (poVRPT->GetRepeatCount() > 1) {
1156 poFeature->SetField("NAME_RCNM_1", RCNM_VC);
1157 poFeature->SetField("NAME_RCID_1", ParseName(poVRPT, 1));
1158 poFeature->SetField("ORNT_1",
1159 poRecord->GetIntSubfield("VRPT", 0, "ORNT", 1));
1160 poFeature->SetField("USAG_1",
1161 poRecord->GetIntSubfield("VRPT", 0, "USAG", 1));
1162 poFeature->SetField("TOPI_1",
1163 poRecord->GetIntSubfield("VRPT", 0, "TOPI", 1));
1164 poFeature->SetField("MASK_1",
1165 poRecord->GetIntSubfield("VRPT", 0, "MASK", 1));
1166 } else {
1167 DDFField *poVRPTEnd = poRecord->FindField("VRPT", 1);
1168
1169 if (poVRPTEnd) {
1170 poFeature->SetField("NAME_RCNM_1", RCNM_VC);
1171 poFeature->SetField("NAME_RCID_1", ParseName(poVRPTEnd, 0));
1172 poFeature->SetField("ORNT_1",
1173 poRecord->GetIntSubfield("VRPT", 1, "ORNT", 0));
1174 poFeature->SetField("USAG_1",
1175 poRecord->GetIntSubfield("VRPT", 1, "USAG", 0));
1176 poFeature->SetField("TOPI_1",
1177 poRecord->GetIntSubfield("VRPT", 1, "TOPI", 0));
1178 poFeature->SetField("MASK_1",
1179 poRecord->GetIntSubfield("VRPT", 1, "MASK", 0));
1180 } else
1181 CPLDebug("S57", "Vector End Point not found, edge omitted.");
1182 }
1183 }
1184
1185 return poFeature;
1186}
1187
1188/************************************************************************/
1189/* FetchPoint() */
1190/* */
1191/* Fetch the location and quality of a spatial point object. */
1192/************************************************************************/
1193
1194int S57Reader::FetchPoint(int nRCNM, int nRCID, double *pdfX, double *pdfY,
1195 double *pdfZ, int *pnquality)
1196
1197{
1198 DDFRecord *poSRecord;
1199
1200 if (nRCNM == RCNM_VI)
1201 poSRecord = oVI_Index.FindRecord(nRCID);
1202 else
1203 poSRecord = oVC_Index.FindRecord(nRCID);
1204
1205 if (poSRecord == NULL) return FALSE;
1206
1207 // Fetch the quality information
1208 if (NULL != pnquality) {
1209 DDFField *f;
1210 if ((f = poSRecord->FindField("ATTV")) != NULL) {
1211 DDFSubfieldDefn *sfd = (f->GetFieldDefn())->FindSubfieldDefn("ATVL");
1212 if (NULL != sfd) {
1213 int nSuccess;
1214 char *s = (char *)poSRecord->GetStringSubfield("ATTV", 0, "ATVL", 0,
1215 &nSuccess);
1216 if (nSuccess) {
1217 *pnquality = atoi(s);
1218 }
1219 }
1220 }
1221 }
1222
1223 double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1224
1225 if (poSRecord->FindField("SG2D") != NULL) {
1226 dfX = poSRecord->GetIntSubfield("SG2D", 0, "XCOO", 0) / (double)nCOMF;
1227 dfY = poSRecord->GetIntSubfield("SG2D", 0, "YCOO", 0) / (double)nCOMF;
1228 } else if (poSRecord->FindField("SG3D") != NULL) {
1229 dfX = poSRecord->GetIntSubfield("SG3D", 0, "XCOO", 0) / (double)nCOMF;
1230 dfY = poSRecord->GetIntSubfield("SG3D", 0, "YCOO", 0) / (double)nCOMF;
1231 dfZ = poSRecord->GetIntSubfield("SG3D", 0, "VE3D", 0) / (double)nSOMF;
1232 } else
1233 return FALSE;
1234
1235 if (pdfX != NULL) *pdfX = dfX;
1236 if (pdfY != NULL) *pdfY = dfY;
1237 if (pdfZ != NULL) *pdfZ = dfZ;
1238
1239 return TRUE;
1240}
1241
1242/************************************************************************/
1243/* AssemblePointGeometry() */
1244/************************************************************************/
1245
1246void S57Reader::AssemblePointGeometry(DDFRecord *poFRecord,
1247 OGRFeature *poFeature)
1248
1249{
1250 DDFField *poFSPT;
1251 int nRCNM, nRCID;
1252
1253 /* -------------------------------------------------------------------- */
1254 /* Feature the spatial record containing the point. */
1255 /* -------------------------------------------------------------------- */
1256 poFSPT = poFRecord->FindField("FSPT");
1257 if (poFSPT == NULL) return;
1258
1259 if (poFSPT->GetRepeatCount() != 1) {
1260#ifdef DEBUG
1261 fprintf(stderr, "Point features with other than one spatial linkage.\n");
1262 poFRecord->Dump(stderr);
1263#endif
1264 CPLDebug("S57",
1265 "Point feature encountered with other than one spatial linkage.");
1266 }
1267
1268 nRCID = ParseName(poFSPT, 0, &nRCNM);
1269
1270 double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1271
1272 int nquality = 10; // default is "precisely known"
1273 if (!FetchPoint(nRCNM, nRCID, &dfX, &dfY, &dfZ, &nquality)) {
1274 CPLAssert(FALSE);
1275 return;
1276 }
1277
1278 poFeature->SetGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
1279 OGRPoint *pp = (OGRPoint *)poFeature->GetGeometryRef();
1280 pp->setnQual(nquality);
1281}
1282
1283/************************************************************************/
1284/* AssembleSoundingGeometry() */
1285/************************************************************************/
1286
1287void S57Reader::AssembleSoundingGeometry(DDFRecord *poFRecord,
1288 OGRFeature *poFeature)
1289
1290{
1291 DDFField *poFSPT;
1292 int nRCNM, nRCID;
1293 DDFRecord *poSRecord;
1294
1295 /* -------------------------------------------------------------------- */
1296 /* Feature the spatial record containing the point. */
1297 /* -------------------------------------------------------------------- */
1298 poFSPT = poFRecord->FindField("FSPT");
1299 if (poFSPT == NULL) return;
1300
1301 CPLAssert(poFSPT->GetRepeatCount() == 1);
1302
1303 nRCID = ParseName(poFSPT, 0, &nRCNM);
1304
1305 if (nRCNM == RCNM_VI)
1306 poSRecord = oVI_Index.FindRecord(nRCID);
1307 else
1308 poSRecord = oVC_Index.FindRecord(nRCID);
1309
1310 if (poSRecord == NULL) return;
1311
1312 /* -------------------------------------------------------------------- */
1313 /* Extract vertices. */
1314 /* -------------------------------------------------------------------- */
1315 OGRMultiPoint *poMP = new OGRMultiPoint();
1316 DDFField *poField;
1317 int nPointCount, i, nBytesLeft;
1318 DDFSubfieldDefn *poXCOO, *poYCOO, *poVE3D;
1319 const char *pachData;
1320
1321 poField = poSRecord->FindField("SG2D");
1322 if (poField == NULL) poField = poSRecord->FindField("SG3D");
1323 if (poField == NULL) return;
1324
1325 poXCOO = poField->GetFieldDefn()->FindSubfieldDefn("XCOO");
1326 poYCOO = poField->GetFieldDefn()->FindSubfieldDefn("YCOO");
1327 poVE3D = poField->GetFieldDefn()->FindSubfieldDefn("VE3D");
1328
1329 nPointCount = poField->GetRepeatCount();
1330
1331 pachData = poField->GetData();
1332 nBytesLeft = poField->GetDataSize();
1333
1334 for (i = 0; i < nPointCount; i++) {
1335 double dfX, dfY, dfZ = 0.0;
1336 int nBytesConsumed;
1337
1338 dfY = poYCOO->ExtractIntData(pachData, nBytesLeft, &nBytesConsumed) /
1339 (double)nCOMF;
1340 nBytesLeft -= nBytesConsumed;
1341 pachData += nBytesConsumed;
1342
1343 dfX = poXCOO->ExtractIntData(pachData, nBytesLeft, &nBytesConsumed) /
1344 (double)nCOMF;
1345 nBytesLeft -= nBytesConsumed;
1346 pachData += nBytesConsumed;
1347
1348 if (poVE3D != NULL) {
1349 dfZ = poYCOO->ExtractIntData(pachData, nBytesLeft, &nBytesConsumed) /
1350 (double)nSOMF;
1351 nBytesLeft -= nBytesConsumed;
1352 pachData += nBytesConsumed;
1353 }
1354
1355 poMP->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
1356 }
1357
1358 poFeature->SetGeometryDirectly(poMP);
1359}
1360
1361/************************************************************************/
1362/* AssembleLineGeometry() */
1363/************************************************************************/
1364
1365void S57Reader::AssembleLineGeometry(DDFRecord *poFRecord,
1366 OGRFeature *poFeature)
1367
1368{
1369 DDFField *poFSPT;
1370 int nEdgeCount;
1371 OGRLineString *poLine = new OGRLineString();
1372
1373 /* -------------------------------------------------------------------- */
1374 /* Find the FSPT field. */
1375 /* -------------------------------------------------------------------- */
1376 poFSPT = poFRecord->FindField("FSPT");
1377 if (poFSPT == NULL) return;
1378
1379 nEdgeCount = poFSPT->GetRepeatCount();
1380
1381 /* ==================================================================== */
1382 /* Loop collecting edges. */
1383 /* ==================================================================== */
1384 for (int iEdge = 0; iEdge < nEdgeCount; iEdge++) {
1385 DDFRecord *poSRecord;
1386 int nRCID;
1387
1388 /* -------------------------------------------------------------------- */
1389 /* Find the spatial record for this edge. */
1390 /* -------------------------------------------------------------------- */
1391 nRCID = ParseName(poFSPT, iEdge);
1392
1393 poSRecord = oVE_Index.FindRecord(nRCID);
1394 if (poSRecord == NULL) {
1395 CPLError(CE_Warning, CPLE_AppDefined,
1396 "Couldn't find spatial record %d.\n"
1397 "Feature OBJL=%s, RCID=%d may have corrupt or"
1398 "missing geometry.",
1399 nRCID, poFeature->GetDefnRef()->GetName(),
1400 poFRecord->GetIntSubfield("FRID", 0, "RCID", 0));
1401 continue;
1402 }
1403
1404 /* -------------------------------------------------------------------- */
1405 /* Establish the number of vertices, and whether we need to */
1406 /* reverse or not. */
1407 /* -------------------------------------------------------------------- */
1408 int nVCount;
1409 int nStart, nEnd, nInc;
1410 DDFField *poSG2D = poSRecord->FindField("SG2D");
1411 DDFSubfieldDefn *poXCOO = NULL, *poYCOO = NULL;
1412
1413 if (poSG2D != NULL) {
1414 poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
1415 poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
1416
1417 nVCount = poSG2D->GetRepeatCount();
1418 } else
1419 nVCount = 0;
1420
1421 DDFField *poField = poSRecord->FindField("VRPT");
1422 int nVC_RCID0 = 0;
1423 int nVC_RCID1 = 0;
1424 int nVC_RCIDStart, nVC_RCIDEnd;
1425
1426 if (poField == NULL) {
1427 CPLError(CE_Warning, CPLE_AppDefined,
1428 "Couldn't find field VRPT in spatial record %d.\n"
1429 "Feature OBJL=%s, RCID=%d may have corrupt or"
1430 "missing geometry.",
1431 nRCID, poFeature->GetDefnRef()->GetName(),
1432 poFRecord->GetIntSubfield("FRID", 0, "RCID", 0));
1433 continue;
1434 }
1435
1436 if (poField->GetRepeatCount() > 1) {
1437 nVC_RCID0 = ParseName(poField, 0);
1438 nVC_RCID1 = ParseName(poField, 1);
1439 } else {
1440 nVC_RCID0 = ParseName(poField, 0);
1441 DDFField *poFieldEnd = poSRecord->FindField("VRPT", 1);
1442 if (poFieldEnd) nVC_RCID1 = ParseName(poFieldEnd, 0);
1443 }
1444
1445 if (poFRecord->GetIntSubfield("FSPT", 0, "ORNT", iEdge) == 2) {
1446 nStart = nVCount - 1;
1447 nEnd = 0;
1448 nInc = -1;
1449 nVC_RCIDStart = nVC_RCID1; // reversed
1450 nVC_RCIDEnd = nVC_RCID0;
1451 } else {
1452 nStart = 0;
1453 nEnd = nVCount - 1;
1454 nInc = 1;
1455 nVC_RCIDStart = nVC_RCID0;
1456 nVC_RCIDEnd = nVC_RCID1;
1457 }
1458
1459 /* -------------------------------------------------------------------- */
1460 /* Add the start node, if this is the first edge. */
1461 /* -------------------------------------------------------------------- */
1462 if (iEdge == 0) {
1463 int nVC_RCID = 0;
1464 double dfX, dfY;
1465 /*
1466 if(poField)
1467 {
1468 if( nInc == 1 )
1469 nVC_RCID = ParseName( poField, 0 );
1470 else
1471 nVC_RCID = ParseName( poField, 1 );
1472 }
1473 */
1474
1475 if (FetchPoint(RCNM_VC, nVC_RCIDStart, &dfX, &dfY))
1476 poLine->addPoint(dfX, dfY);
1477 else
1478 CPLError(CE_Warning, CPLE_AppDefined,
1479 "Unable to fetch start node RCID%d.\n"
1480 "Feature OBJL=%s, RCID=%d may have corrupt or"
1481 " missing geometry.",
1482 nVC_RCID, poFeature->GetDefnRef()->GetName(),
1483 poFRecord->GetIntSubfield("FRID", 0, "RCID", 0));
1484 }
1485
1486 /* -------------------------------------------------------------------- */
1487 /* Collect the vertices. */
1488 /* -------------------------------------------------------------------- */
1489 int nVBase = poLine->getNumPoints();
1490
1491 if (nVCount == 1) {
1492 int jpt = 0;
1493 while (poSRecord->FindField("SG2D", jpt)) {
1494 poLine->addPoint(
1495 poSRecord->GetIntSubfield("SG2D", jpt, "XCOO", 0) / (double)nCOMF,
1496 poSRecord->GetIntSubfield("SG2D", jpt, "YCOO", 0) / (double)nCOMF);
1497 jpt++;
1498 }
1499 } else {
1500 poLine->setNumPoints(nVCount + nVBase);
1501
1502 for (int i = nStart; i != nEnd + nInc; i += nInc) {
1503 double dfX, dfY;
1504 const char *pachData;
1505 int nBytesRemaining;
1506
1507 pachData = poSG2D->GetSubfieldData(poXCOO, &nBytesRemaining, i);
1508
1509 dfX = poXCOO->ExtractIntData(pachData, nBytesRemaining, NULL) /
1510 (double)nCOMF;
1511
1512 pachData = poSG2D->GetSubfieldData(poYCOO, &nBytesRemaining, i);
1513
1514 dfY = poXCOO->ExtractIntData(pachData, nBytesRemaining, NULL) /
1515 (double)nCOMF;
1516
1517 poLine->setPoint(nVBase++, dfX, dfY);
1518 }
1519 }
1520
1521 /* -------------------------------------------------------------------- */
1522 /* Add the end node. */
1523 /* -------------------------------------------------------------------- */
1524 {
1525 int nVC_RCID = 0;
1526 double dfX, dfY;
1527 /*
1528 if(poField)
1529 {
1530 if( nInc == 1 )
1531 nVC_RCID = ParseName( poField, 1 );
1532 else
1533 nVC_RCID = ParseName( poField, 0 );
1534 }
1535 */
1536 if (FetchPoint(RCNM_VC, nVC_RCIDEnd, &dfX, &dfY))
1537 poLine->addPoint(dfX, dfY);
1538 else
1539 CPLError(CE_Warning, CPLE_AppDefined,
1540 "Unable to fetch end node RCID=%d.\n"
1541 "Feature OBJL=%s, RCID=%d may have corrupt or"
1542 " missing geometry.",
1543 nVC_RCID, poFeature->GetDefnRef()->GetName(),
1544 poFRecord->GetIntSubfield("FRID", 0, "RCID", 0));
1545 }
1546 }
1547
1548 if (poLine->getNumPoints() >= 2)
1549 poFeature->SetGeometryDirectly(poLine);
1550 else
1551 delete poLine;
1552}
1553
1554/************************************************************************/
1555/* AssembleAreaGeometry() */
1556/************************************************************************/
1557
1558void S57Reader::AssembleAreaGeometry(DDFRecord *poFRecord,
1559 OGRFeature *poFeature)
1560
1561{
1562 DDFField *poFSPT;
1563 OGRGeometryCollection *poLines = new OGRGeometryCollection();
1564 // poFRecord->Dump(stdout);
1565 /* -------------------------------------------------------------------- */
1566 /* Find the FSPT fields. */
1567 /* -------------------------------------------------------------------- */
1568 for (int iFSPT = 0; (poFSPT = poFRecord->FindField("FSPT", iFSPT)) != NULL;
1569 iFSPT++) {
1570 int nEdgeCount;
1571
1572 nEdgeCount = poFSPT->GetRepeatCount();
1573
1574 /* ==================================================================== */
1575 /* Loop collecting edges. */
1576 /* ==================================================================== */
1577 for (int iEdge = 0; iEdge < nEdgeCount; iEdge++) {
1578 DDFRecord *poSRecord;
1579 int nRCID;
1580
1581 /* -------------------------------------------------------------------- */
1582 /* Find the spatial record for this edge. */
1583 /* -------------------------------------------------------------------- */
1584 nRCID = ParseName(poFSPT, iEdge);
1585
1586 poSRecord = oVE_Index.FindRecord(nRCID);
1587 if (poSRecord == NULL) {
1588 CPLError(CE_Warning, CPLE_AppDefined,
1589 "Couldn't find spatial record %d.", nRCID);
1590 continue;
1591 }
1592
1593 /* -------------------------------------------------------------------- */
1594 /* Establish the number of vertices, and whether we need to */
1595 /* reverse or not. */
1596 /* -------------------------------------------------------------------- */
1597 // poSRecord->Dump(stdout);
1598
1599 OGRLineString *poLine = new OGRLineString();
1600
1601 int nVCount;
1602 int nStart, nEnd, nInc;
1603 DDFField *poSG2D = poSRecord->FindField("SG2D");
1604 DDFSubfieldDefn *poXCOO = NULL, *poYCOO = NULL;
1605
1606 if (poSG2D != NULL) {
1607 poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
1608 poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
1609
1610 nVCount = poSG2D->GetRepeatCount();
1611 } else
1612 nVCount = 0;
1613
1614 DDFField *poField = poSRecord->FindField("VRPT");
1615 int nVC_RCID0 = 0;
1616 int nVC_RCID1 = 0;
1617 int nVC_RCIDStart, nVC_RCIDEnd;
1618
1619 if (poField && poField->GetRepeatCount() > 1) {
1620 nVC_RCID0 = ParseName(poField, 0);
1621 nVC_RCID1 = ParseName(poField, 1);
1622 } else {
1623 if (poField) nVC_RCID0 = ParseName(poField, 0);
1624 DDFField *poFieldEnd = poSRecord->FindField("VRPT", 1);
1625 if (poFieldEnd) nVC_RCID1 = ParseName(poFieldEnd, 0);
1626 }
1627
1628 if (poFRecord->GetIntSubfield("FSPT", 0, "ORNT", iEdge) == 2) {
1629 nStart = nVCount - 1;
1630 nEnd = 0;
1631 nInc = -1;
1632 nVC_RCIDStart = nVC_RCID1; // reversed
1633 nVC_RCIDEnd = nVC_RCID0;
1634 } else {
1635 nStart = 0;
1636 nEnd = nVCount - 1;
1637 nInc = 1;
1638 nVC_RCIDStart = nVC_RCID0;
1639 nVC_RCIDEnd = nVC_RCID1;
1640 }
1641
1642 /* -------------------------------------------------------------------- */
1643 /* Add the start node. */
1644 /* -------------------------------------------------------------------- */
1645 {
1646 double dfX, dfY;
1647
1648 if (FetchPoint(RCNM_VC, nVC_RCIDStart, &dfX, &dfY))
1649 poLine->addPoint(dfX, dfY);
1650 }
1651
1652 /* -------------------------------------------------------------------- */
1653 /* Collect the vertices. */
1654 /* -------------------------------------------------------------------- */
1655 int nVBase = poLine->getNumPoints();
1656
1657 if (nVCount == 1) {
1658 int jpt = 0;
1659 while (poSRecord->FindField("SG2D", jpt)) {
1660 poLine->addPoint(
1661 poSRecord->GetIntSubfield("SG2D", jpt, "XCOO", 0) / (double)nCOMF,
1662 poSRecord->GetIntSubfield("SG2D", jpt, "YCOO", 0) /
1663 (double)nCOMF);
1664 jpt++;
1665 }
1666 } else {
1667 poLine->setNumPoints(nVCount + nVBase);
1668
1669 for (int i = nStart; i != nEnd + nInc; i += nInc) {
1670 double dfX, dfY;
1671 const char *pachData;
1672 int nBytesRemaining;
1673
1674 pachData = poSG2D->GetSubfieldData(poXCOO, &nBytesRemaining, i);
1675
1676 dfX = poXCOO->ExtractIntData(pachData, nBytesRemaining, NULL) /
1677 (double)nCOMF;
1678
1679 pachData = poSG2D->GetSubfieldData(poYCOO, &nBytesRemaining, i);
1680
1681 dfY = poXCOO->ExtractIntData(pachData, nBytesRemaining, NULL) /
1682 (double)nCOMF;
1683
1684 poLine->setPoint(nVBase++, dfX, dfY);
1685 }
1686 }
1687 /* -------------------------------------------------------------------- */
1688 /* Add the end node. */
1689 /* -------------------------------------------------------------------- */
1690 {
1691 double dfX, dfY;
1692
1693 if (FetchPoint(RCNM_VC, nVC_RCIDEnd, &dfX, &dfY))
1694 poLine->addPoint(dfX, dfY);
1695 }
1696
1697 poLines->addGeometryDirectly(poLine);
1698 }
1699 }
1700
1701 /* -------------------------------------------------------------------- */
1702 /* Build lines into a polygon. */
1703 /* -------------------------------------------------------------------- */
1704 OGRPolygon *poPolygon;
1705 OGRErr eErr;
1706
1707 poPolygon = (OGRPolygon *)OGRBuildPolygonFromEdges((OGRGeometryH)poLines,
1708 TRUE, FALSE, 0.0, &eErr);
1709 if (eErr != OGRERR_NONE) {
1710 CPLError(CE_Warning, CPLE_AppDefined,
1711 "Polygon assembly has failed for feature FIDN=%d,FIDS=%d.\n"
1712 "Geometry may be missing or incomplete.",
1713 poFeature->GetFieldAsInteger("FIDN"),
1714 poFeature->GetFieldAsInteger("FIDS"));
1715 }
1716
1717 delete poLines;
1718
1719 if (poPolygon != NULL) poFeature->SetGeometryDirectly(poPolygon);
1720}
1721
1722/************************************************************************/
1723/* FindFDefn() */
1724/* */
1725/* Find the OGRFeatureDefn corresponding to the passed feature */
1726/* record. It will search based on geometry class, or object */
1727/* class depending on the bClassBased setting. */
1728/************************************************************************/
1729
1730OGRFeatureDefn *S57Reader::FindFDefn(DDFRecord *poRecord)
1731
1732{
1733 if (poRegistrar != NULL) {
1734 int nOBJL = poRecord->GetIntSubfield("FRID", 0, "OBJL", 0);
1735
1736 if (!poRegistrar->SelectClass(nOBJL)) {
1737 for (int i = 0; i < nFDefnCount; i++) {
1738 if (EQUAL(papoFDefnList[i]->GetName(), "Generic"))
1739 return papoFDefnList[i];
1740 }
1741 return NULL;
1742 }
1743
1744 for (int i = 0; i < nFDefnCount; i++) {
1745 if (EQUAL(papoFDefnList[i]->GetName(), poRegistrar->GetAcronym()))
1746 return papoFDefnList[i];
1747 }
1748
1749 return NULL;
1750 } else {
1751 int nPRIM = poRecord->GetIntSubfield("FRID", 0, "PRIM", 0);
1752 OGRwkbGeometryType eGType;
1753
1754 if (nPRIM == PRIM_P)
1755 eGType = wkbPoint;
1756 else if (nPRIM == PRIM_L)
1757 eGType = wkbLineString;
1758 else if (nPRIM == PRIM_A)
1759 eGType = wkbPolygon;
1760 else
1761 eGType = wkbNone;
1762
1763 for (int i = 0; i < nFDefnCount; i++) {
1764 if (papoFDefnList[i]->GetGeomType() == eGType) return papoFDefnList[i];
1765 }
1766 }
1767
1768 return NULL;
1769}
1770
1771/************************************************************************/
1772/* ParseName() */
1773/* */
1774/* Pull the RCNM and RCID values from a NAME field. The RCID */
1775/* is returned and the RCNM can be gotten via the pnRCNM argument. */
1776/************************************************************************/
1777
1778int S57Reader::ParseName(DDFField *poField, int nIndex, int *pnRCNM)
1779
1780{
1781 unsigned char *pabyData;
1782
1783 pabyData = (unsigned char *)poField->GetSubfieldData(
1784 poField->GetFieldDefn()->FindSubfieldDefn("NAME"), NULL, nIndex);
1785
1786 if (pnRCNM != NULL) *pnRCNM = pabyData[0];
1787
1788 return pabyData[1] + pabyData[2] * 256 + pabyData[3] * 256 * 256 +
1789 pabyData[4] * 256 * 256 * 256;
1790}
1791
1792/************************************************************************/
1793/* AddFeatureDefn() */
1794/************************************************************************/
1795
1796void S57Reader::AddFeatureDefn(OGRFeatureDefn *poFDefn)
1797
1798{
1799 nFDefnCount++;
1800 papoFDefnList = (OGRFeatureDefn **)CPLRealloc(
1801 papoFDefnList, sizeof(OGRFeatureDefn *) * nFDefnCount);
1802
1803 papoFDefnList[nFDefnCount - 1] = poFDefn;
1804}
1805
1806/************************************************************************/
1807/* CollectClassList() */
1808/* */
1809/* Establish the list of classes (unique OBJL values) that */
1810/* occur in this dataset. */
1811/************************************************************************/
1812
1813int S57Reader::CollectClassList(int *panClassCount, int nMaxClass)
1814
1815{
1816 int bSuccess = TRUE;
1817
1818 if (!bFileIngested) Ingest();
1819
1820 for (int iFEIndex = 0; iFEIndex < oFE_Index.GetCount(); iFEIndex++) {
1821 DDFRecord *poRecord = oFE_Index.GetByIndex(iFEIndex);
1822 int nOBJL = poRecord->GetIntSubfield("FRID", 0, "OBJL", 0);
1823
1824 if (nOBJL >= nMaxClass)
1825 bSuccess = FALSE;
1826 else
1827 panClassCount[nOBJL]++;
1828 }
1829
1830 return bSuccess;
1831}
1832
1833/************************************************************************/
1834/* ApplyRecordUpdate() */
1835/* */
1836/* Update one target record based on an S-57 update record */
1837/* (RUIN=3). */
1838/************************************************************************/
1839
1840int S57Reader::ApplyRecordUpdate(DDFRecord *poTarget, DDFRecord *poUpdate)
1841
1842{
1843 const char *pszKey = poUpdate->GetField(1)->GetFieldDefn()->GetName();
1844
1845 /* -------------------------------------------------------------------- */
1846 /* Validate versioning. */
1847 /* -------------------------------------------------------------------- */
1848 if (poTarget->GetIntSubfield(pszKey, 0, "RVER", 0) + 1 !=
1849 poUpdate->GetIntSubfield(pszKey, 0, "RVER", 0)) {
1850 CPLError(CE_Warning, CPLE_AppDefined,
1851 "On RecordUpdate, mismatched RVER value for "
1852 "RCNM=%d,RCID=%d...update RVER is %d, target RVER is %d.",
1853 poTarget->GetIntSubfield(pszKey, 0, "RCNM", 0),
1854 poTarget->GetIntSubfield(pszKey, 0, "RCID", 0),
1855 poUpdate->GetIntSubfield(pszKey, 0, "RVER", 0),
1856 poTarget->GetIntSubfield(pszKey, 0, "RVER", 0));
1857
1858 CPLAssert(FALSE);
1859 return FALSE;
1860 }
1861
1862 // More checks for validity
1863 if (poUpdate->FindField("FRID") != NULL) {
1864 /*
1865 int up_FIDN = poUpdate->GetIntSubfield( "FOID", 0, "FIDN", 0 );
1866 int up_FIDS = poUpdate->GetIntSubfield( "FOID", 0, "FIDS", 0 );
1867 int tar_FIDN = poTarget->GetIntSubfield( "FOID", 0, "FIDN", 0 );
1868 int tar_FIDS = poTarget->GetIntSubfield( "FOID", 0, "FIDS", 0 );
1869 if((up_FIDN != tar_FIDN) || (up_FIDS != tar_FIDS))
1870 {
1871 CPLError( CE_Warning, CPLE_AppDefined,
1872 "On RecordUpdate, mismatched FIDN/FIDS.... target FIDN=%d, target
1873 FIDS=%d update FIDN=%d, update FIDS=%d.", tar_FIDN, tar_FIDS, up_FIDN,
1874 up_FIDS);
1875
1876 return FALSE;
1877 }
1878 */
1879 int up_PRIM = poUpdate->GetIntSubfield("FRID", 0, "PRIM", 0);
1880 int tar_PRIM = poTarget->GetIntSubfield("FRID", 0, "PRIM", 0);
1881 if (up_PRIM != tar_PRIM) {
1882 CPLError(
1883 CE_Warning, CPLE_AppDefined,
1884 "On RecordUpdate, mismatched PRIM.... target PRIM=%d, update PRIM=%d",
1885 tar_PRIM, up_PRIM);
1886 return FALSE;
1887 }
1888 }
1889
1890 /* -------------------------------------------------------------------- */
1891 /* Update the target version. */
1892 /* -------------------------------------------------------------------- */
1893 unsigned int *pnRVER;
1894 DDFField *poKey = poTarget->FindField(pszKey);
1895 DDFSubfieldDefn *poRVER_SFD;
1896
1897 if (poKey == NULL) {
1898 CPLAssert(FALSE);
1899 return FALSE;
1900 }
1901
1902 poRVER_SFD = poKey->GetFieldDefn()->FindSubfieldDefn("RVER");
1903 if (poRVER_SFD == NULL) return FALSE;
1904
1905 pnRVER = (unsigned int *)poKey->GetSubfieldData(poRVER_SFD, NULL, 0);
1906
1907 *pnRVER += 1;
1908
1909 /* -------------------------------------------------------------------- */
1910 /* Check for, and apply record record to spatial record pointer */
1911 /* updates. */
1912 /* -------------------------------------------------------------------- */
1913 if (poUpdate->FindField("FSPC") != NULL) {
1914 int nFSUI = poUpdate->GetIntSubfield("FSPC", 0, "FSUI", 0);
1915 int nFSIX = poUpdate->GetIntSubfield("FSPC", 0, "FSIX", 0);
1916 int nNSPT = poUpdate->GetIntSubfield("FSPC", 0, "NSPT", 0);
1917 DDFField *poSrcFSPT = poUpdate->FindField("FSPT");
1918 DDFField *poDstFSPT = poTarget->FindField("FSPT");
1919 int nPtrSize;
1920
1921 if ((poSrcFSPT == NULL && nFSUI != 2) || poDstFSPT == NULL) {
1922 CPLAssert(FALSE);
1923 return FALSE;
1924 }
1925
1926 nPtrSize = poDstFSPT->GetFieldDefn()->GetFixedWidth();
1927
1928 if (nFSUI == 1) /* INSERT */
1929 {
1930 char *pachInsertion;
1931 int nInsertionBytes = nPtrSize * nNSPT;
1932
1933 pachInsertion = (char *)CPLMalloc(nInsertionBytes + nPtrSize);
1934 memcpy(pachInsertion, poSrcFSPT->GetData(), nInsertionBytes);
1935
1936 /*
1937 ** If we are inserting before an instance that already
1938 ** exists, we must add it to the end of the data being
1939 ** inserted.
1940 */
1941 if (nFSIX <= poDstFSPT->GetRepeatCount()) {
1942 memcpy(pachInsertion + nInsertionBytes,
1943 poDstFSPT->GetData() + nPtrSize * (nFSIX - 1), nPtrSize);
1944 nInsertionBytes += nPtrSize;
1945 }
1946
1947 poTarget->SetFieldRaw(poDstFSPT, nFSIX - 1, pachInsertion,
1948 nInsertionBytes);
1949 CPLFree(pachInsertion);
1950 } else if (nFSUI == 2) /* DELETE */
1951 {
1952 /* Wipe each deleted coordinate */
1953 for (int i = nNSPT - 1; i >= 0; i--) {
1954 poTarget->SetFieldRaw(poDstFSPT, i + nFSIX - 1, NULL, 0);
1955 }
1956 } else if (nFSUI == 3) /* MODIFY */
1957 {
1958 /* copy over each ptr */
1959 for (int i = 0; i < nNSPT; i++) {
1960 const char *pachRawData;
1961
1962 pachRawData = poSrcFSPT->GetData() + nPtrSize * i;
1963
1964 poTarget->SetFieldRaw(poDstFSPT, i + nFSIX - 1, pachRawData, nPtrSize);
1965 }
1966 }
1967 }
1968
1969 /* -------------------------------------------------------------------- */
1970 /* Check for, and apply vector record to vector record pointer */
1971 /* updates. */
1972 /* -------------------------------------------------------------------- */
1973 if (poUpdate->FindField("VRPC") != NULL) {
1974 int nVPUI = poUpdate->GetIntSubfield("VRPC", 0, "VPUI", 0);
1975 int nVPIX = poUpdate->GetIntSubfield("VRPC", 0, "VPIX", 0);
1976 int nNVPT = poUpdate->GetIntSubfield("VRPC", 0, "NVPT", 0);
1977 DDFField *poSrcVRPT = poUpdate->FindField("VRPT");
1978 DDFField *poDstVRPT = poTarget->FindField("VRPT");
1979 int nPtrSize;
1980
1981 if ((poSrcVRPT == NULL && nVPUI != 2) || poDstVRPT == NULL) {
1982 CPLAssert(FALSE);
1983 return FALSE;
1984 }
1985
1986 nPtrSize = poDstVRPT->GetFieldDefn()->GetFixedWidth();
1987
1988 if (nVPUI == 1) /* INSERT */
1989 {
1990 char *pachInsertion;
1991 int nInsertionBytes = nPtrSize * nNVPT;
1992
1993 pachInsertion = (char *)CPLMalloc(nInsertionBytes + nPtrSize);
1994 memcpy(pachInsertion, poSrcVRPT->GetData(), nInsertionBytes);
1995
1996 /*
1997 ** If we are inserting before an instance that already
1998 ** exists, we must add it to the end of the data being
1999 ** inserted.
2000 */
2001 if (nVPIX <= poDstVRPT->GetRepeatCount()) {
2002 memcpy(pachInsertion + nInsertionBytes,
2003 poDstVRPT->GetData() + nPtrSize * (nVPIX - 1), nPtrSize);
2004 nInsertionBytes += nPtrSize;
2005 }
2006
2007 poTarget->SetFieldRaw(poDstVRPT, nVPIX - 1, pachInsertion,
2008 nInsertionBytes);
2009 CPLFree(pachInsertion);
2010 } else if (nVPUI == 2) /* DELETE */
2011 {
2012 /* Wipe each deleted coordinate */
2013 for (int i = nNVPT - 1; i >= 0; i--) {
2014 poTarget->SetFieldRaw(poDstVRPT, i + nVPIX - 1, NULL, 0);
2015 }
2016 } else if (nVPUI == 3) /* MODIFY */
2017 {
2018 /* copy over each ptr */
2019 for (int i = 0; i < nNVPT; i++) {
2020 const char *pachRawData;
2021
2022 pachRawData = poSrcVRPT->GetData() + nPtrSize * i;
2023
2024 poTarget->SetFieldRaw(poDstVRPT, i + nVPIX - 1, pachRawData, nPtrSize);
2025 }
2026 }
2027 }
2028
2029 /* -------------------------------------------------------------------- */
2030 /* Check for, and apply record update to coordinates. */
2031 /* -------------------------------------------------------------------- */
2032 if (poUpdate->FindField("SGCC") != NULL) {
2033 int nCCUI = poUpdate->GetIntSubfield("SGCC", 0, "CCUI", 0);
2034 int nCCIX = poUpdate->GetIntSubfield("SGCC", 0, "CCIX", 0);
2035 int nCCNC = poUpdate->GetIntSubfield("SGCC", 0, "CCNC", 0);
2036 DDFField *poSrcSG2D = poUpdate->FindField("SG2D");
2037 DDFField *poDstSG2D = poTarget->FindField("SG2D");
2038 int nCoordSize;
2039
2040 /* If we don't have SG2D, check for SG3D */
2041 if (poDstSG2D == NULL) {
2042 poDstSG2D = poTarget->FindField("SG3D");
2043 if (poDstSG2D != NULL) {
2044 poSrcSG2D = poUpdate->FindField("SG3D");
2045 }
2046 }
2047
2048 if (poDstSG2D == NULL && nCCUI == 2) {
2049 // Trying to delete a coordinate that does not exist...
2050 // Theoretically, this is an error.
2051 // But we have seen this from some HOs, (China/HongKong) and seems to be
2052 // OK to ignore
2053 return TRUE;
2054 }
2055
2056 if ((poSrcSG2D == NULL && nCCUI != 2) ||
2057 (poDstSG2D == NULL && nCCUI != 1)) {
2058 // CPLAssert( FALSE );
2059 return FALSE;
2060 }
2061
2062 if (poDstSG2D == NULL) {
2063 poTarget->AddField(poTarget->GetModule()->FindFieldDefn("SG2D"));
2064 poDstSG2D = poTarget->FindField("SG2D");
2065 if (poDstSG2D == NULL) {
2066 // CPLAssert( FALSE );
2067 return FALSE;
2068 }
2069
2070 // Delete null default data that was created
2071 poTarget->SetFieldRaw(poDstSG2D, 0, NULL, 0);
2072 }
2073
2074 nCoordSize = poDstSG2D->GetFieldDefn()->GetFixedWidth();
2075
2076 if (nCCUI == 1) /* INSERT */
2077 {
2078 char *pachInsertion;
2079 int nInsertionBytes = nCoordSize * nCCNC;
2080
2081 pachInsertion = (char *)CPLMalloc(nInsertionBytes + nCoordSize);
2082 memcpy(pachInsertion, poSrcSG2D->GetData(), nInsertionBytes);
2083
2084 /*
2085 ** If we are inserting before an instance that already
2086 ** exists, we must add it to the end of the data being
2087 ** inserted.
2088 */
2089 if (nCCIX <= poDstSG2D->GetRepeatCount()) {
2090 memcpy(pachInsertion + nInsertionBytes,
2091 poDstSG2D->GetData() + nCoordSize * (nCCIX - 1), nCoordSize);
2092 nInsertionBytes += nCoordSize;
2093 }
2094
2095 poTarget->SetFieldRaw(poDstSG2D, nCCIX - 1, pachInsertion,
2096 nInsertionBytes);
2097 CPLFree(pachInsertion);
2098
2099 } else if (nCCUI == 2) /* DELETE */
2100 {
2101 /* Wipe each deleted coordinate */
2102 for (int i = nCCNC - 1; i >= 0; i--) {
2103 poTarget->SetFieldRaw(poDstSG2D, i + nCCIX - 1, NULL, 0);
2104 }
2105 } else if (nCCUI == 3) /* MODIFY */
2106 {
2107 /* copy over each ptr */
2108 for (int i = 0; i < nCCNC; i++) {
2109 const char *pachRawData;
2110
2111 pachRawData = poSrcSG2D->GetData() + nCoordSize * i;
2112
2113 poTarget->SetFieldRaw(poDstSG2D, i + nCCIX - 1, pachRawData,
2114 nCoordSize);
2115 }
2116 }
2117 }
2118
2119 /* -------------------------------------------------------------------- */
2120 /* We don't currently handle FFPC (feature to feature linkage) */
2121 /* issues, but we will at least report them when debugging. */
2122 /* -------------------------------------------------------------------- */
2123 /*
2124 if( poUpdate->FindField( "FFPC" ) != NULL )
2125 {
2126 CPLDebug( "S57", "Found FFPC, but not applying it." );
2127 }
2128 */
2129 /* -------------------------------------------------------------------- */
2130 /* Check for and apply changes to attribute lists. */
2131 /* -------------------------------------------------------------------- */
2132 if (poUpdate->FindField("ATTF") != NULL) {
2133 bool b_newField = false;
2134 DDFSubfieldDefn *poSrcATVLDefn;
2135 DDFField *poSrcATTF = poUpdate->FindField("ATTF");
2136 DDFField *poDstATTF = poTarget->FindField("ATTF");
2137
2138 if (NULL == poDstATTF) {
2139 // This probably means that the update applies to an attribute that
2140 // doesn't (yet) exist To fix, we need to add an attribute, then update
2141 // it.
2142
2143 DDFFieldDefn *poATTF = poTarget->GetModule()->FindFieldDefn("ATTF");
2144 poTarget->AddField(poATTF);
2145 poDstATTF = poTarget->FindField("ATTF");
2146 b_newField = true;
2147 }
2148
2149 int nRepeatCount = poSrcATTF->GetRepeatCount();
2150
2151 poSrcATVLDefn = poSrcATTF->GetFieldDefn()->FindSubfieldDefn("ATVL");
2152
2153 for (int iAtt = 0; iAtt < nRepeatCount; iAtt++) {
2154 int nATTL = poUpdate->GetIntSubfield("ATTF", 0, "ATTL", iAtt);
2155 int iTAtt, nDataBytes;
2156 const char *pszRawData;
2157
2158 for (iTAtt = poDstATTF->GetRepeatCount() - 1; iTAtt >= 0; iTAtt--) {
2159 if (poTarget->GetIntSubfield("ATTF", 0, "ATTL", iTAtt) == nATTL) break;
2160 }
2161 if (iTAtt == -1) iTAtt = poDstATTF->GetRepeatCount();
2162
2163 // If we just added a new field above, then the first attribute will be
2164 // 0.
2165 // We should replace this one
2166 if (b_newField) {
2167 if (poTarget->GetIntSubfield("ATTF", 0, "ATTL", 0) == 0) {
2168 iTAtt = 0;
2169 b_newField = false;
2170 }
2171 }
2172
2173 pszRawData = poSrcATTF->GetInstanceData(iAtt, &nDataBytes);
2174 poTarget->SetFieldRaw(poDstATTF, iTAtt, pszRawData, nDataBytes);
2175 }
2176 }
2177
2178 if (poUpdate->FindField("NATF") != NULL) {
2179 bool b_newField = false;
2180 DDFSubfieldDefn *poSrcATVLDefn;
2181 DDFField *poSrcATTF = poUpdate->FindField("NATF");
2182 DDFField *poDstATTF = poTarget->FindField("NATF");
2183
2184 // int up_FIDN = poUpdate->GetIntSubfield( "FOID", 0, "FIDN", 0 );
2185 // if(up_FIDN == 1103712044 /*1225530334*/){
2186 // poTarget->Dump(stdout);
2187 // }
2188
2189 if (NULL == poDstATTF) {
2190 // This probably means that the update applies to an attribute that
2191 // doesn't (yet) exist To fix, we need to add an attribute, then update
2192 // it.
2193
2194 DDFFieldDefn *poNATF = poTarget->GetModule()->FindFieldDefn("NATF");
2195 poTarget->AddField(poNATF);
2196 poDstATTF = poTarget->FindField("NATF");
2197 b_newField = true;
2198
2199 // poTarget->Dump(stdout);
2200
2201 // CPLDebug( "S57","Could not find target ATTF field for
2202 // attribute update");
2203 // return FALSE;
2204 }
2205
2206 int nRepeatCount = poSrcATTF->GetRepeatCount();
2207
2208 poSrcATVLDefn = poSrcATTF->GetFieldDefn()->FindSubfieldDefn("ATVL");
2209
2210 for (int iAtt = 0; iAtt < nRepeatCount; iAtt++) {
2211 int nATTL = poUpdate->GetIntSubfield("NATF", 0, "ATTL", iAtt);
2212 int iTAtt, nDataBytes;
2213 const char *pszRawData;
2214
2215 for (iTAtt = poDstATTF->GetRepeatCount() - 1; iTAtt >= 0; iTAtt--) {
2216 if (poTarget->GetIntSubfield("NATF", 0, "ATTL", iTAtt) == nATTL) break;
2217 }
2218 if (iTAtt == -1) iTAtt = poDstATTF->GetRepeatCount();
2219
2220 // If we just added a new field above, then the first attribute will be
2221 // 0.
2222 // We should replace this one
2223 if (b_newField) {
2224 if (poTarget->GetIntSubfield("NATF", 0, "ATTL", 0) == 0) {
2225 iTAtt = 0;
2226 b_newField = false;
2227 }
2228 }
2229
2230 pszRawData = poSrcATTF->GetInstanceData(iAtt, &nDataBytes);
2231
2232 // poTarget->Dump(stdout);
2233 poTarget->SetFieldRaw(poDstATTF, iTAtt, pszRawData, nDataBytes);
2234 // poTarget->Dump(stdout);
2235 }
2236 }
2237
2238 return TRUE;
2239}
2240
2241/************************************************************************/
2242/* ApplyUpdates() */
2243/* */
2244/* Read records from an update file, and apply them to the */
2245/* currently loaded index of features. */
2246/************************************************************************/
2247
2248int S57Reader::ApplyUpdates(DDFModule *poUpdateModule, int iUpdate)
2249
2250{
2251 DDFRecord *poRecord;
2252
2253 int ret_code = 0;
2254
2255 /* -------------------------------------------------------------------- */
2256 /* Ensure base file is loaded. */
2257 /* -------------------------------------------------------------------- */
2258 Ingest();
2259
2260 /* -------------------------------------------------------------------- */
2261 /* Read records, and apply as updates. */
2262 /* -------------------------------------------------------------------- */
2263 while ((poRecord = poUpdateModule->ReadRecord()) != NULL) {
2264 DDFField *poKeyField = poRecord->GetField(1);
2265 const char *pszKey = poKeyField->GetFieldDefn()->GetName();
2266
2267 if (EQUAL(pszKey, "VRID") || EQUAL(pszKey, "FRID")) {
2268 int nRCNM = poRecord->GetIntSubfield(pszKey, 0, "RCNM", 0);
2269 int nRCID = poRecord->GetIntSubfield(pszKey, 0, "RCID", 0);
2270 int nRVER = poRecord->GetIntSubfield(pszKey, 0, "RVER", 0);
2271 int nRUIN = poRecord->GetIntSubfield(pszKey, 0, "RUIN", 0);
2272 DDFRecordIndex *poIndex = NULL;
2273
2274 if (EQUAL(poKeyField->GetFieldDefn()->GetName(), "VRID")) {
2275 switch (nRCNM) {
2276 case RCNM_VI:
2277 poIndex = &oVI_Index;
2278 break;
2279
2280 case RCNM_VC:
2281 poIndex = &oVC_Index;
2282 break;
2283
2284 case RCNM_VE:
2285 poIndex = &oVE_Index;
2286 break;
2287
2288 case RCNM_VF:
2289 poIndex = &oVF_Index;
2290 break;
2291
2292 default:
2293 CPLAssert(FALSE);
2294 break;
2295 }
2296 } else {
2297 poIndex = &oFE_Index;
2298 }
2299
2300 if (poIndex != NULL) {
2301 if (nRUIN == 1) /* insert */
2302 {
2303 // CPLDebug( "S57","Insert Record, RCID=%d",
2304 // nRCID);
2305 poIndex->AddRecord(nRCID, poRecord->CloneOn(poModule));
2306 } else if (nRUIN == 2) /* delete */
2307 {
2308 // CPLDebug( "S57","Remove Record, RCID=%d",
2309 // nRCID);
2310 DDFRecord *poTarget;
2311
2312 poTarget = poIndex->FindRecord(nRCID);
2313 if (poTarget == NULL) {
2314 CPLError(CE_Warning, CPLE_AppDefined,
2315 "While applying update %d, Can't find RCNM=%d,RCID=%d for "
2316 "delete.",
2317 iUpdate, nRCNM, nRCID);
2318 ret_code = BAD_UPDATE;
2319 } else if (poTarget->GetIntSubfield(pszKey, 0, "RVER", 0) !=
2320 nRVER - 1) {
2321 CPLError(CE_Warning, CPLE_AppDefined,
2322 "While applying update %d, On RecordRemove, mismatched "
2323 "RVER value for RCNM=%d,RCID=%d...update RVER is %d, "
2324 "target RVER is %d.",
2325 iUpdate, nRCNM, nRCID, nRVER,
2326 poTarget->GetIntSubfield(pszKey, 0, "RVER", 0));
2327 CPLError(
2328 CE_Warning, CPLE_AppDefined,
2329 "While applying update %d, Removal of RCNM=%d,RCID=%d failed.",
2330 iUpdate, nRCNM, nRCID);
2331 ret_code = BAD_UPDATE;
2332
2333 } else {
2334 poIndex->RemoveRecord(nRCID);
2335 }
2336 }
2337
2338 else if (nRUIN == 3) /* modify in place */
2339 {
2340 // CPLDebug( "S57","Update Record, RCID=%d",
2341 // nRCID);
2342 DDFRecord *poTarget;
2343
2344 poTarget = poIndex->FindRecord(nRCID);
2345 if (poTarget == NULL) {
2346 CPLError(CE_Warning, CPLE_AppDefined,
2347 "While applying update %d, Can't find RCNM=%d,RCID=%d for "
2348 "update.",
2349 iUpdate, nRCNM, nRCID);
2350 ret_code = BAD_UPDATE;
2351
2352 } else {
2353 if (!ApplyRecordUpdate(poTarget, poRecord)) {
2354 CPLError(CE_Warning, CPLE_AppDefined,
2355 "While applying update %d, an update to RCNM=%d,RCID=%d "
2356 "failed.",
2357 iUpdate, nRCNM, nRCID);
2358 ret_code = BAD_UPDATE;
2359 }
2360 }
2361 }
2362 }
2363 }
2364
2365 else if (EQUAL(pszKey, "DSID")) {
2366 /* Check for canceled cell */;
2367 char *u = (char *)(poRecord->GetStringSubfield("DSID", 0, "EDTN", 0));
2368 if (!strncmp(u, "0", 1)) {
2369 return BAD_UPDATE;
2370 }
2371 }
2372
2373 else {
2374 CPLDebug("S57",
2375 "While applying update %d, Skipping %s record in "
2376 "S57Reader::ApplyUpdates().",
2377 iUpdate, pszKey);
2378 ret_code = BAD_UPDATE;
2379 }
2380 }
2381
2382 return ret_code;
2383}
2384
2385/************************************************************************/
2386/* FindAndApplyUpdates() */
2387/* */
2388/* Find all update files that would appear to apply to this */
2389/* base file. */
2390/************************************************************************/
2391
2392int S57Reader::FindAndApplyUpdates(const char *pszPath)
2393
2394{
2395 int iUpdate;
2396 int bSuccess = TRUE;
2397 int ret_code = 0;
2398
2399 if (pszPath == NULL) pszPath = pszModuleName;
2400
2401 if (!EQUAL(CPLGetExtension(pszPath), "000")) {
2402 CPLError(CE_Failure, CPLE_AppDefined,
2403 "Can't apply updates to a base file with a different\n"
2404 "extension than .000.");
2405 return BAD_UPDATE;
2406 }
2407
2408 for (iUpdate = 1; bSuccess; iUpdate++) {
2409 char szExtension[16];
2410 char *pszUpdateFilename;
2411 DDFModule oUpdateModule;
2412
2413 assert(iUpdate <= 999);
2414 sprintf(szExtension, "%03d", iUpdate);
2415
2416 pszUpdateFilename = CPLStrdup(CPLResetExtension(pszPath, szExtension));
2417
2418 bSuccess = oUpdateModule.Open(pszUpdateFilename, TRUE);
2419
2420 if (bSuccess)
2421 CPLDebug("S57", "Applying feature updates from %s.", pszUpdateFilename);
2422 CPLFree(pszUpdateFilename);
2423
2424 if (bSuccess) {
2425 int update_ret = ApplyUpdates(&oUpdateModule, iUpdate);
2426 if (update_ret) {
2427 ret_code = update_ret;
2428 bSuccess = false; // Stop the loop
2429 }
2430 }
2431 }
2432
2433 return ret_code;
2434}
2435
2436/************************************************************************/
2437/* GetExtent() */
2438/* */
2439/* Scan all the cached records collecting spatial bounds as */
2440/* efficiently as possible for this transfer. */
2441/************************************************************************/
2442
2443// Android uses clang compiler.
2444// Problem also appears on GCC, on __ARM_ARCH.
2445// At optimization -O3, this function has trouble with alignment of values,
2446// Specifically, conversion of an int32 from a buffer into double.
2447// Workaround: We disable optimization for this little used function.
2448#ifdef __ARM_ARCH
2449#if defined(__clang__)
2450[[clang::optnone]]
2451#elif defined(__GNUC__) || defined(__GNUG__)
2452#pragma GCC push_options
2453#pragma GCC optimize("O0")
2454
2455#endif
2456#endif
2457
2458OGRErr S57Reader::GetExtent(OGREnvelope *psExtent, int bForce)
2459
2460{
2461#define INDEX_COUNT 4
2462
2463 DDFRecordIndex *apoIndex[INDEX_COUNT];
2464
2465 /* -------------------------------------------------------------------- */
2466 /* If we aren't forced to get the extent say no if we haven't */
2467 /* already indexed the iso8211 records. */
2468 /* -------------------------------------------------------------------- */
2469 if (!bForce && !bFileIngested) return OGRERR_FAILURE;
2470
2471 Ingest();
2472
2473 /* -------------------------------------------------------------------- */
2474 /* We will scan all the low level vector elements for extents */
2475 /* coordinates. */
2476 /* -------------------------------------------------------------------- */
2477 int bGotExtents = FALSE;
2478 double nXMin = 0, nXMax = 0, nYMin = 0, nYMax = 0;
2479
2480 apoIndex[0] = &oVI_Index;
2481 apoIndex[1] = &oVC_Index;
2482 apoIndex[2] = &oVE_Index;
2483 apoIndex[3] = &oVF_Index;
2484
2485 for (int iIndex = 0; iIndex < INDEX_COUNT; iIndex++) {
2486 DDFRecordIndex *poIndex = apoIndex[iIndex];
2487
2488 for (int iVIndex = 0; iVIndex < poIndex->GetCount(); iVIndex++) {
2489 DDFRecord *poRecord = poIndex->GetByIndex(iVIndex);
2490 DDFField *poSG3D = poRecord->FindField("SG3D");
2491 DDFField *poSG2D = poRecord->FindField("SG2D");
2492
2493 if (poSG3D != NULL) {
2494 int i, nVCount = poSG3D->GetRepeatCount();
2495 GInt32 *panData, nX, nY;
2496
2497 panData = (GInt32 *)poSG3D->GetData();
2498 for (i = 0; i < nVCount; i++) {
2499 nX = CPL_LSBWORD32(panData[i * 3 + 1]);
2500 nY = CPL_LSBWORD32(panData[i * 3 + 0]);
2501
2502 double dnX = nX / (double)nCOMF;
2503 double dnY = nY / (double)nCOMF;
2504
2505 if (bGotExtents) {
2506 nXMin = MIN(nXMin, dnX);
2507 nXMax = MAX(nXMax, dnX);
2508 nYMin = MIN(nYMin, dnY);
2509 nYMax = MAX(nYMax, dnY);
2510 } else {
2511 nXMin = nXMax = dnX;
2512 nYMin = nYMax = dnY;
2513 bGotExtents = TRUE;
2514 }
2515 }
2516 } else if (poSG2D != NULL) {
2517 int i, nVCount = poSG2D->GetRepeatCount();
2518 GInt32 *panData, nX, nY;
2519
2520 panData = (GInt32 *)poSG2D->GetData();
2521 for (i = 0; i < nVCount; i++) {
2522 nX = CPL_LSBWORD32(panData[i * 2 + 1]);
2523 nY = CPL_LSBWORD32(panData[i * 2 + 0]);
2524
2525 double dnX = nX / (double)nCOMF;
2526 double dnY = nY / (double)nCOMF;
2527
2528 if (bGotExtents) {
2529 nXMin = MIN(nXMin, dnX);
2530 nXMax = MAX(nXMax, dnX);
2531 nYMin = MIN(nYMin, dnY);
2532 nYMax = MAX(nYMax, dnY);
2533 } else {
2534 nXMin = nXMax = dnX;
2535 nYMin = nYMax = dnY;
2536 bGotExtents = TRUE;
2537 }
2538 }
2539 }
2540 }
2541 }
2542
2543 if (!bGotExtents)
2544 return OGRERR_FAILURE;
2545 else {
2546 psExtent->MinX = nXMin;
2547 psExtent->MaxX = nXMax;
2548 psExtent->MinY = nYMin;
2549 psExtent->MaxY = nYMax;
2550
2551 return OGRERR_NONE;
2552 }
2553}
2554
2555#ifdef __ARM_ARCH
2556#if defined(__GNUC__) || defined(__GNUG__)
2557#pragma GCC pop_options
2558#endif
2559#endif
Declarations for classes binding S57 support onto OGRLayer, OGRDataSource and OGRDriver.
Declarations for S-57 translator not including the binding onto OGRLayer/DataSource/Driver which are ...