Skip to content

Commit 270db36

Browse files
committed
refactor: tidy up tests and impl of cohen_sutherland
1 parent a22f53c commit 270db36

1 file changed

Lines changed: 51 additions & 134 deletions

File tree

src/cohen_sutherland.rs

Lines changed: 51 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/// ```
6057
pub 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

8278
fn 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)
10098
bitflags! {
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

112109
impl 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)]
130132
mod 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

Comments
 (0)