1 : /******************************************************************************
2 : * $Id: ogrbnalayer.cpp
3 : *
4 : * Project: BNA Translator
5 : * Purpose: Implements OGRBNALayer class.
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Even Rouault
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_bna.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "cpl_csv.h"
34 :
35 : #ifndef M_PI
36 : # define M_PI 3.1415926535897932384626433832795
37 : #endif
38 :
39 : /************************************************************************/
40 : /* OGRBNALayer() */
41 : /* */
42 : /* Note that the OGRBNALayer assumes ownership of the passed */
43 : /* file pointer. */
44 : /************************************************************************/
45 :
46 41 : OGRBNALayer::OGRBNALayer( const char *pszFilename,
47 : const char* layerName,
48 : BNAFeatureType bnaFeatureType,
49 : OGRwkbGeometryType eLayerGeomType,
50 : int bWriter,
51 : OGRBNADataSource* poDS,
52 41 : int nIDs)
53 :
54 : {
55 41 : eof = FALSE;
56 41 : failed = FALSE;
57 41 : curLine = 0;
58 41 : nNextFID = 0;
59 :
60 41 : this->bWriter = bWriter;
61 41 : this->poDS = poDS;
62 41 : this->nIDs = nIDs;
63 :
64 41 : nFeatures = 0;
65 41 : partialIndexTable = TRUE;
66 41 : offsetAndLineFeaturesTable = NULL;
67 :
68 41 : const char* iKnowHowToCount[] = { "Primary", "Secondary", "Third", "Fourth", "Fifth" };
69 : char tmp[32];
70 :
71 : poFeatureDefn = new OGRFeatureDefn( CPLSPrintf("%s_%s",
72 : CPLGetBasename( pszFilename ) ,
73 41 : layerName ));
74 41 : poFeatureDefn->Reference();
75 41 : poFeatureDefn->SetGeomType( eLayerGeomType );
76 41 : this->bnaFeatureType = bnaFeatureType;
77 :
78 41 : if (! bWriter )
79 : {
80 : int i;
81 88 : for(i=0;i<nIDs;i++)
82 : {
83 59 : if (i < (int) (sizeof(iKnowHowToCount)/sizeof(iKnowHowToCount[0])) )
84 : {
85 59 : sprintf(tmp, "%s ID", iKnowHowToCount[i]);
86 59 : OGRFieldDefn oFieldID(tmp, OFTString );
87 59 : poFeatureDefn->AddFieldDefn( &oFieldID );
88 : }
89 : else
90 : {
91 0 : sprintf(tmp, "%dth ID", i+1);
92 0 : OGRFieldDefn oFieldID(tmp, OFTString );
93 0 : poFeatureDefn->AddFieldDefn( &oFieldID );
94 : }
95 : }
96 :
97 29 : if (bnaFeatureType == BNA_ELLIPSE)
98 : {
99 7 : OGRFieldDefn oFieldMajorRadius( "Major radius", OFTReal );
100 7 : poFeatureDefn->AddFieldDefn( &oFieldMajorRadius );
101 :
102 7 : OGRFieldDefn oFieldMinorRadius( "Minor radius", OFTReal );
103 7 : poFeatureDefn->AddFieldDefn( &oFieldMinorRadius );
104 : }
105 :
106 29 : fpBNA = VSIFOpen( pszFilename, "rb" );
107 29 : if( fpBNA == NULL )
108 0 : return;
109 : }
110 : else
111 : {
112 12 : fpBNA = NULL;
113 : }
114 0 : }
115 :
116 : /************************************************************************/
117 : /* ~OGRBNALayer() */
118 : /************************************************************************/
119 :
120 82 : OGRBNALayer::~OGRBNALayer()
121 :
122 : {
123 41 : poFeatureDefn->Release();
124 :
125 41 : CPLFree(offsetAndLineFeaturesTable);
126 :
127 41 : if (fpBNA)
128 29 : VSIFClose( fpBNA );
129 82 : }
130 :
131 : /************************************************************************/
132 : /* SetFeatureIndexTable() */
133 : /************************************************************************/
134 29 : void OGRBNALayer::SetFeatureIndexTable(int nFeatures, OffsetAndLine* offsetAndLineFeaturesTable, int partialIndexTable)
135 : {
136 29 : this->nFeatures = nFeatures;
137 29 : this->offsetAndLineFeaturesTable = offsetAndLineFeaturesTable;
138 29 : this->partialIndexTable = partialIndexTable;
139 29 : }
140 :
141 : /************************************************************************/
142 : /* ResetReading() */
143 : /************************************************************************/
144 :
145 65 : void OGRBNALayer::ResetReading()
146 :
147 : {
148 65 : eof = FALSE;
149 65 : failed = FALSE;
150 65 : curLine = 0;
151 65 : nNextFID = 0;
152 65 : VSIFSeek( fpBNA, 0, SEEK_SET );
153 65 : }
154 :
155 :
156 : /************************************************************************/
157 : /* GetNextFeature() */
158 : /************************************************************************/
159 :
160 202 : OGRFeature *OGRBNALayer::GetNextFeature()
161 : {
162 : OGRFeature *poFeature;
163 : BNARecord* record;
164 : int offset, line;
165 :
166 202 : if (failed || eof) return NULL;
167 :
168 172 : while(1)
169 : {
170 374 : int ok = FALSE;
171 374 : offset = VSIFTell(fpBNA);
172 374 : line = curLine;
173 374 : if (nNextFID < nFeatures)
174 : {
175 137 : VSIFSeek( fpBNA, offsetAndLineFeaturesTable[nNextFID].offset, SEEK_SET );
176 137 : curLine = offsetAndLineFeaturesTable[nNextFID].line;
177 : }
178 374 : record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType);
179 374 : if (ok == FALSE)
180 : {
181 0 : BNA_FreeRecord(record);
182 0 : failed = TRUE;
183 0 : return NULL;
184 : }
185 374 : if (record == NULL)
186 : {
187 : /* end of file */
188 65 : eof = TRUE;
189 :
190 : /* and we have finally build the whole index table */
191 65 : partialIndexTable = FALSE;
192 65 : return NULL;
193 : }
194 :
195 309 : if (record->featureType == bnaFeatureType)
196 : {
197 137 : if (nNextFID >= nFeatures)
198 : {
199 0 : nFeatures++;
200 : offsetAndLineFeaturesTable =
201 0 : (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine));
202 0 : offsetAndLineFeaturesTable[nFeatures-1].offset = offset;
203 0 : offsetAndLineFeaturesTable[nFeatures-1].line = line;
204 : }
205 :
206 137 : poFeature = BuildFeatureFromBNARecord(record, nNextFID++);
207 :
208 137 : BNA_FreeRecord(record);
209 :
210 137 : if( (m_poFilterGeom == NULL
211 : || FilterGeometry( poFeature->GetGeometryRef() ) )
212 : && (m_poAttrQuery == NULL
213 : || m_poAttrQuery->Evaluate( poFeature )) )
214 : {
215 137 : return poFeature;
216 : }
217 :
218 0 : delete poFeature;
219 : }
220 : else
221 : {
222 172 : BNA_FreeRecord(record);
223 : }
224 : }
225 : }
226 :
227 :
228 24 : void OGRBNALayer::WriteFeatureAttributes(FILE* fp, OGRFeature *poFeature )
229 : {
230 : int i;
231 : OGRFieldDefn *poField;
232 24 : int nbOutID = poDS->GetNbOutId();
233 24 : if (nbOutID < 0)
234 0 : nbOutID = poFeatureDefn->GetFieldCount();
235 72 : for(i=0;i<nbOutID;i++)
236 : {
237 48 : if (i < poFeatureDefn->GetFieldCount())
238 : {
239 48 : poField = poFeatureDefn->GetFieldDefn( i );
240 48 : if( poFeature->IsFieldSet( i ) )
241 : {
242 48 : const char *pszRaw = poFeature->GetFieldAsString( i );
243 48 : VSIFPrintf( fp, "\"%s\",", pszRaw);
244 : }
245 : else
246 : {
247 0 : VSIFPrintf( fp, "\"\",");
248 : }
249 : }
250 : else
251 : {
252 0 : VSIFPrintf( fp, "\"\",");
253 : }
254 : }
255 24 : }
256 :
257 : /************************************************************************/
258 : /* CreateFeature() */
259 : /************************************************************************/
260 :
261 24 : OGRErr OGRBNALayer::CreateFeature( OGRFeature *poFeature )
262 :
263 : {
264 : int i,j,k,n;
265 24 : OGRGeometry *poGeom = poFeature->GetGeometryRef();
266 : char eol[3];
267 24 : const char* partialEol = (poDS->GetMultiLine()) ? eol : poDS->GetCoordinateSeparator();
268 :
269 24 : if (poGeom == NULL || poGeom->IsEmpty() )
270 : {
271 : CPLError(CE_Failure, CPLE_AppDefined,
272 0 : "OGR BNA driver cannot write features with empty geometries.");
273 0 : return OGRERR_FAILURE;
274 : }
275 :
276 24 : if (poDS->GetUseCRLF())
277 : {
278 8 : eol[0] = 13;
279 8 : eol[1] = 10;
280 8 : eol[2] = 0;
281 : }
282 : else
283 : {
284 16 : eol[0] = 10;
285 16 : eol[1] = 0;
286 : }
287 :
288 24 : if ( ! bWriter )
289 : {
290 0 : return OGRERR_FAILURE;
291 : }
292 :
293 24 : if( poFeature->GetFID() == OGRNullFID )
294 24 : poFeature->SetFID( nFeatures++ );
295 :
296 24 : FILE* fp = poDS->GetOutputFP();
297 24 : int nbPairPerLine = poDS->GetNbPairPerLine();
298 : char formatCoordinates[32];
299 : sprintf(formatCoordinates, "%%s%%.%df%s%%.%df",
300 24 : poDS->GetCoordinatePrecision(), poDS->GetCoordinateSeparator(), poDS->GetCoordinatePrecision());
301 :
302 24 : switch( poGeom->getGeometryType() )
303 : {
304 : case wkbPoint:
305 : case wkbPoint25D:
306 : {
307 6 : OGRPoint* point = (OGRPoint*)poGeom;
308 6 : WriteFeatureAttributes(fp, poFeature);
309 6 : VSIFPrintf( fp, "1");
310 6 : VSIFPrintf( fp, formatCoordinates, partialEol, point->getX(), point->getY());
311 6 : VSIFPrintf( fp, "%s", eol);
312 6 : break;
313 : }
314 :
315 : case wkbPolygon:
316 : case wkbPolygon25D:
317 : {
318 6 : OGRPolygon* polygon = (OGRPolygon*)poGeom;
319 6 : OGRLinearRing* ring = polygon->getExteriorRing();
320 6 : if (ring == NULL)
321 : {
322 0 : return OGRERR_FAILURE;
323 : }
324 :
325 6 : double firstX = ring->getX(0);
326 6 : double firstY = ring->getY(0);
327 6 : int nBNAPoints = ring->getNumPoints();
328 6 : int is_ellipse = FALSE;
329 :
330 : /* This code tries to detect an ellipse in a polygon geometry */
331 : /* This will only work presumably on ellipses already read from a BNA file */
332 : /* Mostly a BNA to BNA feature... */
333 6 : if (poDS->GetEllipsesAsEllipses() &&
334 : polygon->getNumInteriorRings() == 0 &&
335 : nBNAPoints == 361)
336 : {
337 3 : double oppositeX = ring->getX(180);
338 3 : double oppositeY = ring->getY(180);
339 3 : double quarterX = ring->getX(90);
340 3 : double quarterY = ring->getY(90);
341 3 : double antiquarterX = ring->getX(270);
342 3 : double antiquarterY = ring->getY(270);
343 3 : double center1X = 0.5*(firstX + oppositeX);
344 3 : double center1Y = 0.5*(firstY + oppositeY);
345 3 : double center2X = 0.5*(quarterX + antiquarterX);
346 3 : double center2Y = 0.5*(quarterY + antiquarterY);
347 3 : if (fabs(center1X - center2X) < 1e-5 && fabs(center1Y - center2Y) < 1e-5 &&
348 : fabs(oppositeY - firstY) < 1e-5 &&
349 : fabs(quarterX - antiquarterX) < 1e-5)
350 : {
351 3 : double major_radius = fabs(firstX - center1X);
352 3 : double minor_radius = fabs(quarterY - center1Y);
353 3 : is_ellipse = TRUE;
354 1083 : for(i=0;i<360;i++)
355 : {
356 1080 : if (!(fabs(center1X + major_radius * cos(i * (M_PI / 180)) - ring->getX(i)) < 1e-5 &&
357 : fabs(center1Y + minor_radius * sin(i * (M_PI / 180)) - ring->getY(i)) < 1e-5))
358 : {
359 0 : is_ellipse = FALSE;
360 0 : break;
361 : }
362 : }
363 3 : if ( is_ellipse == TRUE )
364 : {
365 3 : WriteFeatureAttributes(fp, poFeature);
366 3 : VSIFPrintf( fp, "2");
367 3 : VSIFPrintf( fp, formatCoordinates, partialEol, center1X, center1Y);
368 3 : VSIFPrintf( fp, formatCoordinates, partialEol, major_radius, minor_radius);
369 3 : VSIFPrintf( fp, "%s", eol);
370 : }
371 : }
372 : }
373 :
374 6 : if ( is_ellipse == FALSE)
375 : {
376 3 : int nInteriorRings = polygon->getNumInteriorRings();
377 6 : for(i=0;i<nInteriorRings;i++)
378 : {
379 3 : nBNAPoints += polygon->getInteriorRing(i)->getNumPoints() + 1;
380 : }
381 3 : if (nBNAPoints <= 3)
382 : {
383 0 : CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" );
384 0 : return OGRERR_FAILURE;
385 : }
386 3 : WriteFeatureAttributes(fp, poFeature);
387 3 : VSIFPrintf( fp, "%d", nBNAPoints);
388 3 : n = ring->getNumPoints();
389 3 : int nbPair = 0;
390 18 : for(i=0;i<n;i++)
391 : {
392 : VSIFPrintf( fp, formatCoordinates,
393 15 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(i), ring->getY(i));
394 15 : nbPair++;
395 : }
396 6 : for(i=0;i<nInteriorRings;i++)
397 : {
398 3 : ring = polygon->getInteriorRing(i);
399 3 : n = ring->getNumPoints();
400 18 : for(j=0;j<n;j++)
401 : {
402 : VSIFPrintf( fp, formatCoordinates,
403 15 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(j), ring->getY(j));
404 15 : nbPair++;
405 : }
406 : VSIFPrintf( fp, formatCoordinates,
407 3 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", firstX, firstY);
408 3 : nbPair++;
409 : }
410 3 : VSIFPrintf( fp, "%s", eol);
411 : }
412 6 : break;
413 : }
414 :
415 : case wkbMultiPolygon:
416 : case wkbMultiPolygon25D:
417 : {
418 9 : OGRMultiPolygon* multipolygon = (OGRMultiPolygon*)poGeom;
419 9 : int N = multipolygon->getNumGeometries();
420 9 : int nBNAPoints = 0;
421 9 : double firstX = 0, firstY = 0;
422 30 : for(i=0;i<N;i++)
423 : {
424 21 : OGRPolygon* polygon = (OGRPolygon*)multipolygon->getGeometryRef(i);
425 21 : OGRLinearRing* ring = polygon->getExteriorRing();
426 21 : if (ring == NULL)
427 0 : continue;
428 :
429 21 : if (nBNAPoints)
430 12 : nBNAPoints ++;
431 : else
432 : {
433 9 : firstX = ring->getX(0);
434 9 : firstY = ring->getY(0);
435 : }
436 21 : nBNAPoints += ring->getNumPoints();
437 21 : int nInteriorRings = polygon->getNumInteriorRings();
438 36 : for(j=0;j<nInteriorRings;j++)
439 : {
440 15 : nBNAPoints += polygon->getInteriorRing(j)->getNumPoints() + 1;
441 : }
442 : }
443 9 : if (nBNAPoints <= 3)
444 : {
445 0 : CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" );
446 0 : return OGRERR_FAILURE;
447 : }
448 9 : WriteFeatureAttributes(fp, poFeature);
449 9 : VSIFPrintf( fp, "%d", nBNAPoints);
450 9 : int nbPair = 0;
451 30 : for(i=0;i<N;i++)
452 : {
453 21 : OGRPolygon* polygon = (OGRPolygon*)multipolygon->getGeometryRef(i);
454 21 : OGRLinearRing* ring = polygon->getExteriorRing();
455 21 : if (ring == NULL)
456 0 : continue;
457 :
458 21 : n = ring->getNumPoints();
459 21 : int nInteriorRings = polygon->getNumInteriorRings();
460 135 : for(j=0;j<n;j++)
461 : {
462 : VSIFPrintf( fp, formatCoordinates,
463 114 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ",ring->getX(j), ring->getY(j));
464 114 : nbPair++;
465 : }
466 21 : if (i != 0)
467 : {
468 : VSIFPrintf( fp, formatCoordinates,
469 12 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ",firstX, firstY);
470 12 : nbPair++;
471 : }
472 36 : for(j=0;j<nInteriorRings;j++)
473 : {
474 15 : ring = polygon->getInteriorRing(j);
475 15 : n = ring->getNumPoints();
476 102 : for(k=0;k<n;k++)
477 : {
478 : VSIFPrintf( fp, formatCoordinates,
479 87 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(k), ring->getY(k));
480 87 : nbPair++;
481 : }
482 : VSIFPrintf( fp, formatCoordinates,
483 15 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", firstX, firstY);
484 15 : nbPair++;
485 : }
486 : }
487 9 : VSIFPrintf( fp, "%s", eol);
488 9 : break;
489 : }
490 :
491 : case wkbLineString:
492 : case wkbLineString25D:
493 : {
494 3 : OGRLineString* line = (OGRLineString*)poGeom;
495 3 : int n = line->getNumPoints();
496 : int i;
497 3 : if (n < 2)
498 : {
499 0 : CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" );
500 0 : return OGRERR_FAILURE;
501 : }
502 3 : WriteFeatureAttributes(fp, poFeature);
503 3 : VSIFPrintf( fp, "-%d", n);
504 3 : int nbPair = 0;
505 12 : for(i=0;i<n;i++)
506 : {
507 : VSIFPrintf( fp, formatCoordinates,
508 9 : ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", line->getX(i), line->getY(i));
509 9 : nbPair++;
510 : }
511 3 : VSIFPrintf( fp, "%s", eol);
512 3 : break;
513 : }
514 :
515 : default:
516 : {
517 : CPLError( CE_Failure, CPLE_AppDefined,
518 : "Unsupported geometry type : %s.",
519 0 : poGeom->getGeometryName() );
520 :
521 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
522 : }
523 : }
524 :
525 24 : return OGRERR_NONE;
526 : }
527 :
528 :
529 :
530 : /************************************************************************/
531 : /* CreateField() */
532 : /************************************************************************/
533 :
534 30 : OGRErr OGRBNALayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
535 :
536 : {
537 30 : if( !bWriter || nFeatures != 0)
538 0 : return OGRERR_FAILURE;
539 :
540 30 : poFeatureDefn->AddFieldDefn( poField );
541 :
542 30 : return OGRERR_NONE;
543 : }
544 :
545 :
546 : /************************************************************************/
547 : /* BuildFeatureFromBNARecord() */
548 : /************************************************************************/
549 139 : OGRFeature * OGRBNALayer::BuildFeatureFromBNARecord (BNARecord* record, long fid)
550 : {
551 : OGRFeature *poFeature;
552 : int i;
553 :
554 139 : poFeature = new OGRFeature( poFeatureDefn );
555 419 : for(i=0;i<nIDs;i++)
556 : {
557 280 : poFeature->SetField( i, record->ids[i] ? record->ids[i] : "");
558 : }
559 139 : poFeature->SetFID( fid );
560 139 : if (bnaFeatureType == BNA_POINT)
561 : {
562 36 : poFeature->SetGeometryDirectly( new OGRPoint( record->tabCoords[0][0], record->tabCoords[0][1] ) );
563 : }
564 103 : else if (bnaFeatureType == BNA_POLYLINE)
565 : {
566 17 : OGRLineString* lineString = new OGRLineString ();
567 17 : lineString->setCoordinateDimension(2);
568 17 : lineString->setNumPoints(record->nCoords);
569 68 : for(i=0;i<record->nCoords;i++)
570 : {
571 51 : lineString->setPoint(i, record->tabCoords[i][0], record->tabCoords[i][1] );
572 : }
573 17 : poFeature->SetGeometryDirectly(lineString);
574 : }
575 86 : else if (bnaFeatureType == BNA_POLYGON)
576 : {
577 69 : double firstX = record->tabCoords[0][0];
578 69 : double firstY = record->tabCoords[0][1];
579 69 : int isFirstPolygon = 1;
580 69 : double secondaryFirstX = 0, secondaryFirstY = 0;
581 :
582 69 : OGRLinearRing* ring = new OGRLinearRing ();
583 69 : ring->setCoordinateDimension(2);
584 69 : ring->addPoint(record->tabCoords[0][0], record->tabCoords[0][1] );
585 :
586 : /* record->nCoords is really a safe upper bound */
587 69 : int nbPolygons = 0;
588 : OGRPolygon** tabPolygons =
589 69 : (OGRPolygon**)CPLMalloc(record->nCoords * sizeof(OGRPolygon*));
590 :
591 1075 : for(i=1;i<record->nCoords;i++)
592 : {
593 1075 : ring->addPoint(record->tabCoords[i][0], record->tabCoords[i][1] );
594 1523 : if (isFirstPolygon == 1 &&
595 293 : record->tabCoords[i][0] == firstX &&
596 104 : record->tabCoords[i][1] == firstY)
597 : {
598 69 : OGRPolygon* polygon = new OGRPolygon ();
599 69 : polygon->addRingDirectly(ring);
600 69 : tabPolygons[nbPolygons] = polygon;
601 69 : nbPolygons++;
602 :
603 69 : if (i == record->nCoords - 1)
604 : {
605 18 : break;
606 : }
607 :
608 51 : isFirstPolygon = 0;
609 :
610 51 : i ++;
611 51 : secondaryFirstX = record->tabCoords[i][0];
612 51 : secondaryFirstY = record->tabCoords[i][1];
613 51 : ring = new OGRLinearRing ();
614 51 : ring->setCoordinateDimension(2);
615 51 : ring->addPoint(record->tabCoords[i][0], record->tabCoords[i][1] );
616 : }
617 1975 : else if (isFirstPolygon == 0 &&
618 782 : record->tabCoords[i][0] == secondaryFirstX &&
619 187 : record->tabCoords[i][1] == secondaryFirstY)
620 : {
621 :
622 170 : OGRPolygon* polygon = new OGRPolygon ();
623 170 : polygon->addRingDirectly(ring);
624 170 : tabPolygons[nbPolygons] = polygon;
625 170 : nbPolygons++;
626 :
627 170 : if (i < record->nCoords - 1)
628 : {
629 : /* After the closing of a subpolygon, the first coordinates of the first polygon */
630 : /* should be recalled... in theory */
631 170 : if (record->tabCoords[i+1][0] == firstX && record->tabCoords[i+1][1] == firstY)
632 : {
633 170 : if (i + 1 == record->nCoords - 1)
634 51 : break;
635 119 : i ++;
636 : }
637 : else
638 : {
639 : #if 0
640 : CPLError(CE_Warning, CPLE_AppDefined,
641 : "Geometry of polygon of fid %d starting at line %d is not strictly conformant. "
642 : "Trying to go on...\n",
643 : fid,
644 : offsetAndLineFeaturesTable[fid].line + 1);
645 : #endif
646 : }
647 :
648 119 : i ++;
649 119 : secondaryFirstX = record->tabCoords[i][0];
650 119 : secondaryFirstY = record->tabCoords[i][1];
651 119 : ring = new OGRLinearRing ();
652 119 : ring->setCoordinateDimension(2);
653 119 : ring->addPoint(record->tabCoords[i][0], record->tabCoords[i][1] );
654 : }
655 : else
656 : {
657 : #if 0
658 : CPLError(CE_Warning, CPLE_AppDefined,
659 : "Geometry of polygon of fid %d starting at line %d is not strictly conformant. Trying to go on...\n",
660 : fid,
661 : offsetAndLineFeaturesTable[fid].line + 1);
662 : #endif
663 : }
664 : }
665 : }
666 69 : if (i == record->nCoords)
667 : {
668 : /* Let's be a bit tolerant abount non closing polygons */
669 0 : if (isFirstPolygon)
670 : {
671 0 : ring->addPoint(record->tabCoords[0][0], record->tabCoords[0][1] );
672 :
673 0 : OGRPolygon* polygon = new OGRPolygon ();
674 0 : polygon->addRingDirectly(ring);
675 0 : tabPolygons[nbPolygons] = polygon;
676 0 : nbPolygons++;
677 : }
678 : }
679 :
680 69 : if (nbPolygons == 1)
681 : {
682 : /* Special optimization here : we directly put the polygon into the multipolygon. */
683 : /* This should save quite a few useless copies */
684 18 : OGRMultiPolygon* multipolygon = new OGRMultiPolygon();
685 18 : multipolygon->addGeometryDirectly(tabPolygons[0]);
686 18 : poFeature->SetGeometryDirectly(multipolygon);
687 : }
688 : else
689 : {
690 : int isValidGeometry;
691 : poFeature->SetGeometryDirectly(
692 51 : OGRGeometryFactory::organizePolygons((OGRGeometry**)tabPolygons, nbPolygons, &isValidGeometry, NULL));
693 :
694 51 : if (!isValidGeometry)
695 : {
696 : CPLError(CE_Warning, CPLE_AppDefined,
697 : "Geometry of polygon of fid %ld starting at line %d cannot be translated to Simple Geometry. "
698 : "All polygons will be contained in a multipolygon.\n",
699 : fid,
700 0 : offsetAndLineFeaturesTable[fid].line + 1);
701 : }
702 : }
703 :
704 69 : CPLFree(tabPolygons);
705 : }
706 : else
707 : {
708 : /* Circle or ellipses are not part of the OGR Simple Geometry, so we discretize them
709 : into polygons by 1 degree step */
710 17 : OGRPolygon* polygon = new OGRPolygon ();
711 34 : OGRLinearRing* ring = new OGRLinearRing ();
712 17 : ring->setCoordinateDimension(2);
713 17 : double center_x = record->tabCoords[0][0];
714 17 : double center_y = record->tabCoords[0][1];
715 17 : double major_radius = record->tabCoords[1][0];
716 17 : double minor_radius = record->tabCoords[1][1];
717 17 : if (minor_radius == 0)
718 11 : minor_radius = major_radius;
719 6137 : for(i=0;i<360;i++)
720 : {
721 : ring->addPoint(center_x + major_radius * cos(i * (M_PI / 180)),
722 6120 : center_y + minor_radius * sin(i * (M_PI / 180)) );
723 : }
724 17 : ring->addPoint(center_x + major_radius, center_y);
725 17 : polygon->addRingDirectly ( ring );
726 17 : poFeature->SetGeometryDirectly(polygon);
727 :
728 17 : poFeature->SetField( nIDs, major_radius);
729 17 : poFeature->SetField( nIDs+1, minor_radius);
730 : }
731 :
732 139 : return poFeature;
733 : }
734 :
735 :
736 : /************************************************************************/
737 : /* FastParseUntil() */
738 : /************************************************************************/
739 2 : void OGRBNALayer::FastParseUntil ( int interestFID)
740 : {
741 2 : if (partialIndexTable)
742 : {
743 0 : ResetReading();
744 :
745 : BNARecord* record;
746 :
747 0 : if (nFeatures > 0)
748 : {
749 0 : VSIFSeek( fpBNA, offsetAndLineFeaturesTable[nFeatures-1].offset, SEEK_SET );
750 0 : curLine = offsetAndLineFeaturesTable[nFeatures-1].line;
751 :
752 : /* Just skip the last read one */
753 0 : int ok = FALSE;
754 0 : record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, BNA_READ_NONE);
755 0 : BNA_FreeRecord(record);
756 : }
757 :
758 0 : while(1)
759 : {
760 0 : int ok = FALSE;
761 0 : int offset = VSIFTell(fpBNA);
762 0 : int line = curLine;
763 0 : record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, BNA_READ_NONE);
764 0 : if (ok == FALSE)
765 : {
766 0 : failed = TRUE;
767 0 : return;
768 : }
769 0 : if (record == NULL)
770 : {
771 : /* end of file */
772 0 : eof = TRUE;
773 :
774 : /* and we have finally build the whole index table */
775 0 : partialIndexTable = FALSE;
776 0 : return;
777 : }
778 :
779 0 : if (record->featureType == bnaFeatureType)
780 : {
781 0 : nFeatures++;
782 : offsetAndLineFeaturesTable =
783 0 : (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine));
784 0 : offsetAndLineFeaturesTable[nFeatures-1].offset = offset;
785 0 : offsetAndLineFeaturesTable[nFeatures-1].line = line;
786 :
787 0 : BNA_FreeRecord(record);
788 :
789 0 : if (nFeatures - 1 == interestFID)
790 0 : return;
791 : }
792 : else
793 : {
794 0 : BNA_FreeRecord(record);
795 : }
796 : }
797 : }
798 : }
799 :
800 : /************************************************************************/
801 : /* GetFeature() */
802 : /************************************************************************/
803 :
804 2 : OGRFeature * OGRBNALayer::GetFeature( long nFID )
805 : {
806 : OGRFeature *poFeature;
807 : BNARecord* record;
808 : int ok;
809 :
810 2 : if (nFID < 0)
811 0 : return NULL;
812 :
813 2 : FastParseUntil(nFID);
814 :
815 2 : if (nFID >= nFeatures)
816 0 : return NULL;
817 :
818 2 : VSIFSeek( fpBNA, offsetAndLineFeaturesTable[nFID].offset, SEEK_SET );
819 2 : curLine = offsetAndLineFeaturesTable[nFID].line;
820 2 : record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType);
821 :
822 2 : poFeature = BuildFeatureFromBNARecord(record, nFID);
823 :
824 2 : BNA_FreeRecord(record);
825 :
826 2 : return poFeature;
827 : }
828 :
829 : /************************************************************************/
830 : /* TestCapability() */
831 : /************************************************************************/
832 :
833 0 : int OGRBNALayer::TestCapability( const char * pszCap )
834 :
835 : {
836 0 : if( EQUAL(pszCap,OLCSequentialWrite) )
837 0 : return bWriter;
838 0 : else if( EQUAL(pszCap,OLCCreateField) )
839 0 : return bWriter && nFeatures == 0;
840 : else
841 0 : return FALSE;
842 : }
843 :
|