14#include <GeographicLib/Geocentric.hpp>
15#include <GeographicLib/Geodesic.hpp>
16#include <GeographicLib/LocalCartesian.hpp>
17#include <GeographicLib/UTMUPS.hpp>
49 using ConverterFunc = std::function<void(
const math::Vec3&,
double&,
double&,
double&)>;
52 constexpr int TRACK_NUM_DIVISIONS = 100;
54 constexpr int ISOTROPIC_PATTERN_POINTS = 100;
56 constexpr double ISOTROPIC_PATTERN_RADIUS_KM = 20.0;
58 constexpr double DIRECTIONAL_ANTENNA_ARROW_LENGTH_M = 20000.0;
61 double sincAntennaGain(
const double theta,
const double alpha,
const double beta,
const double gamma)
67 const double gain = alpha * std::pow(std::sin(beta * theta) / (beta * theta), gamma);
71 double find3DbDropAngle(
const double alpha,
const double beta,
const double gamma)
73 constexpr int num_points = 1000;
74 std::vector<double> theta(num_points);
75 std::vector<double> gain(num_points);
76 for (
int i = 0; i < num_points; ++i)
78 theta[i] = -
PI + 2.0 *
PI * i / (num_points - 1);
79 gain[i] = sincAntennaGain(theta[i], alpha, beta, gamma);
81 const double max_gain = *std::max_element(gain.begin() + num_points / 2, gain.end());
82 const double max_gain_db = 10.0 * std::log10(max_gain);
83 const double target_gain_db = max_gain_db - 3.0;
84 double target_gain = std::pow(10.0, target_gain_db / 10.0);
85 const int idx = std::distance(
86 gain.begin() + num_points / 2,
87 std::min_element(gain.begin() + num_points / 2, gain.end(), [target_gain](
const double a,
const double b)
88 { return std::abs(a - target_gain) < std::abs(b - target_gain); }));
89 const double angle_3db_drop = theta[idx + num_points / 2];
90 return angle_3db_drop * 180.0 /
PI;
107 "Gaussian antenna '{}' has a non-positive azimuth scale ({}). 3dB beamwidth is undefined. KML will "
108 "only show boresight.",
112 const double half_angle_rad = std::sqrt(std::log(2.0) / gaussianAnt->
getAzimuthScale());
113 return half_angle_rad * 180.0 /
PI;
122 double findParabolic3DbDropAngle(
const antenna::Parabolic* parabolicAnt,
const double wavelength)
132 "Parabolic antenna '{}' has a non-positive diameter ({}). This is physically impossible. KML will only "
138 const double arg = 1.6 * wavelength / (
PI * parabolicAnt->
getDiameter());
143 "Parabolic antenna '{}': The operating wavelength ({:.4f}m) is very large compared to its diameter "
144 "({:.4f}m), resulting in a nearly omnidirectional pattern. KML visualization will cap the 3dB "
145 "half-angle at 90 degrees.",
149 const double half_angle_rad = std::asin(arg);
150 return half_angle_rad * 180.0 /
PI;
159 double findSquareHorn3DbDropAngle(
const antenna::SquareHorn* squarehornAnt,
const double wavelength)
168 "SquareHorn antenna '{}' has a non-positive dimension ({}). This is physically impossible. KML will "
169 "only show boresight.",
174 const double arg = 1.39155 * wavelength / (
PI * squarehornAnt->
getDimension());
178 "SquareHorn antenna '{}': The operating wavelength ({:.4f}m) is very large compared to its dimension "
179 "({:.4f}m), resulting in a nearly omnidirectional pattern. KML visualization will cap the 3dB "
180 "half-angle at 90 degrees.",
184 const double half_angle_rad = std::asin(arg);
185 return half_angle_rad * 180.0 /
PI;
188 std::string formatCoordinates(
const double lon,
const double lat,
const double alt)
190 std::stringstream ss;
191 ss << std::fixed << std::setprecision(6) << lon <<
"," << lat <<
"," << alt;
195 void calculateDestinationCoordinate(
const double startLatitude,
const double startLongitude,
const double angle,
196 const double distance,
double& destLatitude,
double& destLongitude)
198 const GeographicLib::Geodesic& geod = GeographicLib::Geodesic::WGS84();
199 geod.Direct(startLatitude, startLongitude, angle, distance, destLatitude, destLongitude);
202 std::vector<std::pair<double, double>> generateCircleCoordinates(
const double lat,
const double lon,
203 const double radius_km)
205 std::vector<std::pair<double, double>> circle_coordinates;
206 for (
int i = 0; i < ISOTROPIC_PATTERN_POINTS; i++)
208 const double bearing = i * 360.0 / ISOTROPIC_PATTERN_POINTS;
209 double new_lat, new_lon;
210 calculateDestinationCoordinate(lat, lon, bearing, radius_km * 1000.0, new_lat, new_lon);
211 circle_coordinates.emplace_back(new_lat, new_lon);
213 return circle_coordinates;
217 void writeKmlHeaderAndStyles(std::ofstream& kmlFile)
219 kmlFile <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
220 kmlFile <<
"<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\">\n";
221 kmlFile <<
"<Document>\n";
222 kmlFile <<
" <name>";
225 kmlFile <<
"FERS Simulation Visualization";
231 kmlFile <<
"</name>\n";
232 kmlFile <<
" <Style "
233 "id=\"receiver\"><IconStyle><Icon><href>https://cdn-icons-png.flaticon.com/512/645/645436.png</"
234 "href></Icon></IconStyle></Style>\n";
235 kmlFile <<
" <Style "
236 "id=\"transmitter\"><IconStyle><Icon><href>https://cdn-icons-png.flaticon.com/128/224/224666.png</"
237 "href></Icon></IconStyle></Style>\n";
238 kmlFile <<
" <Style "
239 "id=\"target\"><IconStyle><Icon><href>https://upload.wikimedia.org/wikipedia/commons/thumb/a/ad/"
240 "Target_red_dot1.svg/1200px-Target_red_dot1.svg.png</href></Icon></IconStyle><LineStyle><width>2</"
241 "width></LineStyle></Style>\n";
242 kmlFile <<
" <Style "
243 "id=\"translucentPolygon\"><LineStyle><color>ff0000ff</color><width>2</width></"
244 "LineStyle><PolyStyle><color>00ffffff</color></PolyStyle></Style>\n";
245 kmlFile <<
" <Style "
246 "id=\"arrowStyle\"><IconStyle><Icon><href>http://maps.google.com/mapfiles/kml/shapes/arrow.png</"
247 "href></Icon><scale>0.5</scale></IconStyle></Style>\n";
248 kmlFile <<
" <Style id=\"lineStyle\"><LineStyle><color>ff0000ff</color><width>2</width></LineStyle></Style>\n";
250 <<
" <Style id=\"lineStyleBlue\"><LineStyle><color>ffff0000</color><width>2</width></LineStyle></Style>\n";
253 void writePoint(std::ofstream& kmlFile,
const std::string& indent,
const std::string& name,
254 const std::string& styleUrl,
const std::string& coordinates,
const double objectAltitude,
255 const double referenceAltitude)
257 kmlFile << indent <<
"<Placemark>\n";
258 kmlFile << indent <<
" <name>" << name <<
"</name>\n";
259 kmlFile << indent <<
" <styleUrl>" << styleUrl <<
"</styleUrl>\n";
260 kmlFile << indent <<
" <Point>\n";
261 kmlFile << indent <<
" <coordinates>" << coordinates <<
"</coordinates>\n";
262 kmlFile << indent <<
" <altitudeMode>absolute</altitudeMode>\n";
263 if (objectAltitude > referenceAltitude)
265 kmlFile << indent <<
" <extrude>1</extrude>\n";
267 kmlFile << indent <<
" </Point>\n";
268 kmlFile << indent <<
"</Placemark>\n";
271 void writeAntennaBeamLine(std::ofstream& kmlFile,
const std::string& indent,
const std::string& name,
272 const std::string& style,
const std::string& startCoords,
const std::string& endCoords)
274 kmlFile << indent <<
"<Placemark>\n";
275 kmlFile << indent <<
" <name>" << name <<
"</name>\n";
276 kmlFile << indent <<
" <styleUrl>" << style <<
"</styleUrl>\n";
277 kmlFile << indent <<
" <LineString>\n";
278 kmlFile << indent <<
" <altitudeMode>absolute</altitudeMode>\n";
279 kmlFile << indent <<
" <tessellate>1</tessellate>\n";
280 kmlFile << indent <<
" <coordinates>" << startCoords <<
" " << endCoords <<
"</coordinates>\n";
281 kmlFile << indent <<
" </LineString>\n";
282 kmlFile << indent <<
"</Placemark>\n";
286 std::string getPlacemarkStyleForPlatform(
const std::vector<const radar::Object*>& objects)
288 bool has_receiver =
false;
289 bool has_transmitter =
false;
290 for (
const auto* obj : objects)
298 has_transmitter =
true;
308 return "#transmitter";
313 const radar::Radar* getPrimaryRadar(
const std::vector<const radar::Object*>& objects)
315 for (
const auto* obj : objects)
317 if (
const auto r =
dynamic_cast<const radar::Radar*
>(obj))
325 void generateIsotropicAntennaKml(std::ofstream& kmlFile,
const math::Vec3& position,
const ConverterFunc& converter,
326 const std::string& indent)
328 double lat, lon, alt_abs;
329 converter(position, lat, lon, alt_abs);
331 const auto circle_coordinates = generateCircleCoordinates(lat, lon, ISOTROPIC_PATTERN_RADIUS_KM);
333 kmlFile << indent <<
"<Placemark>\n";
334 kmlFile << indent <<
" <name>Isotropic pattern range</name>\n";
335 kmlFile << indent <<
" <styleUrl>#translucentPolygon</styleUrl>\n";
336 kmlFile << indent <<
" <Polygon>\n";
337 kmlFile << indent <<
" <extrude>1</extrude>\n";
338 kmlFile << indent <<
" <altitudeMode>absolute</altitudeMode>\n";
339 kmlFile << indent <<
" <outerBoundaryIs><LinearRing><coordinates>\n";
340 for (
const auto& [pt_lat, pt_lon] : circle_coordinates)
342 kmlFile << indent <<
" " << formatCoordinates(pt_lon, pt_lat, alt_abs) <<
"\n";
344 kmlFile << indent <<
" "
345 << formatCoordinates(circle_coordinates[0].second, circle_coordinates[0].first, alt_abs) <<
"\n";
346 kmlFile << indent <<
" </coordinates></LinearRing></outerBoundaryIs>\n";
347 kmlFile << indent <<
" </Polygon>\n";
348 kmlFile << indent <<
"</Placemark>\n";
351 void generateDirectionalAntennaKml(std::ofstream& kmlFile,
const radar::Platform* platform,
352 const ConverterFunc& converter,
const std::optional<double>& angle3DbDropDeg,
353 const std::string& indent)
356 double start_lat, start_lon, start_alt;
357 converter(first_wp_pos, start_lat, start_lon, start_alt);
358 const std::string start_coords_str = formatCoordinates(start_lon, start_lat, start_alt);
365 const double fers_azimuth_deg = initial_rotation.
azimuth * 180.0 /
PI;
366 double start_azimuth_deg_kml = 90.0 - fers_azimuth_deg;
368 start_azimuth_deg_kml = std::fmod(start_azimuth_deg_kml, 360.0);
369 if (start_azimuth_deg_kml < 0.0)
371 start_azimuth_deg_kml += 360.0;
376 const double horizontal_distance = DIRECTIONAL_ANTENNA_ARROW_LENGTH_M * std::cos(initial_rotation.
elevation);
377 const double delta_altitude = DIRECTIONAL_ANTENNA_ARROW_LENGTH_M * std::sin(initial_rotation.
elevation);
378 const double end_alt = start_alt + delta_altitude;
385 double dest_lat, dest_lon;
386 calculateDestinationCoordinate(start_lat, start_lon, start_azimuth_deg_kml, horizontal_distance, dest_lat,
388 const std::string end_coords_str = formatCoordinates(dest_lon, dest_lat, end_alt);
389 writeAntennaBeamLine(kmlFile, indent,
"Antenna Boresight",
"#lineStyle", start_coords_str, end_coords_str);
392 if (angle3DbDropDeg.has_value() && *angle3DbDropDeg >
EPSILON)
394 double side1_lat, side1_lon;
395 calculateDestinationCoordinate(start_lat, start_lon, start_azimuth_deg_kml - *angle3DbDropDeg,
396 horizontal_distance, side1_lat, side1_lon);
397 const std::string side1_coords_str = formatCoordinates(side1_lon, side1_lat, end_alt);
398 writeAntennaBeamLine(kmlFile, indent,
"Antenna 3dB Beamwidth",
"#lineStyleBlue", start_coords_str,
401 double side2_lat, side2_lon;
402 calculateDestinationCoordinate(start_lat, start_lon, start_azimuth_deg_kml + *angle3DbDropDeg,
403 horizontal_distance, side2_lat, side2_lon);
404 const std::string side2_coords_str = formatCoordinates(side2_lon, side2_lat, end_alt);
405 writeAntennaBeamLine(kmlFile, indent,
"Antenna 3dB Beamwidth",
"#lineStyleBlue", start_coords_str,
410 const double arrow_heading = std::fmod(start_azimuth_deg_kml + 180.0, 360.0);
411 kmlFile << indent <<
"<Placemark>\n";
412 kmlFile << indent <<
" <name>Antenna Arrow</name>\n";
413 kmlFile << indent <<
" <styleUrl>#arrowStyle</styleUrl>\n";
414 kmlFile << indent <<
" <Point><coordinates>" << end_coords_str
415 <<
"</coordinates><altitudeMode>absolute</altitudeMode></Point>\n";
416 kmlFile << indent <<
" <Style>\n";
417 kmlFile << indent <<
" <IconStyle><heading>" << arrow_heading <<
"</heading></IconStyle>\n";
418 kmlFile << indent <<
" </Style>\n";
419 kmlFile << indent <<
"</Placemark>\n";
423 const ConverterFunc& converter,
const std::string& indent)
434 generateIsotropicAntennaKml(kmlFile, initial_pos, converter, indent);
438 std::optional<double> angle_3db_drop_deg;
441 std::optional<double> wavelength;
446 wavelength =
params::c() / tx->getSignal()->getCarrier();
451 if (
const auto* attached_tx =
dynamic_cast<const radar::Transmitter*
>(rx->getAttached()))
453 if (attached_tx->getSignal())
455 wavelength =
params::c() / attached_tx->getSignal()->getCarrier();
461 if (
const auto* sinc_ant =
dynamic_cast<const antenna::Sinc*
>(ant))
463 angle_3db_drop_deg = find3DbDropAngle(sinc_ant->getAlpha(), sinc_ant->getBeta(), sinc_ant->getGamma());
467 angle_3db_drop_deg = findGaussian3DbDropAngle(gaussian_ant);
473 angle_3db_drop_deg = findParabolic3DbDropAngle(parabolic_ant, *wavelength);
480 angle_3db_drop_deg = findSquareHorn3DbDropAngle(squarehorn_ant, *wavelength);
489 "KML visualization for antenna '{}' ('{}') is symbolic. "
490 "Only the boresight direction is shown, as a 3dB beamwidth is not calculated from file-based "
495 generateDirectionalAntennaKml(kmlFile, platform, converter, angle_3db_drop_deg, indent);
499 void generateDynamicPathKml(std::ofstream& kmlFile,
const radar::Platform* platform,
const std::string& styleUrl,
500 const double refAlt,
const ConverterFunc& converter,
const std::string& indent)
503 const auto& waypoints = path->
getCoords();
505 double first_alt_abs;
508 converter(waypoints.front().pos, lat, lon, first_alt_abs);
511 kmlFile << indent <<
"<Placemark>\n";
512 kmlFile << indent <<
" <name>" << platform->
getName() <<
" Path</name>\n";
513 kmlFile << indent <<
" <styleUrl>" << styleUrl <<
"</styleUrl>\n";
514 kmlFile << indent <<
" <gx:Track>\n";
515 kmlFile << indent <<
" <altitudeMode>absolute</altitudeMode>\n";
516 if (first_alt_abs > refAlt)
518 kmlFile << indent <<
" <extrude>1</extrude>\n";
523 const double start_time = waypoints.front().t;
524 const double end_time = waypoints.back().t;
527 if (
const double time_diff = end_time - start_time; time_diff <= 0.0)
530 double p_lon, p_lat, p_alt_abs;
531 converter(p_pos, p_lat, p_lon, p_alt_abs);
532 kmlFile << indent <<
" <when>" << start_time <<
"</when>\n";
533 kmlFile << indent <<
" <gx:coord>" << p_lon <<
" " << p_lat <<
" " << p_alt_abs <<
"</gx:coord>\n";
537 const double time_step = time_diff / TRACK_NUM_DIVISIONS;
538 for (
int i = 0; i <= TRACK_NUM_DIVISIONS; ++i)
540 const double current_time = start_time + i * time_step;
542 double p_lon, p_lat, p_alt_abs;
543 converter(p_pos, p_lat, p_lon, p_alt_abs);
544 kmlFile << indent <<
" <when>" << current_time <<
"</when>\n";
545 kmlFile << indent <<
" <gx:coord>" << p_lon <<
" " << p_lat <<
" " << p_alt_abs <<
"</gx:coord>\n";
549 kmlFile << indent <<
" </gx:Track>\n";
550 kmlFile << indent <<
"</Placemark>\n";
553 void generateTrackEndpointsKml(std::ofstream& kmlFile,
const radar::Platform* platform,
const double refAlt,
554 const ConverterFunc& converter,
const std::string& indent)
562 const auto& [start_wp_pos, start_wp_t] = path->
getCoords().front();
563 const auto& [end_wp_pos, end_wp_t] = path->
getCoords().back();
565 double start_lat, start_lon, start_alt_abs;
566 converter(start_wp_pos, start_lat, start_lon, start_alt_abs);
567 const std::string start_coordinates = formatCoordinates(start_lon, start_lat, start_alt_abs);
569 double end_lat, end_lon, end_alt_abs;
570 converter(end_wp_pos, end_lat, end_lon, end_alt_abs);
571 const std::string end_coordinates = formatCoordinates(end_lon, end_lat, end_alt_abs);
573 writePoint(kmlFile, indent,
"Start: " + platform->
getName(),
"#target", start_coordinates, start_alt_abs,
575 writePoint(kmlFile, indent,
"End: " + platform->
getName(),
"#target", end_coordinates, end_alt_abs, refAlt);
578 void generateStaticPlacemarkKml(std::ofstream& kmlFile,
const radar::Platform* platform,
579 const std::string& styleUrl,
const double refAlt,
const ConverterFunc& converter,
580 const std::string& indent)
583 double lat, lon, alt_abs;
584 converter(first_wp_pos, lat, lon, alt_abs);
585 const std::string coordinates = formatCoordinates(lon, lat, alt_abs);
587 kmlFile << indent <<
"<Placemark>\n";
588 kmlFile << indent <<
" <name>" << platform->
getName() <<
"</name>\n";
589 kmlFile << indent <<
" <styleUrl>" << styleUrl <<
"</styleUrl>\n";
590 kmlFile << indent <<
" <LookAt>\n";
591 kmlFile << indent <<
" <longitude>" << lon <<
"</longitude>\n";
592 kmlFile << indent <<
" <latitude>" << lat <<
"</latitude>\n";
593 kmlFile << indent <<
" <altitude>" << alt_abs <<
"</altitude>\n";
594 kmlFile << indent <<
" <heading>-148.41</heading><tilt>40.55</tilt><range>500.65</range>\n";
595 kmlFile << indent <<
" </LookAt>\n";
596 kmlFile << indent <<
" <Point>\n";
597 kmlFile << indent <<
" <coordinates>" << coordinates <<
"</coordinates>\n";
598 kmlFile << indent <<
" <altitudeMode>absolute</altitudeMode>\n";
599 if (alt_abs > refAlt)
601 kmlFile << indent <<
" <extrude>1</extrude>\n";
603 kmlFile << indent <<
" </Point>\n";
604 kmlFile << indent <<
"</Placemark>\n";
607 void generatePlatformPathKml(std::ofstream& kmlFile,
const radar::Platform* platform,
const std::string& style,
608 const double refAlt,
const ConverterFunc& converter,
const std::string& indent)
611 const bool is_dynamic =
616 generateDynamicPathKml(kmlFile, platform, style, refAlt, converter, indent);
617 generateTrackEndpointsKml(kmlFile, platform, refAlt, converter, indent);
621 generateStaticPlacemarkKml(kmlFile, platform, style, refAlt, converter, indent);
625 void processPlatform(
const radar::Platform* platform,
const std::vector<const radar::Object*>& objects,
626 std::ofstream& kmlFile,
const ConverterFunc& converter,
const double referenceAltitude,
627 const std::string& indent)
634 kmlFile << indent <<
"<Folder>\n";
635 kmlFile << indent <<
" <name>" << platform->
getName() <<
"</name>\n";
637 const std::string inner_indent = indent +
" ";
638 const auto placemark_style = getPlacemarkStyleForPlatform(objects);
640 if (
const auto* radar_obj = getPrimaryRadar(objects))
642 generateAntennaKml(kmlFile, platform, radar_obj, converter, inner_indent);
645 generatePlatformPathKml(kmlFile, platform, placemark_style, referenceAltitude, converter, inner_indent);
647 kmlFile << indent <<
"</Folder>\n";
659 ConverterFunc converter;
660 double reference_latitude, reference_longitude, reference_altitude;
669 auto proj = std::make_shared<GeographicLib::LocalCartesian>(reference_latitude, reference_longitude,
671 converter = [proj](
const math::Vec3& pos,
double& lat,
double& lon,
double& alt)
672 { proj->Reverse(pos.
x, pos.
y, pos.
z, lat, lon, alt); };
679 converter = [zone, northp](
const math::Vec3& pos,
double& lat,
double& lon,
double& alt)
682 GeographicLib::UTMUPS::Reverse(zone, northp, pos.x, pos.y, lat, lon, gamma, k);
689 const auto& earth = GeographicLib::Geocentric::WGS84();
690 converter = [&earth](
const math::Vec3& pos,
double& lat,
double& lon,
double& alt)
691 { earth.Reverse(pos.
x, pos.
y, pos.
z, lat, lon, alt); };
696 map<const radar::Platform*, vector<const radar::Object*>> platform_to_objects;
697 const auto group_objects = [&](
const auto& objectCollection)
699 for (
const auto& obj_ptr : objectCollection)
701 platform_to_objects[obj_ptr->getPlatform()].push_back(obj_ptr.get());
711 bool ref_set =
false;
712 for (
const auto& platform : platform_to_objects | views::keys)
717 converter(first_pos, reference_latitude, reference_longitude, reference_altitude);
730 std::ofstream kml_file(outputKmlPath.c_str());
731 if (!kml_file.is_open())
737 writeKmlHeaderAndStyles(kml_file);
739 kml_file <<
" <Folder>\n";
740 kml_file <<
" <name>Reference Coordinate</name>\n";
741 kml_file <<
" <description>Placemarks for various elements in the FERSXML file. All Placemarks are "
742 "situated relative to this reference point.</description>\n";
743 kml_file <<
" <LookAt>\n";
744 kml_file <<
" <longitude>" << reference_longitude <<
"</longitude>\n";
745 kml_file <<
" <latitude>" << reference_latitude <<
"</latitude>\n";
746 kml_file <<
" <altitude>" << reference_altitude <<
"</altitude>\n";
747 kml_file <<
" <heading>-148.41</heading><tilt>40.55</tilt><range>10000</range>\n";
748 kml_file <<
" </LookAt>\n";
750 const std::string platform_indent =
" ";
751 for (
const auto& [platform, objects] : platform_to_objects)
753 processPlatform(platform, objects, kml_file, converter, reference_altitude, platform_indent);
756 kml_file <<
" </Folder>\n";
757 kml_file <<
"</Document>\n";
758 kml_file <<
"</kml>\n";
761 catch (
const std::exception& e)
Header file defining various types of antennas and their gain patterns.
Abstract base class representing an antenna.
std::string getName() const noexcept
Retrieves the name of the antenna.
Represents a Gaussian-shaped antenna gain pattern.
RealType getAzimuthScale() const noexcept
Gets the azimuth scale factor.
Represents an antenna whose gain pattern is loaded from a HDF5 file.
Represents an isotropic antenna with uniform gain in all directions.
Represents a parabolic reflector antenna.
RealType getDiameter() const noexcept
Gets the diameter of the parabolic reflector.
Represents a sinc function-based antenna gain pattern.
Represents a square horn antenna.
RealType getDimension() const noexcept
Gets the dimension of the square horn.
Represents an antenna whose gain pattern is defined by an XML file.
The World class manages the simulator environment.
const std::vector< std::unique_ptr< radar::Target > > & getTargets() const noexcept
Retrieves the list of radar targets.
const std::vector< std::unique_ptr< radar::Transmitter > > & getTransmitters() const noexcept
Retrieves the list of radar transmitters.
const std::vector< std::unique_ptr< radar::Receiver > > & getReceivers() const noexcept
Retrieves the list of radar receivers.
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.
const std::vector< Coord > & getCoords() const noexcept
Gets the list of coordinates in the path.
InterpType getType() const noexcept
Retrieves the current interpolation type of the path.
SVec3 getPosition(RealType t) const
Gets the rotational position at a given time.
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.
Represents a radar system on a platform.
Manages radar signal reception and response processing.
Represents a radar transmitter system.
static bool generateKml(const core::World &world, const std::string &outputKmlPath)
Generates a KML file from a pre-built simulation world.
Global configuration file for the project.
constexpr RealType EPSILON
Machine epsilon for real numbers.
constexpr RealType PI
Mathematical constant π (pi).
Coordinate and rotation structure operations.
KML file generator for geographical visualization of FERS scenarios.
Header file for the logging system.
@ WARNING
Warning level for potentially harmful situations.
@ INFO
Info level for informational messages.
@ ERROR
Error level for error events.
RealType startTime() noexcept
Get the start time for the simulation.
double originLongitude() noexcept
@ UTM
Universal Transverse Mercator.
@ ENU
East-North-Up local tangent plane (default)
@ ECEF
Earth-Centered, Earth-Fixed.
CoordinateFrame coordinateFrame() noexcept
double originLatitude() noexcept
bool utmNorthHemisphere() noexcept
RealType c() noexcept
Get the speed of light.
double originAltitude() noexcept
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 Radar class and associated functionality.
Classes for handling radar waveforms and signals.
Radar Receiver class for managing signal reception and response handling.
std::string simulation_name
The name of the simulation, from the XML.
Defines classes for radar targets and their Radar Cross-Section (RCS) models.
Header file for the Transmitter class in the radar namespace.
Header file for the World class in the simulator.