Class: TG::Geometry::Index

Inherits:
Object
  • Object
show all
Defined in:
lib/tg/geometry.rb,
ext/tg_geometry/tg_geometry_ext.c

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.build(*args) ⇒ Object



3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3768

static VALUE rb_tg_geometry_index_build(int argc, VALUE *argv, VALUE klass) {
    VALUE entries_value;
    VALUE kwargs;
    VALUE via_value;
    VALUE strategy_value;
    VALUE predicate_value;
    VALUE geometry_index_value;
    enum tg_geometry_index_via via;
    enum tg_geometry_index_strategy strategy;
    enum tg_geometry_index_predicate predicate;
    enum tg_index geometry_index;
    long len;
    tg_index_t *idx;
    VALUE wrapper;
    tg_index_build_args_t args;
    int state = 0;

    rb_scan_args(argc, argv, "1:", &entries_value, &kwargs);
    {
        ID allowed[] = {id_via, id_strategy, id_predicate, id_geometry_index};
        validate_keywords(kwargs, allowed, sizeof(allowed) / sizeof(allowed[0]));
    }

    if (!RB_TYPE_P(entries_value, T_ARRAY)) {
        rb_raise(rb_eTypeError, "entries must be Array");
    }

    via_value = required_kwargs_value(kwargs, id_via, "via:");
    strategy_value = required_kwargs_value(kwargs, id_strategy, "strategy:");
    predicate_value = kwargs_value(kwargs, id_predicate, ID2SYM(id_covers));
    geometry_index_value = kwargs_value(kwargs, id_geometry_index, ID2SYM(id_ystripes));

    via = parse_index_via_symbol(via_value);
    strategy = parse_index_strategy_symbol(strategy_value);
    predicate = parse_index_predicate_symbol(predicate_value);
    geometry_index = parse_index_symbol(geometry_index_value);

    len = RARRAY_LEN(entries_value);
    wrapper = TypedData_Make_Struct(klass, tg_index_t, &tg_index_type, idx);
    idx->len = len;
    idx->capacity = len;
    idx->initialized = 0;
    idx->strategy = strategy;
    idx->predicate = predicate;
    idx->rtree = NULL;
    idx->frozen = false;
    idx->has_bbox = false;

    if (len > 0) {
        if ((size_t)len > SIZE_MAX / sizeof(tg_index_entry_t)) {
            rb_raise(rb_eNoMemError, "entries allocation size overflow");
        }

#ifdef TG_DEBUG_TEST
        if (tg_debug_fail_next_entries_alloc) {
            tg_debug_fail_next_entries_alloc = false;
            rb_raise(rb_eNoMemError, "entries allocation failed");
        }
#endif

        idx->entries = calloc((size_t)len, sizeof(tg_index_entry_t));
        if (!idx->entries) {
            rb_raise(rb_eNoMemError, "entries allocation failed");
        }

        idx->entries_bytes = (size_t)len * sizeof(tg_index_entry_t);
        rb_gc_adjust_memory_usage((ssize_t)idx->entries_bytes);
    }

    args.idx = idx;
    args.entries = entries_value;
    args.via = via;
    args.geometry_index = geometry_index;

    rb_protect(index_build_body, (VALUE)&args, &state);

    if (state) {
        index_dispose(idx);
        RB_GC_GUARD(entries_value);
        RB_GC_GUARD(wrapper);
        rb_jump_tag(state);
    }

    if (idx->initialized != idx->len) {
        index_dispose(idx);
        rb_raise(eTGGeometryError, "internal index build initialization mismatch");
    }

    idx->frozen = true;
    rb_obj_freeze(wrapper);

    RB_GC_GUARD(entries_value);
    RB_GC_GUARD(wrapper);
    return wrapper;
}

Instance Method Details

#_entries_bytes_for_testObject



4047
4048
4049
4050
# File 'ext/tg_geometry/tg_geometry_ext.c', line 4047

static VALUE rb_tg_geometry_index_entries_bytes_for_test(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);
    return ULL2NUM((unsigned long long)idx->entries_bytes);
}

#_force_dispose_for_test!Object



4062
4063
4064
4065
4066
# File 'ext/tg_geometry/tg_geometry_ext.c', line 4062

static VALUE rb_tg_geometry_index_force_dispose_for_test(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);
    index_dispose(idx);
    return Qnil;
}

#_initialized_entries_for_testObject



4057
4058
4059
4060
# File 'ext/tg_geometry/tg_geometry_ext.c', line 4057

static VALUE rb_tg_geometry_index_initialized_entries_for_test(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);
    return LONG2NUM(idx->initialized);
}

#_owned_geom_bytes_for_testObject



4052
4053
4054
4055
# File 'ext/tg_geometry/tg_geometry_ext.c', line 4052

static VALUE rb_tg_geometry_index_owned_geom_bytes_for_test(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);
    return ULL2NUM((unsigned long long)idx->owned_geom_bytes_total);
}

#_rtree_bytes_for_testObject



4042
4043
4044
4045
# File 'ext/tg_geometry/tg_geometry_ext.c', line 4042

static VALUE rb_tg_geometry_index_rtree_bytes_for_test(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);
    return ULL2NUM((unsigned long long)idx->rtree_bytes);
}

#bboxObject



3895
3896
3897
3898
3899
3900
3901
3902
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3895

static VALUE rb_tg_geometry_index_bbox(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);

    if (!idx->has_bbox)
        return Qnil;

    return rect_from_tg_rect(idx->bbox);
}

#containing_geom_ids(geom) ⇒ Object



3583
3584
3585
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3583

static VALUE rb_tg_geometry_index_containing_geom_ids(VALUE self, VALUE geom) {
    return index_geom_query_ids(self, geom, TG_GEOMETRY_GEOM_QUERY_CONTAINS);
}

#covering_geom_ids(geom) ⇒ Object



3579
3580
3581
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3579

static VALUE rb_tg_geometry_index_covering_geom_ids(VALUE self, VALUE geom) {
    return index_geom_query_ids(self, geom, TG_GEOMETRY_GEOM_QUERY_COVERS);
}

#covering_ids(lon_value, lat_value) ⇒ Object



3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3924

static VALUE rb_tg_geometry_index_covering_ids(VALUE self, VALUE lon_value, VALUE lat_value) {
    tg_index_t *idx = get_index_wrapper(self);
    double lon;
    double lat;
    unsigned char *marks;
    VALUE result;

    parse_public_point_args(lon_value, lat_value, &lon, &lat);
    marks = index_covering_marks(idx, lon, lat);
    result = build_ids_from_marks_protected(idx, marks);

    RB_GC_GUARD(self);
    return result;
}

#covering_ids_batch_packed(input) ⇒ Object



3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3961

static VALUE rb_tg_geometry_index_covering_ids_batch_packed(VALUE self, VALUE input) {
    tg_index_t *idx = get_index_wrapper(self);
    const char *data;
    long byte_len;
    long count;
    VALUE result;

    if (!RB_TYPE_P(input, T_STRING)) {
        rb_raise(rb_eTypeError, "packed input must be String");
    }

    byte_len = RSTRING_LEN(input);
    if (byte_len % (long)(2 * sizeof(double)) != 0) {
        rb_raise(eTGGeometryArgumentError, "packed input length must be multiple of 16 bytes");
    }

    count = byte_len / (long)(2 * sizeof(double));
    result = rb_ary_new_capa(count);
    data = RSTRING_PTR(input);

    for (long i = 0; i < count; i++) {
        double lon;
        double lat;
        VALUE id;

        memcpy(&lon, data + (i * (long)(2 * sizeof(double))), sizeof(double));
        memcpy(&lat, data + (i * (long)(2 * sizeof(double))) + (long)sizeof(double),
               sizeof(double));

        check_finite_double(lon, "lon");
        check_finite_double(lat, "lat");

        id = index_find_covering_value(idx, lon, lat);
        rb_ary_push(result, id);
    }

    RB_GC_GUARD(input);
    RB_GC_GUARD(self);
    RB_GC_GUARD(result);
    return result;
}

#find_covering(lon_value, lat_value) ⇒ Object



3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3911

static VALUE rb_tg_geometry_index_find_covering(VALUE self, VALUE lon_value, VALUE lat_value) {
    tg_index_t *idx = get_index_wrapper(self);
    double lon;
    double lat;
    VALUE result;

    parse_public_point_args(lon_value, lat_value, &lon, &lat);
    result = index_find_covering_value(idx, lon, lat);

    RB_GC_GUARD(self);
    return result;
}

#intersecting_geom_ids(geom) ⇒ Object



3575
3576
3577
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3575

static VALUE rb_tg_geometry_index_intersecting_geom_ids(VALUE self, VALUE geom) {
    return index_geom_query_ids(self, geom, TG_GEOMETRY_GEOM_QUERY_INTERSECTS);
}

#intersecting_rect(min_x_value, min_y_value, max_x_value, max_y_value) ⇒ Object



3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3939

static VALUE rb_tg_geometry_index_intersecting_rect(VALUE self, VALUE min_x_value,
                                                    VALUE min_y_value, VALUE max_x_value,
                                                    VALUE max_y_value) {
    tg_index_t *idx = get_index_wrapper(self);
    double min_x = NUM2DBL(min_x_value);
    double min_y = NUM2DBL(min_y_value);
    double max_x = NUM2DBL(max_x_value);
    double max_y = NUM2DBL(max_y_value);
    struct tg_rect query_rect;
    unsigned char *marks;
    VALUE result;

    validate_rect_coordinates(min_x, min_y, max_x, max_y);
    query_rect = tg_rect_from_xyxy(min_x, min_y, max_x, max_y);

    marks = index_intersecting_rect_marks(idx, query_rect);
    result = build_ids_from_marks_protected(idx, marks);

    RB_GC_GUARD(self);
    return result;
}

#predicateObject



3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3882

static VALUE rb_tg_geometry_index_predicate(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);

    switch (idx->predicate) {
    case TG_GEOMETRY_INDEX_PREDICATE_COVERS:
        return ID2SYM(id_covers);
    case TG_GEOMETRY_INDEX_PREDICATE_CONTAINS:
        return ID2SYM(id_contains);
    }

    return Qnil;
}

#sizeObject



3864
3865
3866
3867
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3864

static VALUE rb_tg_geometry_index_size(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);
    return LONG2NUM(idx->len);
}

#strategyObject



3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
# File 'ext/tg_geometry/tg_geometry_ext.c', line 3869

static VALUE rb_tg_geometry_index_strategy(VALUE self) {
    tg_index_t *idx = get_index_wrapper(self);

    switch (idx->strategy) {
    case TG_GEOMETRY_INDEX_STRATEGY_FLAT:
        return ID2SYM(id_flat);
    case TG_GEOMETRY_INDEX_STRATEGY_RTREE:
        return ID2SYM(id_rtree);
    }

    return Qnil;
}