25#include <nlohmann/json.hpp>
96 catch (
const std::bad_alloc& e)
101 catch (
const std::exception& e)
110 if (context ==
nullptr)
166 std::mutex log_callback_mutex;
168 void* log_callback_user_data =
nullptr;
170 void forward_log_callback(
const logging::Level level,
const std::string& line,
void* )
173 void* user_data =
nullptr;
176 std::scoped_lock lock(log_callback_mutex);
177 callback = log_callback;
178 user_data = log_callback_user_data;
181 if (callback !=
nullptr)
194 if ((log_file_path !=
nullptr) && ((*log_file_path) != 0))
205 catch (
const std::exception& e)
217 std::scoped_lock lock(log_callback_mutex);
218 log_callback = callback;
219 log_callback_user_data = user_data;
227 if (message ==
nullptr)
245 catch (
const std::exception& e)
255 if ((context ==
nullptr) || (out_dir ==
nullptr))
261 auto* ctx =
reinterpret_cast<FersContext*
>(context);
267 catch (
const std::exception& e)
278 if ((context ==
nullptr) || (xml_filepath ==
nullptr))
286 auto* ctx =
reinterpret_cast<FersContext*
>(context);
290 std::filesystem::path p(xml_filepath);
291 auto parent = p.parent_path();
294 ctx->setOutputDir(parent.string());
309 const auto seed = std::random_device{}();
312 ctx->getMasterSeeder().seed(seed);
317 catch (
const std::exception& e)
329 if ((context ==
nullptr) || (xml_content ==
nullptr))
337 auto* ctx =
reinterpret_cast<FersContext*
>(context);
341 ctx->getMasterSeeder());
353 const auto seed = std::random_device{}();
356 ctx->getMasterSeeder().seed(seed);
362 catch (
const std::exception& e)
373 if (context ==
nullptr)
380 const auto* ctx =
reinterpret_cast<FersContext*
>(context);
384 const std::string json_str = j.dump(2);
388 return strdup(json_str.c_str());
390 catch (
const std::exception& e)
400 if (context ==
nullptr)
407 const auto* ctx =
reinterpret_cast<FersContext*
>(context);
413 throw std::runtime_error(
"XML serialization resulted in an empty string.");
418 return strdup(xml_str.c_str());
420 catch (
const std::exception& e)
430 if (context ==
nullptr)
432 last_error_message =
"Invalid context provided to fers_get_last_output_metadata_json.";
437 const auto* ctx =
reinterpret_cast<FersContext*
>(context);
441 return strdup(json_str.c_str());
443 catch (
const std::exception& e)
454 if ((context ==
nullptr) || (json ==
nullptr))
459 auto* ctx =
reinterpret_cast<FersContext*
>(context);
469 auto j = nlohmann::json::parse(json);
471 if (j.contains(
"name"))
473 p->setName(j.at(
"name").get<std::string>());
478 catch (
const std::exception& e)
490 if ((context ==
nullptr) || (json ==
nullptr))
495 auto* ctx =
reinterpret_cast<FersContext*
>(context);
498 auto j = nlohmann::json::parse(json);
503 catch (
const std::exception& e)
514 if ((context ==
nullptr) || (json ==
nullptr))
516 auto* ctx =
reinterpret_cast<FersContext*
>(context);
519 auto j = nlohmann::json::parse(json);
520 auto id = j.at(
"id").is_string() ? std::stoull(j.at(
"id").get<std::string>()) : j.at(
"id").get<uint64_t>();
521 auto* ant = ctx->getWorld()->findAntenna(
id);
530 catch (
const std::exception& e)
540 if ((context ==
nullptr) || (json ==
nullptr))
542 auto* ctx =
reinterpret_cast<FersContext*
>(context);
545 auto j = nlohmann::json::parse(json);
549 ctx->getWorld()->replace(std::move(wf));
553 catch (
const std::exception& e)
563 if ((context ==
nullptr) || (json ==
nullptr))
565 auto* ctx =
reinterpret_cast<FersContext*
>(context);
574 auto j = nlohmann::json::parse(json);
578 catch (
const std::exception& e)
588 if ((context ==
nullptr) || (json ==
nullptr))
590 auto* ctx =
reinterpret_cast<FersContext*
>(context);
599 auto j = nlohmann::json::parse(json);
603 catch (
const std::exception& e)
613 if ((context ==
nullptr) || (json ==
nullptr))
615 auto* ctx =
reinterpret_cast<FersContext*
>(context);
624 auto j = nlohmann::json::parse(json);
628 catch (
const std::exception& e)
638 if ((context ==
nullptr) || (json ==
nullptr))
640 auto* ctx =
reinterpret_cast<FersContext*
>(context);
643 auto j = nlohmann::json::parse(json);
645 j.at(
"tx_id").is_string() ? std::stoull(j.at(
"tx_id").get<std::string>()) : j.at(
"tx_id").get<uint64_t>();
647 j.at(
"rx_id").is_string() ? std::stoull(j.at(
"rx_id").get<std::string>()) : j.at(
"rx_id").get<uint64_t>();
648 auto* tx = ctx->getWorld()->findTransmitter(tx_id);
649 auto* rx = ctx->getWorld()->findReceiver(rx_id);
650 if ((tx ==
nullptr) || (rx ==
nullptr))
658 catch (
const std::exception& e)
668 if ((context ==
nullptr) || (json ==
nullptr))
670 auto* ctx =
reinterpret_cast<FersContext*
>(context);
673 if (ctx->getWorld()->findTiming(
id) ==
nullptr)
678 auto j = nlohmann::json::parse(json);
682 catch (
const std::exception& e)
693 if ((context ==
nullptr) || (scenario_json ==
nullptr))
701 auto* ctx =
reinterpret_cast<FersContext*
>(context);
704 const nlohmann::json j = nlohmann::json::parse(scenario_json);
710 catch (
const nlohmann::json::exception& e)
720 catch (
const std::exception& e)
749 return strdup(warning_json.c_str());
763 if (context ==
nullptr)
770 auto* ctx =
reinterpret_cast<FersContext*
>(context);
774 std::function<void(
const std::string&,
int,
int)> progress_fn;
775 if (callback !=
nullptr)
777 progress_fn = [callback, user_data](
const std::string& msg,
const int current,
const int total)
778 { callback(msg.c_str(), current, total, user_data); };
785 ctx->clearLastOutputMetadata();
787 ctx->setLastOutputMetadata(output_metadata);
791 catch (
const std::exception& e)
801 if ((context ==
nullptr) || (output_kml_filepath ==
nullptr))
808 const auto* ctx =
reinterpret_cast<const FersContext*
>(context);
821 catch (
const std::exception& e)
859 const size_t waypoint_count,
861 const size_t num_points)
864 if ((waypoints ==
nullptr) || waypoint_count == 0 || num_points == 0)
866 last_error_message =
"Invalid arguments: waypoints cannot be null and counts must be > 0.";
882 for (
size_t i = 0; i < waypoint_count; ++i)
885 c.t = waypoints[i].
time;
886 c.pos.x = waypoints[i].
x;
887 c.pos.y = waypoints[i].
y;
888 c.pos.z = waypoints[i].
z;
896 result_path->count = num_points;
898 const double start_time = waypoints[0].
time;
899 const double end_time = waypoints[waypoint_count - 1].
time;
900 const double duration = end_time - start_time;
903 if (waypoint_count < 2 || duration <= 0)
906 for (
size_t i = 0; i < num_points; ++i)
908 result_path->points[i] = {pos.
x, pos.
y, pos.
z, 0.0, 0.0, 0.0};
913 const double time_step =
914 duration /
static_cast<double>(num_points > 1 ? num_points - 1 :
static_cast<size_t>(1));
916 for (
size_t i = 0; i < num_points; ++i)
918 const double t = start_time +
static_cast<double>(i) * time_step;
921 result_path->points[i] = {pos.
x, pos.y, pos.z, vel.
x, vel.
y, vel.
z};
926 catch (
const std::exception& e)
943 const size_t waypoint_count,
946 const size_t num_points)
951 if ((waypoints ==
nullptr) || waypoint_count == 0 || num_points == 0)
953 last_error_message =
"Invalid arguments: waypoints cannot be null and counts must be > 0.";
971 for (
size_t i = 0; i < waypoint_count; ++i)
975 std::format(
"rotation waypoint {}", i),
"azimuth");
978 std::format(
"rotation waypoint {}", i),
"elevation");
980 waypoints[i].azimuth, waypoints[i].elevation, waypoints[i].time, unit));
987 result_path->count = num_points;
989 const double start_time = waypoints[0].
time;
990 const double end_time = waypoints[waypoint_count - 1].
time;
991 const double duration = end_time - start_time;
994 if (waypoint_count < 2 || duration <= 0)
997 for (
size_t i = 0; i < num_points; ++i)
1006 const double time_step =
1007 duration /
static_cast<double>(num_points > 1 ? num_points - 1 :
static_cast<size_t>(1));
1009 for (
size_t i = 0; i < num_points; ++i)
1011 const double t = start_time +
static_cast<double>(i) * time_step;
1021 catch (
const std::exception& e)
1031 if (path !=
nullptr)
1041 const size_t az_samples,
const size_t el_samples,
1042 const double frequency_hz)
1045 if ((context ==
nullptr) || az_samples < 2 || el_samples < 2)
1047 last_error_message =
"Invalid arguments: context must be non-null and sample counts must be >= 2.";
1054 const auto* ctx =
reinterpret_cast<const FersContext*
>(context);
1059 last_error_message =
"Antenna ID '" + std::to_string(antenna_id) +
"' not found in the world.";
1072 if (frequency_hz > 0.0)
1074 wavelength =
params::c() / frequency_hz;
1078 data->az_count = az_samples;
1079 data->el_count = el_samples;
1080 const size_t total_samples = az_samples * el_samples;
1081 data->gains =
new double[total_samples];
1086 double max_gain = 0.0;
1091 for (
size_t i = 0; i < el_samples; ++i)
1095 for (
size_t j = 0; j < az_samples; ++j)
1099 const math::SVec3 sample_angle(1.0, azimuth, elevation);
1100 const RealType gain = ant->
getGain(sample_angle, ref_angle, wavelength);
1101 data->gains[i * az_samples + j] = gain;
1102 max_gain = std::max(gain, max_gain);
1106 data->max_gain = max_gain;
1111 for (
size_t i = 0; i < total_samples; ++i)
1113 data->gains[i] /= max_gain;
1119 catch (
const std::exception& e)
1128 if (data !=
nullptr)
1130 delete[] data->
gains;
1140 if (context ==
nullptr)
1149 const auto* ctx =
reinterpret_cast<const FersContext*
>(context);
1155 result->count = cpp_links.size();
1157 if (!cpp_links.empty())
1160 for (
size_t i = 0; i < result->count; ++i)
1162 const auto& src = cpp_links[i];
1163 auto& dst = result->links[i];
1185 std::strncpy(dst.label, src.label.c_str(),
sizeof(dst.label) - 1);
1186 dst.label[
sizeof(dst.label) - 1] =
'\0';
1188 dst.source_id =
static_cast<uint64_t
>(src.source_id);
1189 dst.dest_id =
static_cast<uint64_t
>(src.dest_id);
1190 dst.origin_id =
static_cast<uint64_t
>(src.origin_id);
1195 result->links =
nullptr;
1199 catch (
const std::exception& e)
1208 if (list !=
nullptr)
1210 delete[] list->
links;
Header file defining various types of antennas and their gain patterns.
static void discard_warning_capture() noexcept
char * fers_get_scenario_as_xml(fers_context_t *context)
Serializes the current simulation scenario into a FERS XML string.
int fers_update_antenna_from_json(fers_context_t *context, const char *json)
Updates a single antenna from JSON without full context recreation.
void fers_free_antenna_pattern_data(fers_antenna_pattern_data_t *data)
Frees the memory allocated for an antenna pattern data structure.
int fers_load_scenario_from_xml_string(fers_context_t *context, const char *xml_content, const int validate)
Loads a scenario into the context from a FERS XML string.
void fers_log(fers_log_level_t level, const char *message)
Submits a log message to the library's unified logging system.
char * fers_get_last_warning_messages_json()
Returns the last deduplicated rotation-unit warning list for the calling thread as JSON.
int fers_update_waveform_from_json(fers_context_t *context, const char *json)
Updates a single waveform from JSON without full context recreation.
int fers_update_transmitter_from_json(fers_context_t *context, uint64_t id, const char *json)
Updates a single transmitter from JSON without full context recreation.
char * fers_get_last_error_message()
Retrieves the last error message that occurred on the current thread.
void fers_free_interpolated_motion_path(fers_interpolated_path_t *path)
Frees the memory allocated for an interpolated motion path.
int fers_update_parameters_from_json(fers_context_t *context, const char *json)
Updates the global simulation parameters from JSON without full context recreation.
int fers_generate_kml(const fers_context_t *context, const char *output_kml_filepath)
Generates a KML file for visualizing the scenario in the context.
int fers_set_output_directory(fers_context_t *context, const char *out_dir)
Sets the output directory for simulation results.
void fers_context_destroy(fers_context_t *context)
Destroys a FERS simulation context and releases all associated memory.
static void handle_api_exception(const std::exception &e, const std::string &function_name)
Centralized exception handler for the C-API boundary.
fers_context_t * fers_context_create()
Creates a new FERS simulation context.
int fers_update_target_from_json(fers_context_t *context, uint64_t id, const char *json)
Updates a single target from JSON without full context recreation.
void fers_free_preview_links(fers_visual_link_list_t *list)
Frees the memory allocated for a preview link list.
int fers_update_receiver_from_json(fers_context_t *context, uint64_t id, const char *json)
Updates a single receiver from JSON without full context recreation.
fers_interpolated_path_t * fers_get_interpolated_motion_path(const fers_motion_waypoint_t *waypoints, const size_t waypoint_count, const fers_interp_type_t interp_type, const size_t num_points)
Calculates an interpolated motion path from a set of waypoints.
int fers_run_simulation(fers_context_t *context, fers_progress_callback_t callback, void *user_data)
Runs the simulation defined in the provided context.
void fers_free_string(char *str)
Frees a string that was allocated and returned by the libfers API.
fers_log_level_t fers_get_log_level()
Returns the current internal logger level.
static void begin_warning_capture() noexcept
math::RotationPath::InterpType to_cpp_rot_interp_type(const fers_interp_type_t type)
fers_antenna_pattern_data_t * fers_get_antenna_pattern(const fers_context_t *context, const uint64_t antenna_id, const size_t az_samples, const size_t el_samples, const double frequency_hz)
Samples the gain pattern of a specified antenna and provides the data.
thread_local std::vector< std::string > last_warning_messages
int fers_configure_logging(fers_log_level_t level, const char *log_file_path)
Configures the internal logger.
void fers_free_interpolated_rotation_path(fers_interpolated_rotation_path_t *path)
Frees the memory allocated for an interpolated rotation path.
math::Path::InterpType to_cpp_interp_type(const fers_interp_type_t type)
void fers_set_log_callback(fers_log_callback_t callback, void *user_data)
Registers a callback for formatted log lines.
int fers_load_scenario_from_xml_file(fers_context_t *context, const char *xml_filepath, const int validate)
Loads a scenario into the context from a FERS XML file.
fers_visual_link_list_t * fers_calculate_preview_links(const fers_context_t *context, const double time)
Calculates visual links for a specific simulation time.
char * fers_get_scenario_as_json(fers_context_t *context)
Serializes the current simulation scenario into a JSON string.
static void complete_warning_capture()
int fers_update_monostatic_from_json(fers_context_t *context, const char *json)
Updates a monostatic radar from JSON without full context recreation.
int fers_update_platform_from_json(fers_context_t *context, uint64_t id, const char *json)
Updates a single platform's paths and name from JSON without full context recreation.
int fers_update_timing_from_json(fers_context_t *context, uint64_t id, const char *json)
Updates a single timing source from JSON without full context recreation.
static logging::Level map_api_log_level(fers_log_level_t level)
fers_interpolated_rotation_path_t * fers_get_interpolated_rotation_path(const fers_rotation_waypoint_t *waypoints, const size_t waypoint_count, const fers_interp_type_t interp_type, const fers_angle_unit_t angle_unit, const size_t num_points)
Calculates an interpolated rotation path from a set of waypoints.
static fers_log_level_t map_internal_log_level(logging::Level level)
int fers_update_scenario_from_json(fers_context_t *context, const char *scenario_json)
Updates the simulation scenario from a JSON string.
char * fers_get_last_output_metadata_json(fers_context_t *context)
Returns JSON metadata for the most recent simulation output files.
int fers_set_thread_count(unsigned num_threads)
Sets the number of worker threads for the simulation.
thread_local std::string last_error_message
fers_angle_unit_t
Units used for external rotation angles and rates.
void(* fers_progress_callback_t)(const char *message, int current, int total, void *user_data)
A function pointer type for progress reporting callbacks.
void(* fers_log_callback_t)(fers_log_level_t level, const char *line, void *user_data)
A function pointer type for receiving formatted log lines.
fers_log_level_t
Log levels for the FERS library.
fers_interp_type_t
Defines the interpolation methods available for path generation.
struct fers_context fers_context_t
@ FERS_LINK_BISTATIC_TX_TGT
@ FERS_LINK_BISTATIC_TGT_RX
Header for radar channel propagation and interaction models.
Manages the lifetime and state of a single FERS simulation scenario.
void setOutputDir(std::string dir)
Sets the output directory for simulation results.
core::World * getWorld() const noexcept
Retrieves a pointer to the simulation world.
std::string getLastOutputMetadataJson() const
Abstract base class representing an antenna.
virtual RealType getGain(const math::SVec3 &angle, const math::SVec3 &refangle, RealType wavelength) const =0
Computes the gain of the antenna based on the input angle and reference angle.
radar::Target * findTarget(const SimId id)
Finds a target by ID.
radar::Receiver * findReceiver(const SimId id)
Finds a receiver by ID.
radar::Transmitter * findTransmitter(const SimId id)
Finds a transmitter by ID.
radar::Platform * findPlatform(const SimId id)
Finds a platform by ID.
void log(Level level, const std::string &message, const std::source_location &location=std::source_location::current()) noexcept
Logs a message with a specific log level and source location.
std::expected< void, std::string > logToFile(const std::string &filePath) noexcept
Sets the log file path to log messages to a file.
void setCallback(Callback callback, void *user_data) noexcept
Sets an optional callback that receives each formatted log line.
void setLevel(Level level) noexcept
Sets the logging level.
Represents a path with coordinates and allows for various interpolation methods.
Vec3 getPosition(RealType t) const
Retrieves the position at a given time along the path.
void setInterp(InterpType settype) noexcept
Changes the interpolation type.
InterpType
Types of interpolation supported by the Path class.
Vec3 getVelocity(RealType t) const
Retrieves the velocity at a given time along the path.
void addCoord(const Coord &coord) noexcept
Adds a coordinate to the path.
void finalize()
Finalizes the path, preparing it for interpolation.
Manages rotational paths with different interpolation techniques.
void finalize()
Finalizes the rotation path for interpolation.
void setInterp(InterpType setinterp) noexcept
Sets the interpolation type for the path.
SVec3 getPosition(RealType t) const
Gets the rotational position at a given time.
InterpType
Enumeration for types of interpolation.
void addCoord(const RotationCoord &coord) noexcept
Adds a rotation coordinate to the path.
A class representing a vector in spherical coordinates.
RealType elevation
The elevation angle of the vector.
RealType azimuth
The azimuth angle of the vector.
A class representing a vector in rectangular coordinates.
RealType x
The x component of the vector.
RealType z
The z component of the vector.
RealType y
The y component of the vector.
A simple thread pool implementation.
static bool generateKml(const core::World &world, const std::string &outputKmlPath)
Generates a KML file from a pre-built simulation world.
double RealType
Type for real numbers.
constexpr RealType PI
Mathematical constant π (pi).
Internal C++ class that encapsulates the state of a simulation instance.
Provides functions to serialize and deserialize the simulation world to/from JSON.
KML file generator for geographical visualization of FERS scenarios.
Header file for the logging system.
OutputMetadata runEventDrivenSim(World *world, pool::ThreadPool &pool, const std::function< void(const std::string &, int, int)> &progress_callback, const std::string &output_dir)
Runs the unified, event-driven radar simulation.
@ WARNING
Warning level for potentially harmful situations.
@ FATAL
Fatal level for severe error events.
@ TRACE
Trace level for detailed debugging information.
@ INFO
Info level for informational messages.
@ OFF
Special level to disable all logging.
@ ERROR
Error level for error events.
@ DEBUG
Debug level for general debugging information.
Logger logger
Externally available logger object.
unsigned renderThreads() noexcept
Get the number of worker threads.
std::expected< void, std::string > setThreads(const unsigned threads) noexcept
Set the number of worker threads.
@ Radians
Compass azimuth and elevation expressed in radians.
@ Degrees
Compass azimuth and elevation expressed in degrees.
RealType c() noexcept
Get the speed of light.
RealType internal_elevation_to_external(const RealType elevation, const params::RotationAngleUnit unit) noexcept
math::RotationCoord external_rotation_to_internal(const RealType azimuth, const RealType elevation, const RealType time, const params::RotationAngleUnit unit) noexcept
RealType internal_azimuth_to_external(const RealType azimuth, const params::RotationAngleUnit unit) noexcept
std::vector< std::string > take_captured_warnings()
void maybe_warn_about_rotation_value(const RealType value, const params::RotationAngleUnit declared_unit, const ValueKind kind, const std::string_view source, const std::string_view owner, const std::string_view field)
void clear_captured_warnings() noexcept
void update_platform_paths_from_json(const nlohmann::json &j, radar::Platform *plat)
Updates a platform's motion and rotation paths from JSON.
void update_parameters_from_json(const nlohmann::json &j, std::mt19937 &masterSeeder)
Updates global simulation parameters from JSON.
void json_to_world(const nlohmann::json &j, core::World &world, std::mt19937 &masterSeeder)
Deserializes a nlohmann::json object and reconstructs the simulation world.
void update_receiver_from_json(const nlohmann::json &j, radar::Receiver *rx, core::World &world, std::mt19937 &)
Updates a receiver from JSON without full context recreation.
void update_timing_from_json(const nlohmann::json &j, core::World &world, const SimId id)
Updates a timing source from JSON without full context recreation.
void update_monostatic_from_json(const nlohmann::json &j, radar::Transmitter *tx, radar::Receiver *rx, core::World &world, std::mt19937 &masterSeeder)
Updates a monostatic radar from JSON without full context recreation.
void update_transmitter_from_json(const nlohmann::json &j, radar::Transmitter *tx, core::World &world, std::mt19937 &)
Updates a transmitter from JSON without full context recreation.
void parseSimulation(const std::string &filename, core::World *world, const bool validate, std::mt19937 &masterSeeder)
Parses a simulation configuration from an XML file.
void update_antenna_from_json(const nlohmann::json &j, antenna::Antenna *ant, core::World &world)
Updates an antenna from JSON without full context recreation.
void update_target_from_json(const nlohmann::json &j, radar::Target *existing_tgt, core::World &world, std::mt19937 &)
Updates a target from JSON without full context recreation.
nlohmann::json world_to_json(const core::World &world)
Serializes the entire simulation world into a nlohmann::json object.
void parseSimulationFromString(const std::string &xmlContent, core::World *world, const bool validate, std::mt19937 &masterSeeder)
Parses a simulation configuration directly from an XML string in memory.
std::string world_to_xml_string(const core::World &world)
Serializes the entire simulation world into an XML formatted string.
std::unique_ptr< fers_signal::RadarSignal > parse_waveform_from_json(const nlohmann::json &j)
Parses a Waveform from JSON.
std::vector< PreviewLink > calculatePreviewLinks(const core::World &world, const RealType time)
Calculates all visual links for the current world state at a specific time.
@ DirectTxRx
Interference path.
@ Monostatic
Combined Tx/Rx path.
@ BistaticTgtRx
Scattered path.
@ BistaticTxTgt
Illuminator path.
Defines the Parameters struct and provides methods for managing simulation parameters.
Provides the definition and functionality of the Path class for handling coordinate-based paths with ...
Classes for handling radar waveforms and signals.
Defines the RotationPath class for handling rotational paths with different interpolation types.
uint64_t SimId
64-bit Unique Simulation ID.
Header file for the main simulation runner.
Represents a sampled 2D antenna gain pattern.
A container for an array of interpolated motion path points.
fers_interpolated_point_t * points
Represents a single interpolated point on a motion path.
A container for an array of interpolated rotation path points.
fers_interpolated_rotation_point_t * points
Represents a single interpolated point on a rotation path.
Represents a single waypoint for a motion path.
double x
X coordinate in meters (East in ENU).
double time
Time in seconds.
double y
Y coordinate in meters (North in ENU).
double z
Z coordinate in meters (Up/Altitude in ENU).
Represents a single waypoint for a rotation path.
double time
Time in seconds.
A container for a list of visual links.
fers_visual_link_t * links
Represents a single renderable line segment metadata.
fers_link_type_t type
Type of the link (Monostatic, Bistatic, etc.).
Represents a position in 3D space with an associated time.
std::optional< unsigned > random_seed
Random seed for simulation.
A simple thread pool implementation.
High-level facade for parsing XML configuration files into the FERS simulation environment.
Provides functions to serialize the simulation world back into the FERS XML format.