Skip to content

Commit

Permalink
Serialization for coordsys objects; Partial support for prepared geoms
Browse files Browse the repository at this point in the history
  • Loading branch information
dazuma committed Jun 7, 2011
1 parent 8bf59e8 commit 8c12b7f
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 17 deletions.
5 changes: 5 additions & 0 deletions History.rdoc
@@ -1,3 +1,8 @@
=== 0.3.2 / 2011-06-06

* GEOS CAPI implementation can now use prepared geometries to speed up certain operations. The GEOS FFI implementation will do the same once I find out how ffi-geos will handle prepared geometries internally.
* Calling dup on a Proj4 object caused a segfault. Fixed.

=== 0.3.1 / 2011-05-24

* Running a == operator comparison between a geometry and a non-geometry caused an exception for some implementations. Fixed. (Reported by Daniel Hackney.)
Expand Down
2 changes: 2 additions & 0 deletions ext/geos_c_impl/extconf.rb
Expand Up @@ -74,6 +74,8 @@
else
$libs.gsub!(' -lgeos -lgeos_c', '')
end
have_func('GEOSPreparedContains_r', 'geos_c.h')
have_func('GEOSPreparedDisjoint_r', 'geos_c.h')
end
unless found_geos_
puts "**** WARNING: Unable to find GEOS headers or GEOS version is too old."
Expand Down
15 changes: 13 additions & 2 deletions ext/geos_c_impl/factory.c
Expand Up @@ -95,6 +95,10 @@ static void destroy_geometry_func(RGeo_GeometryData* data)
if (data->geom) {
GEOSGeom_destroy_r(data->geos_context, data->geom);
}
const GEOSPreparedGeometry* prep = data->prep;
if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
GEOSPreparedGeom_destroy_r(data->geos_context, prep);
}
free(data);
}

Expand Down Expand Up @@ -323,8 +327,10 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
if (geom) {
GEOSSetSRID_r(factory_context, geom, factory_data->srid);
}
data->geom = geom;
data->geos_context = factory_context;
data->geom = geom;
data->prep = factory_data && (factory_data->flags & RGEO_FACTORYFLAGS_PREPARE_HEURISTIC != 0) ?
(GEOSPreparedGeometry*)1 : NULL;
data->factory = factory;
data->klasses = klasses;
result = Data_Wrap_Struct(klass, mark_geometry_func, destroy_geometry_func, data);
Expand Down Expand Up @@ -380,8 +386,13 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, V
*klasses = CLASS_OF(object);
}
}
object_data->geom = NULL;
const GEOSPreparedGeometry* prep = object_data->prep;
if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
GEOSPreparedGeom_destroy_r(object_data->geos_context, prep);
}
object_data->geos_context = NULL;
object_data->geom = NULL;
object_data->prep = NULL;
object_data->factory = Qnil;
object_data->klasses = Qnil;
}
Expand Down
4 changes: 3 additions & 1 deletion ext/geos_c_impl/factory.h
Expand Up @@ -101,6 +101,7 @@ typedef struct {
#define RGEO_FACTORYFLAGS_SUPPORTS_Z 2
#define RGEO_FACTORYFLAGS_SUPPORTS_M 4
#define RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M 6
#define RGEO_FACTORYFLAGS_PREPARE_HEURISTIC 8


/*
Expand All @@ -125,8 +126,9 @@ typedef struct {
here so the destroy_geometry_func can get to it.
*/
typedef struct {
GEOSGeometry* geom;
GEOSContextHandle_t geos_context;
GEOSGeometry* geom;
const GEOSPreparedGeometry* prep;
VALUE factory;
VALUE klasses;
} RGeo_GeometryData;
Expand Down
126 changes: 113 additions & 13 deletions ext/geos_c_impl/geometry.c
Expand Up @@ -101,6 +101,28 @@ static int compute_dimension(GEOSContextHandle_t context, const GEOSGeometry* ge
}


// Returns a prepared geometry, honoring the preparation policy.

static const GEOSPreparedGeometry* rgeo_request_prepared_geometry(RGeo_GeometryData* object_data)
{
const GEOSPreparedGeometry* prep = object_data->prep;
if (prep == (GEOSPreparedGeometry*)1) {
object_data->prep = (GEOSPreparedGeometry*)2;
prep = NULL;
}
else if (prep == (GEOSPreparedGeometry*)2) {
if (object_data->geom) {
prep = GEOSPrepare(object_data->geom);
}
else {
prep = NULL;
}
object_data->prep = prep;
}
return prep;
}


/**** RUBY METHOD DEFINITIONS ****/


Expand All @@ -123,6 +145,26 @@ static VALUE method_geometry_set_factory(VALUE self, VALUE factory)
}


