/src/gdal/ogr/ogrsf_frmts/ili/ili1reader.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: Interlis 1 Reader |
4 | | * Purpose: Implementation of ILI1Reader class. |
5 | | * Author: Pirmin Kalberer, Sourcepole AG |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG |
9 | | * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "cpl_conv.h" |
15 | | #include "cpl_string.h" |
16 | | #include "ogr_api.h" |
17 | | #include "ogr_ili1.h" |
18 | | #include "ogr_geos.h" |
19 | | |
20 | | #include "ili1reader.h" |
21 | | #include "ili1readerp.h" |
22 | | |
23 | | #include <vector> |
24 | | |
25 | | #ifdef HAVE_GEOS |
26 | | #define POLYGONIZE_AREAS |
27 | | #endif |
28 | | |
29 | | #ifndef POLYGONIZE_AREAS |
30 | | #if defined(__GNUC_PREREQ) |
31 | | // # warning Interlis 1 Area polygonizing disabled. Needs GEOS >= 3.1.0 |
32 | | #endif |
33 | | #endif |
34 | | |
35 | | // |
36 | | // ILI1Reader |
37 | | // |
38 | | IILI1Reader::~IILI1Reader() |
39 | 9.27k | { |
40 | 9.27k | } |
41 | | |
42 | | ILI1Reader::ILI1Reader() |
43 | 9.27k | : fpItf(nullptr), nLayers(0), papoLayers(nullptr), curLayer(nullptr), |
44 | 9.27k | codeBlank('_'), codeUndefined('@'), codeContinue('\\') |
45 | 9.27k | { |
46 | 9.27k | } |
47 | | |
48 | | ILI1Reader::~ILI1Reader() |
49 | 9.27k | { |
50 | 9.27k | if (fpItf) |
51 | 9.27k | VSIFCloseL(fpItf); |
52 | | |
53 | 22.3k | for (int i = 0; i < nLayers; i++) |
54 | 13.0k | delete papoLayers[i]; |
55 | 9.27k | CPLFree(papoLayers); |
56 | 9.27k | } |
57 | | |
58 | | /* -------------------------------------------------------------------- */ |
59 | | /* Open the source file. */ |
60 | | /* -------------------------------------------------------------------- */ |
61 | | int ILI1Reader::OpenFile(const char *pszFilename) |
62 | 9.27k | { |
63 | 9.27k | fpItf = VSIFOpenL(pszFilename, "r"); |
64 | 9.27k | if (fpItf == nullptr) |
65 | 0 | { |
66 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open ILI file `%s'.", |
67 | 0 | pszFilename); |
68 | |
|
69 | 0 | return FALSE; |
70 | 0 | } |
71 | 9.27k | return TRUE; |
72 | 9.27k | } |
73 | | |
74 | | const char *ILI1Reader::GetLayerNameString(const char *topicname, |
75 | | const char *tablename) |
76 | 83.5k | { |
77 | | |
78 | 83.5k | return CPLSPrintf("%s__%s", topicname, tablename); |
79 | 83.5k | } |
80 | | |
81 | | int ILI1Reader::ReadModel(ImdReader *poImdReader, const char *pszModelFilename, |
82 | | OGRILI1DataSource *poDS) |
83 | 0 | { |
84 | |
|
85 | 0 | poImdReader->ReadModel(pszModelFilename); |
86 | 0 | for (FeatureDefnInfos::const_iterator it = |
87 | 0 | poImdReader->featureDefnInfos.begin(); |
88 | 0 | it != poImdReader->featureDefnInfos.end(); ++it) |
89 | 0 | { |
90 | | #if DEBUG_VERBOSE |
91 | | CPLDebug("OGR_ILI", "Adding OGRILI1Layer with table '%s'", |
92 | | it->GetTableDefnRef()->GetName()); |
93 | | #endif |
94 | 0 | OGRILI1Layer *layer = |
95 | 0 | new OGRILI1Layer(it->GetTableDefnRef(), it->poGeomFieldInfos, poDS); |
96 | 0 | AddLayer(layer); |
97 | | // Create additional layers for surface and area geometries. |
98 | 0 | for (GeomFieldInfos::const_iterator it2 = it->poGeomFieldInfos.begin(); |
99 | 0 | it2 != it->poGeomFieldInfos.end(); ++it2) |
100 | 0 | { |
101 | 0 | if (it2->second.GetGeomTableDefnRef()) |
102 | 0 | { |
103 | 0 | OGRFeatureDefn *poGeomTableDefn = |
104 | 0 | it2->second.GetGeomTableDefnRef(); |
105 | 0 | OGRGeomFieldDefn *poOGRGeomFieldDefn = |
106 | 0 | poGeomTableDefn->GetGeomFieldDefn(0); |
107 | 0 | GeomFieldInfos oGeomFieldInfos; |
108 | | // We add iliGeomType to recognize Ili1 geom tables |
109 | 0 | oGeomFieldInfos[poOGRGeomFieldDefn->GetNameRef()].iliGeomType = |
110 | 0 | it2->second.iliGeomType; |
111 | | #if DEBUG_VERBOSE |
112 | | CPLDebug("OGR_ILI", |
113 | | "Adding OGRILI1Layer with geometry table '%s'", |
114 | | poGeomTableDefn->GetName()); |
115 | | #endif |
116 | 0 | OGRILI1Layer *geomlayer = |
117 | 0 | new OGRILI1Layer(poGeomTableDefn, oGeomFieldInfos, poDS); |
118 | 0 | AddLayer(geomlayer); |
119 | 0 | } |
120 | 0 | } |
121 | 0 | } |
122 | |
|
123 | 0 | codeBlank = poImdReader->codeBlank; |
124 | 0 | CPLDebug("OGR_ILI", "Ili1Format blankCode '%c'", poImdReader->codeBlank); |
125 | 0 | codeUndefined = poImdReader->codeUndefined; |
126 | 0 | CPLDebug("OGR_ILI", "Ili1Format undefinedCode '%c'", |
127 | 0 | poImdReader->codeUndefined); |
128 | 0 | codeContinue = poImdReader->codeContinue; |
129 | 0 | CPLDebug("OGR_ILI", "Ili1Format continueCode '%c'", |
130 | 0 | poImdReader->codeContinue); |
131 | 0 | return 0; |
132 | 0 | } |
133 | | |
134 | | int ILI1Reader::ReadFeatures() |
135 | 9.27k | { |
136 | 9.27k | char **tokens = nullptr; |
137 | 9.27k | const char *pszLine = nullptr; |
138 | 9.27k | char *topic = CPLStrdup("(null)"); |
139 | 9.27k | int ret = TRUE; |
140 | | |
141 | 625k | while (ret && (tokens = ReadParseLine()) != nullptr) |
142 | 616k | { |
143 | 616k | const char *firsttok = tokens[0]; |
144 | 616k | if (EQUAL(firsttok, "SCNT")) |
145 | 2.28k | { |
146 | | // read description |
147 | 2.28k | do |
148 | 897k | { |
149 | 897k | pszLine = CPLReadLineL(fpItf); |
150 | 897k | } while (pszLine && !STARTS_WITH_CI(pszLine, "////")); |
151 | 2.28k | ret = (pszLine != nullptr); |
152 | 2.28k | } |
153 | 614k | else if (EQUAL(firsttok, "MOTR")) |
154 | 307 | { |
155 | | // read model |
156 | 307 | do |
157 | 177k | { |
158 | 177k | pszLine = CPLReadLineL(fpItf); |
159 | 177k | } while (pszLine && !STARTS_WITH_CI(pszLine, "////")); |
160 | 307 | ret = (pszLine != nullptr); |
161 | 307 | } |
162 | 613k | else if (EQUAL(firsttok, "MTID")) |
163 | 2.21k | { |
164 | 2.21k | } |
165 | 611k | else if (EQUAL(firsttok, "MODL")) |
166 | 1.85k | { |
167 | 1.85k | } |
168 | 609k | else if (EQUAL(firsttok, "TOPI") && CSLCount(tokens) >= 2) |
169 | 5.06k | { |
170 | 5.06k | CPLFree(topic); |
171 | 5.06k | topic = CPLStrdup(CSLGetField(tokens, 1)); |
172 | 5.06k | } |
173 | 604k | else if (EQUAL(firsttok, "TABL") && CSLCount(tokens) >= 2) |
174 | 70.4k | { |
175 | 70.4k | const char *layername = |
176 | 70.4k | GetLayerNameString(topic, CSLGetField(tokens, 1)); |
177 | 70.4k | CPLDebug("OGR_ILI", "Reading table '%s'", layername); |
178 | 70.4k | curLayer = GetLayerByName(layername); |
179 | | |
180 | 70.4k | if (curLayer == nullptr) |
181 | 13.0k | { // create one |
182 | 13.0k | CPLError(CE_Warning, CPLE_AppDefined, |
183 | 13.0k | "No model definition for table '%s' found, " |
184 | 13.0k | "using default field names.", |
185 | 13.0k | layername); |
186 | 13.0k | OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn( |
187 | 13.0k | GetLayerNameString(topic, CSLGetField(tokens, 1))); |
188 | 13.0k | poFeatureDefn->SetGeomType(wkbUnknown); |
189 | 13.0k | GeomFieldInfos oGeomFieldInfos; |
190 | 13.0k | curLayer = |
191 | 13.0k | new OGRILI1Layer(poFeatureDefn, oGeomFieldInfos, nullptr); |
192 | 13.0k | AddLayer(curLayer); |
193 | 13.0k | } |
194 | 70.4k | if (curLayer != nullptr) |
195 | 70.4k | { |
196 | 139k | for (int i = 0; i < curLayer->GetLayerDefn()->GetFieldCount(); |
197 | 70.4k | i++) |
198 | 68.5k | { |
199 | 68.5k | CPLDebug("OGR_ILI", "Field %d: %s", i, |
200 | 68.5k | curLayer->GetLayerDefn() |
201 | 68.5k | ->GetFieldDefn(i) |
202 | 68.5k | ->GetNameRef()); |
203 | 68.5k | } |
204 | 70.4k | } |
205 | 70.4k | ret = ReadTable(layername); |
206 | 70.4k | } |
207 | 534k | else if (EQUAL(firsttok, "ETOP")) |
208 | 4.24k | { |
209 | 4.24k | } |
210 | 529k | else if (EQUAL(firsttok, "EMOD")) |
211 | 2.38k | { |
212 | 2.38k | } |
213 | 527k | else if (EQUAL(firsttok, "ENDE")) |
214 | 8 | { |
215 | 8 | CSLDestroy(tokens); |
216 | 8 | CPLFree(topic); |
217 | 8 | return TRUE; |
218 | 8 | } |
219 | 527k | else |
220 | 527k | { |
221 | 527k | CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s", |
222 | 527k | firsttok); |
223 | 527k | } |
224 | | |
225 | 616k | CSLDestroy(tokens); |
226 | 616k | tokens = nullptr; |
227 | 616k | } |
228 | | |
229 | 9.26k | CSLDestroy(tokens); |
230 | 9.26k | CPLFree(topic); |
231 | | |
232 | 9.26k | return ret; |
233 | 9.27k | } |
234 | | |
235 | | int ILI1Reader::ReadTable(CPL_UNUSED const char *layername) |
236 | 70.4k | { |
237 | 70.4k | char **tokens = nullptr; |
238 | 70.4k | int warned = FALSE; |
239 | 70.4k | int geomIdx = -1; |
240 | | |
241 | 70.4k | OGRFeatureDefn *featureDef = curLayer->GetLayerDefn(); |
242 | 70.4k | OGRFeature *feature = nullptr; |
243 | 70.4k | bool bFeatureAdded = false; |
244 | | |
245 | 1.09M | while ((tokens = ReadParseLine()) != nullptr) |
246 | 1.06M | { |
247 | 1.06M | const char *firsttok = CSLGetField(tokens, 0); |
248 | 1.06M | if (EQUAL(firsttok, "OBJE")) |
249 | 107k | { |
250 | 107k | if (featureDef->GetFieldCount() == 0 && |
251 | 40.0k | curLayer->GetFeatureCount() == 0) |
252 | 9.05k | { |
253 | 9.05k | CPLError(CE_Warning, CPLE_AppDefined, |
254 | 9.05k | "No field definition found for table: %s", |
255 | 9.05k | featureDef->GetName()); |
256 | | // Model not read - use heuristics. |
257 | 20.8k | for (int fIndex = 1; tokens[fIndex] != nullptr; fIndex++) |
258 | 11.8k | { |
259 | 11.8k | char szFieldName[32]; |
260 | 11.8k | snprintf(szFieldName, sizeof(szFieldName), "Field%02d", |
261 | 11.8k | fIndex); |
262 | 11.8k | OGRFieldDefn oFieldDefn(szFieldName, OFTString); |
263 | 11.8k | featureDef->AddFieldDefn(&oFieldDefn); |
264 | 11.8k | } |
265 | 9.05k | } |
266 | | // start new feature |
267 | 107k | if (!bFeatureAdded) |
268 | 43.5k | delete feature; |
269 | 107k | feature = new OGRFeature(featureDef); |
270 | | |
271 | 107k | for (int fIndex = 1, fieldno = 0; |
272 | 233k | tokens[fIndex] != nullptr && |
273 | 142k | fieldno < featureDef->GetFieldCount(); |
274 | 125k | fIndex++, fieldno++) |
275 | 125k | { |
276 | 125k | if (!(tokens[fIndex][0] == codeUndefined && |
277 | 6.09k | tokens[fIndex][1] == '\0')) |
278 | 124k | { |
279 | | #ifdef DEBUG_VERBOSE |
280 | | CPLDebug("READ TABLE OGR_ILI", |
281 | | "Setting Field %d (Type %d): %s", fieldno, |
282 | | featureDef->GetFieldDefn(fieldno)->GetType(), |
283 | | tokens[fIndex]); |
284 | | #endif |
285 | 124k | if (featureDef->GetFieldDefn(fieldno)->GetType() == |
286 | 124k | OFTString) |
287 | 124k | { |
288 | | // Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode |
289 | | // to UTF-8 |
290 | 124k | char *pszRecoded = CPLRecode( |
291 | 124k | tokens[fIndex], CPL_ENC_ISO8859_1, CPL_ENC_UTF8); |
292 | | // Replace space marks |
293 | 1.56M | for (char *pszString = pszRecoded; *pszString != '\0'; |
294 | 1.44M | pszString++) |
295 | 1.44M | { |
296 | 1.44M | if (*pszString == codeBlank) |
297 | 16.4k | *pszString = ' '; |
298 | 1.44M | } |
299 | 124k | feature->SetField(fieldno, pszRecoded); |
300 | 124k | CPLFree(pszRecoded); |
301 | 124k | } |
302 | 0 | else |
303 | 0 | { |
304 | 0 | feature->SetField(fieldno, tokens[fIndex]); |
305 | 0 | } |
306 | 124k | if (featureDef->GetFieldDefn(fieldno)->GetType() == |
307 | 124k | OFTReal && |
308 | 0 | fieldno > 0 && |
309 | 0 | featureDef->GetFieldDefn(fieldno - 1)->GetType() == |
310 | 0 | OFTReal) |
311 | 0 | { |
312 | | // Check for Point geometry (Coord type). |
313 | | // If there is no ili model read, |
314 | | // we have no chance to detect the |
315 | | // geometry column. |
316 | 0 | CPLString geomfldname = |
317 | 0 | featureDef->GetFieldDefn(fieldno)->GetNameRef(); |
318 | | // Check if name ends with _1. |
319 | 0 | if (geomfldname.size() >= 2 && |
320 | 0 | geomfldname[geomfldname.size() - 2] == '_') |
321 | 0 | { |
322 | 0 | geomfldname = |
323 | 0 | geomfldname.substr(0, geomfldname.size() - 2); |
324 | 0 | geomIdx = featureDef->GetGeomFieldIndex( |
325 | 0 | geomfldname.c_str()); |
326 | 0 | if (geomIdx == -1) |
327 | 0 | { |
328 | 0 | CPLError( |
329 | 0 | CE_Warning, CPLE_AppDefined, |
330 | 0 | "No matching definition for field '%s' of " |
331 | 0 | "table %s found", |
332 | 0 | geomfldname.c_str(), featureDef->GetName()); |
333 | 0 | } |
334 | 0 | } |
335 | 0 | else |
336 | 0 | { |
337 | 0 | geomIdx = -1; |
338 | 0 | } |
339 | 0 | if (geomIdx >= 0) |
340 | 0 | { |
341 | 0 | if (featureDef->GetGeomFieldDefn(geomIdx) |
342 | 0 | ->GetType() == wkbPoint) |
343 | 0 | { |
344 | | // Add Point geometry. |
345 | 0 | OGRPoint *ogrPoint = |
346 | 0 | new OGRPoint(CPLAtof(tokens[fIndex - 1]), |
347 | 0 | CPLAtof(tokens[fIndex])); |
348 | 0 | feature->SetGeomFieldDirectly(geomIdx, |
349 | 0 | ogrPoint); |
350 | 0 | } |
351 | 0 | else if (featureDef->GetGeomFieldDefn(geomIdx) |
352 | 0 | ->GetType() == wkbPoint25D && |
353 | 0 | fieldno > 1 && |
354 | 0 | featureDef->GetFieldDefn(fieldno - 2) |
355 | 0 | ->GetType() == OFTReal) |
356 | 0 | { |
357 | | // Add 3D Point geometry. |
358 | 0 | OGRPoint *ogrPoint = |
359 | 0 | new OGRPoint(CPLAtof(tokens[fIndex - 2]), |
360 | 0 | CPLAtof(tokens[fIndex - 1]), |
361 | 0 | CPLAtof(tokens[fIndex])); |
362 | 0 | feature->SetGeomFieldDirectly(geomIdx, |
363 | 0 | ogrPoint); |
364 | 0 | } |
365 | 0 | } |
366 | 0 | } |
367 | 124k | } |
368 | 125k | } |
369 | 107k | if (!warned && featureDef->GetFieldCount() != CSLCount(tokens) - 1) |
370 | 15.0k | { |
371 | 15.0k | CPLError(CE_Warning, CPLE_AppDefined, |
372 | 15.0k | "Field count of table %s doesn't match. %d declared, " |
373 | 15.0k | "%d found (e.g. ignored LINEATTR)", |
374 | 15.0k | featureDef->GetName(), featureDef->GetFieldCount(), |
375 | 15.0k | CSLCount(tokens) - 1); |
376 | 15.0k | warned = TRUE; |
377 | 15.0k | } |
378 | 107k | if (feature->GetFieldCount() > 0) |
379 | 73.6k | { |
380 | | // USE _TID as FID. TODO: respect IDENT field from model. |
381 | 73.6k | feature->SetFID(feature->GetFieldAsInteger64(0)); |
382 | 73.6k | } |
383 | 107k | curLayer->AddFeature(feature); |
384 | 107k | bFeatureAdded = true; |
385 | 107k | geomIdx = -1; // Reset |
386 | 107k | } |
387 | 955k | else if (EQUAL(firsttok, "STPT") && feature != nullptr) |
388 | 39.7k | { |
389 | | // Find next non-Point geometry |
390 | 39.7k | if (geomIdx < 0) |
391 | 12.1k | geomIdx = 0; |
392 | 39.7k | while (geomIdx < featureDef->GetGeomFieldCount() && |
393 | 30.5k | featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint) |
394 | 0 | { |
395 | 0 | geomIdx++; |
396 | 0 | } |
397 | 39.7k | OGRwkbGeometryType geomType = |
398 | 39.7k | (geomIdx < featureDef->GetGeomFieldCount()) |
399 | 39.7k | ? featureDef->GetGeomFieldDefn(geomIdx)->GetType() |
400 | 39.7k | : wkbNone; |
401 | 39.7k | if (CSLCount(tokens) >= 3) |
402 | 24.2k | ReadGeom(tokens, geomIdx, geomType, feature); |
403 | 39.7k | } |
404 | 915k | else if (EQUAL(firsttok, "ELIN")) |
405 | 35.4k | { |
406 | | // Empty geom. |
407 | 35.4k | } |
408 | 880k | else if (EQUAL(firsttok, "EDGE") && feature != nullptr) |
409 | 68.9k | { |
410 | 68.9k | CSLDestroy(tokens); |
411 | 68.9k | tokens = ReadParseLine(); // STPT |
412 | | // Find next non-Point geometry |
413 | 68.9k | do |
414 | 68.9k | { |
415 | 68.9k | geomIdx++; |
416 | 68.9k | } while (geomIdx < featureDef->GetGeomFieldCount() && |
417 | 37.3k | featureDef->GetGeomFieldDefn(geomIdx)->GetType() == |
418 | 37.3k | wkbPoint); |
419 | 68.9k | if (CSLCount(tokens) >= 3) |
420 | 48.8k | ReadGeom(tokens, geomIdx, wkbMultiLineString, feature); |
421 | 68.9k | } |
422 | 811k | else if (EQUAL(firsttok, "PERI")) |
423 | 790 | { |
424 | 790 | } |
425 | 810k | else if (EQUAL(firsttok, "ETAB")) |
426 | 36.8k | { |
427 | 36.8k | CPLDebug("OGR_ILI", "Total features: " CPL_FRMT_GIB, |
428 | 36.8k | curLayer->GetFeatureCount()); |
429 | 36.8k | CSLDestroy(tokens); |
430 | 36.8k | if (!bFeatureAdded) |
431 | 12.4k | delete feature; |
432 | 36.8k | return TRUE; |
433 | 36.8k | } |
434 | 773k | else |
435 | 773k | { |
436 | 773k | CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s", |
437 | 773k | firsttok); |
438 | 773k | } |
439 | | |
440 | 1.02M | CSLDestroy(tokens); |
441 | 1.02M | } |
442 | | |
443 | 33.6k | if (!bFeatureAdded) |
444 | 14.5k | delete feature; |
445 | | |
446 | 33.6k | return TRUE; |
447 | 70.4k | } |
448 | | |
449 | | void ILI1Reader::ReadGeom(char **stgeom, int geomIdx, OGRwkbGeometryType eType, |
450 | | OGRFeature *feature) |
451 | 73.0k | { |
452 | | #ifdef DEBUG_VERBOSE |
453 | | CPLDebug("OGR_ILI", "ILI1Reader::ReadGeom geomIdx: %d OGRGeometryType: %s", |
454 | | geomIdx, OGRGeometryTypeToName(eType)); |
455 | | #endif |
456 | 73.0k | if (eType == wkbNone) |
457 | 4.99k | { |
458 | 4.99k | CPLError(CE_Warning, CPLE_AppDefined, |
459 | 4.99k | "Calling ILI1Reader::ReadGeom with wkbNone"); |
460 | 4.99k | } |
461 | | |
462 | | // Initialize geometry. |
463 | | |
464 | 73.0k | OGRCompoundCurve *ogrCurve = new OGRCompoundCurve(); |
465 | 73.0k | OGRCurvePolygon *ogrPoly = nullptr; // current polygon |
466 | 73.0k | OGRMultiCurve *ogrMultiLine = nullptr; // current multi line |
467 | | |
468 | 73.0k | if (eType == wkbMultiCurve || eType == wkbMultiLineString) |
469 | 48.8k | { |
470 | 48.8k | ogrMultiLine = new OGRMultiCurve(); |
471 | 48.8k | } |
472 | 24.2k | else if (eType == wkbPolygon || eType == wkbCurvePolygon) |
473 | 0 | { |
474 | 0 | ogrPoly = new OGRCurvePolygon(); |
475 | 0 | } |
476 | | |
477 | 73.0k | OGRPoint ogrPoint; // Current point. |
478 | 73.0k | ogrPoint.setX(CPLAtof(stgeom[1])); |
479 | 73.0k | ogrPoint.setY(CPLAtof(stgeom[2])); |
480 | | |
481 | 73.0k | OGRLineString *ogrLine = new OGRLineString(); |
482 | 73.0k | ogrLine->addPoint(&ogrPoint); |
483 | | |
484 | | // Parse geometry. |
485 | | |
486 | 73.0k | char **tokens = nullptr; |
487 | 73.0k | bool end = false; |
488 | 73.0k | OGRCircularString *arc = nullptr; // current arc |
489 | | |
490 | 2.62M | while (!end && (tokens = ReadParseLine()) != nullptr) |
491 | 2.55M | { |
492 | 2.55M | const char *firsttok = CSLGetField(tokens, 0); |
493 | 2.55M | if (firsttok == nullptr) |
494 | 0 | { |
495 | | // do nothing |
496 | 0 | } |
497 | 2.55M | else if (EQUAL(firsttok, "LIPT") && CSLCount(tokens) >= 3) |
498 | 513k | { |
499 | 513k | ogrPoint.setX(CPLAtof(tokens[1])); |
500 | 513k | ogrPoint.setY(CPLAtof(tokens[2])); |
501 | 513k | if (arc) |
502 | 230k | { |
503 | 230k | arc->addPoint(&ogrPoint); |
504 | 230k | OGRErr error = ogrCurve->addCurveDirectly(arc); |
505 | 230k | if (error != OGRERR_NONE) |
506 | 107k | { |
507 | 107k | char *pszJSon = arc->exportToJson(); |
508 | 107k | CPLError(CE_Warning, CPLE_AppDefined, |
509 | 107k | "Could not add geometry: %s", |
510 | 107k | pszJSon ? pszJSon : "(null)"); |
511 | 107k | CPLFree(pszJSon); |
512 | 107k | delete arc; |
513 | 107k | } |
514 | 230k | arc = nullptr; |
515 | 230k | } |
516 | 513k | ogrLine->addPoint(&ogrPoint); |
517 | 513k | } |
518 | 2.04M | else if (EQUAL(firsttok, "ARCP") && CSLCount(tokens) >= 3) |
519 | 311k | { |
520 | | // Finish line and start arc |
521 | 311k | if (ogrLine->getNumPoints() > 1) |
522 | 111k | { |
523 | 111k | OGRErr error = ogrCurve->addCurveDirectly(ogrLine); |
524 | 111k | if (error != OGRERR_NONE) |
525 | 52.5k | { |
526 | 52.5k | char *pszJSon = ogrLine->exportToJson(); |
527 | 52.5k | CPLError(CE_Warning, CPLE_AppDefined, |
528 | 52.5k | "Could not add geometry: %s", |
529 | 52.5k | pszJSon ? pszJSon : "(null)"); |
530 | 52.5k | CPLFree(pszJSon); |
531 | 52.5k | delete ogrLine; |
532 | 52.5k | } |
533 | 111k | ogrLine = new OGRLineString(); |
534 | 111k | } |
535 | 200k | else |
536 | 200k | { |
537 | 200k | ogrLine->empty(); |
538 | 200k | } |
539 | 311k | delete arc; |
540 | 311k | arc = new OGRCircularString(); |
541 | 311k | arc->addPoint(&ogrPoint); |
542 | 311k | ogrPoint.setX(CPLAtof(tokens[1])); |
543 | 311k | ogrPoint.setY(CPLAtof(tokens[2])); |
544 | 311k | arc->addPoint(&ogrPoint); |
545 | 311k | } |
546 | 1.73M | else if (EQUAL(firsttok, "ELIN")) |
547 | 52.8k | { |
548 | 52.8k | if (ogrLine->getNumPoints() > 1) |
549 | 18.3k | { // Ignore single LIPT after ARCP |
550 | 18.3k | OGRErr error = ogrCurve->addCurveDirectly(ogrLine); |
551 | 18.3k | if (error != OGRERR_NONE) |
552 | 6.58k | { |
553 | 6.58k | char *pszJSon = ogrLine->exportToJson(); |
554 | 6.58k | CPLError(CE_Warning, CPLE_AppDefined, |
555 | 6.58k | "Could not add geometry: %s", |
556 | 6.58k | pszJSon ? pszJSon : "(null)"); |
557 | 6.58k | CPLFree(pszJSon); |
558 | 6.58k | delete ogrLine; |
559 | 6.58k | } |
560 | 18.3k | ogrLine = nullptr; |
561 | 18.3k | } |
562 | 52.8k | if (!ogrCurve->IsEmpty()) |
563 | 36.2k | { |
564 | 36.2k | if (ogrMultiLine) |
565 | 29.5k | { |
566 | 29.5k | OGRErr error = ogrMultiLine->addGeometryDirectly(ogrCurve); |
567 | 29.5k | if (error != OGRERR_NONE) |
568 | 0 | { |
569 | 0 | char *pszJSon = ogrCurve->exportToJson(); |
570 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
571 | 0 | "Could not add geometry: %s", |
572 | 0 | pszJSon ? pszJSon : "(null)"); |
573 | 0 | CPLFree(pszJSon); |
574 | 0 | delete ogrCurve; |
575 | 0 | } |
576 | 29.5k | ogrCurve = nullptr; |
577 | 29.5k | } |
578 | 36.2k | if (ogrPoly) |
579 | 0 | { |
580 | 0 | OGRErr error = ogrPoly->addRingDirectly(ogrCurve); |
581 | 0 | if (error != OGRERR_NONE) |
582 | 0 | { |
583 | 0 | char *pszJSon = ogrCurve->exportToJson(); |
584 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
585 | 0 | "Could not add geometry: %s", |
586 | 0 | pszJSon ? pszJSon : "(null)"); |
587 | 0 | CPLFree(pszJSon); |
588 | 0 | delete ogrCurve; |
589 | 0 | } |
590 | 0 | ogrCurve = nullptr; |
591 | 0 | } |
592 | 36.2k | } |
593 | 52.8k | end = true; |
594 | 52.8k | } |
595 | 1.67M | else if (EQUAL(firsttok, "EEDG")) |
596 | 1.74k | { |
597 | 1.74k | end = true; |
598 | 1.74k | } |
599 | 1.67M | else if (EQUAL(firsttok, "LATT")) |
600 | 3.06k | { |
601 | | // Line Attributes (ignored) |
602 | 3.06k | } |
603 | 1.67M | else if (EQUAL(firsttok, "EFLA")) |
604 | 553 | { |
605 | 553 | end = true; |
606 | 553 | } |
607 | 1.67M | else if (EQUAL(firsttok, "ETAB")) |
608 | 6.44k | { |
609 | 6.44k | end = true; |
610 | 6.44k | } |
611 | 1.66M | else |
612 | 1.66M | { |
613 | 1.66M | CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s", |
614 | 1.66M | firsttok); |
615 | 1.66M | } |
616 | | |
617 | 2.55M | CSLDestroy(tokens); |
618 | 2.55M | } |
619 | 73.0k | delete arc; |
620 | | |
621 | 73.0k | delete ogrLine; |
622 | | |
623 | | // Set feature geometry |
624 | 73.0k | if (eType == wkbMultiCurve) |
625 | 0 | { |
626 | 0 | feature->SetGeomFieldDirectly(geomIdx, ogrMultiLine); |
627 | 0 | delete ogrCurve; |
628 | 0 | } |
629 | 73.0k | else if (eType == wkbMultiLineString) |
630 | 48.8k | { |
631 | 48.8k | feature->SetGeomFieldDirectly(geomIdx, |
632 | 48.8k | ogrMultiLine->getLinearGeometry()); |
633 | 48.8k | delete ogrMultiLine; |
634 | 48.8k | delete ogrCurve; |
635 | 48.8k | } |
636 | 24.2k | else if (eType == wkbCurvePolygon) |
637 | 0 | { |
638 | 0 | feature->SetGeomFieldDirectly(geomIdx, ogrPoly); |
639 | 0 | delete ogrCurve; |
640 | 0 | } |
641 | 24.2k | else if (eType == wkbPolygon) |
642 | 0 | { |
643 | 0 | feature->SetGeomFieldDirectly(geomIdx, ogrPoly->getLinearGeometry()); |
644 | 0 | delete ogrPoly; |
645 | 0 | delete ogrCurve; |
646 | 0 | } |
647 | 24.2k | else |
648 | 24.2k | { |
649 | 24.2k | feature->SetGeomFieldDirectly(geomIdx, ogrCurve); |
650 | 24.2k | } |
651 | 73.0k | } |
652 | | |
653 | | /************************************************************************/ |
654 | | /* AddLayer() */ |
655 | | /************************************************************************/ |
656 | | |
657 | | void ILI1Reader::AddLayer(OGRILI1Layer *poNewLayer) |
658 | | |
659 | 13.0k | { |
660 | 13.0k | nLayers++; |
661 | | |
662 | 13.0k | papoLayers = static_cast<OGRILI1Layer **>( |
663 | 13.0k | CPLRealloc(papoLayers, sizeof(void *) * nLayers)); |
664 | | |
665 | 13.0k | papoLayers[nLayers - 1] = poNewLayer; |
666 | 13.0k | } |
667 | | |
668 | | /************************************************************************/ |
669 | | /* GetLayer() */ |
670 | | /************************************************************************/ |
671 | | |
672 | | OGRILI1Layer *ILI1Reader::GetLayer(int iLayer) const |
673 | | |
674 | 5.40k | { |
675 | 5.40k | if (iLayer < 0 || iLayer >= nLayers) |
676 | 0 | return nullptr; |
677 | | |
678 | 5.40k | return papoLayers[iLayer]; |
679 | 5.40k | } |
680 | | |
681 | | OGRILI1Layer *ILI1Reader::GetLayerByName(const char *pszLayerName) |
682 | | |
683 | 71.6k | { |
684 | 402k | for (int iLayer = 0; iLayer < nLayers; iLayer++) |
685 | 388k | { |
686 | 388k | if (EQUAL(pszLayerName, papoLayers[iLayer]->GetLayerDefn()->GetName())) |
687 | 57.4k | return papoLayers[iLayer]; |
688 | 388k | } |
689 | 14.1k | return nullptr; |
690 | 71.6k | } |
691 | | |
692 | | /************************************************************************/ |
693 | | /* GetLayerCount() */ |
694 | | /************************************************************************/ |
695 | | |
696 | | int ILI1Reader::GetLayerCount() const |
697 | | |
698 | 13.3k | { |
699 | 13.3k | return nLayers; |
700 | 13.3k | } |
701 | | |
702 | | /************************************************************************/ |
703 | | /* Read one logical line, and return split into fields. The return */ |
704 | | /* result is a stringlist, in the sense of the CSL functions. */ |
705 | | /************************************************************************/ |
706 | | |
707 | | char **ILI1Reader::ReadParseLine() |
708 | 4.35M | { |
709 | 4.35M | CPLAssert(fpItf != nullptr); |
710 | 4.35M | if (fpItf == nullptr) |
711 | 0 | return nullptr; |
712 | | |
713 | 4.35M | const char *pszLine = CPLReadLineL(fpItf); |
714 | 4.35M | if (pszLine == nullptr) |
715 | 14.2k | return nullptr; |
716 | | |
717 | 4.34M | if (strlen(pszLine) == 0) |
718 | 14.2k | return nullptr; |
719 | | |
720 | 4.32M | char **tokens = CSLTokenizeString2(pszLine, " ", CSLT_PRESERVEESCAPES); |
721 | 4.32M | int nCount = CSLCount(tokens); |
722 | 4.32M | if (nCount == 0) |
723 | 10.0k | { |
724 | 10.0k | CSLDestroy(tokens); |
725 | 10.0k | return nullptr; |
726 | 10.0k | } |
727 | 4.31M | const char *token = tokens[nCount - 1]; |
728 | | |
729 | | // Append CONT lines |
730 | 4.32M | while (strlen(pszLine) && token[0] == codeContinue && token[1] == '\0') |
731 | 27.0k | { |
732 | | // remove last token |
733 | 27.0k | CPLFree(tokens[CSLCount(tokens) - 1]); |
734 | 27.0k | tokens[CSLCount(tokens) - 1] = nullptr; |
735 | | |
736 | 27.0k | pszLine = CPLReadLineL(fpItf); |
737 | 27.0k | if (pszLine == nullptr) |
738 | 10 | { |
739 | 10 | break; |
740 | 10 | } |
741 | 27.0k | char **conttok = CSLTokenizeString2(pszLine, " ", CSLT_PRESERVEESCAPES); |
742 | 27.0k | if (!conttok || conttok[0] == nullptr || !EQUAL(conttok[0], "CONT") || |
743 | 5.61k | conttok[1] == nullptr) |
744 | 21.6k | { |
745 | 21.6k | CSLDestroy(conttok); |
746 | 21.6k | break; |
747 | 21.6k | } |
748 | | |
749 | | // append |
750 | 5.36k | tokens = CSLInsertStrings(tokens, -1, &conttok[1]); |
751 | 5.36k | token = tokens[CSLCount(tokens) - 1]; |
752 | | |
753 | 5.36k | CSLDestroy(conttok); |
754 | 5.36k | } |
755 | 4.31M | if (tokens[0] == nullptr) |
756 | 15.7k | { |
757 | 15.7k | CSLDestroy(tokens); |
758 | 15.7k | tokens = nullptr; |
759 | 15.7k | } |
760 | 4.31M | return tokens; |
761 | 4.32M | } |
762 | | |
763 | | IILI1Reader *CreateILI1Reader() |
764 | 9.27k | { |
765 | 9.27k | return new ILI1Reader(); |
766 | 9.27k | } |
767 | | |
768 | | void DestroyILI1Reader(IILI1Reader *reader) |
769 | 21.9k | { |
770 | 21.9k | if (reader) |
771 | 9.27k | delete reader; |
772 | 21.9k | } |