Module: AIPP::LF::Helpers::Base

Included in:
AD13, AD16, AD2, AD31, ENR21, ENR41, ENR43, ENR51, ENR54, ENR55, NavigationalAid::NavigationalAid
Defined in:
lib/aipp/regions/LF/helpers/base.rb

Constant Summary collapse

BORDERS =

Map border names to OFMX

{
  'franco-allemande' => 'FRANCE_GERMANY',
  'franco-espagnole' =>  'FRANCE_SPAIN',
  'franco-italienne' => 'FRANCE_ITALY',
  'franco-suisse' => 'FRANCE_SWITZERLAND',
  'franco-luxembourgeoise' => 'FRANCE_LUXEMBOURG',
  'franco-belge' => 'BELGIUM_FRANCE',
  'germano-suisse' => 'GERMANY_SWITZERLAND',
  'hispano-andorrane' => 'ANDORRA_SPAIN',
  'la côte atlantique française' => 'FRANCE_ATLANTIC_COAST',
  'côte méditérrannéenne' => 'FRANCE_MEDITERRANEAN_COAST',
  'limite des eaux territoriales atlantique françaises' => 'FRANCE_ATLANTIC_TERRITORIAL_SEA',
  'parc national des écrins' => 'FRANCE_ECRINS_NATIONAL_PARK'
}.freeze
INTERSECTIONS =

Intersection points between three countries

{
  'FRANCE_SPAIN|ANDORRA_SPAIN' => AIXM.xy(lat: 42.502720, long: 1.725965),
  'ANDORRA_SPAIN|FRANCE_SPAIN' => AIXM.xy(lat: 42.603571, long: 1.442681),
  'FRANCE_SWITZERLAND|FRANCE_ITALY' => AIXM.xy(lat: 45.922701, long: 7.044125),
  'BELGIUM_FRANCE|FRANCE_LUXEMBOURG' => AIXM.xy(lat: 49.546428, long: 5.818415),
  'FRANCE_LUXEMBOURG|FRANCE_GERMANY' => AIXM.xy(lat: 49.469438, long: 6.367516),
  'FRANCE_GERMANY|FRANCE_SWITZERLAND' => AIXM.xy(lat: 47.589831, long: 7.589049),
  'GERMANY_SWITZERLAND|FRANCE_GERMANY' => AIXM.xy(lat: 47.589831, long: 7.589049)
}.freeze
SURFACES =

Map surface to OFMX composition, preparation and remarks

{
  /^revêtue?$/ => { preparation: :paved },
  /^non revêtue?$/ => { preparation: :natural },
  'macadam' => { composition: :macadam },
  /^bitume ?(traité|psp)?$/ =>  { composition: :bitumen },
  'ciment' => { composition: :concrete, preparation: :paved },
  /^b[eéè]ton ?(armé|bitume|bitumineux)?$/ => { composition: :concrete, preparation: :paved },
  /^béton( de)? ciment$/ => { composition: :concrete, preparation: :paved },
  'béton herbe' => { composition: :concrete_and_grass },
  'béton avec résine' => { composition: :concrete, preparation: :paved, remarks: 'Avec résine / with resin' },
  "béton + asphalte d'étanchéité sablé" => { composition: :concrete_and_asphalt, preparation: :paved, remarks: 'Étanchéité sablé / sandblasted waterproofing' },
  'béton armé + support bitumastic' => { composition: :concrete, preparation: :paved, remarks: 'Support bitumastic / bitumen support' },
  /résine (époxy )?su[er] béton/ => { composition: :concrete, preparation: :paved, remarks: 'Avec couche résine / with resin seal coat' },
  /^(asphalte|tarmac)$/ => { composition: :asphalt, preparation: :paved },
  'enrobé' => { preparation: :other, remarks: 'Enrobé / coated' },
  'enrobé anti-kérozène' => { preparation: :other, remarks: 'Enrobé anti-kérozène / anti-kerosene coating' },
  /^enrobé bitum(e|iné|ineux)$/ => { composition: :bitumen, preparation: :paved, remarks: 'Enrobé / coated' },
  'enrobé béton' => { composition: :concrete, preparation: :paved, remarks: 'Enrobé / coated' },
  /^résine( époxy)?$/ => { composition: :other, remarks: 'Résine / resin' },
  'tole acier larmé' => { composition: :metal, preparation: :grooved },
  /^(structure métallique|aluminium)$/ => { composition: :metal },
  'matériaux composites ignifugés' => { composition: :other, remarks: 'Matériaux composites ignifugés / fire resistant mixed materials' },
  /^(gazon|herbe)$/ => { composition: :grass },
  'neige' => { composition: :snow },
  'neige damée' => { composition: :snow, preparation: :rolled }
}.freeze
ANGLICISE_MAP =

