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