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