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