librtree 0.8.2 → 0.8.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f559b211be3e93ded31a86b61c68ea28cdea151ef62d0c64a79aa38131fa5a7
4
- data.tar.gz: 7df99f8990a461d60e2276a20891be62c1dc27e6279a2226f2fec6d63d30f5dd
3
+ metadata.gz: b33e172341a9e44682c139df3a6b92198b3dd83059340da9fb8752444afbac70
4
+ data.tar.gz: 7ba6d8c71b6afeb8e5dedde55ff08074db758fa7ea150a67195ff07ca426a312
5
5
  SHA512:
6
- metadata.gz: d6c204e2ba3a7b26fe2ab8ba1148b159a21cc697061d672fa2ccff85924dc56c2a9f19b6241d68e5ec96e3b5f955ffc617ecfc26bc9db94cb0f2190e3178e693
7
- data.tar.gz: c831af24c76a719bfae623a5b525840cf910065426833589d8c04160524e576daf4ad13daf2793387931599187ad80f6bc596aaf21b72334e5230a449cda818d
6
+ metadata.gz: d4440a12038bd07dcb458ff993269fd72ac3826753f6e2757b86f19913a1cc748d7af1f37a7355e015d5a6dd3a750b8335a6f87d2a1dbdc5e4ef5387f9424f6a
7
+ data.tar.gz: ce193b26ab45e5ca2cab29c0c145a9432440355585e5cc5e226bbe0e762b3d4c33bcd693626ccd3f60eaad11513c94d3e8246e86cf8b703a7d89f19b22090d1b
data/ext/rtree/extconf.rb CHANGED
@@ -20,11 +20,9 @@ puts LIB_DIRS.inspect
20
20
 
21
21
  dir_config('librtree', HEADER_DIRS, LIB_DIRS)
22
22
 
23
- abort 'missing csv.h' unless find_header('csv.h')
24
23
  abort 'missing jansson.h' unless find_header('jansson.h')
25
24
  abort 'missing rtree.h' unless find_header('rtree.h')
26
25
 
27
- abort "libcsv is missing" unless find_library('csv', 'csv_init')
28
26
  abort "libjansson is missing" unless find_library('jansson', 'json_pack')
29
27
  abort "librtree is missing" unless find_library('rtree', 'rtree_new')
30
28
 
data/ext/rtree/rtree.c CHANGED
@@ -1,38 +1,36 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/io.h>
3
+ #include <ruby/version.h>
3
4
 
4
5
  #include <rtree.h>
6
+ #include <rtree/package.h>
7
+ #include <rtree/postscript.h>
5
8
 
6
9
  #include <errno.h>
7
10
  #include <stdint.h>
8
11
 
9
- typedef struct
10
- {
11
- rtree_t *rtree;
12
- } lrt_t;
12
+ static rb_data_type_t style_type;
13
+ static rb_data_type_t rtree_type;
13
14
 
14
- static void lrt_free(void *p)
15
+ static void rt_dfree(void *p)
15
16
  {
16
- lrt_t *lrt = p;
17
-
18
- if (lrt->rtree)
19
- {
20
- rtree_destroy(lrt->rtree);
21
- lrt->rtree = NULL;
22
- }
17
+ rtree_destroy((rtree_t*)p);
23
18
  }
24
19
 
25
- static VALUE lrt_alloc(VALUE cls)
20
+ static size_t rt_dsize(const void *p)
26
21
  {
27
- lrt_t *lrt;
28
- VALUE obj = Data_Make_Struct(cls, lrt_t, NULL, lrt_free, lrt);
29
-
30
- lrt->rtree = NULL;
22
+ return rtree_bytes((const rtree_t*)p);
23
+ }
31
24
 
32
- return obj;
25
+ static VALUE rt_alloc(VALUE cls)
26
+ {
27
+ rtree_t *rtree;;
28
+ if ((rtree = rtree_alloc()) == NULL)
29
+ rb_raise(rb_eNoMemError, "failed to alloc rtree");
30
+ return TypedData_Wrap_Struct(cls, &rtree_type, rtree);
33
31
  }
34
32
 
