Use SortedVectors for heaps
This commit is contained in:
parent
dbac2bade5
commit
4d692759a9
|
@ -974,8 +974,8 @@ struct Tiler<'o, 'p> {
|
||||||
|
|
||||||
view_box: Option<Rect<f32>>,
|
view_box: Option<Rect<f32>>,
|
||||||
|
|
||||||
point_queue: BinaryHeap<QueuedEndpoint>,
|
point_queue: SortedVector<QueuedEndpoint>,
|
||||||
active_edges: Vec<ActiveEdge>,
|
active_edges: SortedVector<ActiveEdge>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'o, 'p> Tiler<'o, 'p> {
|
impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
|
@ -991,8 +991,8 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
|
|
||||||
view_box: *view_box,
|
view_box: *view_box,
|
||||||
|
|
||||||
point_queue: BinaryHeap::new(),
|
point_queue: SortedVector::new(),
|
||||||
active_edges: Vec::new(),
|
active_edges: SortedVector::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,6 +1024,8 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
let mut strip_tiles = Vec::with_capacity(tiles_across);
|
let mut strip_tiles = Vec::with_capacity(tiles_across);
|
||||||
let mut used_strip_tiles = FixedBitSet::with_capacity(tiles_across);
|
let mut used_strip_tiles = FixedBitSet::with_capacity(tiles_across);
|
||||||
|
|
||||||
|
let mut new_active_edges = SortedVector::new();
|
||||||
|
|
||||||
// Generate strips.
|
// Generate strips.
|
||||||
while strip_origin.y < bounds.max_y() {
|
while strip_origin.y < bounds.max_y() {
|
||||||
// Determine strip bounds.
|
// Determine strip bounds.
|
||||||
|
@ -1051,45 +1053,11 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
tile_left += TILE_WIDTH;
|
tile_left += TILE_WIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Populate tile strip with active intervals.
|
|
||||||
// TODO(pcwalton): Use only the active edge list!
|
|
||||||
let mut strip_tile_index = 0;
|
|
||||||
for interval in &self.active_intervals.ranges {
|
|
||||||
while strip_tile_index < strip_tiles.len() {
|
|
||||||
let tile_left = strip_tiles[strip_tile_index].position.x;
|
|
||||||
let tile_right = tile_left + TILE_WIDTH;
|
|
||||||
|
|
||||||
let tile_interval = intersect_ranges(tile_left..tile_right,
|
|
||||||
interval.start..interval.end);
|
|
||||||
if interval.winding != 0.0 {
|
|
||||||
if tile_interval == (tile_left..tile_right) {
|
|
||||||
strip_tiles[strip_tile_index].backdrop = interval.winding
|
|
||||||
} else if tile_interval.start < tile_interval.end {
|
|
||||||
let left = Point2D::new(tile_interval.start - tile_left, 0.0);
|
|
||||||
let right = Point2D::new(tile_interval.end - tile_left, 0.0);
|
|
||||||
strip_fills.push(FillPrimitive {
|
|
||||||
from: if interval.winding < 0.0 { left } else { right },
|
|
||||||
to: if interval.winding < 0.0 { right } else { left },
|
|
||||||
tile_index: strip_tile_index as u32,
|
|
||||||
});
|
|
||||||
used_strip_tiles.insert(strip_tile_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if tile_right > interval.end {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
strip_tile_index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Process old active edges.
|
// Process old active edges.
|
||||||
let (mut strip_tile_index, mut current_left) = (0, strip_bounds.origin.x);
|
let (mut strip_tile_index, mut current_left) = (0, strip_bounds.origin.x);
|
||||||
let mut winding = 0;
|
let mut winding = 0;
|
||||||
for active_edge in &mut self.active_edges {
|
debug_assert!(new_active_edges.is_empty());
|
||||||
|
while let Some(mut active_edge) = self.active_edges.pop() {
|
||||||
// Move over to the correct tile, filling in as we go.
|
// Move over to the correct tile, filling in as we go.
|
||||||
// FIXME(pcwalton): Do subtile fills!!
|
// FIXME(pcwalton): Do subtile fills!!
|
||||||
let mut tile_left = strip_bounds.origin.x + (strip_tile_index as f32) * TILE_WIDTH;
|
let mut tile_left = strip_bounds.origin.x + (strip_tile_index as f32) * TILE_WIDTH;
|
||||||
|
@ -1131,7 +1099,30 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
&strip_bounds,
|
&strip_bounds,
|
||||||
fills,
|
fills,
|
||||||
&mut used_strip_tiles);
|
&mut used_strip_tiles);
|
||||||
|
|
||||||
|
if !active_edge.segment.is_none() {
|
||||||
|
new_active_edges.push(active_edge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
mem::swap(&mut self.active_edges, &mut new_active_edges);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Sort point queue.
|
||||||
|
self.point_queue.sort_unstable_by(|this, other| {
|
||||||
|
match other.y.partial_cmp(&this.y) {
|
||||||
|
Some(Ordering::Equal) | None => {
|
||||||
|
match other.point_index.contour_index.cmp(&this.point_index
|
||||||
|
.contour_index) {
|
||||||
|
Ordering::Equal => {
|
||||||
|
other.point_index.point_index.cmp(&this.point_index.point_index)
|
||||||
|
}
|
||||||
|
ordering => ordering,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(ordering) => ordering,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
// Add new active edges.
|
// Add new active edges.
|
||||||
loop {
|
loop {
|
||||||
|
@ -1220,12 +1211,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort active edges.
|
// Sort point queue.
|
||||||
self.active_edges.retain(|edge| !edge.segment.is_none());
|
|
||||||
self.active_edges.sort_unstable_by(|edge_a, edge_b| {
|
|
||||||
edge_a.segment.min_x().partial_cmp(&edge_b.segment.min_x()).unwrap()
|
|
||||||
});
|
|
||||||
|
|
||||||
strip_origin.y = strip_extent.y;
|
strip_origin.y = strip_extent.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1260,7 +1246,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
|
|
||||||
fn process_active_segment(contour: &Contour,
|
fn process_active_segment(contour: &Contour,
|
||||||
from_endpoint_index: usize,
|
from_endpoint_index: usize,
|
||||||
active_edges: &mut Vec<ActiveEdge>,
|
active_edges: &mut SortedVector<ActiveEdge>,
|
||||||
strip_bounds: &Rect<f32>,
|
strip_bounds: &Rect<f32>,
|
||||||
fills: Option<&mut Vec<FillPrimitive>>,
|
fills: Option<&mut Vec<FillPrimitive>>,
|
||||||
used_tiles: &mut FixedBitSet) {
|
used_tiles: &mut FixedBitSet) {
|
||||||
|
@ -1868,6 +1854,37 @@ impl SolveT for CubicAxis {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SortedVector
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SortedVector<T> where T: PartialOrd {
|
||||||
|
array: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> SortedVector<T> where T: PartialOrd {
|
||||||
|
fn new() -> SortedVector<T> {
|
||||||
|
SortedVector { array: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, value: T) {
|
||||||
|
self.array.push(value);
|
||||||
|
let mut index = self.array.len() - 1;
|
||||||
|
while index > 0 {
|
||||||
|
index -= 1;
|
||||||
|
if self.array[index] <= self.array[index + 1] {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
self.array.swap(index, index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(&self) -> Option<&T> { self.array.last() }
|
||||||
|
fn pop(&mut self) -> Option<T> { self.array.pop() }
|
||||||
|
fn len(&self) -> usize { self.array.len() }
|
||||||
|
fn is_empty(&self) -> bool { self.array.is_empty() }
|
||||||
|
fn clear(&mut self) { self.array.clear() }
|
||||||
|
}
|
||||||
|
|
||||||
// Heap
|
// Heap
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -1961,6 +1978,7 @@ impl Eq for QueuedEndpoint {}
|
||||||
|
|
||||||
impl PartialOrd<QueuedEndpoint> for QueuedEndpoint {
|
impl PartialOrd<QueuedEndpoint> for QueuedEndpoint {
|
||||||
fn partial_cmp(&self, other: &QueuedEndpoint) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &QueuedEndpoint) -> Option<Ordering> {
|
||||||
|
// NB: Reversed!
|
||||||
match other.y.partial_cmp(&self.y) {
|
match other.y.partial_cmp(&self.y) {
|
||||||
Some(Ordering::Equal) | None => {
|
Some(Ordering::Equal) | None => {
|
||||||
match other.point_index.contour_index.cmp(&self.point_index.contour_index) {
|
match other.point_index.contour_index.cmp(&self.point_index.contour_index) {
|
||||||
|
@ -1975,6 +1993,7 @@ impl PartialOrd<QueuedEndpoint> for QueuedEndpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
impl Ord for QueuedEndpoint {
|
impl Ord for QueuedEndpoint {
|
||||||
fn cmp(&self, other: &QueuedEndpoint) -> Ordering {
|
fn cmp(&self, other: &QueuedEndpoint) -> Ordering {
|
||||||
match other.y.partial_cmp(&self.y) {
|
match other.y.partial_cmp(&self.y) {
|
||||||
|
@ -1990,6 +2009,7 @@ impl Ord for QueuedEndpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Active edges
|
// Active edges
|
||||||
|
|
||||||
|
@ -2004,24 +2024,15 @@ impl ActiveEdge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for ActiveEdge {}
|
|
||||||
|
|
||||||
impl PartialOrd<ActiveEdge> for ActiveEdge {
|
impl PartialOrd<ActiveEdge> for ActiveEdge {
|
||||||
fn partial_cmp(&self, other: &ActiveEdge) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &ActiveEdge) -> Option<Ordering> {
|
||||||
|
// NB: Reversed!
|
||||||
let this_left = f32::min(self.segment.from.x, self.segment.to.x);
|
let this_left = f32::min(self.segment.from.x, self.segment.to.x);
|
||||||
let other_left = f32::min(other.segment.from.x, other.segment.to.x);
|
let other_left = f32::min(other.segment.from.x, other.segment.to.x);
|
||||||
other_left.partial_cmp(&this_left)
|
other_left.partial_cmp(&this_left)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for ActiveEdge {
|
|
||||||
fn cmp(&self, other: &ActiveEdge) -> Ordering {
|
|
||||||
let this_left = f32::min(self.segment.from.x, self.segment.to.x);
|
|
||||||
let other_left = f32::min(other.segment.from.x, other.segment.to.x);
|
|
||||||
other_left.partial_cmp(&this_left).unwrap_or(Ordering::Equal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trivial utilities
|
// Trivial utilities
|
||||||
|
|
||||||
fn lerp(a: f32, b: f32, t: f32) -> f32 {
|
fn lerp(a: f32, b: f32, t: f32) -> f32 {
|
||||||
|
@ -2051,11 +2062,33 @@ fn t_is_too_close_to_zero_or_one(t: f32) -> bool {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{Heap, IntervalRange, Intervals};
|
use crate::{Heap, IntervalRange, Intervals, SortedVector};
|
||||||
use quickcheck::{self, Arbitrary, Gen};
|
use quickcheck::{self, Arbitrary, Gen};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sorted_vec() {
|
||||||
|
quickcheck::quickcheck(prop_sorted_vec as fn(Vec<i32>) -> bool);
|
||||||
|
|
||||||
|
fn prop_sorted_vec(mut values: Vec<i32>) -> bool {
|
||||||
|
let mut sorted_vec = SortedVector::new();
|
||||||
|
for &value in &values {
|
||||||
|
sorted_vec.push(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
values.sort();
|
||||||
|
let mut results = Vec::with_capacity(values.len());
|
||||||
|
while !sorted_vec.is_empty() {
|
||||||
|
results.push(sorted_vec.pop().unwrap());
|
||||||
|
}
|
||||||
|
results.reverse();
|
||||||
|
assert_eq!(&values, &results);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_heap() {
|
fn test_heap() {
|
||||||
quickcheck::quickcheck(prop_heap as fn(Vec<i32>) -> bool);
|
quickcheck::quickcheck(prop_heap as fn(Vec<i32>) -> bool);
|
||||||
|
|
Loading…
Reference in New Issue