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