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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1612 - (show annotations)
Tue Aug 19 21:29:25 2003 UTC (21 years, 6 months ago) by jan
Original Path: trunk/thuban/libraries/shapelib/shpopen.c
File MIME type: text/plain
File size: 62287 byte(s)
These files have been moved here from thuban/extensions/shapelib/
See there in the Attic for the older history.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26