tg_geometry 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/ext/tg_geometry/tg_geometry_ext.c +264 -149
- data/lib/tg/geometry/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6541db9668ecda1e7fc6a645cffac29fb80528a17b8d05e7b8c0aa2a0f7ef59c
|
|
4
|
+
data.tar.gz: 26d9350239007d0d853e307260d739390cc24f906c13b873f7350619c66242b7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 88954a796fc76ff9c52c060cf6a71f6ec38de7132623bd041aac1cc2ca80192ae6840195ad2f1736eff92087330113bcf6a76705204951c77ff177383c74bf3d
|
|
7
|
+
data.tar.gz: a2c4fb5d1fe739069231e9b709538bbb93cfe5d5cc56fabd04e34c66a4816cdfd65d75b694cc49ddc9faae34f275d1d9d914cd6eeedc0884ff4c3ce32b552a2b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.4 - 28.10.2026
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Split the complex geometry traversal, index construction, FeatureSource preparation and file-read paths into focused helpers. The public API and runtime behavior are unchanged.
|
|
8
|
+
- Split native extension initialization into registration helpers without changing registration order.
|
|
9
|
+
|
|
3
10
|
## 0.3.3 - 28.10.2026
|
|
4
11
|
|
|
5
12
|
### Changed
|
|
@@ -3222,9 +3222,46 @@ static bool tg_distance_accum_poly(tg_distance_accum_t *accum, const struct tg_p
|
|
|
3222
3222
|
return true;
|
|
3223
3223
|
}
|
|
3224
3224
|
|
|
3225
|
-
static bool tg_distance_accum_geom(tg_distance_accum_t *accum, const struct tg_geom *geom)
|
|
3226
|
-
|
|
3225
|
+
static bool tg_distance_accum_geom(tg_distance_accum_t *accum, const struct tg_geom *geom);
|
|
3226
|
+
|
|
3227
|
+
static void tg_distance_accum_multipoint(tg_distance_accum_t *accum,
|
|
3228
|
+
const struct tg_geom *geom) {
|
|
3229
|
+
int count = tg_geom_num_points(geom);
|
|
3230
|
+
for (int i = 0; i < count; i++)
|
|
3231
|
+
tg_distance_accum_point(accum, tg_geom_point_at(geom, i));
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
static bool tg_distance_accum_multiline(tg_distance_accum_t *accum,
|
|
3235
|
+
const struct tg_geom *geom) {
|
|
3236
|
+
int count = tg_geom_num_lines(geom);
|
|
3237
|
+
for (int i = 0; i < count; i++) {
|
|
3238
|
+
if (!tg_distance_accum_line(accum, tg_geom_line_at(geom, i)))
|
|
3239
|
+
return false;
|
|
3240
|
+
}
|
|
3241
|
+
return true;
|
|
3242
|
+
}
|
|
3227
3243
|
|
|
3244
|
+
static bool tg_distance_accum_multipoly(tg_distance_accum_t *accum,
|
|
3245
|
+
const struct tg_geom *geom) {
|
|
3246
|
+
int count = tg_geom_num_polys(geom);
|
|
3247
|
+
for (int i = 0; i < count; i++) {
|
|
3248
|
+
if (!tg_distance_accum_poly(accum, tg_geom_poly_at(geom, i)))
|
|
3249
|
+
return false;
|
|
3250
|
+
}
|
|
3251
|
+
return true;
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
static bool tg_distance_accum_collection(tg_distance_accum_t *accum,
|
|
3255
|
+
const struct tg_geom *geom) {
|
|
3256
|
+
int count = tg_geom_num_geometries(geom);
|
|
3257
|
+
for (int i = 0; i < count; i++) {
|
|
3258
|
+
if (!tg_distance_accum_geom(accum, tg_geom_geometry_at(geom, i)))
|
|
3259
|
+
return false;
|
|
3260
|
+
}
|
|
3261
|
+
return true;
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3264
|
+
static bool tg_distance_accum_geom(tg_distance_accum_t *accum, const struct tg_geom *geom) {
|
|
3228
3265
|
if (!geom || tg_geom_is_empty(geom)) {
|
|
3229
3266
|
return true;
|
|
3230
3267
|
}
|
|
@@ -3234,39 +3271,18 @@ static bool tg_distance_accum_geom(tg_distance_accum_t *accum, const struct tg_g
|
|
|
3234
3271
|
tg_distance_accum_point(accum, tg_geom_point(geom));
|
|
3235
3272
|
return true;
|
|
3236
3273
|
case TG_MULTIPOINT:
|
|
3237
|
-
|
|
3238
|
-
for (int i = 0; i < count; i++) {
|
|
3239
|
-
tg_distance_accum_point(accum, tg_geom_point_at(geom, i));
|
|
3240
|
-
}
|
|
3274
|
+
tg_distance_accum_multipoint(accum, geom);
|
|
3241
3275
|
return true;
|
|
3242
3276
|
case TG_LINESTRING:
|
|
3243
3277
|
return tg_distance_accum_line(accum, tg_geom_line(geom));
|
|
3244
3278
|
case TG_MULTILINESTRING:
|
|
3245
|
-
|
|
3246
|
-
for (int i = 0; i < count; i++) {
|
|
3247
|
-
if (!tg_distance_accum_line(accum, tg_geom_line_at(geom, i))) {
|
|
3248
|
-
return false;
|
|
3249
|
-
}
|
|
3250
|
-
}
|
|
3251
|
-
return true;
|
|
3279
|
+
return tg_distance_accum_multiline(accum, geom);
|
|
3252
3280
|
case TG_POLYGON:
|
|
3253
3281
|
return tg_distance_accum_poly(accum, tg_geom_poly(geom));
|
|
3254
3282
|
case TG_MULTIPOLYGON:
|
|
3255
|
-
|
|
3256
|
-
for (int i = 0; i < count; i++) {
|
|
3257
|
-
if (!tg_distance_accum_poly(accum, tg_geom_poly_at(geom, i))) {
|
|
3258
|
-
return false;
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
|
-
return true;
|
|
3283
|
+
return tg_distance_accum_multipoly(accum, geom);
|
|
3262
3284
|
case TG_GEOMETRYCOLLECTION:
|
|
3263
|
-
|
|
3264
|
-
for (int i = 0; i < count; i++) {
|
|
3265
|
-
if (!tg_distance_accum_geom(accum, tg_geom_geometry_at(geom, i))) {
|
|
3266
|
-
return false;
|
|
3267
|
-
}
|
|
3268
|
-
}
|
|
3269
|
-
return true;
|
|
3285
|
+
return tg_distance_accum_collection(accum, geom);
|
|
3270
3286
|
}
|
|
3271
3287
|
|
|
3272
3288
|
return true;
|
|
@@ -4412,6 +4428,14 @@ typedef struct {
|
|
|
4412
4428
|
enum tg_index geometry_index;
|
|
4413
4429
|
} tg_index_build_args_t;
|
|
4414
4430
|
|
|
4431
|
+
typedef struct {
|
|
4432
|
+
VALUE entries;
|
|
4433
|
+
enum tg_geometry_index_via via;
|
|
4434
|
+
enum tg_geometry_index_strategy strategy;
|
|
4435
|
+
enum tg_geometry_index_predicate predicate;
|
|
4436
|
+
enum tg_index geometry_index;
|
|
4437
|
+
} tg_index_build_options_t;
|
|
4438
|
+
|
|
4415
4439
|
static void index_expand_bbox(tg_index_t *idx, struct tg_rect bbox) {
|
|
4416
4440
|
if (!idx->has_bbox) {
|
|
4417
4441
|
idx->bbox = bbox;
|
|
@@ -4586,30 +4610,20 @@ static VALUE index_build_body(VALUE arg) {
|
|
|
4586
4610
|
return Qnil;
|
|
4587
4611
|
}
|
|
4588
4612
|
|
|
4589
|
-
static
|
|
4590
|
-
VALUE entries_value;
|
|
4613
|
+
static void parse_index_build_options(int argc, VALUE *argv, tg_index_build_options_t *options) {
|
|
4591
4614
|
VALUE kwargs;
|
|
4592
4615
|
VALUE via_value;
|
|
4593
4616
|
VALUE strategy_value;
|
|
4594
4617
|
VALUE predicate_value;
|
|
4595
4618
|
VALUE geometry_index_value;
|
|
4596
|
-
enum tg_geometry_index_via via;
|
|
4597
|
-
enum tg_geometry_index_strategy strategy;
|
|
4598
|
-
enum tg_geometry_index_predicate predicate;
|
|
4599
|
-
enum tg_index geometry_index;
|
|
4600
|
-
long len;
|
|
4601
|
-
tg_index_t *idx;
|
|
4602
|
-
VALUE wrapper;
|
|
4603
|
-
tg_index_build_args_t args;
|
|
4604
|
-
int state = 0;
|
|
4605
4619
|
|
|
4606
|
-
rb_scan_args(argc, argv, "1:", &
|
|
4620
|
+
rb_scan_args(argc, argv, "1:", &options->entries, &kwargs);
|
|
4607
4621
|
{
|
|
4608
4622
|
ID allowed[] = {id_via, id_strategy, id_predicate, id_geometry_index};
|
|
4609
4623
|
validate_keywords(kwargs, allowed, sizeof(allowed) / sizeof(allowed[0]));
|
|
4610
4624
|
}
|
|
4611
4625
|
|
|
4612
|
-
if (!RB_TYPE_P(
|
|
4626
|
+
if (!RB_TYPE_P(options->entries, T_ARRAY)) {
|
|
4613
4627
|
rb_raise(rb_eTypeError, "entries must be Array");
|
|
4614
4628
|
}
|
|
4615
4629
|
|
|
@@ -4618,18 +4632,23 @@ static VALUE rb_tg_geometry_index_build(int argc, VALUE *argv, VALUE klass) {
|
|
|
4618
4632
|
predicate_value = kwargs_value(kwargs, id_predicate, ID2SYM(id_covers));
|
|
4619
4633
|
geometry_index_value = kwargs_value(kwargs, id_geometry_index, ID2SYM(id_ystripes));
|
|
4620
4634
|
|
|
4621
|
-
via = parse_index_via_symbol(via_value);
|
|
4622
|
-
strategy = parse_index_strategy_symbol(strategy_value);
|
|
4623
|
-
predicate = parse_index_predicate_symbol(predicate_value);
|
|
4624
|
-
geometry_index = parse_index_symbol(geometry_index_value);
|
|
4635
|
+
options->via = parse_index_via_symbol(via_value);
|
|
4636
|
+
options->strategy = parse_index_strategy_symbol(strategy_value);
|
|
4637
|
+
options->predicate = parse_index_predicate_symbol(predicate_value);
|
|
4638
|
+
options->geometry_index = parse_index_symbol(geometry_index_value);
|
|
4639
|
+
}
|
|
4640
|
+
|
|
4641
|
+
static VALUE allocate_index_wrapper(VALUE klass, const tg_index_build_options_t *options,
|
|
4642
|
+
tg_index_t **idx_out) {
|
|
4643
|
+
long len = RARRAY_LEN(options->entries);
|
|
4644
|
+
tg_index_t *idx;
|
|
4645
|
+
VALUE wrapper = TypedData_Make_Struct(klass, tg_index_t, &tg_index_type, idx);
|
|
4625
4646
|
|
|
4626
|
-
len = RARRAY_LEN(entries_value);
|
|
4627
|
-
wrapper = TypedData_Make_Struct(klass, tg_index_t, &tg_index_type, idx);
|
|
4628
4647
|
idx->len = len;
|
|
4629
4648
|
idx->capacity = len;
|
|
4630
4649
|
idx->initialized = 0;
|
|
4631
|
-
idx->strategy = strategy;
|
|
4632
|
-
idx->predicate = predicate;
|
|
4650
|
+
idx->strategy = options->strategy;
|
|
4651
|
+
idx->predicate = options->predicate;
|
|
4633
4652
|
idx->rtree = NULL;
|
|
4634
4653
|
idx->frozen = false;
|
|
4635
4654
|
idx->has_bbox = false;
|
|
@@ -4654,17 +4673,29 @@ static VALUE rb_tg_geometry_index_build(int argc, VALUE *argv, VALUE klass) {
|
|
|
4654
4673
|
idx->entries_bytes = (size_t)len * sizeof(tg_index_entry_t);
|
|
4655
4674
|
rb_gc_adjust_memory_usage((ssize_t)idx->entries_bytes);
|
|
4656
4675
|
}
|
|
4676
|
+
*idx_out = idx;
|
|
4677
|
+
return wrapper;
|
|
4678
|
+
}
|
|
4679
|
+
|
|
4680
|
+
static VALUE rb_tg_geometry_index_build(int argc, VALUE *argv, VALUE klass) {
|
|
4681
|
+
tg_index_build_options_t options;
|
|
4682
|
+
tg_index_build_args_t args;
|
|
4683
|
+
tg_index_t *idx;
|
|
4684
|
+
VALUE wrapper;
|
|
4685
|
+
int state = 0;
|
|
4657
4686
|
|
|
4687
|
+
parse_index_build_options(argc, argv, &options);
|
|
4688
|
+
wrapper = allocate_index_wrapper(klass, &options, &idx);
|
|
4658
4689
|
args.idx = idx;
|
|
4659
|
-
args.entries =
|
|
4660
|
-
args.via = via;
|
|
4661
|
-
args.geometry_index = geometry_index;
|
|
4690
|
+
args.entries = options.entries;
|
|
4691
|
+
args.via = options.via;
|
|
4692
|
+
args.geometry_index = options.geometry_index;
|
|
4662
4693
|
|
|
4663
4694
|
rb_protect(index_build_body, (VALUE)&args, &state);
|
|
4664
4695
|
|
|
4665
4696
|
if (state) {
|
|
4666
4697
|
index_dispose(idx);
|
|
4667
|
-
RB_GC_GUARD(
|
|
4698
|
+
RB_GC_GUARD(options.entries);
|
|
4668
4699
|
RB_GC_GUARD(wrapper);
|
|
4669
4700
|
rb_jump_tag(state);
|
|
4670
4701
|
}
|
|
@@ -4677,7 +4708,7 @@ static VALUE rb_tg_geometry_index_build(int argc, VALUE *argv, VALUE klass) {
|
|
|
4677
4708
|
idx->frozen = true;
|
|
4678
4709
|
rb_obj_freeze(wrapper);
|
|
4679
4710
|
|
|
4680
|
-
RB_GC_GUARD(
|
|
4711
|
+
RB_GC_GUARD(options.entries);
|
|
4681
4712
|
RB_GC_GUARD(wrapper);
|
|
4682
4713
|
return wrapper;
|
|
4683
4714
|
}
|
|
@@ -5474,26 +5505,15 @@ static bool fs_extract_id(fs_source_t *source, fs_options_t *opts, struct json f
|
|
|
5474
5505
|
return true;
|
|
5475
5506
|
}
|
|
5476
5507
|
|
|
5477
|
-
static bool
|
|
5478
|
-
|
|
5479
|
-
fs_feature_result_t *result) {
|
|
5508
|
+
static bool fs_feature_geometry_info(struct json feature, fs_feature_result_t *result,
|
|
5509
|
+
struct json *geometry_out, unsigned int *geom_bit_out) {
|
|
5480
5510
|
struct json geometry;
|
|
5481
5511
|
struct json geometry_type;
|
|
5482
|
-
struct json properties;
|
|
5483
|
-
unsigned int geom_bit;
|
|
5484
|
-
VALUE id = Qnil;
|
|
5485
|
-
VALUE error_message = Qnil;
|
|
5486
|
-
|
|
5487
|
-
memset(result, 0, sizeof(*result));
|
|
5488
|
-
result->feature = feature;
|
|
5489
|
-
result->id = Qnil;
|
|
5490
|
-
result->reason_value = Qnil;
|
|
5491
5512
|
|
|
5492
5513
|
if (!json_exists(feature) || json_type(feature) != JSON_OBJECT) {
|
|
5493
5514
|
result->reason = "feature is not an object";
|
|
5494
5515
|
return false;
|
|
5495
5516
|
}
|
|
5496
|
-
|
|
5497
5517
|
geometry = json_object_get(feature, "geometry");
|
|
5498
5518
|
if (!json_exists(geometry) || json_type(geometry) == JSON_NULL) {
|
|
5499
5519
|
result->reason = "missing geometry";
|
|
@@ -5510,12 +5530,50 @@ static bool fs_feature_prepare(fs_source_t *source, fs_options_t *opts, fs_mode_
|
|
|
5510
5530
|
return false;
|
|
5511
5531
|
}
|
|
5512
5532
|
|
|
5513
|
-
|
|
5514
|
-
if (
|
|
5533
|
+
*geom_bit_out = fs_geometry_type_bit(geometry_type);
|
|
5534
|
+
if (*geom_bit_out == 0) {
|
|
5515
5535
|
result->reason = "unsupported geometry.type";
|
|
5516
5536
|
return false;
|
|
5517
5537
|
}
|
|
5518
5538
|
|
|
5539
|
+
*geometry_out = geometry;
|
|
5540
|
+
return true;
|
|
5541
|
+
}
|
|
5542
|
+
|
|
5543
|
+
static bool fs_feature_prepare_properties(fs_mode_t mode, struct json feature,
|
|
5544
|
+
fs_feature_result_t *result) {
|
|
5545
|
+
struct json properties;
|
|
5546
|
+
|
|
5547
|
+
if (mode != FS_MODE_READ_FEATURES)
|
|
5548
|
+
return true;
|
|
5549
|
+
|
|
5550
|
+
properties = json_object_get(feature, "properties");
|
|
5551
|
+
if (json_exists(properties) && json_type(properties) != JSON_NULL &&
|
|
5552
|
+
json_type(properties) != JSON_OBJECT) {
|
|
5553
|
+
result->reason = "properties must be an object or null";
|
|
5554
|
+
return false;
|
|
5555
|
+
}
|
|
5556
|
+
|
|
5557
|
+
result->properties = properties;
|
|
5558
|
+
return true;
|
|
5559
|
+
}
|
|
5560
|
+
|
|
5561
|
+
static bool fs_feature_prepare(fs_source_t *source, fs_options_t *opts, fs_mode_t mode,
|
|
5562
|
+
struct json feature, long feature_index, bool materialize_id,
|
|
5563
|
+
fs_feature_result_t *result) {
|
|
5564
|
+
struct json geometry;
|
|
5565
|
+
unsigned int geom_bit;
|
|
5566
|
+
VALUE id = Qnil;
|
|
5567
|
+
VALUE error_message = Qnil;
|
|
5568
|
+
|
|
5569
|
+
memset(result, 0, sizeof(*result));
|
|
5570
|
+
result->feature = feature;
|
|
5571
|
+
result->id = Qnil;
|
|
5572
|
+
result->reason_value = Qnil;
|
|
5573
|
+
|
|
5574
|
+
if (!fs_feature_geometry_info(feature, result, &geometry, &geom_bit))
|
|
5575
|
+
return false;
|
|
5576
|
+
|
|
5519
5577
|
if (!opts->only_all && (opts->only_mask & geom_bit) == 0) {
|
|
5520
5578
|
result->filtered = true;
|
|
5521
5579
|
return true;
|
|
@@ -5527,16 +5585,8 @@ static bool fs_feature_prepare(fs_source_t *source, fs_options_t *opts, fs_mode_
|
|
|
5527
5585
|
return false;
|
|
5528
5586
|
}
|
|
5529
5587
|
|
|
5530
|
-
if (mode
|
|
5531
|
-
|
|
5532
|
-
if (!json_exists(properties) || json_type(properties) == JSON_NULL) {
|
|
5533
|
-
/* returned as "null" */
|
|
5534
|
-
} else if (json_type(properties) != JSON_OBJECT) {
|
|
5535
|
-
result->reason = "properties must be an object or null";
|
|
5536
|
-
return false;
|
|
5537
|
-
}
|
|
5538
|
-
result->properties = properties;
|
|
5539
|
-
}
|
|
5588
|
+
if (!fs_feature_prepare_properties(mode, feature, result))
|
|
5589
|
+
return false;
|
|
5540
5590
|
|
|
5541
5591
|
result->accepted = true;
|
|
5542
5592
|
result->id = id;
|
|
@@ -5964,21 +6014,16 @@ typedef struct {
|
|
|
5964
6014
|
const char *reason;
|
|
5965
6015
|
} fs_safe_feature_t;
|
|
5966
6016
|
|
|
5967
|
-
static bool
|
|
5968
|
-
|
|
6017
|
+
static bool fs_safe_feature_geometry_info(struct json feature, fs_safe_feature_t *out,
|
|
6018
|
+
struct json *geometry_out,
|
|
6019
|
+
unsigned int *geom_bit_out) {
|
|
5969
6020
|
struct json geometry;
|
|
5970
6021
|
struct json geometry_type;
|
|
5971
|
-
struct json properties;
|
|
5972
|
-
unsigned int geom_bit;
|
|
5973
|
-
|
|
5974
|
-
memset(out, 0, sizeof(*out));
|
|
5975
|
-
out->feature = feature;
|
|
5976
6022
|
|
|
5977
6023
|
if (!json_exists(feature) || json_type(feature) != JSON_OBJECT) {
|
|
5978
6024
|
out->reason = "feature is not an object";
|
|
5979
6025
|
return false;
|
|
5980
6026
|
}
|
|
5981
|
-
|
|
5982
6027
|
geometry = json_object_get(feature, "geometry");
|
|
5983
6028
|
if (!json_exists(geometry) || json_type(geometry) == JSON_NULL) {
|
|
5984
6029
|
out->reason = "missing geometry";
|
|
@@ -5995,12 +6040,46 @@ static bool fs_safe_prepare_feature(fs_safe_job_t *job, struct json feature, lon
|
|
|
5995
6040
|
return false;
|
|
5996
6041
|
}
|
|
5997
6042
|
|
|
5998
|
-
|
|
5999
|
-
if (
|
|
6043
|
+
*geom_bit_out = fs_safe_geometry_type_bit(geometry_type);
|
|
6044
|
+
if (*geom_bit_out == 0) {
|
|
6000
6045
|
out->reason = "unsupported geometry.type";
|
|
6001
6046
|
return false;
|
|
6002
6047
|
}
|
|
6003
6048
|
|
|
6049
|
+
*geometry_out = geometry;
|
|
6050
|
+
return true;
|
|
6051
|
+
}
|
|
6052
|
+
|
|
6053
|
+
static bool fs_safe_feature_properties(fs_mode_t mode, struct json feature,
|
|
6054
|
+
fs_safe_feature_t *out) {
|
|
6055
|
+
struct json properties;
|
|
6056
|
+
|
|
6057
|
+
if (mode != FS_MODE_READ_FEATURES)
|
|
6058
|
+
return true;
|
|
6059
|
+
|
|
6060
|
+
properties = json_object_get(feature, "properties");
|
|
6061
|
+
if (!json_exists(properties) || json_type(properties) == JSON_NULL) {
|
|
6062
|
+
out->properties_null = true;
|
|
6063
|
+
} else if (json_type(properties) != JSON_OBJECT) {
|
|
6064
|
+
out->reason = "properties must be an object or null";
|
|
6065
|
+
return false;
|
|
6066
|
+
} else {
|
|
6067
|
+
out->properties = properties;
|
|
6068
|
+
}
|
|
6069
|
+
return true;
|
|
6070
|
+
}
|
|
6071
|
+
|
|
6072
|
+
static bool fs_safe_prepare_feature(fs_safe_job_t *job, struct json feature, long feature_index,
|
|
6073
|
+
fs_mode_t mode, fs_safe_feature_t *out) {
|
|
6074
|
+
struct json geometry;
|
|
6075
|
+
unsigned int geom_bit;
|
|
6076
|
+
|
|
6077
|
+
memset(out, 0, sizeof(*out));
|
|
6078
|
+
out->feature = feature;
|
|
6079
|
+
|
|
6080
|
+
if (!fs_safe_feature_geometry_info(feature, out, &geometry, &geom_bit))
|
|
6081
|
+
return false;
|
|
6082
|
+
|
|
6004
6083
|
if (!job->opts.only_all && (job->opts.only_mask & geom_bit) == 0) {
|
|
6005
6084
|
out->filtered = true;
|
|
6006
6085
|
return true;
|
|
@@ -6011,17 +6090,8 @@ static bool fs_safe_prepare_feature(fs_safe_job_t *job, struct json feature, lon
|
|
|
6011
6090
|
return false;
|
|
6012
6091
|
}
|
|
6013
6092
|
|
|
6014
|
-
if (mode
|
|
6015
|
-
|
|
6016
|
-
if (!json_exists(properties) || json_type(properties) == JSON_NULL) {
|
|
6017
|
-
out->properties_null = true;
|
|
6018
|
-
} else if (json_type(properties) != JSON_OBJECT) {
|
|
6019
|
-
out->reason = "properties must be an object or null";
|
|
6020
|
-
return false;
|
|
6021
|
-
} else {
|
|
6022
|
-
out->properties = properties;
|
|
6023
|
-
}
|
|
6024
|
-
}
|
|
6093
|
+
if (!fs_safe_feature_properties(mode, feature, out))
|
|
6094
|
+
return false;
|
|
6025
6095
|
|
|
6026
6096
|
out->accepted = true;
|
|
6027
6097
|
out->geometry = geometry;
|
|
@@ -6275,78 +6345,87 @@ static bool fs_safe_fill_build(fs_safe_job_t *job, struct json features) {
|
|
|
6275
6345
|
return true;
|
|
6276
6346
|
}
|
|
6277
6347
|
|
|
6278
|
-
static bool
|
|
6279
|
-
|
|
6348
|
+
static bool fs_safe_allocate_read_buffer(fs_safe_job_t *job, int fd, char **buf_out,
|
|
6349
|
+
size_t *cap_out) {
|
|
6280
6350
|
struct stat st;
|
|
6281
|
-
char *buf = NULL;
|
|
6282
6351
|
size_t cap = 0;
|
|
6283
|
-
size_t len = 0;
|
|
6284
|
-
|
|
6285
|
-
fd = open(job->path, O_RDONLY);
|
|
6286
|
-
if (fd < 0) {
|
|
6287
|
-
fs_safe_set_system_error(job, errno);
|
|
6288
|
-
return false;
|
|
6289
|
-
}
|
|
6290
6352
|
|
|
6291
6353
|
if (fstat(fd, &st) == 0 && st.st_size >= 0) {
|
|
6292
6354
|
cap = (size_t)st.st_size;
|
|
6293
6355
|
if (cap > SIZE_MAX - 1) {
|
|
6294
|
-
close(fd);
|
|
6295
6356
|
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM, "FeatureSource file is too large");
|
|
6296
6357
|
return false;
|
|
6297
6358
|
}
|
|
6298
|
-
buf = (char *)malloc(cap + 1);
|
|
6299
|
-
if (!buf) {
|
|
6300
|
-
close(fd);
|
|
6301
|
-
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM, "FeatureSource file allocation failed");
|
|
6302
|
-
return false;
|
|
6303
|
-
}
|
|
6304
6359
|
} else {
|
|
6305
6360
|
cap = 8192;
|
|
6306
|
-
buf = (char *)malloc(cap + 1);
|
|
6307
|
-
if (!buf) {
|
|
6308
|
-
close(fd);
|
|
6309
|
-
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM, "FeatureSource file allocation failed");
|
|
6310
|
-
return false;
|
|
6311
|
-
}
|
|
6312
6361
|
}
|
|
6313
6362
|
|
|
6363
|
+
*buf_out = (char *)malloc(cap + 1);
|
|
6364
|
+
if (!*buf_out) {
|
|
6365
|
+
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM, "FeatureSource file allocation failed");
|
|
6366
|
+
return false;
|
|
6367
|
+
}
|
|
6368
|
+
*cap_out = cap;
|
|
6369
|
+
return true;
|
|
6370
|
+
}
|
|
6371
|
+
|
|
6372
|
+
static bool fs_safe_grow_read_buffer(fs_safe_job_t *job, char **buf, size_t *cap) {
|
|
6373
|
+
size_t new_cap = *cap < 8192 ? 8192 : *cap * 2;
|
|
6374
|
+
char *grown;
|
|
6375
|
+
|
|
6376
|
+
if (new_cap < *cap || new_cap > SIZE_MAX - 1) {
|
|
6377
|
+
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM, "FeatureSource file allocation overflow");
|
|
6378
|
+
return false;
|
|
6379
|
+
}
|
|
6380
|
+
grown = (char *)realloc(*buf, new_cap + 1);
|
|
6381
|
+
if (!grown) {
|
|
6382
|
+
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM, "FeatureSource file allocation failed");
|
|
6383
|
+
return false;
|
|
6384
|
+
}
|
|
6385
|
+
*buf = grown;
|
|
6386
|
+
*cap = new_cap;
|
|
6387
|
+
return true;
|
|
6388
|
+
}
|
|
6389
|
+
|
|
6390
|
+
static bool fs_safe_read_file_contents(fs_safe_job_t *job, int fd, char **buf, size_t *cap,
|
|
6391
|
+
size_t *len) {
|
|
6314
6392
|
for (;;) {
|
|
6315
6393
|
ssize_t n;
|
|
6316
|
-
if (len == cap) {
|
|
6317
|
-
|
|
6318
|
-
char *grown;
|
|
6319
|
-
if (new_cap < cap || new_cap > SIZE_MAX - 1) {
|
|
6320
|
-
free(buf);
|
|
6321
|
-
close(fd);
|
|
6322
|
-
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM,
|
|
6323
|
-
"FeatureSource file allocation overflow");
|
|
6324
|
-
return false;
|
|
6325
|
-
}
|
|
6326
|
-
grown = (char *)realloc(buf, new_cap + 1);
|
|
6327
|
-
if (!grown) {
|
|
6328
|
-
free(buf);
|
|
6329
|
-
close(fd);
|
|
6330
|
-
fs_safe_set_error(job, FS_SAFE_ERROR_NOMEM, "FeatureSource file allocation failed");
|
|
6394
|
+
if (*len == *cap) {
|
|
6395
|
+
if (!fs_safe_grow_read_buffer(job, buf, cap))
|
|
6331
6396
|
return false;
|
|
6332
|
-
}
|
|
6333
|
-
buf = grown;
|
|
6334
|
-
cap = new_cap;
|
|
6335
6397
|
}
|
|
6336
6398
|
|
|
6337
|
-
n = read(fd, buf + len, cap - len);
|
|
6399
|
+
n = read(fd, *buf + *len, *cap - *len);
|
|
6338
6400
|
if (n < 0) {
|
|
6339
6401
|
if (errno == EINTR)
|
|
6340
6402
|
continue;
|
|
6341
|
-
|
|
6342
|
-
free(buf);
|
|
6343
|
-
close(fd);
|
|
6344
|
-
fs_safe_set_system_error(job, err);
|
|
6403
|
+
fs_safe_set_system_error(job, errno);
|
|
6345
6404
|
return false;
|
|
6346
6405
|
}
|
|
6347
6406
|
if (n == 0)
|
|
6348
6407
|
break;
|
|
6349
|
-
len += (size_t)n;
|
|
6408
|
+
*len += (size_t)n;
|
|
6409
|
+
}
|
|
6410
|
+
|
|
6411
|
+
return true;
|
|
6412
|
+
}
|
|
6413
|
+
|
|
6414
|
+
static bool fs_safe_read_file_no_gvl(fs_safe_job_t *job) {
|
|
6415
|
+
int fd = open(job->path, O_RDONLY);
|
|
6416
|
+
char *buf = NULL;
|
|
6417
|
+
size_t cap = 0;
|
|
6418
|
+
size_t len = 0;
|
|
6419
|
+
|
|
6420
|
+
if (fd < 0) {
|
|
6421
|
+
fs_safe_set_system_error(job, errno);
|
|
6422
|
+
return false;
|
|
6423
|
+
}
|
|
6424
|
+
if (!fs_safe_allocate_read_buffer(job, fd, &buf, &cap) ||
|
|
6425
|
+
!fs_safe_read_file_contents(job, fd, &buf, &cap, &len)) {
|
|
6426
|
+
free(buf);
|
|
6427
|
+
close(fd);
|
|
6428
|
+
return false;
|
|
6350
6429
|
}
|
|
6351
6430
|
|
|
6352
6431
|
if (close(fd) != 0) {
|
|
@@ -7122,9 +7201,7 @@ static VALUE rb_tg_feature_source_build_index_io(int argc, VALUE *argv, VALUE se
|
|
|
7122
7201
|
return fs_safe_dispatch_json(json_string, kwargs, FS_MODE_BUILD_INDEX);
|
|
7123
7202
|
}
|
|
7124
7203
|
|
|
7125
|
-
|
|
7126
|
-
tg_geometry_vendor_header_sanity();
|
|
7127
|
-
|
|
7204
|
+
static void tg_geometry_init_ids(void) {
|
|
7128
7205
|
id_format = rb_intern("format");
|
|
7129
7206
|
id_index = rb_intern("index");
|
|
7130
7207
|
id_srid = rb_intern("srid");
|
|
@@ -7167,7 +7244,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7167
7244
|
id_exterior = rb_intern("exterior");
|
|
7168
7245
|
id_holes = rb_intern("holes");
|
|
7169
7246
|
id_sort = rb_intern("sort");
|
|
7247
|
+
}
|
|
7170
7248
|
|
|
7249
|
+
static void tg_geometry_init_core(void) {
|
|
7171
7250
|
mTG = rb_define_module("TG");
|
|
7172
7251
|
mTGGeometry = rb_define_module_under(mTG, "Geometry");
|
|
7173
7252
|
|
|
@@ -7200,7 +7279,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7200
7279
|
rb_define_singleton_method(mTGGeometry, "line_string", rb_tg_geometry_line_string, -1);
|
|
7201
7280
|
rb_define_singleton_method(mTGGeometry, "polygon", rb_tg_geometry_polygon, -1);
|
|
7202
7281
|
rb_define_singleton_method(mTGGeometry, "multi_polygon", rb_tg_geometry_multi_polygon, -1);
|
|
7282
|
+
}
|
|
7203
7283
|
|
|
7284
|
+
static void tg_geometry_init_geom(void) {
|
|
7204
7285
|
cTGGeometryGeom = rb_define_class_under(mTGGeometry, "Geom", rb_cObject);
|
|
7205
7286
|
rb_undef_alloc_func(cTGGeometryGeom);
|
|
7206
7287
|
rb_define_method(cTGGeometryGeom, "type", rb_tg_geometry_geom_type, 0);
|
|
@@ -7260,7 +7341,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7260
7341
|
rb_define_method(cTGGeometryGeom, "num_geometries", rb_tg_geometry_geom_num_geometries, 0);
|
|
7261
7342
|
rb_define_method(cTGGeometryGeom, "geometry_at", rb_tg_geometry_geom_geometry_at, 1);
|
|
7262
7343
|
rb_define_method(cTGGeometryGeom, "geometries", rb_tg_geometry_geom_geometries, 0);
|
|
7344
|
+
}
|
|
7263
7345
|
|
|
7346
|
+
static void tg_geometry_init_line(void) {
|
|
7264
7347
|
cTGGeometryLine = rb_define_class_under(mTGGeometry, "Line", rb_cObject);
|
|
7265
7348
|
rb_undef_alloc_func(cTGGeometryLine);
|
|
7266
7349
|
rb_define_method(cTGGeometryLine, "bbox", rb_tg_geometry_line_bbox, 0);
|
|
@@ -7273,7 +7356,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7273
7356
|
rb_define_method(cTGGeometryLine, "length", rb_tg_geometry_line_length, 0);
|
|
7274
7357
|
rb_define_method(cTGGeometryLine, "clockwise?", rb_tg_geometry_line_clockwise_p, 0);
|
|
7275
7358
|
rb_define_method(cTGGeometryLine, "nearest_segment", rb_tg_geometry_line_nearest_segment, 2);
|
|
7359
|
+
}
|
|
7276
7360
|
|
|
7361
|
+
static void tg_geometry_init_ring(void) {
|
|
7277
7362
|
cTGGeometryRing = rb_define_class_under(mTGGeometry, "Ring", rb_cObject);
|
|
7278
7363
|
rb_undef_alloc_func(cTGGeometryRing);
|
|
7279
7364
|
rb_define_method(cTGGeometryRing, "bbox", rb_tg_geometry_ring_bbox, 0);
|
|
@@ -7288,7 +7373,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7288
7373
|
rb_define_method(cTGGeometryRing, "clockwise?", rb_tg_geometry_ring_clockwise_p, 0);
|
|
7289
7374
|
rb_define_method(cTGGeometryRing, "convex?", rb_tg_geometry_ring_convex_p, 0);
|
|
7290
7375
|
rb_define_method(cTGGeometryRing, "nearest_segment", rb_tg_geometry_ring_nearest_segment, 2);
|
|
7376
|
+
}
|
|
7291
7377
|
|
|
7378
|
+
static void tg_geometry_init_polygon(void) {
|
|
7292
7379
|
cTGGeometryPolygon = rb_define_class_under(mTGGeometry, "Polygon", rb_cObject);
|
|
7293
7380
|
rb_undef_alloc_func(cTGGeometryPolygon);
|
|
7294
7381
|
rb_define_method(cTGGeometryPolygon, "bbox", rb_tg_geometry_polygon_bbox, 0);
|
|
@@ -7297,7 +7384,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7297
7384
|
rb_define_method(cTGGeometryPolygon, "hole_at", rb_tg_geometry_polygon_hole_at, 1);
|
|
7298
7385
|
rb_define_method(cTGGeometryPolygon, "holes", rb_tg_geometry_polygon_holes, 0);
|
|
7299
7386
|
rb_define_method(cTGGeometryPolygon, "clockwise?", rb_tg_geometry_polygon_clockwise_p, 0);
|
|
7387
|
+
}
|
|
7300
7388
|
|
|
7389
|
+
static void tg_geometry_init_segment(void) {
|
|
7301
7390
|
cTGGeometrySegment = rb_define_class_under(mTGGeometry, "Segment", rb_cObject);
|
|
7302
7391
|
rb_undef_alloc_func(cTGGeometrySegment);
|
|
7303
7392
|
rb_define_method(cTGGeometrySegment, "a", rb_tg_geometry_segment_a, 0);
|
|
@@ -7305,7 +7394,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7305
7394
|
rb_define_method(cTGGeometrySegment, "points", rb_tg_geometry_segment_points, 0);
|
|
7306
7395
|
rb_define_method(cTGGeometrySegment, "bbox", rb_tg_geometry_segment_bbox, 0);
|
|
7307
7396
|
rb_define_method(cTGGeometrySegment, "intersects?", rb_tg_geometry_segment_intersects_p, 1);
|
|
7397
|
+
}
|
|
7308
7398
|
|
|
7399
|
+
static void tg_geometry_init_nearest(void) {
|
|
7309
7400
|
cTGGeometryNearestSegment = rb_define_class_under(mTGGeometry, "NearestSegment", rb_cObject);
|
|
7310
7401
|
rb_undef_alloc_func(cTGGeometryNearestSegment);
|
|
7311
7402
|
rb_define_method(cTGGeometryNearestSegment, "segment", rb_tg_geometry_nearest_segment_segment,
|
|
@@ -7314,7 +7405,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7314
7405
|
rb_define_method(cTGGeometryNearestSegment, "distance", rb_tg_geometry_nearest_segment_distance,
|
|
7315
7406
|
0);
|
|
7316
7407
|
rb_define_method(cTGGeometryNearestSegment, "point", rb_tg_geometry_nearest_segment_point, 0);
|
|
7408
|
+
}
|
|
7317
7409
|
|
|
7410
|
+
static void tg_geometry_init_rect(void) {
|
|
7318
7411
|
cTGGeometryRect = rb_define_class_under(mTGGeometry, "Rect", rb_cObject);
|
|
7319
7412
|
rb_define_alloc_func(cTGGeometryRect, rb_tg_geometry_rect_alloc);
|
|
7320
7413
|
rb_define_method(cTGGeometryRect, "initialize", rb_tg_geometry_rect_initialize, -1);
|
|
@@ -7329,7 +7422,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7329
7422
|
1);
|
|
7330
7423
|
rb_define_method(cTGGeometryRect, "expand_to_include_point",
|
|
7331
7424
|
rb_tg_geometry_rect_expand_to_include_point, 2);
|
|
7425
|
+
}
|
|
7332
7426
|
|
|
7427
|
+
static void tg_geometry_init_feature_source(void) {
|
|
7333
7428
|
mTGGeometryFeatureSource = rb_define_module_under(mTGGeometry, "FeatureSource");
|
|
7334
7429
|
rb_define_singleton_method(mTGGeometryFeatureSource, "read_entries_file",
|
|
7335
7430
|
rb_tg_feature_source_read_entries_file, -1);
|
|
@@ -7349,7 +7444,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7349
7444
|
rb_tg_feature_source_build_index_json, -1);
|
|
7350
7445
|
rb_define_singleton_method(mTGGeometryFeatureSource, "build_index_io",
|
|
7351
7446
|
rb_tg_feature_source_build_index_io, -1);
|
|
7447
|
+
}
|
|
7352
7448
|
|
|
7449
|
+
static void tg_geometry_init_index(void) {
|
|
7353
7450
|
cTGGeometryIndex = rb_define_class_under(mTGGeometry, "Index", rb_cObject);
|
|
7354
7451
|
rb_undef_alloc_func(cTGGeometryIndex);
|
|
7355
7452
|
rb_define_singleton_method(cTGGeometryIndex, "build", rb_tg_geometry_index_build, -1);
|
|
@@ -7377,7 +7474,9 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7377
7474
|
rb_define_method(cTGGeometryIndex, "strategy", rb_tg_geometry_index_strategy, 0);
|
|
7378
7475
|
rb_define_method(cTGGeometryIndex, "predicate", rb_tg_geometry_index_predicate, 0);
|
|
7379
7476
|
rb_define_method(cTGGeometryIndex, "bbox", rb_tg_geometry_index_bbox, 0);
|
|
7477
|
+
}
|
|
7380
7478
|
|
|
7479
|
+
static void tg_geometry_init_debug(void) {
|
|
7381
7480
|
#ifdef TG_DEBUG_TEST
|
|
7382
7481
|
rb_define_singleton_method(mTGGeometry, "_debug_reset_test_hooks!",
|
|
7383
7482
|
rb_tg_geometry_debug_reset_test_hooks, 0);
|
|
@@ -7401,3 +7500,19 @@ RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
|
7401
7500
|
rb_tg_geometry_index_force_dispose_for_test, 0);
|
|
7402
7501
|
#endif
|
|
7403
7502
|
}
|
|
7503
|
+
|
|
7504
|
+
RUBY_FUNC_EXPORTED void Init_tg_geometry_ext_geometry_ext(void) {
|
|
7505
|
+
tg_geometry_vendor_header_sanity();
|
|
7506
|
+
tg_geometry_init_ids();
|
|
7507
|
+
tg_geometry_init_core();
|
|
7508
|
+
tg_geometry_init_geom();
|
|
7509
|
+
tg_geometry_init_line();
|
|
7510
|
+
tg_geometry_init_ring();
|
|
7511
|
+
tg_geometry_init_polygon();
|
|
7512
|
+
tg_geometry_init_segment();
|
|
7513
|
+
tg_geometry_init_nearest();
|
|
7514
|
+
tg_geometry_init_rect();
|
|
7515
|
+
tg_geometry_init_feature_source();
|
|
7516
|
+
tg_geometry_init_index();
|
|
7517
|
+
tg_geometry_init_debug();
|
|
7518
|
+
}
|
data/lib/tg/geometry/version.rb
CHANGED