perf: AABB snap pre-rejection via acadrust bounding_box() (Option K upgrade)
Add `aabb: [f32; 4]` field to WireModel (world-space 2-D bounding box). In tessellate_entity() set each wire's AABB from e.as_entity().bounding_box() via new entity_aabb() helper; Insert sub-entities each get their own AABB. Preview/interim wires and any entity returning a zero-extent default box get UNBOUNDED_AABB so they are never pre-rejected. Replace the chord-sphere heuristic in Snapper::wire_in_range() with a proper AABB vs snap-circle overlap test. The new check is four scalar comparisons and correctly handles closed curves (circles, arcs) which the chord-sphere approach had to special-case. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2da9301a2b
commit
bfd8d0411a
35 changed files with 107 additions and 25 deletions
|
|
@ -1261,6 +1261,7 @@ impl H7CAD {
|
|||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
aabb: crate::scene::WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
previews.push(guide);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ impl CadCommand for AlignedDimensionCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -134,5 +135,6 @@ fn preview_aligned(p1: Vec3, p2: Vec3, dim_pt: Vec3) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,5 +100,6 @@ fn preview_line(a: Vec3, b: Vec3) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ impl CadCommand for DimBaselineCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ impl CadCommand for DimContinueCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ impl CadCommand for DimJogLineCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ impl CadCommand for DimTeditCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -365,6 +365,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ impl CadCommand for QdimCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,5 +111,6 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ impl CadCommand for TableCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ impl CadCommand for ToleranceCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ impl CadCommand for AttdefCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -526,5 +526,6 @@ fn line_wire(from: Vec3, to: Vec3) -> WireModel {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ impl CadCommand for LineCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ impl CadCommand for MlineCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ impl CadCommand for ImageCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ impl CadCommand for RayCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -162,6 +163,7 @@ impl CadCommand for XLineCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ impl CadCommand for RevCloudCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ impl CadCommand for WipeoutCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
WipeoutMode::Polygonal => {
|
||||
|
|
@ -138,6 +139,7 @@ impl CadCommand for WipeoutCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ impl CadCommand for AreaCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ impl CadCommand for DistCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ impl CadCommand for StretchCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ impl CadCommand for MviewCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ impl CadCommand for PlotWindowCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ impl CadCommand for ZoomWindowCommand {
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ pub fn apply_along(
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2552,9 +2552,11 @@ fn tessellate_entity(
|
|||
} else {
|
||||
(0.0_f32, [0.0f32; 8])
|
||||
};
|
||||
return vec![tessellate::tessellate(
|
||||
let mut wire = tessellate::tessellate(
|
||||
document, h, e, sel, color, pattern_length, pattern, 1.5,
|
||||
)];
|
||||
);
|
||||
wire.aabb = entity_aabb(e);
|
||||
return vec![wire];
|
||||
}
|
||||
|
||||
let (entity_color, pattern_length, pattern, line_weight_px, aci) =
|
||||
|
|
@ -2563,11 +2565,13 @@ fn tessellate_entity(
|
|||
let lt_name = render::linetype_name_for(document, e);
|
||||
|
||||
if let EntityType::Dimension(dim) = e {
|
||||
let aabb = entity_aabb(e);
|
||||
let mut wires = tessellate::tessellate_dimension(
|
||||
document, h, dim, sel, entity_color, line_weight_px,
|
||||
);
|
||||
for w in &mut wires {
|
||||
w.aci = aci;
|
||||
w.aabb = aabb;
|
||||
}
|
||||
return wires;
|
||||
}
|
||||
|
|
@ -2583,6 +2587,7 @@ fn tessellate_entity(
|
|||
.flat_map(|sub| {
|
||||
let (sub_color, sub_pattern_length, sub_pattern, sub_line_weight_px, sub_aci) =
|
||||
render::render_style_for(document, &sub);
|
||||
let sub_aabb = entity_aabb(&sub);
|
||||
let mut wire = tessellate::tessellate(
|
||||
document,
|
||||
h,
|
||||
|
|
@ -2595,18 +2600,21 @@ fn tessellate_entity(
|
|||
);
|
||||
wire.name = h.value().to_string();
|
||||
wire.aci = sub_aci;
|
||||
wire.aabb = sub_aabb;
|
||||
vec![wire]
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
let aabb = entity_aabb(e);
|
||||
let mut base = tessellate::tessellate(
|
||||
document, h, e, sel, entity_color, pattern_length, pattern, line_weight_px,
|
||||
);
|
||||
base.aci = aci;
|
||||
base.aabb = aabb;
|
||||
|
||||
if let Some(clt) = crate::linetypes::complex_lt(lt_name) {
|
||||
let wires = complex_lt::apply_along(
|
||||
let mut wires = complex_lt::apply_along(
|
||||
&base.name,
|
||||
&base.points,
|
||||
clt,
|
||||
|
|
@ -2616,6 +2624,7 @@ fn tessellate_entity(
|
|||
base.line_weight_px,
|
||||
);
|
||||
if !wires.is_empty() {
|
||||
for w in &mut wires { w.aabb = aabb; }
|
||||
return wires;
|
||||
}
|
||||
}
|
||||
|
|
@ -2623,3 +2632,17 @@ fn tessellate_entity(
|
|||
vec![base]
|
||||
}
|
||||
|
||||
fn entity_aabb(e: &acadrust::EntityType) -> [f32; 4] {
|
||||
let bbox = e.as_entity().bounding_box();
|
||||
let min_x = bbox.min.x as f32;
|
||||
let min_y = bbox.min.y as f32;
|
||||
let max_x = bbox.max.x as f32;
|
||||
let max_y = bbox.max.y as f32;
|
||||
// A degenerate box (min == max == 0) means bounding_box() returned Default —
|
||||
// use UNBOUNDED so the wire is never wrongly pre-rejected.
|
||||
if min_x == 0.0 && min_y == 0.0 && max_x == 0.0 && max_y == 0.0 {
|
||||
return WireModel::UNBOUNDED_AABB;
|
||||
}
|
||||
[min_x, min_y, max_x, max_y]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ pub fn tessellate(
|
|||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -122,6 +123,7 @@ pub fn tessellate(
|
|||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -142,6 +144,7 @@ pub fn tessellate(
|
|||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -160,6 +163,7 @@ pub fn tessellate(
|
|||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -177,6 +181,7 @@ pub fn tessellate(
|
|||
tangent_geoms: te.tangent_geoms,
|
||||
aci: 0,
|
||||
key_vertices: te.key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -205,6 +210,7 @@ pub fn tessellate(
|
|||
snap_pts,
|
||||
tangent_geoms,
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -241,6 +247,7 @@ pub fn tessellate_dimension(
|
|||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}];
|
||||
|
||||
if let Some(text) = dimension_text_entity(dim) {
|
||||
|
|
@ -287,6 +294,7 @@ fn tessellate_leader(
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -354,6 +362,7 @@ fn tessellate_leader(
|
|||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}]
|
||||
}
|
||||
|
||||
|
|
@ -460,6 +469,7 @@ fn tessellate_multileader(
|
|||
tangent_geoms: vec![],
|
||||
aci: 0,
|
||||
key_vertices: key_verts,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
}];
|
||||
|
||||
// Render text content as MText wire
|
||||
|
|
|
|||
|
|
@ -55,12 +55,20 @@ pub struct WireModel {
|
|||
/// Non-empty only for entities with distinct vertex positions (Line, LwPolyline).
|
||||
/// Empty for tessellated curves (Circle, Arc, Ellipse) which use snap_pts instead.
|
||||
pub key_vertices: Vec<[f32; 3]>,
|
||||
/// World-space 2-D bounding box [min_x, min_y, max_x, max_y].
|
||||
/// Set from acadrust `bounding_box()` in `tessellate_entity()`.
|
||||
/// Preview / interim wires use `UNBOUNDED_AABB` so they are never pre-rejected
|
||||
/// by the snap world-space filter.
|
||||
pub aabb: [f32; 4],
|
||||
}
|
||||
|
||||
impl WireModel {
|
||||
pub const WHITE: [f32; 4] = [1.00, 1.00, 1.00, 1.0];
|
||||
pub const CYAN: [f32; 4] = [0.25, 0.85, 1.00, 1.0];
|
||||
pub const SELECTED: [f32; 4] = [0.15, 0.55, 1.00, 1.0];
|
||||
/// Sentinel AABB that never rejects any snap query.
|
||||
pub const UNBOUNDED_AABB: [f32; 4] =
|
||||
[f32::NEG_INFINITY, f32::NEG_INFINITY, f32::INFINITY, f32::INFINITY];
|
||||
|
||||
/// Create a solid wire (no dash pattern, 1px weight).
|
||||
pub fn solid(name: String, points: Vec<[f32; 3]>, color: [f32; 4], selected: bool) -> Self {
|
||||
|
|
@ -76,6 +84,7 @@ impl WireModel {
|
|||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
aabb: Self::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,3 +168,22 @@ impl WireModel {
|
|||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WireModel {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: String::new(),
|
||||
points: Vec::new(),
|
||||
color: Self::WHITE,
|
||||
selected: false,
|
||||
pattern_length: 0.0,
|
||||
pattern: [0.0; 8],
|
||||
line_weight_px: 1.0,
|
||||
aci: 0,
|
||||
snap_pts: Vec::new(),
|
||||
tangent_geoms: Vec::new(),
|
||||
key_vertices: Vec::new(),
|
||||
aabb: Self::UNBOUNDED_AABB,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -291,29 +291,16 @@ impl Snapper {
|
|||
if s > 1e-6 { self.snap_radius_px / s } else { f32::MAX }
|
||||
};
|
||||
|
||||
// Returns false when the wire's chord sphere is definitely outside the
|
||||
// snap circle — safe to skip all vertex work for this wire.
|
||||
// Uses first/last point of key_vertices (if any) or tessellated points.
|
||||
// Closed wires (first ≈ last) are always passed through because the
|
||||
// chord radius would be ~0 and their arc can still pass near the cursor.
|
||||
// Returns false when the wire's AABB does not overlap the snap circle —
|
||||
// safe to skip all vertex work for this wire.
|
||||
// UNBOUNDED_AABB (±infinity) passes through automatically without a
|
||||
// special-case branch because the arithmetic is exact for infinities.
|
||||
let wire_in_range = |wire: &WireModel| -> bool {
|
||||
let pts: &[[f32; 3]] = if !wire.key_vertices.is_empty() {
|
||||
&wire.key_vertices
|
||||
} else {
|
||||
&wire.points
|
||||
};
|
||||
let (Some(&f), Some(&l)) = (pts.first(), pts.last()) else {
|
||||
return false;
|
||||
};
|
||||
let dx = l[0] - f[0];
|
||||
let dy = l[1] - f[1];
|
||||
let half_chord = (dx * dx + dy * dy).sqrt() * 0.5;
|
||||
if half_chord < 1e-4 {
|
||||
return true; // closed or degenerate — can't prune
|
||||
}
|
||||
let cx = (f[0] + l[0]) * 0.5 - cursor_world.x;
|
||||
let cy = (f[1] + l[1]) * 0.5 - cursor_world.y;
|
||||
cx * cx + cy * cy <= (world_snap_r + half_chord) * (world_snap_r + half_chord)
|
||||
let r = world_snap_r;
|
||||
cursor_world.x + r >= wire.aabb[0]
|
||||
&& cursor_world.x - r <= wire.aabb[2]
|
||||
&& cursor_world.y + r >= wire.aabb[1]
|
||||
&& cursor_world.y - r <= wire.aabb[3]
|
||||
};
|
||||
|
||||
let mut try_pt = |world: Vec3, snap_type: SnapType| {
|
||||
|
|
|
|||
Loading…
Reference in a new issue