Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Segmentize for GeosCapi geometries. #364

Merged
merged 9 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions History.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Fix Naming/VariableNumber from rubocop_todos. (@haroon26) #351
* Fix Lint/MissingSuper from rubocop_todos. (@haroon26) #352
* Drop support for Ruby 2.6. (@seuros) #353
* Add `segmentize` method to CAPI geometires (@arkirchner) #364

**Bug Fixes**

Expand Down
1 change: 1 addition & 0 deletions ext/geos_c_impl/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def create_dummy_makefile
have_func("GEOSPreparedDisjoint_r", "geos_c.h")
have_func("GEOSUnaryUnion_r", "geos_c.h")
have_func("GEOSCoordSeq_isCCW_r", "geos_c.h")
have_func("GEOSDensify", "geos_c.h")
have_func("rb_memhash", "ruby.h")
have_func("rb_gc_mark_movable", "ruby.h")
end
Expand Down
25 changes: 25 additions & 0 deletions ext/geos_c_impl/geometry.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,27 @@ method_geometry_buffer(VALUE self, VALUE distance)
return result;
}

#ifdef RGEO_GEOS_SUPPORTS_DENSIFY
static VALUE
method_geometry_segmentize(VALUE self, VALUE max_segment_length)
{
VALUE result;
RGeo_GeometryData* self_data;
const GEOSGeometry* self_geom;
VALUE factory;

result = Qnil;
self_data = RGEO_GEOMETRY_DATA_PTR(self);
self_geom = self_data->geom;
if (self_geom) {
factory = self_data->factory;
result = rgeo_wrap_geos_geometry(
factory, GEOSDensify(self_geom, rb_num2dbl(max_segment_length)), Qnil);
}
return result;
}
#endif

static VALUE
method_geometry_buffer_with_style(VALUE self,
VALUE distance,
Expand Down Expand Up @@ -1308,6 +1329,10 @@ rgeo_init_geos_geometry()
geos_geometry_methods, "make_valid", method_geometry_make_valid, 0);
rb_define_method(
geos_geometry_methods, "polygonize", method_geometry_polygonize, 0);
#ifdef RGEO_GEOS_SUPPORTS_DENSIFY
rb_define_method(
geos_geometry_methods, "segmentize", method_geometry_segmentize, 1);
#endif
}

RGEO_END_C
Expand Down
3 changes: 3 additions & 0 deletions ext/geos_c_impl/preface.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#ifdef HAVE_GEOSCOORDSEQ_ISCCW_R
#define RGEO_GEOS_SUPPORTS_ISCCW
#endif
#ifdef HAVE_GEOSDENSIFY
#define RGEO_GEOS_SUPPORTS_DENSIFY
#endif
#ifdef HAVE_RB_GC_MARK_MOVABLE
#define mark rb_gc_mark_movable
#else
Expand Down
15 changes: 15 additions & 0 deletions test/geos_capi/line_string_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
# -----------------------------------------------------------------------------

require_relative "../test_helper"
require_relative "./skip_capi"

class GeosLineStringTest < Minitest::Test # :nodoc:
include RGeo::Tests::Common::LineStringTests
prepend SkipCAPI

def setup
skip "CAPI not supported" unless RGeo::Geos.capi_supported?
Expand Down Expand Up @@ -52,4 +54,17 @@ def test_polygonize_dangle

assert_equal expected, input.polygonize
end

def test_segmentize
skip_geos_version_less_then("3.10")

input = @factory.parse_wkt("LINESTRING(0 0, 0 10)")
expected = @factory.parse_wkt("LINESTRING (0 0, 0 5, 0 10)")

assert_equal expected, input.segmentize(5)

assert_raises(TypeError, "no implicit conversion to float from string") { input.segmentize("a") }
assert_raises(TypeError, "no implicit conversion to float from nil") { input.segmentize(nil) }
assert_raises(RGeo::Error::InvalidGeometry, "Tolerance must be positive") { input.segmentize(0) }
end
end
13 changes: 13 additions & 0 deletions test/geos_capi/polygon_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,17 @@ def test_polygonize

assert_equal expected, input.polygonize
end

def test_segmentize
skip_geos_version_less_then("3.10")

input = @factory.parse_wkt("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
expected = @factory.parse_wkt("POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0))")

assert_equal expected, input.segmentize(5)

assert_raises(TypeError, "no implicit conversion to float from string") { input.segmentize("a") }
assert_raises(TypeError, "no implicit conversion to float from nil") { input.segmentize(nil) }
assert_raises(RGeo::Error::InvalidGeometry, "Tolerance must be positive") { input.segmentize(0) }
end
end
6 changes: 6 additions & 0 deletions test/geos_capi/skip_capi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@ def setup
skip "Needs GEOS CAPI." unless RGeo::Geos.capi_supported?
super
end

def skip_geos_version_less_then(version)
return if Gem::Version.new(RGeo::Geos.version) >= Gem::Version.new(version)

skip "Needs GEOS version #{version} or later."
end
end