1
1
//! Contains [`Bounded2d`] implementations for [geometric primitives](crate::primitives).
2
2
3
- use std:: f32:: consts:: PI ;
4
-
5
3
use glam:: { Mat2 , Vec2 } ;
6
4
7
5
use crate :: primitives:: {
8
- Arc2d , BoxedPolygon , BoxedPolyline2d , Capsule2d , Circle , CircularSector , Direction2d , Ellipse ,
9
- Line2d , Plane2d , Polygon , Polyline2d , Rectangle , RegularPolygon , Segment2d , Triangle2d ,
6
+ Arc2d , BoxedPolygon , BoxedPolyline2d , Capsule2d , Circle , CircularSector , CircularSegment ,
7
+ Direction2d , Ellipse , Line2d , Plane2d , Polygon , Polyline2d , Rectangle , RegularPolygon ,
8
+ Segment2d , Triangle2d ,
10
9
} ;
11
10
12
11
use super :: { Aabb2d , Bounded2d , BoundingCircle } ;
@@ -23,31 +22,23 @@ impl Bounded2d for Circle {
23
22
24
23
impl Bounded2d for Arc2d {
25
24
fn aabb_2d ( & self , translation : Vec2 , rotation : f32 ) -> Aabb2d {
26
- // For a sufficiently wide arc, the bounding points in a given direction will be the outer
27
- // limits of a circle centered at the origin.
28
- // For smaller arcs, the two endpoints of the arc could also be bounding points,
29
- // but the start point is always axis-aligned so it's included as one of the circular limits.
25
+ // Because our arcs are always symmetrical around Vec::Y, the uppermost point and the two endpoints will always be extrema.
26
+ // For an arc that is greater than a semicircle, radii to the left and right will also be bounding points.
30
27
// This gives five possible bounding points, so we will lay them out in an array and then
31
28
// select the appropriate slice to compute the bounding box of.
32
- let mut circle_bounds = [
33
- self . end ( ) ,
34
- self . radius * Vec2 :: X ,
29
+ let all_bounds = [
30
+ self . left_endpoint ( ) ,
31
+ self . right_endpoint ( ) ,
35
32
self . radius * Vec2 :: Y ,
33
+ self . radius * Vec2 :: X ,
36
34
self . radius * -Vec2 :: X ,
37
- self . radius * -Vec2 :: Y ,
38
35
] ;
39
- if self . half_angle . is_sign_negative ( ) {
40
- // If we have a negative angle, we are going the opposite direction, so negate the Y-axis points.
41
- circle_bounds[ 2 ] = -circle_bounds[ 2 ] ;
42
- circle_bounds[ 4 ] = -circle_bounds[ 4 ] ;
43
- }
44
- // The number of quarter turns tells us how many extra points to include, between 0 and 3.
45
- let quarter_turns = f32:: floor ( self . angle ( ) . abs ( ) / ( PI / 2.0 ) ) . min ( 3.0 ) as usize ;
46
- Aabb2d :: from_point_cloud (
47
- translation,
48
- rotation,
49
- & circle_bounds[ 0 ..( 2 + quarter_turns) ] ,
50
- )
36
+ let bounds = if self . is_major ( ) {
37
+ & all_bounds[ 0 ..5 ]
38
+ } else {
39
+ & all_bounds[ 0 ..3 ]
40
+ } ;
41
+ Aabb2d :: from_point_cloud ( translation, rotation, bounds)
51
42
}
52
43
53
44
fn bounding_circle ( & self , translation : Vec2 , rotation : f32 ) -> BoundingCircle {
@@ -68,29 +59,23 @@ impl Bounded2d for Arc2d {
68
59
impl Bounded2d for CircularSector {
69
60
fn aabb_2d ( & self , translation : Vec2 , rotation : f32 ) -> Aabb2d {
70
61
// This is identical to the implementation for Arc2d, above, with the additional possibility of the
71
- // origin point, the center of the arc, acting as a bounding point.
62
+ // origin point, the center of the arc, acting as a bounding point when the arc is minor .
72
63
//
73
- // See comments above for discussion .
74
- let mut circle_bounds = [
64
+ // See comments above for an explanation of the logic .
65
+ let all_bounds = [
75
66
Vec2 :: ZERO ,
76
- self . arc . end ( ) ,
77
- self . arc . radius * Vec2 :: X ,
67
+ self . arc . left_endpoint ( ) ,
68
+ self . arc . right_endpoint ( ) ,
78
69
self . arc . radius * Vec2 :: Y ,
70
+ self . arc . radius * Vec2 :: X ,
79
71
self . arc . radius * -Vec2 :: X ,
80
- self . arc . radius * -Vec2 :: Y ,
81
72
] ;
82
- if self . arc . angle ( ) . is_sign_negative ( ) {
83
- // If we have a negative angle, we are going the opposite direction, so negate the Y-axis points.
84
- circle_bounds[ 3 ] = -circle_bounds[ 3 ] ;
85
- circle_bounds[ 5 ] = -circle_bounds[ 5 ] ;
86
- }
87
- // The number of quarter turns tells us how many extra points to include, between 0 and 3.
88
- let quarter_turns = f32:: floor ( self . arc . angle ( ) . abs ( ) / ( PI / 2.0 ) ) . min ( 3.0 ) as usize ;
89
- Aabb2d :: from_point_cloud (
90
- translation,
91
- rotation,
92
- & circle_bounds[ 0 ..( 3 + quarter_turns) ] ,
93
- )
73
+ let bounds = if self . arc . is_major ( ) {
74
+ & all_bounds[ 1 ..6 ]
75
+ } else {
76
+ & all_bounds[ 0 ..4 ]
77
+ } ;
78
+ Aabb2d :: from_point_cloud ( translation, rotation, bounds)
94
79
}
95
80
96
81
fn bounding_circle ( & self , translation : Vec2 , rotation : f32 ) -> BoundingCircle {
@@ -101,10 +86,9 @@ impl Bounded2d for CircularSector {
101
86
BoundingCircle :: new ( translation, self . arc . radius )
102
87
} else if self . arc . chord_length ( ) < self . arc . radius {
103
88
// If the chord length is smaller than the radius, then the radius is the widest distance between two points,
104
- // so the radius is the diameter of the bounding circle .
89
+ // so the bounding circle is centered on the midpoint of the radius .
105
90
let half_radius = self . arc . radius / 2.0 ;
106
- let angle = Vec2 :: from_angle ( self . arc . half_angle + rotation) ;
107
- let center = half_radius * angle;
91
+ let center = half_radius * Vec2 :: Y ;
108
92
BoundingCircle :: new ( center + translation, half_radius)
109
93
} else {
110
94
// Otherwise, the widest distance between two points is the chord,
@@ -115,6 +99,16 @@ impl Bounded2d for CircularSector {
115
99
}
116
100
}
117
101
102
+ impl Bounded2d for CircularSegment {
103
+ fn aabb_2d ( & self , translation : Vec2 , rotation : f32 ) -> Aabb2d {
104
+ self . arc . aabb_2d ( translation, rotation)
105
+ }
106
+
107
+ fn bounding_circle ( & self , translation : Vec2 , rotation : f32 ) -> BoundingCircle {
108
+ self . arc . bounding_circle ( translation, rotation)
109
+ }
110
+ }
111
+
118
112
impl Bounded2d for Ellipse {
119
113
fn aabb_2d ( & self , translation : Vec2 , rotation : f32 ) -> Aabb2d {
120
114
// V = (hh * cos(beta), hh * sin(beta))
0 commit comments