librtree 0.8.5 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rtree/rtree.c +206 -92
  3. data/lib/rtree.rb +184 -11
  4. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9abe4061328dd6a2b8b9f1c00a38f76332a0f0a188af7a5d3e6f1125eab346e
4
- data.tar.gz: 4029ed06803576cc76ec7bd8d3d1eb9a2d628da9fd982d04e80b643177fce244
3
+ metadata.gz: d796bcdad6e023f99009363c9c11a10d8c6dfc7b9c797b487925fa319ace78b9
4
+ data.tar.gz: 83d563781db1c1e1b6bd8b8790cbb68fbbd9a7f997dd49840ff8cba7bfcac3e8
5
5
  SHA512:
6
- metadata.gz: f6b7005f8ec37a45ff8ee894de5642eb969a26af72ad9fa330aeeae1c746447d786b309301e84116de595bed40f70bef8683fbd9a969b2b9c2cabb32e5c4d374
7
- data.tar.gz: c4c6641e2cdfd9f14f21b50047fe2f304ab1446eb643a0f6cd3acd594fbc37469cf71c78434daa82b759bdb2741a1f887add7809d72c7bbc3f39886aee3ecc9b
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 lrt_dfree(void *p)
15
+ static void rt_dfree(void *p)
13
16
  {
14
17
  rtree_destroy((rtree_t*)p);
15
18
  }
16
19
 
17
- static size_t lrt_dsize(const void *p)
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 rb_data_type_t type = {
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, &type, rtree);
30
+ return TypedData_Wrap_Struct(cls, &rtree_type, rtree);
46
31
  }
47
32
 
48
- static VALUE lrt_init(VALUE self, VALUE dim_obj, VALUE flags_obj)
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, &type, rtree);
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 lrt_release(VALUE self)
50
+ static VALUE rt_release(VALUE self)
66
51
  {
67
52
  rtree_t *rtree;
68
- TypedData_Get_Struct(self, rtree_t, &type, rtree);
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 lrt_height(VALUE self)
58
+ static VALUE rt_height(VALUE self)
74
59
  {
75
60
  rtree_t *rtree;
76
- TypedData_Get_Struct(self, rtree_t, &type, rtree);
61
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
77
62
  return INT2NUM(rtree_height(rtree));
78
63
  }
79
64
 
80
- static VALUE lrt_add_rect(VALUE self, VALUE id_obj, VALUE coord_obj)
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, &type, rtree);
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 lrt_update(VALUE self)
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, &type, rtree);
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. I was expecting to
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 implemetation is just
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 lrt_search(VALUE self, VALUE coord_obj)
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, &type, rtree);
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, &type, rtree);
208
+ return TypedData_Wrap_Struct(cls, &rtree_type, rtree);
224
209
  }
225
210
 
226
- static VALUE lrt_json_read(VALUE cls, VALUE io_obj)
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 lrt_bsrt_read(VALUE cls, VALUE io_obj)
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 lrt_csv_read(VALUE cls,
237
- VALUE io_obj, VALUE dim_obj, VALUE flags_obj)
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, &type, rtree);
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, &type, rtree);
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 lrt_json_write(VALUE self, VALUE io_obj)
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 lrt_bsrt_write(VALUE self, VALUE io_obj)
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 lrt_identical(VALUE self, VALUE other)
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, &type, rtree_self);
304
- TypedData_Get_Struct(other, rtree_t, &type, rtree_other);
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 lrt_clone(VALUE self)
297
+ static VALUE rt_clone(VALUE self)
313
298
  {
314
299
  rtree_t *rtree;
315
- TypedData_Get_Struct(self, rtree_t, &type, rtree);
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), &type, clone);
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, &type, rtree);
318
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
334
319
  return INT2NUM(f(rtree->state));
335
320
  }
336
321
 
337
- static VALUE lrt_dim(VALUE self)
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 lrt_page_size(VALUE self)
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 lrt_node_size(VALUE self)
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 lrt_rect_size(VALUE self)
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 lrt_branch_size(VALUE self)
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 lrt_branching_factor(VALUE self)
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 lrt_unit_sphere_volume(VALUE self)
352
+ static VALUE rt_unit_sphere_volume(VALUE self)
368
353
  {
369
354
  rtree_t *rtree;
370
- TypedData_Get_Struct(self, rtree_t, &type, rtree);
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 lrt_size(VALUE self)
359
+ static VALUE rt_size(VALUE self)
375
360
  {
376
361
  rtree_t *rtree;
377
- TypedData_Get_Struct(self, rtree_t, &type, rtree);
362
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
378
363
  return INT2NUM(rtree_bytes(rtree));
379
364
  }
380
365
 
381
- static VALUE lrt_version(VALUE self)
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 lrt_bugreport(VALUE self)
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 lrt_url(VALUE self)
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 cls = rb_const_get(rb_cObject, rb_intern("RTreeC"));
399
-
400
- rb_define_alloc_func(cls, lrt_alloc);
401
- rb_define_method(cls, "initialize", lrt_init, 2);
402
- rb_define_method(cls, "free", lrt_release, 0);
403
- rb_define_method(cls, "clone", lrt_clone, 0);
404
- rb_define_method(cls, "update!", lrt_update, 0);
405
- rb_define_method(cls, "height", lrt_height, 0);
406
- rb_define_method(cls, "add_rect", lrt_add_rect, 2);
407
- rb_define_method(cls, "search", lrt_search, 1);
408
- rb_define_method(cls, "json_write", lrt_json_write, 1);
409
- rb_define_method(cls, "bsrt_write", lrt_bsrt_write, 1);
410
- rb_define_method(cls, "eq?", lrt_identical, 1);
411
- rb_define_method(cls, "dim", lrt_dim, 0);
412
- rb_define_method(cls, "size", lrt_size, 0);
413
- rb_define_method(cls, "page_size", lrt_page_size, 0);
414
- rb_define_method(cls, "node_size", lrt_node_size, 0);
415
- rb_define_method(cls, "rect_size", lrt_rect_size, 0);
416
- rb_define_method(cls, "branch_size", lrt_branch_size, 0);
417
- rb_define_method(cls, "branching_factor", lrt_branching_factor, 0);
418
- rb_define_method(cls, "unit_sphere_volume", lrt_unit_sphere_volume, 0);
419
- rb_define_singleton_method(cls, "version", lrt_version, 0);
420
- rb_define_singleton_method(cls, "bugreport", lrt_bugreport, 0);
421
- rb_define_singleton_method(cls, "url", lrt_url, 0);
422
- rb_define_singleton_method(cls, "json_read", lrt_json_read, 1);
423
- rb_define_singleton_method(cls, "bsrt_read", lrt_bsrt_read, 1);
424
- rb_define_singleton_method(cls, "csv_read", lrt_csv_read, 3);
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, which is not documented in YARD.
2
- class RTreeC ; end
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 < RTreeC
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
- 0
186
+ self::SPLIT_QUADRATIC
143
187
  when :linear
144
- 1
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 strategy,
184
- # the linear strategy is faster to build, the quadratic produces a
185
- # better-quality R-tree which is faster to query.
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
- end
504
+ class << self
400
505
 
401
- require 'rtree/rtree'
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.5
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-06-13 00:00:00.000000000 Z
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.5 or later)
130
- rubygems_version: 3.1.2
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