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

Geos ccw analysis #229

Merged
merged 8 commits into from Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 14 additions & 1 deletion ext/geos_c_impl/analysis.c
Expand Up @@ -24,9 +24,11 @@ RGEO_BEGIN_C
*/
VALUE rgeo_geos_analysis_ccw_p(VALUE self, VALUE ring)
{
char is_ccw = 0;
#ifdef RGEO_GEOS_SUPPORTS_ISCCW
BuonOmo marked this conversation as resolved.
Show resolved Hide resolved

const RGeo_GeometryData* ring_data;
const GEOSCoordSequence* coord_seq;
char is_ccw;

rgeo_check_geos_object(ring);

Expand All @@ -37,17 +39,28 @@ VALUE rgeo_geos_analysis_ccw_p(VALUE self, VALUE ring)
if (!GEOSCoordSeq_isCCW_r(ring_data->geos_context, coord_seq, &is_ccw)) {
rb_raise(geos_error, "Could not determine if the CoordSeq is CCW.");
}
#endif // RGEO_GEOS_SUPPORTS_ISCCW

return is_ccw ? Qtrue : Qfalse;
};

static VALUE rgeo_geos_analysis_supports_ccw(VALUE self)
BuonOmo marked this conversation as resolved.
Show resolved Hide resolved
{
#ifdef RGEO_GEOS_SUPPORTS_ISCCW
return Qtrue;
#else
return Qfalse;
#endif
}


void rgeo_init_geos_analysis(RGeo_Globals* globals)
{
VALUE geos_analysis_module;

geos_analysis_module = rb_define_module_under(globals->geos_module, "Analysis");
rb_define_singleton_method(geos_analysis_module, "ccw?", rgeo_geos_analysis_ccw_p, 1);
rb_define_singleton_method(geos_analysis_module, "ccw_supported?", rgeo_geos_analysis_supports_ccw, 0);
}

RGEO_END_C
Expand Down
2 changes: 1 addition & 1 deletion ext/geos_c_impl/errors.c
Expand Up @@ -12,7 +12,7 @@

RGEO_BEGIN_C

// Anay error relative to RGeo.
// Any error relative to RGeo.
VALUE rgeo_error;
// RGeo error specific to the GEOS implementation.
VALUE geos_error;
Expand Down
2 changes: 1 addition & 1 deletion ext/geos_c_impl/errors.h
Expand Up @@ -8,7 +8,7 @@

RGEO_BEGIN_C

// Anay error relative to RGeo.
// Any error relative to RGeo.
extern VALUE rgeo_error;
// RGeo error specific to the GEOS implementation.
extern VALUE geos_error;
Expand Down
1 change: 1 addition & 0 deletions ext/geos_c_impl/extconf.rb
Expand Up @@ -31,6 +31,7 @@ def create_dummy_makefile
have_func("GEOSPreparedContains_r", "geos_c.h")
have_func("GEOSPreparedDisjoint_r", "geos_c.h")
have_func("GEOSUnaryUnion_r", "geos_c.h")
have_func("GEOSCoordSeq_isCCW_r", "geos_c.h")
have_func("rb_memhash", "ruby.h")
end

Expand Down
3 changes: 3 additions & 0 deletions ext/geos_c_impl/preface.h
Expand Up @@ -21,6 +21,9 @@
#ifdef HAVE_GEOSUNARYUNION_R
#define RGEO_GEOS_SUPPORTS_UNARYUNION
#endif
#ifdef HAVE_GEOSCOORDSEQ_ISCCW_R
#define RGEO_GEOS_SUPPORTS_ISCCW
#endif
#ifdef HAVE_RB_MEMHASH
#define RGEO_SUPPORTS_NEW_HASHING
#endif
Expand Down
2 changes: 1 addition & 1 deletion lib/rgeo/cartesian/analysis.rb
Expand Up @@ -19,7 +19,7 @@ class << self
# If the factory used is GEOS based, use the GEOS implementation to
# check that. Otherwise, this methods falls back to `ring_direction`.
def ccw?(ring)
if RGeo::Geos.is_capi_geos?(ring)
if RGeo::Geos.is_capi_geos?(ring) && RGeo::Geos::Analysis.ccw_supported?
RGeo::Geos::Analysis.ccw?(ring)
else
RGeo::Cartesian::Analysis.ring_direction(ring) == 1
Expand Down
15 changes: 5 additions & 10 deletions test/cartesian_analysis_test.rb
Expand Up @@ -79,14 +79,11 @@ def counterclockwise_near_circle

