forked from 1b-agent/opencadstudio-upstream
Merge pull request #1512 from ramox81/codex/frame-parity
Frames: follow the drawing state, DWF/DGN frames, image frame profile, frame-only picking The codec [patch] to ramox81/cadcodec@ea5edaa is dropped: that commit landed as opencadcodec#63 and main already pins ad16215, which contains it.
This commit is contained in:
commit
7694c506aa
70 files changed
+445
-64
No files matched your search
Vendored
+2
@@ -1750,6 +1750,7 @@ impl Batches {
|
||||
world_width: b.world_width,
|
||||
depth_override: b.local_depth,
|
||||
display_visible: !b.hide_unselected || selected,
|
||||
snap_only: false,
|
||||
plot_visible: b.plot_visible,
|
||||
fill_is_3d: b.fill_is_3d,
|
||||
fill_is_2d_solid: b.fill_is_2d_solid,
|
||||
@@ -2516,6 +2517,7 @@ fn emit_wire(
|
||||
world_width: 0.0,
|
||||
depth_override: local_depth,
|
||||
display_visible: !lw.hide_unselected || ctx.selected,
|
||||
snap_only: false,
|
||||
plot_visible: lw.plot_visible,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -931,6 +931,7 @@ fn tessellate_entity_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1176,6 +1177,7 @@ fn tessellate_entity_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1296,6 +1298,8 @@ fn tessellate_entity_inner(
|
||||
wire.points_low = points_low;
|
||||
wire.display_visible = false;
|
||||
wire.plot_visible = false;
|
||||
// Snaps find it; a click on the page does not select the underlay.
|
||||
wire.snap_only = true;
|
||||
if let Some((center, radius)) = piece.circle {
|
||||
wire.tangent_geoms = vec![crate::scene::model::wire_model::TangentGeom::PlanarCircle {
|
||||
center,
|
||||
@@ -1549,6 +1553,7 @@ fn lod_stub_wire(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1645,6 +1650,7 @@ fn lod_stub_wire_3d(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -373,6 +373,7 @@ fn split_mixed_polyline(
|
||||
world_width,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -508,6 +509,7 @@ fn split_mixed_polyline(
|
||||
world_width: line_world_width,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -571,6 +573,7 @@ fn point_cloud_wires(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -826,6 +829,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: true,
|
||||
@@ -990,6 +994,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1382,6 +1387,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1439,6 +1445,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1493,6 +1500,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1528,6 +1536,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1593,6 +1602,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1640,6 +1650,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1684,6 +1695,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1721,6 +1733,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1792,6 +1805,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1951,6 +1965,7 @@ pub fn tessellate(
|
||||
world_width: polyline_band_width(entity, document.header.fill_mode),
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2022,6 +2037,7 @@ pub fn tessellate(
|
||||
render_instance: None,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
});
|
||||
}
|
||||
@@ -2035,6 +2051,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2094,6 +2111,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2183,6 +2201,7 @@ pub fn tessellate(
|
||||
world_width: polyline_band_width(entity, document.header.fill_mode),
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2261,6 +2280,7 @@ pub fn tessellate(
|
||||
world_width,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2370,6 +2390,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
+57
-13
@@ -5,19 +5,52 @@ use codec::{CadDocument, EntityType, Handle};
|
||||
pub(crate) enum FrameKind {
|
||||
Image,
|
||||
Pdf,
|
||||
Dwf,
|
||||
Dgn,
|
||||
Wipeout,
|
||||
Xclip,
|
||||
PointCloudClip,
|
||||
}
|
||||
|
||||
pub(crate) const ALL_KINDS: [FrameKind; 5] = [
|
||||
pub(crate) const ALL_KINDS: [FrameKind; 7] = [
|
||||
FrameKind::Image,
|
||||
FrameKind::Pdf,
|
||||
FrameKind::Dwf,
|
||||
FrameKind::Dgn,
|
||||
FrameKind::Wipeout,
|
||||
FrameKind::Xclip,
|
||||
FrameKind::PointCloudClip,
|
||||
];
|
||||
|
||||
/// IMAGEFRAME of the user profile: what a drawing without its own image
|
||||
/// variables shows, and what a new drawing starts with. Setting IMAGEFRAME
|
||||
/// updates it, so it carries over to new drawings and later sessions.
|
||||
static PROFILE_IMAGE_FRAME: std::sync::atomic::AtomicI16 = std::sync::atomic::AtomicI16::new(1);
|
||||
|
||||
pub(crate) fn profile_image_mode() -> i16 {
|
||||
PROFILE_IMAGE_FRAME.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub(crate) fn set_profile_image_mode(value: i16) {
|
||||
PROFILE_IMAGE_FRAME.store(value.clamp(0, 2), std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// The image variables store the frame as bits: 1 shown, 2 not plotted, so
|
||||
/// "shown but not plotted" is 3. Any other value is not one the variable
|
||||
/// can hold, and the profile setting applies.
|
||||
fn image_mode_from_flags(flags: i16) -> Option<i16> {
|
||||
match flags {
|
||||
0 => Some(0),
|
||||
1 => Some(1),
|
||||
3 => Some(2),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn image_flags_from_mode(mode: i16) -> i16 {
|
||||
if mode == 2 { 3 } else { mode }
|
||||
}
|
||||
|
||||
fn root_entry(document: &CadDocument, name: &str) -> Option<Handle> {
|
||||
let from_dictionary = |handle| match document.objects.get(&handle) {
|
||||
Some(ObjectType::Dictionary(dictionary)) => dictionary
|
||||
@@ -58,12 +91,15 @@ pub(crate) fn mode(document: &CadDocument, kind: FrameKind) -> i16 {
|
||||
match kind {
|
||||
FrameKind::Image => raster_variables_handle(document)
|
||||
.and_then(|handle| match document.objects.get(&handle) {
|
||||
Some(ObjectType::RasterVariables(value)) => Some(value.display_image_frame),
|
||||
Some(ObjectType::RasterVariables(value)) => {
|
||||
image_mode_from_flags(value.display_image_frame)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(1)
|
||||
.clamp(0, 2),
|
||||
.unwrap_or_else(profile_image_mode),
|
||||
FrameKind::Pdf => drawing_mode(document, "PDFFRAME", 1),
|
||||
FrameKind::Dwf => document.header.dwf_frame.clamp(0, 2),
|
||||
FrameKind::Dgn => document.header.dgn_frame.clamp(0, 2),
|
||||
FrameKind::Wipeout => crate::io::drawing_variable(document, "WIPEOUTFRAME")
|
||||
.and_then(|value| value.parse::<i16>().ok())
|
||||
.or_else(|| {
|
||||
@@ -115,8 +151,9 @@ fn set_image_mode(document: &mut CadDocument, value: i16) {
|
||||
});
|
||||
if let Some(ObjectType::RasterVariables(variables)) = document.objects.get_mut(&handle) {
|
||||
variables.owner = owner;
|
||||
variables.display_image_frame = value;
|
||||
variables.display_image_frame = image_flags_from_mode(value);
|
||||
}
|
||||
set_profile_image_mode(value);
|
||||
attach_root_entry(document, "ACAD_IMAGE_VARS", handle);
|
||||
}
|
||||
|
||||
@@ -145,6 +182,8 @@ pub(crate) fn set_mode(document: &mut CadDocument, kind: FrameKind, value: i16)
|
||||
match kind {
|
||||
FrameKind::Image => set_image_mode(document, value),
|
||||
FrameKind::Pdf => crate::io::set_drawing_variable(document, "PDFFRAME", &value.to_string()),
|
||||
FrameKind::Dwf => document.header.dwf_frame = value,
|
||||
FrameKind::Dgn => document.header.dgn_frame = value,
|
||||
FrameKind::Wipeout => set_wipeout_mode(document, value),
|
||||
FrameKind::Xclip => document.header.xclip_frame = value,
|
||||
FrameKind::PointCloudClip => crate::io::set_drawing_variable(
|
||||
@@ -168,6 +207,8 @@ pub(crate) fn kind_for_name(name: &str) -> Option<FrameKind> {
|
||||
match name {
|
||||
"IMAGEFRAME" => Some(FrameKind::Image),
|
||||
"PDFFRAME" => Some(FrameKind::Pdf),
|
||||
"DWFFRAME" => Some(FrameKind::Dwf),
|
||||
"DGNFRAME" => Some(FrameKind::Dgn),
|
||||
"WIPEOUTFRAME" => Some(FrameKind::Wipeout),
|
||||
"XCLIPFRAME" => Some(FrameKind::Xclip),
|
||||
"POINTCLOUDCLIPFRAME" => Some(FrameKind::PointCloudClip),
|
||||
@@ -178,23 +219,26 @@ pub(crate) fn kind_for_name(name: &str) -> Option<FrameKind> {
|
||||
pub(crate) fn entity_kind(entity: &EntityType) -> Option<FrameKind> {
|
||||
match entity {
|
||||
EntityType::RasterImage(_) => Some(FrameKind::Image),
|
||||
EntityType::Underlay(underlay)
|
||||
if matches!(underlay.underlay_type, codec::entities::UnderlayType::Pdf) =>
|
||||
{
|
||||
Some(FrameKind::Pdf)
|
||||
}
|
||||
EntityType::Underlay(underlay) => Some(underlay_kind(underlay)),
|
||||
EntityType::Wipeout(_) => Some(FrameKind::Wipeout),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn underlay_kind(underlay: &codec::entities::Underlay) -> FrameKind {
|
||||
match underlay.underlay_type {
|
||||
codec::entities::UnderlayType::Pdf => FrameKind::Pdf,
|
||||
codec::entities::UnderlayType::Dwf => FrameKind::Dwf,
|
||||
codec::entities::UnderlayType::Dgn => FrameKind::Dgn,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn affected(entity: &EntityType, kind: FrameKind) -> bool {
|
||||
match kind {
|
||||
FrameKind::Image => matches!(entity, EntityType::RasterImage(_)),
|
||||
FrameKind::Pdf => matches!(
|
||||
FrameKind::Pdf | FrameKind::Dwf | FrameKind::Dgn => matches!(
|
||||
entity,
|
||||
EntityType::Underlay(underlay)
|
||||
if matches!(underlay.underlay_type, codec::entities::UnderlayType::Pdf)
|
||||
EntityType::Underlay(underlay) if underlay_kind(underlay) == kind
|
||||
),
|
||||
FrameKind::Wipeout => matches!(entity, EntityType::Wipeout(_)),
|
||||
FrameKind::Xclip => matches!(entity, EntityType::Insert(_)),
|
||||
|
||||
@@ -506,6 +506,9 @@ pub struct WireModel {
|
||||
pub depth_override: Option<f32>,
|
||||
/// Whether this wire is drawn in the normal viewport pass.
|
||||
pub display_visible: bool,
|
||||
/// Geometry that only object snaps use (the content of an underlay):
|
||||
/// never drawn, plotted or picked.
|
||||
pub snap_only: bool,
|
||||
/// Whether this wire is included in plotted output.
|
||||
pub plot_visible: bool,
|
||||
/// `true` when [`fill_tris`] is a real 3-D surface (PolyfaceMesh /
|
||||
@@ -580,6 +583,7 @@ impl WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1009,6 +1013,7 @@ impl Default for WireModel {
|
||||
fill_tris_low: Vec::new(),
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -249,6 +249,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -277,6 +280,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
} else {
|
||||
// Q: lazy projection — no Vec allocation per wire; NaN resets the segment chain.
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -329,6 +335,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if let Some(depth) = triangle_ref_hit_depth(
|
||||
cursor,
|
||||
wire,
|
||||
@@ -345,6 +354,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.fill_tris.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -381,6 +393,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if let Some(depth) = triangle_ref_hit_depth(
|
||||
cursor,
|
||||
wire,
|
||||
@@ -397,6 +412,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.pick_tris.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -438,6 +456,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let start = glyph.start as usize;
|
||||
let Some(vertices) = wire.text_verts.get(start..start + 6) else {
|
||||
continue;
|
||||
@@ -451,6 +472,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.text_verts.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -516,6 +540,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -550,6 +577,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}));
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -593,6 +623,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
matched.insert(triangle.wire);
|
||||
continue;
|
||||
@@ -614,6 +647,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.fill_tris.is_empty() || hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
continue;
|
||||
}
|
||||
@@ -647,6 +683,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
matched.insert(triangle.wire);
|
||||
continue;
|
||||
@@ -668,6 +707,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.pick_tris.is_empty() || hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
continue;
|
||||
}
|
||||
@@ -697,6 +739,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
matched.insert(glyph.wire);
|
||||
continue;
|
||||
@@ -712,6 +757,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.text_verts.is_empty() || hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
continue;
|
||||
}
|
||||
@@ -1252,6 +1300,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
// path below run identical code.
|
||||
let hit_name = |segment: &SegmentRef| -> Option<&'a str> {
|
||||
let wire = wires.source_wire(segment.wire)?;
|
||||
if wire.snap_only {
|
||||
return None;
|
||||
}
|
||||
let start = segment.start as usize;
|
||||
if start + 1 >= wire.points.len() {
|
||||
return None;
|
||||
@@ -1310,6 +1361,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if already(&wire_hit, triangle.wire) {
|
||||
continue;
|
||||
}
|
||||
@@ -1334,6 +1388,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if already(&wire_hit, glyph.wire) {
|
||||
continue;
|
||||
}
|
||||
@@ -1355,6 +1412,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
|
||||
// Degenerate point-only wires have no indexed segment or surface primitive.
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.points.len() >= 2
|
||||
|| !wire.fill_tris.is_empty()
|
||||
|| !wire.pick_tris.is_empty()
|
||||
@@ -1411,6 +1471,9 @@ pub fn poly_fence_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let start = segment.start as usize;
|
||||
if start + 1 >= wire.points.len() || seen.contains(wire.name.as_str()) {
|
||||
continue;
|
||||
@@ -1442,6 +1505,9 @@ pub fn poly_fence_hit<'a, W: WireSource + ?Sized>(
|
||||
return out;
|
||||
}
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.points.len() < 2 {
|
||||
continue;
|
||||
}
|
||||
@@ -1480,6 +1546,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let start = segment.start as usize;
|
||||
if start + 1 >= wire.points.len() {
|
||||
continue;
|
||||
@@ -1524,6 +1593,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if seen.contains(wire.name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
@@ -1546,6 +1618,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if seen.contains(wire.name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
@@ -1565,6 +1640,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
}
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.points.len() >= 2
|
||||
|| !wire.fill_tris.is_empty()
|
||||
|| !wire.pick_tris.is_empty()
|
||||
@@ -1644,6 +1722,9 @@ pub fn box_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut out = Vec::new();
|
||||
let mut seen = HashSet::default();
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
// Fallback: when wire has no line geometry (e.g. greek text emits
|
||||
// only fill_tris) treat the AABB rectangle as the hit-test shape
|
||||
// so low-LOD text stays selectable. See #19.
|
||||
@@ -1729,6 +1810,9 @@ pub fn box_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut seen = HashSet::default();
|
||||
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let name = wire.name.as_str();
|
||||
if disqualified.contains(name) {
|
||||
continue;
|
||||
@@ -1838,6 +1922,9 @@ pub fn poly_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut out = Vec::new();
|
||||
let mut seen = HashSet::default();
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
// Same AABB fallback as `box_hit`: when a wire has no line
|
||||
// geometry (e.g. greek-LOD text emits only fill_tris) treat the
|
||||
// AABB rectangle as the hit-test shape so low-LOD text stays
|
||||
@@ -1925,6 +2012,9 @@ pub fn poly_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut seen = HashSet::default();
|
||||
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let aabb_pts: Vec<[f32; 3]>;
|
||||
let empty_pts: [[f32; 3]; 0] = [];
|
||||
let pts: &[[f32; 3]] = if !wire.points.is_empty() {
|
||||
|
||||
@@ -551,6 +551,7 @@ pub fn frame_wire(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -316,6 +316,7 @@ pub fn apply_along(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -365,6 +366,7 @@ pub fn apply_along(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
Reference in new issue
Block a user