shp 0.0.1

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 (78) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +34 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +28 -0
  6. data/README.md +30 -0
  7. data/Rakefile +23 -0
  8. data/ext/shp/base.hpp +113 -0
  9. data/ext/shp/dbf.cpp +381 -0
  10. data/ext/shp/dbf.hpp +44 -0
  11. data/ext/shp/extconf.rb +13 -0
  12. data/ext/shp/shape_object.cpp +58 -0
  13. data/ext/shp/shape_object.hpp +27 -0
  14. data/ext/shp/shapefile.cpp +299 -0
  15. data/ext/shp/shapefile.hpp +35 -0
  16. data/ext/shp/shapelib/.cvsignore +15 -0
  17. data/ext/shp/shapelib/ChangeLog +450 -0
  18. data/ext/shp/shapelib/HOWTO-RELEASE +16 -0
  19. data/ext/shp/shapelib/LICENSE.LGPL +483 -0
  20. data/ext/shp/shapelib/Makefile +113 -0
  21. data/ext/shp/shapelib/README +41 -0
  22. data/ext/shp/shapelib/README.tree +172 -0
  23. data/ext/shp/shapelib/contrib/.cvsignore +12 -0
  24. data/ext/shp/shapelib/contrib/Makefile +66 -0
  25. data/ext/shp/shapelib/contrib/ShapeFileII.pas +234 -0
  26. data/ext/shp/shapelib/contrib/Shape_PointInPoly.cpp +238 -0
  27. data/ext/shp/shapelib/contrib/Shape_PointInPoly_README.txt +59 -0
  28. data/ext/shp/shapelib/contrib/csv2shp.c +558 -0
  29. data/ext/shp/shapelib/contrib/dbfcat.c +166 -0
  30. data/ext/shp/shapelib/contrib/dbfinfo.c +106 -0
  31. data/ext/shp/shapelib/contrib/makefile.vc +34 -0
  32. data/ext/shp/shapelib/contrib/my_nan.h +46 -0
  33. data/ext/shp/shapelib/contrib/shpcat.c +100 -0
  34. data/ext/shp/shapelib/contrib/shpcentrd.c +159 -0
  35. data/ext/shp/shapelib/contrib/shpdata.c +129 -0
  36. data/ext/shp/shapelib/contrib/shpdxf.c +340 -0
  37. data/ext/shp/shapelib/contrib/shpfix.c +110 -0
  38. data/ext/shp/shapelib/contrib/shpgeo.c +1595 -0
  39. data/ext/shp/shapelib/contrib/shpgeo.h +154 -0
  40. data/ext/shp/shapelib/contrib/shpinfo.c +113 -0
  41. data/ext/shp/shapelib/contrib/shpproj.c +260 -0
  42. data/ext/shp/shapelib/contrib/shpsort.c +605 -0
  43. data/ext/shp/shapelib/contrib/shpsort.txt +44 -0
  44. data/ext/shp/shapelib/contrib/shpwkb.c +123 -0
  45. data/ext/shp/shapelib/contrib/tests/shpproj.sh +38 -0
  46. data/ext/shp/shapelib/dbfopen.c +2221 -0
  47. data/ext/shp/shapelib/makefile.vc +86 -0
  48. data/ext/shp/shapelib/makeshape.sh +21 -0
  49. data/ext/shp/shapelib/mkdist.sh +37 -0
  50. data/ext/shp/shapelib/mkinstalldirs +38 -0
  51. data/ext/shp/shapelib/mkrelease.sh +55 -0
  52. data/ext/shp/shapelib/safileio.c +286 -0
  53. data/ext/shp/shapelib/shapefil.h +647 -0
  54. data/ext/shp/shapelib/shapelib.def +46 -0
  55. data/ext/shp/shapelib/shpopen.c +2388 -0
  56. data/ext/shp/shapelib/shptree.c +1187 -0
  57. data/ext/shp/shapelib/shputils.c +1072 -0
  58. data/ext/shp/shapelib/stream1.out +1465 -0
  59. data/ext/shp/shapelib/stream1.sh +28 -0
  60. data/ext/shp/shapelib/stream2.out +530 -0
  61. data/ext/shp/shapelib/stream2.sh +11 -0
  62. data/ext/shp/shapelib/stream3.out +37 -0
  63. data/ext/shp/shapelib/web/.cvsignore +2 -0
  64. data/ext/shp/shapelib/web/codepage.html +403 -0
  65. data/ext/shp/shapelib/web/dbf_api.html +436 -0
  66. data/ext/shp/shapelib/web/index.html +235 -0
  67. data/ext/shp/shapelib/web/license.html +78 -0
  68. data/ext/shp/shapelib/web/manifest.html +87 -0
  69. data/ext/shp/shapelib/web/release.html +80 -0
  70. data/ext/shp/shapelib/web/shapelib-tools.html +352 -0
  71. data/ext/shp/shapelib/web/shp_api.html +376 -0
  72. data/ext/shp/shp.cpp +19 -0
  73. data/ext/shp/shp.hpp +47 -0
  74. data/lib/shp.rb +35 -0
  75. data/lib/shp/version.rb +3 -0
  76. data/shp.gemspec +23 -0
  77. data/spec/shp_spec.rb +127 -0
  78. metadata +176 -0
