use std::fs::File;
use std::fs::OpenOptions;
use std::io::Read;
use std::io::Write;
static DEBUG: usize = 1;
macro_rules! dlog {
($loglevel:expr, $($s:expr),*) => (
if DEBUG>=$loglevel { print!("{}:",$loglevel); println!($($s),+); }
)
}
fn parse_json(rawdata: &str) -> Option<Vec<Vec<Vec<f64>>>> {
let mut v: Vec<Vec<Vec<f64>>> = Vec::new();
match serde_json::from_str::<serde_json::Value>(rawdata) {
Err(e) => println!("error deserializing, {}", e),
Ok(jsondata) => {
if jsondata.is_array() {
let contours = jsondata.as_array().unwrap();
dlog!(4, "deserialize ok, {} contours", contours.len());
for (i, contourval) in contours.iter().enumerate() {
if contourval.is_array() {
let contour = contourval.as_array().unwrap();
dlog!(9, "countour {} numpoints {}", i, contour.len());
let mut vc: Vec<Vec<f64>> = Vec::new();
for points in contour {
let points = points.as_array().unwrap();
let mut vp: Vec<f64> = Vec::new();
for val in points {
let val = val.to_string();
let pval = val.parse::<f64>().unwrap();
vp.push(pval);
}
vc.push(vp);
}
v.push(vc);
}
}
}
}
};
Some(v)
}
fn mkoutput(
filename_w_dashes: &str,
tris: Vec<usize>,
data: &Vec<Vec<Vec<f64>>>,
pass: bool,
rpt: &str,
) -> Result<(), std::io::Error> {
dlog!(
4,
"save data + triangles: {}, num tri pts:{}, rpt: {},",
&filename_w_dashes,
tris.len(),
rpt
);
let filename = str::replace(filename_w_dashes, "-", "_");
let outfile = &format!("viz/testoutput/{}.js", filename);
let f = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(outfile)
.unwrap();
writeln!(&f, r###"testOutput["{}"]=[];"###, filename)?;
writeln!(&f, r###"testOutput["{}"]["json"]={:?};"###, filename, data)?;
writeln!(
&f,
r###"testOutput["{}"]["triangles"]={:?};"###,
filename, tris
)?;
writeln!(&f, r###"testOutput["{}"]["pass"]={:?};"###, filename, pass)?;
writeln!(&f, r###"testOutput["{}"]["report"]={:?};"###, filename, rpt)?;
dlog!(4, "wrote results to {}", outfile);
Ok(())
}
fn area_test(filename: &str, expected_num_tris: usize, expected_deviation: f64) -> bool {
let visualize = true;
dlog!(4, "visualization: {}", visualize);
let mut actual_num_tris = 0;
let mut actual_deviation = 0.0;
let mut edeviation = expected_deviation;
let mut triangles: Vec<usize> = Vec::new();
let mut xdata: Vec<Vec<Vec<f64>>> = Vec::new();
if edeviation == 0.0 {
edeviation = 1e-14;
}
let fullname = format!("tests/fixtures/{}.json", filename);
match File::open(&fullname) {
Err(why) => panic!("failed to open file '{}': {}", fullname, why),
Ok(mut f) => {
dlog!(4, "testing {},", fullname);
let mut strdata = String::new();
match f.read_to_string(&mut strdata) {
Err(why) => dlog!(4, "failed to read {}, {}", fullname, why),
Ok(numb) => {
dlog!(4, "read {} bytes", numb);
let rawstring = strdata.trim();
match parse_json(rawstring) {
None => dlog!(4, "failed to parse {}", fullname),
Some(parsed_data) => {
xdata = parsed_data;
let (data, holeidxs, dimensions) = earcutr::legacy::flatten(&xdata);
triangles = earcutr::earcut(&data, &holeidxs, dimensions).unwrap();
actual_num_tris = triangles.len() / 3;
actual_deviation =
earcutr::deviation(&data, &holeidxs, dimensions, &triangles);
}
};
}
};
}
};
let mut pass = true;
if expected_num_tris > 0 && (expected_num_tris < actual_num_tris) {
pass = false;
};
if edeviation < actual_deviation {
pass = false;
};
let rpt = format!(
"exp numtri:{}\nexp dev:{}\nact numtri:{}\nact dev:{}",
expected_num_tris, edeviation, actual_num_tris, actual_deviation
);
if visualize {
if let Err(e) = mkoutput(filename, triangles, &xdata, pass, &rpt) {
println!("error writing output {}", e);
}
}
pass
}
#[test]
fn test_indices_2d() {
let indices = earcutr::earcut(&[10.0, 0.0, 0.0, 50.0, 60.0, 60.0, 70.0, 10.0], &[], 2).unwrap();
assert!(indices == vec![1, 0, 3, 3, 2, 1]);
}
#[test]
fn test_empty() {
let indices = earcutr::earcut::<f64>(&[], &[], 2).unwrap();
assert!(indices.is_empty());
}
#[test]
fn test_building() {
assert!(area_test("building", 13, 0e0));
}
#[test]
fn test_dude() {
assert!(area_test("dude", 106, 0e0));
}
#[test]
fn test_water() {
assert!(area_test("water", 2482, 8e-4));
}
#[test]
fn test_water2() {
assert!(area_test("water2", 1212, 0e0));
}
#[test]
fn test_water3() {
assert!(area_test("water3", 197, 0e0));
}
#[test]
fn test_water3b() {
assert!(area_test("water3b", 25, 0e0));
}
#[test]
fn test_water4() {
assert!(area_test("water4", 705, 0e0));
}
#[test]
fn test_water_huge() {
assert!(area_test("water-huge", 5174, 1.1e-3));
}
#[test]
fn test_water_huge2() {
assert!(area_test("water-huge2", 4461, 2.8e-3));
}
#[test]
fn test_degenerate() {
assert!(area_test("degenerate", 0, 0e0));
}
#[test]
fn test_bad_hole() {
assert!(area_test("bad-hole", 42, 1.9e-2));
}
#[test]
fn test_empty_square() {
assert!(area_test("empty-square", 0, 0e0));
}
#[test]
fn test_issue16() {
assert!(area_test("issue16", 12, 0e0));
}
#[test]
fn test_issue17() {
assert!(area_test("issue17", 11, 0e0));
}
#[test]
fn test_steiner() {
assert!(area_test("steiner", 9, 0e0));
}
#[test]
fn test_issue29() {
assert!(area_test("issue29", 40, 0e0));
}
#[test]
fn test_issue34() {
assert!(area_test("issue34", 139, 0e0));
}
#[test]
fn test_issue35() {
assert!(area_test("issue35", 844, 0e0));
}
#[test]
fn test_self_touching() {
assert!(area_test("self-touching", 124, 3.4e-14));
}
#[test]
fn test_outside_ring() {
assert!(area_test("outside-ring", 64, 0e0));
}
#[test]
fn test_simplified_us_border() {
assert!(area_test("simplified-us-border", 120, 0e0));
}
#[test]
fn test_touching_holes() {
assert!(area_test("touching-holes", 57, 0e0));
}
#[test]
fn test_hole_touching_outer() {
assert!(area_test("hole-touching-outer", 77, 0e0));
}
#[test]
fn test_hilbert() {
assert!(area_test("hilbert", 1024, 0e0));
}
#[test]
fn test_issue45() {
assert!(area_test("issue45", 10, 0e0));
}
#[test]
fn test_eberly_3() {
assert!(area_test("eberly-3", 73, 0e0));
}
#[test]
fn test_eberly_6() {
assert!(area_test("eberly-6", 1429, 0e0));
}
#[test]
fn test_issue52() {
assert!(area_test("issue52", 109, 0e0));
}
#[test]
fn test_shared_points() {
assert!(area_test("shared-points", 4, 0e0));
}
#[test]
fn test_bad_diagonals() {
assert!(area_test("bad-diagonals", 7, 0e0));
}
#[test]
fn test_issue83() {
assert!(area_test("issue83", 0, 1e-14));
}
#[test]
fn test_infinite_loop_jhl() {
assert!(area_test("infinite-loop-jhl", 0, 1e-14));
}
#[test]
fn test_filtered_bridge_jhl() {
assert!(area_test("filtered-bridge-jhl", 0, 1e-14));
}
#[test]
fn test_issue142() {
assert!(area_test("issue142", 0, 1e-14));
}
#[test]
fn test_issue149() {
assert!(area_test("issue149", 0, 1e-14));
}