static VALUE method_geometry_prepared_p(VALUE self)
{
const GEOSPreparedGeometry* prep = RGEO_GEOMETRY_DATA_PTR(self)->prep;
return (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) ? Qtrue : Qfalse;
}


static VALUE method_geometry_prepare(VALUE self)
{
RGeo_GeometryData* self_data = RGEO_GEOMETRY_DATA_PTR(self);
if (self_data->geom) {
const GEOSPreparedGeometry* prep = self_data->prep;
if (!prep || prep == (GEOSPreparedGeometry*)1 || prep == (GEOSPreparedGeometry*)2) {
self_data->prep = GEOSPrepare(self_data->geom);
}
}
return self;
}


static VALUE method_geometry_dimension(VALUE self)
{
VALUE result = Qnil;
Expand Down Expand Up @@ -339,7 +381,14 @@ static VALUE method_geometry_disjoint(VALUE self, VALUE rhs)
if (self_geom) {
const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
if (rhs_geom) {
char val = GEOSDisjoint_r(self_data->geos_context, self_geom, rhs_geom);
char val;
#ifdef RGEO_GEOS_SUPPORTS_PREPARED2
const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
if (prep)
val = GEOSPreparedDisjoint_r(self_data->geos_context, prep, rhs_geom);
else
#endif
val = GEOSDisjoint_r(self_data->geos_context, self_geom, rhs_geom);
if (val == 0) {
result = Qfalse;
}
Expand All @@ -360,7 +409,14 @@ static VALUE method_geometry_intersects(VALUE self, VALUE rhs)
if (self_geom) {
const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
if (rhs_geom) {
char val = GEOSIntersects_r(self_data->geos_context, self_geom, rhs_geom);
char val;
#ifdef RGEO_GEOS_SUPPORTS_PREPARED1
const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
if (prep)
val = GEOSPreparedIntersects_r(self_data->geos_context, prep, rhs_geom);
else
#endif
val = GEOSIntersects_r(self_data->geos_context, self_geom, rhs_geom);
if (val == 0) {
result = Qfalse;
}
Expand All @@ -381,7 +437,14 @@ static VALUE method_geometry_touches(VALUE self, VALUE rhs)
if (self_geom) {
const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
if (rhs_geom) {
char val = GEOSTouches_r(self_data->geos_context, self_geom, rhs_geom);
char val;
#ifdef RGEO_GEOS_SUPPORTS_PREPARED2
const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
if (prep)
val = GEOSPreparedTouches_r(self_data->geos_context, prep, rhs_geom);
else
#endif
val = GEOSTouches_r(self_data->geos_context, self_geom, rhs_geom);
if (val == 0) {
result = Qfalse;
}
Expand All @@ -402,7 +465,14 @@ static VALUE method_geometry_crosses(VALUE self, VALUE rhs)
if (self_geom) {
const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
if (rhs_geom) {
char val = GEOSCrosses_r(self_data->geos_context, self_geom, rhs_geom);
char val;
#ifdef RGEO_GEOS_SUPPORTS_PREPARED2
const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
if (prep)
val = GEOSPreparedCrosses_r(self_data->geos_context, prep, rhs_geom);
else
#endif
val = GEOSCrosses_r(self_data->geos_context, self_geom, rhs_geom);
if (val == 0) {
result = Qfalse;
}
Expand All @@ -423,7 +493,14 @@ static VALUE method_geometry_within(VALUE self, VALUE rhs)
if (self_geom) {
const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
if (rhs_geom) {
char val = GEOSWithin_r(self_data->geos_context, self_geom, rhs_geom);
char val;
#ifdef RGEO_GEOS_SUPPORTS_PREPARED2
const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
if (prep)
val = GEOSPreparedWithin_r(self_data->geos_context, prep, rhs_geom);
else
#endif
val = GEOSWithin_r(self_data->geos_context, self_geom, rhs_geom);
if (val == 0) {
result = Qfalse;
}
Expand All @@ -444,7 +521,14 @@ static VALUE method_geometry_contains(VALUE self, VALUE rhs)
if (self_geom) {
const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
if (rhs_geom) {
char val = GEOSContains_r(self_data->geos_context, self_geom, rhs_geom);
char val;
#ifdef RGEO_GEOS_SUPPORTS_PREPARED1
const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
if (prep)
val = GEOSPreparedContains_r(self_data->geos_context, prep, rhs_geom);
else
#endif
val = GEOSContains_r(self_data->geos_context, self_geom, rhs_geom);
if (val == 0) {
result = Qfalse;
}
Expand All @@ -465,7 +549,14 @@ static VALUE method_geometry_overlaps(VALUE self, VALUE rhs)
if (self_geom) {
const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
if (rhs_geom) {
char val = GEOSOverlaps_r(self_data->geos_context, self_geom, rhs_geom);
char val;
#ifdef RGEO_GEOS_SUPPORTS_PREPARED2
const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
if (prep)
val = GEOSPreparedOverlaps_r(self_data->geos_context, prep, rhs_geom);
else
#endif
val = GEOSOverlaps_r(self_data->geos_context, self_geom, rhs_geom);
if (val == 0) {
result = Qfalse;
}
Expand Down Expand Up @@ -617,14 +708,18 @@ static VALUE method_geometry_initialize_copy(VALUE self, VALUE orig)
{
// Clear out any existing value
RGeo_GeometryData* self_data = RGEO_GEOMETRY_DATA_PTR(self);
GEOSGeometry* self_geom = self_data->geom;
if (self_geom) {
GEOSGeom_destroy_r(self_data->geos_context, self_geom);
if (self_data->geom) {
GEOSGeom_destroy_r(self_data->geos_context, self_data->geom);
self_data->geom = NULL;
self_data->geos_context = NULL;
self_data->factory = Qnil;
self_data->klasses = Qnil;
}
const GEOSPreparedGeometry* prep = self_data->prep;
if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
GEOSPreparedGeom_destroy_r(self_data->geos_context, prep);
}
self_data->prep = NULL;
self_data->geos_context = NULL;
self_data->factory = Qnil;
self_data->klasses = Qnil;

// Copy value from orig
const GEOSGeometry* geom = rgeo_get_geos_geometry_safe(orig);
Expand All @@ -633,9 +728,12 @@ static VALUE method_geometry_initialize_copy(VALUE self, VALUE orig)
GEOSContextHandle_t orig_context = orig_data->geos_context;
GEOSGeometry* clone_geom = GEOSGeom_clone_r(orig_context, geom);
if (clone_geom) {
RGeo_FactoryData* factory_data = RGEO_FACTORY_DATA_PTR(orig_data->factory);
GEOSSetSRID_r(orig_context, clone_geom, GEOSGetSRID_r(orig_context, geom));
self_data->geom = clone_geom;
self_data->geos_context = orig_context;
self_data->prep = factory_data && (factory_data->flags & RGEO_FACTORYFLAGS_PREPARE_HEURISTIC != 0) ?
(GEOSPreparedGeometry*)1 : NULL;
self_data->factory = orig_data->factory;
self_data->klasses = orig_data->klasses;
}
Expand All @@ -660,6 +758,8 @@ void rgeo_init_geos_geometry(RGeo_Globals* globals)
rb_define_method(geos_geometry_class, "initialize_copy", method_geometry_initialize_copy, 1);
rb_define_method(geos_geometry_class, "initialized?", method_geometry_initialized_p, 0);
rb_define_method(geos_geometry_class, "factory", method_geometry_factory, 0);
rb_define_method(geos_geometry_class, "prepared?", method_geometry_prepared_p, 0);
rb_define_method(geos_geometry_class, "prepare!", method_geometry_prepare, 0);
rb_define_method(geos_geometry_class, "dimension", method_geometry_dimension, 0);
rb_define_method(geos_geometry_class, "geometry_type", method_geometry_geometry_type, 0);
rb_define_method(geos_geometry_class, "srid", method_geometry_srid, 0);
Expand Down
7 changes: 7 additions & 0 deletions ext/geos_c_impl/preface.h
Expand Up @@ -41,6 +41,13 @@
#endif
#endif

#ifdef HAVE_GEOSPREPAREDCONTAINS_R
#define RGEO_GEOS_SUPPORTS_PREPARED1
#endif
#ifdef HAVE_GEOSPREPAREDDISJOINT_R
#define RGEO_GEOS_SUPPORTS_PREPARED2
#endif

#ifdef __cplusplus
#define RGEO_BEGIN_C extern "C" {
#define RGEO_END_C }
Expand Down
34 changes: 33 additions & 1 deletion ext/proj4_c_impl/main.c
Expand Up @@ -120,14 +120,43 @@ static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig)

// Copy value from orig
RGeo_Proj4Data* orig_data = RGEO_PROJ4_DATA_PTR(orig);
self_data->pj = orig_data->pj;
if (!NIL_P(orig_data->original_str)) {
self_data->pj = pj_init_plus(RSTRING_PTR(orig_data->original_str));
}
else {
char* str = pj_get_def(orig_data->pj, 0);
self_data->pj = pj_init_plus(str);
pj_dalloc(str);
}
self_data->original_str = orig_data->original_str;
self_data->uses_radians = orig_data->uses_radians;

return self;
}


static VALUE method_proj4_set_value(VALUE self, VALUE str, VALUE uses_radians)
{
Check_Type(str, T_STRING);

// Clear out any existing value
RGeo_Proj4Data* self_data = RGEO_PROJ4_DATA_PTR(self);
projPJ pj = self_data->pj;
if (pj) {
pj_free(pj);
self_data->pj = NULL;
self_data->original_str = Qnil;
}

// Set new data
self_data->pj = pj_init_plus(RSTRING_PTR(str));
self_data->original_str = str;
self_data->uses_radians = RTEST(uses_radians) ? 1 : 0;

return self;
}


static VALUE method_proj4_get_geographic(VALUE self)
{
VALUE result = Qnil;
Expand Down Expand Up @@ -244,8 +273,11 @@ static void rgeo_init_proj4()
VALUE rgeo_module = rb_define_module("RGeo");
VALUE coordsys_module = rb_define_module_under(rgeo_module, "CoordSys");
VALUE proj4_class = rb_define_class_under(coordsys_module, "Proj4", rb_cObject);

rb_define_alloc_func(proj4_class, alloc_proj4);
rb_define_module_function(proj4_class, "_create", cmethod_proj4_create, 2);
rb_define_method(proj4_class, "initialize_copy", method_proj4_initialize_copy, 1);
rb_define_method(proj4_class, "_set_value", method_proj4_set_value, 2);
rb_define_method(proj4_class, "_original_str", method_proj4_original_str, 0);
rb_define_method(proj4_class, "_canonical_str", method_proj4_canonical_str, 0);
rb_define_method(proj4_class, "_valid?", method_proj4_is_valid, 0);
Expand Down

0 comments on commit 8c12b7f

Please sign in to comment.