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