style: apply cargo fmt across workspace

This commit is contained in:
Karim Jerbi committed 2026-10-11 03:14:29 +01:00
1 parent 85710e5454
commit 9cf9ff2c5c
531 files changed
+57740 -33906

No files matched your search

+19 -10
View File
@@ -48,8 +48,15 @@ pub fn gizmo_screen_axes(
project: impl Fn(DVec3) -> Option<Vec2>,
) -> [Option<Vec2>; 3] {
let spans = [0, 1, 2].map(|k| project(world + gizmo_axis(k)).map(|p| p - center));
let longest = spans.iter().flatten().map(|v| v.length()).fold(0.0, f32::max);
spans.map(|span| span.filter(|v| longest > 0.0 && v.length() > 0.15 * longest).map(|v| v.normalize()))
let longest = spans
.iter()
.flatten()
.map(|v| v.length())
.fold(0.0, f32::max);
spans.map(|span| {
span.filter(|v| longest > 0.0 && v.length() > 0.15 * longest)
.map(|v| v.normalize())
})
}
/// Marker position (and direction) of a grip whose centre projects to
@@ -72,7 +79,9 @@ fn placed_marker(
Some((p + (a + b) * 0.3 * GIZMO_AXIS_PX, None))
}
_ => {
let dir = g.dir.and_then(|dir| Some(marker_direction(p, project(g.world + dir)?)));
let dir = g
.dir
.and_then(|dir| Some(marker_direction(p, project(g.world + dir)?)));
let s = marker_screen_position(Point::new(p.x, p.y), g.shape);
Some((Vec2::new(s.x, s.y), dir))
}
@@ -159,12 +168,7 @@ pub struct GripTarget {
}
impl GripEdit {
pub fn single(
handle: Handle,
grip_id: usize,
is_translate: bool,
world: DVec3,
) -> Self {
pub fn single(handle: Handle, grip_id: usize, is_translate: bool, world: DVec3) -> Self {
Self {
handle,
grip_id,
@@ -360,7 +364,12 @@ pub fn find_hit_grip(
/// (see `Scene::composed_viewport_view`) instead of a real camera. `pub(crate)`
/// so any other single-point world→screen projection (e.g. constraint-glyph
/// anchors) can reuse it instead of re-deriving the same NDC math.
pub(crate) fn project_rte(world: DVec3, view_rot: Mat4, eye: DVec3, bounds: Rectangle) -> Option<Vec2> {
pub(crate) fn project_rte(
world: DVec3,
view_rot: Mat4,
eye: DVec3,
bounds: Rectangle,
) -> Option<Vec2> {
let rel = (world - eye).as_vec3();
let clip = view_rot * rel.extend(1.0);
if clip.w.abs() < 1e-9 {
+120 -66
View File
@@ -552,7 +552,11 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
previous = Some(screen);
}
}
hits.extend(marker_hits.into_iter().map(|(name, distance)| (distance, name)));
hits.extend(
marker_hits
.into_iter()
.map(|(name, distance)| (distance, name)),
);
if let Some(segments) = wires.segments() {
let mut best_by_wire: HashMap<u32, f32> = HashMap::default();
for segment in segments {
@@ -817,11 +821,7 @@ pub(crate) fn mesh_edge_click_hit<'a>(
bounds: Rectangle,
tolerance_px: f32,
) -> Option<Handle> {
if cursor.x < 0.0
|| cursor.x > bounds.width
|| cursor.y < 0.0
|| cursor.y > bounds.height
{
if cursor.x < 0.0 || cursor.x > bounds.width || cursor.y < 0.0 || cursor.y > bounds.height {
return None;
}
let tolerance = tolerance_px.max(1.0);
@@ -831,9 +831,7 @@ pub(crate) fn mesh_edge_click_hit<'a>(
continue;
}
let model = transform.map(codec_transform_matrix);
if model.is_some_and(|matrix| {
!matrix.is_finite() || matrix.determinant().abs() <= 1e-18
}) {
if model.is_some_and(|matrix| !matrix.is_finite() || matrix.determinant().abs() <= 1e-18) {
continue;
}
for pair_start in (0..edges.len() - 1).step_by(2) {
@@ -863,11 +861,8 @@ pub(crate) fn mesh_edge_click_hit<'a>(
(1.0 - point.y) * 0.5 * bounds.height,
)
};
let distance = dist_point_to_segment(
cursor,
to_screen(first_ndc),
to_screen(second_ndc),
);
let distance =
dist_point_to_segment(cursor, to_screen(first_ndc), to_screen(second_ndc));
if distance > tolerance {
continue;
}
@@ -912,7 +907,8 @@ pub(crate) fn mesh_click_handle_point<'a>(
eye: glam::DVec3,
bounds: Rectangle,
) -> Option<(Handle, glam::DVec3)> {
mesh_click_result(cursor, meshes, view_rot, eye, bounds).map(|(_, handle, point)| (handle, point))
mesh_click_result(cursor, meshes, view_rot, eye, bounds)
.map(|(_, handle, point)| (handle, point))
}
fn mesh_click_result<'a>(
@@ -960,7 +956,9 @@ fn mesh_click_result<'a>(
}
let inverse = model.inverse();
let origin = inverse.transform_point3(near);
let direction = inverse.transform_vector3(world_direction).normalize_or_zero();
let direction = inverse
.transform_vector3(world_direction)
.normalize_or_zero();
(origin, direction)
} else {
(near, world_direction)
@@ -1017,10 +1015,22 @@ fn mesh_click_result<'a>(
fn codec_transform_matrix(transform: codec::types::Transform) -> glam::DMat4 {
let matrix = transform.matrix.m;
glam::DMat4::from_cols_array(&[
matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3],
matrix[0][0],
matrix[1][0],
matrix[2][0],
matrix[3][0],
matrix[0][1],
matrix[1][1],
matrix[2][1],
matrix[3][1],
matrix[0][2],
matrix[1][2],
matrix[2][2],
matrix[3][2],
matrix[0][3],
matrix[1][3],
matrix[2][3],
matrix[3][3],
])
}
@@ -1080,11 +1090,7 @@ fn ray_triangle(
/// without the low residual the f32 high alone is ~0.5 m off at UTM scale and
/// box / lasso / face selection lands on the wrong place.
#[inline]
fn mesh_vert(
hi: [f32; 3],
low: &[[f32; 3]],
i: usize,
) -> glam::DVec3 {
fn mesh_vert(hi: [f32; 3], low: &[[f32; 3]], i: usize) -> glam::DVec3 {
let l = low.get(i).copied().unwrap_or([0.0; 3]);
glam::DVec3::new(
hi[0] as f64 + l[0] as f64,
@@ -1144,13 +1150,7 @@ pub fn mesh_box_hit<'a>(
a: Point,
b: Point,
crossing: bool,
meshes: impl Iterator<
Item = (
Handle,
&'a MeshModel,
Option<codec::types::Transform>,
),
>,
meshes: impl Iterator<Item = (Handle, &'a MeshModel, Option<codec::types::Transform>)>,
view_rot: Mat4,
eye: glam::DVec3,
bounds: Rectangle,
@@ -1188,13 +1188,7 @@ pub fn mesh_box_hit<'a>(
pub fn mesh_poly_hit<'a>(
poly: &[Point],
crossing: bool,
meshes: impl Iterator<
Item = (
Handle,
&'a MeshModel,
Option<codec::types::Transform>,
),
>,
meshes: impl Iterator<Item = (Handle, &'a MeshModel, Option<codec::types::Transform>)>,
view_rot: Mat4,
eye: glam::DVec3,
bounds: Rectangle,
@@ -1424,8 +1418,7 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
if already(&wire_hit, glyph.wire) {
continue;
}
let Some(screen) =
projected_text_quad(wire, glyph.start as usize, view_rot, eye, bounds)
let Some(screen) = projected_text_quad(wire, glyph.start as usize, view_rot, eye, bounds)
else {
continue;
};
@@ -1654,8 +1647,7 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
if seen.contains(wire.name.as_str()) {
continue;
}
let Some(screen) =
projected_text_quad(wire, glyph.start as usize, view_rot, eye, bounds)
let Some(screen) = projected_text_quad(wire, glyph.start as usize, view_rot, eye, bounds)
else {
continue;
};
@@ -1739,13 +1731,7 @@ pub fn box_hit<'a, W: WireSource + ?Sized>(
let box_br = Point { x: max_x, y: max_y };
let box_corners = [box_tl, box_tr, box_br, box_bl];
if crossing && wires.segments().is_some() {
return indexed_box_crossing_hits(
wires,
box_corners,
view_rot,
eye,
bounds,
);
return indexed_box_crossing_hits(wires, box_corners, view_rot, eye, bounds);
}
if crossing {
@@ -1897,7 +1883,8 @@ pub fn box_hit<'a, W: WireSource + ?Sized>(
let mut glyphs_inside = true;
if all_inside && glyphs_present {
for start in (0..wire.text_verts.len()).step_by(6) {
let Some(screen) = projected_text_quad(wire, start, view_rot, eye, bounds) else {
let Some(screen) = projected_text_quad(wire, start, view_rot, eye, bounds)
else {
continue;
};
if !screen.iter().copied().all(inside) {
@@ -2711,16 +2698,43 @@ mod aabb_reject_tests {
let eye = glam::DVec3::ZERO;
assert_eq!(
click_hit(cursor, std::slice::from_ref(&near), vp, eye, bounds, true, 8.0, &HashMap::default()),
click_hit(
cursor,
std::slice::from_ref(&near),
vp,
eye,
bounds,
true,
8.0,
&HashMap::default()
),
Some("5")
);
assert_eq!(
click_hit(cursor, std::slice::from_ref(&far), vp, eye, bounds, true, 8.0, &HashMap::default()),
click_hit(
cursor,
std::slice::from_ref(&far),
vp,
eye,
bounds,
true,
8.0,
&HashMap::default()
),
None
);
// The far wire must be rejected without hiding the near one.
assert_eq!(
click_hit(cursor, &[far, near], vp, eye, bounds, true, 8.0, &HashMap::default()),
click_hit(
cursor,
&[far, near],
vp,
eye,
bounds,
true,
8.0,
&HashMap::default()
),
Some("5")
);
}
@@ -2823,21 +2837,51 @@ mod aabb_reject_tests {
// Crossing mode selects "4F" because wire_arc is inside:
assert_eq!(
box_hit(box_a, box_b, true, &wires, Mat4::IDENTITY, glam::DVec3::ZERO, bounds),
box_hit(
box_a,
box_b,
true,
&wires,
Mat4::IDENTITY,
glam::DVec3::ZERO,
bounds
),
vec!["4F"]
);
assert_eq!(
poly_hit(&poly_small, true, &wires, Mat4::IDENTITY, glam::DVec3::ZERO, bounds),
poly_hit(
&poly_small,
true,
&wires,
Mat4::IDENTITY,
glam::DVec3::ZERO,
bounds
),
vec!["4F"]
);
// Window mode MUST NOT select "4F" because wire_lines has a vertex at (0.8, 0.8) -> (180.0, 20.0) outside:
assert_eq!(
box_hit(box_a, box_b, false, &wires, Mat4::IDENTITY, glam::DVec3::ZERO, bounds),
box_hit(
box_a,
box_b,
false,
&wires,
Mat4::IDENTITY,
glam::DVec3::ZERO,
bounds
),
Vec::<&str>::new()
);
assert_eq!(
poly_hit(&poly_small, false, &wires, Mat4::IDENTITY, glam::DVec3::ZERO, bounds),
poly_hit(
&poly_small,
false,
&wires,
Mat4::IDENTITY,
glam::DVec3::ZERO,
bounds
),
Vec::<&str>::new()
);
@@ -2853,11 +2897,26 @@ mod aabb_reject_tests {
// Window mode now selects "4F" once (deduplicated):
assert_eq!(
box_hit(big_a, big_b, false, &wires, Mat4::IDENTITY, glam::DVec3::ZERO, bounds),
box_hit(
big_a,
big_b,
false,
&wires,
Mat4::IDENTITY,
glam::DVec3::ZERO,
bounds
),
vec!["4F"]
);
assert_eq!(
poly_hit(&poly_big, false, &wires, Mat4::IDENTITY, glam::DVec3::ZERO, bounds),
poly_hit(
&poly_big,
false,
&wires,
Mat4::IDENTITY,
glam::DVec3::ZERO,
bounds
),
vec!["4F"]
);
}
@@ -2881,12 +2940,7 @@ mod parallel_selection_tests {
[x + 0.01 * f, y + 0.01 * f, 0.0]
})
.collect();
let mut w = WireModel::solid(
(i as u64 + 1).to_string(),
points,
[1.0; 4],
false,
);
let mut w = WireModel::solid((i as u64 + 1).to_string(), points, [1.0; 4], false);
w.aabb = [x, y, x + 0.01, y + 0.01];
w
})
+93 -91
View File
@@ -323,8 +323,7 @@ impl SpatialGrid {
use crate::par::prelude::*;
use std::sync::atomic::{AtomicU32, Ordering};
let counts: Vec<AtomicU32> =
(0..cell_count).map(|_| AtomicU32::new(0)).collect();
let counts: Vec<AtomicU32> = (0..cell_count).map(|_| AtomicU32::new(0)).collect();
let oversized: Vec<u32> = entries
.par_iter()
.enumerate()
@@ -582,8 +581,7 @@ impl<T: Copy + Ord + Sync> SpatialSet<T> {
}
fn prepare_screen(&self) {
self.xyz
.get_or_init(|| SpatialBvh3::build(&self.entries));
self.xyz.get_or_init(|| SpatialBvh3::build(&self.entries));
}
fn query_screen(
@@ -694,17 +692,15 @@ fn append_wire_index_entries(wire_idx: u32, wire: &WireModel, batch: &mut WireIn
.max((wire.line_weight_px * 0.5).max(0.0));
}
if let Some(marker) = wire.point_marker {
batch.max_marker_radius_fraction = batch.max_marker_radius_fraction.max(
marker.viewport_percent.max(0.0) * 0.01 * std::f32::consts::SQRT_2,
);
batch.max_marker_radius_fraction = batch
.max_marker_radius_fraction
.max(marker.viewport_percent.max(0.0) * 0.01 * std::f32::consts::SQRT_2);
}
if wire.point_marker.is_none() && !wire.is_node_marker() {
for start in 0..wire.points.len().saturating_sub(1) {
let Some(aabb) = points_aabb3([
wire_point(wire, start),
wire_point(wire, start + 1),
]) else {
let Some(aabb) = points_aabb3([wire_point(wire, start), wire_point(wire, start + 1)])
else {
continue;
};
batch.segments.push(Entry3 {
@@ -739,8 +735,7 @@ fn append_wire_index_entries(wire_idx: u32, wire: &WireModel, batch: &mut WireIn
}
}
for start in 0..wire.key_vertices.len().saturating_sub(1) {
let Some(aabb) =
points_aabb3([wire.key_vertices[start], wire.key_vertices[start + 1]])
let Some(aabb) = points_aabb3([wire.key_vertices[start], wire.key_vertices[start + 1]])
else {
continue;
};
@@ -922,8 +917,7 @@ impl InteractionIndex {
let mut max_marker_radius_fraction = 0.0f32;
for mut batch in batches {
max_line_half_width_px =
max_line_half_width_px.max(batch.max_line_half_width_px);
max_line_half_width_px = max_line_half_width_px.max(batch.max_line_half_width_px);
max_marker_radius_fraction =
max_marker_radius_fraction.max(batch.max_marker_radius_fraction);
wire_entries.append(&mut batch.wire_entries);
@@ -1038,7 +1032,12 @@ impl InteractionIndex {
crate::par::join(
|| {
crate::par::join(
|| crate::par::join(|| self.wires.prepare_screen(), || self.segments.prepare_screen()),
|| {
crate::par::join(
|| self.wires.prepare_screen(),
|| self.segments.prepare_screen(),
)
},
|| {
crate::par::join(
|| self.snap_points.prepare_screen(),
@@ -1083,8 +1082,8 @@ impl InteractionIndex {
viewport_height_px: f32,
include_line_weight: bool,
) -> f32 {
let radius = base_radius_px
.max(self.max_marker_radius_fraction * viewport_height_px.max(0.0));
let radius =
base_radius_px.max(self.max_marker_radius_fraction * viewport_height_px.max(0.0));
if include_line_weight {
radius.max(self.max_line_half_width_px)
} else {
@@ -1108,12 +1107,7 @@ impl InteractionIndex {
.get(index as usize)
.copied()
.flatten()
.zip(
self.wire_ordinals
.get(index as usize)
.copied()
.flatten(),
)
.zip(self.wire_ordinals.get(index as usize).copied().flatten())
})
.collect();
keys.sort_unstable();
@@ -1143,16 +1137,8 @@ impl InteractionIndex {
index: u32,
slots: &rustc_hash::FxHashMap<(u64, u32), u32>,
) -> Option<u32> {
let handle = self
.wire_handles
.get(index as usize)
.copied()
.flatten()?;
let ordinal = self
.wire_ordinals
.get(index as usize)
.copied()
.flatten()?;
let handle = self.wire_handles.get(index as usize).copied().flatten()?;
let ordinal = self.wire_ordinals.get(index as usize).copied().flatten()?;
slots.get(&(handle, ordinal)).copied()
}
@@ -1246,11 +1232,7 @@ impl InteractionIndex {
) -> InteractionCandidates {
InteractionCandidates {
wires,
wire_indices: Some(self.remap_wire_indices(
self.wires.query_xy(aabb),
slots,
false,
)),
wire_indices: Some(self.remap_wire_indices(self.wires.query_xy(aabb), slots, false)),
segments: Some(self.remap_refs(
self.segments.query_xy(aabb),
slots,
@@ -1311,56 +1293,66 @@ impl InteractionIndex {
InteractionCandidates {
wires,
wire_indices: Some(self.remap_wire_indices(
self.wires
.query_screen(screen_rect, view_rot, eye, bounds),
self.wires.query_screen(screen_rect, view_rot, eye, bounds),
slots,
true,
)),
segments: Some(self.remap_refs(
self.segments
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
)),
snap_points: Some(self.remap_refs(
self.snap_points
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
)),
key_vertices: Some(self.remap_refs(
self.key_vertices
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
)),
key_segments: Some(self.remap_refs(
self.key_segments
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
)),
fill_triangles: Some(self.remap_refs(
self.fill_triangles
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
)),
pick_triangles: Some(self.remap_refs(
self.pick_triangles
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
)),
segments: Some(
self.remap_refs(
self.segments
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
),
),
snap_points: Some(
self.remap_refs(
self.snap_points
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
),
),
key_vertices: Some(
self.remap_refs(
self.key_vertices
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
),
),
key_segments: Some(
self.remap_refs(
self.key_segments
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
),
),
fill_triangles: Some(
self.remap_refs(
self.fill_triangles
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
),
),
pick_triangles: Some(
self.remap_refs(
self.pick_triangles
.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
),
),
glyphs: Some(self.remap_refs(
self.glyphs
.query_screen(screen_rect, view_rot, eye, bounds),
self.glyphs.query_screen(screen_rect, view_rot, eye, bounds),
slots,
|value| value.wire,
|value, wire| value.wire = wire,
@@ -1664,9 +1656,7 @@ impl InteractionCandidates {
target.extend(incoming);
}
if let (Some(target), Some(incoming)) =
(self.wire_indices.as_mut(), other.wire_indices)
{
if let (Some(target), Some(incoming)) = (self.wire_indices.as_mut(), other.wire_indices) {
target.extend(incoming);
target.sort_unstable();
target.dedup();
@@ -2016,9 +2006,21 @@ mod area_query_tests {
fn sample() -> Vec<WireModel> {
vec![
wire("5", vec![[-0.5, -0.5, 0.0], [0.5, 0.5, 0.0]], [-0.5, -0.5, 0.5, 0.5]),
wire("9", vec![[0.1, -0.9, 0.0], [0.9, -0.1, 0.0]], [0.1, -0.9, 0.9, -0.1]),
wire("13", vec![[-0.9, 0.2, 0.0], [-0.2, 0.9, 0.0]], [-0.9, 0.2, -0.2, 0.9]),
wire(
"5",
vec![[-0.5, -0.5, 0.0], [0.5, 0.5, 0.0]],
[-0.5, -0.5, 0.5, 0.5],
),
wire(
"9",
vec![[0.1, -0.9, 0.0], [0.9, -0.1, 0.0]],
[0.1, -0.9, 0.9, -0.1],
),
wire(
"13",
vec![[-0.9, 0.2, 0.0], [-0.2, 0.9, 0.0]],
[-0.9, 0.2, -0.2, 0.9],
),
]
}
+8 -7
View File
@@ -268,10 +268,7 @@ pub fn normalize_aabb(mut aabb: Aabb) -> Aabb {
}
fn aabb_contained(outer: Aabb, inner: Aabb) -> bool {
inner[0] >= outer[0]
&& inner[1] >= outer[1]
&& inner[2] <= outer[2]
&& inner[3] <= outer[3]
inner[0] >= outer[0] && inner[1] >= outer[1] && inner[2] <= outer[2] && inner[3] <= outer[3]
}
fn aabb_intersects(a: Aabb, b: Aabb) -> bool {
@@ -384,7 +381,13 @@ mod tests {
let huge = [-1e9, -1e9, 1e9, 1e9];
let hits = t.query_rect(huge);
let expected = 40 + 100;
assert_eq!(hits.len(), expected, "lost items: tree.len={} hits.len={}", t.len(), hits.len());
assert_eq!(
hits.len(),
expected,
"lost items: tree.len={} hits.len={}",
t.len(),
hits.len()
);
}
#[test]
@@ -429,5 +432,3 @@ mod tests {
assert_eq!(normalized, [10.0, 20.0, 50.0, 60.0]);
}
}
+49 -48
View File
@@ -37,13 +37,15 @@ fn resolve_extension_dictionary(doc: &CadDocument, owner: Handle) -> Option<Hand
return Some(h);
}
}
doc.objects.iter().find_map(|(handle, object)| match object {
ObjectType::Dictionary(d) if d.owner == owner && !handle.is_null() => Some(*handle),
ObjectType::DictionaryWithDefault(d) if d.owner == owner && !handle.is_null() => {
Some(*handle)
}
_ => None,
})
doc.objects
.iter()
.find_map(|(handle, object)| match object {
ObjectType::Dictionary(d) if d.owner == owner && !handle.is_null() => Some(*handle),
ObjectType::DictionaryWithDefault(d) if d.owner == owner && !handle.is_null() => {
Some(*handle)
}
_ => None,
})
}
/// The INSERT's extension dictionary through its own link or the document's
@@ -63,17 +65,12 @@ fn linked_extension_dictionary(doc: &CadDocument, ins: &Insert) -> Option<Handle
/// (dictionary) → SPATIAL (SpatialFilter)`. Returns `None` when there is no
/// filter, it is disabled (code 71 = 0), or it has fewer than two boundary
/// points.
pub fn insert_spatial_filter<'a>(
doc: &'a CadDocument,
ins: &Insert,
) -> Option<&'a SpatialFilter> {
pub fn insert_spatial_filter<'a>(doc: &'a CadDocument, ins: &Insert) -> Option<&'a SpatialFilter> {
let xdict = linked_extension_dictionary(doc, ins)?;
let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?;
let spatial = dict_entry(doc, acad_filter, "SPATIAL")?;
match doc.objects.get(&spatial)? {
ObjectType::SpatialFilter(sf)
if sf.display_enabled && sf.boundary_points.len() >= 2 =>
{
ObjectType::SpatialFilter(sf) if sf.display_enabled && sf.boundary_points.len() >= 2 => {
Some(sf)
}
_ => None,
@@ -90,7 +87,11 @@ pub fn filter_handle(doc: &CadDocument, insert: Handle) -> Option<Handle> {
let xdict = linked_extension_dictionary(doc, ins)?;
let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?;
let spatial = dict_entry(doc, acad_filter, "SPATIAL")?;
matches!(doc.objects.get(&spatial), Some(ObjectType::SpatialFilter(_))).then_some(spatial)
matches!(
doc.objects.get(&spatial),
Some(ObjectType::SpatialFilter(_))
)
.then_some(spatial)
}
const ROUNDTRIP: &str = "ACAD_XREC_ROUNDTRIP";
@@ -120,7 +121,11 @@ pub fn inverted_boundary(doc: &CadDocument, filter: &SpatialFilter) -> Option<Ve
/// The inverted boundary drawn as the XCLIP frame and generated polyline,
/// else the stored one; rectangles as four corners (WCS through the stored
/// transforms).
pub fn clip_outline_world(doc: &CadDocument, filter: &SpatialFilter, xform: &Transform) -> Vec<[f64; 2]> {
pub fn clip_outline_world(
doc: &CadDocument,
filter: &SpatialFilter,
xform: &Transform,
) -> Vec<[f64; 2]> {
match inverted_boundary(doc, filter) {
Some(points) => {
let mut outline = filter.clone();
@@ -177,7 +182,9 @@ pub fn remove_insert_clip(doc: &mut CadDocument, insert: Handle) -> bool {
if let Some(xdict) = doc.extension_dictionary_handle(spatial) {
let children: Vec<Handle> = match doc.objects.get(&xdict) {
Some(ObjectType::Dictionary(d)) => d.entries.iter().map(|(_, h)| *h).collect(),
Some(ObjectType::DictionaryWithDefault(d)) => d.entries.iter().map(|(_, h)| *h).collect(),
Some(ObjectType::DictionaryWithDefault(d)) => {
d.entries.iter().map(|(_, h)| *h).collect()
}
_ => Vec::new(),
};
for child in children {
@@ -315,7 +322,8 @@ pub fn set_insert_clip(
filter.boundary_points = stored.iter().map(|p| Vector2::new(p[0], p[1])).collect();
filter.inverse_block_transform = inverse;
filter.clip_bound_transform = Matrix4::identity();
doc.objects.insert(spatial, ObjectType::SpatialFilter(filter));
doc.objects
.insert(spatial, ObjectType::SpatialFilter(filter));
match doc.objects.get_mut(&acad_filter) {
Some(ObjectType::Dictionary(parent)) => parent.add_entry("SPATIAL", spatial),
Some(ObjectType::DictionaryWithDefault(parent)) => {
@@ -372,10 +380,7 @@ fn dict_entry(doc: &CadDocument, dict: Handle, key: &str) -> Option<Handle> {
/// Build the clip boundary in absolute f64 world coordinates so clipping at
/// large coordinate values remains precise.
#[cfg(test)]
fn world_clip_polygon_f64(
sf: &SpatialFilter,
ins: &Insert,
) -> Vec<[f64; 2]> {
fn world_clip_polygon_f64(sf: &SpatialFilter, ins: &Insert) -> Vec<[f64; 2]> {
world_clip_polygon_for_transform(sf, &ins.get_transform())
}
@@ -385,10 +390,7 @@ fn world_clip_polygon_f64(
///
/// The filter's `inverse_block_transform` is used as stored: the codec decodes
/// the on-disk column-major 4x3 layout into row-major `Matrix4`.
pub fn world_clip_polygon_for_transform(
sf: &SpatialFilter,
xform: &Transform,
) -> Vec<[f64; 2]> {
pub fn world_clip_polygon_for_transform(sf: &SpatialFilter, xform: &Transform) -> Vec<[f64; 2]> {
let inv_block = &sf.inverse_block_transform;
let local: Vec<[f64; 2]> = if sf.boundary_points.len() == 2 {
let a = sf.boundary_points[0];
@@ -475,7 +477,9 @@ pub fn clip_wires(wires: &mut Vec<WireModel>, poly: &[[f64; 2]]) {
&local,
&lpoly,
station_data.map(|(stations, _)| stations),
station_map.as_ref().map(|map| map.point_segments.as_slice()),
station_map
.as_ref()
.map(|map| map.point_segments.as_slice()),
);
// Local → absolute, re-split into double-single high/low.
let mut hi = Vec::with_capacity(clipped.len());
@@ -499,7 +503,9 @@ pub fn clip_wires(wires: &mut Vec<WireModel>, poly: &[[f64; 2]]) {
clipped_stations,
source_length,
&clipped_segments,
station_map.as_ref().map_or(&[], |map| map.pieces.as_slice()),
station_map
.as_ref()
.map_or(&[], |map| map.pieces.as_slice()),
);
} else {
w.pattern_stations.clear();
@@ -574,9 +580,7 @@ pub fn clip_wires(wires: &mut Vec<WireModel>, poly: &[[f64; 2]]) {
}
w.aabb = bb;
}
wires.retain(|w| {
!w.points.is_empty() || !w.fill_tris.is_empty() || !w.text_verts.is_empty()
});
wires.retain(|w| !w.points.is_empty() || !w.fill_tris.is_empty() || !w.text_verts.is_empty());
}
/// Double-single split of an f64 into (high, low) f32 — mirrors
@@ -639,9 +643,9 @@ pub fn frame_wire(
plinegen: true,
fill_tris: vec![],
fill_tris_low: Vec::new(),
..Default::default()
}
}
}
/// Clip a hatch fill boundary to `poly`.
@@ -670,10 +674,7 @@ pub fn clip_hatch_boundary(
continue;
}
let start = i;
while i < boundary.len()
&& boundary[i][0].is_finite()
&& boundary[i][1].is_finite()
{
while i < boundary.len() && boundary[i][0].is_finite() && boundary[i][1].is_finite() {
i += 1;
}
// Lift the loop into the clip polygon's world space.
@@ -817,9 +818,8 @@ fn clip_polyline_stationed(
a + (values[start + j + 1] - a) * t
})
};
let contiguous = last.is_some_and(|l| {
(l[0] - a[0]).abs() <= 1e-4 && (l[1] - a[1]).abs() <= 1e-4
});
let contiguous = last
.is_some_and(|l| (l[0] - a[0]).abs() <= 1e-4 && (l[1] - a[1]).abs() <= 1e-4);
if !contiguous {
if !out.is_empty() {
out.push(NAN3);
@@ -856,11 +856,7 @@ fn clip_polyline_stationed(
/// Handles convex and concave boundaries by testing the midpoint of every
/// interval between consecutive boundary crossings.
#[cfg(test)]
fn clip_segment(
p0: [f32; 3],
p1: [f32; 3],
poly: &[[f32; 2]],
) -> Vec<([f32; 3], [f32; 3])> {
fn clip_segment(p0: [f32; 3], p1: [f32; 3], poly: &[[f32; 2]]) -> Vec<([f32; 3], [f32; 3])> {
let lerp = |t: f32| {
[
p0[0] + (p1[0] - p0[0]) * t,
@@ -1118,7 +1114,7 @@ mod tests {
text_verts: Vec::new(),
points: vec![[5.0, 5.0, 0.0], [15.0, 5.0, 0.0]],
..Default::default()
}];
}];
clip_wires(&mut wires, &poly);
assert_eq!(wires.len(), 1);
@@ -1130,7 +1126,7 @@ mod tests {
#[test]
fn hatch_boundary_clipped_kept_and_dropped() {
let clip = square(); // 0..10
// Hatch loop straddling the right edge → clipped to x<=10.
// Hatch loop straddling the right edge → clipped to x<=10.
let straddle = [[5.0, 5.0], [15.0, 5.0], [15.0, 8.0], [5.0, 8.0]];
let out = clip_hatch_boundary(&straddle, [0.0, 0.0], &clip);
assert!(!out.is_empty());
@@ -1151,7 +1147,12 @@ mod tests {
fn hatch_boundary_respects_world_origin() {
// Same geometry as the straddle case but expressed as offsets from a
// large world_origin — clipping must account for the origin shift.
let clip = vec![[1000.0, 1000.0], [1010.0, 1000.0], [1010.0, 1010.0], [1000.0, 1010.0]];
let clip = vec![
[1000.0, 1000.0],
[1010.0, 1000.0],
[1010.0, 1010.0],
[1000.0, 1010.0],
];
let origin = [1000.0, 1000.0];
let loop_off = [[5.0, 5.0], [15.0, 5.0], [15.0, 8.0], [5.0, 8.0]];
let out = clip_hatch_boundary(&loop_off, origin, &clip);