1 : /******************************************************************************
2 : * $Id: shape2ogr.cpp 19964 2010-07-04 16:27:05Z warmerdam $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements translation of Shapefile shapes into OGR
6 : * representation.
7 : * Author: Frank Warmerdam, warmerda@home.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1999, Les Technologies SoftMap Inc.
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ogrshape.h"
32 : #include "cpl_conv.h"
33 :
34 : CPL_CVSID("$Id: shape2ogr.cpp 19964 2010-07-04 16:27:05Z warmerdam $");
35 :
36 : static const double EPSILON = 1E-5;
37 :
38 : /************************************************************************/
39 : /* epsilonEqual() */
40 : /************************************************************************/
41 :
42 : static inline bool epsilonEqual(double a, double b, double eps)
43 : {
44 : return (::fabs(a - b) < eps);
45 : }
46 :
47 : /************************************************************************/
48 : /* RingStartEnd */
49 : /* set first and last vertex for given ring */
50 : /************************************************************************/
51 1248 : void RingStartEnd ( SHPObject *psShape, int ring, int *start, int *end )
52 : {
53 1248 : if( psShape->panPartStart == NULL )
54 : {
55 0 : *start = 0;
56 0 : *end = psShape->nVertices - 1;
57 : }
58 : else
59 : {
60 1248 : if( ring == psShape->nParts - 1 )
61 1200 : *end = psShape->nVertices - 1;
62 : else
63 48 : *end = psShape->panPartStart[ring+1] - 1;
64 :
65 1248 : *start = psShape->panPartStart[ring];
66 : }
67 1248 : }
68 :
69 : /************************************************************************/
70 : /* CreateLinearRing */
71 : /* */
72 : /************************************************************************/
73 1248 : OGRLinearRing * CreateLinearRing ( SHPObject *psShape, int ring )
74 : {
75 : OGRLinearRing *poRing;
76 : int nRingStart, nRingEnd, nRingPoints;
77 :
78 1248 : poRing = new OGRLinearRing();
79 :
80 1248 : RingStartEnd ( psShape, ring, &nRingStart, &nRingEnd );
81 :
82 1248 : nRingPoints = nRingEnd - nRingStart + 1;
83 :
84 : poRing->setPoints( nRingPoints, psShape->padfX + nRingStart,
85 1248 : psShape->padfY + nRingStart, psShape->padfZ + nRingStart );
86 :
87 1248 : return ( poRing );
88 : }
89 :
90 :
91 : /************************************************************************/
92 : /* SHPReadOGRObject() */
93 : /* */
94 : /* Read an item in a shapefile, and translate to OGR geometry */
95 : /* representation. */
96 : /************************************************************************/
97 :
98 17322 : OGRGeometry *SHPReadOGRObject( SHPHandle hSHP, int iShape, SHPObject *psShape )
99 : {
100 : // CPLDebug( "Shape", "SHPReadOGRObject( iShape=%d )\n", iShape );
101 :
102 17322 : OGRGeometry *poOGR = NULL;
103 :
104 17322 : if( psShape == NULL )
105 17256 : psShape = SHPReadObject( hSHP, iShape );
106 :
107 17322 : if( psShape == NULL )
108 : {
109 10 : return NULL;
110 : }
111 :
112 : /* -------------------------------------------------------------------- */
113 : /* Point. */
114 : /* -------------------------------------------------------------------- */
115 31989 : else if( psShape->nSHPType == SHPT_POINT
116 : || psShape->nSHPType == SHPT_POINTM
117 : || psShape->nSHPType == SHPT_POINTZ )
118 : {
119 : poOGR = new OGRPoint( psShape->padfX[0], psShape->padfY[0],
120 14677 : psShape->padfZ[0] );
121 :
122 14677 : if( psShape->nSHPType == SHPT_POINT )
123 : {
124 34 : poOGR->setCoordinateDimension( 2 );
125 : }
126 : }
127 :
128 : /* -------------------------------------------------------------------- */
129 : /* Multipoint. */
130 : /* -------------------------------------------------------------------- */
131 2643 : else if( psShape->nSHPType == SHPT_MULTIPOINT
132 : || psShape->nSHPType == SHPT_MULTIPOINTM
133 : || psShape->nSHPType == SHPT_MULTIPOINTZ )
134 : {
135 8 : if (psShape->nVertices == 0)
136 : {
137 1 : poOGR = NULL;
138 : }
139 : else
140 : {
141 7 : OGRMultiPoint *poOGRMPoint = new OGRMultiPoint();
142 : int i;
143 :
144 20 : for( i = 0; i < psShape->nVertices; i++ )
145 : {
146 : OGRPoint *poPoint;
147 :
148 : poPoint = new OGRPoint( psShape->padfX[i], psShape->padfY[i],
149 13 : psShape->padfZ[i] );
150 :
151 13 : poOGRMPoint->addGeometry( poPoint );
152 :
153 26 : delete poPoint;
154 : }
155 :
156 7 : poOGR = poOGRMPoint;
157 :
158 7 : if( psShape->nSHPType == SHPT_MULTIPOINT )
159 5 : poOGR->setCoordinateDimension( 2 );
160 : }
161 : }
162 :
163 : /* -------------------------------------------------------------------- */
164 : /* Arc (LineString) */
165 : /* */
166 : /* I am ignoring parts though they can apply to arcs as well. */
167 : /* -------------------------------------------------------------------- */
168 4031 : else if( psShape->nSHPType == SHPT_ARC
169 : || psShape->nSHPType == SHPT_ARCM
170 : || psShape->nSHPType == SHPT_ARCZ )
171 : {
172 1404 : if( psShape->nParts == 0 )
173 : {
174 1 : poOGR = NULL;
175 : }
176 1403 : else if( psShape->nParts == 1 )
177 : {
178 1395 : OGRLineString *poOGRLine = new OGRLineString();
179 :
180 : poOGRLine->setPoints( psShape->nVertices,
181 1395 : psShape->padfX, psShape->padfY, psShape->padfZ );
182 :
183 1395 : poOGR = poOGRLine;
184 : }
185 : else
186 : {
187 : int iRing;
188 : OGRMultiLineString *poOGRMulti;
189 :
190 8 : poOGR = poOGRMulti = new OGRMultiLineString();
191 :
192 25 : for( iRing = 0; iRing < psShape->nParts; iRing++ )
193 : {
194 : OGRLineString *poLine;
195 : int nRingPoints;
196 : int nRingStart;
197 :
198 17 : poLine = new OGRLineString();
199 :
200 17 : if( psShape->panPartStart == NULL )
201 : {
202 0 : nRingPoints = psShape->nVertices;
203 0 : nRingStart = 0;
204 : }
205 : else
206 : {
207 :
208 17 : if( iRing == psShape->nParts - 1 )
209 : nRingPoints =
210 8 : psShape->nVertices - psShape->panPartStart[iRing];
211 : else
212 : nRingPoints = psShape->panPartStart[iRing+1]
213 9 : - psShape->panPartStart[iRing];
214 17 : nRingStart = psShape->panPartStart[iRing];
215 : }
216 :
217 : poLine->setPoints( nRingPoints,
218 : psShape->padfX + nRingStart,
219 : psShape->padfY + nRingStart,
220 17 : psShape->padfZ + nRingStart );
221 :
222 17 : poOGRMulti->addGeometryDirectly( poLine );
223 : }
224 : }
225 :
226 1404 : if( poOGR != NULL && psShape->nSHPType == SHPT_ARC )
227 147 : poOGR->setCoordinateDimension( 2 );
228 : }
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Polygon */
232 : /* */
233 : /* As for now Z coordinate is not handled correctly */
234 : /* -------------------------------------------------------------------- */
235 2423 : else if( psShape->nSHPType == SHPT_POLYGON
236 : || psShape->nSHPType == SHPT_POLYGONM
237 : || psShape->nSHPType == SHPT_POLYGONZ )
238 : {
239 : int iRing;
240 :
241 : //CPLDebug( "Shape", "Shape type: polygon with nParts=%d \n", psShape->nParts );
242 :
243 1200 : if ( psShape->nParts == 0 )
244 : {
245 1 : poOGR = NULL;
246 : }
247 1199 : else if ( psShape->nParts == 1 )
248 : {
249 : /* Surely outer ring */
250 1175 : OGRPolygon *poOGRPoly = NULL;
251 1175 : OGRLinearRing *poRing = NULL;
252 :
253 1175 : poOGR = poOGRPoly = new OGRPolygon();
254 1175 : poRing = CreateLinearRing ( psShape, 0 );
255 1175 : poOGRPoly->addRingDirectly( poRing );
256 : }
257 :
258 : else
259 : {
260 24 : OGRPolygon** tabPolygons = new OGRPolygon*[psShape->nParts];
261 188 : for( iRing = 0; iRing < psShape->nParts; iRing++ )
262 : {
263 70 : tabPolygons[iRing] = new OGRPolygon();
264 70 : tabPolygons[iRing]->addRingDirectly(CreateLinearRing ( psShape, iRing ));
265 : }
266 :
267 : int isValidGeometry;
268 24 : const char* papszOptions[] = { "METHOD=ONLY_CCW", NULL };
269 : poOGR = OGRGeometryFactory::organizePolygons(
270 24 : (OGRGeometry**)tabPolygons, psShape->nParts, &isValidGeometry, papszOptions );
271 :
272 24 : if (!isValidGeometry)
273 : {
274 : CPLError(CE_Warning, CPLE_AppDefined,
275 : "Geometry of polygon of fid %d cannot be translated to Simple Geometry. "
276 : "All polygons will be contained in a multipolygon.\n",
277 0 : iShape);
278 : }
279 :
280 24 : delete[] tabPolygons;
281 : }
282 :
283 1200 : if( poOGR != NULL && psShape->nSHPType == SHPT_POLYGON )
284 : {
285 1195 : poOGR->setCoordinateDimension( 2 );
286 : }
287 : }
288 :
289 : /* -------------------------------------------------------------------- */
290 : /* MultiPatch */
291 : /* -------------------------------------------------------------------- */
292 23 : else if( psShape->nSHPType == SHPT_MULTIPATCH )
293 : {
294 1 : OGRMultiPolygon *poMP = new OGRMultiPolygon();
295 : int iPart;
296 1 : OGRPolygon *poLastPoly = NULL;
297 :
298 6 : for( iPart = 0; iPart < psShape->nParts; iPart++ )
299 : {
300 : int nPartPoints, nPartStart;
301 :
302 : // Figure out details about this part's vertex list.
303 5 : if( psShape->panPartStart == NULL )
304 : {
305 0 : nPartPoints = psShape->nVertices;
306 0 : nPartStart = 0;
307 : }
308 : else
309 : {
310 :
311 5 : if( iPart == psShape->nParts - 1 )
312 : nPartPoints =
313 1 : psShape->nVertices - psShape->panPartStart[iPart];
314 : else
315 : nPartPoints = psShape->panPartStart[iPart+1]
316 4 : - psShape->panPartStart[iPart];
317 5 : nPartStart = psShape->panPartStart[iPart];
318 : }
319 :
320 5 : if( psShape->panPartType[iPart] == SHPP_TRISTRIP )
321 : {
322 : int iBaseVert;
323 :
324 1 : if( poLastPoly != NULL )
325 : {
326 0 : poMP->addGeometryDirectly( poLastPoly );
327 0 : poLastPoly = NULL;
328 : }
329 :
330 14 : for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
331 : {
332 6 : OGRPolygon *poPoly = new OGRPolygon();
333 12 : OGRLinearRing *poRing = new OGRLinearRing();
334 6 : int iSrcVert = iBaseVert + nPartStart;
335 :
336 : poRing->setPoint( 0,
337 : psShape->padfX[iSrcVert],
338 : psShape->padfY[iSrcVert],
339 6 : psShape->padfZ[iSrcVert] );
340 : poRing->setPoint( 1,
341 : psShape->padfX[iSrcVert+1],
342 : psShape->padfY[iSrcVert+1],
343 6 : psShape->padfZ[iSrcVert+1] );
344 :
345 : poRing->setPoint( 2,
346 : psShape->padfX[iSrcVert+2],
347 : psShape->padfY[iSrcVert+2],
348 6 : psShape->padfZ[iSrcVert+2] );
349 : poRing->setPoint( 3,
350 : psShape->padfX[iSrcVert],
351 : psShape->padfY[iSrcVert],
352 6 : psShape->padfZ[iSrcVert] );
353 :
354 6 : poPoly->addRingDirectly( poRing );
355 6 : poMP->addGeometryDirectly( poPoly );
356 : }
357 : }
358 4 : else if( psShape->panPartType[iPart] == SHPP_TRIFAN )
359 : {
360 : int iBaseVert;
361 :
362 1 : if( poLastPoly != NULL )
363 : {
364 0 : poMP->addGeometryDirectly( poLastPoly );
365 0 : poLastPoly = NULL;
366 : }
367 :
368 10 : for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
369 : {
370 4 : OGRPolygon *poPoly = new OGRPolygon();
371 8 : OGRLinearRing *poRing = new OGRLinearRing();
372 4 : int iSrcVert = iBaseVert + nPartStart;
373 :
374 : poRing->setPoint( 0,
375 : psShape->padfX[0],
376 : psShape->padfY[0],
377 4 : psShape->padfZ[0] );
378 : poRing->setPoint( 1,
379 : psShape->padfX[iSrcVert+1],
380 : psShape->padfY[iSrcVert+1],
381 4 : psShape->padfZ[iSrcVert+1] );
382 :
383 : poRing->setPoint( 2,
384 : psShape->padfX[iSrcVert+2],
385 : psShape->padfY[iSrcVert+2],
386 4 : psShape->padfZ[iSrcVert+2] );
387 : poRing->setPoint( 3,
388 : psShape->padfX[0],
389 : psShape->padfY[0],
390 4 : psShape->padfZ[0] );
391 :
392 4 : poPoly->addRingDirectly( poRing );
393 4 : poMP->addGeometryDirectly( poPoly );
394 : }
395 : }
396 6 : else if( psShape->panPartType[iPart] == SHPP_OUTERRING
397 : || psShape->panPartType[iPart] == SHPP_INNERRING
398 : || psShape->panPartType[iPart] == SHPP_FIRSTRING
399 : || psShape->panPartType[iPart] == SHPP_RING )
400 : {
401 3 : if( poLastPoly != NULL
402 : && (psShape->panPartType[iPart] == SHPP_OUTERRING
403 : || psShape->panPartType[iPart] == SHPP_FIRSTRING) )
404 : {
405 0 : poMP->addGeometryDirectly( poLastPoly );
406 0 : poLastPoly = NULL;
407 : }
408 :
409 3 : if( poLastPoly == NULL )
410 1 : poLastPoly = new OGRPolygon();
411 :
412 : poLastPoly->addRingDirectly(
413 3 : CreateLinearRing( psShape, iPart ) );
414 : }
415 : else
416 : CPLDebug( "OGR", "Unrecognised parttype %d, ignored.",
417 0 : psShape->panPartType[iPart] );
418 : }
419 :
420 1 : if( poLastPoly != NULL )
421 : {
422 1 : poMP->addGeometryDirectly( poLastPoly );
423 1 : poLastPoly = NULL;
424 : }
425 :
426 1 : poOGR = poMP;
427 : }
428 :
429 : /* -------------------------------------------------------------------- */
430 : /* Otherwise for now we just ignore the object. */
431 : /* -------------------------------------------------------------------- */
432 : else
433 : {
434 22 : if( psShape->nSHPType != SHPT_NULL )
435 : {
436 0 : CPLDebug( "OGR", "Unsupported shape type in SHPReadOGRObject()" );
437 : }
438 :
439 : /* nothing returned */
440 : }
441 :
442 : /* -------------------------------------------------------------------- */
443 : /* Cleanup shape, and set feature id. */
444 : /* -------------------------------------------------------------------- */
445 17312 : SHPDestroyObject( psShape );
446 :
447 17312 : return poOGR;
448 : }
449 :
450 : /************************************************************************/
451 : /* SHPWriteOGRObject() */
452 : /************************************************************************/
453 :
454 15899 : OGRErr SHPWriteOGRObject( SHPHandle hSHP, int iShape, OGRGeometry *poGeom )
455 :
456 : {
457 : int nReturnedShapeID;
458 : /* ==================================================================== */
459 : /* Write "shape" with no geometry or with empty geometry */
460 : /* ==================================================================== */
461 15899 : if( poGeom == NULL || poGeom->IsEmpty() )
462 : {
463 : SHPObject *psShape;
464 :
465 15 : psShape = SHPCreateSimpleObject( SHPT_NULL, 0, NULL, NULL, NULL );
466 15 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
467 15 : SHPDestroyObject( psShape );
468 15 : if( nReturnedShapeID == -1 )
469 : {
470 : //Assuming error is reported by SHPWriteObject()
471 0 : return OGRERR_FAILURE;
472 : }
473 : }
474 :
475 : /* ==================================================================== */
476 : /* Write point geometry. */
477 : /* ==================================================================== */
478 30555 : else if( hSHP->nShapeType == SHPT_POINT
479 : || hSHP->nShapeType == SHPT_POINTM
480 : || hSHP->nShapeType == SHPT_POINTZ )
481 : {
482 : SHPObject *psShape;
483 14677 : OGRPoint *poPoint = (OGRPoint *) poGeom;
484 14677 : double dfX, dfY, dfZ = 0;
485 :
486 14677 : if( poGeom->getGeometryType() != wkbPoint
487 : && poGeom->getGeometryType() != wkbPoint25D )
488 : {
489 : CPLError( CE_Failure, CPLE_AppDefined,
490 : "Attempt to write non-point (%s) geometry to"
491 : " point shapefile.",
492 6 : poGeom->getGeometryName() );
493 :
494 6 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
495 : }
496 :
497 14671 : dfX = poPoint->getX();
498 14671 : dfY = poPoint->getY();
499 14671 : dfZ = poPoint->getZ();
500 :
501 : psShape = SHPCreateSimpleObject( hSHP->nShapeType, 1,
502 14671 : &dfX, &dfY, &dfZ );
503 14671 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
504 14671 : SHPDestroyObject( psShape );
505 14671 : if( nReturnedShapeID == -1 )
506 0 : return OGRERR_FAILURE;
507 : }
508 : /* ==================================================================== */
509 : /* MultiPoint. */
510 : /* ==================================================================== */
511 1212 : else if( hSHP->nShapeType == SHPT_MULTIPOINT
512 : || hSHP->nShapeType == SHPT_MULTIPOINTM
513 : || hSHP->nShapeType == SHPT_MULTIPOINTZ )
514 : {
515 11 : OGRMultiPoint *poMP = (OGRMultiPoint *) poGeom;
516 : double *padfX, *padfY, *padfZ;
517 : int iPoint;
518 : SHPObject *psShape;
519 :
520 11 : if( wkbFlatten(poGeom->getGeometryType()) != wkbMultiPoint )
521 : {
522 : CPLError( CE_Failure, CPLE_AppDefined,
523 : "Attempt to write non-multipoint (%s) geometry to "
524 : "multipoint shapefile.",
525 6 : poGeom->getGeometryName() );
526 :
527 6 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
528 : }
529 :
530 5 : padfX = (double *) CPLMalloc(sizeof(double)*poMP->getNumGeometries());
531 5 : padfY = (double *) CPLMalloc(sizeof(double)*poMP->getNumGeometries());
532 5 : padfZ = (double *) CPLCalloc(sizeof(double),poMP->getNumGeometries());
533 :
534 5 : int iDstPoints = 0;
535 15 : for( iPoint = 0; iPoint < poMP->getNumGeometries(); iPoint++ )
536 : {
537 10 : OGRPoint *poPoint = (OGRPoint *) poMP->getGeometryRef(iPoint);
538 :
539 : /* Ignore POINT EMPTY */
540 10 : if (poPoint->IsEmpty() == FALSE)
541 : {
542 9 : padfX[iDstPoints] = poPoint->getX();
543 9 : padfY[iDstPoints] = poPoint->getY();
544 9 : padfZ[iDstPoints] = poPoint->getZ();
545 9 : iDstPoints ++;
546 : }
547 : else
548 : CPLDebug( "OGR",
549 1 : "Ignore POINT EMPTY inside MULTIPOINT in shapefile writer." );
550 : }
551 :
552 : psShape = SHPCreateSimpleObject( hSHP->nShapeType,
553 : iDstPoints,
554 5 : padfX, padfY, padfZ );
555 5 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
556 5 : SHPDestroyObject( psShape );
557 :
558 5 : CPLFree( padfX );
559 5 : CPLFree( padfY );
560 5 : CPLFree( padfZ );
561 5 : if( nReturnedShapeID == -1 )
562 0 : return OGRERR_FAILURE;
563 : }
564 :
565 : /* ==================================================================== */
566 : /* Arcs from simple line strings. */
567 : /* ==================================================================== */
568 1196 : else if( (hSHP->nShapeType == SHPT_ARC
569 : || hSHP->nShapeType == SHPT_ARCM
570 : || hSHP->nShapeType == SHPT_ARCZ)
571 : && wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
572 : {
573 762 : OGRLineString *poArc = (OGRLineString *) poGeom;
574 : double *padfX, *padfY, *padfZ;
575 : int iPoint;
576 : SHPObject *psShape;
577 :
578 762 : padfX = (double *) CPLMalloc(sizeof(double)*poArc->getNumPoints());
579 762 : padfY = (double *) CPLMalloc(sizeof(double)*poArc->getNumPoints());
580 762 : padfZ = (double *) CPLCalloc(sizeof(double),poArc->getNumPoints());
581 :
582 22304 : for( iPoint = 0; iPoint < poArc->getNumPoints(); iPoint++ )
583 : {
584 21542 : padfX[iPoint] = poArc->getX( iPoint );
585 21542 : padfY[iPoint] = poArc->getY( iPoint );
586 21542 : padfZ[iPoint] = poArc->getZ( iPoint );
587 : }
588 :
589 : psShape = SHPCreateSimpleObject( hSHP->nShapeType,
590 : poArc->getNumPoints(),
591 762 : padfX, padfY, padfZ );
592 762 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
593 762 : SHPDestroyObject( psShape );
594 :
595 762 : CPLFree( padfX );
596 762 : CPLFree( padfY );
597 762 : CPLFree( padfZ );
598 762 : if( nReturnedShapeID == -1 )
599 0 : return OGRERR_FAILURE;
600 : }
601 : /* ==================================================================== */
602 : /* Arcs - Try to treat as MultiLineString. */
603 : /* ==================================================================== */
604 440 : else if( hSHP->nShapeType == SHPT_ARC
605 : || hSHP->nShapeType == SHPT_ARCM
606 : || hSHP->nShapeType == SHPT_ARCZ )
607 : {
608 : OGRMultiLineString *poML;
609 18 : double *padfX=NULL, *padfY=NULL, *padfZ=NULL;
610 18 : int iGeom, iPoint, nPointCount = 0;
611 : SHPObject *psShape;
612 : int *panRingStart;
613 18 : int nParts = 0;
614 :
615 : poML = (OGRMultiLineString *)
616 18 : OGRGeometryFactory::forceToMultiLineString( poGeom->clone() );
617 :
618 18 : if( wkbFlatten(poML->getGeometryType()) != wkbMultiLineString )
619 : {
620 12 : delete poML;
621 : CPLError( CE_Failure, CPLE_AppDefined,
622 : "Attempt to write non-linestring (%s) geometry to "
623 : "ARC type shapefile.",
624 12 : poGeom->getGeometryName() );
625 :
626 12 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
627 : }
628 :
629 : panRingStart = (int *)
630 6 : CPLMalloc(sizeof(int) * poML->getNumGeometries());
631 :
632 20 : for( iGeom = 0; iGeom < poML->getNumGeometries(); iGeom++ )
633 : {
634 : OGRLineString *poArc = (OGRLineString *)
635 14 : poML->getGeometryRef(iGeom);
636 14 : int nNewPoints = poArc->getNumPoints();
637 :
638 : /* Ignore LINESTRING EMPTY */
639 14 : if (nNewPoints == 0)
640 : {
641 : CPLDebug( "OGR",
642 1 : "Ignore LINESTRING EMPTY inside MULTILINESTRING in shapefile writer." );
643 1 : continue;
644 : }
645 :
646 13 : panRingStart[nParts ++] = nPointCount;
647 :
648 : padfX = (double *)
649 13 : CPLRealloc( padfX, sizeof(double)*(nNewPoints+nPointCount) );
650 : padfY = (double *)
651 13 : CPLRealloc( padfY, sizeof(double)*(nNewPoints+nPointCount) );
652 : padfZ = (double *)
653 13 : CPLRealloc( padfZ, sizeof(double)*(nNewPoints+nPointCount) );
654 :
655 68 : for( iPoint = 0; iPoint < nNewPoints; iPoint++ )
656 : {
657 55 : padfX[nPointCount] = poArc->getX( iPoint );
658 55 : padfY[nPointCount] = poArc->getY( iPoint );
659 55 : padfZ[nPointCount] = poArc->getZ( iPoint );
660 55 : nPointCount++;
661 : }
662 : }
663 :
664 6 : CPLAssert(nParts != 0);
665 :
666 : psShape = SHPCreateObject( hSHP->nShapeType, iShape,
667 : nParts,
668 : panRingStart, NULL,
669 6 : nPointCount, padfX, padfY, padfZ, NULL);
670 6 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
671 6 : SHPDestroyObject( psShape );
672 :
673 6 : CPLFree( panRingStart );
674 6 : CPLFree( padfX );
675 6 : CPLFree( padfY );
676 6 : CPLFree( padfZ );
677 :
678 6 : delete poML;
679 6 : if( nReturnedShapeID == -1 )
680 0 : return OGRERR_FAILURE;
681 : }
682 :
683 : /* ==================================================================== */
684 : /* Polygons/MultiPolygons */
685 : /* ==================================================================== */
686 818 : else if( hSHP->nShapeType == SHPT_POLYGON
687 : || hSHP->nShapeType == SHPT_POLYGONM
688 : || hSHP->nShapeType == SHPT_POLYGONZ )
689 : {
690 : OGRPolygon *poPoly;
691 416 : OGRLinearRing *poRing, **papoRings=NULL;
692 416 : double *padfX=NULL, *padfY=NULL, *padfZ=NULL;
693 416 : int iPoint, iRing, nRings, nVertex=0, *panRingStart;
694 : SHPObject *psShape;
695 :
696 : /* Collect list of rings */
697 :
698 416 : if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
699 : {
700 382 : poPoly = (OGRPolygon *) poGeom;
701 :
702 382 : if( poPoly->getExteriorRing() == NULL ||
703 : poPoly->getExteriorRing()->IsEmpty() )
704 : {
705 : CPLDebug( "OGR",
706 1 : "Ignore POLYGON EMPTY in shapefile writer." );
707 1 : nRings = 0;
708 : }
709 : else
710 : {
711 381 : int nSrcRings = poPoly->getNumInteriorRings()+1;
712 381 : nRings = 0;
713 381 : papoRings = (OGRLinearRing **) CPLMalloc(sizeof(void*)*nSrcRings);
714 769 : for( iRing = 0; iRing < nSrcRings; iRing++ )
715 : {
716 388 : if( iRing == 0 )
717 381 : papoRings[nRings] = poPoly->getExteriorRing();
718 : else
719 7 : papoRings[nRings] = poPoly->getInteriorRing( iRing-1 );
720 :
721 : /* Ignore LINEARRING EMPTY */
722 388 : if (papoRings[nRings]->getNumPoints() != 0)
723 387 : nRings ++;
724 : else
725 : CPLDebug( "OGR",
726 1 : "Ignore LINEARRING EMPTY inside POLYGON in shapefile writer." );
727 : }
728 : }
729 : }
730 34 : else if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon
731 : || wkbFlatten(poGeom->getGeometryType())
732 : == wkbGeometryCollection )
733 : {
734 22 : OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
735 : int iGeom;
736 :
737 22 : nRings = 0;
738 60 : for( iGeom=0; iGeom < poGC->getNumGeometries(); iGeom++ )
739 : {
740 39 : poPoly = (OGRPolygon *) poGC->getGeometryRef( iGeom );
741 :
742 39 : if( wkbFlatten(poPoly->getGeometryType()) != wkbPolygon )
743 : {
744 1 : CPLFree( papoRings );
745 : CPLError( CE_Failure, CPLE_AppDefined,
746 : "Attempt to write non-polygon (%s) geometry to "
747 : "POLYGON type shapefile.",
748 1 : poGeom->getGeometryName());
749 :
750 1 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
751 : }
752 :
753 : /* Ignore POLYGON EMPTY */
754 38 : if( poPoly->getExteriorRing() == NULL ||
755 : poPoly->getExteriorRing()->IsEmpty() )
756 : {
757 : CPLDebug( "OGR",
758 1 : "Ignore POLYGON EMPTY inside MULTIPOLYGON in shapefile writer." );
759 1 : continue;
760 : }
761 :
762 : papoRings = (OGRLinearRing **) CPLRealloc(papoRings,
763 37 : sizeof(void*) * (nRings+poPoly->getNumInteriorRings()+1));
764 86 : for( iRing = 0;
765 : iRing < poPoly->getNumInteriorRings()+1;
766 : iRing++ )
767 : {
768 49 : if( iRing == 0 )
769 37 : papoRings[nRings] = poPoly->getExteriorRing();
770 : else
771 : papoRings[nRings] =
772 12 : poPoly->getInteriorRing( iRing-1 );
773 :
774 : /* Ignore LINEARRING EMPTY */
775 49 : if (papoRings[nRings]->getNumPoints() != 0)
776 48 : nRings ++;
777 : else
778 : CPLDebug( "OGR",
779 1 : "Ignore LINEARRING EMPTY inside POLYGON in shapefile writer." );
780 : }
781 : }
782 : }
783 : else
784 : {
785 : CPLError( CE_Failure, CPLE_AppDefined,
786 : "Attempt to write non-polygon (%s) geometry to "
787 : "POLYGON type shapefile.",
788 12 : poGeom->getGeometryName() );
789 :
790 12 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
791 : }
792 :
793 : /* -------------------------------------------------------------------- */
794 : /* If we only had emptypolygons or unacceptable geometries */
795 : /* write NULL geometry object. */
796 : /* -------------------------------------------------------------------- */
797 403 : if( nRings == 0 )
798 : {
799 : SHPObject *psShape;
800 :
801 1 : psShape = SHPCreateSimpleObject( SHPT_NULL, 0, NULL, NULL, NULL );
802 1 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
803 1 : SHPDestroyObject( psShape );
804 :
805 1 : if( nReturnedShapeID == -1 )
806 0 : return OGRERR_FAILURE;
807 :
808 1 : return OGRERR_NONE;
809 : }
810 :
811 : /* count vertices */
812 402 : nVertex = 0;
813 837 : for( iRing = 0; iRing < nRings; iRing++ )
814 435 : nVertex += papoRings[iRing]->getNumPoints();
815 :
816 402 : panRingStart = (int *) CPLMalloc(sizeof(int) * nRings);
817 402 : padfX = (double *) CPLMalloc(sizeof(double)*nVertex);
818 402 : padfY = (double *) CPLMalloc(sizeof(double)*nVertex);
819 402 : padfZ = (double *) CPLMalloc(sizeof(double)*nVertex);
820 :
821 : /* collect vertices */
822 402 : nVertex = 0;
823 837 : for( iRing = 0; iRing < nRings; iRing++ )
824 : {
825 435 : poRing = papoRings[iRing];
826 435 : panRingStart[iRing] = nVertex;
827 :
828 8572 : for( iPoint = 0; iPoint < poRing->getNumPoints(); iPoint++ )
829 : {
830 8137 : padfX[nVertex] = poRing->getX( iPoint );
831 8137 : padfY[nVertex] = poRing->getY( iPoint );
832 8137 : padfZ[nVertex] = poRing->getZ( iPoint );
833 8137 : nVertex++;
834 : }
835 : }
836 :
837 : psShape = SHPCreateObject( hSHP->nShapeType, iShape, nRings,
838 : panRingStart, NULL,
839 402 : nVertex, padfX, padfY, padfZ, NULL );
840 402 : SHPRewindObject( hSHP, psShape );
841 402 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
842 402 : SHPDestroyObject( psShape );
843 :
844 402 : CPLFree( papoRings );
845 402 : CPLFree( panRingStart );
846 402 : CPLFree( padfX );
847 402 : CPLFree( padfY );
848 402 : CPLFree( padfZ );
849 402 : if( nReturnedShapeID == -1 )
850 0 : return OGRERR_FAILURE;
851 : }
852 : else
853 : {
854 : /* do nothing for multipatch */
855 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
856 : }
857 :
858 15861 : return OGRERR_NONE;
859 : }
860 :
861 : /************************************************************************/
862 : /* SHPReadOGRFeatureDefn() */
863 : /************************************************************************/
864 :
865 : OGRFeatureDefn *SHPReadOGRFeatureDefn( const char * pszName,
866 1023 : SHPHandle hSHP, DBFHandle hDBF )
867 :
868 : {
869 1023 : OGRFeatureDefn *poDefn = new OGRFeatureDefn( pszName );
870 : int iField;
871 :
872 1023 : poDefn->Reference();
873 :
874 2482 : for( iField = 0;
875 : hDBF != NULL && iField < DBFGetFieldCount( hDBF );
876 : iField++ )
877 : {
878 : char szFieldName[20];
879 : int nWidth, nPrecision;
880 : DBFFieldType eDBFType;
881 1459 : OGRFieldDefn oField("", OFTInteger);
882 : char chNativeType;
883 :
884 1459 : chNativeType = DBFGetNativeFieldType( hDBF, iField );
885 : eDBFType = DBFGetFieldInfo( hDBF, iField, szFieldName,
886 1459 : &nWidth, &nPrecision );
887 :
888 1459 : oField.SetName( szFieldName );
889 1459 : oField.SetWidth( nWidth );
890 1459 : oField.SetPrecision( nPrecision );
891 :
892 1459 : if( chNativeType == 'D' )
893 : {
894 : /* XXX - mloskot:
895 : * Shapefile date has following 8-chars long format: 20060101.
896 : * OGR splits it as YYYY/MM/DD, so 2 additional characters are required.
897 : * Is this correct assumtion? What about time part of date?
898 : * Shouldn't this format look as datetime: YYYY/MM/DD HH:MM:SS
899 : * with 4 additional characters?
900 : */
901 22 : oField.SetWidth( nWidth + 2 );
902 22 : oField.SetType( OFTDate );
903 : }
904 1437 : else if( eDBFType == FTDouble )
905 1042 : oField.SetType( OFTReal );
906 395 : else if( eDBFType == FTInteger )
907 54 : oField.SetType( OFTInteger );
908 : else
909 341 : oField.SetType( OFTString );
910 :
911 1459 : poDefn->AddFieldDefn( &oField );
912 : }
913 :
914 1023 : if( hSHP == NULL )
915 23 : poDefn->SetGeomType( wkbNone );
916 : else
917 : {
918 1000 : switch( hSHP->nShapeType )
919 : {
920 : case SHPT_POINT:
921 : case SHPT_POINTM:
922 97 : poDefn->SetGeomType( wkbPoint );
923 97 : break;
924 :
925 : case SHPT_POINTZ:
926 46 : poDefn->SetGeomType( wkbPoint25D );
927 46 : break;
928 :
929 : case SHPT_ARC:
930 : case SHPT_ARCM:
931 213 : poDefn->SetGeomType( wkbLineString );
932 213 : break;
933 :
934 : case SHPT_ARCZ:
935 76 : poDefn->SetGeomType( wkbLineString25D );
936 76 : break;
937 :
938 : case SHPT_MULTIPOINT:
939 : case SHPT_MULTIPOINTM:
940 83 : poDefn->SetGeomType( wkbMultiPoint );
941 83 : break;
942 :
943 : case SHPT_MULTIPOINTZ:
944 41 : poDefn->SetGeomType( wkbMultiPoint25D );
945 41 : break;
946 :
947 : case SHPT_POLYGON:
948 : case SHPT_POLYGONM:
949 379 : poDefn->SetGeomType( wkbPolygon );
950 379 : break;
951 :
952 : case SHPT_POLYGONZ:
953 62 : poDefn->SetGeomType( wkbPolygon25D );
954 : break;
955 :
956 : }
957 : }
958 :
959 1023 : return poDefn;
960 : }
961 :
962 : /************************************************************************/
963 : /* SHPReadOGRFeature() */
964 : /************************************************************************/
965 :
966 : OGRFeature *SHPReadOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
967 : OGRFeatureDefn * poDefn, int iShape,
968 17809 : SHPObject *psShape )
969 :
970 : {
971 17809 : if( iShape < 0
972 : || (hSHP != NULL && iShape >= hSHP->nRecords)
973 : || (hDBF != NULL && iShape >= hDBF->nRecords) )
974 : {
975 : CPLError( CE_Failure, CPLE_AppDefined,
976 : "Attempt to read shape with feature id (%d) out of available"
977 0 : " range.", iShape );
978 0 : return NULL;
979 : }
980 :
981 17809 : if( hDBF && DBFIsRecordDeleted( hDBF, iShape ) )
982 : {
983 : CPLError( CE_Failure, CPLE_AppDefined,
984 : "Attempt to read shape with feature id (%d), but it is marked deleted.",
985 0 : iShape );
986 0 : return NULL;
987 : }
988 :
989 17809 : OGRFeature *poFeature = new OGRFeature( poDefn );
990 :
991 : /* -------------------------------------------------------------------- */
992 : /* Fetch geometry from Shapefile to OGRFeature. */
993 : /* -------------------------------------------------------------------- */
994 17809 : if( hSHP != NULL )
995 : {
996 17322 : OGRGeometry* poGeometry = NULL;
997 17322 : poGeometry = SHPReadOGRObject( hSHP, iShape, psShape );
998 :
999 : /*
1000 : * NOTE - mloskot:
1001 : * Two possibilities are expected here (bot hare tested by GDAL Autotests):
1002 : * 1. Read valid geometry and assign it directly.
1003 : * 2. Read and assign null geometry if it can not be read correctly from a shapefile
1004 : *
1005 : * It's NOT required here to test poGeometry == NULL.
1006 : */
1007 :
1008 17322 : poFeature->SetGeometryDirectly( poGeometry );
1009 : }
1010 :
1011 : /* -------------------------------------------------------------------- */
1012 : /* Fetch feature attributes to OGRFeature fields. */
1013 : /* -------------------------------------------------------------------- */
1014 :
1015 39113 : for( int iField = 0; iField < poDefn->GetFieldCount(); iField++ )
1016 : {
1017 : // Skip null fields.
1018 21304 : if( DBFIsAttributeNULL( hDBF, iShape, iField ) )
1019 510 : continue;
1020 :
1021 20794 : switch( poDefn->GetFieldDefn(iField)->GetType() )
1022 : {
1023 : case OFTString:
1024 : poFeature->SetField( iField,
1025 : DBFReadStringAttribute( hDBF, iShape,
1026 1790 : iField ) );
1027 1790 : break;
1028 :
1029 : case OFTInteger:
1030 : poFeature->SetField( iField,
1031 : DBFReadIntegerAttribute( hDBF, iShape,
1032 1684 : iField ) );
1033 1684 : break;
1034 :
1035 : case OFTReal:
1036 : poFeature->SetField( iField,
1037 : DBFReadDoubleAttribute( hDBF, iShape,
1038 17318 : iField ) );
1039 17318 : break;
1040 :
1041 : case OFTDate:
1042 : {
1043 : OGRField sFld;
1044 : const char* pszDateValue =
1045 2 : DBFReadStringAttribute(hDBF,iShape,iField);
1046 :
1047 2 : memset( &sFld, 0, sizeof(sFld) );
1048 :
1049 3 : if( pszDateValue[2] == '/' && pszDateValue[5] == '/'
1050 : && strlen(pszDateValue) >= 10 )
1051 : {
1052 1 : sFld.Date.Month = (GByte)atoi(pszDateValue+0);
1053 1 : sFld.Date.Day = (GByte)atoi(pszDateValue+3);
1054 1 : sFld.Date.Year = (GInt16)atoi(pszDateValue+6);
1055 : }
1056 : else
1057 : {
1058 1 : int nFullDate = atoi(pszDateValue);
1059 1 : sFld.Date.Year = (GInt16)(nFullDate / 10000);
1060 1 : sFld.Date.Month = (GByte)((nFullDate / 100) % 100);
1061 1 : sFld.Date.Day = (GByte)(nFullDate % 100);
1062 : }
1063 :
1064 2 : poFeature->SetField( iField, &sFld );
1065 : }
1066 2 : break;
1067 :
1068 : default:
1069 0 : CPLAssert( FALSE );
1070 : }
1071 : }
1072 :
1073 17809 : if( poFeature != NULL )
1074 17809 : poFeature->SetFID( iShape );
1075 :
1076 17809 : return( poFeature );
1077 : }
1078 :
1079 : /************************************************************************/
1080 : /* SHPWriteOGRFeature() */
1081 : /* */
1082 : /* Write to an existing feature in a shapefile, or create a new */
1083 : /* feature. */
1084 : /************************************************************************/
1085 :
1086 : OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
1087 : OGRFeatureDefn * poDefn,
1088 15921 : OGRFeature * poFeature )
1089 :
1090 : {
1091 : #ifdef notdef
1092 : /* -------------------------------------------------------------------- */
1093 : /* Don't write objects with missing geometry. */
1094 : /* -------------------------------------------------------------------- */
1095 : if( poFeature->GetGeometryRef() == NULL && hSHP != NULL )
1096 : {
1097 : CPLError( CE_Failure, CPLE_AppDefined,
1098 : "Attempt to write feature without geometry not supported"
1099 : " for shapefile driver." );
1100 :
1101 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1102 : }
1103 : #endif
1104 :
1105 : /* -------------------------------------------------------------------- */
1106 : /* Write the geometry. */
1107 : /* -------------------------------------------------------------------- */
1108 : OGRErr eErr;
1109 :
1110 15921 : if( hSHP != NULL )
1111 : {
1112 : eErr = SHPWriteOGRObject( hSHP, poFeature->GetFID(),
1113 15899 : poFeature->GetGeometryRef() );
1114 15899 : if( eErr != OGRERR_NONE )
1115 37 : return eErr;
1116 : }
1117 :
1118 : /* -------------------------------------------------------------------- */
1119 : /* If there is no DBF, the job is done now. */
1120 : /* -------------------------------------------------------------------- */
1121 15884 : if( hDBF == NULL )
1122 : {
1123 : /* -------------------------------------------------------------------- */
1124 : /* If this is a new feature, establish it's feature id. */
1125 : /* -------------------------------------------------------------------- */
1126 14 : if( hSHP != NULL && poFeature->GetFID() == OGRNullFID )
1127 1 : poFeature->SetFID( hSHP->nRecords - 1 );
1128 :
1129 14 : return OGRERR_NONE;
1130 : }
1131 :
1132 : /* -------------------------------------------------------------------- */
1133 : /* If this is a new feature, establish it's feature id. */
1134 : /* -------------------------------------------------------------------- */
1135 15870 : if( poFeature->GetFID() == OGRNullFID )
1136 15867 : poFeature->SetFID( DBFGetRecordCount( hDBF ) );
1137 :
1138 : /* -------------------------------------------------------------------- */
1139 : /* If this is the first feature to be written, verify that we */
1140 : /* have at least one attribute in the DBF file. If not, create */
1141 : /* a dummy FID attribute to satisfy the requirement that there */
1142 : /* be at least one attribute. */
1143 : /* -------------------------------------------------------------------- */
1144 15870 : if( DBFGetRecordCount( hDBF ) == 0 && DBFGetFieldCount( hDBF ) == 0 )
1145 : {
1146 : CPLDebug( "OGR",
1147 62 : "Created dummy FID field for shapefile since schema is empty.");
1148 62 : DBFAddField( hDBF, "FID", FTInteger, 11, 0 );
1149 : }
1150 :
1151 : /* -------------------------------------------------------------------- */
1152 : /* Write out dummy field value if it exists. */
1153 : /* -------------------------------------------------------------------- */
1154 15870 : if( DBFGetFieldCount( hDBF ) == 1 && poDefn->GetFieldCount() == 0 )
1155 : {
1156 : DBFWriteIntegerAttribute( hDBF, poFeature->GetFID(), 0,
1157 14705 : poFeature->GetFID() );
1158 : }
1159 :
1160 : /* -------------------------------------------------------------------- */
1161 : /* Write all the fields. */
1162 : /* -------------------------------------------------------------------- */
1163 17841 : for( int iField = 0; iField < poDefn->GetFieldCount(); iField++ )
1164 : {
1165 1971 : if( !poFeature->IsFieldSet( iField ) )
1166 : {
1167 2 : DBFWriteNULLAttribute( hDBF, poFeature->GetFID(), iField );
1168 2 : continue;
1169 : }
1170 :
1171 1969 : switch( poDefn->GetFieldDefn(iField)->GetType() )
1172 : {
1173 : case OFTString:
1174 : DBFWriteStringAttribute( hDBF, poFeature->GetFID(), iField,
1175 368 : poFeature->GetFieldAsString( iField ));
1176 368 : break;
1177 :
1178 : case OFTInteger:
1179 : DBFWriteIntegerAttribute( hDBF, poFeature->GetFID(), iField,
1180 805 : poFeature->GetFieldAsInteger(iField) );
1181 805 : break;
1182 :
1183 : case OFTReal:
1184 : DBFWriteDoubleAttribute( hDBF, poFeature->GetFID(), iField,
1185 795 : poFeature->GetFieldAsDouble(iField) );
1186 795 : break;
1187 :
1188 : case OFTDate:
1189 : {
1190 : int nYear, nMonth, nDay;
1191 :
1192 1 : if( poFeature->GetFieldAsDateTime( iField, &nYear, &nMonth, &nDay,
1193 : NULL, NULL, NULL, NULL ) )
1194 : {
1195 : DBFWriteIntegerAttribute( hDBF, poFeature->GetFID(), iField,
1196 1 : nYear*10000 + nMonth*100 + nDay );
1197 : }
1198 : }
1199 : break;
1200 :
1201 : default:
1202 : {
1203 : /* Ignore fields of other types */
1204 : break;
1205 : }
1206 : }
1207 : }
1208 :
1209 15870 : return OGRERR_NONE;
1210 : }
1211 :
|