diff options
author | Jakub Kotur <qtr@google.com> | 2021-03-16 20:53:15 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-03-16 20:53:15 +0000 |
commit | 59b25e0dc5d4ca639c8d46b53a90417f37976169 (patch) | |
tree | a2b9db8395d7a587819e58039f5a575290b1a427 /src/drawing/rasterizer/line.rs | |
parent | 97853433079c3108a7c92b68a671575f945dd5a9 (diff) | |
parent | 15d57486a2b5313937d3dda5f0b74f3d7c4675b7 (diff) | |
download | plotters-59b25e0dc5d4ca639c8d46b53a90417f37976169.tar.gz |
Initial import of plotters-0.2.15. am: 00e4d270b2 am: fa31b59d73 am: 92238a6cd1 am: 15d57486a2
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/plotters/+/1621407
Change-Id: I1c0edc0a5d6d263892cf85d4ff5adf9d484fe22b
Diffstat (limited to 'src/drawing/rasterizer/line.rs')
-rw-r--r-- | src/drawing/rasterizer/line.rs | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/drawing/rasterizer/line.rs b/src/drawing/rasterizer/line.rs new file mode 100644 index 0000000..e1f9e5f --- /dev/null +++ b/src/drawing/rasterizer/line.rs @@ -0,0 +1,126 @@ +use crate::drawing::backend::{BackendCoord, BackendStyle, DrawingErrorKind}; +use crate::drawing::DrawingBackend; + +use crate::style::Color; + +pub fn draw_line<DB: DrawingBackend, S: BackendStyle>( + back: &mut DB, + mut from: BackendCoord, + mut to: BackendCoord, + style: &S, +) -> Result<(), DrawingErrorKind<DB::ErrorType>> { + if style.as_color().alpha() == 0.0 { + return Ok(()); + } + + if style.stroke_width() != 1 { + // If the line is wider than 1px, then we need to make it a polygon + let v = (i64::from(to.0 - from.0), i64::from(to.1 - from.1)); + let l = ((v.0 * v.0 + v.1 * v.1) as f64).sqrt(); + + if l < 1e-5 { + return Ok(()); + } + + let v = (v.0 as f64 / l, v.1 as f64 / l); + + let r = f64::from(style.stroke_width()) / 2.0; + let mut trans = [(v.1 * r, -v.0 * r), (-v.1 * r, v.0 * r)]; + let mut vertices = vec![]; + + for point in [from, to].iter() { + for t in trans.iter() { + vertices.push(( + (f64::from(point.0) + t.0) as i32, + (f64::from(point.1) + t.1) as i32, + )) + } + + trans.swap(0, 1); + } + + return back.fill_polygon(vertices, &style.as_color()); + } + + if from.0 == to.0 { + if from.1 > to.1 { + std::mem::swap(&mut from, &mut to); + } + for y in from.1..=to.1 { + check_result!(back.draw_pixel((from.0, y), &style.as_color())); + } + return Ok(()); + } + + if from.1 == to.1 { + if from.0 > to.0 { + std::mem::swap(&mut from, &mut to); + } + for x in from.0..=to.0 { + check_result!(back.draw_pixel((x, from.1), &style.as_color())); + } + return Ok(()); + } + + let steep = (from.0 - to.0).abs() < (from.1 - to.1).abs(); + + if steep { + from = (from.1, from.0); + to = (to.1, to.0); + } + + let (from, to) = if from.0 > to.0 { + (to, from) + } else { + (from, to) + }; + + let mut size_limit = back.get_size(); + + if steep { + size_limit = (size_limit.1, size_limit.0); + } + + let grad = f64::from(to.1 - from.1) / f64::from(to.0 - from.0); + + let mut put_pixel = |(x, y): BackendCoord, b: f64| { + if steep { + back.draw_pixel((y, x), &style.as_color().mix(b)) + } else { + back.draw_pixel((x, y), &style.as_color().mix(b)) + } + }; + + let y_step_limit = + (f64::from(to.1.min(size_limit.1 as i32 - 1).max(0) - from.1) / grad).floor() as i32; + + let batch_start = (f64::from(from.1.min(size_limit.1 as i32 - 2).max(0) - from.1) / grad) + .abs() + .ceil() as i32 + + from.0; + + let batch_limit = + to.0.min(size_limit.0 as i32 - 2) + .min(from.0 + y_step_limit - 1); + + let mut y = f64::from(from.1) + f64::from(batch_start - from.0) * grad; + + for x in batch_start..=batch_limit { + check_result!(put_pixel((x, y as i32), 1.0 + y.floor() - y)); + check_result!(put_pixel((x, y as i32 + 1), y - y.floor())); + + y += grad; + } + + if to.0 > batch_limit && y < f64::from(to.1) { + let x = batch_limit as i32 + 1; + if 1.0 + y.floor() - y > 1e-5 { + check_result!(put_pixel((x, y as i32), 1.0 + y.floor() - y)); + } + if y - y.floor() > 1e-5 && y + 1.0 < f64::from(to.1) { + check_result!(put_pixel((x, y as i32 + 1), y - y.floor())); + } + } + + Ok(()) +} |