Class: AIPP::Border

Inherits:
Object show all
Defined in:
lib/aipp/border.rb

Overview

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]
      ]
    }
  ]
}

Examples:

border = AIPP::Border.new("/path/to/file.geojson")
border.geometries
# => [[#<AIXM::XY 45.12013320N 006.00953165E>, <AIXM::XY 45.12006703N 006.01574774E>]]

Defined Under Namespace

Classes: Position

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ Border

Returns a new instance of Border.



29
30
31
32
33
# File 'lib/aipp/border.rb', line 29

def initialize(file)
  @file = file.is_a?(Pathname) ? file : Pathname(file)
  fail(ArgumentError, "file must have extension .geojson") unless @file.extname == '.geojson'
  @geometries = load_geometries
end

Instance Attribute Details

#fileObject (readonly)

Returns the value of attribute file.



26
27
28
# File 'lib/aipp/border.rb', line 26

def file
  @file
end

#geometriesObject (readonly)

Returns the value of attribute geometries.



27
28
29
# File 'lib/aipp/border.rb', line 27

def geometries
  @geometries
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.

Parameters:

  • geometry_index (Integer)

    geometry to check

Returns:

  • (Boolean)

    true if the geometry is closed or false otherwise



58
59
60
61
# File 'lib/aipp/border.rb', line 58

def closed?(geometry_index:)
  geometry = @geometries[geometry_index]
  geometry.first == geometry.last
end

#inspectString

Returns:



36
37
38
# File 'lib/aipp/border.rb', line 36

def inspect
  %Q(#<#{self.class} file=#{@file}>)
end

#nameString

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.

Returns:



47
48
49
# File 'lib/aipp/border.rb', line 47

def name
  @file.basename('.geojson').to_s.gsub(/\W/, '').upcase
end

#nearest(geometry_index: nil, xy:) ⇒ AIPP::Border::Position

Find a position on a geometry nearest to the given coordinates

Parameters:

  • geometry_index (Integer) (defaults to: nil)

    index of the geometry on which to search or nil to search on all geometries

  • xy (AIXM::XY)

    coordinates to approximate

Returns:



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/aipp/border.rb', line 69

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).dist
      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.

Parameters:

Returns:

  • (Array<AIXM::XY>)

    array of coordinates describing the segment



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/aipp/border.rb', line 95

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