use geom::{LineSegment, QuadraticBezierSegment};
use math::Point;
use events::{QuadraticEvent, Segment};
use std::mem;
use std::ops::Range;
use std::u32;
#[derive(Clone, Debug)]
pub struct PathBuffer {
pub endpoints: Vec<Endpoint>,
pub control_points: Vec<Point>,
pub subpaths: Vec<Subpath>,
}
impl PathBuffer {
#[inline]
pub fn new() -> PathBuffer {
PathBuffer {
endpoints: vec![],
control_points: vec![],
subpaths: vec![],
}
}
pub fn add_stream<I>(&mut self, stream: I) where I: Iterator<Item = QuadraticEvent> {
let mut first_subpath_endpoint_index = self.endpoints.len() as u32;
for segment in stream {
match segment {
QuadraticEvent::Close => self.close_subpath(&mut first_subpath_endpoint_index),
QuadraticEvent::MoveTo(to) => {
self.end_subpath(&mut first_subpath_endpoint_index);
self.endpoints.push(Endpoint {
position: to,
control_point_index: u32::MAX,
subpath_index: self.subpaths.len() as u32,
})
}
QuadraticEvent::LineTo(to) => {
self.endpoints.push(Endpoint {
position: to,
control_point_index: u32::MAX,
subpath_index: self.subpaths.len() as u32,
})
}
QuadraticEvent::QuadraticTo(ctrl, to) => {
let control_point_index = self.control_points.len() as u32;
self.control_points.push(ctrl);
self.endpoints.push(Endpoint {
position: to,
control_point_index: control_point_index,
subpath_index: self.subpaths.len() as u32,
})
}
}
}
self.end_subpath(&mut first_subpath_endpoint_index)
}
fn close_subpath(&mut self, first_subpath_endpoint_index: &mut u32) {
if self.endpoints.len() > *first_subpath_endpoint_index as usize {
let first_endpoint = self.endpoints[*first_subpath_endpoint_index as usize];
self.endpoints.push(first_endpoint);
}
self.do_end_subpath(first_subpath_endpoint_index, true)
}
fn end_subpath(&mut self, first_subpath_endpoint_index: &mut u32) {
self.do_end_subpath(first_subpath_endpoint_index, false)
}
fn do_end_subpath(&mut self, first_subpath_endpoint_index: &mut u32, closed: bool) {
let last_subpath_endpoint_index = self.endpoints.len() as u32;
if *first_subpath_endpoint_index != last_subpath_endpoint_index {
self.subpaths.push(Subpath {
first_endpoint_index: *first_subpath_endpoint_index,
last_endpoint_index: last_subpath_endpoint_index,
closed: closed,
})
}
*first_subpath_endpoint_index = last_subpath_endpoint_index;
}
pub fn reverse_subpath(&mut self, subpath_index: u32) {
let subpath = &self.subpaths[subpath_index as usize];
let endpoint_range = subpath.range();
if endpoint_range.start == endpoint_range.end {
return
}
self.endpoints[endpoint_range.clone()].reverse();
for endpoint_index in (endpoint_range.start..(endpoint_range.end - 1)).rev() {
let control_point_index = self.endpoints[endpoint_index].control_point_index;
self.endpoints[endpoint_index + 1].control_point_index = control_point_index;
}
self.endpoints[endpoint_range.start].control_point_index = u32::MAX;
}
}
#[derive(Clone)]
pub struct PathBufferStream<'a> {
path_buffer: &'a PathBuffer,
endpoint_index: u32,
subpath_index: u32,
last_subpath_index: u32,
}
impl<'a> PathBufferStream<'a> {
#[inline]
pub fn new<'b>(path_buffer: &'b PathBuffer) -> PathBufferStream<'b> {
PathBufferStream {
path_buffer: path_buffer,
endpoint_index: 0,
subpath_index: 0,
last_subpath_index: path_buffer.subpaths.len() as u32,
}
}
#[inline]
pub fn subpath_range<'b>(path_buffer: &'b PathBuffer, subpath_range: Range<u32>)
-> PathBufferStream<'b> {
let first_endpoint_index = if subpath_range.start == subpath_range.end {
0
} else {
path_buffer.subpaths[subpath_range.start as usize].first_endpoint_index
};
PathBufferStream {
path_buffer: path_buffer,
endpoint_index: first_endpoint_index,
subpath_index: subpath_range.start,
last_subpath_index: subpath_range.end,
}
}
}
impl<'a> Iterator for PathBufferStream<'a> {
type Item = QuadraticEvent;
fn next(&mut self) -> Option<QuadraticEvent> {
if self.subpath_index == self.last_subpath_index {
return None
}
let subpath = &self.path_buffer.subpaths[self.subpath_index as usize];
if self.endpoint_index == subpath.last_endpoint_index {
self.subpath_index += 1;
if subpath.closed {
return Some(QuadraticEvent::Close)
}
return self.next()
}
let endpoint_index = self.endpoint_index;
self.endpoint_index += 1;
let endpoint = &self.path_buffer.endpoints[endpoint_index as usize];
if endpoint_index == subpath.first_endpoint_index {
return Some(QuadraticEvent::MoveTo(endpoint.position))
}
if endpoint.control_point_index == u32::MAX {
return Some(QuadraticEvent::LineTo(endpoint.position))
}
let control_point = &self.path_buffer
.control_points[endpoint.control_point_index as usize];
Some(QuadraticEvent::QuadraticTo(*control_point, endpoint.position))
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Endpoint {
pub position: Point,
pub control_point_index: u32,
pub subpath_index: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Subpath {
pub first_endpoint_index: u32,
pub last_endpoint_index: u32,
pub closed: bool,
}
impl Subpath {
#[inline]
pub fn range(self) -> Range<usize> {
(self.first_endpoint_index as usize)..(self.last_endpoint_index as usize)
}
}
pub struct QuadraticSegments<I> {
inner: I,
current_subpath_index: u32,
current_point: Point,
current_subpath_start_point: Point,
}
impl<I> QuadraticSegments<I> where I: Iterator<Item = QuadraticEvent> {
pub fn new(inner: I) -> QuadraticSegments<I> {
QuadraticSegments {
inner: inner,
current_subpath_index: u32::MAX,
current_point: Point::zero(),
current_subpath_start_point: Point::zero(),
}
}
}
impl<I> Iterator for QuadraticSegments<I> where I: Iterator<Item = QuadraticEvent> {
type Item = (Segment, u32);
fn next(&mut self) -> Option<(Segment, u32)> {
loop {
match self.inner.next() {
None => return None,
Some(QuadraticEvent::MoveTo(point)) => {
self.current_subpath_index = self.current_subpath_index.wrapping_add(1);
self.current_point = point;
self.current_subpath_start_point = point;
}
Some(QuadraticEvent::LineTo(to)) => {
if points_are_sufficiently_far_apart(&self.current_point, &to) {
let from = mem::replace(&mut self.current_point, to);
return Some((
Segment::Line(LineSegment { from, to }),
self.current_subpath_index
));
}
}
Some(QuadraticEvent::QuadraticTo(ctrl, to)) => {
if points_are_sufficiently_far_apart(&self.current_point, &to) {
let from = mem::replace(&mut self.current_point, to);
return Some((
Segment::Quadratic(QuadraticBezierSegment { from, ctrl, to }),
self.current_subpath_index
));
}
}
Some(QuadraticEvent::Close) => {
let to = self.current_subpath_start_point;
if points_are_sufficiently_far_apart(&self.current_point, &to) {
let from = mem::replace(&mut self.current_point, to);
return Some((
Segment::Line(LineSegment { from, to }),
self.current_subpath_index
));
}
}
}
}
fn points_are_sufficiently_far_apart(point_a: &Point, point_b: &Point)
-> bool {
(point_a.x - point_b.x).abs() > 0.001 ||
(point_a.y - point_b.y).abs() > 0.001
}
}
}