20#include <nlohmann/json.hpp>
67 catch (
const std::bad_alloc& e)
72 catch (
const std::exception& e)
118 if (log_file_path && *log_file_path)
129 catch (
const std::exception& e)
155 catch (
const std::exception& e)
165 if (!context || !xml_filepath)
172 auto* ctx =
reinterpret_cast<FersContext*
>(context);
188 const auto seed = std::random_device{}();
191 ctx->getMasterSeeder().seed(seed);
195 catch (
const std::exception& e)
205 if (!context || !xml_content)
212 auto* ctx =
reinterpret_cast<FersContext*
>(context);
216 ctx->getMasterSeeder());
228 const auto seed = std::random_device{}();
231 ctx->getMasterSeeder().seed(seed);
236 catch (
const std::exception& e)
253 const auto* ctx =
reinterpret_cast<FersContext*
>(context);
257 const std::string json_str = j.dump(2);
261 return strdup(json_str.c_str());
263 catch (
const std::exception& e)
280 const auto* ctx =
reinterpret_cast<FersContext*
>(context);
286 throw std::runtime_error(
"XML serialization resulted in an empty string.");
291 return strdup(xml_str.c_str());
293 catch (
const std::exception& e)
303 if (!context || !scenario_json)
310 auto* ctx =
reinterpret_cast<FersContext*
>(context);
313 const nlohmann::json j = nlohmann::json::parse(scenario_json);
318 catch (
const nlohmann::json::exception& e)
327 catch (
const std::exception& e)
364 auto* ctx =
reinterpret_cast<FersContext*
>(context);
368 std::function<void(
const std::string&,
int,
int)> progress_fn;
371 progress_fn = [callback, user_data](
const std::string& msg,
const int current,
const int total)
372 { callback(msg.c_str(), current, total, user_data); };
383 catch (
const std::exception& e)
393 if (!context || !output_kml_filepath)
400 auto* ctx =
reinterpret_cast<const FersContext*
>(context);
413 catch (
const std::exception& e)
451 const size_t waypoint_count,
453 const size_t num_points)
456 if (!waypoints || waypoint_count == 0 || num_points == 0)
458 last_error_message =
"Invalid arguments: waypoints cannot be null and counts must be > 0.";
474 for (
size_t i = 0; i < waypoint_count; ++i)
477 c.t = waypoints[i].
time;
478 c.pos.x = waypoints[i].
x;
479 c.pos.y = waypoints[i].
y;
480 c.pos.z = waypoints[i].
z;
488 result_path->count = num_points;
490 const double start_time = waypoints[0].
time;
491 const double end_time = waypoints[waypoint_count - 1].
time;
492 const double duration = end_time - start_time;
495 if (waypoint_count < 2 || duration <= 0)
498 for (
size_t i = 0; i < num_points; ++i)
500 result_path->points[i] = {pos.
x, pos.
y, pos.
z};
505 const double time_step = duration / (num_points > 1 ? num_points - 1 : 1);
507 for (
size_t i = 0; i < num_points; ++i)
509 const double t = start_time + i * time_step;
512 result_path->points[i] = {pos.
x, pos.
y, pos.
z, vel.
x, vel.
y, vel.
z};
517 catch (
const std::exception& e)
534 const size_t waypoint_count,
536 const size_t num_points)
539 if (!waypoints || waypoint_count == 0 || num_points == 0)
541 last_error_message =
"Invalid arguments: waypoints cannot be null and counts must be > 0.";
557 for (
size_t i = 0; i < waypoint_count; ++i)
563 const RealType az_rad = (90.0 - az_deg) * (
PI / 180.0);
564 const RealType el_rad = el_deg * (
PI / 180.0);
573 result_path->count = num_points;
575 const double start_time = waypoints[0].
time;
576 const double end_time = waypoints[waypoint_count - 1].
time;
577 const double duration = end_time - start_time;
580 if (waypoint_count < 2 || duration <= 0)
586 for (
size_t i = 0; i < num_points; ++i)
588 result_path->points[i] = {az_deg, el_deg};
593 const double time_step = duration / (num_points > 1 ? num_points - 1 : 1);
595 for (
size_t i = 0; i < num_points; ++i)
597 const double t = start_time + i * time_step;
605 result_path->points[i] = {az_deg, el_deg};
610 catch (
const std::exception& e)
629 const size_t az_samples,
const size_t el_samples,
630 const double frequency_hz)
633 if (!context || !antenna_name || az_samples == 0 || el_samples == 0)
635 last_error_message =
"Invalid arguments: context, antenna_name, or sample counts are invalid.";
642 const auto* ctx =
reinterpret_cast<const FersContext*
>(context);
647 last_error_message =
"Antenna '" + std::string(antenna_name) +
"' not found in the world.";
660 if (frequency_hz > 0.0)
666 data->az_count = az_samples;
667 data->el_count = el_samples;
668 const size_t total_samples = az_samples * el_samples;
669 data->gains =
new double[total_samples];
674 double max_gain = 0.0;
676 for (
size_t i = 0; i < el_samples; ++i)
680 for (
size_t j = 0; j < az_samples; ++j)
684 const math::SVec3 sample_angle(1.0, azimuth, elevation);
685 const RealType gain = ant->
getGain(sample_angle, ref_angle, wavelength);
686 data->gains[i * az_samples + j] = gain;
694 data->max_gain = max_gain;
699 for (
size_t i = 0; i < total_samples; ++i)
701 data->gains[i] /= max_gain;
707 catch (
const std::exception& e)
718 delete[] data->
gains;
737 const auto* ctx =
reinterpret_cast<const FersContext*
>(context);
743 result->count = cpp_links.size();
745 if (!cpp_links.empty())
748 for (
size_t i = 0; i < result->count; ++i)
750 const auto& src = cpp_links[i];
751 auto& dst = result->links[i];
773 std::strncpy(dst.label, src.label.c_str(),
sizeof(dst.label) - 1);
774 dst.label[
sizeof(dst.label) - 1] =
'\0';
776 std::strncpy(dst.source_name, src.source_name.c_str(),
sizeof(dst.source_name) - 1);
777 dst.source_name[
sizeof(dst.source_name) - 1] =
'\0';
779 std::strncpy(dst.dest_name, src.dest_name.c_str(),
sizeof(dst.dest_name) - 1);
780 dst.dest_name[
sizeof(dst.dest_name) - 1] =
'\0';
782 std::strncpy(dst.origin_name, src.origin_name.c_str(),
sizeof(dst.origin_name) - 1);
783 dst.origin_name[
sizeof(dst.origin_name) - 1] =
'\0';
788 result->links =
nullptr;
792 catch (
const std::exception& e)
803 delete[] list->
links;
char * fers_get_scenario_as_xml(fers_context_t *context)
Serializes the current simulation scenario into a FERS XML string.
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.
static logging::Level map_level(fers_log_level_t level)
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_generate_kml(const fers_context_t *context, const char *output_kml_filepath)
Generates a KML file for visualizing the scenario in the context.
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.
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 size_t num_points)
Calculates an interpolated rotation path from a set of waypoints.
void fers_free_preview_links(fers_visual_link_list_t *list)
Frees the memory allocated for a preview link list.
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.
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 char *antenna_name, 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.
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)
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.
int fers_update_scenario_from_json(fers_context_t *context, const char *scenario_json)
Updates the simulation scenario from a JSON string.
int fers_set_thread_count(unsigned num_threads)
Sets the number of worker threads for the simulation.
thread_local std::string last_error_message
void(* fers_progress_callback_t)(const char *message, int current, int total, void *user_data)
A function pointer type for progress reporting callbacks.
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.
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.
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 setLevel(const 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.
void runEventDrivenSim(World *world, pool::ThreadPool &pool, const std::function< void(const std::string &, int, int)> &progress_callback)
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.
@ 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.
RealType c() noexcept
Get the speed of light.
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 parseSimulationFromString(const std::string &xmlContent, World *world, const bool validate, std::mt19937 &masterSeeder)
void parseSimulation(const std::string &filename, World *world, const bool validate, std::mt19937 &masterSeeder)
Parses a simulation configuration from an XML file.
nlohmann::json world_to_json(const core::World &world)
Serializes the entire simulation world into a nlohmann::json object.
std::string world_to_xml_string(const core::World &world)
Serializes the entire simulation world into an XML formatted string.
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 ...
Defines the RotationPath class for handling rotational paths with different interpolation types.
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.
double elevation_deg
Elevation angle in degrees (positive up).
double azimuth_deg
Azimuth angle in compass degrees (0=North, 90=East).
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.
Header file for parsing XML configuration files for simulation.
Provides functions to serialize the simulation world back into the FERS XML format.