1
1
use p3_api:: data:: { navigation_matrix:: NavigationMatrix , navigation_vector:: NavigationVector , navpoint_matrix:: NavpointMatrix } ;
2
2
3
+ use crate :: cli:: ConnectedNodesMode ;
4
+
5
+ #[ derive( Debug , Clone ) ]
3
6
pub struct ConnectedNodes {
4
7
pub connected_nodes : Vec < ( u16 , u16 ) > ,
5
8
}
@@ -37,12 +40,12 @@ impl ConnectedNodes {
37
40
neighbours
38
41
}
39
42
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 {
41
44
let mut nodes = vec ! [ ] ;
42
45
for ( source_index, source) in navigation_vector. points . iter ( ) . enumerate ( ) {
43
46
println ! ( "Calculating neighbours for node {source_index}" ) ;
44
47
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 ) {
46
49
nodes. push ( ( source_index as _ , destination_index as _ ) )
47
50
}
48
51
}
@@ -66,23 +69,32 @@ impl ConnectedNodes {
66
69
}
67
70
}
68
71
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 {
70
73
if p0 == p1 {
71
74
return true ;
72
75
}
73
76
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 ) ;
77
91
let dx = ( x1 - x0) . abs ( ) ;
78
92
let sx = if x0 < x1 { 1 } else { -1 } ;
79
- let dy = -( y1 - y0) . abs ( ) ;
93
+ let dy = -( ( y1 - y0) . abs ( ) ) ;
80
94
let sy = if y0 < y1 { 1 } else { -1 } ;
81
95
let mut error = dx + dy;
82
96
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) ) ;
86
98
let e2 = 2 * error;
87
99
if e2 >= dy {
88
100
if x0 == x1 {
@@ -99,6 +111,83 @@ fn is_connected(p0: (i16, i16), p1: (i16, i16), navigation_matrix: &NavigationMa
99
111
y0 += sy;
100
112
}
101
113
}
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 ;
102
158
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
+ }
104
193
}
0 commit comments