librtree 0.8.2 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
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