def setup
@fixtures = Fixtures.new(RGeo::Cartesian.simple_factory)
@cfixtures = Fixtures.new(RGeo::Geos.factory) if RGeo::Geos.supported?
end

# --------------------------------------------- RGeo::Cartesian::Analysis.ccw?

def test_ccw_p_clockwise_triangle
ring = @cfixtures.clockwise_triangle
assert_equal(false, RGeo::Cartesian::Analysis.ccw?(ring))
ring = @fixtures.clockwise_triangle
assert_equal(
false,
Expand All @@ -96,8 +93,6 @@ def test_ccw_p_clockwise_triangle
end

def test_ccw_p_counterclockwise_triangle
ring = @cfixtures.counterclockwise_triangle
assert_equal(true, RGeo::Cartesian::Analysis.ccw?(ring))
ring = @fixtures.counterclockwise_triangle
assert_equal(
true,
Expand All @@ -107,27 +102,27 @@ def test_ccw_p_counterclockwise_triangle
end

def test_ccw_p_clockwise_puckered_quad
ring = @cfixtures.clockwise_puckered_quad
ring = @fixtures.clockwise_puckered_quad
assert_equal(false, RGeo::Cartesian::Analysis.ccw?(ring))
end

def test_ccw_p_counterclockwise_puckered_quad
ring = @cfixtures.counterclockwise_puckered_quad
ring = @fixtures.counterclockwise_puckered_quad
assert_equal(true, RGeo::Cartesian::Analysis.ccw?(ring))
end

def test_ccw_p_clockwise_hat
ring = @cfixtures.clockwise_hat
ring = @fixtures.clockwise_hat
assert_equal(false, RGeo::Cartesian::Analysis.ccw?(ring))
end

def test_ccw_p_counterclockwise_hat
ring = @cfixtures.counterclockwise_hat
ring = @fixtures.counterclockwise_hat
assert_equal(true, RGeo::Cartesian::Analysis.ccw?(ring))
end

def test_ccw_p_counterclockwise_near_circle
ring = @cfixtures.counterclockwise_near_circle
ring = @fixtures.counterclockwise_near_circle
assert_equal(true, RGeo::Cartesian::Analysis.ccw?(ring))
end

Expand Down
15 changes: 14 additions & 1 deletion test/geos_capi/analysis_test.rb
Expand Up @@ -3,12 +3,14 @@
require_relative "../test_helper"

module GeosCapi
class AnalysisTest < Minitest::Test
class AnalysisTest < CartesianAnalysisTest
def setup
skip "Needs GEOS." unless RGeo::Geos.capi_supported?
@fixtures = Fixtures.new(RGeo::Geos.factory)
end

def test_ccw_p_raises_if_not_a_geos_object
skip "Needs GEOS 3.7+" unless RGeo::Geos::Analysis.ccw_supported?
factory = RGeo::Cartesian.simple_factory
pt1 = factory.point(1, 0)
pt2 = factory.point(2, 0)
Expand All @@ -18,12 +20,14 @@ def test_ccw_p_raises_if_not_a_geos_object
end

def test_ccw_p_raises_if_no_coordseq
skip "Needs GEOS 3.7+" unless RGeo::Geos::Analysis.ccw_supported?
factory = RGeo::Geos.factory(native_interface: :capi)
point = factory.point(1, 2)
assert_raises(RGeo::Error::GeosError) { RGeo::Geos::Analysis.ccw?(point) }
end

def test_ccw_p_returns_true_if_ccw
skip "Needs GEOS 3.7+" unless RGeo::Geos::Analysis.ccw_supported?
factory = RGeo::Geos.factory(native_interface: :capi)
pt1 = factory.point(1, 0)
pt2 = factory.point(2, 0)
Expand All @@ -34,5 +38,14 @@ def test_ccw_p_returns_true_if_ccw
assert_equal(false, RGeo::Geos::Analysis.ccw?(ring_cw))
assert_equal(true, RGeo::Geos::Analysis.ccw?(ring_ccw))
end

# no need to re-test the ruby implementation
undef :test_ring_direction_clockwise_triangle
undef :test_ring_direction_counterclockwise_triangle
undef :test_ring_direction_clockwise_puckered_quad
undef :test_ring_direction_counterclockwise_puckered_quad
undef :test_ring_direction_clockwise_hat
undef :test_ring_direction_counterclockwise_hat
undef :test_ring_direction_counterclockwise_near_circle
end
end