parent
9882b85a41
commit
0af1528f4c
|
|
@ -189,10 +189,21 @@ fn run_area(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
let b = a * el.ratio;
|
||||
(cadcraft_geom::PI * a * b, cadcraft_geom::PI * (3.0 * (a + b) - ((3.0 * a + b) * (a + 3.0 * b)).sqrt()))
|
||||
}
|
||||
EntityKind::Hatch(hh) => hh.loops.iter().fold((0.0, 0.0), |acc, l| {
|
||||
let g = Polyline { vertices: l.vertices.clone(), closed: true };
|
||||
(acc.0 + g.area().abs(), acc.1 + g.len())
|
||||
}),
|
||||
EntityKind::Hatch(hh) => {
|
||||
// Odd parity, as drawn: a loop nested inside an odd number of other loops is an unfilled island.
|
||||
let geoms: Vec<Polyline> = hh.loops.iter().map(|l| Polyline { vertices: l.vertices.clone(), closed: true }).collect();
|
||||
let polys: Vec<Vec<Vec2>> = geoms.iter().map(|g| g.tessellate(1e-3)).collect();
|
||||
let mut total = (0.0, 0.0);
|
||||
for (i, g) in geoms.iter().enumerate() {
|
||||
let probe = polys.get(i).and_then(|p| p.first().copied());
|
||||
let depth = probe.map_or(0, |pt| {
|
||||
polys.iter().enumerate().filter(|(j, q)| *j != i && cadcraft_geom::point_in_polygon(q, pt)).count()
|
||||
});
|
||||
total.0 += if depth % 2 == 0 { g.area().abs() } else { -g.area().abs() };
|
||||
total.1 += g.len();
|
||||
}
|
||||
total
|
||||
}
|
||||
_ => return Err(bad("area", "object has no area")),
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -350,6 +350,27 @@ fn dim_auto_vertical_and_radius() {
|
|||
assert!(matches!(kinds[1], cadcraft_doc::DimKind::Radius));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn area_of_hatch_excludes_island() {
|
||||
let mut s = Session::new();
|
||||
s.execute("pline", &json!({"vertices": [[0, 0], [10, 0], [10, 10], [0, 10]], "closed": true})).unwrap();
|
||||
s.execute("pline", &json!({"vertices": [[4, 4], [6, 4], [6, 6], [4, 6]], "closed": true})).unwrap();
|
||||
s.execute("hatch", &json!({"points": [[1, 1]], "pattern": "SOLID"})).unwrap();
|
||||
let h = s.doc().unwrap().model.iter().find_map(|e| if let EntityKind::Hatch(_) = &e.kind { Some(e.handle) } else { None }).unwrap();
|
||||
let r = s.execute("area", &json!({"handle": h.hex()})).unwrap();
|
||||
assert!((r["area"].as_f64().unwrap() - 96.0).abs() < 1e-6);
|
||||
assert!((r["perimeter"].as_f64().unwrap() - 48.0).abs() < 1e-6);
|
||||
// A loop nested inside the island is filled again: 100 - 36 + 4.
|
||||
let mut s = Session::new();
|
||||
s.execute("pline", &json!({"vertices": [[0, 0], [10, 0], [10, 10], [0, 10]], "closed": true})).unwrap();
|
||||
s.execute("pline", &json!({"vertices": [[2, 2], [8, 2], [8, 8], [2, 8]], "closed": true})).unwrap();
|
||||
s.execute("pline", &json!({"vertices": [[4, 4], [6, 4], [6, 6], [4, 6]], "closed": true})).unwrap();
|
||||
s.execute("hatch", &json!({"points": [[1, 1]], "pattern": "SOLID"})).unwrap();
|
||||
let h = s.doc().unwrap().model.iter().find_map(|e| if let EntityKind::Hatch(_) = &e.kind { Some(e.handle) } else { None }).unwrap();
|
||||
let r = s.execute("area", &json!({"handle": h.hex()})).unwrap();
|
||||
assert!((r["area"].as_f64().unwrap() - 68.0).abs() < 1e-6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hatch_by_pick_point_with_island() {
|
||||
let mut s = Session::new();
|
||||
|
|
|
|||
Loading…
Reference in New Issue