11use p3_api:: data:: { navigation_matrix:: NavigationMatrix , navigation_vector:: NavigationVector , navpoint_matrix:: NavpointMatrix } ;
22
3+ use crate :: cli:: ConnectedNodesMode ;
4+
5+ #[ derive( Debug , Clone ) ]
36pub struct ConnectedNodes {
47 pub connected_nodes : Vec < ( u16 , u16 ) > ,
58}
@@ -37,12 +40,12 @@ impl ConnectedNodes {
3740 neighbours
3841 }
3942
40- pub fn from_navigation_matrix ( navigation_vector : & NavigationVector , navigation_matrix : & NavigationMatrix ) -> Self {
43+ pub fn from_navigation_matrix_p3 ( navigation_vector : & NavigationVector , navigation_matrix : & NavigationMatrix , mode : ConnectedNodesMode ) -> Self {
4144 let mut nodes = vec ! [ ] ;
4245 for ( source_index, source) in navigation_vector. points . iter ( ) . enumerate ( ) {
4346 println ! ( "Calculating neighbours for node {source_index}" ) ;
4447 for ( destination_index, destination) in navigation_vector. points . iter ( ) . enumerate ( ) {
45- if is_connected ( * source, * destination, navigation_matrix) {
48+ if is_connected ( * source, * destination, navigation_matrix, mode ) {
4649 nodes. push ( ( source_index as _ , destination_index as _ ) )
4750 }
4851 }
@@ -66,23 +69,32 @@ impl ConnectedNodes {
6669 }
6770}
6871
69- fn is_connected ( p0 : ( i16 , i16 ) , p1 : ( i16 , i16 ) , navigation_matrix : & NavigationMatrix ) -> bool {
72+ fn is_connected ( p0 : ( i16 , i16 ) , p1 : ( i16 , i16 ) , navigation_matrix : & NavigationMatrix , mode : ConnectedNodesMode ) -> bool {
7073 if p0 == p1 {
7174 return true ;
7275 }
7376
74- // Bresenham's Line Algorithm
75- let ( mut x0, mut y0) = p0;
76- let ( x1, y1) = p1;
77+ let line = match mode {
78+ ConnectedNodesMode :: BresenhamLine => get_bresenham_line ( p0. 0 , p0. 1 , p1. 0 , p0. 1 ) ,
79+ //ConnectedNodesMode::P3 => get_p3_line(p0.0, p0.1, p1.0, p0.1),
80+ } ;
81+ for point in line {
82+ if navigation_matrix. data [ point. 0 as usize + navigation_matrix. width as usize * point. 1 as usize ] == 1 {
83+ return false ;
84+ }
85+ }
86+ true
87+ }
88+
89+ pub fn get_bresenham_line ( mut x0 : i16 , mut y0 : i16 , x1 : i16 , y1 : i16 ) -> Vec < ( i16 , i16 ) > {
90+ let mut path = Vec :: with_capacity ( 42 ) ;
7791 let dx = ( x1 - x0) . abs ( ) ;
7892 let sx = if x0 < x1 { 1 } else { -1 } ;
79- let dy = -( y1 - y0) . abs ( ) ;
93+ let dy = -( ( y1 - y0) . abs ( ) ) ;
8094 let sy = if y0 < y1 { 1 } else { -1 } ;
8195 let mut error = dx + dy;
8296 loop {
83- if navigation_matrix. data [ x0 as usize + navigation_matrix. width as usize * y0 as usize ] == 1 {
84- return false ;
85- }
97+ path. push ( ( x0, y0) ) ;
8698 let e2 = 2 * error;
8799 if e2 >= dy {
88100 if x0 == x1 {
@@ -99,6 +111,83 @@ fn is_connected(p0: (i16, i16), p1: (i16, i16), navigation_matrix: &NavigationMa
99111 y0 += sy;
100112 }
101113 }
114+ path
115+ }
116+
117+ pub fn get_p3_line ( mut x0 : i16 , mut y0 : i16 , x1 : i16 , y1 : i16 ) -> Vec < ( i16 , i16 ) > {
118+ let mut path = Vec :: with_capacity ( 42 ) ;
119+ path. push ( ( x0, y0) ) ;
120+ let dx_abs = ( x1 - x0) . abs ( ) ;
121+ let dy_abs = ( y1 - y0) . abs ( ) ;
122+ let sx = if x0 < x1 { 1 } else { -1 } ;
123+ let sy = if y0 < y1 { 1 } else { -1 } ;
124+
125+ let mut diff = dx_abs;
126+ let steps = dx_abs;
127+ for _ in 0 ..steps {
128+ // 0x0044477A
129+ x0 += sx; // Apply x step
130+ diff += 2 * dy_abs; // Add 2*dy to diff
131+ if diff >= 2 * dx_abs {
132+ // 0x00444784
133+ diff -= 2 * dx_abs;
134+ if diff == 0 {
135+ path. push ( ( x0, y0) ) ;
136+ y0 += sy;
137+ } else {
138+ y0 += sy;
139+ path. push ( ( x0, y0) ) ;
140+ }
141+ } else {
142+ // 0x00444793
143+ path. push ( ( x0, y0) ) ;
144+ }
145+ }
146+
147+ path
148+ }
149+
150+ #[ cfg( test) ]
151+ mod tests {
152+ use std:: {
153+ fs,
154+ path:: { Path , PathBuf } ,
155+ } ;
156+
157+ use regex:: Regex ;
102158
103- navigation_matrix. data [ x0 as usize + navigation_matrix. width as usize * y0 as usize ] == 0
159+ use super :: * ;
160+
161+ #[ test]
162+ fn it_works ( ) {
163+ test_file ( & PathBuf :: from ( "tests/lines/line1.txt" ) ) ;
164+ test_file ( & PathBuf :: from ( "tests/lines/line2.txt" ) ) ;
165+ test_file ( & PathBuf :: from ( "tests/lines/line3.txt" ) ) ;
166+ }
167+
168+ fn test_file ( path : & Path ) {
169+ let data = fs:: read_to_string ( path) . unwrap ( ) ;
170+ let mut lines: Vec < & str > = data. split ( "\n " ) . collect ( ) ;
171+ let header = lines. remove ( 0 ) ;
172+ let header_re = Regex :: new ( r"^\((\d+)\, (\d+)\) -> \((\d+)\, (\d+)\)" ) . unwrap ( ) ;
173+ let line_re = Regex :: new ( r"^\((\d+)\, (\d+)\)" ) . unwrap ( ) ;
174+ let header_captures = header_re. captures ( header) . unwrap ( ) ;
175+ let x0: i16 = header_captures. get ( 1 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
176+ let y0: i16 = header_captures. get ( 2 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
177+ let x1: i16 = header_captures. get ( 3 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
178+ let y1: i16 = header_captures. get ( 4 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
179+
180+ let mut calculated_line = get_p3_line ( x1, y1, x0, y0) ;
181+ calculated_line. remove ( 0 ) ;
182+ calculated_line. pop ( ) ;
183+ println ! ( "{calculated_line:?}" ) ;
184+ for ( i, line) in lines. iter ( ) . enumerate ( ) {
185+ let line_captures = line_re. captures ( line) . unwrap ( ) ;
186+ let x: i16 = line_captures. get ( 1 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
187+ let y: i16 = line_captures. get ( 2 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
188+ println ! ( "({}, {})" , calculated_line[ i] . 0 , calculated_line[ i] . 1 ) ;
189+ assert_eq ! ( x, calculated_line[ i] . 0 ) ;
190+ assert_eq ! ( y, calculated_line[ i] . 1 ) ;
191+ }
192+ }
104193}
0 commit comments