Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: VFK Reader - Feature definition
4 : * Purpose: Implements IVFKFeature/VFKFeature class.
5 : * Author: Martin Landa, landa.martin gmail.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2009-2010, 2012-2015, Martin Landa <landa.martin gmail.com>
9 : * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "vfkreader.h"
15 : #include "vfkreaderp.h"
16 :
17 : #include "cpl_conv.h"
18 : #include "cpl_error.h"
19 :
20 : /*!
21 : \brief IVFKFeature constructor
22 :
23 : \param poDataBlock pointer to VFKDataBlock instance
24 : */
25 1558 : IVFKFeature::IVFKFeature(IVFKDataBlock *poDataBlock)
26 : : m_poDataBlock(poDataBlock), m_nFID(-1),
27 3116 : m_nGeometryType(poDataBlock->GetGeometryType()), m_bGeometry(false),
28 1558 : m_bValid(false)
29 : {
30 1558 : CPLAssert(nullptr != poDataBlock);
31 1558 : }
32 :
33 : /*!
34 : \brief IVFKFeature destructor
35 : */
36 3116 : IVFKFeature::~IVFKFeature()
37 : {
38 1558 : m_poDataBlock = nullptr;
39 1558 : }
40 :
41 : /*!
42 : \brief Set feature geometry type
43 : */
44 0 : void IVFKFeature::SetGeometryType(OGRwkbGeometryType nGeomType)
45 : {
46 0 : m_nGeometryType = nGeomType;
47 0 : }
48 :
49 : /*!
50 : \brief Set feature id
51 :
52 : FID: 0 for next, -1 for same
53 :
54 : \param nFID feature id
55 : */
56 0 : void IVFKFeature::SetFID(GIntBig nFID)
57 : {
58 0 : if (m_nFID > 0)
59 : {
60 0 : m_nFID = nFID;
61 : }
62 : else
63 : {
64 0 : m_nFID = m_poDataBlock->GetFeatureCount() + 1;
65 : }
66 0 : }
67 :
68 : /*!
69 : \brief Compute determinant of matrix with columns x,y and z
70 :
71 : Simple formula requires reasonable numbers
72 :
73 : \param x first column array
74 : \param y second column array
75 : \param z third column array
76 :
77 : \return double determinant value
78 : */
79 0 : double IVFKFeature::GetDeterminatOfMatrixDim3(double x[3], double y[3],
80 : double z[3])
81 : {
82 0 : return x[0] * y[1] * z[2] - x[0] * z[1] * y[2] - y[0] * x[1] * z[2] +
83 0 : y[0] * x[2] * z[1] + z[0] * x[1] * y[2] - z[0] * y[1] * x[2];
84 : }
85 :
86 : /*!
87 : \brief Find circle center determined by three point
88 :
89 : \param c_xy circle center coordinates array
90 : \param x array of three x coordinates
91 : \param y array of three x coordinates
92 : */
93 0 : void IVFKFeature::GetCircleCenterFrom3Points(double c_xy[2], double x[3],
94 : double y[3])
95 : {
96 : /* reduce coordinates by average coordinate */
97 0 : int n = 3;
98 0 : double sum_x = 0.0f, sum_y = 0.0f;
99 0 : for (int i = 0; i < n; i++)
100 : {
101 0 : sum_x += x[i];
102 0 : sum_y += y[i];
103 : }
104 :
105 0 : const double x_t = sum_x / 3;
106 0 : const double y_t = sum_y / 3;
107 :
108 : double x_r[3], y_r[3];
109 :
110 0 : for (int i = 0; i < n; i++)
111 : {
112 0 : x_r[i] = x[i] - x_t;
113 0 : y_r[i] = y[i] - y_t;
114 : }
115 :
116 : /* limits to test reasonable value of determinant */
117 0 : const double epsilon_min = 0.0001;
118 0 : const double epsilon_max = 10000e6;
119 :
120 : /* solve three linear equations */
121 0 : double z[3] = {1.0, 1.0, 1.0};
122 0 : double c[3] = {-(pow(x_r[0], 2) + pow(y_r[0], 2)),
123 0 : -(pow(x_r[1], 2) + pow(y_r[1], 2)),
124 0 : -(pow(x_r[2], 2) + pow(y_r[2], 2))};
125 0 : const double det_A = GetDeterminatOfMatrixDim3(x_r, y_r, z);
126 :
127 0 : if (epsilon_min <= std::fabs(det_A) && std::fabs(det_A) <= epsilon_max)
128 : {
129 0 : const double det_a = GetDeterminatOfMatrixDim3(c, y_r, z);
130 0 : const double det_b = GetDeterminatOfMatrixDim3(x_r, c, z);
131 0 : c_xy[0] = -det_a / det_A / 2 + x_t;
132 0 : c_xy[1] = -det_b / det_A / 2 + y_t;
133 : }
134 : else
135 : {
136 0 : c_xy[0] = -1.0;
137 0 : c_xy[1] = -1.0;
138 : }
139 0 : }
140 :
141 : /*!
142 : \brief Add points to circle geometry
143 :
144 : \param poGeomString pointer to OGRCircularString
145 : \param c_x circle center x coordinate
146 : \param c_y circle center y coordinate
147 : \param r circle radius
148 : */
149 0 : void IVFKFeature::AddCirclePointsToGeomString(OGRCircularString &poGeomString,
150 : double c_x, double c_y, double r)
151 : {
152 0 : OGRPoint pt;
153 :
154 : /* define first point on a circle */
155 0 : pt.setX(c_x + r);
156 0 : pt.setY(c_y);
157 0 : poGeomString.addPoint(&pt);
158 :
159 : /* define second point on a circle */
160 0 : pt.setX(c_x);
161 0 : pt.setY(c_y + r);
162 0 : poGeomString.addPoint(&pt);
163 :
164 : /* define third point on a circle */
165 0 : pt.setX(c_x - r);
166 0 : pt.setY(c_y);
167 0 : poGeomString.addPoint(&pt);
168 :
169 : /* define fourth point on a circle */
170 0 : pt.setX(c_x);
171 0 : pt.setY(c_y - r);
172 0 : poGeomString.addPoint(&pt);
173 :
174 : /* define last point (=first) on a circle */
175 0 : pt.setX(c_x + r);
176 0 : pt.setY(c_y);
177 0 : poGeomString.addPoint(&pt);
178 0 : }
179 :
180 : /*!
181 : \brief Set feature geometry
182 :
183 : Also checks if given geometry is valid
184 :
185 : \param poGeom pointer to OGRGeometry
186 : \param ftype geometry VFK type
187 :
188 : \return true on valid feature or otherwise false
189 : */
190 615 : bool IVFKFeature::SetGeometry(const OGRGeometry *poGeom, const char *ftype)
191 : {
192 615 : m_bGeometry = true;
193 :
194 615 : m_bValid = true;
195 :
196 615 : if (!poGeom)
197 : {
198 0 : return m_bValid;
199 : }
200 :
201 : /* check empty geometries */
202 615 : if (m_nGeometryType == wkbNone && poGeom->IsEmpty())
203 : {
204 0 : CPLError(CE_Warning, CPLE_AppDefined,
205 : "%s: empty geometry fid = " CPL_FRMT_GIB,
206 0 : m_poDataBlock->GetName(), m_nFID);
207 0 : m_bValid = false;
208 : }
209 :
210 : /* check coordinates */
211 615 : if (m_nGeometryType == wkbPoint)
212 : {
213 195 : auto poPoint = poGeom->toPoint();
214 195 : const double x = poPoint->getX();
215 195 : const double y = poPoint->getY();
216 195 : if (x > -430000 || x < -910000 || y > -930000 || y < -1230000)
217 : {
218 0 : CPLDebug("OGR-VFK", "%s: invalid point fid = " CPL_FRMT_GIB,
219 0 : m_poDataBlock->GetName(), m_nFID);
220 0 : m_bValid = false;
221 : }
222 : }
223 :
224 : /* check degenerated polygons */
225 615 : if (m_nGeometryType == wkbPolygon)
226 : {
227 15 : const OGRLinearRing *poRing = poGeom->toPolygon()->getExteriorRing();
228 15 : if (!poRing || poRing->getNumPoints() < 3)
229 : {
230 0 : CPLDebug("OGR-VFK", "%s: invalid polygon fid = " CPL_FRMT_GIB,
231 0 : m_poDataBlock->GetName(), m_nFID);
232 0 : m_bValid = false;
233 : }
234 : }
235 :
236 615 : std::unique_ptr<OGRGeometry> newGeom;
237 615 : if (m_bValid)
238 : {
239 615 : if (ftype)
240 : {
241 196 : OGRPoint pt;
242 196 : OGRCircularString poGeomString;
243 :
244 196 : OGRGeometry *poGeomCurved = nullptr;
245 196 : if (EQUAL(ftype, "15") || EQUAL(ftype, "16"))
246 : { /* -> circle or arc */
247 14 : auto poLS = poGeom->toLineString();
248 14 : const int npoints = poLS->getNumPoints();
249 14 : if (!EQUAL(ftype, "15"))
250 : {
251 56 : for (int i = 0; i < npoints; i++)
252 : {
253 42 : poLS->getPoint(i, &pt);
254 42 : poGeomString.addPoint(&pt);
255 : }
256 : }
257 14 : if (EQUAL(ftype, "15"))
258 : {
259 0 : if (npoints < 3)
260 : {
261 0 : CPLError(CE_Warning, CPLE_AppDefined,
262 : "npoints is %d. expected 3", npoints);
263 : }
264 0 : if (npoints > 3)
265 : {
266 0 : CPLError(CE_Warning, CPLE_AppDefined,
267 : "npoints is %d. Will overflow buffers. "
268 : "Cannot continue.",
269 : npoints);
270 0 : m_bValid = false;
271 0 : return false;
272 : }
273 :
274 : /* compute center and radius of a circle */
275 0 : double x[3] = {0.0, 0.0, 0.0};
276 0 : double y[3] = {0.0, 0.0, 0.0};
277 :
278 0 : for (int i = 0; i < npoints; i++)
279 : {
280 0 : poLS->getPoint(i, &pt);
281 0 : x[i] = pt.getX();
282 0 : y[i] = pt.getY();
283 : }
284 :
285 : /* solve as 3 linear equation x^2+y^2+2ax+2by+c=0 */
286 : double c_xy[2];
287 0 : double r = 0.0f;
288 0 : GetCircleCenterFrom3Points(c_xy, x, y);
289 :
290 : /* TODO (seidlmic) how to correctly handle invalid configuration */
291 0 : if (c_xy[0] == -1.0f && c_xy[1] == -1.0f)
292 : {
293 0 : CPLError(CE_Warning, CPLE_AppDefined,
294 : "Invalid 3 points circle configuration. Can "
295 : "not find circle center");
296 0 : m_bValid = false;
297 0 : return false;
298 : }
299 :
300 0 : r = pow(pow((c_xy[0] - x[0]), 2) + pow((c_xy[1] - y[0]), 2),
301 : 0.5);
302 :
303 0 : CPLDebug(
304 : "OGR-VFK",
305 : "Circle center point (ftype 15) X: %f, Y: %f, r: %f",
306 : c_xy[0], c_xy[1], r);
307 :
308 0 : AddCirclePointsToGeomString(poGeomString, c_xy[0], c_xy[1],
309 : r);
310 14 : }
311 : }
312 182 : else if (strlen(ftype) > 2 && STARTS_WITH_CI(ftype, "15"))
313 : { /* -> circle with radius */
314 0 : char s[3] = {}; /* 15 */
315 :
316 0 : float r = 0.0f;
317 0 : if (2 != sscanf(ftype, "%2s %f", s, &r) || r < 0)
318 : {
319 0 : CPLDebug("OGR-VFK",
320 : "%s: invalid circle (unknown or negative radius) "
321 : "fid = " CPL_FRMT_GIB,
322 0 : m_poDataBlock->GetName(), m_nFID);
323 0 : m_bValid = false;
324 : }
325 : else
326 : {
327 0 : auto poLS = poGeom->toLineString();
328 0 : poLS->getPoint(0, &pt);
329 0 : const double c_x = pt.getX();
330 0 : const double c_y = pt.getY();
331 :
332 0 : AddCirclePointsToGeomString(poGeomString, c_x, c_y, r);
333 0 : }
334 : }
335 182 : else if (EQUAL(ftype, "11"))
336 : { /* curve */
337 0 : auto poLS = poGeom->toLineString();
338 0 : const int npoints = poLS->getNumPoints();
339 0 : if (npoints > 2)
340 : { /* circular otherwise line string */
341 0 : for (int i = 0; i < npoints; i++)
342 : {
343 0 : poLS->getPoint(i, &pt);
344 0 : poGeomString.addPoint(&pt);
345 : }
346 : }
347 : }
348 :
349 196 : if (!poGeomString.IsEmpty())
350 14 : poGeomCurved = poGeomString.CurveToLine();
351 :
352 196 : if (poGeomCurved)
353 : {
354 : const int npoints =
355 14 : poGeomCurved->toLineString()->getNumPoints();
356 14 : CPLDebug("OGR-VFK",
357 : "%s: curve (type=%s) to linestring (npoints=%d) fid "
358 : "= " CPL_FRMT_GIB,
359 14 : m_poDataBlock->GetName(), ftype, npoints, m_nFID);
360 14 : if (npoints > 1)
361 14 : newGeom.reset(poGeomCurved->clone());
362 14 : delete poGeomCurved;
363 : }
364 : }
365 :
366 615 : if (!newGeom)
367 : {
368 : /* check degenerated linestrings */
369 601 : if (m_nGeometryType == wkbLineString)
370 : {
371 391 : auto poLS = poGeom->toLineString();
372 391 : const int npoints = poLS->getNumPoints();
373 391 : if (npoints < 2)
374 : {
375 0 : CPLError(CE_Warning, CPLE_AppDefined,
376 : "%s: invalid linestring (%d vertices) fid "
377 : "= " CPL_FRMT_GIB,
378 0 : m_poDataBlock->GetName(), npoints, m_nFID);
379 0 : m_bValid = false;
380 : }
381 : }
382 :
383 601 : if (m_bValid)
384 601 : newGeom.reset(poGeom->clone()); /* make copy */
385 : }
386 : }
387 :
388 615 : m_paGeom = std::move(newGeom);
389 :
390 615 : return m_bValid;
391 : }
392 :
393 : /*!
394 : \brief Get feature geometry
395 :
396 : \return pointer to OGRGeometry or NULL on error
397 : */
398 1529 : const OGRGeometry *IVFKFeature::GetGeometry()
399 : {
400 1529 : if (m_nGeometryType != wkbNone && !m_bGeometry)
401 0 : LoadGeometry();
402 :
403 1529 : return m_paGeom.get();
404 : }
405 :
406 : /*!
407 : \brief Load geometry
408 :
409 : \return true on success or false on failure
410 : */
411 0 : bool IVFKFeature::LoadGeometry()
412 : {
413 0 : if (m_bGeometry)
414 0 : return true;
415 :
416 0 : const char *pszName = m_poDataBlock->GetName();
417 :
418 0 : if (EQUAL(pszName, "SOBR") || EQUAL(pszName, "OBBP") ||
419 0 : EQUAL(pszName, "SPOL") || EQUAL(pszName, "OB") ||
420 0 : EQUAL(pszName, "OP") || EQUAL(pszName, "OBPEJ"))
421 : {
422 : /* -> wkbPoint */
423 :
424 0 : return LoadGeometryPoint();
425 : }
426 0 : else if (EQUAL(pszName, "SBP") || EQUAL(pszName, "SBPG"))
427 : {
428 : /* -> wkbLineString */
429 0 : return LoadGeometryLineStringSBP();
430 : }
431 0 : else if (EQUAL(pszName, "HP") || EQUAL(pszName, "DPM") ||
432 0 : EQUAL(pszName, "ZVB"))
433 : {
434 : /* -> wkbLineString */
435 0 : return LoadGeometryLineStringHP();
436 : }
437 0 : else if (EQUAL(pszName, "PAR") || EQUAL(pszName, "BUD"))
438 : {
439 : /* -> wkbPolygon */
440 0 : return LoadGeometryPolygon();
441 : }
442 :
443 0 : return false;
444 : }
445 :
446 : /*!
447 : \brief VFKFeature constructor
448 :
449 : \param poDataBlock pointer to VFKDataBlock instance
450 : */
451 870 : VFKFeature::VFKFeature(IVFKDataBlock *poDataBlock, GIntBig iFID)
452 870 : : IVFKFeature(poDataBlock)
453 : {
454 870 : m_nFID = iFID;
455 870 : m_propertyList.assign(poDataBlock->GetPropertyCount(), VFKProperty());
456 870 : CPLAssert(size_t(poDataBlock->GetPropertyCount()) == m_propertyList.size());
457 870 : }
458 :
459 : /*!
460 : \brief Set feature properties
461 :
462 : \param pszLine pointer to line containing feature definition
463 :
464 : \return true on success or false on failure
465 : */
466 870 : bool VFKFeature::SetProperties(const char *pszLine)
467 : {
468 870 : const char *poChar = pszLine; // Used after for.
469 5310 : for (; *poChar != '\0' && *poChar != ';'; poChar++)
470 : /* skip data block name */
471 : ;
472 870 : if (*poChar == '\0')
473 0 : return false; /* nothing to read */
474 :
475 870 : poChar++; /* skip ';' after data block name */
476 :
477 : /* remove extra quotes (otherwise due to buggy format the parsing is
478 : * almost impossible) */
479 1740 : CPLString osLine;
480 68760 : while (*poChar != '\0')
481 : {
482 67890 : if (*poChar == '"')
483 : {
484 : /* count quotes */
485 4380 : int nQuotes = 1;
486 5280 : while (*(++poChar) == '"')
487 900 : nQuotes++;
488 :
489 4380 : if (nQuotes % 2 != 0)
490 : {
491 : /* even number of quotes -> only last quote used */
492 3480 : poChar -= 1;
493 : }
494 : else
495 : {
496 900 : if ((*poChar == ';' || *poChar == '\0') &&
497 855 : *(poChar - nQuotes - 1) == ';')
498 : {
499 : /* empty values (;""; / ;"" / ;""""; / ...)
500 : -> only last two quotes used */
501 840 : poChar -= 2;
502 : }
503 60 : else if (*poChar == '\0')
504 0 : break;
505 : /* odd number of quotes -> none of quotes used */
506 : }
507 : }
508 67890 : osLine += *(poChar++);
509 : }
510 870 : poChar = osLine;
511 :
512 : /* read properties into the list */
513 870 : const char *poProp = poChar;
514 870 : unsigned int iIndex = 0;
515 870 : unsigned int nLength = 0;
516 870 : unsigned int nQuotes = 0;
517 870 : bool inString = false;
518 870 : char *pszProp = nullptr;
519 1740 : std::vector<CPLString> oPropList;
520 64440 : while (*poChar != '\0')
521 : {
522 63615 : if ((!inString && *poChar == '"') || /* begin of string */
523 17265 : (inString && *poChar == '"' && nQuotes == 1 && /* end of string */
524 1320 : (*(poChar + 1) == ';' || *(poChar + 1) == '\0')))
525 : {
526 :
527 3480 : poChar++; /* skip '"' */
528 3480 : inString = !inString;
529 3480 : if (inString)
530 : {
531 2160 : nQuotes = 1;
532 2160 : poProp = poChar;
533 2160 : if (*poChar == '"' &&
534 840 : (*(poChar + 1) == ';' || *(poChar + 1) == '\0'))
535 : {
536 : /* process empty string */
537 840 : poChar++;
538 840 : inString = false;
539 : }
540 : else
541 : {
542 : /* count number of starting quotes */
543 1320 : while (*poChar == '"')
544 : {
545 0 : nQuotes++;
546 0 : nLength++;
547 0 : poChar++;
548 : }
549 : }
550 : }
551 3480 : if (*poChar == '\0')
552 : {
553 : /* end of line */
554 45 : break;
555 : }
556 : }
557 63570 : if (*poChar == ';' && !inString)
558 : {
559 : /* end of property */
560 10050 : pszProp = (char *)CPLRealloc(pszProp, nLength + 1);
561 10050 : if (nLength > 0)
562 7380 : strncpy(pszProp, poProp, nLength);
563 10050 : pszProp[nLength] = '\0';
564 : /* add new property into the list */
565 10050 : oPropList.push_back(pszProp);
566 : /* prepare for next property */
567 10050 : iIndex++;
568 10050 : poProp = ++poChar;
569 10050 : nLength = 0;
570 10050 : nQuotes = 0;
571 : }
572 : else
573 : {
574 53520 : if (*poChar == '"' && nQuotes > 1)
575 0 : nQuotes--;
576 :
577 : /* add character to property */
578 53520 : poChar++;
579 53520 : nLength++;
580 : }
581 : }
582 : /* append last property */
583 870 : if (inString && nLength > 0)
584 : {
585 0 : nLength--; /* ignore '"' */
586 : }
587 870 : pszProp = (char *)CPLRealloc(pszProp, nLength + 1);
588 870 : if (nLength > 0)
589 405 : strncpy(pszProp, poProp, nLength);
590 870 : pszProp[nLength] = '\0';
591 870 : oPropList.push_back(pszProp);
592 :
593 : /* set properties from the list */
594 870 : if (oPropList.size() != (size_t)m_poDataBlock->GetPropertyCount())
595 : {
596 : /* try to read also invalid records */
597 0 : CPLError(CE_Warning, CPLE_AppDefined,
598 : "%s: invalid number of properties %d should be %d\n%s",
599 0 : m_poDataBlock->GetName(), (int)oPropList.size(),
600 0 : m_poDataBlock->GetPropertyCount(), pszLine);
601 0 : CPLFree(pszProp);
602 0 : return false;
603 : }
604 870 : iIndex = 0;
605 11790 : for (std::vector<CPLString>::iterator ip = oPropList.begin();
606 22710 : ip != oPropList.end(); ++ip)
607 : {
608 10920 : SetProperty(iIndex++, (*ip).c_str());
609 : }
610 :
611 : // TODO(martinl): Why was this block disabled?
612 : /* set fid
613 : if (EQUAL(m_poDataBlock->GetName(), "SBP")) {
614 : const VFKProperty *poVfkProperty = GetProperty("PORADOVE_CISLO_BODU");
615 : if (poVfkProperty)
616 : {
617 : GUIntBig id = strtoul(poVfkProperty->GetValueS(), NULL, 0);
618 : if (id == 1)
619 : SetFID(0);
620 : else
621 : SetFID(-1);
622 : }
623 : }
624 : else {
625 : SetFID(0);
626 : }
627 : */
628 870 : CPLFree(pszProp);
629 :
630 870 : return true;
631 : }
632 :
633 : /*!
634 : \brief Set feature property
635 :
636 : \param iIndex property index
637 : \param pszValue property value
638 :
639 : \return true on success, false on failure
640 : */
641 10920 : bool VFKFeature::SetProperty(int iIndex, const char *pszValue)
642 : {
643 21840 : if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
644 10920 : size_t(iIndex) >= m_propertyList.size())
645 0 : return false;
646 :
647 10920 : if (strlen(pszValue) < 1)
648 : {
649 3135 : m_propertyList[iIndex] = VFKProperty();
650 3135 : return true;
651 : }
652 :
653 7785 : const OGRFieldType fType = m_poDataBlock->GetProperty(iIndex)->GetType();
654 :
655 7785 : switch (fType)
656 : {
657 6075 : case OFTInteger:
658 : case OFTInteger64:
659 : {
660 6075 : errno = 0;
661 6075 : int pbOverflow = 0;
662 6075 : char *pszLast = nullptr;
663 6075 : if (fType == OFTInteger)
664 4410 : m_propertyList[iIndex] = VFKProperty(
665 4410 : static_cast<int>(strtol(pszValue, &pszLast, 10)));
666 : else /* OFTInteger64 */
667 3870 : m_propertyList[iIndex] =
668 7740 : VFKProperty(CPLAtoGIntBigEx(pszValue, true, &pbOverflow));
669 :
670 8280 : if ((fType == OFTInteger &&
671 2205 : (errno == ERANGE || !pszLast || *pszLast)) ||
672 8280 : CPLGetValueType(pszValue) != CPL_VALUE_INTEGER || pbOverflow)
673 0 : CPLError(
674 : CE_Warning, CPLE_AppDefined,
675 : "Value '%s' parsed incompletely to integer " CPL_FRMT_GIB
676 : ".",
677 : pszValue,
678 : (fType == OFTInteger)
679 0 : ? m_propertyList[iIndex].GetValueI()
680 0 : : m_propertyList[iIndex].GetValueI64());
681 6075 : break;
682 : }
683 390 : case OFTReal:
684 390 : m_propertyList[iIndex] = VFKProperty(CPLAtof(pszValue));
685 390 : break;
686 1320 : default:
687 : const char *pszEncoding =
688 1320 : m_poDataBlock->GetProperty(iIndex)->GetEncoding();
689 1320 : if (pszEncoding)
690 : {
691 : char *pszValueEnc =
692 615 : CPLRecode(pszValue, pszEncoding, CPL_ENC_UTF8);
693 615 : m_propertyList[iIndex] = VFKProperty(pszValueEnc);
694 615 : CPLFree(pszValueEnc);
695 : }
696 : else
697 : {
698 705 : m_propertyList[iIndex] = VFKProperty(pszValue);
699 : }
700 1320 : break;
701 : }
702 :
703 7785 : return true;
704 : }
705 :
706 : /*!
707 : \brief Get property value by index
708 :
709 : \param iIndex property index
710 :
711 : \return property value, NULL on error
712 : */
713 11355 : const VFKProperty *VFKFeature::GetProperty(int iIndex) const
714 : {
715 22710 : if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
716 11355 : size_t(iIndex) >= m_propertyList.size())
717 0 : return nullptr;
718 :
719 11355 : const VFKProperty *poProperty = &m_propertyList[iIndex];
720 11355 : return poProperty;
721 : }
722 :
723 : /*!
724 : \brief Get property value by name
725 :
726 : \param pszName property name
727 :
728 : \return property value, NULL on error
729 : */
730 435 : const VFKProperty *VFKFeature::GetProperty(const char *pszName) const
731 : {
732 435 : return GetProperty(m_poDataBlock->GetPropertyIndex(pszName));
733 : }
734 :
735 : /*!
736 : \brief Load geometry (point layers)
737 :
738 : \todo Really needed?
739 :
740 : \return true on success, false on failure
741 : */
742 0 : bool VFKFeature::LoadGeometryPoint()
743 : {
744 0 : const int i_idxY = m_poDataBlock->GetPropertyIndex("SOURADNICE_Y");
745 0 : const int i_idxX = m_poDataBlock->GetPropertyIndex("SOURADNICE_X");
746 0 : if (i_idxY < 0 || i_idxX < 0)
747 0 : return false;
748 :
749 0 : auto propertyY = GetProperty(i_idxY);
750 0 : auto propertyX = GetProperty(i_idxX);
751 0 : if (!propertyY || !propertyX)
752 0 : return false;
753 0 : const double x = -1.0 * propertyY->GetValueD();
754 0 : const double y = -1.0 * propertyX->GetValueD();
755 0 : OGRPoint pt(x, y);
756 0 : SetGeometry(&pt);
757 :
758 0 : return true;
759 : }
760 :
761 : /*!
762 : \brief Load geometry (linestring SBP/SBPG layer)
763 :
764 : \todo Really needed?
765 :
766 : \return true on success or false on failure
767 : */
768 0 : bool VFKFeature::LoadGeometryLineStringSBP()
769 : {
770 : VFKDataBlock *poDataBlockPoints =
771 0 : (VFKDataBlock *)m_poDataBlock->GetReader()->GetDataBlock("SOBR");
772 0 : if (!poDataBlockPoints)
773 0 : return false;
774 :
775 0 : const int idxId = poDataBlockPoints->GetPropertyIndex("ID");
776 0 : const int idxBp_Id = m_poDataBlock->GetPropertyIndex("BP_ID");
777 0 : const int idxPCB = m_poDataBlock->GetPropertyIndex("PORADOVE_CISLO_BODU");
778 0 : if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
779 0 : return false;
780 :
781 0 : VFKFeature *poLine = this;
782 0 : OGRLineString OGRLine;
783 : while (true)
784 : {
785 0 : auto property_idxBp_Id = poLine->GetProperty(idxBp_Id);
786 0 : if (!property_idxBp_Id)
787 0 : break;
788 0 : auto property_idxPCB = poLine->GetProperty(idxPCB);
789 0 : if (!property_idxPCB)
790 0 : break;
791 :
792 0 : const int id = property_idxBp_Id->GetValueI();
793 0 : const int ipcb = property_idxPCB->GetValueI();
794 0 : if (OGRLine.getNumPoints() > 0 && ipcb == 1)
795 : {
796 0 : m_poDataBlock->GetPreviousFeature(); /* push back */
797 0 : break;
798 : }
799 :
800 0 : VFKFeature *poPoint = poDataBlockPoints->GetFeature(idxId, id);
801 0 : if (!poPoint)
802 : {
803 0 : continue;
804 : }
805 0 : const OGRPoint *pt = poPoint->GetGeometry()->toPoint();
806 0 : OGRLine.addPoint(pt);
807 :
808 0 : poLine = (VFKFeature *)m_poDataBlock->GetNextFeature();
809 0 : if (!poLine)
810 0 : break;
811 0 : };
812 :
813 0 : OGRLine.setCoordinateDimension(2); /* force 2D */
814 0 : SetGeometry(&OGRLine);
815 :
816 : /* reset reading */
817 0 : poDataBlockPoints->ResetReading();
818 :
819 0 : return true;
820 : }
821 :
822 : /*!
823 : \brief Load geometry (linestring HP/DPM layer)
824 :
825 : \todo Really needed?
826 :
827 : \return true on success or false on failure
828 : */
829 0 : bool VFKFeature::LoadGeometryLineStringHP()
830 : {
831 : VFKDataBlock *poDataBlockLines =
832 0 : (VFKDataBlock *)m_poDataBlock->GetReader()->GetDataBlock("SBP");
833 0 : if (!poDataBlockLines)
834 0 : return false;
835 :
836 0 : const int idxId = m_poDataBlock->GetPropertyIndex("ID");
837 0 : const int idxHp_Id = poDataBlockLines->GetPropertyIndex("HP_ID");
838 0 : if (idxId < 0 || idxHp_Id < 0)
839 0 : return false;
840 :
841 0 : auto property = GetProperty(idxId);
842 0 : if (!property)
843 0 : return false;
844 0 : const int id = property->GetValueI();
845 0 : VFKFeature *poLine = poDataBlockLines->GetFeature(idxHp_Id, id);
846 0 : if (!poLine || !poLine->GetGeometry())
847 0 : return false;
848 :
849 0 : SetGeometry(poLine->GetGeometry());
850 0 : poDataBlockLines->ResetReading();
851 :
852 0 : return true;
853 : }
854 :
855 : /*!
856 : \brief Load geometry (polygon BUD/PAR layers)
857 :
858 : \todo Implement (really needed?)
859 :
860 : \return true on success or false on failure
861 : */
862 0 : bool VFKFeature::LoadGeometryPolygon()
863 : {
864 0 : return false;
865 : }
866 :
867 0 : OGRErr VFKFeature::LoadProperties(OGRFeature *poFeature)
868 : {
869 0 : for (int iField = 0; iField < m_poDataBlock->GetPropertyCount(); iField++)
870 : {
871 0 : auto property = GetProperty(iField);
872 0 : if (!property || property->IsNull())
873 0 : continue;
874 :
875 : OGRFieldType fType =
876 0 : poFeature->GetDefnRef()->GetFieldDefn(iField)->GetType();
877 0 : if (fType == OFTInteger)
878 0 : poFeature->SetField(iField, property->GetValueI());
879 0 : else if (fType == OFTReal)
880 0 : poFeature->SetField(iField, property->GetValueD());
881 : else
882 0 : poFeature->SetField(iField, property->GetValueS());
883 : }
884 :
885 0 : return OGRERR_NONE;
886 : }
|