forked from 1b-agent/opencadstudio-upstream
Merge origin/main into plugin/host-model-api
Picks up cadcodec 5b682ed and cadkernel 6f046af and the plotstyle layer-usage speedup. The adapter's Cargo.lock now resolves acadrust to 5b682ed. All host, API and adapter tests pass and no acadrust canary assertion tripped. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
commit
bfb5e7576b
9 files changed
+153
-28
No files matched your search
Generated
+3
-3
@@ -86,7 +86,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
||||
[[package]]
|
||||
name = "acadrust"
|
||||
version = "0.5.5"
|
||||
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=7ea4247#7ea4247134af60c8c1617426849d4fa8233660c8"
|
||||
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=5b682ed#5b682ed66ea2c89be8142c8dd83d83774fc3de08"
|
||||
dependencies = [
|
||||
"ahash 0.8.12",
|
||||
"anyhow",
|
||||
@@ -922,7 +922,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||
[[package]]
|
||||
name = "cadkernel"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=a0b962a#a0b962ae8045e7221ecb5d478adc5ad58e2706ba"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=6f046af#6f046afdda94d8cd9cdbd7fc0ab73ee726aac9ab"
|
||||
dependencies = [
|
||||
"acadrust",
|
||||
"cavalier_contours",
|
||||
@@ -933,7 +933,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "cadkernel-constraints"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=a0b962a#a0b962ae8045e7221ecb5d478adc5ad58e2706ba"
|
||||
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=6f046af#6f046afdda94d8cd9cdbd7fc0ab73ee726aac9ab"
|
||||
dependencies = [
|
||||
"nalgebra",
|
||||
]
|
||||
|
||||
+3
-3
@@ -33,9 +33,9 @@ rfd = "0.17"
|
||||
clap = { version = "4", features = ["derive", "string"] }
|
||||
env_logger = "0.11"
|
||||
log = "0.4"
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "7ea4247", features = ["serde"] }
|
||||
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "a0b962a", features = ["acis", "offset"] }
|
||||
cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "a0b962a" }
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "5b682ed", features = ["serde"] }
|
||||
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "6f046af", features = ["acis", "offset"] }
|
||||
cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "6f046af" }
|
||||
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
||||
flate2 = "1"
|
||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
||||
|
||||
+2
-1
@@ -19,7 +19,7 @@ cargo bench --bench performance_benchmarks -- --quick
|
||||
|
||||
---
|
||||
|
||||
## Benchmark Suite Catalog (25 Metrics)
|
||||
## Benchmark Suite Catalog (26 Metrics)
|
||||
|
||||
### 1. Scene & Entity Management
|
||||
- `scene_entity_ingestion_10k`: Ingestion throughput for 10,000 mixed 2D entities (Lines, Circles, Arcs, Polylines).
|
||||
@@ -51,6 +51,7 @@ cargo bench --bench performance_benchmarks -- --quick
|
||||
- `ui_grid_cache_hit_evaluation`: Grid overlay cache key construction and reuse decision.
|
||||
- `ui_icon_handle_cached`: Themed SVG icon cache hit (FxHashMap lookup + Handle clone).
|
||||
- `ui_icon_handle_uncached`: Uncached SVG icon memory parse and Handle allocation.
|
||||
- `ui_plotstyle_layer_usage`: Plot Style 256-bucket ACI layer-usage table rebuild (200 layers).
|
||||
|
||||
### 6. State Management & Draworder
|
||||
- `selection_state_deep_clone`: Deep cloning of `SelectionState` (with 64 polygon points).
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
//! 10. UI Ribbon View Widget Tree Construction
|
||||
//! 11. UI Viewport Grid Geometry Projection & Overlay Cache Key Evaluation
|
||||
//! 12. UI Themed SVG Icon Lookup Caching vs Uncached Parse
|
||||
//! 12b. Plot Style Layer-Usage Table Rebuild (256-bucket ACI table)
|
||||
//! 13. Wide & Tapered Arc + Donut Tessellation (7.5k offset polyline curves)
|
||||
//! 14. Model Space Extents & Bounding Box Calculation (ZOOM EXTENTS)
|
||||
//! 15. Batch Entity Transformation & Incremental Dirty-Tracking
|
||||
@@ -64,6 +65,7 @@ use OpenCADStudio::ui::overlay::{
|
||||
};
|
||||
use OpenCADStudio::ui::properties::LinetypeItem;
|
||||
use OpenCADStudio::ui::ribbon::{LayerInfo, Ribbon};
|
||||
use OpenCADStudio::ui::style::plotstyle::build_layer_usage;
|
||||
|
||||
// ── Metric Structures ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -1359,6 +1361,53 @@ fn bench_ui_icon_caching(runner: &mut BenchmarkRunner) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 12b. Plot Style Layer-Usage Table Rebuild ───────────────────────────────
|
||||
// Covers Mission #19 `build_layer_usage`: layer names bucketed by ACI into a
|
||||
// 256-bucket table, rebuilt per Plot Style modal view.
|
||||
|
||||
fn bench_ui_plotstyle_layer_usage(runner: &mut BenchmarkRunner) {
|
||||
if !runner.should_run("ui_plotstyle_layer_usage") {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut doc = CadDocument::new();
|
||||
for i in 0..200 {
|
||||
let mut layer = acadrust::tables::Layer::new(&format!("LAYER_{i:03}"));
|
||||
layer.handle = doc.allocate_handle();
|
||||
layer.color = acadrust::types::Color::Index((i % 8 + 1) as u8);
|
||||
let _ = doc.layers.add(layer);
|
||||
}
|
||||
|
||||
// Warm-up for allocator settling
|
||||
for _ in 0..10 {
|
||||
let _ = black_box(build_layer_usage(&doc));
|
||||
}
|
||||
|
||||
let n = if runner.quick_mode { 20 } else { 100 };
|
||||
let runs = 5;
|
||||
let mut samples = Vec::with_capacity(runs);
|
||||
|
||||
for _ in 0..runs {
|
||||
let t0 = Instant::now();
|
||||
for _ in 0..n {
|
||||
let usage = build_layer_usage(black_box(&doc));
|
||||
black_box(usage);
|
||||
}
|
||||
let per_us = (t0.elapsed().as_micros() as f64) / (n as f64);
|
||||
samples.push(per_us);
|
||||
}
|
||||
|
||||
let median_us = samples[samples.len() / 2];
|
||||
runner.record(
|
||||
"ui_plotstyle_layer_usage",
|
||||
"Plot Style 256-bucket ACI layer-usage table rebuild (200 layers, 8 buckets x25)",
|
||||
"µs",
|
||||
samples,
|
||||
Some((1_000_000.0 / median_us, "rebuilds/s")),
|
||||
Some(50.0), // Target threshold < 50 µs
|
||||
);
|
||||
}
|
||||
|
||||
// ── 13. Wide & Tapered Arc + Donut Tessellation ─────────────────────────────
|
||||
|
||||
fn bench_wide_and_tapered_arc_tessellation(runner: &mut BenchmarkRunner) {
|
||||
@@ -1761,6 +1810,7 @@ fn main() {
|
||||
bench_ui_ribbon_view_construction(&mut runner);
|
||||
bench_ui_grid_geometry(&mut runner);
|
||||
bench_ui_icon_caching(&mut runner);
|
||||
bench_ui_plotstyle_layer_usage(&mut runner);
|
||||
bench_wide_and_tapered_arc_tessellation(&mut runner);
|
||||
bench_zoom_extents_calculation(&mut runner);
|
||||
bench_batch_entity_mutation(&mut runner);
|
||||
|
||||
@@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true }
|
||||
# Pulled in only by the `host` feature, which adds the `acadrust`-typed
|
||||
# `HostApi` runtime surface. The default crate stays dependency-free so engine
|
||||
# crates and external tooling can depend on the manifest/ribbon contract cheaply.
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "7ea4247", optional = true, features = ["serde"] }
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "5b682ed", 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"
|
||||
# acadrust is scanned at build time to generate the embedded type registry.
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "7ea4247", features = ["serde"] }
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "5b682ed", features = ["serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1"
|
||||
@@ -8,7 +8,7 @@ publish = false
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "7ea4247", features = ["serde"] }
|
||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "5b682ed", features = ["serde"] }
|
||||
bincode = "1.3"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
|
||||
Generated
+1
-1
@@ -5,7 +5,7 @@ version = 4
|
||||
[[package]]
|
||||
name = "acadrust"
|
||||
version = "0.5.5"
|
||||
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=7ea4247#7ea4247134af60c8c1617426849d4fa8233660c8"
|
||||
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=5b682ed#5b682ed66ea2c89be8142c8dd83d83774fc3de08"
|
||||
dependencies = [
|
||||
"ahash 0.8.12",
|
||||
"anyhow",
|
||||
|
||||
@@ -335,6 +335,8 @@ pub fn prepare_xref_block(
|
||||
anonymous: false,
|
||||
has_attributes: false,
|
||||
is_external: false,
|
||||
// A freshly attached reference is loaded; UNLOAD flips this later.
|
||||
is_xref_unloaded: false,
|
||||
};
|
||||
br.xref_path = store_path.clone();
|
||||
let _ = scene.document.block_records.add(br);
|
||||
|
||||
+89
-17
@@ -84,6 +84,35 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
}
|
||||
}
|
||||
|
||||
/// Layer names bucketed by ACI (AutoCAD Color Index), index = ACI.
|
||||
///
|
||||
/// Pure function of `document.layers`: one entry per layer whose color is
|
||||
/// `Color::Index(aci)` with `1 <= aci < 256`, each bucket sorted
|
||||
/// case-insensitively. Extracted from `view_window` so the table can be
|
||||
/// unit-tested and benched without building widgets. `pub` (not
|
||||
/// `pub(crate)`) so the `cargo bench` harness (`benches/`, an external
|
||||
/// crate) can measure it as `ui_plotstyle_layer_usage`.
|
||||
pub fn build_layer_usage(document: &acadrust::CadDocument) -> Vec<Vec<String>> {
|
||||
let mut layer_usage = vec![Vec::<String>::new(); 256];
|
||||
|
||||
for layer in document.layers.iter() {
|
||||
if let acadrust::types::Color::Index(aci) = &layer.color {
|
||||
let index = *aci as usize;
|
||||
|
||||
if index > 0 && index < layer_usage.len() {
|
||||
layer_usage[index].push(layer.name.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for layers in &mut layer_usage {
|
||||
if layers.len() > 1 {
|
||||
layers.sort_by_cached_key(|name| name.to_ascii_lowercase());
|
||||
}
|
||||
}
|
||||
layer_usage
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(
|
||||
document: &'a acadrust::CadDocument,
|
||||
table: Option<&'a crate::io::plot_style::PlotStyleTable>,
|
||||
@@ -95,23 +124,11 @@ pub fn view_window<'a>(
|
||||
) -> Element<'a, Message> {
|
||||
let show_layer_usage = !table.is_some_and(|table| table.is_stb);
|
||||
|
||||
let mut layer_usage = vec![Vec::<String>::new(); 256];
|
||||
|
||||
if show_layer_usage {
|
||||
for layer in document.layers.iter() {
|
||||
if let acadrust::types::Color::Index(aci) = &layer.color {
|
||||
let index = *aci as usize;
|
||||
|
||||
if index > 0 && index < layer_usage.len() {
|
||||
layer_usage[index].push(layer.name.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for layers in &mut layer_usage {
|
||||
layers.sort_by_key(|name| name.to_ascii_lowercase());
|
||||
}
|
||||
}
|
||||
let layer_usage = if show_layer_usage {
|
||||
build_layer_usage(document)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let table_name = table
|
||||
.map(|t| t.name.clone())
|
||||
.unwrap_or_else(|| t!("(no table loaded)").into_owned());
|
||||
@@ -536,3 +553,58 @@ let mut layer_usage = vec![Vec::<String>::new(); 256];
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod layer_usage_tests {
|
||||
use super::*;
|
||||
|
||||
fn indexed_layer(
|
||||
doc: &mut acadrust::CadDocument,
|
||||
name: &str,
|
||||
aci: u8,
|
||||
) -> acadrust::tables::Layer {
|
||||
let mut layer = acadrust::tables::Layer::new(name);
|
||||
layer.handle = doc.allocate_handle();
|
||||
layer.color = acadrust::types::Color::Index(aci);
|
||||
layer
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_layer_usage_buckets_index_colors() {
|
||||
let mut doc = acadrust::CadDocument::new();
|
||||
let a = indexed_layer(&mut doc, "WALLS", 1);
|
||||
let b = indexed_layer(&mut doc, "doors", 1);
|
||||
let c = indexed_layer(&mut doc, "ROOF", 3);
|
||||
let _ = doc.layers.add(a);
|
||||
let _ = doc.layers.add(b);
|
||||
let _ = doc.layers.add(c);
|
||||
|
||||
let usage = build_layer_usage(&doc);
|
||||
|
||||
assert_eq!(usage.len(), 256);
|
||||
assert_eq!(usage[1], vec!["doors".to_string(), "WALLS".to_string()]);
|
||||
assert_eq!(usage[3], vec!["ROOF".to_string()]);
|
||||
assert!(usage[2].is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_layer_usage_ignores_non_index_colors() {
|
||||
let mut doc = acadrust::CadDocument::new();
|
||||
let mut truecolor = acadrust::tables::Layer::new("TRUECOLOR");
|
||||
truecolor.handle = doc.allocate_handle();
|
||||
truecolor.color = acadrust::types::Color::Rgb {
|
||||
r: 10,
|
||||
g: 20,
|
||||
b: 30,
|
||||
};
|
||||
let _ = doc.layers.add(truecolor);
|
||||
|
||||
let usage = build_layer_usage(&doc);
|
||||
|
||||
assert!(
|
||||
usage.iter().all(|bucket| !bucket.iter().any(|n| n == "TRUECOLOR")),
|
||||
"truecolor layer must not appear in any ACI bucket"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user