perf(hash): swap std HashMap/HashSet for rustc-hash FxHash
Phase 4.1. Handle / u64 keys dominate the hot maps (block_defn, hatch / image / mesh caches, draw-depth map, viewport wire caches); the default SipHash is wasted work on integer keys. Alias the std types to rustc_hash::FxHashMap / FxHashSet crate-wide so every map and set — including the cross-module draw-depth map shared between scene and the GPU pipelines — uses the faster hasher consistently. Mechanical: no behavioural change. Constructors moved from ::new() to ::default() (Fx variants carry no RandomState). Build + 13 tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
3098523b8d
commit
70702d063f
30 changed files with 102 additions and 98 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -28,6 +28,7 @@ dependencies = [
|
||||||
"printpdf",
|
"printpdf",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rfd",
|
"rfd",
|
||||||
|
"rustc-hash 2.1.2",
|
||||||
"truck-meshalgo",
|
"truck-meshalgo",
|
||||||
"truck-modeling",
|
"truck-modeling",
|
||||||
"truck-polymesh",
|
"truck-polymesh",
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@ rayon = "1"
|
||||||
ureq = { version = "3", default-features = false, features = ["rustls"] }
|
ureq = { version = "3", default-features = false, features = ["rustls"] }
|
||||||
inventory = "0.3"
|
inventory = "0.3"
|
||||||
truck-shapeops = "0.4"
|
truck-shapeops = "0.4"
|
||||||
|
# Fast non-cryptographic hasher. Handle/u64 keys dominate the hot block,
|
||||||
|
# hatch, draw-depth and wire caches; the default SipHash is overkill there.
|
||||||
|
rustc-hash = "2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
windows-sys = { version = "0.61", features = ["Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
|
windows-sys = { version = "0.61", features = ["Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ matters.
|
||||||
|
|
||||||
## Phase 4 — Allocation & Memory
|
## Phase 4 — Allocation & Memory
|
||||||
|
|
||||||
### 4.1 Swap `HashMap` for `rustc-hash::FxHashMap`
|
### 4.1 Swap `HashMap` for `rustc-hash::FxHashMap` ✅ DONE
|
||||||
|
|
||||||
`Handle` is an integer wrapper; the default `SipHash` is overkill.
|
`Handle` is an integer wrapper; the default `SipHash` is overkill.
|
||||||
`FxHashMap` gives 20-40 % in hash-heavy sites (block_cache, hatches /
|
`FxHashMap` gives 20-40 % in hash-heavy sites (block_cache, hatches /
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ impl OpenCADStudio {
|
||||||
self.command_line.push_info(&cmd.prompt());
|
self.command_line.push_info(&cmd.prompt());
|
||||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||||
} else {
|
} else {
|
||||||
let layers: std::collections::HashSet<String> = self.tabs[i]
|
let layers: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.selected_entities()
|
.selected_entities()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -153,7 +153,7 @@ impl OpenCADStudio {
|
||||||
self.command_line.push_info(&cmd.prompt());
|
self.command_line.push_info(&cmd.prompt());
|
||||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||||
} else {
|
} else {
|
||||||
let layers: std::collections::HashSet<String> = self.tabs[i]
|
let layers: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.selected_entities()
|
.selected_entities()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -188,7 +188,7 @@ impl OpenCADStudio {
|
||||||
self.command_line.push_info(&cmd.prompt());
|
self.command_line.push_info(&cmd.prompt());
|
||||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||||
} else {
|
} else {
|
||||||
let layers: std::collections::HashSet<String> = self.tabs[i]
|
let layers: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.selected_entities()
|
.selected_entities()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -278,7 +278,7 @@ impl OpenCADStudio {
|
||||||
self.command_line.push_info(&cmd.prompt());
|
self.command_line.push_info(&cmd.prompt());
|
||||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||||
} else {
|
} else {
|
||||||
let layers: std::collections::HashSet<String> = self.tabs[i]
|
let layers: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.selected_entities()
|
.selected_entities()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -299,7 +299,7 @@ impl OpenCADStudio {
|
||||||
|
|
||||||
// LAYISO — turn off all layers except those used by selected entities
|
// LAYISO — turn off all layers except those used by selected entities
|
||||||
"LAYISO" => {
|
"LAYISO" => {
|
||||||
let sel_layers: std::collections::HashSet<String> = self.tabs[i]
|
let sel_layers: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.selected_entities()
|
.selected_entities()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -3090,10 +3090,10 @@ impl OpenCADStudio {
|
||||||
// including ones not yet in the table, which sort by
|
// including ones not yet in the table, which sort by
|
||||||
// their own handle. (min_eff, max_eff) over siblings.
|
// their own handle. (min_eff, max_eff) over siblings.
|
||||||
let fb_baseline: Option<(u64, u64)> = if to_front_opt.is_some() {
|
let fb_baseline: Option<(u64, u64)> = if to_front_opt.is_some() {
|
||||||
let selected_set: std::collections::HashSet<u64> =
|
let selected_set: rustc_hash::FxHashSet<u64> =
|
||||||
selected.iter().map(|h| h.value()).collect();
|
selected.iter().map(|h| h.value()).collect();
|
||||||
let doc_ref = &self.tabs[i].scene.document;
|
let doc_ref = &self.tabs[i].scene.document;
|
||||||
let overrides: std::collections::HashMap<u64, u64> = doc_ref
|
let overrides: rustc_hash::FxHashMap<u64, u64> = doc_ref
|
||||||
.objects
|
.objects
|
||||||
.values()
|
.values()
|
||||||
.find_map(|obj| {
|
.find_map(|obj| {
|
||||||
|
|
@ -4358,7 +4358,7 @@ impl OpenCADStudio {
|
||||||
let all = sub == "ALL" || sub.is_empty();
|
let all = sub == "ALL" || sub.is_empty();
|
||||||
|
|
||||||
// Collect names in use (immutable borrows — done in their own scope)
|
// Collect names in use (immutable borrows — done in their own scope)
|
||||||
let used_layers: std::collections::HashSet<String> = self.tabs[i]
|
let used_layers: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.document
|
.document
|
||||||
.entities()
|
.entities()
|
||||||
|
|
@ -4371,7 +4371,7 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let used_text_styles: std::collections::HashSet<String> = self.tabs[i]
|
let used_text_styles: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.document
|
.document
|
||||||
.entities()
|
.entities()
|
||||||
|
|
@ -4382,7 +4382,7 @@ impl OpenCADStudio {
|
||||||
})
|
})
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.collect();
|
.collect();
|
||||||
let used_linetypes: std::collections::HashSet<String> = self.tabs[i]
|
let used_linetypes: rustc_hash::FxHashSet<String> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.document
|
.document
|
||||||
.entities()
|
.entities()
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ pub(super) fn entities_centroid(wires: &[WireModel]) -> glam::Vec3 {
|
||||||
|
|
||||||
/// Generate the next available auto group name ("*A1", "*A2", …).
|
/// Generate the next available auto group name ("*A1", "*A2", …).
|
||||||
pub(super) fn next_group_auto_name(scene: &crate::scene::Scene) -> String {
|
pub(super) fn next_group_auto_name(scene: &crate::scene::Scene) -> String {
|
||||||
let existing: std::collections::HashSet<String> =
|
let existing: rustc_hash::FxHashSet<String> =
|
||||||
scene.groups().map(|g| g.name.clone()).collect();
|
scene.groups().map(|g| g.name.clone()).collect();
|
||||||
for n in 1..=9999 {
|
for n in 1..=9999 {
|
||||||
let name = format!("*A{n}");
|
let name = format!("*A{n}");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{document::HistorySnapshot, OpenCADStudio};
|
use super::{document::HistorySnapshot, OpenCADStudio};
|
||||||
use std::collections::HashSet;
|
use rustc_hash::FxHashSet as HashSet;
|
||||||
|
|
||||||
impl OpenCADStudio {
|
impl OpenCADStudio {
|
||||||
pub(super) fn history_label_from_active_cmd(&self, i: usize, fallback: &'static str) -> String {
|
pub(super) fn history_label_from_active_cmd(&self, i: usize, fallback: &'static str) -> String {
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ pub(super) struct OpenCADStudio {
|
||||||
|
|
||||||
// ── Keyboard Shortcut Editor ──────────────────────────────────────────
|
// ── Keyboard Shortcut Editor ──────────────────────────────────────────
|
||||||
/// User-defined function-key overrides: "F3" → command string.
|
/// User-defined function-key overrides: "F3" → command string.
|
||||||
shortcut_overrides: std::collections::HashMap<String, String>,
|
shortcut_overrides: rustc_hash::FxHashMap<String, String>,
|
||||||
|
|
||||||
// ── Layout Manager Panel ──────────────────────────────────────────────
|
// ── Layout Manager Panel ──────────────────────────────────────────────
|
||||||
layout_manager_selected: String,
|
layout_manager_selected: String,
|
||||||
|
|
@ -1324,7 +1324,7 @@ impl OpenCADStudio {
|
||||||
// Color scheme (default: dark CAD-style)
|
// Color scheme (default: dark CAD-style)
|
||||||
active_theme: Theme::Dark,
|
active_theme: Theme::Dark,
|
||||||
// Keyboard shortcuts
|
// Keyboard shortcuts
|
||||||
shortcut_overrides: std::collections::HashMap::new(),
|
shortcut_overrides: rustc_hash::FxHashMap::default(),
|
||||||
// Layout Manager
|
// Layout Manager
|
||||||
layout_manager_selected: "Model".to_string(),
|
layout_manager_selected: "Model".to_string(),
|
||||||
layout_manager_rename_buf: String::new(),
|
layout_manager_rename_buf: String::new(),
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ impl OpenCADStudio {
|
||||||
self.tabs[i].scene.meshes = caches.meshes;
|
self.tabs[i].scene.meshes = caches.meshes;
|
||||||
// Invalidate the wire cache so the new document is tessellated.
|
// Invalidate the wire cache so the new document is tessellated.
|
||||||
self.tabs[i].scene.bump_geometry();
|
self.tabs[i].scene.bump_geometry();
|
||||||
self.tabs[i].scene.selected = std::collections::HashSet::new();
|
self.tabs[i].scene.selected = rustc_hash::FxHashSet::default();
|
||||||
self.tabs[i].scene.preview_wires = vec![];
|
self.tabs[i].scene.preview_wires = vec![];
|
||||||
self.tabs[i].scene.current_layout = "Model".to_string();
|
self.tabs[i].scene.current_layout = "Model".to_string();
|
||||||
crate::linetypes::populate_document(&mut self.tabs[i].scene.document);
|
crate::linetypes::populate_document(&mut self.tabs[i].scene.document);
|
||||||
|
|
|
||||||
|
|
@ -808,7 +808,7 @@ pub trait DimensionTess {
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
world_offset: [f64; 3],
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
selected_set: &std::collections::HashSet<acadrust::Handle>,
|
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
|
||||||
active_viewport: Option<acadrust::Handle>,
|
active_viewport: Option<acadrust::Handle>,
|
||||||
bg_color: [f32; 4],
|
bg_color: [f32; 4],
|
||||||
view_aabb: Option<[f32; 4]>,
|
view_aabb: Option<[f32; 4]>,
|
||||||
|
|
@ -826,7 +826,7 @@ impl DimensionTess for Dimension {
|
||||||
line_weight_px: f32,
|
line_weight_px: f32,
|
||||||
world_offset: [f64; 3],
|
world_offset: [f64; 3],
|
||||||
anno_scale: f32,
|
anno_scale: f32,
|
||||||
selected_set: &std::collections::HashSet<acadrust::Handle>,
|
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
|
||||||
active_viewport: Option<acadrust::Handle>,
|
active_viewport: Option<acadrust::Handle>,
|
||||||
bg_color: [f32; 4],
|
bg_color: [f32; 4],
|
||||||
view_aabb: Option<[f32; 4]>,
|
view_aabb: Option<[f32; 4]>,
|
||||||
|
|
@ -862,7 +862,7 @@ fn tessellate_dimension_inner(
|
||||||
// LOD hints — when present, synthesised dim text routes through the
|
// LOD hints — when present, synthesised dim text routes through the
|
||||||
// top-level LOD ladder (baseline / greek / full) instead of the truck
|
// top-level LOD ladder (baseline / greek / full) instead of the truck
|
||||||
// path so far-out drawings collapse to a colored rect or baseline.
|
// path so far-out drawings collapse to a colored rect or baseline.
|
||||||
selected_set: &std::collections::HashSet<acadrust::Handle>,
|
selected_set: &rustc_hash::FxHashSet<acadrust::Handle>,
|
||||||
active_viewport: Option<acadrust::Handle>,
|
active_viewport: Option<acadrust::Handle>,
|
||||||
bg_color: [f32; 4],
|
bg_color: [f32; 4],
|
||||||
view_aabb: Option<[f32; 4]>,
|
view_aabb: Option<[f32; 4]>,
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ impl TruckConvertible for Table {
|
||||||
// hidden borders disappear from the grid. Cells with no style still
|
// hidden borders disappear from the grid. Cells with no style still
|
||||||
// emit the standard four borders. To avoid drawing each shared edge
|
// emit the standard four borders. To avoid drawing each shared edge
|
||||||
// twice we coalesce the segments by their (start, end) coordinates.
|
// twice we coalesce the segments by their (start, end) coordinates.
|
||||||
use std::collections::HashSet;
|
use rustc_hash::FxHashSet as HashSet;
|
||||||
let mut emitted: HashSet<(i32, i32, i32, i32)> = HashSet::new();
|
let mut emitted: HashSet<(i32, i32, i32, i32)> = HashSet::default();
|
||||||
let try_add = |a: Vec3, b: Vec3, vis: bool, emitted: &mut HashSet<(i32, i32, i32, i32)>, pts: &mut Vec<[f32; 3]>| {
|
let try_add = |a: Vec3, b: Vec3, vis: bool, emitted: &mut HashSet<(i32, i32, i32, i32)>, pts: &mut Vec<[f32; 3]>| {
|
||||||
if !vis {
|
if !vis {
|
||||||
return;
|
return;
|
||||||
|
|
@ -334,7 +334,7 @@ pub fn tessellate_table(
|
||||||
use crate::scene::tess_util::aci_to_rgba;
|
use crate::scene::tess_util::aci_to_rgba;
|
||||||
use crate::scene::wire_model::WireModel;
|
use crate::scene::wire_model::WireModel;
|
||||||
use acadrust::types::Color;
|
use acadrust::types::Color;
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
|
|
||||||
if tab.rows.is_empty() || tab.columns.is_empty() {
|
if tab.rows.is_empty() || tab.columns.is_empty() {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
|
|
@ -438,10 +438,10 @@ pub fn tessellate_table(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Accumulators keyed by quantised colour (+ weight for borders).
|
// Accumulators keyed by quantised colour (+ weight for borders).
|
||||||
let mut fills: HashMap<[u8; 4], ([f32; 4], Vec<[f32; 3]>)> = HashMap::new();
|
let mut fills: HashMap<[u8; 4], ([f32; 4], Vec<[f32; 3]>)> = HashMap::default();
|
||||||
let mut texts: HashMap<[u8; 4], ([f32; 4], Vec<[f32; 3]>)> = HashMap::new();
|
let mut texts: HashMap<[u8; 4], ([f32; 4], Vec<[f32; 3]>)> = HashMap::default();
|
||||||
let mut borders: HashMap<([u8; 4], u32), ([f32; 4], f32, Vec<[f32; 3]>)> = HashMap::new();
|
let mut borders: HashMap<([u8; 4], u32), ([f32; 4], f32, Vec<[f32; 3]>)> = HashMap::default();
|
||||||
let mut emitted: std::collections::HashSet<(i32, i32, i32, i32)> = std::collections::HashSet::new();
|
let mut emitted: rustc_hash::FxHashSet<(i32, i32, i32, i32)> = rustc_hash::FxHashSet::default();
|
||||||
let sel_col = WireModel::SELECTED;
|
let sel_col = WireModel::SELECTED;
|
||||||
|
|
||||||
let mut add_edge =
|
let mut add_edge =
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
//! STB files follow the same format but use named styles instead of
|
//! STB files follow the same format but use named styles instead of
|
||||||
//! ACI indices; they are read into a `Vec<NamedPlotStyle>`.
|
//! ACI indices; they are read into a `Vec<NamedPlotStyle>`.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ impl PlotStyleTable {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
is_stb: false,
|
is_stb: false,
|
||||||
aci_entries: (0..=255).map(|_| PlotStyleEntry::default()).collect(),
|
aci_entries: (0..=255).map(|_| PlotStyleEntry::default()).collect(),
|
||||||
named_entries: HashMap::new(),
|
named_entries: HashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +202,7 @@ fn compress_ctb(text: &[u8]) -> Result<Vec<u8>, String> {
|
||||||
fn parse_plot_style_text(text: &str, name: String, is_stb: bool) -> Result<PlotStyleTable, String> {
|
fn parse_plot_style_text(text: &str, name: String, is_stb: bool) -> Result<PlotStyleTable, String> {
|
||||||
let mut aci_entries: Vec<PlotStyleEntry> =
|
let mut aci_entries: Vec<PlotStyleEntry> =
|
||||||
(0..=255).map(|_| PlotStyleEntry::default()).collect();
|
(0..=255).map(|_| PlotStyleEntry::default()).collect();
|
||||||
let mut named_entries: HashMap<String, PlotStyleEntry> = HashMap::new();
|
let mut named_entries: HashMap<String, PlotStyleEntry> = HashMap::default();
|
||||||
let mut style_index: usize = 1; // CTB: 1-based ACI index
|
let mut style_index: usize = 1; // CTB: 1-based ACI index
|
||||||
let mut current: Option<PlotStyleEntry> = None;
|
let mut current: Option<PlotStyleEntry> = None;
|
||||||
let mut current_name: String = String::new();
|
let mut current_name: String = String::new();
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use acadrust::entities::{Block, BlockEnd};
|
||||||
use acadrust::tables::TableEntry;
|
use acadrust::tables::TableEntry;
|
||||||
use acadrust::types::{Handle, Vector3};
|
use acadrust::types::{Handle, Vector3};
|
||||||
use acadrust::{CadDocument, EntityType};
|
use acadrust::{CadDocument, EntityType};
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
/// Status of an external reference block.
|
/// Status of an external reference block.
|
||||||
|
|
@ -160,7 +160,7 @@ fn merge_xref_into_block(
|
||||||
// Prefix every xref layer (including "0"). Entity layer references are
|
// Prefix every xref layer (including "0"). Entity layer references are
|
||||||
// remapped below so the resolver finds the merged copy. Host layers
|
// remapped below so the resolver finds the merged copy. Host layers
|
||||||
// (incl. its own "0") are untouched — no collisions.
|
// (incl. its own "0") are untouched — no collisions.
|
||||||
let mut layer_map: HashMap<String, String> = HashMap::new();
|
let mut layer_map: HashMap<String, String> = HashMap::default();
|
||||||
for layer in xref_doc.layers.iter() {
|
for layer in xref_doc.layers.iter() {
|
||||||
let old = layer.name.clone();
|
let old = layer.name.clone();
|
||||||
let new = format!("{}|{}", prefix, old);
|
let new = format!("{}|{}", prefix, old);
|
||||||
|
|
@ -174,7 +174,7 @@ fn merge_xref_into_block(
|
||||||
// ── Linetypes ───────────────────────────────────────────────────────
|
// ── Linetypes ───────────────────────────────────────────────────────
|
||||||
// Skip the three sentinel names — "ByLayer" / "ByBlock" / "Continuous"
|
// Skip the three sentinel names — "ByLayer" / "ByBlock" / "Continuous"
|
||||||
// are magic strings the resolver matches verbatim in both docs.
|
// are magic strings the resolver matches verbatim in both docs.
|
||||||
let mut linetype_map: HashMap<String, String> = HashMap::new();
|
let mut linetype_map: HashMap<String, String> = HashMap::default();
|
||||||
for lt in xref_doc.line_types.iter() {
|
for lt in xref_doc.line_types.iter() {
|
||||||
let old = lt.name.clone();
|
let old = lt.name.clone();
|
||||||
if is_sentinel_linetype(&old) {
|
if is_sentinel_linetype(&old) {
|
||||||
|
|
@ -195,8 +195,8 @@ fn merge_xref_into_block(
|
||||||
//
|
//
|
||||||
// Tracks (xref-doc BR handle → host BR handle) so entities owned by
|
// Tracks (xref-doc BR handle → host BR handle) so entities owned by
|
||||||
// a nested xref block can be routed to the right host block_record.
|
// a nested xref block can be routed to the right host block_record.
|
||||||
let mut br_handle_map: HashMap<Handle, Handle> = HashMap::new();
|
let mut br_handle_map: HashMap<Handle, Handle> = HashMap::default();
|
||||||
let mut block_name_map: HashMap<String, String> = HashMap::new();
|
let mut block_name_map: HashMap<String, String> = HashMap::default();
|
||||||
for br in xref_doc.block_records.iter() {
|
for br in xref_doc.block_records.iter() {
|
||||||
// Skip layout block records (*Model_Space, *Paper_Space, *Paper_Space0…)
|
// Skip layout block records (*Model_Space, *Paper_Space, *Paper_Space0…)
|
||||||
// and any further-nested xrefs (we don't recurse into xref-of-xref).
|
// and any further-nested xrefs (we don't recurse into xref-of-xref).
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
//!
|
//!
|
||||||
//! [`complex_lt`] returns the complex segment catalog for CPU-side rendering.
|
//! [`complex_lt`] returns the complex segment catalog for CPU-side rendering.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use acadrust::tables::linetype::{LineType, LineTypeElement};
|
use acadrust::tables::linetype::{LineType, LineTypeElement};
|
||||||
|
|
@ -217,7 +217,7 @@ fn push_element(token: &str, out: &mut Vec<LineTypeElement>) {
|
||||||
/// A linetype is "complex" when its A-line contains at least one `[SHAPE,...]`
|
/// A linetype is "complex" when its A-line contains at least one `[SHAPE,...]`
|
||||||
/// element. Simple (dash-only) linetypes are excluded.
|
/// element. Simple (dash-only) linetypes are excluded.
|
||||||
fn parse_complex(src: &str) -> HashMap<String, ComplexLt> {
|
fn parse_complex(src: &str) -> HashMap<String, ComplexLt> {
|
||||||
let mut catalog: HashMap<String, ComplexLt> = HashMap::new();
|
let mut catalog: HashMap<String, ComplexLt> = HashMap::default();
|
||||||
let mut current: Option<(String, String)> = None; // (name, description)
|
let mut current: Option<(String, String)> = None; // (name, description)
|
||||||
|
|
||||||
for raw in src.lines() {
|
for raw in src.lines() {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
// a visited set so a self-referential block produces a marker rather than
|
// a visited set so a self-referential block produces a marker rather than
|
||||||
// recursing forever.
|
// recursing forever.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use acadrust::types::{Color as AcadColor, LineWeight, Transform, Vector3};
|
use acadrust::types::{Color as AcadColor, LineWeight, Transform, Vector3};
|
||||||
|
|
@ -206,8 +206,8 @@ impl BlockCache {
|
||||||
/// Walk all entities + all block_record contents collecting every distinct
|
/// Walk all entities + all block_record contents collecting every distinct
|
||||||
/// `block_name` that appears in an Insert (transitively).
|
/// `block_name` that appears in an Insert (transitively).
|
||||||
fn collect_referenced_blocks(doc: &CadDocument) -> Vec<String> {
|
fn collect_referenced_blocks(doc: &CadDocument) -> Vec<String> {
|
||||||
use std::collections::HashSet;
|
use rustc_hash::FxHashSet as HashSet;
|
||||||
let mut seen: HashSet<String> = HashSet::new();
|
let mut seen: HashSet<String> = HashSet::default();
|
||||||
let mut queue: Vec<String> = Vec::new();
|
let mut queue: Vec<String> = Vec::new();
|
||||||
|
|
||||||
for entity in doc.entities() {
|
for entity in doc.entities() {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
//! to 2-D pixel coordinates, then compared against the cursor or selection box.
|
//! to 2-D pixel coordinates, then compared against the cursor or selection box.
|
||||||
//! This matches the visual result the user sees.
|
//! This matches the visual result the user sees.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
|
|
||||||
use acadrust::Handle;
|
use acadrust::Handle;
|
||||||
use glam::{Mat4, Vec3};
|
use glam::{Mat4, Vec3};
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
// Cap height is 9 glyph units, matching the `height / 9.0` text scale used
|
// Cap height is 9 glyph units, matching the `height / 9.0` text scale used
|
||||||
// throughout the renderer.
|
// throughout the renderer.
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
||||||
use std::sync::{Mutex, OnceLock};
|
use std::sync::{Mutex, OnceLock};
|
||||||
|
|
||||||
// ── Embedded fonts ─────────────────────────────────────────────────────────
|
// ── Embedded fonts ─────────────────────────────────────────────────────────
|
||||||
|
|
@ -154,7 +154,7 @@ fn warn_missing_glyph(font_name: &str, ch: char) {
|
||||||
if ch.is_ascii() {
|
if ch.is_ascii() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let set = WARNED_GLYPHS.get_or_init(|| Mutex::new(HashSet::new()));
|
let set = WARNED_GLYPHS.get_or_init(|| Mutex::new(HashSet::default()));
|
||||||
if let Ok(mut guard) = set.lock() {
|
if let Ok(mut guard) = set.lock() {
|
||||||
if guard.insert((font_name.to_string(), ch)) {
|
if guard.insert((font_name.to_string(), ch)) {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
|
@ -167,7 +167,7 @@ fn warn_missing_glyph(font_name: &str, ch: char) {
|
||||||
|
|
||||||
fn fonts_map() -> &'static HashMap<String, Font> {
|
fn fonts_map() -> &'static HashMap<String, Font> {
|
||||||
FONTS.get_or_init(|| {
|
FONTS.get_or_init(|| {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::default();
|
||||||
// Register every font under its stem and its `# Name:` header.
|
// Register every font under its stem and its `# Name:` header.
|
||||||
for (stem, src) in FONTS_SRC {
|
for (stem, src) in FONTS_SRC {
|
||||||
let f = parse_lff(src);
|
let f = parse_lff(src);
|
||||||
|
|
@ -461,12 +461,12 @@ fn parse_lff(src: &str) -> Font {
|
||||||
letter_spacing: 3.0,
|
letter_spacing: 3.0,
|
||||||
word_spacing: 6.75,
|
word_spacing: 6.75,
|
||||||
line_spacing: 1.0,
|
line_spacing: 1.0,
|
||||||
glyphs: HashMap::new(),
|
glyphs: HashMap::default(),
|
||||||
shapes: HashMap::new(),
|
shapes: HashMap::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut raw: HashMap<char, RawGlyph> = HashMap::new();
|
let mut raw: HashMap<char, RawGlyph> = HashMap::default();
|
||||||
let mut raw_shapes: HashMap<String, RawGlyph> = HashMap::new();
|
let mut raw_shapes: HashMap<String, RawGlyph> = HashMap::default();
|
||||||
let mut cur: Option<char> = None;
|
let mut cur: Option<char> = None;
|
||||||
let mut cur_name: Option<String> = None;
|
let mut cur_name: Option<String> = None;
|
||||||
let mut cur_glyph = RawGlyph::default();
|
let mut cur_glyph = RawGlyph::default();
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ use truck_modeling::{
|
||||||
|
|
||||||
use iced::time::Duration;
|
use iced::time::Duration;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -256,9 +256,9 @@ struct OffsetPrep {
|
||||||
/// `Some` when the model BlockRecord enumerates its entities; the offset
|
/// `Some` when the model BlockRecord enumerates its entities; the offset
|
||||||
/// scan uses this set directly. `None` falls back to the legacy
|
/// scan uses this set directly. `None` falls back to the legacy
|
||||||
/// permissive owner-based interpretation.
|
/// permissive owner-based interpretation.
|
||||||
mspace_set: Option<std::collections::HashSet<Handle>>,
|
mspace_set: Option<rustc_hash::FxHashSet<Handle>>,
|
||||||
any_enumerated: bool,
|
any_enumerated: bool,
|
||||||
owned_by_other_block: std::collections::HashSet<Handle>,
|
owned_by_other_block: rustc_hash::FxHashSet<Handle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset_prep(doc: &acadrust::CadDocument, model_block: Handle) -> OffsetPrep {
|
fn offset_prep(doc: &acadrust::CadDocument, model_block: Handle) -> OffsetPrep {
|
||||||
|
|
@ -266,21 +266,21 @@ fn offset_prep(doc: &acadrust::CadDocument, model_block: Handle) -> OffsetPrep {
|
||||||
.block_records
|
.block_records
|
||||||
.iter()
|
.iter()
|
||||||
.find(|br| br.handle == model_block);
|
.find(|br| br.handle == model_block);
|
||||||
let mspace_set: Option<std::collections::HashSet<Handle>> = model_br
|
let mspace_set: Option<rustc_hash::FxHashSet<Handle>> = model_br
|
||||||
.filter(|br| !br.entity_handles.is_empty())
|
.filter(|br| !br.entity_handles.is_empty())
|
||||||
.map(|br| br.entity_handles.iter().copied().collect());
|
.map(|br| br.entity_handles.iter().copied().collect());
|
||||||
let any_enumerated = doc
|
let any_enumerated = doc
|
||||||
.block_records
|
.block_records
|
||||||
.iter()
|
.iter()
|
||||||
.any(|br| !br.entity_handles.is_empty());
|
.any(|br| !br.entity_handles.is_empty());
|
||||||
let owned_by_other_block: std::collections::HashSet<Handle> = if mspace_set.is_none() {
|
let owned_by_other_block: rustc_hash::FxHashSet<Handle> = if mspace_set.is_none() {
|
||||||
doc.block_records
|
doc.block_records
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|br| br.handle != model_block)
|
.filter(|br| br.handle != model_block)
|
||||||
.flat_map(|br| br.entity_handles.iter().copied())
|
.flat_map(|br| br.entity_handles.iter().copied())
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
std::collections::HashSet::new()
|
rustc_hash::FxHashSet::default()
|
||||||
};
|
};
|
||||||
OffsetPrep { mspace_set, any_enumerated, owned_by_other_block }
|
OffsetPrep { mspace_set, any_enumerated, owned_by_other_block }
|
||||||
}
|
}
|
||||||
|
|
@ -718,31 +718,31 @@ impl Scene {
|
||||||
active_model_tile: std::cell::Cell::new(0),
|
active_model_tile: std::cell::Cell::new(0),
|
||||||
selection: Rc::new(RefCell::new(SelectionState::default())),
|
selection: Rc::new(RefCell::new(SelectionState::default())),
|
||||||
document: CadDocument::new(),
|
document: CadDocument::new(),
|
||||||
selected: HashSet::new(),
|
selected: HashSet::default(),
|
||||||
hidden: HashSet::new(),
|
hidden: HashSet::default(),
|
||||||
hover_highlight: None,
|
hover_highlight: None,
|
||||||
transparency_display: true,
|
transparency_display: true,
|
||||||
selection_filter: HashSet::new(),
|
selection_filter: HashSet::default(),
|
||||||
preview_wires: vec![],
|
preview_wires: vec![],
|
||||||
interim_wire: None,
|
interim_wire: None,
|
||||||
camera_generation: 0,
|
camera_generation: 0,
|
||||||
geometry_epoch: GEOMETRY_EPOCH.fetch_add(1, Ordering::Relaxed),
|
geometry_epoch: GEOMETRY_EPOCH.fetch_add(1, Ordering::Relaxed),
|
||||||
wire_cache: RefCell::new(None),
|
wire_cache: RefCell::new(None),
|
||||||
model_tile_wire_cache: RefCell::new(HashMap::new()),
|
model_tile_wire_cache: RefCell::new(HashMap::default()),
|
||||||
sort_cache: RefCell::new(None),
|
sort_cache: RefCell::new(None),
|
||||||
draw_depth_cache: RefCell::new(None),
|
draw_depth_cache: RefCell::new(None),
|
||||||
hatch_cache: RefCell::new(None),
|
hatch_cache: RefCell::new(None),
|
||||||
wipeout_cache: RefCell::new(None),
|
wipeout_cache: RefCell::new(None),
|
||||||
image_cache: RefCell::new(None),
|
image_cache: RefCell::new(None),
|
||||||
mesh_cache: RefCell::new(None),
|
mesh_cache: RefCell::new(None),
|
||||||
viewport_wire_cache: RefCell::new(HashMap::new()),
|
viewport_wire_cache: RefCell::new(HashMap::default()),
|
||||||
paper_sheet_cache: RefCell::new(None),
|
paper_sheet_cache: RefCell::new(None),
|
||||||
paper_projected_cache: RefCell::new(HashMap::new()),
|
paper_projected_cache: RefCell::new(HashMap::default()),
|
||||||
current_layout: "Model".to_string(),
|
current_layout: "Model".to_string(),
|
||||||
hatches: HashMap::new(),
|
hatches: HashMap::default(),
|
||||||
meshes: HashMap::new(),
|
meshes: HashMap::default(),
|
||||||
model_solids: HashMap::new(),
|
model_solids: HashMap::default(),
|
||||||
images: HashMap::new(),
|
images: HashMap::default(),
|
||||||
active_viewport: None,
|
active_viewport: None,
|
||||||
bg_color: [0.11, 0.11, 0.11, 1.0],
|
bg_color: [0.11, 0.11, 0.11, 1.0],
|
||||||
paper_bg_color: [1.0, 1.0, 1.0, 1.0],
|
paper_bg_color: [1.0, 1.0, 1.0, 1.0],
|
||||||
|
|
@ -1455,7 +1455,7 @@ impl Scene {
|
||||||
// Deduplicate by name: prefer the entry with a non-null block_record (the
|
// Deduplicate by name: prefer the entry with a non-null block_record (the
|
||||||
// real layout from the file) over the default placeholder created by
|
// real layout from the file) over the default placeholder created by
|
||||||
// CadDocument::new().
|
// CadDocument::new().
|
||||||
let mut by_name: std::collections::HashMap<String, (i16, Handle)> = Default::default();
|
let mut by_name: rustc_hash::FxHashMap<String, (i16, Handle)> = Default::default();
|
||||||
for obj in self.document.objects.values() {
|
for obj in self.document.objects.values() {
|
||||||
if let ObjectType::Layout(l) = obj {
|
if let ObjectType::Layout(l) = obj {
|
||||||
if l.name == "Model" || l.name.is_empty() {
|
if l.name == "Model" || l.name.is_empty() {
|
||||||
|
|
@ -1628,7 +1628,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
use acadrust::objects::ObjectType;
|
use acadrust::objects::ObjectType;
|
||||||
// Per-block SortEntitiesTable overrides: block -> (entity_val -> sort_val).
|
// Per-block SortEntitiesTable overrides: block -> (entity_val -> sort_val).
|
||||||
let mut overrides: HashMap<Handle, HashMap<u64, u64>> = HashMap::new();
|
let mut overrides: HashMap<Handle, HashMap<u64, u64>> = HashMap::default();
|
||||||
for obj in self.document.objects.values() {
|
for obj in self.document.objects.values() {
|
||||||
if let ObjectType::SortEntitiesTable(t) = obj {
|
if let ObjectType::SortEntitiesTable(t) = obj {
|
||||||
if !t.is_empty() {
|
if !t.is_empty() {
|
||||||
|
|
@ -1643,7 +1643,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
let ms = self.model_space_block_handle();
|
let ms = self.model_space_block_handle();
|
||||||
// Group entities by owning block, carrying each entity's effective key.
|
// Group entities by owning block, carrying each entity's effective key.
|
||||||
let mut by_block: HashMap<Handle, Vec<(u64, u64)>> = HashMap::new();
|
let mut by_block: HashMap<Handle, Vec<(u64, u64)>> = HashMap::default();
|
||||||
for e in self.document.entities() {
|
for e in self.document.entities() {
|
||||||
let c = e.common();
|
let c = e.common();
|
||||||
// 3D meshes keep real geometric depth — exclude them from
|
// 3D meshes keep real geometric depth — exclude them from
|
||||||
|
|
@ -1667,7 +1667,7 @@ impl Scene {
|
||||||
.unwrap_or(hv);
|
.unwrap_or(hv);
|
||||||
by_block.entry(block).or_default().push((hv, eff));
|
by_block.entry(block).or_default().push((hv, eff));
|
||||||
}
|
}
|
||||||
let mut depth_map: HashMap<u64, f32> = HashMap::new();
|
let mut depth_map: HashMap<u64, f32> = HashMap::default();
|
||||||
for (_block, mut v) in by_block {
|
for (_block, mut v) in by_block {
|
||||||
v.sort_by_key(|(_, eff)| *eff);
|
v.sort_by_key(|(_, eff)| *eff);
|
||||||
let denom = (v.len() as f32) + 1.0;
|
let denom = (v.len() as f32) + 1.0;
|
||||||
|
|
@ -1928,7 +1928,7 @@ impl Scene {
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
|
|
||||||
if needs_rebuild {
|
if needs_rebuild {
|
||||||
let mut idx: HashMap<Handle, HashMap<u64, u64>> = HashMap::new();
|
let mut idx: HashMap<Handle, HashMap<u64, u64>> = HashMap::default();
|
||||||
for obj in self.document.objects.values() {
|
for obj in self.document.objects.values() {
|
||||||
if let ObjectType::SortEntitiesTable(t) = obj {
|
if let ObjectType::SortEntitiesTable(t) = obj {
|
||||||
if !t.is_empty() {
|
if !t.is_empty() {
|
||||||
|
|
@ -2187,7 +2187,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut map: HashMap<Handle, Handle> = HashMap::new();
|
let mut map: HashMap<Handle, Handle> = HashMap::default();
|
||||||
for br in self.document.block_records.iter() {
|
for br in self.document.block_records.iter() {
|
||||||
for &eh in &br.entity_handles {
|
for &eh in &br.entity_handles {
|
||||||
map.insert(eh, br.handle);
|
map.insert(eh, br.handle);
|
||||||
|
|
@ -4098,11 +4098,11 @@ impl Scene {
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.document = CadDocument::new();
|
self.document = CadDocument::new();
|
||||||
self.selected = HashSet::new();
|
self.selected = HashSet::default();
|
||||||
self.preview_wires = vec![];
|
self.preview_wires = vec![];
|
||||||
self.current_layout = "Model".to_string();
|
self.current_layout = "Model".to_string();
|
||||||
self.hatches = HashMap::new();
|
self.hatches = HashMap::default();
|
||||||
self.meshes = HashMap::new();
|
self.meshes = HashMap::default();
|
||||||
*self.camera.borrow_mut() = Camera::default();
|
*self.camera.borrow_mut() = Camera::default();
|
||||||
self.camera_generation += 1;
|
self.camera_generation += 1;
|
||||||
self.bump_geometry();
|
self.bump_geometry();
|
||||||
|
|
@ -4201,7 +4201,7 @@ impl Scene {
|
||||||
if self.selected.is_empty() {
|
if self.selected.is_empty() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let pairs: std::collections::HashSet<(&'static str, String)> = self
|
let pairs: rustc_hash::FxHashSet<(&'static str, String)> = self
|
||||||
.selected
|
.selected
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|h| self.document.get_entity(*h))
|
.filter_map(|h| self.document.get_entity(*h))
|
||||||
|
|
@ -6276,7 +6276,7 @@ impl Scene {
|
||||||
vp_handle: Handle,
|
vp_handle: Handle,
|
||||||
screen_height_px: f32,
|
screen_height_px: f32,
|
||||||
) -> Vec<WireModel> {
|
) -> Vec<WireModel> {
|
||||||
use std::collections::HashSet as HSet;
|
use rustc_hash::FxHashSet as HSet;
|
||||||
|
|
||||||
let (frozen, vp_anno_scale, vp_aspect) = match self.document.get_entity(vp_handle) {
|
let (frozen, vp_anno_scale, vp_aspect) = match self.document.get_entity(vp_handle) {
|
||||||
Some(EntityType::Viewport(vp)) => {
|
Some(EntityType::Viewport(vp)) => {
|
||||||
|
|
@ -6295,7 +6295,7 @@ impl Scene {
|
||||||
};
|
};
|
||||||
(f, anno, aspect)
|
(f, anno, aspect)
|
||||||
}
|
}
|
||||||
_ => (HSet::new(), 1.0_f32, 1.0_f32),
|
_ => (HSet::default(), 1.0_f32, 1.0_f32),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Drive the per-viewport view_aabb / wpp from the *effective* camera
|
// Drive the per-viewport view_aabb / wpp from the *effective* camera
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ impl Face3DGpu {
|
||||||
face3d_wires: &[WireModel],
|
face3d_wires: &[WireModel],
|
||||||
all_wires: &[WireModel],
|
all_wires: &[WireModel],
|
||||||
keep_3d_mesh_fills: bool,
|
keep_3d_mesh_fills: bool,
|
||||||
depth_map: &std::collections::HashMap<u64, f32>,
|
depth_map: &rustc_hash::FxHashMap<u64, f32>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let depth_of = |w: &WireModel| -> f32 {
|
let depth_of = |w: &WireModel| -> f32 {
|
||||||
w.name
|
w.name
|
||||||
|
|
|
||||||
|
|
@ -891,7 +891,7 @@ impl Pipeline {
|
||||||
&mut self,
|
&mut self,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
wires: &[WireModel],
|
wires: &[WireModel],
|
||||||
depth_map: &std::collections::HashMap<u64, f32>,
|
depth_map: &rustc_hash::FxHashMap<u64, f32>,
|
||||||
) {
|
) {
|
||||||
let depth_of = |w: &WireModel| -> f32 {
|
let depth_of = |w: &WireModel| -> f32 {
|
||||||
w.name
|
w.name
|
||||||
|
|
@ -987,7 +987,7 @@ impl Pipeline {
|
||||||
face3d_wires: &[WireModel],
|
face3d_wires: &[WireModel],
|
||||||
all_wires: &[WireModel],
|
all_wires: &[WireModel],
|
||||||
wireframe_only: bool,
|
wireframe_only: bool,
|
||||||
depth_map: &std::collections::HashMap<u64, f32>,
|
depth_map: &rustc_hash::FxHashMap<u64, f32>,
|
||||||
) {
|
) {
|
||||||
// Edge buffer is always built from `face3d_wires`, so 3DFACE
|
// Edge buffer is always built from `face3d_wires`, so 3DFACE
|
||||||
// outlines stay on the screen regardless of mode.
|
// outlines stay on the screen regardless of mode.
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ fn emit_wire_instances(wire: &WireModel, color: [f32; 4], draw_depth: f32) -> Ve
|
||||||
/// Looks up a wire's draw-order depth from the per-entity map using the
|
/// Looks up a wire's draw-order depth from the per-entity map using the
|
||||||
/// handle encoded in its `name`. Falls back to 0.0 (transient / preview
|
/// handle encoded in its `name`. Falls back to 0.0 (transient / preview
|
||||||
/// wires that carry no document handle).
|
/// wires that carry no document handle).
|
||||||
fn wire_draw_depth(wire: &WireModel, depth_map: &std::collections::HashMap<u64, f32>) -> f32 {
|
fn wire_draw_depth(wire: &WireModel, depth_map: &rustc_hash::FxHashMap<u64, f32>) -> f32 {
|
||||||
wire
|
wire
|
||||||
.name
|
.name
|
||||||
.parse::<u64>()
|
.parse::<u64>()
|
||||||
|
|
@ -290,7 +290,7 @@ impl WireGpu {
|
||||||
pub fn from_batch(
|
pub fn from_batch(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
wires: &[WireModel],
|
wires: &[WireModel],
|
||||||
depth_map: &std::collections::HashMap<u64, f32>,
|
depth_map: &rustc_hash::FxHashMap<u64, f32>,
|
||||||
) -> Vec<Self> {
|
) -> Vec<Self> {
|
||||||
let total_segs: usize = wires.iter().map(|w| w.points.len().saturating_sub(1)).sum();
|
let total_segs: usize = wires.iter().map(|w| w.points.len().saturating_sub(1)).sum();
|
||||||
if total_segs == 0 {
|
if total_segs == 0 {
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ pub struct QuadTree {
|
||||||
nodes: Vec<Node>,
|
nodes: Vec<Node>,
|
||||||
/// `handle → (node_idx, item_idx_within_node)` so removal/update
|
/// `handle → (node_idx, item_idx_within_node)` so removal/update
|
||||||
/// is O(1) without walking the tree.
|
/// is O(1) without walking the tree.
|
||||||
locator: std::collections::HashMap<Handle, (u32, u32)>,
|
locator: rustc_hash::FxHashMap<Handle, (u32, u32)>,
|
||||||
/// Items whose AABB falls outside the root bounds. Surfaced on
|
/// Items whose AABB falls outside the root bounds. Surfaced on
|
||||||
/// every query — small set in practice (typically empty for
|
/// every query — small set in practice (typically empty for
|
||||||
/// well-bounded drawings).
|
/// well-bounded drawings).
|
||||||
|
|
@ -74,7 +74,7 @@ impl QuadTree {
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
nodes: vec![root],
|
nodes: vec![root],
|
||||||
locator: std::collections::HashMap::new(),
|
locator: rustc_hash::FxHashMap::default(),
|
||||||
overflow: Vec::new(),
|
overflow: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ pub struct ViewportData {
|
||||||
/// by the wire / face3d pipelines as a clip-z bias. WireModels carry no
|
/// by the wire / face3d pipelines as a clip-z bias. WireModels carry no
|
||||||
/// depth field (84 construction sites); the bias is looked up by handle
|
/// depth field (84 construction sites); the bias is looked up by handle
|
||||||
/// at GPU-upload time from this map instead.
|
/// at GPU-upload time from this map instead.
|
||||||
pub(super) draw_depths: Arc<std::collections::HashMap<u64, f32>>,
|
pub(super) draw_depths: Arc<rustc_hash::FxHashMap<u64, f32>>,
|
||||||
pub(super) hatches: Arc<Vec<HatchModel>>,
|
pub(super) hatches: Arc<Vec<HatchModel>>,
|
||||||
/// Wipeout fills — rendered in a separate pass AFTER wires.
|
/// Wipeout fills — rendered in a separate pass AFTER wires.
|
||||||
pub(super) wipeout_hatches: Arc<Vec<HatchModel>>,
|
pub(super) wipeout_hatches: Arc<Vec<HatchModel>>,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
// All other surface types are silently skipped; partial results are still
|
// All other surface types are silently skipped; partial results are still
|
||||||
// returned so the solid renders with at least its planar faces.
|
// returned so the solid renders with at least its planar faces.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use rustc_hash::FxHashSet as HashSet;
|
||||||
use std::f64::consts::TAU;
|
use std::f64::consts::TAU;
|
||||||
|
|
||||||
use acadrust::entities::acis::types::Sense;
|
use acadrust::entities::acis::types::Sense;
|
||||||
|
|
@ -237,7 +237,7 @@ fn collect_face_polygon(sat: &SatDocument, face: &SatFace) -> Vec<[f64; 3]> {
|
||||||
let first_ptr = sat_loop.first_coedge();
|
let first_ptr = sat_loop.first_coedge();
|
||||||
let mut cur = first_ptr;
|
let mut cur = first_ptr;
|
||||||
let mut pts: Vec<[f64; 3]> = Vec::new();
|
let mut pts: Vec<[f64; 3]> = Vec::new();
|
||||||
let mut visited: HashSet<i32> = HashSet::new();
|
let mut visited: HashSet<i32> = HashSet::default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if cur.is_null() {
|
if cur.is_null() {
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ pub struct SnapResult {
|
||||||
|
|
||||||
// ── Snapper ───────────────────────────────────────────────────────────────
|
// ── Snapper ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use rustc_hash::FxHashSet as HashSet;
|
||||||
|
|
||||||
pub struct Snapper {
|
pub struct Snapper {
|
||||||
/// Global snap on/off toggle. When false, all snapping is bypassed
|
/// Global snap on/off toggle. When false, all snapping is bypassed
|
||||||
|
|
@ -87,7 +87,7 @@ pub struct Snapper {
|
||||||
|
|
||||||
impl Default for Snapper {
|
impl Default for Snapper {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut enabled = HashSet::new();
|
let mut enabled = HashSet::default();
|
||||||
enabled.insert(SnapType::Endpoint);
|
enabled.insert(SnapType::Endpoint);
|
||||||
enabled.insert(SnapType::Midpoint);
|
enabled.insert(SnapType::Midpoint);
|
||||||
enabled.insert(SnapType::Center);
|
enabled.insert(SnapType::Center);
|
||||||
|
|
@ -257,7 +257,7 @@ impl Snapper {
|
||||||
let tmp = Snapper {
|
let tmp = Snapper {
|
||||||
snap_enabled: true,
|
snap_enabled: true,
|
||||||
enabled: {
|
enabled: {
|
||||||
let mut s = HashSet::new();
|
let mut s = HashSet::default();
|
||||||
s.insert(SnapType::Tangent);
|
s.insert(SnapType::Tangent);
|
||||||
s
|
s
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//! • Linetype → read-only for now
|
//! • Linetype → read-only for now
|
||||||
//! • Geometry → text_input per coordinate / dimension field
|
//! • Geometry → text_input per coordinate / dimension field
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::ui::ROW_H;
|
use crate::ui::ROW_H;
|
||||||
|
|
@ -142,12 +142,12 @@ impl Default for PropertiesPanel {
|
||||||
selected_group: None,
|
selected_group: None,
|
||||||
linetype_items: vec![],
|
linetype_items: vec![],
|
||||||
selection_group_combo: combo_box::State::new(vec![]),
|
selection_group_combo: combo_box::State::new(vec![]),
|
||||||
choice_combos: HashMap::new(),
|
choice_combos: HashMap::default(),
|
||||||
layer_combo: combo_box::State::new(vec![]),
|
layer_combo: combo_box::State::new(vec![]),
|
||||||
lineweight_combo: combo_box::State::new(lw_options()),
|
lineweight_combo: combo_box::State::new(lw_options()),
|
||||||
linetype_combo: combo_box::State::new(vec![]),
|
linetype_combo: combo_box::State::new(vec![]),
|
||||||
hatch_pattern_combo: combo_box::State::new(crate::scene::hatch_patterns::names()),
|
hatch_pattern_combo: combo_box::State::new(crate::scene::hatch_patterns::names()),
|
||||||
edit_buf: HashMap::new(),
|
edit_buf: HashMap::default(),
|
||||||
color_picker_open: false,
|
color_picker_open: false,
|
||||||
color_palette_open: false,
|
color_palette_open: false,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
//
|
//
|
||||||
// Dropdown items within a group are collected into columns of 3 rows.
|
// Dropdown items within a group are collected into columns of 3 rows.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
|
|
||||||
use acadrust::types::{Color as AcadColor, LineWeight};
|
use acadrust::types::{Color as AcadColor, LineWeight};
|
||||||
use iced::widget::{button, column, container, mouse_area, row, scrollable, svg, text};
|
use iced::widget::{button, column, container, mouse_area, row, scrollable, svg, text};
|
||||||
|
|
@ -73,7 +73,7 @@ impl Ribbon {
|
||||||
wireframe: false,
|
wireframe: false,
|
||||||
ortho_mode: true,
|
ortho_mode: true,
|
||||||
open_dropdown: None,
|
open_dropdown: None,
|
||||||
last_cmd: HashMap::new(),
|
last_cmd: HashMap::default(),
|
||||||
layer_names: vec!["0".to_string()],
|
layer_names: vec!["0".to_string()],
|
||||||
active_layer: "0".to_string(),
|
active_layer: "0".to_string(),
|
||||||
layer_infos: vec![LayerInfo {
|
layer_infos: vec![LayerInfo {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Shared rendering helpers, button styles, colours, layout constants, and
|
// Shared rendering helpers, button styles, colours, layout constants, and
|
||||||
// free functions used by the Ribbon view/overlay methods.
|
// free functions used by the Ribbon view/overlay methods.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use acadrust::types::{Color as AcadColor, LineWeight};
|
use acadrust::types::{Color as AcadColor, LineWeight};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
//! A checked row means that type can be picked; unchecking it excludes the
|
//! A checked row means that type can be picked; unchecking it excludes the
|
||||||
//! type from interactive selection. Opened from the FILTER status pill.
|
//! type from interactive selection. Opened from the FILTER status pill.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use rustc_hash::FxHashSet as HashSet;
|
||||||
|
|
||||||
use iced::widget::{button, column, container, mouse_area, row, text};
|
use iced::widget::{button, column, container, mouse_area, row, text};
|
||||||
use iced::{Background, Border, Color, Element, Fill, Length, Padding, Theme};
|
use iced::{Background, Border, Color, Element, Fill, Length, Padding, Theme};
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ fn section<'a>(title: &'static str) -> Element<'a, Message> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_window<'a>(
|
pub fn view_window<'a>(
|
||||||
overrides: &'a std::collections::HashMap<String, String>,
|
overrides: &'a rustc_hash::FxHashMap<String, String>,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
// ── Toolbar ───────────────────────────────────────────────────────────
|
// ── Toolbar ───────────────────────────────────────────────────────────
|
||||||
let toolbar = container(
|
let toolbar = container(
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
//! adds or removes that pill from the bar. The choice is persisted so it
|
//! adds or removes that pill from the bar. The choice is persisted so it
|
||||||
//! survives across sessions.
|
//! survives across sessions.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use rustc_hash::FxHashSet as HashSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Identifies a toggleable status-bar pill.
|
/// Identifies a toggleable status-bar pill.
|
||||||
|
|
@ -121,7 +121,7 @@ pub struct StatusBarConfig {
|
||||||
impl StatusBarConfig {
|
impl StatusBarConfig {
|
||||||
/// Load the saved customization, or all-visible when none exists.
|
/// Load the saved customization, or all-visible when none exists.
|
||||||
pub fn load() -> Self {
|
pub fn load() -> Self {
|
||||||
let mut hidden = HashSet::new();
|
let mut hidden = HashSet::default();
|
||||||
if let Some(path) = config_path() {
|
if let Some(path) = config_path() {
|
||||||
if let Ok(body) = std::fs::read_to_string(path) {
|
if let Ok(body) = std::fs::read_to_string(path) {
|
||||||
for line in body.lines() {
|
for line in body.lines() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue