mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:50:06 +00:00 
			
		
		
		
	Finish layer validation, including strong typing for different layer categories
This commit is contained in:
		
							parent
							
								
									8719d2d02a
								
							
						
					
					
						commit
						f222b4f666
					
				
					 3 changed files with 243 additions and 49 deletions
				
			
		|  | @ -44,9 +44,13 @@ static const std::string kDescriptionName_ {"description"}; | |||
| static const std::string kMovableName_ {"movable"}; | ||||
| static const std::string kDisplayedName_ {"displayed"}; | ||||
| 
 | ||||
| typedef std:: | ||||
|    variant<std::monostate, types::Layer, awips::Phenomenon, std::string> | ||||
|       LayerDescription; | ||||
| typedef std::variant<std::monostate, | ||||
|                      types::DataLayer, | ||||
|                      types::InformationLayer, | ||||
|                      types::MapLayer, | ||||
|                      awips::Phenomenon, | ||||
|                      std::string> | ||||
|    LayerDescription; | ||||
| 
 | ||||
| struct LayerInfo | ||||
| { | ||||
|  | @ -59,23 +63,24 @@ struct LayerInfo | |||
| typedef boost::container::stable_vector<LayerInfo> LayerVector; | ||||
| 
 | ||||
| static const std::vector<LayerInfo> kDefaultLayers_ { | ||||
|    {types::LayerType::Information, types::Layer::MapOverlay, false}, | ||||
|    {types::LayerType::Information, types::Layer::ColorTable, false}, | ||||
|    {types::LayerType::Information, types::InformationLayer::MapOverlay, false}, | ||||
|    {types::LayerType::Information, types::InformationLayer::ColorTable, false}, | ||||
|    {types::LayerType::Data, types::DataLayer::RadarRange, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::Tornado, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::SnowSquall, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::SevereThunderstorm, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::FlashFlood, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::Marine, true}, | ||||
|    {types::LayerType::Map, types::Layer::MapSymbology, false}, | ||||
|    {types::LayerType::Map, types::MapLayer::MapSymbology, false}, | ||||
|    {types::LayerType::Radar, std::monostate {}, true}, | ||||
|    {types::LayerType::Map, types::Layer::MapUnderlay, false}, | ||||
|    {types::LayerType::Map, types::MapLayer::MapUnderlay, false}, | ||||
| }; | ||||
| 
 | ||||
| static const std::vector<LayerInfo> kImmovableLayers_ { | ||||
|    {types::LayerType::Information, types::Layer::MapOverlay, false}, | ||||
|    {types::LayerType::Information, types::Layer::ColorTable, false}, | ||||
|    {types::LayerType::Map, types::Layer::MapSymbology, false}, | ||||
|    {types::LayerType::Map, types::Layer::MapUnderlay, false}, | ||||
|    {types::LayerType::Information, types::InformationLayer::MapOverlay, false}, | ||||
|    {types::LayerType::Information, types::InformationLayer::ColorTable, false}, | ||||
|    {types::LayerType::Map, types::MapLayer::MapSymbology, false}, | ||||
|    {types::LayerType::Map, types::MapLayer::MapUnderlay, false}, | ||||
| }; | ||||
| 
 | ||||
| static const std::array<awips::Phenomenon, 5> kAlertPhenomena_ { | ||||
|  | @ -206,8 +211,40 @@ void LayerModel::Impl::ReadLayerSettings() | |||
| 
 | ||||
| void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers) | ||||
| { | ||||
|    // Validate layer properties
 | ||||
|    for (auto it = layers.begin(); it != layers.end();) | ||||
|    { | ||||
|       // If the layer is invalid, remove it
 | ||||
|       if (it->type_ == types::LayerType::Unknown || | ||||
|           (std::holds_alternative<types::DataLayer>(it->description_) && | ||||
|            std::get<types::DataLayer>(it->description_) == | ||||
|               types::DataLayer::Unknown) || | ||||
|           (std::holds_alternative<types::InformationLayer>(it->description_) && | ||||
|            std::get<types::InformationLayer>(it->description_) == | ||||
|               types::InformationLayer::Unknown) || | ||||
|           (std::holds_alternative<types::MapLayer>(it->description_) && | ||||
|            std::get<types::MapLayer>(it->description_) == | ||||
|               types::MapLayer::Unknown) || | ||||
|           (std::holds_alternative<awips::Phenomenon>(it->description_) && | ||||
|            std::get<awips::Phenomenon>(it->description_) == | ||||
|               awips::Phenomenon::Unknown)) | ||||
|       { | ||||
|          // Erase the current layer and continue
 | ||||
|          it = layers.erase(it); | ||||
|          continue; | ||||
|       } | ||||
| 
 | ||||
|       // Ensure layers are appropriately marked movable
 | ||||
|       it->movable_ = (it->type_ != types::LayerType::Information && | ||||
|                       it->type_ != types::LayerType::Map); | ||||
| 
 | ||||
|       // Continue to the next layer
 | ||||
|       ++it; | ||||
|    } | ||||
| 
 | ||||
|    // Validate immovable layers
 | ||||
|    std::vector<LayerVector::iterator> immovableIterators {}; | ||||
|    LayerVector::iterator              colorTableIterator {}; | ||||
|    LayerVector::iterator              mapSymbologyIterator {}; | ||||
|    LayerVector::iterator              mapUnderlayIterator {}; | ||||
|    for (auto& immovableLayer : kImmovableLayers_) | ||||
|  | @ -253,15 +290,27 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers) | |||
|       } | ||||
| 
 | ||||
