Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SDTS Translator
4 : * Purpose: Implementation of SDTSTransfer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "sdts_al.h"
14 :
15 : #include <algorithm>
16 :
17 : /************************************************************************/
18 : /* SDTSTransfer() */
19 : /************************************************************************/
20 :
21 52 : SDTSTransfer::SDTSTransfer()
22 52 : : nLayers(0), panLayerCATDEntry(nullptr), papoLayerReader(nullptr)
23 : {
24 52 : }
25 :
26 : /************************************************************************/
27 : /* ~SDTSTransfer() */
28 : /************************************************************************/
29 :
30 52 : SDTSTransfer::~SDTSTransfer()
31 :
32 : {
33 52 : Close();
34 52 : }
35 :
36 : /************************************************************************/
37 : /* Open() */
38 : /************************************************************************/
39 :
40 : /**
41 : * Open an SDTS transfer, and establish a list of data layers in the
42 : * transfer.
43 : *
44 : * @param pszFilename The name of the CATD file within the transfer.
45 : *
46 : * @return TRUE if the open success, or FALSE if it fails.
47 : */
48 :
49 52 : int SDTSTransfer::Open(const char *pszFilename)
50 :
51 : {
52 : /* -------------------------------------------------------------------- */
53 : /* Open the catalog. */
54 : /* -------------------------------------------------------------------- */
55 52 : if (!oCATD.Read(pszFilename))
56 49 : return FALSE;
57 :
58 : /* -------------------------------------------------------------------- */
59 : /* Read the IREF file. */
60 : /* -------------------------------------------------------------------- */
61 3 : if (oCATD.GetModuleFilePath("IREF") == nullptr)
62 : {
63 0 : CPLError(CE_Failure, CPLE_AppDefined,
64 : "Can't find IREF module in transfer `%s'.\n", pszFilename);
65 0 : return FALSE;
66 : }
67 :
68 3 : if (!oIREF.Read(oCATD.GetModuleFilePath("IREF")))
69 0 : return FALSE;
70 :
71 : /* -------------------------------------------------------------------- */
72 : /* Read the XREF file. */
73 : /* -------------------------------------------------------------------- */
74 3 : if (oCATD.GetModuleFilePath("XREF") == nullptr)
75 : {
76 0 : CPLError(CE_Warning, CPLE_AppDefined,
77 : "Can't find XREF module in transfer `%s'.\n", pszFilename);
78 : }
79 3 : else if (!oXREF.Read(oCATD.GetModuleFilePath("XREF")))
80 : {
81 0 : CPLError(
82 : CE_Warning, CPLE_AppDefined,
83 : "Can't read XREF module, even though found in transfer `%s'.\n",
84 : pszFilename);
85 : }
86 :
87 : /* -------------------------------------------------------------------- */
88 : /* Build an index of layer types we recognise and care about. */
89 : /* -------------------------------------------------------------------- */
90 3 : panLayerCATDEntry =
91 3 : reinterpret_cast<int *>(CPLMalloc(sizeof(int) * oCATD.GetEntryCount()));
92 :
93 63 : for (int iCATDLayer = 0; iCATDLayer < oCATD.GetEntryCount(); iCATDLayer++)
94 : {
95 60 : switch (oCATD.GetEntryType(iCATDLayer))
96 : {
97 10 : case SLTPoint:
98 : case SLTLine:
99 : case SLTAttr:
100 : case SLTPoly:
101 : case SLTRaster:
102 10 : panLayerCATDEntry[nLayers++] = iCATDLayer;
103 10 : break;
104 :
105 50 : default:
106 : /* ignore */
107 50 : break;
108 : }
109 : }
110 :
111 : /* -------------------------------------------------------------------- */
112 : /* Initialized the related indexed readers list. */
113 : /* -------------------------------------------------------------------- */
114 3 : papoLayerReader = reinterpret_cast<SDTSIndexedReader **>(
115 3 : CPLCalloc(sizeof(SDTSIndexedReader *), oCATD.GetEntryCount()));
116 :
117 3 : return TRUE;
118 : }
119 :
120 : /************************************************************************/
121 : /* Close() */
122 : /************************************************************************/
123 :
124 52 : void SDTSTransfer::Close()
125 :
126 : {
127 62 : for (int i = 0; i < nLayers; i++)
128 : {
129 10 : if (papoLayerReader[i] != nullptr)
130 8 : delete papoLayerReader[i];
131 : }
132 52 : CPLFree(papoLayerReader);
133 52 : papoLayerReader = nullptr;
134 52 : CPLFree(panLayerCATDEntry);
135 52 : panLayerCATDEntry = nullptr;
136 52 : nLayers = 0;
137 52 : }
138 :
139 : /************************************************************************/
140 : /* GetLayerType() */
141 : /************************************************************************/
142 :
143 : /**
144 : Fetch type of requested feature layer.
145 :
146 : @param iEntry the index of the layer to fetch information on. A value
147 : from zero to GetLayerCount()-1.
148 :
149 : @return the layer type.
150 :
151 : <ul>
152 : <li> SLTPoint: A point layer. An SDTSPointReader is returned by
153 : SDTSTransfer::GetLayerIndexedReader().
154 :
155 : <li> SLTLine: A line layer. An SDTSLineReader is returned by
156 : SDTSTransfer::GetLayerIndexedReader().
157 :
158 : <li> SLTAttr: An attribute primary or secondary layer. An SDTSAttrReader
159 : is returned by SDTSTransfer::GetLayerIndexedReader().
160 :
161 : <li> SLTPoly: A polygon layer. An SDTSPolygonReader is returned by
162 : SDTSTransfer::GetLayerIndexedReader().
163 :
164 : <li> SLTRaster: A raster layer. SDTSTransfer::GetLayerIndexedReader()
165 : is not implemented. Use SDTSTransfer::GetLayerRasterReader() instead.
166 : </ul>
167 : */
168 :
169 1203 : SDTSLayerType SDTSTransfer::GetLayerType(int iEntry) const
170 :
171 : {
172 1203 : if (iEntry < 0 || iEntry >= nLayers)
173 0 : return SLTUnknown;
174 :
175 1203 : return oCATD.GetEntryType(panLayerCATDEntry[iEntry]);
176 : }
177 :
178 : /************************************************************************/
179 : /* GetLayerCATDEntry() */
180 : /************************************************************************/
181 :
182 : /**
183 : Fetch the CATD module index for a layer. This can be used to fetch
184 : details about the layer/module from the SDTS_CATD object, such as its
185 : filename, and description.
186 :
187 : @param iEntry the layer index from 0 to GetLayerCount()-1.
188 :
189 : @return the module index suitable for use with the various SDTS_CATD
190 : methods.
191 : */
192 :
193 8 : int SDTSTransfer::GetLayerCATDEntry(int iEntry) const
194 :
195 : {
196 8 : if (iEntry < 0 || iEntry >= nLayers)
197 0 : return -1;
198 :
199 8 : return panLayerCATDEntry[iEntry];
200 : }
201 :
202 : /************************************************************************/
203 : /* GetLayerLineReader() */
204 : /************************************************************************/
205 :
206 1 : SDTSLineReader *SDTSTransfer::GetLayerLineReader(int iEntry)
207 :
208 : {
209 2 : if (iEntry < 0 || iEntry >= nLayers ||
210 1 : oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTLine)
211 : {
212 0 : return nullptr;
213 : }
214 :
215 1 : SDTSLineReader *poLineReader = new SDTSLineReader(&oIREF);
216 :
217 1 : if (!poLineReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry])))
218 : {
219 0 : oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt
220 0 : delete poLineReader;
221 0 : return nullptr;
222 : }
223 :
224 1 : return poLineReader;
225 : }
226 :
227 : /************************************************************************/
228 : /* GetLayerPointReader() */
229 : /************************************************************************/
230 :
231 3 : SDTSPointReader *SDTSTransfer::GetLayerPointReader(int iEntry)
232 :
233 : {
234 6 : if (iEntry < 0 || iEntry >= nLayers ||
235 3 : oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTPoint)
236 : {
237 0 : return nullptr;
238 : }
239 :
240 3 : SDTSPointReader *poPointReader = new SDTSPointReader(&oIREF);
241 :
242 3 : if (!poPointReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry])))
243 : {
244 0 : oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt
245 0 : delete poPointReader;
246 0 : return nullptr;
247 : }
248 :
249 3 : return poPointReader;
250 : }
251 :
252 : /************************************************************************/
253 : /* GetLayerPolygonReader() */
254 : /************************************************************************/
255 :
256 1 : SDTSPolygonReader *SDTSTransfer::GetLayerPolygonReader(int iEntry)
257 :
258 : {
259 2 : if (iEntry < 0 || iEntry >= nLayers ||
260 1 : oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTPoly)
261 : {
262 0 : return nullptr;
263 : }
264 :
265 1 : SDTSPolygonReader *poPolyReader = new SDTSPolygonReader();
266 :
267 1 : if (!poPolyReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry])))
268 : {
269 0 : oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt
270 0 : delete poPolyReader;
271 0 : return nullptr;
272 : }
273 :
274 1 : return poPolyReader;
275 : }
276 :
277 : /************************************************************************/
278 : /* GetLayerAttrReader() */
279 : /************************************************************************/
280 :
281 3 : SDTSAttrReader *SDTSTransfer::GetLayerAttrReader(int iEntry)
282 :
283 : {
284 6 : if (iEntry < 0 || iEntry >= nLayers ||
285 3 : oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTAttr)
286 : {
287 0 : return nullptr;
288 : }
289 :
290 3 : SDTSAttrReader *poAttrReader = new SDTSAttrReader();
291 :
292 3 : if (!poAttrReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry])))
293 : {
294 0 : oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt
295 0 : delete poAttrReader;
296 0 : return nullptr;
297 : }
298 :
299 3 : return poAttrReader;
300 : }
301 :
302 : /************************************************************************/
303 : /* GetLayerRasterReader() */
304 : /************************************************************************/
305 :
306 : /**
307 : Instantiate an SDTSRasterReader for the indicated layer.
308 :
309 : @param iEntry the index of the layer to instantiate a reader for. A
310 : value between 0 and GetLayerCount()-1.
311 :
312 : @return a pointer to a new SDTSRasterReader object, or NULL if the method
313 : fails.
314 :
315 : NOTE: The reader returned from GetLayerRasterReader() becomes the
316 : responsibility of the caller to delete, and isn't automatically deleted
317 : when the SDTSTransfer is destroyed. This method is different from
318 : the GetLayerIndexedReader() method in this regard.
319 : */
320 :
321 2 : SDTSRasterReader *SDTSTransfer::GetLayerRasterReader(int iEntry)
322 :
323 : {
324 4 : if (iEntry < 0 || iEntry >= nLayers ||
325 2 : oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTRaster)
326 : {
327 0 : return nullptr;
328 : }
329 :
330 2 : SDTSRasterReader *poRasterReader = new SDTSRasterReader();
331 :
332 2 : if (!poRasterReader->Open(&oCATD, &oIREF,
333 2 : oCATD.GetEntryModule(panLayerCATDEntry[iEntry])))
334 : {
335 0 : oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt
336 0 : delete poRasterReader;
337 0 : return nullptr;
338 : }
339 :
340 2 : return poRasterReader;
341 : }
342 :
343 : /************************************************************************/
344 : /* GetLayerModuleReader() */
345 : /************************************************************************/
346 :
347 0 : DDFModule *SDTSTransfer::GetLayerModuleReader(int iEntry)
348 :
349 : {
350 0 : if (iEntry < 0 || iEntry >= nLayers)
351 : {
352 0 : return nullptr;
353 : }
354 :
355 0 : DDFModule *poModuleReader = new DDFModule;
356 :
357 0 : if (!poModuleReader->Open(
358 0 : oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry])))
359 : {
360 0 : oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt
361 0 : delete poModuleReader;
362 0 : return nullptr;
363 : }
364 :
365 0 : return poModuleReader;
366 : }
367 :
368 : /************************************************************************/
369 : /* GetLayerIndexedReader() */
370 : /************************************************************************/
371 :
372 : /**
373 : Returns a pointer to a reader of the appropriate type to the requested
374 : layer.
375 :
376 : Notes:
377 : <ul>
378 : <li> The returned reader remains owned by the SDTSTransfer, and will be
379 : destroyed when the SDTSTransfer is destroyed. It should not be
380 : destroyed by the application.
381 :
382 : <li> If an indexed reader was already created for this layer using
383 : GetLayerIndexedReader(), it will be returned instead of creating a new
384 : reader. Among other things this means that the returned reader may not
385 : be positioned to read from the beginning of the module, and may already
386 : have its index filled.
387 :
388 : <li> The returned reader will be of a type appropriate to the layer.
389 : See SDTSTransfer::GetLayerType() to see what reader classes correspond
390 : to what layer types, so it can be cast accordingly (if necessary).
391 : </ul>
392 :
393 : @param iEntry the index of the layer to instantiate a reader for. A
394 : value between 0 and GetLayerCount()-1.
395 :
396 : @return a pointer to an appropriate reader or NULL if the method fails.
397 : */
398 :
399 28 : SDTSIndexedReader *SDTSTransfer::GetLayerIndexedReader(int iEntry)
400 :
401 : {
402 28 : if (papoLayerReader[iEntry] == nullptr)
403 : {
404 8 : switch (oCATD.GetEntryType(panLayerCATDEntry[iEntry]))
405 : {
406 3 : case SLTAttr:
407 3 : papoLayerReader[iEntry] = GetLayerAttrReader(iEntry);
408 3 : break;
409 :
410 3 : case SLTPoint:
411 3 : papoLayerReader[iEntry] = GetLayerPointReader(iEntry);
412 3 : break;
413 :
414 1 : case SLTLine:
415 1 : papoLayerReader[iEntry] = GetLayerLineReader(iEntry);
416 1 : break;
417 :
418 1 : case SLTPoly:
419 1 : papoLayerReader[iEntry] = GetLayerPolygonReader(iEntry);
420 1 : break;
421 :
422 0 : default:
423 0 : break;
424 : }
425 : }
426 :
427 28 : return papoLayerReader[iEntry];
428 : }
429 :
430 : /************************************************************************/
431 : /* FindLayer() */
432 : /************************************************************************/
433 :
434 : /**
435 : Fetch the SDTSTransfer layer number corresponding to a module name.
436 :
437 : @param pszModule the name of the module to search for, such as "PC01".
438 :
439 : @return the layer number (between 0 and GetLayerCount()-1 corresponding to
440 : the module, or -1 if it doesn't correspond to a layer.
441 : */
442 :
443 11 : int SDTSTransfer::FindLayer(const char *pszModule)
444 :
445 : {
446 21 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
447 : {
448 21 : if (EQUAL(pszModule, oCATD.GetEntryModule(panLayerCATDEntry[iLayer])))
449 : {
450 11 : return iLayer;
451 : }
452 : }
453 :
454 0 : return -1;
455 : }
456 :
457 : /************************************************************************/
458 : /* GetIndexedFeatureRef() */
459 : /************************************************************************/
460 :
461 6 : SDTSFeature *SDTSTransfer::GetIndexedFeatureRef(SDTSModId *poModId,
462 : SDTSLayerType *peType)
463 :
464 : {
465 : /* -------------------------------------------------------------------- */
466 : /* Find the desired layer ... this is likely a significant slow */
467 : /* point in the whole process ... perhaps the last found could */
468 : /* be cached or something. */
469 : /* -------------------------------------------------------------------- */
470 6 : const int iLayer = FindLayer(poModId->szModule);
471 6 : if (iLayer == -1)
472 0 : return nullptr;
473 :
474 : /* -------------------------------------------------------------------- */
475 : /* Get the reader, and read a feature from it. */
476 : /* -------------------------------------------------------------------- */
477 6 : SDTSIndexedReader *poReader = GetLayerIndexedReader(iLayer);
478 6 : if (poReader == nullptr)
479 0 : return nullptr;
480 :
481 : /* -------------------------------------------------------------------- */
482 : /* return type, if requested. */
483 : /* -------------------------------------------------------------------- */
484 6 : if (peType != nullptr)
485 0 : *peType = GetLayerType(iLayer);
486 :
487 6 : return poReader->GetIndexedFeatureRef(poModId->nRecord);
488 : }
489 :
490 : /************************************************************************/
491 : /* GetAttr() */
492 : /* */
493 : /* Fetch the attribute information corresponding to a given */
494 : /* SDTSModId. */
495 : /************************************************************************/
496 :
497 : /**
498 : Fetch the attribute fields given a particular module/record id.
499 :
500 : @param poModId an attribute record identifier, normally taken from the
501 : aoATID[] array of an SDTSIndexedFeature.
502 :
503 : @return a pointer to the DDFField containing the user attribute values as
504 : subfields.
505 : */
506 :
507 6 : DDFField *SDTSTransfer::GetAttr(SDTSModId *poModId)
508 :
509 : {
510 : SDTSAttrRecord *poAttrRecord =
511 6 : dynamic_cast<SDTSAttrRecord *>(GetIndexedFeatureRef(poModId));
512 :
513 6 : if (poAttrRecord == nullptr)
514 0 : return nullptr;
515 :
516 6 : return poAttrRecord->poATTR;
517 : }
518 :
519 : /************************************************************************/
520 : /* GetBounds() */
521 : /************************************************************************/
522 :
523 : /**
524 : Fetch approximate bounds for a transfer by scanning all point layers
525 : and raster layers.
526 :
527 : For TVP datasets (where point layers are scanned) the results can, in
528 : theory miss some lines that go outside the bounds of the point layers.
529 : However, this isn't common since most TVP sets contain a bounding rectangle
530 : whose corners will define the most extreme extents.
531 :
532 : @param pdfMinX western edge of dataset
533 : @param pdfMinY southern edge of dataset
534 : @param pdfMaxX eastern edge of dataset
535 : @param pdfMaxY northern edge of dataset
536 :
537 : @return TRUE if success, or FALSE on a failure.
538 : */
539 :
540 0 : int SDTSTransfer::GetBounds(double *pdfMinX, double *pdfMinY, double *pdfMaxX,
541 : double *pdfMaxY)
542 :
543 : {
544 0 : bool bFirst = true;
545 :
546 0 : for (int iLayer = 0; iLayer < GetLayerCount(); iLayer++)
547 : {
548 0 : if (GetLayerType(iLayer) == SLTPoint)
549 : {
550 :
551 : SDTSPointReader *poLayer = reinterpret_cast<SDTSPointReader *>(
552 0 : GetLayerIndexedReader(iLayer));
553 0 : if (poLayer == nullptr)
554 0 : continue;
555 :
556 0 : poLayer->Rewind();
557 :
558 0 : SDTSRawPoint *poPoint = nullptr;
559 0 : while ((poPoint = reinterpret_cast<SDTSRawPoint *>(
560 0 : poLayer->GetNextFeature())) != nullptr)
561 : {
562 0 : if (bFirst)
563 : {
564 0 : *pdfMinX = poPoint->dfX;
565 0 : *pdfMaxX = poPoint->dfX;
566 0 : *pdfMinY = poPoint->dfY;
567 0 : *pdfMaxY = poPoint->dfY;
568 0 : bFirst = false;
569 : }
570 : else
571 : {
572 0 : *pdfMinX = std::min(*pdfMinX, poPoint->dfX);
573 0 : *pdfMaxX = std::max(*pdfMaxX, poPoint->dfX);
574 0 : *pdfMinY = std::min(*pdfMinY, poPoint->dfY);
575 0 : *pdfMaxY = std::max(*pdfMaxY, poPoint->dfY);
576 : }
577 :
578 0 : if (!poLayer->IsIndexed())
579 0 : delete poPoint;
580 : }
581 : }
582 0 : else if (GetLayerType(iLayer) == SLTRaster)
583 : {
584 0 : SDTSRasterReader *poRL = GetLayerRasterReader(iLayer);
585 0 : if (poRL == nullptr)
586 0 : continue;
587 :
588 : double adfGeoTransform[6];
589 0 : poRL->GetTransform(adfGeoTransform);
590 :
591 0 : const double dfMinX = adfGeoTransform[0];
592 0 : const double dfMaxY = adfGeoTransform[3];
593 : const double dfMaxX =
594 0 : adfGeoTransform[0] + poRL->GetXSize() * adfGeoTransform[1];
595 : const double dfMinY =
596 0 : adfGeoTransform[3] + poRL->GetYSize() * adfGeoTransform[5];
597 :
598 0 : if (bFirst)
599 : {
600 0 : *pdfMinX = dfMinX;
601 0 : *pdfMaxX = dfMaxX;
602 0 : *pdfMinY = dfMinY;
603 0 : *pdfMaxY = dfMaxY;
604 0 : bFirst = false;
605 : }
606 : else
607 : {
608 0 : *pdfMinX = std::min(dfMinX, *pdfMinX);
609 0 : *pdfMaxX = std::max(dfMaxX, *pdfMaxX);
610 0 : *pdfMinY = std::min(dfMinY, *pdfMinY);
611 0 : *pdfMaxY = std::max(dfMaxY, *pdfMaxY);
612 : }
613 :
614 0 : delete poRL;
615 : }
616 : }
617 :
618 0 : return !bFirst;
619 : }
|