Quickcheck intervals

This commit is contained in:
Patrick Walton 2018-12-12 14:55:53 -08:00
parent ececd70760
commit 4597414e21
3 changed files with 250 additions and 0 deletions

67
Cargo.lock generated
View File

@ -192,6 +192,14 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cmake"
version = "0.1.34"
@ -462,6 +470,20 @@ dependencies = [
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.54"
@ -1035,6 +1057,17 @@ dependencies = [
"memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quickcheck"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.8"
@ -1043,6 +1076,31 @@ dependencies = [
"proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rayon"
version = "0.7.1"
@ -1396,6 +1454,8 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"svgtypes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1596,6 +1656,7 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cmake 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "848b314ea70f48f0e13828c5554e34200952ce5720d6d3aa466b4d983af6c70e"
"checksum cocoa 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53a840785348e998a1433d1f9d0b350fd83e91711fae8507c76ce510afc77e72"
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
@ -1624,6 +1685,8 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11926b2b410b469d0e9399eca4cbbe237a9ef02176c485803b29216307e8e028"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum gdk-pixbuf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16160d212ae91abe9f3324c3fb233929ba322dde63585d15cda3336f8c529ed1"
"checksum gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "798f97101eea8180da363d0e80e07ec7ec6d1809306601c0100c1de5bc8b4f52"
@ -1682,7 +1745,11 @@ source = "git+https://github.com/SergioBenitez/ring?branch=v0.12#9ccfa153a27aecc
"checksum proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8065cbb01701c11cc195cde85cbf39d1c6a80705b67a157ebb3042e0e5777f"
"checksum quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4537d3e4edf73a15dd059b75bed1c292d17d3ea7517f583cebe716794fcf816"
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a"
"checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa"
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"

View File

@ -9,3 +9,7 @@ bitflags = "1.0"
euclid = "0.19"
quick-xml = "0.12"
svgtypes = "0.2"
[dev-dependencies]
quickcheck = "0.7"
rand = "0.5"

View File

@ -11,11 +11,17 @@
#[macro_use]
extern crate bitflags;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
extern crate rand;
use euclid::{Point2D, Transform2D};
use quick_xml::Reader;
use quick_xml::events::Event;
use std::env;
use std::mem;
use std::ops::Range;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use svgtypes::{Color as SvgColor, PathParser, PathSegment as SvgPathSegment, TransformListParser};
@ -378,3 +384,176 @@ impl Contour {
self.flags.push(flags);
}
}
// Tiling
struct Tiler {
outline: Outline,
}
impl Tiler {
fn from_outline(outline: Outline) -> Tiler {
Tiler {
outline,
}
}
}
// Intervals
#[derive(Debug)]
struct Intervals {
ranges: Vec<IntervalRange>,
}
#[derive(Clone, Copy, Debug)]
struct IntervalRange {
start: f32,
end: f32,
winding: f32,
}
impl Intervals {
fn new(end: f32) -> Intervals {
Intervals {
ranges: vec![IntervalRange::new(0.0, end, 0.0)],
}
}
fn add(&mut self, range: IntervalRange) {
self.split_at(range.start);
self.split_at(range.end);
// Find bracketing range.
let mut start_index = 0;
while range.start < self.ranges[start_index].start {
start_index += 1
}
let mut end_index = start_index;
while range.end < self.ranges[end_index].end {
end_index += 1
}
// Adjust winding numbers.
for existing_range in &mut self.ranges[start_index..(end_index + 1)] {
existing_range.winding += range.winding
}
self.merge_adjacent();
}
fn clear(&mut self) {
let end = self.ranges.last().unwrap().end;
self.ranges.truncate(1);
self.ranges[0] = IntervalRange::new(0.0, end, 0.0);
}
fn split_at(&mut self, value: f32) {
let mut range_index = 0;
while range_index < self.ranges.len() {
let IntervalRange {
start: old_start,
end: old_end,
winding,
} = self.ranges[range_index];
if value < old_start || value > old_end {
range_index += 1;
continue
}
self.ranges[range_index] = IntervalRange::new(old_start, value, winding);
self.ranges.insert(range_index + 1, IntervalRange::new(value, old_end, winding));
return
}
}
fn merge_adjacent(&mut self) {
let mut dest_range_index = 0;
let mut current_range = self.ranges[0];
for src_range_index in 1..self.ranges.len() {
if self.ranges[src_range_index].winding == current_range.winding {
current_range.end = self.ranges[src_range_index].end
} else {
self.ranges[dest_range_index] = current_range;
dest_range_index += 1;
current_range = self.ranges[src_range_index];
}
}
self.ranges[dest_range_index] = current_range;
dest_range_index += 1;
self.ranges.truncate(dest_range_index);
}
}
impl IntervalRange {
fn new(start: f32, end: f32, winding: f32) -> IntervalRange {
IntervalRange {
start,
end,
winding,
}
}
fn contains(&self, value: f32) -> bool {
value >= self.start && value < self.end
}
}
#[cfg(test)]
mod test {
use crate::{IntervalRange, Intervals};
use quickcheck::{self, Arbitrary, Gen};
use rand::Rng;
#[test]
fn test_intervals() {
quickcheck::quickcheck(prop_intervals as fn(Spec) -> bool);
fn prop_intervals(spec: Spec) -> bool {
let mut intervals = Intervals::new(spec.end);
for range in spec.ranges {
intervals.add(range);
}
assert!(intervals.ranges.len() > 0);
assert_eq!(intervals.ranges[0].start, 0.0);
assert_eq!(intervals.ranges.last().unwrap().end, spec.end);
for prev_index in 0..(intervals.ranges.len() - 1) {
let next_index = prev_index + 1;
assert_eq!(intervals.ranges[prev_index].end, intervals.ranges[next_index].start);
assert_ne!(intervals.ranges[prev_index].winding,
intervals.ranges[next_index].winding);
}
true
}
#[derive(Clone, Debug)]
struct Spec {
end: f32,
ranges: Vec<IntervalRange>,
}
impl Arbitrary for Spec {
fn arbitrary<G>(g: &mut G) -> Spec where G: Gen {
const EPSILON: f32 = 0.0001;
let size = g.size();
let end = g.gen_range(EPSILON, size as f32);
let mut ranges = vec![];
let range_count = g.gen_range(0, size);
for _ in 0..range_count {
let (a, b) = (g.gen_range(0.0, end), g.gen_range(0.0, end));
let winding = g.gen_range(-(size as i32), size as i32) as f32;
ranges.push(IntervalRange::new(f32::min(a, b), f32::max(a, b), winding));
}
Spec {
end,
ranges,
}
}
}
}
}