@@ -45,29 +45,25 @@ use crate::{LineSegment, Point, Window};
4545/// use line_clipping::{LineSegment, Point, Window};
4646///
4747/// let line = clip_line(
48- /// LineSegment::new(Point { x: 0.0, y: 0.0 } , Point { x: 10.0, y: 10.0 } ),
48+ /// LineSegment::new(Point::new( 0.0, 0.0) , Point::new( 10.0, 10.0) ),
4949/// Window::new(1.0, 9.0, 1.0, 9.0),
5050/// );
5151///
5252/// assert_eq!(
5353/// line,
54- /// Some(LineSegment {
55- /// p1: Point { x: 1.0, y: 1.0 },
56- /// p2: Point { x: 9.0, y: 9.0 }
57- /// })
54+ /// Some(LineSegment::new(Point::new(1.0, 1.0), Point::new(9.0, 9.0)))
5855/// );
5956/// ```
6057pub fn clip_line ( mut line : LineSegment , window : Window ) -> Option < LineSegment > {
6158 let mut region_1 = Region :: from_point ( line. p1 , window) ;
6259 let mut region_2 = Region :: from_point ( line. p2 , window) ;
6360
64- while region_1 != Region :: INSIDE || region_2 != Region :: INSIDE {
61+ while region_1. is_outside ( ) || region_2. is_outside ( ) {
6562 if region_1. intersects ( region_2) {
6663 // The line is completely outside the clipping window.
6764 return None ;
6865 }
69-
70- if region_1 != Region :: INSIDE {
66+ if region_1. is_outside ( ) {
7167 line. p1 = calculate_intersection ( line. p1 , line. p2 , region_1, window) ;
7268 region_1 = Region :: from_point ( line. p1 , window) ;
7369 } else {
@@ -80,18 +76,20 @@ pub fn clip_line(mut line: LineSegment, window: Window) -> Option<LineSegment> {
8076}
8177
8278fn calculate_intersection ( p1 : Point , p2 : Point , region : Region , window : Window ) -> Point {
79+ let dx = p2. x - p1. x ;
80+ let dy = p2. y - p1. y ;
8381 if region. contains ( Region :: LEFT ) {
84- let y = p1. y + ( p2 . y - p1 . y ) * ( window. x_min - p1. x ) / ( p2 . x - p1 . x ) ;
85- Point { x : window. x_min , y }
82+ let y = p1. y + ( window. x_min - p1. x ) * dy / dx ;
83+ Point :: new ( window. x_min , y)
8684 } else if region. contains ( Region :: RIGHT ) {
87- let y = p1. y + ( p2 . y - p1 . y ) * ( window. x_max - p1. x ) / ( p2 . x - p1 . x ) ;
88- Point { x : window. x_max , y }
85+ let y = p1. y + ( window. x_max - p1. x ) * dy / dx ;
86+ Point :: new ( window. x_max , y)
8987 } else if region. contains ( Region :: BOTTOM ) {
90- let x = p1. x + ( p2 . x - p1 . x ) * ( window. y_min - p1. y ) / ( p2 . y - p1 . y ) ;
91- Point { x, y : window. y_min }
88+ let x = p1. x + ( window. y_min - p1. y ) * dx / dy ;
89+ Point :: new ( x, window. y_min )
9290 } else if region. contains ( Region :: TOP ) {
93- let x = p1. x + ( p2 . x - p1 . x ) * ( window. y_max - p1. y ) / ( p2 . y - p1 . y ) ;
94- Point { x, y : window. y_max }
91+ let x = p1. x + ( window. y_max - p1. y ) * dx / dy ;
92+ Point :: new ( x, window. y_max )
9593 } else {
9694 p1
9795 }
@@ -100,8 +98,7 @@ fn calculate_intersection(p1: Point, p2: Point, region: Region, window: Window)
10098bitflags ! {
10199 /// Represents the regions in the Cohen-Sutherland algorithm.
102100 #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
103- pub struct Region : u8 {
104- const INSIDE = 0b0000 ;
101+ struct Region : u8 {
105102 const LEFT = 0b0001 ;
106103 const RIGHT = 0b0010 ;
107104 const BOTTOM = 0b0100 ;
@@ -110,9 +107,13 @@ bitflags! {
110107}
111108
112109impl Region {
110+ const fn is_outside ( self ) -> bool {
111+ !self . is_empty ( )
112+ }
113+
113114 /// Determines the region in which a point lies.
114- pub fn from_point ( point : Point , window : Window ) -> Self {
115- let mut region = Region :: INSIDE ;
115+ fn from_point ( point : Point , window : Window ) -> Self {
116+ let mut region = Region :: empty ( ) ;
116117 if point. x < window. x_min {
117118 region |= Region :: LEFT ;
118119 } else if point. x > window. x_max {
@@ -126,139 +127,55 @@ impl Region {
126127 region
127128 }
128129}
130+
129131#[ cfg( test) ]
130132mod tests {
131133 use super :: * ;
132134
133135 #[ test]
134- fn test_line_completely_inside ( ) {
135- let line = clip_line (
136- LineSegment {
137- p1 : Point { x : 2.0 , y : 2.0 } ,
138- p2 : Point { x : 8.0 , y : 8.0 } ,
139- } ,
140- Window {
141- x_min : 1.0 ,
142- x_max : 9.0 ,
143- y_min : 1.0 ,
144- y_max : 9.0 ,
145- } ,
146- ) ;
147- assert_eq ! (
148- line,
149- Some ( LineSegment {
150- p1: Point { x: 2.0 , y: 2.0 } ,
151- p2: Point { x: 8.0 , y: 8.0 }
152- } )
153- ) ;
136+ fn completely_inside ( ) {
137+ let line = LineSegment :: new ( Point :: new ( 2.0 , 2.0 ) , Point :: new ( 8.0 , 8.0 ) ) ;
138+ let window = Window :: new ( 1.0 , 9.0 , 1.0 , 9.0 ) ;
139+ let expected = LineSegment :: new ( Point :: new ( 2.0 , 2.0 ) , Point :: new ( 8.0 , 8.0 ) ) ;
140+ assert_eq ! ( clip_line( line, window) , Some ( expected) ) ;
154141 }
155142
156143 #[ test]
157- fn test_line_completely_outside ( ) {
158- let line = clip_line (
159- LineSegment {
160- p1 : Point { x : -1.0 , y : -1.0 } ,
161- p2 : Point { x : -5.0 , y : -5.0 } ,
162- } ,
163- Window {
164- x_min : 1.0 ,
165- x_max : 9.0 ,
166- y_min : 1.0 ,
167- y_max : 9.0 ,
168- } ,
169- ) ;
170- assert_eq ! ( line, None ) ;
144+ fn completely_outside ( ) {
145+ let line = LineSegment :: new ( Point :: new ( -1.0 , -1.0 ) , Point :: new ( -5.0 , -5.0 ) ) ;
146+ let window = Window :: new ( 1.0 , 9.0 , 1.0 , 9.0 ) ;
147+ assert_eq ! ( clip_line( line, window) , None ) ;
171148 }
172149
173150 #[ test]
174- fn test_line_partially_inside ( ) {
175- let line = clip_line (
176- LineSegment {
177- p1 : Point { x : 0.0 , y : 0.0 } ,
178- p2 : Point { x : 10.0 , y : 10.0 } ,
179- } ,
180- Window {
181- x_min : 1.0 ,
182- x_max : 9.0 ,
183- y_min : 1.0 ,
184- y_max : 9.0 ,
185- } ,
186- ) ;
187- assert_eq ! (
188- line,
189- Some ( LineSegment {
190- p1: Point { x: 1.0 , y: 1.0 } ,
191- p2: Point { x: 9.0 , y: 9.0 }
192- } )
193- ) ;
151+ fn partially_inside ( ) {
152+ let line = LineSegment :: new ( Point :: new ( 0.0 , 0.0 ) , Point :: new ( 10.0 , 10.0 ) ) ;
153+ let window = Window :: new ( 1.0 , 9.0 , 1.0 , 9.0 ) ;
154+ let expected = LineSegment :: new ( Point :: new ( 1.0 , 1.0 ) , Point :: new ( 9.0 , 9.0 ) ) ;
155+ assert_eq ! ( clip_line( line, window) , Some ( expected) ) ;
194156 }
195157
196158 #[ test]
197- fn test_line_vertical ( ) {
198- let line = clip_line (
199- LineSegment {
200- p1 : Point { x : 5.0 , y : 0.0 } ,
201- p2 : Point { x : 5.0 , y : 10.0 } ,
202- } ,
203- Window {
204- x_min : 1.0 ,
205- x_max : 9.0 ,
206- y_min : 1.0 ,
207- y_max : 9.0 ,
208- } ,
209- ) ;
210- assert_eq ! (
211- line,
212- Some ( LineSegment {
213- p1: Point { x: 5.0 , y: 1.0 } ,
214- p2: Point { x: 5.0 , y: 9.0 }
215- } )
216- ) ;
159+ fn vertical ( ) {
160+ let line = LineSegment :: new ( Point :: new ( 5.0 , 0.0 ) , Point :: new ( 5.0 , 10.0 ) ) ;
161+ let window = Window :: new ( 1.0 , 9.0 , 1.0 , 9.0 ) ;
162+ let expected = LineSegment :: new ( Point :: new ( 5.0 , 1.0 ) , Point :: new ( 5.0 , 9.0 ) ) ;
163+ assert_eq ! ( clip_line( line, window) , Some ( expected) ) ;
217164 }
218165
219166 #[ test]
220- fn test_line_horizontal ( ) {
221- let line = clip_line (
222- LineSegment {
223- p1 : Point { x : 0.0 , y : 5.0 } ,
224- p2 : Point { x : 10.0 , y : 5.0 } ,
225- } ,
226- Window {
227- x_min : 1.0 ,
228- x_max : 9.0 ,
229- y_min : 1.0 ,
230- y_max : 9.0 ,
231- } ,
232- ) ;
233- assert_eq ! (
234- line,
235- Some ( LineSegment {
236- p1: Point { x: 1.0 , y: 5.0 } ,
237- p2: Point { x: 9.0 , y: 5.0 }
238- } )
239- ) ;
167+ fn horizontal ( ) {
168+ let line = LineSegment :: new ( Point :: new ( 0.0 , 5.0 ) , Point :: new ( 10.0 , 5.0 ) ) ;
169+ let window = Window :: new ( 1.0 , 9.0 , 1.0 , 9.0 ) ;
170+ let expected = LineSegment :: new ( Point :: new ( 1.0 , 5.0 ) , Point :: new ( 9.0 , 5.0 ) ) ;
171+ assert_eq ! ( clip_line( line, window) , Some ( expected) ) ;
240172 }
241173
242174 #[ test]
243- fn test_line_diagonal ( ) {
244- let line = clip_line (
245- LineSegment {
246- p1 : Point { x : -5.0 , y : -5.0 } ,
247- p2 : Point { x : 15.0 , y : 15.0 } ,
248- } ,
249- Window {
250- x_min : 1.0 ,
251- x_max : 9.0 ,
252- y_min : 1.0 ,
253- y_max : 9.0 ,
254- } ,
255- ) ;
256- assert_eq ! (
257- line,
258- Some ( LineSegment {
259- p1: Point { x: 1.0 , y: 1.0 } ,
260- p2: Point { x: 9.0 , y: 9.0 }
261- } )
262- ) ;
175+ fn diagonal ( ) {
176+ let line = LineSegment :: new ( Point :: new ( -5.0 , -5.0 ) , Point :: new ( 15.0 , 15.0 ) ) ;
177+ let window = Window :: new ( 1.0 , 9.0 , 1.0 , 9.0 ) ;
178+ let expected = LineSegment :: new ( Point :: new ( 1.0 , 1.0 ) , Point :: new ( 9.0 , 9.0 ) ) ;
179+ assert_eq ! ( clip_line( line, window) , Some ( expected) ) ;
263180 }
264181}
0 commit comments