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