35
- 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)
36
34
  {
37
35
  Check_Type(dim_obj, T_FIXNUM);
38
36
  size_t dim = FIX2ULONG(dim_obj);
@@ -40,43 +38,38 @@ static VALUE lrt_init(VALUE self, VALUE dim_obj, VALUE flags_obj)
40
38
  Check_Type(dim_obj, T_FIXNUM);
41
39
  state_flags_t flags = FIX2UINT(flags_obj);
42
40
 
43
- lrt_t *lrt;
44
- Data_Get_Struct(self, lrt_t, lrt);
41
+ rtree_t *rtree;
42
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
45
43
 
46
- if ((lrt->rtree = rtree_new(dim, flags)) == NULL)
47
- rb_raise(rb_eNoMemError, "failed to create rtree");
44
+ if ((rtree_init(rtree, dim, flags)) != 0)
45
+ rb_raise(rb_eNoMemError, "failed to init rtree");
48
46
 
49
47
  return self;
50
48
  }
51
49
 
52
- static VALUE lrt_release(VALUE self)
50
+ static VALUE rt_release(VALUE self)
53
51
  {
54
- lrt_t *lrt;
55
- Data_Get_Struct(self, lrt_t, lrt);
56
-
57
- free(lrt->rtree);
58
-
52
+ rtree_t *rtree;
53
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
54
+ rtree_destroy(rtree);
59
55
  return self;
60
56
  }
61
57
 
62
- static VALUE lrt_height(VALUE self)
58
+ static VALUE rt_height(VALUE self)
63
59
  {
64
- lrt_t *lrt;
65
- Data_Get_Struct(self, lrt_t, lrt);
66
-
67
- return INT2NUM(rtree_height(lrt->rtree));
60
+ rtree_t *rtree;
61
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
62
+ return INT2NUM(rtree_height(rtree));
68
63
  }
69
64
 
70
- 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)
71
66
  {
72
67
  Check_Type(coord_obj, T_ARRAY);
73
68
  Check_Type(id_obj, T_FIXNUM);
74
69
 
75
- lrt_t *lrt;
76
- Data_Get_Struct(self, lrt_t, lrt);
70
+ rtree_t *rtree;
71
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
77
72
 
78
- rtree_t
79
- *rtree = lrt->rtree;
80
73
  rtree_id_t
81
74
  id = FIX2ULONG(id_obj);
82
75
  size_t
@@ -127,16 +120,15 @@ static int update_cb(rtree_id_t id, rtree_coord_t *coord, void *context)
127
120
  return 0;
128
121
  }
129
122
 
130
- static VALUE lrt_update(VALUE self)
123
+ static VALUE rt_update(VALUE self)
131
124
  {
132
125
  if (!rb_block_given_p())
133
126
  rb_raise(rb_eArgError, "Expected block");
134
127
 
135
- lrt_t *lrt;
136
- Data_Get_Struct(self, lrt_t, lrt);
137
- rtree_t *rtree = lrt->rtree;
138
- size_t len = 2 * state_dims(rtree->state);
128
+ rtree_t *rtree;
129
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
139
130
 
131
+ size_t len = 2 * state_dims(rtree->state);
140
132
  int err = rtree_update(rtree, update_cb, &len);
141
133
 
142
134
  if (err != 0)
@@ -162,18 +154,16 @@ static int search_cb(rtree_id_t id, void *context)
162
154
  return 0;
163
155
  }
164
156
 
165
- static VALUE lrt_search(VALUE self, VALUE coord_obj)
157
+ static VALUE rt_search(VALUE self, VALUE coord_obj)
166
158
  {
167
159
  if (!rb_block_given_p())
168
160
  rb_raise(rb_eArgError, "Expected block");
169
161
 
170
162
  Check_Type(coord_obj, T_ARRAY);
171
163
 
172
- lrt_t *lrt;
173
- Data_Get_Struct(self, lrt_t, lrt);
164
+ rtree_t *rtree;
165
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
174
166
 
175
- rtree_t
176
- *rtree = lrt->rtree;
177
167
  size_t
178
168
  len = RARRAY_LEN(coord_obj),
179
169
  dim = state_dims(rtree->state);
@@ -215,26 +205,21 @@ static VALUE deserialise(VALUE cls, VALUE io_obj, deserialise_t *f)
215
205
  rb_raise(rb_eRuntimeError, "Failed read from stream");
216
206
  }
217
207
 
218
- lrt_t *lrt;
219
- VALUE obj = Data_Make_Struct(cls, lrt_t, NULL, lrt_free, lrt);
220
-
221
- lrt->rtree = rtree;
222
-
223
- return obj;
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,12 +244,7 @@ static VALUE lrt_csv_read(VALUE cls,
259
244
  rb_raise(rb_eRuntimeError, "Failed read from stream");
260
245
  }
261
246
 
262
- lrt_t *lrt;
263
- VALUE obj = Data_Make_Struct(cls, lrt_t, NULL, lrt_free, lrt);
264
-
265
- lrt->rtree = rtree;
266
-
267
- return obj;
247
+ return TypedData_Wrap_Struct(cls, &rtree_type, rtree);
268
248
  }