|       // Store positional iterators
 | ||||
|       if (it->type_ == types::LayerType::Map) | ||||
|       if (it->type_ == types::LayerType::Information) | ||||
|       { | ||||
|          switch (std::get<types::Layer>(it->description_)) | ||||
|          switch (std::get<types::InformationLayer>(it->description_)) | ||||
|          { | ||||
|          case types::Layer::MapSymbology: | ||||
|          case types::InformationLayer::ColorTable: | ||||
|             colorTableIterator = it; | ||||
|             break; | ||||
| 
 | ||||
|          default: | ||||
|             break; | ||||
|          } | ||||
|       } | ||||
|       else if (it->type_ == types::LayerType::Map) | ||||
|       { | ||||
|          switch (std::get<types::MapLayer>(it->description_)) | ||||
|          { | ||||
|          case types::MapLayer::MapSymbology: | ||||
|             mapSymbologyIterator = it; | ||||
|             break; | ||||
| 
 | ||||
|          case types::Layer::MapUnderlay: | ||||
|          case types::MapLayer::MapUnderlay: | ||||
|             mapUnderlayIterator = it; | ||||
|             break; | ||||
| 
 | ||||
|  | @ -274,7 +323,36 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers) | |||
|       immovableIterators.push_back(it); | ||||
|    } | ||||
| 
 | ||||
|    // Validate data layers
 | ||||
|    std::vector<LayerVector::iterator> dataIterators {}; | ||||
|    for (const auto& dataLayer : types::DataLayerIterator()) | ||||
|    { | ||||
|       // Find the data layer
 | ||||
|       auto it = std::find_if(layers.begin(), | ||||
|                              layers.end(), | ||||
|                              [&dataLayer](const LayerInfo& layer) | ||||
|                              { | ||||
|                                 return layer.type_ == types::LayerType::Data && | ||||
|                                        std::get<types::DataLayer>( | ||||
|                                           layer.description_) == dataLayer; | ||||
|                              }); | ||||
| 
 | ||||
|       if (it == layers.end()) | ||||
|       { | ||||
|          // If this is the first data layer, insert after the color table layer,
 | ||||
|          // otherwise, insert after the previous data layer
 | ||||
|          LayerVector::iterator insertPosition = dataIterators.empty() ? | ||||
|                                                    colorTableIterator + 1 : | ||||
|                                                    dataIterators.back() + 1; | ||||
|          it = | ||||
|             layers.insert(insertPosition, {types::LayerType::Data, dataLayer}); | ||||
|       } | ||||
| 
 | ||||
|       dataIterators.push_back(it); | ||||
|    } | ||||
| 
 | ||||
|    // Validate alert layers
 | ||||
