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:
Hakan Seven 2026-06-24 18:35:02 +03:00
commit 56d507fd88
20 changed files with 190 additions and 343 deletions

View file

@ -1241,7 +1241,6 @@ impl OpenCADStudio {
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
if let Some(entity) = entity_opt {
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| {
match te.object {
TruckObject::Contour(wire) => {
@ -1250,7 +1249,7 @@ impl OpenCADStudio {
// tsweep(Face) → Solid
let solid =
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 {
verts,
verts_low,
@ -1309,7 +1308,6 @@ impl OpenCADStudio {
let entity_opt = self.tabs[i].scene.document.get_entity(handle).cloned();
if let Some(entity) = entity_opt {
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 wire: Option<truck_modeling::Wire> = match te.object {
TruckObject::Contour(w) => Some(w),
@ -1330,7 +1328,7 @@ impl OpenCADStudio {
axis,
Rad(angle_deg.to_radians() as f64),
);
match truck_tess::tessellate_shell(&shell, woff) {
match truck_tess::tessellate_shell(&shell) {
truck_tess::TruckTessResult::Mesh {
verts,
verts_low,
@ -1389,7 +1387,6 @@ impl OpenCADStudio {
.get_entity(profile_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 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.
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
let solid = builder::tsweep(&face, dir);
match truck_tess::tessellate_solid(&solid, woff) {
match truck_tess::tessellate_solid(&solid) {
truck_tess::TruckTessResult::Mesh {
verts,
verts_low,
@ -1436,7 +1433,7 @@ impl OpenCADStudio {
}
} else {
let shell = builder::tsweep(&profile_wire, dir);
match truck_tess::tessellate_shell(&shell, woff) {
match truck_tess::tessellate_shell(&shell) {
truck_tess::TruckTessResult::Mesh {
verts,
verts_low,
@ -1470,7 +1467,7 @@ impl OpenCADStudio {
);
if let Ok(face) = builder::try_attach_plane(&[profile_wire.clone()]) {
let solid = builder::tsweep(&face, dir);
match truck_tess::tessellate_solid(&solid, woff) {
match truck_tess::tessellate_solid(&solid) {
truck_tess::TruckTessResult::Mesh {
verts,
verts_low,
@ -1489,7 +1486,7 @@ impl OpenCADStudio {
}
} else {
let shell = builder::tsweep(&profile_wire, dir);
match truck_tess::tessellate_shell(&shell, woff) {
match truck_tess::tessellate_shell(&shell) {
truck_tess::TruckTessResult::Mesh {
verts,
verts_low,
@ -1556,7 +1553,6 @@ impl OpenCADStudio {
}
}
let woff = [0.0_f64; 3];
let result: Option<crate::scene::model::mesh_model::MeshModel> = (|| {
if wires.len() < 2 {
return None;
@ -1581,7 +1577,7 @@ impl OpenCADStudio {
}
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 {
verts,
verts_low,

View file

@ -406,7 +406,6 @@ impl super::OpenCADStudio {
0.0,
[0.0; 8],
1.0,
woff,
anno,
None,
);

View file

@ -849,7 +849,6 @@ pub trait DimensionTess {
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
active_viewport: Option<acadrust::Handle>,
@ -867,7 +866,6 @@ impl DimensionTess for Dimension {
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
active_viewport: Option<acadrust::Handle>,
@ -882,7 +880,6 @@ impl DimensionTess for Dimension {
selected,
entity_color,
line_weight_px,
world_offset,
anno_scale,
selected_set,
active_viewport,
@ -900,7 +897,6 @@ fn tessellate_dimension_inner(
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
// LOD hints — when present, synthesised dim text routes through the
// top-level LOD ladder (baseline / greek / full) instead of the truck
@ -1012,7 +1008,6 @@ fn tessellate_dimension_inner(
let text_break = {
let tp = vec3_local(
dimension_text_pos_f64(dim, style, dim_txt, dim_scale),
world_offset,
);
let tw = dimension_text_value(dim, style)
.map(|t| t.chars().count() as f32 * dim_txt as f32 * 0.6)
@ -1054,7 +1049,6 @@ fn tessellate_dimension_inner(
dim1: dimsd1,
dim2: dimsd2,
},
world_offset,
);
// 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.)
if let Some(s) = style {
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;
if (txt - anchor).length() > gap * 2.0 {
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)
};
let snap_pts = dimension_snap_pts(dim, world_offset);
let snap_pts = dimension_snap_pts(dim);
let key_vertices: Vec<[f64; 3]> = geom
.dim_lines
.iter()
@ -1244,7 +1238,7 @@ fn tessellate_dimension_inner(
// DIMTFILL: 0=none, 1=drawing background (mask), 2=DIMTFILLCLR.
if let Some(s) = style {
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 {
WireModel::SELECTED
} else if s.dimtfill == 1 {
@ -1290,7 +1284,6 @@ fn tessellate_dimension_inner(
document,
selected_set,
active_viewport,
world_offset,
bg_color,
1.0,
&synth_text_entity,
@ -1308,7 +1301,6 @@ fn tessellate_dimension_inner(
document,
selected_set,
active_viewport,
world_offset,
bg_color,
1.0,
&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
/// or has no well-defined dim-line midpoint (radius/diameter handled by
/// 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 txt = base.text_middle_point;
if txt.x * txt.x + txt.y * txt.y + txt.z * txt.z <= 1e-16 {
return None;
}
let lv = |v| vec3_local(v, world_offset);
let lv = |v| vec3_local(v);
let anchor = match dim {
Dimension::Linear(d) => {
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,
style: Option<&DimStyle>,
text_height: f64,
world_offset: [f64; 3],
dim_scale: f64,
) -> Option<Vec<[f32; 3]>> {
let value = dimension_text_value(dim, style)?;
@ -1458,7 +1449,7 @@ fn text_fill_rect(
let (sr, cr) = rot.sin_cos();
let hx = approx_w * 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 cy = (pos.y - oy) as f32;
let cz = (pos.z - oz) as f32;
@ -1503,9 +1494,8 @@ fn dimension_geometry(
arrow2: &ArrowKind,
params: DimLineParams,
suppress: SuppressFlags,
world_offset: [f64; 3],
) -> DimGeom {
let lv = |v| vec3_local(v, world_offset);
let lv = |v| vec3_local(v);
let mut g = DimGeom::new();
match dim {
Dimension::Aligned(d) => {
@ -1547,7 +1537,7 @@ fn dimension_geometry(
Dimension::Radius(d) => {
let center = lv(d.angle_vertex);
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);
// Honour leader_length: extend from the arrow tip past it
// 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);
// DIMETER leader: continue past p2 toward the text.
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);
add_segment(
&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| {
glam::DVec3::new(
v.x - world_offset[0],
v.y - world_offset[1],
v.z - world_offset[2],
v.x,
v.y,
v.z,
)
};
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())
}
fn dimension_text_position(dim: &Dimension, world_offset: [f64; 3]) -> Vec3 {
let lv = |v| vec3_local(v, world_offset);
fn dimension_text_position(dim: &Dimension) -> Vec3 {
let lv = |v| vec3_local(v);
let base = dim.base();
let pos = lv(base.text_middle_point);
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 {
Vec3::new(
(v.x - off[0]) as f32,
(v.y - off[1]) as f32,
(v.z - off[2]) as f32,
)
fn vec3_local(v: Vector3) -> Vec3 {
Vec3::new(v.x as f32, v.y as f32, v.z as f32)
}
/// Style-driven text anchor on the dimension line: a point on the line through

View file

@ -344,14 +344,13 @@ impl Grippable for Hatch {
}
impl FallbackTess for Hatch {
fn fallback_geometry(&self, world_offset: [f64; 3]) -> FallbackGeometry {
let [ox, oy, oz] = world_offset;
fn fallback_geometry(&self) -> FallbackGeometry {
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 (wx, wy, wz) =
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.
let snap_at = |w: [f64; 3]| Vec3::new(w[0] as f32, w[1] as f32, w[2] as f32);

View file

@ -101,13 +101,11 @@ crate::impl_entity_basics!(Insert);
impl crate::entities::traits::FallbackTess for Insert {
fn fallback_geometry(
&self,
world_offset: [f64; 3],
) -> crate::scene::convert::tess_util::FallbackGeometry {
let [ox, oy, oz] = world_offset;
let (ipx, ipy, ipz) = (
self.insert_point.x - ox,
self.insert_point.y - oy,
self.insert_point.z - oz,
self.insert_point.x,
self.insert_point.y,
self.insert_point.z,
);
let ip = Vec3::new(ipx as f32, ipy as f32, ipz as f32);
let s = 0.1_f64;
@ -139,7 +137,6 @@ pub(crate) fn append_insert_attribute_wires(
is_xref: bool,
pslt_factor: f32,
anno_scale: f32,
world_offset: [f64; 3],
) {
if ins.attributes.is_empty() {
return;
@ -172,7 +169,7 @@ pub(crate) fn append_insert_attribute_wires(
} else {
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(
document,
insert_handle,
@ -182,7 +179,6 @@ pub(crate) fn append_insert_attribute_wires(
sub_plen * pslt_factor,
sub_pat.map(|v| v * pslt_factor),
sub_lw_px,
world_offset,
anno_scale,
None,
);

View file

@ -567,7 +567,6 @@ pub trait LeaderTess {
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
) -> crate::scene::model::wire_model::WireModel;
}
@ -580,7 +579,6 @@ impl LeaderTess for Leader {
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
) -> crate::scene::model::wire_model::WireModel {
use crate::scene::convert::tessellate::{append_arrow, arrow_from_block, ArrowKind, DimGeom};
@ -591,7 +589,7 @@ impl LeaderTess for Leader {
entity_color
};
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] {
[(v.x - ox) as f32, (v.y - oy) as f32, (v.z - oz) as f32]
};

View file

@ -1069,7 +1069,6 @@ pub trait MultiLeaderTess {
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
world_per_pixel: Option<f32>,
) -> Vec<crate::scene::model::wire_model::WireModel>;
@ -1083,7 +1082,6 @@ impl MultiLeaderTess for MultiLeader {
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
world_per_pixel: Option<f32>,
) -> Vec<crate::scene::model::wire_model::WireModel> {
@ -1129,7 +1127,7 @@ impl MultiLeaderTess for MultiLeader {
let name = handle.value().to_string();
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] {
[(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,
leader_lw_px,
world_offset,
1.0,
None,
);

View file

@ -182,16 +182,14 @@ crate::impl_entity_basics!(Ole2Frame);
impl crate::entities::traits::FallbackTess for Ole2Frame {
fn fallback_geometry(
&self,
world_offset: [f64; 3],
) -> crate::scene::convert::tess_util::FallbackGeometry {
// OLE objects carry a bounding rectangle in model space.
// Render a simple X-through-rectangle placeholder.
let [ox, oy, oz] = world_offset;
let x0 = self.upper_left_corner.x - ox;
let y0 = self.lower_right_corner.y - oy;
let x1 = self.lower_right_corner.x - ox;
let y1 = self.upper_left_corner.y - oy;
let z = self.upper_left_corner.z - oz;
let x0 = self.upper_left_corner.x;
let y0 = self.lower_right_corner.y;
let x1 = self.lower_right_corner.x;
let y1 = self.upper_left_corner.y;
let z = self.upper_left_corner.z;
if (x1 - x0).abs() < 1e-6 && (y1 - y0).abs() < 1e-6 {
// Degenerate / unknown size — show a small cross.
let s = 0.5_f64;

View file

@ -344,7 +344,6 @@ pub fn tessellate_table(
selected: bool,
entity_color: [f32; 4],
line_weight_px: f32,
world_offset: [f64; 3],
) -> Vec<crate::scene::model::wire_model::WireModel> {
use crate::scene::convert::tess_util::aci_to_rgba;
use crate::scene::model::wire_model::WireModel;
@ -355,7 +354,7 @@ pub fn tessellate_table(
return Vec::new();
}
let [ox, oy, oz] = world_offset;
let [ox, oy, oz] = [0.0_f64; 3];
let rel = |p: Vec3| -> [f32; 3] {
[
(p.x as f64 - ox) as f32,

View file

@ -1702,7 +1702,6 @@ pub(crate) fn text_obb_corners_native(
pub(crate) fn text_baseline_points(
e: &EntityType,
anno_scale: f32,
world_offset: [f64; 3],
n_lines: usize,
) -> Vec<[f32; 3]> {
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![];
}
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] {
[(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(
e: &EntityType,
anno_scale: f32,
world_offset: [f64; 3],
n_lines: usize,
) -> Vec<[f32; 3]> {
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![];
}
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] {
[(p[0] - ox) as f32, (p[1] - oy) as f32, (p[2] - oz) as f32]
};

View file

@ -12,11 +12,11 @@ pub trait TruckConvertible {
}
/// Fallback geometry for entities not routed through the truck topology
/// pipeline (Viewport, Insert, Hatch outline, Ole2Frame). Returns
/// world-offset-relative `f32` points + snap/key vertices the
/// dispatcher wraps into a `WireModel`.
/// pipeline (Viewport, Insert, Hatch outline, Ole2Frame). Returns absolute
/// WCS `f32` points + snap/key vertices the dispatcher wraps into a
/// `WireModel`.
pub trait FallbackTess {
fn fallback_geometry(&self, world_offset: [f64; 3]) -> FallbackGeometry;
fn fallback_geometry(&self) -> FallbackGeometry;
}
pub trait Grippable {

View file

@ -548,12 +548,10 @@ crate::impl_entity_basics!(Viewport);
impl crate::entities::traits::FallbackTess for Viewport {
fn fallback_geometry(
&self,
world_offset: [f64; 3],
) -> crate::scene::convert::tess_util::FallbackGeometry {
let [ox, oy, oz] = world_offset;
let cx = self.center.x - ox;
let cy = self.center.y - oy;
let cz = self.center.z - oz;
let cx = self.center.x;
let cy = self.center.y;
let cz = self.center.z;
let hw = self.width / 2.0;
let hh = self.height / 2.0;
let pts = vec![

View file

@ -423,7 +423,7 @@ fn build_nested_ref(
// its clip when the parent block is expanded — the spatial filter object
// isn't reachable at expand time.
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 {
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
// hot path in `tessellate_entity`.
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() {
return None;
@ -654,7 +654,6 @@ pub fn expand_insert(
ins_pat: [f32; 8],
ins_lw_px: f32,
selected: bool,
world_offset: [f64; 3],
pslt_factor: f32,
// World-space XY view AABB (with world_offset already subtracted, so the
// 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 mut batches = Batches::default();
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.local_offset` (f64) before transforming so the world AABB is
@ -717,7 +716,6 @@ pub fn expand_insert(
ins_pat,
ins_lw_px,
selected,
world_offset,
pslt_factor,
view_aabb,
world_per_pixel,
@ -744,7 +742,7 @@ fn emit_greeked_text(
ctx: &ExpandCtx,
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;
// Re-add the defn's `local_offset` in f64 before composing with
// `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 {
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 xf = |p: [f32; 3]| -> [f32; 3] {
let w = accum_xform.apply(Vector3::new(
@ -1001,7 +999,6 @@ struct ExpandCtx<'a> {
ins_pat: [f32; 8],
ins_lw_px: f32,
selected: bool,
world_offset: [f64; 3],
pslt_factor: f32,
// World-space XY view AABB (post world_offset). `None` = no culling.
view_aabb: Option<[f32; 4]>,
@ -1219,7 +1216,7 @@ fn expand_defn(
// `defn_lo` (in f64) before composing with `accum_xform`
// so culling uses correct world-space corners.
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 = [
world[0] - ox as f32,
world[1] - oy as f32,
@ -1282,7 +1279,7 @@ fn expand_defn(
nested_defn.local_offset,
&composed,
);
let [ox, oy, _] = ctx.world_offset;
let [ox, oy, _] = [0.0_f64; 3];
let local = [
world[0] - ox as f32,
world[1] - oy as f32,
@ -1322,7 +1319,6 @@ fn expand_defn(
ins_pat: nested_pat,
ins_lw_px: nested_lw_px,
selected: ctx.selected,
world_offset: ctx.world_offset,
pslt_factor: ctx.pslt_factor,
view_aabb: ctx.view_aabb,
world_per_pixel: ctx.world_per_pixel,
@ -1387,7 +1383,7 @@ fn emit_wire(
if lw.points.is_empty() && lw.fill_tris.is_empty() {
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;
// Resolve final style for this LocalWire against the outer Insert ctx
@ -1521,7 +1517,7 @@ fn emit_wire(
for tg in &lw.tangent_geoms {
entry
.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 {
let v = accum_xform.apply(Vector3::new(
@ -1540,9 +1536,8 @@ fn transform_tangent(
tg: &TangentGeom,
t: &Transform,
defn_lo: [f64; 3],
woff: [f64; 3],
) -> TangentGeom {
let [ox, oy, oz] = woff;
let [ox, oy, oz] = [0.0_f64; 3];
let [lo_x, lo_y, lo_z] = defn_lo;
match tg {
TangentGeom::Line { p1, p2 } => {

View file

@ -43,13 +43,12 @@ fn split_ds_xyz(x: f64, y: f64, z: f64) -> ([f32; 3], [f32; 3]) {
([xh, yh, zh], [xl, yl, zl])
}
/// Subtract `world_offset` from each f64 source point and split the residual
/// into double-single (high, low) f32 buffers in one pass.
fn offset_to_ds(
/// Split each absolute f64 source point into double-single (high, low) f32
/// buffers in one pass — the relative-to-eye residual the GPU/CPU reconstruct
/// to f64 precision at UTM-scale coordinates.
fn points_to_ds(
src: impl IntoIterator<Item = [f64; 3]>,
world_offset: [f64; 3],
) -> (Vec<[f32; 3]>, Vec<[f32; 3]>) {
let [ox, oy, oz] = world_offset;
let it = src.into_iter();
let (lo, hi) = it.size_hint();
let cap = hi.unwrap_or(lo);
@ -62,7 +61,7 @@ fn offset_to_ds(
low.push([0.0; 3]);
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);
low.push(l);
}
@ -85,7 +84,6 @@ pub fn tessellate(
pattern_length: f32,
pattern: [f32; 8],
line_weight_px: f32,
world_offset: [f64; 3],
anno_scale: f32,
world_per_pixel: Option<f32>,
) -> Vec<WireModel> {
@ -127,7 +125,6 @@ pub fn tessellate(
selected,
entity_color,
line_weight_px,
world_offset,
anno_scale,
)];
}
@ -148,7 +145,7 @@ pub fn tessellate(
// single MTEXT can hand back N colour-distinct wires when the
// value mixes inline colours.
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 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
.key_vertices
.into_iter()
@ -287,12 +284,12 @@ pub fn tessellate(
// ── Standard topology objects ─────────────────────────────────
TruckObject::Point(v) => {
let result = tessellate_vertex(&v, world_offset);
let result = tessellate_vertex(&v);
match result {
TruckTessResult::Point([x, y, z], [xl, yl, zl]) => {
let s = 0.1_f32;
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
let [ox, oy, oz] = world_offset;
let snap_pts = te.snap_pts;
let [ox, oy, oz] = [0.0_f64; 3];
let key_vertices: Vec<[f64; 3]> = te
.key_vertices
.into_iter()
@ -333,10 +330,10 @@ pub fn tessellate(
TruckObject::Curve(e) => {
if let TruckTessResult::Lines(points, points_low) =
tessellate_edge(&e, world_offset)
tessellate_edge(&e)
{
let [ox, oy, oz] = world_offset;
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
let [ox, oy, oz] = [0.0_f64; 3];
let snap_pts = te.snap_pts;
let key_vertices: Vec<[f64; 3]> = te
.key_vertices
.into_iter()
@ -366,10 +363,10 @@ pub fn tessellate(
TruckObject::Contour(w) => {
if let TruckTessResult::Lines(points, points_low) =
tessellate_wire(&w, world_offset)
tessellate_wire(&w)
{
let [ox, oy, oz] = world_offset;
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
let [ox, oy, oz] = [0.0_f64; 3];
let snap_pts = te.snap_pts;
let key_vertices: Vec<[f64; 3]> = te
.key_vertices
.into_iter()
@ -404,15 +401,15 @@ pub fn tessellate(
// GPU shader pairs them so drawings at large UTM-style
// coordinates keep sub-unit precision in the wire model and
// don't jitter on camera movement.
let [ox, oy, oz] = world_offset;
let (local_pts, local_pts_low) = offset_to_ds(points, world_offset);
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
let [ox, oy, oz] = [0.0_f64; 3];
let (local_pts, local_pts_low) = points_to_ds(points);
let snap_pts = te.snap_pts;
let key_vertices: Vec<[f64; 3]> = te
.key_vertices
.into_iter()
.map(|[x, y, z]| [x - ox, y - oy, z - oz])
.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 {
name,
points: local_pts,
@ -435,9 +432,9 @@ pub fn tessellate(
}
TruckObject::SegmentedLines(points) => {
let [ox, oy, oz] = world_offset;
let (local_pts, local_pts_low) = offset_to_ds(points, world_offset);
let snap_pts = offset_snap_pts(te.snap_pts, world_offset);
let [ox, oy, oz] = [0.0_f64; 3];
let (local_pts, local_pts_low) = points_to_ds(points);
let snap_pts = te.snap_pts;
let key_vertices: Vec<[f64; 3]> = te
.key_vertices
.into_iter()
@ -470,10 +467,10 @@ pub fn tessellate(
// edge wires stored in the entity when present (e.g. from
// SOLVIEW output or when the SAT kernel cannot parse the
// 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);
// 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) {
let sp = glam::DVec3::new(p.x - ox, p.y - oy, p.z - oz);
wm.snap_pts.push((sp, SnapHint::Insertion));
@ -485,7 +482,7 @@ pub fn tessellate(
// ── Fallback for Viewport / Insert / Hatch / Ole2Frame ────────────────
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
// high/low pair so the outline reconstructs to f64 precision at UTM scale
// (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::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 {
EntityType::Viewport(vp) => vp.fallback_geometry(world_offset),
EntityType::Insert(ins) => ins.fallback_geometry(world_offset),
EntityType::Hatch(h) => h.fallback_geometry(world_offset),
EntityType::Ole2Frame(ole) => ole.fallback_geometry(world_offset),
EntityType::Viewport(vp) => vp.fallback_geometry(),
EntityType::Insert(ins) => ins.fallback_geometry(),
EntityType::Hatch(h) => h.fallback_geometry(),
EntityType::Ole2Frame(ole) => ole.fallback_geometry(),
// Modeler solids render as meshes (solid3d_tess). Their wire path
// contributes only the pre-computed edge wires (empty for binary SAB)
// 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::Body(_)
| EntityType::Surface(_) => {
let pts = solid_wire_fallback(entity, world_offset);
let pts = solid_wire_fallback(entity);
let mut snap = vec![];
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((
Vec3::new((p.x - ox) as f32, (p.y - oy) as f32, (p.z - oz) as f32),
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
/// ACIS data. We use this as a visible fallback when the SAT tessellator
/// produces no mesh (e.g. binary SAB data or unsupported geometry).
fn solid_wire_fallback(entity: &EntityType, world_offset: [f64; 3]) -> Vec<[f64; 3]> {
let [ox, oy, oz] = world_offset;
fn solid_wire_fallback(entity: &EntityType) -> Vec<[f64; 3]> {
let [ox, oy, oz] = [0.0_f64; 3];
let Some(wires) = crate::entities::solid3d::fallback_wires(entity) else {
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]));
}
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).
/// 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),

View file

@ -94,11 +94,11 @@ pub enum TruckTessResult {
/// before truncating. This preserves sub-unit decimal precision even when the
/// raw world coordinates are in the millions (e.g. Turkish UTM).
#[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,
(y - off[1]) as f32,
(z - off[2]) as f32,
x as f32,
y 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
/// source even when the high half is quantized to half a metre at UTM scale.
#[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,
((y - off[1]) - hi[1] as f64) as f32,
((z - off[2]) - hi[2] as f64) as f32,
(x - hi[0] as f64) as f32,
(y - hi[1] as f64) as f32,
(z - hi[2] as f64) as f32,
]
}
// ── Vertex ────────────────────────────────────────────────────────────────
pub fn tessellate_vertex(v: &Vertex, offset: [f64; 3]) -> TruckTessResult {
pub fn tessellate_vertex(v: &Vertex) -> TruckTessResult {
let p = v.point();
let hi = to_local(p.x, p.y, p.z, offset);
let lo = to_local_low(p.x, p.y, p.z, offset, hi);
let hi = to_local(p.x, p.y, p.z);
let lo = to_local_low(p.x, p.y, p.z, hi);
TruckTessResult::Point(hi, lo)
}
// ── 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).
let curve = e.oriented_curve();
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 low: Vec<[f32; 3]> = Vec::with_capacity(pts.len());
for p in &pts {
let hi = to_local(p.x, p.y, p.z, offset);
let lo = to_local_low(p.x, p.y, p.z, offset, hi);
let hi = to_local(p.x, p.y, p.z);
let lo = to_local_low(p.x, p.y, p.z, hi);
high.push(hi);
low.push(lo);
}
@ -146,11 +146,11 @@ pub fn tessellate_edge(e: &Edge, offset: [f64; 3]) -> TruckTessResult {
// ── 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 low: Vec<[f32; 3]> = Vec::new();
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() {
high = eh;
low = el;
@ -169,14 +169,14 @@ pub fn tessellate_wire(w: &Wire, offset: [f64; 3]) -> TruckTessResult {
#[allow(dead_code)]
#[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);
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.
#[cfg(not(feature = "solid3d"))]
pub fn tessellate_shell(_s: &Shell, _offset: [f64; 3]) -> TruckTessResult {
pub fn tessellate_shell(_s: &Shell) -> TruckTessResult {
TruckTessResult::Mesh {
verts: Vec::new(),
verts_low: Vec::new(),
@ -189,15 +189,15 @@ pub fn tessellate_shell(_s: &Shell, _offset: [f64; 3]) -> TruckTessResult {
#[allow(dead_code)]
#[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);
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.
#[allow(dead_code)]
#[cfg(not(feature = "solid3d"))]
pub fn tessellate_solid(_s: &Solid, _offset: [f64; 3]) -> TruckTessResult {
pub fn tessellate_solid(_s: &Solid) -> TruckTessResult {
TruckTessResult::Mesh {
verts: Vec::new(),
verts_low: Vec::new(),
@ -209,13 +209,13 @@ pub fn tessellate_solid(_s: &Solid, _offset: [f64; 3]) -> TruckTessResult {
// ── Internal ─────────────────────────────────────────────────────────────
#[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 mut verts: 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() {
let hi = to_local(p.x, p.y, p.z, offset);
verts_low.push(to_local_low(p.x, p.y, p.z, offset, hi));
let hi = to_local(p.x, p.y, p.z);
verts_low.push(to_local_low(p.x, p.y, p.z, hi));
verts.push(hi);
}

View file

@ -196,17 +196,11 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
.par_iter()
.filter_map(|&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 color = view::render::adapt_to_bg(raw, LOAD_BG);
let model = match e {
EntityType::Hatch(dxf) => Scene::hatch_model_from_dxf(dxf, color, offset),
EntityType::Solid(solid) => Some(Scene::solid_hatch_model(solid, color, offset)),
EntityType::Hatch(dxf) => Scene::hatch_model_from_dxf(dxf, color),
EntityType::Solid(solid) => Some(Scene::solid_hatch_model(solid, color)),
_ => None,
};
model.map(|m| (handle, m))
@ -218,7 +212,7 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
.par_iter()
.filter_map(|&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 {
None
}
@ -251,7 +245,7 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
let color = view::render::adapt_to_bg(raw, LOAD_BG);
let top_level = layout_blocks.contains(&e.common().owner_handle);
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)
})
})
@ -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
/// geometry. Also recomputes `world_aabb` so per-frame LOD / cull math
/// uses the same space.
fn offset_mesh_lod_set(mut set: MeshLodSet, world_offset: [f64; 3]) -> MeshLodSet {
let [ox, oy, oz] = world_offset;
fn offset_mesh_lod_set(mut set: MeshLodSet) -> MeshLodSet {
let [ox, oy, oz] = [0.0_f64; 3];
let mut min_x = f32::INFINITY;
let mut min_y = f32::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(
set: &MeshLodSet,
xform: &acadrust::types::Transform,
world_offset: [f64; 3],
) -> MeshLodSet {
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 min_x = f32::INFINITY;
let mut min_y = f32::INFINITY;
@ -2318,7 +2311,6 @@ impl Scene {
if self.block_meshes.is_empty() {
return Vec::new();
}
let woff = [0.0_f64; 3];
let mut out = Vec::new();
for e in self.document.entities() {
if e.common().owner_handle != layout_block {
@ -2331,7 +2323,7 @@ impl Scene {
continue;
}
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
// hover / selection highlight (keyed on the mesh name) tints the
// block, not the inner solid's own handle which nothing selects.
@ -2353,7 +2345,6 @@ impl Scene {
block_name: &str,
accum: &acadrust::types::Transform,
depth: usize,
woff: [f64; 3],
out: &mut Vec<MeshLodSet>,
) {
if depth > 16 {
@ -2374,9 +2365,9 @@ impl Scene {
}
if let EntityType::Insert(ins) = e {
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) {
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).
pub fn insert_hatches_for_click(&self) -> Vec<(Handle, HatchModel)> {
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| {
self.document
.layers
@ -2464,7 +2450,7 @@ impl Scene {
continue;
}
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));
}
}
@ -2578,7 +2564,6 @@ impl Scene {
let mut block_owned: Vec<(Handle, crate::scene::model::mesh_model::MeshModel)> = Vec::new();
if !self.block_meshes.is_empty() {
let layout_block = self.current_layout_block_handle();
let woff = [0.0_f64; 3];
for e in self.document.entities() {
if e.common().owner_handle != layout_block {
continue;
@ -2588,7 +2573,7 @@ impl Scene {
continue;
}
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 {
if let Some(m) = set.lods.into_iter().next() {
block_owned.push((ins.common.handle, m));
@ -2621,7 +2606,6 @@ impl Scene {
return Vec::new();
}
let layout_block = self.current_layout_block_handle();
let woff = [0.0_f64; 3];
let mut out = Vec::new();
for e in self.document.entities() {
if e.common().owner_handle != layout_block {
@ -2632,7 +2616,7 @@ impl Scene {
continue;
}
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| {
set.lods.first().map_or(false, |m| {
!pick::hit_test::mesh_box_hit(
@ -2667,7 +2651,6 @@ impl Scene {
return Vec::new();
}
let layout_block = self.current_layout_block_handle();
let woff = [0.0_f64; 3];
let mut out = Vec::new();
for e in self.document.entities() {
if e.common().owner_handle != layout_block {
@ -2678,7 +2661,7 @@ impl Scene {
continue;
}
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| {
set.lods.first().map_or(false, |m| {
!pick::hit_test::mesh_poly_hit(
@ -2860,11 +2843,6 @@ impl Scene {
// `world_offset` subtraction even though `current_layout != "Model"`.
// Decide based on the block being tessellated, not the layout.
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" {
self.bg_color
} else {
@ -2918,9 +2896,6 @@ impl Scene {
}
}
mix(anno.to_bits() as u64);
for c in woff {
mix(c.to_bits());
}
for c in bg {
mix(c.to_bits() as u64);
}
@ -2952,7 +2927,7 @@ impl Scene {
.map(|e| {
let e: &EntityType = e;
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))
})
@ -2971,7 +2946,7 @@ impl Scene {
.into_par_iter()
.flat_map(|e| {
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()
@ -3167,7 +3142,6 @@ impl Scene {
&self.document,
&self.selected,
self.active_viewport,
[0.0_f64; 3],
bg,
anno,
e,
@ -4150,22 +4124,17 @@ impl Scene {
&entity,
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 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 {
let color = self.render_style(&entity).0;
Some(Self::solid_hatch_model(solid, color, hatch_offset))
Some(Self::solid_hatch_model(solid, color))
} else {
None
};
let image_seed = if let EntityType::RasterImage(img) = &entity {
ImageModel::from_raster_image(img, [0.0_f64; 3])
ImageModel::from_raster_image(img)
} else {
None
};
@ -4175,9 +4144,8 @@ impl Scene {
EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) | EntityType::Surface(_)
) {
let color = self.render_style(&entity).0;
let woff = [0.0_f64; 3];
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 {
None
};
@ -4442,11 +4410,6 @@ impl Scene {
fn synced_hatch_models(&self) -> Vec<HatchModel> {
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| {
self.document
@ -4543,7 +4506,7 @@ impl Scene {
// XCLIP: clip this insert's exploded hatch fills to the boundary,
// matching how the line geometry is clipped in expand_insert.
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
// one level, so nested INSERTs are re-exploded here. Each level
// 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;
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 {
let clipped = pick::xclip::clip_hatch_boundary(
@ -4596,7 +4559,7 @@ impl Scene {
}
// Wide LWPolyline and Polyline2D fills
let [ox, oy, _] = hatch_offset;
let [ox, oy, _] = [0.0_f64; 3];
let ox = ox as f32;
let oy = oy as f32;
for entity in self.document.entities() {
@ -4655,7 +4618,6 @@ impl Scene {
} else {
self.bg_color
};
let model_block = self.model_space_block_handle();
// No per-frame view-cull here: GPU wipeout buffer upload is
// gated on geometry_epoch only (see render.rs), so any cull at
// 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
// viewports still see model-block wipeouts at the right local
// coordinates (same rationale as hatches).
let world_offset = if wo.common.owner_handle == model_block {
[0.0_f64; 3]
} else {
[0.0; 3]
};
let boundary = Self::wipeout_boundary_2d(wo, world_offset);
let boundary = Self::wipeout_boundary_2d(wo);
if boundary.len() >= 3 {
let mut fill_color = bg_color;
if self.selected.contains(&wo.common.handle) {
@ -4712,11 +4669,10 @@ impl Scene {
/// Compute the 2D (XY) boundary polygon for a Wipeout entity.
fn wipeout_boundary_2d(
wo: &acadrust::entities::Wipeout,
world_offset: [f64; 3],
) -> Vec<[f32; 2]> {
use acadrust::entities::WipeoutClipType;
let [wox, woy, _woz] = world_offset;
let [wox, woy, _woz] = [0.0_f64; 3];
let is_polygon = wo.clipping_enabled
&& wo.clip_boundary_vertices.len() >= 3
&& matches!(wo.clip_type, WipeoutClipType::Polygonal);
@ -4780,9 +4736,8 @@ impl Scene {
fn hatch_model_from_dxf(
dxf: &DxfHatch,
color: [f32; 4],
world_offset: [f64; 3],
) -> 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);
// Build the boundary in f64 first so the precision-preserving
// origin computation below sees full WCS precision. We only cast
@ -5126,7 +5081,7 @@ impl Scene {
})
.collect();
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);
}
}
@ -5136,9 +5091,6 @@ impl Scene {
pub fn populate_hatches_from_document(&mut self) {
self.hatches.clear();
let model_block = self.model_space_block_handle();
let world_offset = [0.0_f64; 3];
let entries: Vec<(Handle, EntityType)> = self
.document
.entities()
@ -5154,21 +5106,14 @@ impl Scene {
.into_par_iter()
.filter_map(|(handle, kind)| {
// 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 {
EntityType::Hatch(dxf) => {
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) => {
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,
};
@ -5220,7 +5165,6 @@ impl Scene {
use crate::par::prelude::*;
let facet_res = self.document.header.facet_resolution;
let woff = [0.0_f64; 3];
// Top-level solids: offset into the render frame, drawn flat.
// Block-definition solids: keep block-local coords for per-INSERT
// instancing (no offset applied here).
@ -5228,7 +5172,7 @@ impl Scene {
.into_par_iter()
.filter_map(|(handle, entity, color, top_level)| {
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)
})
})
@ -5255,8 +5199,8 @@ impl Scene {
/// Build a solid-fill HatchModel for a DXF Solid entity.
/// DXF SOLID corners are in "Z-order": p0-p1 top, p2-p3 bottom.
/// Visual quad is p0→p1→p3→p2 (closed).
fn solid_hatch_model(solid: &DxfSolid, color: [f32; 4], world_offset: [f64; 3]) -> HatchModel {
let [ox, oy, _oz] = world_offset;
fn solid_hatch_model(solid: &DxfSolid, color: [f32; 4]) -> HatchModel {
let [ox, oy, _oz] = [0.0_f64; 3];
let boundary = vec![
[
(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
// offset back — otherwise the boundary wire, re-projected through the
// normal entity path, lands `world_offset` away from the fill.
let off = if self.current_layout == "Model" {
[0.0_f64; 3]
} else {
[0.0; 3]
};
let wx = model.world_origin[0] + off[0];
let wy = model.world_origin[1] + off[1];
let wx = model.world_origin[0];
let wy = model.world_origin[1];
let verts: Vec<Vector2> = model
.boundary
.iter()
@ -5840,11 +5779,6 @@ impl Scene {
// ── Modify (transform / copy) ─────────────────────────────────────────
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 /
// mtext / shape by the mirror but keeps the original rotation +
// oblique so the text stays right-reading. Capture before the
@ -5907,12 +5841,12 @@ impl Scene {
let existing_color = self.hatches[&h].color;
let new_model = match self.document.get_entity(h) {
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
// the moved corners so the fill follows the transform.
Some(EntityType::Solid(s)) => {
Some(Self::solid_hatch_model(s, existing_color, hatch_offset))
Some(Self::solid_hatch_model(s, existing_color))
}
_ => None,
};
@ -5990,11 +5924,6 @@ impl Scene {
}
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
.iter()
.filter_map(|&h| self.document.get_entity(h).cloned())
@ -6009,11 +5938,11 @@ impl Scene {
let new_model = match self.document.get_entity(h) {
Some(EntityType::Hatch(dxf)) => {
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)) => {
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,
};
@ -6073,15 +6002,10 @@ impl Scene {
}
// 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) {
Some(EntityType::Hatch(dxf)) => {
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);
} else {
self.hatches.remove(&handle);
@ -6090,7 +6014,7 @@ impl Scene {
Some(EntityType::Solid(solid)) => {
let color = convert::tess_util::aci_to_rgba(&solid.common.color);
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,
model_space: 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(
view.direction,
view.target,
@ -6214,7 +6138,6 @@ impl Scene {
},
view.height,
view.twist_angle,
offset,
) else {
return false;
};
@ -6280,7 +6203,6 @@ impl Scene {
// Subtracted from `view_target` to reach wire-space. Model views pass
// `[0.0_f64; 3]`; paper-space views (whose entities carry no
// offset) pass `[0; 3]`.
world_offset: [f64; 3],
) -> Option<Camera> {
if view_height.abs() < 1e-9 {
return None;
@ -6317,9 +6239,9 @@ impl Scene {
// jump on the f32 grid. The axis directions stay f32 (orientation only);
// only the position must stay precise — matching the model camera.
let base = glam::DVec3::new(
view_target.x - world_offset[0],
view_target.y - world_offset[1],
view_target.z - world_offset[2],
view_target.x,
view_target.y,
view_target.z,
);
let target = base
+ view_right.as_dvec3() * view_center.x
@ -6345,7 +6267,6 @@ impl Scene {
vp.view_center,
vp.view_height,
vp.view_twist,
[0.0_f64; 3],
)
}
@ -6607,7 +6528,6 @@ impl Scene {
},
vp.view_height,
vp.twist_angle,
[0.0; 3],
) else {
return false;
};
@ -7646,7 +7566,7 @@ impl Scene {
continue;
}
// 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 {
continue;
}
@ -7719,7 +7639,6 @@ impl Scene {
},
saved_h,
vp.twist_angle,
[0.0_f64; 3],
) {
let half_h = saved_h * 0.5;
let half_w = half_h * aspect_d;
@ -7746,7 +7665,6 @@ impl Scene {
acadrust::types::Vector2::ZERO,
fit_h,
vp.twist_angle,
[0.0_f64; 3],
)
}
@ -8031,7 +7949,6 @@ pub(crate) fn tessellate_entity_dim_text(
document: &acadrust::CadDocument,
selected: &HashSet<Handle>,
active_viewport: Option<Handle>,
world_offset: [f64; 3],
bg_color: [f32; 4],
anno_scale: f32,
e: &EntityType,
@ -8040,7 +7957,7 @@ pub(crate) fn tessellate_entity_dim_text(
text_color: [f32; 4],
) -> Vec<WireModel> {
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,
);
for w in &mut wires {
@ -8059,7 +7976,6 @@ fn tessellate_entity(
document: &acadrust::CadDocument,
selected: &HashSet<Handle>,
active_viewport: Option<Handle>,
world_offset: [f64; 3],
bg_color: [f32; 4],
anno_scale: f32,
e: &EntityType,
@ -8082,7 +7998,7 @@ fn tessellate_entity(
match e {
EntityType::Viewport(_) | EntityType::Insert(_) => {}
_ => {
let ab = entity_aabb(e, world_offset);
let ab = entity_aabb(e);
if ab != WireModel::UNBOUNDED_AABB {
if let Some(view) = view_aabb {
if cache::block_cache::aabb_disjoint_xy(ab, view) {
@ -8129,7 +8045,7 @@ fn tessellate_entity(
// and the geometry visibly shifts when
// the camera crosses the LOD threshold.
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_max = (bbox.max.z - oz) as f32;
return vec![lod_stub_wire_3d(
@ -8189,11 +8105,10 @@ fn tessellate_entity(
pattern_length,
pattern,
1.5,
world_offset,
1.0,
world_per_pixel,
);
let ab = entity_aabb(e, world_offset);
let ab = entity_aabb(e);
for w in &mut wires {
w.aabb = ab;
}
@ -8241,7 +8156,7 @@ fn tessellate_entity(
let sub_color_is_byblock =
sub.common().color == acadrust::types::Color::ByBlock;
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 —
// don't let downstream paths re-apply anno_scale.
1.0, sub, block_cache, view_aabb, world_per_pixel,
@ -8260,7 +8175,7 @@ fn tessellate_entity(
}
}
if !wires.is_empty() {
let aabb = entity_aabb(e, world_offset);
let aabb = entity_aabb(e);
for w in &mut wires {
w.aabb = aabb;
}
@ -8273,7 +8188,7 @@ fn tessellate_entity(
}
if let EntityType::Dimension(dim) = e {
let aabb = entity_aabb(e, world_offset);
let aabb = entity_aabb(e);
use crate::entities::dimension::DimensionTess;
let mut wires = dim.tessellate(
document,
@ -8281,7 +8196,6 @@ fn tessellate_entity(
sel,
entity_color,
line_weight_px,
world_offset,
anno_scale,
selected,
active_viewport,
@ -8297,7 +8211,7 @@ fn tessellate_entity(
}
if let EntityType::MultiLeader(ml) = e {
let aabb = entity_aabb(e, world_offset);
let aabb = entity_aabb(e);
use crate::entities::multileader::MultiLeaderTess;
let mut wires = ml.tessellate(
document,
@ -8305,7 +8219,6 @@ fn tessellate_entity(
sel,
entity_color,
line_weight_px,
world_offset,
anno_scale,
world_per_pixel,
);
@ -8340,7 +8253,7 @@ fn tessellate_entity(
let sub_color_is_byblock =
sub.common().color == acadrust::types::Color::ByBlock;
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,
);
for mut w in sub_wires {
@ -8353,7 +8266,7 @@ fn tessellate_entity(
}
}
if !wires.is_empty() {
let aabb = entity_aabb(e, world_offset);
let aabb = entity_aabb(e);
for w in &mut wires {
w.aabb = aabb;
}
@ -8366,10 +8279,10 @@ fn tessellate_entity(
// geometry from the rows + TableStyle so fills/colours/borders/margins
// are honoured instead of the monochrome fallback.
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() {
let aabb = entity_aabb(e, world_offset);
let aabb = entity_aabb(e);
for w in &mut wires {
w.aci = aci;
w.aabb = aabb;
@ -8382,7 +8295,7 @@ fn tessellate_entity(
// 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 = 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(
(ins.insert_point.x - ox) as f32,
(ins.insert_point.y - oy) as f32,
@ -8425,7 +8338,6 @@ fn tessellate_entity(
ins_pat,
ins_lw_px,
sel,
world_offset,
pslt_factor,
view_aabb,
world_per_pixel,
@ -8436,7 +8348,7 @@ fn tessellate_entity(
// clip the expanded block geometry to the boundary polygon so
// only the portion inside the clip is drawn.
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);
}
@ -8459,7 +8371,6 @@ fn tessellate_entity(
is_xref,
pslt_factor,
anno_scale,
world_offset,
);
wires.push(marker);
return wires;
@ -8494,7 +8405,7 @@ fn tessellate_entity(
} else {
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 = sub_pattern.map(|v| v * pslt_factor);
let mut wires = convert::tessellate::tessellate(
@ -8506,7 +8417,6 @@ fn tessellate_entity(
sub_pattern_length,
sub_pattern,
sub_line_weight_px,
world_offset,
anno_scale,
world_per_pixel,
);
@ -8532,13 +8442,12 @@ fn tessellate_entity(
is_xref,
pslt_factor,
anno_scale,
world_offset,
);
wires.push(marker);
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
// pixels (anno-scaled):
@ -8575,7 +8484,7 @@ fn tessellate_entity(
_ => 1,
};
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 {
return vec![];
}
@ -8622,7 +8531,7 @@ fn tessellate_entity(
}];
}
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() {
// Text greek fallback: also 2-D, keep stub at z=0.
return vec![lod_stub_wire(
@ -8672,7 +8581,6 @@ fn tessellate_entity(
pattern_length,
pattern,
line_weight_px,
world_offset,
anno_scale,
world_per_pixel,
);
@ -8836,9 +8744,9 @@ fn lod_stub_wire_3d(
/// INSERT only stamps the geometry once, attribute text sits at the world
/// position recorded on each ATTRIB. See #20.
#[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 [ox, oy, _] = world_offset;
let [ox, oy, _] = [0.0_f64; 3];
let min_x = (bbox.min.x - ox) as f32;
let min_y = (bbox.min.y - oy) as f32;
let max_x = (bbox.max.x - ox) as f32;

View file

@ -41,7 +41,6 @@ impl ImageModel {
/// Returns `None` if the image file cannot be opened or decoded.
pub fn from_raster_image(
img: &acadrust::entities::RasterImage,
world_offset: [f64; 3],
) -> Option<Self> {
let w = img.size.x;
let h = img.size.y;
@ -50,9 +49,9 @@ impl ImageModel {
// Corners come from a large insertion point plus small u/v spans.
// Split each into double-single (high, low) f32 so the GPU keeps
// sub-unit precision at UTM scale and after a cross-drawing paste.
let oxv = img.insertion_point.x - world_offset[0];
let oyv = img.insertion_point.y - world_offset[1];
let ozv = img.insertion_point.z - world_offset[2];
let oxv = img.insertion_point.x;
let oyv = img.insertion_point.y;
let ozv = img.insertion_point.z;
let ux = (img.u_vector.x * w) as f32;
let uy = (img.u_vector.y * w) as f32;
let uz = (img.u_vector.z * w) as f32;

View file

@ -105,7 +105,7 @@ pub fn edge_wires(solid: &Solid) -> Vec<acadrust::entities::Wire> {
for shell in solid.boundaries() {
for edge in shell.edge_iter() {
if let TruckTessResult::Lines(pts, pts_low) =
tessellate_edge(&edge, [0.0; 3])
tessellate_edge(&edge)
{
if pts.len() < 2 {
continue;
@ -169,7 +169,7 @@ pub fn boolean(_op: Bool, _a: &Solid, _b: &Solid) -> Option<Solid> {
/// before world_offset is applied by the caller).
pub fn mesh_from_solid(solid: &Solid, color: [f32; 4]) -> Option<MeshLodSet> {
use crate::scene::convert::truck_tess::{tessellate_solid, TruckTessResult};
match tessellate_solid(solid, [0.0; 3]) {
match tessellate_solid(solid) {
TruckTessResult::Mesh {
verts,
verts_low,

View file

@ -65,9 +65,8 @@ fn dict_entry(doc: &CadDocument, dict: Handle, key: &str) -> Option<Handle> {
pub fn world_clip_polygon(
sf: &SpatialFilter,
ins: &Insert,
world_offset: [f64; 3],
) -> Vec<[f32; 2]> {
world_clip_polygon_f64(sf, ins, world_offset)
world_clip_polygon_f64(sf, ins)
.into_iter()
.map(|[x, y]| [x as f32, y as f32])
.collect()
@ -80,11 +79,10 @@ pub fn world_clip_polygon(
pub fn world_clip_polygon_f64(
sf: &SpatialFilter,
ins: &Insert,
world_offset: [f64; 3],
) -> Vec<[f64; 2]> {
let xform = ins.get_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 a = sf.boundary_points[0];
let b = sf.boundary_points[1];

View file

@ -162,10 +162,6 @@ impl Snapper {
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) {
if !self.enabled.remove(&t) {
self.enabled.insert(t);