feat(props): make dim-line colour editable for leaders and dimensions
The "Dim line color" row on Leader and Dimension entities was read-only: an earlier attempt wired it to Leader.override_color, which acadrust never serialises, so the pick was lost on save. Store it instead as a standard ACAD_DSTYLE per-object dimension-style override (DXF code 176, an ACI index) through the existing dim_override codec, so it round-trips through both DWG and DXF like the other dim overrides. RGB picks collapse to the nearest ACI, matching the rest of the dim-colour stack (dimension styles are index-only through the file layer). The renderer prefers the override over the style's DIMCLRD. The write branch is guarded to leaders and dimensions so a mixed selection cannot stamp the override onto other entity types. Bumps acadrust to c9fe982, which carries parsed XDATA onto dimensions on DXF read (it was dropping common.extended_data), so the dimension override persists on DXF save as well as DWG. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
04bd49c715
commit
d005cc4ab1
8 changed files with 241 additions and 29 deletions
127
tests/dim_line_color_roundtrip.rs
Normal file
127
tests/dim_line_color_roundtrip.rs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// The editable "Dim line color" property writes an ACAD_DSTYLE dimension-style
|
||||
// override (code 176, an ACI index) on the leader / dimension. That override
|
||||
// must survive a full DWG *and* DXF save/reload — otherwise the picked colour
|
||||
// is silently lost, which is exactly why the row was kept read-only before.
|
||||
// This is the regression guard for that persistence.
|
||||
|
||||
use acadrust::entities::{Dimension, DimensionLinear, Leader, Line};
|
||||
use acadrust::tables::BlockRecord;
|
||||
use acadrust::types::{Color, Vector3};
|
||||
use acadrust::xdata::XDataValue;
|
||||
use acadrust::{CadDocument, EntityType, Handle};
|
||||
use OpenCADStudio::entities::dim_override as dov;
|
||||
use OpenCADStudio::scene::Scene;
|
||||
|
||||
fn roundtrip(doc: &CadDocument, ext: &str) -> CadDocument {
|
||||
let bytes = OpenCADStudio::io::save_to_bytes(doc, ext, doc.version)
|
||||
.unwrap_or_else(|e| panic!("save to {ext}: {e}"));
|
||||
OpenCADStudio::io::load_bytes(&format!("rt.{ext}"), bytes)
|
||||
.unwrap_or_else(|e| panic!("reload {ext}: {e}"))
|
||||
}
|
||||
|
||||
fn leader_color(doc: &CadDocument) -> Option<Color> {
|
||||
doc.entities()
|
||||
.find_map(|e| match e {
|
||||
EntityType::Leader(l) => Some(dov::color(&l.common.extended_data, dov::DIMCLRD)),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn dim_color(doc: &CadDocument) -> Option<Color> {
|
||||
doc.entities()
|
||||
.find_map(|e| match e {
|
||||
EntityType::Dimension(d) => Some(dov::color(&d.base().common.extended_data, dov::DIMCLRD)),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn leader_scene(aci: i16) -> Scene {
|
||||
let mut scene = Scene::new();
|
||||
let mut ld = Leader::new();
|
||||
ld.vertices = vec![Vector3::new(0.0, 0.0, 0.0), Vector3::new(10.0, 5.0, 0.0)];
|
||||
let h = scene.add_entity(EntityType::Leader(ld));
|
||||
dov::set(
|
||||
&mut scene.document,
|
||||
h,
|
||||
dov::DIMCLRD,
|
||||
Some(XDataValue::Integer16(aci)),
|
||||
);
|
||||
scene
|
||||
}
|
||||
|
||||
fn dimension_scene(aci: i16) -> Scene {
|
||||
let mut scene = Scene::new();
|
||||
|
||||
// A baked *D0 block holding one line, so the dimension writes cleanly.
|
||||
let br_h = Handle::new(scene.document.next_handle());
|
||||
let mut br = BlockRecord::new("*D0");
|
||||
br.handle = br_h;
|
||||
scene.document.block_records.add(br).unwrap();
|
||||
let mut sub = Line::new();
|
||||
sub.start = Vector3::new(0.0, 0.0, 0.0);
|
||||
sub.end = Vector3::new(10.0, 0.0, 0.0);
|
||||
let mut sub_e = EntityType::Line(sub);
|
||||
sub_e.common_mut().owner_handle = br_h;
|
||||
scene.document.add_entity(sub_e).unwrap();
|
||||
|
||||
let mut dim =
|
||||
DimensionLinear::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(10.0, 0.0, 0.0));
|
||||
dim.base.block_name = "*D0".to_string();
|
||||
let h = scene.add_entity(EntityType::Dimension(Dimension::Linear(dim)));
|
||||
dov::set(
|
||||
&mut scene.document,
|
||||
h,
|
||||
dov::DIMCLRD,
|
||||
Some(XDataValue::Integer16(aci)),
|
||||
);
|
||||
scene
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leader_dim_line_color_survives_dwg_and_dxf() {
|
||||
for ext in ["dwg", "dxf"] {
|
||||
// ACI 1 (red): an indexed override.
|
||||
let scene = leader_scene(1);
|
||||
assert_eq!(
|
||||
leader_color(&scene.document),
|
||||
Some(Color::Index(1)),
|
||||
"override not applied pre-save ({ext})"
|
||||
);
|
||||
let re = roundtrip(&scene.document, ext);
|
||||
assert_eq!(
|
||||
leader_color(&re),
|
||||
Some(Color::Index(1)),
|
||||
"leader dim-line colour (ACI 1) lost across {ext} round-trip"
|
||||
);
|
||||
|
||||
// ByLayer (256): an explicit override that must persist as ByLayer, not
|
||||
// collapse to "no override".
|
||||
let scene = leader_scene(256);
|
||||
let re = roundtrip(&scene.document, ext);
|
||||
assert_eq!(
|
||||
leader_color(&re),
|
||||
Some(Color::ByLayer),
|
||||
"leader dim-line colour (ByLayer) lost across {ext} round-trip"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dimension_dim_line_color_survives_dwg_and_dxf() {
|
||||
for ext in ["dwg", "dxf"] {
|
||||
let scene = dimension_scene(3);
|
||||
assert_eq!(
|
||||
dim_color(&scene.document),
|
||||
Some(Color::Index(3)),
|
||||
"override not applied pre-save ({ext})"
|
||||
);
|
||||
let re = roundtrip(&scene.document, ext);
|
||||
assert_eq!(
|
||||
dim_color(&re),
|
||||
Some(Color::Index(3)),
|
||||
"dimension dim-line colour (ACI 3) lost across {ext} round-trip"
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue