Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: VFK Reader - Data block definition
4 : * Purpose: Implements VFKDataBlock class.
5 : * Author: Martin Landa, landa.martin gmail.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2009-2013, Martin Landa <landa.martin gmail.com>
9 : * Copyright (c) 2012-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include <ctime>
15 :
16 : #include "vfkreader.h"
17 : #include "vfkreaderp.h"
18 :
19 : #include "cpl_conv.h"
20 : #include "cpl_error.h"
21 :
22 : /*!
23 : \brief VFK Data Block constructor
24 :
25 : \param pszName data block name
26 : */
27 1037 : IVFKDataBlock::IVFKDataBlock(const char *pszName, const IVFKReader *poReader)
28 : : m_papoFeature(nullptr), m_nPropertyCount(0), m_papoProperty(nullptr),
29 2074 : m_pszName(CPLStrdup(pszName)),
30 : m_bGeometry(false), // Geometry is not loaded by default.
31 : m_nGeometryType(wkbUnknown),
32 : m_bGeometryPerBlock(true), // Load geometry per block/feature.
33 : m_nFeatureCount(-1), // Load data on first request.
34 1037 : m_iNextFeature(-1), m_poReader(const_cast<IVFKReader *>(poReader))
35 : {
36 1037 : m_nRecordCount[RecordValid] = 0L; // Number of valid records.
37 1037 : m_nRecordCount[RecordSkipped] = 0L; // Number of skipped (invalid) records.
38 1037 : m_nRecordCount[RecordDuplicated] = 0L; // Number of duplicated records.
39 1037 : }
40 :
41 : /*!
42 : \brief VFKDataBlock destructor
43 : */
44 2074 : IVFKDataBlock::~IVFKDataBlock()
45 : {
46 1037 : CPLFree(m_pszName);
47 :
48 10846 : for (int i = 0; i < m_nPropertyCount; i++)
49 : {
50 9809 : if (m_papoProperty[i])
51 9809 : delete m_papoProperty[i];
52 : }
53 1037 : CPLFree(m_papoProperty);
54 :
55 2006 : for (int i = 0; i < m_nFeatureCount; i++)
56 : {
57 969 : if (m_papoFeature[i])
58 969 : delete m_papoFeature[i];
59 : }
60 1037 : CPLFree(m_papoFeature);
61 1037 : }
62 :
63 : /*!
64 : \brief Get property definition
65 :
66 : \param iIndex property index
67 :
68 : \return pointer to VFKPropertyDefn definition or NULL on failure
69 : */
70 46373 : VFKPropertyDefn *IVFKDataBlock::GetProperty(int iIndex) const
71 : {
72 46373 : if (iIndex < 0 || iIndex >= m_nPropertyCount)
73 0 : return nullptr;
74 :
75 46373 : return m_papoProperty[iIndex];
76 : }
77 :
78 : /*!
79 : \brief Set properties
80 :
81 : \param poLine pointer to line
82 : */
83 1037 : void IVFKDataBlock::SetProperties(const char *poLine)
84 : {
85 : /* skip data block name */
86 1037 : const char *poChar = strchr(poLine, ';');
87 1037 : if (poChar == nullptr)
88 0 : return;
89 :
90 1037 : poChar++;
91 :
92 : /* read property name/type */
93 1037 : const char *poProp = poChar;
94 1037 : char *pszName = nullptr;
95 1037 : char *pszType = nullptr;
96 1037 : int nLength = 0;
97 122315 : while (*poChar != '\0')
98 : {
99 121278 : if (*poChar == ' ')
100 : {
101 9809 : pszName = (char *)CPLRealloc(pszName, nLength + 1);
102 9809 : strncpy(pszName, poProp, nLength);
103 9809 : pszName[nLength] = '\0';
104 :
105 9809 : poProp = ++poChar;
106 9809 : nLength = 0;
107 9809 : if (*poProp == '\0')
108 0 : break;
109 : }
110 111469 : else if (*poChar == ';')
111 : {
112 8772 : pszType = (char *)CPLRealloc(pszType, nLength + 1);
113 8772 : strncpy(pszType, poProp, nLength);
114 8772 : pszType[nLength] = '\0';
115 :
116 : /* add property */
117 8772 : if (pszName && *pszName != '\0' && *pszType != '\0')
118 8772 : AddProperty(pszName, pszType);
119 :
120 8772 : poProp = ++poChar;
121 8772 : nLength = 0;
122 8772 : if (*poProp == '\0')
123 0 : break;
124 : }
125 121278 : poChar++;
126 121278 : nLength++;
127 : }
128 :
129 1037 : pszType = (char *)CPLRealloc(pszType, nLength + 1);
130 1037 : if (nLength > 0)
131 1037 : strncpy(pszType, poProp, nLength);
132 1037 : pszType[nLength] = '\0';
133 :
134 : /* add property */
135 1037 : if (pszName && *pszName != '\0' && *pszType != '\0')
136 1037 : AddProperty(pszName, pszType);
137 :
138 1037 : CPLFree(pszName);
139 1037 : CPLFree(pszType);
140 : }
141 :
142 : /*!
143 : \brief Add data block property
144 :
145 : \param pszName property name
146 : \param pszType property type
147 :
148 : \return number of properties
149 : */
150 9809 : int IVFKDataBlock::AddProperty(const char *pszName, const char *pszType)
151 : {
152 : /* Force text attributes to avoid int64 overflow
153 : see https://github.com/OSGeo/gdal/issues/672 */
154 9809 : if (EQUAL(m_pszName, "VLA") &&
155 204 : (EQUAL(pszName, "PODIL_CITATEL") || EQUAL(pszName, "PODIL_JMENOVATEL")))
156 34 : pszType = "T30";
157 :
158 : VFKPropertyDefn *poNewProperty =
159 9809 : new VFKPropertyDefn(pszName, pszType, m_poReader->GetEncoding());
160 :
161 9809 : m_nPropertyCount++;
162 :
163 19618 : m_papoProperty = (VFKPropertyDefn **)CPLRealloc(
164 9809 : m_papoProperty, sizeof(VFKPropertyDefn *) * m_nPropertyCount);
165 9809 : m_papoProperty[m_nPropertyCount - 1] = poNewProperty;
166 :
167 9809 : return m_nPropertyCount;
168 : }
169 :
170 : /*!
171 : \brief Get number of features for given data block
172 :
173 : \param bForce true to force reading VFK data blocks if needed
174 :
175 : \return number of features
176 : */
177 2324 : GIntBig IVFKDataBlock::GetFeatureCount(bool bForce)
178 : {
179 2324 : if (bForce && m_nFeatureCount == -1)
180 : {
181 0 : m_poReader->ReadDataRecords(this); /* read VFK data records */
182 0 : if (m_bGeometryPerBlock && !m_bGeometry)
183 : {
184 0 : LoadGeometry(); /* get real number of features */
185 : }
186 : }
187 : #if defined(__GNUC__)
188 : #pragma GCC diagnostic push
189 : #pragma GCC diagnostic ignored "-Wnull-dereference"
190 : #endif
191 2324 : return m_nFeatureCount;
192 : #if defined(__GNUC__)
193 : #pragma GCC diagnostic pop
194 : #endif
195 : }
196 :
197 : /*!
198 : \brief Set number of features per data block
199 :
200 : \param nNewCount number of features
201 : \param bIncrement increment current value
202 : */
203 1037 : void IVFKDataBlock::SetFeatureCount(int nNewCount, bool bIncrement)
204 : {
205 1037 : if (bIncrement)
206 : {
207 0 : m_nFeatureCount += nNewCount;
208 : }
209 : else
210 : {
211 1037 : m_nFeatureCount = nNewCount;
212 : }
213 1037 : }
214 :
215 : /*!
216 : \brief Reset reading
217 :
218 : \param iIdx force index
219 : */
220 8 : void IVFKDataBlock::ResetReading(int iIdx)
221 : {
222 8 : if (iIdx > -1)
223 : {
224 0 : m_iNextFeature = iIdx;
225 : }
226 : else
227 : {
228 8 : m_iNextFeature = 0;
229 : }
230 8 : }
231 :
232 : /*!
233 : \brief Get next feature
234 :
235 : \return pointer to VFKFeature instance or NULL on error
236 : */
237 34 : IVFKFeature *IVFKDataBlock::GetNextFeature()
238 : {
239 34 : if (m_nFeatureCount < 0)
240 : {
241 0 : m_poReader->ReadDataRecords(this);
242 : }
243 :
244 34 : if (m_bGeometryPerBlock && !m_bGeometry)
245 : {
246 0 : LoadGeometry();
247 : }
248 :
249 34 : if (m_iNextFeature < 0)
250 0 : ResetReading();
251 :
252 34 : if (m_iNextFeature < 0 || m_iNextFeature >= m_nFeatureCount)
253 3 : return nullptr;
254 :
255 31 : return m_papoFeature[m_iNextFeature++];
256 : }
257 :
258 : /*!
259 : \brief Get previous feature
260 :
261 : \return pointer to VFKFeature instance or NULL on error
262 : */
263 0 : IVFKFeature *IVFKDataBlock::GetPreviousFeature()
264 : {
265 0 : if (m_nFeatureCount < 0)
266 : {
267 0 : m_poReader->ReadDataRecords(this);
268 : }
269 :
270 0 : if (m_bGeometryPerBlock && !m_bGeometry)
271 : {
272 0 : LoadGeometry();
273 : }
274 :
275 0 : if (m_iNextFeature < 0)
276 0 : ResetReading();
277 :
278 0 : if (m_iNextFeature < 0 || m_iNextFeature >= m_nFeatureCount)
279 0 : return nullptr;
280 :
281 0 : return m_papoFeature[m_iNextFeature--];
282 : }
283 :
284 : /*!
285 : \brief Get first feature
286 :
287 : \return pointer to VFKFeature instance or NULL on error
288 : */
289 0 : IVFKFeature *IVFKDataBlock::GetFirstFeature()
290 : {
291 0 : if (m_nFeatureCount < 0)
292 : {
293 0 : m_poReader->ReadDataRecords(this);
294 : }
295 :
296 0 : if (m_bGeometryPerBlock && !m_bGeometry)
297 : {
298 0 : LoadGeometry();
299 : }
300 :
301 0 : if (m_nFeatureCount < 1)
302 0 : return nullptr;
303 :
304 0 : return m_papoFeature[0];
305 : }
306 :
307 : /*!
308 : \brief Get last feature
309 :
310 : \return pointer to VFKFeature instance or NULL on error
311 : */
312 0 : IVFKFeature *IVFKDataBlock::GetLastFeature()
313 : {
314 0 : if (m_nFeatureCount < 0)
315 : {
316 0 : m_poReader->ReadDataRecords(this);
317 : }
318 :
319 0 : if (m_bGeometryPerBlock && !m_bGeometry)
320 : {
321 0 : LoadGeometry();
322 : }
323 :
324 0 : if (m_nFeatureCount < 1)
325 0 : return nullptr;
326 :
327 0 : return m_papoFeature[m_nFeatureCount - 1];
328 : }
329 :
330 : /*!
331 : \brief Get property index by name
332 :
333 : \param pszName property name
334 :
335 : \return property index or -1 on error (property name not found)
336 : */
337 464 : int IVFKDataBlock::GetPropertyIndex(const char *pszName) const
338 : {
339 4176 : for (int i = 0; i < m_nPropertyCount; i++)
340 4176 : if (EQUAL(pszName, m_papoProperty[i]->GetName()))
341 464 : return i;
342 :
343 0 : return -1;
344 : }
345 :
346 : /*!
347 : \brief Set geometry type (point, linestring, polygon)
348 :
349 : \param bSuppressGeometry True for forcing wkbNone type
350 :
351 : \return geometry type
352 : */
353 1037 : OGRwkbGeometryType IVFKDataBlock::SetGeometryType(bool bSuppressGeometry)
354 : {
355 1037 : m_nGeometryType = wkbNone; /* pure attribute records */
356 1037 : if (bSuppressGeometry)
357 : {
358 61 : m_bGeometry = true; /* pretend that geometry is already loaded */
359 :
360 61 : return m_nGeometryType;
361 : }
362 :
363 976 : if (EQUAL(m_pszName, "SOBR") || EQUAL(m_pszName, "OBBP") ||
364 944 : EQUAL(m_pszName, "SPOL") || EQUAL(m_pszName, "OB") ||
365 912 : EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBPEJ"))
366 96 : m_nGeometryType = wkbPoint;
367 :
368 880 : else if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG") ||
369 864 : EQUAL(m_pszName, "HP") || EQUAL(m_pszName, "DPM") ||
370 832 : EQUAL(m_pszName, "ZVB"))
371 64 : m_nGeometryType = wkbLineString;
372 :
373 816 : else if (EQUAL(m_pszName, "PAR"))
374 16 : m_nGeometryType = wkbPolygon;
375 :
376 800 : else if (EQUAL(m_pszName, "BUD"))
377 16 : m_nGeometryType = wkbMultiPolygon;
378 :
379 976 : return m_nGeometryType;
380 : }
381 :
382 : /*!
383 : \brief Get geometry type
384 :
385 : \return geometry type
386 : */
387 6323 : OGRwkbGeometryType IVFKDataBlock::GetGeometryType() const
388 : {
389 6323 : return m_nGeometryType;
390 : }
391 :
392 : /*!
393 : \brief Get feature by index
394 :
395 : \param iIndex feature index
396 :
397 : \return pointer to feature definition or NULL on failure
398 : */
399 1901 : IVFKFeature *IVFKDataBlock::GetFeatureByIndex(int iIndex) const
400 : {
401 1901 : if (iIndex < 0 || iIndex >= m_nFeatureCount)
402 0 : return nullptr;
403 :
404 1901 : return m_papoFeature[iIndex];
405 : }
406 :
407 : /*!
408 : \brief Get feature by FID
409 :
410 : Modifies next feature id.
411 :
412 : \param nFID feature id
413 :
414 : \return pointer to feature definition or NULL on failure (not found)
415 : */
416 1 : IVFKFeature *IVFKDataBlock::GetFeature(GIntBig nFID)
417 : {
418 1 : if (m_nFeatureCount < 0)
419 : {
420 0 : m_poReader->ReadDataRecords(this);
421 : }
422 :
423 1 : if (nFID < 1 || nFID > m_nFeatureCount)
424 0 : return nullptr;
425 :
426 1 : if (m_bGeometryPerBlock && !m_bGeometry)
427 : {
428 0 : LoadGeometry();
429 : }
430 :
431 1 : return GetFeatureByIndex(int(nFID) - 1); /* zero-based index */
432 : }
433 :
434 : /*!
435 : \brief Load geometry
436 :
437 : Print warning when some invalid features are detected.
438 :
439 : \return number of invalid features or -1 on failure
440 : */
441 1104 : int IVFKDataBlock::LoadGeometry()
442 : {
443 : #if defined(__GNUC__)
444 : #pragma GCC diagnostic push
445 : #pragma GCC diagnostic ignored "-Wnull-dereference"
446 : #endif
447 1104 : if (m_bGeometry)
448 128 : return 0;
449 : #if defined(__GNUC__)
450 : #pragma GCC diagnostic pop
451 : #endif
452 :
453 976 : m_bGeometry = true;
454 976 : int nInvalid = 0;
455 :
456 : #ifdef DEBUG_TIMING
457 : const clock_t start = clock();
458 : #endif
459 :
460 976 : if (m_nFeatureCount < 0)
461 : {
462 0 : m_poReader->ReadDataRecords(this);
463 : }
464 :
465 976 : if (EQUAL(m_pszName, "SOBR") || EQUAL(m_pszName, "SPOL") ||
466 944 : EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBPEJ") ||
467 912 : EQUAL(m_pszName, "OB") || EQUAL(m_pszName, "OBBP"))
468 : {
469 : /* -> wkbPoint */
470 96 : nInvalid = LoadGeometryPoint();
471 : }
472 880 : else if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
473 : {
474 : /* -> wkbLineString */
475 16 : nInvalid = LoadGeometryLineStringSBP();
476 : }
477 864 : else if (EQUAL(m_pszName, "HP") || EQUAL(m_pszName, "DPM") ||
478 832 : EQUAL(m_pszName, "ZVB"))
479 : {
480 : /* -> wkbLineString */
481 48 : nInvalid = LoadGeometryLineStringHP();
482 : }
483 816 : else if (EQUAL(m_pszName, "PAR") || EQUAL(m_pszName, "BUD"))
484 : {
485 : /* -> wkbPolygon */
486 32 : nInvalid = LoadGeometryPolygon();
487 : }
488 :
489 : #ifdef DEBUG_TIMING
490 : const clock_t end = clock();
491 : #endif
492 :
493 976 : if (nInvalid > 0)
494 : {
495 0 : CPLError(CE_Warning, CPLE_AppDefined,
496 : "%s: %d features with invalid or empty geometry", m_pszName,
497 : nInvalid);
498 : }
499 :
500 : #ifdef DEBUG_TIMING
501 : CPLDebug("OGR-VFK", "VFKDataBlock::LoadGeometry(): name=%s time=%ld sec",
502 : m_pszName, (long)((end - start) / CLOCKS_PER_SEC));
503 : #endif
504 :
505 976 : return nInvalid;
506 : }
507 :
508 0 : void IVFKDataBlock::FillPointList(PointList *poList,
509 : const OGRLineString *poLine)
510 : {
511 0 : poList->reserve(poLine->getNumPoints());
512 :
513 : /* OGRLineString -> PointList */
514 0 : for (int i = 0; i < poLine->getNumPoints(); i++)
515 : {
516 0 : OGRPoint pt;
517 0 : poLine->getPoint(i, &pt);
518 0 : poList->emplace_back(std::move(pt));
519 : }
520 0 : }
521 :
522 : /*!
523 : \brief Add linestring to a ring (private)
524 :
525 : \param[in,out] papoRing list of rings
526 : \param poLine pointer to linestring to be added to a ring
527 : \param bNewRing create new ring
528 : \param bBackward allow backward direction
529 :
530 : \return true on success or false on failure
531 : */
532 0 : bool IVFKDataBlock::AppendLineToRing(PointListArray *papoRing,
533 : const OGRLineString *poLine, bool bNewRing,
534 : bool bBackward)
535 : {
536 : /* create new ring */
537 0 : if (bNewRing)
538 : {
539 0 : PointList *poList = new PointList();
540 0 : FillPointList(poList, poLine);
541 0 : papoRing->emplace_back(poList);
542 0 : return true;
543 : }
544 :
545 0 : if (poLine->getNumPoints() < 2)
546 0 : return false;
547 0 : OGRPoint oFirstNew;
548 0 : OGRPoint oLastNew;
549 0 : poLine->StartPoint(&oFirstNew);
550 0 : poLine->EndPoint(&oLastNew);
551 :
552 0 : for (PointList *ring : *papoRing)
553 : {
554 0 : const OGRPoint &oFirst = ring->front();
555 0 : const OGRPoint &oLast = ring->back();
556 :
557 0 : if (oFirstNew.getX() == oLast.getX() &&
558 0 : oFirstNew.getY() == oLast.getY())
559 : {
560 0 : PointList oList;
561 0 : FillPointList(&oList, poLine);
562 : /* forward, skip first point */
563 0 : ring->insert(ring->end(), oList.begin() + 1, oList.end());
564 0 : return true;
565 : }
566 :
567 0 : if (bBackward && oFirstNew.getX() == oFirst.getX() &&
568 0 : oFirstNew.getY() == oFirst.getY())
569 : {
570 0 : PointList oList;
571 0 : FillPointList(&oList, poLine);
572 : /* backward, skip last point */
573 0 : ring->insert(ring->begin(), oList.rbegin(), oList.rend() - 1);
574 0 : return true;
575 : }
576 :
577 0 : if (oLastNew.getX() == oLast.getX() && oLastNew.getY() == oLast.getY())
578 : {
579 0 : PointList oList;
580 0 : FillPointList(&oList, poLine);
581 : /* backward, skip first point */
582 0 : ring->insert(ring->end(), oList.rbegin() + 1, oList.rend());
583 0 : return true;
584 : }
585 :
586 0 : if (bBackward && oLastNew.getX() == oFirst.getX() &&
587 0 : oLastNew.getY() == oFirst.getY())
588 : {
589 0 : PointList oList;
590 0 : FillPointList(&oList, poLine);
591 : /* forward, skip last point */
592 0 : ring->insert(ring->begin(), oList.begin(), oList.end() - 1);
593 0 : return true;
594 : }
595 : }
596 :
597 0 : return false;
598 : }
599 :
600 : /*!
601 : \brief Set next feature
602 :
603 : \param poFeature pointer to current feature
604 :
605 : \return index of current feature or -1 on failure
606 : */
607 0 : int IVFKDataBlock::SetNextFeature(const IVFKFeature *poFeature)
608 : {
609 0 : for (int i = 0; i < m_nFeatureCount; i++)
610 : {
611 0 : if (m_papoFeature[i] == poFeature)
612 : {
613 0 : m_iNextFeature = i + 1;
614 0 : return i;
615 : }
616 : }
617 :
618 0 : return -1;
619 : }
620 :
621 : /*!
622 : \brief Add feature
623 :
624 : \param poNewFeature pointer to VFKFeature instance
625 : */
626 969 : void IVFKDataBlock::AddFeature(IVFKFeature *poNewFeature)
627 : {
628 969 : m_nFeatureCount++;
629 :
630 1938 : m_papoFeature = (IVFKFeature **)CPLRealloc(
631 969 : m_papoFeature, sizeof(IVFKFeature *) * m_nFeatureCount);
632 969 : m_papoFeature[m_nFeatureCount - 1] = poNewFeature;
633 969 : }
634 :
635 : /*!
636 : \brief Get number of records
637 :
638 : \param iRec record type (valid, skipped, duplicated)
639 :
640 : \return number of records
641 : */
642 4816 : int IVFKDataBlock::GetRecordCount(RecordType iRec) const
643 : {
644 4816 : return (int)m_nRecordCount[iRec];
645 : }
646 :
647 : /*!
648 : \brief Increment number of records
649 :
650 : \param iRec record type (valid, skipped, duplicated)
651 : */
652 1152 : void IVFKDataBlock::SetIncRecordCount(RecordType iRec)
653 : {
654 1152 : m_nRecordCount[iRec]++;
655 1152 : }
656 :
657 : /*!
658 : \brief Get first found feature based on its properties
659 :
660 : Note: modifies next feature.
661 :
662 : \param idx property index
663 : \param value property value
664 : \param poList list of features (NULL to loop all features)
665 :
666 : \return pointer to feature definition or NULL on failure (not found)
667 : */
668 0 : VFKFeature *VFKDataBlock::GetFeature(int idx, GUIntBig value,
669 : VFKFeatureList *poList)
670 : {
671 0 : if (poList)
672 : {
673 0 : for (VFKFeatureList::iterator i = poList->begin(), e = poList->end();
674 0 : i != e; ++i)
675 : {
676 0 : VFKFeature *poVfkFeature = *i;
677 0 : const GUIntBig iPropertyValue = strtoul(
678 : poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
679 0 : if (iPropertyValue == value)
680 : {
681 0 : poList->erase(i); /* ??? */
682 0 : return poVfkFeature;
683 : }
684 : }
685 : }
686 : else
687 : {
688 0 : for (int i = 0; i < m_nFeatureCount; i++)
689 : {
690 : VFKFeature *poVfkFeature =
691 0 : cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
692 0 : const GUIntBig iPropertyValue = strtoul(
693 : poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
694 0 : if (iPropertyValue == value)
695 : {
696 0 : m_iNextFeature = i + 1;
697 0 : return poVfkFeature;
698 : }
699 : }
700 : }
701 :
702 0 : return nullptr;
703 : }
704 :
705 : /*!
706 : \brief Get features based on properties
707 :
708 : \param idx property index
709 : \param value property value
710 :
711 : \return list of features
712 : */
713 0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx, GUIntBig value)
714 : {
715 0 : std::vector<VFKFeature *> poResult;
716 :
717 0 : for (int i = 0; i < m_nFeatureCount; i++)
718 : {
719 : VFKFeature *poVfkFeature =
720 0 : cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
721 : const GUIntBig iPropertyValue =
722 0 : strtoul(poVfkFeature->GetProperty(idx)->GetValueS(), nullptr, 0);
723 0 : if (iPropertyValue == value)
724 : {
725 0 : poResult.push_back(poVfkFeature);
726 : }
727 : }
728 :
729 0 : return poResult;
730 : }
731 :
732 : /*!
733 : \brief Get features based on properties
734 :
735 : \param idx1 property index
736 : \param idx2 property index
737 : \param value property value
738 :
739 : \return list of features
740 : */
741 0 : VFKFeatureList VFKDataBlock::GetFeatures(int idx1, int idx2, GUIntBig value)
742 : {
743 0 : std::vector<VFKFeature *> poResult;
744 :
745 0 : for (int i = 0; i < m_nFeatureCount; i++)
746 : {
747 : VFKFeature *poVfkFeature =
748 0 : cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
749 : const GUIntBig iPropertyValue1 =
750 0 : strtoul(poVfkFeature->GetProperty(idx1)->GetValueS(), nullptr, 0);
751 0 : if (idx2 < 0)
752 : {
753 0 : if (iPropertyValue1 == value)
754 : {
755 0 : poResult.push_back(poVfkFeature);
756 : }
757 : }
758 : else
759 : {
760 0 : const GUIntBig iPropertyValue2 = strtoul(
761 : poVfkFeature->GetProperty(idx2)->GetValueS(), nullptr, 0);
762 0 : if (iPropertyValue1 == value || iPropertyValue2 == value)
763 : {
764 0 : poResult.push_back(poVfkFeature);
765 : }
766 : }
767 : }
768 :
769 0 : return poResult;
770 : }
771 :
772 : /*!
773 : \brief Get feature count based on property value
774 :
775 : \param pszName property name
776 : \param pszValue property value
777 :
778 : \return number of features or -1 on error
779 : */
780 0 : GIntBig VFKDataBlock::GetFeatureCount(const char *pszName, const char *pszValue)
781 : {
782 0 : const int propIdx = GetPropertyIndex(pszName);
783 0 : if (propIdx < 0)
784 0 : return -1;
785 :
786 0 : int nfeatures = 0;
787 0 : for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
788 : {
789 0 : VFKFeature *poVFKFeature = cpl::down_cast<VFKFeature *>(
790 : ((IVFKDataBlock *)this)->GetFeature(i));
791 0 : if (!poVFKFeature)
792 0 : return -1;
793 0 : if (EQUAL(poVFKFeature->GetProperty(propIdx)->GetValueS(), pszValue))
794 0 : nfeatures++;
795 : }
796 :
797 0 : return nfeatures;
798 : }
799 :
800 : /*!
801 : \brief Load geometry (point layers)
802 :
803 : \return number of invalid features
804 : */
805 0 : int VFKDataBlock::LoadGeometryPoint()
806 : {
807 0 : int nInvalid = 0;
808 0 : int i_idxY = GetPropertyIndex("SOURADNICE_Y");
809 0 : int i_idxX = GetPropertyIndex("SOURADNICE_X");
810 0 : if (i_idxY < 0 || i_idxX < 0)
811 : {
812 0 : CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
813 : m_pszName);
814 0 : return nInvalid;
815 : }
816 :
817 0 : for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
818 : {
819 : VFKFeature *poFeature =
820 0 : cpl::down_cast<VFKFeature *>(GetFeatureByIndex(j));
821 0 : double x = -1.0 * poFeature->GetProperty(i_idxY)->GetValueD();
822 0 : double y = -1.0 * poFeature->GetProperty(i_idxX)->GetValueD();
823 0 : OGRPoint pt(x, y);
824 0 : if (!poFeature->SetGeometry(&pt))
825 0 : nInvalid++;
826 : }
827 :
828 0 : return nInvalid;
829 : }
830 :
831 : /*!
832 : \brief Load geometry (linestring SBP/SBPG layer)
833 :
834 : \return number of invalid features
835 : */
836 0 : int VFKDataBlock::LoadGeometryLineStringSBP()
837 : {
838 : VFKDataBlock *poDataBlockPoints =
839 0 : cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SOBR"));
840 0 : if (nullptr == poDataBlockPoints)
841 : {
842 0 : CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
843 : m_pszName);
844 0 : return 0;
845 : }
846 :
847 0 : poDataBlockPoints->LoadGeometry();
848 0 : int idxId = poDataBlockPoints->GetPropertyIndex("ID");
849 0 : int idxBp_Id = GetPropertyIndex("BP_ID");
850 0 : int idxPCB = GetPropertyIndex("PORADOVE_CISLO_BODU");
851 0 : if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
852 : {
853 0 : CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
854 : m_pszName);
855 0 : return 0;
856 : }
857 :
858 0 : OGRLineString oOGRLine;
859 0 : VFKFeature *poLine = nullptr;
860 0 : int nInvalid = 0;
861 :
862 0 : for (int j = 0; j < ((IVFKDataBlock *)this)->GetFeatureCount(); j++)
863 : {
864 : VFKFeature *poFeature =
865 0 : cpl::down_cast<VFKFeature *>(GetFeatureByIndex(j));
866 0 : CPLAssert(nullptr != poFeature);
867 :
868 0 : poFeature->SetGeometry(nullptr);
869 : GUIntBig id =
870 0 : strtoul(poFeature->GetProperty(idxBp_Id)->GetValueS(), nullptr, 0);
871 : GUIntBig ipcb =
872 0 : strtoul(poFeature->GetProperty(idxPCB)->GetValueS(), nullptr, 0);
873 0 : if (ipcb == 1)
874 : {
875 0 : if (!oOGRLine.IsEmpty())
876 : {
877 0 : oOGRLine.setCoordinateDimension(2); /* force 2D */
878 0 : if (poLine != nullptr && !poLine->SetGeometry(&oOGRLine))
879 0 : nInvalid++;
880 0 : oOGRLine.empty(); /* restore line */
881 : }
882 0 : poLine = poFeature;
883 : }
884 : else
885 : {
886 0 : poFeature->SetGeometryType(wkbUnknown);
887 : }
888 0 : VFKFeature *poPoint = poDataBlockPoints->GetFeature(idxId, id);
889 0 : if (!poPoint)
890 0 : continue;
891 0 : const OGRPoint *pt = poPoint->GetGeometry()->toPoint();
892 0 : oOGRLine.addPoint(pt);
893 : }
894 : /* add last line */
895 0 : oOGRLine.setCoordinateDimension(2); /* force 2D */
896 0 : if (poLine)
897 : {
898 0 : if (!poLine->SetGeometry(&oOGRLine))
899 0 : nInvalid++;
900 : }
901 0 : poDataBlockPoints->ResetReading();
902 :
903 0 : return nInvalid;
904 : }
905 :
906 : /*!
907 : \brief Load geometry (linestring HP/DPM/ZVB layer)
908 :
909 : \return number of invalid features
910 : */
911 0 : int VFKDataBlock::LoadGeometryLineStringHP()
912 : {
913 0 : int nInvalid = 0;
914 :
915 : VFKDataBlock *poDataBlockLines =
916 0 : cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SBP"));
917 0 : if (nullptr == poDataBlockLines)
918 : {
919 0 : CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
920 : m_pszName);
921 0 : return nInvalid;
922 : }
923 :
924 0 : poDataBlockLines->LoadGeometry();
925 0 : const int idxId = GetPropertyIndex("ID");
926 0 : CPLString osColumn;
927 0 : osColumn.Printf("%s_ID", m_pszName);
928 0 : const int idxMy_Id = poDataBlockLines->GetPropertyIndex(osColumn);
929 : const int idxPCB =
930 0 : poDataBlockLines->GetPropertyIndex("PORADOVE_CISLO_BODU");
931 0 : if (idxId < 0 || idxMy_Id < 0 || idxPCB < 0)
932 : {
933 0 : CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
934 : m_pszName);
935 0 : return nInvalid;
936 : }
937 :
938 : // Reduce to first segment.
939 0 : VFKFeatureList poLineList = poDataBlockLines->GetFeatures(idxPCB, 1);
940 0 : for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
941 : {
942 : VFKFeature *poFeature =
943 0 : cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
944 0 : CPLAssert(nullptr != poFeature);
945 : GUIntBig id =
946 0 : strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
947 : VFKFeature *poLine =
948 0 : poDataBlockLines->GetFeature(idxMy_Id, id, &poLineList);
949 0 : if (!poLine || !poLine->GetGeometry())
950 0 : continue;
951 0 : if (!poFeature->SetGeometry(poLine->GetGeometry()))
952 0 : nInvalid++;
953 : }
954 0 : poDataBlockLines->ResetReading();
955 :
956 0 : return nInvalid;
957 : }
958 :
959 : /*!
960 : \brief Load geometry (polygon BUD/PAR layers)
961 :
962 : \return number of invalid features
963 : */
964 0 : int VFKDataBlock::LoadGeometryPolygon()
965 : {
966 0 : VFKDataBlock *poDataBlockLines1 = nullptr;
967 0 : VFKDataBlock *poDataBlockLines2 = nullptr;
968 :
969 0 : bool bIsPar = false;
970 0 : if (EQUAL(m_pszName, "PAR"))
971 : {
972 : poDataBlockLines1 =
973 0 : cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("HP"));
974 0 : poDataBlockLines2 = poDataBlockLines1;
975 0 : bIsPar = true;
976 : }
977 : else
978 : {
979 : poDataBlockLines1 =
980 0 : cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("OB"));
981 : poDataBlockLines2 =
982 0 : cpl::down_cast<VFKDataBlock *>(m_poReader->GetDataBlock("SBP"));
983 0 : bIsPar = false;
984 : }
985 :
986 0 : int nInvalid = 0;
987 0 : if (nullptr == poDataBlockLines1 || nullptr == poDataBlockLines2)
988 : {
989 0 : CPLError(CE_Failure, CPLE_NotSupported, "Data block %s not found.\n",
990 : m_pszName);
991 0 : return nInvalid;
992 : }
993 :
994 0 : poDataBlockLines1->LoadGeometry();
995 0 : poDataBlockLines2->LoadGeometry();
996 0 : int idxId = GetPropertyIndex("ID");
997 0 : if (idxId < 0)
998 : {
999 0 : CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
1000 : m_pszName);
1001 0 : return nInvalid;
1002 : }
1003 :
1004 0 : int idxBud = 0;
1005 0 : int idxOb = 0;
1006 0 : int idxIdOb = 0;
1007 0 : int idxPar1 = 0;
1008 0 : int idxPar2 = 0;
1009 0 : if (bIsPar)
1010 : {
1011 0 : idxPar1 = poDataBlockLines1->GetPropertyIndex("PAR_ID_1");
1012 0 : idxPar2 = poDataBlockLines1->GetPropertyIndex("PAR_ID_2");
1013 0 : if (idxPar1 < 0 || idxPar2 < 0)
1014 : {
1015 0 : CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
1016 : m_pszName);
1017 0 : return nInvalid;
1018 : }
1019 : }
1020 : else
1021 : { /* BUD */
1022 0 : idxIdOb = poDataBlockLines1->GetPropertyIndex("ID");
1023 0 : idxBud = poDataBlockLines1->GetPropertyIndex("BUD_ID");
1024 0 : idxOb = poDataBlockLines2->GetPropertyIndex("OB_ID");
1025 0 : if (idxIdOb < 0 || idxBud < 0 || idxOb < 0)
1026 : {
1027 0 : CPLError(CE_Failure, CPLE_NotSupported, "Corrupted data (%s).\n",
1028 : m_pszName);
1029 0 : return nInvalid;
1030 : }
1031 : }
1032 :
1033 0 : VFKFeatureList poLineList;
1034 0 : PointListArray poRingList; /* first is to be considered as exterior */
1035 0 : OGRLinearRing ogrRing;
1036 0 : OGRPolygon ogrPolygon;
1037 :
1038 0 : for (int i = 0; i < ((IVFKDataBlock *)this)->GetFeatureCount(); i++)
1039 : {
1040 : VFKFeature *poFeature =
1041 0 : cpl::down_cast<VFKFeature *>(GetFeatureByIndex(i));
1042 0 : CPLAssert(nullptr != poFeature);
1043 : const GUIntBig id =
1044 0 : strtoul(poFeature->GetProperty(idxId)->GetValueS(), nullptr, 0);
1045 0 : if (bIsPar)
1046 : {
1047 0 : poLineList = poDataBlockLines1->GetFeatures(idxPar1, idxPar2, id);
1048 : }
1049 : else
1050 : {
1051 : VFKFeature *poLineOb, *poLineSbp;
1052 0 : std::vector<VFKFeature *> poLineListOb;
1053 0 : poLineListOb = poDataBlockLines1->GetFeatures(idxBud, id);
1054 0 : for (std::vector<VFKFeature *>::const_iterator
1055 0 : iOb = poLineListOb.begin(),
1056 0 : eOb = poLineListOb.end();
1057 0 : iOb != eOb; ++iOb)
1058 : {
1059 0 : poLineOb = (*iOb);
1060 0 : GUIntBig idOb = strtoul(
1061 : poLineOb->GetProperty(idxIdOb)->GetValueS(), nullptr, 0);
1062 0 : poLineSbp = poDataBlockLines2->GetFeature(idxOb, idOb);
1063 0 : if (poLineSbp)
1064 0 : poLineList.push_back(poLineSbp);
1065 : }
1066 : }
1067 0 : if (poLineList.size() < 1)
1068 0 : continue;
1069 :
1070 : /* clear */
1071 0 : ogrPolygon.empty();
1072 0 : poRingList.clear();
1073 :
1074 : /* collect rings (points) */
1075 0 : bool bFound = false;
1076 0 : int nCount = 0;
1077 0 : int nCountMax = static_cast<int>(poLineList.size()) * 2;
1078 0 : while (!poLineList.empty() && nCount < nCountMax)
1079 : {
1080 0 : bool bNewRing = !bFound;
1081 0 : bFound = false;
1082 0 : for (VFKFeatureList::iterator iHp = poLineList.begin(),
1083 0 : eHp = poLineList.end();
1084 0 : iHp != eHp; ++iHp)
1085 : {
1086 0 : auto pGeom = (*iHp)->GetGeometry();
1087 0 : if (pGeom && AppendLineToRing(&poRingList,
1088 : pGeom->toLineString(), bNewRing))
1089 : {
1090 0 : bFound = true;
1091 0 : poLineList.erase(iHp);
1092 0 : break;
1093 : }
1094 : }
1095 0 : nCount++;
1096 : }
1097 : /* create rings */
1098 0 : for (PointListArray::const_iterator iRing = poRingList.begin(),
1099 0 : eRing = poRingList.end();
1100 0 : iRing != eRing; ++iRing)
1101 : {
1102 0 : PointList *poList = *iRing;
1103 0 : ogrRing.empty();
1104 0 : for (PointList::iterator iPoint = poList->begin(),
1105 0 : ePoint = poList->end();
1106 0 : iPoint != ePoint; ++iPoint)
1107 : {
1108 0 : ogrRing.addPoint(&(*iPoint));
1109 : }
1110 0 : ogrPolygon.addRing(&ogrRing);
1111 : }
1112 : /* set polygon */
1113 0 : ogrPolygon.setCoordinateDimension(2); /* force 2D */
1114 0 : if (!poFeature->SetGeometry(&ogrPolygon))
1115 0 : nInvalid++;
1116 : }
1117 :
1118 : /* free ring list */
1119 0 : for (PointListArray::iterator iRing = poRingList.begin(),
1120 0 : eRing = poRingList.end();
1121 0 : iRing != eRing; ++iRing)
1122 : {
1123 0 : delete (*iRing);
1124 0 : *iRing = nullptr;
1125 : }
1126 0 : poDataBlockLines1->ResetReading();
1127 0 : poDataBlockLines2->ResetReading();
1128 :
1129 0 : return nInvalid;
1130 : }
|