|
|
|
@@ -1,5 +1,4 @@
|
|
|
|
|
#include "Config.h"
|
|
|
|
|
#include "Config_Default.h"
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <exception>
|
|
|
|
@@ -12,6 +11,255 @@
|
|
|
|
|
#include "Psc_Cpp_Core/Base/Check.h"
|
|
|
|
|
std::string default_config_directory;
|
|
|
|
|
namespace {
|
|
|
|
|
Map_Tile_Source_Config make_local_tile_source(std::string key, std::string name, Map_Tile_Type tile_type,
|
|
|
|
|
std::vector<std::string> files,
|
|
|
|
|
std::optional<Map_Tile_Encoding> encoding = std::nullopt) {
|
|
|
|
|
Map_Tile_Source_Config source;
|
|
|
|
|
source.key = std::move(key);
|
|
|
|
|
source.name = std::move(name);
|
|
|
|
|
source.tile_type = tile_type;
|
|
|
|
|
source.resource.file_format = Map_Tile_File_Format::mbtiles;
|
|
|
|
|
source.resource.files = std::move(files);
|
|
|
|
|
source.resource.y_axis = Map_Tile_Y_Axis::tms;
|
|
|
|
|
source.resource.extension = ".png";
|
|
|
|
|
source.resource.tile_size = 256;
|
|
|
|
|
source.resource.maximum_level = 11;
|
|
|
|
|
source.resource.encoding = encoding;
|
|
|
|
|
return source;
|
|
|
|
|
}
|
|
|
|
|
Map_Tile_Source_Config make_online_tile_source(std::string key, std::string name, std::string url,
|
|
|
|
|
std::uint32_t maximum_level) {
|
|
|
|
|
Map_Tile_Source_Config source;
|
|
|
|
|
source.key = std::move(key);
|
|
|
|
|
source.name = std::move(name);
|
|
|
|
|
source.url = std::move(url);
|
|
|
|
|
source.resource.file_format = Map_Tile_File_Format::online;
|
|
|
|
|
source.resource.extension = ".png";
|
|
|
|
|
source.resource.tile_size = 256;
|
|
|
|
|
source.resource.maximum_level = maximum_level;
|
|
|
|
|
return source;
|
|
|
|
|
}
|
|
|
|
|
void configure_source_display(Data_Source_Map_Display_Data& display, std::string color,
|
|
|
|
|
std::uint32_t aircraft_pixel_size, std::uint32_t base_station_pixel_size,
|
|
|
|
|
double aircraft_scale, bool show_call_sign, bool show_fly_status) {
|
|
|
|
|
display.color = std::move(color);
|
|
|
|
|
display.aircraft_pixel_size = aircraft_pixel_size;
|
|
|
|
|
display.base_station_pixel_size = base_station_pixel_size;
|
|
|
|
|
display.aircraft_scale = aircraft_scale;
|
|
|
|
|
display.base_station_scale = 0.44;
|
|
|
|
|
display.show_call_sign = show_call_sign;
|
|
|
|
|
display.show_fly_status = show_fly_status;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<Dll_Data_Source> make_default_dll_source() {
|
|
|
|
|
auto source = std::make_shared<Dll_Data_Source>();
|
|
|
|
|
source->key = "lzy_dll";
|
|
|
|
|
source->set_enabled(true);
|
|
|
|
|
source->settings.write([](auto& value) {
|
|
|
|
|
value.base_station_has_valid_position = true;
|
|
|
|
|
configure_source_display(value.map_display.map2d, "#454641", 34, 30, 2.0, false, false);
|
|
|
|
|
configure_source_display(value.map_display.map3d, "#454641", 50, 100, 1.0, false, false);
|
|
|
|
|
value.lat = 37.433547;
|
|
|
|
|
value.lon = 121.40873;
|
|
|
|
|
value.alt = 2300.0;
|
|
|
|
|
value.ignore_msg_time = true;
|
|
|
|
|
});
|
|
|
|
|
source->specific.write([](auto& value) {
|
|
|
|
|
value.library_path = "@/dll_source.dll";
|
|
|
|
|
value.function_name = "adsb_read";
|
|
|
|
|
value.data_type = File_Data_Type::BIN_Blank_Text;
|
|
|
|
|
value.buffer_size = 200000;
|
|
|
|
|
});
|
|
|
|
|
return source;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<File_Data_Source> make_default_file_source() {
|
|
|
|
|
auto source = std::make_shared<File_Data_Source>();
|
|
|
|
|
source->key = "aaaa";
|
|
|
|
|
source->set_enabled(false);
|
|
|
|
|
source->settings.write([](auto& value) {
|
|
|
|
|
configure_source_display(value.map_display.map2d, "#d1a54c", 50, 100, 2.0, true, true);
|
|
|
|
|
configure_source_display(value.map_display.map3d, "#d1a54c", 50, 100, 2.0, true, true);
|
|
|
|
|
value.lat = 37.0;
|
|
|
|
|
value.lon = 121.0;
|
|
|
|
|
value.alt = 1000.0;
|
|
|
|
|
value.ignore_msg_time = true;
|
|
|
|
|
});
|
|
|
|
|
source->specific.write([](auto& value) {
|
|
|
|
|
value.file_path = R"(D:\ae\proj\projects\ECAP_Server\data\BIN_Blank_Text\ADS-B_195_0205.txt)";
|
|
|
|
|
value.data_type = File_Data_Type::BIN_Blank_Text;
|
|
|
|
|
value.play_mode = Play_Mode::loop;
|
|
|
|
|
});
|
|
|
|
|
return source;
|
|
|
|
|
}
|
|
|
|
|
void configure_feed(Data_Feed& feed, std::string type, std::string key, bool enabled, Output_Data_Format format,
|
|
|
|
|
bool use_status, Mode_S_Output_Type mode_s_output_type, bool use_mode_ac, bool sbs_only_pos) {
|
|
|
|
|
feed.type = std::move(type);
|
|
|
|
|
feed.key = std::move(key);
|
|
|
|
|
feed.set_enabled(enabled);
|
|
|
|
|
feed.source_key = "lzy_dll";
|
|
|
|
|
feed.output_format.write([&](auto& value) {
|
|
|
|
|
value.type = format;
|
|
|
|
|
value.use_status = use_status;
|
|
|
|
|
value.mode_s_output_type = mode_s_output_type;
|
|
|
|
|
value.use_mode_ac = use_mode_ac;
|
|
|
|
|
value.sbs_only_pos = sbs_only_pos;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<Data_Feed_TCP_Server> make_default_tcp_server_feed(std::string key, bool enabled,
|
|
|
|
|
Output_Data_Format format, bool use_status,
|
|
|
|
|
Mode_S_Output_Type mode_s_output_type,
|
|
|
|
|
bool use_mode_ac, bool sbs_only_pos,
|
|
|
|
|
std::uint16_t port, std::size_t user_buffer_size,
|
|
|
|
|
std::size_t system_buffer_size) {
|
|
|
|
|
auto feed = std::make_shared<Data_Feed_TCP_Server>();
|
|
|
|
|
configure_feed(*feed, "Data_Feed_TCP_Server", std::move(key), enabled, format, use_status, mode_s_output_type,
|
|
|
|
|
use_mode_ac, sbs_only_pos);
|
|
|
|
|
feed->specific.write([&](auto& value) {
|
|
|
|
|
value.port = port;
|
|
|
|
|
value.connect_user_buffer_size = user_buffer_size;
|
|
|
|
|
value.connect_system_buffer_size = system_buffer_size;
|
|
|
|
|
});
|
|
|
|
|
return feed;
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON make_external_resource(std::string name, std::string download_url, std::string description,
|
|
|
|
|
std::uint64_t update_interval_seconds, std::time_t last_updated_at) {
|
|
|
|
|
External_Resources_Data resource;
|
|
|
|
|
resource.name = std::move(name);
|
|
|
|
|
resource.download_url = std::move(download_url);
|
|
|
|
|
resource.description = std::move(description);
|
|
|
|
|
resource.update_interval_seconds = update_interval_seconds;
|
|
|
|
|
resource.last_updated_at = last_updated_at;
|
|
|
|
|
return resource.to_base_json();
|
|
|
|
|
}
|
|
|
|
|
void configure_windows_defaults(Config& config) {
|
|
|
|
|
config.version = "windows_v1.0.5";
|
|
|
|
|
config.dsp_config.library_path = "@/dll_source.dll";
|
|
|
|
|
config.dsp_config.center_freq = 16000000;
|
|
|
|
|
config.dsp_config.band_width = 6000;
|
|
|
|
|
config.dsp_config.sample_rate = 60000;
|
|
|
|
|
config.dsp_config.fft_point_number = 2048;
|
|
|
|
|
config.dsp_config.fft_period_ms = 50;
|
|
|
|
|
config.dsp_config.fft_win_type = UHD_FFTWin::blkmc;
|
|
|
|
|
config.dsp_config.frame_rate = 60;
|
|
|
|
|
config.dsp_config.debug = false;
|
|
|
|
|
config.drogon_config = Psc::JSON::object({{"app", Psc::JSON::object({{"threads_num", 0},
|
|
|
|
|
{"client_max_body_size", "1000M"},
|
|
|
|
|
{"client_max_memory_body_size", "1000M"}})}});
|
|
|
|
|
config.http_monitor_config.access_log = false;
|
|
|
|
|
config.http_monitor_config.slow_request_threshold_ms = 3000;
|
|
|
|
|
config.http_monitor_config.slow_scope_threshold_ms = 1000;
|
|
|
|
|
config.mlat.settings.write([](auto& value) { value.merge = false; });
|
|
|
|
|
config.web_server_config.webapp = "@/../third_party/eacp_webapp/wwwroot";
|
|
|
|
|
config.web_server_config.listen_port = 9081;
|
|
|
|
|
config.map_resources_config.write([](auto& value) {
|
|
|
|
|
value.current_imagery_key = "mixed_imagery";
|
|
|
|
|
value.tile_sources = {
|
|
|
|
|
make_local_tile_source("mixed_imagery", "本地混合图", Map_Tile_Type::imagery,
|
|
|
|
|
{"C:/tiles/混合图-世界-0-8.mbtiles", "C:/tiles/混合图-中国-9-10.mbtiles",
|
|
|
|
|
"C:/tiles/混合图-中国-11.mbtiles"}),
|
|
|
|
|
make_local_tile_source("height_terrain", "本地高程", Map_Tile_Type::terrain,
|
|
|
|
|
{"C:/tiles/高程-世界-0-8.mbtiles", "C:/tiles/高程-中国-9-10.mbtiles",
|
|
|
|
|
"C:/tiles/高程-中国-11.mbtiles"}, Map_Tile_Encoding::terrarium),
|
|
|
|
|
make_online_tile_source("osm_online", "OpenStreetMap在线", "https://tile.openstreetmap.org/{z}/{x}/{y}.png", 19),
|
|
|
|
|
make_online_tile_source("osm_hot_online", "OpenStreetMap HOT在线", "https://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png", 19),
|
|
|
|
|
make_online_tile_source("cyclosm_online", "CyclOSM在线", "https://a.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png", 20),
|
|
|
|
|
make_online_tile_source("carto_light_online", "Carto Light在线", "https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png", 20),
|
|
|
|
|
make_online_tile_source("carto_dark_online", "Carto Dark在线", "https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png", 20),
|
|
|
|
|
make_online_tile_source("carto_voyager_online", "Carto Voyager在线", "https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png", 20),
|
|
|
|
|
make_online_tile_source("carto_dark_nolabels_online", "Carto Dark无标注在线", "https://a.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png", 20),
|
|
|
|
|
make_online_tile_source("opentopomap_online", "OpenTopoMap在线", "https://a.tile.opentopomap.org/{z}/{x}/{y}.png", 17)};
|
|
|
|
|
});
|
|
|
|
|
config.map_view_config.write([](auto& value) {
|
|
|
|
|
value.scene_mode = Map_Scene_Mode::map_3d;
|
|
|
|
|
value.map2d.current_imagery_key = "mixed_imagery";
|
|
|
|
|
value.map2d.current_terrain_key = "terrain";
|
|
|
|
|
value.map2d.tile_display_maximum_level = 8;
|
|
|
|
|
value.map3d.current_imagery_key = "mixed_imagery";
|
|
|
|
|
value.map3d.current_terrain_key = "terrain";
|
|
|
|
|
value.map3d.tile_display_maximum_level = 19;
|
|
|
|
|
value.camera.longitude = 122.014707;
|
|
|
|
|
value.camera.latitude = 35.714108;
|
|
|
|
|
value.camera.height = 241660.03182;
|
|
|
|
|
value.camera.heading = 347.582854;
|
|
|
|
|
value.camera.pitch = -54.917211;
|
|
|
|
|
value.camera.roll = 359.999884;
|
|
|
|
|
});
|
|
|
|
|
config.mode_acs.settings.write([](auto& value) {
|
|
|
|
|
value.timeout_seconds = 160;
|
|
|
|
|
value.max_speed_m_s = 1000;
|
|
|
|
|
value.wait_process_msg = true;
|
|
|
|
|
value.time_space_filter = true;
|
|
|
|
|
value.speed_filter = true;
|
|
|
|
|
value.max_track_point_size = 20000;
|
|
|
|
|
value.mode_s_max_num = 700000;
|
|
|
|
|
value.mode_other_max_num = 10000;
|
|
|
|
|
value.report_data_feed_msg_mum = 10000;
|
|
|
|
|
value.default_min_aircraft_list_num = 10;
|
|
|
|
|
});
|
|
|
|
|
config.mode_acs.data_source_config.map.push_back(make_default_dll_source());
|
|
|
|
|
config.mode_acs.data_source_config.map.push_back(make_default_file_source());
|
|
|
|
|
config.mode_acs.data_feed_config.map.push_back(make_default_tcp_server_feed(
|
|
|
|
|
"Port_10003", true, Output_Data_Format::BIN, true, Mode_S_Output_Type::ALL_Mode_S, true, true, 10003,
|
|
|
|
|
409600, 409600));
|
|
|
|
|
auto udp_server = std::make_shared<Data_Feed_UDP_Server>();
|
|
|
|
|
configure_feed(*udp_server, "Data_Feed_UDP_Server", "22333", false, Output_Data_Format::BIN, false,
|
|
|
|
|
Mode_S_Output_Type::ALL_Mode_S, false, false);
|
|
|
|
|
udp_server->specific.write([](auto& value) { value.port = 50001; });
|
|
|
|
|
config.mode_acs.data_feed_config.map.push_back(udp_server);
|
|
|
|
|
auto udp_client = std::make_shared<Data_Feed_UDP_Client>();
|
|
|
|
|
configure_feed(*udp_client, "Data_Feed_UDP_Client", "Port_10004", false, Output_Data_Format::AVR, false,
|
|
|
|
|
Mode_S_Output_Type::DF_11_17_18, false, true);
|
|
|
|
|
udp_client->specific.write([](auto& value) {
|
|
|
|
|
value.port = 30004;
|
|
|
|
|
value.url = "192.168.1.75";
|
|
|
|
|
});
|
|
|
|
|
config.mode_acs.data_feed_config.map.push_back(udp_client);
|
|
|
|
|
auto tcp_client = std::make_shared<Data_Feed_TCP_Client>();
|
|
|
|
|
configure_feed(*tcp_client, "Data_Feed_TCP_Client", "Port_10005", false, Output_Data_Format::BIN, true,
|
|
|
|
|
Mode_S_Output_Type::NO_POS_Mode_S, true, true);
|
|
|
|
|
tcp_client->specific.write([](auto& value) {
|
|
|
|
|
value.url = "192.168.1.167";
|
|
|
|
|
value.port = 10005;
|
|
|
|
|
});
|
|
|
|
|
config.mode_acs.data_feed_config.map.push_back(tcp_client);
|
|
|
|
|
config.mode_acs.data_feed_config.map.push_back(make_default_tcp_server_feed(
|
|
|
|
|
"Port_30003", false, Output_Data_Format::SBS, false, Mode_S_Output_Type::ALL_Mode_S, true, true, 30003, 0, 0));
|
|
|
|
|
config.log_config.open_mode = Log_Config::Open_Mode::Delete;
|
|
|
|
|
config.log_config.piece_num = 10;
|
|
|
|
|
config.log_config.size_MB = 10;
|
|
|
|
|
config.console_config.record_playback = false;
|
|
|
|
|
config.console_config.mode_s_console = false;
|
|
|
|
|
config.external_resources_manager.ecap_sqlite_path = "@/../data/sqlite/ecap.sqlite";
|
|
|
|
|
auto external_database = Psc::JSON::object();
|
|
|
|
|
external_database.append({"ecap_sqlite_path", config.external_resources_manager.ecap_sqlite_path});
|
|
|
|
|
auto external_resources = Psc::JSON::array();
|
|
|
|
|
external_resources.append(make_external_resource("tar1090_db_aircraft", "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", "wiedehopf/tar1090-db 发布的轻量 ICAO24 飞机静态库,提供注册号、机型、年份和运营方备注。", 604800, 1780388281));
|
|
|
|
|
external_resources.append(make_external_resource("wiedehopf_tar1090_db_aircraft", "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", "wiedehopf/tar1090-db 项目发布的飞机静态数据库镜像,供 tar1090 本地识别飞机。", 604800, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("mictronics_aircraft_database", "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", "Mictronics 社区飞机数据库的 tar1090 汇总镜像,可按 ICAO24 查询注册号、机型和运营方。", 604800, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("opensky_aircraft_database", "https://opensky-network.org/datasets/metadata/aircraftDatabase.csv", "OpenSky Network 飞机元数据 CSV,包含制造商、型号、注册号和运营方等字段。", 604800, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("faa_aircraft_registry", "https://registry.faa.gov/database/ReleasableAircraft.zip", "FAA 官方可公开下载的美国飞机注册库,MASTER.txt 包含 Mode-S Hex 注册信息。", 86400, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("icao_doc_8643_aircraft_type_designators", "", "ICAO Doc 8643 机型代码表,用于将 A320、B738 等 designator 映射为制造商、型号和类别。", 2419200, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("vrs_routes", "https://vrs-standing-data.adsb.lol/routes.csv", "VRS 航线表,以 callsign 查询机场代码序列,用于推断起飞机场、经停机场和目的机场。", 3600, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("vrs_airports", "https://vrs-standing-data.adsb.lol/airports.csv", "VRS 机场字典,提供机场代码、名称、国家、经纬度和高度。", 3600, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("adsblol_vrs_standing_data_routes", "https://vrs-standing-data.adsb.lol/routes.csv", "ADSB.lol 发布的 VRS standing-data 航线镜像,以 callsign 查询机场代码序列。", 3600, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("vradarserver_standing_data_routes", "https://vrs-standing-data.adsb.lol/routes.csv", "Virtual Radar Server standing-data 的航线适配表;当前在线更新使用 ADSB.lol 公共镜像。", 3600, 1780381804));
|
|
|
|
|
external_resources.append(make_external_resource("opensky_flightdata_api_cache", "", "OpenSky FlightData API 查询缓存,按 ICAO24 和时间范围保存历史航班起降机场结果。", 0, 1780381804));
|
|
|
|
|
external_database.append({"list", external_resources});
|
|
|
|
|
config.external_resources_manager.from_json(&external_database);
|
|
|
|
|
config.cesium_graphics_config.settings.write([](auto& value) {
|
|
|
|
|
value.resolution_scale = 1.0;
|
|
|
|
|
value.fxaa = true;
|
|
|
|
|
value.shadows = true;
|
|
|
|
|
value.enable_lighting = true;
|
|
|
|
|
value.solar_lighting = true;
|
|
|
|
|
value.terrain_enabled_in_3d = true;
|
|
|
|
|
value.terrain_exaggeration = 5.0;
|
|
|
|
|
value.surface_navigation_reference_visible = true;
|
|
|
|
|
value.view_axes_visible = true;
|
|
|
|
|
value.view_axes_panel_x = 3.0;
|
|
|
|
|
value.view_axes_panel_y = 337.0;
|
|
|
|
|
value.view_axes_panel_size = 184.0;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
std::filesystem::path config_directory() {
|
|
|
|
|
if (!default_config_directory.empty()) {
|
|
|
|
|
return default_config_directory;
|
|
|
|
@@ -71,24 +319,32 @@ void merge_json_object(Psc::JSON& target, const Psc::JSON& value) {
|
|
|
|
|
*iterator = child;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON read_config_section(Config_Section section, const Psc::JSON& defaults) {
|
|
|
|
|
const auto path = config_section_path(section);
|
|
|
|
|
if (!std::filesystem::exists(path)) {
|
|
|
|
|
const auto name = config_section_name(section);
|
|
|
|
|
const auto value = defaults.get(name);
|
|
|
|
|
if (value == nullptr) {
|
|
|
|
|
throw std::runtime_error("default config section does not exist: " + std::string(name));
|
|
|
|
|
}
|
|
|
|
|
write_config_section(section, *value);
|
|
|
|
|
return *value;
|
|
|
|
|
Psc::JSON default_config() {
|
|
|
|
|
Config config;
|
|
|
|
|
configure_windows_defaults(config);
|
|
|
|
|
return config.toJson();
|
|
|
|
|
}
|
|
|
|
|
[[noreturn]] void config_load_failed(Config_Section section, std::string_view reason) {
|
|
|
|
|
std::cerr << "配置文件加载失败: 【" << config_section_path(section).string() << "】 配置: 【"
|
|
|
|
|
<< config_section_name(section) << "】 原因: " << reason << std::endl;
|
|
|
|
|
std::terminate();
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON read_config_section(Config_Section section) {
|
|
|
|
|
try {
|
|
|
|
|
return read_existing_config_section_unlocked(section);
|
|
|
|
|
}
|
|
|
|
|
std::ifstream input(path, std::ios::binary);
|
|
|
|
|
if (!input) {
|
|
|
|
|
throw std::runtime_error("cannot open config section: " + path.string());
|
|
|
|
|
catch (const std::exception& error) {
|
|
|
|
|
config_load_failed(section, error.what());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
template <typename Function>
|
|
|
|
|
void assign_config_section(Config_Section section, Function&& function) {
|
|
|
|
|
try {
|
|
|
|
|
function();
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& error) {
|
|
|
|
|
config_load_failed(section, error.what());
|
|
|
|
|
}
|
|
|
|
|
std::ostringstream buffer;
|
|
|
|
|
buffer << input.rdbuf();
|
|
|
|
|
return Psc::parse_json(buffer.str());
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON config_section_value(Global& global, Config_Section section) {
|
|
|
|
|
switch (section) {
|
|
|
|
@@ -180,28 +436,22 @@ void migrate_legacy_source_feed_relations(const Psc::JSON* mode_acs, Data_Source
|
|
|
|
|
}
|
|
|
|
|
void Data_Topology_View_Config::from_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object)
|
|
|
|
|
return;
|
|
|
|
|
if (const auto* value = that_json->get("initialized"); value != nullptr && value->valueType == Psc::Bool)
|
|
|
|
|
initialized = value->bool_val();
|
|
|
|
|
if (const auto value = that_json->try_get_number<std::uint32_t>("layout_revision"); value.has_value())
|
|
|
|
|
layout_revision = value.value();
|
|
|
|
|
if (const auto value = that_json->try_get_number<double>("zoom"); value.has_value() && std::isfinite(value.value()) && value.value() > 0.0)
|
|
|
|
|
zoom = value.value();
|
|
|
|
|
if (const auto value = that_json->try_get_number<double>("pan_x"); value.has_value() && std::isfinite(value.value()))
|
|
|
|
|
pan_x = value.value();
|
|
|
|
|
if (const auto value = that_json->try_get_number<double>("pan_y"); value.has_value() && std::isfinite(value.value()))
|
|
|
|
|
pan_y = value.value();
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "data_topology_view");
|
|
|
|
|
Get_J(initialized) Get_J(layout_revision) Get_J(zoom) Get_J(pan_x) Get_J(pan_y)
|
|
|
|
|
if (!std::isfinite(zoom) || zoom <= 0.0 || !std::isfinite(pan_x) || !std::isfinite(pan_y))
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "data_topology_view");
|
|
|
|
|
const auto* positions = that_json->get("node_positions");
|
|
|
|
|
if (positions == nullptr || positions->valueType != Psc::Object)
|
|
|
|
|
return;
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "node_positions");
|
|
|
|
|
node_positions.clear();
|
|
|
|
|
for (const auto& item : positions->children) {
|
|
|
|
|
if (item.valueType != Psc::Object)
|
|
|
|
|
continue;
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), item.key);
|
|
|
|
|
const auto x = item.try_get_number<double>("x");
|
|
|
|
|
const auto y = item.try_get_number<double>("y");
|
|
|
|
|
if (x.has_value() && y.has_value() && std::isfinite(x.value()) && std::isfinite(y.value()))
|
|
|
|
|
node_positions.emplace(item.key, Data_Topology_Node_Position{x.value(), y.value()});
|
|
|
|
|
if (!x.has_value() || !y.has_value() || !std::isfinite(x.value()) || !std::isfinite(y.value()))
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), item.key);
|
|
|
|
|
node_positions.emplace(item.key, Data_Topology_Node_Position{x.value(), y.value()});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Data_Topology_View_Config::to_json() const {
|
|
|
|
@@ -218,49 +468,89 @@ Psc::JSON Mode_ACS_Config::to_base_json() const {
|
|
|
|
|
result.append(Psc::JSON("data_topology_view", data_topology_view.read([](const auto& value) { return value.to_json(); })));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
void Mode_ACS_Config::from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
void Mode_ACS_Config::from_json(const Psc::JSON* that_json) {
|
|
|
|
|
settings.write([&](auto& value) {
|
|
|
|
|
value.from_base_json(that_json, not_exist_use_default_value);
|
|
|
|
|
value.from_base_json(that_json);
|
|
|
|
|
SSR::Monitor_Mode_ACS_Message_Num = value.monitor_msg_live;
|
|
|
|
|
});
|
|
|
|
|
data_source_config.init(that_json->get("data_source"), not_exist_use_default_value);
|
|
|
|
|
data_feed_config.init(that_json->get("data_feed"), not_exist_use_default_value);
|
|
|
|
|
data_source_config.init(that_json->get("data_source"));
|
|
|
|
|
data_feed_config.init(that_json->get("data_feed"));
|
|
|
|
|
migrate_legacy_source_feed_relations(that_json, data_source_config, data_feed_config);
|
|
|
|
|
data_topology_view.write([&](auto& value) { value.from_json(that_json->get("data_topology_view")); });
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Config::load() {
|
|
|
|
|
void Config::create_missing_config_files() {
|
|
|
|
|
std::filesystem::create_directories(config_directory());
|
|
|
|
|
std::error_code ignored_error;
|
|
|
|
|
std::filesystem::remove(config_directory() / "device.json", ignored_error);
|
|
|
|
|
const auto defaults = Psc::parse_json(std::string_view(reinterpret_cast<const char*>(ecap_default_config_json), sizeof(ecap_default_config_json)));
|
|
|
|
|
const auto defaults = default_config();
|
|
|
|
|
for (std::size_t index = 0; index < static_cast<std::size_t>(Config_Section::count); ++index) {
|
|
|
|
|
const auto section = static_cast<Config_Section>(index);
|
|
|
|
|
if (std::filesystem::exists(config_section_path(section)))
|
|
|
|
|
continue;
|
|
|
|
|
const auto* value = defaults.get(config_section_name(section));
|
|
|
|
|
if (value == nullptr)
|
|
|
|
|
config_load_failed(section, "内置 Windows 默认配置缺少该分片");
|
|
|
|
|
try {
|
|
|
|
|
write_config_section(section, *value);
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& error) {
|
|
|
|
|
config_load_failed(section, error.what());
|
|
|
|
|
}
|
|
|
|
|
std::cout << "生成默认配置文件: 【" << config_section_path(section).string() << "】" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Config::load() {
|
|
|
|
|
create_missing_config_files();
|
|
|
|
|
auto result = Psc::JSON::object();
|
|
|
|
|
for (std::size_t index = 0; index < static_cast<std::size_t>(Config_Section::count); ++index) {
|
|
|
|
|
const auto section = static_cast<Config_Section>(index);
|
|
|
|
|
result.append({std::string(config_section_name(section)), read_config_section(section, defaults)});
|
|
|
|
|
result.append({std::string(config_section_name(section)), read_config_section(section)});
|
|
|
|
|
}
|
|
|
|
|
std::cout << get_current_date_string() << " 启动加载配置目录: 【" << config_directory().string() << "】" << std::endl;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
void Config::from_log_json(const Psc::JSON* that_json) {
|
|
|
|
|
assign_config_section(Config_Section::log, [&] { log_config.from_base_json(that_json); });
|
|
|
|
|
}
|
|
|
|
|
void Config::from_base_json(Psc::JSON* that_json) {
|
|
|
|
|
assign_config_section(Config_Section::version, [&] { Get_J(version) });
|
|
|
|
|
assign_config_section(Config_Section::mlat, [&] { mlat.from_json(that_json->get("mlat")); });
|
|
|
|
|
assign_config_section(Config_Section::web_server, [&] { web_server_config.from_base_json(that_json->get("web_server")); });
|
|
|
|
|
assign_config_section(Config_Section::map_resources, [&] {
|
|
|
|
|
map_resources_config.write([&](auto& value) { value.from_base_json(that_json->get("map_resources")); });
|
|
|
|
|
});
|
|
|
|
|
assign_config_section(Config_Section::map_view, [&] {
|
|
|
|
|
map_view_config.write([&](auto& value) { value.from_base_json(that_json->get("map_view")); });
|
|
|
|
|
});
|
|
|
|
|
assign_config_section(Config_Section::cesium_graphics, [&] {
|
|
|
|
|
cesium_graphics_config.from_base_json(that_json->get("cesium_graphics"));
|
|
|
|
|
});
|
|
|
|
|
assign_config_section(Config_Section::map_models, [&] {
|
|
|
|
|
map_model_config.write([&](auto& value) { value.from_base_json(that_json->get("map_models")); });
|
|
|
|
|
});
|
|
|
|
|
assign_config_section(Config_Section::mode_acs, [&] { mode_acs.from_json(that_json->get("mode_acs")); });
|
|
|
|
|
assign_config_section(Config_Section::console, [&] { console_config.from_base_json(that_json->get("console")); });
|
|
|
|
|
assign_config_section(Config_Section::dsp, [&] { dsp_config.from_json(that_json->get("dsp")); });
|
|
|
|
|
assign_config_section(Config_Section::drogon, [&] { drogon_config = *that_json->get("drogon"); });
|
|
|
|
|
assign_config_section(Config_Section::http_monitor, [&] { http_monitor_config.from_base_json(that_json->get("http_monitor")); });
|
|
|
|
|
assign_config_section(Config_Section::external_database, [&] {
|
|
|
|
|
external_resources_manager.from_json(that_json->get("external_database"));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Web_Server_Config::to_base_json() const {
|
|
|
|
|
return Psc::JSON::object({{"webapp", webapp}, {"listen_port", listen_port}});
|
|
|
|
|
}
|
|
|
|
|
void Web_Server_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
void Web_Server_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
std::error_code error;
|
|
|
|
|
auto result = Psc::assign_field_ec(webapp, that_json, "webapp", error);
|
|
|
|
|
if(!not_exist_use_default_value)
|
|
|
|
|
Psc::check_json_assign_field(result, error, that_json, "webapp");
|
|
|
|
|
if(that_json != nullptr && that_json->get("listen_port") != nullptr) {
|
|
|
|
|
error.clear();
|
|
|
|
|
result = Psc::assign_field_ec(listen_port, that_json, "listen_port", error);
|
|
|
|
|
Psc::check_json_assign_field(result, error, that_json, "listen_port");
|
|
|
|
|
}
|
|
|
|
|
Psc::check_json_assign_field(result, error, that_json, "webapp");
|
|
|
|
|
error.clear();
|
|
|
|
|
result = Psc::assign_field_ec(listen_port, that_json, "listen_port", error);
|
|
|
|
|
Psc::check_json_assign_field(result, error, that_json, "listen_port");
|
|
|
|
|
}
|
|
|
|
|
static std::vector<std::string> read_optional_string_array(const Psc::JSON* json, std::string_view key) {
|
|
|
|
|
static std::vector<std::string> read_string_array(const Psc::JSON* json, std::string_view key) {
|
|
|
|
|
auto field = json->get(key);
|
|
|
|
|
if (field == nullptr) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
if (field->valueType != Psc::Array) {
|
|
|
|
|
if (field == nullptr || field->valueType != Psc::Array) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
|
|
|
|
|
}
|
|
|
|
|
std::vector<std::string> ret;
|
|
|
|
@@ -309,24 +599,20 @@ static std::map<std::string, Map_Model_Item_Config> make_default_aircraft_models
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
static std::map<std::string, Map_Model_Item_Config>
|
|
|
|
|
read_optional_model_object_field(const Psc::JSON* json, std::string_view key,
|
|
|
|
|
std::map<std::string, Map_Model_Item_Config> fallback,
|
|
|
|
|
bool not_exist_use_default_value) {
|
|
|
|
|
static std::map<std::string, Map_Model_Item_Config> read_model_object_field(const Psc::JSON* json, std::string_view key) {
|
|
|
|
|
auto field = json->get(key);
|
|
|
|
|
if (field == nullptr) {
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|
|
|
|
|
if (field->valueType != Psc::Object) {
|
|
|
|
|
if (field == nullptr || field->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
|
|
|
|
|
}
|
|
|
|
|
std::map<std::string, Map_Model_Item_Config> result;
|
|
|
|
|
for (const auto& child : field->children) {
|
|
|
|
|
if (child.valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
|
|
|
|
|
}
|
|
|
|
|
fallback[child.key].from_base_json(&child, not_exist_use_default_value);
|
|
|
|
|
auto& item = result[child.key];
|
|
|
|
|
item.from_base_json(&child);
|
|
|
|
|
}
|
|
|
|
|
return fallback;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
static Psc::JSON write_model_object(std::string_view key, const std::map<std::string, Map_Model_Item_Config>& values) {
|
|
|
|
|
auto object = Psc::JSON::object();
|
|
|
|
@@ -345,52 +631,47 @@ static std::string read_optional_string_field(const Psc::JSON* json, std::string
|
|
|
|
|
}
|
|
|
|
|
return field->val;
|
|
|
|
|
}
|
|
|
|
|
static std::string read_optional_string_field(const Psc::JSON* json, std::string_view key, std::string_view fallback) {
|
|
|
|
|
static std::string read_string_field(const Psc::JSON* json, std::string_view key) {
|
|
|
|
|
auto field = json->get(key);
|
|
|
|
|
if (field == nullptr) {
|
|
|
|
|
return std::string(fallback);
|
|
|
|
|
}
|
|
|
|
|
if (field->valueType != Psc::String) {
|
|
|
|
|
if (field == nullptr || field->valueType != Psc::String) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
|
|
|
|
|
}
|
|
|
|
|
return field->val;
|
|
|
|
|
}
|
|
|
|
|
static std::uint32_t read_optional_uint32_field(const Psc::JSON* json, std::string_view key, std::uint32_t fallback) {
|
|
|
|
|
static std::uint32_t read_uint32_field(const Psc::JSON* json, std::string_view key) {
|
|
|
|
|
auto field = json->get(key);
|
|
|
|
|
if (field == nullptr) {
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|
|
|
|
|
if (field->valueType != Psc::Number) {
|
|
|
|
|
if (field == nullptr || field->valueType != Psc::Number) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
|
|
|
|
|
}
|
|
|
|
|
return field->number_val<std::uint32_t>();
|
|
|
|
|
}
|
|
|
|
|
static double read_optional_double_field(const Psc::JSON* json, std::string_view key, double fallback) {
|
|
|
|
|
static double read_double_field(const Psc::JSON* json, std::string_view key) {
|
|
|
|
|
auto field = json->get(key);
|
|
|
|
|
if (field == nullptr) {
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|
|
|
|
|
if (field->valueType != Psc::Number) {
|
|
|
|
|
if (field == nullptr || field->valueType != Psc::Number) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
|
|
|
|
|
}
|
|
|
|
|
return field->number_val<double>();
|
|
|
|
|
}
|
|
|
|
|
void Map_Tile_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
void Map_Tile_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map tile config");
|
|
|
|
|
}
|
|
|
|
|
Map_Tile_Config_Data::from_base_json(that_json, not_exist_use_default_value);
|
|
|
|
|
directories = read_optional_string_array(that_json, "directories");
|
|
|
|
|
files = read_optional_string_array(that_json, "files");
|
|
|
|
|
encoding = read_optional_string_field(that_json, "encoding");
|
|
|
|
|
Map_Tile_Config_Data::from_base_json(that_json);
|
|
|
|
|
directories = read_string_array(that_json, "directories");
|
|
|
|
|
files = read_string_array(that_json, "files");
|
|
|
|
|
encoding.reset();
|
|
|
|
|
if (that_json->get("encoding") != nullptr) {
|
|
|
|
|
std::error_code error;
|
|
|
|
|
const auto result = Psc::assign_field_ec(encoding, that_json, "encoding", error);
|
|
|
|
|
Psc::check_json_assign_field(result, error, that_json, "encoding");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Map_Tile_Config::to_base_json() const {
|
|
|
|
|
auto ret = Map_Tile_Config_Data::to_base_json();
|
|
|
|
|
ret.append(write_string_array("directories", directories));
|
|
|
|
|
ret.append(write_string_array("files", files));
|
|
|
|
|
if (!encoding.empty()) {
|
|
|
|
|
ret.append({"encoding", encoding});
|
|
|
|
|
}
|
|
|
|
|
if (encoding.has_value())
|
|
|
|
|
ret.append({"encoding", encoding.value()});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Map_Tile_Config::to_public_json(std::string_view url) const {
|
|
|
|
@@ -401,18 +682,17 @@ Psc::JSON Map_Tile_Config::to_public_json(std::string_view url) const {
|
|
|
|
|
ret.append({"tile_size", tile_size});
|
|
|
|
|
ret.append({"projection", Psc::to_string(projection)});
|
|
|
|
|
ret.append({"y_axis", Psc::to_string(y_axis)});
|
|
|
|
|
if (!encoding.empty()) {
|
|
|
|
|
ret.append({"encoding", encoding});
|
|
|
|
|
}
|
|
|
|
|
if (encoding.has_value())
|
|
|
|
|
ret.append({"encoding", encoding.value()});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
void Map_Tile_Source_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
void Map_Tile_Source_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map tile source config");
|
|
|
|
|
}
|
|
|
|
|
Map_Tile_Source_Config_Data::from_base_json(that_json, not_exist_use_default_value);
|
|
|
|
|
Map_Tile_Source_Config_Data::from_base_json(that_json);
|
|
|
|
|
url = read_optional_string_field(that_json, "url");
|
|
|
|
|
resource.from_base_json(that_json->get("resource"), not_exist_use_default_value);
|
|
|
|
|
resource.from_base_json(that_json->get("resource"));
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Map_Tile_Source_Config::to_base_json() const {
|
|
|
|
|
auto ret = Map_Tile_Source_Config_Data::to_base_json();
|
|
|
|
@@ -431,20 +711,16 @@ Psc::JSON Map_Tile_Source_Config::to_public_json(std::string_view local_url) con
|
|
|
|
|
ret.append({"resource", resource.to_public_json(local() ? local_url : url)});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
static std::vector<Map_Tile_Source_Config> read_optional_tile_source_array(const Psc::JSON* json, std::string_view key,
|
|
|
|
|
bool not_exist_use_default_value) {
|
|
|
|
|
static std::vector<Map_Tile_Source_Config> read_tile_source_array(const Psc::JSON* json, std::string_view key) {
|
|
|
|
|
auto field = json->get(key);
|
|
|
|
|
if (field == nullptr) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
if (field->valueType != Psc::Array) {
|
|
|
|
|
if (field == nullptr || field->valueType != Psc::Array) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
|
|
|
|
|
}
|
|
|
|
|
std::vector<Map_Tile_Source_Config> ret;
|
|
|
|
|
ret.reserve(field->children.size());
|
|
|
|
|
for (const auto& child : field->children) {
|
|
|
|
|
Map_Tile_Source_Config item;
|
|
|
|
|
item.from_base_json(&child, not_exist_use_default_value);
|
|
|
|
|
item.from_base_json(&child);
|
|
|
|
|
ret.push_back(std::move(item));
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
@@ -456,15 +732,12 @@ static Psc::JSON write_tile_source_array(std::string_view key, const std::vector
|
|
|
|
|
}
|
|
|
|
|
return Psc::JSON(key, array);
|
|
|
|
|
}
|
|
|
|
|
void Map_Resources_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
void Map_Resources_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_resources");
|
|
|
|
|
}
|
|
|
|
|
current_imagery_key = read_optional_string_field(that_json, "current_imagery_key");
|
|
|
|
|
if (current_imagery_key.empty()) {
|
|
|
|
|
current_imagery_key = "imagery";
|
|
|
|
|
}
|
|
|
|
|
tile_sources = read_optional_tile_source_array(that_json, "tile_sources", not_exist_use_default_value);
|
|
|
|
|
current_imagery_key = read_string_field(that_json, "current_imagery_key");
|
|
|
|
|
tile_sources = read_tile_source_array(that_json, "tile_sources");
|
|
|
|
|
if (!is_imagery_key(current_imagery_key)) {
|
|
|
|
|
auto source = std::ranges::find_if(
|
|
|
|
|
tile_sources, [](const Map_Tile_Source_Config& item) { return item.tile_type == Map_Tile_Type::imagery; });
|
|
|
|
@@ -518,22 +791,14 @@ bool Map_Resources_Config::is_terrain_key(std::string_view key) const {
|
|
|
|
|
return source.tile_type == Map_Tile_Type::terrain && source.key == key;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
bool Map_View_Config::is_scene_mode(std::string_view mode) {
|
|
|
|
|
return mode == "2d" || mode == "2.5d" || mode == "3d";
|
|
|
|
|
}
|
|
|
|
|
void Map_Tile_View_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
if (that_json == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (that_json->valueType != Psc::Object) {
|
|
|
|
|
void Map_Tile_View_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_tile_view");
|
|
|
|
|
}
|
|
|
|
|
current_imagery_key = read_optional_string_field(that_json, "current_imagery_key", current_imagery_key);
|
|
|
|
|
current_terrain_key = read_optional_string_field(that_json, "current_terrain_key", current_terrain_key);
|
|
|
|
|
tile_zoom_mode = Psc::to_enum<Map_Tile_Zoom_Mode>(
|
|
|
|
|
read_optional_string_field(that_json, "tile_zoom_mode", Psc::to_string(tile_zoom_mode)));
|
|
|
|
|
tile_display_maximum_level = std::clamp(
|
|
|
|
|
read_optional_uint32_field(that_json, "tile_display_maximum_level", tile_display_maximum_level), 0u, 24u);
|
|
|
|
|
current_imagery_key = read_string_field(that_json, "current_imagery_key");
|
|
|
|
|
current_terrain_key = read_string_field(that_json, "current_terrain_key");
|
|
|
|
|
tile_zoom_mode = Psc::to_enum<Map_Tile_Zoom_Mode>(read_string_field(that_json, "tile_zoom_mode"));
|
|
|
|
|
tile_display_maximum_level = std::clamp(read_uint32_field(that_json, "tile_display_maximum_level"), 0u, 24u);
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Map_Tile_View_Config::to_base_json() const {
|
|
|
|
|
auto ret = Psc::JSON::object();
|
|
|
|
@@ -543,23 +808,17 @@ Psc::JSON Map_Tile_View_Config::to_base_json() const {
|
|
|
|
|
ret.append({"tile_display_maximum_level", tile_display_maximum_level});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
void Map_View_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
if (that_json == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (that_json->valueType != Psc::Object) {
|
|
|
|
|
void Map_View_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_view");
|
|
|
|
|
}
|
|
|
|
|
auto next_scene_mode = read_optional_string_field(that_json, "scene_mode", scene_mode);
|
|
|
|
|
if (!is_scene_mode(next_scene_mode)) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "scene_mode");
|
|
|
|
|
}
|
|
|
|
|
scene_mode = next_scene_mode;
|
|
|
|
|
map2d.from_base_json(that_json->get("map2d"), not_exist_use_default_value);
|
|
|
|
|
map3d.from_base_json(that_json->get("map3d"), not_exist_use_default_value);
|
|
|
|
|
camera.from_base_json(that_json->get("camera"), not_exist_use_default_value);
|
|
|
|
|
base_station_fly_to_height_offset_meters =
|
|
|
|
|
std::max(100.0, read_optional_double_field(that_json, "base_station_fly_to_height_offset_meters", base_station_fly_to_height_offset_meters));
|
|
|
|
|
std::error_code error;
|
|
|
|
|
const auto result = Psc::assign_field_ec(scene_mode, that_json, "scene_mode", error);
|
|
|
|
|
Psc::check_json_assign_field(result, error, that_json, "scene_mode");
|
|
|
|
|
map2d.from_base_json(that_json->get("map2d"));
|
|
|
|
|
map3d.from_base_json(that_json->get("map3d"));
|
|
|
|
|
camera.from_base_json(that_json->get("camera"));
|
|
|
|
|
base_station_fly_to_height_offset_meters = std::max(100.0, read_double_field(that_json, "base_station_fly_to_height_offset_meters"));
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Map_View_Config::to_base_json() const {
|
|
|
|
|
auto ret = Psc::JSON::object();
|
|
|
|
@@ -570,13 +829,11 @@ Psc::JSON Map_View_Config::to_base_json() const {
|
|
|
|
|
ret.append({"base_station_fly_to_height_offset_meters", base_station_fly_to_height_offset_meters});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
void Cesium_Graphics_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
if (that_json == nullptr)
|
|
|
|
|
return;
|
|
|
|
|
if (that_json->valueType != Psc::Object)
|
|
|
|
|
void Cesium_Graphics_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object)
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "cesium_graphics");
|
|
|
|
|
settings.write([&](auto& value) {
|
|
|
|
|
value.from_base_json(that_json, not_exist_use_default_value);
|
|
|
|
|
value.from_base_json(that_json);
|
|
|
|
|
value.target_frame_rate = std::clamp(value.target_frame_rate, 1u, 120u);
|
|
|
|
|
value.resolution_scale = std::clamp(value.resolution_scale, 0.2, 1.5);
|
|
|
|
|
value.msaa_samples = std::clamp(value.msaa_samples, 1u, 8u);
|
|
|
|
@@ -602,15 +859,15 @@ Map_Model_Item_Config::Map_Model_Item_Config(std::string url, double built_in_si
|
|
|
|
|
url(std::move(url)), built_in_size(built_in_size), heading_offset_degrees(heading), pitch_offset_degrees(pitch),
|
|
|
|
|
roll_offset_degrees(roll) {
|
|
|
|
|
}
|
|
|
|
|
void Map_Model_Item_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
void Map_Model_Item_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_model_item");
|
|
|
|
|
}
|
|
|
|
|
url = read_optional_string_field(that_json, "url", url);
|
|
|
|
|
built_in_size = read_optional_double_field(that_json, "built_in_size", built_in_size);
|
|
|
|
|
heading_offset_degrees = read_optional_double_field(that_json, "heading_offset_degrees", heading_offset_degrees);
|
|
|
|
|
pitch_offset_degrees = read_optional_double_field(that_json, "pitch_offset_degrees", pitch_offset_degrees);
|
|
|
|
|
roll_offset_degrees = read_optional_double_field(that_json, "roll_offset_degrees", roll_offset_degrees);
|
|
|
|
|
url = read_string_field(that_json, "url");
|
|
|
|
|
built_in_size = read_double_field(that_json, "built_in_size");
|
|
|
|
|
heading_offset_degrees = read_double_field(that_json, "heading_offset_degrees");
|
|
|
|
|
pitch_offset_degrees = read_double_field(that_json, "pitch_offset_degrees");
|
|
|
|
|
roll_offset_degrees = read_double_field(that_json, "roll_offset_degrees");
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Map_Model_Item_Config::to_base_json() const {
|
|
|
|
|
auto ret = Psc::JSON::object();
|
|
|
|
@@ -623,18 +880,14 @@ Psc::JSON Map_Model_Item_Config::to_base_json() const {
|
|
|
|
|
}
|
|
|
|
|
Map_Model_Config::Map_Model_Config() : aircraft_models(make_default_aircraft_models()) {
|
|
|
|
|
}
|
|
|
|
|
void Map_Model_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
|
|
|
|
if (that_json == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (that_json->valueType != Psc::Object) {
|
|
|
|
|
void Map_Model_Config::from_base_json(const Psc::JSON* that_json) {
|
|
|
|
|
if (that_json == nullptr || that_json->valueType != Psc::Object) {
|
|
|
|
|
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_models");
|
|
|
|
|
}
|
|
|
|
|
aircraft_model.from_base_json(that_json->get("aircraft_model"), not_exist_use_default_value);
|
|
|
|
|
aircraft_models = read_optional_model_object_field(that_json, "aircraft_models", make_default_aircraft_models(),
|
|
|
|
|
not_exist_use_default_value);
|
|
|
|
|
base_station_model.from_base_json(that_json->get("base_station_model"), not_exist_use_default_value);
|
|
|
|
|
device_model.from_base_json(that_json->get("device_model"), not_exist_use_default_value);
|
|
|
|
|
aircraft_model.from_base_json(that_json->get("aircraft_model"));
|
|
|
|
|
aircraft_models = read_model_object_field(that_json, "aircraft_models");
|
|
|
|
|
base_station_model.from_base_json(that_json->get("base_station_model"));
|
|
|
|
|
device_model.from_base_json(that_json->get("device_model"));
|
|
|
|
|
}
|
|
|
|
|
Psc::JSON Map_Model_Config::to_base_json() const {
|
|
|
|
|
auto ret = Psc::JSON::object();
|
|
|
|
|