269
249
 
270
250
  /* serialisation */
@@ -281,9 +261,8 @@ static VALUE serialise(VALUE self, VALUE io_obj, serialise_t *f)
281
261
  rb_io_check_writable(io);
282
262
  FILE *fp = rb_io_stdio_file(io);
283
263
 
284
- lrt_t *lrt;
285
- Data_Get_Struct(self, lrt_t, lrt);
286
- rtree_t *rtree = lrt->rtree;
264
+ rtree_t *rtree;
265
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
287
266
 
288
267
  int err = f(rtree, fp);
289
268
  if (err != 0)
@@ -292,24 +271,22 @@ static VALUE serialise(VALUE self, VALUE io_obj, serialise_t *f)
292
271
  return self;
293
272
  }
294
273
 
295
- static VALUE lrt_json_write(VALUE self, VALUE io_obj)
274
+ static VALUE rt_json_write(VALUE self, VALUE io_obj)
296
275
  {
297
276
  return serialise(self, io_obj, rtree_json_write);
298
277
  }
299
278
 
300
- static VALUE lrt_bsrt_write(VALUE self, VALUE io_obj)
279
+ static VALUE rt_bsrt_write(VALUE self, VALUE io_obj)
301
280
  {
302
281
  return serialise(self, io_obj, rtree_bsrt_write);
303
282
  }
304
283
 
305
- static VALUE lrt_identical(VALUE self, VALUE other)
284
+ static VALUE rt_identical(VALUE self, VALUE other)
306
285
  {
307
- lrt_t *lrt_self, *lrt_other;
308
- Data_Get_Struct(self, lrt_t, lrt_self);
309
- Data_Get_Struct(other, lrt_t, lrt_other);
310
- rtree_t
311
- *rtree_self = lrt_self->rtree,
312
- *rtree_other = lrt_other->rtree;
286
+ rtree_t *rtree_self, *rtree_other;
287
+
288
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree_self);
289
+ TypedData_Get_Struct(other, rtree_t, &rtree_type, rtree_other);
313
290
 
314
291
  if (rtree_identical(rtree_self, rtree_other))
315
292
  return Qtrue;
@@ -317,14 +294,14 @@ static VALUE lrt_identical(VALUE self, VALUE other)
317
294
  return Qfalse;
318
295
  }
319
296
 
320
- static VALUE lrt_clone(VALUE self)
297
+ static VALUE rt_clone(VALUE self)
321
298
  {
322
- lrt_t *lrt;
323
- Data_Get_Struct(self, lrt_t, lrt);
324
299
  rtree_t *rtree;
300
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
325
301
 
302
+ rtree_t *clone;
326
303
  errno = 0;
327
- if ((rtree = rtree_clone(lrt->rtree)) == NULL)
304
+ if ((clone = rtree_clone(rtree)) == NULL)
328
305
  {
329
306
  if (errno)
330
307
  rb_sys_fail(__func__);
@@ -332,83 +309,231 @@ static VALUE lrt_clone(VALUE self)
332
309
  rb_raise(rb_eRuntimeError, "Failed clone");
333
310
  }
334
311
 
335
- lrt_t *lrt_cloned;
336
- VALUE cls = CLASS_OF(self);
337
- VALUE obj = Data_Make_Struct(cls, lrt_t, NULL, lrt_free, lrt_cloned);
338
-
339
- lrt_cloned->rtree = rtree;
340
-
341
- return obj;
312
+ return TypedData_Wrap_Struct(CLASS_OF(self), &rtree_type, clone);
342
313
  }
343
314
 
344
315
  static VALUE state_size_access(VALUE self, size_t (*f)(const state_t*))
345
316
  {
346
- lrt_t *lrt;
347
- Data_Get_Struct(self, lrt_t, lrt);
348
- return INT2NUM(f(lrt->rtree->state));
317
+ rtree_t *rtree;
318
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
319
+ return INT2NUM(f(rtree->state));
349
320
  }
350
321
 
351
- static VALUE lrt_dim(VALUE self)
322
+ static VALUE rt_dim(VALUE self)
352
323
  {
353
324
  return state_size_access(self, state_dims);
354
325
  }
355
326
 
356
- static VALUE lrt_page_size(VALUE self)
327
+ static VALUE rt_page_size(VALUE self)
357
328
  {
358
329
  return state_size_access(self, state_page_size);
359
330
  }
360
331
 
361
- static VALUE lrt_node_size(VALUE self)
332
+ static VALUE rt_node_size(VALUE self)
362
333
  {
363
334
  return state_size_access(self, state_node_size);
364
335
  }
365
336
 
366
- static VALUE lrt_rect_size(VALUE self)
337
+ static VALUE rt_rect_size(VALUE self)
367
338
  {
368
339
  return state_size_access(self, state_rect_size);
369
340
  }
370
341
 
371
- static VALUE lrt_branch_size(VALUE self)
342
+ static VALUE rt_branch_size(VALUE self)
372
343
  {
373
344
  return state_size_access(self, state_branch_size);
374
345
  }
375
346
 
376
- static VALUE lrt_branching_factor(VALUE self)
347
+ static VALUE rt_branching_factor(VALUE self)
377
348
  {
378
349
  return state_size_access(self, state_branching_factor);
379
350
  }
380
351
 
381
- static VALUE lrt_unit_sphere_volume(VALUE self)
352
+ static VALUE rt_unit_sphere_volume(VALUE self)
353
+ {
354
+ rtree_t *rtree;
355
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
356
+ return DBL2NUM(state_unit_sphere_volume(rtree->state));
357
+ }
358
+
359
+ static VALUE rt_size(VALUE self)
360
+ {
361
+ rtree_t *rtree;
362
+ TypedData_Get_Struct(self, rtree_t, &rtree_type, rtree);
363
+ return INT2NUM(rtree_bytes(rtree));
364
+ }
365
+
366
+ static VALUE rt_version(VALUE self)
367
+ {
368
+ return rb_str_new_cstr(rtree_package_version);
369
+ }
370
+
371
+ static VALUE rt_bugreport(VALUE self)
372
+ {
373
+ return rb_str_new_cstr(rtree_package_bugreport);
374
+ }
375
+
376
+ static VALUE rt_url(VALUE self)
377
+ {
378
+ return rb_str_new_cstr(rtree_package_url);
379
+ }
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)
382
387
  {
383
- lrt_t *lrt;
384
- Data_Get_Struct(self, lrt_t, lrt);
385
- return DBL2NUM(state_unit_sphere_volume(lrt->rtree->state));
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);
386
479
  }
387
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
+ };
388
498
 
389
499
  void Init_rtree(void)
