mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 16:00:08 +00:00
P-VTEC parsing
This commit is contained in:
parent
e5c40b9eb5
commit
be1d7323bd
10 changed files with 835 additions and 5 deletions
76
wxdata/include/scwx/awips/phenomenon.hpp
Normal file
76
wxdata/include/scwx/awips/phenomenon.hpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace awips
|
||||
{
|
||||
|
||||
enum class Phenomenon
|
||||
{
|
||||
AshfallLand,
|
||||
AirStagnation,
|
||||
BeachHazard,
|
||||
BriskWind,
|
||||
Blizzard,
|
||||
CoastalFlood,
|
||||
DebrisFlow,
|
||||
DustStorm,
|
||||
BlowingDust,
|
||||
ExtremeCold,
|
||||
ExcessiveHeat,
|
||||
ExtremeWind,
|
||||
Flood,
|
||||
FlashFlood,
|
||||
DenseFogLand,
|
||||
FloodForecastPoints,
|
||||
Frost,
|
||||
FireWeather,
|
||||
Freeze,
|
||||
Gale,
|
||||
HurricaneForceWind,
|
||||
Heat,
|
||||
Hurricane,
|
||||
HighWind,
|
||||
Hydrologic,
|
||||
HardFreeze,
|
||||
IceStorm,
|
||||
LakeEffectSnow,
|
||||
LowWater,
|
||||
LakeshoreFlood,
|
||||
LakeWind,
|
||||
Marine,
|
||||
DenseFogMarine,
|
||||
AshfallMarine,
|
||||
DenseSmokeMarine,
|
||||
RipCurrentRisk,
|
||||
SmallCraft,
|
||||
HazardousSeas,
|
||||
DenseSmokeLand,
|
||||
Storm,
|
||||
StormSurge,
|
||||
SnowSquall,
|
||||
HighSurf,
|
||||
SevereThunderstorm,
|
||||
Tornado,
|
||||
TropicalStorm,
|
||||
Tsunami,
|
||||
Typhoon,
|
||||
HeavyFreezingSpray,
|
||||
WindChill,
|
||||
Wind,
|
||||
WinterStorm,
|
||||
WinterWeather,
|
||||
FreezingFog,
|
||||
FreezingRain,
|
||||
FreezingSpray,
|
||||
Unknown
|
||||
};
|
||||
|
||||
Phenomenon GetPhenomenon(const std::string& code);
|
||||
std::string GetPhenomenonCode(Phenomenon phenomenon);
|
||||
std::string GetPhenomenonText(Phenomenon phenomenon);
|
||||
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
75
wxdata/include/scwx/awips/pvtec.hpp
Normal file
75
wxdata/include/scwx/awips/pvtec.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/awips/phenomenon.hpp>
|
||||
#include <scwx/awips/significance.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace awips
|
||||
{
|
||||
|
||||
class PVtecImpl;
|
||||
|
||||
class PVtec
|
||||
{
|
||||
public:
|
||||
enum class ProductType
|
||||
{
|
||||
Operational,
|
||||
Test,
|
||||
Experimental,
|
||||
OperationalWithExperimentalVtec,
|
||||
Unknown
|
||||
};
|
||||
|
||||
enum class Action
|
||||
{
|
||||
New,
|
||||
Continued,
|
||||
ExtendedInArea,
|
||||
ExtendedInTime,
|
||||
ExtendedInAreaAndTime,
|
||||
Upgraded,
|
||||
Canceled,
|
||||
Expired,
|
||||
Routine,
|
||||
Correction,
|
||||
Unknown
|
||||
};
|
||||
|
||||
explicit PVtec();
|
||||
~PVtec();
|
||||
|
||||
PVtec(const PVtec&) = delete;
|
||||
PVtec& operator=(const PVtec&) = delete;
|
||||
|
||||
PVtec(PVtec&&) noexcept;
|
||||
PVtec& operator=(PVtec&&) noexcept;
|
||||
|
||||
ProductType fixed_identifier() const;
|
||||
Action action() const;
|
||||
std::string office_id() const;
|
||||
Phenomenon phenomenon() const;
|
||||
Significance significance() const;
|
||||
int16_t event_tracking_number() const;
|
||||
|
||||
std::chrono::system_clock::time_point event_begin() const;
|
||||
std::chrono::system_clock::time_point event_end() const;
|
||||
|
||||
bool Parse(const std::string& s);
|
||||
|
||||
static ProductType GetProductType(const std::string& code);
|
||||
static std::string GetProductTypeCode(ProductType productType);
|
||||
|
||||
static Action GetAction(const std::string& code);
|
||||
static std::string GetActionCode(Action action);
|
||||
|
||||
private:
|
||||
std::unique_ptr<PVtecImpl> p;
|
||||
};
|
||||
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
27
wxdata/include/scwx/awips/significance.hpp
Normal file
27
wxdata/include/scwx/awips/significance.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace awips
|
||||
{
|
||||
|
||||
enum class Significance
|
||||
{
|
||||
Warning,
|
||||
Watch,
|
||||
Advisory,
|
||||
Statement,
|
||||
Forecast,
|
||||
Outlook,
|
||||
Synopsis,
|
||||
Unknown
|
||||
};
|
||||
|
||||
Significance GetSignificance(const std::string& code);
|
||||
std::string GetSignificanceCode(Significance significance);
|
||||
std::string GetSignificanceText(Significance significance);
|
||||
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
168
wxdata/source/scwx/awips/phenomenon.cpp
Normal file
168
wxdata/source/scwx/awips/phenomenon.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
#include <scwx/awips/phenomenon.hpp>
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/bimap/unordered_set_of.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace awips
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "[scwx::awips::phenomenon] ";
|
||||
|
||||
typedef boost::bimap<boost::bimaps::unordered_set_of<Phenomenon>,
|
||||
boost::bimaps::unordered_set_of<std::string>>
|
||||
PhenomenonCodesBimap;
|
||||
|
||||
static const PhenomenonCodesBimap phenomenonCodes_ =
|
||||
boost::assign::list_of<PhenomenonCodesBimap::relation> //
|
||||
(Phenomenon::AshfallLand, "AF") //
|
||||
(Phenomenon::AirStagnation, "AS") //
|
||||
(Phenomenon::BeachHazard, "BH") //
|
||||
(Phenomenon::BriskWind, "BW") //
|
||||
(Phenomenon::Blizzard, "BZ") //
|
||||
(Phenomenon::CoastalFlood, "CF") //
|
||||
(Phenomenon::DebrisFlow, "DF") //
|
||||
(Phenomenon::DustStorm, "DS") //
|
||||
(Phenomenon::BlowingDust, "DU") //
|
||||
(Phenomenon::ExtremeCold, "EC") //
|
||||
(Phenomenon::ExcessiveHeat, "EH") //
|
||||
(Phenomenon::ExtremeWind, "EW") //
|
||||
(Phenomenon::Flood, "FA") //
|
||||
(Phenomenon::FlashFlood, "FF") //
|
||||
(Phenomenon::DenseFogLand, "FG") //
|
||||
(Phenomenon::FloodForecastPoints, "FL") //
|
||||
(Phenomenon::Frost, "FR") //
|
||||
(Phenomenon::FireWeather, "FW") //
|
||||
(Phenomenon::Freeze, "FZ") //
|
||||
(Phenomenon::Gale, "GL") //
|
||||
(Phenomenon::HurricaneForceWind, "HF") //
|
||||
(Phenomenon::Heat, "HT") //
|
||||
(Phenomenon::Hurricane, "HU") //
|
||||
(Phenomenon::HighWind, "HW") //
|
||||
(Phenomenon::Hydrologic, "HY") //
|
||||
(Phenomenon::HardFreeze, "HZ") //
|
||||
(Phenomenon::IceStorm, "IS") //
|
||||
(Phenomenon::LakeEffectSnow, "LE") //
|
||||
(Phenomenon::LowWater, "LO") //
|
||||
(Phenomenon::LakeshoreFlood, "LS") //
|
||||
(Phenomenon::LakeWind, "LW") //
|
||||
(Phenomenon::Marine, "MA") //
|
||||
(Phenomenon::DenseFogMarine, "MF") //
|
||||
(Phenomenon::AshfallMarine, "MH") //
|
||||
(Phenomenon::DenseSmokeMarine, "MS") //
|
||||
(Phenomenon::RipCurrentRisk, "RP") //
|
||||
(Phenomenon::SmallCraft, "SC") //
|
||||
(Phenomenon::HazardousSeas, "SE") //
|
||||
(Phenomenon::DenseSmokeLand, "SM") //
|
||||
(Phenomenon::Storm, "SR") //
|
||||
(Phenomenon::StormSurge, "SS") //
|
||||
(Phenomenon::SnowSquall, "SQ") //
|
||||
(Phenomenon::HighSurf, "SU") //
|
||||
(Phenomenon::SevereThunderstorm, "SV") //
|
||||
(Phenomenon::Tornado, "TO") //
|
||||
(Phenomenon::TropicalStorm, "TR") //
|
||||
(Phenomenon::Tsunami, "TS") //
|
||||
(Phenomenon::Typhoon, "TY") //
|
||||
(Phenomenon::HeavyFreezingSpray, "UP") //
|
||||
(Phenomenon::WindChill, "WC") //
|
||||
(Phenomenon::Wind, "WI") //
|
||||
(Phenomenon::WinterStorm, "WS") //
|
||||
(Phenomenon::WinterWeather, "WW") //
|
||||
(Phenomenon::FreezingFog, "ZF") //
|
||||
(Phenomenon::FreezingRain, "ZR") //
|
||||
(Phenomenon::FreezingSpray, "ZY") //
|
||||
(Phenomenon::Unknown, "??");
|
||||
|
||||
static const std::unordered_map<Phenomenon, std::string> phenomenonText_ {
|
||||
{Phenomenon::AshfallLand, "Ashfall (land)"}, //
|
||||
{Phenomenon::AirStagnation, "Air Stagnation"}, //
|
||||
{Phenomenon::BeachHazard, "Beach Hazard"}, //
|
||||
{Phenomenon::BriskWind, "Brisk Wind"}, //
|
||||
{Phenomenon::Blizzard, "Blizzard"}, //
|
||||
{Phenomenon::CoastalFlood, "Coastal Flood"}, //
|
||||
{Phenomenon::DebrisFlow, "Debris Flow"}, //
|
||||
{Phenomenon::DustStorm, "Dust Storm"}, //
|
||||
{Phenomenon::BlowingDust, "Blowing Dust"}, //
|
||||
{Phenomenon::ExtremeCold, "Extreme Cold"}, //
|
||||
{Phenomenon::ExcessiveHeat, "Excessive Heat"}, //
|
||||
{Phenomenon::ExtremeWind, "Extreme Wind"}, //
|
||||
{Phenomenon::Flood, "Flood"}, //
|
||||
{Phenomenon::FlashFlood, "Flash Flood"}, //
|
||||
{Phenomenon::DenseFogLand, "Dense Fog (land)"}, //
|
||||
{Phenomenon::Flood, "Flood (Forecast Points)"}, //
|
||||
{Phenomenon::Frost, "Frost"}, //
|
||||
{Phenomenon::FireWeather, "Fire Weather"}, //
|
||||
{Phenomenon::Freeze, "Freeze"}, //
|
||||
{Phenomenon::Gale, "Gale"}, //
|
||||
{Phenomenon::HurricaneForceWind, "Hurricane Force Wind"}, //
|
||||
{Phenomenon::Heat, "Heat"}, //
|
||||
{Phenomenon::Hurricane, "Hurricane"}, //
|
||||
{Phenomenon::HighWind, "High Wind"}, //
|
||||
{Phenomenon::Hydrologic, "Hydrologic"}, //
|
||||
{Phenomenon::HardFreeze, "Hard Freeze"}, //
|
||||
{Phenomenon::IceStorm, "Ice Storm"}, //
|
||||
{Phenomenon::LakeEffectSnow, "Lake Effect Snow"}, //
|
||||
{Phenomenon::LowWater, "Low Water"}, //
|
||||
{Phenomenon::LakeshoreFlood, "Lakeshore Flood"}, //
|
||||
{Phenomenon::LakeWind, "Lake Wind"}, //
|
||||
{Phenomenon::Marine, "Marine"}, //
|
||||
{Phenomenon::DenseFogMarine, "Dense Fog (marine)"}, //
|
||||
{Phenomenon::AshfallMarine, "Ashfall (marine)"}, //
|
||||
{Phenomenon::DenseSmokeMarine, "Dense Smoke (marine)"}, //
|
||||
{Phenomenon::RipCurrentRisk, "Rip Current Risk"}, //
|
||||
{Phenomenon::SmallCraft, "Small Craft"}, //
|
||||
{Phenomenon::HazardousSeas, "Hazardous Seas"}, //
|
||||
{Phenomenon::DenseSmokeLand, "Dense Smoke (land)"}, //
|
||||
{Phenomenon::Storm, "Storm"}, //
|
||||
{Phenomenon::StormSurge, "Storm Surge"}, //
|
||||
{Phenomenon::SnowSquall, "Snow Squall"}, //
|
||||
{Phenomenon::HighSurf, "High Surf"}, //
|
||||
{Phenomenon::SevereThunderstorm, "Severe Thunderstorm"}, //
|
||||
{Phenomenon::Tornado, "Tornado"}, //
|
||||
{Phenomenon::TropicalStorm, "Tropical Storm"}, //
|
||||
{Phenomenon::Tsunami, "Tsunami"}, //
|
||||
{Phenomenon::Typhoon, "Typhoon"}, //
|
||||
{Phenomenon::HeavyFreezingSpray, "Heavy Freezing Spray"}, //
|
||||
{Phenomenon::WindChill, "Wind Chill"}, //
|
||||
{Phenomenon::Wind, "Wind"}, //
|
||||
{Phenomenon::WinterStorm, "Winter Storm"}, //
|
||||
{Phenomenon::WinterWeather, "Winter Weather"}, //
|
||||
{Phenomenon::FreezingFog, "Freezing Fog"}, //
|
||||
{Phenomenon::FreezingRain, "Freezing Rain"}, //
|
||||
{Phenomenon::FreezingSpray, "Freezing Spray"}, //
|
||||
{Phenomenon::Unknown, "Unknown"}};
|
||||
|
||||
Phenomenon GetPhenomenon(const std::string& code)
|
||||
{
|
||||
Phenomenon phenomenon;
|
||||
|
||||
if (phenomenonCodes_.right.find(code) != phenomenonCodes_.right.end())
|
||||
{
|
||||
phenomenon = phenomenonCodes_.right.at(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
phenomenon = Phenomenon::Unknown;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< logPrefix_ << "Unrecognized code: \"" << code << "\"";
|
||||
}
|
||||
|
||||
return phenomenon;
|
||||
}
|
||||
|
||||
std::string GetPhenomenonCode(Phenomenon phenomenon)
|
||||
{
|
||||
return phenomenonCodes_.left.at(phenomenon);
|
||||
}
|
||||
|
||||
std::string GetPhenomenonText(Phenomenon phenomenon)
|
||||
{
|
||||
return phenomenonText_.at(phenomenon);
|
||||
}
|
||||
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
275
wxdata/source/scwx/awips/pvtec.cpp
Normal file
275
wxdata/source/scwx/awips/pvtec.cpp
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
// Enable chrono formatters
|
||||
#ifndef __cpp_lib_format
|
||||
# define __cpp_lib_format 202110L
|
||||
#endif
|
||||
|
||||
#include <scwx/awips/pvtec.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/bimap/unordered_set_of.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace awips
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "[scwx::awips::pvtec] ";
|
||||
|
||||
typedef boost::bimap<boost::bimaps::unordered_set_of<PVtec::ProductType>,
|
||||
boost::bimaps::unordered_set_of<std::string>>
|
||||
ProductTypeCodesBimap;
|
||||
|
||||
static const ProductTypeCodesBimap productTypeCodes_ =
|
||||
boost::assign::list_of<ProductTypeCodesBimap::relation> //
|
||||
(PVtec::ProductType::Operational, "O") //
|
||||
(PVtec::ProductType::Test, "T") //
|
||||
(PVtec::ProductType::Experimental, "E") //
|
||||
(PVtec::ProductType::OperationalWithExperimentalVtec, "X") //
|
||||
(PVtec::ProductType::Unknown, "??");
|
||||
|
||||
typedef boost::bimap<boost::bimaps::unordered_set_of<PVtec::Action>,
|
||||
boost::bimaps::unordered_set_of<std::string>>
|
||||
ActionCodesBimap;
|
||||
|
||||
static const ActionCodesBimap actionCodes_ =
|
||||
boost::assign::list_of<ActionCodesBimap::relation> //
|
||||
(PVtec::Action::New, "NEW") //
|
||||
(PVtec::Action::Continued, "CON") //
|
||||
(PVtec::Action::ExtendedInArea, "EXA") //
|
||||
(PVtec::Action::ExtendedInTime, "EXT") //
|
||||
(PVtec::Action::ExtendedInAreaAndTime, "EXB") //
|
||||
(PVtec::Action::Upgraded, "UPG") //
|
||||
(PVtec::Action::Canceled, "CAN") //
|
||||
(PVtec::Action::Expired, "EXP") //
|
||||
(PVtec::Action::Routine, "ROU") //
|
||||
(PVtec::Action::Correction, "COR") //
|
||||
(PVtec::Action::Unknown, "???");
|
||||
|
||||
class PVtecImpl
|
||||
{
|
||||
public:
|
||||
explicit PVtecImpl() :
|
||||
pVtecString_ {},
|
||||
fixedIdentifier_ {PVtec::ProductType::Unknown},
|
||||
action_ {PVtec::Action::Unknown},
|
||||
officeId_ {"????"},
|
||||
phenomenon_ {Phenomenon::Unknown},
|
||||
significance_ {Significance::Unknown},
|
||||
eventTrackingNumber_ {-1},
|
||||
eventBegin_ {},
|
||||
eventEnd_ {},
|
||||
valid_ {false}
|
||||
{
|
||||
}
|
||||
|
||||
~PVtecImpl() {}
|
||||
|
||||
std::string pVtecString_;
|
||||
|
||||
PVtec::ProductType fixedIdentifier_;
|
||||
PVtec::Action action_;
|
||||
std::string officeId_;
|
||||
Phenomenon phenomenon_;
|
||||
Significance significance_;
|
||||
int16_t eventTrackingNumber_;
|
||||
|
||||
std::chrono::system_clock::time_point eventBegin_;
|
||||
std::chrono::system_clock::time_point eventEnd_;
|
||||
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
PVtec::PVtec() : p(std::make_unique<PVtecImpl>()) {}
|
||||
PVtec::~PVtec() = default;
|
||||
|
||||
PVtec::PVtec(PVtec&&) noexcept = default;
|
||||
PVtec& PVtec::operator=(PVtec&&) noexcept = default;
|
||||
|
||||
PVtec::ProductType PVtec::fixed_identifier() const
|
||||
{
|
||||
return p->fixedIdentifier_;
|
||||
}
|
||||
|
||||
PVtec::Action PVtec::action() const
|
||||
{
|
||||
return p->action_;
|
||||
}
|
||||
|
||||
std::string PVtec::office_id() const
|
||||
{
|
||||
return p->officeId_;
|
||||
}
|
||||
|
||||
Phenomenon PVtec::phenomenon() const
|
||||
{
|
||||
return p->phenomenon_;
|
||||
}
|
||||
|
||||
Significance PVtec::significance() const
|
||||
{
|
||||
return p->significance_;
|
||||
}
|
||||
|
||||
int16_t PVtec::event_tracking_number() const
|
||||
{
|
||||
return p->eventTrackingNumber_;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point PVtec::event_begin() const
|
||||
{
|
||||
return p->eventBegin_;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point PVtec::event_end() const
|
||||
{
|
||||
return p->eventEnd_;
|
||||
}
|
||||
|
||||
bool PVtec::Parse(const std::string& s)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
// P-VTEC takes the form:
|
||||
// /k.aaa.cccc.pp.s.####.yymmddThhnnZ-yymmddThhnnZ/
|
||||
// 012345678901234567890123456789012345678901234567
|
||||
static constexpr size_t pVtecLength_ = 48u;
|
||||
static constexpr size_t pVtecOffsetStart_ = 0u;
|
||||
static constexpr size_t pVtecOffsetIdentifier_ = 1u;
|
||||
static constexpr size_t pVtecOffsetAction_ = 3u;
|
||||
static constexpr size_t pVtecOffsetOfficeId_ = 7u;
|
||||
static constexpr size_t pVtecOffsetPhenomenon_ = 12u;
|
||||
static constexpr size_t pVtecOffsetSignificance_ = 15u;
|
||||
static constexpr size_t pVtecOffsetEventNumber_ = 17u;
|
||||
static constexpr size_t pVtecOffsetEventBegin_ = 22u;
|
||||
static constexpr size_t pVtecOffsetEventEnd_ = 35u;
|
||||
static constexpr size_t pVtecOffsetEnd_ = 47u;
|
||||
|
||||
bool dataValid = (s.length() >= pVtecLength_ && //
|
||||
s.at(pVtecOffsetStart_) == '/' && //
|
||||
s.at(pVtecOffsetEnd_) == '/');
|
||||
|
||||
if (dataValid)
|
||||
{
|
||||
p->pVtecString_ = s.substr(0, pVtecLength_);
|
||||
|
||||
p->fixedIdentifier_ = GetProductType(s.substr(pVtecOffsetIdentifier_, 1));
|
||||
p->action_ = GetAction(s.substr(pVtecOffsetAction_, 3));
|
||||
p->officeId_ = s.substr(pVtecOffsetOfficeId_, 4);
|
||||
p->phenomenon_ = GetPhenomenon(s.substr(pVtecOffsetPhenomenon_, 2));
|
||||
p->significance_ = GetSignificance(s.substr(pVtecOffsetSignificance_, 1));
|
||||
|
||||
std::string eventNumberString = s.substr(pVtecOffsetEventNumber_, 4);
|
||||
|
||||
try
|
||||
{
|
||||
p->eventTrackingNumber_ =
|
||||
static_cast<int16_t>(std::stoi(eventNumberString));
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(warning)
|
||||
<< logPrefix_ << "Error parsing event tracking number: \""
|
||||
<< eventNumberString << "\" (" << ex.what() << ")";
|
||||
|
||||
p->eventTrackingNumber_ = -1;
|
||||
}
|
||||
|
||||
static const std::string dateTimeFormat {"%y%m%dT%H%MZ"};
|
||||
|
||||
std::string sEventBegin = s.substr(pVtecOffsetEventBegin_, 12);
|
||||
std::string sEventEnd = s.substr(pVtecOffsetEventEnd_, 12);
|
||||
|
||||
std::istringstream ssEventBegin {sEventBegin};
|
||||
std::istringstream ssEventEnd {sEventEnd};
|
||||
|
||||
sys_time<minutes> eventBegin;
|
||||
sys_time<minutes> eventEnd;
|
||||
|
||||
ssEventBegin >> parse(dateTimeFormat, eventBegin);
|
||||
ssEventEnd >> parse(dateTimeFormat, eventEnd);
|
||||
|
||||
if (!ssEventBegin.fail())
|
||||
{
|
||||
p->eventBegin_ = eventBegin;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Time parsing expected to fail if time is "000000T0000Z"
|
||||
p->eventBegin_ = {};
|
||||
}
|
||||
|
||||
if (!ssEventEnd.fail())
|
||||
{
|
||||
p->eventEnd_ = eventEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Time parsing expected to fail if time is "000000T0000Z"
|
||||
p->eventEnd_ = {};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(warning)
|
||||
<< logPrefix_ << "Invalid P-VTEC: \"" << s << "\"";
|
||||
}
|
||||
|
||||
p->valid_ = dataValid;
|
||||
|
||||
return dataValid;
|
||||
}
|
||||
|
||||
PVtec::ProductType PVtec::GetProductType(const std::string& code)
|
||||
{
|
||||
ProductType productType;
|
||||
|
||||
if (productTypeCodes_.right.find(code) != productTypeCodes_.right.end())
|
||||
{
|
||||
productType = productTypeCodes_.right.at(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
productType = ProductType::Unknown;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< logPrefix_ << "Unrecognized product code: \"" << code << "\"";
|
||||
}
|
||||
|
||||
return productType;
|
||||
}
|
||||
|
||||
std::string PVtec::GetProductTypeCode(PVtec::ProductType productType)
|
||||
{
|
||||
return productTypeCodes_.left.at(productType);
|
||||
}
|
||||
|
||||
PVtec::Action PVtec::GetAction(const std::string& code)
|
||||
{
|
||||
Action action;
|
||||
|
||||
if (actionCodes_.right.find(code) != actionCodes_.right.end())
|
||||
{
|
||||
action = actionCodes_.right.at(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
action = Action::Unknown;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< logPrefix_ << "Unrecognized action code: \"" << code << "\"";
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
std::string PVtec::GetActionCode(PVtec::Action action)
|
||||
{
|
||||
return actionCodes_.left.at(action);
|
||||
}
|
||||
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
70
wxdata/source/scwx/awips/significance.cpp
Normal file
70
wxdata/source/scwx/awips/significance.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#include <scwx/awips/significance.hpp>
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/bimap/unordered_set_of.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace awips
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "[scwx::awips::significance] ";
|
||||
|
||||
typedef boost::bimap<boost::bimaps::unordered_set_of<Significance>,
|
||||
boost::bimaps::unordered_set_of<std::string>>
|
||||
SignificanceCodesBimap;
|
||||
|
||||
static const SignificanceCodesBimap significanceCodes_ =
|
||||
boost::assign::list_of<SignificanceCodesBimap::relation> //
|
||||
(Significance::Warning, "W") //
|
||||
(Significance::Watch, "A") //
|
||||
(Significance::Advisory, "Y") //
|
||||
(Significance::Statement, "S") //
|
||||
(Significance::Forecast, "F") //
|
||||
(Significance::Outlook, "O") //
|
||||
(Significance::Synopsis, "N") //
|
||||
(Significance::Unknown, "?");
|
||||
|
||||
static const std::unordered_map<Significance, std::string> significanceText_ {
|
||||
{Significance::Warning, "Warning"}, //
|
||||
{Significance::Watch, "Watch"}, //
|
||||
{Significance::Advisory, "Advisory"}, //
|
||||
{Significance::Statement, "Statement"}, //
|
||||
{Significance::Forecast, "Forecast"}, //
|
||||
{Significance::Outlook, "Outlook"}, //
|
||||
{Significance::Synopsis, "Synopsis"}, //
|
||||
{Significance::Unknown, "Unknown"}};
|
||||
|
||||
Significance GetSignificance(const std::string& code)
|
||||
{
|
||||
Significance significance;
|
||||
|
||||
if (significanceCodes_.right.find(code) != significanceCodes_.right.end())
|
||||
{
|
||||
significance = significanceCodes_.right.at(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
significance = Significance::Unknown;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< logPrefix_ << "Unrecognized code: \"" << code << "\"";
|
||||
}
|
||||
|
||||
return significance;
|
||||
}
|
||||
|
||||
std::string GetSignificanceCode(Significance significance)
|
||||
{
|
||||
return significanceCodes_.left.at(significance);
|
||||
}
|
||||
|
||||
std::string GetSignificanceText(Significance significance)
|
||||
{
|
||||
return significanceText_.at(significance);
|
||||
}
|
||||
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include <scwx/awips/text_product_message.hpp>
|
||||
#include <scwx/awips/pvtec.hpp>
|
||||
#include <scwx/awips/wmo_header.hpp>
|
||||
#include <scwx/common/characters.hpp>
|
||||
#include <scwx/util/streams.hpp>
|
||||
|
|
@ -26,7 +27,7 @@ static const std::regex reDateTimeString {"^[0-9]{3,4} ([AP]M|UTC)"};
|
|||
|
||||
struct Vtec
|
||||
{
|
||||
std::string pVtec_;
|
||||
PVtec pVtec_;
|
||||
std::string hVtec_;
|
||||
|
||||
Vtec() : pVtec_ {}, hVtec_ {} {}
|
||||
|
|
@ -330,7 +331,7 @@ std::optional<Vtec> TryParseVtecString(std::istream& is)
|
|||
if (std::regex_search(line, rePVtecString))
|
||||
{
|
||||
vtec = Vtec();
|
||||
vtec->pVtec_.swap(line);
|
||||
vtec->pVtec_.Parse(line);
|
||||
|
||||
isBegin = is.tellg();
|
||||
|
||||
|
|
@ -342,8 +343,8 @@ std::optional<Vtec> TryParseVtecString(std::istream& is)
|
|||
}
|
||||
else
|
||||
{
|
||||
// H-VTEC was not found, so reset the istream to the beginning of the
|
||||
// line
|
||||
// H-VTEC was not found, so reset the istream to the beginning of
|
||||
// the line
|
||||
is.seekg(isBegin, std::ios_base::beg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,16 @@ project(scwx-data)
|
|||
find_package(Boost)
|
||||
|
||||
set(HDR_AWIPS include/scwx/awips/message.hpp
|
||||
include/scwx/awips/phenomenon.hpp
|
||||
include/scwx/awips/pvtec.hpp
|
||||
include/scwx/awips/significance.hpp
|
||||
include/scwx/awips/text_product_file.hpp
|
||||
include/scwx/awips/text_product_message.hpp
|
||||
include/scwx/awips/wmo_header.hpp)
|
||||
set(SRC_AWIPS source/scwx/awips/message.cpp
|
||||
source/scwx/awips/phenomenon.cpp
|
||||
source/scwx/awips/pvtec.cpp
|
||||
source/scwx/awips/significance.cpp
|
||||
source/scwx/awips/text_product_file.cpp
|
||||
source/scwx/awips/text_product_message.cpp
|
||||
source/scwx/awips/wmo_header.cpp)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue