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