fix: apply world_offset to hatch, solid, and wipeout boundary coordinates
hatch_model_from_dxf(), solid_hatch_model(), and wipeout_boundary_2d() were converting DXF world-space coordinates directly to f32 without subtracting world_offset. After the world_offset change moved all wire geometry to local space, hatches/solids/wipeouts rendered at the wrong position (displaced by the centroid offset, up to ~4M m for Turkish UTM). All three functions now accept world_offset and apply it to every boundary vertex before the f64→f32 cast. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e191315713
commit
5f69d8c3f0
1 changed files with 35 additions and 32 deletions
|
|
@ -1235,10 +1235,10 @@ impl Scene {
|
||||||
pub fn add_entity(&mut self, mut entity: EntityType) -> Handle {
|
pub fn add_entity(&mut self, mut entity: EntityType) -> Handle {
|
||||||
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)
|
Self::hatch_model_from_dxf(dxf, color, self.world_offset)
|
||||||
} 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))
|
Some(Self::solid_hatch_model(solid, color, self.world_offset))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
@ -1473,7 +1473,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(mut model) = Self::hatch_model_from_dxf(&dxf, color) {
|
if let Some(mut model) = Self::hatch_model_from_dxf(&dxf, color, self.world_offset) {
|
||||||
if selected {
|
if selected {
|
||||||
model.color = [0.15, 0.55, 1.00, model.color[3]];
|
model.color = [0.15, 0.55, 1.00, model.color[3]];
|
||||||
}
|
}
|
||||||
|
|
@ -1537,7 +1537,7 @@ impl Scene {
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let boundary = Self::wipeout_boundary_2d(wo);
|
let boundary = Self::wipeout_boundary_2d(wo, self.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) {
|
||||||
|
|
@ -1557,16 +1557,17 @@ 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(wo: &acadrust::entities::Wipeout) -> Vec<[f32; 2]> {
|
fn wipeout_boundary_2d(wo: &acadrust::entities::Wipeout, world_offset: [f64; 3]) -> Vec<[f32; 2]> {
|
||||||
use acadrust::entities::WipeoutClipType;
|
use acadrust::entities::WipeoutClipType;
|
||||||
|
|
||||||
|
let [wox, woy, _woz] = world_offset;
|
||||||
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);
|
||||||
|
|
||||||
if is_polygon {
|
if is_polygon {
|
||||||
let ox = wo.insertion_point.x as f32;
|
let ox = (wo.insertion_point.x - wox) as f32;
|
||||||
let oy = wo.insertion_point.y as f32;
|
let oy = (wo.insertion_point.y - woy) as f32;
|
||||||
wo.clip_boundary_vertices.iter().map(|v| {
|
wo.clip_boundary_vertices.iter().map(|v| {
|
||||||
let wx = (wo.u_vector.x * v.x * wo.size.x + wo.v_vector.x * v.y * wo.size.y) as f32;
|
let wx = (wo.u_vector.x * v.x * wo.size.x + wo.v_vector.x * v.y * wo.size.y) as f32;
|
||||||
let wy = (wo.u_vector.y * v.x * wo.size.x + wo.v_vector.y * v.y * wo.size.y) as f32;
|
let wy = (wo.u_vector.y * v.x * wo.size.x + wo.v_vector.y * v.y * wo.size.y) as f32;
|
||||||
|
|
@ -1574,8 +1575,8 @@ impl Scene {
|
||||||
}).collect()
|
}).collect()
|
||||||
} else {
|
} else {
|
||||||
// Rectangular boundary from 4 corners.
|
// Rectangular boundary from 4 corners.
|
||||||
let ox = wo.insertion_point.x as f32;
|
let ox = (wo.insertion_point.x - wox) as f32;
|
||||||
let oy = wo.insertion_point.y as f32;
|
let oy = (wo.insertion_point.y - woy) as f32;
|
||||||
let oz = wo.insertion_point.z as f32;
|
let oz = wo.insertion_point.z as f32;
|
||||||
let ux = (wo.u_vector.x * wo.size.x) as f32;
|
let ux = (wo.u_vector.x * wo.size.x) as f32;
|
||||||
let uy = (wo.u_vector.y * wo.size.x) as f32;
|
let uy = (wo.u_vector.y * wo.size.x) as f32;
|
||||||
|
|
@ -1591,7 +1592,8 @@ impl Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hatch_model_from_dxf(dxf: &DxfHatch, color: [f32; 4]) -> Option<HatchModel> {
|
fn hatch_model_from_dxf(dxf: &DxfHatch, color: [f32; 4], world_offset: [f64; 3]) -> Option<HatchModel> {
|
||||||
|
let [ox, oy, _oz] = world_offset;
|
||||||
let path = dxf
|
let path = dxf
|
||||||
.paths
|
.paths
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -1615,10 +1617,10 @@ impl Scene {
|
||||||
let v1 = &verts[(i + 1) % count];
|
let v1 = &verts[(i + 1) % count];
|
||||||
let bulge = v0.z;
|
let bulge = v0.z;
|
||||||
if bulge.abs() < 1e-9 {
|
if bulge.abs() < 1e-9 {
|
||||||
boundary.push([v0.x as f32, v0.y as f32]);
|
boundary.push([(v0.x - ox) as f32, (v0.y - oy) as f32]);
|
||||||
} else {
|
} else {
|
||||||
let p0 = [v0.x as f32, v0.y as f32];
|
let p0 = [(v0.x - ox) as f32, (v0.y - oy) as f32];
|
||||||
let p1 = [v1.x as f32, v1.y as f32];
|
let p1 = [(v1.x - ox) as f32, (v1.y - oy) as f32];
|
||||||
let angle = 4.0 * (bulge as f32).atan();
|
let angle = 4.0 * (bulge as f32).atan();
|
||||||
let dx = p1[0] - p0[0];
|
let dx = p1[0] - p0[0];
|
||||||
let dy = p1[1] - p0[1];
|
let dy = p1[1] - p0[1];
|
||||||
|
|
@ -1656,12 +1658,12 @@ impl Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundaryEdge::Line(line) => {
|
BoundaryEdge::Line(line) => {
|
||||||
boundary.push([line.start.x as f32, line.start.y as f32]);
|
boundary.push([(line.start.x - ox) as f32, (line.start.y - oy) as f32]);
|
||||||
boundary.push([line.end.x as f32, line.end.y as f32]);
|
boundary.push([(line.end.x - ox) as f32, (line.end.y - oy) as f32]);
|
||||||
}
|
}
|
||||||
BoundaryEdge::CircularArc(arc) => {
|
BoundaryEdge::CircularArc(arc) => {
|
||||||
let cx = arc.center.x as f32;
|
let cx = (arc.center.x - ox) as f32;
|
||||||
let cy = arc.center.y as f32;
|
let cy = (arc.center.y - oy) as f32;
|
||||||
let r = arc.radius as f32;
|
let r = arc.radius as f32;
|
||||||
let (sa, ea) = if arc.counter_clockwise {
|
let (sa, ea) = if arc.counter_clockwise {
|
||||||
(arc.start_angle as f32, arc.end_angle as f32)
|
(arc.start_angle as f32, arc.end_angle as f32)
|
||||||
|
|
@ -1680,8 +1682,8 @@ impl Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundaryEdge::EllipticArc(ell) => {
|
BoundaryEdge::EllipticArc(ell) => {
|
||||||
let cx = ell.center.x as f32;
|
let cx = (ell.center.x - ox) as f32;
|
||||||
let cy = ell.center.y as f32;
|
let cy = (ell.center.y - oy) as f32;
|
||||||
let maj_x = ell.major_axis_endpoint.x as f32;
|
let maj_x = ell.major_axis_endpoint.x as f32;
|
||||||
let maj_y = ell.major_axis_endpoint.y as f32;
|
let maj_y = ell.major_axis_endpoint.y as f32;
|
||||||
let r_maj = (maj_x * maj_x + maj_y * maj_y).sqrt();
|
let r_maj = (maj_x * maj_x + maj_y * maj_y).sqrt();
|
||||||
|
|
@ -1733,11 +1735,11 @@ impl Scene {
|
||||||
for i in 0..=segs {
|
for i in 0..=segs {
|
||||||
let t = t0 + (t1 - t0) * (i as f64 / segs as f64);
|
let t = t0 + (t1 - t0) * (i as f64 / segs as f64);
|
||||||
let p = bspl.subs(t);
|
let p = bspl.subs(t);
|
||||||
boundary.push([p.x as f32, p.y as f32]);
|
boundary.push([(p.x - ox) as f32, (p.y - oy) as f32]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for cp in &spline.control_points {
|
for cp in &spline.control_points {
|
||||||
boundary.push([cp.x as f32, cp.y as f32]);
|
boundary.push([(cp.x - ox) as f32, (cp.y - oy) as f32]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1834,11 +1836,11 @@ impl Scene {
|
||||||
let model = match &kind {
|
let model = match &kind {
|
||||||
EntityType::Hatch(dxf) => {
|
EntityType::Hatch(dxf) => {
|
||||||
let color = tessellate::aci_to_rgba(&dxf.common.color);
|
let color = tessellate::aci_to_rgba(&dxf.common.color);
|
||||||
Self::hatch_model_from_dxf(dxf, color)
|
Self::hatch_model_from_dxf(dxf, color, self.world_offset)
|
||||||
}
|
}
|
||||||
EntityType::Solid(solid) => {
|
EntityType::Solid(solid) => {
|
||||||
let color = tessellate::aci_to_rgba(&solid.common.color);
|
let color = tessellate::aci_to_rgba(&solid.common.color);
|
||||||
Some(Self::solid_hatch_model(solid, color))
|
Some(Self::solid_hatch_model(solid, color, self.world_offset))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
@ -1896,12 +1898,13 @@ 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]) -> HatchModel {
|
fn solid_hatch_model(solid: &DxfSolid, color: [f32; 4], world_offset: [f64; 3]) -> HatchModel {
|
||||||
|
let [ox, oy, _oz] = world_offset;
|
||||||
let boundary = vec![
|
let boundary = vec![
|
||||||
[solid.first_corner.x as f32, solid.first_corner.y as f32],
|
[(solid.first_corner.x - ox) as f32, (solid.first_corner.y - oy) as f32],
|
||||||
[solid.second_corner.x as f32, solid.second_corner.y as f32],
|
[(solid.second_corner.x - ox) as f32, (solid.second_corner.y - oy) as f32],
|
||||||
[solid.fourth_corner.x as f32, solid.fourth_corner.y as f32],
|
[(solid.fourth_corner.x - ox) as f32, (solid.fourth_corner.y - oy) as f32],
|
||||||
[solid.third_corner.x as f32, solid.third_corner.y as f32],
|
[(solid.third_corner.x - ox) as f32, (solid.third_corner.y - oy) as f32],
|
||||||
];
|
];
|
||||||
HatchModel {
|
HatchModel {
|
||||||
boundary,
|
boundary,
|
||||||
|
|
@ -2161,7 +2164,7 @@ impl Scene {
|
||||||
if self.hatches.contains_key(&h) {
|
if self.hatches.contains_key(&h) {
|
||||||
let existing_color = self.hatches[&h].color;
|
let existing_color = self.hatches[&h].color;
|
||||||
let new_model = if let Some(EntityType::Hatch(dxf)) = self.document.get_entity(h) {
|
let new_model = if let Some(EntityType::Hatch(dxf)) = self.document.get_entity(h) {
|
||||||
Self::hatch_model_from_dxf(dxf, existing_color)
|
Self::hatch_model_from_dxf(dxf, existing_color, self.world_offset)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
@ -2186,7 +2189,7 @@ impl Scene {
|
||||||
if !h.is_null() {
|
if !h.is_null() {
|
||||||
let new_model = if let Some(EntityType::Hatch(dxf)) = self.document.get_entity(h) {
|
let new_model = if let Some(EntityType::Hatch(dxf)) = self.document.get_entity(h) {
|
||||||
let color = tessellate::aci_to_rgba(&dxf.common.color);
|
let color = tessellate::aci_to_rgba(&dxf.common.color);
|
||||||
Self::hatch_model_from_dxf(dxf, color)
|
Self::hatch_model_from_dxf(dxf, color, self.world_offset)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
@ -2210,7 +2213,7 @@ impl Scene {
|
||||||
match self.document.get_entity(handle) {
|
match self.document.get_entity(handle) {
|
||||||
Some(EntityType::Hatch(dxf)) => {
|
Some(EntityType::Hatch(dxf)) => {
|
||||||
let color = tessellate::aci_to_rgba(&dxf.common.color);
|
let color = tessellate::aci_to_rgba(&dxf.common.color);
|
||||||
if let Some(model) = Self::hatch_model_from_dxf(dxf, color) {
|
if let Some(model) = Self::hatch_model_from_dxf(dxf, color, self.world_offset) {
|
||||||
self.hatches.insert(handle, model);
|
self.hatches.insert(handle, model);
|
||||||
} else {
|
} else {
|
||||||
self.hatches.remove(&handle);
|
self.hatches.remove(&handle);
|
||||||
|
|
@ -2218,7 +2221,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
Some(EntityType::Solid(solid)) => {
|
Some(EntityType::Solid(solid)) => {
|
||||||
let color = tessellate::aci_to_rgba(&solid.common.color);
|
let color = tessellate::aci_to_rgba(&solid.common.color);
|
||||||
self.hatches.insert(handle, Self::solid_hatch_model(solid, color));
|
self.hatches.insert(handle, Self::solid_hatch_model(solid, color, self.world_offset));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue