2017-06-28 17:14:40 -04:00
|
|
|
// partitionfinder/partitioner.rs
|
|
|
|
|
|
|
|
use bit_vec::BitVec;
|
|
|
|
use euclid::Point2D;
|
2017-07-13 19:44:11 -04:00
|
|
|
use geometry::{self, SubdividedQuadraticBezier};
|
2017-07-03 19:26:55 -04:00
|
|
|
use log::LogLevel;
|
2017-06-28 17:14:40 -04:00
|
|
|
use std::collections::BinaryHeap;
|
2017-08-08 14:32:51 -04:00
|
|
|
use std::cmp::Ordering;
|
2017-07-13 19:44:11 -04:00
|
|
|
use std::f32;
|
2017-06-28 17:14:40 -04:00
|
|
|
use std::u32;
|
2017-07-13 19:44:11 -04:00
|
|
|
use {BQuad, BVertex, BVertexKind, CurveIndices, Endpoint, LineIndices, Subpath};
|
2017-06-28 17:14:40 -04:00
|
|
|
|
|
|
|
pub struct Partitioner<'a> {
|
|
|
|
endpoints: &'a [Endpoint],
|
2017-07-10 23:07:10 -04:00
|
|
|
control_points: &'a [Point2D<f32>],
|
2017-06-28 17:14:40 -04:00
|
|
|
subpaths: &'a [Subpath],
|
|
|
|
|
2017-07-06 14:39:52 -04:00
|
|
|
b_quads: Vec<BQuad>,
|
2017-07-13 19:44:11 -04:00
|
|
|
b_vertices: Vec<BVertex>,
|
|
|
|
cover_indices: CoverIndicesBuffer,
|
|
|
|
edge_indices: EdgeIndicesBuffer,
|
2017-06-28 17:14:40 -04:00
|
|
|
|
|
|
|
heap: BinaryHeap<Point>,
|
|
|
|
visited_points: BitVec,
|
|
|
|
active_edges: Vec<ActiveEdge>,
|
2017-07-13 19:44:11 -04:00
|
|
|
path_id: u32,
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Partitioner<'a> {
|
|
|
|
#[inline]
|
2017-07-03 15:32:22 -04:00
|
|
|
pub fn new<'b>() -> Partitioner<'b> {
|
2017-06-28 17:14:40 -04:00
|
|
|
Partitioner {
|
2017-07-03 15:32:22 -04:00
|
|
|
endpoints: &[],
|
|
|
|
control_points: &[],
|
|
|
|
subpaths: &[],
|
2017-06-28 17:14:40 -04:00
|
|
|
|
2017-07-06 14:39:52 -04:00
|
|
|
b_quads: vec![],
|
2017-07-13 19:44:11 -04:00
|
|
|
b_vertices: vec![],
|
|
|
|
cover_indices: CoverIndicesBuffer::new(),
|
|
|
|
edge_indices: EdgeIndicesBuffer::new(),
|
2017-06-28 17:14:40 -04:00
|
|
|
|
|
|
|
heap: BinaryHeap::new(),
|
|
|
|
visited_points: BitVec::new(),
|
|
|
|
active_edges: vec![],
|
2017-07-13 19:44:11 -04:00
|
|
|
path_id: 0,
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-03 15:32:22 -04:00
|
|
|
pub fn init(&mut self,
|
|
|
|
new_endpoints: &'a [Endpoint],
|
2017-07-10 23:07:10 -04:00
|
|
|
new_control_points: &'a [Point2D<f32>],
|
2017-07-03 15:32:22 -04:00
|
|
|
new_subpaths: &'a [Subpath]) {
|
2017-07-02 15:48:57 -04:00
|
|
|
self.endpoints = new_endpoints;
|
|
|
|
self.control_points = new_control_points;
|
|
|
|
self.subpaths = new_subpaths;
|
|
|
|
|
2017-07-04 14:51:58 -04:00
|
|
|
// FIXME(pcwalton): Move this initialization to `partition` below. Right now, this bit
|
|
|
|
// vector uses too much memory.
|
2017-07-13 19:44:11 -04:00
|
|
|
self.visited_points = BitVec::from_elem(self.endpoints.len(), false);
|
2017-07-04 14:51:58 -04:00
|
|
|
}
|
2017-07-03 15:32:22 -04:00
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
pub fn partition(&mut self, path_id: u32, first_subpath_index: u32, last_subpath_index: u32) {
|
2017-07-06 14:39:52 -04:00
|
|
|
self.b_quads.clear();
|
2017-07-13 19:44:11 -04:00
|
|
|
self.b_vertices.clear();
|
|
|
|
self.cover_indices.clear();
|
|
|
|
self.edge_indices.clear();
|
2017-07-02 15:48:57 -04:00
|
|
|
self.heap.clear();
|
|
|
|
self.active_edges.clear();
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
self.path_id = path_id;
|
|
|
|
|
2017-07-03 15:32:22 -04:00
|
|
|
self.init_heap(first_subpath_index, last_subpath_index);
|
2017-07-04 14:51:58 -04:00
|
|
|
|
2017-07-02 15:48:57 -04:00
|
|
|
while self.process_next_point() {}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2017-07-06 14:39:52 -04:00
|
|
|
pub fn b_quads(&self) -> &[BQuad] {
|
|
|
|
&self.b_quads
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
#[inline]
|
|
|
|
pub fn b_vertices(&self) -> &[BVertex] {
|
|
|
|
&self.b_vertices
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn cover_indices(&self) -> CoverIndices {
|
|
|
|
self.cover_indices.as_ref()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn edge_indices(&self) -> EdgeIndices {
|
|
|
|
self.edge_indices.as_ref()
|
|
|
|
}
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
fn process_next_point(&mut self) -> bool {
|
|
|
|
let point = match self.heap.peek() {
|
|
|
|
Some(point) => *point,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if self.already_visited_point(&point) {
|
|
|
|
self.heap.pop();
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2017-07-03 19:26:55 -04:00
|
|
|
debug!("processing point {}: {:?}",
|
|
|
|
point.endpoint_index,
|
|
|
|
self.endpoints[point.endpoint_index as usize].position);
|
|
|
|
|
|
|
|
if log_enabled!(LogLevel::Debug) {
|
|
|
|
debug!("... active edges:");
|
|
|
|
for (active_edge_index, active_edge) in self.active_edges.iter().enumerate() {
|
|
|
|
debug!("... ... edge {}: {:?}", active_edge_index, active_edge);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
self.mark_point_as_visited(&point);
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
self.sort_active_edge_list(point.endpoint_index);
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
let matching_active_edges = self.find_right_point_in_active_edge_list(point.endpoint_index);
|
2017-07-13 19:44:11 -04:00
|
|
|
match matching_active_edges.count {
|
|
|
|
0 => self.process_min_endpoint(point.endpoint_index),
|
|
|
|
1 => {
|
|
|
|
self.process_regular_endpoint(point.endpoint_index,
|
|
|
|
matching_active_edges.indices[0])
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
2017-07-13 19:44:11 -04:00
|
|
|
2 => self.process_max_endpoint(point.endpoint_index, matching_active_edges.indices),
|
|
|
|
_ => debug_assert!(false),
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_min_endpoint(&mut self, endpoint_index: u32) {
|
2017-07-03 19:26:55 -04:00
|
|
|
debug!("... MIN point");
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
let next_active_edge_index = self.find_point_between_active_edges(endpoint_index);
|
|
|
|
|
|
|
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
|
|
|
if self.should_fill_above_active_edge(next_active_edge_index) {
|
2017-07-06 14:39:52 -04:00
|
|
|
self.emit_b_quad_above(next_active_edge_index, endpoint.position.x)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
self.add_new_edges_for_min_point(endpoint_index, next_active_edge_index);
|
|
|
|
|
|
|
|
let prev_endpoint_index = self.prev_endpoint_of(endpoint_index);
|
|
|
|
let next_endpoint_index = self.next_endpoint_of(endpoint_index);
|
|
|
|
let new_point = self.create_point_from_endpoint(next_endpoint_index);
|
|
|
|
*self.heap.peek_mut().unwrap() = new_point;
|
|
|
|
if next_endpoint_index != prev_endpoint_index {
|
|
|
|
let new_point = self.create_point_from_endpoint(prev_endpoint_index);
|
|
|
|
self.heap.push(new_point)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_regular_endpoint(&mut self, endpoint_index: u32, active_edge_index: u32) {
|
2017-07-03 19:26:55 -04:00
|
|
|
debug!("... REGULAR point: active edge {}", active_edge_index);
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
2017-07-13 19:44:11 -04:00
|
|
|
let bottom = self.should_fill_above_active_edge(active_edge_index);
|
|
|
|
if !bottom {
|
2017-07-06 14:39:52 -04:00
|
|
|
self.emit_b_quad_below(active_edge_index, endpoint.position.x)
|
2017-07-13 19:44:11 -04:00
|
|
|
} else {
|
2017-07-06 14:39:52 -04:00
|
|
|
self.emit_b_quad_above(active_edge_index, endpoint.position.x)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let prev_endpoint_index = self.prev_endpoint_of(endpoint_index);
|
|
|
|
let next_endpoint_index = self.next_endpoint_of(endpoint_index);
|
|
|
|
|
|
|
|
{
|
|
|
|
let active_edge = &mut self.active_edges[active_edge_index as usize];
|
2017-07-13 19:44:11 -04:00
|
|
|
active_edge.left_vertex_index = self.b_vertices.len() as u32;
|
|
|
|
active_edge.control_point_vertex_index = active_edge.left_vertex_index + 1;
|
|
|
|
|
|
|
|
let endpoint_position = self.endpoints[active_edge.right_endpoint_index as usize]
|
|
|
|
.position;
|
|
|
|
self.b_vertices
|
|
|
|
.push(BVertex::new(&endpoint_position, active_edge.endpoint_kind(), self.path_id));
|
|
|
|
|
|
|
|
active_edge.toggle_parity();
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
if active_edge.left_to_right {
|
|
|
|
active_edge.right_endpoint_index = next_endpoint_index;
|
|
|
|
} else {
|
|
|
|
active_edge.right_endpoint_index = prev_endpoint_index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let right_endpoint_index = self.active_edges[active_edge_index as usize]
|
|
|
|
.right_endpoint_index;
|
|
|
|
let new_point = self.create_point_from_endpoint(right_endpoint_index);
|
|
|
|
*self.heap.peek_mut().unwrap() = new_point;
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
let control_point_index = if self.active_edges[active_edge_index as usize].left_to_right {
|
|
|
|
self.control_point_index_before_endpoint(next_endpoint_index)
|
|
|
|
} else {
|
|
|
|
self.control_point_index_after_endpoint(prev_endpoint_index)
|
|
|
|
};
|
|
|
|
|
|
|
|
match control_point_index {
|
|
|
|
u32::MAX => {
|
|
|
|
self.active_edges[active_edge_index as usize].control_point_vertex_index = u32::MAX
|
|
|
|
}
|
|
|
|
control_point_index => {
|
|
|
|
self.active_edges[active_edge_index as usize].control_point_vertex_index =
|
|
|
|
self.b_vertices.len() as u32;
|
|
|
|
|
|
|
|
let left_vertex_index = self.active_edges[active_edge_index as usize]
|
|
|
|
.left_vertex_index;
|
|
|
|
let control_point_position = &self.control_points[control_point_index as usize];
|
|
|
|
let control_point_b_vertex =
|
|
|
|
BVertex::control_point(&self.b_vertices[left_vertex_index as usize].position,
|
|
|
|
&control_point_position,
|
|
|
|
&new_point.position,
|
|
|
|
self.path_id,
|
|
|
|
bottom);
|
|
|
|
self.b_vertices.push(control_point_b_vertex)
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_max_endpoint(&mut self, endpoint_index: u32, active_edge_indices: [u32; 2]) {
|
2017-07-03 19:26:55 -04:00
|
|
|
debug!("... MAX point: active edges {:?}", active_edge_indices);
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
debug_assert!(active_edge_indices[0] < active_edge_indices[1],
|
|
|
|
"Matching active edge indices in wrong order when processing MAX point");
|
|
|
|
|
|
|
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
|
|
|
|
|
|
|
if self.should_fill_above_active_edge(active_edge_indices[0]) {
|
2017-07-06 14:39:52 -04:00
|
|
|
self.emit_b_quad_above(active_edge_indices[0], endpoint.position.x)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
if self.should_fill_above_active_edge(active_edge_indices[1]) {
|
2017-07-06 14:39:52 -04:00
|
|
|
self.emit_b_quad_above(active_edge_indices[1], endpoint.position.x)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
if self.should_fill_below_active_edge(active_edge_indices[1]) {
|
2017-07-06 14:39:52 -04:00
|
|
|
self.emit_b_quad_below(active_edge_indices[1], endpoint.position.x)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
self.heap.pop();
|
|
|
|
|
|
|
|
// FIXME(pcwalton): This is twice as slow as it needs to be.
|
|
|
|
self.active_edges.remove(active_edge_indices[1] as usize);
|
|
|
|
self.active_edges.remove(active_edge_indices[0] as usize);
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
fn sort_active_edge_list(&mut self, endpoint_index: u32) {
|
|
|
|
for index in 1..self.active_edges.len() {
|
|
|
|
for sorted_index in (1..(index + 1)).rev() {
|
|
|
|
if self.active_edges_are_ordered((sorted_index - 1) as u32,
|
|
|
|
sorted_index as u32,
|
|
|
|
endpoint_index) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
self.active_edges.swap(sorted_index - 1, sorted_index)
|
|
|
|
}
|
2017-07-04 14:51:58 -04:00
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn add_new_edges_for_min_point(&mut self, endpoint_index: u32, next_active_edge_index: u32) {
|
|
|
|
// FIXME(pcwalton): This is twice as slow as it needs to be.
|
|
|
|
self.active_edges.insert(next_active_edge_index as usize, ActiveEdge::default());
|
|
|
|
self.active_edges.insert(next_active_edge_index as usize, ActiveEdge::default());
|
|
|
|
|
|
|
|
let prev_endpoint_index = self.prev_endpoint_of(endpoint_index);
|
|
|
|
let next_endpoint_index = self.next_endpoint_of(endpoint_index);
|
|
|
|
|
|
|
|
let new_active_edges = &mut self.active_edges[next_active_edge_index as usize..
|
|
|
|
next_active_edge_index as usize + 2];
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
let left_vertex_index = self.b_vertices.len() as u32;
|
|
|
|
new_active_edges[0].left_vertex_index = left_vertex_index;
|
|
|
|
new_active_edges[1].left_vertex_index = left_vertex_index;
|
|
|
|
|
|
|
|
let position = self.endpoints[endpoint_index as usize].position;
|
|
|
|
self.b_vertices.push(BVertex::new(&position, BVertexKind::Endpoint0, self.path_id));
|
|
|
|
|
|
|
|
new_active_edges[0].toggle_parity();
|
|
|
|
new_active_edges[1].toggle_parity();
|
2017-07-03 20:02:59 -04:00
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
|
|
|
let prev_endpoint = &self.endpoints[prev_endpoint_index as usize];
|
|
|
|
let next_endpoint = &self.endpoints[next_endpoint_index as usize];
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
let prev_vector = prev_endpoint.position - endpoint.position;
|
|
|
|
let next_vector = next_endpoint.position - endpoint.position;
|
2017-06-28 17:14:40 -04:00
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
let (upper_control_point_index, lower_control_point_index);
|
|
|
|
if prev_vector.cross(next_vector) >= 0.0 {
|
2017-06-28 17:14:40 -04:00
|
|
|
new_active_edges[0].right_endpoint_index = prev_endpoint_index;
|
|
|
|
new_active_edges[1].right_endpoint_index = next_endpoint_index;
|
|
|
|
new_active_edges[0].left_to_right = false;
|
|
|
|
new_active_edges[1].left_to_right = true;
|
2017-07-13 19:44:11 -04:00
|
|
|
|
|
|
|
upper_control_point_index = self.endpoints[endpoint_index as usize].control_point_index;
|
|
|
|
lower_control_point_index = self.endpoints[next_endpoint_index as usize]
|
|
|
|
.control_point_index;
|
2017-06-28 17:14:40 -04:00
|
|
|
} else {
|
|
|
|
new_active_edges[0].right_endpoint_index = next_endpoint_index;
|
|
|
|
new_active_edges[1].right_endpoint_index = prev_endpoint_index;
|
|
|
|
new_active_edges[0].left_to_right = true;
|
|
|
|
new_active_edges[1].left_to_right = false;
|
2017-07-13 19:44:11 -04:00
|
|
|
|
|
|
|
upper_control_point_index = self.endpoints[next_endpoint_index as usize]
|
|
|
|
.control_point_index;
|
|
|
|
lower_control_point_index = self.endpoints[endpoint_index as usize].control_point_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
match upper_control_point_index {
|
|
|
|
u32::MAX => new_active_edges[0].control_point_vertex_index = u32::MAX,
|
|
|
|
upper_control_point_index => {
|
|
|
|
new_active_edges[0].control_point_vertex_index = self.b_vertices.len() as u32;
|
|
|
|
|
|
|
|
let control_point_position =
|
|
|
|
self.control_points[upper_control_point_index as usize];
|
|
|
|
let right_vertex_position =
|
|
|
|
self.endpoints[new_active_edges[0].right_endpoint_index as usize].position;
|
|
|
|
let control_point_b_vertex = BVertex::control_point(&position,
|
|
|
|
&control_point_position,
|
|
|
|
&right_vertex_position,
|
|
|
|
self.path_id,
|
|
|
|
false);
|
|
|
|
self.b_vertices.push(control_point_b_vertex)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match lower_control_point_index {
|
|
|
|
u32::MAX => new_active_edges[1].control_point_vertex_index = u32::MAX,
|
|
|
|
lower_control_point_index => {
|
|
|
|
new_active_edges[1].control_point_vertex_index = self.b_vertices.len() as u32;
|
|
|
|
|
|
|
|
let control_point_position =
|
|
|
|
self.control_points[lower_control_point_index as usize];
|
|
|
|
let right_vertex_position =
|
|
|
|
self.endpoints[new_active_edges[1].right_endpoint_index as usize].position;
|
|
|
|
let control_point_b_vertex = BVertex::control_point(&position,
|
|
|
|
&control_point_position,
|
|
|
|
&right_vertex_position,
|
|
|
|
self.path_id,
|
|
|
|
true);
|
|
|
|
self.b_vertices.push(control_point_b_vertex)
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
fn active_edges_are_ordered(&mut self,
|
|
|
|
prev_active_edge_index: u32,
|
|
|
|
next_active_edge_index: u32,
|
|
|
|
reference_endpoint_index: u32)
|
|
|
|
-> bool {
|
|
|
|
let prev_active_edge = &self.active_edges[prev_active_edge_index as usize];
|
|
|
|
let next_active_edge = &self.active_edges[next_active_edge_index as usize];
|
|
|
|
if prev_active_edge.right_endpoint_index == next_active_edge.right_endpoint_index {
|
|
|
|
// Always ordered.
|
|
|
|
// FIXME(pcwalton): Is this true?
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
let prev_active_edge_right_endpoint =
|
|
|
|
&self.endpoints[prev_active_edge.right_endpoint_index as usize];
|
|
|
|
let next_active_edge_right_endpoint =
|
|
|
|
&self.endpoints[next_active_edge.right_endpoint_index as usize];
|
|
|
|
if prev_active_edge_right_endpoint.position.y <=
|
|
|
|
next_active_edge_right_endpoint.position.y {
|
|
|
|
// Guaranteed to be ordered.
|
|
|
|
// FIXME(pcwalton): Is this true?
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slow path.
|
|
|
|
let reference_endpoint = &self.endpoints[reference_endpoint_index as usize];
|
|
|
|
let prev_active_edge_y = self.solve_active_edge_y_for_x(reference_endpoint.position.x,
|
|
|
|
prev_active_edge);
|
|
|
|
let next_active_edge_y = self.solve_active_edge_y_for_x(reference_endpoint.position.x,
|
|
|
|
next_active_edge);
|
|
|
|
prev_active_edge_y <= next_active_edge_y
|
|
|
|
}
|
|
|
|
|
2017-07-03 15:32:22 -04:00
|
|
|
fn init_heap(&mut self, first_subpath_index: u32, last_subpath_index: u32) {
|
|
|
|
for subpath in &self.subpaths[(first_subpath_index as usize)..
|
|
|
|
(last_subpath_index as usize)] {
|
|
|
|
for endpoint_index in subpath.first_endpoint_index..subpath.last_endpoint_index {
|
|
|
|
match self.classify_endpoint(endpoint_index) {
|
|
|
|
EndpointClass::Min => {
|
|
|
|
let new_point = self.create_point_from_endpoint(endpoint_index);
|
|
|
|
self.heap.push(new_point)
|
|
|
|
}
|
|
|
|
EndpointClass::Regular | EndpointClass::Max => {}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn should_fill_below_active_edge(&self, active_edge_index: u32) -> bool {
|
|
|
|
// TODO(pcwalton): Support the winding fill rule.
|
|
|
|
active_edge_index % 2 == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn should_fill_above_active_edge(&self, active_edge_index: u32) -> bool {
|
|
|
|
// TODO(pcwalton): Support the winding fill rule.
|
|
|
|
active_edge_index % 2 == 1
|
|
|
|
}
|
|
|
|
|
2017-07-06 14:39:52 -04:00
|
|
|
fn emit_b_quad_below(&mut self, upper_active_edge_index: u32, right_x: f32) {
|
|
|
|
self.emit_b_quad_above(upper_active_edge_index + 1, right_x)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
2017-07-06 14:39:52 -04:00
|
|
|
fn emit_b_quad_above(&mut self, lower_active_edge_index: u32, right_x: f32) {
|
2017-06-28 17:14:40 -04:00
|
|
|
// TODO(pcwalton): Assert that the green X position is the same on both edges.
|
|
|
|
debug_assert!(lower_active_edge_index > 0,
|
2017-07-06 14:39:52 -04:00
|
|
|
"Can't emit b_quads above the top active edge");
|
2017-06-28 17:14:40 -04:00
|
|
|
let upper_active_edge_index = lower_active_edge_index - 1;
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
let upper_curve = self.subdivide_active_edge_at(upper_active_edge_index, right_x);
|
|
|
|
let lower_curve = self.subdivide_active_edge_at(lower_active_edge_index, right_x);
|
2017-06-28 17:14:40 -04:00
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
// NB: Order is important here—we depend on the provoking vertex!
|
2017-06-28 17:14:40 -04:00
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
let upper_shape = upper_curve.shape(&self.b_vertices);
|
|
|
|
let lower_shape = lower_curve.shape(&self.b_vertices);
|
2017-06-28 17:14:40 -04:00
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
match upper_shape {
|
|
|
|
Shape::Flat => {
|
|
|
|
self.edge_indices
|
|
|
|
.upper_line_indices
|
|
|
|
.push(LineIndices::new(upper_curve.left_curve_left, upper_curve.middle_point))
|
|
|
|
}
|
|
|
|
Shape::Convex | Shape::Concave => {
|
|
|
|
self.edge_indices
|
|
|
|
.upper_curve_indices
|
|
|
|
.push(CurveIndices::new(upper_curve.left_curve_left,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
upper_curve.middle_point))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match lower_shape {
|
|
|
|
Shape::Flat => {
|
|
|
|
self.edge_indices
|
|
|
|
.lower_line_indices
|
|
|
|
.push(LineIndices::new(lower_curve.left_curve_left, lower_curve.middle_point))
|
|
|
|
}
|
|
|
|
Shape::Convex | Shape::Concave => {
|
|
|
|
self.edge_indices
|
|
|
|
.lower_curve_indices
|
|
|
|
.push(CurveIndices::new(lower_curve.left_curve_left,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
lower_curve.middle_point))
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
match (upper_shape, lower_shape) {
|
|
|
|
(Shape::Flat, Shape::Flat) |
|
|
|
|
(Shape::Flat, Shape::Convex) |
|
|
|
|
(Shape::Convex, Shape::Flat) |
|
|
|
|
(Shape::Convex, Shape::Convex) => {
|
|
|
|
self.cover_indices.interior_indices.extend([
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
].into_iter());
|
|
|
|
if upper_shape != Shape::Flat {
|
|
|
|
self.cover_indices.curve_indices.extend([
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
].into_iter())
|
|
|
|
}
|
|
|
|
if lower_shape != Shape::Flat {
|
|
|
|
self.cover_indices.curve_indices.extend([
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
].into_iter())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(Shape::Concave, Shape::Flat) |
|
|
|
|
(Shape::Concave, Shape::Convex) => {
|
|
|
|
self.cover_indices.interior_indices.extend([
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
].into_iter());
|
|
|
|
self.cover_indices.curve_indices.extend([
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
].into_iter());
|
|
|
|
if lower_shape != Shape::Flat {
|
|
|
|
self.cover_indices.curve_indices.extend([
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
].into_iter())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(Shape::Flat, Shape::Concave) |
|
|
|
|
(Shape::Convex, Shape::Concave) => {
|
|
|
|
self.cover_indices.interior_indices.extend([
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
].into_iter());
|
|
|
|
self.cover_indices.curve_indices.extend([
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
].into_iter());
|
|
|
|
if upper_shape != Shape::Flat {
|
|
|
|
self.cover_indices.curve_indices.extend([
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
].into_iter())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(Shape::Concave, Shape::Concave) => {
|
|
|
|
self.cover_indices.interior_indices.extend([
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
].into_iter());
|
|
|
|
self.cover_indices.curve_indices.extend([
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
upper_curve.left_curve_left,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
lower_curve.middle_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
].into_iter());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.b_quads.push(BQuad::new(upper_curve.left_curve_left,
|
|
|
|
upper_curve.left_curve_control_point,
|
|
|
|
upper_curve.middle_point,
|
|
|
|
lower_curve.left_curve_left,
|
|
|
|
lower_curve.left_curve_control_point,
|
|
|
|
lower_curve.middle_point))
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn already_visited_point(&self, point: &Point) -> bool {
|
|
|
|
// FIXME(pcwalton): This makes the visited vector too big.
|
2017-07-13 19:44:11 -04:00
|
|
|
let index = point.endpoint_index as usize;
|
2017-06-28 17:14:40 -04:00
|
|
|
match self.visited_points.get(index) {
|
|
|
|
None => false,
|
|
|
|
Some(visited) => visited,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mark_point_as_visited(&mut self, point: &Point) {
|
|
|
|
// FIXME(pcwalton): This makes the visited vector too big.
|
2017-07-13 19:44:11 -04:00
|
|
|
self.visited_points.set(point.endpoint_index as usize, true)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn find_right_point_in_active_edge_list(&self, endpoint_index: u32) -> MatchingActiveEdges {
|
|
|
|
let mut matching_active_edges = MatchingActiveEdges {
|
|
|
|
indices: [0, 0],
|
|
|
|
count: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (active_edge_index, active_edge) in self.active_edges.iter().enumerate() {
|
|
|
|
if active_edge.right_endpoint_index == endpoint_index {
|
|
|
|
matching_active_edges.indices[matching_active_edges.count as usize] =
|
|
|
|
active_edge_index as u32;
|
|
|
|
matching_active_edges.count += 1;
|
|
|
|
if matching_active_edges.count == 2 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
matching_active_edges
|
|
|
|
}
|
|
|
|
|
|
|
|
fn classify_endpoint(&self, endpoint_index: u32) -> EndpointClass {
|
|
|
|
// Create temporary points just for the comparison.
|
|
|
|
let point = self.create_point_from_endpoint(endpoint_index);
|
|
|
|
let prev_point = self.create_point_from_endpoint(self.prev_endpoint_of(endpoint_index));
|
|
|
|
let next_point = self.create_point_from_endpoint(self.next_endpoint_of(endpoint_index));
|
|
|
|
|
2017-07-03 19:26:55 -04:00
|
|
|
// Remember to reverse, because the comparison is reversed (as the heap is a max-heap).
|
|
|
|
match (prev_point.cmp(&point).reverse(), next_point.cmp(&point).reverse()) {
|
2017-06-28 17:14:40 -04:00
|
|
|
(Ordering::Less, Ordering::Less) => EndpointClass::Max,
|
|
|
|
(Ordering::Less, _) | (_, Ordering::Less) => EndpointClass::Regular,
|
|
|
|
(_, _) => EndpointClass::Min,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_point_between_active_edges(&self, endpoint_index: u32) -> u32 {
|
|
|
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
|
|
|
match self.active_edges.iter().position(|active_edge| {
|
|
|
|
self.solve_active_edge_y_for_x(endpoint.position.x, active_edge) > endpoint.position.y
|
|
|
|
}) {
|
|
|
|
Some(active_edge_index) => active_edge_index as u32,
|
|
|
|
None => self.active_edges.len() as u32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
fn solve_active_edge_t_for_x(&self, x: f32, active_edge: &ActiveEdge) -> f32 {
|
|
|
|
let left_vertex_position = &self.b_vertices[active_edge.left_vertex_index as usize]
|
|
|
|
.position;
|
|
|
|
let right_endpoint_position = &self.endpoints[active_edge.right_endpoint_index as usize]
|
|
|
|
.position;
|
|
|
|
match active_edge.control_point_vertex_index {
|
|
|
|
u32::MAX => {
|
|
|
|
geometry::solve_line_t_for_x(x, left_vertex_position, right_endpoint_position)
|
|
|
|
}
|
|
|
|
control_point_vertex_index => {
|
|
|
|
let control_point = &self.b_vertices[control_point_vertex_index as usize].position;
|
|
|
|
geometry::solve_quadratic_bezier_t_for_x(x,
|
|
|
|
left_vertex_position,
|
|
|
|
control_point,
|
|
|
|
right_endpoint_position)
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
fn solve_active_edge_y_for_x(&self, x: f32, active_edge: &ActiveEdge) -> f32 {
|
|
|
|
self.sample_active_edge(self.solve_active_edge_t_for_x(x, active_edge), active_edge).y
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
fn sample_active_edge(&self, t: f32, active_edge: &ActiveEdge) -> Point2D<f32> {
|
|
|
|
let left_vertex_position = &self.b_vertices[active_edge.left_vertex_index as usize]
|
|
|
|
.position;
|
|
|
|
let right_endpoint_position = &self.endpoints[active_edge.right_endpoint_index as usize]
|
|
|
|
.position;
|
|
|
|
match active_edge.control_point_vertex_index {
|
|
|
|
u32::MAX => {
|
|
|
|
left_vertex_position.to_vector()
|
|
|
|
.lerp(right_endpoint_position.to_vector(), t)
|
|
|
|
.to_point()
|
|
|
|
}
|
|
|
|
control_point_vertex_index => {
|
|
|
|
let control_point = &self.b_vertices[control_point_vertex_index as usize].position;
|
|
|
|
geometry::sample_quadratic_bezier(t,
|
|
|
|
left_vertex_position,
|
|
|
|
control_point,
|
|
|
|
right_endpoint_position)
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn crossing_point_for_active_edge(&self, upper_active_edge_index: u32)
|
|
|
|
-> Option<Point2D<f32>> {
|
|
|
|
let lower_active_edge_index = upper_active_edge_index + 1;
|
|
|
|
|
|
|
|
let upper_active_edge = &self.active_edges[upper_active_edge_index as usize];
|
|
|
|
let lower_active_edge = &self.active_edges[lower_active_edge_index as usize];
|
2017-07-13 19:44:11 -04:00
|
|
|
if upper_active_edge.left_vertex_index == lower_active_edge.left_vertex_index ||
|
2017-06-28 17:14:40 -04:00
|
|
|
upper_active_edge.right_endpoint_index == lower_active_edge.right_endpoint_index {
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
let upper_left_vertex_position =
|
|
|
|
&self.b_vertices[upper_active_edge.left_vertex_index as usize].position;
|
|
|
|
let upper_right_endpoint_position =
|
|
|
|
&self.endpoints[upper_active_edge.right_endpoint_index as usize].position;
|
|
|
|
let lower_left_vertex_position =
|
|
|
|
&self.b_vertices[lower_active_edge.left_vertex_index as usize].position;
|
|
|
|
let lower_right_endpoint_position =
|
|
|
|
&self.endpoints[lower_active_edge.right_endpoint_index as usize].position;
|
|
|
|
|
|
|
|
match (upper_active_edge.control_point_vertex_index,
|
|
|
|
lower_active_edge.control_point_vertex_index) {
|
2017-06-28 17:14:40 -04:00
|
|
|
(u32::MAX, u32::MAX) => {
|
2017-07-13 19:44:11 -04:00
|
|
|
geometry::line_line_crossing_point(upper_left_vertex_position,
|
|
|
|
upper_right_endpoint_position,
|
|
|
|
lower_left_vertex_position,
|
|
|
|
lower_right_endpoint_position)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
2017-07-13 19:44:11 -04:00
|
|
|
(upper_control_point_vertex_index, u32::MAX) => {
|
|
|
|
let upper_control_point =
|
|
|
|
&self.b_vertices[upper_control_point_vertex_index as usize].position;
|
|
|
|
geometry::line_quadratic_bezier_crossing_point(lower_left_vertex_position,
|
|
|
|
lower_right_endpoint_position,
|
|
|
|
upper_left_vertex_position,
|
|
|
|
upper_control_point,
|
|
|
|
upper_right_endpoint_position)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
2017-07-13 19:44:11 -04:00
|
|
|
(u32::MAX, lower_control_point_vertex_index) => {
|
|
|
|
let lower_control_point =
|
|
|
|
&self.b_vertices[lower_control_point_vertex_index as usize].position;
|
|
|
|
geometry::line_quadratic_bezier_crossing_point(upper_left_vertex_position,
|
|
|
|
upper_right_endpoint_position,
|
|
|
|
lower_left_vertex_position,
|
|
|
|
lower_control_point,
|
|
|
|
lower_right_endpoint_position)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
2017-07-13 19:44:11 -04:00
|
|
|
(upper_control_point_vertex_index, lower_control_point_vertex_index) => {
|
|
|
|
let upper_control_point =
|
|
|
|
&self.b_vertices[upper_control_point_vertex_index as usize].position;
|
|
|
|
let lower_control_point =
|
|
|
|
&self.b_vertices[lower_control_point_vertex_index as usize].position;
|
|
|
|
geometry::quadratic_bezier_quadratic_bezier_crossing_point(
|
|
|
|
upper_left_vertex_position,
|
|
|
|
upper_control_point,
|
|
|
|
upper_right_endpoint_position,
|
|
|
|
lower_left_vertex_position,
|
|
|
|
lower_control_point,
|
|
|
|
lower_right_endpoint_position)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
fn subdivide_active_edge_at(&mut self, active_edge_index: u32, x: f32) -> SubdividedActiveEdge {
|
|
|
|
let t = self.solve_active_edge_t_for_x(x, &self.active_edges[active_edge_index as usize]);
|
|
|
|
|
|
|
|
let bottom = self.should_fill_above_active_edge(active_edge_index);
|
|
|
|
|
|
|
|
let active_edge = &mut self.active_edges[active_edge_index as usize];
|
|
|
|
let left_curve_left = active_edge.left_vertex_index;
|
|
|
|
|
|
|
|
let left_curve_control_point_vertex_index;
|
|
|
|
match active_edge.control_point_vertex_index {
|
|
|
|
u32::MAX => {
|
|
|
|
let left_point = self.b_vertices[left_curve_left as usize];
|
|
|
|
let right_point = self.endpoints[active_edge.right_endpoint_index as usize]
|
|
|
|
.position;
|
|
|
|
let middle_point = left_point.position.to_vector().lerp(right_point.to_vector(), t);
|
|
|
|
|
|
|
|
active_edge.left_vertex_index = self.b_vertices.len() as u32;
|
|
|
|
self.b_vertices.push(BVertex::new(&middle_point.to_point(),
|
|
|
|
active_edge.endpoint_kind(),
|
|
|
|
left_point.path_id));
|
|
|
|
|
|
|
|
active_edge.toggle_parity();
|
|
|
|
|
|
|
|
left_curve_control_point_vertex_index = u32::MAX;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let left_endpoint_position = self.b_vertices[active_edge.left_vertex_index as usize]
|
|
|
|
.position;
|
|
|
|
let right_endpoint_position =
|
|
|
|
self.endpoints[active_edge.right_endpoint_index as usize].position;
|
|
|
|
let subdivided_quadratic_bezier = SubdividedQuadraticBezier::new(
|
|
|
|
t,
|
|
|
|
&left_endpoint_position,
|
|
|
|
&self.b_vertices[active_edge.control_point_vertex_index as usize].position,
|
|
|
|
&right_endpoint_position);
|
|
|
|
|
|
|
|
let control_point_b_vertex_a =
|
|
|
|
BVertex::control_point(&left_endpoint_position,
|
|
|
|
&subdivided_quadratic_bezier.ap1,
|
|
|
|
&subdivided_quadratic_bezier.ap2bp0,
|
|
|
|
self.path_id,
|
|
|
|
bottom);
|
|
|
|
|
|
|
|
left_curve_control_point_vertex_index = self.b_vertices.len() as u32;
|
|
|
|
active_edge.left_vertex_index = left_curve_control_point_vertex_index + 1;
|
|
|
|
|
|
|
|
self.b_vertices.extend([
|
|
|
|
control_point_b_vertex_a,
|
|
|
|
BVertex::new(&subdivided_quadratic_bezier.ap2bp0,
|
|
|
|
active_edge.endpoint_kind(),
|
|
|
|
self.path_id)
|
|
|
|
].into_iter());
|
|
|
|
|
|
|
|
let control_point_b_vertex_b =
|
|
|
|
BVertex::control_point(&subdivided_quadratic_bezier.ap2bp0,
|
|
|
|
&subdivided_quadratic_bezier.bp1,
|
|
|
|
&right_endpoint_position,
|
|
|
|
self.path_id,
|
|
|
|
bottom);
|
|
|
|
|
|
|
|
active_edge.control_point_vertex_index = self.b_vertices.len() as u32;
|
|
|
|
self.b_vertices.push(control_point_b_vertex_b);
|
|
|
|
|
|
|
|
active_edge.toggle_parity();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SubdividedActiveEdge {
|
|
|
|
left_curve_left: left_curve_left,
|
|
|
|
left_curve_control_point: left_curve_control_point_vertex_index,
|
|
|
|
middle_point: active_edge.left_vertex_index,
|
|
|
|
right_curve_control_point: active_edge.control_point_vertex_index,
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn prev_endpoint_of(&self, endpoint_index: u32) -> u32 {
|
|
|
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
2017-07-03 15:32:22 -04:00
|
|
|
let subpath = &self.subpaths[endpoint.subpath_index as usize];
|
|
|
|
if endpoint_index > subpath.first_endpoint_index {
|
2017-06-28 17:14:40 -04:00
|
|
|
endpoint_index - 1
|
|
|
|
} else {
|
2017-07-03 15:32:22 -04:00
|
|
|
subpath.last_endpoint_index - 1
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn next_endpoint_of(&self, endpoint_index: u32) -> u32 {
|
|
|
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
2017-07-03 15:32:22 -04:00
|
|
|
let subpath = &self.subpaths[endpoint.subpath_index as usize];
|
|
|
|
if endpoint_index + 1 < subpath.last_endpoint_index {
|
2017-06-28 17:14:40 -04:00
|
|
|
endpoint_index + 1
|
|
|
|
} else {
|
2017-07-03 15:32:22 -04:00
|
|
|
subpath.first_endpoint_index
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_point_from_endpoint(&self, endpoint_index: u32) -> Point {
|
|
|
|
Point {
|
|
|
|
position: self.endpoints[endpoint_index as usize].position,
|
|
|
|
endpoint_index: endpoint_index,
|
2017-07-13 19:44:11 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn control_point_index_before_endpoint(&self, endpoint_index: u32) -> u32 {
|
|
|
|
self.endpoints[endpoint_index as usize].control_point_index
|
|
|
|
}
|
|
|
|
|
|
|
|
fn control_point_index_after_endpoint(&self, endpoint_index: u32) -> u32 {
|
|
|
|
self.control_point_index_before_endpoint(self.next_endpoint_of(endpoint_index))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct CoverIndicesBuffer {
|
|
|
|
interior_indices: Vec<u32>,
|
|
|
|
curve_indices: Vec<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CoverIndicesBuffer {
|
|
|
|
fn new() -> CoverIndicesBuffer {
|
|
|
|
CoverIndicesBuffer {
|
|
|
|
interior_indices: vec![],
|
|
|
|
curve_indices: vec![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear(&mut self) {
|
|
|
|
self.interior_indices.clear();
|
|
|
|
self.curve_indices.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_ref(&self) -> CoverIndices {
|
|
|
|
CoverIndices {
|
|
|
|
interior_indices: &self.interior_indices,
|
|
|
|
curve_indices: &self.curve_indices,
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub struct CoverIndices<'a> {
|
|
|
|
pub interior_indices: &'a [u32],
|
|
|
|
pub curve_indices: &'a [u32],
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct EdgeIndicesBuffer {
|
|
|
|
upper_line_indices: Vec<LineIndices>,
|
|
|
|
upper_curve_indices: Vec<CurveIndices>,
|
|
|
|
lower_line_indices: Vec<LineIndices>,
|
|
|
|
lower_curve_indices: Vec<CurveIndices>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EdgeIndicesBuffer {
|
|
|
|
fn new() -> EdgeIndicesBuffer {
|
|
|
|
EdgeIndicesBuffer {
|
|
|
|
upper_line_indices: vec![],
|
|
|
|
upper_curve_indices: vec![],
|
|
|
|
lower_line_indices: vec![],
|
|
|
|
lower_curve_indices: vec![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear(&mut self) {
|
|
|
|
self.upper_line_indices.clear();
|
|
|
|
self.upper_curve_indices.clear();
|
|
|
|
self.lower_line_indices.clear();
|
|
|
|
self.lower_curve_indices.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_ref(&self) -> EdgeIndices {
|
|
|
|
EdgeIndices {
|
|
|
|
upper_line_indices: &self.upper_line_indices,
|
|
|
|
upper_curve_indices: &self.upper_curve_indices,
|
|
|
|
lower_line_indices: &self.lower_line_indices,
|
|
|
|
lower_curve_indices: &self.lower_curve_indices,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub struct EdgeIndices<'a> {
|
|
|
|
pub upper_line_indices: &'a [LineIndices],
|
|
|
|
pub upper_curve_indices: &'a [CurveIndices],
|
|
|
|
pub lower_line_indices: &'a [LineIndices],
|
|
|
|
pub lower_curve_indices: &'a [CurveIndices],
|
|
|
|
}
|
|
|
|
|
2017-06-28 17:14:40 -04:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
struct Point {
|
|
|
|
position: Point2D<f32>,
|
|
|
|
endpoint_index: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Point {
|
|
|
|
#[inline]
|
|
|
|
fn eq(&self, other: &Point) -> bool {
|
|
|
|
self.position == other.position && self.endpoint_index == other.endpoint_index
|
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
fn ne(&self, other: &Point) -> bool {
|
|
|
|
self.position != other.position || self.endpoint_index != other.endpoint_index
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for Point {}
|
|
|
|
|
|
|
|
impl PartialOrd for Point {
|
|
|
|
#[inline]
|
|
|
|
fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
|
2017-07-03 19:26:55 -04:00
|
|
|
// Reverse, because `std::collections::BinaryHeap` is a *max*-heap!
|
|
|
|
match other.position.x.partial_cmp(&self.position.x) {
|
2017-06-28 17:14:40 -04:00
|
|
|
None | Some(Ordering::Equal) => {}
|
|
|
|
Some(ordering) => return Some(ordering),
|
|
|
|
}
|
2017-07-03 19:26:55 -04:00
|
|
|
match other.position.y.partial_cmp(&self.position.y) {
|
2017-06-28 17:14:40 -04:00
|
|
|
None | Some(Ordering::Equal) => {}
|
|
|
|
Some(ordering) => return Some(ordering),
|
|
|
|
}
|
2017-07-03 19:26:55 -04:00
|
|
|
other.endpoint_index.partial_cmp(&self.endpoint_index)
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for Point {
|
|
|
|
#[inline]
|
|
|
|
fn cmp(&self, other: &Point) -> Ordering {
|
|
|
|
self.partial_cmp(other).unwrap_or(Ordering::Equal)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
2017-06-28 17:14:40 -04:00
|
|
|
struct ActiveEdge {
|
2017-07-13 19:44:11 -04:00
|
|
|
left_vertex_index: u32,
|
|
|
|
control_point_vertex_index: u32,
|
2017-06-28 17:14:40 -04:00
|
|
|
right_endpoint_index: u32,
|
|
|
|
left_to_right: bool,
|
2017-07-13 19:44:11 -04:00
|
|
|
parity: bool,
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
impl Default for ActiveEdge {
|
|
|
|
fn default() -> ActiveEdge {
|
|
|
|
ActiveEdge {
|
|
|
|
left_vertex_index: 0,
|
|
|
|
control_point_vertex_index: u32::MAX,
|
|
|
|
right_endpoint_index: 0,
|
|
|
|
left_to_right: false,
|
|
|
|
parity: false,
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
2017-07-13 19:44:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ActiveEdge {
|
|
|
|
fn toggle_parity(&mut self) {
|
|
|
|
self.parity = !self.parity
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
|
2017-07-13 19:44:11 -04:00
|
|
|
fn endpoint_kind(&self) -> BVertexKind {
|
|
|
|
if !self.parity {
|
|
|
|
BVertexKind::Endpoint0
|
2017-06-28 17:14:40 -04:00
|
|
|
} else {
|
2017-07-13 19:44:11 -04:00
|
|
|
BVertexKind::Endpoint1
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
2017-07-13 19:44:11 -04:00
|
|
|
struct SubdividedActiveEdge {
|
|
|
|
left_curve_left: u32,
|
|
|
|
left_curve_control_point: u32,
|
|
|
|
middle_point: u32,
|
|
|
|
right_curve_control_point: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SubdividedActiveEdge {
|
|
|
|
fn shape(&self, b_vertices: &[BVertex]) -> Shape {
|
|
|
|
if self.left_curve_control_point == u32::MAX {
|
|
|
|
return Shape::Flat
|
|
|
|
}
|
|
|
|
match b_vertices[self.left_curve_control_point as usize].kind {
|
|
|
|
BVertexKind::ConvexControlPoint => Shape::Convex,
|
|
|
|
_ => Shape::Concave,
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 17:14:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
enum EndpointClass {
|
|
|
|
Min,
|
|
|
|
Regular,
|
|
|
|
Max,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
struct MatchingActiveEdges {
|
|
|
|
indices: [u32; 2],
|
|
|
|
count: u8,
|
|
|
|
}
|
2017-07-13 19:44:11 -04:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
enum Shape {
|
|
|
|
Flat,
|
|
|
|
Convex,
|
|
|
|
Concave,
|
|
|
|
}
|