390
500
  {
391
- VALUE cls = rb_const_get(rb_cObject, rb_intern("RTreeC"));
392
-
393
- rb_define_alloc_func(cls, lrt_alloc);
394
- rb_define_method(cls, "initialize", lrt_init, 2);
395
- rb_define_method(cls, "free", lrt_release, 0);
396
- rb_define_method(cls, "clone", lrt_clone, 0);
397
- rb_define_method(cls, "update!", lrt_update, 0);
398
- rb_define_method(cls, "height", lrt_height, 0);
399
- rb_define_method(cls, "add_rect", lrt_add_rect, 2);
400
- rb_define_method(cls, "search", lrt_search, 1);
401
- rb_define_method(cls, "json_write", lrt_json_write, 1);
402
- rb_define_method(cls, "bsrt_write", lrt_bsrt_write, 1);
403
- rb_define_method(cls, "eq?", lrt_identical, 1);
404
- rb_define_method(cls, "dim", lrt_dim, 0);
405
- rb_define_method(cls, "page_size", lrt_page_size, 0);
406
- rb_define_method(cls, "node_size", lrt_node_size, 0);
407
- rb_define_method(cls, "rect_size", lrt_rect_size, 0);
408
- rb_define_method(cls, "branch_size", lrt_branch_size, 0);
409
- rb_define_method(cls, "branching_factor", lrt_branching_factor, 0);
410
- rb_define_method(cls, "unit_sphere_volume", lrt_unit_sphere_volume, 0);
411
- rb_define_singleton_method(cls, "json_read", lrt_json_read, 1);
412
- rb_define_singleton_method(cls, "bsrt_read", lrt_bsrt_read, 1);
413
- rb_define_singleton_method(cls, "csv_read", lrt_csv_read, 3);
501
+ VALUE cRTree = rb_const_get(rb_cObject, rb_intern("RTreeC"));
502
+
503
+ rb_define_alloc_func(cRTree, rt_alloc);
504
+ rb_define_method(cRTree, "initialize", rt_init, 2);
505
+ rb_define_method(cRTree, "free", rt_release, 0);
506
+ rb_define_method(cRTree, "clone", rt_clone, 0);
507
+ rb_define_method(cRTree, "update!", rt_update, 0);
508
+ rb_define_method(cRTree, "height", rt_height, 0);
509
+ rb_define_method(cRTree, "add_rect", rt_add_rect, 2);
510
+ rb_define_method(cRTree, "search", rt_search, 1);
511
+ rb_define_method(cRTree, "json_write", rt_json_write, 1);
512
+ rb_define_method(cRTree, "bsrt_write", rt_bsrt_write, 1);
513
+ rb_define_method(cRTree, "eq?", rt_identical, 1);
514
+ rb_define_method(cRTree, "dim", rt_dim, 0);
515
+ rb_define_method(cRTree, "size", rt_size, 0);
516
+ rb_define_method(cRTree, "page_size", rt_page_size, 0);
517
+ rb_define_method(cRTree, "node_size", rt_node_size, 0);
518
+ rb_define_method(cRTree, "rect_size", rt_rect_size, 0);
519
+ rb_define_method(cRTree, "branch_size", rt_branch_size, 0);
520
+ rb_define_method(cRTree, "branching_factor", rt_branching_factor, 0);
521
+ rb_define_method(cRTree, "unit_sphere_volume", rt_unit_sphere_volume, 0);
522
+ rb_define_method(cRTree, "postscript", rt_postscript, 5);
523
+ rb_define_singleton_method(cRTree, "version", rt_version, 0);
524
+ rb_define_singleton_method(cRTree, "bugreport", rt_bugreport, 0);
525
+ rb_define_singleton_method(cRTree, "url", rt_url, 0);
526
+ rb_define_singleton_method(cRTree, "json_read", rt_json_read, 1);
527
+ rb_define_singleton_method(cRTree, "bsrt_read", rt_bsrt_read, 1);
528
+ rb_define_singleton_method(cRTree, "csv_read", rt_csv_read, 3);
529
+ rb_define_const(cRTree, "SPLIT_QUADRATIC", INT2NUM(RTREE_SPLIT_QUADRATIC));
530
+ rb_define_const(cRTree, "SPLIT_LINEAR", INT2NUM(RTREE_SPLIT_LINEAR));
531
+ rb_define_const(cRTree, "SPLIT_GREENE", INT2NUM(RTREE_SPLIT_GREENE));
532
+ rb_define_const(cRTree, "AXIS_HEIGHT", INT2NUM(axis_height));
533
+ rb_define_const(cRTree, "AXIS_WIDTH", INT2NUM(axis_width));
534
+
535
+ VALUE cStyle = rb_define_class_under(cRTree, "StyleC", rb_cObject);
536
+
537
+ rb_define_method(cStyle, "free", st_release, 0);
538
+ rb_define_singleton_method(cStyle, "json_read", st_json_read, 1);
414
539
  }
data/lib/rtree.rb CHANGED
@@ -1,5 +1,12 @@
1
- # The Ruby/C interface, which is not documented in YARD.
2
- class RTreeC ; end
1
+ # The Ruby/C interface to RTree, not documented in YARD.
2
+ #
3
+ class RTreeC
4
+ # The Ruby/C interface to RTree::Style, not documented in YARD.
5
+ #
6
+ class StyleC ; end
7
+ end
8
+
9
+ require 'json'
3
10
 
4
11
  # @author RTree J. J. Green
5
12
  #
@@ -61,6 +68,7 @@ class RTree < RTreeC
61
68
  # @see #json_write
62
69
  # @example Read from file
63
70
  # rtree = File.open('rtree.json', 'r') { |io| RTree.json_read(io) }
71
+ #
64
72
  def json_read(io)
65
73
  super
66
74
  end
@@ -69,6 +77,7 @@ class RTree < RTreeC
69
77
  # @param json [String] a JSON string
70
78
  # @return [RTree] the newly instantiated RTree
71
79
  # @see #to_json
80
+ #
72
81
  def from_json(json)
73
82
  deserialise(json, Encoding::UTF_8) { |io| json_read(io) }
74
83
  end
@@ -80,6 +89,7 @@ class RTree < RTreeC
80
89
  # @see #bsrt_write
81
90
  # @example Read from file
82
91
  # rtree = File.open('rtree.bsrt', 'r') { |io| RTree.bsrt_read(io) }
92
+ #
83
93
  def bsrt_read(io)
84
94
  super
85
95
  end
@@ -89,6 +99,7 @@ class RTree < RTreeC
89
99
  # @param bsrt [String] a binary encoded string
90
100
  # @return [RTree] the newly instantiated RTree
91
101
  # @see #to_bsrt
102
+ #
92
103
  def from_bsrt(bsrt)
93
104
  deserialise(bsrt, Encoding::BINARY) { |io| bsrt_read(io) }
