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