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