shapelib 0.7.2 → 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 +4 -4
- 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 +71 -4
- data/Rakefile +142 -33
- 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 +3 -0
- data/ext/shapelib_ext/sfcode.h +49 -17
- 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 +225 -106
- data/ext/shapelib_ext/splist.h +23 -23
- data/ext/shapelib_ext/spwkt.h +24 -19
- data/ext/shapelib_ext/valconv.h +33 -12
- data/lib/shapelib/shape.rb +4 -1
- data/lib/shapelib/version.rb +3 -1
- data/lib/shapelib.rb +2 -1
- data/shapelib.gemspec +49 -49
- data/test/test_zillow_data.rb +2217 -1
- metadata +31 -9
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
|
}
|
|
@@ -467,7 +567,7 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
|
|
|
467
567
|
int ofs;
|
|
468
568
|
|
|
469
569
|
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
470
|
-
cname =
|
|
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
601
|
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
498
|
-
|
|
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
|
|
|
@@ -613,7 +723,12 @@ static VALUE sp_rewind(VALUE obj)
|
|
|
613
723
|
{
|
|
614
724
|
shape_t *self;
|
|
615
725
|
TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
|
|
616
|
-
|
|
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)
|
|
@@ -649,6 +764,7 @@ static VALUE pt_x(VALUE obj)
|
|
|
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);
|
|
@@ -664,6 +780,7 @@ static VALUE pt_y(VALUE obj)
|
|
|
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);
|
|
@@ -678,6 +795,7 @@ static VALUE pt_m(VALUE obj)
|
|
|
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;
|
|
@@ -693,7 +811,8 @@ static VALUE pt_z(VALUE obj)
|
|
|
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;
|
data/ext/shapelib_ext/splist.h
CHANGED
|
@@ -22,32 +22,32 @@ static VALUE sp_to_h(VALUE obj)
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
static method_table_entry sp_methods[] = {
|
|
25
|
-
{ "[]", sp_field_get, 1 },
|
|
26
|
-
{ "[]=", sp_field_set, 2 },
|
|
27
|
-
{ "maxbound", sp_maxbound, 0 },
|
|
28
|
-
{ "minbound", sp_minbound, 0 },
|
|
29
|
-
{ "mvals", sp_mvals, 0 },
|
|
30
|
-
{ "n_parts", sp_n_parts, 0 },
|
|
31
|
-
{ "n_vertices", sp_n_vertices, 0 },
|
|
32
|
-
{ "part_start", sp_part_start, 0 },
|
|
33
|
-
{ "part_type", sp_part_type, 0 },
|
|
34
|
-
{ "shape_type", sp_shape_type, 0 },
|
|
35
|
-
{ "shape_id", sp_shape_id, 0 },
|
|
36
|
-
{ "to_h", sp_to_h, 0 },
|
|
37
|
-
{ "to_s", sp_wkt, 0 },
|
|
38
|
-
{ "rewind_polygon", sp_rewind, 0 },
|
|
39
|
-
{ "wkt", sp_wkt, 0 },
|
|
40
|
-
{ "xvals", sp_xvals, 0 },
|
|
41
|
-
{ "yvals", sp_yvals, 0 },
|
|
42
|
-
{ "zvals", sp_zvals, 0 },
|
|
25
|
+
{ "[]", RUBY_METHOD_FUNC(sp_field_get), 1 },
|
|
26
|
+
{ "[]=", RUBY_METHOD_FUNC(sp_field_set), 2 },
|
|
27
|
+
{ "maxbound", RUBY_METHOD_FUNC(sp_maxbound), 0 },
|
|
28
|
+
{ "minbound", RUBY_METHOD_FUNC(sp_minbound), 0 },
|
|
29
|
+
{ "mvals", RUBY_METHOD_FUNC(sp_mvals), 0 },
|
|
30
|
+
{ "n_parts", RUBY_METHOD_FUNC(sp_n_parts), 0 },
|
|
31
|
+
{ "n_vertices", RUBY_METHOD_FUNC(sp_n_vertices), 0 },
|
|
32
|
+
{ "part_start", RUBY_METHOD_FUNC(sp_part_start), 0 },
|
|
33
|
+
{ "part_type", RUBY_METHOD_FUNC(sp_part_type), 0 },
|
|
34
|
+
{ "shape_type", RUBY_METHOD_FUNC(sp_shape_type), 0 },
|
|
35
|
+
{ "shape_id", RUBY_METHOD_FUNC(sp_shape_id), 0 },
|
|
36
|
+
{ "to_h", RUBY_METHOD_FUNC(sp_to_h), 0 },
|
|
37
|
+
{ "to_s", RUBY_METHOD_FUNC(sp_wkt), 0 },
|
|
38
|
+
{ "rewind_polygon", RUBY_METHOD_FUNC(sp_rewind), 0 },
|
|
39
|
+
{ "wkt", RUBY_METHOD_FUNC(sp_wkt), 0 },
|
|
40
|
+
{ "xvals", RUBY_METHOD_FUNC(sp_xvals), 0 },
|
|
41
|
+
{ "yvals", RUBY_METHOD_FUNC(sp_yvals), 0 },
|
|
42
|
+
{ "zvals", RUBY_METHOD_FUNC(sp_zvals), 0 },
|
|
43
43
|
{ NULL, NULL, 0 }
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
static method_table_entry pt_methods[] = {
|
|
47
|
-
{ "m", pt_m, 0 },
|
|
48
|
-
{ "wkt", pt_wkt, 0 },
|
|
49
|
-
{ "x", pt_x, 0 },
|
|
50
|
-
{ "y", pt_y, 0 },
|
|
51
|
-
{ "z", pt_z, 0 },
|
|
47
|
+
{ "m", RUBY_METHOD_FUNC(pt_m), 0 },
|
|
48
|
+
{ "wkt", RUBY_METHOD_FUNC(pt_wkt), 0 },
|
|
49
|
+
{ "x", RUBY_METHOD_FUNC(pt_x), 0 },
|
|
50
|
+
{ "y", RUBY_METHOD_FUNC(pt_y), 0 },
|
|
51
|
+
{ "z", RUBY_METHOD_FUNC(pt_z), 0 },
|
|
52
52
|
{ NULL, NULL, 0 }
|
|
53
53
|
};
|