### Example Usage of Bearing Macro (Rust) Source: https://docs.rs/sguaba/latest/sguaba/macro.bearing Demonstrates how to use the `bearing` macro to create `Bearing` instances with different angle units and coordinate systems. It shows examples for both explicit and inferred coordinate systems, as well as usage with radians. ```rust use sguaba::{bearing, system}; system!(struct PlaneFrd using FRD); // Using degrees with explicit coordinate system let bearing1 = bearing!(azimuth = deg(20.0), elevation = deg(10.0); in PlaneFrd); // Using degrees with inferred coordinate system (requires type annotation) let bearing2: sguaba::Bearing = bearing!(azimuth = deg(20.0), elevation = deg(10.0)); // Using radians let bearing3 = bearing!(azimuth = rad(0.349), elevation = rad(0.175); in PlaneFrd); ``` -------------------------------- ### WGS84 Macro Usage Examples (Rust) Source: https://docs.rs/sguaba/latest/sguaba/macro.wgs84 Demonstrates how to use the `wgs84` macro with different unit combinations for latitude, longitude, and altitude. These examples showcase the flexibility in specifying coordinates. ```rust use sguaba::wgs84; // Using degrees and meters let location1 = wgs84!(latitude = deg(35.3619), longitude = deg(138.7280), altitude = m(2294.0)); // Using degrees and kilometers let location2 = wgs84!(latitude = deg(35.3619), longitude = deg(138.7280), altitude = km(2.294)); // Using radians and meters let location3 = wgs84!(latitude = rad(0.617), longitude = rad(2.413), altitude = m(2294.0)); ``` -------------------------------- ### Example: Building Orientation with Tait-Bryan Angles Source: https://docs.rs/sguaba/latest/sguaba/engineering/struct.Orientation_search= Demonstrates the usage of the `tait_bryan_builder` to construct an `Orientation` with specific yaw, pitch, and roll values. It shows successful compilation with the correct angle order and provides examples of incorrect angle ordering that would fail to compile. ```rust use sguaba::{system, engineering::Orientation}; use uom::si::{f64::Angle, angle::degree}; system!(struct PlaneNed using NED); let orientation = Orientation::::tait_bryan_builder() .yaw(Angle::new::(90.0)) .pitch(Angle::new::(45.0)) .roll(Angle::new::(5.0)) .build(); // Example of incorrect order (fails to compile): // let orientation = Orientation::::tait_bryan_builder() // .yaw(Angle::new::(90.0)) // .roll(Angle::new::(5.0)) // .pitch(Angle::new::(45.0)) // .build(); // Example of skipping required angle (fails to compile): // let orientation = Orientation::::tait_bryan_builder() // .pitch(Angle::new::(45.0)) // .yaw(Angle::new::(90.0)) // .roll(Angle::new::(5.0)) // .build(); ``` -------------------------------- ### Access Pose Components (Rust) Source: https://docs.rs/sguaba/latest/sguaba/engineering/struct.Pose_search=u32+-%3E+bool Demonstrates how to retrieve the position and orientation from a Pose object. Also shows how to get the distance from the origin. ```rust // Assuming 'pose' is an instance of Pose // let position = pose.position(); // let orientation = pose.orientation(); // let distance = pose.distance_from_origin(); // These methods return the Coordinate, Orientation, and Length respectively. ``` -------------------------------- ### bearing Macro API Source: https://docs.rs/sguaba/latest/sguaba/macro.bearing_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Documentation for the `bearing` macro, including supported units, usage examples, and compile-time validation rules. ```APIDOC ## Macro bearing ### Description Constructs a `Bearing` with compile-time validated angles using unit suffixes. This macro provides a safe way to construct bearings with compile-time known angles, eliminating the need for `.expect()` calls on the elevation validation. ### Supported Units * `deg` - degrees * `rad` - radians ### Syntax Variants 1. **Degrees with explicit coordinate system:** ```rust macro_rules! bearing { (azimuth = deg($az:expr), elevation = deg($el:expr) $(,)?) => { ... }; } ``` 2. **Radians with explicit coordinate system:** ```rust macro_rules! bearing { (azimuth = rad($az:expr), elevation = rad($el:expr) $(,)?) => { ... }; } ``` 3. **Degrees with specified coordinate system type:** ```rust macro_rules! bearing { (azimuth = deg($az:expr), elevation = deg($el:expr); in $system:ty) => { ... }; } ``` 4. **Radians with specified coordinate system type:** ```rust macro_rules! bearing { (azimuth = rad($az:expr), elevation = rad($el:expr); in $system:ty) => { ... }; } ``` ### Examples ```rust use sguaba::{bearing, system}; system!(struct PlaneFrd using FRD); // Using degrees with explicit coordinate system let bearing1 = bearing!(azimuth = deg(20.0), elevation = deg(10.0); in PlaneFrd); // Using degrees with inferred coordinate system (requires type annotation) let bearing2: sguaba::Bearing = bearing!(azimuth = deg(20.0), elevation = deg(10.0)); // Using radians let bearing3 = bearing!(azimuth = rad(0.349), elevation = rad(0.175); in PlaneFrd); ``` ### Compile-time validation The following examples demonstrate elevation values that are out of the valid range (-90° to 90° or -π/2 to π/2 radians) and should cause a compilation error: * **Elevation > 90° should fail:** ```rust // let bearing = bearing!(azimuth = deg(0.0), elevation = deg(91.0); in PlaneFrd); ``` * **Elevation < -90° should fail:** ```rust // let bearing = bearing!(azimuth = deg(0.0), elevation = deg(-91.0); in PlaneFrd); ``` * **Elevation > π/2 radians should fail:** ```rust // let bearing = bearing!(azimuth = rad(0.0), elevation = rad(1.58); in PlaneFrd); ``` * **Elevation < -π/2 radians should fail:** ```rust // let bearing = bearing!(azimuth = rad(0.0), elevation = rad(-1.58); in PlaneFrd); ``` ``` -------------------------------- ### Rotation Multiplication Example in Rust Source: https://docs.rs/sguaba/latest/sguaba/math/struct.Rotation_search=u32+-%3E+bool Demonstrates how `Rotation` types can be chained with other transformations using the `Mul` trait (`*`). It highlights the importance of operand order for correct transformation direction. ```rust let _: Coordinate = Rotation * Coordinate; ``` -------------------------------- ### Get Orientation at Origin - Sguaba Source: https://docs.rs/sguaba/latest/sguaba/struct.Vector The `orientation_at_origin` method calculates the orientation of a vector assuming it starts at the origin of the `In` coordinate system. The roll must be provided as an argument, as vectors themselves do not contain roll information. It returns `None` for zero-length vectors and a zero yaw for vectors aligned with the Z axis. ```Rust pub fn orientation_at_origin( &self, roll: impl Into, ) -> Option> ``` -------------------------------- ### Bearing Construction Example (Rust) Source: https://docs.rs/sguaba/latest/src/sguaba/directions.rs Demonstrates two equivalent ways to construct a Bearing instance for a PlaneFrd coordinate system. One uses the builder pattern, and the other uses a direct build function with Components. Both methods allow setting azimuth and elevation angles. ```rust use sguaba::{Bearing, system}; use uom::si::f64::Angle; use uom::si::angle::degree; system!(struct PlaneFrd using FRD); Bearing::::builder() // clockwise from forward .azimuth(Angle::new::(20.)) // upwards from straight-ahead .elevation(Angle::new::(10.)) .expect("elevation is in [-90º, 90º]") .build(); ``` ```rust use sguaba::{Bearing, system, builder::bearing::Components}; use uom::si::f64::Angle; use uom::si::angle::degree; system!(struct PlaneFrd using FRD); Bearing::::build(Components { // clockwise from forward azimuth: Angle::new::(20.), // upwards from straight-ahead elevation: Angle::new::(10.), }).expect("elevation is in [-90º, 90º]"); ``` -------------------------------- ### Orientation Transformation with map_as_zero_in in Rust Source: https://docs.rs/sguaba/latest/sguaba/engineering/struct.Orientation_search=std%3A%3Avec Demonstrates the use of `map_as_zero_in` to transform an orientation from one coordinate system to another. It constructs a rotation to align the orientation with zero and then inverts to transform coordinates. This is useful for getting absolute bearings or converting between coordinate systems. The example uses the sguaba and uom crates. ```Rust ```rust use approx::assert_relative_eq; use sguaba::{system, Bearing, Coordinate, engineering::Orientation}; use uom::si::f64::{Angle, Length}; use uom::si::{angle::degree, length::meter}; system!(struct PlaneNed using NED); system!(struct PlaneFrd using FRD); // plane orientation in NED is yaw 90° (east), pitch 45° (climbing), roll 5° (tilted right) let orientation = Orientation::::from_tait_bryan_angles( Angle::new::(90.), Angle::new::(45.), Angle::new::(5.), ); // plane observes something below it to its right (45° azimuth, -20° elevation), // at a range of 100m. let observation = Coordinate::::from_bearing( Bearing::builder() .azimuth(Angle::new::(45.)) .elevation(Angle::new::(-20.)).expect("elevation is in-range") .build(), Length::new::(100.) ); // to get the absolute bearing of the observation (ie, with respect to North and horizon), // we can use map_as_zero_in to obtain a transformation from PlaneNed to PlaneFrd, and // then invert it to go from PlaneFrd to PlaneNed: let plane_frd_to_ned = unsafe { orientation.map_as_zero_in::() }.inverse(); // applying that transform gives us the translated coordinate let observation_in_ned = plane_frd_to_ned.transform(observation); ``` ``` -------------------------------- ### Rust Example of Vector Initialization Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates the usage of the `vector!` macro to initialize velocity and acceleration vectors in the `PlaneFrd` coordinate system. It shows how to define the components (f, r, d) and specify the coordinate system. ```rust let velocity = vector!( f = Velocity::new::(5.0), r = Velocity::new::(0.0), d = Velocity::new::(0.0); in PlaneFrd ); // Creates Vector / AccelerationVector (acceleration vector) let acceleration = vector!( f = Acceleration::new::(2.0), r = Acceleration::new::(0.0), d = Acceleration::new::(0.0); in PlaneFrd ); ``` -------------------------------- ### Range Checking for Bounded Angles in Rust Source: https://docs.rs/sguaba/latest/src/sguaba/util.rs_search=std%3A%3Avec Implements a method to check if an angle falls within a specified range [start, stop]. It handles both normal ranges (start <= stop) and wrap-around ranges (stop < start). This functionality is only available when the `test` or `approx` features are enabled. ```rust use uom::si::angle::radian; use uom::si::f64::Angle; impl BoundedAngle { /// Check if the angle is in [start, stop] /// Based on #[cfg(test)] pub(crate) fn is_in_range(&self, start: &BoundedAngle, stop: &BoundedAngle) -> bool { let is_between_angles = (self.angle <= stop.angle) && (start.angle <= self.angle); // Easy case: start is smaller than stop, then the angle needs to be between them. // If start == stop the angle needs to be in there as well. if start.angle <= stop.angle { is_between_angles // Hard case: The stop is "around" the 360 degrees and thus smaller than the start. // Now the angle must NOT be between them. } else { !is_between_angles } } } ``` -------------------------------- ### Constructing and Chaining Transforms (Rust Example) Source: https://docs.rs/sguaba/latest/src/sguaba/math.rs_search=u32+-%3E+bool Demonstrates constructing a RigidBodyTransform from WGS84 coordinates and chaining it with another transform. This involves converting from ECEF to NED and then to PlaneFrd. Safety assertions are crucial when dealing with these transformations. ```Rust /// system!(struct PlaneNed using NED); /// /// // we can construct a transform from ECEF to PlaneNed /// // (we can construct the ECEF from a WGS84 lat/lon) /// let location = Wgs84::builder() /// .latitude(Angle::new::(0.)).expect("latitude is in-range") /// .longitude(Angle::new::(10.)) /// .altitude(Length::new::(0.)) /// .build(); /// /// // SAFETY: we're claiming that `location` is the location of `PlaneNed`'s origin. /// let ecef_to_ned = unsafe { RigidBodyTransform::ecef_to_ned_at(&location) }; /// /// // we can also construct a (rotation) transform from PlaneNed to PlaneFrd /// // assuming we know what direction the plane is facing. /// // SAFETY: we're claiming that these angles are the orientation of the plane in NED. /// let ned_to_frd = unsafe { /// Rotation::::from_tait_bryan_angles( /// Angle::new::(0.), /// Angle::new::(45.), /// Angle::new::(23.), /// ) /// }; /// /// // and we can chain the two to give us a single transform that goes /// // from ECEF to PlaneFrd in a single computation. /// let ecef_to_frd = ecef_to_ned.and_then(ned_to_frd); ``` -------------------------------- ### Rust Search Examples: std::vec, u32 -> bool, Option Source: https://docs.rs/sguaba/latest/sguaba/systems/struct.FrdComponents_search= Provides examples of search queries commonly used within the sguaba project. These examples illustrate searching for standard library types like `std::vec`, function types such as `u32 -> bool`, and generic types like `Option` with functional transformations. ```text Example searches: * std::vec * u32 -> bool * Option, (T -> U) -> Option ``` -------------------------------- ### Initialize Vector using Macro Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search= Demonstrates initializing a Vector with specified front, right, and down components using a macro. This is a concise way to create vector instances in Rust. ```rust let v = vector!(f = m(1.0), r = m(2.0), d = m(3.0); in TestFrd); assert_eq!(v.frd_front(), m(1.0)); assert_eq!(v.frd_right(), m(2.0)); assert_eq!(v.frd_down(), m(3.0)); ``` -------------------------------- ### Create Acceleration Vector in PlaneFrd and PlaneNed Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search= Illustrates the creation of acceleration vectors. The first example uses `PlaneFrd` with components for speed-up and climb (negative down). The second example uses `PlaneNed` and defines acceleration in terms of standard gravity. ```rust use sguaba::{system, vector, Vector, vector::AccelerationVector}; use uom::si::f64::Acceleration; use uom::si::acceleration::meter_per_second_squared; system!(struct PlaneFrd using FRD); system!(struct PlaneNed using NED); // Commanded acceleration (climb has negative d in FRD) let acceleration = vector!( f = Acceleration::new::(2.0), // speed up r = Acceleration::new::(0.0), d = Acceleration::new::(-1.0); // climb in PlaneFrd ); // Can use other acceleration units, such as standard gravity let gravity = vector!( n = Acceleration::new::(0.0), e = Acceleration::new::(0.0), d = Acceleration::new::(1.) in PlaneNed ); ``` -------------------------------- ### Rust Bearing Builder Methods Source: https://docs.rs/sguaba/latest/src/sguaba/directions.rs_search= Demonstrates how to construct a `Bearing` object using the builder pattern. The `azimuth` method sets the azimuthal angle, and the `elevation` method sets the elevation angle, with validation for the elevation range. Dependencies include `Bearing`, `Angle`, `BoundedAngle`, and `PhantomData`. ```rust impl Builder { /// Sets the azimuthal angle of the [`Bearing`]-to-be. pub fn azimuth(mut self, angle: impl Into) -> Builder { self.under_construction.azimuth = angle.into(); Builder { under_construction: self.under_construction, has: (PhantomData::, self.has.1), } } /// Sets the elevation angle of the [`Bearing`]-to-be. /// /// The elevation must be in [-90°,90°] % 360°. If it is not, this function returns `None`. pub fn elevation(mut self, angle: impl Into) -> Option> { let elevation = angle.into(); let elevation_signed = BoundedAngle::new(elevation).to_signed_range(); if !(-std::f64::consts::FRAC_PI_2..=std::f64::consts::FRAC_PI_2).contains(&elevation_signed) { None } else { self.under_construction.elevation = elevation; Some(Builder { under_construction: self.under_construction, has: (self.has.0, PhantomData::), }) } } } ``` -------------------------------- ### Rust: Construct Bearing using Builder Source: https://docs.rs/sguaba/latest/sguaba/struct.Bearing_search= Demonstrates how to create a Bearing instance using the builder pattern in Rust. This method provides a step-by-step approach to setting azimuth and elevation, with explicit error handling for invalid elevation values. It requires the `sguaba` and `uom` crates. ```rust use sguaba::{Bearing, system}; use uom::si::f64::Angle; use uom::si::angle::degree; system!(struct PlaneFrd using FRD); Bearing::::builder() // clockwise from forward .azimuth(Angle::new::(20.)) // upwards from straight-ahead .elevation(Angle::new::(10.)) .expect("elevation is in [-90º, 90º]") .build(); ``` -------------------------------- ### Get ENU Components and Axes (Rust) Source: https://docs.rs/sguaba/latest/sguaba/vector/type.LengthVector_search=std%3A%3Avec Provides methods to retrieve the East, North, and Up components of a vector in an ENU (East-North-Up) coordinate system. Also provides static methods to get the unit vectors representing the East, North, and Up axes. ```rust pub fn enu_east(&self) -> Length pub fn enu_north(&self) -> Length pub fn enu_up(&self) -> Length pub fn enu_east_axis() -> Vector pub fn enu_north_axis() -> Vector pub fn enu_up_axis() -> Vector ``` -------------------------------- ### Initialize Vector using Builder Pattern Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search= Shows how to build a Vector instance by chaining method calls. This pattern is useful for complex object creation, providing a fluent interface. ```rust let v = Vector::::builder() .frd_front(m(1.0)) .frd_right(m(2.0)) .frd_down(m(3.0)) .build(); assert_eq!(v.frd_front(), m(1.0)); assert_eq!(v.frd_right(), m(2.0)); assert_eq!(v.frd_down(), m(3.0)); ``` -------------------------------- ### Initialize Vector using vector! macro Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Illustrates the usage of the `vector!` macro for concise vector initialization. This macro allows direct assignment of component values and specifies the coordinate system. ```rust let v = vector!(f = m(1.0), r = m(2.0), d = m(3.0); in TestFrd); assert_eq!(v.frd_front(), m(1.0)); assert_eq!(v.frd_right(), m(2.0)); assert_eq!(v.frd_down(), m(3.0)); ``` ```rust let v = vector!(f = m(3.0), r = m(4.0), d = m(0.0); in TestFrd); assert_eq!(v.magnitude(), m(5.0)); ``` ```rust let v = vector!(n = m(1.0), e = m(2.0), d = m(3.0); in TestNed); assert_eq!(v.ned_north(), m(1.0)); assert_eq!(v.ned_east(), m(2.0)); assert_eq!(v.ned_down(), m(3.0)); ``` -------------------------------- ### Get FRD Components and Axes (Rust) Source: https://docs.rs/sguaba/latest/sguaba/vector/type.LengthVector_search=std%3A%3Avec Provides methods to retrieve the Front, Right, and Down components of a vector in a FRD (Front-Right-Down) coordinate system. Also provides static methods to get the unit vectors representing the Front, Right, and Down axes. ```rust pub fn frd_front(&self) -> Length pub fn frd_right(&self) -> Length pub fn frd_down(&self) -> Length pub fn frd_front_axis() -> Vector pub fn frd_right_axis() -> Vector pub fn frd_down_axis() -> Vector ``` -------------------------------- ### Construct Bearing using Components Source: https://docs.rs/sguaba/latest/sguaba/struct.Bearing_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Illustrates constructing a Bearing by providing its components (azimuth and elevation) directly to the `build` function. This is an alternative to using the builder pattern. ```rust use sguaba::{Bearing, system, builder::bearing::Components}; use uom::si::f64::Angle; use uom::si::angle::degree; system!(struct PlaneFrd using FRD); Bearing::::build(Components { // clockwise from forward azimuth: Angle::new::(20.), // upwards from straight-ahead elevation: Angle::new::(10.), }).expect("elevation is in [-90º, 90º]"); ``` -------------------------------- ### Get NED Components and Axes (Rust) Source: https://docs.rs/sguaba/latest/sguaba/vector/type.LengthVector_search=std%3A%3Avec Provides methods to retrieve the North, East, and Down components of a vector in a NED (North-East-Down) coordinate system. Also provides static methods to get the unit vectors representing the North, East, and Down axes. ```rust pub fn ned_north(&self) -> Length pub fn ned_east(&self) -> Length pub fn ned_down(&self) -> Length pub fn ned_north_axis() -> Vector pub fn ned_east_axis() -> Vector pub fn ned_down_axis() -> Vector ``` -------------------------------- ### Get XYZ Components and Axes (Rust) Source: https://docs.rs/sguaba/latest/sguaba/vector/type.LengthVector_search=std%3A%3Avec Provides methods to retrieve the X, Y, and Z components of a vector in a right-handed XYZ-like coordinate system. Also provides static methods to get the unit vectors representing the X, Y, and Z axes. ```rust pub fn x(&self) -> Length pub fn y(&self) -> Length pub fn z(&self) -> Length pub fn x_axis() -> Vector pub fn y_axis() -> Vector pub fn z_axis() -> Vector ``` -------------------------------- ### Vector Construction with Builder Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Illustrates how to use the `Vector::builder()` method for constructing vectors with a fluent interface. ```APIDOC ## Vector Construction with Builder ### Description The `Vector::builder()` method provides a fluent interface for constructing `Vector` objects, offering a more explicit way to define components and their order, reducing the risk of argument confusion. ### Method `Vector::builder()` ### Endpoint N/A (Method call) ### Parameters Methods available on the `Builder` object allow setting each component (e.g., `north`, `east`, `down`, `front`, `right`, `up`, `x`, `y`, `z`) and finally calling `.build()` to construct the `Vector`. ### Request Example ```rust // Example using the builder for a NED vector let velocity = Vector::::builder() .north(Velocity::new::(5.0)) .east(Velocity::new::(0.0)) .down(Velocity::new::(0.0)) .build(); // Example using the builder for a FRD vector let acceleration = Vector::::builder() .front(Acceleration::new::(2.0)) .right(Acceleration::new::(0.0)) .down(Acceleration::new::(0.0)) .build(); ``` ### Response N/A (Method call returns a `Vector` object) ``` -------------------------------- ### Coordinate Transformation Example: Plane FRD to WGS84 Source: https://docs.rs/sguaba/latest/src/sguaba/lib.rs Demonstrates converting a coordinate observed in a plane's Forward-Right-Down (FRD) frame of reference to the global World Geodetic System 1984 (WGS84) frame. This example highlights the use of custom system definitions and the conversion process between local and global coordinate systems. ```rust # use sguaba::{system, Bearing, Coordinate, engineering::Orientation, systems::Wgs84}; use uom::si::f64::{Angle, Length}; use uom::si::{angle::degree, length::meter}; // FRD and NED systems are "local" coordinate systems, meaning a given coordinate in the FRD of // one plane will have a completely different coordinate if it were to be expressed in the FRD // of another. so, to guard against accidentally getting them mixed up, we construct a new type // for this plane's FRD and NED: // the pilot observes things in FRD of the plane system!(struct PlaneFrd using FRD); // the pilot's instruments indicate the plane's orientation in NED system!(struct PlaneNed using NED); // what the pilot saw: let observation = Coordinate::::from_bearing( Bearing::builder() // clockwise from forward .azimuth(Angle::new::(20.)) // upwards from straight-ahead .elevation(Angle::new::(10.)).expect("elevation is in [-90, 90]") .build(), Length::new::(400.), // at this range ); // where the plane was at the time (eg, from GPS): let wgs84 = Wgs84::builder() .latitude(Angle::new::(12.)).expect("latitude is in [-90, 90]") .longitude(Angle::new::(30.)) .altitude(Length::new::(1000.)) .build(); // where the plane was facing at the time (eg, from instrument panel); // let plane_orientation = Orientation::::from_parts( // Angle::new::(180.0), // roll // Angle::new::(15.0), // pitch // Angle::new::(90.0) // yaw // ); // to convert, we need to know the plane's position and orientation in the global frame // let transform = Transform::new(wgs84, plane_orientation); // let global_coordinate = transform.apply(observation); ``` -------------------------------- ### Define Custom Plane FRD and NED Coordinate Systems Source: https://docs.rs/sguaba/latest/src/sguaba/lib.rs_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E This example demonstrates how to define custom coordinate system types for a plane's Forward-Right-Down (FRD) and North-East-Down (NED) frames. This is crucial for type safety, ensuring that coordinates from one plane's frame are not accidentally mixed with another's or with Earth-bound frames. ```rust # use sguaba::{system, Bearing, Coordinate, engineering::Orientation, systems::Wgs84}; use uom::si::f64::{Angle, Length}; use uom::si::{angle::degree, length::meter}; // FRD and NED systems are "local" coordinate systems, meaning a given coordinate in the FRD of // one plane will have a completely different coordinate if it were to be expressed in the FRD // of another. so, to guard against accidentally getting them mixed up, we construct a new type // for this plane's FRD and NED: // the pilot observes things in FRD of the plane system!(struct PlaneFrd using FRD); // the pilot's instruments indicate the plane's orientation in NED system!(struct PlaneNed using NED); // what the pilot saw: let observation = Coordinate::::from_bearing( Bearing::builder() // clockwise from forward .azimuth(Angle::new::(20.)) // upwards from straight-ahead .elevation(Angle::new::(10.)).expect("elevation is in [-90, 90]") .build(), Length::new::(400.), // at this range ); // where the plane was at the time (eg, from GPS): let wgs84 = Wgs84::builder() .latitude(Angle::new::(12.)).expect("latitude is in [-90, 90]") .longitude(Angle::new::(30.)) .altitude(Length::new::(1000.)) .build(); // where the plane was facing at the time (eg, from instrument panel); ``` -------------------------------- ### Vector Orientation at Origin Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search=u32+-%3E+bool Computes the orientation of the vector as if it starts at the origin. ```APIDOC ## POST /vectors/orientation_at_origin ### Description Computes the orientation (yaw, pitch, roll) of the vector as if it starts at the origin. The desired roll must be provided. Returns `None` if the vector has zero length. ### Method POST ### Endpoint `/vectors/orientation_at_origin` ### Parameters #### Request Body - **vector** (object) - Required - The vector for which to compute orientation. - **x** (number) - Required - The x-component of the vector. - **y** (number) - Required - The y-component of the vector. - **z** (number) - Required - The z-component of the vector. - **roll** (string) - Required - The desired roll angle (e.g., "45 degrees", "PI/4 radians"). ### Request Example ```json { "vector": { "x": 1.0, "y": 1.0, "z": 1.0 }, "roll": "0 degrees" } ``` ### Response #### Success Response (200) - **orientation** (object) - The computed orientation. - **yaw** (object) - The yaw component. - **degrees** (number) - Yaw in degrees. - **radians** (number) - Yaw in radians. - **pitch** (object) - The pitch component. - **degrees** (number) - Pitch in degrees. - **radians** (number) - Pitch in radians. - **roll** (object) - The roll component. - **degrees** (number) - Roll in degrees. - **radians** (number) - Roll in radians. #### Response Example ```json { "orientation": { "yaw": { "degrees": 45.0, "radians": 0.785398 }, "pitch": { "degrees": 35.264, "radians": 0.615479 }, "roll": { "degrees": 0.0, "radians": 0.0 } } } ``` ``` -------------------------------- ### Initialize Vector using Components Struct Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search= Illustrates creating a Vector by passing a struct containing its components (front, right, down). This is suitable when components are already grouped in a structured format. ```rust use crate::systems::FrdComponents; let v = Vector::::build(FrdComponents { front: m(1.0), right: m(2.0), down: m(3.0), }); assert_eq!(v.frd_front(), m(1.0)); assert_eq!(v.frd_right(), m(2.0)); assert_eq!(v.frd_down(), m(3.0)); ``` -------------------------------- ### Coordinate System Transformations Example (Rust) Source: https://docs.rs/sguaba/latest/src/sguaba/engineering.rs_search= Demonstrates a common use case in geospatial and robotics: determining an object's world (WGS84) coordinates from local observations. This snippet shows the creation of coordinate systems, transformations between ECEF and NED, and the application of platform orientation to achieve the final transformation from world to the platform's local FRD coordinate system. ```rust // Objective: // Platform observes point in azimuth, elevation, range of its body coordinate system (FRD). // Where is it in WGS84? let observation = Coordinate::::from_bearing( Bearing::build(BearingComponents { azimuth: d(20.), elevation: d(10.), }) .expect("elevation is in-range"), m(400.), ); // The pilot also knows where the plane is located given by a GPS device. let wgs84 = Wgs84::build(Wgs84Components { latitude: d(12.), longitude: d(30.), altitude: m(1000.), }) .expect("latitude is in-range"); // The API allows two compatible paths. // One for thinking about transformations between coordinate systems. // One for thinking about objects in a coordinate system. Their pose or orientation. // The pilot can read the instrument of the planes orientation relative to the local NED. // The instruments give the orientation as yaw, pitch, roll // The pilot knows that these are the tait-bryan angles we expect to get. // Here the plane is pitched 45 degrees upwards. let orientation_in_ned = Orientation::::tait_bryan_builder() .yaw(d(0.)) .pitch(d(45.)) .roll(d(0.)) .build(); // And the pilot knows from pilot school, that the pose NED of the plane is defined by the WGS84 coordinate. // Also, the pilot knows that ECEF is a cartesian representation of WGS84. let ecef_to_plane_ned = unsafe { RigidBodyTransform::ecef_to_ned_at(&wgs84) }; // Option 1: Transformation in world. // Now the pilot also needs to account for the planes orientation in NED. // This is done by creating a rotation transform let plane_ned_to_plane_frd = unsafe { orientation_in_ned.map_as_zero_in::() }; // Chaining them together results in the transformation from ECEF to FRD let world_to_plane_frd = ecef_to_plane_ned.and_then(plane_ned_to_plane_frd); // Now the pilot can convert the observed point to the world ``` -------------------------------- ### Vector Bearing Calculation Source: https://docs.rs/sguaba/latest/sguaba/vector/type.LengthVector_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Computes the bearing of the vector as if it starts at the origin. ```APIDOC ## pub fn bearing_at_origin(&self) -> Option> ### Description Computes the bearing of the vector as if the vector starts at the origin of `In`. Returns `None` if the vector has zero length, as the azimuth is then ill-defined. Returns an azimuth of zero if the vector points directly along the Z axis. ### Method `bearing_at_origin` ### Response #### Success Response (Option>) - **Option>**: An optional Bearing object. `None` if the vector has zero length, otherwise `Some(Bearing)`. ``` -------------------------------- ### Vector Orientation Calculation Source: https://docs.rs/sguaba/latest/sguaba/vector/type.LengthVector_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Computes the orientation of the vector as if it starts at the origin, with a specified roll. ```APIDOC ## pub fn orientation_at_origin( &self, roll: impl Into, ) -> Option> ### Description Computes the orientation of the vector as if the vector starts at the origin of `In`. Since vectors do not include roll information, the desired roll must be passed in. It’s worth reading the documentation on `Orientation` for a reminder about the meaning of roll here. Very briefly, it is intrinsic, and 0º roll means the object’s positive Z axis is aligned with `In`’s positive Z axis. Returns `None` if the vector has zero length, as the yaw is then ill-defined. Returns a yaw of zero if the vector points directly along the Z axis. ### Method `orientation_at_origin` ### Parameters #### Path Parameters - **roll** (*impl Into*): The roll angle to be applied to the orientation. ### Response #### Success Response (Option>) - **Option>**: An optional Orientation object. `None` if the vector has zero length, otherwise `Some(Orientation)`. ``` -------------------------------- ### Example Usage: Constructing Vector from Bearing in Rust Source: https://docs.rs/sguaba/latest/src/sguaba/vectors.rs_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Illustrates how to construct a vector from bearing information using `Vector::from_bearing` in a NED coordinate system. It showcases the use of `Bearing::builder` to define azimuth and elevation angles and `uom` for units, with assertions verifying the resulting Cartesian vector components. ```rust use approx::assert_relative_eq; use sguaba::{system, vector, Bearing, Vector}; use uom::si::f64::{Angle, Length}; use uom::si::{angle::degree, length::meter}; system!(struct Ned using NED); let zero = Length::new::(0.); let unit = Length::new::(1.); assert_relative_eq!( Vector::::from_bearing( Bearing::builder() .azimuth(Angle::new::(0.)) .elevation(Angle::new::(0.)).expect("elevation is in-range") .build(), unit ), vector!(n = unit, e = zero, d = zero), ); assert_relative_eq!( Vector::::from_bearing( Bearing::builder() .azimuth(Angle::new::(90.)) .elevation(Angle::new::(0.)).expect("elevation is in-range") .build(), unit ), ``` -------------------------------- ### XYZ Coordinate System Accessors Source: https://docs.rs/sguaba/latest/sguaba/vector/type.VelocityVector_search=u32+-%3E+bool Methods to get the components and axis vectors for the XYZ coordinate system. ```APIDOC ## POST /vectors/xyz/components ### Description Retrieves the X, Y, and Z components of a vector in the XYZ coordinate system. ### Method POST ### Endpoint `/vectors/xyz/components` ### Parameters #### Request Body - **vector_data** (object) - Required - The vector data. - **components** (object) - Required - The components of the vector. - **in_type** (string) - Required - Must be an XYZ-like coordinate system. ### Request Example ```json { "vector_data": { "components": {"x": "5.0m", "y": "2.0m", "z": "8.0m"}, "in_type": "RightHandedXyzLike" } } ``` ### Response #### Success Response (200) - **x** (string) - The X component of the vector. - **y** (string) - The Y component of the vector. - **z** (string) - The Z component of the vector. #### Response Example ```json { "x": "5.0m", "y": "2.0m", "z": "8.0m" } ``` ``` ```APIDOC ## POST /vectors/xyz/axis ### Description Returns a unit vector representing the X, Y, or Z axis in the XYZ coordinate system. ### Method POST ### Endpoint `/vectors/xyz/axis` ### Parameters #### Request Body - **axis_name** (string) - Required - The name of the axis ('x', 'y', or 'z'). - **in_type** (string) - Required - The coordinate system type for the axis vector. ### Request Example ```json { "axis_name": "x", "in_type": "RightHandedXyzLike" } ``` ### Response #### Success Response (200) - **axis_vector** (object) - A vector representing the specified axis. - **components** (object) - The components of the axis vector. - **in_type** (string) - The coordinate system type. #### Response Example ```json { "axis_vector": { "components": {"x": "1.0m", "y": "0.0m", "z": "0.0m"}, "in_type": "RightHandedXyzLike" } } ``` ``` -------------------------------- ### Define Coordinate System Accessors (Rust Macro) Source: https://docs.rs/sguaba/latest/src/sguaba/coordinates.rs A macro to generate accessor methods for different coordinate systems. It defines methods to get the `Length` of components (x, y, z) and to get the axis vectors (x_axis, y_axis, z_axis) for a given coordinate system convention. This macro simplifies the implementation of these common accessors across various coordinate system types. ```rust macro_rules! accessors { { $convention:ident using $x:ident, $y:ident, $z:ident // TODO: https://github.com/rust-lang/rust/issues/124225 + $x_ax:ident, $y_ax:ident, $z_ax:ident } => { impl Coordinate where In: CoordinateSystem { #[must_use] pub fn $x(&self) -> Length { Length::new::(self.point.x) } #[must_use] pub fn $y(&self) -> Length { Length::new::(self.point.y) } #[must_use] pub fn $z(&self) -> Length { Length::new::(self.point.z) } #[must_use] pub fn $x_ax() -> Vector { Vector::$x_ax() } #[must_use] pub fn $y_ax() -> Vector { Vector::$y_ax() } #[must_use] pub fn $z_ax() -> Vector { Vector::$z_ax() } } }; } accessors!(RightHandedXyzLike using x, y, z + x_axis, y_axis, z_axis); // NOTE(jon): it's sad that we need the ned_ and frd_ prefixes here, but it's because we need to // disambigued FRD down and NED down, which is in turn necessary because Rust doesn't know that a // coordinate system cannot implement `NedLike` _and_ `FrdLike`. Or rather, it _does_ know because // a given type can only implement a non-generic trait once, but sadly it fails to realize that // today (see https://github.com/rust-lang/rfcs/pull/1672). accessors!(NedLike using ned_north, ned_east, ned_down + ned_north_axis, ned_east_axis, ned_down_axis); accessors!(FrdLike using frd_front, frd_right, frd_down + frd_front_axis, frd_right_axis, frd_down_axis); accessors!(EnuLike using enu_east, enu_north, enu_up + enu_east_axis, enu_north_axis, enu_up_axis); ``` -------------------------------- ### Bearing Builder Initialization Source: https://docs.rs/sguaba/latest/src/sguaba/directions.rs_search=std%3A%3Avec Provides a static method `builder()` on the `Bearing` struct to create a new builder instance. This builder is in a state where both azimuth and elevation are missing, requiring them to be set before a valid `Bearing` can be constructed. It uses generic type parameters to track the state of construction. ```rust /// Provides a constructor for a bearing in the [`CoordinateSystem`] `In`. pub fn builder() -> Builder { Builder { under_construction: Self { azimuth: Angle::ZERO, elevation: Angle::ZERO, system: PhantomData, }, has: (PhantomData, PhantomData), } } ```