1 : /******************************************************************************
2 : * $Id: ili1reader.cpp 24116 2012-03-13 16:31:27Z pka $
3 : *
4 : * Project: Interlis 1 Reader
5 : * Purpose: Implementation of ILI1Reader class.
6 : * Author: Pirmin Kalberer, Sourcepole AG
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_ili1.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "ogr_api.h"
34 : #include "ogr_geos.h"
35 :
36 : #include "ilihelper.h"
37 : #include "iomhelper.h"
38 : #include "ili1reader.h"
39 : #include "ili1readerp.h"
40 :
41 : #include <vector>
42 :
43 : #ifdef HAVE_GEOS
44 : # define POLYGONIZE_AREAS
45 : #endif
46 :
47 : #ifndef POLYGONIZE_AREAS
48 : # if defined(__GNUC_PREREQ)
49 : # warning Interlis 1 Area polygonizing disabled. Needs GEOS >= 2.1.0
50 : # endif
51 : #endif
52 :
53 : CPL_CVSID("$Id: ili1reader.cpp 24116 2012-03-13 16:31:27Z pka $");
54 :
55 : //
56 : // ILI1Reader
57 : //
58 2 : IILI1Reader::~IILI1Reader() {
59 2 : }
60 :
61 2 : ILI1Reader::ILI1Reader() {
62 2 : fpItf = NULL;
63 2 : nLayers = 0;
64 2 : papoLayers = NULL;
65 2 : curLayer = NULL;
66 2 : metaLayer = NULL;
67 2 : codeBlank = '_';
68 2 : codeUndefined = '@';
69 2 : codeContinue = '\\';
70 2 : SetArcDegrees(1);
71 :
72 2 : }
73 :
74 2 : ILI1Reader::~ILI1Reader() {
75 : int i;
76 2 : if (fpItf) VSIFClose( fpItf );
77 :
78 10 : for(i=0;i<nLayers;i++)
79 8 : delete papoLayers[i];
80 2 : CPLFree(papoLayers);
81 :
82 2 : delete metaLayer;
83 2 : }
84 :
85 2 : void ILI1Reader::SetArcDegrees(double arcDegrees) {
86 2 : arcIncr = arcDegrees*PI/180;
87 2 : }
88 :
89 : /* -------------------------------------------------------------------- */
90 : /* Open the source file. */
91 : /* -------------------------------------------------------------------- */
92 2 : int ILI1Reader::OpenFile( const char *pszFilename ) {
93 2 : fpItf = VSIFOpen( pszFilename, "r" );
94 2 : if( fpItf == NULL )
95 : {
96 : CPLError( CE_Failure, CPLE_OpenFailed,
97 : "Failed to open ILI file `%s'.",
98 0 : pszFilename );
99 :
100 0 : return FALSE;
101 : }
102 2 : return TRUE;
103 : }
104 :
105 16 : int ILI1Reader::HasMultiplePointGeom(const char* layername) {
106 16 : if (metaLayer != NULL) {
107 0 : OGRFeature *metaFeature = NULL;
108 0 : metaLayer->ResetReading();
109 0 : int i = -1;
110 0 : while((metaFeature = metaLayer->GetNextFeature()) != NULL ) {
111 0 : if(EQUAL(layername, metaFeature->GetFieldAsString(0))) {
112 0 : i++;
113 : }
114 0 : delete metaFeature;
115 : }
116 0 : return i;
117 : } else {
118 16 : return -1;
119 : }
120 : }
121 :
122 0 : char* ILI1Reader::GetPointLayerName(const char* layername, char* newlayername) {
123 : static char geomlayername[512];
124 0 : geomlayername[0] = '\0';
125 0 : strcat(geomlayername, layername);
126 0 : strcat(geomlayername, "__");
127 0 : strcat(geomlayername, newlayername);
128 0 : return geomlayername;
129 : }
130 :
131 24 : const char* ILI1Reader::GetLayerNameString(const char* topicname, const char* tablename) {
132 : static char layername[512];
133 24 : layername[0] = '\0';
134 24 : strcat(layername, topicname);
135 24 : strcat(layername, "__");
136 24 : strcat(layername, tablename);
137 24 : return layername;
138 : }
139 :
140 0 : const char* ILI1Reader::GetLayerName(IOM_BASKET model, IOM_OBJECT table) {
141 : static char layername[512];
142 0 : IOM_OBJECT topic = GetAttrObj(model, table, "container");
143 0 : layername[0] = '\0';
144 0 : strcat(layername, iom_getattrvalue(topic, "name"));
145 0 : strcat(layername, "__");
146 0 : strcat(layername, iom_getattrvalue(table, "name"));
147 0 : return layername;
148 : }
149 :
150 0 : void ILI1Reader::AddCoord(OGRILI1Layer* layer, IOM_BASKET model, IOM_OBJECT modelele, IOM_OBJECT typeobj) {
151 0 : unsigned int dim = ::GetCoordDim(model, typeobj);
152 0 : for (unsigned int i=0; i<dim; i++) {
153 0 : OGRFieldDefn fieldDef(CPLSPrintf("%s_%d", iom_getattrvalue(modelele, "name"), i), OFTReal);
154 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
155 : //CPLDebug( "AddCoord OGR_ILI", "Field %s: OFTReal", fieldDef.GetNameRef());
156 : }
157 0 : }
158 :
159 0 : void ILI1Reader::AddEnumTable(OGRILI1Layer* layer, IOM_BASKET model, IOM_OBJECT enumeration) {
160 : //Add enums as features
161 0 : IOM_ITERATOR fieldit=iom_iteratorobject(model);
162 0 : for (IOM_OBJECT fieldele=iom_nextobject(fieldit); fieldele; fieldele=iom_nextobject(fieldit)){
163 0 : const char *etag=iom_getobjecttag(fieldele);
164 0 : if (etag && (EQUAL(etag,"iom04.metamodel.Enumeration_Element"))) {
165 0 : if (GetAttrObj(model, fieldele, "enumeration") == enumeration) {
166 0 : IOM_OBJECT subenum = GetAttrObj(model, fieldele, "subEnumeration");
167 0 : unsigned int order_pos = iom_getobjectreforderpos(iom_getattrobj(fieldele, "enumeration", 0));
168 0 : if (subenum) {
169 0 : AddEnumTable(layer, model, subenum);
170 0 : } else if (order_pos) {
171 0 : OGRFeature *feature = OGRFeature::CreateFeature(layer->GetLayerDefn());
172 0 : feature->SetField("id", (int)order_pos-1);
173 0 : feature->SetField("value", iom_getattrvalue(fieldele, "name"));
174 0 : layer->AddFeature(feature);
175 : }
176 : }
177 : }
178 0 : iom_releaseobject(fieldele);
179 : }
180 0 : iom_releaseiterator(fieldit);
181 0 : }
182 :
183 0 : OGRILI1Layer* ILI1Reader::AddGeomTable(const char* datalayername, const char* geomname, OGRwkbGeometryType eType) {
184 : static char layername[512];
185 0 : layername[0] = '\0';
186 0 : strcat(layername, datalayername);
187 0 : strcat(layername, "_");
188 0 : strcat(layername, geomname);
189 :
190 0 : OGRILI1Layer* geomlayer = new OGRILI1Layer(layername, NULL, 0, eType, NULL);
191 0 : AddLayer(geomlayer);
192 0 : OGRFieldDefn fieldDef("_TID", OFTString);
193 0 : geomlayer->GetLayerDefn()->AddFieldDefn(&fieldDef);
194 0 : if (eType == wkbPolygon)
195 : {
196 0 : OGRFieldDefn fieldDefRef("_RefTID", OFTString);
197 0 : geomlayer->GetLayerDefn()->AddFieldDefn(&fieldDefRef);
198 : }
199 0 : OGRFieldDefn fieldDef2("ILI_Geometry", OFTString); //in write mode only?
200 0 : geomlayer->GetLayerDefn()->AddFieldDefn(&fieldDef2);
201 0 : return geomlayer;
202 : }
203 :
204 0 : void ILI1Reader::AddField(OGRILI1Layer* layer, IOM_BASKET model, IOM_OBJECT obj) {
205 0 : const char* typenam = "Reference";
206 0 : if (EQUAL(iom_getobjecttag(obj),"iom04.metamodel.LocalAttribute")) typenam = GetTypeName(model, obj);
207 : //CPLDebug( "OGR_ILI", "Field %s: %s", iom_getattrvalue(obj, "name"), typenam);
208 0 : if (EQUAL(typenam, "iom04.metamodel.SurfaceType")) {
209 0 : OGRILI1Layer* polyLayer = AddGeomTable(layer->GetLayerDefn()->GetName(), iom_getattrvalue(obj, "name"), wkbPolygon);
210 0 : layer->SetSurfacePolyLayer(polyLayer);
211 : //TODO: add line attributes to geometry
212 0 : } else if (EQUAL(typenam, "iom04.metamodel.AreaType")) {
213 0 : IOM_OBJECT controlPointDomain = GetAttrObj(model, GetTypeObj(model, obj), "controlPointDomain");
214 0 : if (controlPointDomain) {
215 0 : AddCoord(layer, model, obj, GetTypeObj(model, controlPointDomain));
216 0 : layer->GetLayerDefn()->SetGeomType(wkbPoint);
217 : }
218 0 : OGRILI1Layer* areaLineLayer = AddGeomTable(layer->GetLayerDefn()->GetName(), iom_getattrvalue(obj, "name"), wkbMultiLineString);
219 : #ifdef POLYGONIZE_AREAS
220 0 : OGRILI1Layer* areaLayer = new OGRILI1Layer(CPLSPrintf("%s__Areas",layer->GetLayerDefn()->GetName()), NULL, 0, wkbPolygon, NULL);
221 0 : AddLayer(areaLayer);
222 0 : areaLayer->SetAreaLayers(layer, areaLineLayer);
223 : #endif
224 0 : } else if (EQUAL(typenam, "iom04.metamodel.PolylineType") ) {
225 0 : layer->GetLayerDefn()->SetGeomType(wkbMultiLineString);
226 0 : } else if (EQUAL(typenam, "iom04.metamodel.CoordType")) {
227 0 : AddCoord(layer, model, obj, GetTypeObj(model, obj));
228 0 : if (layer->GetLayerDefn()->GetGeomType() == wkbUnknown) layer->GetLayerDefn()->SetGeomType(wkbPoint);
229 0 : } else if (EQUAL(typenam, "iom04.metamodel.NumericType") ) {
230 0 : OGRFieldDefn fieldDef(iom_getattrvalue(obj, "name"), OFTReal);
231 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
232 0 : } else if (EQUAL(typenam, "iom04.metamodel.EnumerationType") ) {
233 0 : OGRFieldDefn fieldDef(iom_getattrvalue(obj, "name"), OFTInteger);
234 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
235 : } else {
236 0 : OGRFieldDefn fieldDef(iom_getattrvalue(obj, "name"), OFTString);
237 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
238 : }
239 0 : }
240 :
241 2 : int ILI1Reader::ReadModel(const char *pszModelFilename) {
242 :
243 : IOM_BASKET model;
244 : IOM_ITERATOR modelelei;
245 : IOM_OBJECT modelele;
246 :
247 2 : iom_init();
248 :
249 : // set error listener to a iom provided one, that just
250 : // dumps all errors to stderr
251 2 : iom_seterrlistener(iom_stderrlistener);
252 :
253 : // compile ili model
254 2 : char *iomarr[1] = {(char *)pszModelFilename};
255 2 : model=iom_compileIli(1, iomarr);
256 2 : if(!model){
257 2 : CPLError( CE_Failure, CPLE_FileIO, "iom_compileIli failed." );
258 2 : iom_end();
259 2 : return FALSE;
260 : }
261 :
262 : // create new layer with meta information (ILI table name and geometry column index)
263 : // while reading the features from the ITF we have to know which column is the geometry column
264 0 : metaLayer = new OGRILI1Layer("Metatable", NULL, 0, wkbUnknown, NULL);
265 0 : OGRFieldDefn fieldDef1("layername", OFTString);
266 0 : metaLayer->GetLayerDefn()->AddFieldDefn(&fieldDef1);
267 0 : OGRFieldDefn fieldDef2("geomIdx", OFTInteger);
268 0 : metaLayer->GetLayerDefn()->AddFieldDefn(&fieldDef2);
269 0 : OGRFieldDefn fieldDef3("geomlayername", OFTString);
270 0 : metaLayer->GetLayerDefn()->AddFieldDefn(&fieldDef3);
271 :
272 :
273 : // read tables
274 0 : int j = 0;
275 0 : modelelei=iom_iteratorobject(model);
276 0 : modelele=iom_nextobject(modelelei);
277 0 : while(modelele){
278 0 : const char *tag=iom_getobjecttag(modelele);
279 :
280 0 : if (tag) {
281 0 : if (EQUAL(tag,"iom04.metamodel.Table")) {
282 :
283 0 : const char* topic = iom_getattrvalue(GetAttrObj(model, modelele, "container"), "name");
284 :
285 0 : if (!EQUAL(topic, "INTERLIS")) {
286 :
287 0 : const char* layername = GetLayerName(model, modelele);
288 0 : OGRSpatialReference *poSRSIn = NULL;
289 0 : int bWriterIn = 0;
290 0 : OGRwkbGeometryType eReqType = wkbUnknown;
291 0 : OGRILI1DataSource *poDSIn = NULL;
292 :
293 0 : CPLDebug( "OGR_ILI", "Reading table model '%s'", layername );
294 :
295 : // read fields
296 : IOM_OBJECT fields[255];
297 : IOM_OBJECT roledefs[255];
298 0 : memset(fields, 0, 255);
299 0 : memset(roledefs, 0, 255);
300 0 : int maxIdx = -1;
301 0 : IOM_ITERATOR fieldit=iom_iteratorobject(model);
302 0 : std::vector<IOM_OBJECT> attributes;
303 :
304 0 : for (IOM_OBJECT fieldele=iom_nextobject(fieldit); fieldele; fieldele=iom_nextobject(fieldit)){
305 0 : const char *etag=iom_getobjecttag(fieldele);
306 :
307 0 : if (etag && (EQUAL(etag,"iom04.metamodel.ViewableAttributesAndRoles"))) {
308 0 : IOM_OBJECT table = GetAttrObj(model, fieldele, "viewable");
309 :
310 0 : if (table == modelele) {
311 :
312 0 : IOM_OBJECT obj = GetAttrObj(model, fieldele, "attributesAndRoles");
313 0 : int ili1AttrIdx = GetAttrObjPos(fieldele, "attributesAndRoles")-1;
314 :
315 0 : if (EQUAL(iom_getobjecttag(obj),"iom04.metamodel.RoleDef")) {
316 0 : int ili1AttrIdxOppend = atoi(iom_getattrvalue(GetAttrObj(model, obj, "oppend"), "ili1AttrIdx"));
317 :
318 0 : if (ili1AttrIdxOppend>=0) {
319 0 : roledefs[ili1AttrIdxOppend] = obj;
320 0 : if (ili1AttrIdxOppend > maxIdx) maxIdx = ili1AttrIdxOppend;
321 : }
322 : } else {
323 0 : fields[ili1AttrIdx] = obj;
324 0 : if (ili1AttrIdx > maxIdx) maxIdx = ili1AttrIdx;
325 : }
326 : }
327 : }
328 0 : iom_releaseobject(fieldele);
329 : }
330 0 : iom_releaseiterator(fieldit);
331 :
332 : // if multiple gets positive we have more than one geometry column (only points)
333 0 : int multiple = -1;
334 :
335 0 : for (int i=0; i<=maxIdx; i++) {
336 0 : IOM_OBJECT obj = fields[i];
337 0 : if (obj) {
338 0 : attributes.push_back(obj);
339 0 : if (EQUAL(GetTypeName(model, obj), "iom04.metamodel.CoordType")) multiple++;
340 : }
341 : }
342 :
343 0 : for (int i=0; i<=maxIdx; i++) {
344 0 : IOM_OBJECT obj = roledefs[i];
345 0 : if (obj) attributes.insert(attributes.begin() + i, obj);
346 : }
347 :
348 0 : OGRFeature *feature = NULL;
349 0 : char* geomlayername = '\0';
350 0 : OGRILI1Layer* layer = NULL;
351 :
352 0 : for(size_t i=0; i<attributes.size(); i++) {
353 0 : IOM_OBJECT obj = attributes.at(i);
354 0 : const char* typenam = GetTypeName(model, obj);
355 0 : if (EQUAL(typenam, "iom04.metamodel.CoordType") || EQUAL(typenam, "iom04.metamodel.AreaType")) {
356 0 : feature = OGRFeature::CreateFeature(metaLayer->GetLayerDefn());
357 0 : feature->SetFID(j+1);
358 0 : feature->SetField("layername", layername);
359 0 : feature->SetField("geomIdx", (int)i);
360 :
361 0 : if(multiple > 0) {
362 0 : geomlayername = GetPointLayerName(layername, iom_getattrvalue(obj, "name"));
363 0 : feature->SetField("geomlayername", geomlayername);
364 0 : layer = new OGRILI1Layer(geomlayername, poSRSIn, bWriterIn, eReqType, poDSIn);
365 0 : AddLayer(layer);
366 :
367 : } else {
368 0 : feature->SetField("geomlayername", layername);
369 0 : layer = new OGRILI1Layer(layername, poSRSIn, bWriterIn, eReqType, poDSIn);
370 0 : AddLayer(layer);
371 : }
372 0 : metaLayer->AddFeature(feature);
373 : }
374 : }
375 :
376 0 : if(layer == NULL) {
377 0 : layer = new OGRILI1Layer(layername, poSRSIn, bWriterIn, eReqType, poDSIn);
378 0 : AddLayer(layer);
379 : }
380 :
381 0 : OGRFieldDefn fieldDef("_TID", OFTString);
382 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
383 :
384 0 : for(size_t i=0; i<attributes.size(); i++) {
385 0 : IOM_OBJECT obj = attributes.at(i);
386 0 : AddField(layer, model, obj);
387 : }
388 :
389 : // additional point layer added
390 0 : if(multiple > 0) {
391 0 : for(int i = 1; i <= multiple; i++) {
392 0 : OGRILI1Layer* pointLayer = papoLayers[nLayers-(i+1)];
393 0 : for (int j=0; j < layer->GetLayerDefn()->GetFieldCount(); j++) {
394 0 : pointLayer->CreateField(layer->GetLayerDefn()->GetFieldDefn(j));
395 : }
396 0 : if (pointLayer->GetLayerDefn()->GetGeomType() == wkbUnknown) pointLayer->GetLayerDefn()->SetGeomType(wkbPoint);
397 : }
398 : }
399 :
400 0 : if (papoLayers[nLayers-1]->GetLayerDefn()->GetFieldCount() == 0) {
401 : //Area layer added
402 0 : OGRILI1Layer* areaLayer = papoLayers[nLayers-1];
403 0 : for (int i=0; i < layer->GetLayerDefn()->GetFieldCount(); i++) {
404 0 : areaLayer->CreateField(layer->GetLayerDefn()->GetFieldDefn(i));
405 : }
406 0 : }
407 : }
408 0 : } else if (EQUAL(tag,"iom04.metamodel.Domain")) {
409 : // Check for enumeration
410 : //Domain -> EnumerationType -> Enumeration
411 : //LocalAttribute -> TypeAlias -> EnumerationType -> Enumeration
412 0 : if (EQUAL(GetTypeName(model, modelele), "iom04.metamodel.EnumerationType")) {
413 : //TODO: Replace LocalAttribute enumeration tables with one table for Domain
414 : }
415 0 : } else if (EQUAL(tag,"iom04.metamodel.LocalAttribute")) {
416 : // Check for enumeration
417 : //LocalAttribute -> EnumerationType -> Enumeration
418 : //Enumeration_Element -> Enumeration
419 : // (-> subEnumeration)
420 0 : if (EQUAL(GetTypeName(model, modelele), "iom04.metamodel.EnumerationType")) {
421 0 : IOM_OBJECT enumeration = GetAttrObj(model, GetTypeObj(model, modelele), "enumeration");
422 0 : OGRSpatialReference *poSRSIn = NULL;
423 0 : int bWriterIn = 0;
424 0 : OGRwkbGeometryType eReqType = wkbUnknown;
425 0 : OGRILI1DataSource *poDSIn = NULL;
426 0 : IOM_OBJECT table = GetAttrObj(model, modelele, "container");
427 0 : char* topicname = CPLStrdup(iom_getattrvalue(GetAttrObj(model, table, "container"), "name"));
428 0 : const char* layername = GetLayerNameString(topicname, GetLayerName(model, modelele));
429 0 : CPLFree(topicname);
430 0 : OGRILI1Layer* layer = new OGRILI1Layer(layername, poSRSIn, bWriterIn, eReqType, poDSIn);
431 0 : AddLayer(layer);
432 : {
433 0 : OGRFieldDefn fieldDef("id", OFTInteger);
434 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
435 : }
436 : {
437 0 : OGRFieldDefn fieldDef("value", OFTString);
438 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
439 : }
440 0 : CPLDebug( "OGR_ILI", "Enumeration layer '%s'", layername );
441 0 : AddEnumTable(layer, model, enumeration);
442 : }
443 0 : } else if (EQUAL(tag,"iom04.metamodel.Ili1Format")) {
444 0 : codeBlank = atoi(iom_getattrvalue(modelele, "blankCode"));
445 0 : CPLDebug( "OGR_ILI", "Reading Ili1Format blankCode '%c'", codeBlank );
446 0 : codeUndefined = atoi(iom_getattrvalue(modelele, "undefinedCode"));
447 0 : CPLDebug( "OGR_ILI", "Reading Ili1Format undefinedCode '%c'", codeUndefined );
448 0 : codeContinue = atoi(iom_getattrvalue(modelele, "continueCode"));
449 0 : CPLDebug( "OGR_ILI", "Reading Ili1Format continueCode '%c'", codeContinue );
450 : }
451 0 : iom_releaseobject(modelele);
452 :
453 0 : modelele=iom_nextobject(modelelei);
454 0 : j++;
455 : }
456 : }
457 :
458 0 : iom_releaseiterator(modelelei);
459 :
460 0 : iom_releasebasket(model);
461 :
462 0 : iom_end();
463 :
464 0 : return 0;
465 : }
466 :
467 2 : int ILI1Reader::ReadFeatures() {
468 2 : char **tokens = NULL;
469 2 : const char *firsttok = NULL;
470 : const char *pszLine;
471 2 : char *topic = NULL;
472 2 : int ret = TRUE;
473 :
474 24 : while (ret && (tokens = ReadParseLine()))
475 : {
476 22 : firsttok = tokens[0];
477 22 : if (EQUAL(firsttok, "SCNT"))
478 : {
479 : //read description
480 4 : do
481 : {
482 4 : pszLine = CPLReadLine( fpItf );
483 : }
484 : while (pszLine && !EQUALN(pszLine, "////", 4));
485 2 : ret = (pszLine != NULL);
486 : }
487 20 : else if (EQUAL(firsttok, "MOTR"))
488 : {
489 : //read model
490 0 : do
491 : {
492 0 : pszLine = CPLReadLine( fpItf );
493 : }
494 : while (pszLine && !EQUALN(pszLine, "////", 4));
495 0 : ret = (pszLine != NULL);
496 : }
497 20 : else if (EQUAL(firsttok, "MTID"))
498 : {
499 : }
500 18 : else if (EQUAL(firsttok, "MODL"))
501 : {
502 : }
503 16 : else if (EQUAL(firsttok, "TOPI"))
504 : {
505 2 : CPLFree(topic);
506 2 : topic = CPLStrdup(CSLGetField(tokens, 1));
507 : }
508 14 : else if (EQUAL(firsttok, "TABL"))
509 : {
510 8 : CPLDebug( "OGR_ILI", "Reading table '%s'", GetLayerNameString(topic, CSLGetField(tokens, 1)) );
511 8 : const char *layername = GetLayerNameString(topic, CSLGetField(tokens, 1));
512 8 : curLayer = GetLayerByName(layername);
513 :
514 8 : int multiple = HasMultiplePointGeom(layername);
515 :
516 : // create only a new layer if there is no curLayer AND
517 : // if there are more than one point geometry columns
518 8 : if (curLayer == NULL && multiple < 1) { //create one
519 8 : CPLDebug( "OGR_ILI", "No model found, using default field names." );
520 8 : OGRSpatialReference *poSRSIn = NULL;
521 8 : int bWriterIn = 0;
522 8 : OGRwkbGeometryType eReqType = wkbUnknown;
523 8 : OGRILI1DataSource *poDSIn = NULL;
524 8 : curLayer = new OGRILI1Layer(GetLayerNameString(topic, CSLGetField(tokens, 1)), poSRSIn, bWriterIn, eReqType, poDSIn);
525 8 : AddLayer(curLayer);
526 : }
527 8 : if(curLayer != NULL) {
528 8 : for (int i=0; i < curLayer->GetLayerDefn()->GetFieldCount(); i++) {
529 0 : CPLDebug( "OGR_ILI", "Field %d: %s", i, curLayer->GetLayerDefn()->GetFieldDefn(i)->GetNameRef());
530 : }
531 : }
532 8 : ret = ReadTable(layername);
533 : }
534 6 : else if (EQUAL(firsttok, "ETOP"))
535 : {
536 : }
537 4 : else if (EQUAL(firsttok, "EMOD"))
538 : {
539 : }
540 2 : else if (EQUAL(firsttok, "ENDE"))
541 : {
542 2 : CSLDestroy(tokens);
543 2 : CPLFree(topic);
544 2 : return TRUE;
545 : }
546 : else
547 : {
548 0 : CPLDebug( "OGR_ILI", "Unexpected token: %s", firsttok );
549 : }
550 :
551 20 : CSLDestroy(tokens);
552 20 : tokens = NULL;
553 : }
554 :
555 0 : CSLDestroy(tokens);
556 0 : CPLFree(topic);
557 :
558 0 : return ret;
559 : }
560 :
561 0 : int ILI1Reader::AddIliGeom(OGRFeature *feature, int iField, long fpos)
562 : {
563 : #if defined(_WIN32) || defined(__WIN32__)
564 : //Other positions on Windows !?
565 : #else
566 0 : long nBlockLen = VSIFTell( fpItf )-fpos;
567 0 : VSIFSeek( fpItf, fpos, SEEK_SET );
568 :
569 0 : char *pszRawData = (char *) CPLMalloc(nBlockLen+1);
570 0 : if( (int) VSIFRead( pszRawData, 1, nBlockLen, fpItf ) != nBlockLen )
571 : {
572 0 : CPLFree( pszRawData );
573 :
574 0 : CPLError( CE_Failure, CPLE_FileIO, "Read of transfer file failed." );
575 0 : return FALSE;
576 : }
577 0 : pszRawData[nBlockLen]= '\0';
578 0 : feature->SetField(iField, pszRawData);
579 0 : CPLFree( pszRawData );
580 : #endif
581 0 : return TRUE;
582 : }
583 :
584 :
585 8 : int ILI1Reader::ReadTable(const char *layername) {
586 8 : char **tokens = NULL;
587 8 : const char *firsttok = NULL;
588 8 : int ret = TRUE;
589 8 : int warned = FALSE;
590 : int fIndex;
591 8 : int geomIdx = 0;
592 :
593 : // curLayer is NULL if we have more than one
594 : // point geometry column
595 8 : if(curLayer == NULL) {
596 0 : OGRFeature *metaFeature = NULL;
597 0 : metaLayer->ResetReading();
598 0 : while((metaFeature = metaLayer->GetNextFeature()) != NULL ) {
599 0 : if(EQUAL(layername, metaFeature->GetFieldAsString(0))) {
600 0 : const char *geomlayername = metaFeature->GetFieldAsString(2);
601 0 : curLayer = GetLayerByName(geomlayername);
602 0 : delete metaFeature;
603 0 : break;
604 : }
605 0 : delete metaFeature;
606 : }
607 : }
608 :
609 8 : OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
610 8 : OGRFeature *feature = NULL;
611 :
612 : // get the geometry index of the current layer
613 : // only if the model is read
614 8 : if(featureDef->GetFieldCount() != 0) {
615 0 : OGRFeature *metaFeature = NULL;
616 0 : metaLayer->ResetReading();
617 0 : while((metaFeature = metaLayer->GetNextFeature()) != NULL ) {
618 0 : if(EQUAL(curLayer->GetLayerDefn()->GetName(), metaFeature->GetFieldAsString(2))) {
619 0 : geomIdx = metaFeature->GetFieldAsInteger(1);
620 : }
621 0 : delete metaFeature;
622 : }
623 : }
624 :
625 8 : long fpos = VSIFTell(fpItf);
626 44 : while (ret && (tokens = ReadParseLine()))
627 : {
628 36 : firsttok = CSLGetField(tokens, 0);
629 36 : if (EQUAL(firsttok, "OBJE"))
630 : {
631 : //Check for features spread over multiple objects
632 18 : if (featureDef->GetGeomType() == wkbPolygon)
633 : {
634 : //Multiple polygon rings
635 0 : feature = curLayer->GetFeatureRef(atol(CSLGetField(tokens, 2)));
636 : }
637 18 : else if (featureDef->GetGeomType() == wkbGeometryCollection)
638 : {
639 : //AREA lines spread over mutltiple objects
640 : }
641 : else
642 : {
643 18 : feature = NULL;
644 : }
645 :
646 18 : if (feature == NULL)
647 : {
648 18 : if (featureDef->GetFieldCount() == 0)
649 : {
650 8 : CPLDebug( "OGR_ILI", "No field definition found for table: %s", featureDef->GetName() );
651 : //Model not read - use heuristics
652 30 : for (fIndex=1; fIndex<CSLCount(tokens); fIndex++)
653 : {
654 : char szFieldName[32];
655 22 : sprintf(szFieldName, "Field%02d", fIndex);
656 22 : OGRFieldDefn oFieldDefn(szFieldName, OFTString);
657 22 : featureDef->AddFieldDefn(&oFieldDefn);
658 : }
659 : }
660 : //start new feature
661 18 : feature = new OGRFeature(featureDef);
662 :
663 18 : int fieldno = 0;
664 62 : for (fIndex=1; fIndex<CSLCount(tokens) && fieldno < featureDef->GetFieldCount(); fIndex++, fieldno++)
665 : {
666 44 : if (!(tokens[fIndex][0] == codeUndefined && tokens[fIndex][1] == '\0')) {
667 : //CPLDebug( "READ TABLE OGR_ILI", "Setting Field %d (Type %d): %s", fieldno, featureDef->GetFieldDefn(fieldno)->GetType(), tokens[fIndex]);
668 44 : if (featureDef->GetFieldDefn(fieldno)->GetType() == OFTString) {
669 : //Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
670 44 : char* pszRecoded = CPLRecode(tokens[fIndex], CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
671 : //Replace space marks
672 186 : for(char* pszString = pszRecoded; *pszString != '\0'; pszString++ ) {
673 142 : if (*pszString == codeBlank) *pszString = ' ';
674 : }
675 44 : feature->SetField(fieldno, pszRecoded);
676 44 : CPLFree(pszRecoded);
677 : } else {
678 0 : feature->SetField(fieldno, tokens[fIndex]);
679 : }
680 44 : if (featureDef->GetFieldDefn(fieldno)->GetType() == OFTReal
681 : && fieldno > 0
682 : && featureDef->GetFieldDefn(fieldno-1)->GetType() == OFTReal
683 : && featureDef->GetGeomType() == wkbPoint
684 :
685 : /*
686 : // if there is no ili model read,
687 : // we have no chance to detect the
688 : // geometry column!!
689 : */
690 :
691 : && (fieldno-2) == geomIdx) {
692 : //add Point geometry
693 0 : OGRPoint *ogrPoint = new OGRPoint(atof(tokens[fIndex-1]), atof(tokens[fIndex]));
694 0 : feature->SetGeometryDirectly(ogrPoint);
695 : }
696 : }
697 : }
698 18 : if (!warned && featureDef->GetFieldCount() != CSLCount(tokens)-1 && !(featureDef->GetFieldCount() == CSLCount(tokens) && EQUAL(featureDef->GetFieldDefn(featureDef->GetFieldCount()-1)->GetNameRef(), "ILI_Geometry"))) {
699 0 : CPLDebug( "OGR_ILI", "Field count doesn't match. %d declared, %d found", featureDef->GetFieldCount(), CSLCount(tokens)-1);
700 0 : warned = TRUE;
701 : }
702 18 : if (featureDef->GetGeomType() == wkbPolygon)
703 0 : feature->SetFID(atol(feature->GetFieldAsString(1)));
704 18 : else if (feature->GetFieldCount() > 0)
705 18 : feature->SetFID(atol(feature->GetFieldAsString(0)));
706 18 : curLayer->AddFeature(feature);
707 : }
708 : }
709 18 : else if (EQUAL(firsttok, "STPT"))
710 : {
711 10 : ReadGeom(tokens, featureDef->GetGeomType(), feature);
712 10 : if (EQUAL(featureDef->GetFieldDefn(featureDef->GetFieldCount()-1)->GetNameRef(), "ILI_Geometry"))
713 : {
714 0 : AddIliGeom(feature, featureDef->GetFieldCount()-1, fpos); //TODO: append multi-OBJECT geometries
715 : }
716 : }
717 8 : else if (EQUAL(firsttok, "ELIN"))
718 : {
719 : //empty geom
720 : }
721 8 : else if (EQUAL(firsttok, "EDGE"))
722 : {
723 0 : tokens = ReadParseLine(); //STPT
724 0 : ReadGeom(tokens, wkbMultiLineString, feature);
725 0 : if (EQUAL(featureDef->GetFieldDefn(featureDef->GetFieldCount()-1)->GetNameRef(), "ILI_Geometry"))
726 : {
727 0 : AddIliGeom(feature, featureDef->GetFieldCount()-1, fpos);
728 : }
729 : }
730 8 : else if (EQUAL(firsttok, "PERI"))
731 : {
732 : }
733 8 : else if (EQUAL(firsttok, "ETAB"))
734 : {
735 8 : if(HasMultiplePointGeom(layername) > 0) {
736 0 : OGRFeature *metaFeature = NULL;
737 0 : metaLayer->ResetReading();
738 0 : while((metaFeature = metaLayer->GetNextFeature()) != NULL ) {
739 0 : int pntCln = 1;
740 0 : if(EQUAL(layername, metaFeature->GetFieldAsString(0)) && !EQUAL(curLayer->GetLayerDefn()->GetName(), metaFeature->GetFieldAsString(2))) {
741 0 : pntCln++;
742 0 : OGRILI1Layer *curLayerTmp = GetLayerByName(metaFeature->GetFieldAsString(2));
743 0 : OGRFeature *tmpFeature = NULL;
744 0 : int geomIdxTmp = metaFeature->GetFieldAsInteger(1);
745 0 : curLayer->ResetReading();
746 0 : while((tmpFeature = curLayer->GetNextFeature()) != NULL ) {
747 0 : OGRPoint *ogrPoint = new OGRPoint(atof(tmpFeature->GetFieldAsString(geomIdxTmp + pntCln)), atof(tmpFeature->GetFieldAsString(geomIdxTmp + pntCln + 1)));
748 0 : tmpFeature->SetGeometryDirectly(ogrPoint);
749 0 : curLayerTmp->AddFeature(tmpFeature);
750 : }
751 : }
752 0 : delete metaFeature;
753 : }
754 : }
755 8 : CSLDestroy(tokens);
756 8 : return TRUE;
757 : }
758 : else
759 : {
760 0 : CPLDebug( "OGR_ILI", "Unexpected token: %s", firsttok );
761 : }
762 :
763 28 : CSLDestroy(tokens);
764 28 : fpos = VSIFTell(fpItf);
765 : }
766 :
767 0 : return ret;
768 : }
769 :
770 10 : void ILI1Reader::ReadGeom(char **stgeom, OGRwkbGeometryType eType, OGRFeature *feature) {
771 :
772 10 : char **tokens = NULL;
773 10 : const char *firsttok = NULL;
774 10 : int end = FALSE;
775 10 : int isArc = FALSE;
776 10 : OGRLineString *ogrLine = NULL; //current line
777 10 : OGRLinearRing *ogrRing = NULL; //current ring
778 10 : OGRPolygon *ogrPoly = NULL; //current polygon
779 10 : OGRPoint ogrPoint, arcPoint, endPoint; //points for arc interpolation
780 10 : OGRMultiLineString *ogrMultiLine = NULL; //current multi line
781 :
782 : //tokens = ["STPT", "1111", "22222"]
783 10 : ogrPoint.setX(atof(stgeom[1])); ogrPoint.setY(atof(stgeom[2]));
784 10 : ogrLine = (eType == wkbPolygon) ? new OGRLinearRing() : new OGRLineString();
785 10 : ogrLine->addPoint(&ogrPoint);
786 :
787 : //Set feature geometry
788 10 : if (eType == wkbMultiLineString)
789 : {
790 0 : ogrMultiLine = new OGRMultiLineString();
791 0 : feature->SetGeometryDirectly(ogrMultiLine);
792 : }
793 10 : else if (eType == wkbGeometryCollection) //AREA
794 : {
795 0 : if (feature->GetGeometryRef())
796 0 : ogrMultiLine = (OGRMultiLineString *)feature->GetGeometryRef();
797 : else
798 : {
799 0 : ogrMultiLine = new OGRMultiLineString();
800 0 : feature->SetGeometryDirectly(ogrMultiLine);
801 : }
802 : }
803 10 : else if (eType == wkbPolygon)
804 : {
805 0 : if (feature->GetGeometryRef())
806 : {
807 0 : ogrPoly = (OGRPolygon *)feature->GetGeometryRef();
808 0 : if (ogrPoly->getNumInteriorRings() > 0)
809 0 : ogrRing = ogrPoly->getInteriorRing(ogrPoly->getNumInteriorRings()-1);
810 : else
811 0 : ogrRing = ogrPoly->getExteriorRing();
812 0 : if (ogrRing && !ogrRing->get_IsClosed()) ogrLine = ogrRing; //SURFACE polygon spread over multiple OBJECTs
813 : }
814 : else
815 : {
816 0 : ogrPoly = new OGRPolygon();
817 0 : feature->SetGeometryDirectly(ogrPoly);
818 : }
819 : }
820 : else
821 : {
822 10 : feature->SetGeometryDirectly(ogrLine);
823 : }
824 :
825 : //Parse geometry
826 72 : while (!end && (tokens = ReadParseLine()))
827 : {
828 52 : firsttok = CSLGetField(tokens, 0);
829 52 : if (EQUAL(firsttok, "LIPT"))
830 : {
831 36 : if (isArc) {
832 6 : endPoint.setX(atof(tokens[1])); endPoint.setY(atof(tokens[2]));
833 6 : interpolateArc(ogrLine, &ogrPoint, &arcPoint, &endPoint, arcIncr);
834 : }
835 36 : ogrPoint.setX(atof(tokens[1])); ogrPoint.setY(atof(tokens[2])); isArc = FALSE;
836 36 : ogrLine->addPoint(&ogrPoint);
837 : }
838 16 : else if (EQUAL(firsttok, "ARCP"))
839 : {
840 6 : isArc = TRUE;
841 6 : arcPoint.setX(atof(tokens[1])); arcPoint.setY(atof(tokens[2]));
842 : }
843 10 : else if (EQUAL(firsttok, "ELIN"))
844 : {
845 10 : if (ogrMultiLine)
846 : {
847 0 : ogrMultiLine->addGeometryDirectly(ogrLine);
848 : }
849 10 : if (ogrPoly && ogrLine != ogrRing)
850 : {
851 0 : ogrPoly->addRingDirectly((OGRLinearRing *)ogrLine);
852 : }
853 10 : end = TRUE;
854 : }
855 0 : else if (EQUAL(firsttok, "EEDG"))
856 : {
857 0 : end = TRUE;
858 : }
859 0 : else if (EQUAL(firsttok, "LATT"))
860 : {
861 : //Line Attributes (ignored)
862 : }
863 0 : else if (EQUAL(firsttok, "EFLA"))
864 : {
865 0 : end = TRUE;
866 : }
867 0 : else if (EQUAL(firsttok, "ETAB"))
868 : {
869 0 : end = TRUE;
870 : }
871 : else
872 : {
873 0 : CPLDebug( "OGR_ILI", "Unexpected token: %s", firsttok );
874 : }
875 :
876 52 : CSLDestroy(tokens);
877 10 : }
878 10 : }
879 :
880 : /************************************************************************/
881 : /* AddLayer() */
882 : /************************************************************************/
883 :
884 8 : void ILI1Reader::AddLayer( OGRILI1Layer * poNewLayer )
885 :
886 : {
887 8 : nLayers++;
888 :
889 : papoLayers = (OGRILI1Layer **)
890 8 : CPLRealloc( papoLayers, sizeof(void*) * nLayers );
891 :
892 8 : papoLayers[nLayers-1] = poNewLayer;
893 8 : }
894 :
895 : /************************************************************************/
896 : /* AddAreaLayer() */
897 : /************************************************************************/
898 :
899 : /************************************************************************/
900 : /* GetLayer() */
901 : /************************************************************************/
902 :
903 0 : OGRILI1Layer *ILI1Reader::GetLayer( int iLayer )
904 :
905 : {
906 0 : if( iLayer < 0 || iLayer >= nLayers )
907 0 : return NULL;
908 : else
909 0 : return papoLayers[iLayer];
910 : }
911 :
912 8 : OGRILI1Layer *ILI1Reader::GetLayerByName( const char* pszLayerName )
913 :
914 : {
915 20 : for(int iLayer = 0; iLayer < nLayers; iLayer++ )
916 : {
917 12 : if( EQUAL(pszLayerName,
918 : papoLayers[iLayer]->GetLayerDefn()->GetName()) )
919 0 : return papoLayers[iLayer];
920 : }
921 8 : return NULL;
922 : }
923 :
924 : /************************************************************************/
925 : /* GetLayerCount() */
926 : /************************************************************************/
927 :
928 2 : int ILI1Reader::GetLayerCount()
929 :
930 : {
931 2 : return nLayers;
932 : }
933 :
934 : /************************************************************************/
935 : /* Read one logical line, and return split into fields. The return */
936 : /* result is a stringlist, in the sense of the CSL functions. */
937 : /************************************************************************/
938 :
939 110 : char ** ILI1Reader::ReadParseLine()
940 : {
941 : const char *pszLine;
942 : char **tokens;
943 : char **conttok;
944 : char *token;
945 :
946 110 : CPLAssert( fpItf != NULL );
947 110 : if( fpItf == NULL )
948 0 : return( NULL );
949 :
950 110 : pszLine = CPLReadLine( fpItf );
951 110 : if( pszLine == NULL )
952 0 : return( NULL );
953 :
954 110 : if (strlen(pszLine) == 0) return NULL;
955 :
956 110 : tokens = CSLTokenizeString2( pszLine, " ", CSLT_PRESERVEESCAPES );
957 110 : token = tokens[CSLCount(tokens)-1];
958 :
959 : //Append CONT lines
960 220 : while (strlen(pszLine) && token[0] == codeContinue && token[1] == '\0')
961 : {
962 : //remove last token
963 0 : CPLFree(tokens[CSLCount(tokens)-1]);
964 0 : tokens[CSLCount(tokens)-1] = NULL;
965 :
966 0 : pszLine = CPLReadLine( fpItf );
967 0 : conttok = CSLTokenizeString2( pszLine, " ", CSLT_PRESERVEESCAPES );
968 0 : if (!conttok || !EQUAL(conttok[0], "CONT"))
969 : {
970 0 : CSLDestroy(conttok);
971 0 : break;
972 : }
973 :
974 : //append
975 0 : tokens = CSLInsertStrings(tokens, -1, &conttok[1]);
976 0 : token = tokens[CSLCount(tokens)-1];
977 :
978 0 : CSLDestroy(conttok);
979 : }
980 110 : return tokens;
981 : }
982 :
983 :
984 :
985 2 : IILI1Reader *CreateILI1Reader() {
986 2 : return new ILI1Reader();
987 : }
988 :
989 438 : void DestroyILI1Reader(IILI1Reader* reader)
990 : {
991 438 : if (reader)
992 2 : delete reader;
993 438 : }
|