class AIPP::Border
Border
GeoJSON file reader
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] ] } ] }
@example
border = AIPP::Border.new("/path/to/file.geojson") border.geometries # => [[#<AIXM::XY 45.12013320N 006.00953165E>, <AIXM::XY 45.12006703N 006.01574774E>]]
Attributes
Public Class Methods
# File lib/aipp/border.rb 29 def initialize(file) 30 @file = file.is_a?(Pathname) ? file : Pathname(file) 31 fail(ArgumentError, "file must have extension .geojson") unless @file.extname == '.geojson' 32 @geometries = load_geometries 33 end
Public Instance Methods
Whether the given geometry is closed or not
A geometry is considered closed when it's first coordinate equals the last coordinate.
@param geometry_index [Integer] geometry to check @return [Boolean] true if the geometry is closed or false otherwise
# File lib/aipp/border.rb 58 def closed?(geometry_index:) 59 geometry = @geometries[geometry_index] 60 geometry.first == geometry.last 61 end
@return [String]
# File lib/aipp/border.rb 36 def inspect 37 %Q(#<#{self.class} file=#{@file}>) 38 end
Name of the border
By convention, the name of the border is taken from the filename with both the extension .geojson and all non alphanumeric characters dropped and the resulting string upcased.
@return [String]
# File lib/aipp/border.rb 47 def name 48 @file.basename('.geojson').to_s.gsub(/\W/, '').upcase 49 end
Find a position on a geometry nearest to the given coordinates
@param geometry_index [Integer] index of the geometry on which to search
or +nil+ to search on all geometries
@param xy [AIXM::XY] coordinates to approximate @return [AIPP::Border::Position] position nearest to the given coordinates
# File lib/aipp/border.rb 69 def nearest(geometry_index: nil, xy:) 70 position = nil 71 min_distance = 21_000_000 # max distance on earth in meters 72 @geometries.each.with_index do |geometry, g_index| 73 next unless geometry_index.nil? || geometry_index == g_index 74 geometry.each.with_index do |coordinates, c_index| 75 distance = xy.distance(coordinates).dist 76 if distance < min_distance 77 position = Position.new(geometries: geometries, geometry_index: g_index, coordinates_index: c_index) 78 min_distance = distance 79 end 80 end 81 end 82 position 83 end
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.
@param from_position [AIPP::Border::Position] starting position @param to_position [AIPP::Border::Position] ending position @return [Array<AIXM::XY>] array of coordinates describing the segment
# File lib/aipp/border.rb 95 def segment(from_position:, to_position:) 96 fail(ArgumentError, "both positions must be on the same geometry") unless from_position.geometry_index == to_position.geometry_index 97 geometry_index = from_position.geometry_index 98 geometry = @geometries[geometry_index] 99 if closed?(geometry_index: geometry_index) 100 up = from_position.coordinates_index.upto(to_position.coordinates_index) 101 down = from_position.coordinates_index.downto(0) + (geometry.count - 2).downto(to_position.coordinates_index) 102 geometry.values_at(*(up.count < down.count ? up : down).to_a) 103 else 104 geometry.values_at(*from_position.coordinates_index.up_or_downto(to_position.coordinates_index).to_a) 105 end 106 end
Private Instance Methods
# File lib/aipp/border.rb 110 def load_geometries 111 JSON.load(@file)['geometries'].map do |line_string| 112 line_string['coordinates'].map do |long, lat| 113 AIXM.xy(long: long, lat: lat) 114 end 115 end 116 end