/[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 2212 - (show annotations)
Mon May 17 15:47:57 2004 UTC (20 years, 9 months ago) by bh
Original Path: trunk/thuban/libraries/shapelib/shpopen.c
File MIME type: text/plain
File size: 74432 byte(s)
Update to newest shapelib and get rid of Thuban specific extensions,
i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge

* libraries/shapelib/shpopen.c: Update to version from current
shapelib CVS.

* libraries/shapelib/shapefil.h: Update to version from current
shapelib CVS.

* libraries/shapelib/dbfopen.c: Update to version from current
shapelib CVS.
(DBFCommit): Effectively removed since shapelib itself has
DBFUpdateHeader now which is better for what DBFCommit wanted to
achieve.
We're now using an unmodified version of dbfopen.

* libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
Update from dbflib.i

* libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
the commit method.  This new indirection is necessary because we use the
DBFUpdateHeader function now which is not available in shapelib <=
1.2.10
(DBFFile::commit): Use DBFInfo_commit as implementation
(pragma __class__): New. Kludge to remove the commit method when
the DBFUpdateHeader function isn't available
(_have_commit): New. Helper for the pragma kludge.

* libraries/pyshapelib/setup.py (dbf_macros): New. Return the
preprocessor macros needed to compile the dbflib wrapper.  Determine
whether DBFUpdateHeader is available and define the right value of
HAVE_UPDATE_HEADER
(extensions): Use dbf_macros for the dbflibc extension

* setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
value '1' to the Lib.dbflibc extension.  This simply reflects the
shapelib and pyshapelib updates

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26