Transform French text fragments to English

{
  /[^A-Z0-9 .\-]/ => '',
  /0(\d)/ => '\1',
  /(\d)-(\d)/ => '\1.\2',
  /PARTIE/ => '',
  /DELEG\./ => 'DELEG ',
  /FRANCAISE?/ => 'FR',
  /ANGLAISE?/ => 'UK',
  /BELGE/ => 'BE',
  /LUXEMBOURGEOISE?/ => 'LU',
  /ALLEMANDE?/ => 'DE',
  /SUISSE/ => 'CH',
  /ITALIEN(?:NE)?/ => 'IT',
  /ESPAGNOLE?/ => 'ES',
  /ANDORRANE?/ => 'AD',
  /NORD/ => 'N',
  /EST/ => 'E',
  /SUD/ => 'S',
  /OEST/ => 'W',
  /ANGLO NORMANDES/ => 'ANGLO-NORMANDES',
  / +/ => ' '
}.freeze

Instance Method Summary collapse

Instance Method Details

#anglicise(name:) ⇒ Object


106
107
108
109
110
111
112
# File 'lib/aipp/regions/LF/helpers/base.rb', line 106

def anglicise(name:)
  name&.uptrans&.tap do |string|
    ANGLICISE_MAP.each do |regexp, replacement|
      string.gsub!(regexp, replacement)
    end
  end
end

#d_from(text) ⇒ Object


144
145
146
147
148
149
150
# File 'lib/aipp/regions/LF/helpers/base.rb', line 144

def d_from(text)
  case text
    when nil then nil
    when /(\d+)(\w+)/ then AIXM.d($1.to_i, $2.to_sym)
    else fail "d `#{text}' not recognized"
  end
end

#elevation_from(text) ⇒ Object


152
153
154
155
# File 'lib/aipp/regions/LF/helpers/base.rb', line 152

def elevation_from(text)
  value, unit = text.strip.split
  AIXM.z(AIXM.d(value.to_i, unit).to_ft.dist, :qnh)
end

#geometry_from(text) ⇒ Object


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/aipp/regions/LF/helpers/base.rb', line 170

