/[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 1769 - (show annotations)
Thu Oct 2 15:15:16 2003 UTC (21 years, 5 months ago) by bh
Original Path: trunk/thuban/libraries/shapelib/shpopen.c
File MIME type: text/plain
File size: 69000 byte(s)
Update to shapelib 1.2.10

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26