@@ -0,0 +1,238 @@
1
+ /******************************************************************************
2
+ * $Id: Shape_PointInPoly.cpp,v 1.1 2004-01-09 16:47:57 fwarmerdam Exp $
3
+ *
4
+ * Project: Shapelib
5
+ * Purpose: Commandline program to generate points-in-polygons from a
6
+ * shapefile as a shapefile.
7
+ * Author: Marko Podgorsek, d-mon@siol.net
8
+ *
9
+ ******************************************************************************
10
+ * Copyright (c) 2004, Marko Podgorsek, d-mon@siol.net
11
+ *
12
+ * This software is available under the following "MIT Style" license,
13
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
14
+ * option is discussed in more detail in shapelib.html.
15
+ *
16
+ * --
17
+ *
18
+ * Permission is hereby granted, free of charge, to any person obtaining a
19
+ * copy of this software and associated documentation files (the "Software"),
20
+ * to deal in the Software without restriction, including without limitation
21
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22
+ * and/or sell copies of the Software, and to permit persons to whom the
23
+ * Software is furnished to do so, subject to the following conditions:
24
+ *
25
+ * The above copyright notice and this permission notice shall be included
26
+ * in all copies or substantial portions of the Software.
27
+ *
28
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34
+ * DEALINGS IN THE SOFTWARE.
35
+ ******************************************************************************
36
+ *
37
+ * $Log: Shape_PointInPoly.cpp,v $
38
+ * Revision 1.1 2004-01-09 16:47:57 fwarmerdam
39
+ * New
40
+ *
41
+ */
42
+
43
+ static char rcsid[] =
44
+ "$Id: Shape_PointInPoly.cpp,v 1.1 2004-01-09 16:47:57 fwarmerdam Exp $";
45
+
46
+ #include <string.h>
47
+ #include <stdlib.h>
48
+ #include <math.h>
49
+ #include <shapefil.h>
50
+
51
+ #define MAXINTERSECTIONPOINTS 255
52
+
53
+ enum loopDir {
54
+ kExterior,
55
+ kInterior,
56
+ kError
57
+ };
58
+
59
+ struct DPoint2d
60
+ {
61
+ DPoint2d()
62
+ {
63
+ x = y = 0.0;
64
+ };
65
+ DPoint2d(double x, double y)
66
+ {
67
+ this->x = x;
68
+ this->y = y;
69
+ };
70
+ double x,y;
71
+ };
72
+
73
+ struct IntersectPoint
74
+ {
75
+ IntersectPoint(void)
76
+ {
77
+ x = y = 0.0;
78
+ boundry_nmb = 0;
79
+ loopdirection = kError;
80
+ };
81
+ double x,y;
82
+ int boundry_nmb;
83
+ loopDir loopdirection;
84
+ };
85
+
86
+ loopDir LoopDirection(DPoint2d *vertices, int vertsize)
87
+ {
88
+ int i;
89
+ double sum = 0.0;
90
+ for(i=0;i<vertsize-1;i++)
91
+ {
92
+ sum += (vertices[i].x*vertices[i+1].y)-(vertices[i].y*vertices[i+1].x);
93
+ }
94
+
95
+ if(sum>0)
96
+ return kInterior;
97
+ else
98
+ return kExterior;
99
+ }
100
+
101
+ DPoint2d CreatePointInPoly(SHPObject *psShape, int quality)
102
+ {
103
+ int i, j, k, end, vert, pointpos;
104
+ double part, dx, xmin, xmax, ymin, ymax, y, x3, x4, y3, y4, len, maxlen = 0;
105
+ DPoint2d *vertices;
106
+ loopDir direction;
107
+ IntersectPoint mp1, mp2, point1, point2, points[MAXINTERSECTIONPOINTS];
108
+
109
+ xmin = psShape->dfXMin;
110
+ ymin = psShape->dfYMin;
111
+ xmax = psShape->dfXMax;
112
+ ymax = psShape->dfYMax;
113
+ part = (ymax-ymin)/(quality+1);
114
+ dx = xmax-xmin;
115
+ for(i=0;i<quality;i++)
116
+ {
117
+ y = ymin+part*(i+1);
118
+ pointpos = 0;
119
+ for(j=0;j<psShape->nParts;j++)
120
+ {
121
+ if(j==psShape->nParts-1)
122
+ end = psShape->nVertices;
123
+ else
124
+ end = psShape->panPartStart[j+1];
125
+ vertices = new DPoint2d [end-psShape->panPartStart[j]];
126
+ for(k=psShape->panPartStart[j],vert=0;k<end;k++)
127
+ {
128
+ vertices[vert].x = psShape->padfX[k];
129
+ vertices[vert++].y = psShape->padfY[k];
130
+ }
131
+ direction = LoopDirection(vertices, vert);
132
+ for(k=0;k<vert-1;k++)
133
+ {
134
+ y3 = vertices[k].y;
135
+ y4 = vertices[k+1].y;
136
+ if((y3 >= y && y4 < y) || (y3 <= y && y4 > y)) //I check >= only once, because if it's not checked now (y3) it will be in the next iteration (which is y4 now)
137
+ {
138
+ point1.boundry_nmb = j;
139
+ point1.loopdirection = direction;
140
+ x3 = vertices[k].x;
141
+ x4 = vertices[k+1].x;
142
+ if(y3==y)
143
+ {
144
+ point1.y = y3;
145
+ point1.x = x3;
146
+ if(direction == kInterior) //add point 2 times if the direction is interior, so that the final count of points is even
147
+ {
148
+ points[pointpos++]=point1;
149
+ }
150
+ }
151
+ else
152
+ {
153
+ point1.x = xmin+(((((x4-x3)*(y-y3))-((y4-y3)*(xmin-x3)))/((y4-y3)*dx))*dx); //striped down calculation of intersection of 2 lines
154
+ point1.y = y;
155
+ }
156
+ points[pointpos++]=point1;
157
+ }
158
+ }
159
+ delete [] vertices;
160
+ }
161
+
162
+ for(j=1;j<pointpos;j++) //sort the found intersection points by x value
163
+ {
164
+ for(k=j;k>0;k--)
165
+ {
166
+ if(points[k].x < points[k-1].x)
167
+ {
168
+ point1 = points[k];
169
+ points[k] = points[k-1];
170
+ points[k-1] = point1;
171
+ }
172
+ else
173
+ {
174
+ break;
175
+ }
176
+ }
177
+ }
178
+
179
+ for(j=0;j<pointpos-1;j++)
180
+ {
181
+ point1 = points[j];
182
+ point2 = points[j+1];
183
+ if((point1.loopdirection == kExterior && //some checkings for valid point
184
+ point2.loopdirection == kExterior &&
185
+ point1.boundry_nmb == point2.boundry_nmb &&
186
+ j%2==0) ||
187
+ (point1.loopdirection == kExterior &&
188
+ point2.loopdirection == kInterior) ||
189
+ (point1.loopdirection == kInterior &&
190
+ point2.loopdirection == kExterior))
191
+ {
192
+ len = sqrt(pow(point1.x-point2.x, 2)+pow(point1.y-point2.y, 2));
193
+ if(len >= maxlen)
194
+ {
195
+ maxlen = len;
196
+ mp1 = point1;
197
+ mp2 = point2;
198
+ }
199
+ }
200
+ }
201
+ }
202
+
203
+ return DPoint2d((mp1.x+mp2.x)*0.5, (mp1.y+mp2.y)*0.5);
204
+ }
205
+
206
+ int main(int argc, char* argv[])
207
+ {
208
+ if(argc != 3)
209
+ {
210
+ printf("Usage: %s shpfile_path quality\n", argv[0]);
211
+ return 1;
212
+ }
213
+
214
+ int i, nEntities, quality;
215
+ SHPHandle hSHP;
216
+ SHPObject *psShape;
217
+ DPoint2d pt;
218
+ quality = atoi(argv[2]);
219
+ hSHP = SHPOpen(argv[1], "rb");
220
+ SHPGetInfo(hSHP, &nEntities, NULL, NULL, NULL);
221
+
222
+ printf("PointInPoly v1.0, by Marko Podgorsek\n----------------\n");
223
+ for( i = 0; i < nEntities; i++ )
224
+ {
225
+ psShape = SHPReadObject( hSHP, i );
226
+ if(psShape->nSHPType == SHPT_POLYGON)
227
+ {
228
+ pt = CreatePointInPoly(psShape, quality);
229
+ printf("%d: x=%f y=%f\n",i, pt.x,pt.y);
230
+ }
231
+ SHPDestroyObject( psShape );
232
+ }
233
+
234
+ SHPClose(hSHP);
235
+
236
+ return 0;
237
+ }
238
+
@@ -0,0 +1,59 @@
1
+ ===============================================================================
2
+ Project: Shape_PoinInPoly
3
+ Purpose: Sample and the function for calculatin a point in a polygon
4
+ (complex,compound - it doesn't matter). Can be used for labeling.
5
+ Author: Copyright (c) 2004, Marko Podgorsek, d-mon@siol.net
6
+ ===============================================================================
7
+ Requires: shapelib 1.2 (http://shapelib.maptools.org/)
8
+ Tested and created on platform:
9
+ Windows 2000 Professional
10
+ Visual Studio .NET 7.0
11
+ P4 2.4 GHz
12
+ 1GB RAM
13
+
14
+ I just found out about the ShapeLib, GDAL and OGR and I must say that they're
15
+ all great projects.
16
+ I belive I'll use some of those libraries in the future. Right now I'm using
17
+ only shapelib.
18
+ The thing that led me to the http://wwww.maptools.org was the need of finding
19
+ the point in poly...but as I found out that even OGR didn't support it. So
20
+ there I was. I was forced to make my own function. Well, it was fun. I learned
21
+ a lot.
22
+ I wrote this function for the Autodesk Autocad 2004 MPolygon, because there was
23
+ no function to do this in the Object Arx SDK (the Acad programming SDK). Well,
24
+ it will be in the 2005 release...but, still. There is a function in the
25
+ Autodesk Map 2004 version...in the menu.
26
+ Not usefull when you need the coordinates, not the point on the screen...
27
+ So when the Acad version was done I was thinking of doing it on the Shape files,
28
+ too. A little bit of changing the structures and variable
29
+ types (so they're not using Object Arx) and I was done.
30
+ And here it is....Contribution from me to the ShapeLib world :)...and maybe even
31
+ OGR (a little bit of changing there).
32
+
33
+ Some statistics:
34
+ For about 69000 polygons in Autocad picture (.dwg files)
35
+ Autodesk Map 2004 was creating centroids (the menu command) about 45s (1 scan
36
+ line)
37
+ My function, with 3 scan lines took about 5s. And I was drawing the dots on the
38
+ picture...
39
+
40
+ -------------------------------------------------------------------------------
41
+ DPoint2d CreatePointInPoly(SHPObject *psShape, int quality)
42
+
43
+ The second parameter quality tell the function just how many rays shall it use
44
+ to get the point.
45
+ quality = 3 works very well, but anything below 5 is good.
46
+ This doesn't mean that the execution will slow down, but it just finds a good
47
+ point. That's all.
48
+
49
+ The qality shows on the compound objects (multiple poligons with more than one
50
+ exterior loop) - if not enough rays, then there may be no centroid.
51
+ Or the U shaped thin polygon, only the bootom (below the y center line) is fat.
52
+ Autodesk Map with one scan line will create the centroid on one of the thin
53
+ parts, because it only uses the y center line. If you have more rays, one will
54
+ surely pass the fat area and centroid will be created there.
55
+
56
+ -------------------------------------------------------------------------------
57
+ Anyone using this function:
58
+ Just send me an e-mail, so I'll see if I did anything good for the public.
59
+ And you can send me e-mail with questions also.
@@ -0,0 +1,558 @@
1
+ /*
2
+ csv2shp - converts a character delimited file to a ESRI shapefile
3
+ Copyright (C) 2005 Springs Rescue Mission
4
+
5
+
6
+ LICENSE
7
+ This program is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU General Public License
9
+ as published by the Free Software Foundation; either version 2
10
+ of the License, or (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program; if not, write to the Free Software
19
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
+
21
+ The GNU General Public License is also available from the web
22
+ site <http://www.gnu.org>.
23
+
24
+
25
+ GRATITUDE
26
+ Like this program? Donate at <http://springsrescuemission.org>.
27
+
28
+
29
+ COMPILING INSTRUCTIONS
30
+ This program was written and tested using Shapefile C Library version
31
+ 1.2.10 available at <http://shapelib.maptools.org>.
32
+
33
+ To compile, copy csv2shp.c to the directory with Shapefile C Library.
34
+ Then, compile Shapefile C library. Then, run something like this:
35
+
36
+ gcc -pedantic -Wall -o csv2shp csv2shp.c -I. *o
37
+
38
+
39
+ USAGE NOTES
40
+ This program operates on single points only (not polygons or lines).
41
+
42
+ The input file may be a .csv file (comma separated values) or tab-separated
43
+ values, or it may be separated by any other character. The first row must
44
+ contain column names. There must be each a column named longitude and
45
+ latitude in the input file.
46
+
47
+ The .csv parser does not understand text delimiters (e.g. quotation mark).
48
+ It parses fields only by the given field delimiter (e.g. comma or tab).
49
+ The program has not been tested with null values, and in this case, the
50
+ behavior is undefined. The program will not accept lines with a trailing
51
+ delimiter character.
52
+
53
+ All columns (including longitude and latitude) in the input file are exported
54
+ to the .dbf file.
55
+
56
+ The program attempts to find the best type (integer, decimal, string) and
57
+ smallest size of the fields necessary for the .dbf file.
58
+
59
+
60
+ SUPPORT
61
+ Springs Rescue Mission does not offer any support for this program.
62
+
63
+
64
+ CONTACT INFORMATION
65
+ Springs Rescue Mission
66
+ 5 West Las Vegas St
67
+ PO Box 2108
68
+ Colorado Springs CO 80901
69
+ Web: <http://springsrescuemission.org>
70
+ Email: <http://springsrescuemission.org/email.php?recipient=webmaster>
71
+
72
+ */
73
+
74
+
75
+ #include <stdio.h>
76
+ #include <stdlib.h>
77
+ #include <string.h>
78
+
79
+ #include "shapefil.h"
80
+ #include "regex.h"
81
+
82
+ #define MAX_COLUMNS 30
83
+
84
+ typedef struct column_t {
85
+ DBFFieldType eType;
86
+ int nWidth;
87
+ int nDecimals;
88
+ } column;
89
+
90
+ /* counts the number of occurances of the character in the string */
91
+ int strnchr(const char *s, char c)
92
+ {
93
+ int n = 0;
94
+ int x = 0;
95
+
96
+ for (; x < strlen(s); x++)
97
+ {
98
+ if (c == s[x])
99
+ {
100
+ n++;
101
+ }
102
+ }
103
+
104
+ return n;
105
+ }
106
+
107
+ /* Returns a field given by column n (0-based) in a character-
108
+ delimited string s */
109
+ char * delimited_column(char *s, char delim, int n)
110
+ {
111
+ static char szreturn[4096];
112
+ char szbuffer[4096]; /* a copy of s */
113
+ char * pchar;
114
+ int x;
115
+ char szdelimiter[2]; /* delim converted to string */
116
+
117
+ if (strnchr(s, delim) < n)
118
+ {
119
+ fprintf(stderr, "delimited_column: n is too large\n");
120
+ return NULL;
121
+ }
122
+
123
+ strcpy(szbuffer, s);
124
+ szdelimiter[0] = delim;
125
+ szdelimiter[1] = '\0';
126
+ x = 0;
127
+ pchar = strtok(szbuffer, szdelimiter);
128
+ while (x < n)
129
+ {
130
+ pchar = strtok(NULL, szdelimiter);
131
+ x++;
132
+ }
133
+
134
+ if (NULL == pchar)
135
+ {
136
+ return NULL;
137
+ }
138
+
139
+ strcpy(szreturn, pchar);
140
+ return szreturn;
141
+ }
142
+
143
+ /* Determines the most specific column type.
144
+ The most specific types from most to least are integer, float, string. */
145
+ DBFFieldType str_to_fieldtype(const char *s)
146
+ {
147
+ regex_t regex_i;
148
+ regex_t regex_d;
149
+
150
+ if (0 != regcomp(&regex_i, "^[0-9]+$", REG_NOSUB|REG_EXTENDED))
151
+ {
152
+ fprintf(stderr, "integer regex complication failed\n");
153
+ exit (EXIT_FAILURE);
154
+ }
155
+
156
+ if (0 == regexec(&regex_i, s, 0, NULL, 0))
157
+ {
158
+ regfree(&regex_i);
159
+ return FTInteger;
160
+ }
161
+
162
+ regfree(&regex_i);
163
+
164
+ if (0 != regcomp(&regex_d, "^-?[0-9]+\\.[0-9]+$", REG_NOSUB|REG_EXTENDED))
165
+ {
166
+ fprintf(stderr, "integer regex complication failed\n");
167
+ exit (EXIT_FAILURE);
168
+ }
169
+
170
+ if (0 == regexec(&regex_d, s, 0, NULL, 0))
171
+ {
172
+ regfree(&regex_d);
173
+ return FTDouble;
174
+ }
175
+
176
+ regfree(&regex_d);
177
+
178
+ return FTString;
179
+ }
180
+
181
+ int float_width(const char *s)
182
+ {
183
+ regex_t regex_d;
184
+ regmatch_t pmatch[2];
185
+ char szbuffer[4096];
186
+
187
+ if (0 != regcomp(&regex_d, "^(-?[0-9]+)\\.[0-9]+$", REG_EXTENDED))
188
+ {
189
+ fprintf(stderr, "integer regex complication failed\n");
190
+ exit (EXIT_FAILURE);
191
+ }
192
+
193
+ if (0 != regexec(&regex_d, s, 2, &pmatch[0], 0))
194
+ {
195
+ return -1;
196
+ }
197
+
198
+ strncpy(szbuffer, &s[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
199
+ szbuffer[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
200
+ regfree(&regex_d);
201
+
202
+ return strlen(szbuffer);
203
+ }
204
+
205
+ /* returns the field width */
206
+ int str_to_nwidth(const char *s, DBFFieldType eType)
207
+ {
208
+ switch (eType)
209
+ {
210
+ case FTString:
211
+ case FTInteger:
212
+ case FTDouble:
213
+ return strlen(s);
214
+
215
+ default:
216
+ fprintf(stderr, "str_to_nwidth: unexpected type\n");
217
+ exit (EXIT_FAILURE);
218
+ }
219
+ }
220
+
221
+ /* returns the number of decimals in a real number given as a string s */
222
+ int str_to_ndecimals(const char *s)
223
+ {
224
+ regex_t regex_d;
225
+ regmatch_t pmatch[2];
226
+ char szbuffer[4096];
227
+
228
+ if (0 != regcomp(&regex_d, "^-?[0-9]+\\.([0-9]+)$", REG_EXTENDED))
229
+ {
230
+ fprintf(stderr, "integer regex complication failed\n");
231
+ exit (EXIT_FAILURE);
232
+ }
233
+
234
+ if (0 != regexec(&regex_d, s, 2, &pmatch[0], 0))
235
+ {
236
+ return -1;
237
+ }
238
+
239
+ strncpy(szbuffer, &s[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
240
+ szbuffer[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
241
+
242
+ regfree(&regex_d);
243
+
244
+ return strlen(szbuffer);
245
+ }
246
+
247
+ /* returns true if f1 is more general than f2, otherwise false */
248
+ int more_general_field_type(DBFFieldType t1, DBFFieldType t2)
249
+ {
250
+ if (FTInteger == t2 && t1 != FTInteger)
251
+ {
252
+ return 1;
253
+ }
254
+
255
+ if (FTDouble == t2 && FTString == t1)
256
+ {
257
+ return 1;
258
+ }
259
+
260
+ return 0;
261
+ }
262
+
263
+ void strip_crlf (char *line)
264
+ {
265
+ /* remove trailing CR/LF */
266
+
267
+ if (strchr (line, 0x0D))
268
+ {
269
+ char *pszline;
270
+ pszline = strchr (line, 0x0D);
271
+ pszline[0] = '\0';
272
+ }
273
+
274
+ if (strchr (line, 0x0A))
275
+ {
276
+ char *pszline;
277
+ pszline = strchr (line, 0x0A);
278
+ pszline[0] = '\0';
279
+ }
280
+ }
281
+
282
+ int main( int argc, char ** argv )
283
+ {
284
+ FILE *csv_f;
285
+ char sbuffer[4096];
286
+ char delimiter;
287
+ int n_columns; /* 1-based */
288
+ int n_line;
289
+ int n_longitude = -1; /* column with x, 0 based */
290
+ int n_latitude = -1; /* column with y, 0 based */
291
+ int x;
292
+ DBFHandle dbf_h;
293
+ SHPHandle shp_h;
294
+ column columns[MAX_COLUMNS + 1];
295
+
296
+ printf("csv2shp version 1, Copyright (C) 2005 Springs Rescue Mission\n");
297
+
298
+ if (4 != argc)
299
+ {
300
+ fprintf(stderr, "csv2shp comes with ABSOLUTELY NO WARRANTY; for details\n");
301
+ fprintf(stderr, "see csv2shp.c. This is free software, and you are welcome\n");
302
+ fprintf(stderr, "to redistribute it under certain conditions; see csv2shp.c\n");
303
+ fprintf(stderr, "for details\n");
304
+ fprintf(stderr, "\n");
305
+ fprintf(stderr, "USAGE\n");
306
+ fprintf(stderr, "csv2shp csv_filename delimiter_character shp_filename\n");
307
+ fprintf(stderr, " csv_filename\n");
308
+ fprintf(stderr, " columns named longitude and latitude must exist\n");
309
+ fprintf(stderr, " delimiter_character\n");
310
+ fprintf(stderr, " one character only\n");
311
+ fprintf(stderr, " shp_filename\n");
312
+ fprintf(stderr, " base name, do not give the extension\n");
313
+ return EXIT_FAILURE;
314
+ }
315
+
316
+ if (strlen(argv[2]) > 1)
317
+ {
318
+ fprintf(stderr, "delimiter must be one character in length\n");
319
+ return EXIT_FAILURE;
320
+ }
321
+
322
+ delimiter = argv[2][0];
323
+
324
+ csv_f = fopen(argv[1], "r");
325
+
326
+ if (NULL == csv_f)
327
+ {
328
+ perror("could not open csv file");
329
+ exit (EXIT_FAILURE);
330
+ }
331
+
332
+ fgets(sbuffer, 4000, csv_f);
333
+
334
+ /* check first row */
335
+
336
+ strip_crlf(sbuffer);
337
+
338
+ if (delimiter == sbuffer[strlen(sbuffer)- 1])
339
+ {
340
+ fprintf(stderr, "lines must not end with the delimiter character\n");
341
+ return EXIT_FAILURE;
342
+
343
+ }
344
+
345
+ /* count columns and verify consistency*/
346
+
347
+ n_columns = strnchr(sbuffer, delimiter);
348
+
349
+ if (n_columns > MAX_COLUMNS)
350
+ {
351
+ fprintf(stderr, "too many columns, maximum is %i\n", MAX_COLUMNS);
352
+ return EXIT_FAILURE;
353
+ }
354
+
355
+ n_line = 1;
356
+
357
+ while (!feof(csv_f))
358
+ {
359
+ n_line++;
360
+ fgets(sbuffer, 4000, csv_f);
361
+ if (n_columns != strnchr(sbuffer, delimiter))
362
+ {
363
+ fprintf(stderr, "Number of columns on row %i does not match number of columns on row 1\n", n_columns);
364
+ return EXIT_FAILURE;
365
+ }
366
+ }
367
+
368
+ /* identify longitude and latitude columns */
369
+
370
+ fseek(csv_f, 0, SEEK_SET);
371
+ fgets(sbuffer, 4000, csv_f);
372
+ strip_crlf(sbuffer);
373
+
374
+ for (x = 0; x <= n_columns; x++)
375
+ {
376
+ if (0 == strcasecmp("Longitude", delimited_column(sbuffer, delimiter, x)))
377
+ {
378
+ n_longitude = x;
379
+ }
380
+
381
+ if (0 == strcasecmp("Latitude", delimited_column(sbuffer, delimiter, x)))
382
+ {
383
+ n_latitude = x;
384
+ }
385
+ }
386
+
387
+ #ifdef DEBUG
388
+ printf("debug lat/long = %i/%i\n", n_latitude, n_longitude);
389
+ #endif
390
+
391
+ if (-1 == n_longitude || -1 == n_latitude)
392
+ {
393
+ fprintf(stderr, "The header row must define one each a column named longitude and latitude\n");
394
+ return EXIT_FAILURE;
395
+ }
396
+
397
+ /* determine best fit for each column */
398
+
399
+ printf ("Anaylzing column types...\n");
400
+
401
+ #ifdef DEBUG
402
+ printf("debug: string type = %i\n", FTString);
403
+ printf("debug: int type = %i\n", FTInteger);
404
+ printf("debug: double type = %i\n", FTDouble);
405
+ #endif
406
+ for (x = 0; x <= n_columns; x++)
407
+ {
408
+ #ifdef DEBUG
409
+ printf("debug: examining column %i\n", x);
410
+ #endif
411
+ columns[x].eType = FTInteger;
412
+ columns[x].nWidth = 2;
413
+ columns[x].nDecimals = 0;
414
+
415
+ fseek(csv_f, 0, SEEK_SET);
416
+ fgets(sbuffer, 4000, csv_f);
417
+
418
+ while (!feof(csv_f))
419
+ {
420
+ char szfield[4096];
421
+ #ifdef DEBUG
422
+ printf ("column %i, type = %i, w = %i, d = %i\n", x, columns[x].eType, columns[x].nWidth, columns[x].nDecimals);
423
+ #endif
424
+ if (NULL == fgets(sbuffer, 4000, csv_f))
425
+ {
426
+ if (!feof(csv_f))
427
+ {
428
+ fprintf(stderr, "error during fgets()\n");
429
+ }
430
+ continue;
431
+ }
432
+ strcpy(szfield, delimited_column(sbuffer, delimiter, x));
433
+ if (more_general_field_type(str_to_fieldtype(szfield), columns[x].eType))
434
+ {
435
+ columns[x].eType = str_to_fieldtype(szfield);
436
+ columns[x].nWidth = 2;
437
+ columns[x].nDecimals = 0;
438
+ fseek(csv_f, 0, SEEK_SET);
439
+ fgets(sbuffer, 4000, csv_f);
440
+ continue;
441
+ }
442
+ if (columns[x].nWidth < str_to_nwidth(szfield, columns[x].eType))
443
+ {
444
+ columns[x].nWidth = str_to_nwidth(szfield, columns[x].eType);
445
+ }
446
+ if (FTDouble == columns[x].eType && columns[x].nDecimals < str_to_ndecimals(szfield))
447
+ {
448
+ columns[x].nDecimals = str_to_ndecimals(szfield);
449
+ }
450
+
451
+ }
452
+ }
453
+
454
+
455
+ /* initilize output files */
456
+
457
+ printf ("Initializing output files...\n");
458
+
459
+ shp_h = SHPCreate(argv[3], SHPT_POINT);
460
+
461
+ dbf_h = DBFCreate(argv[3]);
462
+
463
+ if (NULL == dbf_h)
464
+ {
465
+ fprintf(stderr, "DBFCreate failed\n");
466
+ exit (EXIT_FAILURE);
467
+ }
468
+
469
+ fseek(csv_f, 0, SEEK_SET);
470
+ fgets(sbuffer, 4000, csv_f);
471
+ strip_crlf(sbuffer);
472
+
473
+ for (x = 0; x <= n_columns; x++)
474
+ {
475
+ #ifdef DEBUG
476
+ printf ("debug: final: column %i, type = %i, w = %i, d = %i, name=|%s|\n", x, columns[x].eType, columns[x].nWidth, columns[x].nDecimals, delimited_column(sbuffer, delimiter, x));
477
+ #endif
478
+ if (-1 == DBFAddField(dbf_h, delimited_column(sbuffer, delimiter, x), columns[x].eType, columns[x].nWidth, columns[x].nDecimals))
479
+ {
480
+ fprintf(stderr, "DBFFieldAdd failed column %i\n", x + 1);
481
+ exit (EXIT_FAILURE);
482
+ }
483
+
484
+ }
485
+
486
+ /* write data */
487
+
488
+ printf ("Writing data...\n");
489
+
490
+ fseek(csv_f, 0, SEEK_SET);
491
+ fgets(sbuffer, 4000, csv_f); /* skip header */
492
+
493
+ n_columns = strnchr(sbuffer, delimiter);
494
+ n_line = 1;
495
+
496
+ while (!feof(csv_f))
497
+ {
498
+ SHPObject * shp;
499
+ double x_pt;
500
+ double y_pt;
501
+ int shp_i;
502
+
503
+ n_line++;
504
+ fgets(sbuffer, 4000, csv_f);
505
+
506
+ /* write to shape file */
507
+ x_pt = atof(delimited_column(sbuffer, delimiter, n_longitude));
508
+ y_pt = atof(delimited_column(sbuffer, delimiter, n_latitude));
509
+
510
+ #ifdef DEBUG
511
+ printf("debug: sbuffer=%s", sbuffer);
512
+ printf("debug: x,y = %f, %f\n", x_pt, y_pt);
513
+ #endif
514
+
515
+ shp = SHPCreateSimpleObject(SHPT_POINT, 1, &x_pt, &y_pt, NULL);
516
+ shp_i = SHPWriteObject(shp_h, -1, shp);
517
+ SHPDestroyObject(shp);
518
+
519
+ /* write to dbf */
520
+
521
+ for (x = 0; x <= n_columns; x++)
522
+ {
523
+ char szfield[4096];
524
+ int b;
525
+
526
+ strcpy(szfield, delimited_column(sbuffer, delimiter, x));
527
+
528
+ switch (columns[x].eType)
529
+ {
530
+ case FTInteger:
531
+ b = DBFWriteIntegerAttribute(dbf_h, shp_i, x, atoi(szfield));
532
+ break;
533
+ case FTDouble:
534
+ b = DBFWriteDoubleAttribute(dbf_h, shp_i, x, atof(szfield));
535
+ break;
536
+ case FTString:
537
+ b = DBFWriteStringAttribute(dbf_h, shp_i, x, szfield);
538
+ break;
539
+ default:
540
+ fprintf(stderr, "unexpected column type %i in column %i\n", columns[x].eType, x);
541
+ }
542
+
543
+ if (!b)
544
+ {
545
+ fprintf(stderr, "DBFWrite*Attribute failed\n");
546
+ exit (EXIT_FAILURE);
547
+ }
548
+ }
549
+ }
550
+
551
+ /* finish up */
552
+
553
+ SHPClose(shp_h);
554
+
555
+ DBFClose(dbf_h);
556
+
557
+ return EXIT_SUCCESS;
558
+ }