Skip to content

Commit

Permalink
Merge pull request #3 from nxsaken/iterator
Browse files Browse the repository at this point in the history
Added a family of `Clipline` iterators
  • Loading branch information
nxsaken authored Oct 30, 2023
2 parents 3a7b052 + 4f449e8 commit b40eafd
Show file tree
Hide file tree
Showing 7 changed files with 1,252 additions and 509 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
run: cargo test --verbose --all-features
11 changes: 8 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "clipline"
version = "0.1.0"
version = "0.1.1"
authors = ["Nurzhan Sakén <[email protected]>"]
edition = "2021"
description = "Efficient scan conversion of a line segment with clipping to a rectangular window."
description = "Efficient scan conversion (rasterization) of line segments with clipping to a rectangular window."
readme = "README.md"
repository = "https://github.com/nxsaken/clipline/"
license = "MIT OR Apache-2.0"
Expand All @@ -12,4 +12,9 @@ categories = ["graphics", "rendering", "algorithms"]
include = [
"**/*.rs",
"Cargo.toml",
]
]

[features]
default = ["func", "iter"]
iter = []
func = []
58 changes: 37 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
[![crates.io](https://img.shields.io/crates/v/clipline.svg)](https://crates.io/crates/clipline)
[![docs.rs](https://img.shields.io/docsrs/clipline)](https://docs.rs/clipline/latest/clipline/)

`clipline` is a Rust crate for efficient scan conversion of a line
segment with [clipping](https://en.wikipedia.org/wiki/Line_clipping) to a rectangular window. It is an implementation of
[the 1995 paper by YP Kuzmin](https://doi.org/10.1111/1467-8659.1450275).
`clipline` is a Rust crate for efficient scan conversion (rasterization) of
line segments with [clipping](https://en.wikipedia.org/wiki/Line_clipping) to a
rectangular window. It is an implementation of
[the 1995 paper by YP Kuzmin](https://doi.org/10.1111/1467-8659.1450275).

The key advantage of this algorithm over vanilla Bresenham is that it
eliminates the need for bounds checking on every pixel, which speeds up line drawing.
Furthermore, the clipping is done via integer arithmetic, producing accurate
clipped endpoints. This sets it apart from floating-point clipping algorithms
like [Cohen-Sutherland](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm), which [may distort the line](https://www.virtualdub.org/blog2/entry_341.html) due to rounding errors.
The key advantage of `clipline` over vanilla Bresenham is that it eliminates the need for
bounds checking on every pixel, which speeds up line drawing. Furthermore, the clipping uses
integer arithmetic, producing pixel-perfect endpoints. This sets it apart from floating-point
clipping algorithms like [Cohen-Sutherland](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm), which [may distort the line](https://www.virtualdub.org/blog2/entry_341.html) due to rounding errors.

![`clipline` in action](img/clip_anim.gif)

Expand All @@ -22,29 +22,45 @@ To use `clipline`, add it to your `Cargo.toml` file:

```toml
[dependencies]
clipline = "0.1.0"
clipline = "0.1.1"
```

## Usage
This crate provides two ways of performing scan conversion: the `clipline` function, and the
`Clipline` iterator. The former is slightly more optimized, the latter allows external iteration.
Both methods can be toggled with the `func` and `iter` features (both enabled by default).

```rust
use clipline::clipline;
use clipline::{clipline, Clipline, Clipline::*};

fn draw_pixel(x: isize, y: isize) {
// Your custom pixel drawing logic
// No bounds checks necessary here
}
let draw_pixel = |x, y| {
// Your custom pixel logic
// No bounds checks necessary here!
};

let line = ((0, 0), (10, 10));
let clip_rect = ((2, 2), (8, 8));

// A. Use the `clipline` function for slightly faster operations
// `(start, end)` represents the visible portion of the line.
let (start, end) = clipline(line, clip_rect, draw_pixel)
.expect("line intersects the clipping rectangle");
.expect("line intersects clip_rect");

// Perform any additional logic with the clipped line segment.
// `start` and `end` represent the visible portion of the line.
```
// B. Iterate over `Clipline` with indirection
// `Clipline::new` returns None if `line` is fully outside `clip_rect`.
for (x, y) in Clipline::new(line, clip_rect).unwrap() {
draw_pixel(x, y);
}

In this example, `clipline` takes a line defined by two endpoints, `line`,
and corners of a clipping rectangle, `clip_rect`. The closure `draw_pixel`
handles each pixel within the clipped region, and the visible portion of the line is represented by the `start` and `end` variables.
// C. Iterate over each `Clipline` case directly (faster, recommended)
match Clipline::new(line, clip_rect).unwrap() {
Vlipline(pixels) => pixels.for_each(|(x, y)| draw_pixel(x, y)),
Hlipline(pixels) => pixels.for_each(|(x, y)| draw_pixel(x, y)),
Gentleham(pixels) => pixels.for_each(|(x, y)| draw_pixel(x, y)),
Steepnham(pixels) => {
for (x, y) in pixels {
draw_pixel(x, y);
}
}
}
```
Loading

0 comments on commit b40eafd

Please sign in to comment.