refactor: remove dead world_offset plumbing (RTE migration is complete)
Now that geometry reaches the GPU/CPU as absolute coordinates via the double-single relative-to-eye path, world_offset is always [0,0,0]. Strip the parameter that was threaded through the whole tessellation / block- expansion / fallback / camera-decode chain and the ExpandCtx field that carried it — ~340 references across 20 files, all subtracting zero. - truck_tess: to_local / to_local_low / tessellate_* drop the offset arg; to_local is now a pure double-single split. - tessellate: offset_to_ds → points_to_ds (pure DS split); tessellate(), tessellate_entity(), fallback_geometry(), solid_wire_fallback(), entity_aabb(), expand_insert(), expand_block_meshes(), the dimension helpers (vec3_local, dimension_snap_pts, …), text_support, leader, multileader, image_model, xclip and camera_from_view all lose the param. - block_cache: ExpandCtx loses its world_offset field. - Remove the now-dead offset_snap_pts and the unused set_grid_snap. Behaviour is unchanged (the offset was zero everywhere); the compiler verifies every call site. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
02d40bd2ec
commit
56d507fd88
20 changed files with 190 additions and 343 deletions
|
|
@ -1241,7 +1241,6 @@ impl OpenCADStudio {
|
||||||
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
|
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
|
||||||
if let Some(entity) = entity_opt {
|
if let Some(entity) = entity_opt {
|
||||||
let truck_entity = entity.to_truck_entity(&self.tabs[i].scene.document);
|
let truck_entity = entity.to_truck_entity(&self.tabs[i].scene.document);
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
let result = truck_entity.and_then(|te| {
|
let result = truck_entity.and_then(|te| {
|
||||||
match te.object {
|
match te.object {
|
||||||
TruckObject::Contour(wire) => {
|
TruckObject::Contour(wire) => {
|
||||||
|
|
@ -1250,7 +1249,7 @@ impl OpenCADStudio {
|
||||||
// tsweep(Face) → Solid
|
// tsweep(Face) → Solid
|
||||||
let solid =
|
let solid =
|
||||||
builder::tsweep(&face, TruckVec3::new(0.0, 0.0, height as f64));
|
builder::tsweep(&face, TruckVec3::new(0.0, 0.0, height as f64));
|
||||||
match truck_tess::tessellate_solid(&solid, woff) {
|
match truck_tess::tessellate_solid(&solid) {
|
||||||
truck_tess::TruckTessResult::Mesh {
|
truck_tess::TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
@ -1309,7 +1308,6 @@ impl OpenCADStudio {
|
||||||
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
|
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
|
||||||
if let Some(entity) = entity_opt {
|
if let Some(entity) = entity_opt {
|
||||||
let truck_entity = entity.to_truck_entity(&self.tabs[i].scene.document);
|
let truck_entity = entity.to_truck_entity(&self.tabs[i].scene.document);
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
let result = truck_entity.and_then(|te| {
|
let result = truck_entity.and_then(|te| {
|
||||||
let wire: Option<truck_modeling::Wire> = match te.object {
|
let wire: Option<truck_modeling::Wire> = match te.object {
|
||||||
TruckObject::Contour(w) => Some(w),
|
TruckObject::Contour(w) => Some(w),
|
||||||
|
|
@ -1330,7 +1328,7 @@ impl OpenCADStudio {
|
||||||
axis,
|
axis,
|
||||||
Rad(angle_deg.to_radians() as f64),
|
Rad(angle_deg.to_radians() as f64),
|
||||||
);
|
);
|
||||||
match truck_tess::tessellate_shell(&shell, woff) {
|
match truck_tess::tessellate_shell(&shell) {
|
||||||
truck_tess::TruckTessResult::Mesh {
|
truck_tess::TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
@ -1389,7 +1387,6 @@ impl OpenCADStudio {
|
||||||
.get_entity(profile_handle)
|
.get_entity(profile_handle)
|
||||||
.cloned();
|
.cloned();
|
||||||
let path_ent = self.tabs[i].scene.document.get_entity(path_handle).cloned();
|
let path_ent = self.tabs[i].scene.document.get_entity(path_handle).cloned();
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
|
|
||||||
let result = profile_ent.zip(path_ent).and_then(|(prof_e, path_e)| {
|
let result = profile_ent.zip(path_ent).and_then(|(prof_e, path_e)| {
|
||||||
let prof_truck = prof_e.to_truck_entity(&self.tabs[i].scene.document)?;
|
let prof_truck = prof_e.to_truck_entity(&self.tabs[i].scene.document)?;
|
||||||
|
|
@ -1417,7 +1414,7 @@ impl OpenCADStudio {
|
||||||
// wire we get a Solid, otherwise a Shell.
|
// wire we get a Solid, otherwise a Shell.
|
||||||
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
|
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
|
||||||
let solid = builder::tsweep(&face, dir);
|
let solid = builder::tsweep(&face, dir);
|
||||||
match truck_tess::tessellate_solid(&solid, woff) {
|
match truck_tess::tessellate_solid(&solid) {
|
||||||
truck_tess::TruckTessResult::Mesh {
|
truck_tess::TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
@ -1436,7 +1433,7 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let shell = builder::tsweep(&profile_wire, dir);
|
let shell = builder::tsweep(&profile_wire, dir);
|
||||||
match truck_tess::tessellate_shell(&shell, woff) {
|
match truck_tess::tessellate_shell(&shell) {
|
||||||
truck_tess::TruckTessResult::Mesh {
|
truck_tess::TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
@ -1470,7 +1467,7 @@ impl OpenCADStudio {
|
||||||
);
|
);
|
||||||
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
|
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
|
||||||
let solid = builder::tsweep(&face, dir);
|
let solid = builder::tsweep(&face, dir);
|
||||||
match truck_tess::tessellate_solid(&solid, woff) {
|
match truck_tess::tessellate_solid(&solid) {
|
||||||
truck_tess::TruckTessResult::Mesh {
|
truck_tess::TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
@ -1489,7 +1486,7 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let shell = builder::tsweep(&profile_wire, dir);
|
let shell = builder::tsweep(&profile_wire, dir);
|
||||||
match truck_tess::tessellate_shell(&shell, woff) {
|
match truck_tess::tessellate_shell(&shell) {
|
||||||
truck_tess::TruckTessResult::Mesh {
|
truck_tess::TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
@ -1556,7 +1553,6 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
let result: Option<crate::scene::model::mesh_model::MeshModel> = (|| {
|
let result: Option<crate::scene::model::mesh_model::MeshModel> = (|| {
|
||||||
if wires.len() < 2 {
|
if wires.len() < 2 {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -1581,7 +1577,7 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
|
|
||||||
let shell = truck_modeling::Shell::from(all_faces);
|
let shell = truck_modeling::Shell::from(all_faces);
|
||||||
match truck_tess::tessellate_shell(&shell, woff) {
|
match truck_tess::tessellate_shell(&shell) {
|
||||||
truck_tess::TruckTessResult::Mesh {
|
truck_tess::TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
|
||||||
|
|
@ -406,7 +406,6 @@ impl super::OpenCADStudio {
|
||||||
0.0,
|
0.0,
|
||||||
[0.0; 8],
|
[0.0; 8],
|
||||||
1.0,
|
1.0,
|
||||||
woff,
|
|
||||||
anno,
|
anno,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -849,7 +849,6 @@ pub trait DimensionTess {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
|
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
|
||||||
active_viewport: Option<acadrust::Handle>,
|
active_viewport: Option<acadrust::Handle>,
|
||||||
|
|
@ -867,7 +866,6 @@ impl DimensionTess for Dimension {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
|
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
|
||||||
active_viewport: Option<acadrust::Handle>,
|
active_viewport: Option<acadrust::Handle>,
|
||||||
|
|
@ -882,7 +880,6 @@ impl DimensionTess for Dimension {
|
||||||
selected,
|
selected,
|
||||||
entity_color,
|
entity_color,
|
||||||
line_weight_px,
|
line_weight_px,
|
||||||
world_offset,
|
|
||||||
anno_scale,
|
anno_scale,
|
||||||
selected_set,
|
selected_set,
|
||||||
active_viewport,
|
active_viewport,
|
||||||
|
|
@ -900,7 +897,6 @@ fn tessellate_dimension_inner(
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
// LOD hints — when present, synthesised dim text routes through the
|
// LOD hints — when present, synthesised dim text routes through the
|
||||||
// top-level LOD ladder (baseline / greek / full) instead of the truck
|
// top-level LOD ladder (baseline / greek / full) instead of the truck
|
||||||
|
|
@ -1012,7 +1008,6 @@ fn tessellate_dimension_inner(
|
||||||
let text_break = {
|
let text_break = {
|
||||||
let tp = vec3_local(
|
let tp = vec3_local(
|
||||||
dimension_text_pos_f64(dim, style, dim_txt, dim_scale),
|
dimension_text_pos_f64(dim, style, dim_txt, dim_scale),
|
||||||
world_offset,
|
|
||||||
);
|
);
|
||||||
let tw = dimension_text_value(dim, style)
|
let tw = dimension_text_value(dim, style)
|
||||||
.map(|t| t.chars().count() as f32 * dim_txt as f32 * 0.6)
|
.map(|t| t.chars().count() as f32 * dim_txt as f32 * 0.6)
|
||||||
|
|
@ -1054,7 +1049,6 @@ fn tessellate_dimension_inner(
|
||||||
dim1: dimsd1,
|
dim1: dimsd1,
|
||||||
dim2: dimsd2,
|
dim2: dimsd2,
|
||||||
},
|
},
|
||||||
world_offset,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// DIMTMOVE = 1: when the saved text_middle_point sits far from the
|
// DIMTMOVE = 1: when the saved text_middle_point sits far from the
|
||||||
|
|
@ -1062,7 +1056,7 @@ fn tessellate_dimension_inner(
|
||||||
// to the dim line — no leader; =2 frees text without a leader.)
|
// to the dim line — no leader; =2 frees text without a leader.)
|
||||||
if let Some(s) = style {
|
if let Some(s) = style {
|
||||||
if s.dimtmove == 1 {
|
if s.dimtmove == 1 {
|
||||||
if let Some((anchor, txt)) = dimtmove_leader_endpoints(dim, world_offset) {
|
if let Some((anchor, txt)) = dimtmove_leader_endpoints(dim) {
|
||||||
let gap = dim_txt as f32 * 0.5;
|
let gap = dim_txt as f32 * 0.5;
|
||||||
if (txt - anchor).length() > gap * 2.0 {
|
if (txt - anchor).length() > gap * 2.0 {
|
||||||
add_segment(&mut geom.dim_lines, anchor, txt);
|
add_segment(&mut geom.dim_lines, anchor, txt);
|
||||||
|
|
@ -1120,7 +1114,7 @@ fn tessellate_dimension_inner(
|
||||||
resolve_dim_color(style.map(|s| s.dimclrt).unwrap_or(0), entity_color)
|
resolve_dim_color(style.map(|s| s.dimclrt).unwrap_or(0), entity_color)
|
||||||
};
|
};
|
||||||
|
|
||||||
let snap_pts = dimension_snap_pts(dim, world_offset);
|
let snap_pts = dimension_snap_pts(dim);
|
||||||
let key_vertices: Vec<[f64; 3]> = geom
|
let key_vertices: Vec<[f64; 3]> = geom
|
||||||
.dim_lines
|
.dim_lines
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -1244,7 +1238,7 @@ fn tessellate_dimension_inner(
|
||||||
// DIMTFILL: 0=none, 1=drawing background (mask), 2=DIMTFILLCLR.
|
// DIMTFILL: 0=none, 1=drawing background (mask), 2=DIMTFILLCLR.
|
||||||
if let Some(s) = style {
|
if let Some(s) = style {
|
||||||
if s.dimtfill == 1 || s.dimtfill == 2 {
|
if s.dimtfill == 1 || s.dimtfill == 2 {
|
||||||
if let Some(rect) = text_fill_rect(dim, style, dim_txt, world_offset, dim_scale) {
|
if let Some(rect) = text_fill_rect(dim, style, dim_txt, dim_scale) {
|
||||||
let fill_color = if selected {
|
let fill_color = if selected {
|
||||||
WireModel::SELECTED
|
WireModel::SELECTED
|
||||||
} else if s.dimtfill == 1 {
|
} else if s.dimtfill == 1 {
|
||||||
|
|
@ -1290,7 +1284,6 @@ fn tessellate_dimension_inner(
|
||||||
document,
|
document,
|
||||||
selected_set,
|
selected_set,
|
||||||
active_viewport,
|
active_viewport,
|
||||||
world_offset,
|
|
||||||
bg_color,
|
bg_color,
|
||||||
1.0,
|
1.0,
|
||||||
&synth_text_entity,
|
&synth_text_entity,
|
||||||
|
|
@ -1308,7 +1301,6 @@ fn tessellate_dimension_inner(
|
||||||
document,
|
document,
|
||||||
selected_set,
|
selected_set,
|
||||||
active_viewport,
|
active_viewport,
|
||||||
world_offset,
|
|
||||||
bg_color,
|
bg_color,
|
||||||
1.0,
|
1.0,
|
||||||
&tol_entity_e,
|
&tol_entity_e,
|
||||||
|
|
@ -1395,13 +1387,13 @@ fn split_ext_lines(points: &[[f32; 3]]) -> (Vec<[f32; 3]>, Vec<[f32; 3]>) {
|
||||||
/// text_middle_point). Returns None when the dim has no saved text position
|
/// text_middle_point). Returns None when the dim has no saved text position
|
||||||
/// or has no well-defined dim-line midpoint (radius/diameter handled by
|
/// or has no well-defined dim-line midpoint (radius/diameter handled by
|
||||||
/// their own leg).
|
/// their own leg).
|
||||||
fn dimtmove_leader_endpoints(dim: &Dimension, world_offset: [f64; 3]) -> Option<(Vec3, Vec3)> {
|
fn dimtmove_leader_endpoints(dim: &Dimension) -> Option<(Vec3, Vec3)> {
|
||||||
let base = dim.base();
|
let base = dim.base();
|
||||||
let txt = base.text_middle_point;
|
let txt = base.text_middle_point;
|
||||||
if txt.x * txt.x + txt.y * txt.y + txt.z * txt.z <= 1e-16 {
|
if txt.x * txt.x + txt.y * txt.y + txt.z * txt.z <= 1e-16 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let lv = |v| vec3_local(v, world_offset);
|
let lv = |v| vec3_local(v);
|
||||||
let anchor = match dim {
|
let anchor = match dim {
|
||||||
Dimension::Linear(d) => {
|
Dimension::Linear(d) => {
|
||||||
let perp = Vec3::new(-(d.rotation.sin() as f32), d.rotation.cos() as f32, 0.0);
|
let perp = Vec3::new(-(d.rotation.sin() as f32), d.rotation.cos() as f32, 0.0);
|
||||||
|
|
@ -1437,7 +1429,6 @@ fn text_fill_rect(
|
||||||
dim: &Dimension,
|
dim: &Dimension,
|
||||||
style: Option<&DimStyle>,
|
style: Option<&DimStyle>,
|
||||||
text_height: f64,
|
text_height: f64,
|
||||||
world_offset: [f64; 3],
|
|
||||||
dim_scale: f64,
|
dim_scale: f64,
|
||||||
) -> Option<Vec<[f32; 3]>> {
|
) -> Option<Vec<[f32; 3]>> {
|
||||||
let value = dimension_text_value(dim, style)?;
|
let value = dimension_text_value(dim, style)?;
|
||||||
|
|
@ -1458,7 +1449,7 @@ fn text_fill_rect(
|
||||||
let (sr, cr) = rot.sin_cos();
|
let (sr, cr) = rot.sin_cos();
|
||||||
let hx = approx_w * 0.5;
|
let hx = approx_w * 0.5;
|
||||||
let hy = approx_h * 0.5;
|
let hy = approx_h * 0.5;
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let cx = (pos.x - ox) as f32;
|
let cx = (pos.x - ox) as f32;
|
||||||
let cy = (pos.y - oy) as f32;
|
let cy = (pos.y - oy) as f32;
|
||||||
let cz = (pos.z - oz) as f32;
|
let cz = (pos.z - oz) as f32;
|
||||||
|
|
@ -1503,9 +1494,8 @@ fn dimension_geometry(
|
||||||
arrow2: &ArrowKind,
|
arrow2: &ArrowKind,
|
||||||
params: DimLineParams,
|
params: DimLineParams,
|
||||||
suppress: SuppressFlags,
|
suppress: SuppressFlags,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> DimGeom {
|
) -> DimGeom {
|
||||||
let lv = |v| vec3_local(v, world_offset);
|
let lv = |v| vec3_local(v);
|
||||||
let mut g = DimGeom::new();
|
let mut g = DimGeom::new();
|
||||||
match dim {
|
match dim {
|
||||||
Dimension::Aligned(d) => {
|
Dimension::Aligned(d) => {
|
||||||
|
|
@ -1547,7 +1537,7 @@ fn dimension_geometry(
|
||||||
Dimension::Radius(d) => {
|
Dimension::Radius(d) => {
|
||||||
let center = lv(d.angle_vertex);
|
let center = lv(d.angle_vertex);
|
||||||
let point = lv(d.definition_point);
|
let point = lv(d.definition_point);
|
||||||
let text = dimension_text_position(dim, world_offset);
|
let text = dimension_text_position(dim);
|
||||||
add_segment(&mut g.dim_lines, center, point);
|
add_segment(&mut g.dim_lines, center, point);
|
||||||
// Honour leader_length: extend from the arrow tip past it
|
// Honour leader_length: extend from the arrow tip past it
|
||||||
// toward the text by that distance along (text - point).
|
// toward the text by that distance along (text - point).
|
||||||
|
|
@ -1575,7 +1565,7 @@ fn dimension_geometry(
|
||||||
append_arrow(&mut g, p2, normalized_or(p1 - p2, Vec3::X), arrow2);
|
append_arrow(&mut g, p2, normalized_or(p1 - p2, Vec3::X), arrow2);
|
||||||
// DIMETER leader: continue past p2 toward the text.
|
// DIMETER leader: continue past p2 toward the text.
|
||||||
if d.leader_length.abs() > 1e-9 {
|
if d.leader_length.abs() > 1e-9 {
|
||||||
let text = dimension_text_position(dim, world_offset);
|
let text = dimension_text_position(dim);
|
||||||
let leader_dir = normalized_or(text - p2, p2 - p1);
|
let leader_dir = normalized_or(text - p2, p2 - p1);
|
||||||
add_segment(
|
add_segment(
|
||||||
&mut g.dim_lines,
|
&mut g.dim_lines,
|
||||||
|
|
@ -1839,12 +1829,12 @@ fn append_angular_dimension(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dimension_snap_pts(dim: &Dimension, world_offset: [f64; 3]) -> Vec<(glam::DVec3, SnapHint)> {
|
fn dimension_snap_pts(dim: &Dimension) -> Vec<(glam::DVec3, SnapHint)> {
|
||||||
let lv = |v: acadrust::types::Vector3| {
|
let lv = |v: acadrust::types::Vector3| {
|
||||||
glam::DVec3::new(
|
glam::DVec3::new(
|
||||||
v.x - world_offset[0],
|
v.x,
|
||||||
v.y - world_offset[1],
|
v.y,
|
||||||
v.z - world_offset[2],
|
v.z,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let node = |v: acadrust::types::Vector3| (lv(v), SnapHint::Node);
|
let node = |v: acadrust::types::Vector3| (lv(v), SnapHint::Node);
|
||||||
|
|
@ -2568,8 +2558,8 @@ fn swap_decimal_sep(s: &str, dsep_code: i16) -> String {
|
||||||
s.replace('.', &ch.to_string())
|
s.replace('.', &ch.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dimension_text_position(dim: &Dimension, world_offset: [f64; 3]) -> Vec3 {
|
fn dimension_text_position(dim: &Dimension) -> Vec3 {
|
||||||
let lv = |v| vec3_local(v, world_offset);
|
let lv = |v| vec3_local(v);
|
||||||
let base = dim.base();
|
let base = dim.base();
|
||||||
let pos = lv(base.text_middle_point);
|
let pos = lv(base.text_middle_point);
|
||||||
if pos.length_squared() > 1e-8 {
|
if pos.length_squared() > 1e-8 {
|
||||||
|
|
@ -2586,12 +2576,8 @@ fn dimension_text_position(dim: &Dimension, world_offset: [f64; 3]) -> Vec3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vec3_local(v: Vector3, off: [f64; 3]) -> Vec3 {
|
fn vec3_local(v: Vector3) -> Vec3 {
|
||||||
Vec3::new(
|
Vec3::new(v.x as f32, v.y as f32, v.z as f32)
|
||||||
(v.x - off[0]) as f32,
|
|
||||||
(v.y - off[1]) as f32,
|
|
||||||
(v.z - off[2]) as f32,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Style-driven text anchor on the dimension line: a point on the line through
|
/// Style-driven text anchor on the dimension line: a point on the line through
|
||||||
|
|
|
||||||
|
|
@ -344,14 +344,13 @@ impl Grippable for Hatch {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FallbackTess for Hatch {
|
impl FallbackTess for Hatch {
|
||||||
fn fallback_geometry(&self, world_offset: [f64; 3]) -> FallbackGeometry {
|
fn fallback_geometry(&self) -> FallbackGeometry {
|
||||||
let [ox, oy, oz] = world_offset;
|
|
||||||
let normal = (self.normal.x, self.normal.y, self.normal.z);
|
let normal = (self.normal.x, self.normal.y, self.normal.z);
|
||||||
// Convert a 2D OCS hatch boundary point to WCS, then subtract world_offset.
|
// Convert a 2D OCS hatch boundary point to absolute WCS.
|
||||||
let to_wcs = |x: f64, y: f64| -> [f64; 3] {
|
let to_wcs = |x: f64, y: f64| -> [f64; 3] {
|
||||||
let (wx, wy, wz) =
|
let (wx, wy, wz) =
|
||||||
crate::scene::view::transform::ocs_point_to_wcs((x, y, self.elevation), normal);
|
crate::scene::view::transform::ocs_point_to_wcs((x, y, self.elevation), normal);
|
||||||
[wx - ox, wy - oy, wz - oz]
|
[wx, wy, wz]
|
||||||
};
|
};
|
||||||
// Snap point at a world (f64) location, cast to the f32 snap buffer.
|
// Snap point at a world (f64) location, cast to the f32 snap buffer.
|
||||||
let snap_at = |w: [f64; 3]| Vec3::new(w[0] as f32, w[1] as f32, w[2] as f32);
|
let snap_at = |w: [f64; 3]| Vec3::new(w[0] as f32, w[1] as f32, w[2] as f32);
|
||||||
|
|
|
||||||
|
|
@ -101,13 +101,11 @@ crate::impl_entity_basics!(Insert);
|
||||||
impl crate::entities::traits::FallbackTess for Insert {
|
impl crate::entities::traits::FallbackTess for Insert {
|
||||||
fn fallback_geometry(
|
fn fallback_geometry(
|
||||||
&self,
|
&self,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> crate::scene::convert::tess_util::FallbackGeometry {
|
) -> crate::scene::convert::tess_util::FallbackGeometry {
|
||||||
let [ox, oy, oz] = world_offset;
|
|
||||||
let (ipx, ipy, ipz) = (
|
let (ipx, ipy, ipz) = (
|
||||||
self.insert_point.x - ox,
|
self.insert_point.x,
|
||||||
self.insert_point.y - oy,
|
self.insert_point.y,
|
||||||
self.insert_point.z - oz,
|
self.insert_point.z,
|
||||||
);
|
);
|
||||||
let ip = Vec3::new(ipx as f32, ipy as f32, ipz as f32);
|
let ip = Vec3::new(ipx as f32, ipy as f32, ipz as f32);
|
||||||
let s = 0.1_f64;
|
let s = 0.1_f64;
|
||||||
|
|
@ -139,7 +137,6 @@ pub(crate) fn append_insert_attribute_wires(
|
||||||
is_xref: bool,
|
is_xref: bool,
|
||||||
pslt_factor: f32,
|
pslt_factor: f32,
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) {
|
) {
|
||||||
if ins.attributes.is_empty() {
|
if ins.attributes.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
|
@ -172,7 +169,7 @@ pub(crate) fn append_insert_attribute_wires(
|
||||||
} else {
|
} else {
|
||||||
sub_color
|
sub_color
|
||||||
};
|
};
|
||||||
let sub_aabb = crate::scene::entity_aabb(&attr_entity, world_offset);
|
let sub_aabb = crate::scene::entity_aabb(&attr_entity);
|
||||||
let mut attr_wires = tessellate::tessellate(
|
let mut attr_wires = tessellate::tessellate(
|
||||||
document,
|
document,
|
||||||
insert_handle,
|
insert_handle,
|
||||||
|
|
@ -182,7 +179,6 @@ pub(crate) fn append_insert_attribute_wires(
|
||||||
sub_plen * pslt_factor,
|
sub_plen * pslt_factor,
|
||||||
sub_pat.map(|v| v * pslt_factor),
|
sub_pat.map(|v| v * pslt_factor),
|
||||||
sub_lw_px,
|
sub_lw_px,
|
||||||
world_offset,
|
|
||||||
anno_scale,
|
anno_scale,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -567,7 +567,6 @@ pub trait LeaderTess {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
) -> crate::scene::model::wire_model::WireModel;
|
) -> crate::scene::model::wire_model::WireModel;
|
||||||
}
|
}
|
||||||
|
|
@ -580,7 +579,6 @@ impl LeaderTess for Leader {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
) -> crate::scene::model::wire_model::WireModel {
|
) -> crate::scene::model::wire_model::WireModel {
|
||||||
use crate::scene::convert::tessellate::{append_arrow, arrow_from_block, ArrowKind, DimGeom};
|
use crate::scene::convert::tessellate::{append_arrow, arrow_from_block, ArrowKind, DimGeom};
|
||||||
|
|
@ -591,7 +589,7 @@ impl LeaderTess for Leader {
|
||||||
entity_color
|
entity_color
|
||||||
};
|
};
|
||||||
let name = handle.value().to_string();
|
let name = handle.value().to_string();
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let p3 = |v: &acadrust::types::Vector3| -> [f32; 3] {
|
let p3 = |v: &acadrust::types::Vector3| -> [f32; 3] {
|
||||||
[(v.x - ox) as f32, (v.y - oy) as f32, (v.z - oz) as f32]
|
[(v.x - ox) as f32, (v.y - oy) as f32, (v.z - oz) as f32]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1069,7 +1069,6 @@ pub trait MultiLeaderTess {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
world_per_pixel: Option<f32>,
|
world_per_pixel: Option<f32>,
|
||||||
) -> Vec<crate::scene::model::wire_model::WireModel>;
|
) -> Vec<crate::scene::model::wire_model::WireModel>;
|
||||||
|
|
@ -1083,7 +1082,6 @@ impl MultiLeaderTess for MultiLeader {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
world_per_pixel: Option<f32>,
|
world_per_pixel: Option<f32>,
|
||||||
) -> Vec<crate::scene::model::wire_model::WireModel> {
|
) -> Vec<crate::scene::model::wire_model::WireModel> {
|
||||||
|
|
@ -1129,7 +1127,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||||
|
|
||||||
let name = handle.value().to_string();
|
let name = handle.value().to_string();
|
||||||
let nan = [f32::NAN; 3];
|
let nan = [f32::NAN; 3];
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let p3 = |v: &acadrust::types::Vector3| -> [f32; 3] {
|
let p3 = |v: &acadrust::types::Vector3| -> [f32; 3] {
|
||||||
[(v.x - ox) as f32, (v.y - oy) as f32, (v.z - oz) as f32]
|
[(v.x - ox) as f32, (v.y - oy) as f32, (v.z - oz) as f32]
|
||||||
};
|
};
|
||||||
|
|
@ -1349,7 +1347,6 @@ impl MultiLeaderTess for MultiLeader {
|
||||||
leader_pat_len,
|
leader_pat_len,
|
||||||
leader_pat,
|
leader_pat,
|
||||||
leader_lw_px,
|
leader_lw_px,
|
||||||
world_offset,
|
|
||||||
1.0,
|
1.0,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -182,16 +182,14 @@ crate::impl_entity_basics!(Ole2Frame);
|
||||||
impl crate::entities::traits::FallbackTess for Ole2Frame {
|
impl crate::entities::traits::FallbackTess for Ole2Frame {
|
||||||
fn fallback_geometry(
|
fn fallback_geometry(
|
||||||
&self,
|
&self,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> crate::scene::convert::tess_util::FallbackGeometry {
|
) -> crate::scene::convert::tess_util::FallbackGeometry {
|
||||||
// OLE objects carry a bounding rectangle in model space.
|
// OLE objects carry a bounding rectangle in model space.
|
||||||
// Render a simple X-through-rectangle placeholder.
|
// Render a simple X-through-rectangle placeholder.
|
||||||
let [ox, oy, oz] = world_offset;
|
let x0 = self.upper_left_corner.x;
|
||||||
let x0 = self.upper_left_corner.x - ox;
|
let y0 = self.lower_right_corner.y;
|
||||||
let y0 = self.lower_right_corner.y - oy;
|
let x1 = self.lower_right_corner.x;
|
||||||
let x1 = self.lower_right_corner.x - ox;
|
let y1 = self.upper_left_corner.y;
|
||||||
let y1 = self.upper_left_corner.y - oy;
|
let z = self.upper_left_corner.z;
|
||||||
let z = self.upper_left_corner.z - oz;
|
|
||||||
if (x1 - x0).abs() < 1e-6 && (y1 - y0).abs() < 1e-6 {
|
if (x1 - x0).abs() < 1e-6 && (y1 - y0).abs() < 1e-6 {
|
||||||
// Degenerate / unknown size — show a small cross.
|
// Degenerate / unknown size — show a small cross.
|
||||||
let s = 0.5_f64;
|
let s = 0.5_f64;
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,6 @@ pub fn tessellate_table(
|
||||||
selected: bool,
|
selected: bool,
|
||||||
entity_color: [f32; 4],
|
entity_color: [f32; 4],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> Vec<crate::scene::model::wire_model::WireModel> {
|
) -> Vec<crate::scene::model::wire_model::WireModel> {
|
||||||
use crate::scene::convert::tess_util::aci_to_rgba;
|
use crate::scene::convert::tess_util::aci_to_rgba;
|
||||||
use crate::scene::model::wire_model::WireModel;
|
use crate::scene::model::wire_model::WireModel;
|
||||||
|
|
@ -355,7 +354,7 @@ pub fn tessellate_table(
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let rel = |p: Vec3| -> [f32; 3] {
|
let rel = |p: Vec3| -> [f32; 3] {
|
||||||
[
|
[
|
||||||
(p.x as f64 - ox) as f32,
|
(p.x as f64 - ox) as f32,
|
||||||
|
|
|
||||||
|
|
@ -1702,7 +1702,6 @@ pub(crate) fn text_obb_corners_native(
|
||||||
pub(crate) fn text_baseline_points(
|
pub(crate) fn text_baseline_points(
|
||||||
e: &EntityType,
|
e: &EntityType,
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
n_lines: usize,
|
n_lines: usize,
|
||||||
) -> Vec<[f32; 3]> {
|
) -> Vec<[f32; 3]> {
|
||||||
let Some(corners) = text_obb_corners_native(e, anno_scale, Some(n_lines)) else {
|
let Some(corners) = text_obb_corners_native(e, anno_scale, Some(n_lines)) else {
|
||||||
|
|
@ -1723,7 +1722,7 @@ pub(crate) fn text_baseline_points(
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
let n_lines = n_lines.max(1);
|
let n_lines = n_lines.max(1);
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let cast = |p: [f64; 3]| -> [f32; 3] {
|
let cast = |p: [f64; 3]| -> [f32; 3] {
|
||||||
[(p[0] - ox) as f32, (p[1] - oy) as f32, (p[2] - oz) as f32]
|
[(p[0] - ox) as f32, (p[1] - oy) as f32, (p[2] - oz) as f32]
|
||||||
};
|
};
|
||||||
|
|
@ -1763,7 +1762,6 @@ pub(crate) fn text_baseline_points(
|
||||||
pub(crate) fn text_greek_obb_tris(
|
pub(crate) fn text_greek_obb_tris(
|
||||||
e: &EntityType,
|
e: &EntityType,
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
n_lines: usize,
|
n_lines: usize,
|
||||||
) -> Vec<[f32; 3]> {
|
) -> Vec<[f32; 3]> {
|
||||||
let Some(corners) = text_obb_corners_native(e, anno_scale, Some(n_lines)) else {
|
let Some(corners) = text_obb_corners_native(e, anno_scale, Some(n_lines)) else {
|
||||||
|
|
@ -1784,7 +1782,7 @@ pub(crate) fn text_greek_obb_tris(
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
let n_lines = n_lines.max(1);
|
let n_lines = n_lines.max(1);
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let cast = |p: [f64; 3]| -> [f32; 3] {
|
let cast = |p: [f64; 3]| -> [f32; 3] {
|
||||||
[(p[0] - ox) as f32, (p[1] - oy) as f32, (p[2] - oz) as f32]
|
[(p[0] - ox) as f32, (p[1] - oy) as f32, (p[2] - oz) as f32]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ pub trait TruckConvertible {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fallback geometry for entities not routed through the truck topology
|
/// Fallback geometry for entities not routed through the truck topology
|
||||||
/// pipeline (Viewport, Insert, Hatch outline, Ole2Frame). Returns
|
/// pipeline (Viewport, Insert, Hatch outline, Ole2Frame). Returns absolute
|
||||||
/// world-offset-relative `f32` points + snap/key vertices the
|
/// WCS `f32` points + snap/key vertices the dispatcher wraps into a
|
||||||
/// dispatcher wraps into a `WireModel`.
|
/// `WireModel`.
|
||||||
pub trait FallbackTess {
|
pub trait FallbackTess {
|
||||||
fn fallback_geometry(&self, world_offset: [f64; 3]) -> FallbackGeometry;
|
fn fallback_geometry(&self) -> FallbackGeometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Grippable {
|
pub trait Grippable {
|
||||||
|
|
|
||||||
|
|
@ -548,12 +548,10 @@ crate::impl_entity_basics!(Viewport);
|
||||||
impl crate::entities::traits::FallbackTess for Viewport {
|
impl crate::entities::traits::FallbackTess for Viewport {
|
||||||
fn fallback_geometry(
|
fn fallback_geometry(
|
||||||
&self,
|
&self,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> crate::scene::convert::tess_util::FallbackGeometry {
|
) -> crate::scene::convert::tess_util::FallbackGeometry {
|
||||||
let [ox, oy, oz] = world_offset;
|
let cx = self.center.x;
|
||||||
let cx = self.center.x - ox;
|
let cy = self.center.y;
|
||||||
let cy = self.center.y - oy;
|
let cz = self.center.z;
|
||||||
let cz = self.center.z - oz;
|
|
||||||
let hw = self.width / 2.0;
|
let hw = self.width / 2.0;
|
||||||
let hh = self.height / 2.0;
|
let hh = self.height / 2.0;
|
||||||
let pts = vec![
|
let pts = vec![
|
||||||
|
|
|
||||||
25
src/scene/cache/block_cache.rs
vendored
25
src/scene/cache/block_cache.rs
vendored
|
|
@ -423,7 +423,7 @@ fn build_nested_ref(
|
||||||
// its clip when the parent block is expanded — the spatial filter object
|
// its clip when the parent block is expanded — the spatial filter object
|
||||||
// isn't reachable at expand time.
|
// isn't reachable at expand time.
|
||||||
let clip_poly = crate::scene::pick::xclip::insert_spatial_filter(doc, nested_ins)
|
let clip_poly = crate::scene::pick::xclip::insert_spatial_filter(doc, nested_ins)
|
||||||
.map(|sf| crate::scene::pick::xclip::world_clip_polygon_f64(sf, nested_ins, [0.0; 3]));
|
.map(|sf| crate::scene::pick::xclip::world_clip_polygon_f64(sf, nested_ins));
|
||||||
|
|
||||||
NestedRef {
|
NestedRef {
|
||||||
block_name: nested_ins.block_name.clone(),
|
block_name: nested_ins.block_name.clone(),
|
||||||
|
|
@ -481,7 +481,7 @@ fn tessellate_sub_local(
|
||||||
// top-level MTEXT outside blocks the colour split is preserved via the
|
// top-level MTEXT outside blocks the colour split is preserved via the
|
||||||
// hot path in `tessellate_entity`.
|
// hot path in `tessellate_entity`.
|
||||||
let mut wires_out = tessellate::tessellate(
|
let mut wires_out = tessellate::tessellate(
|
||||||
doc, h, sub, false, sub_color, pat_len, pat, lw_px, local_offset, anno_scale, None,
|
doc, h, sub, false, sub_color, pat_len, pat, lw_px, anno_scale, None,
|
||||||
);
|
);
|
||||||
if wires_out.is_empty() {
|
if wires_out.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -654,7 +654,6 @@ pub fn expand_insert(
|
||||||
ins_pat: [f32; 8],
|
ins_pat: [f32; 8],
|
||||||
ins_lw_px: f32,
|
ins_lw_px: f32,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
world_offset: [f64; 3],
|
|
||||||
pslt_factor: f32,
|
pslt_factor: f32,
|
||||||
// World-space XY view AABB (with world_offset already subtracted, so the
|
// World-space XY view AABB (with world_offset already subtracted, so the
|
||||||
// comparison is in the same f32 space as emitted wires). `None` disables
|
// comparison is in the same f32 space as emitted wires). `None` disables
|
||||||
|
|
@ -674,7 +673,7 @@ pub fn expand_insert(
|
||||||
let name = ins_handle.value().to_string();
|
let name = ins_handle.value().to_string();
|
||||||
let mut batches = Batches::default();
|
let mut batches = Batches::default();
|
||||||
let mut visited: Vec<String> = Vec::with_capacity(8);
|
let mut visited: Vec<String> = Vec::with_capacity(8);
|
||||||
let [ox, oy, _] = world_offset;
|
let [ox, oy, _] = [0.0_f64; 3];
|
||||||
|
|
||||||
// `defn.aabb_local` is in the defn's offset frame — re-add
|
// `defn.aabb_local` is in the defn's offset frame — re-add
|
||||||
// `defn.local_offset` (f64) before transforming so the world AABB is
|
// `defn.local_offset` (f64) before transforming so the world AABB is
|
||||||
|
|
@ -717,7 +716,6 @@ pub fn expand_insert(
|
||||||
ins_pat,
|
ins_pat,
|
||||||
ins_lw_px,
|
ins_lw_px,
|
||||||
selected,
|
selected,
|
||||||
world_offset,
|
|
||||||
pslt_factor,
|
pslt_factor,
|
||||||
view_aabb,
|
view_aabb,
|
||||||
world_per_pixel,
|
world_per_pixel,
|
||||||
|
|
@ -744,7 +742,7 @@ fn emit_greeked_text(
|
||||||
ctx: &ExpandCtx,
|
ctx: &ExpandCtx,
|
||||||
out: &mut Batches,
|
out: &mut Batches,
|
||||||
) {
|
) {
|
||||||
let [ox, oy, oz] = ctx.world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let [lo_x, lo_y, lo_z] = defn_lo;
|
let [lo_x, lo_y, lo_z] = defn_lo;
|
||||||
// Re-add the defn's `local_offset` in f64 before composing with
|
// Re-add the defn's `local_offset` in f64 before composing with
|
||||||
// `accum_xform` so the rect corners share the batch's f32 space
|
// `accum_xform` so the rect corners share the batch's f32 space
|
||||||
|
|
@ -879,7 +877,7 @@ fn emit_text_baseline(
|
||||||
if h_local <= 0.0 {
|
if h_local <= 0.0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let [ox, oy, oz] = ctx.world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let [lo_x, lo_y, lo_z] = defn_lo;
|
let [lo_x, lo_y, lo_z] = defn_lo;
|
||||||
let xf = |p: [f32; 3]| -> [f32; 3] {
|
let xf = |p: [f32; 3]| -> [f32; 3] {
|
||||||
let w = accum_xform.apply(Vector3::new(
|
let w = accum_xform.apply(Vector3::new(
|
||||||
|
|
@ -1001,7 +999,6 @@ struct ExpandCtx<'a> {
|
||||||
ins_pat: [f32; 8],
|
ins_pat: [f32; 8],
|
||||||
ins_lw_px: f32,
|
ins_lw_px: f32,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
world_offset: [f64; 3],
|
|
||||||
pslt_factor: f32,
|
pslt_factor: f32,
|
||||||
// World-space XY view AABB (post world_offset). `None` = no culling.
|
// World-space XY view AABB (post world_offset). `None` = no culling.
|
||||||
view_aabb: Option<[f32; 4]>,
|
view_aabb: Option<[f32; 4]>,
|
||||||
|
|
@ -1219,7 +1216,7 @@ fn expand_defn(
|
||||||
// `defn_lo` (in f64) before composing with `accum_xform`
|
// `defn_lo` (in f64) before composing with `accum_xform`
|
||||||
// so culling uses correct world-space corners.
|
// so culling uses correct world-space corners.
|
||||||
let world = transform_offset_aabb_xy(lw.aabb_local, defn_lo, accum_xform);
|
let world = transform_offset_aabb_xy(lw.aabb_local, defn_lo, accum_xform);
|
||||||
let [ox, oy, _] = ctx.world_offset;
|
let [ox, oy, _] = [0.0_f64; 3];
|
||||||
let local = [
|
let local = [
|
||||||
world[0] - ox as f32,
|
world[0] - ox as f32,
|
||||||
world[1] - oy as f32,
|
world[1] - oy as f32,
|
||||||
|
|
@ -1282,7 +1279,7 @@ fn expand_defn(
|
||||||
nested_defn.local_offset,
|
nested_defn.local_offset,
|
||||||
&composed,
|
&composed,
|
||||||
);
|
);
|
||||||
let [ox, oy, _] = ctx.world_offset;
|
let [ox, oy, _] = [0.0_f64; 3];
|
||||||
let local = [
|
let local = [
|
||||||
world[0] - ox as f32,
|
world[0] - ox as f32,
|
||||||
world[1] - oy as f32,
|
world[1] - oy as f32,
|
||||||
|
|
@ -1322,7 +1319,6 @@ fn expand_defn(
|
||||||
ins_pat: nested_pat,
|
ins_pat: nested_pat,
|
||||||
ins_lw_px: nested_lw_px,
|
ins_lw_px: nested_lw_px,
|
||||||
selected: ctx.selected,
|
selected: ctx.selected,
|
||||||
world_offset: ctx.world_offset,
|
|
||||||
pslt_factor: ctx.pslt_factor,
|
pslt_factor: ctx.pslt_factor,
|
||||||
view_aabb: ctx.view_aabb,
|
view_aabb: ctx.view_aabb,
|
||||||
world_per_pixel: ctx.world_per_pixel,
|
world_per_pixel: ctx.world_per_pixel,
|
||||||
|
|
@ -1387,7 +1383,7 @@ fn emit_wire(
|
||||||
if lw.points.is_empty() && lw.fill_tris.is_empty() {
|
if lw.points.is_empty() && lw.fill_tris.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let [ox, oy, oz] = ctx.world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let [lo_x, lo_y, lo_z] = defn_lo;
|
let [lo_x, lo_y, lo_z] = defn_lo;
|
||||||
|
|
||||||
// Resolve final style for this LocalWire against the outer Insert ctx
|
// Resolve final style for this LocalWire against the outer Insert ctx
|
||||||
|
|
@ -1521,7 +1517,7 @@ fn emit_wire(
|
||||||
for tg in &lw.tangent_geoms {
|
for tg in &lw.tangent_geoms {
|
||||||
entry
|
entry
|
||||||
.tangent_geoms
|
.tangent_geoms
|
||||||
.push(transform_tangent(tg, accum_xform, defn_lo, [ox, oy, oz]));
|
.push(transform_tangent(tg, accum_xform, defn_lo));
|
||||||
}
|
}
|
||||||
for p in &lw.fill_tris {
|
for p in &lw.fill_tris {
|
||||||
let v = accum_xform.apply(Vector3::new(
|
let v = accum_xform.apply(Vector3::new(
|
||||||
|
|
@ -1540,9 +1536,8 @@ fn transform_tangent(
|
||||||
tg: &TangentGeom,
|
tg: &TangentGeom,
|
||||||
t: &Transform,
|
t: &Transform,
|
||||||
defn_lo: [f64; 3],
|
defn_lo: [f64; 3],
|
||||||
woff: [f64; 3],
|
|
||||||
) -> TangentGeom {
|
) -> TangentGeom {
|
||||||
let [ox, oy, oz] = woff;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let [lo_x, lo_y, lo_z] = defn_lo;
|
let [lo_x, lo_y, lo_z] = defn_lo;
|
||||||
match tg {
|
match tg {
|
||||||
TangentGeom::Line { p1, p2 } => {
|
TangentGeom::Line { p1, p2 } => {
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,12 @@ fn split_ds_xyz(x: f64, y: f64, z: f64) -> ([f32; 3], [f32; 3]) {
|
||||||
([xh, yh, zh], [xl, yl, zl])
|
([xh, yh, zh], [xl, yl, zl])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subtract `world_offset` from each f64 source point and split the residual
|
/// Split each absolute f64 source point into double-single (high, low) f32
|
||||||
/// into double-single (high, low) f32 buffers in one pass.
|
/// buffers in one pass — the relative-to-eye residual the GPU/CPU reconstruct
|
||||||
fn offset_to_ds(
|
/// to f64 precision at UTM-scale coordinates.
|
||||||
|
fn points_to_ds(
|
||||||
src: impl IntoIterator<Item = [f64; 3]>,
|
src: impl IntoIterator<Item = [f64; 3]>,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> (Vec<[f32; 3]>, Vec<[f32; 3]>) {
|
) -> (Vec<[f32; 3]>, Vec<[f32; 3]>) {
|
||||||
let [ox, oy, oz] = world_offset;
|
|
||||||
let it = src.into_iter();
|
let it = src.into_iter();
|
||||||
let (lo, hi) = it.size_hint();
|
let (lo, hi) = it.size_hint();
|
||||||
let cap = hi.unwrap_or(lo);
|
let cap = hi.unwrap_or(lo);
|
||||||
|
|
@ -62,7 +61,7 @@ fn offset_to_ds(
|
||||||
low.push([0.0; 3]);
|
low.push([0.0; 3]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let (h, l) = split_ds_xyz(x - ox, y - oy, z - oz);
|
let (h, l) = split_ds_xyz(x, y, z);
|
||||||
high.push(h);
|
high.push(h);
|
||||||
low.push(l);
|
low.push(l);
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +84,6 @@ pub fn tessellate(
|
||||||
pattern_length: f32,
|
pattern_length: f32,
|
||||||
pattern: [f32; 8],
|
pattern: [f32; 8],
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
world_per_pixel: Option<f32>,
|
world_per_pixel: Option<f32>,
|
||||||
) -> Vec<WireModel> {
|
) -> Vec<WireModel> {
|
||||||
|
|
@ -127,7 +125,6 @@ pub fn tessellate(
|
||||||
selected,
|
selected,
|
||||||
entity_color,
|
entity_color,
|
||||||
line_weight_px,
|
line_weight_px,
|
||||||
world_offset,
|
|
||||||
anno_scale,
|
anno_scale,
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +145,7 @@ pub fn tessellate(
|
||||||
// single MTEXT can hand back N colour-distinct wires when the
|
// single MTEXT can hand back N colour-distinct wires when the
|
||||||
// value mixes inline colours.
|
// value mixes inline colours.
|
||||||
TruckObject::Text(stroke_groups) => {
|
TruckObject::Text(stroke_groups) => {
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let entity_zf = entity_z(entity) as f64;
|
let entity_zf = entity_z(entity) as f64;
|
||||||
let elev_v = entity_zf - oz;
|
let elev_v = entity_zf - oz;
|
||||||
|
|
||||||
|
|
@ -212,7 +209,7 @@ pub fn tessellate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
let snap_pts = te.snap_pts;
|
||||||
let key_vertices: Vec<[f64; 3]> = te
|
let key_vertices: Vec<[f64; 3]> = te
|
||||||
.key_vertices
|
.key_vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -287,12 +284,12 @@ pub fn tessellate(
|
||||||
|
|
||||||
// ── Standard topology objects ─────────────────────────────────
|
// ── Standard topology objects ─────────────────────────────────
|
||||||
TruckObject::Point(v) => {
|
TruckObject::Point(v) => {
|
||||||
let result = tessellate_vertex(&v, world_offset);
|
let result = tessellate_vertex(&v);
|
||||||
match result {
|
match result {
|
||||||
TruckTessResult::Point([x, y, z], [xl, yl, zl]) => {
|
TruckTessResult::Point([x, y, z], [xl, yl, zl]) => {
|
||||||
let s = 0.1_f32;
|
let s = 0.1_f32;
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
let snap_pts = te.snap_pts;
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let key_vertices: Vec<[f64; 3]> = te
|
let key_vertices: Vec<[f64; 3]> = te
|
||||||
.key_vertices
|
.key_vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -333,10 +330,10 @@ pub fn tessellate(
|
||||||
|
|
||||||
TruckObject::Curve(e) => {
|
TruckObject::Curve(e) => {
|
||||||
if let TruckTessResult::Lines(points, points_low) =
|
if let TruckTessResult::Lines(points, points_low) =
|
||||||
tessellate_edge(&e, world_offset)
|
tessellate_edge(&e)
|
||||||
{
|
{
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
let snap_pts = te.snap_pts;
|
||||||
let key_vertices: Vec<[f64; 3]> = te
|
let key_vertices: Vec<[f64; 3]> = te
|
||||||
.key_vertices
|
.key_vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -366,10 +363,10 @@ pub fn tessellate(
|
||||||
|
|
||||||
TruckObject::Contour(w) => {
|
TruckObject::Contour(w) => {
|
||||||
if let TruckTessResult::Lines(points, points_low) =
|
if let TruckTessResult::Lines(points, points_low) =
|
||||||
tessellate_wire(&w, world_offset)
|
tessellate_wire(&w)
|
||||||
{
|
{
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
let snap_pts = te.snap_pts;
|
||||||
let key_vertices: Vec<[f64; 3]> = te
|
let key_vertices: Vec<[f64; 3]> = te
|
||||||
.key_vertices
|
.key_vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -404,15 +401,15 @@ pub fn tessellate(
|
||||||
// GPU shader pairs them so drawings at large UTM-style
|
// GPU shader pairs them so drawings at large UTM-style
|
||||||
// coordinates keep sub-unit precision in the wire model and
|
// coordinates keep sub-unit precision in the wire model and
|
||||||
// don't jitter on camera movement.
|
// don't jitter on camera movement.
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let (local_pts, local_pts_low) = offset_to_ds(points, world_offset);
|
let (local_pts, local_pts_low) = points_to_ds(points);
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
let snap_pts = te.snap_pts;
|
||||||
let key_vertices: Vec<[f64; 3]> = te
|
let key_vertices: Vec<[f64; 3]> = te
|
||||||
.key_vertices
|
.key_vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|[x, y, z]| [x - ox, y - oy, z - oz])
|
.map(|[x, y, z]| [x - ox, y - oy, z - oz])
|
||||||
.collect();
|
.collect();
|
||||||
let (fill_tris, fill_tris_low) = offset_to_ds(te.fill_tris, world_offset);
|
let (fill_tris, fill_tris_low) = points_to_ds(te.fill_tris);
|
||||||
return vec![WireModel {
|
return vec![WireModel {
|
||||||
name,
|
name,
|
||||||
points: local_pts,
|
points: local_pts,
|
||||||
|
|
@ -435,9 +432,9 @@ pub fn tessellate(
|
||||||
}
|
}
|
||||||
|
|
||||||
TruckObject::SegmentedLines(points) => {
|
TruckObject::SegmentedLines(points) => {
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let (local_pts, local_pts_low) = offset_to_ds(points, world_offset);
|
let (local_pts, local_pts_low) = points_to_ds(points);
|
||||||
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
|
let snap_pts = te.snap_pts;
|
||||||
let key_vertices: Vec<[f64; 3]> = te
|
let key_vertices: Vec<[f64; 3]> = te
|
||||||
.key_vertices
|
.key_vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -470,10 +467,10 @@ pub fn tessellate(
|
||||||
// edge wires stored in the entity when present (e.g. from
|
// edge wires stored in the entity when present (e.g. from
|
||||||
// SOLVIEW output or when the SAT kernel cannot parse the
|
// SOLVIEW output or when the SAT kernel cannot parse the
|
||||||
// ACIS data).
|
// ACIS data).
|
||||||
let wire_pts = solid_wire_fallback(entity, world_offset);
|
let wire_pts = solid_wire_fallback(entity);
|
||||||
let mut wm = WireModel::solid_f64(name, wire_pts, color, selected);
|
let mut wm = WireModel::solid_f64(name, wire_pts, color, selected);
|
||||||
// Add insertion snap at point_of_reference.
|
// Add insertion snap at point_of_reference.
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
if let Some(p) = crate::entities::solid3d::point_of_reference(entity) {
|
if let Some(p) = crate::entities::solid3d::point_of_reference(entity) {
|
||||||
let sp = glam::DVec3::new(p.x - ox, p.y - oy, p.z - oz);
|
let sp = glam::DVec3::new(p.x - ox, p.y - oy, p.z - oz);
|
||||||
wm.snap_pts.push((sp, SnapHint::Insertion));
|
wm.snap_pts.push((sp, SnapHint::Insertion));
|
||||||
|
|
@ -485,7 +482,7 @@ pub fn tessellate(
|
||||||
|
|
||||||
// ── Fallback for Viewport / Insert / Hatch / Ole2Frame ────────────────
|
// ── Fallback for Viewport / Insert / Hatch / Ole2Frame ────────────────
|
||||||
let (points_f64, snap_pts, tangent_geoms, key_vertices) =
|
let (points_f64, snap_pts, tangent_geoms, key_vertices) =
|
||||||
fallback_geometry(entity, world_offset);
|
fallback_geometry(entity);
|
||||||
// `points_f64` are absolute world coords; split into the double-single
|
// `points_f64` are absolute world coords; split into the double-single
|
||||||
// high/low pair so the outline reconstructs to f64 precision at UTM scale
|
// high/low pair so the outline reconstructs to f64 precision at UTM scale
|
||||||
// (a NaN separator stays NaN in both buffers).
|
// (a NaN separator stays NaN in both buffers).
|
||||||
|
|
@ -691,12 +688,12 @@ pub(crate) fn entity_z(entity: &EntityType) -> f32 {
|
||||||
use crate::entities::traits::FallbackTess;
|
use crate::entities::traits::FallbackTess;
|
||||||
use crate::scene::convert::tess_util::FallbackGeometry as Geometry;
|
use crate::scene::convert::tess_util::FallbackGeometry as Geometry;
|
||||||
|
|
||||||
fn fallback_geometry(entity: &EntityType, world_offset: [f64; 3]) -> Geometry {
|
fn fallback_geometry(entity: &EntityType) -> Geometry {
|
||||||
match entity {
|
match entity {
|
||||||
EntityType::Viewport(vp) => vp.fallback_geometry(world_offset),
|
EntityType::Viewport(vp) => vp.fallback_geometry(),
|
||||||
EntityType::Insert(ins) => ins.fallback_geometry(world_offset),
|
EntityType::Insert(ins) => ins.fallback_geometry(),
|
||||||
EntityType::Hatch(h) => h.fallback_geometry(world_offset),
|
EntityType::Hatch(h) => h.fallback_geometry(),
|
||||||
EntityType::Ole2Frame(ole) => ole.fallback_geometry(world_offset),
|
EntityType::Ole2Frame(ole) => ole.fallback_geometry(),
|
||||||
// Modeler solids render as meshes (solid3d_tess). Their wire path
|
// Modeler solids render as meshes (solid3d_tess). Their wire path
|
||||||
// contributes only the pre-computed edge wires (empty for binary SAB)
|
// contributes only the pre-computed edge wires (empty for binary SAB)
|
||||||
// plus an insertion snap — never the placeholder segment below, which
|
// plus an insertion snap — never the placeholder segment below, which
|
||||||
|
|
@ -706,10 +703,10 @@ fn fallback_geometry(entity: &EntityType, world_offset: [f64; 3]) -> Geometry {
|
||||||
| EntityType::Region(_)
|
| EntityType::Region(_)
|
||||||
| EntityType::Body(_)
|
| EntityType::Body(_)
|
||||||
| EntityType::Surface(_) => {
|
| EntityType::Surface(_) => {
|
||||||
let pts = solid_wire_fallback(entity, world_offset);
|
let pts = solid_wire_fallback(entity);
|
||||||
let mut snap = vec![];
|
let mut snap = vec![];
|
||||||
if let Some(p) = crate::entities::solid3d::point_of_reference(entity) {
|
if let Some(p) = crate::entities::solid3d::point_of_reference(entity) {
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
snap.push((
|
snap.push((
|
||||||
Vec3::new((p.x - ox) as f32, (p.y - oy) as f32, (p.z - oz) as f32),
|
Vec3::new((p.x - ox) as f32, (p.y - oy) as f32, (p.z - oz) as f32),
|
||||||
SnapHint::Insertion,
|
SnapHint::Insertion,
|
||||||
|
|
@ -729,8 +726,8 @@ fn fallback_geometry(entity: &EntityType, world_offset: [f64; 3]) -> Geometry {
|
||||||
/// AutoCAD stores explicit wire geometry (from SOLVIEW / 3DPLOT) alongside the
|
/// AutoCAD stores explicit wire geometry (from SOLVIEW / 3DPLOT) alongside the
|
||||||
/// ACIS data. We use this as a visible fallback when the SAT tessellator
|
/// ACIS data. We use this as a visible fallback when the SAT tessellator
|
||||||
/// produces no mesh (e.g. binary SAB data or unsupported geometry).
|
/// produces no mesh (e.g. binary SAB data or unsupported geometry).
|
||||||
fn solid_wire_fallback(entity: &EntityType, world_offset: [f64; 3]) -> Vec<[f64; 3]> {
|
fn solid_wire_fallback(entity: &EntityType) -> Vec<[f64; 3]> {
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let Some(wires) = crate::entities::solid3d::fallback_wires(entity) else {
|
let Some(wires) = crate::entities::solid3d::fallback_wires(entity) else {
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
|
|
@ -878,16 +875,6 @@ pub(crate) fn add_polyline(points: &mut Vec<[f32; 3]>, polyline: &[Vec3]) {
|
||||||
points.extend(polyline.iter().map(|p| [p.x, p.y, p.z]));
|
points.extend(polyline.iter().map(|p| [p.x, p.y, p.z]));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn offset_snap_pts(
|
|
||||||
pts: Vec<(glam::DVec3, SnapHint)>,
|
|
||||||
off: [f64; 3],
|
|
||||||
) -> Vec<(glam::DVec3, SnapHint)> {
|
|
||||||
let [ox, oy, oz] = off;
|
|
||||||
pts.into_iter()
|
|
||||||
.map(|(p, h)| (glam::DVec3::new(p.x - ox, p.y - oy, p.z - oz), h))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the text position of a dimension in DXF world-space (f64, no offset applied).
|
/// Returns the text position of a dimension in DXF world-space (f64, no offset applied).
|
||||||
/// Used when building a synthetic Text entity so tessellate() can apply world_offset itself.
|
/// Used when building a synthetic Text entity so tessellate() can apply world_offset itself.
|
||||||
/// When the saved `text_middle_point` is zero (i.e. AutoCAD never wrote one),
|
/// When the saved `text_middle_point` is zero (i.e. AutoCAD never wrote one),
|
||||||
|
|
|
||||||
|
|
@ -94,11 +94,11 @@ pub enum TruckTessResult {
|
||||||
/// before truncating. This preserves sub-unit decimal precision even when the
|
/// before truncating. This preserves sub-unit decimal precision even when the
|
||||||
/// raw world coordinates are in the millions (e.g. Turkish UTM).
|
/// raw world coordinates are in the millions (e.g. Turkish UTM).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_local(x: f64, y: f64, z: f64, off: [f64; 3]) -> [f32; 3] {
|
fn to_local(x: f64, y: f64, z: f64) -> [f32; 3] {
|
||||||
[
|
[
|
||||||
(x - off[0]) as f32,
|
x as f32,
|
||||||
(y - off[1]) as f32,
|
y as f32,
|
||||||
(z - off[2]) as f32,
|
z as f32,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,26 +106,26 @@ fn to_local(x: f64, y: f64, z: f64, off: [f64; 3]) -> [f32; 3] {
|
||||||
/// with the high half so the double-single shader path reconstructs the f64
|
/// with the high half so the double-single shader path reconstructs the f64
|
||||||
/// source even when the high half is quantized to half a metre at UTM scale.
|
/// source even when the high half is quantized to half a metre at UTM scale.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_local_low(x: f64, y: f64, z: f64, off: [f64; 3], hi: [f32; 3]) -> [f32; 3] {
|
fn to_local_low(x: f64, y: f64, z: f64, hi: [f32; 3]) -> [f32; 3] {
|
||||||
[
|
[
|
||||||
((x - off[0]) - hi[0] as f64) as f32,
|
(x - hi[0] as f64) as f32,
|
||||||
((y - off[1]) - hi[1] as f64) as f32,
|
(y - hi[1] as f64) as f32,
|
||||||
((z - off[2]) - hi[2] as f64) as f32,
|
(z - hi[2] as f64) as f32,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Vertex ────────────────────────────────────────────────────────────────
|
// ── Vertex ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
pub fn tessellate_vertex(v: &Vertex, offset: [f64; 3]) -> TruckTessResult {
|
pub fn tessellate_vertex(v: &Vertex) -> TruckTessResult {
|
||||||
let p = v.point();
|
let p = v.point();
|
||||||
let hi = to_local(p.x, p.y, p.z, offset);
|
let hi = to_local(p.x, p.y, p.z);
|
||||||
let lo = to_local_low(p.x, p.y, p.z, offset, hi);
|
let lo = to_local_low(p.x, p.y, p.z, hi);
|
||||||
TruckTessResult::Point(hi, lo)
|
TruckTessResult::Point(hi, lo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Edge ──────────────────────────────────────────────────────────────────
|
// ── Edge ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
pub fn tessellate_edge(e: &Edge, offset: [f64; 3]) -> TruckTessResult {
|
pub fn tessellate_edge(e: &Edge) -> TruckTessResult {
|
||||||
// oriented_curve() respects the edge direction (inverts if needed).
|
// oriented_curve() respects the edge direction (inverts if needed).
|
||||||
let curve = e.oriented_curve();
|
let curve = e.oriented_curve();
|
||||||
let (t0, t1) = curve.range_tuple();
|
let (t0, t1) = curve.range_tuple();
|
||||||
|
|
@ -136,8 +136,8 @@ pub fn tessellate_edge(e: &Edge, offset: [f64; 3]) -> TruckTessResult {
|
||||||
let mut high: Vec<[f32; 3]> = Vec::with_capacity(pts.len());
|
let mut high: Vec<[f32; 3]> = Vec::with_capacity(pts.len());
|
||||||
let mut low: Vec<[f32; 3]> = Vec::with_capacity(pts.len());
|
let mut low: Vec<[f32; 3]> = Vec::with_capacity(pts.len());
|
||||||
for p in &pts {
|
for p in &pts {
|
||||||
let hi = to_local(p.x, p.y, p.z, offset);
|
let hi = to_local(p.x, p.y, p.z);
|
||||||
let lo = to_local_low(p.x, p.y, p.z, offset, hi);
|
let lo = to_local_low(p.x, p.y, p.z, hi);
|
||||||
high.push(hi);
|
high.push(hi);
|
||||||
low.push(lo);
|
low.push(lo);
|
||||||
}
|
}
|
||||||
|
|
@ -146,11 +146,11 @@ pub fn tessellate_edge(e: &Edge, offset: [f64; 3]) -> TruckTessResult {
|
||||||
|
|
||||||
// ── Wire ──────────────────────────────────────────────────────────────────
|
// ── Wire ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
pub fn tessellate_wire(w: &Wire, offset: [f64; 3]) -> TruckTessResult {
|
pub fn tessellate_wire(w: &Wire) -> TruckTessResult {
|
||||||
let mut high: Vec<[f32; 3]> = Vec::new();
|
let mut high: Vec<[f32; 3]> = Vec::new();
|
||||||
let mut low: Vec<[f32; 3]> = Vec::new();
|
let mut low: Vec<[f32; 3]> = Vec::new();
|
||||||
for edge in w.edge_iter() {
|
for edge in w.edge_iter() {
|
||||||
if let TruckTessResult::Lines(eh, el) = tessellate_edge(edge, offset) {
|
if let TruckTessResult::Lines(eh, el) = tessellate_edge(edge) {
|
||||||
if high.is_empty() {
|
if high.is_empty() {
|
||||||
high = eh;
|
high = eh;
|
||||||
low = el;
|
low = el;
|
||||||
|
|
@ -169,14 +169,14 @@ pub fn tessellate_wire(w: &Wire, offset: [f64; 3]) -> TruckTessResult {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[cfg(feature = "solid3d")]
|
#[cfg(feature = "solid3d")]
|
||||||
pub fn tessellate_shell(s: &Shell, offset: [f64; 3]) -> TruckTessResult {
|
pub fn tessellate_shell(s: &Shell) -> TruckTessResult {
|
||||||
let meshed = s.triangulation(MESH_TOL);
|
let meshed = s.triangulation(MESH_TOL);
|
||||||
polygon_to_result(meshed.to_polygon(), offset)
|
polygon_to_result(meshed.to_polygon())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Without `solid3d` (e.g. wasm) there is no mesher; a shell yields no mesh.
|
/// Without `solid3d` (e.g. wasm) there is no mesher; a shell yields no mesh.
|
||||||
#[cfg(not(feature = "solid3d"))]
|
#[cfg(not(feature = "solid3d"))]
|
||||||
pub fn tessellate_shell(_s: &Shell, _offset: [f64; 3]) -> TruckTessResult {
|
pub fn tessellate_shell(_s: &Shell) -> TruckTessResult {
|
||||||
TruckTessResult::Mesh {
|
TruckTessResult::Mesh {
|
||||||
verts: Vec::new(),
|
verts: Vec::new(),
|
||||||
verts_low: Vec::new(),
|
verts_low: Vec::new(),
|
||||||
|
|
@ -189,15 +189,15 @@ pub fn tessellate_shell(_s: &Shell, _offset: [f64; 3]) -> TruckTessResult {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[cfg(feature = "solid3d")]
|
#[cfg(feature = "solid3d")]
|
||||||
pub fn tessellate_solid(s: &Solid, offset: [f64; 3]) -> TruckTessResult {
|
pub fn tessellate_solid(s: &Solid) -> TruckTessResult {
|
||||||
let meshed = s.triangulation(MESH_TOL);
|
let meshed = s.triangulation(MESH_TOL);
|
||||||
polygon_to_result(meshed.to_polygon(), offset)
|
polygon_to_result(meshed.to_polygon())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Without `solid3d` (e.g. wasm) there is no mesher; a solid yields no mesh.
|
/// Without `solid3d` (e.g. wasm) there is no mesher; a solid yields no mesh.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[cfg(not(feature = "solid3d"))]
|
#[cfg(not(feature = "solid3d"))]
|
||||||
pub fn tessellate_solid(_s: &Solid, _offset: [f64; 3]) -> TruckTessResult {
|
pub fn tessellate_solid(_s: &Solid) -> TruckTessResult {
|
||||||
TruckTessResult::Mesh {
|
TruckTessResult::Mesh {
|
||||||
verts: Vec::new(),
|
verts: Vec::new(),
|
||||||
verts_low: Vec::new(),
|
verts_low: Vec::new(),
|
||||||
|
|
@ -209,13 +209,13 @@ pub fn tessellate_solid(_s: &Solid, _offset: [f64; 3]) -> TruckTessResult {
|
||||||
// ── Internal ─────────────────────────────────────────────────────────────
|
// ── Internal ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
#[cfg(feature = "solid3d")]
|
#[cfg(feature = "solid3d")]
|
||||||
fn polygon_to_result(mesh: PolygonMesh, offset: [f64; 3]) -> TruckTessResult {
|
fn polygon_to_result(mesh: PolygonMesh) -> TruckTessResult {
|
||||||
let positions = mesh.positions();
|
let positions = mesh.positions();
|
||||||
let mut verts: Vec<[f32; 3]> = Vec::with_capacity(positions.len());
|
let mut verts: Vec<[f32; 3]> = Vec::with_capacity(positions.len());
|
||||||
let mut verts_low: Vec<[f32; 3]> = Vec::with_capacity(positions.len());
|
let mut verts_low: Vec<[f32; 3]> = Vec::with_capacity(positions.len());
|
||||||
for p in positions.iter() {
|
for p in positions.iter() {
|
||||||
let hi = to_local(p.x, p.y, p.z, offset);
|
let hi = to_local(p.x, p.y, p.z);
|
||||||
verts_low.push(to_local_low(p.x, p.y, p.z, offset, hi));
|
verts_low.push(to_local_low(p.x, p.y, p.z, hi));
|
||||||
verts.push(hi);
|
verts.push(hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
222
src/scene/mod.rs
222
src/scene/mod.rs
|
|
@ -196,17 +196,11 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.filter_map(|&handle| {
|
.filter_map(|&handle| {
|
||||||
let e = doc.get_entity(handle)?;
|
let e = doc.get_entity(handle)?;
|
||||||
let owner = e.common().owner_handle;
|
|
||||||
let offset = if owner == model_block {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let (raw, ..) = view::render::render_style_for(doc, e);
|
let (raw, ..) = view::render::render_style_for(doc, e);
|
||||||
let color = view::render::adapt_to_bg(raw, LOAD_BG);
|
let color = view::render::adapt_to_bg(raw, LOAD_BG);
|
||||||
let model = match e {
|
let model = match e {
|
||||||
EntityType::Hatch(dxf) => Scene::hatch_model_from_dxf(dxf, color, offset),
|
EntityType::Hatch(dxf) => Scene::hatch_model_from_dxf(dxf, color),
|
||||||
EntityType::Solid(solid) => Some(Scene::solid_hatch_model(solid, color, offset)),
|
EntityType::Solid(solid) => Some(Scene::solid_hatch_model(solid, color)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
model.map(|m| (handle, m))
|
model.map(|m| (handle, m))
|
||||||
|
|
@ -218,7 +212,7 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.filter_map(|&handle| {
|
.filter_map(|&handle| {
|
||||||
if let EntityType::RasterImage(img) = doc.get_entity(handle)? {
|
if let EntityType::RasterImage(img) = doc.get_entity(handle)? {
|
||||||
ImageModel::from_raster_image(img, [0.0_f64; 3]).map(|m| (handle, m))
|
ImageModel::from_raster_image(img).map(|m| (handle, m))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -251,7 +245,7 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
|
||||||
let color = view::render::adapt_to_bg(raw, LOAD_BG);
|
let color = view::render::adapt_to_bg(raw, LOAD_BG);
|
||||||
let top_level = layout_blocks.contains(&e.common().owner_handle);
|
let top_level = layout_blocks.contains(&e.common().owner_handle);
|
||||||
crate::entities::solid3d::tessellate_volume(e, color, facet_res).map(|m| {
|
crate::entities::solid3d::tessellate_volume(e, color, facet_res).map(|m| {
|
||||||
let m = if top_level { offset_mesh_lod_set(m, [0.0_f64; 3]) } else { m };
|
let m = if top_level { offset_mesh_lod_set(m) } else { m };
|
||||||
(handle, m, top_level)
|
(handle, m, top_level)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -554,8 +548,8 @@ fn overlap_len(a: (f32, f32), b: (f32, f32)) -> f32 {
|
||||||
/// origins would otherwise float far away from the rest of the
|
/// origins would otherwise float far away from the rest of the
|
||||||
/// geometry. Also recomputes `world_aabb` so per-frame LOD / cull math
|
/// geometry. Also recomputes `world_aabb` so per-frame LOD / cull math
|
||||||
/// uses the same space.
|
/// uses the same space.
|
||||||
fn offset_mesh_lod_set(mut set: MeshLodSet, world_offset: [f64; 3]) -> MeshLodSet {
|
fn offset_mesh_lod_set(mut set: MeshLodSet) -> MeshLodSet {
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let mut min_x = f32::INFINITY;
|
let mut min_x = f32::INFINITY;
|
||||||
let mut min_y = f32::INFINITY;
|
let mut min_y = f32::INFINITY;
|
||||||
let mut max_x = f32::NEG_INFINITY;
|
let mut max_x = f32::NEG_INFINITY;
|
||||||
|
|
@ -596,10 +590,9 @@ fn offset_mesh_lod_set(mut set: MeshLodSet, world_offset: [f64; 3]) -> MeshLodSe
|
||||||
fn transform_block_mesh_lod_set(
|
fn transform_block_mesh_lod_set(
|
||||||
set: &MeshLodSet,
|
set: &MeshLodSet,
|
||||||
xform: &acadrust::types::Transform,
|
xform: &acadrust::types::Transform,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> MeshLodSet {
|
) -> MeshLodSet {
|
||||||
use acadrust::types::Vector3;
|
use acadrust::types::Vector3;
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let mut out = set.clone();
|
let mut out = set.clone();
|
||||||
let mut min_x = f32::INFINITY;
|
let mut min_x = f32::INFINITY;
|
||||||
let mut min_y = f32::INFINITY;
|
let mut min_y = f32::INFINITY;
|
||||||
|
|
@ -2318,7 +2311,6 @@ impl Scene {
|
||||||
if self.block_meshes.is_empty() {
|
if self.block_meshes.is_empty() {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for e in self.document.entities() {
|
for e in self.document.entities() {
|
||||||
if e.common().owner_handle != layout_block {
|
if e.common().owner_handle != layout_block {
|
||||||
|
|
@ -2331,7 +2323,7 @@ impl Scene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let start = out.len();
|
let start = out.len();
|
||||||
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, woff, &mut out);
|
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, &mut out);
|
||||||
// Tag the instanced meshes with the parent INSERT handle so the
|
// Tag the instanced meshes with the parent INSERT handle so the
|
||||||
// hover / selection highlight (keyed on the mesh name) tints the
|
// hover / selection highlight (keyed on the mesh name) tints the
|
||||||
// block, not the inner solid's own handle which nothing selects.
|
// block, not the inner solid's own handle which nothing selects.
|
||||||
|
|
@ -2353,7 +2345,6 @@ impl Scene {
|
||||||
block_name: &str,
|
block_name: &str,
|
||||||
accum: &acadrust::types::Transform,
|
accum: &acadrust::types::Transform,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
woff: [f64; 3],
|
|
||||||
out: &mut Vec<MeshLodSet>,
|
out: &mut Vec<MeshLodSet>,
|
||||||
) {
|
) {
|
||||||
if depth > 16 {
|
if depth > 16 {
|
||||||
|
|
@ -2374,9 +2365,9 @@ impl Scene {
|
||||||
}
|
}
|
||||||
if let EntityType::Insert(ins) = e {
|
if let EntityType::Insert(ins) = e {
|
||||||
let composed = ins.get_transform().then(accum);
|
let composed = ins.get_transform().then(accum);
|
||||||
self.expand_block_meshes(&ins.block_name, &composed, depth + 1, woff, out);
|
self.expand_block_meshes(&ins.block_name, &composed, depth + 1, out);
|
||||||
} else if let Some(set) = self.block_meshes.get(&h) {
|
} else if let Some(set) = self.block_meshes.get(&h) {
|
||||||
out.push(transform_block_mesh_lod_set(set, accum, woff));
|
out.push(transform_block_mesh_lod_set(set, accum));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2425,11 +2416,6 @@ impl Scene {
|
||||||
/// selectable; the click resolves to the Insert).
|
/// selectable; the click resolves to the Insert).
|
||||||
pub fn insert_hatches_for_click(&self) -> Vec<(Handle, HatchModel)> {
|
pub fn insert_hatches_for_click(&self) -> Vec<(Handle, HatchModel)> {
|
||||||
let layout_block = self.current_layout_block_handle();
|
let layout_block = self.current_layout_block_handle();
|
||||||
let hatch_offset = if self.current_layout == "Model" {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let layer_hidden = |layer: &str| {
|
let layer_hidden = |layer: &str| {
|
||||||
self.document
|
self.document
|
||||||
.layers
|
.layers
|
||||||
|
|
@ -2464,7 +2450,7 @@ impl Scene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let color = self.render_style(&EntityType::Hatch(dxf.clone())).0;
|
let color = self.render_style(&EntityType::Hatch(dxf.clone())).0;
|
||||||
if let Some(model) = Self::hatch_model_from_dxf(&dxf, color, hatch_offset) {
|
if let Some(model) = Self::hatch_model_from_dxf(&dxf, color) {
|
||||||
out.push((ins.common.handle, model));
|
out.push((ins.common.handle, model));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2578,7 +2564,6 @@ impl Scene {
|
||||||
let mut block_owned: Vec<(Handle, crate::scene::model::mesh_model::MeshModel)> = Vec::new();
|
let mut block_owned: Vec<(Handle, crate::scene::model::mesh_model::MeshModel)> = Vec::new();
|
||||||
if !self.block_meshes.is_empty() {
|
if !self.block_meshes.is_empty() {
|
||||||
let layout_block = self.current_layout_block_handle();
|
let layout_block = self.current_layout_block_handle();
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
for e in self.document.entities() {
|
for e in self.document.entities() {
|
||||||
if e.common().owner_handle != layout_block {
|
if e.common().owner_handle != layout_block {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -2588,7 +2573,7 @@ impl Scene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut sets = Vec::new();
|
let mut sets = Vec::new();
|
||||||
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, woff, &mut sets);
|
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, &mut sets);
|
||||||
for set in sets {
|
for set in sets {
|
||||||
if let Some(m) = set.lods.into_iter().next() {
|
if let Some(m) = set.lods.into_iter().next() {
|
||||||
block_owned.push((ins.common.handle, m));
|
block_owned.push((ins.common.handle, m));
|
||||||
|
|
@ -2621,7 +2606,6 @@ impl Scene {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
let layout_block = self.current_layout_block_handle();
|
let layout_block = self.current_layout_block_handle();
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for e in self.document.entities() {
|
for e in self.document.entities() {
|
||||||
if e.common().owner_handle != layout_block {
|
if e.common().owner_handle != layout_block {
|
||||||
|
|
@ -2632,7 +2616,7 @@ impl Scene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut sets = Vec::new();
|
let mut sets = Vec::new();
|
||||||
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, woff, &mut sets);
|
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, &mut sets);
|
||||||
let hit = sets.iter().any(|set| {
|
let hit = sets.iter().any(|set| {
|
||||||
set.lods.first().map_or(false, |m| {
|
set.lods.first().map_or(false, |m| {
|
||||||
!pick::hit_test::mesh_box_hit(
|
!pick::hit_test::mesh_box_hit(
|
||||||
|
|
@ -2667,7 +2651,6 @@ impl Scene {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
let layout_block = self.current_layout_block_handle();
|
let layout_block = self.current_layout_block_handle();
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for e in self.document.entities() {
|
for e in self.document.entities() {
|
||||||
if e.common().owner_handle != layout_block {
|
if e.common().owner_handle != layout_block {
|
||||||
|
|
@ -2678,7 +2661,7 @@ impl Scene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut sets = Vec::new();
|
let mut sets = Vec::new();
|
||||||
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, woff, &mut sets);
|
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, &mut sets);
|
||||||
let hit = sets.iter().any(|set| {
|
let hit = sets.iter().any(|set| {
|
||||||
set.lods.first().map_or(false, |m| {
|
set.lods.first().map_or(false, |m| {
|
||||||
!pick::hit_test::mesh_poly_hit(
|
!pick::hit_test::mesh_poly_hit(
|
||||||
|
|
@ -2860,11 +2843,6 @@ impl Scene {
|
||||||
// `world_offset` subtraction even though `current_layout != "Model"`.
|
// `world_offset` subtraction even though `current_layout != "Model"`.
|
||||||
// Decide based on the block being tessellated, not the layout.
|
// Decide based on the block being tessellated, not the layout.
|
||||||
let is_model_block = block_handle == self.model_space_block_handle();
|
let is_model_block = block_handle == self.model_space_block_handle();
|
||||||
let woff = if is_model_block {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let bg = if self.current_layout == "Model" {
|
let bg = if self.current_layout == "Model" {
|
||||||
self.bg_color
|
self.bg_color
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2918,9 +2896,6 @@ impl Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mix(anno.to_bits() as u64);
|
mix(anno.to_bits() as u64);
|
||||||
for c in woff {
|
|
||||||
mix(c.to_bits());
|
|
||||||
}
|
|
||||||
for c in bg {
|
for c in bg {
|
||||||
mix(c.to_bits() as u64);
|
mix(c.to_bits() as u64);
|
||||||
}
|
}
|
||||||
|
|
@ -2952,7 +2927,7 @@ impl Scene {
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
let e: &EntityType = e;
|
let e: &EntityType = e;
|
||||||
let w = tessellate_entity(
|
let w = tessellate_entity(
|
||||||
doc, sel, avp, woff, bg, anno, e, Some(blk_ref), view_aabb, wpp,
|
doc, sel, avp, bg, anno, e, Some(blk_ref), view_aabb, wpp,
|
||||||
);
|
);
|
||||||
(e.common().handle, Arc::new(w))
|
(e.common().handle, Arc::new(w))
|
||||||
})
|
})
|
||||||
|
|
@ -2971,7 +2946,7 @@ impl Scene {
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.flat_map(|e| {
|
.flat_map(|e| {
|
||||||
tessellate_entity(
|
tessellate_entity(
|
||||||
doc, sel, avp, woff, bg, anno, e, Some(blk_ref), view_aabb, wpp,
|
doc, sel, avp, bg, anno, e, Some(blk_ref), view_aabb, wpp,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
@ -3167,7 +3142,6 @@ impl Scene {
|
||||||
&self.document,
|
&self.document,
|
||||||
&self.selected,
|
&self.selected,
|
||||||
self.active_viewport,
|
self.active_viewport,
|
||||||
[0.0_f64; 3],
|
|
||||||
bg,
|
bg,
|
||||||
anno,
|
anno,
|
||||||
e,
|
e,
|
||||||
|
|
@ -4150,22 +4124,17 @@ impl Scene {
|
||||||
&entity,
|
&entity,
|
||||||
EntityType::Insert(_) | EntityType::Block(_) | EntityType::BlockEnd(_)
|
EntityType::Insert(_) | EntityType::Block(_) | EntityType::BlockEnd(_)
|
||||||
);
|
);
|
||||||
let hatch_offset = if self.current_layout == "Model" {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let hatch_seed = if let EntityType::Hatch(dxf) = &entity {
|
let hatch_seed = if let EntityType::Hatch(dxf) = &entity {
|
||||||
let color = self.render_style(&entity).0;
|
let color = self.render_style(&entity).0;
|
||||||
Self::hatch_model_from_dxf(dxf, color, hatch_offset)
|
Self::hatch_model_from_dxf(dxf, color)
|
||||||
} else if let EntityType::Solid(solid) = &entity {
|
} else if let EntityType::Solid(solid) = &entity {
|
||||||
let color = self.render_style(&entity).0;
|
let color = self.render_style(&entity).0;
|
||||||
Some(Self::solid_hatch_model(solid, color, hatch_offset))
|
Some(Self::solid_hatch_model(solid, color))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let image_seed = if let EntityType::RasterImage(img) = &entity {
|
let image_seed = if let EntityType::RasterImage(img) = &entity {
|
||||||
ImageModel::from_raster_image(img, [0.0_f64; 3])
|
ImageModel::from_raster_image(img)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
@ -4175,9 +4144,8 @@ impl Scene {
|
||||||
EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) | EntityType::Surface(_)
|
EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) | EntityType::Surface(_)
|
||||||
) {
|
) {
|
||||||
let color = self.render_style(&entity).0;
|
let color = self.render_style(&entity).0;
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
crate::entities::solid3d::tessellate_volume(&entity, color, facet_res)
|
crate::entities::solid3d::tessellate_volume(&entity, color, facet_res)
|
||||||
.map(|m| offset_mesh_lod_set(m, woff))
|
.map(|m| offset_mesh_lod_set(m))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
@ -4442,11 +4410,6 @@ impl Scene {
|
||||||
|
|
||||||
fn synced_hatch_models(&self) -> Vec<HatchModel> {
|
fn synced_hatch_models(&self) -> Vec<HatchModel> {
|
||||||
let layout_block = self.current_layout_block_handle();
|
let layout_block = self.current_layout_block_handle();
|
||||||
let hatch_offset = if self.current_layout == "Model" {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
|
|
||||||
let layer_hidden = |layer: &str| {
|
let layer_hidden = |layer: &str| {
|
||||||
self.document
|
self.document
|
||||||
|
|
@ -4543,7 +4506,7 @@ impl Scene {
|
||||||
// XCLIP: clip this insert's exploded hatch fills to the boundary,
|
// XCLIP: clip this insert's exploded hatch fills to the boundary,
|
||||||
// matching how the line geometry is clipped in expand_insert.
|
// matching how the line geometry is clipped in expand_insert.
|
||||||
let clip_poly = pick::xclip::insert_spatial_filter(&self.document, ins)
|
let clip_poly = pick::xclip::insert_spatial_filter(&self.document, ins)
|
||||||
.map(|sf| pick::xclip::world_clip_polygon(sf, ins, hatch_offset));
|
.map(|sf| pick::xclip::world_clip_polygon(sf, ins));
|
||||||
// Walk the full block tree: `explode_from_document` only descends
|
// Walk the full block tree: `explode_from_document` only descends
|
||||||
// one level, so nested INSERTs are re-exploded here. Each level
|
// one level, so nested INSERTs are re-exploded here. Each level
|
||||||
// bakes its transform into the children it returns, so nested
|
// bakes its transform into the children it returns, so nested
|
||||||
|
|
@ -4571,7 +4534,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
let color = self.render_style(&EntityType::Hatch(dxf.clone())).0;
|
let color = self.render_style(&EntityType::Hatch(dxf.clone())).0;
|
||||||
if let Some(mut model) =
|
if let Some(mut model) =
|
||||||
Self::hatch_model_from_dxf(&dxf, color, hatch_offset)
|
Self::hatch_model_from_dxf(&dxf, color)
|
||||||
{
|
{
|
||||||
if let Some(poly) = &clip_poly {
|
if let Some(poly) = &clip_poly {
|
||||||
let clipped = pick::xclip::clip_hatch_boundary(
|
let clipped = pick::xclip::clip_hatch_boundary(
|
||||||
|
|
@ -4596,7 +4559,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wide LWPolyline and Polyline2D fills
|
// Wide LWPolyline and Polyline2D fills
|
||||||
let [ox, oy, _] = hatch_offset;
|
let [ox, oy, _] = [0.0_f64; 3];
|
||||||
let ox = ox as f32;
|
let ox = ox as f32;
|
||||||
let oy = oy as f32;
|
let oy = oy as f32;
|
||||||
for entity in self.document.entities() {
|
for entity in self.document.entities() {
|
||||||
|
|
@ -4655,7 +4618,6 @@ impl Scene {
|
||||||
} else {
|
} else {
|
||||||
self.bg_color
|
self.bg_color
|
||||||
};
|
};
|
||||||
let model_block = self.model_space_block_handle();
|
|
||||||
// No per-frame view-cull here: GPU wipeout buffer upload is
|
// No per-frame view-cull here: GPU wipeout buffer upload is
|
||||||
// gated on geometry_epoch only (see render.rs), so any cull at
|
// gated on geometry_epoch only (see render.rs), so any cull at
|
||||||
// build time would freeze the visible subset at the geometry
|
// build time would freeze the visible subset at the geometry
|
||||||
|
|
@ -4682,12 +4644,7 @@ impl Scene {
|
||||||
// Per-entity world_offset selection so paper-layout content
|
// Per-entity world_offset selection so paper-layout content
|
||||||
// viewports still see model-block wipeouts at the right local
|
// viewports still see model-block wipeouts at the right local
|
||||||
// coordinates (same rationale as hatches).
|
// coordinates (same rationale as hatches).
|
||||||
let world_offset = if wo.common.owner_handle == model_block {
|
let boundary = Self::wipeout_boundary_2d(wo);
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let boundary = Self::wipeout_boundary_2d(wo, world_offset);
|
|
||||||
if boundary.len() >= 3 {
|
if boundary.len() >= 3 {
|
||||||
let mut fill_color = bg_color;
|
let mut fill_color = bg_color;
|
||||||
if self.selected.contains(&wo.common.handle) {
|
if self.selected.contains(&wo.common.handle) {
|
||||||
|
|
@ -4712,11 +4669,10 @@ impl Scene {
|
||||||
/// Compute the 2D (XY) boundary polygon for a Wipeout entity.
|
/// Compute the 2D (XY) boundary polygon for a Wipeout entity.
|
||||||
fn wipeout_boundary_2d(
|
fn wipeout_boundary_2d(
|
||||||
wo: &acadrust::entities::Wipeout,
|
wo: &acadrust::entities::Wipeout,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> Vec<[f32; 2]> {
|
) -> Vec<[f32; 2]> {
|
||||||
use acadrust::entities::WipeoutClipType;
|
use acadrust::entities::WipeoutClipType;
|
||||||
|
|
||||||
let [wox, woy, _woz] = world_offset;
|
let [wox, woy, _woz] = [0.0_f64; 3];
|
||||||
let is_polygon = wo.clipping_enabled
|
let is_polygon = wo.clipping_enabled
|
||||||
&& wo.clip_boundary_vertices.len() >= 3
|
&& wo.clip_boundary_vertices.len() >= 3
|
||||||
&& matches!(wo.clip_type, WipeoutClipType::Polygonal);
|
&& matches!(wo.clip_type, WipeoutClipType::Polygonal);
|
||||||
|
|
@ -4780,9 +4736,8 @@ impl Scene {
|
||||||
fn hatch_model_from_dxf(
|
fn hatch_model_from_dxf(
|
||||||
dxf: &DxfHatch,
|
dxf: &DxfHatch,
|
||||||
color: [f32; 4],
|
color: [f32; 4],
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> Option<HatchModel> {
|
) -> Option<HatchModel> {
|
||||||
let [ox, oy, _oz] = world_offset;
|
let [ox, oy, _oz] = [0.0_f64; 3];
|
||||||
let normal = (dxf.normal.x, dxf.normal.y, dxf.normal.z);
|
let normal = (dxf.normal.x, dxf.normal.y, dxf.normal.z);
|
||||||
// Build the boundary in f64 first so the precision-preserving
|
// Build the boundary in f64 first so the precision-preserving
|
||||||
// origin computation below sees full WCS precision. We only cast
|
// origin computation below sees full WCS precision. We only cast
|
||||||
|
|
@ -5126,7 +5081,7 @@ impl Scene {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
for (handle, img) in entries {
|
for (handle, img) in entries {
|
||||||
if let Some(model) = ImageModel::from_raster_image(&img, [0.0_f64; 3]) {
|
if let Some(model) = ImageModel::from_raster_image(&img) {
|
||||||
self.images.insert(handle, model);
|
self.images.insert(handle, model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5136,9 +5091,6 @@ impl Scene {
|
||||||
pub fn populate_hatches_from_document(&mut self) {
|
pub fn populate_hatches_from_document(&mut self) {
|
||||||
self.hatches.clear();
|
self.hatches.clear();
|
||||||
|
|
||||||
let model_block = self.model_space_block_handle();
|
|
||||||
let world_offset = [0.0_f64; 3];
|
|
||||||
|
|
||||||
let entries: Vec<(Handle, EntityType)> = self
|
let entries: Vec<(Handle, EntityType)> = self
|
||||||
.document
|
.document
|
||||||
.entities()
|
.entities()
|
||||||
|
|
@ -5154,21 +5106,14 @@ impl Scene {
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.filter_map(|(handle, kind)| {
|
.filter_map(|(handle, kind)| {
|
||||||
// Paper-space entities live in sheet coordinates — world_offset must not
|
// Paper-space entities live in sheet coordinates — world_offset must not
|
||||||
// be applied to them. Only model-space entities need the shift.
|
|
||||||
let owner = kind.common().owner_handle;
|
|
||||||
let offset = if owner == model_block {
|
|
||||||
world_offset
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let model = match &kind {
|
let model = match &kind {
|
||||||
EntityType::Hatch(dxf) => {
|
EntityType::Hatch(dxf) => {
|
||||||
let color = convert::tess_util::aci_to_rgba(&dxf.common.color);
|
let color = convert::tess_util::aci_to_rgba(&dxf.common.color);
|
||||||
Self::hatch_model_from_dxf(dxf, color, offset)
|
Self::hatch_model_from_dxf(dxf, color)
|
||||||
}
|
}
|
||||||
EntityType::Solid(solid) => {
|
EntityType::Solid(solid) => {
|
||||||
let color = convert::tess_util::aci_to_rgba(&solid.common.color);
|
let color = convert::tess_util::aci_to_rgba(&solid.common.color);
|
||||||
Some(Self::solid_hatch_model(solid, color, offset))
|
Some(Self::solid_hatch_model(solid, color))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
@ -5220,7 +5165,6 @@ impl Scene {
|
||||||
|
|
||||||
use crate::par::prelude::*;
|
use crate::par::prelude::*;
|
||||||
let facet_res = self.document.header.facet_resolution;
|
let facet_res = self.document.header.facet_resolution;
|
||||||
let woff = [0.0_f64; 3];
|
|
||||||
// Top-level solids: offset into the render frame, drawn flat.
|
// Top-level solids: offset into the render frame, drawn flat.
|
||||||
// Block-definition solids: keep block-local coords for per-INSERT
|
// Block-definition solids: keep block-local coords for per-INSERT
|
||||||
// instancing (no offset applied here).
|
// instancing (no offset applied here).
|
||||||
|
|
@ -5228,7 +5172,7 @@ impl Scene {
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.filter_map(|(handle, entity, color, top_level)| {
|
.filter_map(|(handle, entity, color, top_level)| {
|
||||||
crate::entities::solid3d::tessellate_volume(&entity, color, facet_res).map(|m| {
|
crate::entities::solid3d::tessellate_volume(&entity, color, facet_res).map(|m| {
|
||||||
let m = if top_level { offset_mesh_lod_set(m, woff) } else { m };
|
let m = if top_level { offset_mesh_lod_set(m) } else { m };
|
||||||
(handle, m, top_level)
|
(handle, m, top_level)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -5255,8 +5199,8 @@ impl Scene {
|
||||||
/// Build a solid-fill HatchModel for a DXF Solid entity.
|
/// Build a solid-fill HatchModel for a DXF Solid entity.
|
||||||
/// DXF SOLID corners are in "Z-order": p0-p1 top, p2-p3 bottom.
|
/// DXF SOLID corners are in "Z-order": p0-p1 top, p2-p3 bottom.
|
||||||
/// Visual quad is p0→p1→p3→p2 (closed).
|
/// Visual quad is p0→p1→p3→p2 (closed).
|
||||||
fn solid_hatch_model(solid: &DxfSolid, color: [f32; 4], world_offset: [f64; 3]) -> HatchModel {
|
fn solid_hatch_model(solid: &DxfSolid, color: [f32; 4]) -> HatchModel {
|
||||||
let [ox, oy, _oz] = world_offset;
|
let [ox, oy, _oz] = [0.0_f64; 3];
|
||||||
let boundary = vec![
|
let boundary = vec![
|
||||||
[
|
[
|
||||||
(solid.first_corner.x - ox) as f32,
|
(solid.first_corner.x - ox) as f32,
|
||||||
|
|
@ -5298,13 +5242,8 @@ impl Scene {
|
||||||
// already subtracted). The stored DXF entity must hold WCS, so add the
|
// already subtracted). The stored DXF entity must hold WCS, so add the
|
||||||
// offset back — otherwise the boundary wire, re-projected through the
|
// offset back — otherwise the boundary wire, re-projected through the
|
||||||
// normal entity path, lands `world_offset` away from the fill.
|
// normal entity path, lands `world_offset` away from the fill.
|
||||||
let off = if self.current_layout == "Model" {
|
let wx = model.world_origin[0];
|
||||||
[0.0_f64; 3]
|
let wy = model.world_origin[1];
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let wx = model.world_origin[0] + off[0];
|
|
||||||
let wy = model.world_origin[1] + off[1];
|
|
||||||
let verts: Vec<Vector2> = model
|
let verts: Vec<Vector2> = model
|
||||||
.boundary
|
.boundary
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -5840,11 +5779,6 @@ impl Scene {
|
||||||
// ── Modify (transform / copy) ─────────────────────────────────────────
|
// ── Modify (transform / copy) ─────────────────────────────────────────
|
||||||
|
|
||||||
pub fn transform_entities(&mut self, handles: &[Handle], t: &EntityTransform) {
|
pub fn transform_entities(&mut self, handles: &[Handle], t: &EntityTransform) {
|
||||||
let hatch_offset = if self.current_layout == "Model" {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
// MIRRTEXT (header.mirror_text): when false AutoCAD positions text /
|
// MIRRTEXT (header.mirror_text): when false AutoCAD positions text /
|
||||||
// mtext / shape by the mirror but keeps the original rotation +
|
// mtext / shape by the mirror but keeps the original rotation +
|
||||||
// oblique so the text stays right-reading. Capture before the
|
// oblique so the text stays right-reading. Capture before the
|
||||||
|
|
@ -5907,12 +5841,12 @@ impl Scene {
|
||||||
let existing_color = self.hatches[&h].color;
|
let existing_color = self.hatches[&h].color;
|
||||||
let new_model = match self.document.get_entity(h) {
|
let new_model = match self.document.get_entity(h) {
|
||||||
Some(EntityType::Hatch(dxf)) => {
|
Some(EntityType::Hatch(dxf)) => {
|
||||||
Self::hatch_model_from_dxf(dxf, existing_color, hatch_offset)
|
Self::hatch_model_from_dxf(dxf, existing_color)
|
||||||
}
|
}
|
||||||
// A DXF SOLID renders as a solid-fill hatch; rebuild it from
|
// A DXF SOLID renders as a solid-fill hatch; rebuild it from
|
||||||
// the moved corners so the fill follows the transform.
|
// the moved corners so the fill follows the transform.
|
||||||
Some(EntityType::Solid(s)) => {
|
Some(EntityType::Solid(s)) => {
|
||||||
Some(Self::solid_hatch_model(s, existing_color, hatch_offset))
|
Some(Self::solid_hatch_model(s, existing_color))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
@ -5990,11 +5924,6 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_entities(&mut self, handles: &[Handle], t: &EntityTransform) -> Vec<Handle> {
|
pub fn copy_entities(&mut self, handles: &[Handle], t: &EntityTransform) -> Vec<Handle> {
|
||||||
let hatch_offset = if self.current_layout == "Model" {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
let clones: Vec<EntityType> = handles
|
let clones: Vec<EntityType> = handles
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&h| self.document.get_entity(h).cloned())
|
.filter_map(|&h| self.document.get_entity(h).cloned())
|
||||||
|
|
@ -6009,11 +5938,11 @@ impl Scene {
|
||||||
let new_model = match self.document.get_entity(h) {
|
let new_model = match self.document.get_entity(h) {
|
||||||
Some(EntityType::Hatch(dxf)) => {
|
Some(EntityType::Hatch(dxf)) => {
|
||||||
let color = convert::tess_util::aci_to_rgba(&dxf.common.color);
|
let color = convert::tess_util::aci_to_rgba(&dxf.common.color);
|
||||||
Self::hatch_model_from_dxf(dxf, color, hatch_offset)
|
Self::hatch_model_from_dxf(dxf, color)
|
||||||
}
|
}
|
||||||
Some(EntityType::Solid(s)) => {
|
Some(EntityType::Solid(s)) => {
|
||||||
let color = convert::tess_util::aci_to_rgba(&s.common.color);
|
let color = convert::tess_util::aci_to_rgba(&s.common.color);
|
||||||
Some(Self::solid_hatch_model(s, color, hatch_offset))
|
Some(Self::solid_hatch_model(s, color))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
@ -6073,15 +6002,10 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebuild GPU hatch/solid model when a boundary vertex or corner moves.
|
// Rebuild GPU hatch/solid model when a boundary vertex or corner moves.
|
||||||
let hatch_offset = if self.current_layout == "Model" {
|
|
||||||
[0.0_f64; 3]
|
|
||||||
} else {
|
|
||||||
[0.0; 3]
|
|
||||||
};
|
|
||||||
match self.document.get_entity(handle) {
|
match self.document.get_entity(handle) {
|
||||||
Some(EntityType::Hatch(dxf)) => {
|
Some(EntityType::Hatch(dxf)) => {
|
||||||
let color = convert::tess_util::aci_to_rgba(&dxf.common.color);
|
let color = convert::tess_util::aci_to_rgba(&dxf.common.color);
|
||||||
if let Some(model) = Self::hatch_model_from_dxf(dxf, color, hatch_offset) {
|
if let Some(model) = Self::hatch_model_from_dxf(dxf, color) {
|
||||||
self.hatches.insert(handle, model);
|
self.hatches.insert(handle, model);
|
||||||
} else {
|
} else {
|
||||||
self.hatches.remove(&handle);
|
self.hatches.remove(&handle);
|
||||||
|
|
@ -6090,7 +6014,7 @@ impl Scene {
|
||||||
Some(EntityType::Solid(solid)) => {
|
Some(EntityType::Solid(solid)) => {
|
||||||
let color = convert::tess_util::aci_to_rgba(&solid.common.color);
|
let color = convert::tess_util::aci_to_rgba(&solid.common.color);
|
||||||
self.hatches
|
self.hatches
|
||||||
.insert(handle, Self::solid_hatch_model(solid, color, hatch_offset));
|
.insert(handle, Self::solid_hatch_model(solid, color));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -6204,7 +6128,7 @@ impl Scene {
|
||||||
view: &acadrust::tables::View,
|
view: &acadrust::tables::View,
|
||||||
model_space: bool,
|
model_space: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let offset = if model_space { [0.0_f64; 3] } else { [0.0; 3] };
|
let _ = model_space;
|
||||||
let Some(cam) = self.camera_from_view(
|
let Some(cam) = self.camera_from_view(
|
||||||
view.direction,
|
view.direction,
|
||||||
view.target,
|
view.target,
|
||||||
|
|
@ -6214,7 +6138,6 @@ impl Scene {
|
||||||
},
|
},
|
||||||
view.height,
|
view.height,
|
||||||
view.twist_angle,
|
view.twist_angle,
|
||||||
offset,
|
|
||||||
) else {
|
) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
@ -6280,7 +6203,6 @@ impl Scene {
|
||||||
// Subtracted from `view_target` to reach wire-space. Model views pass
|
// Subtracted from `view_target` to reach wire-space. Model views pass
|
||||||
// `[0.0_f64; 3]`; paper-space views (whose entities carry no
|
// `[0.0_f64; 3]`; paper-space views (whose entities carry no
|
||||||
// offset) pass `[0; 3]`.
|
// offset) pass `[0; 3]`.
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> Option<Camera> {
|
) -> Option<Camera> {
|
||||||
if view_height.abs() < 1e-9 {
|
if view_height.abs() < 1e-9 {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -6317,9 +6239,9 @@ impl Scene {
|
||||||
// jump on the f32 grid. The axis directions stay f32 (orientation only);
|
// jump on the f32 grid. The axis directions stay f32 (orientation only);
|
||||||
// only the position must stay precise — matching the model camera.
|
// only the position must stay precise — matching the model camera.
|
||||||
let base = glam::DVec3::new(
|
let base = glam::DVec3::new(
|
||||||
view_target.x - world_offset[0],
|
view_target.x,
|
||||||
view_target.y - world_offset[1],
|
view_target.y,
|
||||||
view_target.z - world_offset[2],
|
view_target.z,
|
||||||
);
|
);
|
||||||
let target = base
|
let target = base
|
||||||
+ view_right.as_dvec3() * view_center.x
|
+ view_right.as_dvec3() * view_center.x
|
||||||
|
|
@ -6345,7 +6267,6 @@ impl Scene {
|
||||||
vp.view_center,
|
vp.view_center,
|
||||||
vp.view_height,
|
vp.view_height,
|
||||||
vp.view_twist,
|
vp.view_twist,
|
||||||
[0.0_f64; 3],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6607,7 +6528,6 @@ impl Scene {
|
||||||
},
|
},
|
||||||
vp.view_height,
|
vp.view_height,
|
||||||
vp.twist_angle,
|
vp.twist_angle,
|
||||||
[0.0; 3],
|
|
||||||
) else {
|
) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
@ -7646,7 +7566,7 @@ impl Scene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Paper-block wipeouts live in paper coords — no `world_offset`.
|
// Paper-block wipeouts live in paper coords — no `world_offset`.
|
||||||
let boundary = Self::wipeout_boundary_2d(wo, [0.0; 3]);
|
let boundary = Self::wipeout_boundary_2d(wo);
|
||||||
if boundary.len() < 3 {
|
if boundary.len() < 3 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -7719,7 +7639,6 @@ impl Scene {
|
||||||
},
|
},
|
||||||
saved_h,
|
saved_h,
|
||||||
vp.twist_angle,
|
vp.twist_angle,
|
||||||
[0.0_f64; 3],
|
|
||||||
) {
|
) {
|
||||||
let half_h = saved_h * 0.5;
|
let half_h = saved_h * 0.5;
|
||||||
let half_w = half_h * aspect_d;
|
let half_w = half_h * aspect_d;
|
||||||
|
|
@ -7746,7 +7665,6 @@ impl Scene {
|
||||||
acadrust::types::Vector2::ZERO,
|
acadrust::types::Vector2::ZERO,
|
||||||
fit_h,
|
fit_h,
|
||||||
vp.twist_angle,
|
vp.twist_angle,
|
||||||
[0.0_f64; 3],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8031,7 +7949,6 @@ pub(crate) fn tessellate_entity_dim_text(
|
||||||
document: &acadrust::CadDocument,
|
document: &acadrust::CadDocument,
|
||||||
selected: &HashSet<Handle>,
|
selected: &HashSet<Handle>,
|
||||||
active_viewport: Option<Handle>,
|
active_viewport: Option<Handle>,
|
||||||
world_offset: [f64; 3],
|
|
||||||
bg_color: [f32; 4],
|
bg_color: [f32; 4],
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
e: &EntityType,
|
e: &EntityType,
|
||||||
|
|
@ -8040,7 +7957,7 @@ pub(crate) fn tessellate_entity_dim_text(
|
||||||
text_color: [f32; 4],
|
text_color: [f32; 4],
|
||||||
) -> Vec<WireModel> {
|
) -> Vec<WireModel> {
|
||||||
let mut wires = tessellate_entity(
|
let mut wires = tessellate_entity(
|
||||||
document, selected, active_viewport, world_offset, bg_color,
|
document, selected, active_viewport, bg_color,
|
||||||
anno_scale, e, None, view_aabb, world_per_pixel,
|
anno_scale, e, None, view_aabb, world_per_pixel,
|
||||||
);
|
);
|
||||||
for w in &mut wires {
|
for w in &mut wires {
|
||||||
|
|
@ -8059,7 +7976,6 @@ fn tessellate_entity(
|
||||||
document: &acadrust::CadDocument,
|
document: &acadrust::CadDocument,
|
||||||
selected: &HashSet<Handle>,
|
selected: &HashSet<Handle>,
|
||||||
active_viewport: Option<Handle>,
|
active_viewport: Option<Handle>,
|
||||||
world_offset: [f64; 3],
|
|
||||||
bg_color: [f32; 4],
|
bg_color: [f32; 4],
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
e: &EntityType,
|
e: &EntityType,
|
||||||
|
|
@ -8082,7 +7998,7 @@ fn tessellate_entity(
|
||||||
match e {
|
match e {
|
||||||
EntityType::Viewport(_) | EntityType::Insert(_) => {}
|
EntityType::Viewport(_) | EntityType::Insert(_) => {}
|
||||||
_ => {
|
_ => {
|
||||||
let ab = entity_aabb(e, world_offset);
|
let ab = entity_aabb(e);
|
||||||
if ab != WireModel::UNBOUNDED_AABB {
|
if ab != WireModel::UNBOUNDED_AABB {
|
||||||
if let Some(view) = view_aabb {
|
if let Some(view) = view_aabb {
|
||||||
if cache::block_cache::aabb_disjoint_xy(ab, view) {
|
if cache::block_cache::aabb_disjoint_xy(ab, view) {
|
||||||
|
|
@ -8129,7 +8045,7 @@ fn tessellate_entity(
|
||||||
// and the geometry visibly shifts when
|
// and the geometry visibly shifts when
|
||||||
// the camera crosses the LOD threshold.
|
// the camera crosses the LOD threshold.
|
||||||
let bbox = e.as_entity().bounding_box();
|
let bbox = e.as_entity().bounding_box();
|
||||||
let oz = world_offset[2];
|
let oz = 0.0_f64;
|
||||||
let z_min = (bbox.min.z - oz) as f32;
|
let z_min = (bbox.min.z - oz) as f32;
|
||||||
let z_max = (bbox.max.z - oz) as f32;
|
let z_max = (bbox.max.z - oz) as f32;
|
||||||
return vec![lod_stub_wire_3d(
|
return vec![lod_stub_wire_3d(
|
||||||
|
|
@ -8189,11 +8105,10 @@ fn tessellate_entity(
|
||||||
pattern_length,
|
pattern_length,
|
||||||
pattern,
|
pattern,
|
||||||
1.5,
|
1.5,
|
||||||
world_offset,
|
|
||||||
1.0,
|
1.0,
|
||||||
world_per_pixel,
|
world_per_pixel,
|
||||||
);
|
);
|
||||||
let ab = entity_aabb(e, world_offset);
|
let ab = entity_aabb(e);
|
||||||
for w in &mut wires {
|
for w in &mut wires {
|
||||||
w.aabb = ab;
|
w.aabb = ab;
|
||||||
}
|
}
|
||||||
|
|
@ -8241,7 +8156,7 @@ fn tessellate_entity(
|
||||||
let sub_color_is_byblock =
|
let sub_color_is_byblock =
|
||||||
sub.common().color == acadrust::types::Color::ByBlock;
|
sub.common().color == acadrust::types::Color::ByBlock;
|
||||||
let sub_wires = tessellate_entity(
|
let sub_wires = tessellate_entity(
|
||||||
document, selected, active_viewport, world_offset, bg_color,
|
document, selected, active_viewport, bg_color,
|
||||||
// Block contents are baked at the final WCS size —
|
// Block contents are baked at the final WCS size —
|
||||||
// don't let downstream paths re-apply anno_scale.
|
// don't let downstream paths re-apply anno_scale.
|
||||||
1.0, sub, block_cache, view_aabb, world_per_pixel,
|
1.0, sub, block_cache, view_aabb, world_per_pixel,
|
||||||
|
|
@ -8260,7 +8175,7 @@ fn tessellate_entity(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !wires.is_empty() {
|
if !wires.is_empty() {
|
||||||
let aabb = entity_aabb(e, world_offset);
|
let aabb = entity_aabb(e);
|
||||||
for w in &mut wires {
|
for w in &mut wires {
|
||||||
w.aabb = aabb;
|
w.aabb = aabb;
|
||||||
}
|
}
|
||||||
|
|
@ -8273,7 +8188,7 @@ fn tessellate_entity(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let EntityType::Dimension(dim) = e {
|
if let EntityType::Dimension(dim) = e {
|
||||||
let aabb = entity_aabb(e, world_offset);
|
let aabb = entity_aabb(e);
|
||||||
use crate::entities::dimension::DimensionTess;
|
use crate::entities::dimension::DimensionTess;
|
||||||
let mut wires = dim.tessellate(
|
let mut wires = dim.tessellate(
|
||||||
document,
|
document,
|
||||||
|
|
@ -8281,7 +8196,6 @@ fn tessellate_entity(
|
||||||
sel,
|
sel,
|
||||||
entity_color,
|
entity_color,
|
||||||
line_weight_px,
|
line_weight_px,
|
||||||
world_offset,
|
|
||||||
anno_scale,
|
anno_scale,
|
||||||
selected,
|
selected,
|
||||||
active_viewport,
|
active_viewport,
|
||||||
|
|
@ -8297,7 +8211,7 @@ fn tessellate_entity(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let EntityType::MultiLeader(ml) = e {
|
if let EntityType::MultiLeader(ml) = e {
|
||||||
let aabb = entity_aabb(e, world_offset);
|
let aabb = entity_aabb(e);
|
||||||
use crate::entities::multileader::MultiLeaderTess;
|
use crate::entities::multileader::MultiLeaderTess;
|
||||||
let mut wires = ml.tessellate(
|
let mut wires = ml.tessellate(
|
||||||
document,
|
document,
|
||||||
|
|
@ -8305,7 +8219,6 @@ fn tessellate_entity(
|
||||||
sel,
|
sel,
|
||||||
entity_color,
|
entity_color,
|
||||||
line_weight_px,
|
line_weight_px,
|
||||||
world_offset,
|
|
||||||
anno_scale,
|
anno_scale,
|
||||||
world_per_pixel,
|
world_per_pixel,
|
||||||
);
|
);
|
||||||
|
|
@ -8340,7 +8253,7 @@ fn tessellate_entity(
|
||||||
let sub_color_is_byblock =
|
let sub_color_is_byblock =
|
||||||
sub.common().color == acadrust::types::Color::ByBlock;
|
sub.common().color == acadrust::types::Color::ByBlock;
|
||||||
let sub_wires = tessellate_entity(
|
let sub_wires = tessellate_entity(
|
||||||
document, selected, active_viewport, world_offset, bg_color,
|
document, selected, active_viewport, bg_color,
|
||||||
anno_scale, sub, block_cache, view_aabb, world_per_pixel,
|
anno_scale, sub, block_cache, view_aabb, world_per_pixel,
|
||||||
);
|
);
|
||||||
for mut w in sub_wires {
|
for mut w in sub_wires {
|
||||||
|
|
@ -8353,7 +8266,7 @@ fn tessellate_entity(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !wires.is_empty() {
|
if !wires.is_empty() {
|
||||||
let aabb = entity_aabb(e, world_offset);
|
let aabb = entity_aabb(e);
|
||||||
for w in &mut wires {
|
for w in &mut wires {
|
||||||
w.aabb = aabb;
|
w.aabb = aabb;
|
||||||
}
|
}
|
||||||
|
|
@ -8366,10 +8279,10 @@ fn tessellate_entity(
|
||||||
// geometry from the rows + TableStyle so fills/colours/borders/margins
|
// geometry from the rows + TableStyle so fills/colours/borders/margins
|
||||||
// are honoured instead of the monochrome fallback.
|
// are honoured instead of the monochrome fallback.
|
||||||
let mut wires = crate::entities::table::tessellate_table(
|
let mut wires = crate::entities::table::tessellate_table(
|
||||||
tab, document, sel, entity_color, line_weight_px, world_offset,
|
tab, document, sel, entity_color, line_weight_px,
|
||||||
);
|
);
|
||||||
if !wires.is_empty() {
|
if !wires.is_empty() {
|
||||||
let aabb = entity_aabb(e, world_offset);
|
let aabb = entity_aabb(e);
|
||||||
for w in &mut wires {
|
for w in &mut wires {
|
||||||
w.aci = aci;
|
w.aci = aci;
|
||||||
w.aabb = aabb;
|
w.aabb = aabb;
|
||||||
|
|
@ -8382,7 +8295,7 @@ fn tessellate_entity(
|
||||||
// Resolve the INSERT's own style so ByBlock sub-entities can inherit it.
|
// Resolve the INSERT's own style so ByBlock sub-entities can inherit it.
|
||||||
let (ins_color, ins_pat_len, ins_pat, ins_lw_px, _) = view::render::render_style_for(document, e);
|
let (ins_color, ins_pat_len, ins_pat, ins_lw_px, _) = view::render::render_style_for(document, e);
|
||||||
let ins_color = view::render::adapt_to_bg(ins_color, bg_color);
|
let ins_color = view::render::adapt_to_bg(ins_color, bg_color);
|
||||||
let [ox, oy, oz] = world_offset;
|
let [ox, oy, oz] = [0.0_f64; 3];
|
||||||
let ip = glam::Vec3::new(
|
let ip = glam::Vec3::new(
|
||||||
(ins.insert_point.x - ox) as f32,
|
(ins.insert_point.x - ox) as f32,
|
||||||
(ins.insert_point.y - oy) as f32,
|
(ins.insert_point.y - oy) as f32,
|
||||||
|
|
@ -8425,7 +8338,6 @@ fn tessellate_entity(
|
||||||
ins_pat,
|
ins_pat,
|
||||||
ins_lw_px,
|
ins_lw_px,
|
||||||
sel,
|
sel,
|
||||||
world_offset,
|
|
||||||
pslt_factor,
|
pslt_factor,
|
||||||
view_aabb,
|
view_aabb,
|
||||||
world_per_pixel,
|
world_per_pixel,
|
||||||
|
|
@ -8436,7 +8348,7 @@ fn tessellate_entity(
|
||||||
// clip the expanded block geometry to the boundary polygon so
|
// clip the expanded block geometry to the boundary polygon so
|
||||||
// only the portion inside the clip is drawn.
|
// only the portion inside the clip is drawn.
|
||||||
if let Some(sf) = pick::xclip::insert_spatial_filter(document, ins) {
|
if let Some(sf) = pick::xclip::insert_spatial_filter(document, ins) {
|
||||||
let poly = pick::xclip::world_clip_polygon_f64(sf, ins, world_offset);
|
let poly = pick::xclip::world_clip_polygon_f64(sf, ins);
|
||||||
pick::xclip::clip_wires(&mut wires, &poly);
|
pick::xclip::clip_wires(&mut wires, &poly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8459,7 +8371,6 @@ fn tessellate_entity(
|
||||||
is_xref,
|
is_xref,
|
||||||
pslt_factor,
|
pslt_factor,
|
||||||
anno_scale,
|
anno_scale,
|
||||||
world_offset,
|
|
||||||
);
|
);
|
||||||
wires.push(marker);
|
wires.push(marker);
|
||||||
return wires;
|
return wires;
|
||||||
|
|
@ -8494,7 +8405,7 @@ fn tessellate_entity(
|
||||||
} else {
|
} else {
|
||||||
sub_color
|
sub_color
|
||||||
};
|
};
|
||||||
let sub_aabb = entity_aabb(&sub, world_offset);
|
let sub_aabb = entity_aabb(&sub);
|
||||||
let sub_pattern_length = sub_pattern_length * pslt_factor;
|
let sub_pattern_length = sub_pattern_length * pslt_factor;
|
||||||
let sub_pattern = sub_pattern.map(|v| v * pslt_factor);
|
let sub_pattern = sub_pattern.map(|v| v * pslt_factor);
|
||||||
let mut wires = convert::tessellate::tessellate(
|
let mut wires = convert::tessellate::tessellate(
|
||||||
|
|
@ -8506,7 +8417,6 @@ fn tessellate_entity(
|
||||||
sub_pattern_length,
|
sub_pattern_length,
|
||||||
sub_pattern,
|
sub_pattern,
|
||||||
sub_line_weight_px,
|
sub_line_weight_px,
|
||||||
world_offset,
|
|
||||||
anno_scale,
|
anno_scale,
|
||||||
world_per_pixel,
|
world_per_pixel,
|
||||||
);
|
);
|
||||||
|
|
@ -8532,13 +8442,12 @@ fn tessellate_entity(
|
||||||
is_xref,
|
is_xref,
|
||||||
pslt_factor,
|
pslt_factor,
|
||||||
anno_scale,
|
anno_scale,
|
||||||
world_offset,
|
|
||||||
);
|
);
|
||||||
wires.push(marker);
|
wires.push(marker);
|
||||||
return wires;
|
return wires;
|
||||||
}
|
}
|
||||||
|
|
||||||
let aabb = entity_aabb(e, world_offset);
|
let aabb = entity_aabb(e);
|
||||||
|
|
||||||
// Text-specific LOD ladder, keyed off the entity's glyph height in
|
// Text-specific LOD ladder, keyed off the entity's glyph height in
|
||||||
// pixels (anno-scaled):
|
// pixels (anno-scaled):
|
||||||
|
|
@ -8575,7 +8484,7 @@ fn tessellate_entity(
|
||||||
_ => 1,
|
_ => 1,
|
||||||
};
|
};
|
||||||
if h_px < 1.0 {
|
if h_px < 1.0 {
|
||||||
let pts = crate::entities::text_support::text_baseline_points(e, anno_scale, world_offset, n_lines);
|
let pts = crate::entities::text_support::text_baseline_points(e, anno_scale, n_lines);
|
||||||
if pts.len() < 2 {
|
if pts.len() < 2 {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
|
|
@ -8622,7 +8531,7 @@ fn tessellate_entity(
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
if h_px < 5.0 && aabb != WireModel::UNBOUNDED_AABB {
|
if h_px < 5.0 && aabb != WireModel::UNBOUNDED_AABB {
|
||||||
let fill_tris = crate::entities::text_support::text_greek_obb_tris(e, anno_scale, world_offset, n_lines);
|
let fill_tris = crate::entities::text_support::text_greek_obb_tris(e, anno_scale, n_lines);
|
||||||
if fill_tris.is_empty() {
|
if fill_tris.is_empty() {
|
||||||
// Text greek fallback: also 2-D, keep stub at z=0.
|
// Text greek fallback: also 2-D, keep stub at z=0.
|
||||||
return vec![lod_stub_wire(
|
return vec![lod_stub_wire(
|
||||||
|
|
@ -8672,7 +8581,6 @@ fn tessellate_entity(
|
||||||
pattern_length,
|
pattern_length,
|
||||||
pattern,
|
pattern,
|
||||||
line_weight_px,
|
line_weight_px,
|
||||||
world_offset,
|
|
||||||
anno_scale,
|
anno_scale,
|
||||||
world_per_pixel,
|
world_per_pixel,
|
||||||
);
|
);
|
||||||
|
|
@ -8836,9 +8744,9 @@ fn lod_stub_wire_3d(
|
||||||
/// INSERT only stamps the geometry once, attribute text sits at the world
|
/// INSERT only stamps the geometry once, attribute text sits at the world
|
||||||
/// position recorded on each ATTRIB. See #20.
|
/// position recorded on each ATTRIB. See #20.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn entity_aabb(e: &acadrust::EntityType, world_offset: [f64; 3]) -> [f32; 4] {
|
pub(crate) fn entity_aabb(e: &acadrust::EntityType) -> [f32; 4] {
|
||||||
let bbox = e.as_entity().bounding_box();
|
let bbox = e.as_entity().bounding_box();
|
||||||
let [ox, oy, _] = world_offset;
|
let [ox, oy, _] = [0.0_f64; 3];
|
||||||
let min_x = (bbox.min.x - ox) as f32;
|
let min_x = (bbox.min.x - ox) as f32;
|
||||||
let min_y = (bbox.min.y - oy) as f32;
|
let min_y = (bbox.min.y - oy) as f32;
|
||||||
let max_x = (bbox.max.x - ox) as f32;
|
let max_x = (bbox.max.x - ox) as f32;
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ impl ImageModel {
|
||||||
/// Returns `None` if the image file cannot be opened or decoded.
|
/// Returns `None` if the image file cannot be opened or decoded.
|
||||||
pub fn from_raster_image(
|
pub fn from_raster_image(
|
||||||
img: &acadrust::entities::RasterImage,
|
img: &acadrust::entities::RasterImage,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let w = img.size.x;
|
let w = img.size.x;
|
||||||
let h = img.size.y;
|
let h = img.size.y;
|
||||||
|
|
@ -50,9 +49,9 @@ impl ImageModel {
|
||||||
// Corners come from a large insertion point plus small u/v spans.
|
// Corners come from a large insertion point plus small u/v spans.
|
||||||
// Split each into double-single (high, low) f32 so the GPU keeps
|
// Split each into double-single (high, low) f32 so the GPU keeps
|
||||||
// sub-unit precision at UTM scale and after a cross-drawing paste.
|
// sub-unit precision at UTM scale and after a cross-drawing paste.
|
||||||
let oxv = img.insertion_point.x - world_offset[0];
|
let oxv = img.insertion_point.x;
|
||||||
let oyv = img.insertion_point.y - world_offset[1];
|
let oyv = img.insertion_point.y;
|
||||||
let ozv = img.insertion_point.z - world_offset[2];
|
let ozv = img.insertion_point.z;
|
||||||
let ux = (img.u_vector.x * w) as f32;
|
let ux = (img.u_vector.x * w) as f32;
|
||||||
let uy = (img.u_vector.y * w) as f32;
|
let uy = (img.u_vector.y * w) as f32;
|
||||||
let uz = (img.u_vector.z * w) as f32;
|
let uz = (img.u_vector.z * w) as f32;
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ pub fn edge_wires(solid: &Solid) -> Vec<acadrust::entities::Wire> {
|
||||||
for shell in solid.boundaries() {
|
for shell in solid.boundaries() {
|
||||||
for edge in shell.edge_iter() {
|
for edge in shell.edge_iter() {
|
||||||
if let TruckTessResult::Lines(pts, pts_low) =
|
if let TruckTessResult::Lines(pts, pts_low) =
|
||||||
tessellate_edge(&edge, [0.0; 3])
|
tessellate_edge(&edge)
|
||||||
{
|
{
|
||||||
if pts.len() < 2 {
|
if pts.len() < 2 {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -169,7 +169,7 @@ pub fn boolean(_op: Bool, _a: &Solid, _b: &Solid) -> Option<Solid> {
|
||||||
/// before world_offset is applied by the caller).
|
/// before world_offset is applied by the caller).
|
||||||
pub fn mesh_from_solid(solid: &Solid, color: [f32; 4]) -> Option<MeshLodSet> {
|
pub fn mesh_from_solid(solid: &Solid, color: [f32; 4]) -> Option<MeshLodSet> {
|
||||||
use crate::scene::convert::truck_tess::{tessellate_solid, TruckTessResult};
|
use crate::scene::convert::truck_tess::{tessellate_solid, TruckTessResult};
|
||||||
match tessellate_solid(solid, [0.0; 3]) {
|
match tessellate_solid(solid) {
|
||||||
TruckTessResult::Mesh {
|
TruckTessResult::Mesh {
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,8 @@ fn dict_entry(doc: &CadDocument, dict: Handle, key: &str) -> Option<Handle> {
|
||||||
pub fn world_clip_polygon(
|
pub fn world_clip_polygon(
|
||||||
sf: &SpatialFilter,
|
sf: &SpatialFilter,
|
||||||
ins: &Insert,
|
ins: &Insert,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> Vec<[f32; 2]> {
|
) -> Vec<[f32; 2]> {
|
||||||
world_clip_polygon_f64(sf, ins, world_offset)
|
world_clip_polygon_f64(sf, ins)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|[x, y]| [x as f32, y as f32])
|
.map(|[x, y]| [x as f32, y as f32])
|
||||||
.collect()
|
.collect()
|
||||||
|
|
@ -80,11 +79,10 @@ pub fn world_clip_polygon(
|
||||||
pub fn world_clip_polygon_f64(
|
pub fn world_clip_polygon_f64(
|
||||||
sf: &SpatialFilter,
|
sf: &SpatialFilter,
|
||||||
ins: &Insert,
|
ins: &Insert,
|
||||||
world_offset: [f64; 3],
|
|
||||||
) -> Vec<[f64; 2]> {
|
) -> Vec<[f64; 2]> {
|
||||||
let xform = ins.get_transform();
|
let xform = ins.get_transform();
|
||||||
let inv_block = &sf.inverse_block_transform;
|
let inv_block = &sf.inverse_block_transform;
|
||||||
let [ox, oy, _] = world_offset;
|
let [ox, oy, _] = [0.0_f64; 3];
|
||||||
let local: Vec<[f64; 2]> = if sf.boundary_points.len() == 2 {
|
let local: Vec<[f64; 2]> = if sf.boundary_points.len() == 2 {
|
||||||
let a = sf.boundary_points[0];
|
let a = sf.boundary_points[0];
|
||||||
let b = sf.boundary_points[1];
|
let b = sf.boundary_points[1];
|
||||||
|
|
|
||||||
|
|
@ -162,10 +162,6 @@ impl Snapper {
|
||||||
self.grid_snap_on = !self.grid_snap_on;
|
self.grid_snap_on = !self.grid_snap_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_grid_snap(&mut self, on: bool) {
|
|
||||||
self.grid_snap_on = on;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toggle(&mut self, t: SnapType) {
|
pub fn toggle(&mut self, t: SnapType) {
|
||||||
if !self.enabled.remove(&t) {
|
if !self.enabled.remove(&t) {
|
||||||
self.enabled.insert(t);
|
self.enabled.insert(t);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue