shp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }