1 : /******************************************************************************
2 : * $Id: ogrpgeolayer.cpp 19778 2010-05-27 20:44:52Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRPGeoLayer class, code shared between
6 : * the direct table access, and the generic SQL results.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_conv.h"
32 : #include "ogr_pgeo.h"
33 : #include "cpl_string.h"
34 :
35 : CPL_CVSID("$Id: ogrpgeolayer.cpp 19778 2010-05-27 20:44:52Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRPGeoLayer() */
39 : /************************************************************************/
40 :
41 0 : OGRPGeoLayer::OGRPGeoLayer()
42 :
43 : {
44 0 : poDS = NULL;
45 :
46 0 : pszGeomColumn = NULL;
47 0 : pszFIDColumn = NULL;
48 :
49 0 : poStmt = NULL;
50 :
51 0 : iNextShapeId = 0;
52 :
53 0 : poSRS = NULL;
54 0 : nSRSId = -2; // we haven't even queried the database for it yet.
55 0 : }
56 :
57 : /************************************************************************/
58 : /* ~OGRPGeoLayer() */
59 : /************************************************************************/
60 :
61 0 : OGRPGeoLayer::~OGRPGeoLayer()
62 :
63 : {
64 0 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
65 : {
66 : CPLDebug( "PGeo", "%d features read on layer '%s'.",
67 : (int) m_nFeaturesRead,
68 0 : poFeatureDefn->GetName() );
69 : }
70 :
71 0 : if( poStmt != NULL )
72 : {
73 0 : delete poStmt;
74 0 : poStmt = NULL;
75 : }
76 :
77 0 : if( poFeatureDefn != NULL )
78 : {
79 0 : poFeatureDefn->Release();
80 0 : poFeatureDefn = NULL;
81 : }
82 :
83 0 : CPLFree( pszGeomColumn );
84 0 : CPLFree( panFieldOrdinals );
85 0 : CPLFree( pszFIDColumn );
86 :
87 0 : if( poSRS != NULL )
88 : {
89 0 : poSRS->Release();
90 0 : poSRS = NULL;
91 : }
92 0 : }
93 :
94 : /************************************************************************/
95 : /* BuildFeatureDefn() */
96 : /* */
97 : /* Build feature definition from a set of column definitions */
98 : /* set on a statement. Sift out geometry and FID fields. */
99 : /************************************************************************/
100 :
101 : CPLErr OGRPGeoLayer::BuildFeatureDefn( const char *pszLayerName,
102 0 : CPLODBCStatement *poStmt )
103 :
104 : {
105 0 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
106 0 : int nRawColumns = poStmt->GetColCount();
107 :
108 0 : poFeatureDefn->Reference();
109 :
110 0 : panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * nRawColumns );
111 :
112 0 : for( int iCol = 0; iCol < nRawColumns; iCol++ )
113 : {
114 0 : OGRFieldDefn oField( poStmt->GetColName(iCol), OFTString );
115 :
116 0 : oField.SetWidth( MAX(0,poStmt->GetColSize( iCol )) );
117 :
118 0 : if( pszGeomColumn != NULL
119 : && EQUAL(poStmt->GetColName(iCol),pszGeomColumn) )
120 0 : continue;
121 :
122 0 : if( pszFIDColumn == NULL
123 : && EQUAL(poStmt->GetColName(iCol),"OBJECTID") )
124 : {
125 0 : pszFIDColumn = CPLStrdup(poStmt->GetColName(iCol));
126 : }
127 :
128 0 : if( pszGeomColumn == NULL
129 : && EQUAL(poStmt->GetColName(iCol),"Shape") )
130 : {
131 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iCol));
132 : continue;
133 : }
134 :
135 0 : switch( poStmt->GetColType(iCol) )
136 : {
137 : case SQL_INTEGER:
138 : case SQL_SMALLINT:
139 0 : oField.SetType( OFTInteger );
140 0 : break;
141 :
142 : case SQL_BINARY:
143 : case SQL_VARBINARY:
144 : case SQL_LONGVARBINARY:
145 0 : oField.SetType( OFTBinary );
146 0 : break;
147 :
148 : case SQL_DECIMAL:
149 0 : oField.SetType( OFTReal );
150 0 : oField.SetPrecision( poStmt->GetColPrecision(iCol) );
151 0 : break;
152 :
153 : case SQL_FLOAT:
154 : case SQL_REAL:
155 : case SQL_DOUBLE:
156 0 : oField.SetType( OFTReal );
157 0 : oField.SetWidth( 0 );
158 0 : break;
159 :
160 : case SQL_C_DATE:
161 0 : oField.SetType( OFTDate );
162 0 : break;
163 :
164 : case SQL_C_TIME:
165 0 : oField.SetType( OFTTime );
166 0 : break;
167 :
168 : case SQL_C_TIMESTAMP:
169 0 : oField.SetType( OFTDateTime );
170 : break;
171 :
172 : default:
173 : /* leave it as OFTString */;
174 : }
175 :
176 0 : poFeatureDefn->AddFieldDefn( &oField );
177 0 : panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol+1;
178 : }
179 :
180 0 : return CE_None;
181 : }
182 :
183 :
184 : /************************************************************************/
185 : /* ResetReading() */
186 : /************************************************************************/
187 :
188 0 : void OGRPGeoLayer::ResetReading()
189 :
190 : {
191 0 : iNextShapeId = 0;
192 0 : }
193 :
194 : /************************************************************************/
195 : /* GetNextFeature() */
196 : /************************************************************************/
197 :
198 0 : OGRFeature *OGRPGeoLayer::GetNextFeature()
199 :
200 : {
201 0 : for( ; TRUE; )
202 : {
203 : OGRFeature *poFeature;
204 :
205 0 : poFeature = GetNextRawFeature();
206 0 : if( poFeature == NULL )
207 0 : return NULL;
208 :
209 0 : if( (m_poFilterGeom == NULL
210 : || FilterGeometry( poFeature->GetGeometryRef() ) )
211 : && (m_poAttrQuery == NULL
212 : || m_poAttrQuery->Evaluate( poFeature )) )
213 0 : return poFeature;
214 :
215 0 : delete poFeature;
216 : }
217 : }
218 :
219 : /************************************************************************/
220 : /* GetNextRawFeature() */
221 : /************************************************************************/
222 :
223 0 : OGRFeature *OGRPGeoLayer::GetNextRawFeature()
224 :
225 : {
226 0 : OGRErr err = OGRERR_NONE;
227 :
228 0 : if( GetStatement() == NULL )
229 0 : return NULL;
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* If we are marked to restart then do so, and fetch a record. */
233 : /* -------------------------------------------------------------------- */
234 0 : if( !poStmt->Fetch() )
235 : {
236 0 : delete poStmt;
237 0 : poStmt = NULL;
238 0 : return NULL;
239 : }
240 :
241 : /* -------------------------------------------------------------------- */
242 : /* Create a feature from the current result. */
243 : /* -------------------------------------------------------------------- */
244 : int iField;
245 0 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
246 :
247 0 : if( pszFIDColumn != NULL && poStmt->GetColId(pszFIDColumn) > -1 )
248 : poFeature->SetFID(
249 0 : atoi(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))) );
250 : else
251 0 : poFeature->SetFID( iNextShapeId );
252 :
253 0 : iNextShapeId++;
254 0 : m_nFeaturesRead++;
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* Set the fields. */
258 : /* -------------------------------------------------------------------- */
259 0 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
260 : {
261 0 : int iSrcField = panFieldOrdinals[iField]-1;
262 0 : const char *pszValue = poStmt->GetColData( iSrcField );
263 :
264 0 : if( pszValue == NULL )
265 : /* no value */;
266 0 : else if( poFeature->GetFieldDefnRef(iField)->GetType() == OFTBinary )
267 : poFeature->SetField( iField,
268 : poStmt->GetColDataLength(iSrcField),
269 0 : (GByte *) pszValue );
270 : else
271 0 : poFeature->SetField( iField, pszValue );
272 : }
273 :
274 : /* -------------------------------------------------------------------- */
275 : /* Try to extract a geometry. */
276 : /* -------------------------------------------------------------------- */
277 0 : if( pszGeomColumn != NULL )
278 : {
279 0 : int iField = poStmt->GetColId( pszGeomColumn );
280 0 : GByte *pabyShape = (GByte *) poStmt->GetColData( iField );
281 0 : int nBytes = poStmt->GetColDataLength(iField);
282 0 : OGRGeometry *poGeom = NULL;
283 :
284 0 : if( pabyShape != NULL )
285 : {
286 0 : err = createFromShapeBin( pabyShape, &poGeom, nBytes );
287 0 : if( OGRERR_NONE != err )
288 : {
289 : CPLDebug( "PGeo",
290 : "Translation shape binary to OGR geometry failed (FID=%ld)",
291 0 : (long)poFeature->GetFID() );
292 : }
293 : }
294 :
295 0 : if( poGeom != NULL && OGRERR_NONE == err )
296 : {
297 0 : poGeom->assignSpatialReference( poSRS );
298 0 : poFeature->SetGeometryDirectly( poGeom );
299 : }
300 : }
301 :
302 0 : return poFeature;
303 : }
304 :
305 : /************************************************************************/
306 : /* GetFeature() */
307 : /************************************************************************/
308 :
309 0 : OGRFeature *OGRPGeoLayer::GetFeature( long nFeatureId )
310 :
311 : {
312 : /* This should be implemented directly! */
313 :
314 0 : return OGRLayer::GetFeature( nFeatureId );
315 : }
316 :
317 : /************************************************************************/
318 : /* TestCapability() */
319 : /************************************************************************/
320 :
321 0 : int OGRPGeoLayer::TestCapability( const char * pszCap )
322 :
323 : {
324 0 : return FALSE;
325 : }
326 :
327 : /************************************************************************/
328 : /* GetSpatialRef() */
329 : /************************************************************************/
330 :
331 0 : OGRSpatialReference *OGRPGeoLayer::GetSpatialRef()
332 :
333 : {
334 0 : return poSRS;
335 : }
336 :
337 : /************************************************************************/
338 : /* TestCapability() */
339 : /************************************************************************/
340 :
341 0 : void OGRPGeoLayer::LookupSRID( int nSRID )
342 :
343 : {
344 : /* -------------------------------------------------------------------- */
345 : /* Fetch the corresponding WKT from the SpatialRef table. */
346 : /* -------------------------------------------------------------------- */
347 0 : CPLODBCStatement oStmt( poDS->GetSession() );
348 :
349 : oStmt.Appendf( "SELECT srtext FROM GDB_SpatialRefs WHERE srid = %d",
350 0 : nSRID );
351 :
352 0 : if( !oStmt.ExecuteSQL() )
353 : {
354 : CPLError( CE_Failure, CPLE_AppDefined,
355 : "'%s' failed.\n%s",
356 : oStmt.GetCommand(),
357 0 : poDS->GetSession()->GetLastError() );
358 0 : return;
359 : }
360 :
361 0 : if( !oStmt.Fetch() )
362 : {
363 : CPLError( CE_Warning, CPLE_AppDefined,
364 : "SRID %d lookup failed.\n%s",
365 0 : nSRID, poDS->GetSession()->GetLastError() );
366 : return;
367 : }
368 :
369 : /* -------------------------------------------------------------------- */
370 : /* Check that it isn't just a GUID. We don't know how to */
371 : /* translate those. */
372 : /* -------------------------------------------------------------------- */
373 0 : char *pszSRText = (char *) oStmt.GetColData(0);
374 :
375 0 : if( pszSRText[0] == '{' )
376 : {
377 0 : CPLDebug( "PGEO", "Ignoreing GUID SRTEXT: %s", pszSRText );
378 : return;
379 : }
380 :
381 : /* -------------------------------------------------------------------- */
382 : /* Turn it into an OGRSpatialReference. */
383 : /* -------------------------------------------------------------------- */
384 0 : poSRS = new OGRSpatialReference();
385 :
386 0 : if( poSRS->importFromWkt( &pszSRText ) != OGRERR_NONE )
387 : {
388 : CPLError( CE_Failure, CPLE_AppDefined,
389 : "importFromWKT() failed on SRS '%s'.",
390 0 : pszSRText);
391 0 : delete poSRS;
392 0 : poSRS = NULL;
393 : }
394 0 : else if( poSRS->morphFromESRI() != OGRERR_NONE )
395 : {
396 : CPLError( CE_Failure, CPLE_AppDefined,
397 0 : "morphFromESRI() failed on SRS." );
398 0 : delete poSRS;
399 0 : poSRS = NULL;
400 : }
401 : else
402 0 : nSRSId = nSRID;
403 : }
404 :
405 : /************************************************************************/
406 : /* createFromShapeBin() */
407 : /* */
408 : /* Translate shapefile binary representation to an OGR */
409 : /* geometry. */
410 : /************************************************************************/
411 :
412 : OGRErr OGRPGeoLayer::createFromShapeBin( GByte *pabyShape,
413 : OGRGeometry **ppoGeom,
414 0 : int nBytes )
415 :
416 : {
417 0 : *ppoGeom = NULL;
418 :
419 0 : if( nBytes < 1 )
420 0 : return OGRERR_FAILURE;
421 :
422 0 : int nSHPType = pabyShape[0];
423 :
424 :
425 : // CPLDebug( "PGeo",
426 : // "Shape type read from PGeo data is nSHPType = %d",
427 : // nSHPType );
428 :
429 : /* -------------------------------------------------------------------- */
430 : /* type 50 appears to just be an alias for normal line */
431 : /* strings. (#1484) */
432 : /* Type 51 appears to just be an alias for normal polygon. (#3100) */
433 : /* TODO: These types include additional attributes including */
434 : /* non-linear segments and such. They should be handled. */
435 : /* -------------------------------------------------------------------- */
436 0 : switch( nSHPType )
437 : {
438 : case 50:
439 0 : nSHPType = SHPT_ARC;
440 0 : break;
441 : case 51:
442 0 : nSHPType = SHPT_POLYGON;
443 0 : break;
444 : case 52:
445 0 : nSHPType = SHPT_POINT;
446 0 : break;
447 : case 53:
448 0 : nSHPType = SHPT_MULTIPOINT;
449 0 : break;
450 : case 54:
451 0 : nSHPType = SHPT_MULTIPATCH;
452 : }
453 :
454 : /* ==================================================================== */
455 : /* Extract vertices for a Polygon or Arc. */
456 : /* ==================================================================== */
457 0 : if( nSHPType == SHPT_ARC
458 : || nSHPType == SHPT_ARCZ
459 : || nSHPType == SHPT_ARCM
460 : || nSHPType == SHPT_ARCZM
461 : || nSHPType == SHPT_POLYGON
462 : || nSHPType == SHPT_POLYGONZ
463 : || nSHPType == SHPT_POLYGONM
464 : || nSHPType == SHPT_POLYGONZM
465 : || nSHPType == SHPT_MULTIPATCH
466 : || nSHPType == SHPT_MULTIPATCHM)
467 : {
468 : GInt32 nPoints, nParts;
469 : int i, nOffset;
470 : GInt32 *panPartStart;
471 :
472 0 : if (nBytes < 44)
473 : {
474 : CPLError(CE_Failure, CPLE_AppDefined,
475 0 : "Corrupted Shape : nBytes=%d, nSHPType=%d", nBytes, nSHPType);
476 0 : return OGRERR_FAILURE;
477 : }
478 :
479 : /* -------------------------------------------------------------------- */
480 : /* Extract part/point count, and build vertex and part arrays */
481 : /* to proper size. */
482 : /* -------------------------------------------------------------------- */
483 0 : memcpy( &nPoints, pabyShape + 40, 4 );
484 0 : memcpy( &nParts, pabyShape + 36, 4 );
485 :
486 : CPL_LSBPTR32( &nPoints );
487 : CPL_LSBPTR32( &nParts );
488 :
489 0 : if (nPoints < 0 || nParts < 0 ||
490 : nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
491 : {
492 : CPLError(CE_Failure, CPLE_AppDefined, "Corrupted Shape : nPoints=%d, nParts=%d.",
493 0 : nPoints, nParts);
494 0 : return OGRERR_FAILURE;
495 : }
496 :
497 : int bHasZ = ( nSHPType == SHPT_POLYGONZ
498 : || nSHPType == SHPT_POLYGONZM
499 : || nSHPType == SHPT_ARCZ
500 : || nSHPType == SHPT_ARCZM
501 : || nSHPType == SHPT_MULTIPATCH
502 0 : || nSHPType == SHPT_MULTIPATCHM );
503 :
504 0 : int bIsMultiPatch = ( nSHPType == SHPT_MULTIPATCH || nSHPType == SHPT_MULTIPATCHM );
505 :
506 : /* With the previous checks on nPoints and nParts, */
507 : /* we should not overflow here and after */
508 : /* since 50 M * (16 + 8 + 8) = 1 600 MB */
509 0 : int nRequiredSize = 44 + 4 * nParts + 16 * nPoints;
510 0 : if ( bHasZ )
511 : {
512 0 : nRequiredSize += 16 + 8 * nPoints;
513 : }
514 0 : if( bIsMultiPatch )
515 : {
516 0 : nRequiredSize += 4 * nParts;
517 : }
518 0 : if (nRequiredSize > nBytes)
519 : {
520 : CPLError(CE_Failure, CPLE_AppDefined,
521 : "Corrupted Shape : nPoints=%d, nParts=%d, nBytes=%d, nSHPType=%d",
522 0 : nPoints, nParts, nBytes, nSHPType);
523 0 : return OGRERR_FAILURE;
524 : }
525 :
526 0 : panPartStart = (GInt32 *) VSICalloc(nParts,sizeof(GInt32));
527 0 : if (panPartStart == NULL)
528 : {
529 : CPLError(CE_Failure, CPLE_OutOfMemory,
530 0 : "Not enough memory for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
531 0 : return OGRERR_FAILURE;
532 : }
533 :
534 : /* -------------------------------------------------------------------- */
535 : /* Copy out the part array from the record. */
536 : /* -------------------------------------------------------------------- */
537 0 : memcpy( panPartStart, pabyShape + 44, 4 * nParts );
538 0 : for( i = 0; i < nParts; i++ )
539 : {
540 : CPL_LSBPTR32( panPartStart + i );
541 :
542 : /* We check that the offset is inside the vertex array */
543 0 : if (panPartStart[i] < 0 ||
544 : panPartStart[i] >= nPoints)
545 : {
546 : CPLError(CE_Failure, CPLE_AppDefined,
547 : "Corrupted Shape : panPartStart[%d] = %d, nPoints = %d",
548 0 : i, panPartStart[i], nPoints);
549 0 : CPLFree(panPartStart);
550 0 : return OGRERR_FAILURE;
551 : }
552 0 : if (i > 0 && panPartStart[i] <= panPartStart[i-1])
553 : {
554 : CPLError(CE_Failure, CPLE_AppDefined,
555 : "Corrupted Shape : panPartStart[%d] = %d, panPartStart[%d] = %d",
556 0 : i, panPartStart[i], i - 1, panPartStart[i - 1]);
557 0 : CPLFree(panPartStart);
558 0 : return OGRERR_FAILURE;
559 : }
560 : }
561 :
562 0 : nOffset = 44 + 4*nParts;
563 :
564 : /* -------------------------------------------------------------------- */
565 : /* If this is a multipatch, we will also have parts types. For */
566 : /* now we ignore and skip past them. */
567 : /* -------------------------------------------------------------------- */
568 0 : if( bIsMultiPatch )
569 0 : nOffset += 4*nParts;
570 :
571 : /* -------------------------------------------------------------------- */
572 : /* Copy out the vertices from the record. */
573 : /* -------------------------------------------------------------------- */
574 0 : double *padfX = (double *) VSIMalloc(sizeof(double)*nPoints);
575 0 : double *padfY = (double *) VSIMalloc(sizeof(double)*nPoints);
576 0 : double *padfZ = (double *) VSICalloc(sizeof(double),nPoints);
577 0 : if (padfX == NULL || padfY == NULL || padfZ == NULL)
578 : {
579 0 : CPLFree( panPartStart );
580 0 : CPLFree( padfX );
581 0 : CPLFree( padfY );
582 0 : CPLFree( padfZ );
583 : CPLError(CE_Failure, CPLE_OutOfMemory,
584 0 : "Not enough memory for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
585 0 : return OGRERR_FAILURE;
586 : }
587 :
588 0 : for( i = 0; i < nPoints; i++ )
589 : {
590 0 : memcpy(padfX + i, pabyShape + nOffset + i * 16, 8 );
591 0 : memcpy(padfY + i, pabyShape + nOffset + i * 16 + 8, 8 );
592 : CPL_LSBPTR64( padfX + i );
593 : CPL_LSBPTR64( padfY + i );
594 : }
595 :
596 0 : nOffset += 16*nPoints;
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* If we have a Z coordinate, collect that now. */
600 : /* -------------------------------------------------------------------- */
601 0 : if( bHasZ )
602 : {
603 0 : for( i = 0; i < nPoints; i++ )
604 : {
605 0 : memcpy( padfZ + i, pabyShape + nOffset + 16 + i*8, 8 );
606 : CPL_LSBPTR64( padfZ + i );
607 : }
608 :
609 0 : nOffset += 16 + 8*nPoints;
610 : }
611 :
612 : /* -------------------------------------------------------------------- */
613 : /* Build corresponding OGR objects. */
614 : /* -------------------------------------------------------------------- */
615 0 : if( nSHPType == SHPT_ARC
616 : || nSHPType == SHPT_ARCZ
617 : || nSHPType == SHPT_ARCM
618 : || nSHPType == SHPT_ARCZM )
619 : {
620 : /* -------------------------------------------------------------------- */
621 : /* Arc - As LineString */
622 : /* -------------------------------------------------------------------- */
623 0 : if( nParts == 1 )
624 : {
625 0 : OGRLineString *poLine = new OGRLineString();
626 0 : *ppoGeom = poLine;
627 :
628 0 : poLine->setPoints( nPoints, padfX, padfY, padfZ );
629 : }
630 :
631 : /* -------------------------------------------------------------------- */
632 : /* Arc - As MultiLineString */
633 : /* -------------------------------------------------------------------- */
634 : else
635 : {
636 0 : OGRMultiLineString *poMulti = new OGRMultiLineString;
637 0 : *ppoGeom = poMulti;
638 :
639 0 : for( i = 0; i < nParts; i++ )
640 : {
641 0 : OGRLineString *poLine = new OGRLineString;
642 : int nVerticesInThisPart;
643 :
644 0 : if( i == nParts-1 )
645 0 : nVerticesInThisPart = nPoints - panPartStart[i];
646 : else
647 : nVerticesInThisPart =
648 0 : panPartStart[i+1] - panPartStart[i];
649 :
650 : poLine->setPoints( nVerticesInThisPart,
651 : padfX + panPartStart[i],
652 : padfY + panPartStart[i],
653 0 : padfZ + panPartStart[i] );
654 :
655 0 : poMulti->addGeometryDirectly( poLine );
656 : }
657 : }
658 : } /* ARC */
659 :
660 : /* -------------------------------------------------------------------- */
661 : /* Polygon */
662 : /* -------------------------------------------------------------------- */
663 0 : else if( nSHPType == SHPT_POLYGON
664 : || nSHPType == SHPT_POLYGONZ
665 : || nSHPType == SHPT_POLYGONM
666 : || nSHPType == SHPT_POLYGONZM )
667 : {
668 0 : if (nParts != 0)
669 : {
670 0 : if (nParts == 1)
671 : {
672 0 : OGRPolygon *poOGRPoly = new OGRPolygon;
673 0 : *ppoGeom = poOGRPoly;
674 0 : OGRLinearRing *poRing = new OGRLinearRing;
675 0 : int nVerticesInThisPart = nPoints - panPartStart[0];
676 :
677 : poRing->setPoints( nVerticesInThisPart,
678 : padfX + panPartStart[0],
679 : padfY + panPartStart[0],
680 0 : padfZ + panPartStart[0] );
681 :
682 0 : poOGRPoly->addRingDirectly( poRing );
683 : }
684 : else
685 : {
686 0 : OGRGeometry *poOGR = NULL;
687 0 : OGRPolygon** tabPolygons = new OGRPolygon*[nParts];
688 :
689 0 : for( i = 0; i < nParts; i++ )
690 : {
691 0 : tabPolygons[i] = new OGRPolygon();
692 0 : OGRLinearRing *poRing = new OGRLinearRing;
693 : int nVerticesInThisPart;
694 :
695 0 : if( i == nParts-1 )
696 0 : nVerticesInThisPart = nPoints - panPartStart[i];
697 : else
698 : nVerticesInThisPart =
699 0 : panPartStart[i+1] - panPartStart[i];
700 :
701 : poRing->setPoints( nVerticesInThisPart,
702 : padfX + panPartStart[i],
703 : padfY + panPartStart[i],
704 0 : padfZ + panPartStart[i] );
705 0 : tabPolygons[i]->addRingDirectly(poRing);
706 : }
707 :
708 : int isValidGeometry;
709 0 : const char* papszOptions[] = { "METHOD=ONLY_CCW", NULL };
710 : poOGR = OGRGeometryFactory::organizePolygons(
711 0 : (OGRGeometry**)tabPolygons, nParts, &isValidGeometry, papszOptions );
712 :
713 0 : if (!isValidGeometry)
714 : {
715 : CPLError(CE_Warning, CPLE_AppDefined,
716 : "Geometry of polygon cannot be translated to Simple Geometry. "
717 0 : "All polygons will be contained in a multipolygon.\n");
718 : }
719 :
720 0 : *ppoGeom = poOGR;
721 0 : delete[] tabPolygons;
722 : }
723 : }
724 : } /* polygon */
725 :
726 : /* -------------------------------------------------------------------- */
727 : /* Multipatch */
728 : /* -------------------------------------------------------------------- */
729 : else if( bIsMultiPatch )
730 : {
731 : /* return to this later */
732 : }
733 :
734 0 : CPLFree( panPartStart );
735 0 : CPLFree( padfX );
736 0 : CPLFree( padfY );
737 0 : CPLFree( padfZ );
738 :
739 0 : if( !bHasZ )
740 0 : (*ppoGeom)->setCoordinateDimension( 2 );
741 :
742 0 : return OGRERR_NONE;
743 : }
744 :
745 : /* ==================================================================== */
746 : /* Extract vertices for a MultiPoint. */
747 : /* ==================================================================== */
748 0 : else if( nSHPType == SHPT_MULTIPOINT
749 : || nSHPType == SHPT_MULTIPOINTM
750 : || nSHPType == SHPT_MULTIPOINTZ
751 : || nSHPType == SHPT_MULTIPOINTZM )
752 : {
753 : #ifdef notdef
754 : int32 nPoints;
755 : int i, nOffset;
756 :
757 : memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
758 : if( bBigEndian ) SwapWord( 4, &nPoints );
759 :
760 : psShape->nVertices = nPoints;
761 : psShape->padfX = (double *) calloc(nPoints,sizeof(double));
762 : psShape->padfY = (double *) calloc(nPoints,sizeof(double));
763 : psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
764 : psShape->padfM = (double *) calloc(nPoints,sizeof(double));
765 :
766 : for( i = 0; i < nPoints; i++ )
767 : {
768 : memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
769 : memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
770 :
771 : if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
772 : if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
773 : }
774 :
775 : nOffset = 48 + 16*nPoints;
776 :
777 : /* -------------------------------------------------------------------- */
778 : /* Get the X/Y bounds. */
779 : /* -------------------------------------------------------------------- */
780 : memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
781 : memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
782 : memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
783 : memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
784 :
785 : if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
786 : if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
787 : if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
788 : if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
789 :
790 : /* -------------------------------------------------------------------- */
791 : /* If we have a Z coordinate, collect that now. */
792 : /* -------------------------------------------------------------------- */
793 : if( psShape->nSHPType == SHPT_MULTIPOINTZ || psShape->nSHPType == SHPT_MULTIPOINTZM )
794 : {
795 : memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
796 : memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
797 :
798 : if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
799 : if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
800 :
801 : for( i = 0; i < nPoints; i++ )
802 : {
803 : memcpy( psShape->padfZ + i,
804 : psSHP->pabyRec + nOffset + 16 + i*8, 8 );
805 : if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
806 : }
807 :
808 : nOffset += 16 + 8*nPoints;
809 : }
810 :
811 : /* -------------------------------------------------------------------- */
812 : /* If we have a M measure value, then read it now. We assume */
813 : /* that the measure can be present for any shape if the size is */
814 : /* big enough, but really it will only occur for the Z shapes */
815 : /* (options), and the M shapes. */
816 : /* -------------------------------------------------------------------- */
817 : if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
818 : {
819 : memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
820 : memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
821 :
822 : if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
823 : if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
824 :
825 : for( i = 0; i < nPoints; i++ )
826 : {
827 : memcpy( psShape->padfM + i,
828 : psSHP->pabyRec + nOffset + 16 + i*8, 8 );
829 : if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
830 : }
831 : }
832 : #endif
833 : }
834 :
835 : /* ==================================================================== */
836 : /* Extract vertices for a point. */
837 : /* ==================================================================== */
838 0 : else if( nSHPType == SHPT_POINT
839 : || nSHPType == SHPT_POINTM
840 : || nSHPType == SHPT_POINTZ
841 : || nSHPType == SHPT_POINTZM )
842 : {
843 : int nOffset;
844 0 : double dfX, dfY, dfZ = 0;
845 :
846 0 : int bHasZ = (nSHPType == SHPT_POINTZ || nSHPType == SHPT_POINTZM);
847 :
848 0 : if (nBytes < 4 + 8 + 8 + ((nSHPType == SHPT_POINTZ) ? 8 : 0))
849 : {
850 : CPLError(CE_Failure, CPLE_AppDefined,
851 0 : "Corrupted Shape : nBytes=%d, nSHPType=%d", nBytes, nSHPType);
852 0 : return OGRERR_FAILURE;
853 : }
854 :
855 0 : memcpy( &dfX, pabyShape + 4, 8 );
856 0 : memcpy( &dfY, pabyShape + 4 + 8, 8 );
857 :
858 : CPL_LSBPTR64( &dfX );
859 : CPL_LSBPTR64( &dfY );
860 0 : nOffset = 20 + 8;
861 :
862 0 : if( bHasZ )
863 : {
864 0 : memcpy( &dfZ, pabyShape + 4 + 16, 8 );
865 : CPL_LSBPTR64( &dfZ );
866 : }
867 :
868 0 : *ppoGeom = new OGRPoint( dfX, dfY, dfZ );
869 :
870 0 : if( !bHasZ )
871 0 : (*ppoGeom)->setCoordinateDimension( 2 );
872 :
873 0 : return OGRERR_NONE;
874 : }
875 :
876 0 : char* pszHex = CPLBinaryToHex( nBytes, pabyShape );
877 : CPLDebug( "PGEO", "Unsupported geometry type:%d\nnBytes=%d, hex=%s",
878 0 : nSHPType, nBytes, pszHex );
879 0 : CPLFree(pszHex);
880 :
881 0 : return OGRERR_FAILURE;
882 : }
883 :
884 : /************************************************************************/
885 : /* GetFIDColumn() */
886 : /************************************************************************/
887 :
888 0 : const char *OGRPGeoLayer::GetFIDColumn()
889 :
890 : {
891 0 : if( pszFIDColumn != NULL )
892 0 : return pszFIDColumn;
893 : else
894 0 : return "";
895 : }
896 :
897 : /************************************************************************/
898 : /* GetGeometryColumn() */
899 : /************************************************************************/
900 :
901 0 : const char *OGRPGeoLayer::GetGeometryColumn()
902 :
903 : {
904 0 : if( pszGeomColumn != NULL )
905 0 : return pszGeomColumn;
906 : else
907 0 : return "";
908 : }
|