Class: AIPP::Border
- Inherits:
-
Object
- Object
- AIPP::Border
- Defined in:
- lib/aipp/border.rb
Overview
Custom border geometries
The border consists of one ore more open or closed geometries which are defined by either a GeoJSON file or arrays of coordinate pairs.
Defined Under Namespace
Classes: Position
Instance Attribute Summary collapse
- #geometries ⇒ Array<AIXM::XY> readonly
Class Method Summary collapse
-
.from_array(array) ⇒ Object
New border object from array of points.
-
.from_file(file) ⇒ Object
New border object from GeoJSON file.
Instance Method Summary collapse
-
#closed?(geometry_index:) ⇒ Boolean
Whether the given geometry is closed or not.
-
#initialize(geometries) ⇒ Border
constructor
A new instance of Border.
- #inspect ⇒ String
-
#nearest(geometry_index: nil, xy:) ⇒ AIPP::Border::Position
Find a position on a geometry nearest to the given coordinates.
-
#segment(from_position:, to_position:) ⇒ Array<AIXM::XY>
Get a segment of a geometry between the given starting and ending positions.
Constructor Details
#initialize(geometries) ⇒ Border
Returns a new instance of Border.
12 13 14 |
# File 'lib/aipp/border.rb', line 12 def initialize(geometries) @geometries = geometries end |
Instance Attribute Details
#geometries ⇒ Array<AIXM::XY> (readonly)
10 11 12 |
# File 'lib/aipp/border.rb', line 10 def geometries @geometries end |
Class Method Details
.from_array(array) ⇒ Object
New border object from array of points
The array must contain coordinate tuples in geographical order as latitude longitude separated by whitespace and/or commas.
71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/aipp/border.rb', line 71 def from_array(array) geometries = array.map do |collection| collection.map do |coordinates| lat, long = coordinates.split(/[\s,]+/) AIXM.xy(lat: lat.to_f, long: long.to_f) end end allocate.instance_eval do initialize(geometries) self end end |
.from_file(file) ⇒ Object
New border object from GeoJSON file
The border GeoJSON files must be a geometry collection of one or more line strings:
{
"type": "GeometryCollection",
"geometries": [
{
"type": "LineString",
"coordinates": [
[6.009531650000042, 45.12013319700009],
[6.015747738000073, 45.12006702600007]
]
}
]
}
Please note that GeoJSON orders coordinate tuples in mathematical order as [longitude, latitude]!
46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/aipp/border.rb', line 46 def from_file(file) file = Pathname(file) unless file.is_a? Pathname fail(ArgumentError, "file must have extension .geojson") unless file.extname == '.geojson' geometries = JSON.load(file)['geometries'].map do |collection| collection['coordinates'].map do |long, lat| AIXM.xy(lat: lat, long: long) end end allocate.instance_eval do initialize(geometries) self end end |
Instance Method Details
#closed?(geometry_index:) ⇒ Boolean
Whether the given geometry is closed or not
A geometry is considered closed when it’s first coordinate equals the last coordinate.
97 98 99 100 |
# File 'lib/aipp/border.rb', line 97 def closed?(geometry_index:) geometry = @geometries[geometry_index] geometry.first == geometry.last end |
#inspect ⇒ String
86 87 88 |
# File 'lib/aipp/border.rb', line 86 def inspect %Q(#<#{self.class} #{@geometries.count} geometries>) end |
#nearest(geometry_index: nil, xy:) ⇒ AIPP::Border::Position
Find a position on a geometry nearest to the given coordinates
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/aipp/border.rb', line 108 def nearest(geometry_index: nil, xy:) position = nil min_distance = 21_000_000 # max distance on earth in meters @geometries.each.with_index do |geometry, g_index| next unless geometry_index.nil? || geometry_index == g_index geometry.each.with_index do |coordinates, c_index| distance = xy.distance(coordinates).dim if distance < min_distance position = Position.new(geometries: geometries, geometry_index: g_index, coordinates_index: c_index) min_distance = distance end end end position end |
#segment(from_position:, to_position:) ⇒ Array<AIXM::XY>
Get a segment of a geometry between the given starting and ending positions
The segment ends either at the given ending position or at the last coordinates of the geometry. However, if the geometry is closed, the segment always continues up to the given ending position.
134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/aipp/border.rb', line 134 def segment(from_position:, to_position:) fail(ArgumentError, "both positions must be on the same geometry") unless from_position.geometry_index == to_position.geometry_index geometry_index = from_position.geometry_index geometry = @geometries[geometry_index] if closed?(geometry_index: geometry_index) up = from_position.coordinates_index.upto(to_position.coordinates_index) down = from_position.coordinates_index.downto(0) + (geometry.count - 2).downto(to_position.coordinates_index) geometry.values_at(*(up.count < down.count ? up : down).to_a) else geometry.values_at(*from_position.coordinates_index.up_or_downto(to_position.coordinates_index).to_a) end end |