forked from 1b-agent/opencadstudio-upstream
fix(wblock): exported drawings carry their block definitions and styles
WBLOCK copied only the entities and their layers, so INSERTs pointed at missing blocks and the file opened almost empty or needed recovery. It now goes through the cross-drawing paste kernels, which bring layers, linetypes, styles, block definitions and baked dimension blocks along. Fixes #1111 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
805979ea36
commit
c8c2238d4a
3 files changed
+37
-54
No files matched your search
@@ -94,7 +94,9 @@ mod text_edit;
|
||||
mod constraint;
|
||||
mod dim_edit;
|
||||
|
||||
pub(crate) use clipboard::{copy_to_clipboard_kernel, remap_ext_subtree_reference};
|
||||
pub(crate) use clipboard::{
|
||||
copy_to_clipboard_kernel, paste_entities_kernel, remap_ext_subtree_reference,
|
||||
};
|
||||
|
||||
impl OpenCADStudio {
|
||||
/// Applies one command result, then — when that result ended the active
|
||||
|
||||
@@ -9,6 +9,7 @@ pub(crate) mod config;
|
||||
pub use automation::{export_headless, serve};
|
||||
mod annotation_data;
|
||||
mod command_driver;
|
||||
pub(crate) use command_driver::{copy_to_clipboard_kernel, paste_entities_kernel};
|
||||
pub(crate) mod commands;
|
||||
pub(crate) mod dim_viewport;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -50,29 +50,7 @@ pub fn extract_block_into(
|
||||
.into_owned());
|
||||
}
|
||||
|
||||
// Copy layers referenced by the block entities.
|
||||
for h in &handles {
|
||||
if let Some(e) = src.get_entity(*h) {
|
||||
let layer = e.common().layer.clone();
|
||||
if !layer.is_empty() && !layer.eq("0") && out.layers.get(&layer).is_none() {
|
||||
if let Some(src_layer) = src.layers.get(&layer) {
|
||||
let _ = out.layers.add(src_layer.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for h in handles {
|
||||
if let Some(entity) = src.get_entity(h) {
|
||||
if matches!(entity, EntityType::Block(_) | EntityType::BlockEnd(_)) {
|
||||
continue;
|
||||
}
|
||||
let mut clone = entity.clone();
|
||||
clone.common_mut().handle = codec::types::Handle::NULL;
|
||||
clone.common_mut().owner_handle = codec::types::Handle::NULL;
|
||||
let _ = out.add_entity(clone);
|
||||
}
|
||||
}
|
||||
copy_with_dependencies(src, &handles, out, None);
|
||||
|
||||
if out.entities().count() == 0 {
|
||||
return Err(t!(
|
||||
@@ -106,24 +84,7 @@ pub fn extract_entities_into(
|
||||
return Err(t!("No entities selected for WBLOCK.").into_owned());
|
||||
}
|
||||
|
||||
for &h in handles {
|
||||
if let Some(entity) = src.get_entity(h) {
|
||||
if matches!(entity, EntityType::Block(_) | EntityType::BlockEnd(_)) {
|
||||
continue;
|
||||
}
|
||||
// Copy layer definition.
|
||||
let layer = entity.common().layer.clone();
|
||||
if !layer.is_empty() && !layer.eq("0") && out.layers.get(&layer).is_none() {
|
||||
if let Some(src_layer) = src.layers.get(&layer) {
|
||||
let _ = out.layers.add(src_layer.clone());
|
||||
}
|
||||
}
|
||||
let mut clone = entity.clone();
|
||||
clone.common_mut().handle = codec::types::Handle::NULL;
|
||||
clone.common_mut().owner_handle = codec::types::Handle::NULL;
|
||||
let _ = out.add_entity(clone);
|
||||
}
|
||||
}
|
||||
copy_with_dependencies(src, handles, out, None);
|
||||
|
||||
if out.entities().count() == 0 {
|
||||
return Err(t!("None of the selected entities could be exported.").into_owned());
|
||||
@@ -132,6 +93,30 @@ pub fn extract_entities_into(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Copy entities into `out` the way a cross-drawing paste does: fresh handles,
|
||||
/// plus the layers, linetypes, styles, block definitions and baked dimension
|
||||
/// blocks they use — without those an exported INSERT points at nothing and
|
||||
/// the file opens empty or needs recovery. (#1111)
|
||||
fn copy_with_dependencies(
|
||||
src: &CadDocument,
|
||||
handles: &[codec::Handle],
|
||||
out: &mut CadDocument,
|
||||
translate: Option<&crate::command::EntityTransform>,
|
||||
) {
|
||||
let handles: Vec<codec::Handle> = handles
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|&handle| {
|
||||
!matches!(
|
||||
src.get_entity(handle),
|
||||
Some(EntityType::Block(_) | EntityType::BlockEnd(_))
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let (entities, deps) = crate::app::copy_to_clipboard_kernel(src, &handles);
|
||||
crate::app::paste_entities_kernel(out, &entities, &deps, translate);
|
||||
}
|
||||
|
||||
/// Translate every entity of `out` so the overall bounds minimum lands on
|
||||
/// the origin — SPM.ACAD's clone flow normalizes the new drawing to 0,0,0
|
||||
/// after the copy (Catalog §2.1/CF-01.2). Opt-in per request; the
|
||||
@@ -193,18 +178,13 @@ pub fn extract_entities_to_doc_with_base(
|
||||
) -> Result<CadDocument, String> {
|
||||
let mut out = CadDocument::new();
|
||||
out.header.insertion_units = unit;
|
||||
extract_entities_into(src, handles, &mut out)?;
|
||||
if base_point != glam::DVec3::ZERO {
|
||||
let shift = crate::command::EntityTransform::Affine(
|
||||
codec::types::Transform::from_translation(codec::types::Vector3::new(
|
||||
-base_point.x,
|
||||
-base_point.y,
|
||||
-base_point.z,
|
||||
)),
|
||||
);
|
||||
for entity in out.entities_mut() {
|
||||
crate::scene::view::dispatch::apply_transform(entity, &shift);
|
||||
}
|
||||
if handles.is_empty() {
|
||||
return Err(t!("No entities selected for WBLOCK.").into_owned());
|
||||
}
|
||||
let shift = crate::command::EntityTransform::Translate(-base_point);
|
||||
copy_with_dependencies(src, handles, &mut out, Some(&shift));
|
||||
if out.entities().count() == 0 {
|
||||
return Err(t!("None of the selected entities could be exported.").into_owned());
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user