forked from 1b-agent/opencadstudio-upstream
style: apply cargo fmt across workspace
This commit is contained in:
1 parent
85710e5454
commit
9cf9ff2c5c
531 files changed
+57740
-33906
No files matched your search
+19
-10
@@ -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
@@ -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
|
||||
})
|
||||
|
||||
@@ -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],
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user