1 : /******************************************************************************
2 : * $Id: ogrpgeogeometry.cpp 22752 2011-07-18 17:42:07Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements decoder of shapebin geometry for PGeo
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : * Paul Ramsey, pramsey at cleverelephant.ca
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
11 : * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "ogrpgeogeometry.h"
33 : #include "ogr_p.h"
34 : #include "cpl_string.h"
35 : #include "zlib.h"
36 :
37 : CPL_CVSID("$Id: ogrpgeogeometry.cpp 22752 2011-07-18 17:42:07Z rouault $");
38 :
39 : #define SHPP_TRISTRIP 0
40 : #define SHPP_TRIFAN 1
41 : #define SHPP_OUTERRING 2
42 : #define SHPP_INNERRING 3
43 : #define SHPP_FIRSTRING 4
44 : #define SHPP_RING 5
45 : #define SHPP_TRIANGLES 6 /* Multipatch 9.0 specific */
46 :
47 :
48 : /************************************************************************/
49 : /* OGRCreateFromMultiPatch() */
50 : /* */
51 : /* Translate a multipatch representation to an OGR geometry */
52 : /* Mostly copied from shape2ogr.cpp */
53 : /************************************************************************/
54 :
55 0 : static OGRGeometry* OGRCreateFromMultiPatch(int nParts,
56 : GInt32* panPartStart,
57 : GInt32* panPartType,
58 : int nPoints,
59 : double* padfX,
60 : double* padfY,
61 : double* padfZ)
62 : {
63 0 : OGRMultiPolygon *poMP = new OGRMultiPolygon();
64 : int iPart;
65 0 : OGRPolygon *poLastPoly = NULL;
66 :
67 0 : for( iPart = 0; iPart < nParts; iPart++ )
68 : {
69 : int nPartPoints, nPartStart;
70 :
71 : // Figure out details about this part's vertex list.
72 0 : if( panPartStart == NULL )
73 : {
74 0 : nPartPoints = nPoints;
75 0 : nPartStart = 0;
76 : }
77 : else
78 : {
79 :
80 0 : if( iPart == nParts - 1 )
81 : nPartPoints =
82 0 : nPoints - panPartStart[iPart];
83 : else
84 0 : nPartPoints = panPartStart[iPart+1]
85 0 : - panPartStart[iPart];
86 0 : nPartStart = panPartStart[iPart];
87 : }
88 :
89 0 : panPartType[iPart] &= 0xf;
90 :
91 0 : if( panPartType[iPart] == SHPP_TRISTRIP )
92 : {
93 : int iBaseVert;
94 :
95 0 : if( poLastPoly != NULL )
96 : {
97 0 : poMP->addGeometryDirectly( poLastPoly );
98 0 : poLastPoly = NULL;
99 : }
100 :
101 0 : for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
102 : {
103 0 : OGRPolygon *poPoly = new OGRPolygon();
104 0 : OGRLinearRing *poRing = new OGRLinearRing();
105 0 : int iSrcVert = iBaseVert + nPartStart;
106 :
107 : poRing->setPoint( 0,
108 : padfX[iSrcVert],
109 : padfY[iSrcVert],
110 0 : padfZ[iSrcVert] );
111 : poRing->setPoint( 1,
112 : padfX[iSrcVert+1],
113 : padfY[iSrcVert+1],
114 0 : padfZ[iSrcVert+1] );
115 :
116 : poRing->setPoint( 2,
117 : padfX[iSrcVert+2],
118 : padfY[iSrcVert+2],
119 0 : padfZ[iSrcVert+2] );
120 : poRing->setPoint( 3,
121 : padfX[iSrcVert],
122 : padfY[iSrcVert],
123 0 : padfZ[iSrcVert] );
124 :
125 0 : poPoly->addRingDirectly( poRing );
126 0 : poMP->addGeometryDirectly( poPoly );
127 : }
128 : }
129 0 : else if( panPartType[iPart] == SHPP_TRIFAN )
130 : {
131 : int iBaseVert;
132 :
133 0 : if( poLastPoly != NULL )
134 : {
135 0 : poMP->addGeometryDirectly( poLastPoly );
136 0 : poLastPoly = NULL;
137 : }
138 :
139 0 : for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
140 : {
141 0 : OGRPolygon *poPoly = new OGRPolygon();
142 0 : OGRLinearRing *poRing = new OGRLinearRing();
143 0 : int iSrcVert = iBaseVert + nPartStart;
144 :
145 : poRing->setPoint( 0,
146 : padfX[nPartStart],
147 : padfY[nPartStart],
148 0 : padfZ[nPartStart] );
149 : poRing->setPoint( 1,
150 : padfX[iSrcVert+1],
151 : padfY[iSrcVert+1],
152 0 : padfZ[iSrcVert+1] );
153 :
154 : poRing->setPoint( 2,
155 : padfX[iSrcVert+2],
156 : padfY[iSrcVert+2],
157 0 : padfZ[iSrcVert+2] );
158 : poRing->setPoint( 3,
159 : padfX[nPartStart],
160 : padfY[nPartStart],
161 0 : padfZ[nPartStart] );
162 :
163 0 : poPoly->addRingDirectly( poRing );
164 0 : poMP->addGeometryDirectly( poPoly );
165 : }
166 : }
167 0 : else if( panPartType[iPart] == SHPP_OUTERRING
168 0 : || panPartType[iPart] == SHPP_INNERRING
169 0 : || panPartType[iPart] == SHPP_FIRSTRING
170 0 : || panPartType[iPart] == SHPP_RING )
171 : {
172 0 : if( poLastPoly != NULL
173 0 : && (panPartType[iPart] == SHPP_OUTERRING
174 0 : || panPartType[iPart] == SHPP_FIRSTRING) )
175 : {
176 0 : poMP->addGeometryDirectly( poLastPoly );
177 0 : poLastPoly = NULL;
178 : }
179 :
180 0 : if( poLastPoly == NULL )
181 0 : poLastPoly = new OGRPolygon();
182 :
183 0 : OGRLinearRing *poRing = new OGRLinearRing;
184 :
185 : poRing->setPoints( nPartPoints,
186 : padfX + nPartStart,
187 : padfY + nPartStart,
188 0 : padfZ + nPartStart );
189 :
190 0 : poRing->closeRings();
191 :
192 0 : poLastPoly->addRingDirectly( poRing );
193 : }
194 0 : else if ( panPartType[iPart] == SHPP_TRIANGLES )
195 : {
196 : int iBaseVert;
197 :
198 0 : if( poLastPoly != NULL )
199 : {
200 0 : poMP->addGeometryDirectly( poLastPoly );
201 0 : poLastPoly = NULL;
202 : }
203 :
204 0 : for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert+=3 )
205 : {
206 0 : OGRPolygon *poPoly = new OGRPolygon();
207 0 : OGRLinearRing *poRing = new OGRLinearRing();
208 0 : int iSrcVert = iBaseVert + nPartStart;
209 :
210 : poRing->setPoint( 0,
211 : padfX[iSrcVert],
212 : padfY[iSrcVert],
213 0 : padfZ[iSrcVert] );
214 : poRing->setPoint( 1,
215 : padfX[iSrcVert+1],
216 : padfY[iSrcVert+1],
217 0 : padfZ[iSrcVert+1] );
218 :
219 : poRing->setPoint( 2,
220 : padfX[iSrcVert+2],
221 : padfY[iSrcVert+2],
222 0 : padfZ[iSrcVert+2] );
223 : poRing->setPoint( 3,
224 : padfX[iSrcVert],
225 : padfY[iSrcVert],
226 0 : padfZ[iSrcVert] );
227 :
228 0 : poPoly->addRingDirectly( poRing );
229 0 : poMP->addGeometryDirectly( poPoly );
230 : }
231 : }
232 : else
233 : CPLDebug( "OGR", "Unrecognised parttype %d, ignored.",
234 0 : panPartType[iPart] );
235 : }
236 :
237 0 : if( poLastPoly != NULL )
238 : {
239 0 : poMP->addGeometryDirectly( poLastPoly );
240 0 : poLastPoly = NULL;
241 : }
242 :
243 0 : return poMP;
244 : }
245 :
246 :
247 : /************************************************************************/
248 : /* OGRWriteToShapeBin() */
249 : /* */
250 : /* Translate OGR geometry to a shapefile binary representation */
251 : /************************************************************************/
252 :
253 22 : OGRErr OGRWriteToShapeBin( OGRGeometry *poGeom,
254 : GByte **ppabyShape,
255 : int *pnBytes )
256 : {
257 22 : GUInt32 nGType = SHPT_NULL;
258 22 : int nShpSize = 4; /* All types start with integer type number */
259 22 : int nShpZSize = 0; /* Z gets tacked onto the end */
260 22 : GUInt32 nPoints = 0;
261 22 : GUInt32 nParts = 0;
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* Null or Empty input maps to SHPT_NULL. */
265 : /* -------------------------------------------------------------------- */
266 22 : if ( ! poGeom || poGeom->IsEmpty() )
267 : {
268 0 : *ppabyShape = (GByte*)VSIMalloc(nShpSize);
269 0 : GUInt32 zero = SHPT_NULL;
270 0 : memcpy(*ppabyShape, &zero, nShpSize);
271 0 : *pnBytes = nShpSize;
272 0 : return OGRERR_NONE;
273 : }
274 :
275 22 : OGRwkbGeometryType nOGRType = wkbFlatten(poGeom->getGeometryType());
276 22 : int b3d = (poGeom->getGeometryType() & wkb25DBit);
277 22 : int nCoordDims = b3d ? 3 : 2;
278 :
279 : /* -------------------------------------------------------------------- */
280 : /* Calculate the shape buffer size */
281 : /* -------------------------------------------------------------------- */
282 22 : if ( nOGRType == wkbPoint )
283 : {
284 2 : nShpSize += 8 * nCoordDims;
285 : }
286 20 : else if ( nOGRType == wkbLineString )
287 : {
288 2 : OGRLineString *poLine = (OGRLineString*)poGeom;
289 2 : nPoints = poLine->getNumPoints();
290 2 : nParts = 1;
291 2 : nShpSize += 16 * nCoordDims; /* xy(z) box */
292 2 : nShpSize += 4; /* nparts */
293 2 : nShpSize += 4; /* npoints */
294 2 : nShpSize += 4; /* parts[1] */
295 2 : nShpSize += 8 * nCoordDims * nPoints; /* points */
296 2 : nShpZSize = 16 + 8 * nPoints;
297 : }
298 18 : else if ( nOGRType == wkbPolygon )
299 : {
300 2 : poGeom->closeRings();
301 2 : OGRPolygon *poPoly = (OGRPolygon*)poGeom;
302 2 : nParts = poPoly->getNumInteriorRings() + 1;
303 4 : for ( GUInt32 i = 0; i < nParts; i++ )
304 : {
305 : OGRLinearRing *poRing;
306 2 : if ( i == 0 )
307 2 : poRing = poPoly->getExteriorRing();
308 : else
309 0 : poRing = poPoly->getInteriorRing(i-1);
310 2 : nPoints += poRing->getNumPoints();
311 : }
312 2 : nShpSize += 16 * nCoordDims; /* xy(z) box */
313 2 : nShpSize += 4; /* nparts */
314 2 : nShpSize += 4; /* npoints */
315 2 : nShpSize += 4 * nParts; /* parts[nparts] */
316 2 : nShpSize += 8 * nCoordDims * nPoints; /* points */
317 2 : nShpZSize = 16 + 8 * nPoints;
318 : }
319 16 : else if ( nOGRType == wkbMultiPoint )
320 : {
321 2 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
322 6 : for ( int i = 0; i < poMPoint->getNumGeometries(); i++ )
323 : {
324 4 : OGRPoint *poPoint = (OGRPoint*)(poMPoint->getGeometryRef(i));
325 4 : if ( poPoint->IsEmpty() )
326 0 : continue;
327 4 : nPoints++;
328 : }
329 2 : nShpSize += 16 * nCoordDims; /* xy(z) box */
330 2 : nShpSize += 4; /* npoints */
331 2 : nShpSize += 8 * nCoordDims * nPoints; /* points */
332 2 : nShpZSize = 16 + 8 * nPoints;
333 : }
334 14 : else if ( nOGRType == wkbMultiLineString )
335 : {
336 2 : OGRMultiLineString *poMLine = (OGRMultiLineString*)poGeom;
337 4 : for ( int i = 0; i < poMLine->getNumGeometries(); i++ )
338 : {
339 2 : OGRLineString *poLine = (OGRLineString*)(poMLine->getGeometryRef(i));
340 : /* Skip empties */
341 2 : if ( poLine->IsEmpty() )
342 0 : continue;
343 2 : nParts++;
344 2 : nPoints += poLine->getNumPoints();
345 : }
346 2 : nShpSize += 16 * nCoordDims; /* xy(z) box */
347 2 : nShpSize += 4; /* nparts */
348 2 : nShpSize += 4; /* npoints */
349 2 : nShpSize += 4 * nParts; /* parts[nparts] */
350 2 : nShpSize += 8 * nCoordDims * nPoints ; /* points */
351 2 : nShpZSize = 16 + 8 * nPoints;
352 : }
353 12 : else if ( nOGRType == wkbMultiPolygon )
354 : {
355 12 : poGeom->closeRings();
356 12 : OGRMultiPolygon *poMPoly = (OGRMultiPolygon*)poGeom;
357 24 : for( int j = 0; j < poMPoly->getNumGeometries(); j++ )
358 : {
359 12 : OGRPolygon *poPoly = (OGRPolygon*)(poMPoly->getGeometryRef(j));
360 12 : int nRings = poPoly->getNumInteriorRings() + 1;
361 :
362 : /* Skip empties */
363 12 : if ( poPoly->IsEmpty() )
364 0 : continue;
365 :
366 12 : nParts += nRings;
367 24 : for ( int i = 0; i < nRings; i++ )
368 : {
369 : OGRLinearRing *poRing;
370 12 : if ( i == 0 )
371 12 : poRing = poPoly->getExteriorRing();
372 : else
373 0 : poRing = poPoly->getInteriorRing(i-1);
374 12 : nPoints += poRing->getNumPoints();
375 : }
376 : }
377 12 : nShpSize += 16 * nCoordDims; /* xy(z) box */
378 12 : nShpSize += 4; /* nparts */
379 12 : nShpSize += 4; /* npoints */
380 12 : nShpSize += 4 * nParts; /* parts[nparts] */
381 12 : nShpSize += 8 * nCoordDims * nPoints ; /* points */
382 12 : nShpZSize = 16 + 8 * nPoints;
383 : }
384 : else
385 : {
386 0 : return OGRERR_UNSUPPORTED_OPERATION;
387 : }
388 :
389 : /* Allocate our shape buffer */
390 22 : *ppabyShape = (GByte*)VSIMalloc(nShpSize);
391 22 : if ( ! *ppabyShape )
392 0 : return OGRERR_FAILURE;
393 :
394 : /* Fill in the output size. */
395 22 : *pnBytes = nShpSize;
396 :
397 : /* Set up write pointers */
398 22 : unsigned char *pabyPtr = *ppabyShape;
399 22 : unsigned char *pabyPtrZ = NULL;
400 22 : if ( b3d )
401 6 : pabyPtrZ = pabyPtr + nShpSize - nShpZSize;
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Write in the Shape type number now */
405 : /* -------------------------------------------------------------------- */
406 22 : switch(nOGRType)
407 : {
408 : case wkbPoint:
409 : {
410 2 : nGType = b3d ? SHPT_POINTZ : SHPT_POINT;
411 2 : break;
412 : }
413 : case wkbMultiPoint:
414 : {
415 2 : nGType = b3d ? SHPT_MULTIPOINTZ : SHPT_MULTIPOINT;
416 2 : break;
417 : }
418 : case wkbLineString:
419 : case wkbMultiLineString:
420 : {
421 4 : nGType = b3d ? SHPT_ARCZ : SHPT_ARC;
422 4 : break;
423 : }
424 : case wkbPolygon:
425 : case wkbMultiPolygon:
426 : {
427 14 : nGType = b3d ? SHPT_POLYGONZ : SHPT_POLYGON;
428 14 : break;
429 : }
430 : default:
431 : {
432 0 : return OGRERR_UNSUPPORTED_OPERATION;
433 : }
434 : }
435 : /* Write in the type number and advance the pointer */
436 22 : nGType = CPL_LSBWORD32( nGType );
437 22 : memcpy( pabyPtr, &nGType, 4 );
438 22 : pabyPtr += 4;
439 :
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* POINT and POINTZ */
443 : /* -------------------------------------------------------------------- */
444 22 : if ( nOGRType == wkbPoint )
445 : {
446 2 : OGRPoint *poPoint = (OGRPoint*)poGeom;
447 2 : double x = poPoint->getX();
448 2 : double y = poPoint->getY();
449 :
450 : /* Copy in the raw data. */
451 2 : memcpy( pabyPtr, &x, 8 );
452 2 : memcpy( pabyPtr+8, &y, 8 );
453 2 : if( b3d )
454 : {
455 1 : double z = poPoint->getZ();
456 1 : memcpy( pabyPtr+8+8, &z, 8 );
457 : }
458 :
459 : /* Swap if needed. Shape doubles always LSB */
460 : if( OGR_SWAP( wkbNDR ) )
461 : {
462 : CPL_SWAPDOUBLE( pabyPtr );
463 : CPL_SWAPDOUBLE( pabyPtr+8 );
464 : if( b3d )
465 : CPL_SWAPDOUBLE( pabyPtr+8+8 );
466 : }
467 :
468 2 : return OGRERR_NONE;
469 : }
470 :
471 : /* -------------------------------------------------------------------- */
472 : /* All the non-POINT types require an envelope next */
473 : /* -------------------------------------------------------------------- */
474 20 : OGREnvelope3D envelope;
475 20 : poGeom->getEnvelope(&envelope);
476 20 : memcpy( pabyPtr, &(envelope.MinX), 8 );
477 20 : memcpy( pabyPtr+8, &(envelope.MinY), 8 );
478 20 : memcpy( pabyPtr+8+8, &(envelope.MaxX), 8 );
479 20 : memcpy( pabyPtr+8+8+8, &(envelope.MaxY), 8 );
480 :
481 : /* Swap box if needed. Shape doubles are always LSB */
482 : if( OGR_SWAP( wkbNDR ) )
483 : {
484 : for ( int i = 0; i < 4; i++ )
485 : CPL_SWAPDOUBLE( pabyPtr + 8*i );
486 : }
487 20 : pabyPtr += 32;
488 :
489 : /* Write in the Z bounds at the end of the XY buffer */
490 20 : if ( b3d )
491 : {
492 5 : memcpy( pabyPtrZ, &(envelope.MinZ), 8 );
493 5 : memcpy( pabyPtrZ+8, &(envelope.MaxZ), 8 );
494 :
495 : /* Swap Z bounds if necessary */
496 : if( OGR_SWAP( wkbNDR ) )
497 : {
498 : for ( int i = 0; i < 2; i++ )
499 : CPL_SWAPDOUBLE( pabyPtrZ + 8*i );
500 : }
501 5 : pabyPtrZ += 16;
502 : }
503 :
504 : /* -------------------------------------------------------------------- */
505 : /* LINESTRING and LINESTRINGZ */
506 : /* -------------------------------------------------------------------- */
507 20 : if ( nOGRType == wkbLineString )
508 : {
509 2 : const OGRLineString *poLine = (OGRLineString*)poGeom;
510 :
511 : /* Write in the nparts (1) */
512 2 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
513 2 : memcpy( pabyPtr, &nPartsLsb, 4 );
514 2 : pabyPtr += 4;
515 :
516 : /* Write in the npoints */
517 2 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
518 2 : memcpy( pabyPtr, &nPointsLsb, 4 );
519 2 : pabyPtr += 4;
520 :
521 : /* Write in the part index (0) */
522 2 : GUInt32 nPartIndex = 0;
523 2 : memcpy( pabyPtr, &nPartIndex, 4 );
524 2 : pabyPtr += 4;
525 :
526 : /* Write in the point data */
527 2 : poLine->getPoints((OGRRawPoint*)pabyPtr, (double*)pabyPtrZ);
528 :
529 : /* Swap if necessary */
530 : if( OGR_SWAP( wkbNDR ) )
531 : {
532 : for( GUInt32 k = 0; k < nPoints; k++ )
533 : {
534 : CPL_SWAPDOUBLE( pabyPtr + 16*k );
535 : CPL_SWAPDOUBLE( pabyPtr + 16*k + 8 );
536 : if( b3d )
537 : CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
538 : }
539 : }
540 2 : return OGRERR_NONE;
541 :
542 : }
543 : /* -------------------------------------------------------------------- */
544 : /* POLYGON and POLYGONZ */
545 : /* -------------------------------------------------------------------- */
546 18 : else if ( nOGRType == wkbPolygon )
547 : {
548 2 : OGRPolygon *poPoly = (OGRPolygon*)poGeom;
549 :
550 : /* Write in the part count */
551 2 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
552 2 : memcpy( pabyPtr, &nPartsLsb, 4 );
553 2 : pabyPtr += 4;
554 :
555 : /* Write in the total point count */
556 2 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
557 2 : memcpy( pabyPtr, &nPointsLsb, 4 );
558 2 : pabyPtr += 4;
559 :
560 : /* -------------------------------------------------------------------- */
561 : /* Now we have to visit each ring and write an index number into */
562 : /* the parts list, and the coordinates into the points list. */
563 : /* to do it in one pass, we will use three write pointers. */
564 : /* pabyPtr writes the part indexes */
565 : /* pabyPoints writes the xy coordinates */
566 : /* pabyPtrZ writes the z coordinates */
567 : /* -------------------------------------------------------------------- */
568 :
569 : /* Just past the partindex[nparts] array */
570 2 : unsigned char* pabyPoints = pabyPtr + 4*nParts;
571 :
572 2 : int nPointIndexCount = 0;
573 :
574 4 : for( GUInt32 i = 0; i < nParts; i++ )
575 : {
576 : /* Check our Ring and condition it */
577 : OGRLinearRing *poRing;
578 2 : if ( i == 0 )
579 : {
580 2 : poRing = poPoly->getExteriorRing();
581 : /* Outer ring must be clockwise */
582 2 : if ( ! poRing->isClockwise() )
583 0 : poRing->reverseWindingOrder();
584 : }
585 : else
586 : {
587 0 : poRing = poPoly->getInteriorRing(i-1);
588 : /* Inner rings should be anti-clockwise */
589 0 : if ( poRing->isClockwise() )
590 0 : poRing->reverseWindingOrder();
591 : }
592 :
593 2 : int nRingNumPoints = poRing->getNumPoints();
594 :
595 : /* Cannot write un-closed rings to shape */
596 2 : if( nRingNumPoints <= 2 || ! poRing->get_IsClosed() )
597 0 : return OGRERR_FAILURE;
598 :
599 : /* Write in the part index */
600 2 : GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
601 2 : memcpy( pabyPtr, &nPartIndex, 4 );
602 :
603 : /* Write in the point data */
604 2 : poRing->getPoints((OGRRawPoint*)pabyPoints, (double*)pabyPtrZ);
605 :
606 : /* Swap if necessary */
607 : if( OGR_SWAP( wkbNDR ) )
608 : {
609 : for( int k = 0; k < nRingNumPoints; k++ )
610 : {
611 : CPL_SWAPDOUBLE( pabyPoints + 16*k );
612 : CPL_SWAPDOUBLE( pabyPoints + 16*k + 8 );
613 : if( b3d )
614 : CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
615 : }
616 : }
617 :
618 2 : nPointIndexCount += nRingNumPoints;
619 : /* Advance the write pointers */
620 2 : pabyPtr += 4;
621 2 : pabyPoints += 16 * nRingNumPoints;
622 2 : if ( b3d )
623 1 : pabyPtrZ += 8 * nRingNumPoints;
624 : }
625 :
626 2 : return OGRERR_NONE;
627 :
628 : }
629 : /* -------------------------------------------------------------------- */
630 : /* MULTIPOINT and MULTIPOINTZ */
631 : /* -------------------------------------------------------------------- */
632 16 : else if ( nOGRType == wkbMultiPoint )
633 : {
634 2 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
635 :
636 : /* Write in the total point count */
637 2 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
638 2 : memcpy( pabyPtr, &nPointsLsb, 4 );
639 2 : pabyPtr += 4;
640 :
641 : /* -------------------------------------------------------------------- */
642 : /* Now we have to visit each point write it into the points list */
643 : /* We will use two write pointers. */
644 : /* pabyPtr writes the xy coordinates */
645 : /* pabyPtrZ writes the z coordinates */
646 : /* -------------------------------------------------------------------- */
647 :
648 6 : for( GUInt32 i = 0; i < nPoints; i++ )
649 : {
650 4 : const OGRPoint *poPt = (OGRPoint*)(poMPoint->getGeometryRef(i));
651 :
652 : /* Skip empties */
653 4 : if ( poPt->IsEmpty() )
654 0 : continue;
655 :
656 : /* Write the coordinates */
657 4 : double x = poPt->getX();
658 4 : double y = poPt->getY();
659 4 : memcpy(pabyPtr, &x, 8);
660 4 : memcpy(pabyPtr+8, &y, 8);
661 4 : if ( b3d )
662 : {
663 2 : double z = poPt->getZ();
664 2 : memcpy(pabyPtrZ, &z, 8);
665 : }
666 :
667 : /* Swap if necessary */
668 : if( OGR_SWAP( wkbNDR ) )
669 : {
670 : CPL_SWAPDOUBLE( pabyPtr );
671 : CPL_SWAPDOUBLE( pabyPtr + 8 );
672 : if( b3d )
673 : CPL_SWAPDOUBLE( pabyPtrZ );
674 : }
675 :
676 : /* Advance the write pointers */
677 4 : pabyPtr += 16;
678 4 : if ( b3d )
679 2 : pabyPtrZ += 8;
680 : }
681 :
682 2 : return OGRERR_NONE;
683 : }
684 :
685 : /* -------------------------------------------------------------------- */
686 : /* MULTILINESTRING and MULTILINESTRINGZ */
687 : /* -------------------------------------------------------------------- */
688 14 : else if ( nOGRType == wkbMultiLineString )
689 : {
690 2 : OGRMultiLineString *poMLine = (OGRMultiLineString*)poGeom;
691 :
692 : /* Write in the part count */
693 2 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
694 2 : memcpy( pabyPtr, &nPartsLsb, 4 );
695 2 : pabyPtr += 4;
696 :
697 : /* Write in the total point count */
698 2 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
699 2 : memcpy( pabyPtr, &nPointsLsb, 4 );
700 2 : pabyPtr += 4;
701 :
702 : /* Just past the partindex[nparts] array */
703 2 : unsigned char* pabyPoints = pabyPtr + 4*nParts;
704 :
705 2 : int nPointIndexCount = 0;
706 :
707 4 : for( GUInt32 i = 0; i < nParts; i++ )
708 : {
709 2 : const OGRLineString *poLine = (OGRLineString*)(poMLine->getGeometryRef(i));
710 :
711 : /* Skip empties */
712 2 : if ( poLine->IsEmpty() )
713 0 : continue;
714 :
715 2 : int nLineNumPoints = poLine->getNumPoints();
716 :
717 : /* Write in the part index */
718 2 : GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
719 2 : memcpy( pabyPtr, &nPartIndex, 4 );
720 :
721 : /* Write in the point data */
722 2 : poLine->getPoints((OGRRawPoint*)pabyPoints, (double*)pabyPtrZ);
723 :
724 : /* Swap if necessary */
725 : if( OGR_SWAP( wkbNDR ) )
726 : {
727 : for( int k = 0; k < nLineNumPoints; k++ )
728 : {
729 : CPL_SWAPDOUBLE( pabyPoints + 16*k );
730 : CPL_SWAPDOUBLE( pabyPoints + 16*k + 8 );
731 : if( b3d )
732 : CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
733 : }
734 : }
735 :
736 2 : nPointIndexCount += nLineNumPoints;
737 :
738 : /* Advance the write pointers */
739 2 : pabyPtr += 4;
740 2 : pabyPoints += 16 * nLineNumPoints;
741 2 : if ( b3d )
742 1 : pabyPtrZ += 8 * nLineNumPoints;
743 : }
744 :
745 2 : return OGRERR_NONE;
746 :
747 : }
748 : /* -------------------------------------------------------------------- */
749 : /* MULTIPOLYGON and MULTIPOLYGONZ */
750 : /* -------------------------------------------------------------------- */
751 12 : else if ( nOGRType == wkbMultiPolygon )
752 : {
753 12 : OGRMultiPolygon *poMPoly = (OGRMultiPolygon*)poGeom;
754 :
755 : /* Write in the part count */
756 12 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
757 12 : memcpy( pabyPtr, &nPartsLsb, 4 );
758 12 : pabyPtr += 4;
759 :
760 : /* Write in the total point count */
761 12 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
762 12 : memcpy( pabyPtr, &nPointsLsb, 4 );
763 12 : pabyPtr += 4;
764 :
765 : /* -------------------------------------------------------------------- */
766 : /* Now we have to visit each ring and write an index number into */
767 : /* the parts list, and the coordinates into the points list. */
768 : /* to do it in one pass, we will use three write pointers. */
769 : /* pabyPtr writes the part indexes */
770 : /* pabyPoints writes the xy coordinates */
771 : /* pabyPtrZ writes the z coordinates */
772 : /* -------------------------------------------------------------------- */
773 :
774 : /* Just past the partindex[nparts] array */
775 12 : unsigned char* pabyPoints = pabyPtr + 4*nParts;
776 :
777 12 : int nPointIndexCount = 0;
778 :
779 24 : for( int i = 0; i < poMPoly->getNumGeometries(); i++ )
780 : {
781 12 : OGRPolygon *poPoly = (OGRPolygon*)(poMPoly->getGeometryRef(i));
782 :
783 : /* Skip empties */
784 12 : if ( poPoly->IsEmpty() )
785 0 : continue;
786 :
787 12 : int nRings = 1 + poPoly->getNumInteriorRings();
788 :
789 24 : for( int j = 0; j < nRings; j++ )
790 : {
791 : /* Check our Ring and condition it */
792 : OGRLinearRing *poRing;
793 12 : if ( j == 0 )
794 : {
795 12 : poRing = poPoly->getExteriorRing();
796 : /* Outer ring must be clockwise */
797 12 : if ( ! poRing->isClockwise() )
798 0 : poRing->reverseWindingOrder();
799 : }
800 : else
801 : {
802 0 : poRing = poPoly->getInteriorRing(j-1);
803 : /* Inner rings should be anti-clockwise */
804 0 : if ( poRing->isClockwise() )
805 0 : poRing->reverseWindingOrder();
806 : }
807 :
808 12 : int nRingNumPoints = poRing->getNumPoints();
809 :
810 : /* Cannot write closed rings to shape */
811 12 : if( nRingNumPoints <= 2 || ! poRing->get_IsClosed() )
812 0 : return OGRERR_FAILURE;
813 :
814 : /* Write in the part index */
815 12 : GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
816 12 : memcpy( pabyPtr, &nPartIndex, 4 );
817 :
818 : /* Write in the point data */
819 12 : poRing->getPoints((OGRRawPoint*)pabyPoints, (double*)pabyPtrZ);
820 :
821 : /* Swap if necessary */
822 : if( OGR_SWAP( wkbNDR ) )
823 : {
824 : for( int k = 0; k < nRingNumPoints; k++ )
825 : {
826 : CPL_SWAPDOUBLE( pabyPoints + 16*k );
827 : CPL_SWAPDOUBLE( pabyPoints + 16*k + 8 );
828 : if( b3d )
829 : CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
830 : }
831 : }
832 :
833 12 : nPointIndexCount += nRingNumPoints;
834 : /* Advance the write pointers */
835 12 : pabyPtr += 4;
836 12 : pabyPoints += 16 * nRingNumPoints;
837 12 : if ( b3d )
838 1 : pabyPtrZ += 8 * nRingNumPoints;
839 : }
840 : }
841 :
842 12 : return OGRERR_NONE;
843 :
844 : }
845 : else
846 : {
847 0 : return OGRERR_UNSUPPORTED_OPERATION;
848 : }
849 :
850 : }
851 :
852 :
853 : /************************************************************************/
854 : /* OGRCreateFromShapeBin() */
855 : /* */
856 : /* Translate shapefile binary representation to an OGR */
857 : /* geometry. */
858 : /************************************************************************/
859 :
860 207660 : OGRErr OGRCreateFromShapeBin( GByte *pabyShape,
861 : OGRGeometry **ppoGeom,
862 : int nBytes )
863 :
864 : {
865 207660 : *ppoGeom = NULL;
866 :
867 207660 : if( nBytes < 4 )
868 : {
869 : CPLError(CE_Failure, CPLE_AppDefined,
870 : "Shape buffer size (%d) too small",
871 0 : nBytes);
872 0 : return OGRERR_FAILURE;
873 : }
874 :
875 : /* -------------------------------------------------------------------- */
876 : /* Detect zlib compressed shapes and uncompress buffer if necessary */
877 : /* NOTE: this seems to be an undocumented feature, even in the */
878 : /* extended_shapefile_format.pdf found in the FileGDB API documentation*/
879 : /* -------------------------------------------------------------------- */
880 415320 : if( nBytes >= 14 &&
881 207660 : pabyShape[12] == 0x78 && pabyShape[13] == 0xDA /* zlib marker */)
882 : {
883 : GInt32 nUncompressedSize, nCompressedSize;
884 0 : memcpy( &nUncompressedSize, pabyShape + 4, 4 );
885 0 : memcpy( &nCompressedSize, pabyShape + 8, 4 );
886 : CPL_LSBPTR32( &nUncompressedSize );
887 : CPL_LSBPTR32( &nCompressedSize );
888 0 : if (nCompressedSize + 12 == nBytes &&
889 : nUncompressedSize > 0)
890 : {
891 0 : GByte* pabyUncompressedBuffer = (GByte*)VSIMalloc(nUncompressedSize);
892 0 : if (pabyUncompressedBuffer == NULL)
893 : {
894 : CPLError(CE_Failure, CPLE_OutOfMemory,
895 : "Cannot allocate %d bytes to uncompress zlib buffer",
896 0 : nUncompressedSize);
897 0 : return OGRERR_FAILURE;
898 : }
899 :
900 : z_stream stream;
901 0 : stream.zalloc = (alloc_func)0;
902 0 : stream.zfree = (free_func)0;
903 0 : stream.opaque = (voidpf)0;
904 0 : stream.next_in = pabyShape + 12;
905 0 : stream.next_out = pabyUncompressedBuffer;
906 0 : stream.avail_in = nCompressedSize;
907 0 : stream.avail_out = nUncompressedSize;
908 : int err;
909 0 : if ( (err = inflateInit(&stream)) != Z_OK )
910 : {
911 : CPLError(CE_Failure, CPLE_AppDefined,
912 0 : "inflateInit() failed : err code = %d", err);
913 0 : VSIFree(pabyUncompressedBuffer);
914 0 : return OGRERR_FAILURE;
915 : }
916 0 : if ( (err = inflate(&stream, Z_NO_FLUSH)) != Z_STREAM_END )
917 : {
918 : CPLError(CE_Failure, CPLE_AppDefined,
919 0 : "inflate() failed : err code = %d", err);
920 0 : VSIFree(pabyUncompressedBuffer);
921 0 : inflateEnd(&stream);
922 0 : return OGRERR_FAILURE;
923 : }
924 0 : if (stream.avail_in != 0)
925 : {
926 : CPLDebug("OGR", "%d remaining in bytes after zlib uncompression",
927 0 : stream.avail_in);
928 : }
929 0 : if (stream.avail_out != 0)
930 : {
931 : CPLDebug("OGR", "%d remaining out bytes after zlib uncompression",
932 0 : stream.avail_out);
933 : }
934 :
935 0 : inflateEnd(&stream);
936 :
937 : OGRErr eErr = OGRCreateFromShapeBin(pabyUncompressedBuffer,
938 : ppoGeom,
939 0 : nUncompressedSize - stream.avail_out);
940 :
941 0 : VSIFree(pabyUncompressedBuffer);
942 :
943 0 : return eErr;
944 : }
945 : }
946 :
947 207660 : int nSHPType = pabyShape[0];
948 :
949 : /* -------------------------------------------------------------------- */
950 : /* Return a NULL geometry when SHPT_NULL is encountered. */
951 : /* Watch out, null return does not mean "bad data" it means */
952 : /* "no geometry here". Watch the OGRErr for the error status */
953 : /* -------------------------------------------------------------------- */
954 207660 : if ( nSHPType == SHPT_NULL )
955 : {
956 0 : *ppoGeom = NULL;
957 0 : return OGRERR_NONE;
958 : }
959 :
960 : // CPLDebug( "PGeo",
961 : // "Shape type read from PGeo data is nSHPType = %d",
962 : // nSHPType );
963 :
964 : /* -------------------------------------------------------------------- */
965 : /* TODO: These types include additional attributes including */
966 : /* non-linear segments and such. They should be handled. */
967 : /* This is documented in the extended_shapefile_format.pdf */
968 : /* from the FileGDB API */
969 : /* -------------------------------------------------------------------- */
970 207660 : switch( nSHPType )
971 : {
972 : case SHPT_GENERALPOLYLINE:
973 0 : nSHPType = SHPT_ARC;
974 0 : break;
975 : case SHPT_GENERALPOLYGON:
976 0 : nSHPType = SHPT_POLYGON;
977 0 : break;
978 : case SHPT_GENERALPOINT:
979 0 : nSHPType = SHPT_POINT;
980 0 : break;
981 : case SHPT_GENERALMULTIPOINT:
982 0 : nSHPType = SHPT_MULTIPOINT;
983 0 : break;
984 : case SHPT_GENERALMULTIPATCH:
985 0 : nSHPType = SHPT_MULTIPATCH;
986 : }
987 :
988 : /* ==================================================================== */
989 : /* Extract vertices for a Polygon or Arc. */
990 : /* ==================================================================== */
991 207660 : if( nSHPType == SHPT_ARC
992 : || nSHPType == SHPT_ARCZ
993 : || nSHPType == SHPT_ARCM
994 : || nSHPType == SHPT_ARCZM
995 : || nSHPType == SHPT_POLYGON
996 : || nSHPType == SHPT_POLYGONZ
997 : || nSHPType == SHPT_POLYGONM
998 : || nSHPType == SHPT_POLYGONZM
999 : || nSHPType == SHPT_MULTIPATCH
1000 : || nSHPType == SHPT_MULTIPATCHM)
1001 : {
1002 : GInt32 nPoints, nParts;
1003 : int i, nOffset;
1004 : GInt32 *panPartStart;
1005 207427 : GInt32 *panPartType = NULL;
1006 :
1007 207427 : if (nBytes < 44)
1008 : {
1009 : CPLError(CE_Failure, CPLE_AppDefined,
1010 0 : "Corrupted Shape : nBytes=%d, nSHPType=%d", nBytes, nSHPType);
1011 0 : return OGRERR_FAILURE;
1012 : }
1013 :
1014 : /* -------------------------------------------------------------------- */
1015 : /* Extract part/point count, and build vertex and part arrays */
1016 : /* to proper size. */
1017 : /* -------------------------------------------------------------------- */
1018 207427 : memcpy( &nPoints, pabyShape + 40, 4 );
1019 207427 : memcpy( &nParts, pabyShape + 36, 4 );
1020 :
1021 : CPL_LSBPTR32( &nPoints );
1022 : CPL_LSBPTR32( &nParts );
1023 :
1024 207427 : if (nPoints < 0 || nParts < 0 ||
1025 : nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
1026 : {
1027 : CPLError(CE_Failure, CPLE_AppDefined, "Corrupted Shape : nPoints=%d, nParts=%d.",
1028 0 : nPoints, nParts);
1029 0 : return OGRERR_FAILURE;
1030 : }
1031 :
1032 : int bHasZ = ( nSHPType == SHPT_POLYGONZ
1033 : || nSHPType == SHPT_POLYGONZM
1034 : || nSHPType == SHPT_ARCZ
1035 : || nSHPType == SHPT_ARCZM
1036 : || nSHPType == SHPT_MULTIPATCH
1037 207427 : || nSHPType == SHPT_MULTIPATCHM );
1038 :
1039 207427 : int bIsMultiPatch = ( nSHPType == SHPT_MULTIPATCH || nSHPType == SHPT_MULTIPATCHM );
1040 :
1041 : /* With the previous checks on nPoints and nParts, */
1042 : /* we should not overflow here and after */
1043 : /* since 50 M * (16 + 8 + 8) = 1 600 MB */
1044 207427 : int nRequiredSize = 44 + 4 * nParts + 16 * nPoints;
1045 207427 : if ( bHasZ )
1046 : {
1047 207315 : nRequiredSize += 16 + 8 * nPoints;
1048 : }
1049 207427 : if( bIsMultiPatch )
1050 : {
1051 0 : nRequiredSize += 4 * nParts;
1052 : }
1053 207427 : if (nRequiredSize > nBytes)
1054 : {
1055 : CPLError(CE_Failure, CPLE_AppDefined,
1056 : "Corrupted Shape : nPoints=%d, nParts=%d, nBytes=%d, nSHPType=%d",
1057 0 : nPoints, nParts, nBytes, nSHPType);
1058 0 : return OGRERR_FAILURE;
1059 : }
1060 :
1061 207427 : panPartStart = (GInt32 *) VSICalloc(nParts,sizeof(GInt32));
1062 207427 : if (panPartStart == NULL)
1063 : {
1064 : CPLError(CE_Failure, CPLE_OutOfMemory,
1065 0 : "Not enough memory for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
1066 0 : return OGRERR_FAILURE;
1067 : }
1068 :
1069 : /* -------------------------------------------------------------------- */
1070 : /* Copy out the part array from the record. */
1071 : /* -------------------------------------------------------------------- */
1072 207427 : memcpy( panPartStart, pabyShape + 44, 4 * nParts );
1073 414854 : for( i = 0; i < nParts; i++ )
1074 : {
1075 : CPL_LSBPTR32( panPartStart + i );
1076 :
1077 : /* We check that the offset is inside the vertex array */
1078 414854 : if (panPartStart[i] < 0 ||
1079 207427 : panPartStart[i] >= nPoints)
1080 : {
1081 : CPLError(CE_Failure, CPLE_AppDefined,
1082 : "Corrupted Shape : panPartStart[%d] = %d, nPoints = %d",
1083 0 : i, panPartStart[i], nPoints);
1084 0 : CPLFree(panPartStart);
1085 0 : return OGRERR_FAILURE;
1086 : }
1087 207427 : if (i > 0 && panPartStart[i] <= panPartStart[i-1])
1088 : {
1089 : CPLError(CE_Failure, CPLE_AppDefined,
1090 : "Corrupted Shape : panPartStart[%d] = %d, panPartStart[%d] = %d",
1091 0 : i, panPartStart[i], i - 1, panPartStart[i - 1]);
1092 0 : CPLFree(panPartStart);
1093 0 : return OGRERR_FAILURE;
1094 : }
1095 : }
1096 :
1097 207427 : nOffset = 44 + 4*nParts;
1098 :
1099 : /* -------------------------------------------------------------------- */
1100 : /* If this is a multipatch, we will also have parts types. */
1101 : /* -------------------------------------------------------------------- */
1102 207427 : if( bIsMultiPatch )
1103 : {
1104 0 : panPartType = (GInt32 *) VSICalloc(nParts,sizeof(GInt32));
1105 0 : if (panPartType == NULL)
1106 : {
1107 : CPLError(CE_Failure, CPLE_OutOfMemory,
1108 0 : "Not enough memory for panPartType for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
1109 0 : CPLFree(panPartStart);
1110 0 : return OGRERR_FAILURE;
1111 : }
1112 :
1113 0 : memcpy( panPartType, pabyShape + nOffset, 4*nParts );
1114 0 : for( i = 0; i < nParts; i++ )
1115 : {
1116 : CPL_LSBPTR32( panPartType + i );
1117 : }
1118 0 : nOffset += 4*nParts;
1119 : }
1120 :
1121 : /* -------------------------------------------------------------------- */
1122 : /* Copy out the vertices from the record. */
1123 : /* -------------------------------------------------------------------- */
1124 207427 : double *padfX = (double *) VSIMalloc(sizeof(double)*nPoints);
1125 207427 : double *padfY = (double *) VSIMalloc(sizeof(double)*nPoints);
1126 207427 : double *padfZ = (double *) VSICalloc(sizeof(double),nPoints);
1127 207427 : if (padfX == NULL || padfY == NULL || padfZ == NULL)
1128 : {
1129 0 : CPLFree( panPartStart );
1130 0 : CPLFree( panPartType );
1131 0 : CPLFree( padfX );
1132 0 : CPLFree( padfY );
1133 0 : CPLFree( padfZ );
1134 : CPLError(CE_Failure, CPLE_OutOfMemory,
1135 0 : "Not enough memory for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
1136 0 : return OGRERR_FAILURE;
1137 : }
1138 :
1139 1000861 : for( i = 0; i < nPoints; i++ )
1140 : {
1141 793434 : memcpy(padfX + i, pabyShape + nOffset + i * 16, 8 );
1142 793434 : memcpy(padfY + i, pabyShape + nOffset + i * 16 + 8, 8 );
1143 : CPL_LSBPTR64( padfX + i );
1144 : CPL_LSBPTR64( padfY + i );
1145 : }
1146 :
1147 207427 : nOffset += 16*nPoints;
1148 :
1149 : /* -------------------------------------------------------------------- */
1150 : /* If we have a Z coordinate, collect that now. */
1151 : /* -------------------------------------------------------------------- */
1152 207427 : if( bHasZ )
1153 : {
1154 998796 : for( i = 0; i < nPoints; i++ )
1155 : {
1156 791481 : memcpy( padfZ + i, pabyShape + nOffset + 16 + i*8, 8 );
1157 : CPL_LSBPTR64( padfZ + i );
1158 : }
1159 :
1160 207315 : nOffset += 16 + 8*nPoints;
1161 : }
1162 :
1163 : /* -------------------------------------------------------------------- */
1164 : /* Build corresponding OGR objects. */
1165 : /* -------------------------------------------------------------------- */
1166 414680 : if( nSHPType == SHPT_ARC
1167 : || nSHPType == SHPT_ARCZ
1168 : || nSHPType == SHPT_ARCM
1169 : || nSHPType == SHPT_ARCZM )
1170 : {
1171 : /* -------------------------------------------------------------------- */
1172 : /* Arc - As LineString */
1173 : /* -------------------------------------------------------------------- */
1174 207253 : if( nParts == 1 )
1175 : {
1176 207253 : OGRLineString *poLine = new OGRLineString();
1177 207253 : *ppoGeom = poLine;
1178 :
1179 207253 : poLine->setPoints( nPoints, padfX, padfY, padfZ );
1180 : }
1181 :
1182 : /* -------------------------------------------------------------------- */
1183 : /* Arc - As MultiLineString */
1184 : /* -------------------------------------------------------------------- */
1185 : else
1186 : {
1187 0 : OGRMultiLineString *poMulti = new OGRMultiLineString;
1188 0 : *ppoGeom = poMulti;
1189 :
1190 0 : for( i = 0; i < nParts; i++ )
1191 : {
1192 0 : OGRLineString *poLine = new OGRLineString;
1193 : int nVerticesInThisPart;
1194 :
1195 0 : if( i == nParts-1 )
1196 0 : nVerticesInThisPart = nPoints - panPartStart[i];
1197 : else
1198 : nVerticesInThisPart =
1199 0 : panPartStart[i+1] - panPartStart[i];
1200 :
1201 : poLine->setPoints( nVerticesInThisPart,
1202 0 : padfX + panPartStart[i],
1203 0 : padfY + panPartStart[i],
1204 0 : padfZ + panPartStart[i] );
1205 :
1206 0 : poMulti->addGeometryDirectly( poLine );
1207 : }
1208 : }
1209 : } /* ARC */
1210 :
1211 : /* -------------------------------------------------------------------- */
1212 : /* Polygon */
1213 : /* -------------------------------------------------------------------- */
1214 348 : else if( nSHPType == SHPT_POLYGON
1215 : || nSHPType == SHPT_POLYGONZ
1216 : || nSHPType == SHPT_POLYGONM
1217 : || nSHPType == SHPT_POLYGONZM )
1218 : {
1219 174 : if (nParts != 0)
1220 : {
1221 174 : if (nParts == 1)
1222 : {
1223 174 : OGRPolygon *poOGRPoly = new OGRPolygon;
1224 174 : *ppoGeom = poOGRPoly;
1225 348 : OGRLinearRing *poRing = new OGRLinearRing;
1226 174 : int nVerticesInThisPart = nPoints - panPartStart[0];
1227 :
1228 : poRing->setPoints( nVerticesInThisPart,
1229 174 : padfX + panPartStart[0],
1230 174 : padfY + panPartStart[0],
1231 522 : padfZ + panPartStart[0] );
1232 :
1233 174 : poOGRPoly->addRingDirectly( poRing );
1234 : }
1235 : else
1236 : {
1237 0 : OGRGeometry *poOGR = NULL;
1238 0 : OGRPolygon** tabPolygons = new OGRPolygon*[nParts];
1239 :
1240 0 : for( i = 0; i < nParts; i++ )
1241 : {
1242 0 : tabPolygons[i] = new OGRPolygon();
1243 0 : OGRLinearRing *poRing = new OGRLinearRing;
1244 : int nVerticesInThisPart;
1245 :
1246 0 : if( i == nParts-1 )
1247 0 : nVerticesInThisPart = nPoints - panPartStart[i];
1248 : else
1249 : nVerticesInThisPart =
1250 0 : panPartStart[i+1] - panPartStart[i];
1251 :
1252 : poRing->setPoints( nVerticesInThisPart,
1253 0 : padfX + panPartStart[i],
1254 0 : padfY + panPartStart[i],
1255 0 : padfZ + panPartStart[i] );
1256 0 : tabPolygons[i]->addRingDirectly(poRing);
1257 : }
1258 :
1259 : int isValidGeometry;
1260 0 : const char* papszOptions[] = { "METHOD=ONLY_CCW", NULL };
1261 : poOGR = OGRGeometryFactory::organizePolygons(
1262 0 : (OGRGeometry**)tabPolygons, nParts, &isValidGeometry, papszOptions );
1263 :
1264 0 : if (!isValidGeometry)
1265 : {
1266 : CPLError(CE_Warning, CPLE_AppDefined,
1267 : "Geometry of polygon cannot be translated to Simple Geometry. "
1268 0 : "All polygons will be contained in a multipolygon.\n");
1269 : }
1270 :
1271 0 : *ppoGeom = poOGR;
1272 0 : delete[] tabPolygons;
1273 : }
1274 : }
1275 : } /* polygon */
1276 :
1277 : /* -------------------------------------------------------------------- */
1278 : /* Multipatch */
1279 : /* -------------------------------------------------------------------- */
1280 0 : else if( bIsMultiPatch )
1281 : {
1282 : *ppoGeom = OGRCreateFromMultiPatch( nParts,
1283 : panPartStart,
1284 : panPartType,
1285 : nPoints,
1286 : padfX,
1287 : padfY,
1288 0 : padfZ );
1289 : }
1290 :
1291 207427 : CPLFree( panPartStart );
1292 207427 : CPLFree( panPartType );
1293 207427 : CPLFree( padfX );
1294 207427 : CPLFree( padfY );
1295 207427 : CPLFree( padfZ );
1296 :
1297 207427 : (*ppoGeom)->setCoordinateDimension( bHasZ ? 3 : 2 );
1298 :
1299 207427 : return OGRERR_NONE;
1300 : }
1301 :
1302 : /* ==================================================================== */
1303 : /* Extract vertices for a MultiPoint. */
1304 : /* ==================================================================== */
1305 233 : else if( nSHPType == SHPT_MULTIPOINT
1306 : || nSHPType == SHPT_MULTIPOINTM
1307 : || nSHPType == SHPT_MULTIPOINTZ
1308 : || nSHPType == SHPT_MULTIPOINTZM )
1309 : {
1310 : GInt32 nPoints;
1311 : GInt32 nOffsetZ;
1312 : int i;
1313 :
1314 : int bHasZ = ( nSHPType == SHPT_MULTIPOINTZ
1315 20 : || nSHPType == SHPT_MULTIPOINTZM );
1316 :
1317 :
1318 20 : memcpy( &nPoints, pabyShape + 36, 4 );
1319 : CPL_LSBPTR32( &nPoints );
1320 :
1321 20 : if (nPoints < 0 || nPoints > 50 * 1000 * 1000 )
1322 : {
1323 : CPLError(CE_Failure, CPLE_AppDefined, "Corrupted Shape : nPoints=%d.",
1324 0 : nPoints);
1325 0 : return OGRERR_FAILURE;
1326 : }
1327 :
1328 20 : nOffsetZ = 40 + 2*8*nPoints + 2*8;
1329 :
1330 20 : OGRMultiPoint *poMultiPt = new OGRMultiPoint;
1331 20 : *ppoGeom = poMultiPt;
1332 :
1333 60 : for( i = 0; i < nPoints; i++ )
1334 : {
1335 : double x, y, z;
1336 40 : OGRPoint *poPt = new OGRPoint;
1337 :
1338 : /* Copy X */
1339 40 : memcpy(&x, pabyShape + 40 + i*16, 8);
1340 : CPL_LSBPTR64(&x);
1341 40 : poPt->setX(x);
1342 :
1343 : /* Copy Y */
1344 40 : memcpy(&y, pabyShape + 40 + i*16 + 8, 8);
1345 : CPL_LSBPTR64(&y);
1346 40 : poPt->setY(y);
1347 :
1348 : /* Copy Z */
1349 40 : if ( bHasZ )
1350 : {
1351 20 : memcpy(&z, pabyShape + nOffsetZ + i*8, 8);
1352 : CPL_LSBPTR64(&z);
1353 20 : poPt->setZ(z);
1354 : }
1355 :
1356 40 : poMultiPt->addGeometryDirectly( poPt );
1357 : }
1358 :
1359 20 : poMultiPt->setCoordinateDimension( bHasZ ? 3 : 2 );
1360 :
1361 20 : return OGRERR_NONE;
1362 : }
1363 :
1364 : /* ==================================================================== */
1365 : /* Extract vertices for a point. */
1366 : /* ==================================================================== */
1367 213 : else if( nSHPType == SHPT_POINT
1368 : || nSHPType == SHPT_POINTM
1369 : || nSHPType == SHPT_POINTZ
1370 : || nSHPType == SHPT_POINTZM )
1371 : {
1372 : int nOffset;
1373 213 : double dfX, dfY, dfZ = 0;
1374 :
1375 213 : int bHasZ = (nSHPType == SHPT_POINTZ || nSHPType == SHPT_POINTZM);
1376 :
1377 213 : if (nBytes < 4 + 8 + 8 + ((bHasZ) ? 8 : 0))
1378 : {
1379 : CPLError(CE_Failure, CPLE_AppDefined,
1380 0 : "Corrupted Shape : nBytes=%d, nSHPType=%d", nBytes, nSHPType);
1381 0 : return OGRERR_FAILURE;
1382 : }
1383 :
1384 213 : memcpy( &dfX, pabyShape + 4, 8 );
1385 213 : memcpy( &dfY, pabyShape + 4 + 8, 8 );
1386 :
1387 : CPL_LSBPTR64( &dfX );
1388 : CPL_LSBPTR64( &dfY );
1389 213 : nOffset = 20 + 8;
1390 :
1391 213 : if( bHasZ )
1392 : {
1393 203 : memcpy( &dfZ, pabyShape + 4 + 16, 8 );
1394 : CPL_LSBPTR64( &dfZ );
1395 : }
1396 :
1397 213 : *ppoGeom = new OGRPoint( dfX, dfY, dfZ );
1398 416 : (*ppoGeom)->setCoordinateDimension( bHasZ ? 3 : 2 );
1399 :
1400 213 : return OGRERR_NONE;
1401 : }
1402 :
1403 : CPLError(CE_Failure, CPLE_AppDefined,
1404 : "Unsupported geometry type: %d",
1405 0 : nSHPType );
1406 :
1407 0 : return OGRERR_FAILURE;
1408 : }
|