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