~ubuntu-branches/ubuntu/quantal/qgis/quantal

« back to all changes in this revision

Viewing changes to src/plugins/grid_maker/shpopen.c

  • Committer: Bazaar Package Importer
  • Author(s): William Grant
  • Date: 2007-05-06 13:42:32 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070506134232-pyli6t388w5asd8x
Tags: 0.8.0-3ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - debian/rules, debian/qgis.install, debian/qgis.dirs debian/qgis.desktop:
    Add and install .desktop.
* debian/qgis.desktop: Remove Applications category; it's not real.
* Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

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