shapelib 0.7.0 → 0.8.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.
- checksums.yaml +7 -0
- data/LICENSE +36 -0
- data/LICENSE-CC-BY-SA-3.0 +375 -0
- data/LICENSE-LGPL +481 -0
- data/LICENSE-MIT +21 -0
- data/README.md +75 -24
- data/Rakefile +142 -32
- data/doc/Interface.html +53 -32
- data/doc/Interface.rd +51 -30
- data/ext/shapelib_ext/extconf.rb +5 -1
- data/ext/shapelib_ext/main.c +37 -0
- data/ext/shapelib_ext/sfcode.h +67 -39
- data/ext/shapelib_ext/sflist.h +18 -18
- data/ext/shapelib_ext/shpplus.c +245 -57
- data/ext/shapelib_ext/shpplus.h +1 -0
- data/ext/shapelib_ext/spcode.h +245 -126
- data/ext/shapelib_ext/splist.h +23 -41
- data/ext/shapelib_ext/spwkt.h +29 -24
- data/ext/shapelib_ext/valconv.h +33 -21
- data/lib/shapelib/shape.rb +8 -1
- data/lib/shapelib/version.rb +4 -2
- data/lib/shapelib.rb +2 -1
- data/shapelib.gemspec +58 -0
- data/test/data/ZillowNeighborhoods-CA/ZillowNeighborhoods-CA.dbf +0 -0
- data/test/data/ZillowNeighborhoods-CA/ZillowNeighborhoods-CA.prj +1 -0
- data/test/data/ZillowNeighborhoods-CA/ZillowNeighborhoods-CA.shp +0 -0
- data/test/data/ZillowNeighborhoods-CA/ZillowNeighborhoods-CA.shp.xml +3 -0
- data/test/data/ZillowNeighborhoods-CA/ZillowNeighborhoods-CA.shx +0 -0
- data/test/test_zillow_data.rb +2233 -0
- metadata +70 -65
- data/test/libtest.rb +0 -80
- data/test/zsample1.rb +0 -168
- data/test/ztest1.rb +0 -253
data/ext/shapelib_ext/spcode.h
CHANGED
|
@@ -3,35 +3,72 @@
|
|
|
3
3
|
*/
|
|
4
4
|
#define NUM2DBLo(val) (NIL_P((val)) ? 0.0 : NUM2DBL((val)))
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
struct shape_wrap_args {
|
|
7
|
+
VALUE klass;
|
|
8
|
+
shape_t *shape;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
static VALUE WrapShapeProtected(VALUE ptr)
|
|
12
|
+
{
|
|
13
|
+
struct shape_wrap_args *args = (struct shape_wrap_args *)ptr;
|
|
14
|
+
return TypedData_Wrap_Struct(args->klass, &shape_data_type, args->shape);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static VALUE WrapShape(VALUE klass, shape_t *shape)
|
|
18
|
+
{
|
|
19
|
+
struct shape_wrap_args args = { klass, shape };
|
|
20
|
+
int state;
|
|
21
|
+
VALUE obj;
|
|
22
|
+
if (shape == NULL)
|
|
23
|
+
rb_raise(rb_eRuntimeError, "SHPCreateObject fails");
|
|
24
|
+
obj = rb_protect(WrapShapeProtected, (VALUE)&args, &state);
|
|
25
|
+
if (state) {
|
|
26
|
+
shape_close(shape);
|
|
27
|
+
rb_jump_tag(state);
|
|
28
|
+
}
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static void CheckPartStarts(SHPObject *obj)
|
|
7
33
|
{
|
|
8
|
-
int *buf;
|
|
9
34
|
int i;
|
|
35
|
+
for (i = 0; i < obj->nParts; i++) {
|
|
36
|
+
if (obj->panPartStart[i] < 0 || obj->panPartStart[i] > obj->nVertices)
|
|
37
|
+
rb_raise(rb_eArgError, "part_start[%d] must be between 0 and %d", i, obj->nVertices);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static void CheckPointVertices(SHPObject *obj)
|
|
42
|
+
{
|
|
43
|
+
if (obj->nVertices < 1)
|
|
44
|
+
rb_raise(rb_eArgError, "point has no vertices");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static void IntPack(VALUE array, int decode_p, int *buf)
|
|
48
|
+
{
|
|
49
|
+
long i, length;
|
|
10
50
|
Check_Type(array, T_ARRAY);
|
|
11
|
-
|
|
12
|
-
for (i = 0; i <
|
|
51
|
+
length = RARRAY_LEN(array);
|
|
52
|
+
for (i = 0; i < length; i++) {
|
|
13
53
|
if (decode_p)
|
|
14
54
|
buf[i] = Ruby2PartType(RARRAY_PTR(array)[i]);
|
|
15
55
|
else
|
|
16
56
|
buf[i] = NUM2INT(RARRAY_PTR(array)[i]);
|
|
17
57
|
}
|
|
18
|
-
return buf;
|
|
19
58
|
}
|
|
20
59
|
|
|
21
|
-
static
|
|
60
|
+
static void DoublePack(VALUE array, double nilval, double *buf)
|
|
22
61
|
{
|
|
23
|
-
|
|
24
|
-
int i;
|
|
62
|
+
long i, length;
|
|
25
63
|
if (NIL_P(array))
|
|
26
|
-
return
|
|
64
|
+
return;
|
|
27
65
|
Check_Type(array, T_ARRAY);
|
|
28
|
-
|
|
29
|
-
for (i = 0; i <
|
|
66
|
+
length = RARRAY_LEN(array);
|
|
67
|
+
for (i = 0; i < length; i++) {
|
|
30
68
|
VALUE v;
|
|
31
69
|
v = RARRAY_PTR(array)[i];
|
|
32
70
|
buf[i] = (NIL_P(v) ? nilval : NUM2DBL(RARRAY_PTR(array)[i]));
|
|
33
71
|
}
|
|
34
|
-
return buf;
|
|
35
72
|
}
|
|
36
73
|
|
|
37
74
|
static VALUE HashDeref(VALUE hash, const char *key)
|
|
@@ -42,12 +79,19 @@ static VALUE HashDeref(VALUE hash, const char *key)
|
|
|
42
79
|
static ID op = 0;
|
|
43
80
|
if (op == 0)
|
|
44
81
|
op = rb_intern("[]");
|
|
45
|
-
return rb_funcall(hash, op, CSTR2SYM(key));
|
|
82
|
+
return rb_funcall(hash, op, 1, CSTR2SYM(key));
|
|
46
83
|
}
|
|
47
84
|
}
|
|
48
85
|
|
|
49
86
|
static VALUE sp_field_set(VALUE obj, VALUE name, VALUE val);
|
|
50
87
|
|
|
88
|
+
static void CheckArrayLength(VALUE array, int count, const char *name)
|
|
89
|
+
{
|
|
90
|
+
Check_Type(array, T_ARRAY);
|
|
91
|
+
if (RARRAY_LEN(array) < count)
|
|
92
|
+
rb_raise(rb_eArgError, "%s must contain at least %d entries", name, count);
|
|
93
|
+
}
|
|
94
|
+
|
|
51
95
|
static void HashLoadAttrib(VALUE vshape, VALUE hash)
|
|
52
96
|
{
|
|
53
97
|
VALUE ary, *argv;
|
|
@@ -79,6 +123,10 @@ static VALUE sp_s_new(VALUE klass, VALUE hash)
|
|
|
79
123
|
{
|
|
80
124
|
shape_t *shape;
|
|
81
125
|
VALUE qlass, vshape;
|
|
126
|
+
VALUE arrays[6];
|
|
127
|
+
VALUE storage[6] = { 0 };
|
|
128
|
+
static const char *array_names[] = { "part_type", "part_start", "xvals", "yvals", "zvals", "mvals" };
|
|
129
|
+
int i;
|
|
82
130
|
int shape_type, shape_id, n_parts, n_vertices;
|
|
83
131
|
int *part_type, *part_start;
|
|
84
132
|
double *xvals, *yvals, *zvals, *mvals;
|
|
@@ -87,43 +135,72 @@ static VALUE sp_s_new(VALUE klass, VALUE hash)
|
|
|
87
135
|
shape_id = NUM2INT_nil(HashDeref(hash, "shape_id"));
|
|
88
136
|
n_parts = NUM2INT(HashDeref(hash, "n_parts"));
|
|
89
137
|
n_vertices = NUM2INT(HashDeref(hash, "n_vertices"));
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
138
|
+
if (n_parts < 0) rb_raise(rb_eArgError, "n_parts must be nonnegative");
|
|
139
|
+
if (n_vertices < 0) rb_raise(rb_eArgError, "n_vertices must be nonnegative");
|
|
140
|
+
for (i = 0; i < 6; i++)
|
|
141
|
+
arrays[i] = HashDeref(hash, array_names[i]);
|
|
142
|
+
/* Numeric conversion can mutate any of the caller's arrays. */
|
|
143
|
+
for (i = 0; i < 6; i++) {
|
|
144
|
+
if (i < 2 && n_parts == 0 && NIL_P(arrays[i]))
|
|
145
|
+
arrays[i] = rb_ary_new();
|
|
146
|
+
if (!NIL_P(arrays[i])) {
|
|
147
|
+
Check_Type(arrays[i], T_ARRAY);
|
|
148
|
+
arrays[i] = rb_ary_dup(arrays[i]);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
for (i = 0; i < 6; i++) {
|
|
152
|
+
if (i < 2 || !NIL_P(arrays[i]))
|
|
153
|
+
CheckArrayLength(arrays[i], i < 2 ? n_parts : n_vertices, array_names[i]);
|
|
154
|
+
}
|
|
155
|
+
if (NIL_P(arrays[4])) rb_raise(rb_eRuntimeError, "missing zvals");
|
|
156
|
+
if (NIL_P(arrays[5])) rb_raise(rb_eRuntimeError, "missing mvals");
|
|
157
|
+
/* Allocate here: ALLOCV_N may use this constructor's stack frame. */
|
|
158
|
+
part_type = ALLOCV_N(int, storage[0], RARRAY_LEN(arrays[0]));
|
|
159
|
+
IntPack(arrays[0], 1, part_type);
|
|
160
|
+
part_start = ALLOCV_N(int, storage[1], RARRAY_LEN(arrays[1]));
|
|
161
|
+
IntPack(arrays[1], 0, part_start);
|
|
162
|
+
xvals = NIL_P(arrays[2]) ? NULL : ALLOCV_N(double, storage[2], RARRAY_LEN(arrays[2]));
|
|
163
|
+
DoublePack(arrays[2], 0.0, xvals);
|
|
164
|
+
yvals = NIL_P(arrays[3]) ? NULL : ALLOCV_N(double, storage[3], RARRAY_LEN(arrays[3]));
|
|
165
|
+
DoublePack(arrays[3], 0.0, yvals);
|
|
166
|
+
zvals = ALLOCV_N(double, storage[4], RARRAY_LEN(arrays[4]));
|
|
167
|
+
DoublePack(arrays[4], 0.0, zvals);
|
|
168
|
+
mvals = ALLOCV_N(double, storage[5], RARRAY_LEN(arrays[5]));
|
|
169
|
+
DoublePack(arrays[5], SHP_NODATA, mvals);
|
|
170
|
+
shape = shape_new(shape_type, shape_id, n_parts, part_type, part_start, n_vertices, xvals, yvals, zvals, mvals);
|
|
171
|
+
for (i = 0; i < 6; i++) {
|
|
172
|
+
ALLOCV_END(storage[i]);
|
|
173
|
+
RB_GC_GUARD(arrays[i]);
|
|
174
|
+
}
|
|
175
|
+
vshape = WrapShape(qlass, shape);
|
|
176
|
+
CheckPartStarts(shape->obj);
|
|
109
177
|
HashLoadAttrib(vshape, hash);
|
|
110
178
|
return vshape;
|
|
111
179
|
}
|
|
112
180
|
|
|
113
|
-
|
|
114
|
-
|
|
181
|
+
/* Snapshot all coordinate arrays before any numeric conversion can mutate them. */
|
|
182
|
+
static VALUE SnapshotPoints(VALUE points)
|
|
183
|
+
{
|
|
184
|
+
VALUE snapshot = rb_ary_dup(points);
|
|
185
|
+
long i;
|
|
186
|
+
for (i = 0; i < RARRAY_LEN(snapshot); i++) {
|
|
187
|
+
VALUE point = rb_ary_entry(snapshot, i);
|
|
188
|
+
if (T_ARRAY == TYPE(point))
|
|
189
|
+
rb_ary_store(snapshot, i, rb_ary_dup(point));
|
|
190
|
+
}
|
|
191
|
+
return snapshot;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static int CheckPartSize(VALUE parts, int *part_start, int *part_type)
|
|
115
195
|
{
|
|
116
196
|
int pstart = 0;
|
|
117
197
|
int i;
|
|
118
|
-
for (i = 0; i <
|
|
198
|
+
for (i = 0; i < RARRAY_LEN(parts); i++) {
|
|
199
|
+
VALUE part = rb_ary_entry(parts, i);
|
|
119
200
|
VALUE first;
|
|
120
201
|
int partlen;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return -1;
|
|
124
|
-
}
|
|
125
|
-
partlen = RARRAY_LEN(argv[i]);
|
|
126
|
-
first = RARRAY_PTR(argv[i])[0];
|
|
202
|
+
partlen = RARRAY_LEN(part);
|
|
203
|
+
first = rb_ary_entry(part, 0);
|
|
127
204
|
switch (TYPE(first)) {
|
|
128
205
|
case T_SYMBOL: case T_STRING:
|
|
129
206
|
part_type[i] = Ruby2PartType(first);
|
|
@@ -140,8 +217,7 @@ static int CheckPartSize(int argc, VALUE *argv, int *part_start,
|
|
|
140
217
|
return pstart;
|
|
141
218
|
}
|
|
142
219
|
|
|
143
|
-
static void ExtractXYMZ(VALUE v,
|
|
144
|
-
double *x, double *y, double *m, double *z)
|
|
220
|
+
static void ExtractXYMZ(VALUE v, double *x, double *y, double *m, double *z)
|
|
145
221
|
{
|
|
146
222
|
static int idx = 0, idy, idz, idm;
|
|
147
223
|
if (idx == 0) {
|
|
@@ -150,11 +226,10 @@ static void ExtractXYMZ(VALUE v,
|
|
|
150
226
|
}
|
|
151
227
|
if (T_ARRAY == TYPE(v)) {
|
|
152
228
|
int argc = RARRAY_LEN(v);
|
|
153
|
-
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*z = (argc > 3) ? NUM2DBL(argv[3]) : 0.0;
|
|
229
|
+
*x = (argc > 0) ? NUM2DBLo(rb_ary_entry(v, 0)) : 0.0;
|
|
230
|
+
*y = (argc > 1) ? NUM2DBLo(rb_ary_entry(v, 1)) : 0.0;
|
|
231
|
+
*m = SHP_NUM2DBL((argc > 2) ? rb_ary_entry(v, 2) : Qnil);
|
|
232
|
+
*z = (argc > 3) ? NUM2DBL(rb_ary_entry(v, 3)) : 0.0;
|
|
158
233
|
} else {
|
|
159
234
|
*x = NUM2DBLo(rb_funcall(v, idx, 0));
|
|
160
235
|
*y = NUM2DBLo(rb_funcall(v, idy, 0));
|
|
@@ -171,78 +246,92 @@ static void ExtractXYMZ(VALUE v,
|
|
|
171
246
|
}
|
|
172
247
|
}
|
|
173
248
|
|
|
174
|
-
static void CollectPoints(
|
|
175
|
-
double *x, double *y, double *m, double *z)
|
|
249
|
+
static void CollectPoints(VALUE points, double *x, double *y, double *m, double *z)
|
|
176
250
|
{
|
|
177
251
|
int i, ofs;
|
|
252
|
+
int argc = RARRAY_LEN(points);
|
|
178
253
|
ofs = 0;
|
|
179
254
|
if (argc > 0) {
|
|
180
|
-
switch (TYPE(
|
|
255
|
+
switch (TYPE(rb_ary_entry(points, 0))) {
|
|
181
256
|
case T_SYMBOL: case T_STRING:
|
|
182
257
|
ofs++;
|
|
183
258
|
}
|
|
184
259
|
}
|
|
185
260
|
for (i = 0; i < argc - ofs; i++) {
|
|
186
|
-
ExtractXYMZ(
|
|
261
|
+
ExtractXYMZ(rb_ary_entry(points, i + ofs), x + i, y + i, m + i, z + i);
|
|
187
262
|
}
|
|
188
263
|
}
|
|
189
264
|
|
|
190
265
|
static shape_t *NewMultiPart(int argc, VALUE *argv, VALUE klass, int shapetype)
|
|
191
266
|
{
|
|
192
267
|
shape_t *shape;
|
|
268
|
+
VALUE parts = rb_ary_new4(argc, argv);
|
|
269
|
+
VALUE part_start_storage = 0, part_type_storage = 0, dblock_storage = 0;
|
|
193
270
|
double *dblock, *x, *y, *m, *z;
|
|
194
271
|
int *part_start, *part_type;
|
|
195
272
|
int n_parts, n_vert;
|
|
196
273
|
int ipart;
|
|
197
274
|
|
|
275
|
+
for (ipart = 0; ipart < argc; ipart++) {
|
|
276
|
+
VALUE part = rb_ary_entry(parts, ipart);
|
|
277
|
+
if (T_ARRAY != TYPE(part))
|
|
278
|
+
rb_raise(rb_eArgError, "arg %d must be Array", ipart);
|
|
279
|
+
if (RARRAY_LEN(part) == 0)
|
|
280
|
+
rb_raise(rb_eArgError, "part %d must not be empty", ipart);
|
|
281
|
+
rb_ary_store(parts, ipart, SnapshotPoints(part));
|
|
282
|
+
}
|
|
198
283
|
n_parts = argc;
|
|
199
|
-
part_start =
|
|
200
|
-
part_type =
|
|
201
|
-
n_vert = CheckPartSize(
|
|
202
|
-
dblock =
|
|
284
|
+
part_start = ALLOCV_N(int, part_start_storage, n_parts);
|
|
285
|
+
part_type = ALLOCV_N(int, part_type_storage, n_parts);
|
|
286
|
+
n_vert = CheckPartSize(parts, part_start, part_type);
|
|
287
|
+
dblock = ALLOCV_N(double, dblock_storage, (size_t)n_vert * 4);
|
|
203
288
|
x = dblock;
|
|
204
289
|
y = dblock + n_vert;
|
|
205
290
|
m = dblock + n_vert * 2;
|
|
206
291
|
z = dblock + n_vert * 3;
|
|
207
292
|
for (ipart = 0; ipart < argc; ipart++) {
|
|
208
293
|
CollectPoints(
|
|
209
|
-
|
|
294
|
+
rb_ary_entry(parts, ipart),
|
|
210
295
|
x + part_start[ipart], y + part_start[ipart],
|
|
211
296
|
m + part_start[ipart], z + part_start[ipart]);
|
|
212
297
|
}
|
|
213
298
|
shape = shape_new_obj(shapetype,
|
|
214
299
|
n_parts, part_start, part_type, n_vert,
|
|
215
300
|
x, y, m, z);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
301
|
+
ALLOCV_END(dblock_storage);
|
|
302
|
+
ALLOCV_END(part_start_storage);
|
|
303
|
+
ALLOCV_END(part_type_storage);
|
|
304
|
+
RB_GC_GUARD(parts);
|
|
219
305
|
return shape;
|
|
220
306
|
}
|
|
221
307
|
|
|
222
308
|
static shape_t *NewSinglePart(int argc, VALUE *argv, VALUE klass, int shapetype)
|
|
223
309
|
{
|
|
224
310
|
shape_t *shape;
|
|
311
|
+
VALUE points = SnapshotPoints(rb_ary_new4(argc, argv));
|
|
312
|
+
VALUE storage = 0;
|
|
225
313
|
double *dblock, *x, *y, *m, *z;
|
|
226
314
|
int n_vert, part_type_buf;
|
|
227
315
|
int part_start_buf = 0;
|
|
228
316
|
n_vert = argc;
|
|
229
|
-
switch (TYPE(
|
|
317
|
+
switch (TYPE(rb_ary_entry(points, 0))) {
|
|
230
318
|
case T_STRING: case T_SYMBOL:
|
|
231
|
-
part_type_buf = Ruby2PartType(
|
|
319
|
+
part_type_buf = Ruby2PartType(rb_ary_entry(points, 0));
|
|
232
320
|
n_vert--;
|
|
233
321
|
break;
|
|
234
322
|
default:
|
|
235
323
|
part_type_buf = SHPP_RING;
|
|
236
324
|
}
|
|
237
|
-
dblock =
|
|
325
|
+
dblock = ALLOCV_N(double, storage, (size_t)n_vert * 4);
|
|
238
326
|
x = dblock;
|
|
239
327
|
y = dblock + n_vert;
|
|
240
328
|
m = dblock + n_vert * 2;
|
|
241
329
|
z = dblock + n_vert * 3;
|
|
242
|
-
CollectPoints(
|
|
330
|
+
CollectPoints(points, x, y, m, z);
|
|
243
331
|
shape = shape_new_obj(shapetype,
|
|
244
332
|
1, &part_start_buf, &part_type_buf, n_vert, x, y, m, z);
|
|
245
|
-
|
|
333
|
+
ALLOCV_END(storage);
|
|
334
|
+
RB_GC_GUARD(points);
|
|
246
335
|
return shape;
|
|
247
336
|
}
|
|
248
337
|
|
|
@@ -262,16 +351,13 @@ static VALUE NewShape(int argc, VALUE *argv, VALUE klass, int shapetype)
|
|
|
262
351
|
shape_t *shape;
|
|
263
352
|
int multipart;
|
|
264
353
|
monitor(("NewShape"));
|
|
354
|
+
if (argc == 0)
|
|
355
|
+
rb_raise(rb_eArgError, "at least one point is required");
|
|
265
356
|
if (T_ARRAY == TYPE(argv[0])) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
break;
|
|
271
|
-
default:
|
|
272
|
-
multipart = 1;
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
357
|
+
VALUE first = rb_ary_entry(argv[0], 0);
|
|
358
|
+
if (RARRAY_LEN(argv[0]) == 0)
|
|
359
|
+
rb_raise(rb_eArgError, "first geometry array must not be empty");
|
|
360
|
+
multipart = !(RB_INTEGER_TYPE_P(first) || RB_TYPE_P(first, T_FLOAT));
|
|
275
361
|
} else {
|
|
276
362
|
multipart = 0;
|
|
277
363
|
}
|
|
@@ -280,27 +366,42 @@ static VALUE NewShape(int argc, VALUE *argv, VALUE klass, int shapetype)
|
|
|
280
366
|
} else {
|
|
281
367
|
shape = NewSinglePart(argc, argv, klass, shapetype);
|
|
282
368
|
}
|
|
283
|
-
return
|
|
369
|
+
return WrapShape(klass, shape);
|
|
284
370
|
}
|
|
285
371
|
|
|
286
372
|
static VALUE MultiPointNew(int argc, VALUE *argv, VALUE klass, int shapetype)
|
|
287
373
|
{
|
|
288
374
|
shape_t *shape;
|
|
375
|
+
VALUE points = SnapshotPoints(rb_ary_new4(argc, argv));
|
|
376
|
+
VALUE storage = 0;
|
|
289
377
|
double *dblock, *x, *y, *m, *z;
|
|
290
378
|
int *part_start;
|
|
291
379
|
int n_vert;
|
|
292
380
|
int part_start_buf = 0;
|
|
381
|
+
if (argc == 1 && TYPE(rb_ary_entry(points, 0)) == T_ARRAY) {
|
|
382
|
+
/* Snapshot nested coordinates before point detection can invoke Ruby. */
|
|
383
|
+
VALUE candidate = SnapshotPoints(rb_ary_entry(points, 0));
|
|
384
|
+
VALUE first = rb_ary_entry(candidate, 0);
|
|
385
|
+
if (RARRAY_LEN(candidate) > 0 &&
|
|
386
|
+
(TYPE(first) == T_ARRAY ||
|
|
387
|
+
(rb_respond_to(first, rb_intern("x")) && rb_respond_to(first, rb_intern("y")))))
|
|
388
|
+
points = candidate;
|
|
389
|
+
RB_GC_GUARD(candidate);
|
|
390
|
+
}
|
|
391
|
+
if (TYPE(rb_ary_entry(points, 0)) == T_STRING || TYPE(rb_ary_entry(points, 0)) == T_SYMBOL)
|
|
392
|
+
rb_raise(rb_eArgError, "MultiPoint does not accept part type labels");
|
|
293
393
|
part_start = &part_start_buf;
|
|
294
|
-
n_vert =
|
|
295
|
-
dblock =
|
|
394
|
+
n_vert = RARRAY_LEN(points);
|
|
395
|
+
dblock = ALLOCV_N(double, storage, (size_t)n_vert * 4);
|
|
296
396
|
x = dblock;
|
|
297
397
|
y = dblock + n_vert;
|
|
298
398
|
m = dblock + n_vert * 2;
|
|
299
399
|
z = dblock + n_vert * 3;
|
|
300
|
-
CollectPoints(
|
|
400
|
+
CollectPoints(points, x, y, m, z);
|
|
301
401
|
shape = shape_new_obj(shapetype, 1, part_start, NULL, n_vert, x, y, m, z);
|
|
302
|
-
|
|
303
|
-
|
|
402
|
+
ALLOCV_END(storage);
|
|
403
|
+
RB_GC_GUARD(points);
|
|
404
|
+
return WrapShape(klass, shape);
|
|
304
405
|
}
|
|
305
406
|
|
|
306
407
|
static VALUE arc_s_new(int argc, VALUE *argv, VALUE klass) {
|
|
@@ -346,22 +447,21 @@ static VALUE mpz_s_new(int argc, VALUE *argv, VALUE klass) {
|
|
|
346
447
|
|
|
347
448
|
static void PointAddAttr(VALUE pt, VALUE attrs)
|
|
348
449
|
{
|
|
349
|
-
VALUE *argv;
|
|
350
450
|
VALUE ary;
|
|
351
451
|
int i, argc;
|
|
352
452
|
Check_Type(attrs, T_HASH);
|
|
353
453
|
ary = rb_funcall(attrs, rb_intern("to_a"), 0);
|
|
354
454
|
Check_Type(ary, T_ARRAY);
|
|
355
|
-
|
|
455
|
+
ary = SnapshotPoints(ary);
|
|
356
456
|
argc = RARRAY_LEN(ary);
|
|
357
457
|
for (i = 0; i < argc; i++) {
|
|
358
|
-
VALUE
|
|
359
|
-
Check_Type(
|
|
360
|
-
if (RARRAY_LEN(
|
|
361
|
-
|
|
362
|
-
pair
|
|
363
|
-
sp_field_set(pt, pair[0], pair[1]);
|
|
458
|
+
VALUE pair = rb_ary_entry(ary, i);
|
|
459
|
+
Check_Type(pair, T_ARRAY);
|
|
460
|
+
if (RARRAY_LEN(pair) != 2)
|
|
461
|
+
rb_raise(rb_eArgError, "attribute pair must contain exactly two entries");
|
|
462
|
+
sp_field_set(pt, rb_ary_entry(pair, 0), rb_ary_entry(pair, 1));
|
|
364
463
|
}
|
|
464
|
+
RB_GC_GUARD(ary);
|
|
365
465
|
}
|
|
366
466
|
|
|
367
467
|
|
|
@@ -372,7 +472,7 @@ static VALUE pt_s_new(int argc, VALUE *argv, VALUE klass)
|
|
|
372
472
|
rb_scan_args(argc, argv, "21", &vx, &vy, &attrs);
|
|
373
473
|
shape = shape_new_point(SHPT_POINT,
|
|
374
474
|
NUM2DBLo(vx), NUM2DBLo(vy), 0.0, 0.0);
|
|
375
|
-
pt =
|
|
475
|
+
pt = WrapShape(klass, shape);
|
|
376
476
|
if (!NIL_P(attrs)) {
|
|
377
477
|
PointAddAttr(pt, attrs);
|
|
378
478
|
}
|
|
@@ -386,7 +486,7 @@ static VALUE ptm_s_new(int argc, VALUE *argv, VALUE klass)
|
|
|
386
486
|
rb_scan_args(argc, argv, "31", &vx, &vy, &vm, &attrs);
|
|
387
487
|
shape = shape_new_point(SHPT_POINTM,
|
|
388
488
|
NUM2DBLo(vx), NUM2DBLo(vy), SHP_NUM2DBL(vm), 0.0);
|
|
389
|
-
pt =
|
|
489
|
+
pt = WrapShape(klass, shape);
|
|
390
490
|
if (!NIL_P(attrs)) {
|
|
391
491
|
PointAddAttr(pt, attrs);
|
|
392
492
|
}
|
|
@@ -400,25 +500,25 @@ static VALUE ptz_s_new(int argc, VALUE *argv, VALUE klass)
|
|
|
400
500
|
rb_scan_args(argc, argv, "41", &vx, &vy, &vm, &vz, &attrs);
|
|
401
501
|
shape = shape_new_point(SHPT_POINTZ,
|
|
402
502
|
NUM2DBLo(vx), NUM2DBLo(vy), SHP_NUM2DBL(vm), NUM2DBLo(vz));
|
|
403
|
-
pt =
|
|
503
|
+
pt = WrapShape(klass, shape);
|
|
404
504
|
if (!NIL_P(attrs)) {
|
|
405
505
|
PointAddAttr(pt, attrs);
|
|
406
506
|
}
|
|
407
507
|
return pt;
|
|
408
508
|
}
|
|
409
509
|
|
|
410
|
-
/*
|
|
510
|
+
/* Shapelib.new_point */
|
|
411
511
|
static VALUE sl_m_new_point(int argc, VALUE *argv, VALUE klass)
|
|
412
512
|
{
|
|
413
513
|
if (2 == argc || (3 == argc && T_HASH == TYPE(argv[2]))) {
|
|
414
514
|
return pt_s_new(argc, argv, cPoint);
|
|
415
|
-
} else if (3 == argc || (4 == argc && T_HASH
|
|
515
|
+
} else if (3 == argc || (4 == argc && (T_HASH == TYPE(argv[3]) || NIL_P(argv[3])))) {
|
|
416
516
|
return ptm_s_new(argc, argv, cPointM);
|
|
417
|
-
} else if (4 == argc ||
|
|
517
|
+
} else if (4 == argc || 5 == argc) {
|
|
418
518
|
return ptz_s_new(argc, argv, cPointZ);
|
|
419
519
|
} else {
|
|
420
520
|
rb_raise(rb_eArgError,
|
|
421
|
-
"usage:
|
|
521
|
+
"usage: Shapelib.new_point x, y, m, z, attr_array");
|
|
422
522
|
return Qnil;
|
|
423
523
|
}
|
|
424
524
|
}
|
|
@@ -431,7 +531,7 @@ static void Attr_to_Hash(VALUE h, VALUE obj)
|
|
|
431
531
|
{
|
|
432
532
|
shape_t *self;
|
|
433
533
|
int i;
|
|
434
|
-
|
|
534
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
435
535
|
if (self->nattr <= 0)
|
|
436
536
|
return;
|
|
437
537
|
for (i = 0; i < self->nattr; i++) {
|
|
@@ -466,8 +566,8 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
|
|
|
466
566
|
char *cname;
|
|
467
567
|
int ofs;
|
|
468
568
|
|
|
469
|
-
|
|
470
|
-
cname =
|
|
569
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
570
|
+
cname = StringValueCStr(name);
|
|
471
571
|
ofs = shape_attrib_index(self, cname, 0);
|
|
472
572
|
if (ofs < 0) {
|
|
473
573
|
return Qnil;
|
|
@@ -481,6 +581,9 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
|
|
|
481
581
|
return rb_float_new(self->attr[ofs].val.fval);
|
|
482
582
|
case FTString:
|
|
483
583
|
case FTLogical:
|
|
584
|
+
#ifdef HAVE_CONST_FTDATE
|
|
585
|
+
case FTDate:
|
|
586
|
+
#endif
|
|
484
587
|
return rb_str_new2(self->attr[ofs].val.sval);
|
|
485
588
|
default:
|
|
486
589
|
rb_raise(rb_eTypeError, "unacceptable field type");
|
|
@@ -491,35 +594,42 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
|
|
|
491
594
|
static VALUE sp_field_set(VALUE obj, VALUE name, VALUE val)
|
|
492
595
|
{
|
|
493
596
|
shape_t *self;
|
|
597
|
+
attrib_t replacement;
|
|
494
598
|
char *cname;
|
|
495
599
|
int ofs;
|
|
496
600
|
|
|
497
|
-
|
|
498
|
-
|
|
601
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
602
|
+
rb_check_frozen(obj);
|
|
603
|
+
cname = StringValueCStr(name);
|
|
604
|
+
rb_check_frozen(obj);
|
|
499
605
|
ofs = shape_attrib_index(self, cname, 1);
|
|
500
606
|
if (ofs < 0) {
|
|
501
607
|
return Qnil;
|
|
502
608
|
}
|
|
609
|
+
memset(&replacement.val, 0, sizeof(replacement.val));
|
|
503
610
|
switch (TYPE(val)) {
|
|
504
611
|
case T_STRING:
|
|
505
|
-
|
|
506
|
-
|
|
612
|
+
replacement.type = FTString;
|
|
613
|
+
replacement.val.sval = StringDup(StringValueCStr(val));
|
|
507
614
|
break;
|
|
508
615
|
case T_FIXNUM:
|
|
509
|
-
|
|
510
|
-
|
|
616
|
+
replacement.type = FTInteger;
|
|
617
|
+
replacement.val.ival = FIX2INT(val);
|
|
511
618
|
break;
|
|
512
619
|
case T_FLOAT:
|
|
513
|
-
|
|
514
|
-
|
|
620
|
+
replacement.type = FTDouble;
|
|
621
|
+
replacement.val.fval = RFLOAT_VALUE(val);
|
|
515
622
|
break;
|
|
516
623
|
case T_NIL:
|
|
517
|
-
|
|
624
|
+
replacement.type = -1;
|
|
518
625
|
break;
|
|
519
626
|
default:
|
|
520
627
|
rb_raise(rb_eTypeError,
|
|
521
628
|
"give me String, Integer, or Float");
|
|
522
629
|
}
|
|
630
|
+
shape_attrib_clear_value(&self->attr[ofs]);
|
|
631
|
+
self->attr[ofs].type = replacement.type;
|
|
632
|
+
self->attr[ofs].val = replacement.val;
|
|
523
633
|
return obj;
|
|
524
634
|
}
|
|
525
635
|
|
|
@@ -527,7 +637,7 @@ static VALUE sp_maxbound(VALUE obj)
|
|
|
527
637
|
{
|
|
528
638
|
shape_t *self;
|
|
529
639
|
double buf[4];
|
|
530
|
-
|
|
640
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
531
641
|
buf[0] = self->obj->dfXMax;
|
|
532
642
|
buf[1] = self->obj->dfYMax;
|
|
533
643
|
buf[2] = self->obj->dfMMax;
|
|
@@ -539,7 +649,7 @@ static VALUE sp_minbound(VALUE obj)
|
|
|
539
649
|
{
|
|
540
650
|
shape_t *self;
|
|
541
651
|
double buf[4];
|
|
542
|
-
|
|
652
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
543
653
|
buf[0] = self->obj->dfXMin;
|
|
544
654
|
buf[1] = self->obj->dfYMin;
|
|
545
655
|
buf[2] = self->obj->dfMMin;
|
|
@@ -550,28 +660,28 @@ static VALUE sp_minbound(VALUE obj)
|
|
|
550
660
|
static VALUE sp_mvals(VALUE obj)
|
|
551
661
|
{
|
|
552
662
|
shape_t *self;
|
|
553
|
-
|
|
663
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
554
664
|
return DoubleUnpackM(self->obj->padfM, self->obj->nVertices, -1);
|
|
555
665
|
}
|
|
556
666
|
|
|
557
667
|
static VALUE sp_n_parts(VALUE obj)
|
|
558
668
|
{
|
|
559
669
|
shape_t *self;
|
|
560
|
-
|
|
670
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
561
671
|
return INT2NUM(self->obj->nParts);
|
|
562
672
|
}
|
|
563
673
|
|
|
564
674
|
static VALUE sp_n_vertices(VALUE obj)
|
|
565
675
|
{
|
|
566
676
|
shape_t *self;
|
|
567
|
-
|
|
677
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
568
678
|
return INT2NUM(self->obj->nVertices);
|
|
569
679
|
}
|
|
570
680
|
|
|
571
681
|
static VALUE sp_part_start(VALUE obj)
|
|
572
682
|
{
|
|
573
683
|
shape_t *self;
|
|
574
|
-
|
|
684
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
575
685
|
if (self->obj->nParts == 0)
|
|
576
686
|
return Qnil;
|
|
577
687
|
return IntUnpack(self->obj->panPartStart, self->obj->nParts);
|
|
@@ -582,7 +692,7 @@ static VALUE sp_part_type(VALUE obj)
|
|
|
582
692
|
shape_t *self;
|
|
583
693
|
VALUE ary;
|
|
584
694
|
int i;
|
|
585
|
-
|
|
695
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
586
696
|
if (self->obj->nParts == 0)
|
|
587
697
|
return Qnil;
|
|
588
698
|
#if 0
|
|
@@ -598,42 +708,47 @@ static VALUE sp_part_type(VALUE obj)
|
|
|
598
708
|
static VALUE sp_shape_id(VALUE obj)
|
|
599
709
|
{
|
|
600
710
|
shape_t *self;
|
|
601
|
-
|
|
711
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
602
712
|
return (self->obj->nShapeId < 0) ? Qnil : INT2NUM(self->obj->nShapeId);
|
|
603
713
|
}
|
|
604
714
|
|
|
605
715
|
static VALUE sp_shape_type(VALUE obj)
|
|
606
716
|
{
|
|
607
717
|
shape_t *self;
|
|
608
|
-
|
|
718
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
609
719
|
return ShapeType2Ruby(self->obj->nSHPType);
|
|
610
720
|
}
|
|
611
721
|
|
|
612
722
|
static VALUE sp_rewind(VALUE obj)
|
|
613
723
|
{
|
|
614
724
|
shape_t *self;
|
|
615
|
-
|
|
616
|
-
|
|
725
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
726
|
+
rb_check_frozen(obj);
|
|
727
|
+
if (SHPRewindObject(NULL, self->obj)) {
|
|
728
|
+
rb_iv_set(obj, "@latlngs", Qnil);
|
|
729
|
+
return Qtrue;
|
|
730
|
+
}
|
|
731
|
+
return Qfalse;
|
|
617
732
|
}
|
|
618
733
|
|
|
619
734
|
static VALUE sp_xvals(VALUE obj)
|
|
620
735
|
{
|
|
621
736
|
shape_t *self;
|
|
622
|
-
|
|
737
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
623
738
|
return DoubleUnpack(self->obj->padfX, self->obj->nVertices);
|
|
624
739
|
}
|
|
625
740
|
|
|
626
741
|
static VALUE sp_yvals(VALUE obj)
|
|
627
742
|
{
|
|
628
743
|
shape_t *self;
|
|
629
|
-
|
|
744
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
630
745
|
return DoubleUnpack(self->obj->padfY, self->obj->nVertices);
|
|
631
746
|
}
|
|
632
747
|
|
|
633
748
|
static VALUE sp_zvals(VALUE obj)
|
|
634
749
|
{
|
|
635
750
|
shape_t *self;
|
|
636
|
-
|
|
751
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
637
752
|
return DoubleUnpack(self->obj->padfZ, self->obj->nVertices);
|
|
638
753
|
}
|
|
639
754
|
|
|
@@ -644,11 +759,12 @@ static VALUE sp_zvals(VALUE obj)
|
|
|
644
759
|
static VALUE pt_x(VALUE obj)
|
|
645
760
|
{
|
|
646
761
|
shape_t *self;
|
|
647
|
-
|
|
762
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
648
763
|
switch (self->obj->nSHPType) {
|
|
649
764
|
case SHPT_POINT:
|
|
650
765
|
case SHPT_POINTM:
|
|
651
766
|
case SHPT_POINTZ:
|
|
767
|
+
CheckPointVertices(self->obj);
|
|
652
768
|
return rb_float_new(self->obj->padfX[0]);
|
|
653
769
|
default:
|
|
654
770
|
rb_bug("shape type %d is not Point", self->obj->nSHPType);
|
|
@@ -659,11 +775,12 @@ static VALUE pt_x(VALUE obj)
|
|
|
659
775
|
static VALUE pt_y(VALUE obj)
|
|
660
776
|
{
|
|
661
777
|
shape_t *self;
|
|
662
|
-
|
|
778
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
663
779
|
switch (self->obj->nSHPType) {
|
|
664
780
|
case SHPT_POINT:
|
|
665
781
|
case SHPT_POINTM:
|
|
666
782
|
case SHPT_POINTZ:
|
|
783
|
+
CheckPointVertices(self->obj);
|
|
667
784
|
return rb_float_new(self->obj->padfY[0]);
|
|
668
785
|
default:
|
|
669
786
|
rb_bug("shape type %d is not Point", self->obj->nSHPType);
|
|
@@ -674,10 +791,11 @@ static VALUE pt_y(VALUE obj)
|
|
|
674
791
|
static VALUE pt_m(VALUE obj)
|
|
675
792
|
{
|
|
676
793
|
shape_t *self;
|
|
677
|
-
|
|
794
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
678
795
|
switch (self->obj->nSHPType) {
|
|
679
796
|
case SHPT_POINTM:
|
|
680
797
|
case SHPT_POINTZ:
|
|
798
|
+
CheckPointVertices(self->obj);
|
|
681
799
|
return SHP_FLOAT_NEW(self->obj->padfM[0]);
|
|
682
800
|
case SHPT_POINT:
|
|
683
801
|
return Qnil;
|
|
@@ -690,10 +808,11 @@ static VALUE pt_m(VALUE obj)
|
|
|
690
808
|
static VALUE pt_z(VALUE obj)
|
|
691
809
|
{
|
|
692
810
|
shape_t *self;
|
|
693
|
-
|
|
811
|
+
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
694
812
|
switch (self->obj->nSHPType) {
|
|
695
813
|
case SHPT_POINTZ:
|
|
696
|
-
|
|
814
|
+
CheckPointVertices(self->obj);
|
|
815
|
+
return rb_float_new(self->obj->padfZ[0]);
|
|
697
816
|
case SHPT_POINTM:
|
|
698
817
|
case SHPT_POINT:
|
|
699
818
|
return Qnil;
|