forked from 1b-agent/opencadstudio-upstream
Merge branch 'main' into feature/parametric-constraint-system
Brings in 54 commits from origin/main: a selection-performance overhaul, surface thickening, GPU-native wide/tapered stroke rendering, continued ocs_doc_api evolution, and assorted fixes/polish (block double-click editing, DWG hatch/database repair, clipboard, collapsible Properties sections). Six real conflicts, all where this branch had independently re-applied a fix upstream later revised or already carried natively: - src/app/automation.rs, src/app/command_driver.rs: combined both sides — kept this branch's sketch-constraint/named-parameter loading on "new"/"open", adopted main's Scene::clear()/material_base_dir and its newer rebuild_derived_caches() over the older bump_geometry(). Scene::clear() (src/scene/entity.rs) now also resets sketch_constraints/named_parameters, so every caller gets this for free instead of each call site repeating it. - src/io/mod.rs, src/scene/render_graph.rs: adopted main's design outright (commit973af87d, authored by Hakan directly) — a large MINSERT is no longer purged as "corrupt" at load, only its rendering is bounded, preserving the source data. This branch's own earlier design (reject at load) predates that revision. - src/scene/pipeline/mesh_gpu.rs: adopted main's valid_rgba_size() guard (a real robustness improvement over this branch's version). - src/snap.rs: replaced wholesale with main's version — this branch's copy was an explicit verbatim snapshot from an earlier upstream PR (commit4c264b8c) with zero constraint-system-specific content, and main has since evolved it considerably further. Also removed two now-dead duplicates the merge surfaced without a conflict marker (both branches had independently fixed the same things): the OPTIONS/OP command dispatch/autocomplete entries, and automation.rs's open_finalizes_and_purges_like_the_ui_open_path test (kept main's version, which covers strictly more: solid_models/ material_base_dir reset on "new"). Full workspace suite passes (812 lib tests + this branch's own 24 constraint/persistence integration tests) except the one pre-existing, unrelated font-test failure already present on main. Zero clippy findings in the hand-written merge resolution itself; the ~1,171 warnings clippy reports are pre-existing in the 54 absorbed commits, not introduced here. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
commit
d675244fb8
89 files changed
+5700
-1101
No files matched your search
+443
-52
@@ -3,6 +3,7 @@ use acadrust::entities::{
|
||||
PointCloudData, PointCloudExData, RemoteTextData, SectionObjectData,
|
||||
};
|
||||
use acadrust::types::{Handle, Transform, Vector3};
|
||||
use acadrust::xdata::{ExtendedDataRecord, XDataValue};
|
||||
use crate::t;
|
||||
|
||||
use crate::command::EntityTransform;
|
||||
@@ -17,6 +18,69 @@ use crate::scene::model::object::{
|
||||
use crate::scene::model::wire_model::SnapHint;
|
||||
|
||||
const NAN: [f64; 3] = [f64::NAN; 3];
|
||||
const SECTION_SLICE_APP: &str = "IsSlice";
|
||||
const SECTION_THICKNESS_APP: &str = "ThicknessDepth";
|
||||
|
||||
pub(crate) fn section_is_slice(entity: &ExtendedEntity) -> bool {
|
||||
entity
|
||||
.common
|
||||
.extended_data
|
||||
.get_record(SECTION_SLICE_APP)
|
||||
.is_some_and(|record| {
|
||||
record
|
||||
.values
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|value| match value {
|
||||
XDataValue::Integer16(value) => Some(*value != 0),
|
||||
XDataValue::Integer32(value) => Some(*value != 0),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn section_slice_depth(entity: &ExtendedEntity) -> Option<f64> {
|
||||
entity
|
||||
.common
|
||||
.extended_data
|
||||
.get_record(SECTION_THICKNESS_APP)?
|
||||
.values
|
||||
.iter()
|
||||
.find_map(|value| match value {
|
||||
XDataValue::Real(value) | XDataValue::Distance(value) => Some(*value),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|value| value.is_finite())
|
||||
.map(f64::abs)
|
||||
}
|
||||
|
||||
pub(crate) fn set_section_slice_metadata(
|
||||
entity: &mut ExtendedEntity,
|
||||
enabled: bool,
|
||||
depth: f64,
|
||||
) {
|
||||
if !enabled {
|
||||
entity.common.extended_data.remove_record(SECTION_SLICE_APP);
|
||||
entity
|
||||
.common
|
||||
.extended_data
|
||||
.remove_record(SECTION_THICKNESS_APP);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut slice = ExtendedDataRecord::new(SECTION_SLICE_APP);
|
||||
slice.values = vec![XDataValue::Integer16(0), XDataValue::Integer16(1)];
|
||||
entity.common.extended_data.upsert_record(slice);
|
||||
|
||||
let mut thickness = ExtendedDataRecord::new(SECTION_THICKNESS_APP);
|
||||
thickness.values = vec![XDataValue::Real(if depth.is_finite() {
|
||||
depth.abs()
|
||||
} else {
|
||||
0.0
|
||||
})];
|
||||
entity.common.extended_data.upsert_record(thickness);
|
||||
}
|
||||
|
||||
fn vector_text(value: Vector3) -> String {
|
||||
format!("{:.6}, {:.6}, {:.6}", value.x, value.y, value.z)
|
||||
@@ -46,6 +110,22 @@ fn bool_prop(label: &str, field: &'static str, value: bool) -> Property {
|
||||
}
|
||||
}
|
||||
|
||||
fn choice_prop(
|
||||
label: &str,
|
||||
field: &'static str,
|
||||
selected: &str,
|
||||
options: &[&str],
|
||||
) -> Property {
|
||||
Property {
|
||||
label: label.into(),
|
||||
field,
|
||||
value: PropValue::Choice {
|
||||
selected: selected.to_string(),
|
||||
options: options.iter().map(|option| (*option).to_string()).collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn push_segment(points: &mut Vec<[f64; 3]>, first: [f64; 3], second: [f64; 3]) {
|
||||
if !points.is_empty() {
|
||||
points.push(NAN);
|
||||
@@ -211,14 +291,73 @@ fn append_arc_aligned_text(points: &mut Vec<[f64; 3]>, data: &ArcAlignedTextData
|
||||
|
||||
fn section_lines(data: &SectionObjectData) -> Vec<[f64; 3]> {
|
||||
let mut points = Vec::new();
|
||||
let vertical = normalized(data.vertical_direction, Vector3::UNIT_Z);
|
||||
let offset = |point: &Vector3, distance: f64| {
|
||||
[
|
||||
point.x + vertical.x * distance,
|
||||
point.y + vertical.y * distance,
|
||||
point.z + vertical.z * distance,
|
||||
]
|
||||
};
|
||||
push_chain(
|
||||
&mut points,
|
||||
data.vertices.iter().map(|p| [p.x, p.y, p.z]),
|
||||
);
|
||||
push_chain(
|
||||
&mut points,
|
||||
data.vertices.iter().map(|point| offset(point, data.top_height)),
|
||||
);
|
||||
push_chain(
|
||||
&mut points,
|
||||
data.vertices.iter().map(|point| offset(point, -data.bottom_height)),
|
||||
);
|
||||
for point in &data.vertices {
|
||||
push_segment(
|
||||
&mut points,
|
||||
offset(point, -data.bottom_height),
|
||||
offset(point, data.top_height),
|
||||
);
|
||||
}
|
||||
push_chain(
|
||||
&mut points,
|
||||
data.back_line_vertices.iter().map(|p| [p.x, p.y, p.z]),
|
||||
);
|
||||
if !data.back_line_vertices.is_empty() {
|
||||
push_chain(
|
||||
&mut points,
|
||||
data.back_line_vertices
|
||||
.iter()
|
||||
.map(|point| offset(point, data.top_height)),
|
||||
);
|
||||
push_chain(
|
||||
&mut points,
|
||||
data.back_line_vertices
|
||||
.iter()
|
||||
.map(|point| offset(point, -data.bottom_height)),
|
||||
);
|
||||
for point in &data.back_line_vertices {
|
||||
push_segment(
|
||||
&mut points,
|
||||
offset(point, -data.bottom_height),
|
||||
offset(point, data.top_height),
|
||||
);
|
||||
}
|
||||
if let (Some(front), Some(back)) = (
|
||||
data.vertices.first().zip(data.vertices.last()),
|
||||
data.back_line_vertices
|
||||
.first()
|
||||
.zip(data.back_line_vertices.last()),
|
||||
) {
|
||||
for (a, b) in [(front.0, back.0), (front.1, back.1)] {
|
||||
push_segment(&mut points, offset(a, data.top_height), offset(b, data.top_height));
|
||||
push_segment(
|
||||
&mut points,
|
||||
offset(a, -data.bottom_height),
|
||||
offset(b, -data.bottom_height),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
points
|
||||
}
|
||||
|
||||
@@ -483,56 +622,220 @@ fn to_render(entity: &ExtendedEntity, document: &acadrust::CadDocument) -> Optio
|
||||
})
|
||||
}
|
||||
|
||||
fn section_properties(data: &SectionObjectData) -> Vec<PropSection> {
|
||||
fn section_properties(entity: &ExtendedEntity, data: &SectionObjectData) -> Vec<PropSection> {
|
||||
let vertices = data
|
||||
.vertices
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, point)| format!("{}: {}", index + 1, vector_text(*point)))
|
||||
.map(|point| vector_text(*point))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let back_vertices = data
|
||||
.back_line_vertices
|
||||
.join("; ");
|
||||
let kind = section_kind(entity, data);
|
||||
let viewing = section_viewing_direction(data);
|
||||
let offset = section_plane_offset(data);
|
||||
let depth = section_slice_depth(entity).unwrap_or_else(|| section_depth(data));
|
||||
vec![PropSection {
|
||||
title: t!("Section Plane").into_owned(),
|
||||
props: vec![
|
||||
text_prop(t!("Name").as_ref(), "ext_section_name", &data.name),
|
||||
choice_prop(
|
||||
t!("State").as_ref(),
|
||||
"ext_section_state",
|
||||
kind,
|
||||
&["Plane", "Slice", "Boundary", "Volume"],
|
||||
),
|
||||
text_prop(
|
||||
t!("Viewing Direction").as_ref(),
|
||||
"ext_section_viewing",
|
||||
&vector_text(viewing),
|
||||
),
|
||||
text_prop(
|
||||
t!("Vertical Direction").as_ref(),
|
||||
"ext_section_vertical",
|
||||
&vector_text(data.vertical_direction),
|
||||
),
|
||||
ro_prop(t!("Normal").as_ref(), "ext_section_normal", vector_text(viewing)),
|
||||
bool_prop(
|
||||
t!("Live Section Enabled").as_ref(),
|
||||
"ext_section_live",
|
||||
data.flags & 1 != 0,
|
||||
),
|
||||
edit_prop(
|
||||
t!("Indicator Transparency").as_ref(),
|
||||
"ext_section_alpha",
|
||||
f64::from(data.indicator_alpha),
|
||||
),
|
||||
Property {
|
||||
label: t!("Indicator Fill Color").into_owned(),
|
||||
field: "indicator_fill_color",
|
||||
value: PropValue::ColorChoice(data.indicator_color),
|
||||
},
|
||||
edit_prop(t!("Elevation").as_ref(), "ext_section_elevation", offset),
|
||||
edit_prop(t!("Top Height").as_ref(), "ext_section_top", data.top_height),
|
||||
edit_prop(t!("Bottom Height").as_ref(), "ext_section_bottom", data.bottom_height),
|
||||
ro_prop(
|
||||
t!("Number of Vertices").as_ref(),
|
||||
"ext_section_vertex_count",
|
||||
data.vertices.len().to_string(),
|
||||
),
|
||||
text_prop(t!("Vertices").as_ref(), "ext_section_vertices", &vertices),
|
||||
ro_prop(
|
||||
t!("Settings").as_ref(),
|
||||
"ext_section_settings",
|
||||
handle_text(data.settings_handle),
|
||||
),
|
||||
choice_prop(
|
||||
t!("State2").as_ref(),
|
||||
"ext_section_state2",
|
||||
kind,
|
||||
&["Plane", "Slice", "Boundary", "Volume"],
|
||||
),
|
||||
edit_prop(t!("Slice Depth").as_ref(), "ext_section_depth", depth),
|
||||
edit_prop(
|
||||
t!("Section Plane Offset").as_ref(),
|
||||
"ext_section_offset",
|
||||
offset,
|
||||
),
|
||||
],
|
||||
}]
|
||||
}
|
||||
|
||||
fn section_tangent(data: &SectionObjectData) -> Vector3 {
|
||||
let Some((first, last)) = data.vertices.first().zip(data.vertices.last()) else {
|
||||
return Vector3::UNIT_X;
|
||||
};
|
||||
normalized(*last - *first, Vector3::UNIT_X)
|
||||
}
|
||||
|
||||
fn section_viewing_direction(data: &SectionObjectData) -> Vector3 {
|
||||
let tangent = section_tangent(data);
|
||||
let vertical = normalized(data.vertical_direction, Vector3::UNIT_Z);
|
||||
let base = normalized(vertical.cross(&tangent), Vector3::new(0.0, 0.0, -1.0));
|
||||
if data.flags & 4 != 0 { base } else { -base }
|
||||
}
|
||||
|
||||
fn section_depth(data: &SectionObjectData) -> f64 {
|
||||
data.vertices
|
||||
.first()
|
||||
.zip(data.back_line_vertices.first())
|
||||
.map_or(0.0, |(front, back)| (*back - *front).length())
|
||||
}
|
||||
|
||||
fn section_kind(entity: &ExtendedEntity, data: &SectionObjectData) -> &'static str {
|
||||
if section_is_slice(entity) {
|
||||
return "Slice";
|
||||
}
|
||||
match data.state {
|
||||
1 => "Plane",
|
||||
4 => "Volume",
|
||||
2 => "Boundary",
|
||||
_ => "Plane",
|
||||
}
|
||||
}
|
||||
|
||||
fn section_plane_offset(data: &SectionObjectData) -> f64 {
|
||||
let Some(first) = data.vertices.first() else {
|
||||
return 0.0;
|
||||
};
|
||||
-section_viewing_direction(data).dot(first)
|
||||
}
|
||||
|
||||
fn parse_vector(value: &str) -> Option<Vector3> {
|
||||
let values = value
|
||||
.split(|character: char| character == ',' || character == ';' || character.is_whitespace())
|
||||
.filter(|part| !part.is_empty())
|
||||
.map(str::parse::<f64>)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.ok()?;
|
||||
(values.len() == 3).then(|| Vector3::new(values[0], values[1], values[2]))
|
||||
}
|
||||
|
||||
fn parse_vertices(value: &str) -> Option<Vec<Vector3>> {
|
||||
let values = value
|
||||
.split(|character: char| {
|
||||
character == ',' || character == ';' || character == ':' || character.is_whitespace()
|
||||
})
|
||||
.filter(|part| !part.trim().is_empty())
|
||||
.map(str::parse::<f64>)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.ok()?;
|
||||
if values.len() < 6 || values.len() % 3 != 0 {
|
||||
return None;
|
||||
}
|
||||
let vertices = values
|
||||
.chunks_exact(3)
|
||||
.map(|point| Vector3::new(point[0], point[1], point[2]))
|
||||
.collect::<Vec<_>>();
|
||||
let valid = vertices
|
||||
.first()
|
||||
.zip(vertices.last())
|
||||
.is_some_and(|(first, last)| (*last - *first).length() > 1e-12);
|
||||
valid.then_some(vertices)
|
||||
}
|
||||
|
||||
fn set_section_depth(data: &mut SectionObjectData, depth: f64) {
|
||||
let depth = depth.max(0.0);
|
||||
if depth <= 1e-12 || data.vertices.is_empty() {
|
||||
data.back_line_vertices.clear();
|
||||
return;
|
||||
}
|
||||
let viewing = section_viewing_direction(data);
|
||||
data.back_line_vertices = data
|
||||
.vertices
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, point)| format!("{}: {}", index + 1, vector_text(*point)))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
vec![
|
||||
PropSection {
|
||||
title: t!("Section Object").into_owned(),
|
||||
props: vec![
|
||||
text_prop(t!("Name").as_ref(), "ext_section_name", &data.name),
|
||||
ro_prop(t!("State").as_ref(), "ext_section_state", data.state.to_string()),
|
||||
ro_prop(t!("Flags").as_ref(), "ext_section_flags", data.flags.to_string()),
|
||||
ro_prop(t!("Vertical Direction").as_ref(),
|
||||
"ext_section_vertical",
|
||||
vector_text(data.vertical_direction),
|
||||
),
|
||||
edit_prop(t!("Top Height").as_ref(), "ext_section_top", data.top_height),
|
||||
edit_prop(t!("Bottom Height").as_ref(), "ext_section_bottom", data.bottom_height),
|
||||
ro_prop(t!("Indicator Alpha").as_ref(),
|
||||
"ext_section_alpha",
|
||||
data.indicator_alpha.to_string(),
|
||||
),
|
||||
ro_prop(t!("Indicator Color").as_ref(),
|
||||
"ext_section_color",
|
||||
format!("{:?}", data.indicator_color),
|
||||
),
|
||||
ro_prop(t!("Settings").as_ref(),
|
||||
"ext_section_settings",
|
||||
handle_text(data.settings_handle),
|
||||
),
|
||||
],
|
||||
},
|
||||
PropSection {
|
||||
title: t!("Section Vertices").into_owned(),
|
||||
props: vec![
|
||||
ro_prop(t!("Cutting Line").as_ref(), "ext_section_vertices", vertices),
|
||||
ro_prop(t!("Back Line").as_ref(), "ext_section_back_vertices", back_vertices),
|
||||
],
|
||||
},
|
||||
]
|
||||
.map(|point| *point + viewing * depth)
|
||||
.collect();
|
||||
}
|
||||
|
||||
fn set_section_kind(data: &mut SectionObjectData, value: &str) {
|
||||
let span = data
|
||||
.vertices
|
||||
.first()
|
||||
.zip(data.vertices.last())
|
||||
.map_or(1.0, |(first, last)| (*last - *first).length().max(1e-4));
|
||||
match value.trim().to_ascii_uppercase().as_str() {
|
||||
"SLICE" => {
|
||||
data.state = 1;
|
||||
data.back_line_vertices.clear();
|
||||
}
|
||||
"BOUNDARY" => {
|
||||
data.state = 2;
|
||||
set_section_depth(data, span);
|
||||
}
|
||||
"VOLUME" => {
|
||||
data.state = 4;
|
||||
set_section_depth(data, span);
|
||||
}
|
||||
_ => {
|
||||
data.state = 1;
|
||||
data.back_line_vertices.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn move_section_to_offset(data: &mut SectionObjectData, desired: f64) {
|
||||
let current = section_plane_offset(data);
|
||||
let delta = section_viewing_direction(data) * (current - desired);
|
||||
for point in data.vertices.iter_mut().chain(data.back_line_vertices.iter_mut()) {
|
||||
*point = *point + delta;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_viewing_direction(data: &mut SectionObjectData, value: Vector3) {
|
||||
if value.length() <= 1e-12 || data.vertices.len() < 2 {
|
||||
return;
|
||||
}
|
||||
let desired = normalized(value, section_viewing_direction(data));
|
||||
let tangent = section_tangent(data);
|
||||
let vertical = tangent.cross(&desired);
|
||||
if vertical.length() <= 1e-12 {
|
||||
return;
|
||||
}
|
||||
data.vertical_direction = normalized(vertical, data.vertical_direction);
|
||||
data.flags |= 4;
|
||||
let depth = section_depth(data);
|
||||
if depth > 0.0 {
|
||||
set_section_depth(data, depth);
|
||||
}
|
||||
}
|
||||
|
||||
fn arc_text_properties(data: &ArcAlignedTextData) -> Vec<PropSection> {
|
||||
@@ -892,7 +1195,7 @@ fn properties(entity: &ExtendedEntity) -> Vec<PropSection> {
|
||||
title: t!("Camera").into_owned(),
|
||||
props: vec![ro_prop(t!("View").as_ref(), "ext_camera_view", handle_text(*view_handle))],
|
||||
}],
|
||||
ExtendedEntityData::SectionObject(data) => section_properties(data),
|
||||
ExtendedEntityData::SectionObject(data) => section_properties(entity, data),
|
||||
ExtendedEntityData::ArcAlignedText(data) => arc_text_properties(data),
|
||||
ExtendedEntityData::RemoteText(data) => remote_text_properties(data),
|
||||
ExtendedEntityData::GeoPositionMarker(data) => geo_marker_properties(data),
|
||||
@@ -1039,14 +1342,97 @@ fn set_f64(value: &str, target: &mut f64) {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_section_prop(entity: &mut ExtendedEntity, field: &str, value: &str) {
|
||||
let was_slice = section_is_slice(entity);
|
||||
let stored_slice_depth = section_slice_depth(entity).unwrap_or(0.0);
|
||||
let ExtendedEntityData::SectionObject(data) = &mut entity.data else {
|
||||
return;
|
||||
};
|
||||
let mut slice_update = None;
|
||||
match field {
|
||||
"ext_section_name" => data.name = value.to_string(),
|
||||
"ext_section_state" | "ext_section_state2" => {
|
||||
let kind = value.trim().to_ascii_uppercase();
|
||||
let span = data
|
||||
.vertices
|
||||
.first()
|
||||
.zip(data.vertices.last())
|
||||
.map_or(1.0, |(first, last)| (*last - *first).length().max(1e-4));
|
||||
set_section_kind(data, &kind);
|
||||
slice_update = Some((kind == "SLICE", (span / 60.0).max(1e-4)));
|
||||
}
|
||||
"ext_section_viewing" => {
|
||||
if let Some(direction) = parse_vector(value) {
|
||||
set_viewing_direction(data, direction);
|
||||
}
|
||||
}
|
||||
"ext_section_vertical" => {
|
||||
if let Some(direction) = parse_vector(value) {
|
||||
let depth = section_depth(data);
|
||||
let direction = normalized(direction, data.vertical_direction);
|
||||
if direction.dot(§ion_tangent(data)).abs() < 1.0 - 1e-9 {
|
||||
data.vertical_direction = direction;
|
||||
if depth > 0.0 {
|
||||
set_section_depth(data, depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"ext_section_live" => data.flags ^= 1,
|
||||
"ext_section_alpha" => {
|
||||
if let Ok(alpha) = value.trim().parse::<i16>() {
|
||||
data.indicator_alpha = alpha.clamp(0, 100);
|
||||
}
|
||||
}
|
||||
"ext_section_elevation" | "ext_section_offset" => {
|
||||
if let Some(offset) = parse_f64(value) {
|
||||
move_section_to_offset(data, offset);
|
||||
}
|
||||
}
|
||||
"ext_section_top" => {
|
||||
if let Some(height) = parse_f64(value).filter(|height| *height >= 0.0) {
|
||||
data.top_height = height;
|
||||
}
|
||||
}
|
||||
"ext_section_bottom" => {
|
||||
if let Some(height) = parse_f64(value).filter(|height| *height >= 0.0) {
|
||||
data.bottom_height = height;
|
||||
}
|
||||
}
|
||||
"ext_section_vertices" => {
|
||||
if let Some(vertices) = parse_vertices(value) {
|
||||
let depth = section_depth(data);
|
||||
data.vertices = vertices;
|
||||
if depth > 0.0 {
|
||||
set_section_depth(data, depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
"ext_section_depth" => {
|
||||
if let Some(depth) = parse_f64(value) {
|
||||
if was_slice {
|
||||
slice_update = Some((true, depth));
|
||||
} else {
|
||||
set_section_depth(data, depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some((enabled, depth)) = slice_update {
|
||||
set_section_slice_metadata(entity, enabled, depth);
|
||||
} else if was_slice && field != "ext_section_depth" {
|
||||
set_section_slice_metadata(entity, true, stored_slice_depth);
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_geom_prop(entity: &mut ExtendedEntity, field: &str, value: &str) {
|
||||
if matches!(entity.data, ExtendedEntityData::SectionObject(_)) {
|
||||
apply_section_prop(entity, field, value);
|
||||
return;
|
||||
}
|
||||
match &mut entity.data {
|
||||
ExtendedEntityData::SectionObject(data) => match field {
|
||||
"ext_section_name" => data.name = value.to_string(),
|
||||
"ext_section_top" => set_f64(value, &mut data.top_height),
|
||||
"ext_section_bottom" => set_f64(value, &mut data.bottom_height),
|
||||
_ => {}
|
||||
},
|
||||
ExtendedEntityData::ArcAlignedText(data) => match field {
|
||||
"ext_arc_text" => data.text = value.to_string(),
|
||||
"ext_arc_font" => data.font_name = value.to_string(),
|
||||
@@ -1398,6 +1784,8 @@ fn transformed_planar_angle(
|
||||
fn apply_transform(entity: &mut ExtendedEntity, requested: &EntityTransform) {
|
||||
let transform = entity_transform(requested);
|
||||
let scale = scalar_scale(requested);
|
||||
let slice_depth = section_is_slice(entity)
|
||||
.then(|| section_slice_depth(entity).unwrap_or(0.0) * scale);
|
||||
match &mut entity.data {
|
||||
ExtendedEntityData::SectionObject(data) => {
|
||||
for point in data
|
||||
@@ -1536,6 +1924,9 @@ fn apply_transform(entity: &mut ExtendedEntity, requested: &EntityTransform) {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(depth) = slice_depth {
|
||||
set_section_slice_metadata(entity, true, depth);
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderConvertible for ExtendedEntity {
|
||||
|
||||
@@ -66,6 +66,11 @@ pub fn ui_name(e: &EntityType) -> &'static str {
|
||||
EntityType::Light(_) => "Light",
|
||||
EntityType::SectionSymbol(_) => "Section Symbol",
|
||||
EntityType::ViewBorder(_) => "View Border",
|
||||
EntityType::Extended(extended)
|
||||
if matches!(
|
||||
extended.data,
|
||||
acadrust::entities::ExtendedEntityData::SectionObject(_)
|
||||
) => "Section Plane",
|
||||
EntityType::Extended(_) => "Extended Entity",
|
||||
EntityType::Seqend(_) => "Seqend",
|
||||
EntityType::Unknown(_) => "Unknown",
|
||||
@@ -79,6 +84,12 @@ pub fn ui_name(e: &EntityType) -> &'static str {
|
||||
/// (the numeric `DWG_TYPE_<n>` placeholder).
|
||||
pub fn ui_name_or_class(e: &EntityType) -> String {
|
||||
if let EntityType::Extended(entity) = e {
|
||||
if matches!(
|
||||
entity.data,
|
||||
acadrust::entities::ExtendedEntityData::SectionObject(_)
|
||||
) {
|
||||
return "Section Plane".to_string();
|
||||
}
|
||||
return entity.class_name().to_string();
|
||||
}
|
||||
if let EntityType::Unknown(u) = e {
|
||||
@@ -148,6 +159,11 @@ pub fn dxf_name(e: &EntityType) -> &'static str {
|
||||
EntityType::Light(_) => "LIGHT",
|
||||
EntityType::SectionSymbol(_) => "SECTIONLINE",
|
||||
EntityType::ViewBorder(_) => "DRAWINGVIEW",
|
||||
EntityType::Extended(extended)
|
||||
if matches!(
|
||||
extended.data,
|
||||
acadrust::entities::ExtendedEntityData::SectionObject(_)
|
||||
) => "SECTIONOBJECT",
|
||||
_ => "ENTITY",
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user