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