pihmLIBS/shpopen.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  * $Id: shpopen.c,v 1.39 2002/08/26 06:46:56 warmerda Exp $
00003  *
00004  * Project:  Shapelib
00005  * Purpose:  Implementation of core Shapefile read/write functions.
00006  * Author:   Frank Warmerdam, warmerdam@pobox.com
00007  *
00008  ******************************************************************************
00009  * Copyright (c) 1999, 2001, Frank Warmerdam
00010  *
00011  * This software is available under the following "MIT Style" license,
00012  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
00013  * option is discussed in more detail in shapelib.html.
00014  *
00015  * --
00016  * 
00017  * Permission is hereby granted, free of charge, to any person obtaining a
00018  * copy of this software and associated documentation files (the "Software"),
00019  * to deal in the Software without restriction, including without limitation
00020  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00021  * and/or sell copies of the Software, and to permit persons to whom the
00022  * Software is furnished to do so, subject to the following conditions:
00023  *
00024  * The above copyright notice and this permission notice shall be included
00025  * in all copies or substantial portions of the Software.
00026  *
00027  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00028  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00029  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00030  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00031  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00032  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00033  * DEALINGS IN THE SOFTWARE.
00034  ******************************************************************************
00035  *
00036  * $Log: shpopen.c,v $
00037  * Revision 1.39  2002/08/26 06:46:56  warmerda
00038  * avoid c++ comments
00039  *
00040  * Revision 1.38  2002/05/07 16:43:39  warmerda
00041  * Removed debugging printf.
00042  *
00043  * Revision 1.37  2002/04/10 17:35:22  warmerda
00044  * fixed bug in ring reversal code
00045  *
00046  * Revision 1.36  2002/04/10 16:59:54  warmerda
00047  * added SHPRewindObject
00048  *
00049  * Revision 1.35  2001/12/07 15:10:44  warmerda
00050  * fix if .shx fails to open
00051  *
00052  * Revision 1.34  2001/11/01 16:29:55  warmerda
00053  * move pabyRec into SHPInfo for thread safety
00054  *
00055  * Revision 1.33  2001/07/03 12:18:15  warmerda
00056  * Improved cleanup if SHX not found, provied by Riccardo Cohen.
00057  *
00058  * Revision 1.32  2001/06/22 01:58:07  warmerda
00059  * be more careful about establishing initial bounds in face of NULL shapes
00060  *
00061  * Revision 1.31  2001/05/31 19:35:29  warmerda
00062  * added support for writing null shapes
00063  *
00064  * Revision 1.30  2001/05/28 12:46:29  warmerda
00065  * Add some checking on reasonableness of record count when opening.
00066  *
00067  * Revision 1.29  2001/05/23 13:36:52  warmerda
00068  * added use of SHPAPI_CALL
00069  *
00070  * Revision 1.28  2001/02/06 22:25:06  warmerda
00071  * fixed memory leaks when SHPOpen() fails
00072  *
00073  * Revision 1.27  2000/07/18 15:21:33  warmerda
00074  * added better enforcement of -1 for append in SHPWriteObject
00075  *
00076  * Revision 1.26  2000/02/16 16:03:51  warmerda
00077  * added null shape support
00078  *
00079  * Revision 1.25  1999/12/15 13:47:07  warmerda
00080  * Fixed record size settings in .shp file (was 4 words too long)
00081  * Added stdlib.h.
00082  *
00083  * Revision 1.24  1999/11/05 14:12:04  warmerda
00084  * updated license terms
00085  *
00086  * Revision 1.23  1999/07/27 00:53:46  warmerda
00087  * added support for rewriting shapes
00088  *
00089  * Revision 1.22  1999/06/11 19:19:11  warmerda
00090  * Cleanup pabyRec static buffer on SHPClose().
00091  *
00092  * Revision 1.21  1999/06/02 14:57:56  kshih
00093  * Remove unused variables
00094  *
00095  * Revision 1.20  1999/04/19 21:04:17  warmerda
00096  * Fixed syntax error.
00097  *
00098  * Revision 1.19  1999/04/19 21:01:57  warmerda
00099  * Force access string to binary in SHPOpen().
00100  *
00101  * Revision 1.18  1999/04/01 18:48:07  warmerda
00102  * Try upper case extensions if lower case doesn't work.
00103  *
00104  * Revision 1.17  1998/12/31 15:29:39  warmerda
00105  * Disable writing measure values to multipatch objects if
00106  * DISABLE_MULTIPATCH_MEASURE is defined.
00107  *
00108  * Revision 1.16  1998/12/16 05:14:33  warmerda
00109  * Added support to write MULTIPATCH.  Fixed reading Z coordinate of
00110  * MULTIPATCH. Fixed record size written for all feature types.
00111  *
00112  * Revision 1.15  1998/12/03 16:35:29  warmerda
00113  * r+b is proper binary access string, not rb+.
00114  *
00115  * Revision 1.14  1998/12/03 15:47:56  warmerda
00116  * Fixed setting of nVertices in SHPCreateObject().
00117  *
00118  * Revision 1.13  1998/12/03 15:33:54  warmerda
00119  * Made SHPCalculateExtents() separately callable.
00120  *
00121  * Revision 1.12  1998/11/11 20:01:50  warmerda
00122  * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
00123  *
00124  * Revision 1.11  1998/11/09 20:56:44  warmerda
00125  * Fixed up handling of file wide bounds.
00126  *
00127  * Revision 1.10  1998/11/09 20:18:51  warmerda
00128  * Converted to support 3D shapefiles, and use of SHPObject.
00129  *
00130  * Revision 1.9  1998/02/24 15:09:05  warmerda
00131  * Fixed memory leak.
00132  *
00133  * Revision 1.8  1997/12/04 15:40:29  warmerda
00134  * Fixed byte swapping of record number, and record length fields in the
00135  * .shp file.
00136  *
00137  * Revision 1.7  1995/10/21 03:15:58  warmerda
00138  * Added support for binary file access, the magic cookie 9997
00139  * and tried to improve the int32 selection logic for 16bit systems.
00140  *
00141  * Revision 1.6  1995/09/04  04:19:41  warmerda
00142  * Added fix for file bounds.
00143  *
00144  * Revision 1.5  1995/08/25  15:16:44  warmerda
00145  * Fixed a couple of problems with big endian systems ... one with bounds
00146  * and the other with multipart polygons.
00147  *
00148  * Revision 1.4  1995/08/24  18:10:17  warmerda
00149  * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()
00150  * functions (such as on the Sun).
00151  *
00152  * Revision 1.3  1995/08/23  02:23:15  warmerda
00153  * Added support for reading bounds, and fixed up problems in setting the
00154  * file wide bounds.
00155  *
00156  * Revision 1.2  1995/08/04  03:16:57  warmerda
00157  * Added header.
00158  *
00159  */
00160 
00161 static char rcsid[] = 
00162   "$Id: shpopen.c,v 1.39 2002/08/26 06:46:56 warmerda Exp $";
00163 
00164 #include "shapefil.h"
00165 
00166 #include <math.h>
00167 #include <limits.h>
00168 #include <assert.h>
00169 #include <stdlib.h>
00170 #include <string.h>
00171 
00172 typedef unsigned char uchar;
00173 
00174 #if UINT_MAX == 65535
00175 typedef long          int32;
00176 #else
00177 typedef int           int32;
00178 #endif
00179 
00180 #ifndef FALSE
00181 #  define FALSE         0
00182 #  define TRUE          1
00183 #endif
00184 
00185 #define ByteCopy( a, b, c )     memcpy( b, a, c )
00186 #ifndef MAX
00187 #  define MIN(a,b)      ((a<b) ? a : b)
00188 #  define MAX(a,b)      ((a>b) ? a : b)
00189 #endif
00190 
00191 static int      bBigEndian;
00192 
00193 
00194 /************************************************************************/
00195 /*                              SwapWord()                              */
00196 /*                                                                      */
00197 /*      Swap a 2, 4 or 8 byte word.                                     */
00198 /************************************************************************/
00199 
00200 static void     SwapWord( int length, void * wordP )
00201 
00202 {
00203     int         i;
00204     uchar       temp;
00205 
00206     for( i=0; i < length/2; i++ )
00207     {
00208         temp = ((uchar *) wordP)[i];
00209         ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
00210         ((uchar *) wordP)[length-i-1] = temp;
00211     }
00212 }
00213 
00214 /************************************************************************/
00215 /*                             SfRealloc()                              */
00216 /*                                                                      */
00217 /*      A realloc cover function that will access a NULL pointer as     */
00218 /*      a valid input.                                                  */
00219 /************************************************************************/
00220 
00221 static void * SfRealloc( void * pMem, int nNewSize )
00222 
00223 {
00224     if( pMem == NULL )
00225         return( (void *) malloc(nNewSize) );
00226     else
00227         return( (void *) realloc(pMem,nNewSize) );
00228 }
00229 
00230 /************************************************************************/
00231 /*                          SHPWriteHeader()                            */
00232 /*                                                                      */
00233 /*      Write out a header for the .shp and .shx files as well as the   */
00234 /*      contents of the index (.shx) file.                              */
00235 /************************************************************************/
00236 
00237 static void SHPWriteHeader( SHPHandle psSHP )
00238 
00239 {
00240     uchar       abyHeader[100];
00241     int         i;
00242     int32       i32;
00243     double      dValue;
00244     int32       *panSHX;
00245 
00246 /* -------------------------------------------------------------------- */
00247 /*      Prepare header block for .shp file.                             */
00248 /* -------------------------------------------------------------------- */
00249     for( i = 0; i < 100; i++ )
00250       abyHeader[i] = 0;
00251 
00252     abyHeader[2] = 0x27;                                /* magic cookie */
00253     abyHeader[3] = 0x0a;
00254 
00255     i32 = psSHP->nFileSize/2;                           /* file size */
00256     ByteCopy( &i32, abyHeader+24, 4 );
00257     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00258     
00259     i32 = 1000;                                         /* version */
00260     ByteCopy( &i32, abyHeader+28, 4 );
00261     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
00262     
00263     i32 = psSHP->nShapeType;                            /* shape type */
00264     ByteCopy( &i32, abyHeader+32, 4 );
00265     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
00266 
00267     dValue = psSHP->adBoundsMin[0];                     /* set bounds */
00268     ByteCopy( &dValue, abyHeader+36, 8 );
00269     if( bBigEndian ) SwapWord( 8, abyHeader+36 );
00270 
00271     dValue = psSHP->adBoundsMin[1];
00272     ByteCopy( &dValue, abyHeader+44, 8 );
00273     if( bBigEndian ) SwapWord( 8, abyHeader+44 );
00274 
00275     dValue = psSHP->adBoundsMax[0];
00276     ByteCopy( &dValue, abyHeader+52, 8 );
00277     if( bBigEndian ) SwapWord( 8, abyHeader+52 );
00278 
00279     dValue = psSHP->adBoundsMax[1];
00280     ByteCopy( &dValue, abyHeader+60, 8 );
00281     if( bBigEndian ) SwapWord( 8, abyHeader+60 );
00282 
00283     dValue = psSHP->adBoundsMin[2];                     /* z */
00284     ByteCopy( &dValue, abyHeader+68, 8 );
00285     if( bBigEndian ) SwapWord( 8, abyHeader+68 );
00286 
00287     dValue = psSHP->adBoundsMax[2];
00288     ByteCopy( &dValue, abyHeader+76, 8 );
00289     if( bBigEndian ) SwapWord( 8, abyHeader+76 );
00290 
00291     dValue = psSHP->adBoundsMin[3];                     /* m */
00292     ByteCopy( &dValue, abyHeader+84, 8 );
00293     if( bBigEndian ) SwapWord( 8, abyHeader+84 );
00294 
00295     dValue = psSHP->adBoundsMax[3];
00296     ByteCopy( &dValue, abyHeader+92, 8 );
00297     if( bBigEndian ) SwapWord( 8, abyHeader+92 );
00298 
00299 /* -------------------------------------------------------------------- */
00300 /*      Write .shp file header.                                         */
00301 /* -------------------------------------------------------------------- */
00302     fseek( psSHP->fpSHP, 0, 0 );
00303     fwrite( abyHeader, 100, 1, psSHP->fpSHP );
00304 
00305 /* -------------------------------------------------------------------- */
00306 /*      Prepare, and write .shx file header.                            */
00307 /* -------------------------------------------------------------------- */
00308     i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2;   /* file size */
00309     ByteCopy( &i32, abyHeader+24, 4 );
00310     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00311     
00312     fseek( psSHP->fpSHX, 0, 0 );
00313     fwrite( abyHeader, 100, 1, psSHP->fpSHX );
00314 
00315 /* -------------------------------------------------------------------- */
00316 /*      Write out the .shx contents.                                    */
00317 /* -------------------------------------------------------------------- */
00318     panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
00319 
00320     for( i = 0; i < psSHP->nRecords; i++ )
00321     {
00322         panSHX[i*2  ] = psSHP->panRecOffset[i]/2;
00323         panSHX[i*2+1] = psSHP->panRecSize[i]/2;
00324         if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
00325         if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
00326     }
00327 
00328     fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX );
00329 
00330     free( panSHX );
00331 }
00332 
00333 /************************************************************************/
00334 /*                              SHPOpen()                               */
00335 /*                                                                      */
00336 /*      Open the .shp and .shx files based on the basename of the       */
00337 /*      files or either file name.                                      */
00338 /************************************************************************/
00339    
00340 SHPHandle SHPAPI_CALL
00341 SHPOpen( const char * pszLayer, const char * pszAccess )
00342 
00343 {
00344     char                *pszFullname, *pszBasename;
00345     SHPHandle           psSHP;
00346     
00347     uchar               *pabyBuf;
00348     int                 i;
00349     double              dValue;
00350     
00351 /* -------------------------------------------------------------------- */
00352 /*      Ensure the access string is one of the legal ones.  We          */
00353 /*      ensure the result string indicates binary to avoid common       */
00354 /*      problems on Windows.                                            */
00355 /* -------------------------------------------------------------------- */
00356     if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
00357         || strcmp(pszAccess,"r+") == 0 )
00358         pszAccess = "r+b";
00359     else
00360         pszAccess = "rb";
00361     
00362 /* -------------------------------------------------------------------- */
00363 /*      Establish the byte order on this machine.                       */
00364 /* -------------------------------------------------------------------- */
00365     i = 1;
00366     if( *((uchar *) &i) == 1 )
00367         bBigEndian = FALSE;
00368     else
00369         bBigEndian = TRUE;
00370 
00371 /* -------------------------------------------------------------------- */
00372 /*      Initialize the info structure.                                  */
00373 /* -------------------------------------------------------------------- */
00374     psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
00375 
00376     psSHP->bUpdated = FALSE;
00377 
00378 /* -------------------------------------------------------------------- */
00379 /*      Compute the base (layer) name.  If there is any extension       */
00380 /*      on the passed in filename we will strip it off.                 */
00381 /* -------------------------------------------------------------------- */
00382     pszBasename = (char *) malloc(strlen(pszLayer)+5);
00383     strcpy( pszBasename, pszLayer );
00384     for( i = strlen(pszBasename)-1; 
00385          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
00386                && pszBasename[i] != '\\';
00387          i-- ) {}
00388 
00389     if( pszBasename[i] == '.' )
00390         pszBasename[i] = '\0';
00391 
00392 /* -------------------------------------------------------------------- */
00393 /*      Open the .shp and .shx files.  Note that files pulled from      */
00394 /*      a PC to Unix with upper case filenames won't work!              */
00395 /* -------------------------------------------------------------------- */
00396     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
00397     sprintf( pszFullname, "%s.shp", pszBasename );
00398     psSHP->fpSHP = fopen(pszFullname, pszAccess );
00399     if( psSHP->fpSHP == NULL )
00400     {
00401         sprintf( pszFullname, "%s.SHP", pszBasename );
00402         psSHP->fpSHP = fopen(pszFullname, pszAccess );
00403     }
00404     
00405     if( psSHP->fpSHP == NULL )
00406     {
00407         free( psSHP );
00408         free( pszBasename );
00409         free( pszFullname );
00410         return( NULL );
00411     }
00412 
00413     sprintf( pszFullname, "%s.shx", pszBasename );
00414     psSHP->fpSHX = fopen(pszFullname, pszAccess );
00415     if( psSHP->fpSHX == NULL )
00416     {
00417         sprintf( pszFullname, "%s.SHX", pszBasename );
00418         psSHP->fpSHX = fopen(pszFullname, pszAccess );
00419     }
00420     
00421     if( psSHP->fpSHX == NULL )
00422     {
00423         fclose( psSHP->fpSHP );
00424         free( psSHP );
00425         free( pszBasename );
00426         free( pszFullname );
00427         return( NULL );
00428     }
00429 
00430     free( pszFullname );
00431     free( pszBasename );
00432 
00433 /* -------------------------------------------------------------------- */
00434 /*  Read the file size from the SHP file.                               */
00435 /* -------------------------------------------------------------------- */
00436     pabyBuf = (uchar *) malloc(100);
00437     fread( pabyBuf, 100, 1, psSHP->fpSHP );
00438 
00439     psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
00440                         + pabyBuf[25] * 256 * 256
00441                         + pabyBuf[26] * 256
00442                         + pabyBuf[27]) * 2;
00443 
00444 /* -------------------------------------------------------------------- */
00445 /*  Read SHX file Header info                                           */
00446 /* -------------------------------------------------------------------- */
00447     fread( pabyBuf, 100, 1, psSHP->fpSHX );
00448 
00449     if( pabyBuf[0] != 0 
00450         || pabyBuf[1] != 0 
00451         || pabyBuf[2] != 0x27 
00452         || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
00453     {
00454         fclose( psSHP->fpSHP );
00455         fclose( psSHP->fpSHX );
00456         free( psSHP );
00457 
00458         return( NULL );
00459     }
00460 
00461     psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
00462       + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
00463     psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
00464 
00465     psSHP->nShapeType = pabyBuf[32];
00466 
00467     if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
00468     {
00469         /* this header appears to be corrupt.  Give up. */
00470         fclose( psSHP->fpSHP );
00471         fclose( psSHP->fpSHX );
00472         free( psSHP );
00473 
00474         return( NULL );
00475     }
00476 
00477 /* -------------------------------------------------------------------- */
00478 /*      Read the bounds.                                                */
00479 /* -------------------------------------------------------------------- */
00480     if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
00481     memcpy( &dValue, pabyBuf+36, 8 );
00482     psSHP->adBoundsMin[0] = dValue;
00483 
00484     if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
00485     memcpy( &dValue, pabyBuf+44, 8 );
00486     psSHP->adBoundsMin[1] = dValue;
00487 
00488     if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
00489     memcpy( &dValue, pabyBuf+52, 8 );
00490     psSHP->adBoundsMax[0] = dValue;
00491 
00492     if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
00493     memcpy( &dValue, pabyBuf+60, 8 );
00494     psSHP->adBoundsMax[1] = dValue;
00495 
00496     if( bBigEndian ) SwapWord( 8, pabyBuf+68 );         /* z */
00497     memcpy( &dValue, pabyBuf+68, 8 );
00498     psSHP->adBoundsMin[2] = dValue;
00499     
00500     if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
00501     memcpy( &dValue, pabyBuf+76, 8 );
00502     psSHP->adBoundsMax[2] = dValue;
00503     
00504     if( bBigEndian ) SwapWord( 8, pabyBuf+84 );         /* z */
00505     memcpy( &dValue, pabyBuf+84, 8 );
00506     psSHP->adBoundsMin[3] = dValue;
00507 
00508     if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
00509     memcpy( &dValue, pabyBuf+92, 8 );
00510     psSHP->adBoundsMax[3] = dValue;
00511 
00512     free( pabyBuf );
00513 
00514 /* -------------------------------------------------------------------- */
00515 /*      Read the .shx file to get the offsets to each record in         */
00516 /*      the .shp file.                                                  */
00517 /* -------------------------------------------------------------------- */
00518     psSHP->nMaxRecords = psSHP->nRecords;
00519 
00520     psSHP->panRecOffset =
00521         (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
00522     psSHP->panRecSize =
00523         (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
00524 
00525     pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
00526     fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX );
00527 
00528     for( i = 0; i < psSHP->nRecords; i++ )
00529     {
00530         int32           nOffset, nLength;
00531 
00532         memcpy( &nOffset, pabyBuf + i * 8, 4 );
00533         if( !bBigEndian ) SwapWord( 4, &nOffset );
00534 
00535         memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
00536         if( !bBigEndian ) SwapWord( 4, &nLength );
00537 
00538         psSHP->panRecOffset[i] = nOffset*2;
00539         psSHP->panRecSize[i] = nLength*2;
00540     }
00541     free( pabyBuf );
00542 
00543     return( psSHP );
00544 }
00545 
00546 /************************************************************************/
00547 /*                              SHPClose()                              */
00548 /*                                                                      */
00549 /*      Close the .shp and .shx files.                                  */
00550 /************************************************************************/
00551 
00552 void SHPAPI_CALL
00553 SHPClose(SHPHandle psSHP )
00554 
00555 {
00556 /* -------------------------------------------------------------------- */
00557 /*      Update the header if we have modified anything.                 */
00558 /* -------------------------------------------------------------------- */
00559     if( psSHP->bUpdated )
00560     {
00561         SHPWriteHeader( psSHP );
00562     }
00563 
00564 /* -------------------------------------------------------------------- */
00565 /*      Free all resources, and close files.                            */
00566 /* -------------------------------------------------------------------- */
00567     free( psSHP->panRecOffset );
00568     free( psSHP->panRecSize );
00569 
00570     fclose( psSHP->fpSHX );
00571     fclose( psSHP->fpSHP );
00572 
00573     if( psSHP->pabyRec != NULL )
00574     {
00575         free( psSHP->pabyRec );
00576     }
00577     
00578     free( psSHP );
00579 }
00580 
00581 /************************************************************************/
00582 /*                             SHPGetInfo()                             */
00583 /*                                                                      */
00584 /*      Fetch general information about the shape file.                 */
00585 /************************************************************************/
00586 
00587 void SHPAPI_CALL
00588 SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
00589            double * padfMinBound, double * padfMaxBound )
00590 
00591 {
00592     int         i;
00593     
00594     if( pnEntities != NULL )
00595         *pnEntities = psSHP->nRecords;
00596 
00597     if( pnShapeType != NULL )
00598         *pnShapeType = psSHP->nShapeType;
00599 
00600     for( i = 0; i < 4; i++ )
00601     {
00602         if( padfMinBound != NULL )
00603             padfMinBound[i] = psSHP->adBoundsMin[i];
00604         if( padfMaxBound != NULL )
00605             padfMaxBound[i] = psSHP->adBoundsMax[i];
00606     }
00607 }
00608 
00609 /************************************************************************/
00610 /*                             SHPCreate()                              */
00611 /*                                                                      */
00612 /*      Create a new shape file and return a handle to the open         */
00613 /*      shape file with read/write access.                              */
00614 /************************************************************************/
00615 
00616 SHPHandle SHPAPI_CALL
00617 SHPCreate( const char * pszLayer, int nShapeType )
00618 
00619 {
00620     char        *pszBasename, *pszFullname;
00621     int         i;
00622     FILE        *fpSHP, *fpSHX;
00623     uchar       abyHeader[100];
00624     int32       i32;
00625     double      dValue;
00626     
00627 /* -------------------------------------------------------------------- */
00628 /*      Establish the byte order on this system.                        */
00629 /* -------------------------------------------------------------------- */
00630     i = 1;
00631     if( *((uchar *) &i) == 1 )
00632         bBigEndian = FALSE;
00633     else
00634         bBigEndian = TRUE;
00635 
00636 /* -------------------------------------------------------------------- */
00637 /*      Compute the base (layer) name.  If there is any extension       */
00638 /*      on the passed in filename we will strip it off.                 */
00639 /* -------------------------------------------------------------------- */
00640     pszBasename = (char *) malloc(strlen(pszLayer)+5);
00641     strcpy( pszBasename, pszLayer );
00642     for( i = strlen(pszBasename)-1; 
00643          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
00644                && pszBasename[i] != '\\';
00645          i-- ) {}
00646 
00647     if( pszBasename[i] == '.' )
00648         pszBasename[i] = '\0';
00649 
00650 /* -------------------------------------------------------------------- */
00651 /*      Open the two files so we can write their headers.               */
00652 /* -------------------------------------------------------------------- */
00653     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
00654     sprintf( pszFullname, "%s.shp", pszBasename );
00655     fpSHP = fopen(pszFullname, "wb" );
00656     if( fpSHP == NULL )
00657         return( NULL );
00658 
00659     sprintf( pszFullname, "%s.shx", pszBasename );
00660     fpSHX = fopen(pszFullname, "wb" );
00661     if( fpSHX == NULL )
00662         return( NULL );
00663 
00664     free( pszFullname );
00665     free( pszBasename );
00666 
00667 /* -------------------------------------------------------------------- */
00668 /*      Prepare header block for .shp file.                             */
00669 /* -------------------------------------------------------------------- */
00670     for( i = 0; i < 100; i++ )
00671       abyHeader[i] = 0;
00672 
00673     abyHeader[2] = 0x27;                                /* magic cookie */
00674     abyHeader[3] = 0x0a;
00675 
00676     i32 = 50;                                           /* file size */
00677     ByteCopy( &i32, abyHeader+24, 4 );
00678     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00679     
00680     i32 = 1000;                                         /* version */
00681     ByteCopy( &i32, abyHeader+28, 4 );
00682     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
00683     
00684     i32 = nShapeType;                                   /* shape type */
00685     ByteCopy( &i32, abyHeader+32, 4 );
00686     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
00687 
00688     dValue = 0.0;                                       /* set bounds */
00689     ByteCopy( &dValue, abyHeader+36, 8 );
00690     ByteCopy( &dValue, abyHeader+44, 8 );
00691     ByteCopy( &dValue, abyHeader+52, 8 );
00692     ByteCopy( &dValue, abyHeader+60, 8 );
00693 
00694 /* -------------------------------------------------------------------- */
00695 /*      Write .shp file header.                                         */
00696 /* -------------------------------------------------------------------- */
00697     fwrite( abyHeader, 100, 1, fpSHP );
00698 
00699 /* -------------------------------------------------------------------- */
00700 /*      Prepare, and write .shx file header.                            */
00701 /* -------------------------------------------------------------------- */
00702     i32 = 50;                                           /* file size */
00703     ByteCopy( &i32, abyHeader+24, 4 );
00704     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00705     
00706     fwrite( abyHeader, 100, 1, fpSHX );
00707 
00708 /* -------------------------------------------------------------------- */
00709 /*      Close the files, and then open them as regular existing files.  */
00710 /* -------------------------------------------------------------------- */
00711     fclose( fpSHP );
00712     fclose( fpSHX );
00713 
00714     return( SHPOpen( pszLayer, "r+b" ) );
00715 }
00716 
00717 /************************************************************************/
00718 /*                           _SHPSetBounds()                            */
00719 /*                                                                      */
00720 /*      Compute a bounds rectangle for a shape, and set it into the     */
00721 /*      indicated location in the record.                               */
00722 /************************************************************************/
00723 
00724 static void     _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
00725 
00726 {
00727     ByteCopy( &(psShape->dfXMin), pabyRec +  0, 8 );
00728     ByteCopy( &(psShape->dfYMin), pabyRec +  8, 8 );
00729     ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
00730     ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
00731 
00732     if( bBigEndian )
00733     {
00734         SwapWord( 8, pabyRec + 0 );
00735         SwapWord( 8, pabyRec + 8 );
00736         SwapWord( 8, pabyRec + 16 );
00737         SwapWord( 8, pabyRec + 24 );
00738     }
00739 }
00740 
00741 /************************************************************************/
00742 /*                         SHPComputeExtents()                          */
00743 /*                                                                      */
00744 /*      Recompute the extents of a shape.  Automatically done by        */
00745 /*      SHPCreateObject().                                              */
00746 /************************************************************************/
00747 
00748 void SHPAPI_CALL
00749 SHPComputeExtents( SHPObject * psObject )
00750 
00751 {
00752     int         i;
00753     
00754 /* -------------------------------------------------------------------- */
00755 /*      Build extents for this object.                                  */
00756 /* -------------------------------------------------------------------- */
00757     if( psObject->nVertices > 0 )
00758     {
00759         psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
00760         psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
00761         psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
00762         psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
00763     }
00764     
00765     for( i = 0; i < psObject->nVertices; i++ )
00766     {
00767         psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
00768         psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
00769         psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
00770         psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
00771 
00772         psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
00773         psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
00774         psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
00775         psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
00776     }
00777 }
00778 
00779 /************************************************************************/
00780 /*                          SHPCreateObject()                           */
00781 /*                                                                      */
00782 /*      Create a shape object.  It should be freed with                 */
00783 /*      SHPDestroyObject().                                             */
00784 /************************************************************************/
00785 
00786 SHPObject SHPAPI_CALL1(*)
00787 SHPCreateObject( int nSHPType, int nShapeId, int nParts,
00788                  int * panPartStart, int * panPartType,
00789                  int nVertices, double * padfX, double * padfY,
00790                  double * padfZ, double * padfM )
00791 
00792 {
00793     SHPObject   *psObject;
00794     int         i, bHasM, bHasZ;
00795 
00796     psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
00797     psObject->nSHPType = nSHPType;
00798     psObject->nShapeId = nShapeId;
00799 
00800 /* -------------------------------------------------------------------- */
00801 /*      Establish whether this shape type has M, and Z values.          */
00802 /* -------------------------------------------------------------------- */
00803     if( nSHPType == SHPT_ARCM
00804         || nSHPType == SHPT_POINTM
00805         || nSHPType == SHPT_POLYGONM
00806         || nSHPType == SHPT_MULTIPOINTM )
00807     {
00808         bHasM = TRUE;
00809         bHasZ = FALSE;
00810     }
00811     else if( nSHPType == SHPT_ARCZ
00812              || nSHPType == SHPT_POINTZ
00813              || nSHPType == SHPT_POLYGONZ
00814              || nSHPType == SHPT_MULTIPOINTZ
00815              || nSHPType == SHPT_MULTIPATCH )
00816     {
00817         bHasM = TRUE;
00818         bHasZ = TRUE;
00819     }
00820     else
00821     {
00822         bHasM = FALSE;
00823         bHasZ = FALSE;
00824     }
00825 
00826 /* -------------------------------------------------------------------- */
00827 /*      Capture parts.  Note that part type is optional, and            */
00828 /*      defaults to ring.                                               */
00829 /* -------------------------------------------------------------------- */
00830     if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
00831         || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM
00832         || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ
00833         || nSHPType == SHPT_MULTIPATCH )
00834     {
00835         psObject->nParts = MAX(1,nParts);
00836 
00837         psObject->panPartStart = (int *)
00838             malloc(sizeof(int) * psObject->nParts);
00839         psObject->panPartType = (int *)
00840             malloc(sizeof(int) * psObject->nParts);
00841 
00842         psObject->panPartStart[0] = 0;
00843         psObject->panPartType[0] = SHPP_RING;
00844         
00845         for( i = 0; i < nParts; i++ )
00846         {
00847             psObject->panPartStart[i] = panPartStart[i];
00848             if( panPartType != NULL )
00849                 psObject->panPartType[i] = panPartType[i];
00850             else
00851                 psObject->panPartType[i] = SHPP_RING;
00852         }
00853     }
00854 
00855 /* -------------------------------------------------------------------- */
00856 /*      Capture vertices.  Note that Z and M are optional, but X and    */
00857 /*      Y are not.                                                      */
00858 /* -------------------------------------------------------------------- */
00859     if( nVertices > 0 )
00860     {
00861         psObject->padfX = (double *) calloc(sizeof(double),nVertices);
00862         psObject->padfY = (double *) calloc(sizeof(double),nVertices);
00863         psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
00864         psObject->padfM = (double *) calloc(sizeof(double),nVertices);
00865 
00866         assert( padfX != NULL );
00867         assert( padfY != NULL );
00868     
00869         for( i = 0; i < nVertices; i++ )
00870         {
00871             psObject->padfX[i] = padfX[i];
00872             psObject->padfY[i] = padfY[i];
00873             if( padfZ != NULL && bHasZ )
00874                 psObject->padfZ[i] = padfZ[i];
00875             if( padfM != NULL && bHasM )
00876                 psObject->padfM[i] = padfM[i];
00877         }
00878     }
00879 
00880 /* -------------------------------------------------------------------- */
00881 /*      Compute the extents.                                            */
00882 /* -------------------------------------------------------------------- */
00883     psObject->nVertices = nVertices;
00884     SHPComputeExtents( psObject );
00885 
00886     return( psObject );
00887 }
00888 
00889 /************************************************************************/
00890 /*                       SHPCreateSimpleObject()                        */
00891 /*                                                                      */
00892 /*      Create a simple (common) shape object.  Destroy with            */
00893 /*      SHPDestroyObject().                                             */
00894 /************************************************************************/
00895 
00896 SHPObject SHPAPI_CALL1(*)
00897 SHPCreateSimpleObject( int nSHPType, int nVertices,
00898                        double * padfX, double * padfY,
00899                        double * padfZ )
00900 
00901 {
00902     return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
00903                              nVertices, padfX, padfY, padfZ, NULL ) );
00904 }
00905                                   
00906 /************************************************************************/
00907 /*                           SHPWriteObject()                           */
00908 /*                                                                      */
00909 /*      Write out the vertices of a new structure.  Note that it is     */
00910 /*      only possible to write vertices at the end of the file.         */
00911 /************************************************************************/
00912 
00913 int SHPAPI_CALL
00914 SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
00915                       
00916 {
00917     int         nRecordOffset, i, nRecordSize;
00918     uchar       *pabyRec;
00919     int32       i32;
00920 
00921     psSHP->bUpdated = TRUE;
00922 
00923 /* -------------------------------------------------------------------- */
00924 /*      Ensure that shape object matches the type of the file it is     */
00925 /*      being written to.                                               */
00926 /* -------------------------------------------------------------------- */
00927     assert( psObject->nSHPType == psSHP->nShapeType 
00928             || psObject->nSHPType == SHPT_NULL );
00929 
00930 /* -------------------------------------------------------------------- */
00931 /*      Ensure that -1 is used for appends.  Either blow an             */
00932 /*      assertion, or if they are disabled, set the shapeid to -1       */
00933 /*      for appends.                                                    */
00934 /* -------------------------------------------------------------------- */
00935     assert( nShapeId == -1 
00936             || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
00937 
00938     if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
00939         nShapeId = -1;
00940 
00941 /* -------------------------------------------------------------------- */
00942 /*      Add the new entity to the in memory index.                      */
00943 /* -------------------------------------------------------------------- */
00944     if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
00945     {
00946         psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
00947 
00948         psSHP->panRecOffset = (int *) 
00949             SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
00950         psSHP->panRecSize = (int *) 
00951             SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
00952     }
00953 
00954 /* -------------------------------------------------------------------- */
00955 /*      Initialize record.                                              */
00956 /* -------------------------------------------------------------------- */
00957     pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) 
00958                                + psObject->nParts * 8 + 128);
00959     
00960 /* -------------------------------------------------------------------- */
00961 /*  Extract vertices for a Polygon or Arc.                              */
00962 /* -------------------------------------------------------------------- */
00963     if( psObject->nSHPType == SHPT_POLYGON
00964         || psObject->nSHPType == SHPT_POLYGONZ
00965         || psObject->nSHPType == SHPT_POLYGONM
00966         || psObject->nSHPType == SHPT_ARC 
00967         || psObject->nSHPType == SHPT_ARCZ
00968         || psObject->nSHPType == SHPT_ARCM
00969         || psObject->nSHPType == SHPT_MULTIPATCH )
00970     {
00971         int32           nPoints, nParts;
00972         int             i;
00973 
00974         nPoints = psObject->nVertices;
00975         nParts = psObject->nParts;
00976 
00977         _SHPSetBounds( pabyRec + 12, psObject );
00978 
00979         if( bBigEndian ) SwapWord( 4, &nPoints );
00980         if( bBigEndian ) SwapWord( 4, &nParts );
00981 
00982         ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
00983         ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
00984 
00985         nRecordSize = 52;
00986 
00987         /*
00988          * Write part start positions.
00989          */
00990         ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
00991                   4 * psObject->nParts );
00992         for( i = 0; i < psObject->nParts; i++ )
00993         {
00994             if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
00995             nRecordSize += 4;
00996         }
00997 
00998         /*
00999          * Write multipatch part types if needed.
01000          */
01001         if( psObject->nSHPType == SHPT_MULTIPATCH )
01002         {
01003             memcpy( pabyRec + nRecordSize, psObject->panPartType,
01004                     4*psObject->nParts );
01005             for( i = 0; i < psObject->nParts; i++ )
01006             {
01007                 if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
01008                 nRecordSize += 4;
01009             }
01010         }
01011 
01012         /*
01013          * Write the (x,y) vertex values.
01014          */
01015         for( i = 0; i < psObject->nVertices; i++ )
01016         {
01017             ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
01018             ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
01019 
01020             if( bBigEndian )
01021                 SwapWord( 8, pabyRec + nRecordSize );
01022             
01023             if( bBigEndian )
01024                 SwapWord( 8, pabyRec + nRecordSize + 8 );
01025 
01026             nRecordSize += 2 * 8;
01027         }
01028 
01029         /*
01030          * Write the Z coordinates (if any).
01031          */
01032         if( psObject->nSHPType == SHPT_POLYGONZ
01033             || psObject->nSHPType == SHPT_ARCZ
01034             || psObject->nSHPType == SHPT_MULTIPATCH )
01035         {
01036             ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
01037             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01038             nRecordSize += 8;
01039             
01040             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
01041             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01042             nRecordSize += 8;
01043 
01044             for( i = 0; i < psObject->nVertices; i++ )
01045             {
01046                 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
01047                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01048                 nRecordSize += 8;
01049             }
01050         }
01051 
01052         /*
01053          * Write the M values, if any.
01054          */
01055         if( psObject->nSHPType == SHPT_POLYGONM
01056             || psObject->nSHPType == SHPT_ARCM
01057 #ifndef DISABLE_MULTIPATCH_MEASURE            
01058             || psObject->nSHPType == SHPT_MULTIPATCH
01059 #endif            
01060             || psObject->nSHPType == SHPT_POLYGONZ
01061             || psObject->nSHPType == SHPT_ARCZ )
01062         {
01063             ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
01064             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01065             nRecordSize += 8;
01066             
01067             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
01068             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01069             nRecordSize += 8;
01070 
01071             for( i = 0; i < psObject->nVertices; i++ )
01072             {
01073                 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
01074                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01075                 nRecordSize += 8;
01076             }
01077         }
01078     }
01079 
01080 /* -------------------------------------------------------------------- */
01081 /*  Extract vertices for a MultiPoint.                                  */
01082 /* -------------------------------------------------------------------- */
01083     else if( psObject->nSHPType == SHPT_MULTIPOINT
01084              || psObject->nSHPType == SHPT_MULTIPOINTZ
01085              || psObject->nSHPType == SHPT_MULTIPOINTM )
01086     {
01087         int32           nPoints;
01088         int             i;
01089 
01090         nPoints = psObject->nVertices;
01091 
01092         _SHPSetBounds( pabyRec + 12, psObject );
01093 
01094         if( bBigEndian ) SwapWord( 4, &nPoints );
01095         ByteCopy( &nPoints, pabyRec + 44, 4 );
01096         
01097         for( i = 0; i < psObject->nVertices; i++ )
01098         {
01099             ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
01100             ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
01101 
01102             if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
01103             if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
01104         }
01105 
01106         nRecordSize = 48 + 16 * psObject->nVertices;
01107 
01108         if( psObject->nSHPType == SHPT_MULTIPOINTZ )
01109         {
01110             ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
01111             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01112             nRecordSize += 8;
01113 
01114             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
01115             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01116             nRecordSize += 8;
01117             
01118             for( i = 0; i < psObject->nVertices; i++ )
01119             {
01120                 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
01121                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01122                 nRecordSize += 8;
01123             }
01124         }
01125 
01126         if( psObject->nSHPType == SHPT_MULTIPOINTZ
01127             || psObject->nSHPType == SHPT_MULTIPOINTM )
01128         {
01129             ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
01130             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01131             nRecordSize += 8;
01132 
01133             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
01134             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01135             nRecordSize += 8;
01136             
01137             for( i = 0; i < psObject->nVertices; i++ )
01138             {
01139                 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
01140                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01141                 nRecordSize += 8;
01142             }
01143         }
01144     }
01145 
01146 /* -------------------------------------------------------------------- */
01147 /*      Write point.                                                    */
01148 /* -------------------------------------------------------------------- */
01149     else if( psObject->nSHPType == SHPT_POINT
01150              || psObject->nSHPType == SHPT_POINTZ
01151              || psObject->nSHPType == SHPT_POINTM )
01152     {
01153         ByteCopy( psObject->padfX, pabyRec + 12, 8 );
01154         ByteCopy( psObject->padfY, pabyRec + 20, 8 );
01155 
01156         if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
01157         if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
01158 
01159         nRecordSize = 28;
01160         
01161         if( psObject->nSHPType == SHPT_POINTZ )
01162         {
01163             ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
01164             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01165             nRecordSize += 8;
01166         }
01167         
01168         if( psObject->nSHPType == SHPT_POINTZ
01169             || psObject->nSHPType == SHPT_POINTM )
01170         {
01171             ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
01172             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01173             nRecordSize += 8;
01174         }
01175     }
01176 
01177 /* -------------------------------------------------------------------- */
01178 /*      Not much to do for null geometries.                             */
01179 /* -------------------------------------------------------------------- */
01180     else if( psObject->nSHPType == SHPT_NULL )
01181     {
01182         nRecordSize = 12;
01183     }
01184 
01185     else
01186     {
01187         /* unknown type */
01188         assert( FALSE );
01189     }
01190 
01191 /* -------------------------------------------------------------------- */
01192 /*      Establish where we are going to put this record. If we are      */
01193 /*      rewriting and existing record, and it will fit, then put it     */
01194 /*      back where the original came from.  Otherwise write at the end. */
01195 /* -------------------------------------------------------------------- */
01196     if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
01197     {
01198         if( nShapeId == -1 )
01199             nShapeId = psSHP->nRecords++;
01200 
01201         psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
01202         psSHP->panRecSize[nShapeId] = nRecordSize-8;
01203         psSHP->nFileSize += nRecordSize;
01204     }
01205     else
01206     {
01207         nRecordOffset = psSHP->panRecOffset[nShapeId];
01208     }
01209     
01210 /* -------------------------------------------------------------------- */
01211 /*      Set the shape type, record number, and record size.             */
01212 /* -------------------------------------------------------------------- */
01213     i32 = nShapeId+1;                                   /* record # */
01214     if( !bBigEndian ) SwapWord( 4, &i32 );
01215     ByteCopy( &i32, pabyRec, 4 );
01216 
01217     i32 = (nRecordSize-8)/2;                            /* record size */
01218     if( !bBigEndian ) SwapWord( 4, &i32 );
01219     ByteCopy( &i32, pabyRec + 4, 4 );
01220 
01221     i32 = psObject->nSHPType;                           /* shape type */
01222     if( bBigEndian ) SwapWord( 4, &i32 );
01223     ByteCopy( &i32, pabyRec + 8, 4 );
01224 
01225 /* -------------------------------------------------------------------- */
01226 /*      Write out record.                                               */
01227 /* -------------------------------------------------------------------- */
01228     if( fseek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
01229         || fwrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
01230     {
01231         printf( "Error in fseek() or fwrite().\n" );
01232         free( pabyRec );
01233         return -1;
01234     }
01235     
01236     free( pabyRec );
01237 
01238 /* -------------------------------------------------------------------- */
01239 /*      Expand file wide bounds based on this shape.                    */
01240 /* -------------------------------------------------------------------- */
01241     if( psSHP->adBoundsMin[0] == 0.0
01242         && psSHP->adBoundsMax[0] == 0.0
01243         && psSHP->adBoundsMin[1] == 0.0
01244         && psSHP->adBoundsMax[1] == 0.0 
01245         && psObject->nSHPType != SHPT_NULL )
01246     {
01247         psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
01248         psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
01249         psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
01250         psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
01251     }
01252 
01253     for( i = 0; i < psObject->nVertices; i++ )
01254     {
01255         psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
01256         psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
01257         psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
01258         psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
01259         psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
01260         psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
01261         psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
01262         psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
01263     }
01264 
01265     return( nShapeId  );
01266 }
01267 
01268 /************************************************************************/
01269 /*                          SHPReadObject()                             */
01270 /*                                                                      */
01271 /*      Read the vertices, parts, and other non-attribute information   */
01272 /*      for one shape.                                                  */
01273 /************************************************************************/
01274 
01275 SHPObject SHPAPI_CALL1(*)
01276 SHPReadObject( SHPHandle psSHP, int hEntity )
01277 
01278 {
01279     SHPObject           *psShape;
01280 
01281 /* -------------------------------------------------------------------- */
01282 /*      Validate the record/entity number.                              */
01283 /* -------------------------------------------------------------------- */
01284     if( hEntity < 0 || hEntity >= psSHP->nRecords )
01285         return( NULL );
01286 
01287 /* -------------------------------------------------------------------- */
01288 /*      Ensure our record buffer is large enough.                       */
01289 /* -------------------------------------------------------------------- */
01290     if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize )
01291     {
01292         psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
01293         psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
01294     }
01295 
01296 /* -------------------------------------------------------------------- */
01297 /*      Read the record.                                                */
01298 /* -------------------------------------------------------------------- */
01299     fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 );
01300     fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
01301 
01302 /* -------------------------------------------------------------------- */
01303 /*      Allocate and minimally initialize the object.                   */
01304 /* -------------------------------------------------------------------- */
01305     psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
01306     psShape->nShapeId = hEntity;
01307 
01308     memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
01309     if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
01310 
01311 /* ==================================================================== */
01312 /*  Extract vertices for a Polygon or Arc.                              */
01313 /* ==================================================================== */
01314     if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
01315         || psShape->nSHPType == SHPT_POLYGONZ
01316         || psShape->nSHPType == SHPT_POLYGONM
01317         || psShape->nSHPType == SHPT_ARCZ
01318         || psShape->nSHPType == SHPT_ARCM
01319         || psShape->nSHPType == SHPT_MULTIPATCH )
01320     {
01321         int32           nPoints, nParts;
01322         int             i, nOffset;
01323 
01324 /* -------------------------------------------------------------------- */
01325 /*      Get the X/Y bounds.                                             */
01326 /* -------------------------------------------------------------------- */
01327         memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 +  4, 8 );
01328         memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
01329         memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
01330         memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
01331 
01332         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
01333         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
01334         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
01335         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
01336 
01337 /* -------------------------------------------------------------------- */
01338 /*      Extract part/point count, and build vertex and part arrays      */
01339 /*      to proper size.                                                 */
01340 /* -------------------------------------------------------------------- */
01341         memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
01342         memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
01343 
01344         if( bBigEndian ) SwapWord( 4, &nPoints );
01345         if( bBigEndian ) SwapWord( 4, &nParts );
01346 
01347         psShape->nVertices = nPoints;
01348         psShape->padfX = (double *) calloc(nPoints,sizeof(double));
01349         psShape->padfY = (double *) calloc(nPoints,sizeof(double));
01350         psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
01351         psShape->padfM = (double *) calloc(nPoints,sizeof(double));
01352 
01353         psShape->nParts = nParts;
01354         psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
01355         psShape->panPartType = (int *) calloc(nParts,sizeof(int));
01356 
01357         for( i = 0; i < nParts; i++ )
01358             psShape->panPartType[i] = SHPP_RING;
01359 
01360 /* -------------------------------------------------------------------- */
01361 /*      Copy out the part array from the record.                        */
01362 /* -------------------------------------------------------------------- */
01363         memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
01364         for( i = 0; i < nParts; i++ )
01365         {
01366             if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
01367         }
01368 
01369         nOffset = 44 + 8 + 4*nParts;
01370 
01371 /* -------------------------------------------------------------------- */
01372 /*      If this is a multipatch, we will also have parts types.         */
01373 /* -------------------------------------------------------------------- */
01374         if( psShape->nSHPType == SHPT_MULTIPATCH )
01375         {
01376             memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
01377             for( i = 0; i < nParts; i++ )
01378             {
01379                 if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
01380             }
01381 
01382             nOffset += 4*nParts;
01383         }
01384         
01385 /* -------------------------------------------------------------------- */
01386 /*      Copy out the vertices from the record.                          */
01387 /* -------------------------------------------------------------------- */
01388         for( i = 0; i < nPoints; i++ )
01389         {
01390             memcpy(psShape->padfX + i,
01391                    psSHP->pabyRec + nOffset + i * 16,
01392                    8 );
01393 
01394             memcpy(psShape->padfY + i,
01395                    psSHP->pabyRec + nOffset + i * 16 + 8,
01396                    8 );
01397 
01398             if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
01399             if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
01400         }
01401 
01402         nOffset += 16*nPoints;
01403         
01404 /* -------------------------------------------------------------------- */
01405 /*      If we have a Z coordinate, collect that now.                    */
01406 /* -------------------------------------------------------------------- */
01407         if( psShape->nSHPType == SHPT_POLYGONZ
01408             || psShape->nSHPType == SHPT_ARCZ
01409             || psShape->nSHPType == SHPT_MULTIPATCH )
01410         {
01411             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
01412             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
01413             
01414             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
01415             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
01416             
01417             for( i = 0; i < nPoints; i++ )
01418             {
01419                 memcpy( psShape->padfZ + i,
01420                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01421                 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
01422             }
01423 
01424             nOffset += 16 + 8*nPoints;
01425         }
01426 
01427 /* -------------------------------------------------------------------- */
01428 /*      If we have a M measure value, then read it now.  We assume      */
01429 /*      that the measure can be present for any shape if the size is    */
01430 /*      big enough, but really it will only occur for the Z shapes      */
01431 /*      (options), and the M shapes.                                    */
01432 /* -------------------------------------------------------------------- */
01433         if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
01434         {
01435             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
01436             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
01437             
01438             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
01439             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
01440             
01441             for( i = 0; i < nPoints; i++ )
01442             {
01443                 memcpy( psShape->padfM + i,
01444                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01445                 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
01446             }
01447         }
01448         
01449     }
01450 
01451 /* ==================================================================== */
01452 /*  Extract vertices for a MultiPoint.                                  */
01453 /* ==================================================================== */
01454     else if( psShape->nSHPType == SHPT_MULTIPOINT
01455              || psShape->nSHPType == SHPT_MULTIPOINTM
01456              || psShape->nSHPType == SHPT_MULTIPOINTZ )
01457     {
01458         int32           nPoints;
01459         int             i, nOffset;
01460 
01461         memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
01462         if( bBigEndian ) SwapWord( 4, &nPoints );
01463 
01464         psShape->nVertices = nPoints;
01465         psShape->padfX = (double *) calloc(nPoints,sizeof(double));
01466         psShape->padfY = (double *) calloc(nPoints,sizeof(double));
01467         psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
01468         psShape->padfM = (double *) calloc(nPoints,sizeof(double));
01469 
01470         for( i = 0; i < nPoints; i++ )
01471         {
01472             memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
01473             memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
01474 
01475             if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
01476             if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
01477         }
01478 
01479         nOffset = 48 + 16*nPoints;
01480         
01481 /* -------------------------------------------------------------------- */
01482 /*      Get the X/Y bounds.                                             */
01483 /* -------------------------------------------------------------------- */
01484         memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 +  4, 8 );
01485         memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
01486         memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
01487         memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
01488 
01489         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
01490         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
01491         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
01492         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
01493 
01494 /* -------------------------------------------------------------------- */
01495 /*      If we have a Z coordinate, collect that now.                    */
01496 /* -------------------------------------------------------------------- */
01497         if( psShape->nSHPType == SHPT_MULTIPOINTZ )
01498         {
01499             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
01500             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
01501             
01502             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
01503             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
01504             
01505             for( i = 0; i < nPoints; i++ )
01506             {
01507                 memcpy( psShape->padfZ + i,
01508                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01509                 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
01510             }
01511 
01512             nOffset += 16 + 8*nPoints;
01513         }
01514 
01515 /* -------------------------------------------------------------------- */
01516 /*      If we have a M measure value, then read it now.  We assume      */
01517 /*      that the measure can be present for any shape if the size is    */
01518 /*      big enough, but really it will only occur for the Z shapes      */
01519 /*      (options), and the M shapes.                                    */
01520 /* -------------------------------------------------------------------- */
01521         if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
01522         {
01523             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
01524             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
01525             
01526             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
01527             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
01528             
01529             for( i = 0; i < nPoints; i++ )
01530             {
01531                 memcpy( psShape->padfM + i,
01532                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01533                 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
01534             }
01535         }
01536     }
01537 
01538 /* ==================================================================== */
01539 /*      Extract vertices for a point.                                   */
01540 /* ==================================================================== */
01541     else if( psShape->nSHPType == SHPT_POINT
01542              || psShape->nSHPType == SHPT_POINTM
01543              || psShape->nSHPType == SHPT_POINTZ )
01544     {
01545         int     nOffset;
01546         
01547         psShape->nVertices = 1;
01548         psShape->padfX = (double *) calloc(1,sizeof(double));
01549         psShape->padfY = (double *) calloc(1,sizeof(double));
01550         psShape->padfZ = (double *) calloc(1,sizeof(double));
01551         psShape->padfM = (double *) calloc(1,sizeof(double));
01552 
01553         memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
01554         memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
01555 
01556         if( bBigEndian ) SwapWord( 8, psShape->padfX );
01557         if( bBigEndian ) SwapWord( 8, psShape->padfY );
01558 
01559         nOffset = 20 + 8;
01560         
01561 /* -------------------------------------------------------------------- */
01562 /*      If we have a Z coordinate, collect that now.                    */
01563 /* -------------------------------------------------------------------- */
01564         if( psShape->nSHPType == SHPT_POINTZ )
01565         {
01566             memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
01567         
01568             if( bBigEndian ) SwapWord( 8, psShape->padfZ );
01569             
01570             nOffset += 8;
01571         }
01572 
01573 /* -------------------------------------------------------------------- */
01574 /*      If we have a M measure value, then read it now.  We assume      */
01575 /*      that the measure can be present for any shape if the size is    */
01576 /*      big enough, but really it will only occur for the Z shapes      */
01577 /*      (options), and the M shapes.                                    */
01578 /* -------------------------------------------------------------------- */
01579         if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 )
01580         {
01581             memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
01582         
01583             if( bBigEndian ) SwapWord( 8, psShape->padfM );
01584         }
01585 
01586 /* -------------------------------------------------------------------- */
01587 /*      Since no extents are supplied in the record, we will apply      */
01588 /*      them from the single vertex.                                    */
01589 /* -------------------------------------------------------------------- */
01590         psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
01591         psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
01592         psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
01593         psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
01594     }
01595 
01596     return( psShape );
01597 }
01598 
01599 /************************************************************************/
01600 /*                            SHPTypeName()                             */
01601 /************************************************************************/
01602 
01603 const char SHPAPI_CALL1(*)
01604 SHPTypeName( int nSHPType )
01605 
01606 {
01607     switch( nSHPType )
01608     {
01609       case SHPT_NULL:
01610         return "NullShape";
01611 
01612       case SHPT_POINT:
01613         return "Point";
01614 
01615       case SHPT_ARC:
01616         return "Arc";
01617 
01618       case SHPT_POLYGON:
01619         return "Polygon";
01620 
01621       case SHPT_MULTIPOINT:
01622         return "MultiPoint";
01623         
01624       case SHPT_POINTZ:
01625         return "PointZ";
01626 
01627       case SHPT_ARCZ:
01628         return "ArcZ";
01629 
01630       case SHPT_POLYGONZ:
01631         return "PolygonZ";
01632 
01633       case SHPT_MULTIPOINTZ:
01634         return "MultiPointZ";
01635         
01636       case SHPT_POINTM:
01637         return "PointM";
01638 
01639       case SHPT_ARCM:
01640         return "ArcM";
01641 
01642       case SHPT_POLYGONM:
01643         return "PolygonM";
01644 
01645       case SHPT_MULTIPOINTM:
01646         return "MultiPointM";
01647 
01648       case SHPT_MULTIPATCH:
01649         return "MultiPatch";
01650 
01651       default:
01652         return "UnknownShapeType";
01653     }
01654 }
01655 
01656 /************************************************************************/
01657 /*                          SHPPartTypeName()                           */
01658 /************************************************************************/
01659 
01660 const char SHPAPI_CALL1(*)
01661 SHPPartTypeName( int nPartType )
01662 
01663 {
01664     switch( nPartType )
01665     {
01666       case SHPP_TRISTRIP:
01667         return "TriangleStrip";
01668         
01669       case SHPP_TRIFAN:
01670         return "TriangleFan";
01671 
01672       case SHPP_OUTERRING:
01673         return "OuterRing";
01674 
01675       case SHPP_INNERRING:
01676         return "InnerRing";
01677 
01678       case SHPP_FIRSTRING:
01679         return "FirstRing";
01680 
01681       case SHPP_RING:
01682         return "Ring";
01683 
01684       default:
01685         return "UnknownPartType";
01686     }
01687 }
01688 
01689 /************************************************************************/
01690 /*                          SHPDestroyObject()                          */
01691 /************************************************************************/
01692 
01693 void SHPAPI_CALL
01694 SHPDestroyObject( SHPObject * psShape )
01695 
01696 {
01697     if( psShape == NULL )
01698         return;
01699     
01700     if( psShape->padfX != NULL )
01701         free( psShape->padfX );
01702     if( psShape->padfY != NULL )
01703         free( psShape->padfY );
01704     if( psShape->padfZ != NULL )
01705         free( psShape->padfZ );
01706     if( psShape->padfM != NULL )
01707         free( psShape->padfM );
01708 
01709     if( psShape->panPartStart != NULL )
01710         free( psShape->panPartStart );
01711     if( psShape->panPartType != NULL )
01712         free( psShape->panPartType );
01713 
01714     free( psShape );
01715 }
01716 
01717 /************************************************************************/
01718 /*                          SHPRewindObject()                           */
01719 /*                                                                      */
01720 /*      Reset the winding of polygon objects to adhere to the           */
01721 /*      specification.                                                  */
01722 /************************************************************************/
01723 
01724 int SHPAPI_CALL
01725 SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
01726 
01727 {
01728     int  iOpRing, bAltered = 0;
01729 
01730 /* -------------------------------------------------------------------- */
01731 /*      Do nothing if this is not a polygon object.                     */
01732 /* -------------------------------------------------------------------- */
01733     if( psObject->nSHPType != SHPT_POLYGON
01734         && psObject->nSHPType != SHPT_POLYGONZ
01735         && psObject->nSHPType != SHPT_POLYGONM )
01736         return 0;
01737 
01738 /* -------------------------------------------------------------------- */
01739 /*      Process each of the rings.                                      */
01740 /* -------------------------------------------------------------------- */
01741     for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
01742     {
01743         int      bInner, iVert, nVertCount, nVertStart, iCheckRing;
01744         double   dfSum, dfTestX, dfTestY;
01745 
01746 /* -------------------------------------------------------------------- */
01747 /*      Determine if this ring is an inner ring or an outer ring        */
01748 /*      relative to all the other rings.  For now we assume the         */
01749 /*      first ring is outer and all others are inner, but eventually    */
01750 /*      we need to fix this to handle multiple island polygons and      */
01751 /*      unordered sets of rings.                                        */
01752 /* -------------------------------------------------------------------- */
01753         dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]];
01754         dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]];
01755 
01756         bInner = FALSE;
01757         for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
01758         {
01759             int iEdge;
01760 
01761             if( iCheckRing == iOpRing )
01762                 continue;
01763             
01764             nVertStart = psObject->panPartStart[iCheckRing];
01765 
01766             if( iCheckRing == psObject->nParts-1 )
01767                 nVertCount = psObject->nVertices 
01768                     - psObject->panPartStart[iCheckRing];
01769             else
01770                 nVertCount = psObject->panPartStart[iCheckRing+1] 
01771                     - psObject->panPartStart[iCheckRing];
01772 
01773             for( iEdge = 0; iEdge < nVertCount; iEdge++ )
01774             {
01775                 int iNext;
01776 
01777                 if( iEdge < nVertCount-1 )
01778                     iNext = iEdge+1;
01779                 else
01780                     iNext = 0;
01781 
01782                 if( (psObject->padfY[iEdge+nVertStart] < dfTestY 
01783                      && psObject->padfY[iNext+nVertStart] >= dfTestY)
01784                     || (psObject->padfY[iNext+nVertStart] < dfTestY 
01785                         && psObject->padfY[iEdge+nVertStart] >= dfTestY) )
01786                 {
01787                     if( psObject->padfX[iEdge+nVertStart] 
01788                         + (dfTestY - psObject->padfY[iEdge+nVertStart])
01789                            / (psObject->padfY[iNext+nVertStart]
01790                               - psObject->padfY[iEdge+nVertStart])
01791                            * (psObject->padfX[iNext+nVertStart]
01792                               - psObject->padfX[iEdge+nVertStart]) < dfTestX )
01793                         bInner = !bInner;
01794                 }
01795             }
01796         }
01797 
01798 /* -------------------------------------------------------------------- */
01799 /*      Determine the current order of this ring so we will know if     */
01800 /*      it has to be reversed.                                          */
01801 /* -------------------------------------------------------------------- */
01802         nVertStart = psObject->panPartStart[iOpRing];
01803 
01804         if( iOpRing == psObject->nParts-1 )
01805             nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
01806         else
01807             nVertCount = psObject->panPartStart[iOpRing+1] 
01808                 - psObject->panPartStart[iOpRing];
01809 
01810         dfSum = 0.0;
01811         for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
01812         {
01813             dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
01814                 - psObject->padfY[iVert] * psObject->padfX[iVert+1];
01815         }
01816 
01817         dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
01818                - psObject->padfY[iVert] * psObject->padfX[nVertStart];
01819 
01820 /* -------------------------------------------------------------------- */
01821 /*      Reverse if necessary.                                           */
01822 /* -------------------------------------------------------------------- */
01823         if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
01824         {
01825             int   i;
01826 
01827             bAltered++;
01828             for( i = 0; i < nVertCount/2; i++ )
01829             {
01830                 double dfSaved;
01831 
01832                 /* Swap X */
01833                 dfSaved = psObject->padfX[nVertStart+i];
01834                 psObject->padfX[nVertStart+i] = 
01835                     psObject->padfX[nVertStart+nVertCount-i-1];
01836                 psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
01837 
01838                 /* Swap Y */
01839                 dfSaved = psObject->padfY[nVertStart+i];
01840                 psObject->padfY[nVertStart+i] = 
01841                     psObject->padfY[nVertStart+nVertCount-i-1];
01842                 psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
01843 
01844                 /* Swap Z */
01845                 if( psObject->padfZ )
01846                 {
01847                     dfSaved = psObject->padfZ[nVertStart+i];
01848                     psObject->padfZ[nVertStart+i] = 
01849                         psObject->padfZ[nVertStart+nVertCount-i-1];
01850                     psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
01851                 }
01852 
01853                 /* Swap M */
01854                 if( psObject->padfM )
01855                 {
01856                     dfSaved = psObject->padfM[nVertStart+i];
01857                     psObject->padfM[nVertStart+i] = 
01858                         psObject->padfM[nVertStart+nVertCount-i-1];
01859                     psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
01860                 }
01861             }
01862         }
01863     }
01864 
01865     return bAltered;
01866 }

Generated on Sun Aug 5 17:34:00 2007 for PIHMgis by  doxygen 1.5.2