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