@@ -124,6 +124,35 @@ impl BoundingBox2D {
124124 BoundingBox2D :: new_unchecked ( lower_left_coordinate, upper_right_coordinate)
125125 }
126126
127+ /// Creates a new bounding box with `upper_left` and `lower_right` coordinates
128+ /// This is usually used with raster data and matches with the gdal geotransform
129+ ///
130+ /// # Examples
131+ ///
132+ /// ```
133+ /// use geoengine_datatypes::primitives::{Coordinate2D, BoundingBox2D};
134+ ///
135+ /// let ul = Coordinate2D::new(1.0, 2.0);
136+ /// let lr = Coordinate2D::new(2.0, 1.0);
137+ /// let bbox = BoundingBox2D::new_upper_left_lower_right(ul, lr).unwrap();
138+ /// ```
139+ ///
140+ /// # Errors
141+ ///
142+ /// This constructor fails if the order of coordinates is not correct
143+ ///
144+ pub fn new_from_center (
145+ center : Coordinate2D ,
146+ half_width : f64 ,
147+ half_height : f64 ,
148+ ) -> Result < Self > {
149+ // TODO: fail if half_width or half_height is negative
150+
151+ let lower_left_coordinate = ( center. x - half_width, center. y - half_height) . into ( ) ;
152+ let upper_right_coordinate = ( center. x + half_width, center. y + half_height) . into ( ) ;
153+ BoundingBox2D :: new ( lower_left_coordinate, upper_right_coordinate)
154+ }
155+
127156 /// Checks if a coordinate is located inside the bounding box
128157 ///
129158 /// # Examples
@@ -340,6 +369,49 @@ impl BoundingBox2D {
340369 f
341370 } )
342371 }
372+
373+ /// This method generates four new `BoundingBox2D`s by splitting the current one in four quadrants.
374+ pub fn split_into_quarters ( & self ) -> ( Self , Self , Self , Self ) {
375+ let half_width = self . size_x ( ) / 2. ;
376+ let half_height = self . size_x ( ) / 2. ;
377+
378+ let upper_left = Self :: new_unchecked (
379+ Coordinate2D :: new (
380+ self . lower_left_coordinate . x ,
381+ self . lower_left_coordinate . y + half_height,
382+ ) ,
383+ Coordinate2D :: new (
384+ self . lower_left_coordinate . x + half_width,
385+ self . upper_right_coordinate . y ,
386+ ) ,
387+ ) ;
388+ let upper_right = Self :: new_unchecked (
389+ Coordinate2D :: new (
390+ self . lower_left_coordinate . x + half_width,
391+ self . lower_left_coordinate . y + half_height,
392+ ) ,
393+ self . upper_right_coordinate ,
394+ ) ;
395+ let lower_left = Self :: new_unchecked (
396+ self . lower_left_coordinate ,
397+ Coordinate2D :: new (
398+ self . lower_left_coordinate . x + half_width,
399+ self . lower_left_coordinate . y + half_height,
400+ ) ,
401+ ) ;
402+ let lower_right = Self :: new_unchecked (
403+ Coordinate2D :: new (
404+ self . lower_left_coordinate . x + half_width,
405+ self . lower_left_coordinate . y ,
406+ ) ,
407+ Coordinate2D :: new (
408+ self . upper_right_coordinate . x ,
409+ self . lower_left_coordinate . y + half_height,
410+ ) ,
411+ ) ;
412+
413+ ( lower_left, lower_right, upper_left, upper_right)
414+ }
343415}
344416
345417impl AxisAlignedRectangle for BoundingBox2D {
@@ -481,6 +553,7 @@ impl TryFrom<BoundingBox2D> for gdal::vector::Geometry {
481553mod tests {
482554
483555 use crate :: primitives:: { AxisAlignedRectangle , BoundingBox2D , Coordinate2D , SpatialBounded } ;
556+
484557 #[ test]
485558 #[ allow( clippy:: float_cmp) ]
486559 fn bounding_box_new ( ) {
@@ -985,4 +1058,36 @@ mod tests {
9851058 let bbox = BoundingBox2D :: from_coord_ref_iter ( coordinates. iter ( ) ) . unwrap ( ) ;
9861059 assert_eq ! ( bbox, expected) ;
9871060 }
1061+
1062+ #[ test]
1063+ fn test_split_into_quarters ( ) {
1064+ let bbox = BoundingBox2D :: new ( ( -50. , -50. ) . into ( ) , ( 50. , 50. ) . into ( ) ) . unwrap ( ) ;
1065+
1066+ let ( lower_left, lower_right, upper_left, upper_right) = bbox. split_into_quarters ( ) ;
1067+
1068+ assert_eq ! (
1069+ upper_left,
1070+ BoundingBox2D :: new( ( -50. , 0. ) . into( ) , ( 0. , 50. ) . into( ) ) . unwrap( )
1071+ ) ;
1072+ assert_eq ! (
1073+ upper_right,
1074+ BoundingBox2D :: new( ( 0. , 0. ) . into( ) , ( 50. , 50. ) . into( ) ) . unwrap( )
1075+ ) ;
1076+ assert_eq ! (
1077+ lower_left,
1078+ BoundingBox2D :: new( ( -50. , -50. ) . into( ) , ( 0. , 0. ) . into( ) ) . unwrap( )
1079+ ) ;
1080+ assert_eq ! (
1081+ lower_right,
1082+ BoundingBox2D :: new( ( 0. , -50. ) . into( ) , ( 50. , 0. ) . into( ) ) . unwrap( )
1083+ ) ;
1084+ }
1085+
1086+ #[ test]
1087+ fn test_new_from_center ( ) {
1088+ assert_eq ! (
1089+ BoundingBox2D :: new_from_center( ( 0. , 0. ) . into( ) , 50. , 50. ) . unwrap( ) ,
1090+ BoundingBox2D :: new( ( -50. , -50. ) . into( ) , ( 50. , 50. ) . into( ) ) . unwrap( ) ,
1091+ ) ;
1092+ }
9881093}
0 commit comments