FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
api.h File Reference
#include <stddef.h>
+ Include dependency graph for api.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  fers_antenna_pattern_data_t
 Represents a sampled 2D antenna gain pattern. More...
 
struct  fers_motion_waypoint_t
 Represents a single waypoint for a motion path. More...
 
struct  fers_rotation_waypoint_t
 Represents a single waypoint for a rotation path. More...
 
struct  fers_interpolated_point_t
 Represents a single interpolated point on a motion path. More...
 
struct  fers_interpolated_rotation_point_t
 Represents a single interpolated point on a rotation path. More...
 
struct  fers_interpolated_path_t
 A container for an array of interpolated motion path points. More...
 
struct  fers_interpolated_rotation_path_t
 A container for an array of interpolated rotation path points. More...
 
struct  fers_visual_link_t
 Represents a single renderable line segment metadata. More...
 
struct  fers_visual_link_list_t
 A container for a list of visual links. More...
 

Typedefs

typedef struct fers_context fers_context_t
 
typedef void(* fers_progress_callback_t) (const char *message, int current, int total, void *user_data)
 A function pointer type for progress reporting callbacks.
 

Enumerations

enum  fers_log_level_t {
  FERS_LOG_TRACE , FERS_LOG_DEBUG , FERS_LOG_INFO , FERS_LOG_WARNING ,
  FERS_LOG_ERROR , FERS_LOG_FATAL
}
 Log levels for the FERS library. More...
 
enum  fers_interp_type_t { FERS_INTERP_STATIC , FERS_INTERP_LINEAR , FERS_INTERP_CUBIC }
 Defines the interpolation methods available for path generation. More...
 
enum  fers_link_quality_t { FERS_LINK_STRONG , FERS_LINK_WEAK }
 Quality of the radio link based on SNR. More...
 
enum  fers_link_type_t { FERS_LINK_MONOSTATIC , FERS_LINK_BISTATIC_TX_TGT , FERS_LINK_BISTATIC_TGT_RX , FERS_LINK_DIRECT_TX_RX }
 Type of visual link to render. More...
 

Functions

fers_context_tfers_context_create ()
 Creates a new FERS simulation context.
 
void fers_context_destroy (fers_context_t *context)
 Destroys a FERS simulation context and releases all associated memory.
 
int fers_configure_logging (fers_log_level_t level, const char *log_file_path)
 Configures the internal logger.
 
void fers_log (fers_log_level_t level, const char *message)
 Submits a log message to the library's unified logging system.
 
int fers_set_thread_count (unsigned num_threads)
 Sets the number of worker threads for the simulation.
 
int fers_load_scenario_from_xml_file (fers_context_t *context, const char *xml_filepath, int validate)
 Loads a scenario into the context from a FERS XML file.
 
int fers_load_scenario_from_xml_string (fers_context_t *context, const char *xml_content, int validate)
 Loads a scenario into the context from a FERS XML string.
 
char * fers_get_scenario_as_json (fers_context_t *context)
 Serializes the current simulation scenario into a JSON string.
 
char * fers_get_scenario_as_xml (fers_context_t *context)
 Serializes the current simulation scenario into a FERS XML string.
 
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_error_message ()
 Retrieves the last error message that occurred on the current thread.
 
void fers_free_string (char *str)
 Frees a string that was allocated and returned by the libfers API.
 
int fers_run_simulation (fers_context_t *context, fers_progress_callback_t callback, void *user_data)
 Runs the simulation defined in the provided context.
 
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.
 
fers_antenna_pattern_data_tfers_get_antenna_pattern (const fers_context_t *context, const char *antenna_name, size_t az_samples, size_t el_samples, double frequency_hz)
 Samples the gain pattern of a specified antenna and provides the data.
 
void fers_free_antenna_pattern_data (fers_antenna_pattern_data_t *data)
 Frees the memory allocated for an antenna pattern data structure.
 
fers_interpolated_path_tfers_get_interpolated_motion_path (const fers_motion_waypoint_t *waypoints, size_t waypoint_count, fers_interp_type_t interp_type, size_t num_points)
 Calculates an interpolated motion path from a set of waypoints.
 
void fers_free_interpolated_motion_path (fers_interpolated_path_t *path)
 Frees the memory allocated for an interpolated motion path.
 
fers_interpolated_rotation_path_tfers_get_interpolated_rotation_path (const fers_rotation_waypoint_t *waypoints, size_t waypoint_count, fers_interp_type_t interp_type, size_t num_points)
 Calculates an interpolated rotation path from a set of waypoints.
 
void fers_free_interpolated_rotation_path (fers_interpolated_rotation_path_t *path)
 Frees the memory allocated for an interpolated rotation path.
 
fers_visual_link_list_tfers_calculate_preview_links (const fers_context_t *context, double time)
 Calculates visual links for a specific simulation time.
 
void fers_free_preview_links (fers_visual_link_list_t *list)
 Frees the memory allocated for a preview link list.
 

Typedef Documentation

◆ fers_context_t

typedef struct fers_context fers_context_t

Definition at line 25 of file api.h.

◆ fers_progress_callback_t

typedef void(* fers_progress_callback_t) (const char *message, int current, int total, void *user_data)

A function pointer type for progress reporting callbacks.

This callback can be implemented by the client to receive progress updates during long-running operations like fers_run_simulation.

Parameters
messageA descriptive message about the current operation.
currentThe current progress step.
totalThe total number of steps for the operation.
user_dataAn opaque pointer passed back to the caller, useful for maintaining state (e.g., a class instance or application handle).

Definition at line 39 of file api.h.

Enumeration Type Documentation

◆ fers_interp_type_t

Defines the interpolation methods available for path generation.

This enum provides a language-agnostic way to specify the desired interpolation algorithm when calling the path generation functions.

Enumerator
FERS_INTERP_STATIC 
FERS_INTERP_LINEAR 
FERS_INTERP_CUBIC 

