clipline 0.2.0

Efficient scan conversion (rasterization) of line segments with clipping to a rectangular window.
Documentation
# ✂️ clipline 📏

[![Rust](https://github.com/nxsaken/clipline/actions/workflows/rust.yml/badge.svg)](https://github.com/nxsaken/clipline/actions/workflows/rust.yml)
[![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 (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 `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)

## Benchmarks

[Benchmarks are available here](BENCHMARKS.md). I used [criterion.rs](https://github.com/bheisler/criterion.rs) to 
compare 
`clipline` to two 
popular line drawing crates – `bresenham` and `line_drawing`, by "drawing" 256 lines of varying 
clipping window sizes and line orientations. 

In practice, `bresenham` and `line_drawing` will require bounds checks when indexing into a frame buffer, hence the difference between the `draw_pixel_checked` and `draw_pixel_unchecked` functions.

## Installation

To use `clipline`, add it to your `Cargo.toml` file:

```toml
[dependencies]
clipline = "0.2.0"
```

## 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, Clipline, Clipline::*};

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 clip_rect");

// 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);
}

// C. Iterate over each `Clipline` case directly
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);
        }
    }
}
```