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