Definition at line 312 of file api.h.

313{
fers_interp_type_t
Defines the interpolation methods available for path generation.
Definition api.h:313
@ FERS_INTERP_CUBIC
Definition api.h:316
@ FERS_INTERP_STATIC
Definition api.h:314
@ FERS_INTERP_LINEAR
Definition api.h:315

◆ fers_link_quality_t

Quality of the radio link based on SNR.

Enumerator
FERS_LINK_STRONG 
FERS_LINK_WEAK 

Definition at line 439 of file api.h.

440{
441 FERS_LINK_STRONG, // SNR > 0 dB
442 FERS_LINK_WEAK // SNR < 0 dB (Geometric possibility but sub-noise)
fers_link_quality_t
Quality of the radio link based on SNR.
Definition api.h:440
@ FERS_LINK_WEAK
Definition api.h:442
@ FERS_LINK_STRONG
Definition api.h:441

◆ fers_link_type_t

Type of visual link to render.

Enumerator
FERS_LINK_MONOSTATIC 
FERS_LINK_BISTATIC_TX_TGT 
FERS_LINK_BISTATIC_TGT_RX 
FERS_LINK_DIRECT_TX_RX 

Definition at line 448 of file api.h.

449{
450 FERS_LINK_MONOSTATIC, // Combined Tx/Rx path
451 FERS_LINK_BISTATIC_TX_TGT, // Illuminator path
452 FERS_LINK_BISTATIC_TGT_RX, // Scattered path
453 FERS_LINK_DIRECT_TX_RX // Interference path
fers_link_type_t
Type of visual link to render.
Definition api.h:449
@ FERS_LINK_BISTATIC_TX_TGT
Definition api.h:451
@ FERS_LINK_MONOSTATIC
Definition api.h:450
@ FERS_LINK_BISTATIC_TGT_RX
Definition api.h:452
@ FERS_LINK_DIRECT_TX_RX
Definition api.h:453

◆ fers_log_level_t

Log levels for the FERS library.

Enumerator
FERS_LOG_TRACE 
FERS_LOG_DEBUG 
FERS_LOG_INFO 
FERS_LOG_WARNING 
FERS_LOG_ERROR 
FERS_LOG_FATAL 

Definition at line 75 of file api.h.

76{
fers_log_level_t
Log levels for the FERS library.
Definition api.h:76
@ FERS_LOG_FATAL
Definition api.h:82
@ FERS_LOG_DEBUG
Definition api.h:78
@ FERS_LOG_ERROR
Definition api.h:81
@ FERS_LOG_INFO
Definition api.h:79
@ FERS_LOG_TRACE
Definition api.h:77
@ FERS_LOG_WARNING
Definition api.h:80

Function Documentation

◆ fers_calculate_preview_links()

fers_visual_link_list_t * fers_calculate_preview_links ( const fers_context_t context,
double  time 
)

Calculates visual links for a specific simulation time.

Parameters
contextThe simulation context.
timeThe simulation time in seconds.
Returns
A pointer to a link list. Caller must free with fers_free_preview_links.

Definition at line 725 of file api.cpp.

726{
727 last_error_message.clear();
728 if (!context)
729 {
730 last_error_message = "Invalid context passed to fers_calculate_preview_links";
732 return nullptr;
733 }
734
735 try
736 {
737 const auto* ctx = reinterpret_cast<const FersContext*>(context);
738 // Call the core physics logic in channel_model.cpp
739 const auto cpp_links = simulation::calculatePreviewLinks(*ctx->getWorld(), time);
740
741 // Convert C++ vector to C-API struct
742 auto* result = new fers_visual_link_list_t();
743 result->count = cpp_links.size();
744
745 if (!cpp_links.empty())
746 {
747 result->links = new fers_visual_link_t[result->count];
748 for (size_t i = 0; i < result->count; ++i)
749 {
750 const auto& src = cpp_links[i];
751 auto& dst = result->links[i];
752
753 // Map enums
754 switch (src.type)
755 {
758 break;
760 dst.type = FERS_LINK_BISTATIC_TX_TGT;
761 break;
763 dst.type = FERS_LINK_BISTATIC_TGT_RX;
764 break;
766 dst.type = FERS_LINK_DIRECT_TX_RX;
767 break;
768 }
769
770 dst.quality = (src.quality == simulation::LinkQuality::Strong) ? FERS_LINK_STRONG : FERS_LINK_WEAK;
771
772 // Safe string copy
773 std::strncpy(dst.label, src.label.c_str(), sizeof(dst.label) - 1);
774 dst.label[sizeof(dst.label) - 1] = '\0';
775
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';
778
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';
781
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';
784 }
785 }
786 else
787 {
788 result->links = nullptr;
789 }
790 return result;
791 }
792 catch (const std::exception& e)
793 {
794 handle_api_exception(e, "fers_calculate_preview_links");
795 return nullptr;
796 }
797}
static void handle_api_exception(const std::exception &e, const std::string &function_name)
Centralized exception handler for the C-API boundary.
Definition api.cpp:52
thread_local std::string last_error_message
Definition api.cpp:41
Manages the lifetime and state of a single FERS simulation scenario.
#define LOG(level,...)
Definition logging.h:19
@ ERROR
Error level for error events.
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.

References simulation::BistaticTgtRx, simulation::BistaticTxTgt, simulation::calculatePreviewLinks(), simulation::DirectTxRx, logging::ERROR, FERS_LINK_BISTATIC_TGT_RX, FERS_LINK_BISTATIC_TX_TGT, FERS_LINK_DIRECT_TX_RX, FERS_LINK_MONOSTATIC, FERS_LINK_STRONG, FERS_LINK_WEAK, handle_api_exception(), last_error_message, LOG, simulation::Monostatic, simulation::Strong, and fers_visual_link_t::type.

+ Here is the call graph for this function:

◆ fers_configure_logging()

int fers_configure_logging ( fers_log_level_t  level,
const char *  log_file_path 
)

Configures the internal logger.

Parameters
levelThe minimum severity level to log.
log_file_pathOptional path to a log file. Pass NULL to disable file logging.
Returns
0 on success, non-zero on error.

Definition at line 112 of file api.cpp.

113{
114 last_error_message.clear();
115 try
116 {
118 if (log_file_path && *log_file_path)
119 {
120 auto result = logging::logger.logToFile(log_file_path);
121 if (!result)
122 {
123 last_error_message = result.error();
124 return 1;
125 }
126 }
127 return 0;
128 }
129 catch (const std::exception& e)
130 {
131 handle_api_exception(e, "fers_configure_logging");
132 return 1;
133 }
134}
static logging::Level map_level(fers_log_level_t level)
Definition api.cpp:91
std::expected< void, std::string > logToFile(const std::string &filePath) noexcept
Sets the log file path to log messages to a file.
Definition logging.cpp:59
void setLevel(const Level level) noexcept
Sets the logging level.
Definition logging.h:57
Logger logger
Externally available logger object.
Definition logging.cpp:23

References handle_api_exception(), last_error_message, logging::logger, logging::Logger::logToFile(), map_level(), and logging::Logger::setLevel().

Referenced by main().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fers_context_create()

fers_context_t * fers_context_create ( )

Creates a new FERS simulation context.

Allocates and initializes a new, empty simulation context in memory. This context serves as the container for a scenario loaded via one of the fers_load_... or fers_update_... functions.

Note
In a C API, RAII is not available. The caller is responsible for destroying the returned context using fers_context_destroy() to prevent resource leaks.
Returns
A non-null opaque pointer (handle) to the simulation context on success. Returns NULL on failure (e.g., out of memory).

Definition at line 60 of file api.cpp.

61{
62 last_error_message.clear();
63 try
64 {
65 return new fers_context_t();
66 }
67 catch (const std::bad_alloc& e)
68 {
69 handle_api_exception(e, "fers_context_create");
70 return nullptr;
71 }
72 catch (const std::exception& e)
73 {
74 handle_api_exception(e, "fers_context_create");
75 return nullptr;
76 }
77}
struct fers_context fers_context_t
Definition api.h:25

References handle_api_exception(), and last_error_message.

Referenced by main().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fers_context_destroy()

void fers_context_destroy ( fers_context_t context)

Destroys a FERS simulation context and releases all associated memory.

This function must be called for every context created by fers_context_create() to ensure proper cleanup of the underlying C++ objects. Accessing the context handle after calling this function results in undefined behavior.

Parameters
contextA valid pointer to a fers_context_t handle. If context is NULL, the function performs no action for safety.

Definition at line 79 of file api.cpp.

80{
81 if (!context)
82 {
83 last_error_message = "Invalid context provided to fers_context_destroy.";
85 return;
86 }
87 delete context;
88}
@ WARNING
Warning level for potentially harmful situations.

References last_error_message, LOG, and logging::WARNING.

Referenced by main().

+ Here is the caller graph for this function:

◆ fers_free_antenna_pattern_data()

void fers_free_antenna_pattern_data ( fers_antenna_pattern_data_t data)

Frees the memory allocated for an antenna pattern data structure.

Parameters
dataA pointer to the fers_antenna_pattern_data_t struct to free.

Definition at line 714 of file api.cpp.

715{
716 if (data)
717 {
718 delete[] data->gains;
719 delete data;
720 }
721}

References fers_antenna_pattern_data_t::gains.

◆ fers_free_interpolated_motion_path()

void fers_free_interpolated_motion_path ( fers_interpolated_path_t path)

Frees the memory allocated for an interpolated motion path.

Parameters
pathA pointer to the fers_interpolated_path_t struct to free.

Definition at line 524 of file api.cpp.

525{
526 if (path)
527 {
528 delete[] path->points;
529 delete path;
530 }
531}
fers_interpolated_point_t * points
Definition api.h:373

References fers_interpolated_path_t::points.

◆ fers_free_interpolated_rotation_path()

void fers_free_interpolated_rotation_path ( fers_interpolated_rotation_path_t path)

Frees the memory allocated for an interpolated rotation path.

Parameters
pathA pointer to the fers_interpolated_rotation_path_t struct to free.

Definition at line 617 of file api.cpp.

618{
619 if (path)
620 {
621 delete[] path->points;
622 delete path;
623 }
624}
fers_interpolated_rotation_point_t * points
Definition api.h:383

References fers_interpolated_rotation_path_t::points.

◆ fers_free_preview_links()

void fers_free_preview_links ( fers_visual_link_list_t list)

Frees the memory allocated for a preview link list.

Parameters
listThe list to free.

Definition at line 799 of file api.cpp.

800{
801 if (list)
802 {
803 delete[] list->links;
804 delete list;
805 }
806}

References fers_visual_link_list_t::links.

◆ fers_free_string()

void fers_free_string ( char *  str)

Frees a string that was allocated and returned by the libfers API.

This function must be used to release memory for any string returned by functions like fers_get_scenario_as_json or fers_get_last_error_message. It exists to ensure that the memory deallocation mechanism (free) matches the allocation mechanism (strdup/malloc) used within the C++ library, preventing potential crashes from mismatched allocators across language boundaries.

Parameters
strA pointer to the string to be freed. If str is NULL, no action is taken.

Definition at line 346 of file api.cpp.

347{
348 if (str)
349 {
350 free(str);
351 }
352}

Referenced by main().

+ Here is the caller graph for this function:

◆ fers_generate_kml()

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.

This utility exists to provide a simple, out-of-the-box method for users to validate and visualize the geographic layout and motion paths of their scenarios in common external tools like Google Earth.

Parameters
contextA valid fers_context_t handle containing a loaded scenario.
output_kml_filepathA null-terminated UTF-8 string for the output KML file path.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve error details.

Definition at line 390 of file api.cpp.

391{
392 last_error_message.clear();
393 if (!context || !output_kml_filepath)
394 {
395 last_error_message = "Invalid arguments: context or output_kml_filepath is NULL.";
397 return -1;
398 }
399
400 auto* ctx = reinterpret_cast<const FersContext*>(context);
401
402 try
403 {
404 if (serial::KmlGenerator::generateKml(*ctx->getWorld(), output_kml_filepath))
405 {
406 return 0; // Success
407 }
408
409 last_error_message = "KML generation failed for an unknown reason.";
411 return 2; // Generation failed
412 }
413 catch (const std::exception& e)
414 {
415 handle_api_exception(e, "fers_generate_kml");
416 return 1; // Exception thrown
417 }
418}
static bool generateKml(const core::World &world, const std::string &outputKmlPath)
Generates a KML file from a pre-built simulation world.

References logging::ERROR, serial::KmlGenerator::generateKml(), handle_api_exception(), last_error_message, and LOG.

Referenced by main().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fers_get_antenna_pattern()

fers_antenna_pattern_data_t * fers_get_antenna_pattern ( const fers_context_t context,
const char *  antenna_name,
size_t  az_samples,
size_t  el_samples,
double  frequency_hz 
)

Samples the gain pattern of a specified antenna and provides the data.

This function calculates the antenna's far-field gain at a specified resolution over the full sphere of directions (azimuth and elevation). The resulting gain values are linear (not in dB) and normalized relative to the pattern's peak gain. This is a stateless utility useful for UI previews and analysis.

Parameters
contextA valid fers_context_t handle containing a loaded scenario with the antenna.
antenna_nameThe name of the antenna asset to sample.
az_samplesThe desired number of sample points along the azimuth axis.
el_samplesThe desired number of sample points along the elevation axis.
frequency_hzThe frequency in Hz to use for gain calculation (affects aperture antennas).
Returns
A pointer to a fers_antenna_pattern_data_t struct containing the results. Returns NULL on failure (e.g., antenna not found). The caller owns the returned struct and must free it with fers_free_antenna_pattern_data.

Definition at line 628 of file api.cpp.

631{
632 last_error_message.clear();
633 if (!context || !antenna_name || az_samples == 0 || el_samples == 0)
634 {
635 last_error_message = "Invalid arguments: context, antenna_name, or sample counts are invalid.";
637 return nullptr;
638 }
639
640 try
641 {
642 const auto* ctx = reinterpret_cast<const FersContext*>(context);
643 antenna::Antenna* ant = ctx->getWorld()->findAntenna(antenna_name);
644
645 if (!ant)
646 {
647 last_error_message = "Antenna '" + std::string(antenna_name) + "' not found in the world.";
649 return nullptr;
650 }
651
652 // TODO: Currently only using the first-found waveform. This is incorrect but also difficult to represent
653 // correctly in scenarios with multiple waveforms as the gain for squarehorn and parabolic antennas
654 // depends on the wavelength. Hence a decision needs to be made about whether to return multiple patterns
655 // per waveform or have the user specify a representative wavelength in the UI per antenna.
656 // Calculate wavelength from the provided frequency.
657 // Default to 1GHz (0.3m) if frequency is invalid/zero, though the UI should prevent this
658 // for antennas that strictly require it (Horn/Parabolic).
659 RealType wavelength = 0.3;
660 if (frequency_hz > 0.0)
661 {
662 wavelength = params::c() / frequency_hz;
663 }
664
665 auto* data = new fers_antenna_pattern_data_t();
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];
670
671 // The reference angle (boresight) is implicitly the local X-axis in the FERS engine.
672 // We pass a zero rotation to get the gain relative to this boresight.
673 const math::SVec3 ref_angle(1.0, 0.0, 0.0);
674 double max_gain = 0.0;
675
676 for (size_t i = 0; i < el_samples; ++i)
677 {
678 // Elevation from -PI/2 to PI/2
679 const RealType elevation = (static_cast<RealType>(i) / (el_samples - 1)) * PI - (PI / 2.0);
680 for (size_t j = 0; j < az_samples; ++j)
681 {
682 // Azimuth from -PI to PI
683 const RealType azimuth = (static_cast<RealType>(j) / (az_samples - 1)) * 2.0 * PI - PI;
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;
687 if (gain > max_gain)
688 {
689 max_gain = gain;
690 }
691 }
692 }
693
694 data->max_gain = max_gain;
695
696 // Normalize the gains
697 if (max_gain > 0)
698 {
699 for (size_t i = 0; i < total_samples; ++i)
700 {
701 data->gains[i] /= max_gain;
702 }
703 }
704
705 return data;
706 }
707 catch (const std::exception& e)
708 {
709 handle_api_exception(e, "fers_get_antenna_pattern");
710 return nullptr;
711 }
712}
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.
A class representing a vector in spherical coordinates.
double RealType
Type for real numbers.
Definition config.h:27
constexpr RealType PI
Mathematical constant π (pi).
Definition config.h:43
RealType c() noexcept
Get the speed of light.
Definition parameters.h:79
Represents a sampled 2D antenna gain pattern.
Definition api.h:270

References params::c(), logging::ERROR, antenna::Antenna::getGain(), handle_api_exception(), last_error_message, LOG, and PI.

+ Here is the call graph for this function:

◆ fers_get_interpolated_motion_path()

fers_interpolated_path_t * fers_get_interpolated_motion_path ( const fers_motion_waypoint_t waypoints,
size_t  waypoint_count,
fers_interp_type_t  interp_type,
size_t  num_points 
)

Calculates an interpolated motion path from a set of waypoints.

This function is a stateless utility that computes the path without needing a full simulation context. It is useful for UI previews.

Parameters
waypointsAn array of fers_motion_waypoint_t structs.
waypoint_countThe number of waypoints in the array.
interp_typeThe interpolation algorithm to use.
num_pointsThe desired number of points in the output interpolated path.
Returns
A pointer to a fers_interpolated_path_t struct containing the results. Returns NULL on failure. The caller owns the returned struct and must free it with fers_free_interpolated_motion_path.

Definition at line 450 of file api.cpp.

454{
455 last_error_message.clear();
456 if (!waypoints || waypoint_count == 0 || num_points == 0)
457 {
458 last_error_message = "Invalid arguments: waypoints cannot be null and counts must be > 0.";
460 return nullptr;
461 }
462 if (interp_type == FERS_INTERP_CUBIC && waypoint_count < 2)
463 {
464 last_error_message = "Cubic interpolation requires at least 2 waypoints.";
466 return nullptr;
467 }
468
469 try
470 {
471 math::Path path;
472 path.setInterp(to_cpp_interp_type(interp_type));
473
474 for (size_t i = 0; i < waypoint_count; ++i)
475 {
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;
481 path.addCoord(c);
482 }
483
484 path.finalize();
485
486 auto* result_path = new fers_interpolated_path_t();
487 result_path->points = new fers_interpolated_point_t[num_points];
488 result_path->count = num_points;
489
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;
493
494 // Handle static case separately
495 if (waypoint_count < 2 || duration <= 0)
496 {
497 const math::Vec3 pos = path.getPosition(start_time);
498 for (size_t i = 0; i < num_points; ++i)
499 {
500 result_path->points[i] = {pos.x, pos.y, pos.z};
501 }
502 return result_path;
503 }
504
505 const double time_step = duration / (num_points > 1 ? num_points - 1 : 1);
506
507 for (size_t i = 0; i < num_points; ++i)
508 {
509 const double t = start_time + i * time_step;
510 const math::Vec3 pos = path.getPosition(t);
511 const math::Vec3 vel = path.getVelocity(t);
512 result_path->points[i] = {pos.x, pos.y, pos.z, vel.x, vel.y, vel.z};
513 }
514
515 return result_path;
516 }
517 catch (const std::exception& e)
518 {
519 handle_api_exception(e, "fers_get_interpolated_motion_path");
520 return nullptr;
521 }
522}
math::Path::InterpType to_cpp_interp_type(const fers_interp_type_t type)
Definition api.cpp:421
Represents a path with coordinates and allows for various interpolation methods.
Definition path.h:30
Vec3 getPosition(RealType t) const
Retrieves the position at a given time along the path.
Definition path.cpp:35
void setInterp(InterpType settype) noexcept
Changes the interpolation type.
Definition path.cpp:158
Vec3 getVelocity(RealType t) const
Retrieves the velocity at a given time along the path.
Definition path.cpp:59
void addCoord(const Coord &coord) noexcept
Adds a coordinate to the path.
Definition path.cpp:26
void finalize()
Finalizes the path, preparing it for interpolation.
Definition path.cpp:141
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 container for an array of interpolated motion path points.
Definition api.h:372
Represents a single interpolated point on a motion path.
Definition api.h:347
double x
X coordinate in meters (East in ENU).
Definition api.h:326
double time
Time in seconds.
Definition api.h:325
double y
Y coordinate in meters (North in ENU).
Definition api.h:327
double z
Z coordinate in meters (Up/Altitude in ENU).
Definition api.h:328
Represents a position in 3D space with an associated time.
Definition coord.h:24

References math::Path::addCoord(), logging::ERROR, FERS_INTERP_CUBIC, math::Path::finalize(), math::Path::getPosition(), math::Path::getVelocity(), handle_api_exception(), last_error_message, LOG, math::Path::setInterp(), fers_motion_waypoint_t::time, to_cpp_interp_type(), fers_motion_waypoint_t::x, math::Vec3::x, fers_motion_waypoint_t::y, math::Vec3::y, fers_motion_waypoint_t::z, and math::Vec3::z.

+ Here is the call graph for this function:

◆ fers_get_interpolated_rotation_path()

fers_interpolated_rotation_path_t * fers_get_interpolated_rotation_path ( const fers_rotation_waypoint_t waypoints,
size_t  waypoint_count,
fers_interp_type_t  interp_type,
size_t  num_points 
)

Calculates an interpolated rotation path from a set of waypoints.

This function is a stateless utility for UI previews.

Parameters
waypointsAn array of fers_rotation_waypoint_t structs.
waypoint_countThe number of waypoints in the array.
interp_typeThe interpolation algorithm to use (STATIC, LINEAR, CUBIC).
num_pointsThe desired number of points in the output interpolated path.
Returns
A pointer to a fers_interpolated_rotation_path_t struct containing the results. Returns NULL on failure. The caller owns the returned struct and must free it with fers_free_interpolated_rotation_path.

Definition at line 533 of file api.cpp.

537{
538 last_error_message.clear();
539 if (!waypoints || waypoint_count == 0 || num_points == 0)
540 {
541 last_error_message = "Invalid arguments: waypoints cannot be null and counts must be > 0.";
543 return nullptr;
544 }
545 if (interp_type == FERS_INTERP_CUBIC && waypoint_count < 2)
546 {
547 last_error_message = "Cubic interpolation requires at least 2 waypoints.";
549 return nullptr;
550 }
551
552 try
553 {
555 path.setInterp(to_cpp_rot_interp_type(interp_type));
556
557 for (size_t i = 0; i < waypoint_count; ++i)
558 {
559 const RealType az_deg = waypoints[i].azimuth_deg;
560 const RealType el_deg = waypoints[i].elevation_deg;
561
562 // Convert from compass degrees (from C-API) to internal mathematical radians
563 const RealType az_rad = (90.0 - az_deg) * (PI / 180.0);
564 const RealType el_rad = el_deg * (PI / 180.0);
565
566 path.addCoord({az_rad, el_rad, waypoints[i].time});
567 }
568
569 path.finalize();
570
571 auto* result_path = new fers_interpolated_rotation_path_t();
572 result_path->points = new fers_interpolated_rotation_point_t[num_points];
573 result_path->count = num_points;
574
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;
578
579 // Handle static case separately
580 if (waypoint_count < 2 || duration <= 0)
581 {
582 const math::SVec3 rot = path.getPosition(start_time);
583 // Convert back to compass degrees for output without normalization
584 const RealType az_deg = 90.0 - rot.azimuth * 180.0 / PI;
585 const RealType el_deg = rot.elevation * 180.0 / PI;
586 for (size_t i = 0; i < num_points; ++i)
587 {
588 result_path->points[i] = {az_deg, el_deg};
589 }
590 return result_path;
591 }
592
593 const double time_step = duration / (num_points > 1 ? num_points - 1 : 1);
594
595 for (size_t i = 0; i < num_points; ++i)
596 {
597 const double t = start_time + i * time_step;
598 const math::SVec3 rot = path.getPosition(t);
599
600 // Convert from internal mathematical radians back to compass degrees for C-API output
601 // We do NOT normalize to [0, 360) to preserve winding/negative angles for the UI.
602 const RealType az_deg = 90.0 - rot.azimuth * 180.0 / PI;
603 const RealType el_deg = rot.elevation * 180.0 / PI;
604
605 result_path->points[i] = {az_deg, el_deg};
606 }
607
608 return result_path;
609 }
610 catch (const std::exception& e)
611 {
612 handle_api_exception(e, "fers_get_interpolated_rotation_path");
613 return nullptr;
614 }
615}
math::RotationPath::InterpType to_cpp_rot_interp_type(const fers_interp_type_t type)
Definition api.cpp:435
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.
void addCoord(const RotationCoord &coord) noexcept
Adds a rotation coordinate to the path.
RealType elevation
The elevation angle of the vector.
RealType azimuth
The azimuth angle of the vector.
A container for an array of interpolated rotation path points.
Definition api.h:382
Represents a single interpolated point on a rotation path.
Definition api.h:361
double time
Time in seconds.
Definition api.h:337
double elevation_deg
Elevation angle in degrees (positive up).
Definition api.h:339
double azimuth_deg
Azimuth angle in compass degrees (0=North, 90=East).
Definition api.h:338

References math::RotationPath::addCoord(), math::SVec3::azimuth, fers_rotation_waypoint_t::azimuth_deg, math::SVec3::elevation, fers_rotation_waypoint_t::elevation_deg, logging::ERROR, FERS_INTERP_CUBIC, math::RotationPath::finalize(), math::RotationPath::getPosition(), handle_api_exception(), last_error_message, LOG, PI, math::RotationPath::setInterp(), fers_rotation_waypoint_t::time, and to_cpp_rot_interp_type().

+ Here is the call graph for this function:

◆ fers_get_last_error_message()

char * fers_get_last_error_message ( )

Retrieves the last error message that occurred on the current thread.

Because C++ exceptions cannot safely propagate across the FFI boundary into other languages, this function provides the standard C-style error reporting mechanism. The error state is stored in a thread-local variable to ensure that concurrent API calls from different threads do not overwrite each other's error messages. The error is cleared at the start of each fallible API call.

Note
Memory Management: The returned string's ownership is transferred to the caller. It MUST be freed using fers_free_string() to prevent memory leaks.
Returns
A dynamically allocated, null-terminated C-string containing the last error message, or NULL if no error has occurred.

Definition at line 334 of file api.cpp.

335{
336 if (last_error_message.empty())
337 {
338 return nullptr; // No error to report
339 }
340 // `strdup` allocates with `malloc`, which is part of the C standard ABI,
341 // making it safe to transfer ownership across the FFI boundary. The caller
342 // must then free this memory using `fers_free_string`.
343 return strdup(last_error_message.c_str());
344}

References last_error_message.

Referenced by main().

+ Here is the caller graph for this function:

◆ fers_get_scenario_as_json()

char * fers_get_scenario_as_json ( fers_context_t context)

Serializes the current simulation scenario into a JSON string.

This function is the primary method for the UI to retrieve the full state of the simulation. JSON is used as the interchange format because it is lightweight, human-readable, and natively supported by web technologies, making it trivial to parse and use in the React/TypeScript frontend.

Note
Memory Management: The returned string is allocated by this library and its ownership is transferred to the caller. It is crucial to free this string using fers_free_string() to prevent memory leaks.
Parameters
contextA valid fers_context_t handle.
Returns
A dynamically allocated, null-terminated C-string containing the JSON representation of the scenario. Returns NULL on failure.

Definition at line 243 of file api.cpp.

244{
245 last_error_message.clear();
246 if (!context)
247 {
248 last_error_message = "Invalid context provided to fers_get_scenario_as_json.";
250 return nullptr;
251 }
252
253 const auto* ctx = reinterpret_cast<FersContext*>(context);
254 try
255 {
256 const nlohmann::json j = serial::world_to_json(*ctx->getWorld());
257 const std::string json_str = j.dump(2);
258 // A heap-allocated copy of the string is returned. This is necessary
259 // to transfer ownership of the memory across the FFI boundary to a
260 // client that will free it using `fers_free_string`.
261 return strdup(json_str.c_str());
262 }
263 catch (const std::exception& e)
264 {
265 handle_api_exception(e, "fers_get_scenario_as_json");
266 return nullptr;
267 }
268}
nlohmann::json world_to_json(const core::World &world)
Serializes the entire simulation world into a nlohmann::json object.

References logging::ERROR, handle_api_exception(), last_error_message, LOG, and serial::world_to_json().

+ Here is the call graph for this function:

◆ fers_get_scenario_as_xml()

char * fers_get_scenario_as_xml ( fers_context_t context)

Serializes the current simulation scenario into a FERS XML string.

This function enables exporting the in-memory state back into the standard FERS XML file format. This is essential for interoperability with legacy tools and for allowing a user to save a scenario that was created or modified in the UI.

Note
Memory Management: The returned string is dynamically allocated and its ownership is transferred to the caller. It must be freed using fers_free_string() to prevent memory leaks.
Parameters
contextA valid fers_context_t handle.
Returns
A dynamically allocated, null-terminated C-string containing the XML representation of the scenario. Returns NULL on failure.

Definition at line 270 of file api.cpp.

271{
272 last_error_message.clear();
273 if (!context)
274 {
275 last_error_message = "Invalid context provided to fers_get_scenario_as_xml.";
277 return nullptr;
278 }
279
280 const auto* ctx = reinterpret_cast<FersContext*>(context);
281 try
282 {
283 const std::string xml_str = serial::world_to_xml_string(*ctx->getWorld());
284 if (xml_str.empty())
285 {
286 throw std::runtime_error("XML serialization resulted in an empty string.");
287 }
288 // `strdup` is used to create a heap-allocated string that can be safely
289 // passed across the FFI boundary. The client is responsible for freeing
290 // this memory with `fers_free_string`.
291 return strdup(xml_str.c_str());
292 }
293 catch (const std::exception& e)
294 {
295 handle_api_exception(e, "fers_get_scenario_as_xml");
296 return nullptr;
297 }
298}
std::string world_to_xml_string(const core::World &world)
Serializes the entire simulation world into an XML formatted string.

References logging::ERROR, handle_api_exception(), last_error_message, LOG, and serial::world_to_xml_string().

+ Here is the call graph for this function:

◆ fers_load_scenario_from_xml_file()

int fers_load_scenario_from_xml_file ( fers_context_t context,
const char *  xml_filepath,
int  validate 
)

Loads a scenario into the context from a FERS XML file.

This is the standard method for initializing a simulation context from a file on disk. It is essential for interoperability with the CLI and legacy workflows that rely on the FERS XML format.

Parameters
contextA valid fers_context_t handle.
xml_filepathA null-terminated UTF-8 string for the input XML file path.
validateA boolean (0 or 1) indicating whether to validate the XML against the embedded FERS schema. Validation is recommended to ensure scenario correctness.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve error details.

Definition at line 162 of file api.cpp.

163{
164 last_error_message.clear();
165 if (!context || !xml_filepath)
166 {
167 last_error_message = "Invalid arguments: context or xml_filepath is NULL.";
169 return -1;
170 }
171
172 auto* ctx = reinterpret_cast<FersContext*>(context);
173 try
174 {
175 serial::parseSimulation(xml_filepath, ctx->getWorld(), static_cast<bool>(validate), ctx->getMasterSeeder());
176
177 // After parsing, seed the master random number generator. This is done
178 // to ensure simulation reproducibility. If the scenario specifies a seed,
179 // it is used; otherwise, a non-deterministic seed is generated so that
180 // subsequent runs are unique by default.
181 if (params::params.random_seed)
182 {
183 LOG(logging::Level::INFO, "Using master seed from scenario file: {}", *params::params.random_seed);
184 ctx->getMasterSeeder().seed(*params::params.random_seed);
185 }
186 else
187 {
188 const auto seed = std::random_device{}();
189 LOG(logging::Level::INFO, "No master seed provided in scenario. Using random_device seed: {}", seed);
191 ctx->getMasterSeeder().seed(seed);
192 }
193 return 0; // Success
194 }
195 catch (const std::exception& e)
196 {
197 handle_api_exception(e, "fers_load_scenario_from_xml_file");
198 return 1; // Error
199 }
200}
@ INFO
Info level for informational messages.
Parameters params
Definition parameters.h:73
void parseSimulation(const std::string &filename, World *world, const bool validate, std::mt19937 &masterSeeder)
Parses a simulation configuration from an XML file.
std::optional< unsigned > random_seed
Random seed for simulation.
Definition parameters.h:58

References logging::ERROR, handle_api_exception(), logging::INFO, last_error_message, LOG, params::params, serial::parseSimulation(), and params::Parameters::random_seed.

Referenced by main().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fers_load_scenario_from_xml_string()

int fers_load_scenario_from_xml_string ( fers_context_t context,
const char *  xml_content,
int  validate 
)

Loads a scenario into the context from a FERS XML string.

This function provides a way to load a scenario from an in-memory string, avoiding file I/O. It is useful for test harnesses or for UIs that manage scenarios as text content before parsing.

Parameters
contextA valid fers_context_t handle.
xml_contentA null-terminated UTF-8 string containing the FERS scenario in XML format.
validateA boolean (0 or 1) indicating whether to validate the XML against the embedded FERS schema.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve error details.

Definition at line 202 of file api.cpp.

203{
204 last_error_message.clear();
205 if (!context || !xml_content)
206 {
207 last_error_message = "Invalid arguments: context or xml_content is NULL.";
209 return -1;
210 }
211
212 auto* ctx = reinterpret_cast<FersContext*>(context);
213 try
214 {
215 serial::parseSimulationFromString(xml_content, ctx->getWorld(), static_cast<bool>(validate),
216 ctx->getMasterSeeder());
217
218 // After parsing, seed the master random number generator. This ensures
219 // that if the scenario provides a seed, the simulation will be
220 // reproducible. If not, a random seed is used to ensure unique runs.
221 if (params::params.random_seed)
222 {
223 LOG(logging::Level::INFO, "Using master seed from scenario string: {}", *params::params.random_seed);
224 ctx->getMasterSeeder().seed(*params::params.random_seed);
225 }
226 else
227 {
228 const auto seed = std::random_device{}();
229 LOG(logging::Level::INFO, "No master seed provided in scenario. Using random_device seed: {}", seed);
231 ctx->getMasterSeeder().seed(seed);
232 }
233
234 return 0; // Success
235 }
236 catch (const std::exception& e)
237 {
238 handle_api_exception(e, "fers_load_scenario_from_xml_string");
239 return 1; // Parsing or logic error
240 }
241}
void parseSimulationFromString(const std::string &xmlContent, World *world, const bool validate, std::mt19937 &masterSeeder)

References logging::ERROR, handle_api_exception(), logging::INFO, last_error_message, LOG, params::params, serial::parseSimulationFromString(), and params::Parameters::random_seed.

+ Here is the call graph for this function:

◆ fers_log()

void fers_log ( fers_log_level_t  level,
const char *  message 
)

Submits a log message to the library's unified logging system.

This ensures CLI messages match the format (timestamps, alignment) of library messages.

Definition at line 136 of file api.cpp.

137{
138 if (!message)
139 return;
140 // We pass a default source_location because C-API calls don't provide C++ source info
141 logging::logger.log(map_level(level), message, std::source_location::current());
142}
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.
Definition logging.cpp:37

References logging::Logger::log(), logging::logger, and map_level().

+ Here is the call graph for this function:

◆ fers_run_simulation()

int fers_run_simulation ( fers_context_t context,
fers_progress_callback_t  callback,
void *  user_data 
)

Runs the simulation defined in the provided context.

This function is synchronous and will block the calling thread until the simulation is complete. This design keeps the API simple. For use in a responsive UI, it is the responsibility of the caller (e.g., the Tauri backend) to invoke this function on a separate worker thread to avoid freezing the user interface.

Parameters
contextA valid fers_context_t handle containing a loaded scenario.
callbackA function pointer to a progress callback. Can be NULL.
user_dataAn opaque pointer passed to the callback function.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve error details.

Definition at line 354 of file api.cpp.

355{
356 last_error_message.clear();
357 if (!context)
358 {
359 last_error_message = "Invalid context provided to fers_run_simulation.";
361 return -1;
362 }
363
364 auto* ctx = reinterpret_cast<FersContext*>(context);
365
366 // Wrap the C-style callback in a std::function for easier use in C++.
367 // This also handles the case where the callback is null.
368 std::function<void(const std::string&, int, int)> progress_fn;
369 if (callback)
370 {
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); };
373 }
374
375 try
376 {
378
379 core::runEventDrivenSim(ctx->getWorld(), pool, progress_fn);
380
381 return 0;
382 }
383 catch (const std::exception& e)
384 {
385 handle_api_exception(e, "fers_run_simulation");
386 return 1;
387 }
388}
A simple thread pool implementation.
Definition thread_pool.h:29
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.
unsigned renderThreads() noexcept
Get the number of worker threads.
Definition parameters.h:133

References logging::ERROR, handle_api_exception(), last_error_message, LOG, params::renderThreads(), and core::runEventDrivenSim().

Referenced by main().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fers_set_thread_count()

int fers_set_thread_count ( unsigned  num_threads)

Sets the number of worker threads for the simulation.

Parameters
num_threadsThe number of threads to use.
Returns
0 on success, non-zero on error.

Definition at line 144 of file api.cpp.

145{
146 try
147 {
148 if (auto res = params::setThreads(num_threads); !res)
149 {
150 last_error_message = res.error();
151 return 1;
152 }
153 return 0;
154 }
155 catch (const std::exception& e)
156 {
157 handle_api_exception(e, "fers_set_thread_count");
158 return 1;
159 }
160}
std::expected< void, std::string > setThreads(const unsigned threads) noexcept
Set the number of worker threads.
Definition parameters.h:248

References handle_api_exception(), last_error_message, and params::setThreads().

Referenced by main().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fers_update_scenario_from_json()

int fers_update_scenario_from_json ( fers_context_t context,
const char *  scenario_json 
)

Updates the simulation scenario from a JSON string.

This is the primary method for the UI to push its state back to the C++ core. It performs a full replacement of the existing scenario.

Parameters
contextA valid fers_context_t handle.
scenario_jsonA null-terminated UTF-8 string containing the FERS scenario in JSON format.
Returns
0 on success. 1 on generic logic error. 2 on JSON parsing/schema validation error. Use fers_get_last_error_message() to retrieve error details.

Definition at line 300 of file api.cpp.

301{
302 last_error_message.clear();
303 if (!context || !scenario_json)
304 {
305 last_error_message = "Invalid arguments: context or scenario_json is NULL.";
307 return -1;
308 }
309
310 auto* ctx = reinterpret_cast<FersContext*>(context);
311 try
312 {
313 const nlohmann::json j = nlohmann::json::parse(scenario_json);
314 serial::json_to_world(j, *ctx->getWorld(), ctx->getMasterSeeder());
315
316 return 0; // Success
317 }
318 catch (const nlohmann::json::exception& e)
319 {
320 // A specific catch block for JSON errors is used to provide more
321 // detailed feedback to the client (e.g., the UI), which can help
322 // developers diagnose schema or data format issues more easily.
323 last_error_message = "JSON parsing/deserialization error: " + std::string(e.what());
324 LOG(logging::Level::ERROR, "API Error in {}: {}", "fers_update_scenario_from_json", last_error_message);
325 return 2; // JSON error
326 }
327 catch (const std::exception& e)
328 {
329 handle_api_exception(e, "fers_update_scenario_from_json");
330 return 1; // Generic error
331 }
332}
void json_to_world(const nlohmann::json &j, core::World &world, std::mt19937 &masterSeeder)
Deserializes a nlohmann::json object and reconstructs the simulation world.

References logging::ERROR, handle_api_exception(), serial::json_to_world(), last_error_message, and LOG.

+ Here is the call graph for this function: