1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
extern crate nalgebra as na; use na::{Point3, Matrix4 as Matrix, Vector3 as Vector}; use super::traits::{self, Transform, Plane}; /// A struct for sensors of rectangular geometry pub struct Rectangle { points : [na::Point3<f32>; 4], normal: Option<Vector<f32>>, tfm: na::Affine3<f32> } impl Rectangle { /// This is the constructor for the rectangular geometry. It expects a 4x4 `nalgebra::Matrix4<f32>` that is invertible /// and a 4 element array of `nalgebra::Point3<f32>`. If the matrix is not invertible it will return `Err(&str)`. /// The provided matrix should be an affine transformation for converting from R2->R3 /// /// # Examples /// ``` /// use nalgebra as na; /// use na::Point3; /// /// let rectangular_points = [Point3::new(0.0, 0.0, 0.0), /// Point3::new(5.0,0.0,0.0), /// Point3::new(0.0,5.0,0.0), /// Point3::new(5.0,5.0,0.0)]; /// let tfm_matrix : na::Matrix4<f32>= na::Matrix4::new(1.0,5.0,7.0,2.0, 3.0,5.0,7.0,4.0, 8.0,4.0,1.0,9.0, 2.0,6.0,4.0,8.0); /// let mut rectangle_sensor = kalman_rs::Rectangle::new(rectangular_points, tfm_matrix).unwrap(); /// ``` pub fn new(mut points: [Point3<f32>; 4], tfm_matrix: Matrix<f32>) -> Result<Rectangle, &'static str>{ let affine_transform = na::Affine3::from_matrix_unchecked(tfm_matrix); match affine_transform.try_inverse(){ Some(_x) => { let points = traits::organize_points(&mut points); Ok(Rectangle{points: *points, normal: None,tfm: affine_transform})}, None => return Err("matrix was not invertable") } } } impl Transform for Rectangle{ /// Converts a point in the global reference frame to a point in the local reference frame of the sensor. /// /// # Examples /// ``` /// use nalgebra as na; /// use na::Point3; /// use kalman_rs::sensor_traits::Transform; /// /// let rectangular_points = [Point3::new(0.0, 0.0, 0.0), /// Point3::new(5.0,0.0,0.0), /// Point3::new(0.0,5.0,0.0), /// Point3::new(5.0,5.0,0.0)]; /// let tfm_matrix : na::Matrix4<f32>= na::Matrix4::new(1.0,5.0,7.0,2.0, 3.0,5.0,7.0,4.0, 8.0,4.0,1.0,9.0, 2.0,6.0,4.0,8.0); /// let mut rectangle_sensor = kalman_rs::Rectangle::new(rectangular_points, tfm_matrix).unwrap(); /// /// let global_point = rectangle_sensor.to_global(na::Point3::new(1.0, 2.0, 0.0)); /// ``` fn to_global(&self, input_point: Point3<f32>)-> na::Point3<f32>{ return self.tfm * input_point; } /// Converts a point in the local refernce frame of the sensor to the global reference frame. /// /// # Examples /// /// ``` /// use nalgebra as na; /// use na::Point3; /// use kalman_rs::sensor_traits::Transform; /// /// let rectangular_points = [Point3::new(0.0, 0.0, 0.0), /// Point3::new(5.0,0.0,0.0), /// Point3::new(0.0,5.0,0.0), /// Point3::new(5.0,5.0,0.0)]; /// let tfm_matrix : na::Matrix4<f32>= na::Matrix4::new(1.0,5.0,7.0,2.0, 3.0,5.0,7.0,4.0, 8.0,4.0,1.0,9.0, 2.0,6.0,4.0,8.0); /// let mut rectangle_sensor = kalman_rs::Rectangle::new(rectangular_points, tfm_matrix).unwrap(); /// /// let global_point = rectangle_sensor.to_local(na::Point3::new(6.0, 3.0, 5.0)); /// ``` fn to_local(&self, input_point: Point3<f32>) -> na::Point3<f32>{ self.tfm.inverse() * input_point } /// Checks if a local point is contained within the bounds of a sensor. /// NOTE: `plane()` must be called before checking for bounds of the sensor since the normal /// vector must be calculated first. /// /// # Examples /// ``` /// use nalgebra as na; /// use na::Point3; /// use kalman_rs::sensor_traits::Transform; /// /// let rectangular_points = [Point3::new(0.0, 0.0, 0.0), /// Point3::new(5.0,0.0,0.0), /// Point3::new(5.0,5.0,0.0), /// Point3::new(5.0, 0.0, 0.0)]; /// let tfm_matrix : na::Matrix4<f32>= na::Matrix4::new(1.0,5.0,7.0,2.0, 3.0,5.0,7.0,4.0, 8.0,4.0,1.0,9.0, 2.0,6.0,4.0,8.0); /// let mut rectangle_sensor = kalman_rs::Rectangle::new(rectangular_points, tfm_matrix).unwrap(); /// /// let is_point_on_sensor = rectangle_sensor.contains_from_local(&na::Point3::new(1.0, 6.0, 0.0)); /// ``` fn contains_from_local(&self, input: &Point3<f32>) ->Result<bool, &'static str> { let xy_contains = traits::quadralateral_contains(&self.points, &input); let z_contains = self.on_plane(&input); match z_contains{ Ok(x) =>{ if xy_contains && x { return Ok(true) } Ok(false) }, Err(x) => return Err(x) } } } impl Plane for Rectangle{ /// Calculate the current normal vector of the plane of the surface. /// NOTE: `plane()` must be called before `contains_from_local` since `contains_from_local` /// requires the normal vector to be defined /// /// # Examples /// /// ``` /// use nalgebra as na; /// use na::Point3; /// use kalman_rs::sensor_traits::Plane; /// /// let rectangular_points = [Point3::new(0.0, 0.0, 0.0), /// Point3::new(5.0,0.0,0.0), /// Point3::new(0.0,5.0,0.0), /// Point3::new(5.0,5.0,0.0)]; /// let tfm_matrix : na::Matrix4<f32>= na::Matrix4::new(1.0,5.0,7.0,2.0, 3.0,5.0,7.0,4.0, 8.0,4.0,1.0,9.0, 2.0,6.0,4.0,8.0); /// let mut rectangle_sensor = kalman_rs::Rectangle::new(rectangular_points, tfm_matrix).unwrap(); /// /// let normal_vector = rectangle_sensor.plane(); /// ``` fn plane(&mut self) -> Vector<f32>{ // calculate the normal vector of the surface if it has not been calculated before // if it has been calculated return the original calculation // this would need to change if the suface moves match self.normal{ Some(x)=>x, None =>{ let normal_vector = traits::plane_normal_vector(&self.points[0], &self.points[1], &self.points[2]); self.normal = Some(normal_vector); normal_vector }, } } /// Check if a given point is located on the same plane as the sensor /// NOTE: `plane()` must be called becuase the normal vector is not currently known /// # Examples /// /// ``` /// use nalgebra as na; /// use na::Point3; /// use kalman_rs::sensor_traits::Plane; /// /// let rectangular_points = [Point3::new(0.0, 0.0, 0.0), /// Point3::new(5.0,0.0,0.0), /// Point3::new(0.0,5.0,0.0), /// Point3::new(5.0,5.0,0.0)]; /// let tfm_matrix : na::Matrix4<f32>= na::Matrix4::new(1.0,5.0,7.0,2.0, 3.0,5.0,7.0,4.0, 8.0,4.0,1.0,9.0, 2.0,6.0,4.0,8.0); /// let mut rectangle_sensor = kalman_rs::Rectangle::new(rectangular_points, tfm_matrix).unwrap(); /// /// let on_plane = rectangle_sensor.on_plane(&na::Point3::new(1.0, 3.0, 0.0)); //true /// ``` fn on_plane(&self, input_point: &Point3<f32>) -> Result<bool, &'static str> { let pv = traits::vector3_from_points(&self.points[0], &input_point); match self.normal{ Some(x) => { if x.dot(&pv) ==0.0 { return Ok(true) } Ok(false) } None => Err("self.plane() method must be called before normal vector can be used") } } }