/[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 1769 - (hide annotations)
Thu Oct 2 15:15:16 2003 UTC (21 years, 5 months ago) by bh
Original Path: trunk/thuban/libraries/shapelib/shpopen.c
File MIME type: text/plain
File size: 69000 byte(s)
Update to shapelib 1.2.10

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26