librtree 0.8.5 → 0.8.9
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/ext/rtree/rtree.c +206 -92
- data/lib/rtree.rb +184 -11
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d796bcdad6e023f99009363c9c11a10d8c6dfc7b9c797b487925fa319ace78b9
|
4
|
+
data.tar.gz: 83d563781db1c1e1b6bd8b8790cbb68fbbd9a7f997dd49840ff8cba7bfcac3e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1a6c56ad9c14ae15c8ed047e980262477f36b672bb08c5cc584eff7b2fba3b20845e8671ee166f8929abbb5a7d11e596cca36da6d89a67cef167773ada20577
|
7
|
+
data.tar.gz: b699d85386e8ea991eb2d4e4816635b6a0d550e2dbeb36b670526186d0b72f72f8cf763d22ba6339fe595dc3f70c7d6f9e9bfa5714216ec125e0b1748c146d97
|
data/ext/rtree/rtree.c
CHANGED
@@ -4,48 +4,33 @@
|
|
4
4
|
|
5
5
|
#include <rtree.h>
|
6
6
|
#include <rtree/package.h>
|
7
|
+
#include <rtree/postscript.h>
|
7
8
|
|
8
9
|
#include <errno.h>
|
9
10
|
#include <stdint.h>
|
10
11
|
|
12
|
+
static rb_data_type_t style_type;
|
13
|
+
static rb_data_type_t rtree_type;
|
11
14
|
|
12
|
-
static void
|
15
|
+
static void rt_dfree(void *p)
|
13
16
|
{
|
14
17
|
rtree_destroy((rtree_t*)p);
|
15
18
|
}
|
16
19
|
|
17
|
-
static size_t
|
20
|
+
static size_t rt_dsize(const void *p)
|
18
21
|
{
|
19
22
|
return rtree_bytes((const rtree_t*)p);
|
20
23
|
}
|
21
24
|
|
22
|
-
static
|
23
|
-
.wrap_struct_name = "rtree-wrap",
|
24
|
-
.function = {
|
25
|
-
.dmark = NULL,
|
26
|
-
.dfree = lrt_dfree,
|
27
|
-
.dsize = lrt_dsize,
|
28
|
-
#if RUBY_API_VERSION_CODE < 20700
|
29
|
-
.reserved = { NULL, NULL }
|
30
|
-
#else
|
31
|
-
.dcompact = NULL,
|
32
|
-
.reserved = { NULL }
|
33
|
-
#endif
|
34
|
-
},
|
35
|
-
.parent = NULL,
|
36
|
-
.data = NULL,
|
37
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
38
|
-
};
|
39
|
-
|
40
|
-
static VALUE lrt_alloc(VALUE cls)
|
25
|
+
static VALUE rt_alloc(VALUE cls)
|
41
26
|
{
|
42
27
|
rtree_t *rtree;;
|
43
28
|
if ((rtree = rtree_alloc()) == NULL)
|
44
29
|
rb_raise(rb_eNoMemError, "failed to alloc rtree");
|
45
|
-
return TypedData_Wrap_Struct(cls, &
|
30
|
+
return TypedData_Wrap_Struct(cls, &rtree_type, rtree);
|
46
31
|
}
|
47
32
|
|
48
|
-
static VALUE
|
33
|
+
static VALUE rt_init(VALUE self, VALUE dim_obj, VALUE flags_obj)
|
49
34
|
{
|
50
35
|
Check_Type(dim_obj, T_FIXNUM);
|
51
36
|
size_t dim = FIX2ULONG(dim_obj);
|
@@ -54,7 +39,7 @@ static VALUE lrt_init(VALUE self, VALUE dim_obj, VALUE flags_obj)
|
|
54
39
|
state_flags_t flags = FIX2UINT(flags_obj);
|
55
40
|
|
56
41
|
rtree_t *rtree;
|
57
|
-
TypedData_Get_Struct(self, rtree_t, &
|
42
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
58
43
|
|
59
44
|
if ((rtree_init(rtree, dim, flags)) != 0)
|
60
45
|
rb_raise(rb_eNoMemError, "failed to init rtree");
|
@@ -62,28 +47,28 @@ static VALUE lrt_init(VALUE self, VALUE dim_obj, VALUE flags_obj)
|
|
62
47
|
return self;
|
63
48
|
}
|
64
49
|
|
65
|
-
static VALUE
|
50
|
+
static VALUE rt_release(VALUE self)
|
66
51
|
{
|
67
52
|
rtree_t *rtree;
|
68
|
-
TypedData_Get_Struct(self, rtree_t, &
|
53
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
69
54
|
rtree_destroy(rtree);
|
70
55
|
return self;
|
71
56
|
}
|
72
57
|
|
73
|
-
static VALUE
|
58
|
+
static VALUE rt_height(VALUE self)
|
74
59
|
{
|
75
60
|
rtree_t *rtree;
|
76
|
-
TypedData_Get_Struct(self, rtree_t, &
|
61
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
77
62
|
return INT2NUM(rtree_height(rtree));
|
78
63
|
}
|
79
64
|
|
80
|
-
static VALUE
|
65
|
+
static VALUE rt_add_rect(VALUE self, VALUE id_obj, VALUE coord_obj)
|
81
66
|
{
|
82
67
|
Check_Type(coord_obj, T_ARRAY);
|
83
68
|
Check_Type(id_obj, T_FIXNUM);
|
84
69
|
|
85
70
|
rtree_t *rtree;
|
86
|
-
TypedData_Get_Struct(self, rtree_t, &
|
71
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
87
72
|
|
88
73
|
rtree_id_t
|
89
74
|
id = FIX2ULONG(id_obj);
|
@@ -135,13 +120,13 @@ static int update_cb(rtree_id_t id, rtree_coord_t *coord, void *context)
|
|
135
120
|
return 0;
|
136
121
|
}
|
137
122
|
|
138
|
-
static VALUE
|
123
|
+
static VALUE rt_update(VALUE self)
|
139
124
|
{
|
140
125
|
if (!rb_block_given_p())
|
141
126
|
rb_raise(rb_eArgError, "Expected block");
|
142
127
|
|
143
128
|
rtree_t *rtree;
|
144
|
-
TypedData_Get_Struct(self, rtree_t, &
|
129
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
145
130
|
|
146
131
|
size_t len = 2 * state_dims(rtree->state);
|
147
132
|
int err = rtree_update(rtree, update_cb, &len);
|
@@ -154,10 +139,10 @@ static VALUE lrt_update(VALUE self)
|
|
154
139
|
|
155
140
|
/*
|
156
141
|
The librtree API expects the search callback to return zero to
|
157
|
-
continue the search, non-zero to terminate.
|
142
|
+
continue the search, non-zero to terminate. I was expecting to
|
158
143
|
need to wrap the 'yield' in 'rescue's and 'ensure's to handle
|
159
144
|
exceptions and breaks, but find that doing nothing actually does
|
160
|
-
the right thing (see specs). The search
|
145
|
+
the right thing (see specs). The search implementation is just
|
161
146
|
a recursive search through the tree (as you would expect) so
|
162
147
|
there is no end-of-search cleanup to do, so I think this is all
|
163
148
|
just fine ... wild
|
@@ -169,7 +154,7 @@ static int search_cb(rtree_id_t id, void *context)
|
|
169
154
|
return 0;
|
170
155
|
}
|
171
156
|
|
172
|
-
static VALUE
|
157
|
+
static VALUE rt_search(VALUE self, VALUE coord_obj)
|
173
158
|
{
|
174
159
|
if (!rb_block_given_p())
|
175
160
|
rb_raise(rb_eArgError, "Expected block");
|
@@ -177,7 +162,7 @@ static VALUE lrt_search(VALUE self, VALUE coord_obj)
|
|
177
162
|
Check_Type(coord_obj, T_ARRAY);
|
178
163
|
|
179
164
|
rtree_t *rtree;
|
180
|
-
TypedData_Get_Struct(self, rtree_t, &
|
165
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
181
166
|
|
182
167
|
size_t
|
183
168
|
len = RARRAY_LEN(coord_obj),
|
@@ -220,21 +205,21 @@ static VALUE deserialise(VALUE cls, VALUE io_obj, deserialise_t *f)
|
|
220
205
|
rb_raise(rb_eRuntimeError, "Failed read from stream");
|
221
206
|
}
|
222
207
|
|
223
|
-
return TypedData_Wrap_Struct(cls, &
|
208
|
+
return TypedData_Wrap_Struct(cls, &rtree_type, rtree);
|
224
209
|
}
|
225
210
|
|
226
|
-
static VALUE
|
211
|
+
static VALUE rt_json_read(VALUE cls, VALUE io_obj)
|
227
212
|
{
|
228
213
|
return deserialise(cls, io_obj, rtree_json_read);
|
229
214
|
}
|
230
215
|
|
231
|
-
static VALUE
|
216
|
+
static VALUE rt_bsrt_read(VALUE cls, VALUE io_obj)
|
232
217
|
{
|
233
218
|
return deserialise(cls, io_obj, rtree_bsrt_read);
|
234
219
|
}
|
235
220
|
|
236
|
-
static VALUE
|
237
|
-
|
221
|
+
static VALUE rt_csv_read(VALUE cls,
|
222
|
+
VALUE io_obj, VALUE dim_obj, VALUE flags_obj)
|
238
223
|
{
|
239
224
|
Check_Type(io_obj, T_FILE);
|
240
225
|
rb_io_t *io;
|
@@ -259,7 +244,7 @@ static VALUE lrt_csv_read(VALUE cls,
|
|
259
244
|
rb_raise(rb_eRuntimeError, "Failed read from stream");
|
260
245
|
}
|
261
246
|
|
262
|
-
return TypedData_Wrap_Struct(cls, &
|
247
|
+
return TypedData_Wrap_Struct(cls, &rtree_type, rtree);
|
263
248
|
}
|
264
249
|
|
265
250
|
/* serialisation */
|
@@ -277,7 +262,7 @@ static VALUE serialise(VALUE self, VALUE io_obj, serialise_t *f)
|
|
277
262
|
FILE *fp = rb_io_stdio_file(io);
|
278
263
|
|
279
264
|
rtree_t *rtree;
|
280
|
-
TypedData_Get_Struct(self, rtree_t, &
|
265
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
281
266
|
|
282
267
|
int err = f(rtree, fp);
|
283
268
|
if (err != 0)
|
@@ -286,22 +271,22 @@ static VALUE serialise(VALUE self, VALUE io_obj, serialise_t *f)
|
|
286
271
|
return self;
|
287
272
|
}
|
288
273
|
|
289
|
-
static VALUE
|
274
|
+
static VALUE rt_json_write(VALUE self, VALUE io_obj)
|
290
275
|
{
|
291
276
|
return serialise(self, io_obj, rtree_json_write);
|
292
277
|
}
|
293
278
|
|
294
|
-
static VALUE
|
279
|
+
static VALUE rt_bsrt_write(VALUE self, VALUE io_obj)
|
295
280
|
{
|
296
281
|
return serialise(self, io_obj, rtree_bsrt_write);
|
297
282
|
}
|
298
283
|
|
299
|
-
static VALUE
|
284
|
+
static VALUE rt_identical(VALUE self, VALUE other)
|
300
285
|
{
|
301
286
|
rtree_t *rtree_self, *rtree_other;
|
302
287
|
|
303
|
-
TypedData_Get_Struct(self, rtree_t, &
|
304
|
-
TypedData_Get_Struct(other, rtree_t, &
|
288
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree_self);
|
289
|
+
TypedData_Get_Struct(other, rtree_t, &rtree_type, rtree_other);
|
305
290
|
|
306
291
|
if (rtree_identical(rtree_self, rtree_other))
|
307
292
|
return Qtrue;
|
@@ -309,10 +294,10 @@ static VALUE lrt_identical(VALUE self, VALUE other)
|
|
309
294
|
return Qfalse;
|
310
295
|
}
|
311
296
|
|
312
|
-
static VALUE
|
297
|
+
static VALUE rt_clone(VALUE self)
|
313
298
|
{
|
314
299
|
rtree_t *rtree;
|
315
|
-
TypedData_Get_Struct(self, rtree_t, &
|
300
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
316
301
|
|
317
302
|
rtree_t *clone;
|
318
303
|
errno = 0;
|
@@ -324,102 +309,231 @@ static VALUE lrt_clone(VALUE self)
|
|
324
309
|
rb_raise(rb_eRuntimeError, "Failed clone");
|
325
310
|
}
|
326
311
|
|
327
|
-
return TypedData_Wrap_Struct(CLASS_OF(self), &
|
312
|
+
return TypedData_Wrap_Struct(CLASS_OF(self), &rtree_type, clone);
|
328
313
|
}
|
329
314
|
|
330
315
|
static VALUE state_size_access(VALUE self, size_t (*f)(const state_t*))
|
331
316
|
{
|
332
317
|
rtree_t *rtree;
|
333
|
-
TypedData_Get_Struct(self, rtree_t, &
|
318
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
334
319
|
return INT2NUM(f(rtree->state));
|
335
320
|
}
|
336
321
|
|
337
|
-
static VALUE
|
322
|
+
static VALUE rt_dim(VALUE self)
|
338
323
|
{
|
339
324
|
return state_size_access(self, state_dims);
|
340
325
|
}
|
341
326
|
|
342
|
-
static VALUE
|
327
|
+
static VALUE rt_page_size(VALUE self)
|
343
328
|
{
|
344
329
|
return state_size_access(self, state_page_size);
|
345
330
|
}
|
346
331
|
|
347
|
-
static VALUE
|
332
|
+
static VALUE rt_node_size(VALUE self)
|
348
333
|
{
|
349
334
|
return state_size_access(self, state_node_size);
|
350
335
|
}
|
351
336
|
|
352
|
-
static VALUE
|
337
|
+
static VALUE rt_rect_size(VALUE self)
|
353
338
|
{
|
354
339
|
return state_size_access(self, state_rect_size);
|
355
340
|
}
|
356
341
|
|
357
|
-
static VALUE
|
342
|
+
static VALUE rt_branch_size(VALUE self)
|
358
343
|
{
|
359
344
|
return state_size_access(self, state_branch_size);
|
360
345
|
}
|
361
346
|
|
362
|
-
static VALUE
|
347
|
+
static VALUE rt_branching_factor(VALUE self)
|
363
348
|
{
|
364
349
|
return state_size_access(self, state_branching_factor);
|
365
350
|
}
|
366
351
|
|
367
|
-
static VALUE
|
352
|
+
static VALUE rt_unit_sphere_volume(VALUE self)
|
368
353
|
{
|
369
354
|
rtree_t *rtree;
|
370
|
-
TypedData_Get_Struct(self, rtree_t, &
|
355
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
371
356
|
return DBL2NUM(state_unit_sphere_volume(rtree->state));
|
372
357
|
}
|
373
358
|
|
374
|
-
static VALUE
|
359
|
+
static VALUE rt_size(VALUE self)
|
375
360
|
{
|
376
361
|
rtree_t *rtree;
|
377
|
-
TypedData_Get_Struct(self, rtree_t, &
|
362
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
378
363
|
return INT2NUM(rtree_bytes(rtree));
|
379
364
|
}
|
380
365
|
|
381
|
-
static VALUE
|
366
|
+
static VALUE rt_version(VALUE self)
|
382
367
|
{
|
383
368
|
return rb_str_new_cstr(rtree_package_version);
|
384
369
|
}
|
385
370
|
|
386
|
-
static VALUE
|
371
|
+
static VALUE rt_bugreport(VALUE self)
|
387
372
|
{
|
388
373
|
return rb_str_new_cstr(rtree_package_bugreport);
|
389
374
|
}
|
390
375
|
|
391
|
-
static VALUE
|
376
|
+
static VALUE rt_url(VALUE self)
|
392
377
|
{
|
393
378
|
return rb_str_new_cstr(rtree_package_url);
|
394
379
|
}
|
395
380
|
|
381
|
+
static VALUE rt_postscript(VALUE self,
|
382
|
+
VALUE style_obj,
|
383
|
+
VALUE axis_obj,
|
384
|
+
VALUE extent_obj,
|
385
|
+
VALUE margin_obj,
|
386
|
+
VALUE io_obj)
|
387
|
+
{
|
388
|
+
rtree_t *rtree;
|
389
|
+
TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
|
390
|
+
|
391
|
+
style_t *style;
|
392
|
+
TypedData_Get_Struct(style_obj, style_t, &style_type, style);
|
393
|
+
|
394
|
+
Check_Type(io_obj, T_FILE);
|
395
|
+
rb_io_t *io;
|
396
|
+
GetOpenFile(io_obj, io);
|
397
|
+
rb_io_check_initialized(io);
|
398
|
+
rb_io_check_writable(io);
|
399
|
+
FILE *fp = rb_io_stdio_file(io);
|
400
|
+
|
401
|
+
float
|
402
|
+
extent = NUM2DBL(extent_obj),
|
403
|
+
margin = NUM2DBL(margin_obj);
|
404
|
+
|
405
|
+
Check_Type(axis_obj, T_FIXNUM);
|
406
|
+
extent_axis_t axis = FIX2UINT(axis_obj);
|
407
|
+
|
408
|
+
rtree_postscript_t opt =
|
409
|
+
{
|
410
|
+
.style = style,
|
411
|
+
.axis = axis,
|
412
|
+
.extent = extent,
|
413
|
+
.margin = margin,
|
414
|
+
.title = "librtree-ruby output"
|
415
|
+
};
|
416
|
+
|
417
|
+
int err;
|
418
|
+
if ((err = rtree_postscript(rtree, &opt, fp)) != 0)
|
419
|
+
rb_raise(rb_eRuntimeError, "librtree: %s", rtree_strerror(err));
|
420
|
+
|
421
|
+
return Qnil;
|
422
|
+
}
|
423
|
+
|
424
|
+
static rb_data_type_t rtree_type = {
|
425
|
+
.wrap_struct_name = "rtree-wrap",
|
426
|
+
.function = {
|
427
|
+
.dmark = NULL,
|
428
|
+
.dfree = rt_dfree,
|
429
|
+
.dsize = rt_dsize,
|
430
|
+
#if RUBY_API_VERSION_CODE < 20700
|
431
|
+
.reserved = { NULL, NULL }
|
432
|
+
#else
|
433
|
+
.dcompact = NULL,
|
434
|
+
.reserved = { NULL }
|
435
|
+
#endif
|
436
|
+
},
|
437
|
+
.parent = NULL,
|
438
|
+
.data = NULL,
|
439
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
440
|
+
};
|
441
|
+
|
442
|
+
/* RTree::Style */
|
443
|
+
|
444
|
+
static void st_dfree(void *p)
|
445
|
+
{
|
446
|
+
postscript_style_destroy((style_t*)p);
|
447
|
+
}
|
448
|
+
|
449
|
+
static VALUE st_release(VALUE self)
|
450
|
+
{
|
451
|
+
style_t *style;
|
452
|
+
TypedData_Get_Struct(self, style_t, &style_type, style);
|
453
|
+
postscript_style_destroy(style);
|
454
|
+
return self;
|
455
|
+
}
|
456
|
+
|
457
|
+
static VALUE st_json_read(VALUE cls, VALUE io_obj)
|
458
|
+
{
|
459
|
+
Check_Type(io_obj, T_FILE);
|
460
|
+
|
461
|
+
rb_io_t *io;
|
462
|
+
GetOpenFile(io_obj, io);
|
463
|
+
rb_io_check_initialized(io);
|
464
|
+
rb_io_check_readable(io);
|
465
|
+
FILE *fp = rb_io_stdio_file(io);
|
466
|
+
|
467
|
+
style_t *style;
|
468
|
+
errno = 0;
|
469
|
+
|
470
|
+
if ((style = postscript_style_read(fp)) == NULL)
|
471
|
+
{
|
472
|
+
if (errno)
|
473
|
+
rb_sys_fail(__func__);
|
474
|
+
else
|
475
|
+
rb_raise(rb_eRuntimeError, "Failed read from stream");
|
476
|
+
}
|
477
|
+
|
478
|
+
return TypedData_Wrap_Struct(cls, &style_type, style);
|
479
|
+
}
|
480
|
+
|
481
|
+
static rb_data_type_t style_type = {
|
482
|
+
.wrap_struct_name = "style-wrap",
|
483
|
+
.function = {
|
484
|
+
.dmark = NULL,
|
485
|
+
.dfree = st_dfree,
|
486
|
+
.dsize = NULL,
|
487
|
+
#if RUBY_API_VERSION_CODE < 20700
|
488
|
+
.reserved = { NULL, NULL }
|
489
|
+
#else
|
490
|
+
.dcompact = NULL,
|
491
|
+
.reserved = { NULL }
|
492
|
+
#endif
|
493
|
+
},
|
494
|
+
.parent = NULL,
|
495
|
+
.data = NULL,
|
496
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
497
|
+
};
|
498
|
+
|
396
499
|
void Init_rtree(void)
|
397
500
|
{
|
398
|
-
VALUE
|
399
|
-
|
400
|
-
rb_define_alloc_func(
|
401
|
-
rb_define_method(
|
402
|
-
rb_define_method(
|
403
|
-
rb_define_method(
|
404
|
-
rb_define_method(
|
405
|
-
rb_define_method(
|
406
|
-
rb_define_method(
|
407
|
-
rb_define_method(
|
408
|
-
rb_define_method(
|
409
|
-
rb_define_method(
|
410
|
-
rb_define_method(
|
411
|
-
rb_define_method(
|
412
|
-
rb_define_method(
|
413
|
-
rb_define_method(
|
414
|
-
rb_define_method(
|
415
|
-
rb_define_method(
|
416
|
-
rb_define_method(
|
417
|
-
rb_define_method(
|
418
|
-
rb_define_method(
|
419
|
-
|
420
|
-
rb_define_singleton_method(
|
421
|
-
rb_define_singleton_method(
|
422
|
-
rb_define_singleton_method(
|
423
|
-
rb_define_singleton_method(
|
424
|
-
rb_define_singleton_method(
|
501
|
+
VALUE cRTreeBase = rb_const_get(rb_cObject, rb_intern("RTreeBase"));
|
502
|
+
|
503
|
+
rb_define_alloc_func(cRTreeBase, rt_alloc);
|
504
|
+
rb_define_method(cRTreeBase, "initialize", rt_init, 2);
|
505
|
+
rb_define_method(cRTreeBase, "free", rt_release, 0);
|
506
|
+
rb_define_method(cRTreeBase, "clone", rt_clone, 0);
|
507
|
+
rb_define_method(cRTreeBase, "update!", rt_update, 0);
|
508
|
+
rb_define_method(cRTreeBase, "height", rt_height, 0);
|
509
|
+
rb_define_method(cRTreeBase, "add_rect", rt_add_rect, 2);
|
510
|
+
rb_define_method(cRTreeBase, "search", rt_search, 1);
|
511
|
+
rb_define_method(cRTreeBase, "json_write", rt_json_write, 1);
|
512
|
+
rb_define_method(cRTreeBase, "bsrt_write", rt_bsrt_write, 1);
|
513
|
+
rb_define_method(cRTreeBase, "eq?", rt_identical, 1);
|
514
|
+
rb_define_method(cRTreeBase, "dim", rt_dim, 0);
|
515
|
+
rb_define_method(cRTreeBase, "size", rt_size, 0);
|
516
|
+
rb_define_method(cRTreeBase, "page_size", rt_page_size, 0);
|
517
|
+
rb_define_method(cRTreeBase, "node_size", rt_node_size, 0);
|
518
|
+
rb_define_method(cRTreeBase, "rect_size", rt_rect_size, 0);
|
519
|
+
rb_define_method(cRTreeBase, "branch_size", rt_branch_size, 0);
|
520
|
+
rb_define_method(cRTreeBase, "branching_factor", rt_branching_factor, 0);
|
521
|
+
rb_define_method(cRTreeBase, "unit_sphere_volume", rt_unit_sphere_volume, 0);
|
522
|
+
rb_define_method(cRTreeBase, "postscript", rt_postscript, 5);
|
523
|
+
rb_define_singleton_method(cRTreeBase, "version", rt_version, 0);
|
524
|
+
rb_define_singleton_method(cRTreeBase, "bugreport", rt_bugreport, 0);
|
525
|
+
rb_define_singleton_method(cRTreeBase, "url", rt_url, 0);
|
526
|
+
rb_define_singleton_method(cRTreeBase, "json_read", rt_json_read, 1);
|
527
|
+
rb_define_singleton_method(cRTreeBase, "bsrt_read", rt_bsrt_read, 1);
|
528
|
+
rb_define_singleton_method(cRTreeBase, "csv_read", rt_csv_read, 3);
|
529
|
+
rb_define_const(cRTreeBase, "SPLIT_QUADRATIC", INT2NUM(RTREE_SPLIT_QUADRATIC));
|
530
|
+
rb_define_const(cRTreeBase, "SPLIT_LINEAR", INT2NUM(RTREE_SPLIT_LINEAR));
|
531
|
+
rb_define_const(cRTreeBase, "SPLIT_GREENE", INT2NUM(RTREE_SPLIT_GREENE));
|
532
|
+
rb_define_const(cRTreeBase, "AXIS_HEIGHT", INT2NUM(axis_height));
|
533
|
+
rb_define_const(cRTreeBase, "AXIS_WIDTH", INT2NUM(axis_width));
|
534
|
+
|
535
|
+
VALUE cRTreeStyleBase = rb_const_get(rb_cObject, rb_intern("RTreeStyleBase"));
|
536
|
+
|
537
|
+
rb_define_method(cRTreeStyleBase, "free", st_release, 0);
|
538
|
+
rb_define_singleton_method(cRTreeStyleBase, "json_read", st_json_read, 1);
|
425
539
|
}
|
data/lib/rtree.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
-
# The Ruby/C interface
|
2
|
-
|
1
|
+
# The internal Ruby/C interface for RTree, not documented in YARD.
|
2
|
+
#
|
3
|
+
class RTreeBase ; end
|
4
|
+
|
5
|
+
# The internal Ruby/C interface for RTree::Style, not documented in YARD.
|
6
|
+
#
|
7
|
+
class RTreeStyleBase ; end
|
8
|
+
|
9
|
+
require 'rtree/rtree'
|
10
|
+
require 'json'
|
11
|
+
require 'fcntl'
|
3
12
|
|
4
13
|
# @author RTree J. J. Green
|
5
14
|
#
|
@@ -51,7 +60,26 @@ class RTreeC ; end
|
|
51
60
|
# determined at compile-time (with the RTREE_ID_TYPE variable) and by
|
52
61
|
# default this is a 64-bit unsigned integer.
|
53
62
|
#
|
54
|
-
class RTree <
|
63
|
+
class RTree < RTreeBase
|
64
|
+
|
65
|
+
module IOUtil
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# In Ruby 3, the Fibres facility exploits non-blocking IO and so pipes
|
70
|
+
# are non-blocking by default, this buggers-up the deserialise method
|
71
|
+
# since there is short delay forking here -- so we reinstate blocking
|
72
|
+
# with some fairly low-level fcntl)2) magick.
|
73
|
+
|
74
|
+
def unset_nonblock(fd)
|
75
|
+
flags0 = fd.fcntl(Fcntl::F_GETFL, 0)
|
76
|
+
flags1 = flags0 & ~Fcntl::O_NONBLOCK
|
77
|
+
fd.fcntl(Fcntl::F_SETFL, flags1)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
extend IOUtil
|
55
83
|
|
56
84
|
class << self
|
57
85
|
|
@@ -61,6 +89,7 @@ class RTree < RTreeC
|
|
61
89
|
# @see #json_write
|
62
90
|
# @example Read from file
|
63
91
|
# rtree = File.open('rtree.json', 'r') { |io| RTree.json_read(io) }
|
92
|
+
#
|
64
93
|
def json_read(io)
|
65
94
|
super
|
66
95
|
end
|
@@ -69,6 +98,7 @@ class RTree < RTreeC
|
|
69
98
|
# @param json [String] a JSON string
|
70
99
|
# @return [RTree] the newly instantiated RTree
|
71
100
|
# @see #to_json
|
101
|
+
#
|
72
102
|
def from_json(json)
|
73
103
|
deserialise(json, Encoding::UTF_8) { |io| json_read(io) }
|
74
104
|
end
|
@@ -80,6 +110,7 @@ class RTree < RTreeC
|
|
80
110
|
# @see #bsrt_write
|
81
111
|
# @example Read from file
|
82
112
|
# rtree = File.open('rtree.bsrt', 'r') { |io| RTree.bsrt_read(io) }
|
113
|
+
#
|
83
114
|
def bsrt_read(io)
|
84
115
|
super
|
85
116
|
end
|
@@ -89,6 +120,7 @@ class RTree < RTreeC
|
|
89
120
|
# @param bsrt [String] a binary encoded string
|
90
121
|
# @return [RTree] the newly instantiated RTree
|
91
122
|
# @see #to_bsrt
|
123
|
+
#
|
92
124
|
def from_bsrt(bsrt)
|
93
125
|
deserialise(bsrt, Encoding::BINARY) { |io| bsrt_read(io) }
|
94
126
|
end
|
@@ -96,7 +128,7 @@ class RTree < RTreeC
|
|
96
128
|
# Build a new RTree instance from CSV stream
|
97
129
|
# @param io [IO] a readable stream object
|
98
130
|
# @param dim [Integer] the dimension of the tree
|
99
|
-
# @param split [:linear, :quadratic] See {#initialize}
|
131
|
+
# @param split [:linear, :quadratic, :greene] See {#initialize}
|
100
132
|
# @param node_page [Integer] See {#initialize}
|
101
133
|
# @return [RTree] the newly built RTree
|
102
134
|
# @note The CSV file (without header) should have the id in the
|
@@ -104,6 +136,7 @@ class RTree < RTreeC
|
|
104
136
|
# Extra columns may be present and will be ignored (this
|
105
137
|
# useful feature is the reason that the dimension is a required
|
106
138
|
# argument).
|
139
|
+
#
|
107
140
|
def csv_read(io, dim, split: :quadratic, node_page: 0)
|
108
141
|
flags = split_flag(split) | node_page_flag(node_page)
|
109
142
|
super(io, dim, flags)
|
@@ -114,6 +147,7 @@ class RTree < RTreeC
|
|
114
147
|
# @param dim [Integer] the dimension of the tree
|
115
148
|
# @param kwarg [Hash] As for {.csv_read}
|
116
149
|
# @return [RTree] the newly built RTree
|
150
|
+
#
|
117
151
|
def from_csv(csv, dim, **kwarg)
|
118
152
|
deserialise(csv, Encoding::UTF_8) do |io|
|
119
153
|
csv_read(io, dim, **kwarg)
|
@@ -121,33 +155,46 @@ class RTree < RTreeC
|
|
121
155
|
end
|
122
156
|
|
123
157
|
# @return [Array<Integer>] version of librtree
|
158
|
+
#
|
124
159
|
def version
|
125
160
|
@version ||= super.split('.').map(&:to_i)
|
126
161
|
end
|
127
162
|
|
128
163
|
# @return [String] email address for librtree bug reports
|
164
|
+
#
|
129
165
|
def bugreport
|
130
166
|
super
|
131
167
|
end
|
132
168
|
|
133
169
|
# @return [String] librtree homepage
|
170
|
+
#
|
134
171
|
def url
|
135
172
|
super
|
136
173
|
end
|
137
174
|
|
138
175
|
# @!visibility private
|
176
|
+
# This seems to need the self qualification on the constants,
|
177
|
+
# without them we get a NameError, not sure why so asked on SO
|
178
|
+
# https://stackoverflow.com/questions/68122256/ It's still not
|
179
|
+
# clear to me why this qualification is needed, but that's a
|
180
|
+
# problem with my understanding of the Ruby Eigenclass, it is
|
181
|
+
# the expected behaviour
|
182
|
+
#
|
139
183
|
def split_flag(split)
|
140
184
|
case split
|
141
185
|
when :quadratic
|
142
|
-
|
186
|
+
self::SPLIT_QUADRATIC
|
143
187
|
when :linear
|
144
|
-
|
188
|
+
self::SPLIT_LINEAR
|
189
|
+
when :greene
|
190
|
+
self::SPLIT_GREENE
|
145
191
|
else
|
146
192
|
raise ArgumentError, "bad split value: #{split}"
|
147
193
|
end
|
148
194
|
end
|
149
195
|
|
150
196
|
# @!visibility private
|
197
|
+
#
|
151
198
|
def node_page_flag(node_page)
|
152
199
|
node_page << 2
|
153
200
|
end
|
@@ -157,6 +204,7 @@ class RTree < RTreeC
|
|
157
204
|
def deserialise(string, encoding)
|
158
205
|
raise TypeError unless string.is_a? String
|
159
206
|
rd, wr = IO.pipe(encoding)
|
207
|
+
unset_nonblock(rd)
|
160
208
|
if fork then
|
161
209
|
wr.close
|
162
210
|
begin
|
@@ -180,9 +228,10 @@ class RTree < RTreeC
|
|
180
228
|
|
181
229
|
# Initialize a new (empty) RTree
|
182
230
|
# @param dim [Integer] the dimension of the tree
|
183
|
-
# @param split [:linear, :quadratic] determines the splitting
|
184
|
-
# the linear strategy is faster to build, the quadratic
|
185
|
-
# better-quality R-
|
231
|
+
# @param split [:linear, :quadratic, :greene] determines the splitting
|
232
|
+
# strategy, the linear strategy is faster to build, the quadratic
|
233
|
+
# and greene strategies produce better-quality R-trees which are
|
234
|
+
# faster to query.
|
186
235
|
# @param node_page [Integer] the nodes-per-page value. This value can
|
187
236
|
# affect performance quite dramatically, particularly build time. A
|
188
237
|
# value which is too large would result in an infeasible branching
|
@@ -192,6 +241,7 @@ class RTree < RTreeC
|
|
192
241
|
# You may get better performance for your use-case by manual
|
193
242
|
# experimentation, but zero is a good place to start.
|
194
243
|
# @return [RTree] the newly instantiated RTree
|
244
|
+
#
|
195
245
|
def initialize(dim, split: :quadratic, node_page: 0)
|
196
246
|
@split = split
|
197
247
|
@node_page = node_page
|
@@ -200,6 +250,7 @@ class RTree < RTreeC
|
|
200
250
|
|
201
251
|
# Create a deep copy
|
202
252
|
# @return [RTree] a deep copy of the RTree
|
253
|
+
#
|
203
254
|
def clone
|
204
255
|
super
|
205
256
|
end
|
@@ -216,6 +267,7 @@ class RTree < RTreeC
|
|
216
267
|
# @example Add a rectangle to a dimension two RTree
|
217
268
|
# rtree = RTree.new(2)
|
218
269
|
# rtree.add_rect(7, [0, 0, 1, 1])
|
270
|
+
#
|
219
271
|
def add_rect(id, coords)
|
220
272
|
super
|
221
273
|
end
|
@@ -225,6 +277,7 @@ class RTree < RTreeC
|
|
225
277
|
# @return [Array<Integer>] the ids of all rectangles which intersect
|
226
278
|
# the search rectangle. If a block is given then these values will
|
227
279
|
# be yielded to the block (one at a time).
|
280
|
+
#
|
228
281
|
def search(coords)
|
229
282
|
if block_given? then
|
230
283
|
super
|
@@ -250,18 +303,21 @@ class RTree < RTreeC
|
|
250
303
|
# block and then convert the returned Ruby Floats to C; so we would
|
251
304
|
# expect that it loses much of its competitive advantage when
|
252
305
|
# compared to an R-tree rebuild.
|
306
|
+
#
|
253
307
|
def update!
|
254
308
|
super
|
255
309
|
end
|
256
310
|
|
257
311
|
# The height to the tree in the usual mathematical sense
|
258
312
|
# @return [Integer] the tree height
|
313
|
+
#
|
259
314
|
def height
|
260
315
|
super
|
261
316
|
end
|
262
317
|
|
263
318
|
# Whether the RTree has any rectangles or not
|
264
319
|
# @return [Boolean] true if the RTree is empty
|
320
|
+
#
|
265
321
|
def empty?
|
266
322
|
height == 0
|
267
323
|
end
|
@@ -272,6 +328,7 @@ class RTree < RTreeC
|
|
272
328
|
# @see .json_read
|
273
329
|
# @example Write to file
|
274
330
|
# File.open('rtree.json', 'w') { |io| rtree.json_write(io) }
|
331
|
+
#
|
275
332
|
def json_write(io)
|
276
333
|
super
|
277
334
|
end
|
@@ -282,6 +339,7 @@ class RTree < RTreeC
|
|
282
339
|
# @see .bsrt_read
|
283
340
|
# @example Write to file
|
284
341
|
# File.open('rtree.bsrt', 'w') { |io| rtree.bsrt_write(io) }
|
342
|
+
#
|
285
343
|
def bsrt_write(io)
|
286
344
|
super
|
287
345
|
end
|
@@ -289,6 +347,7 @@ class RTree < RTreeC
|
|
289
347
|
# Serialise to JSON string
|
290
348
|
# @return [String] the UTF-8 encoded JSON
|
291
349
|
# @see .from_json
|
350
|
+
#
|
292
351
|
def to_json
|
293
352
|
serialise(Encoding::UTF_8) { |io| json_write(io) }
|
294
353
|
end
|
@@ -296,12 +355,14 @@ class RTree < RTreeC
|
|
296
355
|
# Serialise to BSRT string
|
297
356
|
# @return [String] the binary encoded BSRT
|
298
357
|
# @see .from_bsrt
|
358
|
+
#
|
299
359
|
def to_bsrt
|
300
360
|
serialise(Encoding::BINARY) { |io| bsrt_write(io) }
|
301
361
|
end
|
302
362
|
|
303
363
|
# The RTree structure in hash form
|
304
364
|
# @return [Hash]
|
365
|
+
#
|
305
366
|
def to_h
|
306
367
|
JSON.parse(to_json, symbolize_names: true)
|
307
368
|
end
|
@@ -311,6 +372,7 @@ class RTree < RTreeC
|
|
311
372
|
# must be in the same order. Certainly {#clone} will produce
|
312
373
|
# an instance which is equal in this sense.
|
313
374
|
# @return [Boolean] true if the instances are identical
|
375
|
+
#
|
314
376
|
def eq?(other)
|
315
377
|
super
|
316
378
|
end
|
@@ -318,6 +380,7 @@ class RTree < RTreeC
|
|
318
380
|
alias_method(:==, :eq?)
|
319
381
|
|
320
382
|
# @return [Integer] the dimension of the R-tree
|
383
|
+
#
|
321
384
|
def dim
|
322
385
|
super
|
323
386
|
end
|
@@ -328,41 +391,74 @@ class RTree < RTreeC
|
|
328
391
|
# running count). Performance-minded users may wish to
|
329
392
|
# cache this value (invalidating the cache when calling
|
330
393
|
# {#add_rect} of course).
|
394
|
+
#
|
331
395
|
def size
|
332
396
|
super
|
333
397
|
end
|
334
398
|
|
335
399
|
# @return [Integer] the bytes in a page of memory
|
400
|
+
#
|
336
401
|
def page_size
|
337
402
|
super
|
338
403
|
end
|
339
404
|
|
340
405
|
# @return [Integer] the size in bytes of a node
|
406
|
+
#
|
341
407
|
def node_size
|
342
408
|
super
|
343
409
|
end
|
344
410
|
|
345
411
|
# @return [Integer] the size in bytes of a rectangle
|
412
|
+
#
|
346
413
|
def rect_size
|
347
414
|
super
|
348
415
|
end
|
349
416
|
|
350
417
|
# @return [Integer] the size in bytes of a branch
|
418
|
+
#
|
351
419
|
def branch_size
|
352
420
|
super
|
353
421
|
end
|
354
422
|
|
355
423
|
# @return [Integer] the number of branches from each node
|
424
|
+
#
|
356
425
|
def branching_factor
|
357
426
|
super
|
358
427
|
end
|
359
428
|
|
360
429
|
# @return [Float] the volume of the unit sphere in the R-tree's
|
361
430
|
# dimension
|
431
|
+
#
|
362
432
|
def unit_sphere_volume
|
363
433
|
super
|
364
434
|
end
|
365
435
|
|
436
|
+
# Create a PostScript plot of the RTree
|
437
|
+
# @param io [IO] a writeable stream object
|
438
|
+
# @param style [RTree::Style] a style object describing the fill
|
439
|
+
# colour and stroke width and colour for each level of the tree.
|
440
|
+
# @param height [Float] the height of the plot in units of PostScript
|
441
|
+
# point (1/72 inch)
|
442
|
+
# @param width [Float] the width of the plot in units of PostScript
|
443
|
+
# point (1/72 inch), if neither height nor width is given then a
|
444
|
+
# width of 216 (3 inches) will be taken as default
|
445
|
+
# @param margin [Float] extra space around the plot in units of
|
446
|
+
# PostScript point (1/72 inch), default zero
|
447
|
+
#
|
448
|
+
def postscript(io, style, height: nil, width: nil, margin: 0)
|
449
|
+
if height && width then
|
450
|
+
raise ArgumentError, 'cannot specify both height and width'
|
451
|
+
end
|
452
|
+
if height then
|
453
|
+
axis = AXIS_HEIGHT
|
454
|
+
extent = height
|
455
|
+
else
|
456
|
+
axis = AXIS_WIDTH
|
457
|
+
extent = width || 216
|
458
|
+
end
|
459
|
+
super(style, axis, extent, margin, io)
|
460
|
+
end
|
461
|
+
|
366
462
|
private
|
367
463
|
|
368
464
|
attr_reader :split, :node_page
|
@@ -394,8 +490,85 @@ class RTree < RTreeC
|
|
394
490
|
end
|
395
491
|
result
|
396
492
|
end
|
493
|
+
end
|
494
|
+
|
495
|
+
# @author RTree::Style J. J. Green
|
496
|
+
#
|
497
|
+
# A Ruby wrapper around RTree styles, used in PostScript plotting.
|
498
|
+
# in particular by {RTree#postscript}.
|
499
|
+
#
|
500
|
+
class RTree::Style < RTreeStyleBase
|
397
501
|
|
502
|
+
extend RTree::IOUtil
|
398
503
|
|
399
|
-
|
504
|
+
class << self
|
400
505
|
|
401
|
-
|
506
|
+
# Create a new Style instance from JSON stream
|
507
|
+
# @param io [IO] a readable stream object
|
508
|
+
# @return [RTree::Style] the newly instantiated Style
|
509
|
+
# @example Read from file
|
510
|
+
# style = File.open('some.style', 'r') do |io|
|
511
|
+
# RTree::Style.json_read(io)
|
512
|
+
# end
|
513
|
+
#
|
514
|
+
def json_read(io)
|
515
|
+
super
|
516
|
+
end
|
517
|
+
|
518
|
+
# Create a new Style instance from JSON string
|
519
|
+
# @param json [String] a JSON string
|
520
|
+
# @return [RTree::Style] the newly instantiated Style
|
521
|
+
# @see .json_read
|
522
|
+
#
|
523
|
+
def from_json(json)
|
524
|
+
raise TypeError unless json.is_a? String
|
525
|
+
rd, wr = IO.pipe(Encoding::UTF_8)
|
526
|
+
unset_nonblock(rd)
|
527
|
+
if fork then
|
528
|
+
wr.close
|
529
|
+
begin
|
530
|
+
result = json_read(rd)
|
531
|
+
ensure
|
532
|
+
rd.close
|
533
|
+
Process.wait
|
534
|
+
end
|
535
|
+
else
|
536
|
+
rd.close
|
537
|
+
begin
|
538
|
+
wr.write(json)
|
539
|
+
ensure
|
540
|
+
wr.close
|
541
|
+
exit!
|
542
|
+
end
|
543
|
+
end
|
544
|
+
result
|
545
|
+
end
|
546
|
+
|
547
|
+
# Create a new Style instance from array of Hash
|
548
|
+
# @param array [Array] an array of hash, this will be converted
|
549
|
+
# to JSON and read by .from_json
|
550
|
+
# @return [RTree::Style] the newly instantiated Style
|
551
|
+
# @see .from_json
|
552
|
+
# @example Create a simple one-level style:
|
553
|
+
# style = RTree::Style.from_a(
|
554
|
+
# [
|
555
|
+
# {
|
556
|
+
# fill: {
|
557
|
+
# rgb: [0.5, 0.5, 0.5]
|
558
|
+
# },
|
559
|
+
# stroke: {
|
560
|
+
# rgb: [0, 0, 1],
|
561
|
+
# width: 3
|
562
|
+
# }
|
563
|
+
# }
|
564
|
+
# ]
|
565
|
+
# )
|
566
|
+
#
|
567
|
+
def from_a(array)
|
568
|
+
from_json(array.to_json)
|
569
|
+
end
|
570
|
+
|
571
|
+
alias_method :from_array, :from_a
|
572
|
+
|
573
|
+
end
|
574
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: librtree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- J.J. Green
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -126,8 +126,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
126
|
- !ruby/object:Gem::Version
|
127
127
|
version: '0'
|
128
128
|
requirements:
|
129
|
-
- The librtree library (1.0.
|
130
|
-
rubygems_version: 3.
|
129
|
+
- The librtree library (1.0.6 or later)
|
130
|
+
rubygems_version: 3.2.3
|
131
131
|
signing_key:
|
132
132
|
specification_version: 4
|
133
133
|
summary: R-tree spatial index
|