/[thuban]/branches/WIP-pyshapelib-bramz/libraries/shapelib/shpopen.c
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/libraries/shapelib/shpopen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2734 - (hide annotations)
Thu Mar 1 12:42:59 2007 UTC (18 years ago) by bramz
File MIME type: text/plain
File size: 74432 byte(s)
made a copy
1 jan 1612 /******************************************************************************
2     * $Id$
3     *
4     * Project: Shapelib
5     * Purpose: Implementation of core Shapefile read/write functions.
6     * Author: Frank Warmerdam, [email protected]
7     *
8     ******************************************************************************
9     * Copyright (c) 1999, 2001, Frank Warmerdam
10     *
11     * This software is available under the following "MIT Style" license,
12     * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
13     * option is discussed in more detail in shapelib.html.
14     *
15     * --
16     *
17     * Permission is hereby granted, free of charge, to any person obtaining a
18     * copy of this software and associated documentation files (the "Software"),
19     * to deal in the Software without restriction, including without limitation
20     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21     * and/or sell copies of the Software, and to permit persons to whom the
22     * Software is furnished to do so, subject to the following conditions:
23     *
24     * The above copyright notice and this permission notice shall be included
25     * in all copies or substantial portions of the Software.
26     *
27     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28     * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33     * DEALINGS IN THE SOFTWARE.
34     ******************************************************************************
35     *
36     * $Log$
37 bh 2212 * Revision 1.3 2004/05/17 15:47:57 bh
38     * Update to newest shapelib and get rid of Thuban specific extensions,
39     * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
40 jan 1612 *
41 bh 2212 * * libraries/shapelib/shpopen.c: Update to version from current
42     * shapelib CVS.
43     *
44     * * libraries/shapelib/shapefil.h: Update to version from current
45     * shapelib CVS.
46     *
47     * * libraries/shapelib/dbfopen.c: Update to version from current
48     * shapelib CVS.
49     * (DBFCommit): Effectively removed since shapelib itself has
50     * DBFUpdateHeader now which is better for what DBFCommit wanted to
51     * achieve.
52     * We're now using an unmodified version of dbfopen.
53     *
54     * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
55     * Update from dbflib.i
56     *
57     * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
58     * the commit method. This new indirection is necessary because we use the
59     * DBFUpdateHeader function now which is not available in shapelib <=
60     * 1.2.10
61     * (DBFFile::commit): Use DBFInfo_commit as implementation
62     * (pragma __class__): New. Kludge to remove the commit method when
63     * the DBFUpdateHeader function isn't available
64     * (_have_commit): New. Helper for the pragma kludge.
65     *
66     * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
67     * preprocessor macros needed to compile the dbflib wrapper. Determine
68     * whether DBFUpdateHeader is available and define the right value of
69     * HAVE_UPDATE_HEADER
70     * (extensions): Use dbf_macros for the dbflibc extension
71     *
72     * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
73     * value '1' to the Lib.dbflibc extension. This simply reflects the
74     * shapelib and pyshapelib updates
75     *
76     * Revision 1.44 2003/12/29 00:18:39 fwarmerdam
77     * added error checking for failed IO and optional CPL error reporting
78     *
79     * Revision 1.43 2003/12/01 16:20:08 warmerda
80     * be careful of zero vertex shapes
81     *
82     * Revision 1.42 2003/12/01 14:58:27 warmerda
83     * added degenerate object check in SHPRewindObject()
84     *
85     * Revision 1.41 2003/07/08 15:22:43 warmerda
86     * avoid warning
87     *
88     * Revision 1.40 2003/04/21 18:30:37 warmerda
89     * added header write/update public methods
90     *
91 bh 1769 * Revision 1.39 2002/08/26 06:46:56 warmerda
92     * avoid c++ comments
93 jan 1612 *
94 bh 1769 * Revision 1.38 2002/05/07 16:43:39 warmerda
95     * Removed debugging printf.
96     *
97     * Revision 1.37 2002/04/10 17:35:22 warmerda
98     * fixed bug in ring reversal code
99     *
100     * Revision 1.36 2002/04/10 16:59:54 warmerda
101     * added SHPRewindObject
102     *
103     * Revision 1.35 2001/12/07 15:10:44 warmerda
104     * fix if .shx fails to open
105     *
106     * Revision 1.34 2001/11/01 16:29:55 warmerda
107     * move pabyRec into SHPInfo for thread safety
108     *
109 jan 1612 * Revision 1.33 2001/07/03 12:18:15 warmerda
110     * Improved cleanup if SHX not found, provied by Riccardo Cohen.
111     *
112     * Revision 1.32 2001/06/22 01:58:07 warmerda
113     * be more careful about establishing initial bounds in face of NULL shapes
114     *
115     * Revision 1.31 2001/05/31 19:35:29 warmerda
116     * added support for writing null shapes
117     *
118     * Revision 1.30 2001/05/28 12:46:29 warmerda
119     * Add some checking on reasonableness of record count when opening.
120     *
121     * Revision 1.29 2001/05/23 13:36:52 warmerda
122     * added use of SHPAPI_CALL
123     *
124     * Revision 1.28 2001/02/06 22:25:06 warmerda
125     * fixed memory leaks when SHPOpen() fails
126     *
127     * Revision 1.27 2000/07/18 15:21:33 warmerda
128     * added better enforcement of -1 for append in SHPWriteObject
129     *
130     * Revision 1.26 2000/02/16 16:03:51 warmerda
131     * added null shape support
132     *
133     * Revision 1.25 1999/12/15 13:47:07 warmerda
134     * Fixed record size settings in .shp file (was 4 words too long)
135     * Added stdlib.h.
136     *
137     * Revision 1.24 1999/11/05 14:12:04 warmerda
138     * updated license terms
139     *
140     * Revision 1.23 1999/07/27 00:53:46 warmerda
141     * added support for rewriting shapes
142     *
143     * Revision 1.22 1999/06/11 19:19:11 warmerda
144     * Cleanup pabyRec static buffer on SHPClose().
145     *
146     * Revision 1.21 1999/06/02 14:57:56 kshih
147     * Remove unused variables
148     *
149     * Revision 1.20 1999/04/19 21:04:17 warmerda
150     * Fixed syntax error.
151     *
152     * Revision 1.19 1999/04/19 21:01:57 warmerda
153     * Force access string to binary in SHPOpen().
154     *
155     * Revision 1.18 1999/04/01 18:48:07 warmerda
156     * Try upper case extensions if lower case doesn't work.
157     *
158     * Revision 1.17 1998/12/31 15:29:39 warmerda
159     * Disable writing measure values to multipatch objects if
160     * DISABLE_MULTIPATCH_MEASURE is defined.
161     *
162     * Revision 1.16 1998/12/16 05:14:33 warmerda
163     * Added support to write MULTIPATCH. Fixed reading Z coordinate of
164     * MULTIPATCH. Fixed record size written for all feature types.
165     *
166     * Revision 1.15 1998/12/03 16:35:29 warmerda
167     * r+b is proper binary access string, not rb+.
168     *
169     * Revision 1.14 1998/12/03 15:47:56 warmerda
170     * Fixed setting of nVertices in SHPCreateObject().
171     *
172     * Revision 1.13 1998/12/03 15:33:54 warmerda
173     * Made SHPCalculateExtents() separately callable.
174     *
175     * Revision 1.12 1998/11/11 20:01:50 warmerda
176     * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
177     *
178     * Revision 1.11 1998/11/09 20:56:44 warmerda
179     * Fixed up handling of file wide bounds.
180     *
181     * Revision 1.10 1998/11/09 20:18:51 warmerda
182     * Converted to support 3D shapefiles, and use of SHPObject.
183     *
184     * Revision 1.9 1998/02/24 15:09:05 warmerda
185     * Fixed memory leak.
186     *
187     * Revision 1.8 1997/12/04 15:40:29 warmerda
188     * Fixed byte swapping of record number, and record length fields in the
189     * .shp file.
190     *
191     * Revision 1.7 1995/10/21 03:15:58 warmerda
192     * Added support for binary file access, the magic cookie 9997
193     * and tried to improve the int32 selection logic for 16bit systems.
194     *
195     * Revision 1.6 1995/09/04 04:19:41 warmerda
196     * Added fix for file bounds.
197     *
198     * Revision 1.5 1995/08/25 15:16:44 warmerda
199     * Fixed a couple of problems with big endian systems ... one with bounds
200     * and the other with multipart polygons.
201     *
202     * Revision 1.4 1995/08/24 18:10:17 warmerda
203     * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()
204     * functions (such as on the Sun).
205     *
206     * Revision 1.3 1995/08/23 02:23:15 warmerda
207     * Added support for reading bounds, and fixed up problems in setting the
208     * file wide bounds.
209     *
210     * Revision 1.2 1995/08/04 03:16:57 warmerda
211     * Added header.
212     *
213     */
214    
215     static char rcsid[] =
216     "$Id$";
217    
218     #include "shapefil.h"
219    
220     #include <math.h>
221     #include <limits.h>
222     #include <assert.h>
223     #include <stdlib.h>
224     #include <string.h>
225    
226     typedef unsigned char uchar;
227    
228     #if UINT_MAX == 65535
229     typedef long int32;
230     #else
231     typedef int int32;
232     #endif
233    
234     #ifndef FALSE
235     # define FALSE 0
236     # define TRUE 1
237     #endif
238    
239     #define ByteCopy( a, b, c ) memcpy( b, a, c )
240     #ifndef MAX
241     # define MIN(a,b) ((a<b) ? a : b)
242     # define MAX(a,b) ((a>b) ? a : b)
243     #endif
244    
245     static int bBigEndian;
246    
247    
248     /************************************************************************/
249     /* SwapWord() */
250     /* */
251     /* Swap a 2, 4 or 8 byte word. */
252     /************************************************************************/
253    
254     static void SwapWord( int length, void * wordP )
255    
256     {
257     int i;
258     uchar temp;
259    
260     for( i=0; i < length/2; i++ )
261     {
262     temp = ((uchar *) wordP)[i];
263     ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
264     ((uchar *) wordP)[length-i-1] = temp;
265     }
266     }
267    
268     /************************************************************************/
269     /* SfRealloc() */
270     /* */
271     /* A realloc cover function that will access a NULL pointer as */
272     /* a valid input. */
273     /************************************************************************/
274    
275     static void * SfRealloc( void * pMem, int nNewSize )
276    
277     {
278     if( pMem == NULL )
279     return( (void *) malloc(nNewSize) );
280     else
281     return( (void *) realloc(pMem,nNewSize) );
282     }
283    
284     /************************************************************************/
285     /* SHPWriteHeader() */
286     /* */
287     /* Write out a header for the .shp and .shx files as well as the */
288     /* contents of the index (.shx) file. */
289     /************************************************************************/
290    
291 bh 2212 void SHPWriteHeader( SHPHandle psSHP )
292 jan 1612
293     {
294     uchar abyHeader[100];
295     int i;
296     int32 i32;
297     double dValue;
298     int32 *panSHX;
299    
300     /* -------------------------------------------------------------------- */
301     /* Prepare header block for .shp file. */
302     /* -------------------------------------------------------------------- */
303     for( i = 0; i < 100; i++ )
304     abyHeader[i] = 0;
305    
306     abyHeader[2] = 0x27; /* magic cookie */
307     abyHeader[3] = 0x0a;
308    
309     i32 = psSHP->nFileSize/2; /* file size */
310     ByteCopy( &i32, abyHeader+24, 4 );
311     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
312    
313     i32 = 1000; /* version */
314     ByteCopy( &i32, abyHeader+28, 4 );
315     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
316    
317     i32 = psSHP->nShapeType; /* shape type */
318     ByteCopy( &i32, abyHeader+32, 4 );
319     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
320    
321     dValue = psSHP->adBoundsMin[0]; /* set bounds */
322     ByteCopy( &dValue, abyHeader+36, 8 );
323     if( bBigEndian ) SwapWord( 8, abyHeader+36 );
324    
325     dValue = psSHP->adBoundsMin[1];
326     ByteCopy( &dValue, abyHeader+44, 8 );
327     if( bBigEndian ) SwapWord( 8, abyHeader+44 );
328    
329     dValue = psSHP->adBoundsMax[0];
330     ByteCopy( &dValue, abyHeader+52, 8 );
331     if( bBigEndian ) SwapWord( 8, abyHeader+52 );
332    
333     dValue = psSHP->adBoundsMax[1];
334     ByteCopy( &dValue, abyHeader+60, 8 );
335     if( bBigEndian ) SwapWord( 8, abyHeader+60 );
336    
337     dValue = psSHP->adBoundsMin[2]; /* z */
338     ByteCopy( &dValue, abyHeader+68, 8 );
339     if( bBigEndian ) SwapWord( 8, abyHeader+68 );
340    
341     dValue = psSHP->adBoundsMax[2];
342     ByteCopy( &dValue, abyHeader+76, 8 );
343     if( bBigEndian ) SwapWord( 8, abyHeader+76 );
344    
345     dValue = psSHP->adBoundsMin[3]; /* m */
346     ByteCopy( &dValue, abyHeader+84, 8 );
347     if( bBigEndian ) SwapWord( 8, abyHeader+84 );
348    
349     dValue = psSHP->adBoundsMax[3];
350     ByteCopy( &dValue, abyHeader+92, 8 );
351     if( bBigEndian ) SwapWord( 8, abyHeader+92 );
352    
353     /* -------------------------------------------------------------------- */
354     /* Write .shp file header. */
355     /* -------------------------------------------------------------------- */
356 bh 2212 if( fseek( psSHP->fpSHP, 0, 0 ) != 0
357     || fwrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
358     {
359     #ifdef USE_CPL
360     CPLError( CE_Failure, CPLE_OpenFailed,
361     "Failure writing .shp header." );
362     #endif
363     return;
364     }
365 jan 1612
366     /* -------------------------------------------------------------------- */
367     /* Prepare, and write .shx file header. */
368     /* -------------------------------------------------------------------- */
369     i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */
370     ByteCopy( &i32, abyHeader+24, 4 );
371     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
372    
373 bh 2212 if( fseek( psSHP->fpSHX, 0, 0 ) != 0
374     || fwrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
375     {
376     #ifdef USE_CPL
377     CPLError( CE_Failure, CPLE_OpenFailed,
378     "Failure writing .shx header." );
379     #endif
380     return;
381     }
382 jan 1612
383     /* -------------------------------------------------------------------- */
384     /* Write out the .shx contents. */
385     /* -------------------------------------------------------------------- */
386     panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
387    
388     for( i = 0; i < psSHP->nRecords; i++ )
389     {
390     panSHX[i*2 ] = psSHP->panRecOffset[i]/2;
391     panSHX[i*2+1] = psSHP->panRecSize[i]/2;
392     if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
393     if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
394     }
395    
396 bh 2212 if( fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX )
397     != psSHP->nRecords )
398     {
399     #ifdef USE_CPL
400     CPLError( CE_Failure, CPLE_OpenFailed,
401     "Failure writing .shx contents." );
402     #endif
403     }
404 jan 1612
405     free( panSHX );
406 bh 2212
407     /* -------------------------------------------------------------------- */
408     /* Flush to disk. */
409     /* -------------------------------------------------------------------- */
410     fflush( psSHP->fpSHP );
411     fflush( psSHP->fpSHX );
412 jan 1612 }
413    
414     /************************************************************************/
415 bh 2212 /* shpopen() */
416 jan 1612 /* */
417     /* Open the .shp and .shx files based on the basename of the */
418     /* files or either file name. */
419     /************************************************************************/
420    
421     SHPHandle SHPAPI_CALL
422     SHPOpen( const char * pszLayer, const char * pszAccess )
423    
424     {
425     char *pszFullname, *pszBasename;
426     SHPHandle psSHP;
427    
428     uchar *pabyBuf;
429     int i;
430     double dValue;
431    
432     /* -------------------------------------------------------------------- */
433     /* Ensure the access string is one of the legal ones. We */
434     /* ensure the result string indicates binary to avoid common */
435     /* problems on Windows. */
436     /* -------------------------------------------------------------------- */
437     if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
438     || strcmp(pszAccess,"r+") == 0 )
439     pszAccess = "r+b";
440     else
441     pszAccess = "rb";
442    
443     /* -------------------------------------------------------------------- */
444     /* Establish the byte order on this machine. */
445     /* -------------------------------------------------------------------- */
446     i = 1;
447     if( *((uchar *) &i) == 1 )
448     bBigEndian = FALSE;
449     else
450     bBigEndian = TRUE;
451    
452     /* -------------------------------------------------------------------- */
453     /* Initialize the info structure. */
454     /* -------------------------------------------------------------------- */
455 bh 1769 psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
456 jan 1612
457     psSHP->bUpdated = FALSE;
458    
459     /* -------------------------------------------------------------------- */
460     /* Compute the base (layer) name. If there is any extension */
461     /* on the passed in filename we will strip it off. */
462     /* -------------------------------------------------------------------- */
463     pszBasename = (char *) malloc(strlen(pszLayer)+5);
464     strcpy( pszBasename, pszLayer );
465     for( i = strlen(pszBasename)-1;
466     i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
467     && pszBasename[i] != '\\';
468     i-- ) {}
469    
470     if( pszBasename[i] == '.' )
471     pszBasename[i] = '\0';
472    
473     /* -------------------------------------------------------------------- */
474     /* Open the .shp and .shx files. Note that files pulled from */
475     /* a PC to Unix with upper case filenames won't work! */
476     /* -------------------------------------------------------------------- */
477     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
478     sprintf( pszFullname, "%s.shp", pszBasename );
479     psSHP->fpSHP = fopen(pszFullname, pszAccess );
480     if( psSHP->fpSHP == NULL )
481     {
482     sprintf( pszFullname, "%s.SHP", pszBasename );
483     psSHP->fpSHP = fopen(pszFullname, pszAccess );
484     }
485    
486     if( psSHP->fpSHP == NULL )
487     {
488 bh 2212 #ifdef USE_CPL
489     CPLError( CE_Failure, CPLE_OpenFailed,
490     "Unable to open %s.shp or %s.SHP.",
491     pszBasename, pszBasename );
492     #endif
493 jan 1612 free( psSHP );
494     free( pszBasename );
495     free( pszFullname );
496     return( NULL );
497     }
498    
499     sprintf( pszFullname, "%s.shx", pszBasename );
500     psSHP->fpSHX = fopen(pszFullname, pszAccess );
501     if( psSHP->fpSHX == NULL )
502     {
503     sprintf( pszFullname, "%s.SHX", pszBasename );
504     psSHP->fpSHX = fopen(pszFullname, pszAccess );
505     }
506    
507     if( psSHP->fpSHX == NULL )
508     {
509 bh 2212 #ifdef USE_CPL
510     CPLError( CE_Failure, CPLE_OpenFailed,
511     "Unable to open %s.shx or %s.SHX.",
512     pszBasename, pszBasename );
513     #endif
514 bh 1769 fclose( psSHP->fpSHP );
515 jan 1612 free( psSHP );
516     free( pszBasename );
517     free( pszFullname );
518     return( NULL );
519     }
520    
521     free( pszFullname );
522     free( pszBasename );
523    
524     /* -------------------------------------------------------------------- */
525     /* Read the file size from the SHP file. */
526     /* -------------------------------------------------------------------- */
527     pabyBuf = (uchar *) malloc(100);
528     fread( pabyBuf, 100, 1, psSHP->fpSHP );
529    
530     psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
531     + pabyBuf[25] * 256 * 256
532     + pabyBuf[26] * 256
533     + pabyBuf[27]) * 2;
534    
535     /* -------------------------------------------------------------------- */
536     /* Read SHX file Header info */
537     /* -------------------------------------------------------------------- */
538 bh 2212 if( fread( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
539     || pabyBuf[0] != 0
540 jan 1612 || pabyBuf[1] != 0
541     || pabyBuf[2] != 0x27
542     || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
543     {
544 bh 2212 #ifdef USE_CPL
545     CPLError( CE_Failure, CPLE_AppDefined,
546     ".shx file is unreadable, or corrupt." );
547     #endif
548 jan 1612 fclose( psSHP->fpSHP );
549     fclose( psSHP->fpSHX );
550     free( psSHP );
551    
552     return( NULL );
553     }
554    
555     psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
556     + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
557     psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
558    
559     psSHP->nShapeType = pabyBuf[32];
560    
561     if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
562     {
563 bh 2212 #ifdef USE_CPL
564     CPLError( CE_Failure, CPLE_AppDefined,
565     "Record count in .shp header is %d, which seems\n"
566     "unreasonable. Assuming header is corrupt.",
567     psSHP->nRecords );
568     #endif
569 jan 1612 fclose( psSHP->fpSHP );
570     fclose( psSHP->fpSHX );
571     free( psSHP );
572    
573     return( NULL );
574     }
575    
576     /* -------------------------------------------------------------------- */
577     /* Read the bounds. */
578     /* -------------------------------------------------------------------- */
579     if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
580     memcpy( &dValue, pabyBuf+36, 8 );
581     psSHP->adBoundsMin[0] = dValue;
582    
583     if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
584     memcpy( &dValue, pabyBuf+44, 8 );
585     psSHP->adBoundsMin[1] = dValue;
586    
587     if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
588     memcpy( &dValue, pabyBuf+52, 8 );
589     psSHP->adBoundsMax[0] = dValue;
590    
591     if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
592     memcpy( &dValue, pabyBuf+60, 8 );
593     psSHP->adBoundsMax[1] = dValue;
594    
595     if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
596     memcpy( &dValue, pabyBuf+68, 8 );
597     psSHP->adBoundsMin[2] = dValue;
598    
599     if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
600     memcpy( &dValue, pabyBuf+76, 8 );
601     psSHP->adBoundsMax[2] = dValue;
602    
603     if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
604     memcpy( &dValue, pabyBuf+84, 8 );
605     psSHP->adBoundsMin[3] = dValue;
606    
607     if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
608     memcpy( &dValue, pabyBuf+92, 8 );
609     psSHP->adBoundsMax[3] = dValue;
610    
611     free( pabyBuf );
612    
613     /* -------------------------------------------------------------------- */
614     /* Read the .shx file to get the offsets to each record in */
615     /* the .shp file. */
616     /* -------------------------------------------------------------------- */
617     psSHP->nMaxRecords = psSHP->nRecords;
618    
619     psSHP->panRecOffset =
620     (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
621     psSHP->panRecSize =
622     (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
623    
624     pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
625 bh 2212 if( fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) != psSHP->nRecords )
626     {
627     #ifdef USE_CPL
628     CPLError( CE_Failure, CPLE_AppDefined,
629     "Failed to read all values for %d records in .shx file.",
630     psSHP->nRecords );
631     #endif
632     /* SHX is short or unreadable for some reason. */
633     fclose( psSHP->fpSHP );
634     fclose( psSHP->fpSHX );
635     free( psSHP->panRecOffset );
636     free( psSHP->panRecSize );
637     free( psSHP );
638 jan 1612
639 bh 2212 return( NULL );
640     }
641    
642 jan 1612 for( i = 0; i < psSHP->nRecords; i++ )
643     {
644     int32 nOffset, nLength;
645    
646     memcpy( &nOffset, pabyBuf + i * 8, 4 );
647     if( !bBigEndian ) SwapWord( 4, &nOffset );
648    
649     memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
650     if( !bBigEndian ) SwapWord( 4, &nLength );
651    
652     psSHP->panRecOffset[i] = nOffset*2;
653     psSHP->panRecSize[i] = nLength*2;
654     }
655     free( pabyBuf );
656    
657     return( psSHP );
658     }
659    
660     /************************************************************************/
661     /* SHPClose() */
662     /* */
663     /* Close the .shp and .shx files. */
664     /************************************************************************/
665    
666     void SHPAPI_CALL
667     SHPClose(SHPHandle psSHP )
668    
669     {
670 bh 2212 if( psSHP == NULL )
671     return;
672    
673 jan 1612 /* -------------------------------------------------------------------- */
674     /* Update the header if we have modified anything. */
675     /* -------------------------------------------------------------------- */
676     if( psSHP->bUpdated )
677     SHPWriteHeader( psSHP );
678    
679     /* -------------------------------------------------------------------- */
680     /* Free all resources, and close files. */
681     /* -------------------------------------------------------------------- */
682     free( psSHP->panRecOffset );
683     free( psSHP->panRecSize );
684    
685     fclose( psSHP->fpSHX );
686     fclose( psSHP->fpSHP );
687    
688 bh 1769 if( psSHP->pabyRec != NULL )
689 jan 1612 {
690 bh 1769 free( psSHP->pabyRec );
691 jan 1612 }
692 bh 1769
693     free( psSHP );
694 jan 1612 }
695    
696     /************************************************************************/
697     /* SHPGetInfo() */
698     /* */
699     /* Fetch general information about the shape file. */
700     /************************************************************************/
701    
702     void SHPAPI_CALL
703     SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
704     double * padfMinBound, double * padfMaxBound )
705    
706     {
707     int i;
708 bh 2212
709     if( psSHP == NULL )
710     return;
711 jan 1612
712     if( pnEntities != NULL )
713     *pnEntities = psSHP->nRecords;
714    
715     if( pnShapeType != NULL )
716     *pnShapeType = psSHP->nShapeType;
717    
718     for( i = 0; i < 4; i++ )
719     {
720     if( padfMinBound != NULL )
721     padfMinBound[i] = psSHP->adBoundsMin[i];
722     if( padfMaxBound != NULL )
723     padfMaxBound[i] = psSHP->adBoundsMax[i];
724     }
725     }
726    
727     /************************************************************************/
728     /* SHPCreate() */
729     /* */
730     /* Create a new shape file and return a handle to the open */
731     /* shape file with read/write access. */
732     /************************************************************************/
733    
734     SHPHandle SHPAPI_CALL
735     SHPCreate( const char * pszLayer, int nShapeType )
736    
737     {
738     char *pszBasename, *pszFullname;
739     int i;
740     FILE *fpSHP, *fpSHX;
741     uchar abyHeader[100];
742     int32 i32;
743     double dValue;
744    
745     /* -------------------------------------------------------------------- */
746     /* Establish the byte order on this system. */
747     /* -------------------------------------------------------------------- */
748     i = 1;
749     if( *((uchar *) &i) == 1 )
750     bBigEndian = FALSE;
751     else
752     bBigEndian = TRUE;
753    
754     /* -------------------------------------------------------------------- */
755     /* Compute the base (layer) name. If there is any extension */
756     /* on the passed in filename we will strip it off. */
757     /* -------------------------------------------------------------------- */
758     pszBasename = (char *) malloc(strlen(pszLayer)+5);
759     strcpy( pszBasename, pszLayer );
760     for( i = strlen(pszBasename)-1;
761     i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
762     && pszBasename[i] != '\\';
763     i-- ) {}
764    
765     if( pszBasename[i] == '.' )
766     pszBasename[i] = '\0';
767    
768     /* -------------------------------------------------------------------- */
769     /* Open the two files so we can write their headers. */
770     /* -------------------------------------------------------------------- */
771     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
772     sprintf( pszFullname, "%s.shp", pszBasename );
773     fpSHP = fopen(pszFullname, "wb" );
774     if( fpSHP == NULL )
775 bh 2212 {
776     #ifdef USE_CPL
777     CPLError( CE_Failure, CPLE_AppDefined,
778     "Failed to create file %s.",
779     pszFullname );
780     #endif
781 jan 1612 return( NULL );
782 bh 2212 }
783 jan 1612
784     sprintf( pszFullname, "%s.shx", pszBasename );
785     fpSHX = fopen(pszFullname, "wb" );
786     if( fpSHX == NULL )
787 bh 2212 {
788     #ifdef USE_CPL
789     CPLError( CE_Failure, CPLE_AppDefined,
790     "Failed to create file %s.",
791     pszFullname );
792     #endif
793 jan 1612 return( NULL );
794 bh 2212 }
795 jan 1612
796     free( pszFullname );
797     free( pszBasename );
798    
799     /* -------------------------------------------------------------------- */
800     /* Prepare header block for .shp file. */
801     /* -------------------------------------------------------------------- */
802     for( i = 0; i < 100; i++ )
803     abyHeader[i] = 0;
804    
805     abyHeader[2] = 0x27; /* magic cookie */
806     abyHeader[3] = 0x0a;
807    
808     i32 = 50; /* file size */
809     ByteCopy( &i32, abyHeader+24, 4 );
810     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
811    
812     i32 = 1000; /* version */
813     ByteCopy( &i32, abyHeader+28, 4 );
814     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
815    
816     i32 = nShapeType; /* shape type */
817     ByteCopy( &i32, abyHeader+32, 4 );
818     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
819    
820     dValue = 0.0; /* set bounds */
821     ByteCopy( &dValue, abyHeader+36, 8 );
822     ByteCopy( &dValue, abyHeader+44, 8 );
823     ByteCopy( &dValue, abyHeader+52, 8 );
824     ByteCopy( &dValue, abyHeader+60, 8 );
825    
826     /* -------------------------------------------------------------------- */
827     /* Write .shp file header. */
828     /* -------------------------------------------------------------------- */
829 bh 2212 if( fwrite( abyHeader, 100, 1, fpSHP ) != 1 )
830     {
831     #ifdef USE_CPL
832     CPLError( CE_Failure, CPLE_AppDefined,
833     "Failed to write .shp header." );
834     #endif
835     return NULL;
836     }
837 jan 1612
838     /* -------------------------------------------------------------------- */
839     /* Prepare, and write .shx file header. */
840     /* -------------------------------------------------------------------- */
841     i32 = 50; /* file size */
842     ByteCopy( &i32, abyHeader+24, 4 );
843     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
844    
845 bh 2212 if( fwrite( abyHeader, 100, 1, fpSHX ) != 1 )
846     {
847     #ifdef USE_CPL
848     CPLError( CE_Failure, CPLE_AppDefined,
849     "Failed to write .shx header." );
850     #endif
851     return NULL;
852     }
853 jan 1612
854     /* -------------------------------------------------------------------- */
855     /* Close the files, and then open them as regular existing files. */
856     /* -------------------------------------------------------------------- */
857     fclose( fpSHP );
858     fclose( fpSHX );
859    
860     return( SHPOpen( pszLayer, "r+b" ) );
861     }
862    
863     /************************************************************************/
864     /* _SHPSetBounds() */
865     /* */
866     /* Compute a bounds rectangle for a shape, and set it into the */
867     /* indicated location in the record. */
868     /************************************************************************/
869    
870     static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
871    
872     {
873     ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 );
874     ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 );
875     ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
876     ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
877    
878     if( bBigEndian )
879     {
880     SwapWord( 8, pabyRec + 0 );
881     SwapWord( 8, pabyRec + 8 );
882     SwapWord( 8, pabyRec + 16 );
883     SwapWord( 8, pabyRec + 24 );
884     }
885     }
886    
887     /************************************************************************/
888     /* SHPComputeExtents() */
889     /* */
890     /* Recompute the extents of a shape. Automatically done by */
891     /* SHPCreateObject(). */
892     /************************************************************************/
893    
894     void SHPAPI_CALL
895     SHPComputeExtents( SHPObject * psObject )
896    
897     {
898     int i;
899    
900     /* -------------------------------------------------------------------- */
901     /* Build extents for this object. */
902     /* -------------------------------------------------------------------- */
903     if( psObject->nVertices > 0 )
904     {
905     psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
906     psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
907     psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
908     psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
909     }
910    
911     for( i = 0; i < psObject->nVertices; i++ )
912     {
913     psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
914     psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
915     psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
916     psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
917    
918     psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
919     psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
920     psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
921     psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
922     }
923     }
924    
925     /************************************************************************/
926     /* SHPCreateObject() */
927     /* */
928     /* Create a shape object. It should be freed with */
929     /* SHPDestroyObject(). */
930     /************************************************************************/
931    
932     SHPObject SHPAPI_CALL1(*)
933     SHPCreateObject( int nSHPType, int nShapeId, int nParts,
934     int * panPartStart, int * panPartType,
935     int nVertices, double * padfX, double * padfY,
936     double * padfZ, double * padfM )
937    
938     {
939     SHPObject *psObject;
940     int i, bHasM, bHasZ;
941    
942     psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
943     psObject->nSHPType = nSHPType;
944     psObject->nShapeId = nShapeId;
945    
946     /* -------------------------------------------------------------------- */
947     /* Establish whether this shape type has M, and Z values. */
948     /* -------------------------------------------------------------------- */
949     if( nSHPType == SHPT_ARCM
950     || nSHPType == SHPT_POINTM
951     || nSHPType == SHPT_POLYGONM
952     || nSHPType == SHPT_MULTIPOINTM )
953     {
954     bHasM = TRUE;
955     bHasZ = FALSE;
956     }
957     else if( nSHPType == SHPT_ARCZ
958     || nSHPType == SHPT_POINTZ
959     || nSHPType == SHPT_POLYGONZ
960     || nSHPType == SHPT_MULTIPOINTZ
961     || nSHPType == SHPT_MULTIPATCH )
962     {
963     bHasM = TRUE;
964     bHasZ = TRUE;
965     }
966     else
967     {
968     bHasM = FALSE;
969     bHasZ = FALSE;
970     }
971    
972     /* -------------------------------------------------------------------- */
973     /* Capture parts. Note that part type is optional, and */
974     /* defaults to ring. */
975     /* -------------------------------------------------------------------- */
976     if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
977     || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM
978     || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ
979     || nSHPType == SHPT_MULTIPATCH )
980     {
981     psObject->nParts = MAX(1,nParts);
982    
983     psObject->panPartStart = (int *)
984     malloc(sizeof(int) * psObject->nParts);
985     psObject->panPartType = (int *)
986     malloc(sizeof(int) * psObject->nParts);
987    
988     psObject->panPartStart[0] = 0;
989     psObject->panPartType[0] = SHPP_RING;
990    
991     for( i = 0; i < nParts; i++ )
992     {
993     psObject->panPartStart[i] = panPartStart[i];
994     if( panPartType != NULL )
995     psObject->panPartType[i] = panPartType[i];
996     else
997     psObject->panPartType[i] = SHPP_RING;
998     }
999     }
1000    
1001     /* -------------------------------------------------------------------- */
1002     /* Capture vertices. Note that Z and M are optional, but X and */
1003     /* Y are not. */
1004     /* -------------------------------------------------------------------- */
1005     if( nVertices > 0 )
1006     {
1007     psObject->padfX = (double *) calloc(sizeof(double),nVertices);
1008     psObject->padfY = (double *) calloc(sizeof(double),nVertices);
1009     psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
1010     psObject->padfM = (double *) calloc(sizeof(double),nVertices);
1011    
1012     assert( padfX != NULL );
1013     assert( padfY != NULL );
1014    
1015     for( i = 0; i < nVertices; i++ )
1016     {
1017     psObject->padfX[i] = padfX[i];
1018     psObject->padfY[i] = padfY[i];
1019     if( padfZ != NULL && bHasZ )
1020     psObject->padfZ[i] = padfZ[i];
1021     if( padfM != NULL && bHasM )
1022     psObject->padfM[i] = padfM[i];
1023     }
1024     }
1025    
1026     /* -------------------------------------------------------------------- */
1027     /* Compute the extents. */
1028     /* -------------------------------------------------------------------- */
1029     psObject->nVertices = nVertices;
1030     SHPComputeExtents( psObject );
1031    
1032     return( psObject );
1033     }
1034    
1035     /************************************************************************/
1036     /* SHPCreateSimpleObject() */
1037     /* */
1038     /* Create a simple (common) shape object. Destroy with */
1039     /* SHPDestroyObject(). */
1040     /************************************************************************/
1041    
1042     SHPObject SHPAPI_CALL1(*)
1043     SHPCreateSimpleObject( int nSHPType, int nVertices,
1044     double * padfX, double * padfY,
1045     double * padfZ )
1046    
1047     {
1048     return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
1049     nVertices, padfX, padfY, padfZ, NULL ) );
1050     }
1051    
1052     /************************************************************************/
1053     /* SHPWriteObject() */
1054     /* */
1055     /* Write out the vertices of a new structure. Note that it is */
1056     /* only possible to write vertices at the end of the file. */
1057     /************************************************************************/
1058    
1059     int SHPAPI_CALL
1060     SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
1061    
1062     {
1063 bh 2212 int nRecordOffset, i, nRecordSize=0;
1064 jan 1612 uchar *pabyRec;
1065     int32 i32;
1066    
1067     psSHP->bUpdated = TRUE;
1068    
1069     /* -------------------------------------------------------------------- */
1070     /* Ensure that shape object matches the type of the file it is */
1071     /* being written to. */
1072     /* -------------------------------------------------------------------- */
1073     assert( psObject->nSHPType == psSHP->nShapeType
1074     || psObject->nSHPType == SHPT_NULL );
1075    
1076     /* -------------------------------------------------------------------- */
1077     /* Ensure that -1 is used for appends. Either blow an */
1078     /* assertion, or if they are disabled, set the shapeid to -1 */
1079     /* for appends. */
1080     /* -------------------------------------------------------------------- */
1081     assert( nShapeId == -1
1082     || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
1083    
1084     if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
1085     nShapeId = -1;
1086    
1087     /* -------------------------------------------------------------------- */
1088     /* Add the new entity to the in memory index. */
1089     /* -------------------------------------------------------------------- */
1090     if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
1091     {
1092     psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
1093    
1094     psSHP->panRecOffset = (int *)
1095     SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
1096     psSHP->panRecSize = (int *)
1097     SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
1098     }
1099    
1100     /* -------------------------------------------------------------------- */
1101     /* Initialize record. */
1102     /* -------------------------------------------------------------------- */
1103     pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
1104     + psObject->nParts * 8 + 128);
1105    
1106     /* -------------------------------------------------------------------- */
1107     /* Extract vertices for a Polygon or Arc. */
1108     /* -------------------------------------------------------------------- */
1109     if( psObject->nSHPType == SHPT_POLYGON
1110     || psObject->nSHPType == SHPT_POLYGONZ
1111     || psObject->nSHPType == SHPT_POLYGONM
1112     || psObject->nSHPType == SHPT_ARC
1113     || psObject->nSHPType == SHPT_ARCZ
1114     || psObject->nSHPType == SHPT_ARCM
1115     || psObject->nSHPType == SHPT_MULTIPATCH )
1116     {
1117     int32 nPoints, nParts;
1118     int i;
1119    
1120     nPoints = psObject->nVertices;
1121     nParts = psObject->nParts;
1122    
1123     _SHPSetBounds( pabyRec + 12, psObject );
1124    
1125     if( bBigEndian ) SwapWord( 4, &nPoints );
1126     if( bBigEndian ) SwapWord( 4, &nParts );
1127    
1128     ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
1129     ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
1130    
1131     nRecordSize = 52;
1132    
1133     /*
1134     * Write part start positions.
1135     */
1136     ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
1137     4 * psObject->nParts );
1138     for( i = 0; i < psObject->nParts; i++ )
1139     {
1140     if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
1141     nRecordSize += 4;
1142     }
1143    
1144     /*
1145     * Write multipatch part types if needed.
1146     */
1147     if( psObject->nSHPType == SHPT_MULTIPATCH )
1148     {
1149     memcpy( pabyRec + nRecordSize, psObject->panPartType,
1150     4*psObject->nParts );
1151     for( i = 0; i < psObject->nParts; i++ )
1152     {
1153     if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
1154     nRecordSize += 4;
1155     }
1156     }
1157    
1158     /*
1159     * Write the (x,y) vertex values.
1160     */
1161     for( i = 0; i < psObject->nVertices; i++ )
1162     {
1163     ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
1164     ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
1165    
1166     if( bBigEndian )
1167     SwapWord( 8, pabyRec + nRecordSize );
1168    
1169     if( bBigEndian )
1170     SwapWord( 8, pabyRec + nRecordSize + 8 );
1171    
1172     nRecordSize += 2 * 8;
1173     }
1174    
1175     /*
1176     * Write the Z coordinates (if any).
1177     */
1178     if( psObject->nSHPType == SHPT_POLYGONZ
1179     || psObject->nSHPType == SHPT_ARCZ
1180     || psObject->nSHPType == SHPT_MULTIPATCH )
1181     {
1182     ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1183     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1184     nRecordSize += 8;
1185    
1186     ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1187     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1188     nRecordSize += 8;
1189    
1190     for( i = 0; i < psObject->nVertices; i++ )
1191     {
1192     ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1193     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1194     nRecordSize += 8;
1195     }
1196     }
1197    
1198     /*
1199     * Write the M values, if any.
1200     */
1201     if( psObject->nSHPType == SHPT_POLYGONM
1202     || psObject->nSHPType == SHPT_ARCM
1203     #ifndef DISABLE_MULTIPATCH_MEASURE
1204     || psObject->nSHPType == SHPT_MULTIPATCH
1205     #endif
1206     || psObject->nSHPType == SHPT_POLYGONZ
1207     || psObject->nSHPType == SHPT_ARCZ )
1208     {
1209     ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1210     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1211     nRecordSize += 8;
1212    
1213     ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1214     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1215     nRecordSize += 8;
1216    
1217     for( i = 0; i < psObject->nVertices; i++ )
1218     {
1219     ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1220     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1221     nRecordSize += 8;
1222     }
1223     }
1224     }
1225    
1226     /* -------------------------------------------------------------------- */
1227     /* Extract vertices for a MultiPoint. */
1228     /* -------------------------------------------------------------------- */
1229     else if( psObject->nSHPType == SHPT_MULTIPOINT
1230     || psObject->nSHPType == SHPT_MULTIPOINTZ
1231     || psObject->nSHPType == SHPT_MULTIPOINTM )
1232     {
1233     int32 nPoints;
1234     int i;
1235    
1236     nPoints = psObject->nVertices;
1237    
1238     _SHPSetBounds( pabyRec + 12, psObject );
1239    
1240     if( bBigEndian ) SwapWord( 4, &nPoints );
1241     ByteCopy( &nPoints, pabyRec + 44, 4 );
1242    
1243     for( i = 0; i < psObject->nVertices; i++ )
1244     {
1245     ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
1246     ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
1247    
1248     if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
1249     if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
1250     }
1251    
1252     nRecordSize = 48 + 16 * psObject->nVertices;
1253    
1254     if( psObject->nSHPType == SHPT_MULTIPOINTZ )
1255     {
1256     ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1257     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1258     nRecordSize += 8;
1259    
1260     ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1261     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1262     nRecordSize += 8;
1263    
1264     for( i = 0; i < psObject->nVertices; i++ )
1265     {
1266     ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1267     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1268     nRecordSize += 8;
1269     }
1270     }
1271    
1272     if( psObject->nSHPType == SHPT_MULTIPOINTZ
1273     || psObject->nSHPType == SHPT_MULTIPOINTM )
1274     {
1275     ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1276     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1277     nRecordSize += 8;
1278    
1279     ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1280     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1281     nRecordSize += 8;
1282    
1283     for( i = 0; i < psObject->nVertices; i++ )
1284     {
1285     ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1286     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1287     nRecordSize += 8;
1288     }
1289     }
1290     }
1291    
1292     /* -------------------------------------------------------------------- */
1293     /* Write point. */
1294     /* -------------------------------------------------------------------- */
1295     else if( psObject->nSHPType == SHPT_POINT
1296     || psObject->nSHPType == SHPT_POINTZ
1297     || psObject->nSHPType == SHPT_POINTM )
1298     {
1299     ByteCopy( psObject->padfX, pabyRec + 12, 8 );
1300     ByteCopy( psObject->padfY, pabyRec + 20, 8 );
1301    
1302     if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
1303     if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
1304    
1305     nRecordSize = 28;
1306    
1307     if( psObject->nSHPType == SHPT_POINTZ )
1308     {
1309     ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
1310     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1311     nRecordSize += 8;
1312     }
1313    
1314     if( psObject->nSHPType == SHPT_POINTZ
1315     || psObject->nSHPType == SHPT_POINTM )
1316     {
1317     ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
1318     if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1319     nRecordSize += 8;
1320     }
1321     }
1322    
1323     /* -------------------------------------------------------------------- */
1324     /* Not much to do for null geometries. */
1325     /* -------------------------------------------------------------------- */
1326     else if( psObject->nSHPType == SHPT_NULL )
1327     {
1328     nRecordSize = 12;
1329     }
1330    
1331     else
1332     {
1333     /* unknown type */
1334     assert( FALSE );
1335     }
1336    
1337     /* -------------------------------------------------------------------- */
1338     /* Establish where we are going to put this record. If we are */
1339     /* rewriting and existing record, and it will fit, then put it */
1340     /* back where the original came from. Otherwise write at the end. */
1341     /* -------------------------------------------------------------------- */
1342     if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
1343     {
1344     if( nShapeId == -1 )
1345     nShapeId = psSHP->nRecords++;
1346    
1347     psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
1348     psSHP->panRecSize[nShapeId] = nRecordSize-8;
1349     psSHP->nFileSize += nRecordSize;
1350     }
1351     else
1352     {
1353     nRecordOffset = psSHP->panRecOffset[nShapeId];
1354     }
1355    
1356     /* -------------------------------------------------------------------- */
1357     /* Set the shape type, record number, and record size. */
1358     /* -------------------------------------------------------------------- */
1359     i32 = nShapeId+1; /* record # */
1360     if( !bBigEndian ) SwapWord( 4, &i32 );
1361     ByteCopy( &i32, pabyRec, 4 );
1362    
1363     i32 = (nRecordSize-8)/2; /* record size */
1364     if( !bBigEndian ) SwapWord( 4, &i32 );
1365     ByteCopy( &i32, pabyRec + 4, 4 );
1366    
1367     i32 = psObject->nSHPType; /* shape type */
1368     if( bBigEndian ) SwapWord( 4, &i32 );
1369     ByteCopy( &i32, pabyRec + 8, 4 );
1370    
1371     /* -------------------------------------------------------------------- */
1372     /* Write out record. */
1373     /* -------------------------------------------------------------------- */
1374     if( fseek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
1375     || fwrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
1376     {
1377 bh 2212 #ifdef USE_CPL
1378     CPLError( CE_Failure, CPLE_FileIO,
1379     "Error in fseek() or fwrite() writing object to .shp file." );
1380     #endif
1381 jan 1612 free( pabyRec );
1382     return -1;
1383     }
1384    
1385     free( pabyRec );
1386    
1387     /* -------------------------------------------------------------------- */
1388     /* Expand file wide bounds based on this shape. */
1389     /* -------------------------------------------------------------------- */
1390     if( psSHP->adBoundsMin[0] == 0.0
1391     && psSHP->adBoundsMax[0] == 0.0
1392     && psSHP->adBoundsMin[1] == 0.0
1393 bh 2212 && psSHP->adBoundsMax[1] == 0.0 )
1394 jan 1612 {
1395 bh 2212 if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
1396     {
1397     psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
1398     psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
1399     psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
1400     psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
1401     }
1402     else
1403     {
1404     psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
1405     psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
1406     psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
1407     psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
1408     }
1409 jan 1612 }
1410    
1411     for( i = 0; i < psObject->nVertices; i++ )
1412     {
1413     psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
1414     psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
1415     psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
1416     psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
1417     psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
1418     psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
1419     psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
1420     psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
1421     }
1422    
1423     return( nShapeId );
1424     }
1425    
1426     /************************************************************************/
1427     /* SHPReadObject() */
1428     /* */
1429     /* Read the vertices, parts, and other non-attribute information */
1430     /* for one shape. */
1431     /************************************************************************/
1432    
1433     SHPObject SHPAPI_CALL1(*)
1434     SHPReadObject( SHPHandle psSHP, int hEntity )
1435    
1436     {
1437     SHPObject *psShape;
1438    
1439     /* -------------------------------------------------------------------- */
1440     /* Validate the record/entity number. */
1441     /* -------------------------------------------------------------------- */
1442     if( hEntity < 0 || hEntity >= psSHP->nRecords )
1443     return( NULL );
1444    
1445     /* -------------------------------------------------------------------- */
1446     /* Ensure our record buffer is large enough. */
1447     /* -------------------------------------------------------------------- */
1448 bh 1769 if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize )
1449 jan 1612 {
1450 bh 1769 psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
1451     psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
1452 jan 1612 }
1453    
1454     /* -------------------------------------------------------------------- */
1455     /* Read the record. */
1456     /* -------------------------------------------------------------------- */
1457 bh 2212 if( fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0
1458     || fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1,
1459     psSHP->fpSHP ) != 1 )
1460     {
1461     #ifdef USE_CPL
1462     CPLError( CE_Failure, CPLE_FileIO,
1463     "Error in fseek() or fread() reading object from .shp file." );
1464     #endif
1465     return NULL;
1466     }
1467 jan 1612
1468     /* -------------------------------------------------------------------- */
1469     /* Allocate and minimally initialize the object. */
1470     /* -------------------------------------------------------------------- */
1471     psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
1472     psShape->nShapeId = hEntity;
1473    
1474 bh 1769 memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
1475 jan 1612 if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
1476    
1477     /* ==================================================================== */
1478     /* Extract vertices for a Polygon or Arc. */
1479     /* ==================================================================== */
1480     if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
1481     || psShape->nSHPType == SHPT_POLYGONZ
1482     || psShape->nSHPType == SHPT_POLYGONM
1483     || psShape->nSHPType == SHPT_ARCZ
1484     || psShape->nSHPType == SHPT_ARCM
1485     || psShape->nSHPType == SHPT_MULTIPATCH )
1486     {
1487     int32 nPoints, nParts;
1488     int i, nOffset;
1489    
1490     /* -------------------------------------------------------------------- */
1491     /* Get the X/Y bounds. */
1492     /* -------------------------------------------------------------------- */
1493 bh 1769 memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
1494     memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
1495     memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
1496     memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
1497 jan 1612
1498     if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
1499     if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
1500     if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
1501     if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
1502    
1503     /* -------------------------------------------------------------------- */
1504     /* Extract part/point count, and build vertex and part arrays */
1505     /* to proper size. */
1506     /* -------------------------------------------------------------------- */
1507 bh 1769 memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
1508     memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
1509 jan 1612
1510     if( bBigEndian ) SwapWord( 4, &nPoints );
1511     if( bBigEndian ) SwapWord( 4, &nParts );
1512    
1513     psShape->nVertices = nPoints;
1514     psShape->padfX = (double *) calloc(nPoints,sizeof(double));
1515     psShape->padfY = (double *) calloc(nPoints,sizeof(double));
1516     psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
1517     psShape->padfM = (double *) calloc(nPoints,sizeof(double));
1518    
1519     psShape->nParts = nParts;
1520     psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
1521     psShape->panPartType = (int *) calloc(nParts,sizeof(int));
1522    
1523     for( i = 0; i < nParts; i++ )
1524     psShape->panPartType[i] = SHPP_RING;
1525    
1526     /* -------------------------------------------------------------------- */
1527     /* Copy out the part array from the record. */
1528     /* -------------------------------------------------------------------- */
1529 bh 1769 memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
1530 jan 1612 for( i = 0; i < nParts; i++ )
1531     {
1532     if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
1533     }
1534    
1535     nOffset = 44 + 8 + 4*nParts;
1536    
1537     /* -------------------------------------------------------------------- */
1538     /* If this is a multipatch, we will also have parts types. */
1539     /* -------------------------------------------------------------------- */
1540     if( psShape->nSHPType == SHPT_MULTIPATCH )
1541     {
1542 bh 1769 memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
1543 jan 1612 for( i = 0; i < nParts; i++ )
1544     {
1545     if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
1546     }
1547    
1548     nOffset += 4*nParts;
1549     }
1550    
1551     /* -------------------------------------------------------------------- */
1552     /* Copy out the vertices from the record. */
1553     /* -------------------------------------------------------------------- */
1554     for( i = 0; i < nPoints; i++ )
1555     {
1556     memcpy(psShape->padfX + i,
1557 bh 1769 psSHP->pabyRec + nOffset + i * 16,
1558 jan 1612 8 );
1559    
1560     memcpy(psShape->padfY + i,
1561 bh 1769 psSHP->pabyRec + nOffset + i * 16 + 8,
1562 jan 1612 8 );
1563    
1564     if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1565     if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1566     }
1567    
1568     nOffset += 16*nPoints;
1569    
1570     /* -------------------------------------------------------------------- */
1571     /* If we have a Z coordinate, collect that now. */
1572     /* -------------------------------------------------------------------- */
1573     if( psShape->nSHPType == SHPT_POLYGONZ
1574     || psShape->nSHPType == SHPT_ARCZ
1575     || psShape->nSHPType == SHPT_MULTIPATCH )
1576     {
1577 bh 1769 memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
1578     memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
1579 jan 1612
1580     if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1581     if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1582    
1583     for( i = 0; i < nPoints; i++ )
1584     {
1585     memcpy( psShape->padfZ + i,
1586 bh 1769 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1587 jan 1612 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
1588     }
1589    
1590     nOffset += 16 + 8*nPoints;
1591     }
1592    
1593     /* -------------------------------------------------------------------- */
1594     /* If we have a M measure value, then read it now. We assume */
1595     /* that the measure can be present for any shape if the size is */
1596     /* big enough, but really it will only occur for the Z shapes */
1597     /* (options), and the M shapes. */
1598     /* -------------------------------------------------------------------- */
1599     if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
1600     {
1601 bh 1769 memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
1602     memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
1603 jan 1612
1604     if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
1605     if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
1606    
1607     for( i = 0; i < nPoints; i++ )
1608     {
1609     memcpy( psShape->padfM + i,
1610 bh 1769 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1611 jan 1612 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
1612     }
1613     }
1614    
1615     }
1616    
1617     /* ==================================================================== */
1618     /* Extract vertices for a MultiPoint. */
1619     /* ==================================================================== */
1620     else if( psShape->nSHPType == SHPT_MULTIPOINT
1621     || psShape->nSHPType == SHPT_MULTIPOINTM
1622     || psShape->nSHPType == SHPT_MULTIPOINTZ )
1623     {
1624     int32 nPoints;
1625     int i, nOffset;
1626    
1627 bh 1769 memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
1628 jan 1612 if( bBigEndian ) SwapWord( 4, &nPoints );
1629    
1630     psShape->nVertices = nPoints;
1631     psShape->padfX = (double *) calloc(nPoints,sizeof(double));
1632     psShape->padfY = (double *) calloc(nPoints,sizeof(double));
1633     psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
1634     psShape->padfM = (double *) calloc(nPoints,sizeof(double));
1635    
1636     for( i = 0; i < nPoints; i++ )
1637     {
1638 bh 1769 memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
1639     memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
1640 jan 1612
1641     if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1642     if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1643     }
1644    
1645     nOffset = 48 + 16*nPoints;
1646    
1647     /* -------------------------------------------------------------------- */
1648     /* Get the X/Y bounds. */
1649     /* -------------------------------------------------------------------- */
1650 bh 1769 memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
1651     memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
1652     memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
1653     memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
1654 jan 1612
1655     if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
1656     if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
1657     if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
1658     if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
1659    
1660     /* -------------------------------------------------------------------- */
1661     /* If we have a Z coordinate, collect that now. */
1662     /* -------------------------------------------------------------------- */
1663     if( psShape->nSHPType == SHPT_MULTIPOINTZ )
1664     {
1665 bh 1769 memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
1666     memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
1667 jan 1612
1668     if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1669     if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1670    
1671     for( i = 0; i < nPoints; i++ )
1672     {
1673     memcpy( psShape->padfZ + i,
1674 bh 1769 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1675 jan 1612 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
1676     }
1677    
1678     nOffset += 16 + 8*nPoints;
1679     }
1680    
1681     /* -------------------------------------------------------------------- */
1682     /* If we have a M measure value, then read it now. We assume */
1683     /* that the measure can be present for any shape if the size is */
1684     /* big enough, but really it will only occur for the Z shapes */
1685     /* (options), and the M shapes. */
1686     /* -------------------------------------------------------------------- */
1687     if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
1688     {
1689 bh 1769 memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
1690     memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
1691 jan 1612
1692     if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
1693     if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
1694    
1695     for( i = 0; i < nPoints; i++ )
1696     {
1697     memcpy( psShape->padfM + i,
1698 bh 1769 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1699 jan 1612 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
1700     }
1701     }
1702     }
1703    
1704     /* ==================================================================== */
1705     /* Extract vertices for a point. */
1706     /* ==================================================================== */
1707     else if( psShape->nSHPType == SHPT_POINT
1708     || psShape->nSHPType == SHPT_POINTM
1709     || psShape->nSHPType == SHPT_POINTZ )
1710     {
1711     int nOffset;
1712    
1713     psShape->nVertices = 1;
1714     psShape->padfX = (double *) calloc(1,sizeof(double));
1715     psShape->padfY = (double *) calloc(1,sizeof(double));
1716     psShape->padfZ = (double *) calloc(1,sizeof(double));
1717     psShape->padfM = (double *) calloc(1,sizeof(double));
1718    
1719 bh 1769 memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
1720     memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
1721 jan 1612
1722     if( bBigEndian ) SwapWord( 8, psShape->padfX );
1723     if( bBigEndian ) SwapWord( 8, psShape->padfY );
1724    
1725     nOffset = 20 + 8;
1726    
1727     /* -------------------------------------------------------------------- */
1728     /* If we have a Z coordinate, collect that now. */
1729     /* -------------------------------------------------------------------- */
1730     if( psShape->nSHPType == SHPT_POINTZ )
1731     {
1732 bh 1769 memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
1733 jan 1612
1734     if( bBigEndian ) SwapWord( 8, psShape->padfZ );
1735    
1736     nOffset += 8;
1737     }
1738    
1739     /* -------------------------------------------------------------------- */
1740     /* If we have a M measure value, then read it now. We assume */
1741     /* that the measure can be present for any shape if the size is */
1742     /* big enough, but really it will only occur for the Z shapes */
1743     /* (options), and the M shapes. */
1744     /* -------------------------------------------------------------------- */
1745     if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 )
1746     {
1747 bh 1769 memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
1748 jan 1612
1749     if( bBigEndian ) SwapWord( 8, psShape->padfM );
1750     }
1751    
1752     /* -------------------------------------------------------------------- */
1753     /* Since no extents are supplied in the record, we will apply */
1754     /* them from the single vertex. */
1755     /* -------------------------------------------------------------------- */
1756     psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
1757     psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
1758     psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
1759     psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
1760     }
1761    
1762     return( psShape );
1763     }
1764    
1765     /************************************************************************/
1766     /* SHPTypeName() */
1767     /************************************************************************/
1768    
1769     const char SHPAPI_CALL1(*)
1770     SHPTypeName( int nSHPType )
1771    
1772     {
1773     switch( nSHPType )
1774     {
1775     case SHPT_NULL:
1776     return "NullShape";
1777    
1778     case SHPT_POINT:
1779     return "Point";
1780    
1781     case SHPT_ARC:
1782     return "Arc";
1783    
1784     case SHPT_POLYGON:
1785     return "Polygon";
1786    
1787     case SHPT_MULTIPOINT:
1788     return "MultiPoint";
1789    
1790     case SHPT_POINTZ:
1791     return "PointZ";
1792    
1793     case SHPT_ARCZ:
1794     return "ArcZ";
1795    
1796     case SHPT_POLYGONZ:
1797     return "PolygonZ";
1798    
1799     case SHPT_MULTIPOINTZ:
1800     return "MultiPointZ";
1801    
1802     case SHPT_POINTM:
1803     return "PointM";
1804    
1805     case SHPT_ARCM:
1806     return "ArcM";
1807    
1808     case SHPT_POLYGONM:
1809     return "PolygonM";
1810    
1811     case SHPT_MULTIPOINTM:
1812     return "MultiPointM";
1813    
1814     case SHPT_MULTIPATCH:
1815     return "MultiPatch";
1816    
1817     default:
1818     return "UnknownShapeType";
1819     }
1820     }
1821    
1822     /************************************************************************/
1823     /* SHPPartTypeName() */
1824     /************************************************************************/
1825    
1826     const char SHPAPI_CALL1(*)
1827     SHPPartTypeName( int nPartType )
1828    
1829     {
1830     switch( nPartType )
1831     {
1832     case SHPP_TRISTRIP:
1833     return "TriangleStrip";
1834    
1835     case SHPP_TRIFAN:
1836     return "TriangleFan";
1837    
1838     case SHPP_OUTERRING:
1839     return "OuterRing";
1840    
1841     case SHPP_INNERRING:
1842     return "InnerRing";
1843    
1844     case SHPP_FIRSTRING:
1845     return "FirstRing";
1846    
1847     case SHPP_RING:
1848     return "Ring";
1849    
1850     default:
1851     return "UnknownPartType";
1852     }
1853     }
1854    
1855     /************************************************************************/
1856     /* SHPDestroyObject() */
1857     /************************************************************************/
1858    
1859     void SHPAPI_CALL
1860     SHPDestroyObject( SHPObject * psShape )
1861    
1862     {
1863     if( psShape == NULL )
1864     return;
1865    
1866     if( psShape->padfX != NULL )
1867     free( psShape->padfX );
1868     if( psShape->padfY != NULL )
1869     free( psShape->padfY );
1870     if( psShape->padfZ != NULL )
1871     free( psShape->padfZ );
1872     if( psShape->padfM != NULL )
1873     free( psShape->padfM );
1874    
1875     if( psShape->panPartStart != NULL )
1876     free( psShape->panPartStart );
1877     if( psShape->panPartType != NULL )
1878     free( psShape->panPartType );
1879    
1880     free( psShape );
1881     }
1882 bh 1769
1883     /************************************************************************/
1884     /* SHPRewindObject() */
1885     /* */
1886     /* Reset the winding of polygon objects to adhere to the */
1887     /* specification. */
1888     /************************************************************************/
1889    
1890     int SHPAPI_CALL
1891     SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
1892    
1893     {
1894     int iOpRing, bAltered = 0;
1895    
1896     /* -------------------------------------------------------------------- */
1897     /* Do nothing if this is not a polygon object. */
1898     /* -------------------------------------------------------------------- */
1899     if( psObject->nSHPType != SHPT_POLYGON
1900     && psObject->nSHPType != SHPT_POLYGONZ
1901     && psObject->nSHPType != SHPT_POLYGONM )
1902     return 0;
1903    
1904 bh 2212 if( psObject->nVertices == 0 || psObject->nParts == 0 )
1905     return 0;
1906    
1907 bh 1769 /* -------------------------------------------------------------------- */
1908     /* Process each of the rings. */
1909     /* -------------------------------------------------------------------- */
1910     for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
1911     {
1912     int bInner, iVert, nVertCount, nVertStart, iCheckRing;
1913     double dfSum, dfTestX, dfTestY;
1914    
1915     /* -------------------------------------------------------------------- */
1916     /* Determine if this ring is an inner ring or an outer ring */
1917     /* relative to all the other rings. For now we assume the */
1918     /* first ring is outer and all others are inner, but eventually */
1919     /* we need to fix this to handle multiple island polygons and */
1920     /* unordered sets of rings. */
1921     /* -------------------------------------------------------------------- */
1922     dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]];
1923     dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]];
1924    
1925     bInner = FALSE;
1926     for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
1927     {
1928     int iEdge;
1929    
1930     if( iCheckRing == iOpRing )
1931     continue;
1932    
1933     nVertStart = psObject->panPartStart[iCheckRing];
1934    
1935     if( iCheckRing == psObject->nParts-1 )
1936     nVertCount = psObject->nVertices
1937     - psObject->panPartStart[iCheckRing];
1938     else
1939     nVertCount = psObject->panPartStart[iCheckRing+1]
1940     - psObject->panPartStart[iCheckRing];
1941    
1942     for( iEdge = 0; iEdge < nVertCount; iEdge++ )
1943     {
1944     int iNext;
1945    
1946     if( iEdge < nVertCount-1 )
1947     iNext = iEdge+1;
1948     else
1949     iNext = 0;
1950    
1951     if( (psObject->padfY[iEdge+nVertStart] < dfTestY
1952     && psObject->padfY[iNext+nVertStart] >= dfTestY)
1953     || (psObject->padfY[iNext+nVertStart] < dfTestY
1954     && psObject->padfY[iEdge+nVertStart] >= dfTestY) )
1955     {
1956     if( psObject->padfX[iEdge+nVertStart]
1957     + (dfTestY - psObject->padfY[iEdge+nVertStart])
1958     / (psObject->padfY[iNext+nVertStart]
1959     - psObject->padfY[iEdge+nVertStart])
1960     * (psObject->padfX[iNext+nVertStart]
1961     - psObject->padfX[iEdge+nVertStart]) < dfTestX )
1962     bInner = !bInner;
1963     }
1964     }
1965     }
1966    
1967     /* -------------------------------------------------------------------- */
1968     /* Determine the current order of this ring so we will know if */
1969     /* it has to be reversed. */
1970     /* -------------------------------------------------------------------- */
1971     nVertStart = psObject->panPartStart[iOpRing];
1972    
1973     if( iOpRing == psObject->nParts-1 )
1974     nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
1975     else
1976     nVertCount = psObject->panPartStart[iOpRing+1]
1977     - psObject->panPartStart[iOpRing];
1978    
1979     dfSum = 0.0;
1980     for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
1981     {
1982     dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
1983     - psObject->padfY[iVert] * psObject->padfX[iVert+1];
1984     }
1985    
1986     dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
1987     - psObject->padfY[iVert] * psObject->padfX[nVertStart];
1988    
1989     /* -------------------------------------------------------------------- */
1990     /* Reverse if necessary. */
1991     /* -------------------------------------------------------------------- */
1992     if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
1993     {
1994     int i;
1995    
1996     bAltered++;
1997     for( i = 0; i < nVertCount/2; i++ )
1998     {
1999     double dfSaved;
2000    
2001     /* Swap X */
2002     dfSaved = psObject->padfX[nVertStart+i];
2003     psObject->padfX[nVertStart+i] =
2004     psObject->padfX[nVertStart+nVertCount-i-1];
2005     psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
2006    
2007     /* Swap Y */
2008     dfSaved = psObject->padfY[nVertStart+i];
2009     psObject->padfY[nVertStart+i] =
2010     psObject->padfY[nVertStart+nVertCount-i-1];
2011     psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
2012    
2013     /* Swap Z */
2014     if( psObject->padfZ )
2015     {
2016     dfSaved = psObject->padfZ[nVertStart+i];
2017     psObject->padfZ[nVertStart+i] =
2018     psObject->padfZ[nVertStart+nVertCount-i-1];
2019     psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
2020     }
2021    
2022     /* Swap M */
2023     if( psObject->padfM )
2024     {
2025     dfSaved = psObject->padfM[nVertStart+i];
2026     psObject->padfM[nVertStart+i] =
2027     psObject->padfM[nVertStart+nVertCount-i-1];
2028     psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
2029     }
2030     }
2031     }
2032     }
2033    
2034     return bAltered;
2035     }

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26