94
105
  end
@@ -96,7 +107,7 @@ class RTree < RTreeC
96
107
  # Build a new RTree instance from CSV stream
97
108
  # @param io [IO] a readable stream object
98
109
  # @param dim [Integer] the dimension of the tree
99
- # @param split [:linear, :quadratic] See {#initialize}
110
+ # @param split [:linear, :quadratic, :greene] See {#initialize}
100
111
  # @param node_page [Integer] See {#initialize}
101
112
  # @return [RTree] the newly built RTree
102
113
  # @note The CSV file (without header) should have the id in the
@@ -104,6 +115,7 @@ class RTree < RTreeC
104
115
  # Extra columns may be present and will be ignored (this
105
116
  # useful feature is the reason that the dimension is a required
106
117
  # argument).
118
+ #
107
119
  def csv_read(io, dim, split: :quadratic, node_page: 0)
108
120
  flags = split_flag(split) | node_page_flag(node_page)
109
121
  super(io, dim, flags)
@@ -114,25 +126,48 @@ class RTree < RTreeC
114
126
  # @param dim [Integer] the dimension of the tree
115
127
  # @param kwarg [Hash] As for {.csv_read}
116
128
  # @return [RTree] the newly built RTree
129
+ #
117
130
  def from_csv(csv, dim, **kwarg)
118
131
  deserialise(csv, Encoding::UTF_8) do |io|
119
132
  csv_read(io, dim, **kwarg)
120
133
  end
121
134
  end
122
135
 
136
+ # @return [Array<Integer>] version of librtree
137
+ #
138
+ def version
139
+ @version ||= super.split('.').map(&:to_i)
140
+ end
141
+
142
+ # @return [String] email address for librtree bug reports
143
+ #
144
+ def bugreport
145
+ super
146
+ end
147
+
148
+ # @return [String] librtree homepage
149
+ #
150
+ def url
151
+ super
152
+ end
153
+
123
154
  # @!visibility private
155
+ #
124
156
  def split_flag(split)
125
157
  case split
126
158
  when :quadratic
127
- 0
159
+ self::SPLIT_QUADRATIC
128
160
  when :linear
129
- 1
161
+ self::SPLIT_LINEAR
162
+ when :greene
163
+ self::SPLIT_GREENE
130
164
  else
131
165
  raise ArgumentError, "bad split value: #{split}"
132
166
  end
133
167
  end
134
168
 
135
169
  # @!visibility private
170
+ #
136
171
  def node_page_flag(node_page)
137
172
  node_page << 2
138
173
  end
@@ -165,9 +200,10 @@ class RTree < RTreeC
165
200
 
166
201
  # Initialize a new (empty) RTree
167
202
  # @param dim [Integer] the dimension of the tree
168
- # @param split [:linear, :quadratic] determines the splitting strategy,
169
- # the linear strategy is faster to build, the quadratic produces a
170
- # better-quality R-tree which is faster to query.
203
+ # @param split [:linear, :quadratic, :greene] determines the splitting
204
+ # strategy, the linear strategy is faster to build, the quadratic
205
+ # and greene strategies produce better-quality R-trees which are
206
+ # faster to query.
171
207
  # @param node_page [Integer] the nodes-per-page value. This value can
172
208
  # affect performance quite dramatically, particularly build time. A
173
209
  # value which is too large would result in an infeasible branching
@@ -177,6 +213,7 @@ class RTree < RTreeC
177
213
  # You may get better performance for your use-case by manual
178
214
  # experimentation, but zero is a good place to start.
179
215
  # @return [RTree] the newly instantiated RTree
216
+ #
180
217
  def initialize(dim, split: :quadratic, node_page: 0)
181
218
  @split = split
182
219
  @node_page = node_page
@@ -185,6 +222,7 @@ class RTree < RTreeC
185
222
 
186
223
  # Create a deep copy
187
224
  # @return [RTree] a deep copy of the RTree
225
+ #
188
226
  def clone
189
227
  super
190
228
  end
@@ -201,6 +239,7 @@ class RTree < RTreeC
201
239
  # @example Add a rectangle to a dimension two RTree
202
240
  # rtree = RTree.new(2)
203
241
  # rtree.add_rect(7, [0, 0, 1, 1])
242
+ #
204
243
  def add_rect(id, coords)
205
244
  super
206
245
  end
@@ -210,6 +249,7 @@ class RTree < RTreeC
210
249
  # @return [Array<Integer>] the ids of all rectangles which intersect
211
250
  # the search rectangle. If a block is given then these values will
212
251
  # be yielded to the block (one at a time).
