forked from 1b-agent/opencadstudio-upstream
fix(renderer): match leader and dash styles
Read canonical ACAD/DSTYLE overrides for leader color and arrow size. Scale block-local linetype patterns through INSERT transforms. Closes #436
This commit is contained in:
1 parent
7a1c0ead0d
commit
ceddb287f5
3 files changed
+131
-35
No files matched your search
@@ -1,10 +1,11 @@
|
||||
//! Per-object dimension-variable overrides.
|
||||
//!
|
||||
//! A leader (or dimension) that departs from its dimension style stores the
|
||||
//! changed variables in the standard `ACAD_DSTYLE` XDATA record as a list of
|
||||
//! (dimvar group code, value) pairs wrapped in `{ }` control strings. Both the
|
||||
//! renderer and the properties panel prefer an override over the style default,
|
||||
//! so editing one of these rows writes here and the change round-trips to file.
|
||||
//! changed variables in the standard `ACAD` XDATA record, identified by a
|
||||
//! leading `DSTYLE` string, as a list of (dimvar group code, value) pairs wrapped
|
||||
//! in `{ }` control strings. Both the renderer and the properties panel prefer
|
||||
//! an override over the style default, so editing one of these rows writes here
|
||||
//! and the change round-trips to file.
|
||||
|
||||
use acadrust::types::Color;
|
||||
use acadrust::xdata::{ExtendedData, XDataValue};
|
||||
@@ -19,13 +20,24 @@ pub const DIMGAP: i16 = 147; // text offset / gap (real)
|
||||
pub const DIMLWD: i16 = 371; // dim line lineweight (int16)
|
||||
pub const DIMLDRBLK: i16 = 341; // leader arrow block (handle)
|
||||
|
||||
/// Every (code, value) override present in the `ACAD_DSTYLE` record.
|
||||
/// Every (code, value) override present in the `ACAD`/`DSTYLE` record.
|
||||
pub fn pairs(xd: &ExtendedData) -> Vec<(i16, XDataValue)> {
|
||||
let Some(rec) = xd.get_record("ACAD_DSTYLE") else {
|
||||
let values = xd
|
||||
.get_record("ACAD")
|
||||
.and_then(|rec| match rec.values.first() {
|
||||
Some(XDataValue::String(name)) if name == "DSTYLE" => Some(&rec.values[1..]),
|
||||
_ => None,
|
||||
})
|
||||
// Retain compatibility with records produced by older OCS versions.
|
||||
.or_else(|| {
|
||||
xd.get_record("ACAD_DSTYLE")
|
||||
.map(|rec| rec.values.as_slice())
|
||||
});
|
||||
let Some(values) = values else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut out = Vec::new();
|
||||
let mut it = rec.values.iter();
|
||||
let mut it = values.iter();
|
||||
// The record is a flat stream: a 1070 code marker followed by its typed
|
||||
// value, bracketed by 1002 "{" / "}" control strings (which are skipped).
|
||||
while let Some(v) = it.next() {
|
||||
@@ -78,9 +90,55 @@ pub fn handle(xd: &ExtendedData, code: i16) -> Option<Handle> {
|
||||
})
|
||||
}
|
||||
|
||||
fn write_pairs(doc: &mut CadDocument, handle: Handle, pairs: Vec<(i16, XDataValue)>) {
|
||||
let Some(entity) = doc.get_entity(handle) else {
|
||||
return;
|
||||
};
|
||||
let use_canonical_record = entity
|
||||
.common()
|
||||
.extended_data
|
||||
.get_record("ACAD")
|
||||
.map(|rec| {
|
||||
matches!(
|
||||
rec.values.first(),
|
||||
Some(XDataValue::String(name)) if name == "DSTYLE"
|
||||
)
|
||||
})
|
||||
.unwrap_or(true);
|
||||
|
||||
let mut values = if pairs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut vals = vec![XDataValue::ControlString("{".to_string())];
|
||||
for (code, value) in pairs {
|
||||
vals.push(XDataValue::Integer16(code));
|
||||
vals.push(value);
|
||||
}
|
||||
vals.push(XDataValue::ControlString("}".to_string()));
|
||||
Some(vals)
|
||||
};
|
||||
|
||||
if use_canonical_record {
|
||||
if let Some(vals) = &mut values {
|
||||
vals.insert(0, XDataValue::String("DSTYLE".to_string()));
|
||||
}
|
||||
crate::scene::view::dispatch::set_entity_xdata(doc, handle, "ACAD_DSTYLE", None);
|
||||
crate::scene::view::dispatch::set_entity_xdata(doc, handle, "ACAD", values);
|
||||
} else {
|
||||
// Preserve unrelated Autodesk XDATA already occupying the ACAD record.
|
||||
crate::scene::view::dispatch::set_entity_xdata(doc, handle, "ACAD_DSTYLE", values);
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace every dimension-variable override on entity `handle`.
|
||||
pub fn replace(doc: &mut CadDocument, handle: Handle, values: Vec<(i16, XDataValue)>) {
|
||||
write_pairs(doc, handle, values);
|
||||
}
|
||||
|
||||
/// Set — or, with `value: None`, clear — a single override on entity `handle`,
|
||||
/// leaving the other overrides in the record untouched. Clearing the last one
|
||||
/// drops the whole `ACAD_DSTYLE` record.
|
||||
/// drops the whole `ACAD`/`DSTYLE` record. Legacy `ACAD_DSTYLE` records written
|
||||
/// by older OCS versions are migrated when the canonical `ACAD` slot is free.
|
||||
pub fn set(doc: &mut CadDocument, handle: Handle, code: i16, value: Option<XDataValue>) {
|
||||
let Some(entity) = doc.get_entity(handle) else {
|
||||
return;
|
||||
@@ -92,16 +150,5 @@ pub fn set(doc: &mut CadDocument, handle: Handle, code: i16, value: Option<XData
|
||||
if let Some(v) = value {
|
||||
kept.push((code, v));
|
||||
}
|
||||
let values = if kept.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut vals = vec![XDataValue::ControlString("{".to_string())];
|
||||
for (c, v) in kept {
|
||||
vals.push(XDataValue::Integer16(c));
|
||||
vals.push(v);
|
||||
}
|
||||
vals.push(XDataValue::ControlString("}".to_string()));
|
||||
Some(vals)
|
||||
};
|
||||
crate::scene::view::dispatch::set_entity_xdata(doc, handle, "ACAD_DSTYLE", values);
|
||||
write_pairs(doc, handle, kept);
|
||||
}
|
||||
Reference in new issue
Block a user