@@ -4,7 +4,7 @@ use geometry::line::Line;
4
4
use serde:: { Deserialize , Serialize } ;
5
5
6
6
use coordinate_systems:: Pixel ;
7
- use linear_algebra:: { point , Point2 } ;
7
+ use linear_algebra:: Point2 ;
8
8
use path_serde:: { PathDeserialize , PathIntrospect , PathSerialize } ;
9
9
10
10
#[ derive(
@@ -14,21 +14,35 @@ pub struct Limb {
14
14
pub pixel_polygon : Vec < Point2 < Pixel > > ,
15
15
}
16
16
17
- pub fn is_above_limbs ( pixel_position : Point2 < Pixel > , projected_limbs : & [ Limb ] ) -> bool {
18
- projected_limbs. iter ( ) . all ( |limb| {
19
- match limb. pixel_polygon . as_slice ( ) . windows ( 2 ) . find ( |points| {
20
- points[ 0 ] . x ( ) <= pixel_position. x ( ) && points[ 1 ] . x ( ) >= pixel_position. x ( )
21
- } ) {
22
- Some ( points) => {
23
- if points[ 0 ] . x ( ) == points[ 1 ] . x ( ) {
24
- return ( pixel_position. y ( ) ) < f32:: min ( points[ 0 ] . y ( ) , points[ 1 ] . y ( ) ) ;
25
- }
26
-
27
- // since Y is pointing downwards, "is above" is actually !Line::is_above()
28
- !Line ( points[ 0 ] , points[ 1 ] ) . is_above ( point ! [ pixel_position. x( ) , pixel_position. y( ) ] )
29
- }
30
- None => true ,
31
- }
17
+ pub fn project_onto_limbs ( position : Point2 < Pixel > , projected_limbs : & [ Limb ] ) -> Option < f32 > {
18
+ projected_limbs
19
+ . iter ( )
20
+ . flat_map ( |limb| {
21
+ limb. pixel_polygon
22
+ . as_slice ( )
23
+ . windows ( 2 )
24
+ . filter_map ( |points| {
25
+ let is_outside_of_segment =
26
+ position. x ( ) < points[ 0 ] . x ( ) || position. x ( ) > points[ 1 ] . x ( ) ;
27
+ if is_outside_of_segment {
28
+ return None ;
29
+ }
30
+
31
+ let is_vertical_segment = points[ 0 ] . x ( ) == points[ 1 ] . x ( ) ;
32
+ if is_vertical_segment {
33
+ return Some ( f32:: min ( points[ 0 ] . y ( ) , points[ 1 ] . y ( ) ) ) ;
34
+ }
35
+
36
+ Some ( Line ( points[ 0 ] , points[ 1 ] ) . project_onto_segment_in_x_axis ( position) )
37
+ } )
38
+ . min_by ( f32:: total_cmp)
39
+ } )
40
+ . min_by ( f32:: total_cmp)
41
+ }
42
+
43
+ pub fn is_above_limbs ( position : Point2 < Pixel > , projected_limbs : & [ Limb ] ) -> bool {
44
+ project_onto_limbs ( position, projected_limbs) . map_or ( true , |projected_position_y| {
45
+ position. y ( ) < projected_position_y
32
46
} )
33
47
}
34
48
@@ -38,3 +52,46 @@ pub fn is_above_limbs(pixel_position: Point2<Pixel>, projected_limbs: &[Limb]) -
38
52
pub struct ProjectedLimbs {
39
53
pub limbs : Vec < Limb > ,
40
54
}
55
+
56
+ #[ cfg( test) ]
57
+ mod tests {
58
+ use linear_algebra:: point;
59
+
60
+ use super :: * ;
61
+
62
+ #[ test]
63
+ fn left_limb_is_ignored ( ) {
64
+ let position = point ! [ 2.0 , 0.0 ] ;
65
+ let projected_limbs = vec ! [ Limb {
66
+ pixel_polygon: vec![ point![ 0.0 , 0.0 ] , point![ 1.0 , 1.0 ] ] ,
67
+ } ] ;
68
+ assert ! ( is_above_limbs( position, & projected_limbs) ) ;
69
+ }
70
+
71
+ #[ test]
72
+ fn right_limb_is_ignored ( ) {
73
+ let position = point ! [ 2.0 , 0.0 ] ;
74
+ let projected_limbs = vec ! [ Limb {
75
+ pixel_polygon: vec![ point![ 3.0 , 0.0 ] , point![ 4.0 , 1.0 ] ] ,
76
+ } ] ;
77
+ assert ! ( is_above_limbs( position, & projected_limbs) ) ;
78
+ }
79
+
80
+ #[ test]
81
+ fn too_high_limb_leads_to_point_being_below ( ) {
82
+ let position = point ! [ 2.0 , 0.0 ] ;
83
+ let projected_limbs = vec ! [ Limb {
84
+ pixel_polygon: vec![ point![ 1.0 , 10.0 ] , point![ 3.0 , 11.0 ] ] ,
85
+ } ] ;
86
+ assert ! ( is_above_limbs( position, & projected_limbs) ) ;
87
+ }
88
+
89
+ #[ test]
90
+ fn low_limb_leads_to_point_being_above ( ) {
91
+ let position = point ! [ 2.0 , 10.0 ] ;
92
+ let projected_limbs = vec ! [ Limb {
93
+ pixel_polygon: vec![ point![ 1.0 , 0.0 ] , point![ 3.0 , 1.0 ] ] ,
94
+ } ] ;
95
+ assert ! ( !is_above_limbs( position, & projected_limbs) ) ;
96
+ }
97
+ }
0 commit comments