252
+ #
213
253
  def search(coords)
214
254
  if block_given? then
215
255
  super
@@ -235,18 +275,21 @@ class RTree < RTreeC
235
275
  # block and then convert the returned Ruby Floats to C; so we would
236
276
  # expect that it loses much of its competitive advantage when
237
277
  # compared to an R-tree rebuild.
278
+ #
238
279
  def update!
239
280
  super
240
281
  end
241
282
 
242
283
  # The height to the tree in the usual mathematical sense
243
284
  # @return [Integer] the tree height
285
+ #
244
286
  def height
245
287
  super
246
288
  end
247
289
 
248
290
  # Whether the RTree has any rectangles or not
249
291
  # @return [Boolean] true if the RTree is empty
292
+ #
250
293
  def empty?
251
294
  height == 0
252
295
  end
@@ -257,6 +300,7 @@ class RTree < RTreeC
257
300
  # @see .json_read
258
301
  # @example Write to file
259
302
  # File.open('rtree.json', 'w') { |io| rtree.json_write(io) }
303
+ #
260
304
  def json_write(io)
261
305
  super
262
306
  end
@@ -267,6 +311,7 @@ class RTree < RTreeC
267
311
  # @see .bsrt_read
268
312
  # @example Write to file
269
313
  # File.open('rtree.bsrt', 'w') { |io| rtree.bsrt_write(io) }
314
+ #
270
315
  def bsrt_write(io)
271
316
  super
272
317
  end
@@ -274,6 +319,7 @@ class RTree < RTreeC
274
319
  # Serialise to JSON string
275
320
  # @return [String] the UTF-8 encoded JSON
276
321
  # @see .from_json
322
+ #
277
323
  def to_json
278
324
  serialise(Encoding::UTF_8) { |io| json_write(io) }
279
325
  end
@@ -281,12 +327,14 @@ class RTree < RTreeC
281
327
  # Serialise to BSRT string
282
328
  # @return [String] the binary encoded BSRT
283
329
  # @see .from_bsrt
330
+ #
284
331
  def to_bsrt
285
332
  serialise(Encoding::BINARY) { |io| bsrt_write(io) }
286
333
  end
287
334
 
288
335
  # The RTree structure in hash form
289
336
  # @return [Hash]
337
+ #
290
338
  def to_h
291
339
  JSON.parse(to_json, symbolize_names: true)
292
340
  end
@@ -296,6 +344,7 @@ class RTree < RTreeC
296
344
  # must be in the same order. Certainly {#clone} will produce
297
345
  # an instance which is equal in this sense.
298
346
  # @return [Boolean] true if the instances are identical
347
+ #
299
348
  def eq?(other)
300
349
  super
301
350
  end
@@ -303,41 +352,85 @@ class RTree < RTreeC
303
352
  alias_method(:==, :eq?)
304
353
 
305
354
  # @return [Integer] the dimension of the R-tree
355
+ #
306
356
  def dim
307
357
  super
308
358
  end
309
359
 
360
+ # @return [Integer] the total bytes allocated for the instance
361
+ # @note This method traverses the entire tree summing the
362
+ # contributions for each node (rather than maintaining a
363
+ # running count). Performance-minded users may wish to
364
+ # cache this value (invalidating the cache when calling
365
+ # {#add_rect} of course).
366
+ #
367
+ def size
368
+ super
369
+ end
370
+
310
371
  # @return [Integer] the bytes in a page of memory
372
+ #
311
373
  def page_size
312
374
  super
313
375
  end
314
376
 
315
377
  # @return [Integer] the size in bytes of a node
378
+ #
316
379
  def node_size
317
380
  super
318
381
  end
319
382
 
320
383
  # @return [Integer] the size in bytes of a rectangle
384
+ #
321
385
  def rect_size
322
386
  super
323
387
  end
324
388
 
325
389
  # @return [Integer] the size in bytes of a branch
390
+ #
326
391
  def branch_size
327
392
  super
328
393
  end
329
394
 
330
395
  # @return [Integer] the number of branches from each node
396
+ #
331
397
  def branching_factor
332
398
  super
333
399
  end
334
400
 
335
401
  # @return [Float] the volume of the unit sphere in the R-tree's
336
402
  # dimension
403
+ #
337
404
  def unit_sphere_volume
338
405
  super
339
406
  end
340
407
 
