Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
[package]
name = "earcut-rs"
version = "0.3.0"
version = "0.3.1"
edition = "2021"
description = "A Rust port of the Earcut polygon triangulation library"
authors = ["Taku Fukada <[email protected]>", "MIERUNE Inc. <[email protected]>"]
license-file = "LICENSE.txt"
license = "MIT"
repository = "https://github.com/MIERUNE/earcut-rs"
categories = ["graphics", "science"]

[dependencies]
num-traits = "0.2.18"
num-traits = "0.2"

[dev-dependencies]
serde_json = { version = "1.0.115", features = ["float_roundtrip"] }
serde = { version = "1.0.197", features = ["derive"] }
criterion = "0.5.1"
serde_json = { version = "1.0", features = ["float_roundtrip"] }
serde = { version = "1.0", features = ["derive"] }
criterion = "0.5"

[[bench]]
name = "benchmark"
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

[![Test](https://github.com/MIERUNE/earcut-rs/actions/workflows/Test.yml/badge.svg)](https://github.com/MIERUNE/earcut-rs/actions/workflows/Test.yml)
[![codecov](https://codecov.io/gh/MIERUNE/earcut-rs/graph/badge.svg?token=thKlQiVjLc)](https://codecov.io/gh/MIERUNE/earcut-rs)
[![Crates.io Version](https://img.shields.io/crates/v/earcut-rs)](https://crates.io/crates/earcut-rs)

A Rust port of the [mapbox/earcut](https://github.com/mapbox/earcut) polygon triangulation library, implemented from scratch with reference to [donbright/earcutr](https://github.com/donbright/earcutr).
A Rust port of the [mapbox/earcut](https://github.com/mapbox/earcut) polygon triangulation library, implemented from scratch with some reference to [donbright/earcutr](https://github.com/donbright/earcutr).

- Based on the latest earcut 2.2.4 release.
- An additional utility `utils3d` can be used to project polygons from 3D to 2D space before triangulation.
- Designed to avoid unnecessary memory allocations. You can reuse the internal buffer and the output index vector.
- (Experimental) An additional module, `utils3d`, can rotate polygons from 3D to 2D space before triangulation.
- License: ISC

<p align="center">
Expand Down
18 changes: 7 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ impl<T: Float> Default for Earcut<T> {
}

impl<T: Float> Earcut<T> {
/// Creates a new instance for the earcut algorithm.
///
/// You can reuse the same instance for multiple triangulations to reduce memory allocations.
pub fn new() -> Self {
Self {
data: Vec::new(),
Expand All @@ -118,6 +121,9 @@ impl<T: Float> Earcut<T> {
self.nodes.reserve(capacity);
}

/// Performs the earcut triangulation on a polygon.
///
/// The API is similar to the original JavaScript implementation, except you can provide a vector for the output indices.
pub fn earcut<N: Index>(
&mut self,
data: impl IntoIterator<Item = T>,
Expand Down Expand Up @@ -317,7 +323,6 @@ impl<T: Float> Earcut<T> {
}

/// check whether a polygon node forms a valid ear with adjacent nodes
#[inline]
fn is_ear(&self, ear_i: usize) -> bool {
let b = node!(self.nodes, ear_i);
let a = node!(self.nodes, b.prev_i);
Expand Down Expand Up @@ -860,7 +865,6 @@ impl<T: Float> Earcut<T> {

/// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
/// if one belongs to the outer ring and another to a hole, it merges it into a single ring
#[inline(always)]
fn split_polygon(&mut self, a_i: usize, b_i: usize) -> usize {
let a2_i = self.nodes.len();
let b2_i = a2_i + 1;
Expand Down Expand Up @@ -890,7 +894,6 @@ impl<T: Float> Earcut<T> {
}

/// create a node and optionally link it with previous one (in a circular doubly linked list)
#[inline(always)]
fn insert_node<T: Float>(
nodes: &mut Vec<Node<T>>,
i: usize,
Expand All @@ -916,7 +919,6 @@ fn insert_node<T: Float>(
p_i
}

#[inline(always)]
fn remove_node<T: Float>(nodes: &mut [Node<T>], p_i: usize) -> (usize, usize) {
let p = node!(nodes, p_i);
let p_next_i = p.next_i;
Expand All @@ -934,7 +936,7 @@ fn remove_node<T: Float>(nodes: &mut [Node<T>], p_i: usize) -> (usize, usize) {
(p_prev_i, p_next_i)
}

/// return a percentage difference between the polygon area and its triangulation area;
/// Returns a percentage difference between the polygon area and its triangulation area;
/// used to verify correctness of triangulation
pub fn deviation<T: Float, N: Index>(
data: impl IntoIterator<Item = T>,
Expand Down Expand Up @@ -1002,7 +1004,6 @@ fn signed_area<T: Float>(data: &[T], start: usize, end: usize) -> T {
}

/// z-order of a point given coords and inverse of the longer side of data bbox
#[inline(always)]
fn z_order<T: Float>(x: T, y: T, min_x: T, min_y: T, inv_size: T) -> u32 {
// coords are transformed into non-negative 15-bit integer range
let mut x = ((x - min_x) * inv_size).to_u32().unwrap();
Expand All @@ -1018,7 +1019,6 @@ fn z_order<T: Float>(x: T, y: T, min_x: T, min_y: T, inv_size: T) -> u32 {
x | (y << 1)
}

#[inline(always)]
#[allow(clippy::too_many_arguments)]
fn point_in_triangle<T: Float>(ax: T, ay: T, bx: T, by: T, cx: T, cy: T, px: T, py: T) -> bool {
(cx - px) * (ay - py) >= (ax - px) * (cy - py)
Expand All @@ -1027,24 +1027,20 @@ fn point_in_triangle<T: Float>(ax: T, ay: T, bx: T, by: T, cx: T, cy: T, px: T,
}

/// signed area of a triangle
#[inline(always)]
fn area<T: Float>(p: &Node<T>, q: &Node<T>, r: &Node<T>) -> T {
(q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y)
}

/// check if two points are equal
#[inline(always)]
fn equals<T: Float>(p1: &Node<T>, p2: &Node<T>) -> bool {
p1.x == p2.x && p1.y == p2.y
}

/// for collinear points p, q, r, check if point q lies on segment pr
#[inline(always)]
fn on_segment<T: Float>(p: &Node<T>, q: &Node<T>, r: &Node<T>) -> bool {
q.x <= p.x.max(r.x) && q.x >= p.x.min(r.x) && q.y <= p.y.max(r.y) && q.y >= p.y.max(r.y)
}

#[inline(always)]
fn sign<T: Float>(v: T) -> i8 {
(v > T::zero()) as i8 - (v < T::zero()) as i8
}