def geometry_from(text)
  AIXM.geometry.tap do |geometry|
    buffer = {}
    text.gsub(/\s+/, ' ').strip.split(/ - /).append('end').each do |element|
      case element
      when /arc (anti-)?horaire .+ sur (\S+) , (\S+)/i
        geometry.add_segment AIXM.arc(
          xy: buffer.delete(:xy),
          center_xy: AIXM.xy(lat: $2, long: $3),
          clockwise: $1.nil?
        )
      when /cercle de ([\d\.]+) (NM|km|m) .+ sur (\S+) , (\S+)/i
        geometry.add_segment AIXM.circle(
          center_xy: AIXM.xy(lat: $3, long: $4),
          radius: AIXM.d($1.to_f, $2)
        )
      when /end|(\S+) , (\S+)/
        geometry.add_segment AIXM.point(xy: buffer[:xy]) if buffer.has_key?(:xy)
        buffer[:xy] = AIXM.xy(lat: $1, long: $2) if $1
        if border = buffer.delete(:border)
          from = border.nearest(xy: geometry.segments.last.xy)
          to = border.nearest(xy: buffer[:xy], geometry_index: from.geometry_index)
          geometry.add_segments border.segment(from_position: from, to_position: to).map(&:to_point)
        end
      when /^frontière ([\w-]+)/i, /^(\D[^(]+)/i
        border_name = BORDERS.fetch($1.downcase.strip)
        if borders.has_key? border_name   # border from GeoJSON
          buffer[:border] = borders[border_name]
        else   # named border
          buffer[:xy] ||= INTERSECTIONS.fetch("#{buffer[:border_name]}|#{border_name}")
          buffer[:border_name] = border_name
          if border_name == 'FRANCE_SPAIN'   # specify which part of this split border
            border_name += buffer[:xy].lat < 42.55 ? '_EAST' : '_WEST'
          end
          geometry.add_segment AIXM.border(
            xy: buffer.delete(:xy),
            name: border_name
          )
        end
      else
        fail "geometry `#{element}' not recognized"
      end
    end
  end
end

#layer_from(text_for_limit, text_for_class = nil) ⇒ Object


157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/aipp/regions/LF/helpers/base.rb', line 157

def layer_from(text_for_limit, text_for_class=nil)
  above, below = text_for_limit.gsub(/ /, '').split(/\n+/).select(&:blank_to_nil).split { _1.match? '---+' }
  AIXM.layer(
    class: text_for_class,
    vertical_limit: AIXM.vertical_limit(
      upper_z: z_from(above[0]),
      max_z: z_from(above[1]),
      lower_z: z_from(below[0]),
      min_z: z_from(below[1])
    )
  )
end

#organisation_lfObject

Templates


89
90
91
92
93
94
95
96
# File 'lib/aipp/regions/LF/helpers/base.rb', line 89

def organisation_lf
  @organisation_lf ||= AIXM.organisation(
    name: 'FRANCE',
    type: 'S'
  ).tap do |organisation|
    organisation.id = 'LF'
  end
end

#prepare(html:) ⇒ Object

Transformations


100
101
102
103
104
# File 'lib/aipp/regions/LF/helpers/base.rb', line 100

def prepare(html:)
  html.tap do |node|
    node.css('del, *[class*="AmdtDeletedAIRAC"]').each(&:remove)   # remove deleted entries
  end
end

#source(position:, aip_file: nil) ⇒ Object

Parsers


116
117
118
119
120
121
122
123
124
125
# File 'lib/aipp/regions/LF/helpers/base.rb', line 116

def source(position:, aip_file: nil)
  aip_file ||= @aip
  [
    options[:region],
    aip_file.split('-').first,
    aip_file,
    options[:airac].date.xmlschema,
    position
  ].join('|')
end

#timetable_from!(text) ⇒ Object


216
217
218
219
220
# File 'lib/aipp/regions/LF/helpers/base.rb', line 216

def timetable_from!(text)
  if text.gsub!(/^\s*#{AIXM::H_RE}\s*$/, '')
    AIXM.timetable(code: Regexp.last_match&.to_s&.strip)
  end
end

#xy_from(text) ⇒ Object


127
128
129
130
# File 'lib/aipp/regions/LF/helpers/base.rb', line 127

def xy_from(text)
  parts = text.strip.split(/\s+/)
  AIXM.xy(lat: parts[0], long: parts[1])
end

#z_from(limit) ⇒ Object


132
133
134
135
136
137
138
139
140
141
142
# File 'lib/aipp/regions/LF/helpers/base.rb', line 132

def z_from(limit)
  case limit
    when nil then nil
    when 'SFC' then AIXM::GROUND
    when 'UNL' then AIXM::UNLIMITED
    when /(\d+)ftASFC/ then AIXM.z($1.to_i, :qfe)
    when /(\d+)ftAMSL/ then AIXM.z($1.to_i, :qnh)
    when /FL(\d+)/ then AIXM.z($1.to_i, :qne)
    else fail "z `#{limit}' not recognized"
  end
end