1
/******************************************************************************
2
* $Id: shpopen.c 1155 2004-04-05 15:39:45Z timlinux $
5
* Purpose: Implementation of core Shapefile read/write functions.
6
* Author: Frank Warmerdam, warmerda@home.com
8
******************************************************************************
9
* Copyright (c) 1999, Frank Warmerdam
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.
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:
24
* The above copyright notice and this permission notice shall be included
25
* in all copies or substantial portions of the Software.
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
******************************************************************************
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.
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
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.
46
* Revision 1.26 2000/02/16 16:03:51 warmerda
47
* added null shape support
49
* Revision 1.25 1999/12/15 13:47:07 warmerda
50
* Fixed record size settings in .shp file (was 4 words too long)
53
* Revision 1.24 1999/11/05 14:12:04 warmerda
54
* updated license terms
56
* Revision 1.23 1999/07/27 00:53:46 warmerda
57
* added support for rewriting shapes
59
* Revision 1.22 1999/06/11 19:19:11 warmerda
60
* Cleanup pabyRec static buffer on SHPClose().
62
* Revision 1.21 1999/06/02 14:57:56 kshih
63
* Remove unused variables
65
* Revision 1.20 1999/04/19 21:04:17 warmerda
68
* Revision 1.19 1999/04/19 21:01:57 warmerda
69
* Force access string to binary in SHPOpen().
71
* Revision 1.18 1999/04/01 18:48:07 warmerda
72
* Try upper case extensions if lower case doesn't work.
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.
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.
82
* Revision 1.15 1998/12/03 16:35:29 warmerda
83
* r+b is proper binary access string, not rb+.
85
* Revision 1.14 1998/12/03 15:47:56 warmerda
86
* Fixed setting of nVertices in SHPCreateObject().
88
* Revision 1.13 1998/12/03 15:33:54 warmerda
89
* Made SHPCalculateExtents() separately callable.
91
* Revision 1.12 1998/11/11 20:01:50 warmerda
92
* Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
94
* Revision 1.11 1998/11/09 20:56:44 warmerda
95
* Fixed up handling of file wide bounds.
97
* Revision 1.10 1998/11/09 20:18:51 warmerda
98
* Converted to support 3D shapefiles, and use of SHPObject.
100
* Revision 1.9 1998/02/24 15:09:05 warmerda
103
* Revision 1.8 1997/12/04 15:40:29 warmerda
104
* Fixed byte swapping of record number, and record length fields in the
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.
111
* Revision 1.6 1995/09/04 04:19:41 warmerda
112
* Added fix for file bounds.
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.
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).
122
* Revision 1.3 1995/08/23 02:23:15 warmerda
123
* Added support for reading bounds, and fixed up problems in setting the
126
* Revision 1.2 1995/08/04 03:16:57 warmerda
131
static char rcsid[] =
132
"$Id: shpopen.c 1155 2004-04-05 15:39:45Z timlinux $";
134
#include "shapefile.h"
141
typedef unsigned char uchar;
143
#if UINT_MAX == 65535
154
#define ByteCopy( a, b, c ) memcpy( b, a, c )
156
# define MIN(a,b) ((a<b) ? a : b)
157
# define MAX(a,b) ((a>b) ? a : b)
160
static int bBigEndian;
161
static uchar *pabyRec = NULL;
162
static int nBufSize = 0;
165
/************************************************************************/
168
/* Swap a 2, 4 or 8 byte word. */
169
/************************************************************************/
171
static void SwapWord( int length, void * wordP )
177
for( i=0; i < length/2; i++ )
179
temp = ((uchar *) wordP)[i];
180
((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
181
((uchar *) wordP)[length-i-1] = temp;
185
/************************************************************************/
188
/* A realloc cover function that will access a NULL pointer as */
190
/************************************************************************/
192
static void * SfRealloc( void * pMem, int nNewSize )
196
return( (void *) malloc(nNewSize) );
198
return( (void *) realloc(pMem,nNewSize) );
201
/************************************************************************/
202
/* SHPWriteHeader() */
204
/* Write out a header for the .shp and .shx files as well as the */
205
/* contents of the index (.shx) file. */
206
/************************************************************************/
208
static void SHPWriteHeader( SHPHandle psSHP )
211
uchar abyHeader[100];
217
/* -------------------------------------------------------------------- */
218
/* Prepare header block for .shp file. */
219
/* -------------------------------------------------------------------- */
220
for( i = 0; i < 100; i++ )
223
abyHeader[2] = 0x27; /* magic cookie */
226
i32 = psSHP->nFileSize/2; /* file size */
227
ByteCopy( &i32, abyHeader+24, 4 );
228
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
230
i32 = 1000; /* version */
231
ByteCopy( &i32, abyHeader+28, 4 );
232
if( bBigEndian ) SwapWord( 4, abyHeader+28 );
234
i32 = psSHP->nShapeType; /* shape type */
235
ByteCopy( &i32, abyHeader+32, 4 );
236
if( bBigEndian ) SwapWord( 4, abyHeader+32 );
238
dValue = psSHP->adBoundsMin[0]; /* set bounds */
239
ByteCopy( &dValue, abyHeader+36, 8 );
240
if( bBigEndian ) SwapWord( 8, abyHeader+36 );
242
dValue = psSHP->adBoundsMin[1];
243
ByteCopy( &dValue, abyHeader+44, 8 );
244
if( bBigEndian ) SwapWord( 8, abyHeader+44 );
246
dValue = psSHP->adBoundsMax[0];
247
ByteCopy( &dValue, abyHeader+52, 8 );
248
if( bBigEndian ) SwapWord( 8, abyHeader+52 );
250
dValue = psSHP->adBoundsMax[1];
251
ByteCopy( &dValue, abyHeader+60, 8 );
252
if( bBigEndian ) SwapWord( 8, abyHeader+60 );
254
dValue = psSHP->adBoundsMin[2]; /* z */
255
ByteCopy( &dValue, abyHeader+68, 8 );
256
if( bBigEndian ) SwapWord( 8, abyHeader+68 );
258
dValue = psSHP->adBoundsMax[2];
259
ByteCopy( &dValue, abyHeader+76, 8 );
260
if( bBigEndian ) SwapWord( 8, abyHeader+76 );
262
dValue = psSHP->adBoundsMin[3]; /* m */
263
ByteCopy( &dValue, abyHeader+84, 8 );
264
if( bBigEndian ) SwapWord( 8, abyHeader+84 );
266
dValue = psSHP->adBoundsMax[3];
267
ByteCopy( &dValue, abyHeader+92, 8 );
268
if( bBigEndian ) SwapWord( 8, abyHeader+92 );
270
/* -------------------------------------------------------------------- */
271
/* Write .shp file header. */
272
/* -------------------------------------------------------------------- */
273
fseek( psSHP->fpSHP, 0, 0 );
274
fwrite( abyHeader, 100, 1, psSHP->fpSHP );
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 );
283
fseek( psSHP->fpSHX, 0, 0 );
284
fwrite( abyHeader, 100, 1, psSHP->fpSHX );
286
/* -------------------------------------------------------------------- */
287
/* Write out the .shx contents. */
288
/* -------------------------------------------------------------------- */
289
panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
291
for( i = 0; i < psSHP->nRecords; i++ )
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 );
299
fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX );
304
/************************************************************************/
307
/* Open the .shp and .shx files based on the basename of the */
308
/* files or either file name. */
309
/************************************************************************/
311
SHPHandle SHPOpen( const char * pszLayer, const char * pszAccess )
314
char *pszFullname, *pszBasename;
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 )
332
/* -------------------------------------------------------------------- */
333
/* Establish the byte order on this machine. */
334
/* -------------------------------------------------------------------- */
336
if( *((uchar *) &i) == 1 )
341
/* -------------------------------------------------------------------- */
342
/* Initialize the info structure. */
343
/* -------------------------------------------------------------------- */
344
psSHP = (SHPHandle) malloc(sizeof(SHPInfo));
346
psSHP->bUpdated = FALSE;
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] != '\\';
359
if( pszBasename[i] == '.' )
360
pszBasename[i] = '\0';
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 )
371
sprintf( pszFullname, "%s.SHP", pszBasename );
372
psSHP->fpSHP = fopen(pszFullname, pszAccess );
375
if( psSHP->fpSHP == NULL )
378
sprintf( pszFullname, "%s.shx", pszBasename );
379
psSHP->fpSHX = fopen(pszFullname, pszAccess );
380
if( psSHP->fpSHX == NULL )
382
sprintf( pszFullname, "%s.SHX", pszBasename );
383
psSHP->fpSHX = fopen(pszFullname, pszAccess );
386
if( psSHP->fpSHX == NULL )
392
/* -------------------------------------------------------------------- */
393
/* Read the file size from the SHP file. */
394
/* -------------------------------------------------------------------- */
395
pabyBuf = (uchar *) malloc(100);
396
fread( pabyBuf, 100, 1, psSHP->fpSHP );
398
psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
399
+ pabyBuf[25] * 256 * 256
403
/* -------------------------------------------------------------------- */
404
/* Read SHX file Header info */
405
/* -------------------------------------------------------------------- */
406
fread( pabyBuf, 100, 1, psSHP->fpSHX );
410
|| pabyBuf[2] != 0x27
411
|| (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
413
fclose( psSHP->fpSHP );
414
fclose( psSHP->fpSHX );
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;
424
psSHP->nShapeType = pabyBuf[32];
426
/* -------------------------------------------------------------------- */
427
/* Read the bounds. */
428
/* -------------------------------------------------------------------- */
429
if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
430
memcpy( &dValue, pabyBuf+36, 8 );
431
psSHP->adBoundsMin[0] = dValue;
433
if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
434
memcpy( &dValue, pabyBuf+44, 8 );
435
psSHP->adBoundsMin[1] = dValue;
437
if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
438
memcpy( &dValue, pabyBuf+52, 8 );
439
psSHP->adBoundsMax[0] = dValue;
441
if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
442
memcpy( &dValue, pabyBuf+60, 8 );
443
psSHP->adBoundsMax[1] = dValue;
445
if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
446
memcpy( &dValue, pabyBuf+68, 8 );
447
psSHP->adBoundsMin[2] = dValue;
449
if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
450
memcpy( &dValue, pabyBuf+76, 8 );
451
psSHP->adBoundsMax[2] = dValue;
453
if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
454
memcpy( &dValue, pabyBuf+84, 8 );
455
psSHP->adBoundsMin[3] = dValue;
457
if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
458
memcpy( &dValue, pabyBuf+92, 8 );
459
psSHP->adBoundsMax[3] = dValue;
463
/* -------------------------------------------------------------------- */
464
/* Read the .shx file to get the offsets to each record in */
466
/* -------------------------------------------------------------------- */
467
psSHP->nMaxRecords = psSHP->nRecords;
469
psSHP->panRecOffset =
470
(int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
472
(int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
474
pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
475
fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX );
477
for( i = 0; i < psSHP->nRecords; i++ )
479
int32 nOffset, nLength;
481
memcpy( &nOffset, pabyBuf + i * 8, 4 );
482
if( !bBigEndian ) SwapWord( 4, &nOffset );
484
memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
485
if( !bBigEndian ) SwapWord( 4, &nLength );
487
psSHP->panRecOffset[i] = nOffset*2;
488
psSHP->panRecSize[i] = nLength*2;
495
/************************************************************************/
498
/* Close the .shp and .shx files. */
499
/************************************************************************/
501
void SHPClose(SHPHandle psSHP )
504
/* -------------------------------------------------------------------- */
505
/* Update the header if we have modified anything. */
506
/* -------------------------------------------------------------------- */
507
if( psSHP->bUpdated )
509
SHPWriteHeader( psSHP );
512
/* -------------------------------------------------------------------- */
513
/* Free all resources, and close files. */
514
/* -------------------------------------------------------------------- */
515
free( psSHP->panRecOffset );
516
free( psSHP->panRecSize );
518
fclose( psSHP->fpSHX );
519
fclose( psSHP->fpSHP );
523
if( pabyRec != NULL )
531
/************************************************************************/
534
/* Fetch general information about the shape file. */
535
/************************************************************************/
537
void SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
538
double * padfMinBound, double * padfMaxBound )
543
if( pnEntities != NULL )
544
*pnEntities = psSHP->nRecords;
546
if( pnShapeType != NULL )
547
*pnShapeType = psSHP->nShapeType;
549
for( i = 0; i < 4; i++ )
551
if( padfMinBound != NULL )
552
padfMinBound[i] = psSHP->adBoundsMin[i];
553
if( padfMaxBound != NULL )
554
padfMaxBound[i] = psSHP->adBoundsMax[i];
558
/************************************************************************/
561
/* Create a new shape file and return a handle to the open */
562
/* shape file with read/write access. */
563
/************************************************************************/
565
SHPHandle SHPCreate( const char * pszLayer, int nShapeType )
568
char *pszBasename, *pszFullname;
571
uchar abyHeader[100];
575
/* -------------------------------------------------------------------- */
576
/* Establish the byte order on this system. */
577
/* -------------------------------------------------------------------- */
579
if( *((uchar *) &i) == 1 )
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] != '\\';
595
if( pszBasename[i] == '.' )
596
pszBasename[i] = '\0';
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" );
607
sprintf( pszFullname, "%s.shx", pszBasename );
608
fpSHX = fopen(pszFullname, "wb" );
615
/* -------------------------------------------------------------------- */
616
/* Prepare header block for .shp file. */
617
/* -------------------------------------------------------------------- */
618
for( i = 0; i < 100; i++ )
621
abyHeader[2] = 0x27; /* magic cookie */
624
i32 = 50; /* file size */
625
ByteCopy( &i32, abyHeader+24, 4 );
626
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
628
i32 = 1000; /* version */
629
ByteCopy( &i32, abyHeader+28, 4 );
630
if( bBigEndian ) SwapWord( 4, abyHeader+28 );
632
i32 = nShapeType; /* shape type */
633
ByteCopy( &i32, abyHeader+32, 4 );
634
if( bBigEndian ) SwapWord( 4, abyHeader+32 );
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 );
642
/* -------------------------------------------------------------------- */
643
/* Write .shp file header. */
644
/* -------------------------------------------------------------------- */
645
fwrite( abyHeader, 100, 1, fpSHP );
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 );
654
fwrite( abyHeader, 100, 1, fpSHX );
656
/* -------------------------------------------------------------------- */
657
/* Close the files, and then open them as regular existing files. */
658
/* -------------------------------------------------------------------- */
662
return( SHPOpen( pszLayer, "r+b" ) );
665
/************************************************************************/
666
/* _SHPSetBounds() */
668
/* Compute a bounds rectangle for a shape, and set it into the */
669
/* indicated location in the record. */
670
/************************************************************************/
672
static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
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 );
682
SwapWord( 8, pabyRec + 0 );
683
SwapWord( 8, pabyRec + 8 );
684
SwapWord( 8, pabyRec + 16 );
685
SwapWord( 8, pabyRec + 24 );
689
/************************************************************************/
690
/* SHPComputeExtents() */
692
/* Recompute the extents of a shape. Automatically done by */
693
/* SHPCreateObject(). */
694
/************************************************************************/
696
void SHPComputeExtents( SHPObject * psObject )
701
/* -------------------------------------------------------------------- */
702
/* Build extents for this object. */
703
/* -------------------------------------------------------------------- */
704
if( psObject->nVertices > 0 )
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];
712
for( i = 0; i < psObject->nVertices; i++ )
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]);
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]);
726
/************************************************************************/
727
/* SHPCreateObject() */
729
/* Create a shape object. It should be freed with */
730
/* SHPDestroyObject(). */
731
/************************************************************************/
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 )
742
psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
743
psObject->nSHPType = nSHPType;
744
psObject->nShapeId = nShapeId;
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 )
757
else if( nSHPType == SHPT_ARCZ
758
|| nSHPType == SHPT_POINTZ
759
|| nSHPType == SHPT_POLYGONZ
760
|| nSHPType == SHPT_MULTIPOINTZ
761
|| nSHPType == SHPT_MULTIPATCH )
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 )
781
psObject->nParts = MAX(1,nParts);
783
psObject->panPartStart = (int *)
784
malloc(sizeof(int) * psObject->nParts);
785
psObject->panPartType = (int *)
786
malloc(sizeof(int) * psObject->nParts);
788
psObject->panPartStart[0] = 0;
789
psObject->panPartType[0] = SHPP_RING;
791
for( i = 0; i < nParts; i++ )
793
psObject->panPartStart[i] = panPartStart[i];
794
if( panPartType != NULL )
795
psObject->panPartType[i] = panPartType[i];
797
psObject->panPartType[i] = SHPP_RING;
801
/* -------------------------------------------------------------------- */
802
/* Capture vertices. Note that Z and M are optional, but X and */
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);
810
assert( padfX != NULL );
811
assert( padfY != NULL );
813
for( i = 0; i < nVertices; i++ )
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];
823
/* -------------------------------------------------------------------- */
824
/* Compute the extents. */
825
/* -------------------------------------------------------------------- */
826
psObject->nVertices = nVertices;
828
SHPComputeExtents( psObject );
833
/************************************************************************/
834
/* SHPCreateSimpleObject() */
836
/* Create a simple (common) shape object. Destroy with */
837
/* SHPDestroyObject(). */
838
/************************************************************************/
840
SHPObject *SHPCreateSimpleObject( int nSHPType, int nVertices,
841
double * padfX, double * padfY,
845
return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
846
nVertices, padfX, padfY, padfZ, NULL ) );
849
/************************************************************************/
850
/* SHPWriteObject() */
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
/************************************************************************/
856
int SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
859
int nRecordOffset, i, nRecordSize;
863
psSHP->bUpdated = TRUE;
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 );
871
/* -------------------------------------------------------------------- */
872
/* Add the new entity to the in memory index. */
873
/* -------------------------------------------------------------------- */
874
if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
876
psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
878
psSHP->panRecOffset = (int *)
879
SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
880
psSHP->panRecSize = (int *)
881
SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
884
/* -------------------------------------------------------------------- */
885
/* Initialize record. */
886
/* -------------------------------------------------------------------- */
887
pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
888
+ psObject->nParts * 8 + 128);
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 )
901
int32 nPoints, nParts;
904
nPoints = psObject->nVertices;
905
nParts = psObject->nParts;
907
_SHPSetBounds( pabyRec + 12, psObject );
909
if( bBigEndian ) SwapWord( 4, &nPoints );
910
if( bBigEndian ) SwapWord( 4, &nParts );
912
ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
913
ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
918
* Write part start positions.
920
ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
921
4 * psObject->nParts );
922
for( i = 0; i < psObject->nParts; i++ )
924
if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
929
* Write multipatch part types if needed.
931
if( psSHP->nShapeType == SHPT_MULTIPATCH )
933
memcpy( pabyRec + nRecordSize, psObject->panPartType,
934
4*psObject->nParts );
935
for( i = 0; i < psObject->nParts; i++ )
937
if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
943
* Write the (x,y) vertex values.
945
for( i = 0; i < psObject->nVertices; i++ )
947
ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
948
ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
951
SwapWord( 8, pabyRec + nRecordSize );
954
SwapWord( 8, pabyRec + nRecordSize + 8 );
956
nRecordSize += 2 * 8;
960
* Write the Z coordinates (if any).
962
if( psSHP->nShapeType == SHPT_POLYGONZ
963
|| psSHP->nShapeType == SHPT_ARCZ
964
|| psSHP->nShapeType == SHPT_MULTIPATCH )
966
ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
967
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
970
ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
971
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
974
for( i = 0; i < psObject->nVertices; i++ )
976
ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
977
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
983
* Write the M values, if any.
985
if( psSHP->nShapeType == SHPT_POLYGONM
986
|| psSHP->nShapeType == SHPT_ARCM
987
#ifndef DISABLE_MULTIPATCH_MEASURE
988
|| psSHP->nShapeType == SHPT_MULTIPATCH
990
|| psSHP->nShapeType == SHPT_POLYGONZ
991
|| psSHP->nShapeType == SHPT_ARCZ )
993
ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
994
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
997
ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
998
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1001
for( i = 0; i < psObject->nVertices; i++ )
1003
ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1004
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
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 )
1020
nPoints = psObject->nVertices;
1022
_SHPSetBounds( pabyRec + 12, psObject );
1024
if( bBigEndian ) SwapWord( 4, &nPoints );
1025
ByteCopy( &nPoints, pabyRec + 44, 4 );
1027
for( i = 0; i < psObject->nVertices; i++ )
1029
ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
1030
ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
1032
if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
1033
if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
1036
nRecordSize = 48 + 16 * psObject->nVertices;
1038
if( psSHP->nShapeType == SHPT_MULTIPOINTZ )
1040
ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1041
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1044
ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1045
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1048
for( i = 0; i < psObject->nVertices; i++ )
1050
ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1051
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1056
if( psSHP->nShapeType == SHPT_MULTIPOINTZ
1057
|| psSHP->nShapeType == SHPT_MULTIPOINTM )
1059
ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1060
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1063
ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1064
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1067
for( i = 0; i < psObject->nVertices; i++ )
1069
ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1070
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
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 )
1083
ByteCopy( psObject->padfX, pabyRec + 12, 8 );
1084
ByteCopy( psObject->padfY, pabyRec + 20, 8 );
1086
if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
1087
if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
1091
if( psSHP->nShapeType == SHPT_POINTZ )
1093
ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
1094
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1098
if( psSHP->nShapeType == SHPT_POINTZ
1099
|| psSHP->nShapeType == SHPT_POINTM )
1101
ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
1102
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
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 )
1120
if( nShapeId == -1 )
1121
nShapeId = psSHP->nRecords++;
1123
psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
1124
psSHP->panRecSize[nShapeId] = nRecordSize-8;
1125
psSHP->nFileSize += nRecordSize;
1129
nRecordOffset = psSHP->panRecOffset[nShapeId];
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 );
1139
i32 = (nRecordSize-8)/2; /* record size */
1140
if( !bBigEndian ) SwapWord( 4, &i32 );
1141
ByteCopy( &i32, pabyRec + 4, 4 );
1143
i32 = psSHP->nShapeType; /* shape type */
1144
if( bBigEndian ) SwapWord( 4, &i32 );
1145
ByteCopy( &i32, pabyRec + 8, 4 );
1147
/* -------------------------------------------------------------------- */
1148
/* Write out record. */
1149
/* -------------------------------------------------------------------- */
1150
if( fseek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
1151
|| fwrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
1153
printf( "Error in fseek() or fwrite().\n" );
1160
/* -------------------------------------------------------------------- */
1161
/* Expand file wide bounds based on this shape. */
1162
/* -------------------------------------------------------------------- */
1163
if( psSHP->nRecords == 1 )
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];
1171
for( i = 0; i < psObject->nVertices; i++ )
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]);
1186
/************************************************************************/
1187
/* SHPReadObject() */
1189
/* Read the vertices, parts, and other non-attribute information */
1190
/* for one shape. */
1191
/************************************************************************/
1193
SHPObject *SHPReadObject( SHPHandle psSHP, int hEntity )
1198
/* -------------------------------------------------------------------- */
1199
/* Validate the record/entity number. */
1200
/* -------------------------------------------------------------------- */
1201
if( hEntity < 0 || hEntity >= psSHP->nRecords )
1204
/* -------------------------------------------------------------------- */
1205
/* Ensure our record buffer is large enough. */
1206
/* -------------------------------------------------------------------- */
1207
if( psSHP->panRecSize[hEntity]+8 > nBufSize )
1209
nBufSize = psSHP->panRecSize[hEntity]+8;
1210
pabyRec = (uchar *) SfRealloc(pabyRec,nBufSize);
1213
/* -------------------------------------------------------------------- */
1214
/* Read the record. */
1215
/* -------------------------------------------------------------------- */
1216
fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 );
1217
fread( pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
1219
/* -------------------------------------------------------------------- */
1220
/* Allocate and minimally initialize the object. */
1221
/* -------------------------------------------------------------------- */
1222
psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
1223
psShape->nShapeId = hEntity;
1225
memcpy( &psShape->nSHPType, pabyRec + 8, 4 );
1226
if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
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 )
1238
int32 nPoints, nParts;
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 );
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) );
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 );
1261
if( bBigEndian ) SwapWord( 4, &nPoints );
1262
if( bBigEndian ) SwapWord( 4, &nParts );
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));
1270
psShape->nParts = nParts;
1271
psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
1272
psShape->panPartType = (int *) calloc(nParts,sizeof(int));
1274
for( i = 0; i < nParts; i++ )
1275
psShape->panPartType[i] = SHPP_RING;
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++ )
1283
if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
1286
nOffset = 44 + 8 + 4*nParts;
1288
/* -------------------------------------------------------------------- */
1289
/* If this is a multipatch, we will also have parts types. */
1290
/* -------------------------------------------------------------------- */
1291
if( psShape->nSHPType == SHPT_MULTIPATCH )
1293
memcpy( psShape->panPartType, pabyRec + nOffset, 4*nParts );
1294
for( i = 0; i < nParts; i++ )
1296
if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
1299
nOffset += 4*nParts;
1302
/* -------------------------------------------------------------------- */
1303
/* Copy out the vertices from the record. */
1304
/* -------------------------------------------------------------------- */
1305
for( i = 0; i < nPoints; i++ )
1307
memcpy(psShape->padfX + i,
1308
pabyRec + nOffset + i * 16,
1311
memcpy(psShape->padfY + i,
1312
pabyRec + nOffset + i * 16 + 8,
1315
if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1316
if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1319
nOffset += 16*nPoints;
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 )
1328
memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 );
1329
memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 );
1331
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1332
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1334
for( i = 0; i < nPoints; i++ )
1336
memcpy( psShape->padfZ + i,
1337
pabyRec + nOffset + 16 + i*8, 8 );
1338
if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
1341
nOffset += 16 + 8*nPoints;
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 )
1352
memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 );
1353
memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 );
1355
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
1356
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
1358
for( i = 0; i < nPoints; i++ )
1360
memcpy( psShape->padfM + i,
1361
pabyRec + nOffset + 16 + i*8, 8 );
1362
if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
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 )
1378
memcpy( &nPoints, pabyRec + 44, 4 );
1379
if( bBigEndian ) SwapWord( 4, &nPoints );
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));
1387
for( i = 0; i < nPoints; i++ )
1389
memcpy(psShape->padfX+i, pabyRec + 48 + 16 * i, 8 );
1390
memcpy(psShape->padfY+i, pabyRec + 48 + 16 * i + 8, 8 );
1392
if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1393
if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1396
nOffset = 48 + 16*nPoints;
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 );
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) );
1411
/* -------------------------------------------------------------------- */
1412
/* If we have a Z coordinate, collect that now. */
1413
/* -------------------------------------------------------------------- */
1414
if( psShape->nSHPType == SHPT_MULTIPOINTZ )
1416
memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 );
1417
memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 );
1419
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1420
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1422
for( i = 0; i < nPoints; i++ )
1424
memcpy( psShape->padfZ + i,
1425
pabyRec + nOffset + 16 + i*8, 8 );
1426
if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
1429
nOffset += 16 + 8*nPoints;
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 )
1440
memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 );
1441
memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 );
1443
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
1444
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
1446
for( i = 0; i < nPoints; i++ )
1448
memcpy( psShape->padfM + i,
1449
pabyRec + nOffset + 16 + i*8, 8 );
1450
if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
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 )
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));
1470
memcpy( psShape->padfX, pabyRec + 12, 8 );
1471
memcpy( psShape->padfY, pabyRec + 20, 8 );
1473
if( bBigEndian ) SwapWord( 8, psShape->padfX );
1474
if( bBigEndian ) SwapWord( 8, psShape->padfY );
1478
/* -------------------------------------------------------------------- */
1479
/* If we have a Z coordinate, collect that now. */
1480
/* -------------------------------------------------------------------- */
1481
if( psShape->nSHPType == SHPT_POINTZ )
1483
memcpy( psShape->padfZ, pabyRec + nOffset, 8 );
1485
if( bBigEndian ) SwapWord( 8, psShape->padfZ );
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 )
1498
memcpy( psShape->padfM, pabyRec + nOffset, 8 );
1500
if( bBigEndian ) SwapWord( 8, psShape->padfM );
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];
1516
/************************************************************************/
1518
/************************************************************************/
1520
const char *SHPTypeName( int nSHPType )
1537
case SHPT_MULTIPOINT:
1538
return "MultiPoint";
1549
case SHPT_MULTIPOINTZ:
1550
return "MultiPointZ";
1561
case SHPT_MULTIPOINTM:
1562
return "MultiPointM";
1564
case SHPT_MULTIPATCH:
1565
return "MultiPatch";
1568
return "UnknownShapeType";
1572
/************************************************************************/
1573
/* SHPPartTypeName() */
1574
/************************************************************************/
1576
const char *SHPPartTypeName( int nPartType )
1582
return "TriangleStrip";
1585
return "TriangleFan";
1587
case SHPP_OUTERRING:
1590
case SHPP_INNERRING:
1593
case SHPP_FIRSTRING:
1600
return "UnknownPartType";
1604
/************************************************************************/
1605
/* SHPDestroyObject() */
1606
/************************************************************************/
1608
void SHPDestroyObject( SHPObject * psShape )
1611
if( psShape == NULL )
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 );
1623
if( psShape->panPartStart != NULL )
1624
free( psShape->panPartStart );
1625
if( psShape->panPartType != NULL )
1626
free( psShape->panPartType );