Select: pick a solid hatch inside its fill, islands left out, not its bounding rectangle (follow-up to #747) (#763)
Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
966356545d
commit
76b0ef8897
|
|
@ -89,11 +89,18 @@ pub fn entity_distance(d: &Drawing, e: &Entity, p: Vec2, tol: f64) -> f64 {
|
|||
let polys = hit_polylines(d, e, tol);
|
||||
let mut best = polys.iter().map(|pl| dist_to_polyline(pl, p)).fold(f64::INFINITY, f64::min);
|
||||
let filled = matches!(e.kind, EntityKind::Text(_) | EntityKind::MText(_) | EntityKind::AttDef(_) | EntityKind::Table(_))
|
||||
|| matches!(e.kind, EntityKind::Tolerance(_))
|
||||
|| matches!(&e.kind, EntityKind::Hatch(h) if h.solid);
|
||||
|| matches!(e.kind, EntityKind::Tolerance(_));
|
||||
if (filled && entity_bounds(d, e, 0).contains(p)) || in_text(d, e, p) {
|
||||
best = 0.0;
|
||||
}
|
||||
// A solid hatch fills its loops with odd parity under its island style, as it is drawn, not
|
||||
// its bounding rectangle.
|
||||
if let EntityKind::Hatch(h) = &e.kind
|
||||
&& h.solid
|
||||
&& cadcraft_render::hatch_fill_loops(h, tol).iter().filter(|l| point_in_polygon(l, p)).count() % 2 == 1
|
||||
{
|
||||
best = 0.0;
|
||||
}
|
||||
// A SOLID fills its polygon, not its bounding rectangle (half of which is empty for a triangle).
|
||||
if matches!(e.kind, EntityKind::Solid(_)) && e.kind.prims().iter().any(|prim| matches!(prim, Prim::Fill(poly) if point_in_polygon(poly, p))) {
|
||||
best = 0.0;
|
||||
|
|
@ -553,4 +560,51 @@ mod hatch_pattern_pick_tests {
|
|||
assert!(pick(&d, &Space::Model, Vec2::new(1.0, 1.0), 0.05).is_some());
|
||||
assert!(pick(&d, &Space::Model, Vec2::new(5.0, 5.0), 0.05).is_none());
|
||||
}
|
||||
|
||||
fn solid_hatch(loops: Vec<HatchLoop>, style: u8) -> Drawing {
|
||||
let mut d = Drawing::new_metric();
|
||||
let hatch = Hatch {
|
||||
pattern: "SOLID".into(),
|
||||
solid: true,
|
||||
loops,
|
||||
scale: 1.0,
|
||||
angle: 0.0,
|
||||
associative: false,
|
||||
style,
|
||||
elevation: 0.0,
|
||||
gradient: None,
|
||||
origin: Vec2::ZERO,
|
||||
background: None,
|
||||
pattern_lines: Vec::new(),
|
||||
};
|
||||
d.add(&Space::Model, Common::default(), EntityKind::Hatch(hatch)).unwrap();
|
||||
d
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn solid_hatch_is_picked_inside_its_fill_not_its_bounding_rectangle() {
|
||||
let tri = HatchLoop {
|
||||
vertices: [(0.0, 0.0), (10.0, 0.0), (0.0, 10.0)].iter().map(|&(x, y)| PolyVertex::new(Vec2::new(x, y))).collect(),
|
||||
outer: true,
|
||||
sources: Vec::new(),
|
||||
};
|
||||
let d = solid_hatch(vec![tri], 0);
|
||||
// The empty corner of the bounding rectangle, 5.66 from the hypotenuse.
|
||||
assert!(pick(&d, &Space::Model, Vec2::new(9.0, 9.0), 0.25).is_none());
|
||||
assert!(pick(&d, &Space::Model, Vec2::new(2.0, 2.0), 0.25).is_some());
|
||||
// Outside the fill but within the aperture of the hypotenuse.
|
||||
assert!(pick(&d, &Space::Model, Vec2::new(5.1, 5.1), 0.25).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn solid_hatch_island_follows_the_island_style() {
|
||||
let loops = || vec![square(0.0, 10.0, true), square(4.0, 6.0, false)];
|
||||
// Normal style leaves the island empty, as it is drawn.
|
||||
let d = solid_hatch(loops(), 0);
|
||||
assert!(pick(&d, &Space::Model, Vec2::new(5.0, 5.0), 0.05).is_none());
|
||||
assert!(pick(&d, &Space::Model, Vec2::new(2.0, 2.0), 0.05).is_some());
|
||||
// Ignore style fills over the island.
|
||||
let d = solid_hatch(loops(), 2);
|
||||
assert!(pick(&d, &Space::Model, Vec2::new(5.0, 5.0), 0.05).is_some());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ fn dedup_polygons(loops: &mut Vec<Vec<Vec2>>) {
|
|||
/// detection style (DXF group 75), filled with odd parity: 0 normal keeps every loop (islands
|
||||
/// within islands alternate), 1 outer keeps the outermost loops and their first islands, 2
|
||||
/// ignore keeps only the outermost loops. Nesting depth = how many other loops enclose a loop.
|
||||
pub(crate) fn fill_loops(h: &Hatch, tol: f64) -> Vec<Vec<Vec2>> {
|
||||
pub fn fill_loops(h: &Hatch, tol: f64) -> Vec<Vec<Vec2>> {
|
||||
let mut loops: Vec<Vec<Vec2>> = h.loops.iter().map(|l| Polyline { vertices: l.vertices.clone(), closed: true }.tessellate(tol)).collect();
|
||||
dedup_polygons(&mut loops);
|
||||
let max_depth = match h.style {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use pen::Pen;
|
|||
|
||||
pub use dim::{ArrowGeom, Arrowhead, DimGeometry, DimText, LineRole, arrowhead, dimension_geometry, dimension_geometry_with, format_linear_value};
|
||||
pub use fill::triangulate_evenodd;
|
||||
pub use hatch::pattern_swatch;
|
||||
pub use hatch::{fill_loops as hatch_fill_loops, pattern_swatch};
|
||||
pub use paper::{PAPER_SIZES, PaperSize, Sheet, paper_size, sheet};
|
||||
pub use tolerance::{gdt_points, tolerance_in};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue