diff --git a/lib/skywatch/brief/analysis/adverse_filter.rb b/lib/skywatch/brief/analysis/adverse_filter.rb index b83d3ef..6955e32 100644 --- a/lib/skywatch/brief/analysis/adverse_filter.rb +++ b/lib/skywatch/brief/analysis/adverse_filter.rb @@ -9,6 +9,8 @@ def self.covers?(product, lat, lon) return false if polygon.nil? polygon.contains?(Skywatch::Shared::Geometry.point(lat, lon)) + rescue RGeo::Error::InvalidGeometry + false end def self.within(items, lat:, lon:, radius_nm:) diff --git a/lib/skywatch/nimbus/models/outlook.rb b/lib/skywatch/nimbus/models/outlook.rb index 2b6324b..911189d 100644 --- a/lib/skywatch/nimbus/models/outlook.rb +++ b/lib/skywatch/nimbus/models/outlook.rb @@ -70,6 +70,8 @@ def covers?(lat:, lon:) return false if geometry.nil? geometry.contains?(FACTORY.point(lon, lat)) + rescue RGeo::Error::InvalidGeometry + false end def to_h # rubocop:disable Metrics/MethodLength diff --git a/spec/brief/analysis/adverse_filter_spec.rb b/spec/brief/analysis/adverse_filter_spec.rb index 2fe89f3..90be894 100644 --- a/spec/brief/analysis/adverse_filter_spec.rb +++ b/spec/brief/analysis/adverse_filter_spec.rb @@ -27,6 +27,19 @@ degenerate = Skywatch::Briefer::Models::Sigmet.new(coords: []) expect(described_class.covers?(degenerate, 40.875, -74.282)).to be false end + + it 'returns false when the polygon is self-intersecting (RGeo InvalidGeometry)' do + # Bowtie ring: edges cross — RGeo raises Self-intersection on contains? + bowtie = Skywatch::Briefer::Models::Sigmet.new(coords: [ + Skywatch::Shared::Position.new(lat: 40.0, lon: -74.0), + Skywatch::Shared::Position.new(lat: 41.0, lon: -73.0), + Skywatch::Shared::Position.new(lat: 40.0, lon: -73.0), + Skywatch::Shared::Position.new(lat: 41.0, lon: -74.0), + Skywatch::Shared::Position.new(lat: 40.0, lon: -74.0) + ]) + expect { described_class.covers?(bowtie, 40.5, -73.5) }.not_to raise_error + expect(described_class.covers?(bowtie, 40.5, -73.5)).to be false + end end describe '.within' do diff --git a/spec/nimbus/models/outlook_spec.rb b/spec/nimbus/models/outlook_spec.rb index eb103a3..5ab703c 100644 --- a/spec/nimbus/models/outlook_spec.rb +++ b/spec/nimbus/models/outlook_spec.rb @@ -93,6 +93,20 @@ expect(mrgl.covers?(lat: 41.4, lon: -74.9)).to be(true) expect(slgt.covers?(lat: 41.4, lon: -74.9)).to be(false) end + + it 'returns false when the geometry is self-intersecting (RGeo InvalidGeometry)' do + factory = described_class::FACTORY + bowtie_ring = factory.linear_ring([ + factory.point(-74.0, 40.0), + factory.point(-73.0, 41.0), + factory.point(-73.0, 40.0), + factory.point(-74.0, 41.0), + factory.point(-74.0, 40.0) + ]) + bad = described_class.new(**attrs, geometry: factory.polygon(bowtie_ring)) + expect { bad.covers?(lat: 40.5, lon: -73.5) }.not_to raise_error + expect(bad.covers?(lat: 40.5, lon: -73.5)).to be(false) + end end describe '#to_h' do