1 : /******************************************************************************
2 : * $Id: shape2ogr.cpp 23972 2012-02-13 21:19:46Z rouault $
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 23972 2012-02-13 21:19:46Z rouault $");
35 :
36 : /************************************************************************/
37 : /* RingStartEnd */
38 : /* set first and last vertex for given ring */
39 : /************************************************************************/
40 58193 : static void RingStartEnd ( SHPObject *psShape, int ring, int *start, int *end )
41 : {
42 58193 : if( psShape->panPartStart == NULL )
43 : {
44 0 : *start = 0;
45 0 : *end = psShape->nVertices - 1;
46 : }
47 : else
48 : {
49 58193 : if( ring == psShape->nParts - 1 )
50 58081 : *end = psShape->nVertices - 1;
51 : else
52 112 : *end = psShape->panPartStart[ring+1] - 1;
53 :
54 58193 : *start = psShape->panPartStart[ring];
55 : }
56 58193 : }
57 :
58 : /************************************************************************/
59 : /* CreateLinearRing */
60 : /* */
61 : /************************************************************************/
62 58193 : static OGRLinearRing * CreateLinearRing ( SHPObject *psShape, int ring, int bHasZ )
63 : {
64 : OGRLinearRing *poRing;
65 : int nRingStart, nRingEnd, nRingPoints;
66 :
67 58193 : poRing = new OGRLinearRing();
68 :
69 58193 : RingStartEnd ( psShape, ring, &nRingStart, &nRingEnd );
70 :
71 58193 : nRingPoints = nRingEnd - nRingStart + 1;
72 :
73 58193 : if (bHasZ)
74 : poRing->setPoints( nRingPoints, psShape->padfX + nRingStart,
75 : psShape->padfY + nRingStart,
76 36 : psShape->padfZ + nRingStart );
77 : else
78 : poRing->setPoints( nRingPoints, psShape->padfX + nRingStart,
79 58157 : psShape->padfY + nRingStart );
80 :
81 58193 : return ( poRing );
82 : }
83 :
84 :
85 : /************************************************************************/
86 : /* SHPReadOGRObject() */
87 : /* */
88 : /* Read an item in a shapefile, and translate to OGR geometry */
89 : /* representation. */
90 : /************************************************************************/
91 :
92 92417 : OGRGeometry *SHPReadOGRObject( SHPHandle hSHP, int iShape, SHPObject *psShape )
93 : {
94 : // CPLDebug( "Shape", "SHPReadOGRObject( iShape=%d )\n", iShape );
95 :
96 92417 : OGRGeometry *poOGR = NULL;
97 :
98 92417 : if( psShape == NULL )
99 63218 : psShape = SHPReadObject( hSHP, iShape );
100 :
101 92417 : if( psShape == NULL )
102 : {
103 20 : return NULL;
104 : }
105 :
106 : /* -------------------------------------------------------------------- */
107 : /* Point. */
108 : /* -------------------------------------------------------------------- */
109 92397 : else if( psShape->nSHPType == SHPT_POINT )
110 : {
111 1066 : poOGR = new OGRPoint( psShape->padfX[0], psShape->padfY[0] );
112 : }
113 91331 : else if(psShape->nSHPType == SHPT_POINTZ )
114 : {
115 : poOGR = new OGRPoint( psShape->padfX[0], psShape->padfY[0],
116 29290 : psShape->padfZ[0] );
117 : }
118 62041 : else if(psShape->nSHPType == SHPT_POINTM )
119 : {
120 : // Read XYM as XYZ
121 : poOGR = new OGRPoint( psShape->padfX[0], psShape->padfY[0],
122 2 : psShape->padfM[0] );
123 : }
124 : /* -------------------------------------------------------------------- */
125 : /* Multipoint. */
126 : /* -------------------------------------------------------------------- */
127 62059 : else if( psShape->nSHPType == SHPT_MULTIPOINT
128 : || psShape->nSHPType == SHPT_MULTIPOINTM
129 : || psShape->nSHPType == SHPT_MULTIPOINTZ )
130 : {
131 20 : if (psShape->nVertices == 0)
132 : {
133 2 : poOGR = NULL;
134 : }
135 : else
136 : {
137 18 : OGRMultiPoint *poOGRMPoint = new OGRMultiPoint();
138 : int i;
139 :
140 52 : for( i = 0; i < psShape->nVertices; i++ )
141 : {
142 : OGRPoint *poPoint;
143 :
144 34 : if( psShape->nSHPType == SHPT_MULTIPOINTZ )
145 : poPoint = new OGRPoint( psShape->padfX[i], psShape->padfY[i],
146 12 : psShape->padfZ[i] );
147 : else
148 22 : poPoint = new OGRPoint( psShape->padfX[i], psShape->padfY[i] );
149 :
150 34 : poOGRMPoint->addGeometry( poPoint );
151 :
152 34 : delete poPoint;
153 : }
154 :
155 18 : poOGR = poOGRMPoint;
156 : }
157 : }
158 :
159 : /* -------------------------------------------------------------------- */
160 : /* Arc (LineString) */
161 : /* */
162 : /* I am ignoring parts though they can apply to arcs as well. */
163 : /* -------------------------------------------------------------------- */
164 64583 : else if( psShape->nSHPType == SHPT_ARC
165 : || psShape->nSHPType == SHPT_ARCM
166 : || psShape->nSHPType == SHPT_ARCZ )
167 : {
168 2564 : if( psShape->nParts == 0 )
169 : {
170 2 : poOGR = NULL;
171 : }
172 2562 : else if( psShape->nParts == 1 )
173 : {
174 2542 : OGRLineString *poOGRLine = new OGRLineString();
175 :
176 2542 : if( psShape->nSHPType == SHPT_ARCZ )
177 : poOGRLine->setPoints( psShape->nVertices,
178 2510 : psShape->padfX, psShape->padfY, psShape->padfZ );
179 32 : else if( psShape->nSHPType == SHPT_ARCM )
180 : // Read XYM as XYZ
181 : poOGRLine->setPoints( psShape->nVertices,
182 0 : psShape->padfX, psShape->padfY, psShape->padfM );
183 : else
184 : poOGRLine->setPoints( psShape->nVertices,
185 32 : psShape->padfX, psShape->padfY );
186 :
187 2542 : poOGR = poOGRLine;
188 : }
189 : else
190 : {
191 : int iRing;
192 : OGRMultiLineString *poOGRMulti;
193 :
194 20 : poOGR = poOGRMulti = new OGRMultiLineString();
195 :
196 62 : for( iRing = 0; iRing < psShape->nParts; iRing++ )
197 : {
198 : OGRLineString *poLine;
199 : int nRingPoints;
200 : int nRingStart;
201 :
202 42 : poLine = new OGRLineString();
203 :
204 42 : if( psShape->panPartStart == NULL )
205 : {
206 0 : nRingPoints = psShape->nVertices;
207 0 : nRingStart = 0;
208 : }
209 : else
210 : {
211 :
212 42 : if( iRing == psShape->nParts - 1 )
213 : nRingPoints =
214 20 : psShape->nVertices - psShape->panPartStart[iRing];
215 : else
216 22 : nRingPoints = psShape->panPartStart[iRing+1]
217 22 : - psShape->panPartStart[iRing];
218 42 : nRingStart = psShape->panPartStart[iRing];
219 : }
220 :
221 42 : if( psShape->nSHPType == SHPT_ARCZ )
222 : poLine->setPoints( nRingPoints,
223 : psShape->padfX + nRingStart,
224 : psShape->padfY + nRingStart,
225 12 : psShape->padfZ + nRingStart );
226 30 : else if( psShape->nSHPType == SHPT_ARCM )
227 : // Read XYM as XYZ
228 : poLine->setPoints( nRingPoints,
229 : psShape->padfX + nRingStart,
230 : psShape->padfY + nRingStart,
231 0 : psShape->padfM + nRingStart );
232 : else
233 : poLine->setPoints( nRingPoints,
234 : psShape->padfX + nRingStart,
235 30 : psShape->padfY + nRingStart );
236 :
237 42 : poOGRMulti->addGeometryDirectly( poLine );
238 : }
239 : }
240 : }
241 :
242 : /* -------------------------------------------------------------------- */
243 : /* Polygon */
244 : /* */
245 : /* As for now Z coordinate is not handled correctly */
246 : /* -------------------------------------------------------------------- */
247 117536 : else if( psShape->nSHPType == SHPT_POLYGON
248 : || psShape->nSHPType == SHPT_POLYGONM
249 : || psShape->nSHPType == SHPT_POLYGONZ )
250 : {
251 : int iRing;
252 58081 : int bHasZ = ( psShape->nSHPType == SHPT_POLYGONZ );
253 :
254 : //CPLDebug( "Shape", "Shape type: polygon with nParts=%d \n", psShape->nParts );
255 :
256 58081 : if ( psShape->nParts == 0 )
257 : {
258 2 : poOGR = NULL;
259 : }
260 58079 : else if ( psShape->nParts == 1 )
261 : {
262 : /* Surely outer ring */
263 58015 : OGRPolygon *poOGRPoly = NULL;
264 58015 : OGRLinearRing *poRing = NULL;
265 :
266 58015 : poOGR = poOGRPoly = new OGRPolygon();
267 58015 : poRing = CreateLinearRing ( psShape, 0, bHasZ );
268 58015 : poOGRPoly->addRingDirectly( poRing );
269 : }
270 :
271 : else
272 : {
273 64 : OGRPolygon** tabPolygons = new OGRPolygon*[psShape->nParts];
274 472 : for( iRing = 0; iRing < psShape->nParts; iRing++ )
275 : {
276 172 : tabPolygons[iRing] = new OGRPolygon();
277 172 : tabPolygons[iRing]->addRingDirectly(CreateLinearRing ( psShape, iRing, bHasZ ));
278 : }
279 :
280 : int isValidGeometry;
281 64 : const char* papszOptions[] = { "METHOD=ONLY_CCW", NULL };
282 : poOGR = OGRGeometryFactory::organizePolygons(
283 64 : (OGRGeometry**)tabPolygons, psShape->nParts, &isValidGeometry, papszOptions );
284 :
285 64 : if (!isValidGeometry)
286 : {
287 : CPLError(CE_Warning, CPLE_AppDefined,
288 : "Geometry of polygon of fid %d cannot be translated to Simple Geometry. "
289 : "All polygons will be contained in a multipolygon.\n",
290 0 : iShape);
291 : }
292 :
293 64 : delete[] tabPolygons;
294 : }
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* MultiPatch */
299 : /* -------------------------------------------------------------------- */
300 1374 : else if( psShape->nSHPType == SHPT_MULTIPATCH )
301 : {
302 2 : OGRMultiPolygon *poMP = new OGRMultiPolygon();
303 : int iPart;
304 2 : OGRPolygon *poLastPoly = NULL;
305 :
306 12 : for( iPart = 0; iPart < psShape->nParts; iPart++ )
307 : {
308 : int nPartPoints, nPartStart;
309 :
310 : // Figure out details about this part's vertex list.
311 10 : if( psShape->panPartStart == NULL )
312 : {
313 0 : nPartPoints = psShape->nVertices;
314 0 : nPartStart = 0;
315 : }
316 : else
317 : {
318 :
319 10 : if( iPart == psShape->nParts - 1 )
320 : nPartPoints =
321 2 : psShape->nVertices - psShape->panPartStart[iPart];
322 : else
323 8 : nPartPoints = psShape->panPartStart[iPart+1]
324 8 : - psShape->panPartStart[iPart];
325 10 : nPartStart = psShape->panPartStart[iPart];
326 : }
327 :
328 10 : if( psShape->panPartType[iPart] == SHPP_TRISTRIP )
329 : {
330 : int iBaseVert;
331 :
332 2 : if( poLastPoly != NULL )
333 : {
334 0 : poMP->addGeometryDirectly( poLastPoly );
335 0 : poLastPoly = NULL;
336 : }
337 :
338 28 : for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
339 : {
340 12 : OGRPolygon *poPoly = new OGRPolygon();
341 24 : OGRLinearRing *poRing = new OGRLinearRing();
342 12 : int iSrcVert = iBaseVert + nPartStart;
343 :
344 : poRing->setPoint( 0,
345 : psShape->padfX[iSrcVert],
346 : psShape->padfY[iSrcVert],
347 12 : psShape->padfZ[iSrcVert] );
348 : poRing->setPoint( 1,
349 : psShape->padfX[iSrcVert+1],
350 : psShape->padfY[iSrcVert+1],
351 12 : psShape->padfZ[iSrcVert+1] );
352 :
353 : poRing->setPoint( 2,
354 : psShape->padfX[iSrcVert+2],
355 : psShape->padfY[iSrcVert+2],
356 12 : psShape->padfZ[iSrcVert+2] );
357 : poRing->setPoint( 3,
358 : psShape->padfX[iSrcVert],
359 : psShape->padfY[iSrcVert],
360 12 : psShape->padfZ[iSrcVert] );
361 :
362 12 : poPoly->addRingDirectly( poRing );
363 12 : poMP->addGeometryDirectly( poPoly );
364 : }
365 : }
366 8 : else if( psShape->panPartType[iPart] == SHPP_TRIFAN )
367 : {
368 : int iBaseVert;
369 :
370 2 : if( poLastPoly != NULL )
371 : {
372 0 : poMP->addGeometryDirectly( poLastPoly );
373 0 : poLastPoly = NULL;
374 : }
375 :
376 20 : for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
377 : {
378 8 : OGRPolygon *poPoly = new OGRPolygon();
379 16 : OGRLinearRing *poRing = new OGRLinearRing();
380 8 : int iSrcVert = iBaseVert + nPartStart;
381 :
382 : poRing->setPoint( 0,
383 : psShape->padfX[nPartStart],
384 : psShape->padfY[nPartStart],
385 8 : psShape->padfZ[nPartStart] );
386 : poRing->setPoint( 1,
387 : psShape->padfX[iSrcVert+1],
388 : psShape->padfY[iSrcVert+1],
389 8 : psShape->padfZ[iSrcVert+1] );
390 :
391 : poRing->setPoint( 2,
392 : psShape->padfX[iSrcVert+2],
393 : psShape->padfY[iSrcVert+2],
394 8 : psShape->padfZ[iSrcVert+2] );
395 : poRing->setPoint( 3,
396 : psShape->padfX[nPartStart],
397 : psShape->padfY[nPartStart],
398 8 : psShape->padfZ[nPartStart] );
399 :
400 8 : poPoly->addRingDirectly( poRing );
401 8 : poMP->addGeometryDirectly( poPoly );
402 : }
403 : }
404 16 : else if( psShape->panPartType[iPart] == SHPP_OUTERRING
405 4 : || psShape->panPartType[iPart] == SHPP_INNERRING
406 0 : || psShape->panPartType[iPart] == SHPP_FIRSTRING
407 0 : || psShape->panPartType[iPart] == SHPP_RING )
408 : {
409 14 : if( poLastPoly != NULL
410 4 : && (psShape->panPartType[iPart] == SHPP_OUTERRING
411 4 : || psShape->panPartType[iPart] == SHPP_FIRSTRING) )
412 : {
413 0 : poMP->addGeometryDirectly( poLastPoly );
414 0 : poLastPoly = NULL;
415 : }
416 :
417 6 : if( poLastPoly == NULL )
418 2 : poLastPoly = new OGRPolygon();
419 :
420 : poLastPoly->addRingDirectly(
421 6 : CreateLinearRing( psShape, iPart, TRUE ) );
422 : }
423 : else
424 : CPLDebug( "OGR", "Unrecognised parttype %d, ignored.",
425 0 : psShape->panPartType[iPart] );
426 : }
427 :
428 2 : if( poLastPoly != NULL )
429 : {
430 2 : poMP->addGeometryDirectly( poLastPoly );
431 2 : poLastPoly = NULL;
432 : }
433 :
434 2 : poOGR = poMP;
435 : }
436 :
437 : /* -------------------------------------------------------------------- */
438 : /* Otherwise for now we just ignore the object. */
439 : /* -------------------------------------------------------------------- */
440 : else
441 : {
442 1372 : if( psShape->nSHPType != SHPT_NULL )
443 : {
444 0 : CPLDebug( "OGR", "Unsupported shape type in SHPReadOGRObject()" );
445 : }
446 :
447 : /* nothing returned */
448 : }
449 :
450 : /* -------------------------------------------------------------------- */
451 : /* Cleanup shape, and set feature id. */
452 : /* -------------------------------------------------------------------- */
453 92397 : SHPDestroyObject( psShape );
454 :
455 92397 : return poOGR;
456 : }
457 :
458 : /************************************************************************/
459 : /* SHPWriteOGRObject() */
460 : /************************************************************************/
461 :
462 59094 : OGRErr SHPWriteOGRObject( SHPHandle hSHP, int iShape, OGRGeometry *poGeom )
463 :
464 : {
465 : int nReturnedShapeID;
466 : /* ==================================================================== */
467 : /* Write "shape" with no geometry or with empty geometry */
468 : /* ==================================================================== */
469 59094 : if( poGeom == NULL || poGeom->IsEmpty() )
470 : {
471 : SHPObject *psShape;
472 :
473 1076 : psShape = SHPCreateSimpleObject( SHPT_NULL, 0, NULL, NULL, NULL );
474 1076 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
475 1076 : SHPDestroyObject( psShape );
476 1076 : if( nReturnedShapeID == -1 )
477 : {
478 : //Assuming error is reported by SHPWriteObject()
479 0 : return OGRERR_FAILURE;
480 : }
481 : }
482 :
483 : /* ==================================================================== */
484 : /* Write point geometry. */
485 : /* ==================================================================== */
486 88384 : else if( hSHP->nShapeType == SHPT_POINT
487 : || hSHP->nShapeType == SHPT_POINTM
488 : || hSHP->nShapeType == SHPT_POINTZ )
489 : {
490 : SHPObject *psShape;
491 30378 : OGRPoint *poPoint = (OGRPoint *) poGeom;
492 30378 : double dfX, dfY, dfZ = 0;
493 :
494 59678 : if( poGeom->getGeometryType() != wkbPoint
495 29300 : && poGeom->getGeometryType() != wkbPoint25D )
496 : {
497 : CPLError( CE_Failure, CPLE_AppDefined,
498 : "Attempt to write non-point (%s) geometry to"
499 : " point shapefile.",
500 12 : poGeom->getGeometryName() );
501 :
502 12 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
503 : }
504 :
505 30366 : dfX = poPoint->getX();
506 30366 : dfY = poPoint->getY();
507 30366 : dfZ = poPoint->getZ();
508 :
509 : psShape = SHPCreateSimpleObject( hSHP->nShapeType, 1,
510 30366 : &dfX, &dfY, &dfZ );
511 30366 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
512 30366 : SHPDestroyObject( psShape );
513 30366 : if( nReturnedShapeID == -1 )
514 0 : return OGRERR_FAILURE;
515 : }
516 : /* ==================================================================== */
517 : /* MultiPoint. */
518 : /* ==================================================================== */
519 27654 : else if( hSHP->nShapeType == SHPT_MULTIPOINT
520 : || hSHP->nShapeType == SHPT_MULTIPOINTM
521 : || hSHP->nShapeType == SHPT_MULTIPOINTZ )
522 : {
523 26 : OGRMultiPoint *poMP = (OGRMultiPoint *) poGeom;
524 : double *padfX, *padfY, *padfZ;
525 : int iPoint;
526 : SHPObject *psShape;
527 :
528 26 : if( wkbFlatten(poGeom->getGeometryType()) != wkbMultiPoint )
529 : {
530 : CPLError( CE_Failure, CPLE_AppDefined,
531 : "Attempt to write non-multipoint (%s) geometry to "
532 : "multipoint shapefile.",
533 12 : poGeom->getGeometryName() );
534 :
535 12 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
536 : }
537 :
538 14 : padfX = (double *) CPLMalloc(sizeof(double)*poMP->getNumGeometries());
539 14 : padfY = (double *) CPLMalloc(sizeof(double)*poMP->getNumGeometries());
540 14 : padfZ = (double *) CPLCalloc(sizeof(double),poMP->getNumGeometries());
541 :
542 14 : int iDstPoints = 0;
543 42 : for( iPoint = 0; iPoint < poMP->getNumGeometries(); iPoint++ )
544 : {
545 28 : OGRPoint *poPoint = (OGRPoint *) poMP->getGeometryRef(iPoint);
546 :
547 : /* Ignore POINT EMPTY */
548 28 : if (poPoint->IsEmpty() == FALSE)
549 : {
550 26 : padfX[iDstPoints] = poPoint->getX();
551 26 : padfY[iDstPoints] = poPoint->getY();
552 26 : padfZ[iDstPoints] = poPoint->getZ();
553 26 : iDstPoints ++;
554 : }
555 : else
556 : CPLDebug( "OGR",
557 2 : "Ignore POINT EMPTY inside MULTIPOINT in shapefile writer." );
558 : }
559 :
560 : psShape = SHPCreateSimpleObject( hSHP->nShapeType,
561 : iDstPoints,
562 14 : padfX, padfY, padfZ );
563 14 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
564 14 : SHPDestroyObject( psShape );
565 :
566 14 : CPLFree( padfX );
567 14 : CPLFree( padfY );
568 14 : CPLFree( padfZ );
569 14 : if( nReturnedShapeID == -1 )
570 0 : return OGRERR_FAILURE;
571 : }
572 :
573 : /* ==================================================================== */
574 : /* Arcs from simple line strings. */
575 : /* ==================================================================== */
576 29182 : else if( (hSHP->nShapeType == SHPT_ARC
577 : || hSHP->nShapeType == SHPT_ARCM
578 : || hSHP->nShapeType == SHPT_ARCZ)
579 1568 : && wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
580 : {
581 1528 : OGRLineString *poArc = (OGRLineString *) poGeom;
582 : double *padfX, *padfY, *padfZ;
583 : int iPoint;
584 : SHPObject *psShape;
585 :
586 1528 : padfX = (double *) CPLMalloc(sizeof(double)*poArc->getNumPoints());
587 1528 : padfY = (double *) CPLMalloc(sizeof(double)*poArc->getNumPoints());
588 1528 : padfZ = (double *) CPLCalloc(sizeof(double),poArc->getNumPoints());
589 :
590 44620 : for( iPoint = 0; iPoint < poArc->getNumPoints(); iPoint++ )
591 : {
592 43092 : padfX[iPoint] = poArc->getX( iPoint );
593 43092 : padfY[iPoint] = poArc->getY( iPoint );
594 43092 : padfZ[iPoint] = poArc->getZ( iPoint );
595 : }
596 :
597 : psShape = SHPCreateSimpleObject( hSHP->nShapeType,
598 : poArc->getNumPoints(),
599 1528 : padfX, padfY, padfZ );
600 1528 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
601 1528 : SHPDestroyObject( psShape );
602 :
603 1528 : CPLFree( padfX );
604 1528 : CPLFree( padfY );
605 1528 : CPLFree( padfZ );
606 1528 : if( nReturnedShapeID == -1 )
607 0 : return OGRERR_FAILURE;
608 : }
609 : /* ==================================================================== */
610 : /* Arcs - Try to treat as MultiLineString. */
611 : /* ==================================================================== */
612 26102 : else if( hSHP->nShapeType == SHPT_ARC
613 : || hSHP->nShapeType == SHPT_ARCM
614 : || hSHP->nShapeType == SHPT_ARCZ )
615 : {
616 : OGRMultiLineString *poML;
617 40 : double *padfX=NULL, *padfY=NULL, *padfZ=NULL;
618 40 : int iGeom, iPoint, nPointCount = 0;
619 : SHPObject *psShape;
620 : int *panRingStart;
621 40 : int nParts = 0;
622 :
623 : poML = (OGRMultiLineString *)
624 40 : OGRGeometryFactory::forceToMultiLineString( poGeom->clone() );
625 :
626 40 : if( wkbFlatten(poML->getGeometryType()) != wkbMultiLineString )
627 : {
628 24 : delete poML;
629 : CPLError( CE_Failure, CPLE_AppDefined,
630 : "Attempt to write non-linestring (%s) geometry to "
631 : "ARC type shapefile.",
632 24 : poGeom->getGeometryName() );
633 :
634 24 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
635 : }
636 :
637 : panRingStart = (int *)
638 16 : CPLMalloc(sizeof(int) * poML->getNumGeometries());
639 :
640 52 : for( iGeom = 0; iGeom < poML->getNumGeometries(); iGeom++ )
641 : {
642 : OGRLineString *poArc = (OGRLineString *)
643 36 : poML->getGeometryRef(iGeom);
644 36 : int nNewPoints = poArc->getNumPoints();
645 :
646 : /* Ignore LINESTRING EMPTY */
647 36 : if (nNewPoints == 0)
648 : {
649 : CPLDebug( "OGR",
650 2 : "Ignore LINESTRING EMPTY inside MULTILINESTRING in shapefile writer." );
651 2 : continue;
652 : }
653 :
654 34 : panRingStart[nParts ++] = nPointCount;
655 :
656 : padfX = (double *)
657 34 : CPLRealloc( padfX, sizeof(double)*(nNewPoints+nPointCount) );
658 : padfY = (double *)
659 34 : CPLRealloc( padfY, sizeof(double)*(nNewPoints+nPointCount) );
660 : padfZ = (double *)
661 34 : CPLRealloc( padfZ, sizeof(double)*(nNewPoints+nPointCount) );
662 :
663 160 : for( iPoint = 0; iPoint < nNewPoints; iPoint++ )
664 : {
665 126 : padfX[nPointCount] = poArc->getX( iPoint );
666 126 : padfY[nPointCount] = poArc->getY( iPoint );
667 126 : padfZ[nPointCount] = poArc->getZ( iPoint );
668 126 : nPointCount++;
669 : }
670 : }
671 :
672 16 : CPLAssert(nParts != 0);
673 :
674 : psShape = SHPCreateObject( hSHP->nShapeType, iShape,
675 : nParts,
676 : panRingStart, NULL,
677 16 : nPointCount, padfX, padfY, padfZ, NULL);
678 16 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
679 16 : SHPDestroyObject( psShape );
680 :
681 16 : CPLFree( panRingStart );
682 16 : CPLFree( padfX );
683 16 : CPLFree( padfY );
684 16 : CPLFree( padfZ );
685 :
686 16 : delete poML;
687 16 : if( nReturnedShapeID == -1 )
688 0 : return OGRERR_FAILURE;
689 : }
690 :
691 : /* ==================================================================== */
692 : /* Polygons/MultiPolygons */
693 : /* ==================================================================== */
694 52064 : else if( hSHP->nShapeType == SHPT_POLYGON
695 : || hSHP->nShapeType == SHPT_POLYGONM
696 : || hSHP->nShapeType == SHPT_POLYGONZ )
697 : {
698 : OGRPolygon *poPoly;
699 26046 : OGRLinearRing *poRing, **papoRings=NULL;
700 26046 : double *padfX=NULL, *padfY=NULL, *padfZ=NULL;
701 26046 : int iPoint, iRing, nRings, nVertex=0, *panRingStart;
702 : SHPObject *psShape;
703 :
704 : /* Collect list of rings */
705 :
706 26046 : if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
707 : {
708 25972 : poPoly = (OGRPolygon *) poGeom;
709 :
710 51944 : if( poPoly->getExteriorRing() == NULL ||
711 25972 : poPoly->getExteriorRing()->IsEmpty() )
712 : {
713 : CPLDebug( "OGR",
714 2 : "Ignore POLYGON EMPTY in shapefile writer." );
715 2 : nRings = 0;
716 : }
717 : else
718 : {
719 25970 : int nSrcRings = poPoly->getNumInteriorRings()+1;
720 25970 : nRings = 0;
721 25970 : papoRings = (OGRLinearRing **) CPLMalloc(sizeof(void*)*nSrcRings);
722 51962 : for( iRing = 0; iRing < nSrcRings; iRing++ )
723 : {
724 25992 : if( iRing == 0 )
725 25970 : papoRings[nRings] = poPoly->getExteriorRing();
726 : else
727 22 : papoRings[nRings] = poPoly->getInteriorRing( iRing-1 );
728 :
729 : /* Ignore LINEARRING EMPTY */
730 25992 : if (papoRings[nRings]->getNumPoints() != 0)
731 25990 : nRings ++;
732 : else
733 : CPLDebug( "OGR",
734 2 : "Ignore LINEARRING EMPTY inside POLYGON in shapefile writer." );
735 : }
736 : }
737 : }
738 102 : else if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon
739 28 : || wkbFlatten(poGeom->getGeometryType())
740 : == wkbGeometryCollection )
741 : {
742 50 : OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
743 : int iGeom;
744 :
745 50 : nRings = 0;
746 138 : for( iGeom=0; iGeom < poGC->getNumGeometries(); iGeom++ )
747 : {
748 90 : poPoly = (OGRPolygon *) poGC->getGeometryRef( iGeom );
749 :
750 90 : if( wkbFlatten(poPoly->getGeometryType()) != wkbPolygon )
751 : {
752 2 : CPLFree( papoRings );
753 : CPLError( CE_Failure, CPLE_AppDefined,
754 : "Attempt to write non-polygon (%s) geometry to "
755 : "POLYGON type shapefile.",
756 2 : poGeom->getGeometryName());
757 :
758 2 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
759 : }
760 :
761 : /* Ignore POLYGON EMPTY */
762 174 : if( poPoly->getExteriorRing() == NULL ||
763 86 : poPoly->getExteriorRing()->IsEmpty() )
764 : {
765 : CPLDebug( "OGR",
766 2 : "Ignore POLYGON EMPTY inside MULTIPOLYGON in shapefile writer." );
767 2 : continue;
768 : }
769 :
770 : papoRings = (OGRLinearRing **) CPLRealloc(papoRings,
771 86 : sizeof(void*) * (nRings+poPoly->getNumInteriorRings()+1));
772 196 : for( iRing = 0;
773 : iRing < poPoly->getNumInteriorRings()+1;
774 : iRing++ )
775 : {
776 110 : if( iRing == 0 )
777 86 : papoRings[nRings] = poPoly->getExteriorRing();
778 : else
779 24 : papoRings[nRings] =
780 24 : poPoly->getInteriorRing( iRing-1 );
781 :
782 : /* Ignore LINEARRING EMPTY */
783 110 : if (papoRings[nRings]->getNumPoints() != 0)
784 108 : nRings ++;
785 : else
786 : CPLDebug( "OGR",
787 2 : "Ignore LINEARRING EMPTY inside POLYGON in shapefile writer." );
788 : }
789 : }
790 : }
791 : else
792 : {
793 : CPLError( CE_Failure, CPLE_AppDefined,
794 : "Attempt to write non-polygon (%s) geometry to "
795 : "POLYGON type shapefile.",
796 24 : poGeom->getGeometryName() );
797 :
798 24 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
799 : }
800 :
801 : /* -------------------------------------------------------------------- */
802 : /* If we only had emptypolygons or unacceptable geometries */
803 : /* write NULL geometry object. */
804 : /* -------------------------------------------------------------------- */
805 26020 : if( nRings == 0 )
806 : {
807 : SHPObject *psShape;
808 :
809 2 : psShape = SHPCreateSimpleObject( SHPT_NULL, 0, NULL, NULL, NULL );
810 2 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
811 2 : SHPDestroyObject( psShape );
812 :
813 2 : if( nReturnedShapeID == -1 )
814 0 : return OGRERR_FAILURE;
815 :
816 2 : return OGRERR_NONE;
817 : }
818 :
819 : /* count vertices */
820 26018 : nVertex = 0;
821 52116 : for( iRing = 0; iRing < nRings; iRing++ )
822 26098 : nVertex += papoRings[iRing]->getNumPoints();
823 :
824 26018 : panRingStart = (int *) CPLMalloc(sizeof(int) * nRings);
825 26018 : padfX = (double *) CPLMalloc(sizeof(double)*nVertex);
826 26018 : padfY = (double *) CPLMalloc(sizeof(double)*nVertex);
827 26018 : padfZ = (double *) CPLMalloc(sizeof(double)*nVertex);
828 :
829 : /* collect vertices */
830 26018 : nVertex = 0;
831 52116 : for( iRing = 0; iRing < nRings; iRing++ )
832 : {
833 26098 : poRing = papoRings[iRing];
834 26098 : panRingStart[iRing] = nVertex;
835 :
836 178952 : for( iPoint = 0; iPoint < poRing->getNumPoints(); iPoint++ )
837 : {
838 152854 : padfX[nVertex] = poRing->getX( iPoint );
839 152854 : padfY[nVertex] = poRing->getY( iPoint );
840 152854 : padfZ[nVertex] = poRing->getZ( iPoint );
841 152854 : nVertex++;
842 : }
843 : }
844 :
845 : psShape = SHPCreateObject( hSHP->nShapeType, iShape, nRings,
846 : panRingStart, NULL,
847 26018 : nVertex, padfX, padfY, padfZ, NULL );
848 26018 : SHPRewindObject( hSHP, psShape );
849 26018 : nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
850 26018 : SHPDestroyObject( psShape );
851 :
852 26018 : CPLFree( papoRings );
853 26018 : CPLFree( panRingStart );
854 26018 : CPLFree( padfX );
855 26018 : CPLFree( padfY );
856 26018 : CPLFree( padfZ );
857 26018 : if( nReturnedShapeID == -1 )
858 0 : return OGRERR_FAILURE;
859 : }
860 : else
861 : {
862 : /* do nothing for multipatch */
863 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
864 : }
865 :
866 59018 : return OGRERR_NONE;
867 : }
868 :
869 : /************************************************************************/
870 : /* SHPReadOGRFeatureDefn() */
871 : /************************************************************************/
872 :
873 7390 : OGRFeatureDefn *SHPReadOGRFeatureDefn( const char * pszName,
874 : SHPHandle hSHP, DBFHandle hDBF,
875 : const char* pszSHPEncoding )
876 :
877 : {
878 7390 : OGRFeatureDefn *poDefn = new OGRFeatureDefn( pszName );
879 : int iField;
880 :
881 7390 : poDefn->Reference();
882 :
883 13928 : for( iField = 0;
884 : hDBF != NULL && iField < DBFGetFieldCount( hDBF );
885 : iField++ )
886 : {
887 : char szFieldName[20];
888 : int nWidth, nPrecision;
889 : DBFFieldType eDBFType;
890 6538 : OGRFieldDefn oField("", OFTInteger);
891 : char chNativeType;
892 :
893 6538 : chNativeType = DBFGetNativeFieldType( hDBF, iField );
894 : eDBFType = DBFGetFieldInfo( hDBF, iField, szFieldName,
895 6538 : &nWidth, &nPrecision );
896 :
897 6538 : if( strlen(pszSHPEncoding) > 0 )
898 : {
899 : char *pszUTF8Field = CPLRecode( szFieldName,
900 5352 : pszSHPEncoding, CPL_ENC_UTF8);
901 5352 : oField.SetName( pszUTF8Field );
902 5352 : CPLFree( pszUTF8Field );
903 : }
904 : else
905 1186 : oField.SetName( szFieldName );
906 :
907 6538 : oField.SetWidth( nWidth );
908 6538 : oField.SetPrecision( nPrecision );
909 :
910 6538 : if( chNativeType == 'D' )
911 : {
912 : /* XXX - mloskot:
913 : * Shapefile date has following 8-chars long format: 20060101.
914 : * OGR splits it as YYYY/MM/DD, so 2 additional characters are required.
915 : * Is this correct assumtion? What about time part of date?
916 : * Shouldn't this format look as datetime: YYYY/MM/DD HH:MM:SS
917 : * with 4 additional characters?
918 : */
919 38 : oField.SetWidth( nWidth + 2 );
920 38 : oField.SetType( OFTDate );
921 : }
922 6500 : else if( eDBFType == FTDouble )
923 2330 : oField.SetType( OFTReal );
924 4170 : else if( eDBFType == FTInteger )
925 188 : oField.SetType( OFTInteger );
926 : else
927 3982 : oField.SetType( OFTString );
928 :
929 6538 : poDefn->AddFieldDefn( &oField );
930 : }
931 :
932 7390 : if( hSHP == NULL )
933 54 : poDefn->SetGeomType( wkbNone );
934 : else
935 : {
936 7336 : switch( hSHP->nShapeType )
937 : {
938 : case SHPT_POINT:
939 1694 : poDefn->SetGeomType( wkbPoint );
940 1694 : break;
941 :
942 : case SHPT_POINTZ:
943 : case SHPT_POINTM:
944 96 : poDefn->SetGeomType( wkbPoint25D );
945 96 : break;
946 :
947 : case SHPT_ARC:
948 4040 : poDefn->SetGeomType( wkbLineString );
949 4040 : break;
950 :
951 : case SHPT_ARCZ:
952 : case SHPT_ARCM:
953 152 : poDefn->SetGeomType( wkbLineString25D );
954 152 : break;
955 :
956 : case SHPT_MULTIPOINT:
957 152 : poDefn->SetGeomType( wkbMultiPoint );
958 152 : break;
959 :
960 : case SHPT_MULTIPOINTZ:
961 : case SHPT_MULTIPOINTM:
962 82 : poDefn->SetGeomType( wkbMultiPoint25D );
963 82 : break;
964 :
965 : case SHPT_POLYGON:
966 986 : poDefn->SetGeomType( wkbPolygon );
967 986 : break;
968 :
969 : case SHPT_POLYGONZ:
970 : case SHPT_POLYGONM:
971 132 : poDefn->SetGeomType( wkbPolygon25D );
972 : break;
973 :
974 : }
975 : }
976 :
977 7390 : return poDefn;
978 : }
979 :
980 : /************************************************************************/
981 : /* SHPReadOGRFeature() */
982 : /************************************************************************/
983 :
984 95490 : OGRFeature *SHPReadOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
985 : OGRFeatureDefn * poDefn, int iShape,
986 : SHPObject *psShape, const char *pszSHPEncoding )
987 :
988 : {
989 95490 : if( iShape < 0
990 : || (hSHP != NULL && iShape >= hSHP->nRecords)
991 : || (hDBF != NULL && iShape >= hDBF->nRecords) )
992 : {
993 : CPLError( CE_Failure, CPLE_AppDefined,
994 : "Attempt to read shape with feature id (%d) out of available"
995 2 : " range.", iShape );
996 2 : return NULL;
997 : }
998 :
999 95488 : if( hDBF && DBFIsRecordDeleted( hDBF, iShape ) )
1000 : {
1001 : CPLError( CE_Failure, CPLE_AppDefined,
1002 : "Attempt to read shape with feature id (%d), but it is marked deleted.",
1003 2 : iShape );
1004 2 : return NULL;
1005 : }
1006 :
1007 95486 : OGRFeature *poFeature = new OGRFeature( poDefn );
1008 :
1009 : /* -------------------------------------------------------------------- */
1010 : /* Fetch geometry from Shapefile to OGRFeature. */
1011 : /* -------------------------------------------------------------------- */
1012 189728 : if( hSHP != NULL && !poDefn->IsGeometryIgnored() )
1013 : {
1014 91340 : OGRGeometry* poGeometry = NULL;
1015 91340 : poGeometry = SHPReadOGRObject( hSHP, iShape, psShape );
1016 :
1017 : /*
1018 : * NOTE - mloskot:
1019 : * Two possibilities are expected here (bot hare tested by GDAL Autotests):
1020 : * 1. Read valid geometry and assign it directly.
1021 : * 2. Read and assign null geometry if it can not be read correctly from a shapefile
1022 : *
1023 : * It's NOT required here to test poGeometry == NULL.
1024 : */
1025 :
1026 91340 : poFeature->SetGeometryDirectly( poGeometry );
1027 : }
1028 :
1029 : /* -------------------------------------------------------------------- */
1030 : /* Fetch feature attributes to OGRFeature fields. */
1031 : /* -------------------------------------------------------------------- */
1032 :
1033 197474 : for( int iField = 0; iField < poDefn->GetFieldCount(); iField++ )
1034 : {
1035 101988 : OGRFieldDefn* poFieldDefn = poDefn->GetFieldDefn(iField);
1036 101988 : if (poFieldDefn->IsIgnored() )
1037 2648 : continue;
1038 :
1039 99340 : switch( poFieldDefn->GetType() )
1040 : {
1041 : case OFTString:
1042 : {
1043 : const char *pszFieldVal =
1044 12222 : DBFReadStringAttribute( hDBF, iShape, iField );
1045 12222 : if( pszFieldVal != NULL && pszFieldVal[0] != '\0' )
1046 : {
1047 10246 : if( pszSHPEncoding[0] != '\0' )
1048 : {
1049 : char *pszUTF8Field = CPLRecode( pszFieldVal,
1050 4000 : pszSHPEncoding, CPL_ENC_UTF8);
1051 4000 : poFeature->SetField( iField, pszUTF8Field );
1052 4000 : CPLFree( pszUTF8Field );
1053 : }
1054 : else
1055 6246 : poFeature->SetField( iField, pszFieldVal );
1056 : }
1057 : }
1058 12222 : break;
1059 :
1060 : case OFTInteger:
1061 :
1062 3880 : if( !DBFIsAttributeNULL( hDBF, iShape, iField ) )
1063 : poFeature->SetField( iField,
1064 : DBFReadIntegerAttribute( hDBF, iShape,
1065 3836 : iField ) );
1066 3880 : break;
1067 :
1068 : case OFTReal:
1069 83234 : if( !DBFIsAttributeNULL( hDBF, iShape, iField ) )
1070 : poFeature->SetField( iField,
1071 : DBFReadDoubleAttribute( hDBF, iShape,
1072 83220 : iField ) );
1073 83234 : break;
1074 :
1075 : case OFTDate:
1076 : {
1077 : OGRField sFld;
1078 4 : if( DBFIsAttributeNULL( hDBF, iShape, iField ) )
1079 0 : continue;
1080 :
1081 : const char* pszDateValue =
1082 4 : DBFReadStringAttribute(hDBF,iShape,iField);
1083 :
1084 : /* Some DBF files have fields filled with spaces */
1085 : /* (trimmed by DBFReadStringAttribute) to indicate null */
1086 : /* values for dates (#4265) */
1087 4 : if (pszDateValue[0] == '\0')
1088 0 : continue;
1089 :
1090 4 : memset( &sFld, 0, sizeof(sFld) );
1091 :
1092 10 : if( strlen(pszDateValue) >= 10 &&
1093 4 : pszDateValue[2] == '/' && pszDateValue[5] == '/' )
1094 : {
1095 2 : sFld.Date.Month = (GByte)atoi(pszDateValue+0);
1096 2 : sFld.Date.Day = (GByte)atoi(pszDateValue+3);
1097 2 : sFld.Date.Year = (GInt16)atoi(pszDateValue+6);
1098 : }
1099 : else
1100 : {
1101 2 : int nFullDate = atoi(pszDateValue);
1102 2 : sFld.Date.Year = (GInt16)(nFullDate / 10000);
1103 2 : sFld.Date.Month = (GByte)((nFullDate / 100) % 100);
1104 2 : sFld.Date.Day = (GByte)(nFullDate % 100);
1105 : }
1106 :
1107 4 : poFeature->SetField( iField, &sFld );
1108 : }
1109 4 : break;
1110 :
1111 : default:
1112 0 : CPLAssert( FALSE );
1113 : }
1114 : }
1115 :
1116 95486 : if( poFeature != NULL )
1117 95486 : poFeature->SetFID( iShape );
1118 :
1119 95486 : return( poFeature );
1120 : }
1121 :
1122 : /************************************************************************/
1123 : /* GrowField() */
1124 : /************************************************************************/
1125 :
1126 4 : static OGRErr GrowField(DBFHandle hDBF, int iField, OGRFieldDefn* poFieldDefn,
1127 : int nNewSize)
1128 : {
1129 : char szFieldName[20];
1130 : int nOriWidth, nPrecision;
1131 : char chNativeType;
1132 : DBFFieldType eDBFType;
1133 :
1134 4 : chNativeType = DBFGetNativeFieldType( hDBF, iField );
1135 : eDBFType = DBFGetFieldInfo( hDBF, iField, szFieldName,
1136 4 : &nOriWidth, &nPrecision );
1137 :
1138 : CPLDebug("SHAPE", "Extending field %d (%s) from %d to %d characters",
1139 4 : iField, poFieldDefn->GetNameRef(), nOriWidth, nNewSize);
1140 :
1141 4 : if ( !DBFAlterFieldDefn( hDBF, iField, szFieldName,
1142 : chNativeType, nNewSize, nPrecision ) )
1143 : {
1144 : CPLError(CE_Failure, CPLE_AppDefined,
1145 : "Extending field %d (%s) from %d to %d characters failed",
1146 0 : iField, poFieldDefn->GetNameRef(), nOriWidth, nNewSize);
1147 0 : return OGRERR_FAILURE;
1148 : }
1149 : else
1150 : {
1151 4 : poFieldDefn->SetWidth(nNewSize);
1152 4 : return OGRERR_NONE;
1153 : }
1154 : }
1155 :
1156 : /************************************************************************/
1157 : /* SHPWriteOGRFeature() */
1158 : /* */
1159 : /* Write to an existing feature in a shapefile, or create a new */
1160 : /* feature. */
1161 : /************************************************************************/
1162 :
1163 59150 : OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
1164 : OGRFeatureDefn * poDefn,
1165 : OGRFeature * poFeature,
1166 : const char *pszSHPEncoding,
1167 : int* pbTruncationWarningEmitted )
1168 :
1169 : {
1170 : #ifdef notdef
1171 : /* -------------------------------------------------------------------- */
1172 : /* Don't write objects with missing geometry. */
1173 : /* -------------------------------------------------------------------- */
1174 : if( poFeature->GetGeometryRef() == NULL && hSHP != NULL )
1175 : {
1176 : CPLError( CE_Failure, CPLE_AppDefined,
1177 : "Attempt to write feature without geometry not supported"
1178 : " for shapefile driver." );
1179 :
1180 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1181 : }
1182 : #endif
1183 :
1184 : /* -------------------------------------------------------------------- */
1185 : /* Write the geometry. */
1186 : /* -------------------------------------------------------------------- */
1187 : OGRErr eErr;
1188 :
1189 59150 : if( hSHP != NULL )
1190 : {
1191 : eErr = SHPWriteOGRObject( hSHP, poFeature->GetFID(),
1192 59094 : poFeature->GetGeometryRef() );
1193 59094 : if( eErr != OGRERR_NONE )
1194 74 : return eErr;
1195 : }
1196 :
1197 : /* -------------------------------------------------------------------- */
1198 : /* If there is no DBF, the job is done now. */
1199 : /* -------------------------------------------------------------------- */
1200 59076 : if( hDBF == NULL )
1201 : {
1202 : /* -------------------------------------------------------------------- */
1203 : /* If this is a new feature, establish it's feature id. */
1204 : /* -------------------------------------------------------------------- */
1205 28 : if( hSHP != NULL && poFeature->GetFID() == OGRNullFID )
1206 2 : poFeature->SetFID( hSHP->nRecords - 1 );
1207 :
1208 28 : return OGRERR_NONE;
1209 : }
1210 :
1211 : /* -------------------------------------------------------------------- */
1212 : /* If this is a new feature, establish it's feature id. */
1213 : /* -------------------------------------------------------------------- */
1214 59048 : if( poFeature->GetFID() == OGRNullFID )
1215 59024 : poFeature->SetFID( DBFGetRecordCount( hDBF ) );
1216 :
1217 : /* -------------------------------------------------------------------- */
1218 : /* If this is the first feature to be written, verify that we */
1219 : /* have at least one attribute in the DBF file. If not, create */
1220 : /* a dummy FID attribute to satisfy the requirement that there */
1221 : /* be at least one attribute. */
1222 : /* -------------------------------------------------------------------- */
1223 59048 : if( DBFGetRecordCount( hDBF ) == 0 && DBFGetFieldCount( hDBF ) == 0 )
1224 : {
1225 : CPLDebug( "OGR",
1226 164 : "Created dummy FID field for shapefile since schema is empty.");
1227 164 : DBFAddField( hDBF, "FID", FTInteger, 11, 0 );
1228 : }
1229 :
1230 : /* -------------------------------------------------------------------- */
1231 : /* Write out dummy field value if it exists. */
1232 : /* -------------------------------------------------------------------- */
1233 59048 : if( DBFGetFieldCount( hDBF ) == 1 && poDefn->GetFieldCount() == 0 )
1234 : {
1235 : DBFWriteIntegerAttribute( hDBF, poFeature->GetFID(), 0,
1236 54050 : poFeature->GetFID() );
1237 : }
1238 :
1239 : /* -------------------------------------------------------------------- */
1240 : /* Write all the fields. */
1241 : /* -------------------------------------------------------------------- */
1242 78318 : for( int iField = 0; iField < poDefn->GetFieldCount(); iField++ )
1243 : {
1244 19270 : if( !poFeature->IsFieldSet( iField ) )
1245 : {
1246 32 : DBFWriteNULLAttribute( hDBF, poFeature->GetFID(), iField );
1247 32 : continue;
1248 : }
1249 :
1250 19238 : int nRet = FALSE;
1251 :
1252 19238 : OGRFieldDefn* poFieldDefn = poDefn->GetFieldDefn(iField);
1253 :
1254 19238 : switch( poFieldDefn->GetType() )
1255 : {
1256 : case OFTString:
1257 : {
1258 6690 : const char *pszStr = poFeature->GetFieldAsString(iField);
1259 6690 : char *pszEncoded = NULL;
1260 6690 : if( strlen(pszSHPEncoding) > 0 )
1261 : {
1262 : pszEncoded =
1263 6674 : CPLRecode( pszStr, CPL_ENC_UTF8, pszSHPEncoding );
1264 6674 : pszStr = pszEncoded;
1265 : }
1266 :
1267 6690 : int nStrLen = (int) strlen(pszStr);
1268 6690 : if (nStrLen > 255)
1269 : {
1270 2 : if (!(*pbTruncationWarningEmitted))
1271 : {
1272 2 : *pbTruncationWarningEmitted = TRUE;
1273 : CPLError(CE_Warning, CPLE_AppDefined,
1274 : "Value '%s' of field %s has been truncated to 255 characters.\n"
1275 : "This warning will not be emitted any more for that layer.",
1276 : poFeature->GetFieldAsString(iField),
1277 2 : poFieldDefn->GetNameRef());
1278 : }
1279 2 : nStrLen = 255;
1280 : }
1281 :
1282 6690 : if ( nStrLen > poFieldDefn->GetWidth() )
1283 : {
1284 2 : if (GrowField(hDBF, iField, poFieldDefn, nStrLen) != OGRERR_NONE)
1285 : {
1286 0 : CPLFree( pszEncoded );
1287 0 : return OGRERR_FAILURE;
1288 : }
1289 : }
1290 :
1291 : nRet = DBFWriteStringAttribute( hDBF, poFeature->GetFID(), iField,
1292 6690 : pszStr );
1293 :
1294 6690 : CPLFree( pszEncoded );
1295 : }
1296 6690 : break;
1297 :
1298 : case OFTInteger:
1299 : {
1300 : char szFormat[20];
1301 : char szValue[20];
1302 9910 : int nFieldWidth = poFieldDefn->GetWidth();
1303 9910 : sprintf(szFormat, "%%%dd", nFieldWidth);
1304 9910 : sprintf(szValue, szFormat, poFeature->GetFieldAsInteger(iField) );
1305 9910 : int nStrLen = strlen(szValue);
1306 9910 : if( nStrLen > nFieldWidth )
1307 : {
1308 2 : if (GrowField(hDBF, iField, poFieldDefn, nStrLen) != OGRERR_NONE)
1309 : {
1310 0 : return OGRERR_FAILURE;
1311 : }
1312 : }
1313 :
1314 : nRet = DBFWriteAttributeDirectly( hDBF, poFeature->GetFID(), iField,
1315 9910 : szValue );
1316 9910 : break;
1317 : }
1318 :
1319 : case OFTReal:
1320 : nRet = DBFWriteDoubleAttribute( hDBF, poFeature->GetFID(), iField,
1321 2636 : poFeature->GetFieldAsDouble(iField) );
1322 2636 : break;
1323 :
1324 : case OFTDate:
1325 : {
1326 : int nYear, nMonth, nDay;
1327 :
1328 2 : if( poFeature->GetFieldAsDateTime( iField, &nYear, &nMonth, &nDay,
1329 : NULL, NULL, NULL, NULL ) )
1330 : {
1331 : nRet = DBFWriteIntegerAttribute( hDBF, poFeature->GetFID(), iField,
1332 2 : nYear*10000 + nMonth*100 + nDay );
1333 : }
1334 : }
1335 : break;
1336 :
1337 : default:
1338 : {
1339 : /* Ignore fields of other types */
1340 : break;
1341 : }
1342 : }
1343 :
1344 : }
1345 :
1346 59048 : return OGRERR_NONE;
1347 : }
1348 :
|