geo_coder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }