From e4d04ef1323adcde510b40c99af9b4265c5230d1 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 16 Oct 2026 09:17:01 +0300 Subject: [PATCH 1/3] Cargo: codec e023bc3 (acadrust sync), kernel abca4e8, graph c63556f The codec now holds wide EntityType variants boxed (MText, Helix, Dimension, Hatch, Viewport, MultiLeader, Surface, Table, Ole2Frame, Light, Extended). Constructors box their entity; nested patterns reach a dimension through entities::dimension::as_dimension(_mut). Also follows BlockAction::action_ids, LineTypeComplexData::source_flags and the decimal tab stop with an explicit character. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 44 +++++++++--- Cargo.toml | 8 +-- benches/command_benchmarks.rs | 2 +- crates/ocs_plugin_api/Cargo.toml | 4 +- crates/ocs_plugin_api/src/entity_coverage.rs | 14 ++-- crates/ocs_save/Cargo.toml | 2 +- crates/ocs_web_worker/Cargo.toml | 2 +- docs/plugin-template-v2/Cargo.toml | 2 +- plugins/opencad-python/Cargo.lock | 12 +++- .../examples/create_layout_fixture.rs | 2 +- plugins/opencad-python/src/ocs_module.rs | 2 +- src/app/automation.rs | 14 ++-- src/app/command_driver/clipboard.rs | 2 +- src/app/command_driver/dim_edit.rs | 22 +++--- src/app/command_driver/entity_commit.rs | 16 ++--- src/app/command_driver/text_edit.rs | 2 +- src/app/command_driver/transform.rs | 2 +- src/app/command_driver/viewport.rs | 5 +- src/app/commands/pdf_shx_text.rs | 2 +- src/app/commands/sheet_set.rs | 2 +- src/app/commands/ucsfollow.rs | 4 +- src/app/commands/view.rs | 7 +- src/app/dim_viewport.rs | 4 +- src/app/mtext_editor.rs | 10 +-- src/app/navigation.rs | 2 +- src/app/plugin_host.rs | 8 +-- src/app/properties.rs | 70 ++++++++++--------- src/app/update/block_ops_tests.rs | 4 +- src/app/update/command.rs | 19 +++-- src/app/update/graphic_attributes.rs | 2 +- src/app/viewport_dimension_tests.rs | 10 +-- src/entities/dimension.rs | 29 ++++++-- src/entities/object_data.rs | 6 +- src/entities/text_support.rs | 4 +- src/entities/traits.rs | 10 +++ src/entity_creation.rs | 4 +- src/io/linetypes.rs | 2 + src/io/mod.rs | 13 ++-- src/io/ole_embed.rs | 2 +- src/io/xref.rs | 2 +- src/modules/annotate/aligned_dim.rs | 2 +- src/modules/annotate/angular_dim.rs | 6 +- src/modules/annotate/arc_length_dim.rs | 2 +- src/modules/annotate/diameter_dim.rs | 4 +- src/modules/annotate/dim_baseline.rs | 6 +- src/modules/annotate/dim_continue.rs | 6 +- src/modules/annotate/dimjogline.rs | 10 ++- src/modules/annotate/dimspace.rs | 13 ++-- src/modules/annotate/field_cmd.rs | 2 +- src/modules/annotate/jogged_radius_dim.rs | 4 +- src/modules/annotate/leader_cmd.rs | 2 +- src/modules/annotate/linear_dim.rs | 2 +- src/modules/annotate/mleader_cmd.rs | 2 +- src/modules/annotate/ordinate_dim.rs | 2 +- src/modules/annotate/qdim.rs | 10 +-- src/modules/annotate/radius_dim.rs | 4 +- src/modules/annotate/txt2mtxt.rs | 7 +- src/modules/draw/clipboard/pastespec.rs | 2 +- src/modules/draw/draw/hatchedit.rs | 4 +- src/modules/draw/draw/raster_image.rs | 2 +- src/modules/draw/modify/explode.rs | 26 +++---- src/modules/insert/dgn_import.rs | 2 +- src/modules/insert/pdf_import.rs | 4 +- src/modules/layout/mvsetup.rs | 2 +- src/scene/annotative.rs | 2 +- src/scene/block_service.rs | 4 +- src/scene/camera_ops.rs | 4 +- src/scene/dimension_assoc.rs | 48 +++++++------ src/scene/entity.rs | 2 +- src/scene/layout.rs | 6 +- src/scene/mod.rs | 10 +-- src/scene/mspace.rs | 4 +- src/scene/parametric_constraints.rs | 26 ++++--- src/scene/project.rs | 4 +- src/ui/node_graph.rs | 2 +- tests/active_space_roundtrip.rs | 4 +- tests/annotative_context_synthesis.rs | 6 +- tests/block_hatch_export.rs | 8 +-- tests/dim_copy_check.rs | 2 +- tests/dim_leader_render_check.rs | 2 +- tests/dim_line_color_roundtrip.rs | 2 +- tests/explode_regression.rs | 2 +- tests/pdf_export_images_check.rs | 2 +- tests/pdf_export_text_check.rs | 2 +- tests/text_font_rendering.rs | 2 +- tests/viewport_wide_polyline_plot_width.rs | 2 +- tests/zoom_extents_coverage.rs | 4 +- 87 files changed, 380 insertions(+), 269 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf8d59d12..dbea93f19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2397,7 +2397,7 @@ dependencies = [ "hayro-syntax", "kurbo 0.13.1", "moxcms", - "phf", + "phf 0.13.1", "rustc-hash 2.1.3", "siphasher", "skrifa 0.42.1", @@ -4348,6 +4348,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "oem_cp" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7959d3349f484aec36462f98226983578bf7d33f9b034c32967489c7000e1f" +dependencies = [ + "phf 0.11.3", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -4373,7 +4382,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=102f04c#102f04c8ecda1cd409f7ecc4b6eab2dc895c9095" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=e023bc3#e023bc37235dddecf9b3e79c522d8936d15e21e6" dependencies = [ "anyhow", "bitflags 2.13.1", @@ -4385,6 +4394,7 @@ dependencies = [ "itoa", "memmap2", "nom 7.1.3", + "oem_cp", "once_cell", "rayon", "ryu", @@ -4396,7 +4406,7 @@ dependencies = [ [[package]] name = "opencadgraph" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=88cdae0#88cdae06858f6811f5058a5686bc1edb5ff39910" +source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=c63556f#c63556f9f7a3cf658fd003a2e47fe67283b6afa7" dependencies = [ "opencadkernel", "serde_json", @@ -4405,7 +4415,7 @@ dependencies = [ [[package]] name = "opencadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=5811296#5811296a6c98ea9b12defa977f08d74cfc739014" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=abca4e8#abca4e81b089114a776ad6fe72a40c51a35646cb" dependencies = [ "cavalier_contours", "opencadcodec", @@ -4416,7 +4426,7 @@ dependencies = [ [[package]] name = "opencadkernel-constraints" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=5811296#5811296a6c98ea9b12defa977f08d74cfc739014" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=abca4e8#abca4e81b089114a776ad6fe72a40c51a35646cb" dependencies = [ "nalgebra", ] @@ -4595,6 +4605,15 @@ dependencies = [ "indexmap", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", +] + [[package]] name = "phf" version = "0.13.1" @@ -4602,7 +4621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_macros", - "phf_shared", + "phf_shared 0.13.1", ] [[package]] @@ -4612,7 +4631,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared", + "phf_shared 0.13.1", ] [[package]] @@ -4622,12 +4641,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ "phf_generator", - "phf_shared", + "phf_shared 0.13.1", "proc-macro2", "quote", "syn 2.0.119", ] +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "phf_shared" version = "0.13.1" diff --git a/Cargo.toml b/Cargo.toml index a3cbad80c..76f14f916 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,10 @@ rfd = "0.17" clap = { version = "4", features = ["derive", "string"] } env_logger = "0.11" log = "0.4" -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "102f04c", features = ["serde"] } -kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "5811296", features = ["acis", "offset"] } -kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "5811296" } -graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "88cdae0" } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } +kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "abca4e8", features = ["acis", "offset"] } +kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "abca4e8" } +graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "c63556f" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } # Shared SAVE serialization dispatch + web-worker wire format: one # implementation for the inline (fallback/native) path and the worker path. diff --git a/benches/command_benchmarks.rs b/benches/command_benchmarks.rs index c65439c4a..8e90a5c00 100644 --- a/benches/command_benchmarks.rs +++ b/benches/command_benchmarks.rs @@ -101,7 +101,7 @@ fn push_fixture_entities(doc: &mut CadDocument, quick: bool) -> Vec { d.definition_point = Vector3::new(x + 5.0, y + 3.0, 0.0); d.base.text_middle_point = Vector3::new(x + 5.0, y + 4.0, 0.0); handles.push( - doc.add_entity(EntityType::Dimension(Dimension::Linear(d))) + doc.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(), ); } diff --git a/crates/ocs_plugin_api/Cargo.toml b/crates/ocs_plugin_api/Cargo.toml index 6a528cac8..f5f538245 100644 --- a/crates/ocs_plugin_api/Cargo.toml +++ b/crates/ocs_plugin_api/Cargo.toml @@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true } # Pulled in only by the `host` feature, which adds the `opencadcodec`-typed # `HostApi` runtime surface. The default crate stays dependency-free so engine # crates and external tooling can depend on the manifest/ribbon contract cheaply. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "102f04c", optional = true, features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", optional = true, features = ["serde"] } # Runtime IPC and serialization (host feature only). interprocess = { version = "2", optional = true } @@ -39,7 +39,7 @@ serde_json = "1" serde = { version = "1", features = ["derive"] } cargo-lock = "11" # opencadcodec is scanned at build time to generate the embedded type registry. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "102f04c", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } [dev-dependencies] serde_json = "1" diff --git a/crates/ocs_plugin_api/src/entity_coverage.rs b/crates/ocs_plugin_api/src/entity_coverage.rs index aa2901297..c723c1266 100644 --- a/crates/ocs_plugin_api/src/entity_coverage.rs +++ b/crates/ocs_plugin_api/src/entity_coverage.rs @@ -3583,7 +3583,7 @@ mod tests { #[test] fn unsupported_canvas_kind_has_typed_snapshot_fields() { use crate::host::codec; - let hatch = codec::EntityType::Hatch(codec::entities::Hatch::default()); + let hatch = codec::EntityType::Hatch(Box::new(codec::entities::Hatch::default())); let snapshot = entity_snapshot(&hatch).unwrap(); let fields = snapshot .get("Hatch") @@ -3713,7 +3713,7 @@ mod tests { #[test] fn canvas_layer_patch_preserves_unmapped_hatch_fields() { use crate::host::codec; - let hatch = codec::EntityType::Hatch(codec::entities::Hatch::default()); + let hatch = codec::EntityType::Hatch(Box::new(codec::entities::Hatch::default())); let patched = patch_canvas_layer(&hatch, "HATCHES").unwrap(); assert_eq!(patched.common().layer, "HATCHES"); assert_eq!(hatch.common().layer, "0"); @@ -3809,13 +3809,13 @@ mod tests { })); } hatch.paths.push(path); - let entity = codec::EntityType::Hatch(hatch.clone()); + let entity = codec::EntityType::Hatch(Box::new(hatch.clone())); validate_new_canvas_entity(&entity).unwrap(); let mut invalid = hatch.clone(); invalid.paths.clear(); assert!( - validate_new_canvas_entity(&codec::EntityType::Hatch(invalid)) + validate_new_canvas_entity(&codec::EntityType::Hatch(Box::new(invalid))) .unwrap_err() .contains("at least one boundary path") ); @@ -3824,7 +3824,7 @@ mod tests { invalid.is_solid = false; invalid.pattern_scale = 0.0; assert!( - validate_new_canvas_entity(&codec::EntityType::Hatch(invalid)) + validate_new_canvas_entity(&codec::EntityType::Hatch(Box::new(invalid))) .unwrap_err() .contains("greater than zero") ); @@ -3841,13 +3841,13 @@ mod tests { associative.paths[0].boundary_handles.push(boundary); validate_canvas_entity_references( &document, - &codec::EntityType::Hatch(associative.clone()), + &codec::EntityType::Hatch(Box::new(associative.clone())), ) .unwrap(); associative.paths[0].boundary_handles[0] = codec::Handle::new(u64::MAX); assert!(validate_canvas_entity_references( &document, - &codec::EntityType::Hatch(associative), + &codec::EntityType::Hatch(Box::new(associative)), ) .unwrap_err() .contains("does not exist")); diff --git a/crates/ocs_save/Cargo.toml b/crates/ocs_save/Cargo.toml index 687cbe234..150de8021 100644 --- a/crates/ocs_save/Cargo.toml +++ b/crates/ocs_save/Cargo.toml @@ -10,6 +10,6 @@ publish = false # exactly one implementation. No UI/app dependencies — only the codec + serde. [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "102f04c", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } diff --git a/crates/ocs_web_worker/Cargo.toml b/crates/ocs_web_worker/Cargo.toml index 656935b3c..42aabfcd1 100644 --- a/crates/ocs_web_worker/Cargo.toml +++ b/crates/ocs_web_worker/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "102f04c", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } console_error_panic_hook = "0.1" diff --git a/docs/plugin-template-v2/Cargo.toml b/docs/plugin-template-v2/Cargo.toml index 484fad237..d0a847190 100644 --- a/docs/plugin-template-v2/Cargo.toml +++ b/docs/plugin-template-v2/Cargo.toml @@ -16,4 +16,4 @@ ocs_plugin_api = { path = "../../crates/ocs_plugin_api", features = ["host"] } # entry): the plugin's entities and the host's re-exports are the same types # only when both resolve the same revision. The registration `rustc` / # `acadrust_source` gates enforce this at load time too. -acadrust = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "102f04c" } +acadrust = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3" } diff --git a/plugins/opencad-python/Cargo.lock b/plugins/opencad-python/Cargo.lock index b4227ff83..d5afa7615 100644 --- a/plugins/opencad-python/Cargo.lock +++ b/plugins/opencad-python/Cargo.lock @@ -1245,6 +1245,15 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "oem_cp" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7959d3349f484aec36462f98226983578bf7d33f9b034c32967489c7000e1f" +dependencies = [ + "phf 0.11.3", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1264,7 +1273,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=102f04c#102f04c8ecda1cd409f7ecc4b6eab2dc895c9095" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=e023bc3#e023bc37235dddecf9b3e79c522d8936d15e21e6" dependencies = [ "anyhow", "bitflags", @@ -1276,6 +1285,7 @@ dependencies = [ "itoa", "memmap2", "nom", + "oem_cp", "once_cell", "rayon", "ryu", diff --git a/plugins/opencad-python/examples/create_layout_fixture.rs b/plugins/opencad-python/examples/create_layout_fixture.rs index b76e2158b..5cff8d471 100644 --- a/plugins/opencad-python/examples/create_layout_fixture.rs +++ b/plugins/opencad-python/examples/create_layout_fixture.rs @@ -41,7 +41,7 @@ fn main() -> Result<(), Box> { viewport.twist_angle = std::f64::consts::FRAC_PI_2; viewport.view_target = Vector3::new(5.0, 10.0, 0.0); } - document.add_entity_to_layout(EntityType::Viewport(viewport), "Sheet")?; + document.add_entity_to_layout(EntityType::Viewport(Box::new(viewport)), "Sheet")?; let mut file = std::fs::OpenOptions::new() .write(true) diff --git a/plugins/opencad-python/src/ocs_module.rs b/plugins/opencad-python/src/ocs_module.rs index 929268656..04f70baef 100644 --- a/plugins/opencad-python/src/ocs_module.rs +++ b/plugins/opencad-python/src/ocs_module.rs @@ -406,7 +406,7 @@ mod ocs { text.rotation = rotation; host_ctx::with_host(|host| { host_ctx::ensure_undo_started(host); - host.add_entity(EntityType::MText(text)).value() + host.add_entity(EntityType::MText(Box::new(text))).value() }) .ok_or_else(|| vm.new_runtime_error("ocs: not running inside a PY_ command".to_owned())) } diff --git a/src/app/automation.rs b/src/app/automation.rs index 20ed24436..74b95ce18 100644 --- a/src/app/automation.rs +++ b/src/app/automation.rs @@ -2129,7 +2129,7 @@ mod tests { dimension.definition_point = Vector3::new(0.0, 5.0, 0.0); dimension.base.text_middle_point = Vector3::new(5.0, 5.0, 0.0); document - .add_entity(EntityType::Dimension(Dimension::Linear(dimension))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dimension)))) .unwrap(); crate::modules::draw::modify::explode::bake_dimension_blocks(&mut document); @@ -2152,7 +2152,7 @@ mod tests { dimension.base.text_middle_point = Vector3::new(5.0, 5.0, 0.0); app.tabs[app.active_tab] .scene - .add_entity(EntityType::Dimension(Dimension::Linear(dimension))); + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dimension)))); let path = std::env::temp_dir().join(format!( "ocs_verified_dimension_{}_{}.dwg", std::process::id(), @@ -2190,7 +2190,7 @@ mod tests { let i = app.active_tab; app.tabs[i] .scene - .add_entity(EntityType::Dimension(Dimension::Linear(dimension))); + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dimension)))); let path = std::env::temp_dir().join(format!( "ocs_verified_dimension_follow_up_{}_{}.dwg", std::process::id(), @@ -2240,7 +2240,7 @@ mod tests { app.tabs[i] .scene .document - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); let path = std::env::temp_dir().join(format!( "ocs_verified_dim_{}_{}.dwg", @@ -2330,7 +2330,7 @@ mod tests { viewport.width = 100.0; viewport.height = 50.0; viewport.turn_on(); - scene.add_entity(codec::EntityType::Viewport(viewport)); + scene.add_entity(codec::EntityType::Viewport(Box::new(viewport))); for entity in scene.document.entities_mut() { if let codec::EntityType::Viewport(viewport) = entity { viewport.status.grid_on = true; @@ -2774,7 +2774,7 @@ mod tests { codec::MText::with_value("\\A1;10.5000", codec::types::Vector3::new(10.0, 20.0, 0.0)); app.tabs[i] .scene - .add_entity(codec::EntityType::MText(mtext)); + .add_entity(codec::EntityType::MText(Box::new(mtext))); let q = app.automation_op( r#"{"op":"query","type":"MTEXT","detail":"full","fields":["value","text","height","bounds"]}"#, @@ -3642,7 +3642,7 @@ mod tests { let mut dst_mtext = MText::new(); dst_mtext.value = "DSTM".into(); dst_mtext.height = 2.0; - let dst_mtext_h = app.tabs[i].scene.add_entity(EntityType::MText(dst_mtext)); + let dst_mtext_h = app.tabs[i].scene.add_entity(EntityType::MText(Box::new(dst_mtext))); // Drive the interactive command exactly as the viewport does: // phase 1 source pick, phase 2 destination selection. diff --git a/src/app/command_driver/clipboard.rs b/src/app/command_driver/clipboard.rs index 64827cad8..8e9d687ab 100644 --- a/src/app/command_driver/clipboard.rs +++ b/src/app/command_driver/clipboard.rs @@ -1405,7 +1405,7 @@ mod paste_entities_kernel_tests { fn remaps_leader_annotation_link_to_pasted_handles() { let mut seed = codec::CadDocument::new(); let note = seed - .add_entity(codec::EntityType::MText(codec::entities::MText::new())) + .add_entity(codec::EntityType::MText(Box::new(codec::entities::MText::new()))) .unwrap(); let mut leader = codec::entities::Leader::default(); leader.annotation_handle = note; diff --git a/src/app/command_driver/dim_edit.rs b/src/app/command_driver/dim_edit.rs index 906b4c636..e845bfe9a 100644 --- a/src/app/command_driver/dim_edit.rs +++ b/src/app/command_driver/dim_edit.rs @@ -36,10 +36,12 @@ impl OpenCADStudio { ) { let i = self.active_tab; let valid = matches!( - self.tabs[i].scene.document.get_entity(dimension), - Some(codec::EntityType::Dimension( - codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_) - )) + self.tabs[i] + .scene + .document + .get_entity(dimension) + .and_then(crate::entities::dimension::as_dimension), + Some(codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_)) ); if !valid { self.command_line.push_error( @@ -415,8 +417,12 @@ fn apply_dimspace( requested_spacing: Option, ) -> bool { use codec::entities::Dimension; - let (axis, normal, definition, auto_spacing) = match scene.document.get_entity(base_h) { - Some(codec::EntityType::Dimension(dimension @ Dimension::Linear(d))) => { + let base = scene + .document + .get_entity(base_h) + .and_then(crate::entities::dimension::as_dimension); + let (axis, normal, definition, auto_spacing) = match base { + Some(dimension @ Dimension::Linear(d)) => { let spacing = dimension_auto_spacing( &scene.document, dimension, @@ -433,7 +439,7 @@ fn apply_dimspace( spacing, ) } - Some(codec::EntityType::Dimension(dimension @ Dimension::Aligned(d))) => { + Some(dimension @ Dimension::Aligned(d)) => { let spacing = dimension_auto_spacing( &scene.document, dimension, @@ -471,7 +477,7 @@ fn apply_dimspace( kernel::space::move_to_dimension_spacing([p.x, p.y, p.z], frame, target); *p = codec::types::Vector3::new(point[0], point[1], point[2]); }; - match dim { + match &mut **dim { Dimension::Linear(d) => { slide(&mut d.definition_point); d.base.definition_point = d.definition_point; diff --git a/src/app/command_driver/entity_commit.rs b/src/app/command_driver/entity_commit.rs index 559961a35..b4ca6eac0 100644 --- a/src/app/command_driver/entity_commit.rs +++ b/src/app/command_driver/entity_commit.rs @@ -39,10 +39,8 @@ impl OpenCADStudio { let delta_safe = self.delta_add_safe(i, &entity); let pending = self.begin_undo(i, label, 1, delta_safe); let is_associative_dimension = matches!( - entity, - codec::EntityType::Dimension( - codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_) - ) + crate::entities::dimension::as_dimension(&entity), + Some(codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_)) ); let association_enabled = self.tabs[i].scene.document.header.dimension_associativity == 2; let committed = if preserve_commit_layer { @@ -257,10 +255,8 @@ impl OpenCADStudio { }; let pending = self.begin_undo(i, label, 1, delta_safe); let is_associative_dimension = matches!( - entity, - codec::EntityType::Dimension( - codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_) - ) + crate::entities::dimension::as_dimension(&entity), + Some(codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_)) ); let association_enabled = self.tabs[i].scene.document.header.dimension_associativity == 2; let committed = if preserve_commit_layer { @@ -324,8 +320,8 @@ impl OpenCADStudio { let label = self.history_label_from_active_cmd(i, "DIMENSION"); let association_mode = self.tabs[i].scene.document.header.dimension_associativity; let single_source_dimension = matches!( - &entity, - codec::EntityType::Dimension(codec::entities::Dimension::Ordinate(_)) + crate::entities::dimension::as_dimension(&entity), + Some(codec::entities::Dimension::Ordinate(_)) ); // A dimension placed on the sheet but measuring model geometry // through a viewport carries the compensation as a negative diff --git a/src/app/command_driver/text_edit.rs b/src/app/command_driver/text_edit.rs index 86cb2b713..3cf316d42 100644 --- a/src/app/command_driver/text_edit.rs +++ b/src/app/command_driver/text_edit.rs @@ -160,7 +160,7 @@ impl OpenCADStudio { Operation::Rotate(degrees) => { dimension.base_mut().text_rotation = degrees.to_radians(); } - Operation::Oblique(degrees) => match dimension { + Operation::Oblique(degrees) => match &mut **dimension { codec::entities::Dimension::Linear(value) => { value.ext_line_rotation = degrees.to_radians(); } diff --git a/src/app/command_driver/transform.rs b/src/app/command_driver/transform.rs index 421cdc274..dc4f070e3 100644 --- a/src/app/command_driver/transform.rs +++ b/src/app/command_driver/transform.rs @@ -463,7 +463,7 @@ impl OpenCADStudio { false } }; - match dim { + match &mut **dim { Dimension::Linear(d) => { stretched |= mv(&mut d.first_point); stretched |= mv(&mut d.second_point); diff --git a/src/app/command_driver/viewport.rs b/src/app/command_driver/viewport.rs index 05c5bfb5c..3208a1ca6 100644 --- a/src/app/command_driver/viewport.rs +++ b/src/app/command_driver/viewport.rs @@ -21,7 +21,7 @@ impl OpenCADStudio { }); let label = self.history_label_from_active_cmd(i, "MVIEW"); let pending = self.begin_undo(i, label, 1, true); - let handle = self.commit_entity_handle(codec::EntityType::Viewport(viewport)); + let handle = self.commit_entity_handle(codec::EntityType::Viewport(Box::new(viewport))); if let (Some(handle), Some(saved)) = (handle, saved_view) { if let Some(codec::EntityType::Viewport(viewport)) = self.tabs[i].scene.document.get_entity_mut(handle) @@ -244,7 +244,8 @@ impl OpenCADStudio { viewport.id = 2; viewport.clip_boundary_handle = clip_handle; viewport.status.non_rectangular_clipping = !clip_handle.is_null(); - let viewport_handle = self.commit_entity_handle(codec::EntityType::Viewport(viewport)); + let viewport_handle = + self.commit_entity_handle(codec::EntityType::Viewport(Box::new(viewport))); if let Some(viewport_handle) = viewport_handle { if !created_boundary { let before = self.tabs[i] diff --git a/src/app/commands/pdf_shx_text.rs b/src/app/commands/pdf_shx_text.rs index 3f500d98e..182448672 100644 --- a/src/app/commands/pdf_shx_text.rs +++ b/src/app/commands/pdf_shx_text.rs @@ -294,7 +294,7 @@ impl OpenCADStudio { } else { line.layer }; - scene.add_entity(codec::EntityType::MText(mtext)); + scene.add_entity(codec::EntityType::MText(Box::new(mtext))); erase.extend(line.handles); } erase.sort(); diff --git a/src/app/commands/sheet_set.rs b/src/app/commands/sheet_set.rs index 3da99868d..c62a06dce 100644 --- a/src/app/commands/sheet_set.rs +++ b/src/app/commands/sheet_set.rs @@ -2389,7 +2389,7 @@ impl OpenCADStudio { Vector3::new(mv.center.x - mv.target.x, mv.center.y - mv.target.y, 0.0); vp.view_height = mv.height; vp.custom_scale = scale; - scene.add_entity(codec::EntityType::Viewport(vp)); + scene.add_entity(codec::EntityType::Viewport(Box::new(vp))); // A paper-space named view of the same name frames it. let mut named = codec::tables::View::new(title.as_str()); named.handle = scene.document.allocate_handle(); diff --git a/src/app/commands/ucsfollow.rs b/src/app/commands/ucsfollow.rs index 77213208c..f76c4075c 100644 --- a/src/app/commands/ucsfollow.rs +++ b/src/app/commands/ucsfollow.rs @@ -126,10 +126,10 @@ mod tests { let i = app.active_tab; let first = app.tabs[i] .scene - .add_entity(codec::EntityType::Viewport(codec::entities::Viewport::new())); + .add_entity(codec::EntityType::Viewport(Box::new(codec::entities::Viewport::new()))); let second = app.tabs[i] .scene - .add_entity(codec::EntityType::Viewport(codec::entities::Viewport::new())); + .add_entity(codec::EntityType::Viewport(Box::new(codec::entities::Viewport::new()))); app.tabs[i].scene.active_viewport = Some(first); let _ = app.run_command_line("UCSFOLLOW 1"); assert!(app.tabs[i].scene.ucs_follow()); diff --git a/src/app/commands/view.rs b/src/app/commands/view.rs index 87e312163..5e7a7dfa7 100644 --- a/src/app/commands/view.rs +++ b/src/app/commands/view.rs @@ -1000,7 +1000,10 @@ impl OpenCADStudio { match self.tabs[i] .scene .document - .add_entity_to_layout(codec::EntityType::Viewport(vp), &layout_name) + .add_entity_to_layout( + codec::EntityType::Viewport(Box::new(vp)), + &layout_name, + ) { Ok(handle) => { self.tabs[i].scene.auto_fit_viewport(handle); @@ -2207,7 +2210,7 @@ mod tests { locked_hatch.common.layer = "LOCKED_LAYER".into(); let h_locked_hatch = app.tabs[i] .scene - .add_entity_clone(EntityType::Hatch(locked_hatch)); + .add_entity_clone(EntityType::Hatch(Box::new(locked_hatch))); let h_line = app.tabs[i] .scene diff --git a/src/app/dim_viewport.rs b/src/app/dim_viewport.rs index db3fc9322..49ffaded8 100644 --- a/src/app/dim_viewport.rs +++ b/src/app/dim_viewport.rs @@ -352,7 +352,7 @@ impl OpenCADStudio { fn is_angular_dimension(entity: &EntityType) -> bool { matches!( - entity, - EntityType::Dimension(Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_)) + crate::entities::dimension::as_dimension(entity), + Some(Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_)) ) } diff --git a/src/app/mtext_editor.rs b/src/app/mtext_editor.rs index 2f67342d1..24aa40da0 100644 --- a/src/app/mtext_editor.rs +++ b/src/app/mtext_editor.rs @@ -841,7 +841,7 @@ impl super::OpenCADStudio { // catastrophic cancellation. Insertion is a pure translation, so zeroing // it keeps the layout's shape, wrapping and alignment identical. mt.insertion_point = Vector3::new(0.0, 0.0, 0.0); - let entity = EntityType::MText(mt.clone()); + let entity = EntityType::MText(Box::new(mt.clone())); let anno = 1.0; let bg = self.tabs[i].scene.bg_color; let wires: Vec = tessellate::tessellate( @@ -1753,7 +1753,8 @@ impl super::OpenCADStudio { )); mt.insertion_point = codec::types::Vector3::new(position.x, position.y, position.z); self.push_undo_snapshot(i, "MTEXT"); - let handle = self.commit_entity_handle(plane.place_entity(EntityType::MText(mt))); + let handle = + self.commit_entity_handle(plane.place_entity(EntityType::MText(Box::new(mt)))); if annotative { let scale = self.tabs[i].scene.creation_annotation_scale_handle(); if let (Some(handle), Some(scale)) = (handle, scale) { @@ -1869,7 +1870,8 @@ impl super::OpenCADStudio { )); mt.insertion_point = codec::types::Vector3::new(position.x, position.y, position.z); self.push_undo_snapshot(i, "MTEXT"); - let handle = self.commit_entity_handle(plane.place_entity(EntityType::MText(mt))); + let handle = + self.commit_entity_handle(plane.place_entity(EntityType::MText(Box::new(mt)))); self.tabs[i].dirty = true; if annotative { let scale = self.tabs[i].scene.creation_annotation_scale_handle(); @@ -1885,7 +1887,7 @@ impl super::OpenCADStudio { if let (Some(h), Some(ed)) = (handle, self.mtext_editor.as_mut()) { ed.editing = Some(h); if let Some(EntityType::MText(mtext)) = self.tabs[i].scene.document.get_entity(h) { - ed.original = Some(mtext.clone()); + ed.original = Some((**mtext).clone()); } } } diff --git a/src/app/navigation.rs b/src/app/navigation.rs index 5a7267692..54c8c4e92 100644 --- a/src/app/navigation.rs +++ b/src/app/navigation.rs @@ -497,7 +497,7 @@ mod tests { vp.width = 200.; vp.height = 100.; vp.view_height = 50.; - let handle = scene.add_entity(codec::EntityType::Viewport(vp)); + let handle = scene.add_entity(codec::EntityType::Viewport(Box::new(vp))); scene.active_viewport = Some(handle); let mut camera = scene.navigation_camera(); camera.target = DVec3::new(120., 30., 8.); diff --git a/src/app/plugin_host.rs b/src/app/plugin_host.rs index 3088a9e07..e023cdb31 100644 --- a/src/app/plugin_host.rs +++ b/src/app/plugin_host.rs @@ -943,7 +943,7 @@ impl<'a> HostSession<'a> { frame.common.layer = layer; } self.push_undo("Embed picture"); - let handle = self.add_entity(EntityType::Ole2Frame(frame)); + let handle = self.add_entity(EntityType::Ole2Frame(Box::new(frame))); if handle.is_null() { return Err("the picture frame could not be added".into()); } @@ -6708,7 +6708,7 @@ mod tests { let EntityType::Dimension(dimension) = &mut after else { unreachable!() }; - if let codec::entities::Dimension::Linear(value) = dimension { + if let codec::entities::Dimension::Linear(value) = &mut **dimension { value.second_point.x = 30.0; } ocs_plugin_api::entity_coverage::validate_entity_mutation(&before, &after).unwrap(); @@ -7414,7 +7414,7 @@ mod tests { .unwrap(); let mut viewport = codec::entities::Viewport::new(); viewport.common.owner_handle = owner; - let viewport_handle = host.add_entity(EntityType::Viewport(viewport)); + let viewport_handle = host.add_entity(EntityType::Viewport(Box::new(viewport))); let scale_handle = host.document_mut().allocate_handle(); let mut scale = codec::objects::Scale::new("1:1", 1.0, 1.0); scale.handle = scale_handle; @@ -10861,7 +10861,7 @@ mod tests { bare.height = 30.0; let bare = host .document_mut() - .add_entity(EntityType::Viewport(bare)) + .add_entity(EntityType::Viewport(Box::new(bare))) .unwrap(); assert_eq!( host.document().get_entity(bare).map(|e| match e { diff --git a/src/app/properties.rs b/src/app/properties.rs index e376a84e9..1b88ad023 100644 --- a/src/app/properties.rs +++ b/src/app/properties.rs @@ -1489,12 +1489,14 @@ impl OpenCADStudio { if let Some((anno_field, insert_after)) = anno { let is_anno = crate::scene::annotative::is_annotative(doc, entity) || match entity { - codec::EntityType::Dimension(codec::entities::Dimension::Arc( - dimension, - )) => crate::scene::annotative::dim_style_is_annotative( - doc, - &dimension.base.style_name, - ), + codec::EntityType::Dimension(dimension) + if matches!(**dimension, codec::entities::Dimension::Arc(_)) => + { + crate::scene::annotative::dim_style_is_annotative( + doc, + &dimension.base().style_name, + ) + } codec::EntityType::Tolerance(_) => { crate::scene::annotative::annotation_style_is_annotative(doc, entity) } @@ -1530,7 +1532,9 @@ impl OpenCADStudio { "annotative", yes_no_choice(t.is_annotative || is_anno), ), - codec::EntityType::Dimension(codec::entities::Dimension::Arc(_)) => { + codec::EntityType::Dimension(dimension) + if matches!(**dimension, codec::entities::Dimension::Arc(_)) => + { set_row( &mut sections, "annotative", @@ -1683,10 +1687,14 @@ impl OpenCADStudio { format!("{} ({})", t!("Surface"), t!("Extrusion")) } // The reference names an angular dimension by its kind. - codec::EntityType::Dimension(codec::entities::Dimension::Angular2Ln(_)) => { + codec::EntityType::Dimension(dimension) + if matches!(**dimension, codec::entities::Dimension::Angular2Ln(_)) => + { t!("Angular Dimension").into_owned() } - codec::EntityType::Dimension(codec::entities::Dimension::Angular3Pt(_)) => { + codec::EntityType::Dimension(dimension) + if matches!(**dimension, codec::entities::Dimension::Angular3Pt(_)) => + { t!("3 Point Angular Dimension").into_owned() } codec::EntityType::Underlay(underlay) => match underlay.underlay_type { @@ -1719,22 +1727,14 @@ impl OpenCADStudio { title } else { use codec::entities::Dimension; - match entity { - codec::EntityType::Dimension(Dimension::Aligned(_)) => { - t!("Aligned Dimensional Constraint") - } - codec::EntityType::Dimension(Dimension::Angular2Ln(_)) => { - t!("Angular Dimension (Dynamic)") - } - codec::EntityType::Dimension(Dimension::Angular3Pt(_)) => { + match crate::entities::dimension::as_dimension(entity) { + Some(Dimension::Aligned(_)) => t!("Aligned Dimensional Constraint"), + Some(Dimension::Angular2Ln(_)) => t!("Angular Dimension (Dynamic)"), + Some(Dimension::Angular3Pt(_)) => { t!("3 Point Angular Dimension (Dynamic)") } - codec::EntityType::Dimension(Dimension::Radius(_)) => { - t!("Radius Dimensional Constraint") - } - codec::EntityType::Dimension(Dimension::Diameter(_)) => { - t!("Diameter Dimensional Constraint") - } + Some(Dimension::Radius(_)) => t!("Radius Dimensional Constraint"), + Some(Dimension::Diameter(_)) => t!("Diameter Dimensional Constraint"), _ => t!("Linear Dimensional Constraint"), } .into_owned() @@ -2743,7 +2743,7 @@ handles={handles_ms:.1} panel={:.1} ribbon={ribbon_ms:.1} tail={:.1} selected={} // scale are available. if let codec::EntityType::Dimension(dim) = contextual.as_ref() { if matches!( - dim, + &**dim, codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_) ) && !dim.base().text_user_positioned @@ -2780,13 +2780,17 @@ handles={handles_ms:.1} panel={:.1} ribbon={ribbon_ms:.1} tail={:.1} selected={} } } } - let dynamic_angle = match contextual.as_ref() { - codec::EntityType::Dimension( - dim @ (codec::entities::Dimension::Angular2Ln(_) - | codec::entities::Dimension::Angular3Pt(_)), - ) if self.tabs[i].scene.is_dynamic_dimension(handle) => Some(dim), - _ => None, - }; + let contextual_dimension = + crate::entities::dimension::as_dimension(contextual.as_ref()); + let dynamic_angle = contextual_dimension + .filter(|dim| { + matches!( + dim, + codec::entities::Dimension::Angular2Ln(_) + | codec::entities::Dimension::Angular3Pt(_) + ) + }) + .filter(|_| self.tabs[i].scene.is_dynamic_dimension(handle)); if let Some(dim) = dynamic_angle { // A dynamic angle shows a triangle at each end of its arc // pointing away from it, and squares at the arc point and @@ -3060,8 +3064,8 @@ handles={handles_ms:.1} panel={:.1} ribbon={ribbon_ms:.1} tail={:.1} selected={} ) -> Option { let i = self.active_tab; let tracks_dimension_chain = matches!( - &entity, - codec::EntityType::Dimension( + crate::entities::dimension::as_dimension(&entity), + Some( codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_) | codec::entities::Dimension::Angular2Ln(_) diff --git a/src/app/update/block_ops_tests.rs b/src/app/update/block_ops_tests.rs index 8afcf5910..5d3c49121 100644 --- a/src/app/update/block_ops_tests.rs +++ b/src/app/update/block_ops_tests.rs @@ -224,7 +224,7 @@ fn fixture_dimension_reference(app: &mut OpenCADStudio) -> String { dimension.base.style_name = "BO_ARROWSTYLE".to_string(); app.tabs[i] .scene - .add_entity(EntityType::Dimension(Dimension::Aligned(dimension))); + .add_entity(EntityType::Dimension(Box::new(Dimension::Aligned(dimension)))); name.to_string() } @@ -244,7 +244,7 @@ fn fixture_dimension_name_reference(app: &mut OpenCADStudio) -> String { dimension.base.style_name = "BO_ARROWNAMESTYLE".to_string(); app.tabs[i] .scene - .add_entity(EntityType::Dimension(Dimension::Aligned(dimension))); + .add_entity(EntityType::Dimension(Box::new(Dimension::Aligned(dimension)))); name.to_string() } diff --git a/src/app/update/command.rs b/src/app/update/command.rs index 2d2a8ca8e..83e6fbc47 100644 --- a/src/app/update/command.rs +++ b/src/app/update/command.rs @@ -2913,9 +2913,12 @@ impl OpenCADStudio { &value, ); if applied && field == "dim_text_inside" { - if let Some(codec::EntityType::Dimension( - codec::entities::Dimension::LargeRadial(dimension), - )) = app.tabs[i].scene.document.get_entity_mut(handle) + let radial = app.tabs[i] + .scene + .document + .get_entity_mut(handle) + .and_then(crate::entities::dimension::as_dimension_mut); + if let Some(codec::entities::Dimension::LargeRadial(dimension)) = radial { dimension.base.text_user_positioned = false; } @@ -4182,9 +4185,13 @@ impl OpenCADStudio { &val, ); if applied && field == "dim_text_inside" { - if let Some(codec::EntityType::Dimension( - codec::entities::Dimension::LargeRadial(dimension), - )) = self.tabs[i].scene.document.get_entity_mut(handle) + if let Some(codec::entities::Dimension::LargeRadial( + dimension, + )) = self.tabs[i] + .scene + .document + .get_entity_mut(handle) + .and_then(crate::entities::dimension::as_dimension_mut) { dimension.base.text_user_positioned = false; } diff --git a/src/app/update/graphic_attributes.rs b/src/app/update/graphic_attributes.rs index 3157cd1bc..d34314779 100644 --- a/src/app/update/graphic_attributes.rs +++ b/src/app/update/graphic_attributes.rs @@ -1084,7 +1084,7 @@ mod tests { .document .entities() .filter_map(|entity| match entity { - EntityType::Hatch(hatch) => Some(hatch), + EntityType::Hatch(hatch) => Some(&**hatch), _ => None, }) .collect() diff --git a/src/app/viewport_dimension_tests.rs b/src/app/viewport_dimension_tests.rs index 0866e4f8d..94f0bd326 100644 --- a/src/app/viewport_dimension_tests.rs +++ b/src/app/viewport_dimension_tests.rs @@ -28,7 +28,7 @@ fn fixture() -> (OpenCADStudio, Handle, ViewportFrame) { viewport.custom_scale = 0.1; viewport.view_direction = Vector3::UNIT_Z; viewport.turn_on(); - let viewport = scene.add_entity(EntityType::Viewport(viewport)); + let viewport = scene.add_entity(EntityType::Viewport(Box::new(viewport))); let frame = scene.viewport_frame(viewport).unwrap(); scene.document.header.dimension_associativity = 2; let i = app.active_tab; @@ -323,7 +323,7 @@ fn viewport_dimension_linear_aligned_and_radial_object_picks() { assert_eq!( preview_text( &app, - &EntityType::Dimension(dimension(&app.tabs[i].scene.document).clone()) + &EntityType::Dimension(Box::new(dimension(&app.tabs[i].scene.document).clone())) ), value, "{name}" @@ -361,7 +361,7 @@ fn viewport_dimension_angular_preserves_angle_without_length_factor() { let _ = app.feed_command(StepInput::Point(place)); let doc = &app.tabs[app.active_tab].scene.document; assert_eq!( - preview_text(&app, &EntityType::Dimension(dimension(doc).clone())), + preview_text(&app, &EntityType::Dimension(Box::new(dimension(doc).clone()))), value ); assert!((dimension(doc).measurement() - 90.0).abs() < 1e-5); @@ -1461,9 +1461,9 @@ fn viewport_dimension_invalid_paths_leave_no_partial_association() { Vector3::new(55.0, 60.0, 0.0), ))); for (source, path) in [(model, vec![Handle::new(u64::MAX)]), (leaf, vec![root])] { - let dim = scene.add_entity(EntityType::Dimension(Dimension::Aligned( + let dim = scene.add_entity(EntityType::Dimension(Box::new(Dimension::Aligned( DimensionAligned::new(Vector3::new(50.0, 50.0, 0.0), Vector3::new(55.0, 50.0, 0.0)), - ))); + )))); let invalid = AcceptedSnap { paper_point: DVec3::new(50.0, 50.0, 0.0), model_point: DVec3::ZERO, diff --git a/src/entities/dimension.rs b/src/entities/dimension.rs index 9b3eb9129..7c2bc8d6d 100644 --- a/src/entities/dimension.rs +++ b/src/entities/dimension.rs @@ -3248,7 +3248,7 @@ pub(crate) fn materialize_large_radial_text_position( let Some(EntityType::Dimension(dimension)) = document.get_entity(handle) else { return; }; - if !matches!(dimension, Dimension::LargeRadial(_)) || dimension.base().text_user_positioned { + if !matches!(&**dimension, Dimension::LargeRadial(_)) || dimension.base().text_user_positioned { return; } let source = document.dim_styles.iter().find(|style| { @@ -3262,8 +3262,8 @@ pub(crate) fn materialize_large_radial_text_position( .map(|style| resolved_dimension_style(style, dimension, document)) .map(|style| styled_dimension_text_position(dimension, &style, 1.0)) .unwrap_or_else(|| dimension_text_pos_f64(dimension, None, 2.5, 1.0)); - if let Some(EntityType::Dimension(Dimension::LargeRadial(radial))) = - document.get_entity_mut(handle) + if let Some(Dimension::LargeRadial(radial)) = + document.get_entity_mut(handle).and_then(as_dimension_mut) { radial.base.text_middle_point = position; } @@ -6491,7 +6491,7 @@ fn dimension_text_entity( } mtext.normal = base.normal; mtext.common = base.common.clone(); - return Some(EntityType::MText(mtext)); + return Some(EntityType::MText(Box::new(mtext))); } let value = if style.is_some_and(|style| style.dimtxtdirection) { @@ -7150,7 +7150,7 @@ fn dimension_tolerance_entity( mtext.style = primary_style; mtext.attachment_point = codec::entities::AttachmentPoint::MiddleCenter; mtext.common = primary_common; - return Some(EntityType::MText(mtext)); + return Some(EntityType::MText(Box::new(mtext))); } let mut t = Text::with_value(tol, pos) @@ -9559,3 +9559,22 @@ mod layout_parity_tests { ); } } + +/// The dimension an entity is, if it is one. The variant holds it boxed, so +/// a pattern cannot reach into it; match on this instead. +pub(crate) fn as_dimension(entity: &codec::EntityType) -> Option<&codec::entities::Dimension> { + match entity { + codec::EntityType::Dimension(dimension) => Some(dimension), + _ => None, + } +} + +/// [`as_dimension`], mutably. +pub(crate) fn as_dimension_mut( + entity: &mut codec::EntityType, +) -> Option<&mut codec::entities::Dimension> { + match entity { + codec::EntityType::Dimension(dimension) => Some(dimension), + _ => None, + } +} diff --git a/src/entities/object_data.rs b/src/entities/object_data.rs index d55d2cf86..71f9116bd 100644 --- a/src/entities/object_data.rs +++ b/src/entities/object_data.rs @@ -620,7 +620,7 @@ fn dynamic_data_text(data: &DynamicBlockData) -> String { "{}; dependencies {}; parameters {}; distance multiplier {:.6}; angle {:.6}", value.action.element.name, value.action.dependencies.len(), - value.action.parameter_ids.len(), + value.action.action_ids.len(), value.offsets.distance_multiplier, value.offsets.angle_offset ), @@ -628,14 +628,14 @@ fn dynamic_data_text(data: &DynamicBlockData) -> String { "{}; dependencies {}; parameters {}; connections {}", value.action.element.name, value.action.dependencies.len(), - value.action.parameter_ids.len(), + value.action.action_ids.len(), value.connections.len() ), DynamicBlockData::RotateAction(value) | DynamicBlockData::ScaleAction(value) => format!( "{}; dependencies {}; parameters {}; base {:.6},{:.6},{:.6}; dependent {}", value.action.action.element.name, value.action.action.dependencies.len(), - value.action.action.parameter_ids.len(), + value.action.action.action_ids.len(), value.action.base_point.x, value.action.base_point.y, value.action.base_point.z, diff --git a/src/entities/text_support.rs b/src/entities/text_support.rs index 16e827685..6d8b9d361 100644 --- a/src/entities/text_support.rs +++ b/src/entities/text_support.rs @@ -676,7 +676,9 @@ pub fn adapt_mtext_paragraphs( ATab::Left(_) => TabKind::Left, ATab::Center(_) => TabKind::Center, ATab::Right(_) => TabKind::Right, - ATab::Decimal(..) => TabKind::Decimal, + ATab::Decimal(..) | ATab::DecimalWithCharacter { .. } => { + TabKind::Decimal + } }; TabStop { position: ts.position() as f32 * entity_height, diff --git a/src/entities/traits.rs b/src/entities/traits.rs index 4fc27b30a..9a95575b7 100644 --- a/src/entities/traits.rs +++ b/src/entities/traits.rs @@ -158,6 +158,16 @@ pub trait TextContent { fn replace_text(&mut self, search: &str, rep: &str); } +/// Entity variants holding their entity boxed (MTEXT) dispatch through here. +impl TextContent for Box { + fn text_content(&self) -> Option { + (**self).text_content() + } + fn replace_text(&mut self, search: &str, rep: &str) { + (**self).replace_text(search, rep) + } +} + /// Human-readable variant name used by Quick Select / Select Similar /// filtering. Stable across releases — the strings here are the canonical /// type identifiers throughout the UI. diff --git a/src/entity_creation.rs b/src/entity_creation.rs index f07bfa678..96e5c29c4 100644 --- a/src/entity_creation.rs +++ b/src/entity_creation.rs @@ -638,7 +638,7 @@ pub(crate) fn build_entity( if let Some(style) = text_style_field(spec, document)? { mtext.style = style; } - EntityType::MText(mtext) + EntityType::MText(Box::new(mtext)) } "INSERT" => { let block = spec["block"].as_str().unwrap_or(""); @@ -724,7 +724,7 @@ pub(crate) fn build_entity( let mut path = BoundaryPath::external(); path.add_edge(BoundaryEdge::Polyline(PolylineEdge::new(vertices, true))); hatch.paths.push(path); - EntityType::Hatch(hatch) + EntityType::Hatch(Box::new(hatch)) } other => { return Err(failure( diff --git a/src/io/linetypes.rs b/src/io/linetypes.rs index f029496e5..7afc4b8ba 100644 --- a/src/io/linetypes.rs +++ b/src/io/linetypes.rs @@ -472,6 +472,7 @@ fn complex_elements( scale: decimal(*scale), rotation: decimal(*rot_deg).to_radians(), absolute_rotation: false, + source_flags: 0, offset: [decimal(*x), decimal(*y)], } } @@ -492,6 +493,7 @@ fn complex_elements( scale: decimal(*scale), rotation: decimal(*rot_deg).to_radians(), absolute_rotation: false, + source_flags: 0, offset: [decimal(*x), decimal(*y)], }, }; diff --git a/src/io/mod.rs b/src/io/mod.rs index 11392d93f..a0e639614 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -2969,7 +2969,7 @@ mod dimension_arrow_save_tests { dimension.definition_point = Vector3::new(0.0, 20.0, 0.0); dimension.base.definition_point = dimension.definition_point; dimension.base.text_middle_point = Vector3::new(50.0, 20.0, 0.0); - doc.add_entity(EntityType::Dimension(Dimension::Linear(dimension))) + doc.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dimension)))) .unwrap(); doc } @@ -3545,11 +3545,12 @@ mod prepare_save_tests { dim.base.definition_point = Vector3::ZERO; dim.base.common.handle = doc.allocate_handle(); let handle = dim.base.common.handle; - doc.add_entity(EntityType::Dimension(Dimension::Linear(dim))) + doc.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dim)))) .unwrap(); let prepared = prepare_document_for_save(doc.clone(), doc.version); - let EntityType::Dimension(Dimension::Linear(linear)) = prepared.get_entity(handle).unwrap() + let Some(Dimension::Linear(linear)) = + crate::entities::dimension::as_dimension(prepared.get_entity(handle).unwrap()) else { panic!("dimension missing from prepared clone"); }; @@ -3565,7 +3566,9 @@ mod prepare_save_tests { assert_eq!(linear.base.definition_point, linear.definition_point); // The live document is untouched: no block name, stale group-10. - let EntityType::Dimension(Dimension::Linear(live)) = doc.get_entity(handle).unwrap() else { + let Some(Dimension::Linear(live)) = + crate::entities::dimension::as_dimension(doc.get_entity(handle).unwrap()) + else { panic!("dimension missing from live document"); }; assert!(live.base.block_name.is_empty()); @@ -3582,7 +3585,7 @@ mod prepare_save_tests { let mut dim = DimensionLinear::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(10.0, 0.0, 0.0)); dim.base.common.handle = doc.allocate_handle(); - doc.add_entity(EntityType::Dimension(Dimension::Linear(dim))) + doc.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dim)))) .unwrap(); for ext in ["dwg", "dxf"] { let inline = save_to_bytes(&doc, ext, codec::DxfVersion::AC1032).expect("inline"); diff --git a/src/io/ole_embed.rs b/src/io/ole_embed.rs index c82e93cdc..29a87cec3 100644 --- a/src/io/ole_embed.rs +++ b/src/io/ole_embed.rs @@ -168,7 +168,7 @@ pub fn add_embedded_image( ) -> Result { let (upper_left, lower_right) = corners_from_placement(origin, width, image.aspect()); let ole = build_embedded_ole(image, upper_left, lower_right); - doc.add_entity(codec::EntityType::Ole2Frame(ole)) + doc.add_entity(codec::EntityType::Ole2Frame(Box::new(ole))) .map_err(|e| e.to_string()) } diff --git a/src/io/xref.rs b/src/io/xref.rs index 541362102..13c34f34f 100644 --- a/src/io/xref.rs +++ b/src/io/xref.rs @@ -3336,7 +3336,7 @@ mod tests { // Hatch (pattern names have no table — preserved verbatim). let mut hatch = codec::entities::Hatch::new(); hatch.pattern.name = "ANSI31".to_string(); - doc.add_entity(codec::EntityType::Hatch(hatch)).unwrap(); + doc.add_entity(codec::EntityType::Hatch(Box::new(hatch))).unwrap(); // Dim-style reference via a tolerance entity. doc.dim_styles .add(codec::tables::DimStyle::new("ARCH")) diff --git a/src/modules/annotate/aligned_dim.rs b/src/modules/annotate/aligned_dim.rs index ea0e326d6..5d62c941e 100644 --- a/src/modules/annotate/aligned_dim.rs +++ b/src/modules/annotate/aligned_dim.rs @@ -95,7 +95,7 @@ pub(crate) fn aligned_dimension_entity( crate::entities::dimension::reset_automatic_text_position(&mut dim.base); dim.base.actual_measurement = dim.measurement(); crate::entities::dimension::set_dimension_text_override(&mut dim.base, text_override); - EntityType::Dimension(Dimension::Aligned(dim)) + EntityType::Dimension(Box::new(Dimension::Aligned(dim))) } impl CadCommand for AlignedDimensionCommand { diff --git a/src/modules/annotate/angular_dim.rs b/src/modules/annotate/angular_dim.rs index e101214fd..309d379e0 100644 --- a/src/modules/annotate/angular_dim.rs +++ b/src/modules/annotate/angular_dim.rs @@ -232,7 +232,7 @@ impl AngularDimensionCommand { } fn commit(&self, dimension: Dimension) -> CmdResult { - let entity = self.plane.place_entity(EntityType::Dimension(dimension)); + let entity = self.plane.place_entity(EntityType::Dimension(Box::new(dimension))); CmdResult::CommitDimension { entity, association: DimensionAssociationInput::Explicit(self.source_refs.clone()), @@ -1242,7 +1242,7 @@ pub(crate) fn angular_two_line_entity( dim.base.insertion_point = dim.dimension_arc; dim.base.actual_measurement = dim.measurement_degrees(); crate::entities::dimension::set_dimension_text_override(&mut dim.base, text); - Some(EntityType::Dimension(Dimension::Angular2Ln(dim))) + Some(EntityType::Dimension(Box::new(Dimension::Angular2Ln(dim)))) } /// A three-point angular dimension (vertex, two points, arc point), for a @@ -1261,7 +1261,7 @@ pub(crate) fn angular_three_point_entity( dim.base.insertion_point = dim.definition_point; dim.base.actual_measurement = dim.measurement_degrees(); crate::entities::dimension::set_dimension_text_override(&mut dim.base, text); - Some(EntityType::Dimension(Dimension::Angular3Pt(dim))) + Some(EntityType::Dimension(Box::new(Dimension::Angular3Pt(dim)))) } fn v3(point: DVec3) -> Vector3 { diff --git a/src/modules/annotate/arc_length_dim.rs b/src/modules/annotate/arc_length_dim.rs index 7dcfc758e..bd2476b9a 100644 --- a/src/modules/annotate/arc_length_dim.rs +++ b/src/modules/annotate/arc_length_dim.rs @@ -258,7 +258,7 @@ impl ArcLengthDimensionCommand { |handle| DimensionAssociationInput::Explicit(selection.association_sources(handle)), ); CmdResult::CommitDimension { - entity: plane.place_entity(EntityType::Dimension(Dimension::Arc(dimension))), + entity: plane.place_entity(EntityType::Dimension(Box::new(Dimension::Arc(dimension)))), association, preserve_base_style: false, continue_command: false, diff --git a/src/modules/annotate/diameter_dim.rs b/src/modules/annotate/diameter_dim.rs index 800370674..1dad74115 100644 --- a/src/modules/annotate/diameter_dim.rs +++ b/src/modules/annotate/diameter_dim.rs @@ -83,7 +83,7 @@ impl DiameterDimensionCommand { if let Some(angle) = self.text_angle { dim.base.text_rotation = angle; } - plane.place_entity(EntityType::Dimension(Dimension::Diameter(dim))) + plane.place_entity(EntityType::Dimension(Box::new(Dimension::Diameter(dim)))) } } @@ -103,7 +103,7 @@ pub(crate) fn diameter_constraint_entity( dim.leader_length = chord.distance(location).max(radius * 0.5); dim.base.actual_measurement = dim.measurement(); crate::entities::dimension::set_dimension_text_override(&mut dim.base, text); - Some(EntityType::Dimension(Dimension::Diameter(dim))) + Some(EntityType::Dimension(Box::new(Dimension::Diameter(dim)))) } impl CadCommand for DiameterDimensionCommand { diff --git a/src/modules/annotate/dim_baseline.rs b/src/modules/annotate/dim_baseline.rs index 23612384c..4d2e862e8 100644 --- a/src/modules/annotate/dim_baseline.rs +++ b/src/modules/annotate/dim_baseline.rs @@ -151,7 +151,7 @@ impl DimBaselineCommand { let increment = self.effective_increment(&style.style_name); let plane = plane_from_normal(dimension.base().definition_point, style.normal); let pick = pick.and_then(|point| plane.project(point.to_array()).map(Vec2::from)); - let kind = match dimension { + let kind = match &**dimension { Dimension::Linear(source) => { let first = project(&plane, source.first_point); let second = project(&plane, source.second_point); @@ -441,7 +441,7 @@ impl CadCommand for DimBaselineCommand { self.committed += 1; self.advance(1.0); CmdResult::CommitDimension { - entity: EntityType::Dimension(dimension), + entity: EntityType::Dimension(Box::new(dimension)), association: DimensionAssociationInput::Infer(None), preserve_base_style: self.preserve_base_style, continue_command: true, @@ -489,7 +489,7 @@ impl CadCommand for DimBaselineCommand { fn dimension_preview(&self, cursor: DVec3) -> Option> { self.build_dimension(cursor).map(|dimension| { vec![DimensionPreview { - entity: EntityType::Dimension(dimension), + entity: EntityType::Dimension(Box::new(dimension)), preserve_base_style: self.preserve_base_style, }] }) diff --git a/src/modules/annotate/dim_continue.rs b/src/modules/annotate/dim_continue.rs index 8922e019b..1496f956d 100644 --- a/src/modules/annotate/dim_continue.rs +++ b/src/modules/annotate/dim_continue.rs @@ -117,7 +117,7 @@ impl DimContinueCommand { let style = SourceStyle::from_base(dimension.base()); let plane = plane_from_normal(dimension.base().definition_point, style.normal); let pick = pick_world.and_then(|point| plane.project(point.to_array()).map(Vec2::from)); - let kind = match dimension { + let kind = match &**dimension { Dimension::Linear(source) => { let rotation = source.rotation; let perpendicular = Vec2::new(-rotation.sin(), rotation.cos()); @@ -383,7 +383,7 @@ impl CadCommand for DimContinueCommand { } self.advance(point); CmdResult::CommitDimension { - entity: EntityType::Dimension(dimension), + entity: EntityType::Dimension(Box::new(dimension)), association: DimensionAssociationInput::Infer(None), preserve_base_style: self.preserve_base_style, continue_command: true, @@ -433,7 +433,7 @@ impl CadCommand for DimContinueCommand { fn dimension_preview(&self, cursor: DVec3) -> Option> { self.build_dimension(cursor).map(|dimension| { vec![DimensionPreview { - entity: EntityType::Dimension(dimension), + entity: EntityType::Dimension(Box::new(dimension)), preserve_base_style: self.preserve_base_style, }] }) diff --git a/src/modules/annotate/dimjogline.rs b/src/modules/annotate/dimjogline.rs index a80260e16..b63527637 100644 --- a/src/modules/annotate/dimjogline.rs +++ b/src/modules/annotate/dimjogline.rs @@ -145,13 +145,17 @@ impl CadCommand for DimJogLineCommand { } fn on_entity_pick(&mut self, handle: Handle, _point: DVec3) -> CmdResult { - let Some(EntityType::Dimension(dimension @ (Dimension::Linear(_) | Dimension::Aligned(_)))) = - self.picked_entity.take() - else { + let Some(EntityType::Dimension(dimension)) = self.picked_entity.take() else { return CmdResult::ReportError( t!("DIMJOGLINE: select a linear or aligned dimension.").into_owned(), ); }; + let dimension = *dimension; + if !matches!(dimension, Dimension::Linear(_) | Dimension::Aligned(_)) { + return CmdResult::ReportError( + t!("DIMJOGLINE: select a linear or aligned dimension.").into_owned(), + ); + } if handle.is_null() { return CmdResult::NeedPoint; } diff --git a/src/modules/annotate/dimspace.rs b/src/modules/annotate/dimspace.rs index ef0ef9e64..8c5959ff8 100644 --- a/src/modules/annotate/dimspace.rs +++ b/src/modules/annotate/dimspace.rs @@ -104,8 +104,8 @@ impl CadCommand for DimSpaceCommand { for selected in entities { if selected.handle != *base && matches!( - selected.entity, - EntityType::Dimension( + crate::entities::dimension::as_dimension(&selected.entity), + Some( codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_) ) @@ -124,11 +124,14 @@ impl CadCommand for DimSpaceCommand { match &mut self.step { Step::PickBase => { if !matches!( - self.picked_entity.take(), - Some(EntityType::Dimension( + self.picked_entity + .take() + .as_ref() + .and_then(crate::entities::dimension::as_dimension), + Some( codec::entities::Dimension::Linear(_) | codec::entities::Dimension::Aligned(_) - )) + ) ) { return CmdResult::ReportError( t!("DIMSPACE: select a linear or aligned dimension.").into_owned(), diff --git a/src/modules/annotate/field_cmd.rs b/src/modules/annotate/field_cmd.rs index 7ab6a2920..6d24ae657 100644 --- a/src/modules/annotate/field_cmd.rs +++ b/src/modules/annotate/field_cmd.rs @@ -158,7 +158,7 @@ impl CadCommand for FieldPlaceCommand { mtext.attachment_point = self.attachment; // No defined width: the field text never wraps. mtext.rectangle_width = 0.0; - CmdResult::CommitAndExit(self.plane.place_entity(EntityType::MText(mtext))) + CmdResult::CommitAndExit(self.plane.place_entity(EntityType::MText(Box::new(mtext)))) } fn on_enter(&mut self) -> CmdResult { diff --git a/src/modules/annotate/jogged_radius_dim.rs b/src/modules/annotate/jogged_radius_dim.rs index f566d5bf8..fe43b88bb 100644 --- a/src/modules/annotate/jogged_radius_dim.rs +++ b/src/modules/annotate/jogged_radius_dim.rs @@ -138,7 +138,9 @@ impl JoggedRadiusDimensionCommand { ); CmdResult::CommitDimension { - entity: plane.place_entity(EntityType::Dimension(Dimension::LargeRadial(dimension))), + entity: plane.place_entity(EntityType::Dimension(Box::new(Dimension::LargeRadial( + dimension, + )))), association, preserve_base_style: false, continue_command: false, diff --git a/src/modules/annotate/leader_cmd.rs b/src/modules/annotate/leader_cmd.rs index 654c7c281..6f03e83f1 100644 --- a/src/modules/annotate/leader_cmd.rs +++ b/src/modules/annotate/leader_cmd.rs @@ -151,7 +151,7 @@ impl LeaderCommand { CmdResult::CommitManyAndEditText { entities: vec![ self.plane.place_entity(EntityType::Leader(leader)), - self.plane.place_entity(EntityType::MText(mtext)), + self.plane.place_entity(EntityType::MText(Box::new(mtext))), ], edit_index: 1, open_editor, diff --git a/src/modules/annotate/linear_dim.rs b/src/modules/annotate/linear_dim.rs index c997067cd..ee365950e 100644 --- a/src/modules/annotate/linear_dim.rs +++ b/src/modules/annotate/linear_dim.rs @@ -141,7 +141,7 @@ pub(crate) fn linear_dimension_entity( crate::entities::dimension::reset_automatic_text_position(&mut dim.base); dim.base.actual_measurement = dim.measurement(); crate::entities::dimension::set_dimension_text_override(&mut dim.base, text_override); - EntityType::Dimension(Dimension::Linear(dim)) + EntityType::Dimension(Box::new(Dimension::Linear(dim))) } impl CadCommand for LinearDimensionCommand { diff --git a/src/modules/annotate/mleader_cmd.rs b/src/modules/annotate/mleader_cmd.rs index 81eef14ea..c1cc4cab8 100644 --- a/src/modules/annotate/mleader_cmd.rs +++ b/src/modules/annotate/mleader_cmd.rs @@ -648,7 +648,7 @@ impl CadCommand for MLeaderCommand { text.insertion_point.z, )); self.text = text.value.clone(); - self.selected_mtext = Some(text); + self.selected_mtext = Some(*text); self.content_type = LeaderContentType::MText; self.order = CreationOrder::ContentFirst; self.step = Step::PickPoints; diff --git a/src/modules/annotate/ordinate_dim.rs b/src/modules/annotate/ordinate_dim.rs index 0aa9ddb48..b8dff08b5 100644 --- a/src/modules/annotate/ordinate_dim.rs +++ b/src/modules/annotate/ordinate_dim.rs @@ -80,7 +80,7 @@ impl OrdinateDimCommand { } dim.refresh_measurement(); self.plane - .place_entity(EntityType::Dimension(Dimension::Ordinate(dim))) + .place_entity(EntityType::Dimension(Box::new(Dimension::Ordinate(dim)))) } } diff --git a/src/modules/annotate/qdim.rs b/src/modules/annotate/qdim.rs index 3f1f2357a..e60029e5c 100644 --- a/src/modules/annotate/qdim.rs +++ b/src/modules/annotate/qdim.rs @@ -341,7 +341,7 @@ impl QdimCommand { ]); ( self.plane - .place_entity(EntityType::Dimension(Dimension::Linear(dimension))), + .place_entity(EntityType::Dimension(Box::new(Dimension::Linear(dimension)))), association, ) } @@ -366,7 +366,7 @@ impl QdimCommand { dimension.refresh_measurement(); ( self.plane - .place_entity(EntityType::Dimension(Dimension::Ordinate(dimension))), + .place_entity(EntityType::Dimension(Box::new(Dimension::Ordinate(dimension)))), DimensionAssociationInput::Explicit(vec![point.sources.first().copied()]), ) } @@ -405,7 +405,7 @@ impl QdimCommand { dimension.base.text_user_positioned = true; dimension.leader_length = chord.distance(text); dimension.base.actual_measurement = dimension.measurement(); - EntityType::Dimension(Dimension::Radius(dimension)) + EntityType::Dimension(Box::new(Dimension::Radius(dimension))) } else { let opposite = center - direction * radius; let mut dimension = DimensionDiameter::new(v3(chord), v3(opposite)); @@ -415,7 +415,7 @@ impl QdimCommand { dimension.base.text_user_positioned = true; dimension.leader_length = chord.distance(text); dimension.base.actual_measurement = dimension.measurement(); - EntityType::Dimension(Dimension::Diameter(dimension)) + EntityType::Dimension(Box::new(Dimension::Diameter(dimension))) }; (self.plane.place_entity(entity), association) }) @@ -680,7 +680,7 @@ fn preview_entity(index: usize, entity: &EntityType) -> Vec { return Vec::new(); }; let mut lines: Vec> = Vec::new(); - match dimension { + match &**dimension { Dimension::Linear(value) => { let first = d3(value.first_point); let second = d3(value.second_point); diff --git a/src/modules/annotate/radius_dim.rs b/src/modules/annotate/radius_dim.rs index 435ae9277..7a8d79f93 100644 --- a/src/modules/annotate/radius_dim.rs +++ b/src/modules/annotate/radius_dim.rs @@ -93,7 +93,7 @@ pub(crate) fn radial_dimension_entity( if let Some(angle) = text_angle { dim.base.text_rotation = angle; } - plane.place_entity(EntityType::Dimension(Dimension::Radius(dim))) + plane.place_entity(EntityType::Dimension(Box::new(Dimension::Radius(dim)))) } /// A radius dimension for a dimensional constraint: the leader leaves the @@ -111,7 +111,7 @@ pub(crate) fn radius_constraint_entity( dim.leader_length = chord.distance(location).max(radius * 0.5); dim.base.actual_measurement = dim.measurement(); crate::entities::dimension::set_dimension_text_override(&mut dim.base, text); - Some(EntityType::Dimension(Dimension::Radius(dim))) + Some(EntityType::Dimension(Box::new(Dimension::Radius(dim)))) } /// The unit direction a radial constraint's dimension points in, from the diff --git a/src/modules/annotate/txt2mtxt.rs b/src/modules/annotate/txt2mtxt.rs index c0970a8aa..bd55200be 100644 --- a/src/modules/annotate/txt2mtxt.rs +++ b/src/modules/annotate/txt2mtxt.rs @@ -222,7 +222,7 @@ fn separate(p: &Piece, doc: &CadDocument) -> Vec { let at = p.point(p.rect[0] + x * (p.rect[1] - p.rect[0]), p.rect[3]); let mut m = mtext_from(p.entity, p.content.clone(), at, p.height, p.rotation); m.attachment_point = attachment; - vec![EntityType::MText(m)] + vec![EntityType::MText(Box::new(m))] } EntityType::MText(m) => { // The drawn words, grouped into lines by their baseline. @@ -261,7 +261,8 @@ fn separate(p: &Piece, doc: &CadDocument) -> Vec { .collect::>() .join(" "); let at = p.point(line[0].0 - origin_along, p.rect[3] - k as f64 * step); - EntityType::MText(mtext_from(p.entity, value, at, line[0].1.height, m.rotation)) + let height = line[0].1.height; + EntityType::MText(Box::new(mtext_from(p.entity, value, at, height, m.rotation))) }) .collect() } @@ -352,7 +353,7 @@ pub fn plan( } Some(Txt2MtxtPlan { erase: pieces.iter().map(|p| p.handle).collect(), - add: vec![EntityType::MText(m)], + add: vec![EntityType::MText(Box::new(m))], }) } diff --git a/src/modules/draw/clipboard/pastespec.rs b/src/modules/draw/clipboard/pastespec.rs index cbbefc93f..cc770ed7b 100644 --- a/src/modules/draw/clipboard/pastespec.rs +++ b/src/modules/draw/clipboard/pastespec.rs @@ -113,7 +113,7 @@ impl CadCommand for PasteSpecCommand { mtext.style = self.style.clone(); mtext.attachment_point = AttachmentPoint::TopLeft; mtext.rectangle_width = 0.0; - CmdResult::CommitAndExit(self.plane.place_entity(EntityType::MText(mtext))) + CmdResult::CommitAndExit(self.plane.place_entity(EntityType::MText(Box::new(mtext)))) } fn on_enter(&mut self) -> CmdResult { diff --git a/src/modules/draw/draw/hatchedit.rs b/src/modules/draw/draw/hatchedit.rs index e05a26400..8acb6989d 100644 --- a/src/modules/draw/draw/hatchedit.rs +++ b/src/modules/draw/draw/hatchedit.rs @@ -925,7 +925,7 @@ mod tests { })); } hatch.paths.push(path); - let entity = EntityType::Hatch(hatch); + let entity = EntityType::Hatch(Box::new(hatch)); HatcheditCommand::with_handle(Handle::new(7), "ANSI31".into(), 1.0, 0.0, false) .with_appearance(Some(&entity), Color::Index(6), Transparency::T_40) .with_origin([9.0, 8.0]) @@ -1096,7 +1096,7 @@ mod tests { counter_clockwise: true, })); hatch.paths.push(path); - let entity = EntityType::Hatch(hatch); + let entity = EntityType::Hatch(Box::new(hatch)); let mut command = HatcheditCommand::with_handle(Handle::new(7), "ANSI31".into(), 1.0, 0.0, false) .with_appearance(Some(&entity), Color::ByLayer, Transparency::ByLayer); diff --git a/src/modules/draw/draw/raster_image.rs b/src/modules/draw/draw/raster_image.rs index 27b10c863..da1015837 100644 --- a/src/modules/draw/draw/raster_image.rs +++ b/src/modules/draw/draw/raster_image.rs @@ -104,7 +104,7 @@ impl ImageCommand { let (upper_left, lower_right) = corners_from_placement(ins, world_width, self.aspect()); let ole = build_embedded_ole(image, upper_left, lower_right); - self.plane.place_entity(EntityType::Ole2Frame(ole)) + self.plane.place_entity(EntityType::Ole2Frame(Box::new(ole))) } } } diff --git a/src/modules/draw/modify/explode.rs b/src/modules/draw/modify/explode.rs index 441909933..9e3c7c158 100644 --- a/src/modules/draw/modify/explode.rs +++ b/src/modules/draw/modify/explode.rs @@ -1439,7 +1439,7 @@ fn sync_dimension_base_points_and_collect_pending(doc: &mut CadDocument) -> Vec< let EntityType::Dimension(dimension) = entity else { return None; }; - let definition_point = match dimension { + let definition_point = match &**dimension { Dimension::Linear(value) => Some(value.definition_point), Dimension::Aligned(value) => Some(value.definition_point), Dimension::Radius(value) => Some(value.definition_point), @@ -1493,7 +1493,7 @@ pub fn bake_dimension_blocks(doc: &mut CadDocument) { let dimensions: Vec<(Handle, Dimension)> = pending .into_iter() .filter_map(|handle| match doc.get_entity(handle) { - Some(EntityType::Dimension(d)) => Some((handle, d.clone())), + Some(EntityType::Dimension(d)) => Some((handle, (**d).clone())), _ => None, }) .collect(); @@ -1654,7 +1654,7 @@ mod tests { d.base.text_middle_point = Vector3::new(5.0, 5.0, 0.0); // block_name is left empty — exactly what OCS-created dimensions carry. let handle = doc - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); bake_dimension_blocks(&mut doc); @@ -1693,7 +1693,7 @@ mod tests { // Exactly what OCS-created dimensions carry: insertion == text anchor. d.base.insertion_point = d.base.text_middle_point; let handle = doc - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); bake_dimension_blocks(&mut doc); @@ -1720,7 +1720,7 @@ mod tests { d.definition_point = Vector3::new(0.0, 5.0, 0.0); d.base.text_middle_point = Vector3::new(5.0, 5.0, 0.0); let handle = doc - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); bake_dimension_blocks(&mut doc); @@ -1798,7 +1798,7 @@ mod tests { d.rotation = 0.0; d.definition_point = Vector3::new(0.0, 8.0, 0.0); let handle = doc - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); bake_dimension_blocks(&mut doc); let name = match doc.get_entity(handle) { @@ -1827,7 +1827,7 @@ mod tests { let mut d = DimensionLinear::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(10.0, 0.0, 0.0)); d.definition_point = Vector3::new(0.0, 5.0, 0.0); let handle = doc - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); bake_dimension_blocks(&mut doc); let name = match doc.get_entity(handle) { @@ -1875,7 +1875,7 @@ mod tests { .collect(); assert!(!expected.is_empty(), "the dimension explodes into no lines"); - let mut turned = EntityType::Dimension(flat); + let mut turned = EntityType::Dimension(Box::new(flat)); crate::scene::view::dispatch::apply_transform( &mut turned, &EntityTransform::Rotate { @@ -1911,7 +1911,7 @@ mod tests { ); d.definition_point = Vector3::new(5.0, 5.0, 0.0); // arc location let handle = doc - .add_entity(EntityType::Dimension(Dimension::Angular3Pt(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Angular3Pt(d)))) .unwrap(); bake_dimension_blocks(&mut doc); let name = match doc.get_entity(handle) { @@ -1940,7 +1940,7 @@ mod tests { let mut d = DimensionDiameter::new(edge, far); d.base.text_middle_point = Vector3::new(3.0, 9.0, 0.0); let handle = doc - .add_entity(EntityType::Dimension(Dimension::Diameter(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Diameter(d)))) .unwrap(); bake_dimension_blocks(&mut doc); let name = match doc.get_entity(handle) { @@ -1971,7 +1971,7 @@ mod tests { d.rotation = std::f64::consts::FRAC_PI_2; // 90°, vertical dimension line d.definition_point = Vector3::new(8.0, 0.0, 0.0); let handle = doc - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); bake_dimension_blocks(&mut doc); let name = match doc.get_entity(handle) { @@ -2064,7 +2064,7 @@ mod tests { DimensionLinear::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(10.0, 0.0, 0.0)); d.definition_point = Vector3::new(0.0, 5.0, 0.0); d.base.text_middle_point = Vector3::new(5.0, 5.0, 0.0); - doc.add_entity(EntityType::Dimension(Dimension::Linear(d))) + doc.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); let path = @@ -2171,7 +2171,7 @@ mod tests { d.base.text_middle_point = Vector3::new(5.0, 5.0, 0.0); d.base.common.xdictionary_handle = Some(dict_handle); let dim_handle = doc - .add_entity(EntityType::Dimension(Dimension::Linear(d))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Linear(d)))) .unwrap(); bake_dimension_blocks(&mut doc); diff --git a/src/modules/insert/dgn_import.rs b/src/modules/insert/dgn_import.rs index 41b22f575..4b15efb03 100644 --- a/src/modules/insert/dgn_import.rs +++ b/src/modules/insert/dgn_import.rs @@ -262,7 +262,7 @@ fn mtext(lines: &[DgnGeom], style: String, node: bool) -> Option { m.rotation = *rotation; m.rectangle_width = 0.0; m.style = style; - Some(EntityType::MText(m)) + Some(EntityType::MText(Box::new(m))) } /// The object(s) one element converts to. diff --git a/src/modules/insert/pdf_import.rs b/src/modules/insert/pdf_import.rs index b8eb3c2bd..2c82251a5 100644 --- a/src/modules/insert/pdf_import.rs +++ b/src/modules/insert/pdf_import.rs @@ -1482,7 +1482,7 @@ pub fn convert( let layer = naming.layer(pdf_layer, Kind::Text); mtext.common.color = color_on(&layer, color_of(text.color)); mtext.common.layer = layer; - result.entities.push(EntityType::MText(mtext)); + result.entities.push(EntityType::MText(Box::new(mtext))); } } @@ -1712,7 +1712,7 @@ fn fill_entities( return Vec::new(); } hatch.elevation = z; - vec![EntityType::Hatch(hatch)] + vec![EntityType::Hatch(Box::new(hatch))] } inventory::submit!(crate::command::CommandRegistration { diff --git a/src/modules/layout/mvsetup.rs b/src/modules/layout/mvsetup.rs index 40b858ff1..50de2d2fb 100644 --- a/src/modules/layout/mvsetup.rs +++ b/src/modules/layout/mvsetup.rs @@ -144,7 +144,7 @@ impl MvsetupCommand { if self.arrangement == Arrangement::Engineering { viewport.view_direction = directions[(row * 2 + column) as usize].clone(); } - viewports.push(EntityType::Viewport(viewport)); + viewports.push(EntityType::Viewport(Box::new(viewport))); } } CmdResult::CommitEntitiesAndExit(viewports) diff --git a/src/scene/annotative.rs b/src/scene/annotative.rs index 9d1decb69..c7b287b29 100644 --- a/src/scene/annotative.rs +++ b/src/scene/annotative.rs @@ -322,7 +322,7 @@ pub fn supports_annotation_context(entity: &EntityType) -> bool { | EntityType::Tolerance(_) | EntityType::Hatch(_) => true, EntityType::Dimension(dimension) => { - !matches!(dimension, codec::entities::Dimension::Arc(_)) + !matches!(&**dimension, codec::entities::Dimension::Arc(_)) } _ => false, } diff --git a/src/scene/block_service.rs b/src/scene/block_service.rs index 5b20152d2..541321358 100644 --- a/src/scene/block_service.rs +++ b/src/scene/block_service.rs @@ -788,7 +788,7 @@ mod tests { dimension.base.block_name = "SVC_TARGET".to_string(); scene .document - .add_entity(EntityType::Dimension(Dimension::Aligned(dimension))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Aligned(dimension)))) .unwrap(); // A table's picture block and a block-valued cell, by handle. @@ -894,7 +894,7 @@ mod tests { dimension.base.block_name = "SVC_RENAMED".to_string(); scene .document - .add_entity(EntityType::Dimension(Dimension::Aligned(dimension))) + .add_entity(EntityType::Dimension(Box::new(Dimension::Aligned(dimension)))) .unwrap(); let mut style = DimStyle::new("SVC_STYLE"); style.dimblk = target; diff --git a/src/scene/camera_ops.rs b/src/scene/camera_ops.rs index 62d728ded..179e4261b 100644 --- a/src/scene/camera_ops.rs +++ b/src/scene/camera_ops.rs @@ -479,7 +479,7 @@ impl Scene { self.previous_view = Some(ViewSnapshot::Floating { layout, handle, - viewport: Box::new(viewport.clone()), + viewport: viewport.clone(), }); return; } @@ -538,7 +538,7 @@ impl Scene { }); return false; } - let current = Box::new(current.clone()); + let current = current.clone(); if let Some(EntityType::Viewport(destination)) = self.document.get_entity_mut(handle) { diff --git a/src/scene/dimension_assoc.rs b/src/scene/dimension_assoc.rs index bbb40ae90..f6394d49e 100644 --- a/src/scene/dimension_assoc.rs +++ b/src/scene/dimension_assoc.rs @@ -869,7 +869,7 @@ pub(crate) fn constraint_from_associative_dimension( Some(ParametricRef::whole(*reference.xrefs.first()?)) }; let measurement = DrivingValue::Literal(dimension.measurement()); - match dimension { + match &**dimension { Dimension::Aligned(_) => Some(( ConstraintKind::Distance, vec![point(0)?, point(1)?], @@ -921,7 +921,7 @@ pub(crate) fn radial_extension_points( let EntityType::Dimension(dimension_entity) = document.get_entity(dimension)? else { return None; }; - let target_point = match dimension_entity { + let target_point = match &**dimension_entity { Dimension::Radius(radius) => radius.definition_point, Dimension::Diameter(diameter) => diameter.angle_vertex, Dimension::LargeRadial(radial) => radial.chord_point, @@ -1009,7 +1009,7 @@ impl Scene { else { return; }; - let radial_data = match dimension_entity { + let radial_data = match &**dimension_entity { Dimension::Radius(radius) => Some(( radius.angle_vertex, radius.measurement(), @@ -1223,7 +1223,7 @@ impl Scene { }; // Radial references identify a circle/arc and angle, rather than a vertex. let radial_dimension = matches!( - dimension_entity, + &**dimension_entity, Dimension::Radius(_) | Dimension::Diameter(_) | Dimension::LargeRadial(_) ); if radial_dimension { @@ -1383,7 +1383,7 @@ impl Scene { let Some(EntityType::Dimension(entity)) = self.document.get_entity(dimension) else { return Vec::new(); }; - match entity { + match &**entity { // A radial dimension's single reference describes the point where // the leader meets the circle. Dimension::Radius(radius) => vec![radius.definition_point], @@ -1458,17 +1458,15 @@ impl Scene { let measurement_supported = !association.trans_space || self.document.get_entity(dimension).is_some_and(|entity| { matches!( - entity, - EntityType::Dimension(Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_)) + crate::entities::dimension::as_dimension(entity), + Some(Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_)) ) || persisted_measurement_scale(&self.document, entity).is_some() }); let measurement_supported = measurement_supported && self.document.get_entity(dimension).is_some_and(|entity| { if !matches!( - entity, - EntityType::Dimension( - Dimension::Radius(_) | Dimension::Diameter(_) | Dimension::LargeRadial(_) - ) + crate::entities::dimension::as_dimension(entity), + Some(Dimension::Radius(_) | Dimension::Diameter(_) | Dimension::LargeRadial(_)) ) { return true; } @@ -1652,7 +1650,7 @@ impl Scene { let Some(EntityType::Dimension(entity)) = self.document.get_entity(dimension) else { return Vec::new(); }; - let radial_data = match entity { + let radial_data = match &**entity { Dimension::Radius(radius) => Some(( radius.angle_vertex, radius.measurement(), @@ -1850,8 +1848,8 @@ impl Scene { continue; }; let angular = matches!( - &before, - EntityType::Dimension(Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_)) + crate::entities::dimension::as_dimension(&before), + Some(Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_)) ); let measurement_scale = if let Some(frame) = map.frame.filter(|_| !angular) { let Some(mut scale) = persisted_measurement_scale(&self.document, &before) else { @@ -1874,7 +1872,7 @@ impl Scene { else { continue; }; - match dimension { + match &mut **dimension { Dimension::Linear(linear) => { // The sheet annotation the user placed — the dimension // line's standoff and, when they dragged it, the text — is @@ -2104,7 +2102,7 @@ impl Scene { arc.base.actual_measurement = arc.measurement(); } } - let measurement = match &*dimension { + let measurement = match &**dimension { Dimension::Linear(linear) => linear_measurement(linear), _ => dimension.measurement(), }; @@ -2155,8 +2153,12 @@ impl Scene { refreshed } pub(crate) fn sync_diameter_association_angle(&mut self, dimension: Handle) { - let chord = match self.document.get_entity(dimension) { - Some(EntityType::Dimension(Dimension::Diameter(diameter))) => diameter.angle_vertex, + let chord = match self + .document + .get_entity(dimension) + .and_then(crate::entities::dimension::as_dimension) + { + Some(Dimension::Diameter(diameter)) => diameter.angle_vertex, _ => return, }; @@ -2247,9 +2249,9 @@ mod tests { Vector3::ZERO, 5.0, ))); - let dimension = scene.add_entity(EntityType::Dimension(Dimension::Diameter( + let dimension = scene.add_entity(EntityType::Dimension(Box::new(Dimension::Diameter( DimensionDiameter::new(Vector3::new(5.0, 0.0, 0.0), Vector3::new(-5.0, 0.0, 0.0)), - ))); + )))); scene.attach_dimension_association(dimension, vec![Some(circle)]); let association = scene .document @@ -2270,8 +2272,10 @@ mod tests { .expect("diameter association"); scene.begin_undo_recording(); - let Some(EntityType::Dimension(Dimension::Diameter(diameter))) = - scene.document.get_entity_mut(dimension) + let Some(Dimension::Diameter(diameter)) = scene + .document + .get_entity_mut(dimension) + .and_then(crate::entities::dimension::as_dimension_mut) else { panic!("diameter dimension"); }; diff --git a/src/scene/entity.rs b/src/scene/entity.rs index 2b6c14419..ac89c65c6 100644 --- a/src/scene/entity.rs +++ b/src/scene/entity.rs @@ -3206,7 +3206,7 @@ impl Scene { if let Some(origin) = model.pattern_origin { dxf.record_pattern_origin(Vector2::new(origin[0], origin[1])); } - let mut entity = EntityType::Hatch(dxf); + let mut entity = EntityType::Hatch(Box::new(dxf)); if let Some(layer) = layer { entity.as_entity_mut().set_layer(layer.to_string()); diff --git a/src/scene/layout.rs b/src/scene/layout.rs index a727d8fe7..d10d5d461 100644 --- a/src/scene/layout.rs +++ b/src/scene/layout.rs @@ -64,10 +64,10 @@ impl Scene { if let Some(EntityType::Viewport(sheet)) = self.document.get_entity(from.viewport).cloned() { if let Some(EntityType::Viewport(target)) = self.document.get_entity_mut(to.viewport) { - *target = codec::entities::Viewport { + *target = Box::new(codec::entities::Viewport { common: target.common.clone(), - ..sheet - }; + ..*sheet + }); } } self.unopened_layouts.remove(name); diff --git a/src/scene/mod.rs b/src/scene/mod.rs index d90117db5..a81d2f444 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -4956,7 +4956,7 @@ impl Scene { fit_sheet_viewport(&mut vp, min_lim, max_lim); if let Ok(handle) = self .document - .add_entity_to_layout(EntityType::Viewport(vp), layout_name) + .add_entity_to_layout(EntityType::Viewport(Box::new(vp)), layout_name) { if let Some(ObjectType::Layout(l)) = self.document.objects.get_mut(&layout_handle) { l.viewports.retain(|candidate| *candidate != handle); @@ -5027,7 +5027,7 @@ impl Scene { viewport.status = codec::entities::ViewportStatusFlags::default_on(); if let Ok(handle) = self .document - .add_entity_to_layout(EntityType::Viewport(viewport), layout_name) + .add_entity_to_layout(EntityType::Viewport(Box::new(viewport)), layout_name) { // The reference zooms the new viewport to the model's extents // with a margin of under one percent. @@ -13802,7 +13802,7 @@ mod journal_tests { let mut annotative = MText::new(); annotative.value = "annotative".to_string(); annotative.is_annotative = true; - let annotative = s.add_entity(EntityType::MText(annotative)); + let annotative = s.add_entity(EntityType::MText(Box::new(annotative))); let before_points = s.geometry_epoch; s.invalidate_point_dependencies(); @@ -14117,7 +14117,7 @@ mod journal_tests { scene.document.layers.add_or_replace(Layer::new("Shadows")); let mut hatch = Hatch::new(); hatch.common.layer = "Shadows".to_string(); - let handle = scene.add_entity(EntityType::Hatch(hatch)); + let handle = scene.add_entity(EntityType::Hatch(Box::new(hatch))); let model = scene.model_space_block_handle(); assert_eq!( scene @@ -15447,7 +15447,7 @@ mod layout_cache_tests { vp.height = 100.0; let handle = scene .document - .add_entity_to_layout(codec::EntityType::Viewport(vp), "P1") + .add_entity_to_layout(codec::EntityType::Viewport(Box::new(vp)), "P1") .unwrap(); assert!(scene.set_viewport_scale_named_for(handle, "1:50").is_some()); assert!(scene.active_viewport.is_none()); diff --git a/src/scene/mspace.rs b/src/scene/mspace.rs index 688376cca..d1c01595d 100644 --- a/src/scene/mspace.rs +++ b/src/scene/mspace.rs @@ -285,7 +285,7 @@ mod viewport_zoom_tests { viewport.width = 100.0; viewport.height = 100.0; viewport.view_height = 200.0; - let handle = scene.add_entity(EntityType::Viewport(viewport)); + let handle = scene.add_entity(EntityType::Viewport(Box::new(viewport))); scene.active_viewport = Some(handle); let view_height = |scene: &Scene| match scene.document.get_entity(handle) { @@ -337,7 +337,7 @@ mod clip_tests { viewport.height = 20.0; viewport.clip_boundary_handle = clip; viewport.status.non_rectangular_clipping = true; - let viewport = scene.add_entity(EntityType::Viewport(viewport)); + let viewport = scene.add_entity(EntityType::Viewport(Box::new(viewport))); for (x, y, inside) in [ (2.0, 2.0, true), (8.0, 2.0, true), diff --git a/src/scene/parametric_constraints.rs b/src/scene/parametric_constraints.rs index 4accc1dfe..5ac4bc6f4 100644 --- a/src/scene/parametric_constraints.rs +++ b/src/scene/parametric_constraints.rs @@ -696,7 +696,7 @@ fn dynamic_dimension_follow_points( target.attachment_point = base.attachment_point; target.line_spacing_style = base.line_spacing_style; target.line_spacing_factor = base.line_spacing_factor; - *dimension = rebuilt; + *dimension = *rebuilt; true } @@ -794,7 +794,7 @@ fn dynamic_dimension_follow_radial( let Some(codec::EntityType::Dimension(mut rebuilt)) = rebuilt else { return false; }; - let unchanged = match (&*dimension, &rebuilt) { + let unchanged = match (&*dimension, &*rebuilt) { (Dimension::Radius(old), Dimension::Radius(new)) => { same(old.angle_vertex, new.angle_vertex) && same(old.definition_point, new.definition_point) @@ -808,7 +808,7 @@ fn dynamic_dimension_follow_radial( if unchanged { return false; } - match &mut rebuilt { + match &mut *rebuilt { Dimension::Radius(new) => new.leader_length = leader, Dimension::Diameter(new) => new.leader_length = leader, _ => {} @@ -821,7 +821,7 @@ fn dynamic_dimension_follow_radial( target.attachment_point = base.attachment_point; target.line_spacing_style = base.line_spacing_style; target.line_spacing_factor = base.line_spacing_factor; - *dimension = rebuilt; + *dimension = *rebuilt; true } @@ -881,7 +881,7 @@ fn dynamic_dimension_follow_angle( target.attachment_point = base.attachment_point; target.line_spacing_style = base.line_spacing_style; target.line_spacing_factor = base.line_spacing_factor; - *dimension = rebuilt; + *dimension = *rebuilt; true } @@ -2264,10 +2264,14 @@ impl super::Scene { }); let measured = points.filter(|_| !angular).map(|(first, second)| { let delta = second - first; - let axis = match self.document.get_entity(*dimension) { - Some(codec::EntityType::Dimension(codec::entities::Dimension::Linear( - linear, - ))) => Some((linear.rotation.cos(), linear.rotation.sin())), + let axis = match self + .document + .get_entity(*dimension) + .and_then(crate::entities::dimension::as_dimension) + { + Some(codec::entities::Dimension::Linear(linear)) => { + Some((linear.rotation.cos(), linear.rotation.sin())) + } _ => None, }; match (constraint.kind, axis) { @@ -2605,7 +2609,7 @@ impl super::Scene { // line, which breaks around the text, so the text is centred on // it rather than lifted above it. let radial = matches!( - dimension, + &**dimension, codec::entities::Dimension::Radius(_) | codec::entities::Dimension::Diameter(_) ); let centred = !radial || ov::int(xdata, ov::DIMTAD) == Some(0); @@ -2615,7 +2619,7 @@ impl super::Scene { // The reference draws dynamic distance text horizontally; an // angle's text keeps its style's alignment. let angular = matches!( - dimension, + &**dimension, codec::entities::Dimension::Angular2Ln(_) | codec::entities::Dimension::Angular3Pt(_) ); diff --git a/src/scene/project.rs b/src/scene/project.rs index a2433eadf..711d371a6 100644 --- a/src/scene/project.rs +++ b/src/scene/project.rs @@ -16,7 +16,7 @@ impl Scene { let viewports: Vec<&Viewport> = viewport_handles .iter() .filter_map(|handle| match self.document.get_entity(*handle) { - Some(EntityType::Viewport(vp)) => Some(vp), + Some(EntityType::Viewport(vp)) => Some(&**vp), _ => None, }) .filter(|vp| { @@ -446,7 +446,7 @@ impl Scene { Some(EntityType::Viewport(viewport)) if viewport.common.owner_handle == paper_block && viewport.is_on() => { - Some(viewport) + Some(&**viewport) } _ => None, }) diff --git a/src/ui/node_graph.rs b/src/ui/node_graph.rs index c7ff9ded5..cdcbbc439 100644 --- a/src/ui/node_graph.rs +++ b/src/ui/node_graph.rs @@ -152,7 +152,7 @@ impl ObjectKind { EntityType::Text(e::Text::with_value("Text", origin).with_height(2.5)) } ObjectKind::MText => { - EntityType::MText(e::MText::with_value("MText", origin).with_height(2.5)) + EntityType::MText(Box::new(e::MText::with_value("MText", origin).with_height(2.5))) } } } diff --git a/tests/active_space_roundtrip.rs b/tests/active_space_roundtrip.rs index 85739c387..15530c41a 100644 --- a/tests/active_space_roundtrip.rs +++ b/tests/active_space_roundtrip.rs @@ -90,13 +90,13 @@ fn entered_viewport_survives_a_save_and_reload() { sheet.id = 1; sheet.width = 420.0; sheet.height = 297.0; - let sheet = scene.add_entity(EntityType::Viewport(sheet)); + let sheet = scene.add_entity(EntityType::Viewport(Box::new(sheet))); let mut model = Viewport::new(); model.id = 2; model.width = 100.0; model.height = 80.0; model.view_height = 80.0; - let model = scene.add_entity(EntityType::Viewport(model)); + let model = scene.add_entity(EntityType::Viewport(Box::new(model))); assert_ne!(sheet, model); for entered in [Some(model), None] { diff --git a/tests/annotative_context_synthesis.rs b/tests/annotative_context_synthesis.rs index 1f52ce560..4de593b2e 100644 --- a/tests/annotative_context_synthesis.rs +++ b/tests/annotative_context_synthesis.rs @@ -20,7 +20,7 @@ fn empty_annotation_scales_is_not_annotative() { let mut doc = CadDocument::with_version(DxfVersion::AC1032); let mut m = MText::new(); m.is_annotative = false; // no native flag, no annotative style - let ent = doc.add_entity(EntityType::MText(m)).unwrap(); + let ent = doc.add_entity(EntityType::MText(Box::new(m))).unwrap(); // Build xdict -> "AcDbContextDataManager" -> "ACDB_ANNOTATIONSCALES" (empty). let mk = |doc: &mut CadDocument, owner: Handle| -> Handle { @@ -92,7 +92,7 @@ fn ocs_synthesized_mtext_context_survives_dwg_roundtrip() { m.insertion_point = Vector3::new(100.0, 200.0, 0.0); m.rectangle_width = 50.0; m.is_annotative = true; - let ent = doc.add_entity(EntityType::MText(m)).expect("add mtext"); + let ent = doc.add_entity(EntityType::MText(Box::new(m))).expect("add mtext"); let sh = doc.allocate_handle(); let mut scale = Scale::new("1:50", 1.0, 50.0); @@ -174,7 +174,7 @@ fn object_scale_membership_add_remove_roundtrips() { let mut doc = CadDocument::with_version(DxfVersion::AC1032); let mut m = MText::new(); m.insertion_point = Vector3::new(1.0, 2.0, 0.0); - let ent = doc.add_entity(EntityType::MText(m)).unwrap(); + let ent = doc.add_entity(EntityType::MText(Box::new(m))).unwrap(); let mk_scale = |doc: &mut CadDocument, name: &str, d: f64| { let h = doc.allocate_handle(); diff --git a/tests/block_hatch_export.rs b/tests/block_hatch_export.rs index b65381871..574d2c98f 100644 --- a/tests/block_hatch_export.rs +++ b/tests/block_hatch_export.rs @@ -75,7 +75,7 @@ fn block_internal_hatch_reaches_export() { // A blue hatch, wrapped into a block and inserted in model space — the // minimal shape of "coloured fill nested in a block". - let h = scene.add_entity(EntityType::Hatch(square_hatch(5))); + let h = scene.add_entity(EntityType::Hatch(Box::new(square_hatch(5)))); let identity = codec::types::Transform::identity(); scene .create_block_from_entities(&[h], "LOGO", &identity, &identity) @@ -100,7 +100,7 @@ fn block_internal_hatch_reaches_export() { fn pattern_hatch_uses_stored_line_spacing() { let mut scene = Scene::new(); // Spacing 0.5; a big pattern_scale (10) that the catalog path would apply. - scene.add_entity(EntityType::Hatch(ansi31_stored(0.5, 10.0))); + scene.add_entity(EntityType::Hatch(Box::new(ansi31_stored(0.5, 10.0)))); scene.populate_hatches_from_document(); let hatches = scene.paper_plot_hatches(); @@ -143,7 +143,7 @@ fn far_from_origin_pattern_hatch_still_fills() { // the perpendicular index is |k| ≈ 4000·sin45°/0.3 ≈ 9400, well past the // 4096 clamp on both ends; the old absolute-index clamp inverts the range // (k_lo > k_hi) there and emits nothing. - scene.add_entity(EntityType::Hatch(ansi31_stored_at(0.3, 1.0, 4000.0, 0.0))); + scene.add_entity(EntityType::Hatch(Box::new(ansi31_stored_at(0.3, 1.0, 4000.0, 0.0)))); scene.populate_hatches_from_document(); let hatches = scene.paper_plot_hatches(); @@ -188,7 +188,7 @@ fn textbox_boundary_path_is_not_filled() { let mut tb = rect_path(0.0, 0.0, 200.0, 50.0); tb.flags = BoundaryPathFlags::from_bits(8 | 1); // TEXTBOX + EXTERNAL hatch.paths.push(tb); - scene.add_entity(EntityType::Hatch(hatch)); + scene.add_entity(EntityType::Hatch(Box::new(hatch))); scene.populate_hatches_from_document(); let hatches = scene.paper_plot_hatches(); diff --git a/tests/dim_copy_check.rs b/tests/dim_copy_check.rs index 0eb46f9cb..03388833c 100644 --- a/tests/dim_copy_check.rs +++ b/tests/dim_copy_check.rs @@ -28,7 +28,7 @@ fn copy_dimension_duplicates_its_block() { // A linear dimension whose drawn geometry is that baked block. 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 dim_h = scene.add_entity(EntityType::Dimension(Dimension::Linear(dim))); + let dim_h = scene.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dim)))); // Copy the dimension by (0, 50). let copies = scene.copy_entities( diff --git a/tests/dim_leader_render_check.rs b/tests/dim_leader_render_check.rs index 2484b52ef..7c48bf7d4 100644 --- a/tests/dim_leader_render_check.rs +++ b/tests/dim_leader_render_check.rs @@ -38,7 +38,7 @@ fn dim_leader_extends_only_when_requested() { base.insertion_point = base.text_middle_point; base.text_user_positioned = true; base.style_name = "Standard".into(); - let handle = scene.add_entity(EntityType::Dimension(dim)); + let handle = scene.add_entity(EntityType::Dimension(Box::new(dim))); for (code, value) in [ (ov::DIMTMOVE, XDataValue::Integer16(movement)), (ov::DIMTXT, XDataValue::Real(3.5)), diff --git a/tests/dim_line_color_roundtrip.rs b/tests/dim_line_color_roundtrip.rs index 1f800be11..e67d9a687 100644 --- a/tests/dim_line_color_roundtrip.rs +++ b/tests/dim_line_color_roundtrip.rs @@ -70,7 +70,7 @@ fn dimension_scene(aci: i16) -> Scene { 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))); + let h = scene.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dim)))); dov::set( &mut scene.document, h, diff --git a/tests/explode_regression.rs b/tests/explode_regression.rs index 1b277e15d..9ec6bbc95 100644 --- a/tests/explode_regression.rs +++ b/tests/explode_regression.rs @@ -130,7 +130,7 @@ fn explode_dimension_linear_golden_segments() { let mut d = DimensionLinear::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(10.0, 0.0, 0.0)); d.definition_point = Vector3::new(5.0, 3.0, 0.0); d.base.text_middle_point = Vector3::new(5.0, 5.0, 0.0); - let pieces = explode_entity(&EntityType::Dimension(Dimension::Linear(d)), &doc); + let pieces = explode_entity(&EntityType::Dimension(Box::new(Dimension::Linear(d))), &doc); // A baked linear dimension explodes to exactly 2 extension lines + 1 // dimension line. The arrowheads bake as SOLIDs (see the unit test // `linear_dim_bakes_filled_arrowheads`), which is why the Lines count is diff --git a/tests/pdf_export_images_check.rs b/tests/pdf_export_images_check.rs index 6859e6a1c..5e552458c 100644 --- a/tests/pdf_export_images_check.rs +++ b/tests/pdf_export_images_check.rs @@ -331,7 +331,7 @@ fn viewport_projection_clips_images_and_respects_frozen_and_nonplot_layers() { viewport.view_center = Vector3::new(20.0, 10.0, 0.0); viewport.id = 2; viewport.status.is_on = true; - let handle = scene.add_entity(EntityType::Viewport(viewport)); + let handle = scene.add_entity(EntityType::Viewport(Box::new(viewport))); let (_, _, _, images) = scene.viewport_plot_fills(); assert_eq!(images.len(), 1); let raster = Raster::from_pdf(&export(&[page(images)]), 0); diff --git a/tests/pdf_export_text_check.rs b/tests/pdf_export_text_check.rs index 8ad8037b3..947f6092e 100644 --- a/tests/pdf_export_text_check.rs +++ b/tests/pdf_export_text_check.rs @@ -26,7 +26,7 @@ fn text_and_dim_reach_pdf_export() { // A linear dimension — its measurement value is synthesized as SDF text too, // and dimension text is what #385 was actually filed about. let dim = DimensionLinear::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(40.0, 0.0, 0.0)); - let dim_h = scene.add_entity(EntityType::Dimension(Dimension::Linear(dim))); + let dim_h = scene.add_entity(EntityType::Dimension(Box::new(Dimension::Linear(dim)))); let wires = scene.entity_wires(); diff --git a/tests/text_font_rendering.rs b/tests/text_font_rendering.rs index 805988e6a..66ba96bf0 100644 --- a/tests/text_font_rendering.rs +++ b/tests/text_font_rendering.rs @@ -43,7 +43,7 @@ fn expand_block_mtext( mtext.style = "SHOP".to_string(); mtext.height = 20.0; mtext.rectangle_width = 0.0; - let mut sub = EntityType::MText(mtext); + let mut sub = EntityType::MText(Box::new(mtext)); sub.common_mut().owner_handle = br_h; doc.add_entity(sub).unwrap(); diff --git a/tests/viewport_wide_polyline_plot_width.rs b/tests/viewport_wide_polyline_plot_width.rs index 8ccf6851c..d898b5b43 100644 --- a/tests/viewport_wide_polyline_plot_width.rs +++ b/tests/viewport_wide_polyline_plot_width.rs @@ -43,7 +43,7 @@ fn viewport_projection_scales_wide_polyline_band_width() { viewport.view_center = Vector3::new(50.0, 0.0, 0.0); viewport.id = 2; viewport.status.is_on = true; - scene.add_entity(EntityType::Viewport(viewport)); + scene.add_entity(EntityType::Viewport(Box::new(viewport))); let (_paper, model) = scene.plot_wire_groups(None); let band = model diff --git a/tests/zoom_extents_coverage.rs b/tests/zoom_extents_coverage.rs index 455349760..c8fbb518d 100644 --- a/tests/zoom_extents_coverage.rs +++ b/tests/zoom_extents_coverage.rs @@ -75,7 +75,7 @@ fn fit_all_reaches_an_entity_parked_far_from_the_rest() { #[test] fn fit_all_frames_a_hatch_only_drawing() { let mut scene = Scene::new(); - scene.add_entity(EntityType::Hatch(square_hatch(100.0, 200.0, 40.0))); + scene.add_entity(EntityType::Hatch(Box::new(square_hatch(100.0, 200.0, 40.0)))); scene.fit_all(); @@ -103,7 +103,7 @@ fn fit_all_keeps_a_hatch_outside_the_wires_in_view() { } // The fill is the outermost thing in the drawing; the wires alone would // frame a 12 x 10 strip and leave it off screen. - scene.add_entity(EntityType::Hatch(square_hatch(500.0, 500.0, 50.0))); + scene.add_entity(EntityType::Hatch(Box::new(square_hatch(500.0, 500.0, 50.0)))); scene.fit_all(); From 3c9404510f668291d4f1ed8cca870f8f3e9b50ce Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 16 Oct 2026 10:06:14 +0300 Subject: [PATCH 2/3] Cargo: codec cb3ce6a (acadrust through 3a3098a), kernel 40f59ca, graph a4bd351 Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 8 ++++---- Cargo.toml | 8 ++++---- crates/ocs_plugin_api/Cargo.toml | 4 ++-- crates/ocs_save/Cargo.toml | 2 +- crates/ocs_web_worker/Cargo.toml | 2 +- docs/plugin-template-v2/Cargo.toml | 2 +- plugins/opencad-python/Cargo.lock | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbea93f19..0244239b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4382,7 +4382,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=e023bc3#e023bc37235dddecf9b3e79c522d8936d15e21e6" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cb3ce6a#cb3ce6a93c76a5069f5c2391ee44ea38b4485d15" dependencies = [ "anyhow", "bitflags 2.13.1", @@ -4406,7 +4406,7 @@ dependencies = [ [[package]] name = "opencadgraph" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=c63556f#c63556f9f7a3cf658fd003a2e47fe67283b6afa7" +source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=a4bd351#a4bd351b4a11e6072bd3269b7936da716a782577" dependencies = [ "opencadkernel", "serde_json", @@ -4415,7 +4415,7 @@ dependencies = [ [[package]] name = "opencadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=abca4e8#abca4e81b089114a776ad6fe72a40c51a35646cb" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=40f59ca#40f59caf1e18df6c4bad3b53389fe59d0e740796" dependencies = [ "cavalier_contours", "opencadcodec", @@ -4426,7 +4426,7 @@ dependencies = [ [[package]] name = "opencadkernel-constraints" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=abca4e8#abca4e81b089114a776ad6fe72a40c51a35646cb" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=40f59ca#40f59caf1e18df6c4bad3b53389fe59d0e740796" dependencies = [ "nalgebra", ] diff --git a/Cargo.toml b/Cargo.toml index 76f14f916..e37088072 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,10 @@ rfd = "0.17" clap = { version = "4", features = ["derive", "string"] } env_logger = "0.11" log = "0.4" -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } -kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "abca4e8", features = ["acis", "offset"] } -kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "abca4e8" } -graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "c63556f" } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } +kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "40f59ca", features = ["acis", "offset"] } +kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "40f59ca" } +graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "a4bd351" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } # Shared SAVE serialization dispatch + web-worker wire format: one # implementation for the inline (fallback/native) path and the worker path. diff --git a/crates/ocs_plugin_api/Cargo.toml b/crates/ocs_plugin_api/Cargo.toml index f5f538245..67ed604a2 100644 --- a/crates/ocs_plugin_api/Cargo.toml +++ b/crates/ocs_plugin_api/Cargo.toml @@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true } # Pulled in only by the `host` feature, which adds the `opencadcodec`-typed # `HostApi` runtime surface. The default crate stays dependency-free so engine # crates and external tooling can depend on the manifest/ribbon contract cheaply. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", optional = true, features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", optional = true, features = ["serde"] } # Runtime IPC and serialization (host feature only). interprocess = { version = "2", optional = true } @@ -39,7 +39,7 @@ serde_json = "1" serde = { version = "1", features = ["derive"] } cargo-lock = "11" # opencadcodec is scanned at build time to generate the embedded type registry. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } [dev-dependencies] serde_json = "1" diff --git a/crates/ocs_save/Cargo.toml b/crates/ocs_save/Cargo.toml index 150de8021..c4c8a1036 100644 --- a/crates/ocs_save/Cargo.toml +++ b/crates/ocs_save/Cargo.toml @@ -10,6 +10,6 @@ publish = false # exactly one implementation. No UI/app dependencies — only the codec + serde. [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } diff --git a/crates/ocs_web_worker/Cargo.toml b/crates/ocs_web_worker/Cargo.toml index 42aabfcd1..755654723 100644 --- a/crates/ocs_web_worker/Cargo.toml +++ b/crates/ocs_web_worker/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } console_error_panic_hook = "0.1" diff --git a/docs/plugin-template-v2/Cargo.toml b/docs/plugin-template-v2/Cargo.toml index d0a847190..0a02cbd66 100644 --- a/docs/plugin-template-v2/Cargo.toml +++ b/docs/plugin-template-v2/Cargo.toml @@ -16,4 +16,4 @@ ocs_plugin_api = { path = "../../crates/ocs_plugin_api", features = ["host"] } # entry): the plugin's entities and the host's re-exports are the same types # only when both resolve the same revision. The registration `rustc` / # `acadrust_source` gates enforce this at load time too. -acadrust = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "e023bc3" } +acadrust = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a" } diff --git a/plugins/opencad-python/Cargo.lock b/plugins/opencad-python/Cargo.lock index d5afa7615..c74034305 100644 --- a/plugins/opencad-python/Cargo.lock +++ b/plugins/opencad-python/Cargo.lock @@ -1273,7 +1273,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=e023bc3#e023bc37235dddecf9b3e79c522d8936d15e21e6" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cb3ce6a#cb3ce6a93c76a5069f5c2391ee44ea38b4485d15" dependencies = [ "anyhow", "bitflags", From 04b2c07a381f3902d9f0cc50e7afc55d5251c3a2 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 16 Oct 2026 12:02:39 +0300 Subject: [PATCH 3/3] Use the codec audit and repair in place of OCS's corruption guard Opening a drawing no longer drops entities with its own sanity checks or rewrites knotless splines; recovery runs the codec's repair and records its actions and unresolved issues in the drawing's notifications. Xref merges keep every entity. The dropped-entity counts, their command-line warnings, recovery report rows and the automation "purged" field go with the guard. AUDIT now reports the codec's audit (counts plus the first 50 issues) and asks whether to fix; Yes applies the codec repair as one undo step. Cargo: codec 325fa98, kernel dfca391, graph 5d4e713. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 8 +- Cargo.toml | 8 +- crates/ocs_plugin_api/Cargo.toml | 4 +- crates/ocs_save/Cargo.toml | 2 +- crates/ocs_web_worker/Cargo.toml | 2 +- docs/plugin-template-v2/Cargo.toml | 2 +- locales/ar-SA/opencadstudio.ftl | 10 +- locales/bg-BG/opencadstudio.ftl | 10 +- locales/cs-CZ/opencadstudio.ftl | 10 +- locales/de-DE/opencadstudio.ftl | 10 +- locales/el-GR/opencadstudio.ftl | 10 +- locales/en-US/opencadstudio.ftl | 10 +- locales/es-ES/opencadstudio.ftl | 10 +- locales/fi-FI/opencadstudio.ftl | 10 +- locales/fr-FR/opencadstudio.ftl | 10 +- locales/hi-IN/opencadstudio.ftl | 10 +- locales/hu-HU/opencadstudio.ftl | 10 +- locales/it-IT/opencadstudio.ftl | 10 +- locales/ja-JP/opencadstudio.ftl | 10 +- locales/ko-KR/opencadstudio.ftl | 10 +- locales/lo-LA/opencadstudio.ftl | 10 +- locales/nl-NL/opencadstudio.ftl | 10 +- locales/pl-PL/opencadstudio.ftl | 10 +- locales/pt-BR/opencadstudio.ftl | 10 +- locales/ru-RU/opencadstudio.ftl | 10 +- locales/tr-TR/opencadstudio.ftl | 10 +- locales/zh-CN/opencadstudio.ftl | 10 +- locales/zh-TW/opencadstudio.ftl | 10 +- plugins/opencad-python/Cargo.lock | 2 +- src/app/automation.rs | 32 +-- src/app/commands/blocks.rs | 4 +- src/app/commands/styleprops.rs | 89 +++--- src/app/control/mod.rs | 3 +- src/app/control/sheets.rs | 8 +- src/app/update/dialog.rs | 4 +- src/app/update/file.rs | 27 +- src/io/mod.rs | 429 ++--------------------------- src/io/recovery.rs | 19 -- src/io/xref.rs | 60 ++-- src/locale_catalog.rs | 8 +- src/scene/cache/block_cache.rs | 2 +- src/scene/mod.rs | 8 - src/ui/window/recovery.rs | 14 - 43 files changed, 192 insertions(+), 763 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0244239b9..9e0cbba2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4382,7 +4382,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cb3ce6a#cb3ce6a93c76a5069f5c2391ee44ea38b4485d15" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=325fa98#325fa98d2b881f48e106a830d5cf161624f63131" dependencies = [ "anyhow", "bitflags 2.13.1", @@ -4406,7 +4406,7 @@ dependencies = [ [[package]] name = "opencadgraph" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=a4bd351#a4bd351b4a11e6072bd3269b7936da716a782577" +source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=5d4e713#5d4e713968bd515be15302079d9edc1fd3df4df0" dependencies = [ "opencadkernel", "serde_json", @@ -4415,7 +4415,7 @@ dependencies = [ [[package]] name = "opencadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=40f59ca#40f59caf1e18df6c4bad3b53389fe59d0e740796" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=dfca391#dfca3912228b19d4df25c8695b628ccb13497a78" dependencies = [ "cavalier_contours", "opencadcodec", @@ -4426,7 +4426,7 @@ dependencies = [ [[package]] name = "opencadkernel-constraints" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=40f59ca#40f59caf1e18df6c4bad3b53389fe59d0e740796" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=dfca391#dfca3912228b19d4df25c8695b628ccb13497a78" dependencies = [ "nalgebra", ] diff --git a/Cargo.toml b/Cargo.toml index e37088072..dedd35878 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,10 @@ rfd = "0.17" clap = { version = "4", features = ["derive", "string"] } env_logger = "0.11" log = "0.4" -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } -kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "40f59ca", features = ["acis", "offset"] } -kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "40f59ca" } -graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "a4bd351" } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "325fa98", features = ["serde"] } +kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "dfca391", features = ["acis", "offset"] } +kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "dfca391" } +graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "5d4e713" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } # Shared SAVE serialization dispatch + web-worker wire format: one # implementation for the inline (fallback/native) path and the worker path. diff --git a/crates/ocs_plugin_api/Cargo.toml b/crates/ocs_plugin_api/Cargo.toml index 67ed604a2..dc495b6eb 100644 --- a/crates/ocs_plugin_api/Cargo.toml +++ b/crates/ocs_plugin_api/Cargo.toml @@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true } # Pulled in only by the `host` feature, which adds the `opencadcodec`-typed # `HostApi` runtime surface. The default crate stays dependency-free so engine # crates and external tooling can depend on the manifest/ribbon contract cheaply. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", optional = true, features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "325fa98", optional = true, features = ["serde"] } # Runtime IPC and serialization (host feature only). interprocess = { version = "2", optional = true } @@ -39,7 +39,7 @@ serde_json = "1" serde = { version = "1", features = ["derive"] } cargo-lock = "11" # opencadcodec is scanned at build time to generate the embedded type registry. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "325fa98", features = ["serde"] } [dev-dependencies] serde_json = "1" diff --git a/crates/ocs_save/Cargo.toml b/crates/ocs_save/Cargo.toml index c4c8a1036..a64f550ef 100644 --- a/crates/ocs_save/Cargo.toml +++ b/crates/ocs_save/Cargo.toml @@ -10,6 +10,6 @@ publish = false # exactly one implementation. No UI/app dependencies — only the codec + serde. [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "325fa98", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } diff --git a/crates/ocs_web_worker/Cargo.toml b/crates/ocs_web_worker/Cargo.toml index 755654723..bc91d4438 100644 --- a/crates/ocs_web_worker/Cargo.toml +++ b/crates/ocs_web_worker/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "325fa98", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } console_error_panic_hook = "0.1" diff --git a/docs/plugin-template-v2/Cargo.toml b/docs/plugin-template-v2/Cargo.toml index 0a02cbd66..63a19d6b5 100644 --- a/docs/plugin-template-v2/Cargo.toml +++ b/docs/plugin-template-v2/Cargo.toml @@ -16,4 +16,4 @@ ocs_plugin_api = { path = "../../crates/ocs_plugin_api", features = ["host"] } # entry): the plugin's entities and the host's re-exports are the same types # only when both resolve the same revision. The registration `rustc` / # `acadrust_source` gates enforce this at load time too. -acadrust = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cb3ce6a" } +acadrust = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "325fa98" } diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 6429a0f89..e259076a2 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = تعذر على الاسترداد إنتاج بيانات رسم قابلة للاستخدام. راجع التقرير وجرّب نسخة احتياطية أو نسخة حفظ تلقائي. .entities-checked = الكيانات التي تم فحصها .issues-found = المشكلات الموجودة - .entities-removed = الكيانات التي تمت إزالتها .references-checked = المراجع التي تم فحصها - .referenced-entities-removed = الكيانات المرجعية التي تمت إزالتها .references-unavailable = المراجع غير المتاحة .log-path = سجل الاسترداد .log-write-failed = تعذرت كتابة سجل الاسترداد @@ -2603,8 +2601,6 @@ file = .usage-undo-number-of-steps = الاستخدام: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = يُستخدم للحفظ الأول لرسم جديد. تحتفظ الرسومات الحالية بنوع ملفها وإصدارها. .visual-style-label = النمط المرئي: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = تحذير: أُسقط __ocs_fmt_0__ كيان تالف (بيانات تحليل غير صالحة — اتجاهات/أعداد سيئة) - .warning-corrupt-xref-entities-dropped = تحذير: أُسقط __ocs_fmt_0__ كيان مرجع خارجي تالف .xref-loaded = XREF حُمّل "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: لا يمكن إنشاء ZIP الإرسال (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: تعذر إنشاء المجلد (__ocs_fmt_1__). @@ -5650,9 +5646,9 @@ styles = .aci-color-index = فهرس ألوان ACI .aci = ACI: .audit-no-issues-found = AUDIT: لم يُعثر على مشكلات. - .audit-reference-s-to-undefined-block-s = AUDIT: مراجع إلى كتل غير معرّفة: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: مراجع إلى طبقات غير معرّفة: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: تقرير فقط — لم يُجرَ إصلاح تلقائي. + .audit-fix-any-errors-detected = AUDIT هل تريد إصلاح الأخطاء المكتشفة؟ [نعم / لا] <لا>: + .audit-error-s-warning-s-found = AUDIT: تم العثور على __ocs_fmt_0__ خطأ و__ocs_fmt_1__ تحذير. + .audit-repair-s-applied-issue-s-left = AUDIT: تم تطبيق __ocs_fmt_0__ إصلاح، و__ocs_fmt_1__ مشكلة بلا حل. .audit-scanned-total-object-s = AUDIT: فُحص __ocs_fmt_0__ كائن. .above-text = أعلى النص .active-dim-style-set-to-name-arg = عُيّن نمط الأبعاد النشط إلى "__ocs_fmt_0__" diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index c37642d03..a20f37406 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Възстановяването не успя да генерира използваеми чертожни данни. Прегледай отчета и опитай резервно копие или копие от автоматично запазване. .entities-checked = Проверени обекти .issues-found = Открити проблеми - .entities-removed = Премахнати обекти .references-checked = Проверени препратки - .referenced-entities-removed = Премахнати препратени обекти .references-unavailable = Препратките не са налични .log-path = Дневник за възстановяване .log-write-failed = Дневникът за възстановяване не можа да бъде записан @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = Употреба: UNDO [брой стъпки] .used-for-the-first-save-of-a-new-drawing-exist = Използва се при първото запазване на нов чертеж. Съществуващите чертежи запазват своя тип файл и версия. .visual-style-label = Визуален стил: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Предупреждение: __ocs_fmt_0__ повредени обекта отхвърлени (грешка в анализатора — лоши нормали / брой) - .warning-corrupt-xref-entities-dropped = Предупреждение: __ocs_fmt_0__ повредени xref обекта отхвърлени .xref-loaded = XREF Зареден "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: не може да се създаде ZIP за предаване (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: папката не може да бъде създадена (__ocs_fmt_1__). @@ -5638,9 +5634,9 @@ styles = .aci-color-index = ACI Цветови индекс .aci = ACI: .audit-no-issues-found = AUDIT: не са открити проблеми. - .audit-reference-s-to-undefined-block-s = AUDIT: препратка/и към недефинирани блок(ове): __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: препратка/и към недефинирани слой(еве): __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: само отчет — не е извършена автоматична поправка. + .audit-fix-any-errors-detected = AUDIT Да се поправят ли откритите грешки? [Да / Не] <Не>: + .audit-error-s-warning-s-found = AUDIT: открити грешки: __ocs_fmt_0__, предупреждения: __ocs_fmt_1__. + .audit-repair-s-applied-issue-s-left = AUDIT: приложени поправки: __ocs_fmt_0__, нерешени проблеми: __ocs_fmt_1__. .audit-scanned-total-object-s = AUDIT: сканирани __ocs_fmt_0__ обект(а). .above-text = Над текста .active-dim-style-set-to-name-arg = Активният стил за оразмеряване е зададен на "__ocs_fmt_0__" diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index abf843f86..b36cac75e 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Při obnovení se nepodařilo získat použitelná data výkresu. Projděte zprávu a zkuste zálohu nebo automaticky uloženou kopii. .entities-checked = Zkontrolované entity .issues-found = Nalezené problémy - .entities-removed = Odstraněné entity .references-checked = Zkontrolované reference - .referenced-entities-removed = Odstraněné odkazované entity .references-unavailable = Nedostupné reference .log-path = Protokol obnovení .log-write-failed = Protokol obnovení se nepodařilo zapsat @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = Použití: UNDO [počet kroků] .used-for-the-first-save-of-a-new-drawing-exist = Používá se pro první uložení nového výkresu. Stávající výkresy si ponechají svůj typ souboru a verzi. .visual-style-label = Vizuální styl: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Varování: __ocs_fmt_0__ poškozené entity byly odstraněny (nevyžádaná analyzátor – špatné normály / počty) - .warning-corrupt-xref-entities-dropped = Varování: __ocs_fmt_0__ poškozené entity externí reference byly zrušeny .xref-loaded = XREF Načteno "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: nelze vytvořit přenosový ZIP (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: Nelze vytvořit složku (__ocs_fmt_1__). @@ -5635,9 +5631,9 @@ styles = .aci-color-index = Barevný index ACI .aci = ACI: .audit-no-issues-found = AUDIT: nebyly nalezeny žádné problémy. - .audit-reference-s-to-undefined-block-s = AUDIT: reference na nedefinované bloky: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: reference na nedefinované vrstvy: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: pouze zpráva – neprovádí se žádná automatická oprava. + .audit-fix-any-errors-detected = AUDIT Opravit zjištěné chyby? [Ano / Ne] : + .audit-error-s-warning-s-found = AUDIT: nalezeno chyb: __ocs_fmt_0__, varování: __ocs_fmt_1__. + .audit-repair-s-applied-issue-s-left = AUDIT: provedeno oprav: __ocs_fmt_0__, nevyřešeno problémů: __ocs_fmt_1__. .audit-scanned-total-object-s = AUDIT: skenovaný objekt(y) __ocs_fmt_0__. .above-text = Nad textem .active-dim-style-set-to-name-arg = Styl aktivního ztlumení nastaven na "__ocs_fmt_0__" diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index ba3802c7f..fc1946179 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Die Wiederherstellung konnte keine verwendbaren Zeichnungsdaten erzeugen. Prüfen Sie den Bericht und versuchen Sie eine Sicherungskopie oder automatisch gespeicherte Kopie. .entities-checked = Geprüfte Objekte .issues-found = Gefundene Probleme - .entities-removed = Entfernte Objekte .references-checked = Geprüfte Referenzen - .referenced-entities-removed = Entfernte referenzierte Objekte .references-unavailable = Nicht verfügbare Referenzen .log-path = Wiederherstellungsprotokoll .log-write-failed = Wiederherstellungsprotokoll konnte nicht geschrieben werden @@ -2591,8 +2589,6 @@ file = .usage-undo-number-of-steps = Anwendung: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = Wird für die erste Speicherung einer neuen Zeichnung verwendet. Bestehende Zeichnungen behalten ihren Dateityp und ihre Version bei. .visual-style-label = Visueller Stil: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Warnung: __ocs_fmt_0__ beschädigte Objekte verworfen (ungültige Analysedaten — fehlerhafte Normalen oder Anzahlen) - .warning-corrupt-xref-entities-dropped = Warnung: __ocs_fmt_0__ beschädigte XRef-Objekte verworfen .xref-loaded = XREF Geladen "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: das Übertragungs-ZIP kann nicht erstellt werden (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: kann keinen Ordner erstellen (__ocs_fmt_1__). @@ -5636,9 +5632,9 @@ styles = .aci-color-index = ACI Farbindex .aci = ACI: .audit-no-issues-found = AUDIT: keine Probleme gefunden. - .audit-reference-s-to-undefined-block-s = AUDIT: Verweis(e) auf undefinierte(n) Block(e): __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: Referenz(en) auf undefinierte Ebene(n): __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: Nur Bericht erstatten — keine automatische Reparatur durchgeführt. + .audit-fix-any-errors-detected = AUDIT Gefundene Fehler beheben? [Ja / Nein] : + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ Fehler, __ocs_fmt_1__ Warnung(en) gefunden. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ Reparatur(en) ausgeführt, __ocs_fmt_1__ Problem(e) ungelöst. .audit-scanned-total-object-s = AUDIT: gescanntes __ocs_fmt_0__ Objekt(e). .above-text = Vorstehender Text .active-dim-style-set-to-name-arg = Aktiver Bemaßungsstil auf „__ocs_fmt_0__“ gesetzt diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 9ea02d2ca..2f187eb4e 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -224,9 +224,7 @@ recovery = .failed-description = Η ανάκτηση δεν μπόρεσε να παραγάγει αξιοποιήσιμα δεδομένα σχεδίου. Ελέγξτε την αναφορά και δοκιμάστε ένα αντίγραφο ασφαλείας ή αυτόματης αποθήκευσης. .entities-checked = Οντότητες που ελέγχθηκαν .issues-found = Προβλήματα που βρέθηκαν - .entities-removed = Οντότητες που αφαιρέθηκαν .references-checked = Αναφορές που ελέγχθηκαν - .referenced-entities-removed = Αναφερόμενες οντότητες που αφαιρέθηκαν .references-unavailable = Οι αναφορές δεν είναι διαθέσιμες .log-path = Αρχείο καταγραφής ανάκτησης .log-write-failed = Δεν ήταν δυνατή η εγγραφή του αρχείου καταγραφής ανάκτησης @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = Χρήση: UNDO [αριθμός βημάτων] .used-for-the-first-save-of-a-new-drawing-exist = Χρησιμοποιείται στην πρώτη αποθήκευση ενός νέου σχεδίου. Τα υπάρχοντα σχέδια διατηρούν τον τύπο και την έκδοση του αρχείου τους. .visual-style-label = Οπτικό στυλ: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Προειδοποίηση: απορρίφθηκαν __ocs_fmt_0__ κατεστραμμένες οντότητες (άχρηστα δεδομένα αναλυτή — εσφαλμένα κάθετα διανύσματα / πλήθη) - .warning-corrupt-xref-entities-dropped = Προειδοποίηση: απορρίφθηκαν __ocs_fmt_0__ κατεστραμμένες οντότητες xref .xref-loaded = XREF Φορτώθηκε το "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: δεν είναι δυνατή η δημιουργία του ZIP μεταφοράς (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: δεν είναι δυνατή η δημιουργία φακέλου (__ocs_fmt_1__). @@ -5638,9 +5634,9 @@ styles = .aci-color-index = Δείκτης χρώματος ACI .aci = ACI: .audit-no-issues-found = AUDIT: δεν βρέθηκαν προβλήματα. - .audit-reference-s-to-undefined-block-s = AUDIT: αναφορά(ές) σε μη ορισμένα μπλοκ: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: αναφορά(ές) σε μη ορισμένα επίπεδα: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: μόνο αναφορά — δεν έγινε αυτόματη επιδιόρθωση. + .audit-fix-any-errors-detected = AUDIT Διόρθωση των σφαλμάτων που εντοπίστηκαν; [Ναι / Όχι] <Όχι>: + .audit-error-s-warning-s-found = AUDIT: βρέθηκαν __ocs_fmt_0__ σφάλματα, __ocs_fmt_1__ προειδοποιήσεις. + .audit-repair-s-applied-issue-s-left = AUDIT: εφαρμόστηκαν __ocs_fmt_0__ επιδιορθώσεις, __ocs_fmt_1__ προβλήματα παραμένουν άλυτα. .audit-scanned-total-object-s = AUDIT: σαρώθηκαν __ocs_fmt_0__ αντικείμενο(α). .above-text = Πάνω από το κείμενο .active-dim-style-set-to-name-arg = Το ενεργό στυλ διαστάσεων ορίστηκε σε "__ocs_fmt_0__" diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 0b25e247b..913d9e300 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -224,9 +224,7 @@ recovery = .failed-description = Recovery could not produce usable drawing data. Review the report and try a backup or automatic-save copy. .entities-checked = Entities checked .issues-found = Issues found - .entities-removed = Entities removed .references-checked = References checked - .referenced-entities-removed = Referenced entities removed .references-unavailable = References unavailable .log-path = Recovery log .log-write-failed = Recovery log could not be written @@ -2591,8 +2589,6 @@ file = .usage-undo-number-of-steps = Usage: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = Used for the first save of a new drawing. Existing drawings keep their file type and version. .visual-style-label = Visual style: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Warning: __ocs_fmt_0__ corrupt entities dropped (parser junk — bad normals / counts) - .warning-corrupt-xref-entities-dropped = Warning: __ocs_fmt_0__ corrupt xref entities dropped .xref-loaded = XREF Loaded "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: cannot build the transmittal ZIP (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: cannot create folder (__ocs_fmt_1__). @@ -5637,9 +5633,9 @@ styles = .aci-color-index = ACI Color Index .aci = ACI: .audit-no-issues-found = AUDIT: no issues found. - .audit-reference-s-to-undefined-block-s = AUDIT: reference(s) to undefined block(s): __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: reference(s) to undefined layer(s): __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: report only — no automatic repair performed. + .audit-fix-any-errors-detected = AUDIT Fix any errors detected? [Yes / No] : + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ error(s), __ocs_fmt_1__ warning(s) found. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ repair(s) applied, __ocs_fmt_1__ issue(s) left unresolved. .audit-scanned-total-object-s = AUDIT: scanned __ocs_fmt_0__ object(s). .above-text = Above text .active-dim-style-set-to-name-arg = Active dim style set to "__ocs_fmt_0__" diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index a5efe2c3e..65613bb20 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = La recuperación no pudo producir datos de dibujo utilizables. Revise el informe e intente usar una copia de seguridad o de guardado automático. .entities-checked = Entidades comprobadas .issues-found = Problemas encontrados - .entities-removed = Entidades eliminadas .references-checked = Referencias comprobadas - .referenced-entities-removed = Entidades referenciadas eliminadas .references-unavailable = Referencias no disponibles .log-path = Registro de recuperación .log-write-failed = No se pudo escribir el registro de recuperación @@ -2591,8 +2589,6 @@ file = .usage-undo-number-of-steps = Uso: UNDO [número de pasos] .used-for-the-first-save-of-a-new-drawing-exist = Se usa para el primer guardado de un dibujo nuevo. Los dibujos existentes conservan su tipo y versión de archivo. .visual-style-label = Estilo visual: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Advertencia: se descartaron __ocs_fmt_0__ entidades dañadas (datos inválidos del analizador: normales o recuentos erróneos) - .warning-corrupt-xref-entities-dropped = Advertencia: se descartaron __ocs_fmt_0__ entidades de referencia externa dañadas .xref-loaded = XREF Se cargó «__ocs_fmt_0__» .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: no se puede crear el ZIP de transmisión (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: no se puede crear la carpeta (__ocs_fmt_1__). @@ -5638,9 +5634,9 @@ styles = .aci-color-index = Índice de color ACI .aci = ACI: .audit-no-issues-found = AUDIT: no se encontraron problemas. - .audit-reference-s-to-undefined-block-s = AUDIT: referencias a bloques no definidos: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: referencias a capas no definidas: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: solo informe; no se realizó ninguna reparación automática. + .audit-fix-any-errors-detected = AUDIT ¿Corregir los errores detectados? [Sí / No] : + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ error(es), __ocs_fmt_1__ advertencia(s) encontrados. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ reparación(es) aplicada(s), __ocs_fmt_1__ problema(s) sin resolver. .audit-scanned-total-object-s = AUDIT: se examinaron __ocs_fmt_0__ objetos. .above-text = Encima del texto .active-dim-style-set-to-name-arg = Estilo de cota activo definido como «__ocs_fmt_0__» diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index d4e00edd1..26fb97570 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Palautus ei tuottanut käyttökelpoisia piirustustietoja. Tarkista raportti ja kokeile varmuuskopiota tai automaattisesti tallennettua kopiota. .entities-checked = Tarkistetut entiteetit .issues-found = Havaitut ongelmat - .entities-removed = Poistetut entiteetit .references-checked = Tarkistetut viitteet - .referenced-entities-removed = Poistetut viitatut entiteetit .references-unavailable = Viitteet eivät ole käytettävissä .log-path = Palautusloki .log-write-failed = Palautuslokia ei voitu kirjoittaa @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = Käyttö: UNDO [vaiheiden määrä] .used-for-the-first-save-of-a-new-drawing-exist = Käytetään uuden piirustuksen ensimmäiseen tallennukseen. Olemassa olevat piirustukset säilyttävät tiedostotyyppinsä ja -versionsa. .visual-style-label = Visuaalinen tyyli: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Varoitus: __ocs_fmt_0__-korruptoituneet entiteetit pudotettiin (jäsennysroska - huonot normaalit / määrät) - .warning-corrupt-xref-entities-dropped = Varoitus: __ocs_fmt_0__-korruptoituneet xref-entiteetit putosivat .xref-loaded = XREF Ladattu "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: siirto-ZIP:n luominen epäonnistui (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: kansiota (__ocs_fmt_1__) ei voi luoda. @@ -5637,9 +5633,9 @@ styles = .aci-color-index = ACI väriindeksi .aci = ACI: .audit-no-issues-found = AUDIT: ongelmia ei löytynyt. - .audit-reference-s-to-undefined-block-s = AUDIT: viittaus määrittelemättömiin lohkoihin: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: viittaukset määrittelemättömiin tasoihin: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: vain raportti – automaattista korjausta ei suoritettu. + .audit-fix-any-errors-detected = AUDIT Korjataanko havaitut virheet? [Kyllä / Ei] : + .audit-error-s-warning-s-found = AUDIT: löytyi __ocs_fmt_0__ virhettä, __ocs_fmt_1__ varoitusta. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ korjausta tehty, __ocs_fmt_1__ ongelmaa ratkaisematta. .audit-scanned-total-object-s = AUDIT: skannatut __ocs_fmt_0__-objektit. .above-text = Tekstin yläpuolella .active-dim-style-set-to-name-arg = Aktiivinen himmennystyyli asetettu "__ocs_fmt_0__" diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 0e5473ea4..697f5a59a 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = La récupération n'a pas produit de données de dessin utilisables. Consultez le rapport et essayez une sauvegarde ou une copie d'enregistrement automatique. .entities-checked = Entités vérifiées .issues-found = Problèmes détectés - .entities-removed = Entités supprimées .references-checked = Références vérifiées - .referenced-entities-removed = Entités référencées supprimées .references-unavailable = Références indisponibles .log-path = Journal de récupération .log-write-failed = Impossible d'écrire le journal de récupération @@ -2591,8 +2589,6 @@ file = .usage-undo-number-of-steps = Utilisation : UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = Utilisé pour la première sauvegarde d'un nouveau dessin. Les dessins existants conservent leur type de fichier et leur version. .visual-style-label = Style visuel : __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Avertissement : __ocs_fmt_0__ objet(s) corrompu(s) ignoré(s) (données d’analyse invalides — normales ou nombres incorrects) - .warning-corrupt-xref-entities-dropped = Avertissement : __ocs_fmt_0__ objet(s) de référence externe corrompu(s) ignoré(s) .xref-loaded = XREF Charge "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__ : impossible de créer le ZIP de transmission (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: ne peut pas créer de dossier (__ocs_fmt_1__). @@ -5639,9 +5635,9 @@ styles = .aci-color-index = ACI Indice de couleur .aci = ACI: .audit-no-issues-found = AUDIT: aucun problème trouvé. - .audit-reference-s-to-undefined-block-s = AUDIT: référence(s) à un ou plusieurs blocs non définis: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT : références à des calques non définis : __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: rapport seulement — aucune réparation automatique n'est effectuée. + .audit-fix-any-errors-detected = AUDIT Corriger les erreurs détectées ? [Oui / Non] : + .audit-error-s-warning-s-found = AUDIT : __ocs_fmt_0__ erreur(s), __ocs_fmt_1__ avertissement(s) trouvé(s). + .audit-repair-s-applied-issue-s-left = AUDIT : __ocs_fmt_0__ réparation(s) appliquée(s), __ocs_fmt_1__ problème(s) non résolu(s). .audit-scanned-total-object-s = AUDIT : objets analysés : __ocs_fmt_0__. .above-text = Texte ci-dessus .active-dim-style-set-to-name-arg = Style de cote courant défini sur « __ocs_fmt_0__ » diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index e7f26c977..1a08d75dd 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = पुनर्प्राप्ति उपयोग योग्य ड्रॉइंग डेटा नहीं बना सकी। रिपोर्ट की समीक्षा करें और बैकअप या स्वतः-सहेजी गई प्रति आज़माएँ। .entities-checked = जाँची गई एंटिटियाँ .issues-found = मिली समस्याएँ - .entities-removed = हटाई गई एंटिटियाँ .references-checked = जाँचे गए संदर्भ - .referenced-entities-removed = हटाई गई संदर्भित एंटिटियाँ .references-unavailable = अनुपलब्ध संदर्भ .log-path = पुनर्प्राप्ति लॉग .log-write-failed = पुनर्प्राप्ति लॉग लिखा नहीं जा सका @@ -2579,8 +2577,6 @@ file = .usage-undo-number-of-steps = उपयोग: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = नई ड्रॉइंग को पहली बार सहेजते समय उपयोग होता है। मौजूदा ड्रॉइंग अपना फ़ाइल प्रकार और संस्करण बनाए रखती हैं। .visual-style-label = दृश्य शैली: __ocs_fmt_0__ - .warning-corrupt-entities-dropped-parser-junk-b = चेतावनी: __ocs_fmt_0__ दूषित ऑब्जेक्ट छोड़े गए (अमान्य पार्सर डेटा — गलत नॉर्मल या गिनती) - .warning-corrupt-xref-entities-dropped = चेतावनी: __ocs_fmt_0__ दूषित xref ऑब्जेक्ट छोड़े गए .xref-loaded = XREF लोड हो गया "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: ट्रांसमिट ZIP नहीं बनाया जा सकता (__ocs_fmt_1__)। .cmd-cannot-create-folder-e = __ocs_fmt_0__: फ़ोल्डर नहीं बना सकता (__ocs_fmt_1__). @@ -5626,9 +5622,9 @@ styles = .aci-color-index = ACI रंग सूचकांक .aci = ACI: .audit-no-issues-found = AUDIT: कोई समस्या नहीं मिली। - .audit-reference-s-to-undefined-block-s = AUDIT: संदर्भ (s) अपरिभाषित ब्लॉकों के लिए: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: अपरिभाषित लेयर के संदर्भ: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: केवल रिपोर्ट - कोई स्वचालित मरम्मत नहीं की जाती है। + .audit-fix-any-errors-detected = AUDIT पाई गई त्रुटियाँ ठीक करें? [हाँ / नहीं] <नहीं>: + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ त्रुटि(याँ), __ocs_fmt_1__ चेतावनी(याँ) मिलीं। + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ सुधार लागू हुए, __ocs_fmt_1__ समस्या(एँ) अनसुलझी रहीं। .audit-scanned-total-object-s = AUDIT: __ocs_fmt_0__ ऑब्जेक्ट जाँचे गए। .above-text = पाठ के ऊपर .active-dim-style-set-to-name-arg = सक्रिय मंद शैली "__ocs_fmt_0__" के लिए सेट diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 15bee6825..d5b06aa60 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -224,9 +224,7 @@ recovery = .failed-description = A helyreállítás nem eredményezett használható rajzadatokat. Tekintse át a jelentést, és próbáljon meg egy biztonsági vagy automatikusan mentett példányt. .entities-checked = Ellenőrzött entitások .issues-found = Talált problémák - .entities-removed = Eltávolított entitások .references-checked = Ellenőrzött hivatkozások - .referenced-entities-removed = Eltávolított hivatkozott entitások .references-unavailable = Nem elérhető hivatkozások .log-path = Helyreállítási napló .log-write-failed = A helyreállítási napló nem írható @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = Használat: UNDO [lépések száma] .used-for-the-first-save-of-a-new-drawing-exist = Egy új rajz első mentésénél használatos. A meglévő rajzok megtartják fájltípusukat és verziójukat. .visual-style-label = Vizuális stílus: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Figyelmeztetés: __ocs_fmt_0__ sérült objektum kihagyva (érvénytelen adatok: hibás normálvektorok / elemszámok) - .warning-corrupt-xref-entities-dropped = Figyelmeztetés: __ocs_fmt_0__ sérült xref-objektum kihagyva .xref-loaded = XREF betöltve: "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: nem hozható létre az átviteli ZIP (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: nem hozható létre mappa (__ocs_fmt_1__). @@ -5627,9 +5623,9 @@ styles = .aci-color-index = ACI színindex .aci = ACI: .audit-no-issues-found = AUDIT: nem található probléma. - .audit-reference-s-to-undefined-block-s = AUDIT: hivatkozás(ok) meghatározatlan blokk(ok)ra: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: hivatkozások nem definiált fóliákra: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: csak jelentés – nem történt automatikus javítás. + .audit-fix-any-errors-detected = AUDIT Javítsa az észlelt hibákat? [Igen / Nem] : + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ hiba, __ocs_fmt_1__ figyelmeztetés található. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ javítás alkalmazva, __ocs_fmt_1__ probléma megoldatlan. .audit-scanned-total-object-s = AUDIT: __ocs_fmt_0__ objektum ellenőrizve. .above-text = A szöveg felett .active-dim-style-set-to-name-arg = Aktív méretezési stílus: „__ocs_fmt_0__” diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index df881cc37..ab3f753aa 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Il recupero non ha prodotto dati di disegno utilizzabili. Esamina il rapporto e prova una copia di backup o di salvataggio automatico. .entities-checked = Entità controllate .issues-found = Problemi rilevati - .entities-removed = Entità rimosse .references-checked = Riferimenti controllati - .referenced-entities-removed = Entità referenziate rimosse .references-unavailable = Riferimenti non disponibili .log-path = Registro di recupero .log-write-failed = Impossibile scrivere il registro di recupero @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = Utilizzo: UNDO [numero di passi] .used-for-the-first-save-of-a-new-drawing-exist = Utilizzato per il primo salvataggio di un nuovo disegno. I disegni esistenti mantengono il tipo e la versione del file. .visual-style-label = Stile visivo: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Avviso: entità corrotte __ocs_fmt_0__ eliminate (spazzatura del parser: valori normali/conteggi errati) - .warning-corrupt-xref-entities-dropped = Avviso: entità xrif corrotte __ocs_fmt_0__ eliminate .xref-loaded = XREF Caricato "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: impossibile creare il ZIP di trasmissione (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: impossibile creare la cartella (__ocs_fmt_1__). @@ -5637,9 +5633,9 @@ styles = .aci-color-index = ACI Indice colori .aci = ACI: .audit-no-issues-found = AUDIT: nessun problema trovato. - .audit-reference-s-to-undefined-block-s = AUDIT: riferimento/i a blocchi non definiti: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: riferimento/i a livelli non definiti: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: solo rapporto: nessuna riparazione automatica eseguita. + .audit-fix-any-errors-detected = AUDIT Correggere gli errori rilevati? [Sì / No] : + .audit-error-s-warning-s-found = AUDIT: trovati __ocs_fmt_0__ errore/i, __ocs_fmt_1__ avviso/i. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ riparazione/i applicata/e, __ocs_fmt_1__ problema/i irrisolto/i. .audit-scanned-total-object-s = AUDIT: oggetto/i __ocs_fmt_0__ scansionato/i. .above-text = Sopra il testo .active-dim-style-set-to-name-arg = Stile di attenuazione attivo impostato su "__ocs_fmt_0__" diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index 271c127f7..d0f40ad57 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = 修復処理で使用可能な図面データを生成できませんでした。レポートを確認し、バックアップまたは自動保存コピーをお試しください。 .entities-checked = 確認したエンティティ .issues-found = 検出した問題 - .entities-removed = 削除したエンティティ .references-checked = 確認した参照 - .referenced-entities-removed = 削除した参照エンティティ .references-unavailable = 使用できない参照 .log-path = 修復ログ .log-write-failed = 修復ログを書き込めませんでした @@ -2581,8 +2579,6 @@ file = .usage-undo-number-of-steps = 使用法: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = 新しい図面の初回保存時に使用されます。既存の図面ではファイル形式とバージョンが維持されます。 .visual-style-label = 表示スタイル: __ocs_fmt_0__。 - .warning-corrupt-entities-dropped-parser-junk-b = 警告: __ocs_fmt_0__ 個の破損した図形を除外しました(パーサーの不正データ — 法線 / 数の異常) - .warning-corrupt-xref-entities-dropped = 警告: __ocs_fmt_0__ 個の破損した外部参照図形を除外しました .xref-loaded = XREF 「__ocs_fmt_0__」をロードしました .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: 転送 ZIP を作成できません(__ocs_fmt_1__)。 .cmd-cannot-create-folder-e = __ocs_fmt_0__: フォルダーを作成できません(__ocs_fmt_1__)。 @@ -5626,9 +5622,9 @@ styles = .aci-color-index = ACI カラーインデックス .aci = ACI: .audit-no-issues-found = AUDIT: 問題は見つかりませんでした。 - .audit-reference-s-to-undefined-block-s = AUDIT: 未定義ブロックへの参照: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: 未定義レイヤーへの参照: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: レポートのみ — 自動修復は行いませんでした。 + .audit-fix-any-errors-detected = AUDIT 検出されたエラーを修正しますか? [はい / いいえ] <いいえ>: + .audit-error-s-warning-s-found = AUDIT: エラー __ocs_fmt_0__ 件、警告 __ocs_fmt_1__ 件が見つかりました。 + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ 件の修復を適用し、__ocs_fmt_1__ 件の問題が未解決です。 .audit-scanned-total-object-s = AUDIT: __ocs_fmt_0__ 個のオブジェクトを検査しました。 .above-text = 文字の上 .active-dim-style-set-to-name-arg = 現在の寸法スタイルを "__ocs_fmt_0__" に設定しました diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 63f5bfb85..25428a492 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = 복구 과정에서 사용 가능한 도면 데이터를 만들지 못했습니다. 보고서를 검토하고 백업 또는 자동 저장 사본을 사용해 보세요. .entities-checked = 검사한 엔티티 .issues-found = 발견된 문제 - .entities-removed = 제거된 엔티티 .references-checked = 검사한 참조 - .referenced-entities-removed = 제거된 참조 엔티티 .references-unavailable = 사용할 수 없는 참조 .log-path = 복구 로그 .log-write-failed = 복구 로그를 쓸 수 없습니다 @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = 사용법: UNDO [단계 수] .used-for-the-first-save-of-a-new-drawing-exist = 새 도면을 처음 저장할 때 사용됩니다. 기존 도면은 파일 유형과 버전을 유지합니다. .visual-style-label = 시각적 스타일: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = 경고: __ocs_fmt_0__ 손상된 엔터티가 삭제됨(파서 정크 - 잘못된 노멀/카운트) - .warning-corrupt-xref-entities-dropped = 경고: __ocs_fmt_0__ 손상된 외부 참조 엔티티가 삭제되었습니다. .xref-loaded = XREF가 "__ocs_fmt_0__"를 로드했습니다. .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: 전송 ZIP을 만들 수 없습니다(__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: 폴더(__ocs_fmt_1__)를 생성할 수 없습니다. @@ -5637,9 +5633,9 @@ styles = .aci-color-index = ACI 컬러 인덱스 .aci = ACI: .audit-no-issues-found = AUDIT: 문제가 발견되지 않았습니다. - .audit-reference-s-to-undefined-block-s = AUDIT: 정의되지 않은 블록에 대한 참조: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: 정의되지 않은 레이어에 대한 참조: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: 보고 전용 - 자동 복구가 수행되지 않습니다. + .audit-fix-any-errors-detected = AUDIT 감지된 오류를 수정하시겠습니까? [예 / 아니요] <아니요>: + .audit-error-s-warning-s-found = AUDIT: 오류 __ocs_fmt_0__개, 경고 __ocs_fmt_1__개를 찾았습니다. + .audit-repair-s-applied-issue-s-left = AUDIT: 복구 __ocs_fmt_0__개 적용, 미해결 문제 __ocs_fmt_1__개. .audit-scanned-total-object-s = AUDIT: __ocs_fmt_0__ 개체를 스캔했습니다. .above-text = 텍스트 위 .active-dim-style-set-to-name-arg = 활성 밝기 스타일이 "__ocs_fmt_0__"로 설정됨 diff --git a/locales/lo-LA/opencadstudio.ftl b/locales/lo-LA/opencadstudio.ftl index fc88b2625..573647583 100644 --- a/locales/lo-LA/opencadstudio.ftl +++ b/locales/lo-LA/opencadstudio.ftl @@ -224,9 +224,7 @@ recovery = .failed-description = ການກູ້ຄືນບໍ່ສາມາດສ້າງຂໍ້ມູນຮູບແຕ້ມທີ່ໃຊ້ງານໄດ້. ກະລຸນາກວດສອບລາຍງານ ແລະ ລອງໃຊ້ສຳເນົາສຳຮອງ ຫຼື ໄຟລ໌ບັນທຶກອັດຕະໂນມັດ. .entities-checked = ອົງປະກອບທີ່ກວດສອບແລ້ວ .issues-found = ບັນຫາທີ່ພົບ - .entities-removed = ອົງປະກອບທີ່ຖືກລຶບອອກ .references-checked = ຈຸດອ້າງອີງທີ່ກວດສອບແລ້ວ - .referenced-entities-removed = ອົງປະກອບອ້າງອີງທີ່ຖືກລຶບອອກ .references-unavailable = ຈຸດອ້າງອີງບໍ່ພ້ອມໃຊ້ງານ .log-path = ບັນທຶກເຫດການການກູ້ຄືນ .log-write-failed = ບໍ່ສາມາດຂຽນບັນທຶກເຫດການການກູ້ຄືນໄດ້ @@ -2598,8 +2596,6 @@ file = .usage-undo-number-of-steps = ວິທີໃຊ້: UNDO [ຈຳນວນຂັ້ນຕອນ] .used-for-the-first-save-of-a-new-drawing-exist = ໃຊ້ສຳລັບການບັນທຶກຄັ້ງທຳອິດຂອງແບບແຕ້ມໃໝ່. ແບບແຕ້ມທີ່ມີຢູ່ແລ້ວຈະຮັກສາປະເພດໄຟລ໌ ແລະ ເວີຊັນເດີມໄວ້. .visual-style-label = ຮູບແບບມຸມມອງ: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = ຄຳເຕືອນ: ຕັດອົງປະກອບທີ່ເສຍຫາຍຖິ້ມ __ocs_fmt_0__ ອັນ (ຂໍ້ມູນເສດຈາກການວິເຄາະ — ຄ່າແນວຕັ້ງສາກ/ຈຳນວນຜິດພາດ) - .warning-corrupt-xref-entities-dropped = ຄຳເຕືອນ: ຕັດອົງປະກອບ xref ທີ່ເສຍຫາຍຖິ້ມ __ocs_fmt_0__ ອັນ .xref-loaded = XREF ໂຫຼດແລ້ວ "__ocs_fmt_0__" .cmd-cannot-create-folder-e = __ocs_fmt_0__: ບໍ່ສາມາດສ້າງໂຟລເດີໄດ້ (__ocs_fmt_1__). .cmd-packaged-copied-file-s-into = __ocs_fmt_0__: ລວມໄຟລ໌ ແລະ ສຳເນົາ __ocs_fmt_1__ ໄຟລ໌ ລົງໃນ __ocs_fmt_2__ @@ -5638,9 +5634,9 @@ styles = .aci-color-index = ດັດຊະນີສີ ACI .aci = ACI: .audit-no-issues-found = AUDIT: ບໍ່ພົບຂໍ້ຜິດພາດ. - .audit-reference-s-to-undefined-block-s = AUDIT: ການອ້າງອີງເຖິງບລັອກທີ່ບໍ່ໄດ້ກຳນົດ: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: ການອ້າງອີງເຖິງເລເຢີທີ່ບໍ່ໄດ້ກຳນົດ: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: ລາຍງານເທົ່ານັ້ນ — ບໍ່ໄດ້ມີການສ້ອມແປງອັດຕະໂນມັດ. + .audit-fix-any-errors-detected = AUDIT ແກ້ໄຂຂໍ້ຜິດພາດທີ່ກວດພົບບໍ? [ແມ່ນ / ບໍ່] <ບໍ່>: + .audit-error-s-warning-s-found = AUDIT: ພົບຂໍ້ຜິດພາດ __ocs_fmt_0__ ລາຍການ, ຄຳເຕືອນ __ocs_fmt_1__ ລາຍການ. + .audit-repair-s-applied-issue-s-left = AUDIT: ສ້ອມແປງແລ້ວ __ocs_fmt_0__ ລາຍການ, ບັນຫາທີ່ຍັງບໍ່ໄດ້ແກ້ __ocs_fmt_1__ ລາຍການ. .audit-scanned-total-object-s = AUDIT: ສະແກນທັງໝົດ __ocs_fmt_0__ ວັດຖຸ. .above-text = ເທິງຂໍ້ຄວາມ .active-dim-style-set-to-name-arg = ຮູບແບບຂະໜາດທີ່ໃຊ້ງານຕັ້ງເປັນ "__ocs_fmt_0__" diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 60ff5d8e4..3e01ed379 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Het herstel kon geen bruikbare tekeninggegevens opleveren. Controleer het rapport en probeer een reservekopie of automatisch opgeslagen kopie. .entities-checked = Gecontroleerde objecten .issues-found = Gevonden problemen - .entities-removed = Verwijderde objecten .references-checked = Gecontroleerde verwijzingen - .referenced-entities-removed = Verwijderde objecten waarnaar werd verwezen .references-unavailable = Niet-beschikbare verwijzingen .log-path = Herstellogboek .log-write-failed = Het herstellogboek kon niet worden geschreven @@ -2591,8 +2589,6 @@ file = .usage-undo-number-of-steps = Gebruik: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = Gebruikt voor de eerste opslag van een nieuwe tekening. Bestaande tekeningen houden hun bestandstype en versie. .visual-style-label = Visuele stijl: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Waarschuwing: __ocs_fmt_0__ beschadigde objecten overgeslagen (ongeldige parsergegevens — foutieve normalen of aantallen) - .warning-corrupt-xref-entities-dropped = Waarschuwing: __ocs_fmt_0__ beschadigde xref-objecten overgeslagen .xref-loaded = XREF geladen "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: kan de transmissie-ZIP niet maken (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: kan map (__ocs_fmt_1__) niet aanmaken. @@ -5636,9 +5632,9 @@ styles = .aci-color-index = ACI Kleurindex .aci = ACI: .audit-no-issues-found = AUDIT: geen problemen gevonden. - .audit-reference-s-to-undefined-block-s = AUDIT: verwijzing(s) naar ongedefinieerd symbool(en): __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: verwijzing(s) naar ongedefinieerde laag(en): __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: alleen melden + .audit-fix-any-errors-detected = AUDIT Gevonden fouten herstellen? [Ja / Nee] : + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ fout(en), __ocs_fmt_1__ waarschuwing(en) gevonden. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ herstelling(en) toegepast, __ocs_fmt_1__ probleem/problemen onopgelost. .audit-scanned-total-object-s = AUDIT: __ocs_fmt_0__ object(en) gecontroleerd. .above-text = Bovenstaande tekst .active-dim-style-set-to-name-arg = Actieve maatstijl ingesteld op "__ocs_fmt_0__" diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index 3801846f2..8146fe178 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Odzyskiwanie nie przyniosło użytecznych danych rysunku. Przejrzyj raport i spróbuj użyć kopii zapasowej lub automatycznie zapisanej. .entities-checked = Sprawdzone elementy .issues-found = Znalezione problemy - .entities-removed = Usunięte elementy .references-checked = Sprawdzone odnośniki - .referenced-entities-removed = Usunięte elementy przywoływane .references-unavailable = Niedostępne odnośniki .log-path = Dziennik odzyskiwania .log-write-failed = Nie można zapisać dziennika odzyskiwania @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = Sposób użycia: UNDO [liczba kroków] .used-for-the-first-save-of-a-new-drawing-exist = Używane przy pierwszym zapisie nowego rysunku. Istniejące rysunki zachowują swój typ pliku i wersję. .visual-style-label = Styl wizualny: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Ostrzeżenie: usunięte zostały uszkodzone jednostki __ocs_fmt_0__ (śmieci parsera — złe wartości normalne/liczby) - .warning-corrupt-xref-entities-dropped = Ostrzeżenie: usunięte zostały uszkodzone elementy odnośników zewnętrznych __ocs_fmt_0__ .xref-loaded = XREF Załadowano „__ocs_fmt_0__” .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: nie można utworzyć archiwum ZIP transmittalu (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: nie można utworzyć folderu (__ocs_fmt_1__). @@ -5637,9 +5633,9 @@ styles = .aci-color-index = Indeks kolorów ACI .aci = ACI: .audit-no-issues-found = AUDIT: nie znaleziono żadnych problemów. - .audit-reference-s-to-undefined-block-s = AUDIT: odniesienia do niezdefiniowanych bloków: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: odniesienia do niezdefiniowanych warstw: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: tylko raport — nie wykonano automatycznej naprawy. + .audit-fix-any-errors-detected = AUDIT Naprawić wykryte błędy? [Tak / Nie] : + .audit-error-s-warning-s-found = AUDIT: znaleziono błędy: __ocs_fmt_0__, ostrzeżenia: __ocs_fmt_1__. + .audit-repair-s-applied-issue-s-left = AUDIT: zastosowane naprawy: __ocs_fmt_0__, nierozwiązane problemy: __ocs_fmt_1__. .audit-scanned-total-object-s = AUDIT: zeskanowane obiekty __ocs_fmt_0__. .above-text = Powyżej tekstu .active-dim-style-set-to-name-arg = Aktywny styl przyciemnienia ustawiony na „__ocs_fmt_0__” diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index 22723a1dc..35c9279a3 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = A recuperação não conseguiu produzir dados de desenho utilizáveis. Revise o relatório e tente um backup ou uma cópia de salvamento automático. .entities-checked = Entidades verificadas .issues-found = Problemas encontrados - .entities-removed = Entidades removidas .references-checked = Referências verificadas - .referenced-entities-removed = Entidades referenciadas removidas .references-unavailable = Referências indisponíveis .log-path = Log de recuperação .log-write-failed = Não foi possível gravar o log de recuperação @@ -2591,8 +2589,6 @@ file = .usage-undo-number-of-steps = Uso: UNDO [número de etapas] .used-for-the-first-save-of-a-new-drawing-exist = Usado no primeiro salvamento de um novo desenho. Desenhos existentes mantêm seu tipo e versão de arquivo. .visual-style-label = Estilo visual: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Aviso: __ocs_fmt_0__ entidades corrompidas descartadas (dados inválidos do analisador — normais/contagens incorretas) - .warning-corrupt-xref-entities-dropped = Aviso: __ocs_fmt_0__ entidades de referência externa corrompidas descartadas .xref-loaded = XREF “__ocs_fmt_0__” carregada .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: não foi possível criar o ZIP de transmissão (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: não é possível criar a pasta (__ocs_fmt_1__). @@ -5638,9 +5634,9 @@ styles = .aci-color-index = Índice de cor ACI .aci = ACI: .audit-no-issues-found = AUDIT: nenhum problema encontrado. - .audit-reference-s-to-undefined-block-s = AUDIT: referências a blocos indefinidos: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: referências a camadas indefinidas: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: somente relatório — nenhum reparo automático realizado. + .audit-fix-any-errors-detected = AUDIT Corrigir os erros detectados? [Sim / Não] : + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ erro(s), __ocs_fmt_1__ aviso(s) encontrado(s). + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ reparo(s) aplicado(s), __ocs_fmt_1__ problema(s) não resolvido(s). .audit-scanned-total-object-s = AUDIT: __ocs_fmt_0__ objetos verificados. .above-text = Acima do texto .active-dim-style-set-to-name-arg = Estilo de cota ativo definido como “__ocs_fmt_0__” diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index ae46aa3b6..c60d33e8e 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -225,9 +225,7 @@ recovery = .failed-description = Восстановить пригодные данные чертежа не удалось. Просмотрите отчёт и попробуйте резервную или автоматически сохранённую копию. .entities-checked = Проверено объектов .issues-found = Обнаружено проблем - .entities-removed = Удалено объектов .references-checked = Проверено ссылок - .referenced-entities-removed = Удалено ссылочных объектов .references-unavailable = Недоступные ссылки .log-path = Журнал восстановления .log-write-failed = Не удалось записать журнал восстановления @@ -2594,8 +2592,6 @@ file = .usage-undo-number-of-steps = Использование: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = Используется при первом сохранении нового чертежа. Существующие чертежи сохраняют свой тип и версию файла. .visual-style-label = Визуальный стиль: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Предупреждение: повреждённые объекты пропущены: __ocs_fmt_0__ (ошибочные данные анализатора — неверные нормали или количества) - .warning-corrupt-xref-entities-dropped = Предупреждение: повреждённые объекты внешней ссылки пропущены: __ocs_fmt_0__ .xref-loaded = XREF Загруженный "__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: не удалось создать ZIP-пакет передачи (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: не может создавать папку (__ocs_fmt_1__). @@ -5639,9 +5635,9 @@ styles = .aci-color-index = Индекс цвета ACI .aci = ACI: .audit-no-issues-found = AUDIT: не найдено никаких проблем. - .audit-reference-s-to-undefined-block-s = AUDIT: ссылка(ы) на неопределенный(ые) блок(ы): __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: ссылка(ы) на неопределенный(ые) слой(ы): __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: только отчет - не выполняется автоматический ремонт. + .audit-fix-any-errors-detected = AUDIT Исправить обнаруженные ошибки? [Да / Нет] <Нет>: + .audit-error-s-warning-s-found = AUDIT: найдено ошибок: __ocs_fmt_0__, предупреждений: __ocs_fmt_1__. + .audit-repair-s-applied-issue-s-left = AUDIT: применено исправлений: __ocs_fmt_0__, не устранено проблем: __ocs_fmt_1__. .audit-scanned-total-object-s = AUDIT: сканируемый объект (объекты) __ocs_fmt_0__. .above-text = Выше текста .active-dim-style-set-to-name-arg = Активным стилем размеров назначен «__ocs_fmt_0__» diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 80109e3fe..ebca91193 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -222,9 +222,7 @@ recovery = .failed-description = Kurtarma işlemi kullanılabilir çizim verisi üretemedi. Raporu inceleyip bir yedek veya otomatik kayıt kopyasını deneyin. .entities-checked = Denetlenen obje .issues-found = Bulunan sorun - .entities-removed = Kaldırılan obje .references-checked = Denetlenen referans - .referenced-entities-removed = Referanslardan kaldırılan obje .references-unavailable = Kullanılamayan referans .log-path = Kurtarma günlüğü .log-write-failed = Kurtarma günlüğü yazılamadı @@ -2574,8 +2572,6 @@ file = .usage-undo-number-of-steps = Kullanım: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = Yeni bir çizimin ilk kaydında kullanılır. Mevcut çizimler dosya türünü ve sürümünü korur. .visual-style-label = Görsel stil: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = Uyarı: __ocs_fmt_0__ bozuk nesne atıldı (ayrıştırıcı artığı — hatalı normaller / sayılar) - .warning-corrupt-xref-entities-dropped = Uyarı: __ocs_fmt_0__ bozuk dış referans nesnesi atıldı .xref-loaded = XREF "__ocs_fmt_0__" yüklendi .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: aktarım ZIP'i oluşturulamıyor (__ocs_fmt_1__). .cmd-cannot-create-folder-e = __ocs_fmt_0__: Klasör oluşturulamıyor (__ocs_fmt_1__). @@ -5576,9 +5572,9 @@ styles = .aci-color-index = ACI renk dizini .aci = ACI: .audit-no-issues-found = AUDIT: sorun bulunamadı. - .audit-reference-s-to-undefined-block-s = AUDIT: tanımsız bloklara başvurular: __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: tanımsız katmanlara başvurular: __ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT: yalnızca rapor oluşturuldu; otomatik onarım yapılmadı. + .audit-fix-any-errors-detected = AUDIT Bulunan hatalar düzeltilsin mi? [Evet / Hayır] : + .audit-error-s-warning-s-found = AUDIT: __ocs_fmt_0__ hata, __ocs_fmt_1__ uyarı bulundu. + .audit-repair-s-applied-issue-s-left = AUDIT: __ocs_fmt_0__ onarım uygulandı, __ocs_fmt_1__ sorun çözülemedi. .audit-scanned-total-object-s = AUDIT: __ocs_fmt_0__ nesne tarandı. .above-text = Metnin üstünde .active-dim-style-set-to-name-arg = Etkin ölçü stili "__ocs_fmt_0__" olarak ayarlandı. diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index a87e01d6e..993d5f538 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -224,9 +224,7 @@ recovery = .failed-description = 修复未能生成可用的图形数据。请查看报告并尝试备份或自动保存的副本。 .entities-checked = 已检查实体 .issues-found = 发现的问题 - .entities-removed = 已删除实体 .references-checked = 已检查参照 - .referenced-entities-removed = 已删除被参照实体 .references-unavailable = 不可用参照 .log-path = 修复日志 .log-write-failed = 无法写入修复日志 @@ -2578,8 +2576,6 @@ file = .usage-undo-number-of-steps = 用法: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = 用于新图形的首次保存。现有图形会保留其自身的文件类型和版本。 .visual-style-label = 视觉风格: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = 警告:已丢弃 __ocs_fmt_0__ 个损坏对象(解析数据无效——法线或计数错误) - .warning-corrupt-xref-entities-dropped = 警告:已丢弃 __ocs_fmt_0__ 个损坏的 xref 对象 .xref-loaded = XREF已装入"__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: 无法创建传输 ZIP(__ocs_fmt_1__)。 .cmd-cannot-create-folder-e = __ocs_fmt_0__:无法创建文件夹(__ocs_fmt_1__). @@ -5621,9 +5617,9 @@ styles = .aci-color-index = ACI 颜色索引 .aci = ACI: .audit-no-issues-found = AUDIT:没有找到问题。 - .audit-reference-s-to-undefined-block-s = AUDIT: 未定义块的引用 : __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: 未定义层的参考:__ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT:只报告——没有进行自动修复。 + .audit-fix-any-errors-detected = AUDIT 修复检测到的错误? [是 / 否] <否>: + .audit-error-s-warning-s-found = AUDIT: 发现 __ocs_fmt_0__ 个错误,__ocs_fmt_1__ 个警告。 + .audit-repair-s-applied-issue-s-left = AUDIT: 已应用 __ocs_fmt_0__ 项修复,__ocs_fmt_1__ 个问题未解决。 .audit-scanned-total-object-s = AUDIT: 扫描__ocs_fmt_0__对象。 .above-text = 上方为文本 .active-dim-style-set-to-name-arg = 当前标注样式已设为“__ocs_fmt_0__” diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index 0ff11fa53..efbf617ad 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -224,9 +224,7 @@ recovery = .failed-description = 修復未能產生可用的圖形資料。請查看報告並嘗試備份或自動儲存的副本。 .entities-checked = 已檢查實體 .issues-found = 發現的問題 - .entities-removed = 已刪除實體 .references-checked = 已檢查參照 - .referenced-entities-removed = 已刪除被參照實體 .references-unavailable = 不可用參照 .log-path = 修復日誌 .log-write-failed = 無法寫入修復日誌 @@ -2590,8 +2588,6 @@ file = .usage-undo-number-of-steps = 用法: UNDO [number of steps] .used-for-the-first-save-of-a-new-drawing-exist = 用於新圖形的首次儲存。現有圖形會保留其自身的檔案類型和版本。 .visual-style-label = 視覺風格: __ocs_fmt_0__. - .warning-corrupt-entities-dropped-parser-junk-b = 警告:已丟棄 __ocs_fmt_0__ 個損壞物件(解析資料無效——法線或計數錯誤) - .warning-corrupt-xref-entities-dropped = 警告:已丟棄 __ocs_fmt_0__ 個損壞的 xref 物件 .xref-loaded = XREF已載入"__ocs_fmt_0__" .cmd-cannot-build-the-transmittal-zip-e = __ocs_fmt_0__: 無法建立傳送 ZIP(__ocs_fmt_1__)。 .cmd-cannot-create-folder-e = __ocs_fmt_0__:無法建立資料夾(__ocs_fmt_1__). @@ -5633,9 +5629,9 @@ styles = .aci-color-index = ACI 顏色索引 .aci = ACI: .audit-no-issues-found = AUDIT:沒有找到問題。 - .audit-reference-s-to-undefined-block-s = AUDIT: 未定義圖塊的引用 : __ocs_fmt_0__ - .audit-reference-s-to-undefined-layer-s = AUDIT: 未定義層的參考:__ocs_fmt_0__ - .audit-report-only-no-automatic-repair-performe = AUDIT:只報告——沒有進行自動修復。 + .audit-fix-any-errors-detected = AUDIT 修復偵測到的錯誤? [是 / 否] <否>: + .audit-error-s-warning-s-found = AUDIT: 發現 __ocs_fmt_0__ 個錯誤,__ocs_fmt_1__ 個警告。 + .audit-repair-s-applied-issue-s-left = AUDIT: 已套用 __ocs_fmt_0__ 項修復,__ocs_fmt_1__ 個問題未解決。 .audit-scanned-total-object-s = AUDIT: 掃描__ocs_fmt_0__物件。 .above-text = 上方為文字 .active-dim-style-set-to-name-arg = 目前標註樣式已設為“__ocs_fmt_0__” diff --git a/plugins/opencad-python/Cargo.lock b/plugins/opencad-python/Cargo.lock index c74034305..11cfbc9aa 100644 --- a/plugins/opencad-python/Cargo.lock +++ b/plugins/opencad-python/Cargo.lock @@ -1273,7 +1273,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cb3ce6a#cb3ce6a93c76a5069f5c2391ee44ea38b4485d15" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=325fa98#325fa98d2b881f48e106a830d5cf161624f63131" dependencies = [ "anyhow", "bitflags", diff --git a/src/app/automation.rs b/src/app/automation.rs index 74b95ce18..1524e09c9 100644 --- a/src/app/automation.rs +++ b/src/app/automation.rs @@ -762,7 +762,7 @@ impl OpenCADStudio { Err(e) => return err(format!("open: {e}")), }; match crate::io::load_bytes_finalized(&path_buf, bytes) { - Ok((doc, dropped)) => { + Ok(doc) => { let i = self.active_tab; self.tabs[i].scene.clear(); self.tabs[i].scene.document = doc; @@ -784,13 +784,7 @@ impl OpenCADStudio { // The opened document settled (API v9): the post-op // boundary announces `DocumentOpened` once for this load. self.tabs[i].note_document_loaded(); - let mut summary = self.entity_summary(); - if dropped > 0 { - if let Some(obj) = summary.as_object_mut() { - obj.insert("purged".to_string(), json!(dropped)); - } - } - summary + self.entity_summary() } Err(e) => err(format!("open: {e}")), } @@ -1903,8 +1897,7 @@ mod tests { fingerprint: None, }); let bytes = std::fs::read(&path).expect("read the fixture back"); - let (document, _dropped) = - crate::io::load_bytes_finalized(&path, bytes).expect("reparse the fixture"); + let document = crate::io::load_bytes_finalized(&path, bytes).expect("reparse the fixture"); let caches = crate::scene::build_derived_caches_with_progress(&document, &|_| {}, None); let _ = plugin_dispatch_log(); let _ = app.update(crate::app::Message::FileOpened( @@ -3839,7 +3832,7 @@ mod tests { } #[test] - fn open_finalizes_and_purges_like_the_ui_open_path() { + fn open_finalizes_like_the_ui_open_path() { let mut app = OpenCADStudio::new_for_test(); let stale = codec::Handle::from(9999); app.tabs[app.active_tab].scene.solid_models.insert( @@ -3857,26 +3850,13 @@ mod tests { good.center = codec::types::Vector3::new(5.0, 5.0, 0.0); good.radius = 2.0; doc.add_entity(codec::EntityType::Circle(good)).unwrap(); - let mut corrupt = codec::entities::Circle::new(); - corrupt.center = codec::types::Vector3::new(1.0, 1.0, 0.0); - // An absurd radius is rejected; a zero radius is valid. - corrupt.radius = 1.0e11; - doc.add_entity(codec::EntityType::Circle(corrupt)).unwrap(); - let bytes = crate::io::save_to_bytes(&doc, "dxf", doc.version) - .expect("save a document containing a corrupt entity"); + let bytes = crate::io::save_to_bytes(&doc, "dxf", doc.version).expect("save the fixture"); std::fs::write(&path, bytes).unwrap(); let p = path.to_string_lossy().replace('\\', "\\\\"); let result = app.automation_op(&format!(r#"{{"op":"open","path":"{p}"}}"#)); assert_eq!(result["ok"], true, "{}", result["error"]); - assert_eq!( - result["total"], 1, - "the corrupt circle must not survive the open" - ); - assert_eq!( - result["purged"], 1, - "the purge count must be reported, matching the UI open path's diagnostics" - ); + assert_eq!(result["total"], 1); let i = app.active_tab; assert!(!app.tabs[i].scene.solid_models.contains_key(&stale)); diff --git a/src/app/commands/blocks.rs b/src/app/commands/blocks.rs index 5259bc53e..c4ca382f9 100644 --- a/src/app/commands/blocks.rs +++ b/src/app/commands/blocks.rs @@ -1128,7 +1128,7 @@ impl OpenCADStudio { .filter(|br| reload_keys.contains(&br.handle.value())) .map(|br| br.handle) .collect(); - let (infos, _dropped) = crate::io::xref::resolve_xrefs_for_keys( + let infos = crate::io::xref::resolve_xrefs_for_keys( &mut self.tabs[i].scene.document, base_dir, &handles, @@ -1674,7 +1674,7 @@ impl OpenCADStudio { self.tabs[i].xref_unloaded.remove(key); self.tabs[i].xref_stat_cache.remove(key); } - let (infos, _dropped) = crate::io::xref::resolve_xrefs( + let infos = crate::io::xref::resolve_xrefs( &mut self.tabs[i].scene.document, &base_dir, ); diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index d1147aa5f..376f0ae63 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -3635,53 +3635,62 @@ impl OpenCADStudio { .push_error(crate::tf!("COMPARE: {error}").as_ref()), } } + // AUDIT runs the codec's audit; `AUDIT Yes` also applies its + // repair, undoable as one step. "AUDIT" => { - use std::collections::BTreeSet; - let mut undefined_layers: BTreeSet = BTreeSet::new(); - let mut undefined_blocks: BTreeSet = BTreeSet::new(); - let mut total = 0usize; - { + use crate::command::KeywordCommand; + let c = KeywordCommand::new( + "AUDIT", + "AUDIT Fix any errors detected? [Yes / No] :", + vec![("Yes", "YES", None), ("No", "NO", None)], + ) + .with_default("NO"); + self.command_line.push_info(&c.prompt()); + self.tabs[i].active_cmd = Some(Box::new(c)); + } + cmd if cmd.starts_with("AUDIT ") => { + let fix = cmd[6..].trim().to_uppercase().starts_with('Y'); + let report = self.tabs[i].scene.document.audit(); + let total = { let doc = &self.tabs[i].scene.document; - for e in doc.entities() { - total += 1; - let layer = &e.common().layer; - if !layer.is_empty() && doc.layers.get(layer).is_none() { - undefined_layers.insert(layer.clone()); - } - if let codec::EntityType::Insert(ins) = e { - if doc.block_records.get(&ins.block_name).is_none() { - undefined_blocks.insert(ins.block_name.clone()); - } - } - } - } + doc.entities().count() + doc.objects.len() + }; self.command_line .push_output(crate::tf!("AUDIT: scanned {total} object(s).").as_ref()); - if undefined_layers.is_empty() && undefined_blocks.is_empty() { + if report.is_clean() { self.command_line .push_output(crate::t!("AUDIT: no issues found.").as_ref()); - } else { - if !undefined_layers.is_empty() { - self.command_line.push_error( - crate::tf!( - "AUDIT: reference(s) to undefined layer(s): {}", - undefined_layers.into_iter().collect::>().join(", ") - ) - .as_ref(), - ); - } - if !undefined_blocks.is_empty() { - self.command_line.push_error( - crate::tf!( - "AUDIT: reference(s) to undefined block(s): {}", - undefined_blocks.into_iter().collect::>().join(", ") - ) - .as_ref(), - ); - } - self.command_line.push_info( - crate::t!("AUDIT: report only — no automatic repair performed.").as_ref(), + return Some(Task::none()); + } + self.command_line.push_error( + crate::tf!( + "AUDIT: {} error(s), {} warning(s) found.", + report.error_count(), + report.warning_count() + ) + .as_ref(), + ); + // ponytail: first 50 issues only; the counts above cover the rest. + for issue in report.issues.iter().take(50) { + self.command_line + .push_info(&format!(" {:?}: {}", issue.code, issue.message)); + } + if fix { + self.push_undo_snapshot(i, "AUDIT"); + let repair = self.tabs[i].scene.document.repair(); + self.command_line.push_output( + crate::tf!( + "AUDIT: {} repair(s) applied, {} issue(s) left unresolved.", + repair.actions.len(), + repair.unresolved.len() + ) + .as_ref(), ); + if !repair.actions.is_empty() { + self.tabs[i].dirty = true; + self.tabs[i].scene.rebuild_derived_caches(); + self.refresh_layer_panel(); + } } } diff --git a/src/app/control/mod.rs b/src/app/control/mod.rs index cd1dccfd1..834b60e26 100644 --- a/src/app/control/mod.rs +++ b/src/app/control/mod.rs @@ -1009,10 +1009,9 @@ impl OpenCADStudio { "new" => { if let Some(template) = req["template"].as_str() { match self.apply_template(template) { - Ok(purged) => { + Ok(()) => { self.set_control_result(json!({ "template": template, - "purged": purged, "total": self.tabs[i].scene.document.entities().count(), })); Task::none() diff --git a/src/app/control/sheets.rs b/src/app/control/sheets.rs index 3045149ac..486929b5a 100644 --- a/src/app/control/sheets.rs +++ b/src/app/control/sheets.rs @@ -434,7 +434,7 @@ impl OpenCADStudio { /// `new` with `"template"` — the web build reads no files from a path, so /// a template is refused there rather than silently ignored. #[cfg(target_arch = "wasm32")] - pub(in crate::app) fn apply_template(&mut self, _template: &str) -> Result { + pub(in crate::app) fn apply_template(&mut self, _template: &str) -> Result<(), Value> { Err(failure( "invalid_request", "starting from a template needs the desktop build", @@ -445,7 +445,7 @@ impl OpenCADStudio { /// file. Tables and styles come from the template; the document keeps no /// source path. #[cfg(not(target_arch = "wasm32"))] - pub(in crate::app) fn apply_template(&mut self, template: &str) -> Result { + pub(in crate::app) fn apply_template(&mut self, template: &str) -> Result<(), Value> { let path = std::path::PathBuf::from(template); let bytes = self .read_drawing(&path) @@ -461,7 +461,7 @@ impl OpenCADStudio { } else { path.clone() }; - let (mut document, purged) = crate::io::load_bytes_finalized(&load_path, bytes) + let mut document = crate::io::load_bytes_finalized(&load_path, bytes) .map_err(|e| failure("template_failed", e))?; document.source_path = Some(path.to_string_lossy().into_owned()); let i = self.active_tab; @@ -482,7 +482,7 @@ impl OpenCADStudio { // A whole document just became resident in the tab (API v9): the // boundary announces `DocumentOpened` once. self.tabs[i].note_document_loaded(); - Ok(purged) + Ok(()) } /// `file_identity` — stable per-document GUID (the drawing's SPMDOCUNIQUE value, diff --git a/src/app/update/dialog.rs b/src/app/update/dialog.rs index ea74e5f10..66223bb6a 100644 --- a/src/app/update/dialog.rs +++ b/src/app/update/dialog.rs @@ -886,7 +886,7 @@ impl OpenCADStudio { .filter(|br| dwg_picked.iter().any(|(key, _)| *key == br.handle.value())) .map(|br| br.handle) .collect(); - let (infos, _dropped) = crate::io::xref::resolve_xrefs_for_keys( + let infos = crate::io::xref::resolve_xrefs_for_keys( &mut self.tabs[i].scene.document, &base_dir, &handles, @@ -1093,7 +1093,7 @@ impl OpenCADStudio { self.tabs[i].xref_unloaded.remove(key); self.tabs[i].xref_stat_cache.remove(key); } - let (infos, _dropped) = + let infos = crate::io::xref::resolve_xrefs(&mut self.tabs[i].scene.document, &base_dir); let fresh = crate::io::xref::collect_entries_with_prev( &self.tabs[i].scene.document, diff --git a/src/app/update/file.rs b/src/app/update/file.rs index 16bd379cb..c4a7b38bc 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -2051,34 +2051,13 @@ impl OpenCADStudio { .xrefs .iter() .any(|item| item.status == crate::io::xref::XrefStatus::Failed); - let document_repaired = parser_errors_recovered - || reference_recovered - || caches.corrupt_dropped > 0 - || caches.xref_dropped > 0; + let document_repaired = parser_errors_recovered || reference_recovered; let recovery_needed = document_repaired || reference_failed; let total_ms = open_started .map(|started| started.elapsed().as_millis() as u32) .unwrap_or(0); self.command_line .push_output(crate::tf!("Opened \"{name}\" — {entity_count} entities").as_ref()); - if caches.corrupt_dropped > 0 { - self.command_line.push_error( - crate::tf!( - "Warning: {} corrupt entities dropped (parser junk — bad normals / counts)", - caches.corrupt_dropped - ) - .as_ref(), - ); - } - if caches.xref_dropped > 0 { - self.command_line.push_error( - crate::tf!( - "Warning: {} corrupt xref entities dropped", - caches.xref_dropped - ) - .as_ref(), - ); - } for info in &caches.xrefs { match info.status { crate::io::xref::XrefStatus::Loaded => { @@ -2178,9 +2157,7 @@ impl OpenCADStudio { size_bytes, caches.source_sha256.clone(), caches.read_stats.clone(), - entity_count.saturating_add(caches.corrupt_dropped), - caches.corrupt_dropped, - caches.xref_dropped, + entity_count, &caches.xrefs, &doc.notifications, document_repaired, diff --git a/src/io/mod.rs b/src/io/mod.rs index a0e639614..fa8a619f7 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -130,7 +130,7 @@ fn recovery_fingerprint_needed(caches: &DerivedCaches) -> bool { crate::io::xref::XrefStatus::Recovered | crate::io::xref::XrefStatus::Failed ) }); - parser_issue || caches.corrupt_dropped > 0 || caches.xref_dropped > 0 || reference_issue + parser_issue || reference_issue } #[derive(Debug, Clone)] @@ -439,17 +439,10 @@ async fn open_path_with_phase_attempt( let parse_ms = t_parse.elapsed().as_millis() as u32; progress2.set(crate::app::OPEN_PHASE_PARSING, 5800, 1000, 1000); let t_purge = Instant::now(); - let dropped = purge_corrupt_entities(&mut doc); - let purge_ms = t_purge.elapsed().as_millis() as u32; - if matches!(attempt, OpenAttempt::Strict) && dropped > 0 { - return Err(OpenAttemptFailure { - message: format!( - "normal read found {dropped} structurally invalid drawing records" - ), - read_stats: Some(read_stats), - recoverable: true, - }); + if matches!(attempt, OpenAttempt::Recovery(..)) { + repair_drawing(&mut doc); } + let purge_ms = t_purge.elapsed().as_millis() as u32; // Before the geometry is prepared below: repairing the // drawing's stripped catalog linetypes after it would leave // the first view drawn without their shapes. None is added: @@ -457,7 +450,7 @@ async fn open_path_with_phase_attempt( crate::io::linetypes::repair_document(&mut doc); progress2.set(crate::app::OPEN_PHASE_XREF, 6000, 0, 1); let t_xref = Instant::now(); - let (xref_infos, xref_dropped) = if let Some(base_dir) = path2.parent() { + let xref_infos = if let Some(base_dir) = path2.parent() { let xref_progress = { let progress = Arc::clone(&progress2); let callback: Arc = @@ -479,7 +472,7 @@ async fn open_path_with_phase_attempt( Some(xref_progress), ) } else { - (Vec::new(), 0) + Vec::new() }; let xref_ms = t_xref.elapsed().as_millis() as u32; progress2.set(crate::app::OPEN_PHASE_CACHING, 7400, 0, 10000); @@ -506,9 +499,7 @@ async fn open_path_with_phase_attempt( // Filled in after `prepare_open_geometry` below. finalize_ms: 0, }; - caches.corrupt_dropped = dropped; caches.read_stats = Some(read_stats); - caches.xref_dropped = xref_dropped; caches.xrefs = xref_infos; if recovery_fingerprint_needed(&caches) { caches.source_sha256 = @@ -800,25 +791,17 @@ async fn load_web_bytes( fix_current_style_names(&mut doc); crate::entities::field::local_header_dates(&mut doc); progress.set(crate::app::OPEN_PHASE_CACHING, 7000, 0, 1); - let dropped = purge_corrupt_entities(&mut doc); - if !recovery_mode && dropped > 0 { - return Err(OpenLoadError { - message: format!("normal read found {dropped} structurally invalid drawing records"), - source_sha256: None, - read_stats: Some(outcome.stats), - recovery_available: true, - }); + if recovery_mode { + repair_drawing(&mut doc); } // XREFs inside the opened drawing resolve from the in-session bytes // registry (see `resolve_web_xrefs`) before the caches snapshot the // document, so merged xref geometry is part of the caches — the same // phase order the native open uses. - let (xref_infos, xref_dropped) = resolve_web_xrefs(&mut doc, progress.clone()).await; + let xref_infos = resolve_web_xrefs(&mut doc, progress.clone()).await; let mut caches = crate::scene::build_derived_caches(&doc); - caches.corrupt_dropped = dropped; caches.read_stats = Some(outcome.stats); caches.xrefs = xref_infos; - caches.xref_dropped = xref_dropped; if source_sha256.is_none() && recovery_fingerprint_needed(&caches) { source_sha256 = web_worker::sha256_document(bytes).await.ok(); } @@ -891,7 +874,7 @@ pub async fn parse_drawing_bytes_web(name: &str, bytes: &[u8]) -> Result, -) -> (Vec, usize) { +) -> Vec { let pending: Vec = doc .block_records .iter() @@ -995,7 +978,7 @@ pub fn load_bytes(name: &str, bytes: Vec) -> Result { } #[cfg(not(target_arch = "wasm32"))] -pub fn load_bytes_finalized(path: &Path, bytes: Vec) -> Result<(CadDocument, usize), String> { +pub fn load_bytes_finalized(path: &Path, bytes: Vec) -> Result { let name = path .file_name() .map(|n| n.to_string_lossy().into_owned()) @@ -1006,8 +989,7 @@ pub fn load_bytes_finalized(path: &Path, bytes: Vec) -> Result<(CadDocument, doc.source_path = Some(path.to_string_lossy().into_owned()); // Opening is a field evaluation event (FIELDEVAL bit 1). crate::entities::field::update_fields(&mut doc, 1, None); - let dropped = purge_corrupt_entities(&mut doc); - Ok((doc, dropped)) + Ok(doc) } /// Load a DWG or DXF file directly from a path (auto-detect by extension). @@ -1254,7 +1236,6 @@ fn finalize_loaded_outcome( let doc = &mut outcome.document; normalize_block_origins(doc); materialize_missing_block_markers(doc); - normalize_knotless_splines(doc); if outcome.stats.source_format == Some(codec::SourceFormat::Dxf) { fix_dxf_dimension_rotations(doc); fix_dxf_layout_plot_settings(doc); @@ -2679,174 +2660,24 @@ fn sync_current_styles_on_save(doc: &mut CadDocument) { set_sketch_settings(doc, sketch_type, increment, tolerance); } -// ── Corrupt-entity guard ────────────────────────────────────────────────── -// -// opencadcodec's DWG parser occasionally desynchronises on certain files and -// produces entities with garbage fields: non-unit normals (components in -// 1e200+), nonsensical vertex counts (e.g. 100000), or infinite/NaN -// coordinates. Tessellating such entities triggers huge allocations and -// numerical blow-ups in the wire pipeline. -// -// `purge_corrupt_entities` scans the document and removes any entity that -// fails a cheap sanity check, returning the number dropped so the caller can -// surface it to the UI / log. -// -// Keep valid degenerate geometry: dropping it would trigger strict-open recovery. - -fn finite_unit_normal(n: &codec::types::Vector3) -> bool { - let (x, y, z) = (n.x, n.y, n.z); - if !x.is_finite() || !y.is_finite() || !z.is_finite() { - return false; +/// Recovery runs the codec's repair and reports what it did, and what it +/// left, through the drawing's notifications. +pub(crate) fn repair_drawing(doc: &mut CadDocument) { + let repair = doc.repair(); + for action in &repair.actions { + doc.notifications.notify( + codec::notification::NotificationType::Warning, + format!("Recovery repair: {action:?}"), + ); } - let mag2 = x * x + y * y + z * z; - // Accept anything within ~10% of unit length. Real files sometimes - // store slightly denormalised normals from rounding. - (mag2 - 1.0).abs() < 0.21 -} - -fn finite_coord(v: f64) -> bool { - v.is_finite() && v.abs() < 1.0e12 -} - -fn finite_vec3(v: &codec::types::Vector3) -> bool { - finite_coord(v.x) && finite_coord(v.y) && finite_coord(v.z) -} - -/// Returns true if the entity looks like parser garbage and should be dropped. -pub(crate) fn is_entity_corrupt(e: &EntityType) -> bool { - use codec::entities::EntityType as E; - // Reject polylines at or above this vertex count. Even valid drawings - // rarely use this many — and parser desync produces exactly-100_000-vertex - // junk records. - const MAX_VERTS: usize = 100_000; - match e { - E::LwPolyline(p) => { - !finite_unit_normal(&p.normal) - || p.vertices.len() >= MAX_VERTS - || !finite_coord(p.elevation) - || p.elevation.abs() > 1.0e10 - || !finite_coord(p.thickness) - || p.thickness.abs() > 1.0e10 - || p.vertices - .iter() - .any(|v| !finite_coord(v.location.x) || !finite_coord(v.location.y)) - } - E::Polyline2D(p) => { - !finite_unit_normal(&p.normal) - || p.vertices.len() >= MAX_VERTS - || !finite_coord(p.elevation) - || p.elevation.abs() > 1.0e10 - || !finite_coord(p.thickness) - || p.thickness.abs() > 1.0e10 - || p.vertices.iter().any(|v| !finite_vec3(&v.location)) - } - E::Polyline3D(p) => { - p.vertices.len() >= MAX_VERTS || p.vertices.iter().any(|v| !finite_vec3(&v.position)) - } - E::Polyline(p) => { - p.vertices.len() >= MAX_VERTS || p.vertices.iter().any(|v| !finite_vec3(&v.location)) - } - E::Line(l) => !finite_vec3(&l.start) || !finite_vec3(&l.end), - // Zero-radius curves are valid and have bounded kernel tessellation. - E::Circle(c) => { - !finite_vec3(&c.center) || !finite_coord(c.radius) || c.radius.abs() > 1.0e10 - } - E::Arc(a) => { - !finite_vec3(&a.center) - || !finite_coord(a.radius) - || !a.start_angle.is_finite() - || !a.end_angle.is_finite() - || a.radius.abs() > 1.0e10 - || !finite_unit_normal(&a.normal) - } - E::Ellipse(e) => { - !finite_vec3(&e.center) - || !finite_vec3(&e.major_axis) - || !e.start_parameter.is_finite() - || !e.end_parameter.is_finite() - || (e.end_parameter - e.start_parameter).abs() < 1.0e-9 - || { - let m2 = e.major_axis.x * e.major_axis.x - + e.major_axis.y * e.major_axis.y - + e.major_axis.z * e.major_axis.z; - !m2.is_finite() || m2 < 1.0e-20 || m2 > 1.0e20 - } - || !e.minor_axis_ratio.is_finite() - || e.minor_axis_ratio.abs() < 1.0e-10 - } - E::Spline(s) => { - // Parser desync emits exactly-100_000-control-point splines with a - // garbage knot vector. Building a NURBS from one and - // tessellating it runs `parameter_division` into an unbounded - // allocation — single-threaded, 32 GB+ — long before the drawing - // finishes loading. Reject the desync signature plus any spline - // the kernel can't build: non-finite control points, or a knot vector - // that's non-finite, non-monotonic, or the wrong length - // (the kernel requires `knots.len() == ctrl.len() + degree + 1`). - let n = s.control_points.len(); - let degree_bad = s.degree < 1; - let deg = s.degree.max(0) as usize; - let compact_periodic_knots = s.flags.periodic && s.knots.len() == n.saturating_add(1); - let knots_bad = !s.knots.is_empty() - && (s.knots.iter().any(|k| !k.is_finite()) - || s.knots.windows(2).any(|w| w[1] < w[0]) - || (!compact_periodic_knots && s.knots.len() != n + deg + 1)); - // A single control point with no knots and no fit points cannot - // form a curve, and no knot vector exists for it. - let lone_point = n == 1 && s.knots.is_empty() && s.fit_points.is_empty(); - n >= MAX_VERTS - || degree_bad - || lone_point - || s.control_points.iter().any(|p| !finite_vec3(p)) - || knots_bad - } - _ => false, + for issue in &repair.unresolved { + doc.notifications.notify( + codec::notification::NotificationType::Warning, + format!("Recovery left unresolved: {}", issue.message), + ); } } -/// Give control-point splines stored without knots a degree their control -/// points can carry, and the matching clamped knot vector. -/// -/// A degree-p curve needs at least p + 1 control points. Knot generation -/// (here, and in the DWG writer for knot-less splines) subtracts in `usize` -/// and underflows when there are fewer; in release builds the wrapped count -/// drives an unbounded allocation. Lowering the degree keeps the geometry the -/// points describe: two points are a straight segment at any degree. -fn normalize_knotless_splines(doc: &mut CadDocument) { - for entity in doc.entities_mut() { - let EntityType::Spline(spline) = entity else { - continue; - }; - let n = spline.control_points.len(); - if !spline.knots.is_empty() || n < 2 || spline.degree < 1 { - continue; - } - let degree = (spline.degree as usize).min(n - 1); - spline.degree = degree as i32; - spline.knots = codec::entities::Spline::generate_clamped_knots(degree, n); - } -} - -pub fn purge_corrupt_entities(doc: &mut CadDocument) -> usize { - use crate::par::prelude::*; - normalize_knotless_splines(doc); - // Detection is pure and read-only; the per-vertex finite/extent checks on - // large polylines dominate, so fan the scan out across cores. Gather - // entity references in one pass, test in parallel, then remove serially - // (`remove_entity` needs `&mut doc`). - let entities: Vec<&EntityType> = doc.entities().collect(); - let bad: Vec = entities - .par_iter() - .filter(|e| is_entity_corrupt(e)) - .map(|e| e.common().handle) - .collect(); - let n = bad.len(); - for h in bad { - doc.remove_entity(h); - } - n -} - /// opencadcodec's ViewportStatusFlags::from_bits() maps bit 0 → is_on and bit 15 → locked, /// but the real DXF/DWG spec uses bit 15 (0x8000) → viewport on and bit 14 (0x4000) → locked. /// Files from AutoCAD and other tools always set bit 15 for active viewports, leaving bit 0 @@ -3161,214 +2992,6 @@ mod layer_roundtrip_tests { } } -#[cfg(test)] -mod corrupt_guard_tests { - use super::*; - use codec::entities::{Arc, Circle, EntityType, Spline}; - use codec::types::Vector3; - - fn knotless_spline(degree: i32, points: usize) -> Spline { - let mut spline = Spline::new(); - spline.degree = degree; - spline.control_points = (0..points) - .map(|index| Vector3::new(index as f64, index as f64, 0.0)) - .collect(); - spline - } - - // Degree 3 over two control points with no knot vector: generating knots - // for it underflows, and writing it to DWG used to panic (debug) or - // allocate without bound (release). - #[test] - fn knotless_spline_with_too_few_points_is_lowered_and_saves_as_dwg() { - let mut doc = CadDocument::new(); - doc.add_entity(EntityType::Spline(knotless_spline(3, 2))) - .unwrap(); - doc.add_entity(EntityType::Spline(knotless_spline(3, 1))) - .unwrap(); - assert_eq!( - purge_corrupt_entities(&mut doc), - 1, - "the lone point is dropped" - ); - let spline = doc - .entities() - .find_map(|entity| match entity { - EntityType::Spline(spline) => Some(spline.clone()), - _ => None, - }) - .expect("the two-point spline is kept"); - assert_eq!(spline.degree, 1); - assert_eq!(spline.knots, vec![0.0, 0.0, 1.0, 1.0]); - - let path = - std::env::temp_dir().join(format!("ocs_knotless_spline_{}.dwg", std::process::id())); - save_as_version(&doc, &path, codec::DxfVersion::AC1032).expect("save"); - let _ = std::fs::remove_file(&path); - } - - // `load_file` (headless export, xrefs, block import) does not purge, so - // the spline repair has to happen when any load is finalized. - #[test] - fn knotless_spline_is_repaired_by_every_load_path() { - const DXF: &str = - "0\nSECTION\n2\nENTITIES\n0\nSPLINE\n8\n0\n70\n0\n71\n3\n72\n0\n73\n2\n74\n0\n\ -10\n0\n20\n0\n30\n0\n10\n1\n20\n1\n30\n0\n0\nENDSEC\n0\nEOF\n"; - let dir = std::env::temp_dir(); - let source = dir.join(format!("ocs_knotless_load_{}.dxf", std::process::id())); - let target = dir.join(format!("ocs_knotless_load_{}.dwg", std::process::id())); - std::fs::write(&source, DXF).unwrap(); - let doc = load_file(&source).expect("load"); - let _ = std::fs::remove_file(&source); - let spline = doc - .entities() - .find_map(|entity| match entity { - EntityType::Spline(spline) => Some(spline), - _ => None, - }) - .expect("spline"); - assert_eq!(spline.degree, 1); - assert_eq!(spline.knots.len(), 4); - save_as_version(&doc, &target, codec::DxfVersion::AC1032).expect("save"); - let _ = std::fs::remove_file(&target); - } - - // Small but finite arcs are valid records. Kernel tessellation is bounded, - // so opening must retain them instead of treating their size as corruption. - #[test] - fn keeps_small_finite_arc() { - let mut a = Arc::new(); - a.center = Vector3::new(2880.84, 891.83, 0.0); - a.radius = 0.0038974142851181423; - a.start_angle = 1.0401656235942365; - a.end_angle = 1.0401671831670538; - a.normal = Vector3::new(0.0, 0.0, 1.0); - assert!(!is_entity_corrupt(&EntityType::Arc(a))); - } - - // A nearly straight arc still carries valid source geometry. - #[test] - fn keeps_nearly_straight_arc() { - let mut a = Arc::new(); - a.center = Vector3::new(551435.3071786845, 4051623.7156955916, 0.0); - a.radius = 35.0; - a.start_angle = 5.823361856481176; - a.end_angle = 5.823362506017916; - a.normal = Vector3::new(0.0, 0.0, 1.0); - assert!(!is_entity_corrupt(&EntityType::Arc(a))); - } - - // A large-radius small-sweep arc is still a visible curve and must survive: - // radius 1e6 × sweep 1e-4 ≈ 100 units of arc. - #[test] - fn keeps_large_radius_small_sweep_arc() { - let mut a = Arc::new(); - a.radius = 1.0e6; - a.start_angle = 0.0; - a.end_angle = 1.0e-4; - a.normal = Vector3::new(0.0, 0.0, 1.0); - assert!(!is_entity_corrupt(&EntityType::Arc(a))); - } - - #[test] - fn keeps_zero_radius_circle_and_arc() { - let mut c = Circle::new(); - c.center = Vector3::new(206.2, 150.7, 0.0); - c.radius = 0.0; - assert!(!is_entity_corrupt(&EntityType::Circle(c))); - - let mut a = Arc::new(); - a.center = Vector3::new(223.5, 174.5, 0.0); - a.radius = 0.0; - a.start_angle = 0.0; - a.end_angle = 0.0; - a.normal = Vector3::new(0.0, 0.0, 1.0); - assert!(!is_entity_corrupt(&EntityType::Arc(a))); - } - - #[test] - fn drops_absurd_radius_circle() { - let mut c = Circle::new(); - c.radius = 1.0e11; - assert!(is_entity_corrupt(&EntityType::Circle(c))); - let mut c = Circle::new(); - c.radius = f64::NAN; - assert!(is_entity_corrupt(&EntityType::Circle(c))); - } - - // Parser desync emits 100_000-control-point splines; building a kernel - // NURBS from one and tessellating it OOMs. The control-point cap rejects it. - #[test] - fn rejects_desync_spline() { - let pts = vec![Vector3::new(0.0, 0.0, 0.0); 100_000]; - let s = Spline::from_control_points(3, pts); - assert!(is_entity_corrupt(&EntityType::Spline(s))); - } - - // A collapsed spline is still a valid source record. Kernel subdivision - // has a fixed depth bound and can process it safely. - #[test] - fn keeps_degenerate_point_spline() { - let pts = vec![Vector3::new(1e-12, -1e-12, 0.0); 9]; - let s = Spline::from_control_points(3, pts); - assert!(!is_entity_corrupt(&EntityType::Spline(s))); - } - - #[test] - fn keeps_compact_periodic_spline_knots() { - let pts = (0..12) - .map(|index| Vector3::new(index as f64, (index % 3) as f64, 0.0)) - .collect(); - let mut s = Spline::from_control_points(2, pts); - s.flags.closed = true; - s.flags.periodic = true; - s.knots = (0..13).map(|value| value as f64).collect(); - assert!(!is_entity_corrupt(&EntityType::Spline(s))); - } - - // A normal cubic spline (4 control points, valid clamped knots) survives. - #[test] - fn keeps_valid_spline() { - let pts = vec![ - Vector3::new(0.0, 0.0, 0.0), - Vector3::new(1.0, 1.0, 0.0), - Vector3::new(2.0, -1.0, 0.0), - Vector3::new(3.0, 0.0, 0.0), - ]; - let s = Spline::from_control_points(3, pts); - assert!(!is_entity_corrupt(&EntityType::Spline(s))); - } - - // A corrupt or adversarial MINSERT row/column pair (u16, so its unchecked - // product can reach into the billions) must be rejected before it can - // drive the render graph's per-instance allocation and expansion. - #[test] - fn preserves_large_minsert_data_while_rendering_is_bounded() { - let mut i = codec::entities::Insert::new("BLOCK", Vector3::ZERO); - i.row_count = u16::MAX; - i.column_count = u16::MAX; - assert!(!is_entity_corrupt(&EntityType::Insert(i))); - } - - // An ordinary array insert, well under the budget, is valid source data. - #[test] - fn keeps_a_reasonable_minsert() { - let mut i = codec::entities::Insert::new("BLOCK", Vector3::ZERO); - i.row_count = 10; - i.column_count = 10; - i.row_spacing = 5.0; - i.column_spacing = 5.0; - assert!(!is_entity_corrupt(&EntityType::Insert(i))); - } - - // A plain (non-array) INSERT is never treated as a MINSERT-count problem. - #[test] - fn keeps_a_plain_insert() { - let i = codec::entities::Insert::new("BLOCK", Vector3::ZERO); - assert!(!is_entity_corrupt(&EntityType::Insert(i))); - } -} - #[cfg(test)] mod pre_r2000_layer_plot_tests { use super::*; diff --git a/src/io/recovery.rs b/src/io/recovery.rs index 0b1ae1b4d..700033b02 100644 --- a/src/io/recovery.rs +++ b/src/io/recovery.rs @@ -24,8 +24,6 @@ pub struct RecoveryReport { pub source_sha256: Option, pub read_stats: Option, pub entities_scanned: usize, - pub entities_removed: usize, - pub referenced_entities_removed: usize, pub parser_errors_recovered: usize, pub diagnostics: Vec<(String, String)>, pub references_checked: usize, @@ -54,8 +52,6 @@ impl RecoveryReport { source_sha256: Option, read_stats: Option, entities_scanned: usize, - entities_removed: usize, - referenced_entities_removed: usize, references: &[XrefInfo], notifications: &codec::notification::NotificationCollection, save_as_required: bool, @@ -163,8 +159,6 @@ impl RecoveryReport { source_sha256, read_stats, entities_scanned, - entities_removed, - referenced_entities_removed, parser_errors_recovered, diagnostics, references_checked: references.len(), @@ -211,8 +205,6 @@ impl RecoveryReport { .unwrap_or(0), read_stats, entities_scanned: 0, - entities_removed: 0, - referenced_entities_removed: 0, diagnostics: Vec::new(), references_checked: 0, references_loaded: 0, @@ -233,17 +225,11 @@ impl RecoveryReport { } } - pub fn removed_total(&self) -> usize { - self.entities_removed - .saturating_add(self.referenced_entities_removed) - } - pub fn issues_found(&self) -> usize { self.parser_errors_recovered .saturating_add(self.references_recovered) .saturating_add(self.references_failed) .saturating_add(self.references_missing) - .saturating_add(self.removed_total()) .saturating_add(usize::from(self.error.is_some())) } @@ -315,11 +301,6 @@ impl RecoveryReport { )); } lines.push(format!("Entities scanned: {}", self.entities_scanned)); - lines.push(format!("Entities removed: {}", self.entities_removed)); - lines.push(format!( - "Referenced entities removed: {}", - self.referenced_entities_removed - )); lines.push(format!( "Parser errors recovered: {}", self.parser_errors_recovered diff --git a/src/io/xref.rs b/src/io/xref.rs index 13c34f34f..6aade03b0 100644 --- a/src/io/xref.rs +++ b/src/io/xref.rs @@ -277,12 +277,8 @@ fn read_outcome_from_bytes( /// `base_dir`, and populate each xref block with entities from the /// referenced file. /// -/// Returns a list of [`XrefInfo`] describing each xref block found, plus the -/// number of corrupt xref entities dropped during merge. Purging happens -/// inline as each xref's entities are merged — xref content is parser output -/// just like the host doc, so it gets the same corrupt-entity guard. Folding -/// it in here avoids a second full-document `entities()` walk after resolve. -pub fn resolve_xrefs(doc: &mut CadDocument, base_dir: &Path) -> (Vec, usize) { +/// Returns a list of [`XrefInfo`] describing each xref block found. +pub fn resolve_xrefs(doc: &mut CadDocument, base_dir: &Path) -> Vec { resolve_xrefs_with_filter(doc, base_dir, None, None) } @@ -295,7 +291,7 @@ pub fn resolve_xrefs_for_keys( doc: &mut CadDocument, base_dir: &Path, keys: &HashSet, -) -> (Vec, usize) { +) -> Vec { resolve_xrefs_with_filter(doc, base_dir, None, Some(keys)) } @@ -308,7 +304,7 @@ pub fn resolve_xrefs_with_progress( doc: &mut CadDocument, base_dir: &Path, progress: Option>, -) -> (Vec, usize) { +) -> Vec { resolve_xrefs_with_filter(doc, base_dir, progress, None) } @@ -317,7 +313,7 @@ fn resolve_xrefs_with_filter( base_dir: &Path, progress: Option>, only: Option<&HashSet>, -) -> (Vec, usize) { +) -> Vec { // Auto-resolve every xref — frustum + LOD culling keep GPU cost bounded. let xref_entries: Vec<(String, String, Handle)> = doc .block_records @@ -432,7 +428,6 @@ fn resolve_xrefs_with_filter( // Phase 2 — merge each parsed xref into the host document, in the original // block order (par_iter preserves it), so handle allocation is deterministic. let mut result = Vec::with_capacity(parsed.len()); - let mut dropped = 0usize; #[allow(unused_mut, unused_variables)] for ( merge_index, @@ -468,19 +463,7 @@ fn resolve_xrefs_with_filter( .iter() .map(|diagnostic| diagnostic.message.clone()), ); - let invalid = super::purge_corrupt_entities(&mut outcome.document); - if invalid > 0 { - diagnostics.push(format!( - "normal read found {invalid} structurally invalid reference records" - )); - #[cfg(not(target_arch = "wasm32"))] - if source_sha256.is_none() { - source_sha256 = resolved.as_ref().and_then(|path| { - super::stable_sha256_file(path, initial_fingerprint.as_ref()) - }); - } - } - if recovered || invalid > 0 { + if recovered { (XrefStatus::Failed, diagnostics, Some(outcome.stats)) } else { // Reload is replacement, never append. Keep the prior merge @@ -502,7 +485,7 @@ fn resolve_xrefs_with_filter( let _ = unload_reference(doc, br_handle.value()); remove_pipe_symbols(doc, &block_name); ensure_block_entities(doc, &block_name); - dropped += merge_xref_into_block(doc, &block_name, br_handle, outcome.document); + merge_xref_into_block(doc, &block_name, br_handle, outcome.document); if visretain { restore_dependent_layers(doc, &block_name, kept_layers); } @@ -533,7 +516,7 @@ fn resolve_xrefs_with_filter( } } - (result, dropped) + result } /// Underlay files named by a relative (or moved) path: read them from where @@ -1218,13 +1201,12 @@ fn copy_xref_sortents( /// — which doesn't know about the xref's layers — and silently falls /// back to WHITE / 1 px line weight. AutoCAD's BIND command uses the /// same naming scheme. -/// Returns the number of corrupt entities skipped during the merge. fn merge_xref_into_block( doc: &mut CadDocument, xref_block_name: &str, br_handle: Handle, xref_doc: CadDocument, -) -> usize { +) { let prefix = xref_block_name; // Carry the xref's INSUNITS onto the host BlockRecord. Used at INSERT @@ -1264,7 +1246,7 @@ fn merge_xref_into_block( // ── Entities (shared helper) ──────────────────────────────────────── // The unremapped-handle count is ignored on the load path (BIND reports // it per bind). - let (dropped, _, entity_handle_map) = merge_source_entities(doc, &xref_doc, br_handle, &maps); + let (_, entity_handle_map) = merge_source_entities(doc, &xref_doc, br_handle, &maps); // ── Draw-order overrides (shared helper) ────────────────────────────── copy_xref_sortents( @@ -1274,7 +1256,6 @@ fn merge_xref_into_block( &maps.br_handles, &entity_handle_map, ); - dropped } /// Source entities in display order: each block record's `entity_handles` @@ -1308,26 +1289,18 @@ fn ordered_source_entities(xref_doc: &CadDocument) -> Vec<(Handle, EntityType)> /// Merge one source doc's entities into `target`, routing model-space content /// into `target_br` and nested-block content into its imported counterpart -/// (`maps.br_handles`). Returns corrupt-drop count, unremapped-handle count, -/// and the old→new entity handle map for the sortents copy. +/// (`maps.br_handles`). Returns the unremapped-handle count and the old→new +/// entity handle map for the sortents copy. fn merge_source_entities( target: &mut CadDocument, source: &CadDocument, target_br: Handle, maps: &XrefSymbolMaps, -) -> (usize, usize, HashMap) { +) -> (usize, HashMap) { let source_ms_handle = source.header.model_space_block_handle; let mut entity_handle_map: HashMap = HashMap::default(); - let mut dropped = 0usize; let mut unremapped = 0usize; for (old_h, mut entity) in ordered_source_entities(source) { - // Drop parser-garbage entities (bad normals / vertex counts / inf - // coords) before they enter the host doc — they trigger huge - // allocations and unbounded recursion in the wire pipeline. - if super::is_entity_corrupt(&entity) { - dropped += 1; - continue; - } // Remap every symbol reference so the host's resolver hits the copies // just imported (load path ignores the unremapped count; BIND reports // it per bind). @@ -1351,7 +1324,7 @@ fn merge_source_entities( entity_handle_map.insert(old_h, new_h); } } - (dropped, unremapped, entity_handle_map) + (unremapped, entity_handle_map) } fn is_sentinel_linetype(name: &str) -> bool { @@ -2170,8 +2143,7 @@ fn merge_bound_doc( taken, }; let maps = import_xref_symbols(target, source, &mut naming); - let (_, unremapped, entity_handle_map) = - merge_source_entities(target, source, target_br, &maps); + let (unremapped, entity_handle_map) = merge_source_entities(target, source, target_br, &maps); copy_xref_sortents( target, source, @@ -2970,7 +2942,7 @@ mod tests { // 3. Targeted reload: back to Loaded. let mut handles = HashSet::default(); handles.insert(doc.block_records.get("MID").unwrap().handle); - let (infos, _) = resolve_xrefs_for_keys(&mut doc, &dir, &handles); + let infos = resolve_xrefs_for_keys(&mut doc, &dir, &handles); assert!(infos.iter().any(|i| i.name == "MID")); let listed = collect_entries_with_prev(&doc, &dir, &empty, &no_prev); assert!(listed diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 8868a5457..16904c85e 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -696,10 +696,10 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "ATTSYNC block name to sync:" => Some(("insert", "attsync-block-name-to-sync")), "ATTSYNC: no block named \"{arg}\"." => Some(("insert", "attsync-no-block-named-arg")), "ATTSYNC: synchronised {synced} insert(s) of \"{block}\" against {} attribute definition(s)." => Some(("insert", "attsync-synchronised-synced-insert-s-of-block")), + "AUDIT Fix any errors detected? [Yes / No] :" => Some(("styles", "audit-fix-any-errors-detected")), "AUDIT: no issues found." => Some(("styles", "audit-no-issues-found")), - "AUDIT: reference(s) to undefined block(s): {}" => Some(("styles", "audit-reference-s-to-undefined-block-s")), - "AUDIT: reference(s) to undefined layer(s): {}" => Some(("styles", "audit-reference-s-to-undefined-layer-s")), - "AUDIT: report only — no automatic repair performed." => Some(("styles", "audit-report-only-no-automatic-repair-performe")), + "AUDIT: {} error(s), {} warning(s) found." => Some(("styles", "audit-error-s-warning-s-found")), + "AUDIT: {} repair(s) applied, {} issue(s) left unresolved." => Some(("styles", "audit-repair-s-applied-issue-s-left")), "AUDIT: scanned {total} object(s)." => Some(("styles", "audit-scanned-total-object-s")), "About" => Some(("manage", "about")), "Above" => Some(("common", "above")), @@ -3803,8 +3803,6 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "WIPEOUT Rectangular Specify first corner:" => Some(("draw", "wipeout-rectangular-specify-first-corner")), "WIPEOUT Rectangular Specify opposite corner:" => Some(("draw", "wipeout-rectangular-specify-opposite-corner")), "Warning" => Some(("errors", "warning")), - "Warning: {} corrupt entities dropped (parser junk — bad normals / counts)" => Some(("file", "warning-corrupt-entities-dropped-parser-junk-b")), - "Warning: {} corrupt xref entities dropped" => Some(("file", "warning-corrupt-xref-entities-dropped")), "Watertight" => Some(("properties", "watertight")), "Web" => Some(("common", "web")), "Web File" => Some(("properties", "web-file")), diff --git a/src/scene/cache/block_cache.rs b/src/scene/cache/block_cache.rs index 11897898d..cf0214220 100644 --- a/src/scene/cache/block_cache.rs +++ b/src/scene/cache/block_cache.rs @@ -747,7 +747,7 @@ fn tessellate_sub_local( // Sanity guard: skip sub-entities whose primary dimension is so large // that adaptive tessellation will explode into hundreds of millions // of points. These are typically corrupt-radius primitives that slipped - // past purge_corrupt_entities (finite but absurd values). + // past the codec's unusable-geometry audit (finite but absurd values). if is_unreasonable_extent(sub) { return vec![]; } diff --git a/src/scene/mod.rs b/src/scene/mod.rs index a81d2f444..b79bf2ae8 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -1221,12 +1221,6 @@ pub struct DerivedCaches { /// Prepared during file open so entity selection/deselection never scans /// the complete object store on the UI thread. pub object_data: crate::entities::object_data::ObjectDataCache, - /// Number of entities removed by the corrupt-entity guard during load. - /// Reported back to the UI so the user knows when a file had parser-junk - /// entities silently dropped. - pub corrupt_dropped: usize, - /// Corrupt entities dropped while resolving referenced drawings. - pub xref_dropped: usize, /// XREF resolution results produced by the loader worker. Keeping these in /// the open bundle prevents parsing and merging references on the UI thread. pub xrefs: Vec, @@ -1523,8 +1517,6 @@ fn build_derived_caches_impl( meshes, block_meshes, object_data, - corrupt_dropped: 0, - xref_dropped: 0, xrefs: Vec::new(), prepared_geometry: None, timings: OpenTimings::default(), diff --git a/src/ui/window/recovery.rs b/src/ui/window/recovery.rs index 1030a2b26..beae8d90c 100644 --- a/src/ui/window/recovery.rs +++ b/src/ui/window/recovery.rs @@ -62,10 +62,6 @@ pub fn view_window<'a>( crate::tr!("recovery", "issues-found"), report.issues_found().to_string(), ), - metric( - crate::tr!("recovery", "entities-removed"), - report.removed_total().to_string(), - ), metric( crate::tr!("recovery", "references-checked"), report.references_checked.to_string(), @@ -75,16 +71,6 @@ pub fn view_window<'a>( .width(Fill); let mut details = column![].spacing(6); - if report.referenced_entities_removed > 0 { - details = details.push( - text(format!( - "{}: {}", - crate::tr!("recovery", "referenced-entities-removed"), - report.referenced_entities_removed - )) - .size(11), - ); - } if report.references_missing > 0 || report.references_failed > 0 { details = details.push( text(format!(