geo_coder 0.1.0

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