|    std::vector<LayerVector::iterator> alertIterators {}; | ||||
|    for (auto& phenomenon : kAlertPhenomena_) | ||||
|    { | ||||
|       // Find the alert layer
 | ||||
|  | @ -289,16 +367,24 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers) | |||
| 
 | ||||
|       if (it == layers.end()) | ||||
|       { | ||||
|          layers.insert(mapSymbologyIterator, | ||||
|                        {types::LayerType::Alert, phenomenon}); | ||||
|          // Insert before the map symbology layer
 | ||||
|          it = layers.insert(mapSymbologyIterator, | ||||
|                             {types::LayerType::Alert, phenomenon}); | ||||
|       } | ||||
| 
 | ||||
|       alertIterators.push_back(it); | ||||
|    } | ||||
| 
 | ||||
|    // Ensure layers are appropriately marked movable
 | ||||
|    for (auto& layer : layers) | ||||
|    // Validate the radar layer
 | ||||
|    auto it = std::find_if(layers.begin(), | ||||
|                           layers.end(), | ||||
|                           [](const LayerInfo& layer) | ||||
|                           { return layer.type_ == types::LayerType::Radar; }); | ||||
|    if (it == layers.end()) | ||||
|    { | ||||
|       layer.movable_ = (layer.type_ != types::LayerType::Information && | ||||
|                         layer.type_ != types::LayerType::Map); | ||||
|       // Insert before the map underlay layer
 | ||||
|       it = layers.insert(mapUnderlayIterator, | ||||
|                          {types::LayerType::Radar, std::monostate {}}); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
|  | @ -470,10 +556,23 @@ QVariant LayerModel::data(const QModelIndex& index, int role) const | |||
|                return QString::fromStdString( | ||||
|                   std::get<std::string>(layer.description_)); | ||||
|             } | ||||
|             else if (std::holds_alternative<types::Layer>(layer.description_)) | ||||
|             else if (std::holds_alternative<types::DataLayer>( | ||||
|                         layer.description_)) | ||||
|             { | ||||
|                return QString::fromStdString(types::GetLayerName( | ||||
|                   std::get<types::Layer>(layer.description_))); | ||||
|                return QString::fromStdString(types::GetDataLayerName( | ||||
|                   std::get<types::DataLayer>(layer.description_))); | ||||
|             } | ||||
|             else if (std::holds_alternative<types::InformationLayer>( | ||||
|                         layer.description_)) | ||||
|             { | ||||
|                return QString::fromStdString(types::GetInformationLayerName( | ||||
|                   std::get<types::InformationLayer>(layer.description_))); | ||||
|             } | ||||
|             else if (std::holds_alternative<types::MapLayer>( | ||||
|                         layer.description_)) | ||||
|             { | ||||
|                return QString::fromStdString(types::GetMapLayerName( | ||||
|                   std::get<types::MapLayer>(layer.description_))); | ||||
|             } | ||||
|             else if (std::holds_alternative<awips::Phenomenon>( | ||||
|                         layer.description_)) | ||||
|  | @ -873,9 +972,10 @@ void LayerModel::Impl::AddPlacefile(const std::string& name) | |||
|       layers_.end(), | ||||
|       [](const LayerInfo& layerInfo) | ||||
|       { | ||||
|          return std::holds_alternative<types::Layer>(layerInfo.description_) && | ||||
|                 std::get<types::Layer>(layerInfo.description_) == | ||||
|                    types::Layer::ColorTable; | ||||
|          return std::holds_alternative<types::InformationLayer>( | ||||
|                    layerInfo.description_) && | ||||
|                 std::get<types::InformationLayer>(layerInfo.description_) == | ||||
|                    types::InformationLayer::ColorTable; | ||||
|       }); | ||||
|    if (insertPosition != layers_.end()) | ||||
|    { | ||||
|  | @ -899,10 +999,21 @@ void tag_invoke(boost::json::value_from_tag, | |||
|       description = awips::GetPhenomenonCode( | ||||
|          std::get<awips::Phenomenon>(record.description_)); | ||||
|    } | ||||
|    else if (std::holds_alternative<types::Layer>(record.description_)) | ||||
|    else if (std::holds_alternative<types::DataLayer>(record.description_)) | ||||
|    { | ||||
|       description = types::GetDataLayerName( | ||||
|          std::get<types::DataLayer>(record.description_)); | ||||
|    } | ||||
|    else if (std::holds_alternative<types::InformationLayer>( | ||||
|                record.description_)) | ||||
|    { | ||||
|       description = types::GetInformationLayerName( | ||||
|          std::get<types::InformationLayer>(record.description_)); | ||||
|    } | ||||
|    else if (std::holds_alternative<types::MapLayer>(record.description_)) | ||||
|    { | ||||
|       description = | ||||
|          types::GetLayerName(std::get<types::Layer>(record.description_)); | ||||
|          types::GetMapLayerName(std::get<types::MapLayer>(record.description_)); | ||||
|    } | ||||
|    else if (std::holds_alternative<std::string>(record.description_)) | ||||
|    { | ||||
|  | @ -940,10 +1051,17 @@ LayerInfo tag_invoke(boost::json::value_to_tag<LayerInfo>, | |||
| 
 | ||||
|    LayerDescription description {}; | ||||
| 
 | ||||
|    if (layerType == types::LayerType::Map || | ||||
|        layerType == types::LayerType::Information) | ||||
|    if (layerType == types::LayerType::Map) | ||||
|    { | ||||
|       description = types::GetLayer(descriptionName); | ||||
|       description = types::GetMapLayer(descriptionName); | ||||
|    } | ||||
|    else if (layerType == types::LayerType::Information) | ||||
|    { | ||||
|       description = types::GetInformationLayer(descriptionName); | ||||
|    } | ||||
|    else if (layerType == types::LayerType::Data) | ||||
|    { | ||||
|       description = types::GetDataLayer(descriptionName); | ||||
|    } | ||||
|    else if (layerType == types::LayerType::Radar) | ||||
|    { | ||||
|  |  | |||
|  | @ -17,14 +17,21 @@ static const std::unordered_map<LayerType, std::string> layerTypeName_ { | |||
|    {LayerType::Alert, "Alert"}, | ||||
|    {LayerType::Placefile, "Placefile"}, | ||||
|    {LayerType::Information, "Information"}, | ||||
|    {LayerType::Data, "Data"}, | ||||
|    {LayerType::Unknown, "?"}}; | ||||
| 
 | ||||
| static const std::unordered_map<Layer, std::string> layerName_ { | ||||
|    {Layer::MapOverlay, "Map Overlay"}, | ||||
|    {Layer::ColorTable, "Color Table"}, | ||||
|    {Layer::MapSymbology, "Map Symbology"}, | ||||
|    {Layer::MapUnderlay, "Map Underlay"}, | ||||
|    {Layer::Unknown, "?"}}; | ||||
| static const std::unordered_map<DataLayer, std::string> dataLayerName_ { | ||||
|    {DataLayer::RadarRange, "Radar Range"}, {DataLayer::Unknown, "?"}}; | ||||
| 
 | ||||
| static const std::unordered_map<InformationLayer, std::string> | ||||
|    informationLayerName_ {{InformationLayer::MapOverlay, "Map Overlay"}, | ||||
|                           {InformationLayer::ColorTable, "Color Table"}, | ||||
|                           {InformationLayer::Unknown, "?"}}; | ||||
| 
 | ||||
| static const std::unordered_map<MapLayer, std::string> mapLayerName_ { | ||||
|    {MapLayer::MapSymbology, "Map Symbology"}, | ||||
|    {MapLayer::MapUnderlay, "Map Underlay"}, | ||||
|    {MapLayer::Unknown, "?"}}; | ||||
| 
 | ||||
| LayerType GetLayerType(const std::string& name) | ||||
| { | ||||
|  | @ -49,27 +56,73 @@ std::string GetLayerTypeName(LayerType layerType) | |||
|    return layerTypeName_.at(layerType); | ||||
| } | ||||
| 
 | ||||
| Layer GetLayer(const std::string& name) | ||||
| DataLayer GetDataLayer(const std::string& name) | ||||
| { | ||||
|    auto result = | ||||
|       std::find_if(layerName_.cbegin(), | ||||
|                    layerName_.cend(), | ||||
|                    [&](const std::pair<Layer, std::string>& pair) -> bool | ||||
|       std::find_if(dataLayerName_.cbegin(), | ||||
|                    dataLayerName_.cend(), | ||||
|                    [&](const std::pair<DataLayer, std::string>& pair) -> bool | ||||
|                    { return boost::iequals(pair.second, name); }); | ||||
| 
 | ||||
|    if (result != layerName_.cend()) | ||||
|    if (result != dataLayerName_.cend()) | ||||
|    { | ||||
|       return result->first; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       return Layer::Unknown; | ||||
|       return DataLayer::Unknown; | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| std::string GetLayerName(Layer layer) | ||||
| std::string GetDataLayerName(DataLayer layer) | ||||
| { | ||||
|    return layerName_.at(layer); | ||||
|    return dataLayerName_.at(layer); | ||||
| } | ||||
| 
 | ||||
| InformationLayer GetInformationLayer(const std::string& name) | ||||
| { | ||||
|    auto result = std::find_if( | ||||
|       informationLayerName_.cbegin(), | ||||
|       informationLayerName_.cend(), | ||||
|       [&](const std::pair<InformationLayer, std::string>& pair) -> bool | ||||
|       { return boost::iequals(pair.second, name); }); | ||||
| 
 | ||||
|    if (result != informationLayerName_.cend()) | ||||
|    { | ||||
|       return result->first; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       return InformationLayer::Unknown; | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| std::string GetInformationLayerName(InformationLayer layer) | ||||
| { | ||||
|    return informationLayerName_.at(layer); | ||||
| } | ||||
| 
 | ||||
| MapLayer GetMapLayer(const std::string& name) | ||||
| { | ||||
|    auto result = | ||||
|       std::find_if(mapLayerName_.cbegin(), | ||||
|                    mapLayerName_.cend(), | ||||
|                    [&](const std::pair<MapLayer, std::string>& pair) -> bool | ||||
|                    { return boost::iequals(pair.second, name); }); | ||||
| 
 | ||||
|    if (result != mapLayerName_.cend()) | ||||
|    { | ||||
|       return result->first; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       return MapLayer::Unknown; | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| std::string GetMapLayerName(MapLayer layer) | ||||
| { | ||||
|    return mapLayerName_.at(layer); | ||||
| } | ||||
| 
 | ||||
| } // namespace types
 | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/util/iterator.hpp> | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace scwx | ||||
|  | @ -16,13 +18,28 @@ enum class LayerType | |||
|    Alert, | ||||
|    Placefile, | ||||
|    Information, | ||||
|    Data, | ||||
|    Unknown | ||||
| }; | ||||
| 
 | ||||
| enum class Layer | ||||
| enum class DataLayer | ||||
| { | ||||
|    RadarRange, | ||||
|    Unknown | ||||
| }; | ||||
| typedef scwx::util:: | ||||
|    Iterator<DataLayer, DataLayer::RadarRange, DataLayer::RadarRange> | ||||
|       DataLayerIterator; | ||||
| 
 | ||||
| enum class InformationLayer | ||||
| { | ||||
|    MapOverlay, | ||||
|    ColorTable, | ||||
|    Unknown | ||||
| }; | ||||
| 
 | ||||
| enum class MapLayer | ||||
| { | ||||
|    MapSymbology, | ||||
|    MapUnderlay, | ||||
|    Unknown | ||||
|  | @ -31,8 +48,14 @@ enum class Layer | |||
| LayerType   GetLayerType(const std::string& name); | ||||
| std::string GetLayerTypeName(LayerType layerType); | ||||
| 
 | ||||
| Layer       GetLayer(const std::string& name); | ||||
| std::string GetLayerName(Layer layer); | ||||
| DataLayer   GetDataLayer(const std::string& name); | ||||
| std::string GetDataLayerName(DataLayer layer); | ||||
| 
 | ||||
| InformationLayer GetInformationLayer(const std::string& name); | ||||
| std::string      GetInformationLayerName(InformationLayer layer); | ||||
| 
 | ||||
| MapLayer    GetMapLayer(const std::string& name); | ||||
| std::string GetMapLayerName(MapLayer layer); | ||||
| 
 | ||||
| } // namespace types
 | ||||
| } // namespace qt
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat