1 : /******************************************************************************
2 : * $Id: ogrpgeogeometry.cpp 23752 2012-01-13 00:34:09Z 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 23752 2012-01-13 00:34:09Z 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 1135 : OGRErr OGRWriteToShapeBin( OGRGeometry *poGeom,
254 : GByte **ppabyShape,
255 : int *pnBytes )
256 : {
257 1135 : GUInt32 nGType = SHPT_NULL;
258 1135 : int nShpSize = 4; /* All types start with integer type number */
259 1135 : int nShpZSize = 0; /* Z gets tacked onto the end */
260 1135 : GUInt32 nPoints = 0;
261 1135 : GUInt32 nParts = 0;
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* Null or Empty input maps to SHPT_NULL. */
265 : /* -------------------------------------------------------------------- */
266 1135 : 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 1135 : OGRwkbGeometryType nOGRType = wkbFlatten(poGeom->getGeometryType());
276 1135 : int b3d = (poGeom->getGeometryType() & wkb25DBit);
277 1135 : int nCoordDims = b3d ? 3 : 2;
278 :
279 : /* -------------------------------------------------------------------- */
280 : /* Calculate the shape buffer size */
281 : /* -------------------------------------------------------------------- */
282 1135 : if ( nOGRType == wkbPoint )
283 : {
284 1020 : nShpSize += 8 * nCoordDims;
285 : }
286 115 : else if ( nOGRType == wkbLineString )
287 : {
288 10 : OGRLineString *poLine = (OGRLineString*)poGeom;
289 10 : nPoints = poLine->getNumPoints();
290 10 : nParts = 1;
291 10 : nShpSize += 16 * nCoordDims; /* xy(z) box */
292 10 : nShpSize += 4; /* nparts */
293 10 : nShpSize += 4; /* npoints */
294 10 : nShpSize += 4; /* parts[1] */
295 10 : nShpSize += 8 * nCoordDims * nPoints; /* points */
296 10 : nShpZSize = 16 + 8 * nPoints;
297 : }
298 105 : else if ( nOGRType == wkbPolygon )
299 : {
300 10 : poGeom->closeRings();
301 10 : OGRPolygon *poPoly = (OGRPolygon*)poGeom;
302 10 : nParts = poPoly->getNumInteriorRings() + 1;
303 20 : for ( GUInt32 i = 0; i < nParts; i++ )
304 : {
305 : OGRLinearRing *poRing;
306 10 : if ( i == 0 )
307 10 : poRing = poPoly->getExteriorRing();
308 : else
309 0 : poRing = poPoly->getInteriorRing(i-1);
310 10 : nPoints += poRing->getNumPoints();
311 : }
312 10 : nShpSize += 16 * nCoordDims; /* xy(z) box */
313 10 : nShpSize += 4; /* nparts */
314 10 : nShpSize += 4; /* npoints */
315 10 : nShpSize += 4 * nParts; /* parts[nparts] */
316 10 : nShpSize += 8 * nCoordDims * nPoints; /* points */
317 10 : nShpZSize = 16 + 8 * nPoints;
318 : }
319 95 : else if ( nOGRType == wkbMultiPoint )
320 : {
321 20 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
322 60 : for ( int i = 0; i < poMPoint->getNumGeometries(); i++ )
323 : {
324 40 : OGRPoint *poPoint = (OGRPoint*)(poMPoint->getGeometryRef(i));
325 40 : if ( poPoint->IsEmpty() )
326 0 : continue;
327 40 : nPoints++;
328 : }
329 20 : nShpSize += 16 * nCoordDims; /* xy(z) box */
330 20 : nShpSize += 4; /* npoints */
331 20 : nShpSize += 8 * nCoordDims * nPoints; /* points */
332 20 : nShpZSize = 16 + 8 * nPoints;
333 : }
334 75 : else if ( nOGRType == wkbMultiLineString )
335 : {
336 30 : OGRMultiLineString *poMLine = (OGRMultiLineString*)poGeom;
337 60 : for ( int i = 0; i < poMLine->getNumGeometries(); i++ )
338 : {
339 30 : OGRLineString *poLine = (OGRLineString*)(poMLine->getGeometryRef(i));
340 : /* Skip empties */
341 30 : if ( poLine->IsEmpty() )
342 0 : continue;
343 30 : nParts++;
344 30 : nPoints += poLine->getNumPoints();
345 : }
346 30 : nShpSize += 16 * nCoordDims; /* xy(z) box */
347 30 : nShpSize += 4; /* nparts */
348 30 : nShpSize += 4; /* npoints */
349 30 : nShpSize += 4 * nParts; /* parts[nparts] */
350 30 : nShpSize += 8 * nCoordDims * nPoints ; /* points */
351 30 : nShpZSize = 16 + 8 * nPoints;
352 : }
353 45 : else if ( nOGRType == wkbMultiPolygon )
354 : {
355 45 : poGeom->closeRings();
356 45 : OGRMultiPolygon *poMPoly = (OGRMultiPolygon*)poGeom;
357 90 : for( int j = 0; j < poMPoly->getNumGeometries(); j++ )
358 : {
359 45 : OGRPolygon *poPoly = (OGRPolygon*)(poMPoly->getGeometryRef(j));
360 45 : int nRings = poPoly->getNumInteriorRings() + 1;
361 :
362 : /* Skip empties */
363 45 : if ( poPoly->IsEmpty() )
364 0 : continue;
365 :
366 45 : nParts += nRings;
367 90 : for ( int i = 0; i < nRings; i++ )
368 : {
369 : OGRLinearRing *poRing;
370 45 : if ( i == 0 )
371 45 : poRing = poPoly->getExteriorRing();
372 : else
373 0 : poRing = poPoly->getInteriorRing(i-1);
374 45 : nPoints += poRing->getNumPoints();
375 : }
376 : }
377 45 : nShpSize += 16 * nCoordDims; /* xy(z) box */
378 45 : nShpSize += 4; /* nparts */
379 45 : nShpSize += 4; /* npoints */
380 45 : nShpSize += 4 * nParts; /* parts[nparts] */
381 45 : nShpSize += 8 * nCoordDims * nPoints ; /* points */
382 45 : nShpZSize = 16 + 8 * nPoints;
383 : }
384 : else
385 : {
386 0 : return OGRERR_UNSUPPORTED_OPERATION;
387 : }
388 :
389 : /* Allocate our shape buffer */
390 1135 : *ppabyShape = (GByte*)VSIMalloc(nShpSize);
391 1135 : if ( ! *ppabyShape )
392 0 : return OGRERR_FAILURE;
393 :
394 : /* Fill in the output size. */
395 1135 : *pnBytes = nShpSize;
396 :
397 : /* Set up write pointers */
398 1135 : unsigned char *pabyPtr = *ppabyShape;
399 1135 : unsigned char *pabyPtrZ = NULL;
400 1135 : if ( b3d )
401 60 : pabyPtrZ = pabyPtr + nShpSize - nShpZSize;
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Write in the Shape type number now */
405 : /* -------------------------------------------------------------------- */
406 1135 : switch(nOGRType)
407 : {
408 : case wkbPoint:
409 : {
410 1020 : nGType = b3d ? SHPT_POINTZ : SHPT_POINT;
411 1020 : break;
412 : }
413 : case wkbMultiPoint:
414 : {
415 20 : nGType = b3d ? SHPT_MULTIPOINTZ : SHPT_MULTIPOINT;
416 20 : break;
417 : }
418 : case wkbLineString:
419 : case wkbMultiLineString:
420 : {
421 40 : nGType = b3d ? SHPT_ARCZ : SHPT_ARC;
422 40 : break;
423 : }
424 : case wkbPolygon:
425 : case wkbMultiPolygon:
426 : {
427 55 : nGType = b3d ? SHPT_POLYGONZ : SHPT_POLYGON;
428 55 : break;
429 : }
430 : default:
431 : {
432 0 : return OGRERR_UNSUPPORTED_OPERATION;
433 : }
434 : }
435 : /* Write in the type number and advance the pointer */
436 1135 : nGType = CPL_LSBWORD32( nGType );
437 1135 : memcpy( pabyPtr, &nGType, 4 );
438 1135 : pabyPtr += 4;
439 :
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* POINT and POINTZ */
443 : /* -------------------------------------------------------------------- */
444 1135 : if ( nOGRType == wkbPoint )
445 : {
446 1020 : OGRPoint *poPoint = (OGRPoint*)poGeom;
447 1020 : double x = poPoint->getX();
448 1020 : double y = poPoint->getY();
449 :
450 : /* Copy in the raw data. */
451 1020 : memcpy( pabyPtr, &x, 8 );
452 1020 : memcpy( pabyPtr+8, &y, 8 );
453 1020 : if( b3d )
454 : {
455 10 : double z = poPoint->getZ();
456 10 : 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 1020 : return OGRERR_NONE;
469 : }
470 :
471 : /* -------------------------------------------------------------------- */
472 : /* All the non-POINT types require an envelope next */
473 : /* -------------------------------------------------------------------- */
474 115 : OGREnvelope3D envelope;
475 115 : poGeom->getEnvelope(&envelope);
476 115 : memcpy( pabyPtr, &(envelope.MinX), 8 );
477 115 : memcpy( pabyPtr+8, &(envelope.MinY), 8 );
478 115 : memcpy( pabyPtr+8+8, &(envelope.MaxX), 8 );
479 115 : 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 115 : pabyPtr += 32;
488 :
489 : /* Write in the Z bounds at the end of the XY buffer */
490 115 : if ( b3d )
491 : {
492 50 : memcpy( pabyPtrZ, &(envelope.MinZ), 8 );
493 50 : 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 50 : pabyPtrZ += 16;
502 : }
503 :
504 : /* -------------------------------------------------------------------- */
505 : /* LINESTRING and LINESTRINGZ */
506 : /* -------------------------------------------------------------------- */
507 115 : if ( nOGRType == wkbLineString )
508 : {
509 10 : const OGRLineString *poLine = (OGRLineString*)poGeom;
510 :
511 : /* Write in the nparts (1) */
512 10 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
513 10 : memcpy( pabyPtr, &nPartsLsb, 4 );
514 10 : pabyPtr += 4;
515 :
516 : /* Write in the npoints */
517 10 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
518 10 : memcpy( pabyPtr, &nPointsLsb, 4 );
519 10 : pabyPtr += 4;
520 :
521 : /* Write in the part index (0) */
522 10 : GUInt32 nPartIndex = 0;
523 10 : memcpy( pabyPtr, &nPartIndex, 4 );
524 10 : pabyPtr += 4;
525 :
526 : /* Write in the point data */
527 10 : 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 10 : return OGRERR_NONE;
541 :
542 : }
543 : /* -------------------------------------------------------------------- */
544 : /* POLYGON and POLYGONZ */
545 : /* -------------------------------------------------------------------- */
546 105 : else if ( nOGRType == wkbPolygon )
547 : {
548 10 : OGRPolygon *poPoly = (OGRPolygon*)poGeom;
549 :
550 : /* Write in the part count */
551 10 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
552 10 : memcpy( pabyPtr, &nPartsLsb, 4 );
553 10 : pabyPtr += 4;
554 :
555 : /* Write in the total point count */
556 10 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
557 10 : memcpy( pabyPtr, &nPointsLsb, 4 );
558 10 : 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 10 : unsigned char* pabyPoints = pabyPtr + 4*nParts;
571 :
572 10 : int nPointIndexCount = 0;
573 :
574 20 : for( GUInt32 i = 0; i < nParts; i++ )
575 : {
576 : /* Check our Ring and condition it */
577 : OGRLinearRing *poRing;
578 10 : if ( i == 0 )
579 : {
580 10 : poRing = poPoly->getExteriorRing();
581 : /* Outer ring must be clockwise */
582 10 : 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 10 : int nRingNumPoints = poRing->getNumPoints();
594 :
595 : /* Cannot write un-closed rings to shape */
596 10 : if( nRingNumPoints <= 2 || ! poRing->get_IsClosed() )
597 0 : return OGRERR_FAILURE;
598 :
599 : /* Write in the part index */
600 10 : GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
601 10 : memcpy( pabyPtr, &nPartIndex, 4 );
602 :
603 : /* Write in the point data */
604 10 : 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 10 : nPointIndexCount += nRingNumPoints;
619 : /* Advance the write pointers */
620 10 : pabyPtr += 4;
621 10 : pabyPoints += 16 * nRingNumPoints;
622 10 : if ( b3d )
623 5 : pabyPtrZ += 8 * nRingNumPoints;
624 : }
625 :
626 10 : return OGRERR_NONE;
627 :
628 : }
629 : /* -------------------------------------------------------------------- */
630 : /* MULTIPOINT and MULTIPOINTZ */
631 : /* -------------------------------------------------------------------- */
632 95 : else if ( nOGRType == wkbMultiPoint )
633 : {
634 20 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
635 :
636 : /* Write in the total point count */
637 20 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
638 20 : memcpy( pabyPtr, &nPointsLsb, 4 );
639 20 : 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 60 : for( GUInt32 i = 0; i < nPoints; i++ )
649 : {
650 40 : const OGRPoint *poPt = (OGRPoint*)(poMPoint->getGeometryRef(i));
651 :
652 : /* Skip empties */
653 40 : if ( poPt->IsEmpty() )
654 0 : continue;
655 :
656 : /* Write the coordinates */
657 40 : double x = poPt->getX();
658 40 : double y = poPt->getY();
659 40 : memcpy(pabyPtr, &x, 8);
660 40 : memcpy(pabyPtr+8, &y, 8);
661 40 : if ( b3d )
662 : {
663 20 : double z = poPt->getZ();
664 20 : 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 40 : pabyPtr += 16;
678 40 : if ( b3d )
679 20 : pabyPtrZ += 8;
680 : }
681 :
682 20 : return OGRERR_NONE;
683 : }
684 :
685 : /* -------------------------------------------------------------------- */
686 : /* MULTILINESTRING and MULTILINESTRINGZ */
687 : /* -------------------------------------------------------------------- */
688 75 : else if ( nOGRType == wkbMultiLineString )
689 : {
690 30 : OGRMultiLineString *poMLine = (OGRMultiLineString*)poGeom;
691 :
692 : /* Write in the part count */
693 30 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
694 30 : memcpy( pabyPtr, &nPartsLsb, 4 );
695 30 : pabyPtr += 4;
696 :
697 : /* Write in the total point count */
698 30 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
699 30 : memcpy( pabyPtr, &nPointsLsb, 4 );
700 30 : pabyPtr += 4;
701 :
702 : /* Just past the partindex[nparts] array */
703 30 : unsigned char* pabyPoints = pabyPtr + 4*nParts;
704 :
705 30 : int nPointIndexCount = 0;
706 :
707 60 : for( GUInt32 i = 0; i < nParts; i++ )
708 : {
709 30 : const OGRLineString *poLine = (OGRLineString*)(poMLine->getGeometryRef(i));
710 :
711 : /* Skip empties */
712 30 : if ( poLine->IsEmpty() )
713 0 : continue;
714 :
715 30 : int nLineNumPoints = poLine->getNumPoints();
716 :
717 : /* Write in the part index */
718 30 : GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
719 30 : memcpy( pabyPtr, &nPartIndex, 4 );
720 :
721 : /* Write in the point data */
722 30 : 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 30 : nPointIndexCount += nLineNumPoints;
737 :
738 : /* Advance the write pointers */
739 30 : pabyPtr += 4;
740 30 : pabyPoints += 16 * nLineNumPoints;
741 30 : if ( b3d )
742 15 : pabyPtrZ += 8 * nLineNumPoints;
743 : }
744 :
745 30 : return OGRERR_NONE;
746 :
747 : }
748 : /* -------------------------------------------------------------------- */
749 : /* MULTIPOLYGON and MULTIPOLYGONZ */
750 : /* -------------------------------------------------------------------- */
751 45 : else if ( nOGRType == wkbMultiPolygon )
752 : {
753 45 : OGRMultiPolygon *poMPoly = (OGRMultiPolygon*)poGeom;
754 :
755 : /* Write in the part count */
756 45 : GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
757 45 : memcpy( pabyPtr, &nPartsLsb, 4 );
758 45 : pabyPtr += 4;
759 :
760 : /* Write in the total point count */
761 45 : GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
762 45 : memcpy( pabyPtr, &nPointsLsb, 4 );
763 45 : 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 45 : unsigned char* pabyPoints = pabyPtr + 4*nParts;
776 :
777 45 : int nPointIndexCount = 0;
778 :
779 90 : for( int i = 0; i < poMPoly->getNumGeometries(); i++ )
780 : {
781 45 : OGRPolygon *poPoly = (OGRPolygon*)(poMPoly->getGeometryRef(i));
782 :
783 : /* Skip empties */
784 45 : if ( poPoly->IsEmpty() )
785 0 : continue;
786 :
787 45 : int nRings = 1 + poPoly->getNumInteriorRings();
788 :
789 90 : for( int j = 0; j < nRings; j++ )
790 : {
791 : /* Check our Ring and condition it */
792 : OGRLinearRing *poRing;
793 45 : if ( j == 0 )
794 : {
795 45 : poRing = poPoly->getExteriorRing();
796 : /* Outer ring must be clockwise */
797 45 : 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 45 : int nRingNumPoints = poRing->getNumPoints();
809 :
810 : /* Cannot write closed rings to shape */
811 45 : if( nRingNumPoints <= 2 || ! poRing->get_IsClosed() )
812 0 : return OGRERR_FAILURE;
813 :
814 : /* Write in the part index */
815 45 : GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
816 45 : memcpy( pabyPtr, &nPartIndex, 4 );
817 :
818 : /* Write in the point data */
819 45 : 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 45 : nPointIndexCount += nRingNumPoints;
834 : /* Advance the write pointers */
835 45 : pabyPtr += 4;
836 45 : pabyPoints += 16 * nRingNumPoints;
837 45 : if ( b3d )
838 15 : pabyPtrZ += 8 * nRingNumPoints;
839 : }
840 : }
841 :
842 45 : 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 274306 : OGRErr OGRCreateFromShapeBin( GByte *pabyShape,
861 : OGRGeometry **ppoGeom,
862 : int nBytes )
863 :
864 : {
865 274306 : *ppoGeom = NULL;
866 :
867 274306 : 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 548612 : if( nBytes >= 14 &&
881 274306 : 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 274306 : 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 274306 : 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 274306 : 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 274306 : 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 273791 : GInt32 *panPartType = NULL;
1006 :
1007 273791 : 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 273791 : memcpy( &nPoints, pabyShape + 40, 4 );
1019 273791 : memcpy( &nParts, pabyShape + 36, 4 );
1020 :
1021 : CPL_LSBPTR32( &nPoints );
1022 : CPL_LSBPTR32( &nParts );
1023 :
1024 273791 : 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 273791 : || nSHPType == SHPT_MULTIPATCHM );
1038 :
1039 273791 : 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 273791 : int nRequiredSize = 44 + 4 * nParts + 16 * nPoints;
1045 273791 : if ( bHasZ )
1046 : {
1047 273457 : nRequiredSize += 16 + 8 * nPoints;
1048 : }
1049 273791 : if( bIsMultiPatch )
1050 : {
1051 0 : nRequiredSize += 4 * nParts;
1052 : }
1053 273791 : 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 273791 : panPartStart = (GInt32 *) VSICalloc(nParts,sizeof(GInt32));
1062 273791 : 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 273791 : memcpy( panPartStart, pabyShape + 44, 4 * nParts );
1073 547582 : 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 547582 : if (panPartStart[i] < 0 ||
1079 273791 : 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 273791 : 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 273791 : nOffset = 44 + 4*nParts;
1098 :
1099 : /* -------------------------------------------------------------------- */
1100 : /* If this is a multipatch, we will also have parts types. */
1101 : /* -------------------------------------------------------------------- */
1102 273791 : 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 273791 : double *padfX = (double *) VSIMalloc(sizeof(double)*nPoints);
1125 273791 : double *padfY = (double *) VSIMalloc(sizeof(double)*nPoints);
1126 273791 : double *padfZ = (double *) VSICalloc(sizeof(double),nPoints);
1127 273791 : 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 1324420 : for( i = 0; i < nPoints; i++ )
1140 : {
1141 1050629 : memcpy(padfX + i, pabyShape + nOffset + i * 16, 8 );
1142 1050629 : memcpy(padfY + i, pabyShape + nOffset + i * 16 + 8, 8 );
1143 : CPL_LSBPTR64( padfX + i );
1144 : CPL_LSBPTR64( padfY + i );
1145 : }
1146 :
1147 273791 : nOffset += 16*nPoints;
1148 :
1149 : /* -------------------------------------------------------------------- */
1150 : /* If we have a Z coordinate, collect that now. */
1151 : /* -------------------------------------------------------------------- */
1152 273791 : if( bHasZ )
1153 : {
1154 1320833 : for( i = 0; i < nPoints; i++ )
1155 : {
1156 1047376 : memcpy( padfZ + i, pabyShape + nOffset + 16 + i*8, 8 );
1157 : CPL_LSBPTR64( padfZ + i );
1158 : }
1159 :
1160 273457 : nOffset += 16 + 8*nPoints;
1161 : }
1162 :
1163 : /* -------------------------------------------------------------------- */
1164 : /* Build corresponding OGR objects. */
1165 : /* -------------------------------------------------------------------- */
1166 547163 : if( nSHPType == SHPT_ARC
1167 : || nSHPType == SHPT_ARCZ
1168 : || nSHPType == SHPT_ARCM
1169 : || nSHPType == SHPT_ARCZM )
1170 : {
1171 : /* -------------------------------------------------------------------- */
1172 : /* Arc - As LineString */
1173 : /* -------------------------------------------------------------------- */
1174 273372 : if( nParts == 1 )
1175 : {
1176 273372 : OGRLineString *poLine = new OGRLineString();
1177 273372 : *ppoGeom = poLine;
1178 :
1179 273372 : 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 838 : else if( nSHPType == SHPT_POLYGON
1215 : || nSHPType == SHPT_POLYGONZ
1216 : || nSHPType == SHPT_POLYGONM
1217 : || nSHPType == SHPT_POLYGONZM )
1218 : {
1219 419 : if (nParts != 0)
1220 : {
1221 419 : if (nParts == 1)
1222 : {
1223 419 : OGRPolygon *poOGRPoly = new OGRPolygon;
1224 419 : *ppoGeom = poOGRPoly;
1225 838 : OGRLinearRing *poRing = new OGRLinearRing;
1226 419 : int nVerticesInThisPart = nPoints - panPartStart[0];
1227 :
1228 : poRing->setPoints( nVerticesInThisPart,
1229 419 : padfX + panPartStart[0],
1230 419 : padfY + panPartStart[0],
1231 1257 : padfZ + panPartStart[0] );
1232 :
1233 419 : 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 273791 : CPLFree( panPartStart );
1292 273791 : CPLFree( panPartType );
1293 273791 : CPLFree( padfX );
1294 273791 : CPLFree( padfY );
1295 273791 : CPLFree( padfZ );
1296 :
1297 273791 : if (*ppoGeom != NULL)
1298 273791 : (*ppoGeom)->setCoordinateDimension( bHasZ ? 3 : 2 );
1299 :
1300 273791 : return OGRERR_NONE;
1301 : }
1302 :
1303 : /* ==================================================================== */
1304 : /* Extract vertices for a MultiPoint. */
1305 : /* ==================================================================== */
1306 515 : else if( nSHPType == SHPT_MULTIPOINT
1307 : || nSHPType == SHPT_MULTIPOINTM
1308 : || nSHPType == SHPT_MULTIPOINTZ
1309 : || nSHPType == SHPT_MULTIPOINTZM )
1310 : {
1311 : GInt32 nPoints;
1312 : GInt32 nOffsetZ;
1313 : int i;
1314 :
1315 : int bHasZ = ( nSHPType == SHPT_MULTIPOINTZ
1316 116 : || nSHPType == SHPT_MULTIPOINTZM );
1317 :
1318 :
1319 116 : memcpy( &nPoints, pabyShape + 36, 4 );
1320 : CPL_LSBPTR32( &nPoints );
1321 :
1322 116 : if (nPoints < 0 || nPoints > 50 * 1000 * 1000 )
1323 : {
1324 : CPLError(CE_Failure, CPLE_AppDefined, "Corrupted Shape : nPoints=%d.",
1325 0 : nPoints);
1326 0 : return OGRERR_FAILURE;
1327 : }
1328 :
1329 116 : nOffsetZ = 40 + 2*8*nPoints + 2*8;
1330 :
1331 116 : OGRMultiPoint *poMultiPt = new OGRMultiPoint;
1332 116 : *ppoGeom = poMultiPt;
1333 :
1334 348 : for( i = 0; i < nPoints; i++ )
1335 : {
1336 : double x, y, z;
1337 232 : OGRPoint *poPt = new OGRPoint;
1338 :
1339 : /* Copy X */
1340 232 : memcpy(&x, pabyShape + 40 + i*16, 8);
1341 : CPL_LSBPTR64(&x);
1342 232 : poPt->setX(x);
1343 :
1344 : /* Copy Y */
1345 232 : memcpy(&y, pabyShape + 40 + i*16 + 8, 8);
1346 : CPL_LSBPTR64(&y);
1347 232 : poPt->setY(y);
1348 :
1349 : /* Copy Z */
1350 232 : if ( bHasZ )
1351 : {
1352 116 : memcpy(&z, pabyShape + nOffsetZ + i*8, 8);
1353 : CPL_LSBPTR64(&z);
1354 116 : poPt->setZ(z);
1355 : }
1356 :
1357 232 : poMultiPt->addGeometryDirectly( poPt );
1358 : }
1359 :
1360 116 : poMultiPt->setCoordinateDimension( bHasZ ? 3 : 2 );
1361 :
1362 116 : return OGRERR_NONE;
1363 : }
1364 :
1365 : /* ==================================================================== */
1366 : /* Extract vertices for a point. */
1367 : /* ==================================================================== */
1368 399 : else if( nSHPType == SHPT_POINT
1369 : || nSHPType == SHPT_POINTM
1370 : || nSHPType == SHPT_POINTZ
1371 : || nSHPType == SHPT_POINTZM )
1372 : {
1373 : int nOffset;
1374 399 : double dfX, dfY, dfZ = 0;
1375 :
1376 399 : int bHasZ = (nSHPType == SHPT_POINTZ || nSHPType == SHPT_POINTZM);
1377 :
1378 399 : if (nBytes < 4 + 8 + 8 + ((bHasZ) ? 8 : 0))
1379 : {
1380 : CPLError(CE_Failure, CPLE_AppDefined,
1381 0 : "Corrupted Shape : nBytes=%d, nSHPType=%d", nBytes, nSHPType);
1382 0 : return OGRERR_FAILURE;
1383 : }
1384 :
1385 399 : memcpy( &dfX, pabyShape + 4, 8 );
1386 399 : memcpy( &dfY, pabyShape + 4 + 8, 8 );
1387 :
1388 : CPL_LSBPTR64( &dfX );
1389 : CPL_LSBPTR64( &dfY );
1390 399 : nOffset = 20 + 8;
1391 :
1392 399 : if( bHasZ )
1393 : {
1394 335 : memcpy( &dfZ, pabyShape + 4 + 16, 8 );
1395 : CPL_LSBPTR64( &dfZ );
1396 : }
1397 :
1398 399 : *ppoGeom = new OGRPoint( dfX, dfY, dfZ );
1399 734 : (*ppoGeom)->setCoordinateDimension( bHasZ ? 3 : 2 );
1400 :
1401 399 : return OGRERR_NONE;
1402 : }
1403 :
1404 : CPLError(CE_Failure, CPLE_AppDefined,
1405 : "Unsupported geometry type: %d",
1406 0 : nSHPType );
1407 :
1408 0 : return OGRERR_FAILURE;
1409 : }
|