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