408
+ # Create a PostScript plot of the RTree
409
+ # @param io [IO] a writeable stream object
410
+ # @param style [RTree::Style] a style object describing the fill
411
+ # colour and stroke width and colour for each level of the tree.
412
+ # @param height [Float] the height of the plot in units of PostScript
413
+ # point (1/72 inch)
414
+ # @param width [Float] the width of the plot in units of PostScript
415
+ # point (1/72 inch), if neither height nor width is given then a
416
+ # width of 216 (3 inches) will be taken as default
417
+ # @param margin [Float] extra space around the plot in units of
418
+ # PostScript point (1/72 inch), default zero
419
+ #
420
+ def postscript(io, style, height: nil, width: nil, margin: 0)
421
+ if height && width then
422
+ raise ArgumentError, 'cannot specify both height and width'
423
+ end
424
+ if height then
425
+ axis = AXIS_HEIGHT
426
+ extent = height
427
+ else
428
+ axis = AXIS_WIDTH
429
+ extent = width || 216
430
+ end
431
+ super(style, axis, extent, margin, io)
432
+ end
433
+
341
434
  private
342
435
 
343
436
  attr_reader :split, :node_page
@@ -369,8 +462,89 @@ class RTree < RTreeC
369
462
  end
370
463
  result
371
464
  end
465
+ end
466
+
467
+
468
+ class RTree < RTreeC
469
+ class Style < RTreeC::StyleC
470
+ end
471
+ end
472
+
473
+ # @author RTree::Style J. J. Green
474
+ #
475
+ # A Ruby wrapper around RTree styles, used in PostScript plotting.
476
+ # in particular by {RTree#postscript}.
477
+ #
478
+ class RTree::Style
479
+
480
+ class << self
372
481
 
482
+ # Create a new Style instance from JSON stream
483
+ # @param io [IO] a readable stream object
484
+ # @return [RTree::Style] the newly instantiated Style
485
+ # @example Read from file
486
+ # style = File.open('some.style', 'r') do |io|
487
+ # RTree::Style.json_read(io)
488
+ # end
489
+ #
490
+ def json_read(io)
491
+ super
492
+ end
373
493
 
494
+ # Create a new Style instance from JSON string
495
+ # @param json [String] a JSON string
496
+ # @return [RTree::Style] the newly instantiated Style
497
+ # @see .json_read
498
+ #
499
+ def from_json(json)
500
+ raise TypeError unless json.is_a? String
501
+ rd, wr = IO.pipe(Encoding::UTF_8)
502
+ if fork then
503
+ wr.close
504
+ begin
505
+ result = json_read(rd)
506
+ ensure
507
+ rd.close
508
+ Process.wait
509
+ end
510
+ else
511
+ rd.close
512
+ begin
513
+ wr.write(json)
514
+ ensure
515
+ wr.close
516
+ exit!
517
+ end
518
+ end
519
+ result
520
+ end
521
+
522
+ # Create a new Style instance from array of Hash
523
+ # @param array [Array] an array of hash, this will be converted
524
+ # to JSON and read by .from_json
525
+ # @return [RTree::Style] the newly instantiated Style
526
+ # @see .from_json
527
+ # @example Create a simple one-level style:
528
+ # style = RTree::Style.from_a(
529
+ # [
530
+ # {
531
+ # fill: {
532
+ # rgb: [0.5, 0.5, 0.5]
533
+ # },
534
+ # stroke: {
535
+ # rgb: [0, 0, 1],
536
+ # width: 3
537
+ # }
538
+ # }
539
+ # ]
540
+ # )
541
+ #
542
+ def from_a(array)
543
+ from_json(array.to_json)
544
+ end
545
+
546
+ alias_method :from_array, :from_a
547
+ end
374
548
  end
375
549
 
376
550
  require 'rtree/rtree'
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.2
4
+ version: 0.8.7
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-05-22 00:00:00.000000000 Z
11
+ date: 2021-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -95,8 +95,8 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1'
97
97
  description: |
98
- A Ruby extension for librtree implementing the R-tree
99
- spatial-index of Guttman-Green.
98
+ A Ruby extension implementing the R-tree spatial-index of
99
+ Guttman-Green.
100
100
  email: j.j.green@gmx.co.uk
101
101
  executables: []
102
102
  extensions:
@@ -119,14 +119,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - ">="
121
121
  - !ruby/object:Gem::Version
122
- version: '0'
122
+ version: '2.0'
123
123
  required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  requirements:
125
125
  - - ">="
126
126
  - !ruby/object:Gem::Version
127
127
  version: '0'
128
128
  requirements:
129
- - The librtree library
129
+ - The librtree library (1.0.6 or later)
130
130
  rubygems_version: 3.1.2
131
131
  signing_key:
132
132
  specification_version: 4