Remove abbreviations to make decoded reports easier to read
This commit is contained in:
parent
6116c1d9b7
commit
35c5c70b25
154
convert.go
Normal file
154
convert.go
Normal file
@ -0,0 +1,154 @@
|
||||
package taf
|
||||
|
||||
func convertSkyConditionType(s string) SkyConditionType {
|
||||
switch s {
|
||||
case "FEW":
|
||||
return Few
|
||||
case "SCT":
|
||||
return Scattered
|
||||
case "BKN":
|
||||
return Broken
|
||||
case "OVC":
|
||||
return Overcast
|
||||
case "VV":
|
||||
return VerticalVisibility
|
||||
case "SKC":
|
||||
return SkyClear
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertCloudType(s string) CloudType {
|
||||
switch s {
|
||||
case "CB":
|
||||
return CumuloNimbus
|
||||
case "TCU":
|
||||
return ToweringCumulus
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertModifier(s string) Modifier {
|
||||
switch s {
|
||||
case "+":
|
||||
return Heavy
|
||||
case "-":
|
||||
return Light
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertDescriptor(s string) Descriptor {
|
||||
switch s {
|
||||
case "MI":
|
||||
return Shallow
|
||||
case "BC":
|
||||
return Patches
|
||||
case "DC":
|
||||
return LowDrifting
|
||||
case "BL":
|
||||
return Blowing
|
||||
case "SH":
|
||||
return Showers
|
||||
case "TS":
|
||||
return Thunderstorm
|
||||
case "FZ":
|
||||
return Freezing
|
||||
case "PR":
|
||||
return Partial
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertPrecipitation(s string) Precipitation {
|
||||
switch s {
|
||||
case "DZ":
|
||||
return Drizzle
|
||||
case "RA":
|
||||
return Rain
|
||||
case "SN":
|
||||
return Snow
|
||||
case "SG":
|
||||
return SnowGrains
|
||||
case "IC":
|
||||
return IceCrystals
|
||||
case "PL":
|
||||
return IcePellets
|
||||
case "GR":
|
||||
return Hail
|
||||
case "GS":
|
||||
return SmallHail
|
||||
case "UP":
|
||||
return Unknown
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertObscuration(s string) Obscuration {
|
||||
switch s {
|
||||
case "BR":
|
||||
return Mist
|
||||
case "FG":
|
||||
return Fog
|
||||
case "FU":
|
||||
return Smoke
|
||||
case "DU":
|
||||
return Dust
|
||||
case "SA":
|
||||
return Sand
|
||||
case "HZ":
|
||||
return Haze
|
||||
case "PY":
|
||||
return Spray
|
||||
case "VA":
|
||||
return VolcanicAsh
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertPhenomenon(s string) Phenomenon {
|
||||
switch s {
|
||||
case "PO":
|
||||
return Whirls
|
||||
case "SQ":
|
||||
return Squalls
|
||||
case "FC":
|
||||
return FunnelCloud
|
||||
case "SS":
|
||||
return Sandstorm
|
||||
case "DS":
|
||||
return Duststorm
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertTemperatureType(s string) TemperatureType {
|
||||
switch s {
|
||||
case "TX":
|
||||
return High
|
||||
case "TN":
|
||||
return Low
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func convertChangeType(s string) ChangeType {
|
||||
switch s {
|
||||
case "FM":
|
||||
return From
|
||||
case "BECMG":
|
||||
return Becoming
|
||||
case "TEMPO":
|
||||
return Temporary
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
34
taf.go
34
taf.go
@ -94,17 +94,17 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) {
|
||||
setField(out, "Valid", vp)
|
||||
case item.Weather != nil:
|
||||
appendField(out, "Weather", Weather{
|
||||
Modifier: Modifier(item.Weather.Modifier),
|
||||
Descriptor: Descriptor(item.Weather.Descriptor),
|
||||
Precipitation: Precipitation(item.Weather.Precipitation),
|
||||
Obscuration: Obscuration(item.Weather.Obscuration),
|
||||
Phenomenon: Phenomenon(item.Weather.Other),
|
||||
Modifier: convertModifier(item.Weather.Modifier),
|
||||
Descriptor: convertDescriptor(item.Weather.Descriptor),
|
||||
Precipitation: convertPrecipitation(item.Weather.Precipitation),
|
||||
Obscuration: convertObscuration(item.Weather.Obscuration),
|
||||
Phenomenon: convertPhenomenon(item.Weather.Other),
|
||||
})
|
||||
case item.Vicinity != nil:
|
||||
appendField(out, "Weather", Weather{
|
||||
Vicinity: true,
|
||||
Descriptor: Descriptor(item.Vicinity.Descriptor),
|
||||
Precipitation: Precipitation(item.Vicinity.Precipitation),
|
||||
Descriptor: convertDescriptor(item.Vicinity.Descriptor),
|
||||
Precipitation: convertPrecipitation(item.Vicinity.Precipitation),
|
||||
})
|
||||
case item.SkyCondition != nil:
|
||||
var altitude int
|
||||
@ -117,8 +117,8 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) {
|
||||
|
||||
appendField(out, "SkyCondition", SkyCondition{
|
||||
Altitude: altitude * 100, // Scale factor for altitude is 100
|
||||
Type: SkyConditionType(item.SkyCondition.Type),
|
||||
CloudType: CloudType(item.SkyCondition.CloudType),
|
||||
Type: convertSkyConditionType(item.SkyCondition.Type),
|
||||
CloudType: convertCloudType(item.SkyCondition.CloudType),
|
||||
})
|
||||
case item.Temperature != nil:
|
||||
vt, err := parseValidTime(item.Temperature.Time)
|
||||
@ -132,7 +132,7 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) {
|
||||
}
|
||||
|
||||
appendField(out, "Temperature", Temperature{
|
||||
Type: TemperatureType(item.Temperature.Type),
|
||||
Type: convertTemperatureType(item.Temperature.Type),
|
||||
Time: vt,
|
||||
Value: val,
|
||||
})
|
||||
@ -173,7 +173,11 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) {
|
||||
item.Visibility.Unit = "M"
|
||||
}
|
||||
|
||||
unit := units.Distance(item.Visibility.Unit)
|
||||
unit, ok := units.ParseDistance(item.Visibility.Unit)
|
||||
if !ok {
|
||||
return nil, participle.Errorf(item.Visibility.Pos, "visibility: invalid unit %q", item.Visibility.Unit)
|
||||
}
|
||||
|
||||
val, _ := ratNum.Float64()
|
||||
|
||||
if opts.DistanceUnit != "" {
|
||||
@ -234,7 +238,11 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) {
|
||||
}
|
||||
}
|
||||
|
||||
unit := units.Speed(item.WindSpeed.Unit)
|
||||
unit, ok := units.ParseSpeed(item.WindSpeed.Unit)
|
||||
if !ok {
|
||||
return nil, participle.Errorf(item.WindSpeed.Pos, "wind: invalid unit %q", item.Visibility.Unit)
|
||||
}
|
||||
|
||||
if opts.SpeedUnit != "" {
|
||||
speed = unit.Convert(opts.SpeedUnit, speed)
|
||||
if gusts != 0 {
|
||||
@ -260,7 +268,7 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) {
|
||||
}
|
||||
case item.Change != nil:
|
||||
ch := &Change{
|
||||
Type: ChangeType(item.Change.Type),
|
||||
Type: convertChangeType(item.Change.Type),
|
||||
}
|
||||
|
||||
// FM changes don't have a valid pair, they only come with a single time string
|
||||
|
12
taf_test.go
12
taf_test.go
@ -28,7 +28,7 @@ func TestKLAX(t *testing.T) {
|
||||
Visibility: Visibility{
|
||||
Plus: true,
|
||||
Value: 6,
|
||||
Unit: units.StatuteMiles,
|
||||
Unit: units.Miles,
|
||||
},
|
||||
Wind: Wind{
|
||||
Direction: Direction{
|
||||
@ -60,7 +60,7 @@ func TestKLAX(t *testing.T) {
|
||||
Visibility: Visibility{
|
||||
Plus: true,
|
||||
Value: 6,
|
||||
Unit: units.StatuteMiles,
|
||||
Unit: units.Miles,
|
||||
},
|
||||
Wind: Wind{
|
||||
Direction: Direction{
|
||||
@ -84,7 +84,7 @@ func TestKLAX(t *testing.T) {
|
||||
Visibility: Visibility{
|
||||
Plus: true,
|
||||
Value: 6,
|
||||
Unit: units.StatuteMiles,
|
||||
Unit: units.Miles,
|
||||
},
|
||||
Wind: Wind{
|
||||
Direction: Direction{
|
||||
@ -108,7 +108,7 @@ func TestKLAX(t *testing.T) {
|
||||
Visibility: Visibility{
|
||||
Plus: true,
|
||||
Value: 6,
|
||||
Unit: units.StatuteMiles,
|
||||
Unit: units.Miles,
|
||||
},
|
||||
Wind: Wind{
|
||||
Direction: Direction{
|
||||
@ -132,7 +132,7 @@ func TestKLAX(t *testing.T) {
|
||||
Visibility: Visibility{
|
||||
Plus: true,
|
||||
Value: 6,
|
||||
Unit: units.StatuteMiles,
|
||||
Unit: units.Miles,
|
||||
},
|
||||
Wind: Wind{
|
||||
Direction: Direction{
|
||||
@ -156,7 +156,7 @@ func TestKLAX(t *testing.T) {
|
||||
Visibility: Visibility{
|
||||
Plus: true,
|
||||
Value: 6,
|
||||
Unit: units.StatuteMiles,
|
||||
Unit: units.Miles,
|
||||
},
|
||||
Wind: Wind{
|
||||
Direction: Direction{
|
||||
|
92
types.go
92
types.go
@ -60,19 +60,19 @@ type Visibility struct {
|
||||
type SkyConditionType string
|
||||
|
||||
const (
|
||||
Few SkyConditionType = "FEW"
|
||||
Scattered SkyConditionType = "SCT"
|
||||
Broken SkyConditionType = "BKN"
|
||||
Overcast SkyConditionType = "OVC"
|
||||
VerticalVisibility SkyConditionType = "VV"
|
||||
SkyClear SkyConditionType = "SKC"
|
||||
Few SkyConditionType = "Few"
|
||||
Scattered SkyConditionType = "Scattered"
|
||||
Broken SkyConditionType = "Broken"
|
||||
Overcast SkyConditionType = "Overcast"
|
||||
VerticalVisibility SkyConditionType = "VerticalVisibility"
|
||||
SkyClear SkyConditionType = "SkyClear"
|
||||
)
|
||||
|
||||
type CloudType string
|
||||
|
||||
const (
|
||||
CumuloNimbus CloudType = "CB"
|
||||
ToweringCumulus CloudType = "TCU"
|
||||
CumuloNimbus CloudType = "CumuloNumbus"
|
||||
ToweringCumulus CloudType = "ToweringCumulus"
|
||||
)
|
||||
|
||||
type SkyCondition struct {
|
||||
@ -97,58 +97,58 @@ type Direction struct {
|
||||
type Modifier string
|
||||
|
||||
const (
|
||||
Heavy Modifier = "+"
|
||||
Light Modifier = "-"
|
||||
Heavy Modifier = "Heavy"
|
||||
Light Modifier = "Light"
|
||||
)
|
||||
|
||||
type Descriptor string
|
||||
|
||||
const (
|
||||
Shallow Descriptor = "MI"
|
||||
Patches Descriptor = "BC"
|
||||
LowDrifting Descriptor = "DC"
|
||||
Blowing Descriptor = "BL"
|
||||
Showers Descriptor = "SH"
|
||||
Thunderstorm Descriptor = "TS"
|
||||
Freezing Descriptor = "FZ"
|
||||
Partial Descriptor = "PR"
|
||||
Shallow Descriptor = "Shallow"
|
||||
Patches Descriptor = "Patches"
|
||||
LowDrifting Descriptor = "LowDrifting"
|
||||
Blowing Descriptor = "Blowing"
|
||||
Showers Descriptor = "Showers"
|
||||
Thunderstorm Descriptor = "Thunderstorm"
|
||||
Freezing Descriptor = "Freezing"
|
||||
Partial Descriptor = "Partial"
|
||||
)
|
||||
|
||||
type Precipitation string
|
||||
|
||||
const (
|
||||
Drizzle Precipitation = "DZ"
|
||||
Rain Precipitation = "RA"
|
||||
Snow Precipitation = "SN"
|
||||
SnowGrains Precipitation = "SG"
|
||||
IceCrystals Precipitation = "IC"
|
||||
IcePellets Precipitation = "PL"
|
||||
Hail Precipitation = "GR"
|
||||
SmallHail Precipitation = "GS"
|
||||
Unknown Precipitation = "UP"
|
||||
Drizzle Precipitation = "Drizzle"
|
||||
Rain Precipitation = "Rain"
|
||||
Snow Precipitation = "Snow"
|
||||
SnowGrains Precipitation = "SnowGrains"
|
||||
IceCrystals Precipitation = "IceCrystals"
|
||||
IcePellets Precipitation = "IcePellets"
|
||||
Hail Precipitation = "Hail"
|
||||
SmallHail Precipitation = "SmallHail"
|
||||
Unknown Precipitation = "Unknown"
|
||||
)
|
||||
|
||||
type Obscuration string
|
||||
|
||||
const (
|
||||
Mist Obscuration = "BR"
|
||||
Fog Obscuration = "FG"
|
||||
Smoke Obscuration = "FU"
|
||||
Dust Obscuration = "DU"
|
||||
Sand Obscuration = "SA"
|
||||
Haze Obscuration = "HZ"
|
||||
Spray Obscuration = "PY"
|
||||
VolcanicAsh Obscuration = "VA"
|
||||
Mist Obscuration = "Mist"
|
||||
Fog Obscuration = "Fog"
|
||||
Smoke Obscuration = "Smoke"
|
||||
Dust Obscuration = "Dust"
|
||||
Sand Obscuration = "Sand"
|
||||
Haze Obscuration = "Haze"
|
||||
Spray Obscuration = "Spray"
|
||||
VolcanicAsh Obscuration = "VolcanicAsh"
|
||||
)
|
||||
|
||||
type Phenomenon string
|
||||
|
||||
const (
|
||||
Whirls Phenomenon = "PO"
|
||||
Squalls Phenomenon = "SQ"
|
||||
FunnelCloud Phenomenon = "FC"
|
||||
SandStorm Phenomenon = "SS"
|
||||
DustStorm Phenomenon = "DS"
|
||||
Whirls Phenomenon = "Whirls"
|
||||
Squalls Phenomenon = "Squalls"
|
||||
FunnelCloud Phenomenon = "FunnelCloud"
|
||||
Sandstorm Phenomenon = "Sandstorm"
|
||||
Duststorm Phenomenon = "Duststorm"
|
||||
)
|
||||
|
||||
type Weather struct {
|
||||
@ -163,8 +163,8 @@ type Weather struct {
|
||||
type TemperatureType string
|
||||
|
||||
const (
|
||||
High TemperatureType = "TX"
|
||||
Low TemperatureType = "TN"
|
||||
High TemperatureType = "High"
|
||||
Low TemperatureType = "Low"
|
||||
)
|
||||
|
||||
type Temperature struct {
|
||||
@ -176,13 +176,13 @@ type Temperature struct {
|
||||
type ChangeType string
|
||||
|
||||
const (
|
||||
From ChangeType = "FM"
|
||||
Becoming ChangeType = "BECMG"
|
||||
Temporary ChangeType = "TEMPO"
|
||||
From ChangeType = "From"
|
||||
Becoming ChangeType = "Becoming"
|
||||
Temporary ChangeType = "Temporary"
|
||||
)
|
||||
|
||||
type Flag string
|
||||
|
||||
const (
|
||||
CeilingAndVisibilityOK Flag = "CAVOK"
|
||||
CeilingAndVisibilityOK Flag = "CeilingAndVisibilityOK"
|
||||
)
|
||||
|
@ -9,25 +9,11 @@ type Speed string
|
||||
|
||||
// Speed units
|
||||
const (
|
||||
MetersPerSecond Speed = "MPS"
|
||||
KilometersPerHour Speed = "KMH"
|
||||
Knots Speed = "KT"
|
||||
MetersPerSecond Speed = "MetersPerSecond"
|
||||
KilometersPerHour Speed = "KilometersPerHour"
|
||||
Knots Speed = "Knots"
|
||||
)
|
||||
|
||||
var speedNames = map[Speed]string{
|
||||
MetersPerSecond: "m/s",
|
||||
KilometersPerHour: "kph",
|
||||
Knots: "kts",
|
||||
}
|
||||
|
||||
func (su Speed) String() string {
|
||||
name, ok := speedNames[su]
|
||||
if !ok {
|
||||
return "<unknown>"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// Convert converts a value from one unit to another
|
||||
func (sf Speed) Convert(st Speed, val int) int {
|
||||
switch {
|
||||
@ -52,18 +38,16 @@ func (sf Speed) Convert(st Speed, val int) int {
|
||||
// mps, m/s, kmh, kph, kt, and kts.
|
||||
// This function is case-insensitive.
|
||||
func ParseSpeed(s string) (Speed, bool) {
|
||||
if _, ok := speedNames[Speed(s)]; ok {
|
||||
return Speed(s), true
|
||||
switch strings.ToLower(s) {
|
||||
case "m/s", "mps", "meterspersecond", "meters per second":
|
||||
return MetersPerSecond, true
|
||||
case "kmh", "kph", "km/h", "kilometersperhour", "kilometers per hour":
|
||||
return KilometersPerHour, true
|
||||
case "kt", "kts", "knot", "knots":
|
||||
return Knots, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
|
||||
for su, name := range speedNames {
|
||||
if strings.EqualFold(s, name) ||
|
||||
strings.EqualFold(s, string(su)) {
|
||||
return su, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Distance represents a unit of distance
|
||||
@ -71,29 +55,16 @@ type Distance string
|
||||
|
||||
// Distance units
|
||||
const (
|
||||
StatuteMiles Distance = "SM"
|
||||
Meters Distance = "M"
|
||||
Miles Distance = "Miles"
|
||||
Meters Distance = "Meters"
|
||||
)
|
||||
|
||||
var distanceNames = map[Distance]string{
|
||||
StatuteMiles: "mi",
|
||||
Meters: "m",
|
||||
}
|
||||
|
||||
func (du Distance) String() string {
|
||||
name, ok := distanceNames[du]
|
||||
if !ok {
|
||||
return "<unknown>"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// Convert converts a value from one unit to another
|
||||
func (df Distance) Convert(dt Distance, val float64) float64 {
|
||||
switch {
|
||||
case df == StatuteMiles && dt == Meters:
|
||||
case df == Miles && dt == Meters:
|
||||
return val * 1609
|
||||
case df == Meters && dt == StatuteMiles:
|
||||
case df == Meters && dt == Miles:
|
||||
return val / 1609
|
||||
default:
|
||||
return val
|
||||
@ -103,16 +74,12 @@ func (df Distance) Convert(dt Distance, val float64) float64 {
|
||||
// ParseDistance parses a speed value. Valid inputs include:
|
||||
// sm, mi, and m. This function is case-insensitive.
|
||||
func ParseDistance(s string) (Distance, bool) {
|
||||
if _, ok := distanceNames[Distance(s)]; ok {
|
||||
return Distance(s), true
|
||||
switch strings.ToLower(s) {
|
||||
case "sm", "mi", "mile", "miles":
|
||||
return Miles, true
|
||||
case "m", "meter", "meters":
|
||||
return Meters, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
|
||||
for d, name := range distanceNames {
|
||||
if strings.EqualFold(s, name) ||
|
||||
strings.EqualFold(s, string(d)) {
|
||||
return d, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user