Remove abbreviations to make decoded reports easier to read

This commit is contained in:
Elara 2023-08-22 17:34:26 -07:00
parent 6116c1d9b7
commit 35c5c70b25
5 changed files with 250 additions and 121 deletions

154
convert.go Normal file
View 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
View File

@ -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

View File

@ -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{

View File

@ -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"
)

View File

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