diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3357bf74..ff096349 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,10 +34,10 @@ jobs: mkdir -p AppDir/usr/bin mkdir -p AppDir/usr/share/applications mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps - cp target/release/H7CAD AppDir/usr/bin/H7CAD - cp packaging/H7CAD.desktop AppDir/usr/share/applications/io.github.HakanSeven12.H7CAD.desktop + cp target/release/OpenCADStudio AppDir/usr/bin/OpenCADStudio + cp packaging/OpenCADStudio.desktop AppDir/usr/share/applications/io.github.HakanSeven12.OpenCadStudio.desktop rsvg-convert -w 256 -h 256 assets/logo.svg \ - -o AppDir/usr/share/icons/hicolor/256x256/apps/io.github.HakanSeven12.H7CAD.png + -o AppDir/usr/share/icons/hicolor/256x256/apps/io.github.HakanSeven12.OpenCadStudio.png - name: Download linuxdeploy run: | @@ -50,18 +50,18 @@ jobs: run: | ./linuxdeploy-x86_64.AppImage \ --appdir AppDir \ - --desktop-file AppDir/usr/share/applications/io.github.HakanSeven12.H7CAD.desktop \ - --icon-file AppDir/usr/share/icons/hicolor/256x256/apps/io.github.HakanSeven12.H7CAD.png \ + --desktop-file AppDir/usr/share/applications/io.github.HakanSeven12.OpenCadStudio.desktop \ + --icon-file AppDir/usr/share/icons/hicolor/256x256/apps/io.github.HakanSeven12.OpenCadStudio.png \ --output appimage - mv H7CAD*.AppImage H7CAD.AppImage + mv Open*CAD*Studio*.AppImage OpenCADStudio.AppImage - name: Upload AppImage to release if: github.event_name == 'release' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv H7CAD.AppImage H7CAD-${{ github.ref_name }}-linux-x86_64.AppImage - gh release upload ${{ github.ref_name }} H7CAD-${{ github.ref_name }}-linux-x86_64.AppImage --clobber --repo ${{ github.repository }} + mv OpenCADStudio.AppImage OpenCADStudio-${{ github.ref_name }}-linux-x86_64.AppImage + gh release upload ${{ github.ref_name }} OpenCADStudio-${{ github.ref_name }}-linux-x86_64.AppImage --clobber --repo ${{ github.repository }} build-windows: runs-on: windows-latest @@ -83,8 +83,8 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv target/release/H7CAD.exe H7CAD-${{ github.ref_name }}-windows-x86_64.exe - gh release upload ${{ github.ref_name }} H7CAD-${{ github.ref_name }}-windows-x86_64.exe --clobber --repo ${{ github.repository }} + mv target/release/OpenCADStudio.exe OpenCADStudio-${{ github.ref_name }}-windows-x86_64.exe + gh release upload ${{ github.ref_name }} OpenCADStudio-${{ github.ref_name }}-windows-x86_64.exe --clobber --repo ${{ github.repository }} build-macos: runs-on: macos-14 # Apple Silicon (arm64) only @@ -110,25 +110,25 @@ jobs: - name: Build .icns from SVG run: | - mkdir -p H7CAD.iconset + mkdir -p OpenCADStudio.iconset # Render all the sizes Apple expects in an .icns. for SIZE in 16 32 64 128 256 512 1024; do - rsvg-convert -w $SIZE -h $SIZE assets/logo.svg -o H7CAD.iconset/icon_${SIZE}x${SIZE}.png + rsvg-convert -w $SIZE -h $SIZE assets/logo.svg -o OpenCADStudio.iconset/icon_${SIZE}x${SIZE}.png done # @2x retina variants (half-size base name) for BASE in 16 32 128 256 512; do DOUBLE=$((BASE * 2)) - cp H7CAD.iconset/icon_${DOUBLE}x${DOUBLE}.png H7CAD.iconset/icon_${BASE}x${BASE}@2x.png + cp OpenCADStudio.iconset/icon_${DOUBLE}x${DOUBLE}.png OpenCADStudio.iconset/icon_${BASE}x${BASE}@2x.png done - iconutil -c icns H7CAD.iconset -o AppIcon.icns + iconutil -c icns OpenCADStudio.iconset -o AppIcon.icns - name: Assemble .app bundle run: | - APP=H7CAD.app + APP=OpenCADStudio.app rm -rf "$APP" mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources" - cp target/aarch64-apple-darwin/release/H7CAD "$APP/Contents/MacOS/H7CAD" - chmod +x "$APP/Contents/MacOS/H7CAD" + cp target/aarch64-apple-darwin/release/OpenCADStudio "$APP/Contents/MacOS/OpenCADStudio" + chmod +x "$APP/Contents/MacOS/OpenCADStudio" cp AppIcon.icns "$APP/Contents/Resources/AppIcon.icns" # Substitute version into Info.plist. VERSION="${{ github.ref_name }}" @@ -139,15 +139,15 @@ jobs: - name: Create .dmg run: | hdiutil create \ - -volname "H7CAD" \ - -srcfolder H7CAD.app \ + -volname "Open CAD Studio" \ + -srcfolder OpenCADStudio.app \ -ov -format UDZO \ - H7CAD.dmg + OpenCADStudio.dmg - name: Upload .dmg to release if: github.event_name == 'release' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv H7CAD.dmg H7CAD-${{ github.ref_name }}-macos-arm64.dmg - gh release upload ${{ github.ref_name }} H7CAD-${{ github.ref_name }}-macos-arm64.dmg --clobber --repo ${{ github.repository }} + mv OpenCADStudio.dmg OpenCADStudio-${{ github.ref_name }}-macos-arm64.dmg + gh release upload ${{ github.ref_name }} OpenCADStudio-${{ github.ref_name }}-macos-arm64.dmg --clobber --repo ${{ github.repository }} diff --git a/.gitignore b/.gitignore index b12df8ac..7acd88e1 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ target # Flatpak flatpak/cargo-sources.json -flatpak/io.github.HakanSeven12.H7CAD.local.yml +flatpak/io.github.HakanSeven12.OpenCadStudio.local.yml .flatpak-builder/ build-dir/ diff --git a/COMMANDS.md b/COMMANDS.md index 91d1374e..ff54c13c 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -1,6 +1,6 @@ -# H7CAD β€” Command Reference +# Open CAD Studio β€” Command Reference -Status of every standard CAD command in H7CAD: +Status of every standard CAD command in Open CAD Studio: - βœ… **Implemented** β€” fully working - πŸ”Ά **Partial** β€” command is accepted but logic is a stub diff --git a/Cargo.lock b/Cargo.lock index 1e6e14ac..55f97c5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ version = 4 [[package]] -name = "H7CAD" +name = "OpenCADStudio" version = "0.3.8" dependencies = [ "acadrust", diff --git a/Cargo.toml b/Cargo.toml index c60acc76..22b73d62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "H7CAD" +name = "OpenCADStudio" version = "0.3.8" edition = "2021" build = "build.rs" diff --git a/README.md b/README.md index 371615e4..fcebc88a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# H7CAD +# Open CAD Studio Ekran gΓΆrΓΌntΓΌsΓΌ 2026-05-23 105715 @@ -102,34 +102,34 @@ A CAD application for 2D drafting and 3D modeling, built with Rust. Reads and wr ### Linux (AppImage) -Download `H7CAD-*-linux-x86_64.AppImage` from the [latest release](https://github.com/HakanSeven12/H7CAD/releases/latest), then: +Download `OpenCADStudio-*-linux-x86_64.AppImage` from the [latest release](https://github.com/HakanSeven12/open-cad-studio/releases/latest), then: ```bash -chmod +x H7CAD-*-linux-x86_64.AppImage -./H7CAD-*-linux-x86_64.AppImage +chmod +x OpenCADStudio-*-linux-x86_64.AppImage +./OpenCADStudio-*-linux-x86_64.AppImage ``` No installation required β€” runs directly on any modern Linux distribution. ### Windows -Download `H7CAD-*-windows-x86_64.exe` from the [latest release](https://github.com/HakanSeven12/H7CAD/releases/latest) and run it directly. Windows SmartScreen may show "Windows protected your PC" because the binary is not yet code-signed β€” click **More info β†’ Run anyway**. +Download `OpenCADStudio-*-windows-x86_64.exe` from the [latest release](https://github.com/HakanSeven12/open-cad-studio/releases/latest) and run it directly. Windows SmartScreen may show "Windows protected your PC" because the binary is not yet code-signed β€” click **More info β†’ Run anyway**. ### macOS (Apple Silicon) -Download `H7CAD-*-macos-arm64.dmg` from the [latest release](https://github.com/HakanSeven12/H7CAD/releases/latest) β€” Apple Silicon (M-series) only; Intel macOS isn't built. +Download `OpenCADStudio-*-macos-arm64.dmg` from the [latest release](https://github.com/HakanSeven12/open-cad-studio/releases/latest) β€” Apple Silicon (M-series) only; Intel macOS isn't built. -Open the .dmg and drag `H7CAD.app` to `/Applications`. The first launch may be blocked by Gatekeeper because the app is not notarised β€” right-click `H7CAD.app β†’ Open` and confirm, or run once via `xattr -dr com.apple.quarantine /Applications/H7CAD.app`. +Open the .dmg and drag `OpenCADStudio.app` to `/Applications`. The first launch may be blocked by Gatekeeper because the app is not notarised β€” right-click `OpenCADStudio.app β†’ Open` and confirm, or run once via `xattr -dr com.apple.quarantine /Applications/OpenCADStudio.app`. ### Build from Source Requirements: Rust 1.75+ ```bash -git clone https://github.com/HakanSeven12/H7CAD.git -cd H7CAD -cargo build --release --bin H7CAD -./target/release/H7CAD +git clone https://github.com/HakanSeven12/open-cad-studio.git +cd open-cad-studio +cargo build --release --bin OpenCADStudio +./target/release/OpenCADStudio ``` ## License diff --git a/ROADMAP.md b/ROADMAP.md index bbf64d7d..33a79ad2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,4 +1,4 @@ -# H7CAD β€” File Open & Render Speed Roadmap +# Open CAD Studio β€” File Open & Render Speed Roadmap This document lists the planned improvements for cutting **file open time** and **on-screen draw (render) time**. It builds on the already-landed @@ -91,7 +91,7 @@ decode until **first render** (per-handle lazy `OnceCell`). ### 1.7 File-hash cache (warm re-open) When re-opening the same file (`(path, mtime, size)` key) keep a disk -snapshot of `CadDocument` + `DerivedCaches` (e.g. `~/.cache/h7cad/`). Skip +snapshot of `CadDocument` + `DerivedCaches` (e.g. `~/.cache/open-cad-studio/`). Skip DWG parse entirely. **Win:** most-recently-opened file goes from 1-2 s to sub-100 ms. @@ -278,6 +278,6 @@ Then, measurement-guided: - **GPU compute culling:** for orthographic 2D CAD the CPU quadtree is enough. Already covered by Phase 1-4. - **Out-of-core entity streaming:** meaningful for 100 MB+ single files; - typical H7CAD files are not there yet. + typical Open CAD Studio files are not there yet. - **Multi-frame async tessellation pipeline:** if 2.3 progressive render works cleanly, this isn't needed. diff --git a/assets/linetypes/H7CAD.lin b/assets/linetypes/OpenCADStudio.lin similarity index 100% rename from assets/linetypes/H7CAD.lin rename to assets/linetypes/OpenCADStudio.lin diff --git a/assets/logo.svg b/assets/logo.svg index 490060df..aa1d0409 100644 --- a/assets/logo.svg +++ b/assets/logo.svg @@ -29,60 +29,26 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> - + - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/assets/patterns/H7CAD.pat b/assets/patterns/OpenCADStudio.pat similarity index 100% rename from assets/patterns/H7CAD.pat rename to assets/patterns/OpenCADStudio.pat diff --git a/examples/dump_index_stats.rs b/examples/dump_index_stats.rs deleted file mode 100644 index 482edfa6..00000000 --- a/examples/dump_index_stats.rs +++ /dev/null @@ -1,171 +0,0 @@ -// Diagnostic: simulate Scene::entity_index() build on a DXF/DWG file -// and report per-type stats for indexed / unbounded / unindexable -// entities, plus how many would survive a hypothetical view query. -// -// cargo run --release --example dump_index_stats -- - -use acadrust::EntityType; -use std::collections::BTreeMap; - -fn entity_kind(e: &EntityType) -> &'static str { - match e { - EntityType::Line(_) => "Line", - EntityType::LwPolyline(_) => "LwPolyline", - EntityType::Polyline2D(_) => "Polyline2D", - EntityType::Polyline3D(_) => "Polyline3D", - EntityType::Polyline(_) => "Polyline", - EntityType::Circle(_) => "Circle", - EntityType::Arc(_) => "Arc", - EntityType::Ellipse(_) => "Ellipse", - EntityType::Spline(_) => "Spline", - EntityType::Text(_) => "Text", - EntityType::MText(_) => "MText", - EntityType::Hatch(_) => "Hatch", - EntityType::Wipeout(_) => "Wipeout", - EntityType::Insert(_) => "Insert", - EntityType::Viewport(_) => "Viewport", - EntityType::Block(_) => "Block", - EntityType::BlockEnd(_) => "BlockEnd", - EntityType::Dimension(_) => "Dimension", - EntityType::Leader(_) => "Leader", - EntityType::MLine(_) => "MLine", - EntityType::Point(_) => "Point", - EntityType::Solid(_) => "Solid", - EntityType::Face3D(_) => "Face3D", - EntityType::RasterImage(_) => "RasterImage", - EntityType::Solid3D(_) => "Solid3D", - EntityType::Region(_) => "Region", - EntityType::Body(_) => "Body", - EntityType::Ole2Frame(_) => "Ole2Frame", - EntityType::Ray(_) => "Ray", - EntityType::XLine(_) => "XLine", - _ => "Other", - } -} - -fn is_unindexable(e: &EntityType) -> bool { - matches!( - e, - EntityType::Insert(_) - | EntityType::Viewport(_) - | EntityType::Block(_) - | EntityType::BlockEnd(_) - ) -} - -fn world_aabb_f64(e: &EntityType) -> Option<[f64; 4]> { - let bb = e.as_entity().bounding_box(); - let (xmin, ymin, xmax, ymax) = (bb.min.x, bb.min.y, bb.max.x, bb.max.y); - if xmin == xmax && ymin == ymax { - return None; - } - if !xmin.is_finite() || !ymin.is_finite() || !xmax.is_finite() || !ymax.is_finite() { - return None; - } - Some([xmin, ymin, xmax, ymax]) -} - -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).expect("usage: dump_index_stats "); - let mut doc = if path.to_lowercase().ends_with(".dwg") { - acadrust::io::dwg::DwgReader::from_file(&path)?.read()? - } else { - acadrust::io::dxf::DxfReader::from_file(&path)?.read()? - }; - let base_dir = std::path::Path::new(&path) - .parent() - .unwrap_or(std::path::Path::new(".")); - let _ = H7CAD::io::xref::resolve_xrefs(&mut doc, base_dir); - - let model_block = doc.header.model_space_block_handle; - println!("file: {}", path); - println!("model_space_block_handle: {:?}", model_block); - println!("total entities: {}", doc.entities().count()); - println!(); - - let mut total: BTreeMap<&str, usize> = BTreeMap::new(); - let mut indexed: BTreeMap<&str, usize> = BTreeMap::new(); - let mut unbounded: BTreeMap<&str, usize> = BTreeMap::new(); - let mut unindexable_count: BTreeMap<&str, usize> = BTreeMap::new(); - let mut top_level: BTreeMap<&str, usize> = BTreeMap::new(); - let mut block_internal: BTreeMap<&str, usize> = BTreeMap::new(); - let mut union: Option<[f64; 4]> = None; - - for e in doc.entities() { - let k = entity_kind(e); - *total.entry(k).or_default() += 1; - let owner = e.common().owner_handle; - if owner == model_block { - *top_level.entry(k).or_default() += 1; - } else { - *block_internal.entry(k).or_default() += 1; - } - if is_unindexable(e) { - *unindexable_count.entry(k).or_default() += 1; - continue; - } - match world_aabb_f64(e) { - Some(ab) => { - *indexed.entry(k).or_default() += 1; - union = Some(match union { - None => ab, - Some(u) => [ - u[0].min(ab[0]), - u[1].min(ab[1]), - u[2].max(ab[2]), - u[3].max(ab[3]), - ], - }); - } - None => *unbounded.entry(k).or_default() += 1, - } - } - - println!("──── per type ────────────────────────────────────────────────"); - println!( - "{:<14} {:>6} {:>6} {:>6} {:>6} {:>10} {:>10}", - "Type", "total", "idx", "unb", "skip", "top-lvl", "blk-int" - ); - let mut all_keys: std::collections::BTreeSet<&str> = std::collections::BTreeSet::new(); - all_keys.extend(total.keys()); - for k in &all_keys { - println!( - "{:<14} {:>6} {:>6} {:>6} {:>6} {:>10} {:>10}", - k, - total.get(k).copied().unwrap_or(0), - indexed.get(k).copied().unwrap_or(0), - unbounded.get(k).copied().unwrap_or(0), - unindexable_count.get(k).copied().unwrap_or(0), - top_level.get(k).copied().unwrap_or(0), - block_internal.get(k).copied().unwrap_or(0), - ); - } - - println!(); - println!("union of indexed AABBs: {:?}", union); - - // Sample top-level entity bboxes by type - println!(); - println!("──── sample top-level entity bboxes (first 5 per type) ────────"); - let mut shown: BTreeMap<&str, usize> = BTreeMap::new(); - for e in doc.entities() { - let k = entity_kind(e); - if e.common().owner_handle != model_block { - continue; - } - let c = shown.entry(k).or_insert(0); - if *c >= 5 { - continue; - } - *c += 1; - let bb = e.as_entity().bounding_box(); - println!( - " {:<12} h={:?} bb=({:.3},{:.3})β†’({:.3},{:.3})", - k, - e.common().handle, - bb.min.x, bb.min.y, bb.max.x, bb.max.y, - ); - } - - Ok(()) -} diff --git a/examples/find_raster.rs b/examples/find_raster.rs deleted file mode 100644 index af01c082..00000000 --- a/examples/find_raster.rs +++ /dev/null @@ -1,14 +0,0 @@ -use acadrust::entities::EntityType; -use acadrust::io::dwg::DwgReader; -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).unwrap(); - let doc = DwgReader::from_file(&path)?.read()?; - for e in doc.entities() { - if let EntityType::RasterImage(img) = e { - println!("file_path: {}", img.file_path); - println!("size: {} x {}", img.size.x, img.size.y); - if let Ok(meta) = std::fs::metadata(&img.file_path) { println!("disk size: {} bytes", meta.len()); } - } - } - Ok(()) -} diff --git a/examples/inspect_anno.rs b/examples/inspect_anno.rs deleted file mode 100644 index f2102353..00000000 --- a/examples/inspect_anno.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Inspect DIMSCALE, dimstyles, text heights, and xdata to diagnose -// annotation-scale bugs in paper-space viewports. -// -// cargo run --release --example inspect_anno -- - -use acadrust::entities::{Dimension, EntityType}; -use acadrust::io::dwg::DwgReader; - -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).expect("usage: inspect_anno "); - let doc = DwgReader::from_file(&path)?.read()?; - println!("file: {}\n", path); - - println!("─── header ──────────────────────────────"); - println!(" DIMSCALE (dim_scale) = {}", doc.header.dim_scale); - println!(" DIMTXT (dim_text_height)= {}", doc.header.dim_text_height); - println!(" DIMASZ (dim_arrow_size) = {}", doc.header.dim_arrow_size); - println!(" TEXTSIZE (text_height) = {}", doc.header.text_height); - println!(" LTSCALE = {}", doc.header.linetype_scale); - println!(" PSLTSCALE (psls) = {}", doc.header.paper_space_linetype_scaling); - println!(" CELTSCALE = {}", doc.header.current_entity_linetype_scale); - println!(" viewport_scale_factor = {}", doc.header.viewport_scale_factor); - println!(); - println!("─── linetypes (first 10) ────────────────"); - let mut shown = 0; - for lt in doc.line_types.iter() { - if shown >= 10 { break; } - println!( - " {:<24} pattern_len={:.4} elements={}", - lt.name, lt.pattern_length, lt.elements.len() - ); - shown += 1; - } - println!(); - - println!("─── dim_styles ──────────────────────────"); - println!( - " {:<24} {:>10} {:>10} {:>10} {:>10}", - "name", "dimscale", "dimtxt", "dimasz", "dimexe" - ); - for s in doc.dim_styles.iter() { - println!( - " {:<24} {:>10.4} {:>10.4} {:>10.4} {:>10.4}", - s.name, s.dimscale, s.dimtxt, s.dimasz, s.dimexe - ); - } - println!(); - - println!("─── text_styles ─────────────────────────"); - for s in doc.text_styles.iter() { - println!( - " {:<24} height={:.4} last_height={:.4} font={:?}", - s.name, s.height, s.last_height, s.font_file - ); - } - println!(); - - let mut n_text = 0u32; - let mut n_text_with_xdata = 0u32; - let mut n_text_with_acanno = 0u32; - let mut n_mtext = 0u32; - let mut n_mtext_with_xdata = 0u32; - let mut n_mtext_with_acanno = 0u32; - let mut n_dim = 0u32; - let mut n_dim_with_xdata = 0u32; - let mut n_dim_with_acanno = 0u32; - let mut xd_app_counts: std::collections::BTreeMap = Default::default(); - - let mut sample_text_h: Vec = vec![]; - let mut sample_mtext_h: Vec = vec![]; - let mut sample_dim_style: std::collections::BTreeMap = Default::default(); - // For MTEXT: bucket by owner block name (paper vs model) and height range. - let mut mtext_by_owner: std::collections::BTreeMap> = Default::default(); - - let acanno_keys = ["AcAnnoPO", "AcAnnotativeData", "AcAnnoScaleObj", "AcDbXrecObject"]; - - for e in doc.entities() { - match e { - EntityType::Text(t) => { - n_text += 1; - let xd = &t.common.extended_data; - let has_xd = !xd.records().is_empty(); - if has_xd { - n_text_with_xdata += 1; - for r in xd.records() { - *xd_app_counts.entry(r.application_name.clone()).or_default() += 1; - } - } - if acanno_keys.iter().any(|k| xd.get_record(k).is_some()) { - n_text_with_acanno += 1; - } - if sample_text_h.len() < 10 { - sample_text_h.push(t.height); - } - } - EntityType::MText(t) => { - n_mtext += 1; - let xd = &t.common.extended_data; - let has_xd = !xd.records().is_empty(); - if has_xd { - n_mtext_with_xdata += 1; - for r in xd.records() { - *xd_app_counts.entry(r.application_name.clone()).or_default() += 1; - } - } - if acanno_keys.iter().any(|k| xd.get_record(k).is_some()) { - n_mtext_with_acanno += 1; - } - if sample_mtext_h.len() < 10 { - sample_mtext_h.push(t.height); - } - // Look up the owning block-record by handle and label as - // "*Model_Space" / "*Paper_Space*" / "". - let owner_h = t.common.owner_handle; - let owner_label = doc - .block_records - .iter() - .find_map(|br: &acadrust::BlockRecord| { - if br.handle == owner_h { - Some(br.name.clone()) - } else { - None - } - }) - .unwrap_or_else(|| format!("h{}", owner_h.value())); - mtext_by_owner - .entry(owner_label) - .or_default() - .push(t.height); - } - EntityType::Dimension(d) => { - n_dim += 1; - let base = match d { - Dimension::Aligned(d) => &d.base, - Dimension::Linear(d) => &d.base, - Dimension::Radius(d) => &d.base, - Dimension::Diameter(d) => &d.base, - Dimension::Angular2Ln(d) => &d.base, - Dimension::Angular3Pt(d) => &d.base, - Dimension::Ordinate(d) => &d.base, - }; - let xd = &base.common.extended_data; - let has_xd = !xd.records().is_empty(); - if has_xd { - n_dim_with_xdata += 1; - for r in xd.records() { - *xd_app_counts.entry(r.application_name.clone()).or_default() += 1; - } - } - if acanno_keys.iter().any(|k| xd.get_record(k).is_some()) { - n_dim_with_acanno += 1; - } - *sample_dim_style.entry(base.style_name.clone()).or_default() += 1; - } - _ => {} - } - } - - println!("─── annotation entity counts ────────────"); - println!( - " TEXT total={:<5} xdata={:<5} AcAnno={}", - n_text, n_text_with_xdata, n_text_with_acanno - ); - println!( - " MTEXT total={:<5} xdata={:<5} AcAnno={}", - n_mtext, n_mtext_with_xdata, n_mtext_with_acanno - ); - println!( - " DIMENSION total={:<5} xdata={:<5} AcAnno={}", - n_dim, n_dim_with_xdata, n_dim_with_acanno - ); - println!(); - - println!("─── xdata application names seen ────────"); - for (k, v) in &xd_app_counts { - println!(" {:>5} {}", v, k); - } - println!(); - - if !sample_text_h.is_empty() { - println!("─── first 10 TEXT heights ───────────────"); - for h in &sample_text_h { - println!(" {:.4}", h); - } - println!(); - } - if !sample_mtext_h.is_empty() { - println!("─── first 10 MTEXT heights ──────────────"); - for h in &sample_mtext_h { - println!(" {:.4}", h); - } - println!(); - } - if !mtext_by_owner.is_empty() { - println!("─── MTEXT by owner ──────────────────────"); - for (owner, heights) in &mtext_by_owner { - let mut h = heights.clone(); - h.sort_by(|a, b| a.partial_cmp(b).unwrap()); - let min = h.first().copied().unwrap_or(0.0); - let max = h.last().copied().unwrap_or(0.0); - let median = h[h.len() / 2]; - let n_below_10 = h.iter().filter(|&&x| x < 10.0).count(); - let n_above_100 = h.iter().filter(|&&x| x > 100.0).count(); - println!( - " {:<20} n={:<4} min={:.2} med={:.2} max={:.2} <10:{} >100:{}", - owner, - h.len(), - min, - median, - max, - n_below_10, - n_above_100 - ); - } - println!(); - } - - if !sample_dim_style.is_empty() { - println!("─── dimension styles used (count) ───────"); - for (k, v) in &sample_dim_style { - let used_style = doc.dim_styles.iter().find(|s| s.name == *k); - let ds = used_style.map(|s| s.dimscale).unwrap_or(f64::NAN); - let dt = used_style.map(|s| s.dimtxt).unwrap_or(f64::NAN); - let da = used_style.map(|s| s.dimasz).unwrap_or(f64::NAN); - println!( - " {:>5}Γ— style=\"{}\" dimscale={:.4} dimtxt={:.4} dimasz={:.4}", - v, k, ds, dt, da - ); - } - } - - Ok(()) -} diff --git a/examples/inspect_block.rs b/examples/inspect_block.rs deleted file mode 100644 index 1ce6a277..00000000 --- a/examples/inspect_block.rs +++ /dev/null @@ -1,128 +0,0 @@ -// List entities inside a named block, showing their layer + resolved linetype. -// -// cargo run --release --example inspect_block -- - -use acadrust::entities::EntityType; -use acadrust::io::dwg::DwgReader; - -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).expect("usage: inspect_block [block]"); - let block_name = std::env::args().nth(2); - let doc = DwgReader::from_file(&path)?.read()?; - - if block_name.is_none() { - let mut blocks: Vec<_> = doc - .block_records - .iter() - .map(|br| { - let n = doc - .entities() - .filter(|e| e.common().owner_handle == br.handle) - .count(); - (br.name.clone(), n) - }) - .collect(); - blocks.sort_by_key(|(_, n)| std::cmp::Reverse(*n)); - println!("─── top 30 blocks by entity count ───────"); - for (name, n) in blocks.iter().take(30) { - println!(" {:>5} {}", n, name); - } - return Ok(()); - } - let block_name = block_name.unwrap(); - - // Find the block record by name. - let br = doc - .block_records - .iter() - .find(|br| br.name.eq_ignore_ascii_case(&block_name)) - .ok_or_else(|| format!("block '{}' not found", block_name))?; - - println!("block: \"{}\" handle={:?}", br.name, br.handle); - println!(); - - let mut counts: std::collections::BTreeMap<&'static str, u32> = Default::default(); - let mut sample_by_kind: std::collections::BTreeMap<&'static str, Vec> = - Default::default(); - - for e in doc.entities() { - if e.common().owner_handle != br.handle { - continue; - } - let kind: &'static str = match e { - EntityType::Line(_) => "Line", - EntityType::LwPolyline(_) => "LwPolyline", - EntityType::Polyline(_) => "Polyline", - EntityType::Polyline2D(_) => "Polyline2D", - EntityType::Arc(_) => "Arc", - EntityType::Circle(_) => "Circle", - EntityType::Spline(_) => "Spline", - EntityType::Ellipse(_) => "Ellipse", - EntityType::Text(_) => "Text", - EntityType::MText(_) => "MText", - EntityType::Insert(_) => "Insert", - EntityType::Hatch(_) => "Hatch", - EntityType::Solid(_) => "Solid", - _ => "Other", - }; - *counts.entry(kind).or_default() += 1; - - let c = e.common(); - let extra = match e { - EntityType::Insert(i) => format!(" β†’ block=\"{}\"", i.block_name), - _ => String::new(), - }; - let line = format!( - " [{:?}] layer=\"{}\" lt=\"{}\" lt_scale={:.4}{}", - e.common().handle, c.layer, c.linetype, c.linetype_scale, extra - ); - let bucket = sample_by_kind.entry(kind).or_default(); - if bucket.len() < 4 { - bucket.push(line); - } - } - - println!("─── entity counts in block ──────────────"); - for (k, v) in &counts { - println!(" {:<12} {}", k, v); - } - println!(); - for (k, samples) in &sample_by_kind { - println!("─── sample {} (first {}) ────────", k, samples.len()); - for s in samples { - println!("{}", s); - } - println!(); - } - - println!("─── relevant layers ─────────────────────"); - let mut seen: std::collections::BTreeSet = Default::default(); - for e in doc.entities() { - if e.common().owner_handle == br.handle { - seen.insert(e.common().layer.clone()); - } - } - for layer_name in &seen { - if let Some(l) = doc.layers.get(layer_name) { - println!( - " \"{}\" lt=\"{}\" off={} frozen={}", - l.name, l.line_type, l.flags.off, l.flags.frozen - ); - } - } - - println!(); - println!("─── linetype table (dashed only) ────────"); - for lt in doc.line_types.iter() { - if lt.elements.is_empty() || lt.is_continuous() { - continue; - } - let elems: Vec = lt.elements.iter().map(|el| el.length).collect(); - println!( - " {:<24} pattern_len={:.4} elements={:?}", - lt.name, lt.pattern_length, elems - ); - } - - Ok(()) -} diff --git a/examples/inspect_insert.rs b/examples/inspect_insert.rs deleted file mode 100644 index e36437c2..00000000 --- a/examples/inspect_insert.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Lists every Insert in the doc (after xref resolve) with sub-entity counts. -// cargo run --release --example inspect_insert -- -use acadrust::entities::EntityType; -use acadrust::io::dwg::DwgReader; - -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).unwrap(); - let mut doc = DwgReader::from_file(&path)?.read()?; - if let Some(base) = std::path::Path::new(&path).parent() { - let infos = H7CAD::io::xref::resolve_xrefs(&mut doc, base); - for i in &infos { - println!("XREF: {} -> {:?}", i.name, i.status); - } - } - println!("total entities: {}", doc.entities().count()); - - let inserts: Vec<_> = doc - .entities() - .filter_map(|e| if let EntityType::Insert(i) = e { Some(i.clone()) } else { None }) - .collect(); - println!("total inserts: {}", inserts.len()); - - let mut by_block: std::collections::HashMap = std::collections::HashMap::new(); - for i in &inserts { - *by_block.entry(i.block_name.clone()).or_insert(0) += 1; - } - let mut by_block: Vec<_> = by_block.into_iter().collect(); - by_block.sort_by(|a, b| b.1.cmp(&a.1)); - - println!("\ninserts grouped by block_name:"); - for (name, n) in &by_block { - let sub_count = inserts.iter().find(|i| &i.block_name == name) - .map(|i| i.explode_from_document(&doc).len()) - .unwrap_or(0); - let nested = doc.block_records.get(name) - .map(|br| br.entity_handles.iter() - .filter(|h| matches!(doc.get_entity(**h), Some(EntityType::Insert(_)))) - .count()) - .unwrap_or(0); - println!(" {:>4} Γ— {} (sub={}, nested-inserts={})", n, name, sub_count, nested); - } - Ok(()) -} diff --git a/examples/inspect_lt.rs b/examples/inspect_lt.rs deleted file mode 100644 index f87c1444..00000000 --- a/examples/inspect_lt.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Summarise linetype usage in a DWG/DXF: which layers use which linetype, -// and which entities carry an explicit (non-bylayer) dashed linetype. -// -// cargo run --release --example inspect_lt -- - -use acadrust::entities::EntityType; -use acadrust::io::dwg::DwgReader; -use std::collections::BTreeMap; - -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).expect("usage: inspect_lt "); - let doc = DwgReader::from_file(&path)?.read()?; - - println!("─── layers (linetype) ───────────────────"); - let dashed_lts: std::collections::BTreeSet = doc - .line_types - .iter() - .filter(|lt| !lt.elements.is_empty() && !lt.is_continuous()) - .map(|lt| lt.name.clone()) - .collect(); - println!(" dashed linetypes in table: {:?}", dashed_lts); - println!(); - - let mut dashed_layers: BTreeMap = BTreeMap::new(); - for l in doc.layers.iter() { - if dashed_lts.contains(&l.line_type) { - dashed_layers.insert(l.name.clone(), l.line_type.clone()); - } - } - println!(" layers using a dashed linetype:"); - if dashed_layers.is_empty() { - println!(" (none)"); - } - for (n, lt) in &dashed_layers { - println!(" \"{}\" β†’ \"{}\"", n, lt); - } - println!(); - - // Per-entity explicit dashed override (lt field non-empty and non-byLayer/byBlock/Continuous). - let mut explicit_dashed: u32 = 0; - let mut by_layer_in_dashed_layer: u32 = 0; - let mut by_layer_in_continuous: u32 = 0; - let mut by_kind: BTreeMap<&'static str, u32> = BTreeMap::new(); - let mut sample_explicit: Vec = vec![]; - let mut sample_layer_inh: Vec = vec![]; - - for e in doc.entities() { - let c = e.common(); - let kind: &'static str = match e { - EntityType::Line(_) => "Line", - EntityType::LwPolyline(_) => "LwPolyline", - EntityType::Polyline(_) => "Polyline", - EntityType::Polyline2D(_) => "Polyline2D", - EntityType::Arc(_) => "Arc", - EntityType::Circle(_) => "Circle", - EntityType::Spline(_) => "Spline", - EntityType::Ellipse(_) => "Ellipse", - EntityType::Insert(_) => "Insert", - _ => "Other", - }; - let lt = c.linetype.trim(); - let lt_norm = lt.to_ascii_lowercase(); - let is_bylayer = lt.is_empty() || lt_norm == "bylayer"; - let is_explicit_dashed = !is_bylayer - && lt_norm != "byblock" - && lt_norm != "continuous" - && dashed_lts.iter().any(|d| d.eq_ignore_ascii_case(lt)); - if is_explicit_dashed { - explicit_dashed += 1; - *by_kind.entry(kind).or_default() += 1; - if sample_explicit.len() < 6 { - sample_explicit.push(format!( - " [{:?}] {} layer=\"{}\" lt=\"{}\" lt_scale={:.4}", - c.handle, kind, c.layer, lt, c.linetype_scale - )); - } - } else if is_bylayer && dashed_layers.contains_key(&c.layer) { - by_layer_in_dashed_layer += 1; - if sample_layer_inh.len() < 6 { - sample_layer_inh.push(format!( - " [{:?}] {} layer=\"{}\" (inherits \"{}\") lt_scale={:.4}", - c.handle, - kind, - c.layer, - dashed_layers.get(&c.layer).unwrap(), - c.linetype_scale - )); - } - } else if is_bylayer { - by_layer_in_continuous += 1; - } - } - - println!("─── entities w/ explicit dashed lt ──────"); - println!(" total: {}", explicit_dashed); - for (k, v) in &by_kind { - println!(" {}: {}", k, v); - } - for s in &sample_explicit { - println!("{}", s); - } - println!(); - - println!("─── entities inheriting dashed via layer:"); - println!(" total: {}", by_layer_in_dashed_layer); - for s in &sample_layer_inh { - println!("{}", s); - } - println!(); - println!( - "─── entities bylayer/continuous: {}", - by_layer_in_continuous - ); - - Ok(()) -} diff --git a/examples/inspect_polyline.rs b/examples/inspect_polyline.rs deleted file mode 100644 index bd5994f5..00000000 --- a/examples/inspect_polyline.rs +++ /dev/null @@ -1,174 +0,0 @@ -// One-off inspector for diagnosing a DWG: dumps every LwPolyline/Polyline2D/ -// Polyline3D with its elevation, normal vector, and per-vertex coordinates. -// Run with: cargo run --example inspect_polyline -- - -use acadrust::entities::EntityType; -use acadrust::io::dwg::DwgReader; -use acadrust::DxfReader; -use std::env; - -fn main() -> Result<(), Box> { - let path = env::args().nth(1).ok_or("usage: inspect_polyline ")?; - let mut doc = if path.to_lowercase().ends_with(".dxf") { - DxfReader::from_file(&path)?.read()? - } else { - DwgReader::from_file(&path)?.read()? - }; - - // Cheap inline corruption check β€” mirrors the rules in src/io/mod.rs so the - // example reports the same drop count without needing a library crate. - let total = doc.entities().count(); - let bad = doc - .entities() - .filter(|e| { - use acadrust::entities::EntityType as E; - const MAX: usize = 100_000; - let bad_normal = |n: &acadrust::types::Vector3| { - !n.x.is_finite() - || !n.y.is_finite() - || !n.z.is_finite() - || ((n.x * n.x + n.y * n.y + n.z * n.z) - 1.0).abs() >= 0.21 - }; - match e { - E::LwPolyline(p) => { - bad_normal(&p.normal) - || p.vertices.len() > MAX - || !p.elevation.is_finite() - || p.elevation.abs() > 1e10 - } - E::Polyline2D(p) => { - bad_normal(&p.normal) - || p.vertices.len() > MAX - || !p.elevation.is_finite() - || p.elevation.abs() > 1e10 - } - _ => false, - } - }) - .count(); - println!("Entities: total={} corrupt={}", total, bad); - println!(); - let _ = &mut doc; // silence unused-mut warning if we don't mutate below - - let h = &doc.header; - println!( - "Header extents: min=({:.3},{:.3},{:.3}) max=({:.3},{:.3},{:.3})", - h.model_space_extents_min.x, - h.model_space_extents_min.y, - h.model_space_extents_min.z, - h.model_space_extents_max.x, - h.model_space_extents_max.y, - h.model_space_extents_max.z, - ); - println!(); - - let mut lwp = 0usize; - let mut p2d = 0usize; - let mut p3d = 0usize; - let mut pl = 0usize; - - for (i, e) in doc.entities().enumerate() { - match e { - EntityType::LwPolyline(p) => { - lwp += 1; - if p.common.layer != "PLN_Sev" { - continue; - } - let nx_abs = p.normal.x.abs(); - let ny_abs = p.normal.y.abs(); - let corrupt = !nx_abs.is_finite() - || nx_abs > 1.0 - || ny_abs > 1.0 - || p.vertices.len() > 1000; - if corrupt { - println!( - "[{}] CORRUPT handle={:?} verts={} elev={:.3e} normal=({:.2e},{:.2e},{:.2e})", - i, - p.common.handle, - p.vertices.len(), - p.elevation, - p.normal.x, - p.normal.y, - p.normal.z, - ); - } else { - println!( - "[{}] OK handle={:?} verts={} elev={:.3} normal=({:.4},{:.4},{:.4})", - i, - p.common.handle, - p.vertices.len(), - p.elevation, - p.normal.x, - p.normal.y, - p.normal.z, - ); - for (vi, v) in p.vertices.iter().take(3).enumerate() { - println!(" v{}: ({:.3}, {:.3}) bulge={}", vi, v.location.x, v.location.y, v.bulge); - } - } - } - EntityType::Polyline2D(p) => { - p2d += 1; - if p2d <= 5 { - println!( - "[{}] Polyline2D handle={:?} layer={:?}", - i, p.common.handle, p.common.layer - ); - println!( - " elevation={} thickness={} normal=({},{},{})", - p.elevation, p.thickness, p.normal.x, p.normal.y, p.normal.z - ); - println!(" closed={} verts={}", p.is_closed(), p.vertices.len()); - for (vi, v) in p.vertices.iter().enumerate() { - println!( - " v{}: ({}, {}, {}) bulge={}", - vi, v.location.x, v.location.y, v.location.z, v.bulge - ); - } - println!(); - } - } - EntityType::Polyline3D(p) => { - p3d += 1; - if p3d <= 5 { - println!( - "[{}] Polyline3D handle={:?} layer={:?}", - i, p.common.handle, p.common.layer - ); - println!(" closed={} verts={}", p.is_closed(), p.vertices.len()); - for (vi, v) in p.vertices.iter().enumerate() { - println!( - " v{}: ({}, {}, {})", - vi, v.position.x, v.position.y, v.position.z - ); - } - println!(); - } - } - EntityType::Polyline(p) => { - pl += 1; - if pl <= 5 { - println!( - "[{}] Polyline (heavy 3D) handle={:?} layer={:?}", - i, p.common.handle, p.common.layer - ); - println!(" closed={} verts={}", p.flags.is_closed(), p.vertices.len()); - for (vi, v) in p.vertices.iter().enumerate() { - println!( - " v{}: ({}, {}, {})", - vi, v.location.x, v.location.y, v.location.z - ); - } - println!(); - } - } - _ => {} - } - } - - println!( - "Totals: LwPolyline={} Polyline2D={} Polyline3D={} Polyline={}", - lwp, p2d, p3d, pl - ); - Ok(()) -} diff --git a/examples/inspect_viewports.rs b/examples/inspect_viewports.rs deleted file mode 100644 index 328c5e0d..00000000 --- a/examples/inspect_viewports.rs +++ /dev/null @@ -1,126 +0,0 @@ -// Dumps every paper-space viewport's view fields from a DWG/DXF. -// cargo run --release --example inspect_viewports -- -use acadrust::entities::EntityType; -use acadrust::io::dwg::DwgReader; - -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).expect("usage: inspect_viewports "); - let doc = DwgReader::from_file(&path)?.read()?; - println!("file: {}", path); - println!("total entities: {}", doc.entities().count()); - let unit_name = match doc.header.insertion_units { - 0 => "Unitless", - 1 => "Inches", - 2 => "Feet", - 3 => "Miles", - 4 => "Millimeters", - 5 => "Centimeters", - 6 => "Meters", - 7 => "Kilometers", - _ => "Other", - }; - println!( - "header.insertion_units = {} ({})", - doc.header.insertion_units, unit_name - ); - println!( - "header.model_space_extents min=({:.3}, {:.3}, {:.3}) max=({:.3}, {:.3}, {:.3})", - doc.header.model_space_extents_min.x, - doc.header.model_space_extents_min.y, - doc.header.model_space_extents_min.z, - doc.header.model_space_extents_max.x, - doc.header.model_space_extents_max.y, - doc.header.model_space_extents_max.z, - ); - println!(); - - let viewports: Vec<_> = doc - .entities() - .filter_map(|e| { - if let EntityType::Viewport(v) = e { - Some(v.clone()) - } else { - None - } - }) - .collect(); - println!("viewports: {}\n", viewports.len()); - - for (i, vp) in viewports.iter().enumerate() { - let scale_from_view_height = if vp.view_height.abs() > 1e-9 { - vp.height / vp.view_height - } else { - f64::NAN - }; - println!( - "[{}] id={} handle={:?}", - i, vp.id, vp.common.handle - ); - println!( - " paper center=({:.3}, {:.3}) size={:.3} Γ— {:.3}", - vp.center.x, vp.center.y, vp.width, vp.height - ); - println!( - " view_target=({:.3}, {:.3}, {:.3})", - vp.view_target.x, vp.view_target.y, vp.view_target.z - ); - println!( - " view_direction=({:.3}, {:.3}, {:.3})", - vp.view_direction.x, vp.view_direction.y, vp.view_direction.z - ); - println!( - " view_center=({:.3}, {:.3})", - vp.view_center.x, vp.view_center.y - ); - println!( - " view_height={:.6} == vp.height? {} β‡’ height/view_height = {:.6}", - vp.view_height, - (vp.view_height - vp.height).abs() < 1e-6, - scale_from_view_height - ); - println!( - " custom_scale={:.6} twist={:.4} lens={:.2}", - vp.custom_scale, vp.twist_angle, vp.lens_length - ); - println!( - " status: on={}, locked={}, perspective={}", - vp.status.is_on, vp.status.locked, vp.status.perspective - ); - println!(); - } - - // Summary stats - let n_with_view_eq_height = viewports - .iter() - .filter(|v| (v.view_height - v.height).abs() < 1e-6) - .count(); - let n_with_target_zero = viewports - .iter() - .filter(|v| { - v.view_target.x.abs() < 1e-9 - && v.view_target.y.abs() < 1e-9 - && v.view_target.z.abs() < 1e-9 - }) - .count(); - let unique_view_heights: std::collections::BTreeSet = viewports - .iter() - .map(|v| v.view_height.to_bits()) - .collect(); - - println!("─────── summary ───────"); - println!( - " view_height == vp.height : {}/{}", - n_with_view_eq_height, - viewports.len() - ); - println!( - " view_target == (0, 0, 0) : {}/{}", - n_with_target_zero, - viewports.len() - ); - println!( - " unique view_height values : {}", - unique_view_heights.len() - ); - Ok(()) -} diff --git a/examples/time_open.rs b/examples/time_open.rs deleted file mode 100644 index bba5940e..00000000 --- a/examples/time_open.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Times each open phase: parse / purge / derived caches. -// Run with: cargo run --release --example time_open -- - -use acadrust::entities::EntityType; -use std::env; -use std::path::Path; -use std::time::Instant; -use H7CAD::io::{load_file, purge_corrupt_entities}; -use H7CAD::scene::{build_derived_caches, Scene}; - -fn main() -> Result<(), Box> { - let path = env::args().nth(1).ok_or("usage: time_open ")?; - - let t0 = Instant::now(); - let mut doc = load_file(Path::new(&path))?; - let parse_ms = t0.elapsed().as_millis(); - - let t1 = Instant::now(); - let dropped = purge_corrupt_entities(&mut doc); - let purge_ms = t1.elapsed().as_millis(); - - let t2 = Instant::now(); - let caches = build_derived_caches(&doc); - let caches_ms = t2.elapsed().as_millis(); - - let mut counts = std::collections::HashMap::<&'static str, usize>::new(); - let mut total = 0usize; - for e in doc.entities() { - total += 1; - let tag: &'static str = match e { - EntityType::Line(_) => "Line", - EntityType::Arc(_) => "Arc", - EntityType::Circle(_) => "Circle", - EntityType::LwPolyline(_) => "LwPolyline", - EntityType::Polyline2D(_) => "Polyline2D", - EntityType::Polyline3D(_) => "Polyline3D", - EntityType::Polyline(_) => "Polyline", - EntityType::Hatch(_) => "Hatch", - EntityType::Solid(_) => "Solid", - EntityType::RasterImage(_) => "RasterImage", - EntityType::Solid3D(_) => "Solid3D", - EntityType::Region(_) => "Region", - EntityType::Body(_) => "Body", - EntityType::Text(_) => "Text", - EntityType::MText(_) => "MText", - EntityType::Insert(_) => "Insert", - EntityType::Dimension(_) => "Dimension", - EntityType::Spline(_) => "Spline", - EntityType::Ellipse(_) => "Ellipse", - _ => "_other", - }; - *counts.entry(tag).or_insert(0) += 1; - } - let mut counts: Vec<_> = counts.into_iter().collect(); - counts.sort_by(|a, b| b.1.cmp(&a.1)); - - // Set up a Scene as the UI thread does and time first wire tessellation. - let mut scene = Scene::new(); - scene.document = doc; - scene.world_offset = caches.world_offset; - scene.local_extent_max = caches.local_extent_max; - scene.hatches = caches.hatches.clone(); - scene.images = caches.images.clone(); - scene.meshes = caches.meshes.clone(); - scene.bump_geometry(); - scene.current_layout = "Model".to_string(); - H7CAD::linetypes::populate_document(&mut scene.document); - - let t3 = Instant::now(); - let wires = scene.entity_wires(); - let wires_ms = t3.elapsed().as_millis(); - - println!("file: {}", path); - println!("parse: {} ms", parse_ms); - println!("purge: {} ms (dropped {})", purge_ms, dropped); - println!("derived caches: {} ms", caches_ms); - println!("first wires: {} ms ({} wires)", wires_ms, wires.len()); - println!(" hatches: {}", caches.hatches.len()); - println!(" images: {}", caches.images.len()); - println!(" meshes: {}", caches.meshes.len()); - println!(); - println!("entities: {}", total); - for (tag, n) in counts.iter().take(20) { - println!(" {:>14} {}", tag, n); - } - Ok(()) -} diff --git a/examples/xref_states.rs b/examples/xref_states.rs deleted file mode 100644 index dff5252a..00000000 --- a/examples/xref_states.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Dump every xref block_record's raw is_loaded bit before any resolve. -// cargo run --release --example xref_states -- -use acadrust::io::dwg::DwgReader; - -fn main() -> Result<(), Box> { - let path = std::env::args().nth(1).unwrap(); - let doc = DwgReader::from_file(&path)?.read()?; - - for br in doc.block_records.iter() { - if br.flags.is_xref || br.flags.is_xref_overlay { - println!( - "name={:<30} is_xref={} overlay={} is_loaded={:?} xref_path={:?} entity_handles={}", - br.name, - br.flags.is_xref, - br.flags.is_xref_overlay, - br.is_loaded, - br.xref_path, - br.entity_handles.len(), - ); - } - } - Ok(()) -} diff --git a/packaging/Info.plist b/packaging/Info.plist index bfd271df..a7f7913f 100644 --- a/packaging/Info.plist +++ b/packaging/Info.plist @@ -5,17 +5,17 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - H7CAD + Open CAD Studio CFBundleExecutable - H7CAD + OpenCADStudio CFBundleIconFile AppIcon CFBundleIdentifier - io.github.HakanSeven12.H7CAD + io.github.HakanSeven12.OpenCadStudio CFBundleInfoDictionaryVersion 6.0 CFBundleName - H7CAD + Open CAD Studio CFBundlePackageType APPL CFBundleShortVersionString diff --git a/packaging/H7CAD.desktop b/packaging/OpenCADStudio.desktop similarity index 65% rename from packaging/H7CAD.desktop rename to packaging/OpenCADStudio.desktop index bdc9a433..6b9fe993 100644 --- a/packaging/H7CAD.desktop +++ b/packaging/OpenCADStudio.desktop @@ -1,11 +1,11 @@ [Desktop Entry] -Name=H7CAD +Name=Open CAD Studio Comment=A CAD application for 2D/3D drawing and design -Exec=H7CAD -Icon=io.github.HakanSeven12.H7CAD +Exec=OpenCADStudio +Icon=io.github.HakanSeven12.OpenCadStudio Terminal=false Type=Application Categories=Graphics;Engineering; MimeType=image/vnd.dxf; Keywords=CAD;DXF;drawing;design;engineering;2D;3D; -StartupWMClass=H7CAD +StartupWMClass=OpenCADStudio diff --git a/src/app/cmd_result.rs b/src/app/cmd_result.rs index 81ae0674..e2732699 100644 --- a/src/app/cmd_result.rs +++ b/src/app/cmd_result.rs @@ -1,9 +1,9 @@ -use super::{Message, H7CAD}; +use super::{Message, OpenCADStudio}; use crate::command::CmdResult; use acadrust::Handle; use iced::Task; -impl H7CAD { +impl OpenCADStudio { pub(super) fn apply_cmd_result(&mut self, result: CmdResult) -> Task { let i = self.active_tab; match result { diff --git a/src/app/commands.rs b/src/app/commands.rs index 41e3e1b2..8736e748 100644 --- a/src/app/commands.rs +++ b/src/app/commands.rs @@ -1,10 +1,10 @@ -use super::{Message, H7CAD}; +use super::{Message, OpenCADStudio}; use crate::command::CadCommand; use crate::scene::Scene; use iced::Task; use std::path::PathBuf; -impl H7CAD { +impl OpenCADStudio { pub(super) fn dispatch_command(&mut self, cmd: &str) -> Task { let i = self.active_tab; // Cancel any running command before starting a new one. @@ -2524,7 +2524,7 @@ impl H7CAD { } "REPORT" => { - let _ = open::that("https://github.com/HakanSeven12/H7CAD/issues/new"); + let _ = open::that("https://github.com/HakanSeven12/open-cad-studio/issues/new"); self.command_line.push_info("Opening GitHub issue page..."); } @@ -2533,7 +2533,7 @@ impl H7CAD { } "CHANGELOG" => { - let _ = open::that("https://github.com/HakanSeven12/H7CAD/releases"); + let _ = open::that("https://github.com/HakanSeven12/open-cad-studio/releases"); self.command_line.push_info("Opening release notes..."); } @@ -4831,7 +4831,7 @@ impl H7CAD { } } "SET" => { - let app = parts.get(1).copied().unwrap_or("H7CAD"); + let app = parts.get(1).copied().unwrap_or("OpenCADStudio"); let val = parts.get(2).copied().unwrap_or(""); self.push_undo_snapshot(i, "XDATA SET"); for sh in &selected_handles { diff --git a/src/app/helpers.rs b/src/app/helpers.rs index 00e64f6f..e712a5da 100644 --- a/src/app/helpers.rs +++ b/src/app/helpers.rs @@ -229,7 +229,7 @@ pub(super) fn title_case_word(value: &str) -> String { // ── Window icon ──────────────────────────────────────────────────────────── -/// Builds a 32Γ—32 RGBA icon: red background with H7 drawn in white pixels. +/// Builds a 32Γ—32 RGBA icon: red background with OCS drawn in white pixels. pub(super) fn build_window_icon() -> Vec { const W: usize = 32; const SZ: usize = W * W * 4; @@ -261,14 +261,21 @@ pub(super) fn build_window_icon() -> Vec { } } - // H - stroke(&mut px, 4, 5, 4, 26, fg); - stroke(&mut px, 13, 5, 13, 26, fg); - stroke(&mut px, 4, 15, 13, 15, fg); - // 7 - stroke(&mut px, 17, 5, 27, 5, fg); - stroke(&mut px, 27, 5, 20, 26, fg); - stroke(&mut px, 20, 16, 26, 16, fg); + // O + stroke(&mut px, 3, 6, 9, 6, fg); + stroke(&mut px, 3, 25, 9, 25, fg); + stroke(&mut px, 3, 6, 3, 25, fg); + stroke(&mut px, 9, 6, 9, 25, fg); + // C + stroke(&mut px, 12, 6, 18, 6, fg); + stroke(&mut px, 12, 25, 18, 25, fg); + stroke(&mut px, 12, 6, 12, 25, fg); + // S + stroke(&mut px, 21, 6, 27, 6, fg); + stroke(&mut px, 21, 6, 21, 15, fg); + stroke(&mut px, 21, 15, 27, 15, fg); + stroke(&mut px, 27, 15, 27, 25, fg); + stroke(&mut px, 21, 25, 27, 25, fg); px } diff --git a/src/app/history.rs b/src/app/history.rs index 9e3b5d3e..5d22b83b 100644 --- a/src/app/history.rs +++ b/src/app/history.rs @@ -1,7 +1,7 @@ -use super::{document::HistorySnapshot, H7CAD}; +use super::{document::HistorySnapshot, OpenCADStudio}; use std::collections::HashSet; -impl H7CAD { +impl OpenCADStudio { pub(super) fn history_label_from_active_cmd(&self, i: usize, fallback: &'static str) -> String { self.tabs[i] .active_cmd diff --git a/src/app/layers.rs b/src/app/layers.rs index b0b193f0..e914bcf2 100644 --- a/src/app/layers.rs +++ b/src/app/layers.rs @@ -1,7 +1,7 @@ -use super::H7CAD; +use super::OpenCADStudio; use crate::ui; -impl H7CAD { +impl OpenCADStudio { pub(super) fn sync_ribbon_layers(&mut self) { let i = self.active_tab; let active = self.tabs[i].active_layer.clone(); diff --git a/src/app/mod.rs b/src/app/mod.rs index fb2a5467..24861433 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -44,7 +44,7 @@ pub struct OpenProgress { // ── Application state ────────────────────────────────────────────────────── -pub(super) struct H7CAD { +pub(super) struct OpenCADStudio { start: Instant, tabs: Vec, active_tab: usize, @@ -697,7 +697,7 @@ pub enum Message { ObjImportPath(Option), } -impl H7CAD { +impl OpenCADStudio { fn new() -> Self { // Boot with only the Welcome/Start tab. The user creates drawings // explicitly (File β†’ New); we never auto-spawn Drawing1. @@ -855,9 +855,9 @@ impl H7CAD { use std::path::PathBuf; pub fn run() -> iced::Result { - iced::daemon(H7CAD::boot, H7CAD::update, H7CAD::view) - .subscription(H7CAD::subscription) - .title(|state: &H7CAD, window_id: window::Id| { + iced::daemon(OpenCADStudio::boot, OpenCADStudio::update, OpenCADStudio::view) + .subscription(OpenCADStudio::subscription) + .title(|state: &OpenCADStudio, window_id: window::Id| { if Some(window_id) == state.layer_window { return "Layer Properties Manager".into(); } @@ -886,7 +886,7 @@ pub fn run() -> iced::Result { return "Keyboard Shortcuts".into(); } if Some(window_id) == state.about_window { - return "About H7CAD".into(); + return "About Open CAD Studio".into(); } if Some(window_id) == state.update_notice_window { return "Update Available".into(); @@ -900,11 +900,11 @@ pub fn run() -> iced::Result { if let Some(tab) = state.tabs.get(state.active_tab) { let dot = if tab.dirty { "● " } else { "" }; let name = tab.tab_display_name(); - format!("{}H7CAD β€” {}", dot, name) + format!("{}Open CAD Studio β€” {}", dot, name) } else { - "H7CAD".to_string() + "Open CAD Studio".to_string() } }) - .theme(|state: &H7CAD, _| state.active_theme.clone()) + .theme(|state: &OpenCADStudio, _| state.active_theme.clone()) .run() } diff --git a/src/app/properties.rs b/src/app/properties.rs index a8080ef5..8aeaba4f 100644 --- a/src/app/properties.rs +++ b/src/app/properties.rs @@ -1,11 +1,11 @@ use super::helpers::{entity_type_key, entity_type_label, title_case_word}; -use super::{H7CAD, VARIES_LABEL}; +use super::{OpenCADStudio, VARIES_LABEL}; use crate::linetypes; use crate::scene::dispatch; use crate::ui; use acadrust::{EntityType, Handle}; -impl H7CAD { +impl OpenCADStudio { /// Rebuild the PropertiesPanel from the current entity selection. /// Preserves UI state (open pickers, edit buffer) across refreshes. pub(super) fn refresh_properties(&mut self) { diff --git a/src/app/update.rs b/src/app/update.rs index 50407af0..56bdb622 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -1,7 +1,7 @@ use super::helpers::{ angle_close, ortho_constrain, parse_coord, polar_constrain, ucs_to_wcs, ucs_z_axis, }; -use super::{Message, H7CAD, POLY_START_DELAY_MS}; +use super::{Message, OpenCADStudio, POLY_START_DELAY_MS}; use crate::modules::ModuleEvent; use crate::scene::grip::{find_hit_grip, find_hit_grip_paper, GripEdit}; use crate::scene::object::GripApply; @@ -31,7 +31,7 @@ fn format_size(bytes: u64) -> String { } } -impl H7CAD { +impl OpenCADStudio { pub fn update(&mut self, msg: Message) -> Task { match msg { Message::Tick(t) => { @@ -3414,7 +3414,7 @@ impl H7CAD { Message::AboutCopyInfo => { let info = format!( - "H7CAD v{}\nOS: {}\nArch: {}", + "Open CAD Studio v{}\nOS: {}\nArch: {}", env!("CARGO_PKG_VERSION"), std::env::consts::OS, std::env::consts::ARCH, @@ -4826,7 +4826,7 @@ impl H7CAD { // ── DimStyle dialog helpers ───────────────────────────────────────────────── -impl H7CAD { +impl OpenCADStudio { /// Populate all edit buffers from the currently selected dim style. fn load_dimstyle_bufs(&mut self, tab: usize) { let doc = &self.tabs[tab].scene.document; diff --git a/src/app/view.rs b/src/app/view.rs index 9e648c06..c758e146 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -1,7 +1,7 @@ use super::document::DocumentTab; use super::helpers::grid_plane_from_camera; use super::history::history_dropdown_labels; -use super::{Message, H7CAD}; +use super::{Message, OpenCADStudio}; use crate::scene::grip::{grips_to_screen, grips_to_screen_paper}; use crate::scene::paper_canvas::PaperCanvas; use crate::scene::viewport_pane::{PaperViewportPane, ViewportPane}; @@ -16,7 +16,7 @@ use iced::{keyboard, Background, Border, Color, Element, Fill, Subscription, Tas const VIEWCUBE_HIT_SIZE: f32 = VIEWCUBE_DRAW_PX; -impl H7CAD { +impl OpenCADStudio { pub fn view(&self, window_id: window::Id) -> Element<'_, Message> { // ── Floating panel windows ───────────────────────────────────────── if Some(window_id) == self.layer_window { @@ -1594,7 +1594,7 @@ fn unsaved_changes_dialog_window(name: &str) -> Element<'static, Message> { // is the public welcome screen and stays consistent across locales. // // The page picks up the application icon's red-brown (#B03020) as a tint so -// it visually belongs to H7CAD without overpowering the dark workspace. +// it visually belongs to OpenCADStudio without overpowering the dark workspace. const BRAND: Color = Color { r: 0.690, g: 0.188, b: 0.125, a: 1.0 }; // #B03020 const BRAND_DARK: Color = Color { r: 0.45, g: 0.12, b: 0.08, a: 1.0 }; @@ -1605,16 +1605,16 @@ pub(super) fn start_page_view<'a>() -> Element<'a, Message> { const CARD_BG: Color = Color { r: 0.12, g: 0.12, b: 0.13, a: 1.0 }; const CARD_BORDER: Color = Color { r: 0.20, g: 0.20, b: 0.22, a: 1.0 }; - // Brand-tinted "Welcome to" β€” the "H7CAD" word takes the accent colour + // Brand-tinted "Welcome to" β€” the "OpenCADStudio" word takes the accent colour // (Thunderbird-style coloured headline split). let headline = row![ text("Welcome to ").size(40).color(TEXT), - text("H7CAD").size(40).color(BRAND), + text("Open CAD Studio").size(40).color(BRAND), ] .align_y(iced::Center); let subtitle = text( - "H7CAD is an open-source CAD viewer and editor β€” a gift from contributors like you. \ + "Open CAD Studio is an open-source CAD viewer and editor β€” a gift from contributors like you. \ Open a DWG/DXF file, start a new drawing, or help shape what comes next.", ) .size(13) @@ -1728,9 +1728,9 @@ pub(super) fn start_page_view<'a>() -> Element<'a, Message> { let cards = row![ card_section( "Free and open source", - "H7CAD belongs to its users.", + "Open CAD Studio belongs to its users.", "Source is openly developed and distributed under a permissive licence. \ - You are free to use, study, modify, and share H7CAD.", + You are free to use, study, modify, and share Open CAD Studio.", ), card_section( "Community driven", diff --git a/src/io/obj.rs b/src/io/obj.rs index fd92972c..0f56b223 100644 --- a/src/io/obj.rs +++ b/src/io/obj.rs @@ -27,7 +27,7 @@ pub fn parse_obj(src: &str, color: [f32; 4]) -> Option { "v" => { let vals: Vec = parts.filter_map(|s| s.parse().ok()).collect(); if vals.len() >= 3 { - // OBJ: Y-up right-handed. H7CAD viewport is also Y-up β†’ keep as-is. + // OBJ: Y-up right-handed. OpenCADStudio viewport is also Y-up β†’ keep as-is. positions.push([vals[0], vals[1], vals[2]]); } } diff --git a/src/io/pdf_export.rs b/src/io/pdf_export.rs index 943ea794..823ad80c 100644 --- a/src/io/pdf_export.rs +++ b/src/io/pdf_export.rs @@ -78,7 +78,7 @@ fn build_pdf( rotation_deg: i32, plot_style: Option<&PlotStyleTable>, ) -> Vec { - let mut doc = PdfDocument::new("H7CAD Export"); + let mut doc = PdfDocument::new("Open CAD Studio Export"); let mut ops: Vec = Vec::new(); // White page background. diff --git a/src/io/print_to_printer.rs b/src/io/print_to_printer.rs index 14276f4d..5d0b4026 100644 --- a/src/io/print_to_printer.rs +++ b/src/io/print_to_printer.rs @@ -28,7 +28,7 @@ pub async fn print_wires( plot_style: Option, ) -> Result { // ── 1. Write to a named temp file ───────────────────────────────────── - let tmp_path = std::env::temp_dir().join("h7cad_print.pdf"); + let tmp_path = std::env::temp_dir().join("open_cad_studio_print.pdf"); pdf_export::export_pdf( &wires, &hatches, diff --git a/src/io/step.rs b/src/io/step.rs index 12abbd67..fbf73c39 100644 --- a/src/io/step.rs +++ b/src/io/step.rs @@ -199,7 +199,7 @@ pub fn build_step(meshes: &[&MeshModel]) -> Option { let msb_id = alloc(); writeln!( data, - "#{} = MANIFOLD_SOLID_BREP('H7CAD_Solid',#{});", + "#{} = MANIFOLD_SOLID_BREP('OpenCADStudio_Solid',#{});", msb_id, shell_id ) .ok(); @@ -217,7 +217,7 @@ pub fn build_step(meshes: &[&MeshModel]) -> Option { writeln!(data, "#{} = GEOMETRIC_REPRESENTATION_CONTEXT(3);", gc_id).ok(); writeln!( data, - "#{sr_id} = SHAPE_REPRESENTATION('H7CAD_Shape',(#{}),#{gc_id});", + "#{sr_id} = SHAPE_REPRESENTATION('OpenCADStudio_Shape',(#{}),#{gc_id});", msb_id ) .ok(); @@ -227,7 +227,7 @@ pub fn build_step(meshes: &[&MeshModel]) -> Option { let file = format!( "ISO-10303-21;\n\ HEADER;\n\ - FILE_DESCRIPTION(('H7CAD STEP export'),'2;1');\n\ + FILE_DESCRIPTION(('Open CAD Studio STEP export'),'2;1');\n\ FILE_NAME('{ts}','','',(''),'',' ',' ');\n\ FILE_SCHEMA(('CONFIG_CONTROL_DESIGN'));\n\ ENDSEC;\n\ diff --git a/src/io/stl.rs b/src/io/stl.rs index e45d4135..c34b10e0 100644 --- a/src/io/stl.rs +++ b/src/io/stl.rs @@ -67,7 +67,7 @@ pub fn build_stl(meshes: &[&MeshModel]) -> Option> { // 80-byte header. let mut header = [0u8; 80]; - let title = b"H7CAD STL export"; + let title = b"Open CAD Studio STL export"; header[..title.len()].copy_from_slice(title); buf.extend_from_slice(&header); diff --git a/src/linetypes.rs b/src/linetypes.rs index 356720ac..e7b0286a 100644 --- a/src/linetypes.rs +++ b/src/linetypes.rs @@ -1,4 +1,4 @@ -//! H7CAD linetype catalog β€” loaded from `assets/linetypes/H7CAD.lin`. +//! OpenCADStudio linetype catalog β€” loaded from `assets/linetypes/OpenCADStudio.lin`. //! //! Call [`populate_document`] to add all standard linetypes to a new document. //! Linetypes that already exist in the document are skipped. @@ -68,7 +68,7 @@ pub fn complex_lt(name: &str) -> Option<&'static ComplexLt> { .get(&name.to_ascii_uppercase()) } -const LIN_SOURCE: &str = include_str!("../assets/linetypes/H7CAD.lin"); +const LIN_SOURCE: &str = include_str!("../assets/linetypes/OpenCADStudio.lin"); // ── Pattern art extraction ──────────────────────────────────────────────── @@ -93,7 +93,7 @@ pub fn extract_pattern(desc: &str) -> String { // ── Public API ──────────────────────────────────────────────────────────── -/// Add all standard H7CAD linetypes to `doc`, skipping existing ones. +/// Add all standard OpenCADStudio linetypes to `doc`, skipping existing ones. pub fn populate_document(doc: &mut CadDocument) { for mut lt in parse(LIN_SOURCE) { if !doc.line_types.contains(<.name) { diff --git a/src/modules/home/draw/arc.rs b/src/modules/home/draw/arc.rs index 4f6675a2..f9212a70 100644 --- a/src/modules/home/draw/arc.rs +++ b/src/modules/home/draw/arc.rs @@ -1,4 +1,4 @@ -// Arc tool β€” ribbon dropdown + all H7CAD arc creation methods. +// Arc tool β€” ribbon dropdown + all OpenCADStudio arc creation methods. // // Methods: // ARC β€” Center, Start, End (CSE β€” default) diff --git a/src/modules/home/draw/circle.rs b/src/modules/home/draw/circle.rs index fabdcc6a..efc7b54e 100644 --- a/src/modules/home/draw/circle.rs +++ b/src/modules/home/draw/circle.rs @@ -1,4 +1,4 @@ -// Circle tool β€” ribbon dropdown + all H7CAD circle creation methods. +// Circle tool β€” ribbon dropdown + all OpenCADStudio circle creation methods. // // Methods: // CIRCLE β€” Center, Radius (default) diff --git a/src/modules/home/draw/ellipse.rs b/src/modules/home/draw/ellipse.rs index 8593ac87..9b9648e1 100644 --- a/src/modules/home/draw/ellipse.rs +++ b/src/modules/home/draw/ellipse.rs @@ -1,4 +1,4 @@ -// Ellipse tool β€” ribbon dropdown + all H7CAD ellipse creation methods. +// Ellipse tool β€” ribbon dropdown + all OpenCADStudio ellipse creation methods. // // Commands: // ELLIPSE β€” Center, Axes (center β†’ major endpoint β†’ minor distance) diff --git a/src/modules/home/draw/hatch.rs b/src/modules/home/draw/hatch.rs index 8dced9ed..2936e210 100644 --- a/src/modules/home/draw/hatch.rs +++ b/src/modules/home/draw/hatch.rs @@ -1,11 +1,11 @@ -// Hatch/Gradient/Boundary commands β€” H7CAD Home > Draw > Hatch dropdown. +// Hatch/Gradient/Boundary commands β€” OpenCADStudio Home > Draw > Hatch dropdown. // // Commands: // HATCH β€” ANSI31: 45Β° hatch lines (pick inside or type S for manual) // GRADIENT β€” Linear gradient fill (pick inside or type S for manual) // BOUNDARY β€” Traces the enclosing boundary as a closed LwPolyline // -// Primary workflow (matches H7CAD): +// Primary workflow (matches OpenCADStudio): // Click a point INSIDE a closed region β†’ boundary auto-detected. // Type "S" to switch to manual vertex-picking mode (HATCH/GRADIENT only). diff --git a/src/modules/home/draw/line.rs b/src/modules/home/draw/line.rs index 922076db..dfc3e4be 100644 --- a/src/modules/home/draw/line.rs +++ b/src/modules/home/draw/line.rs @@ -1,6 +1,6 @@ // Line tool β€” ribbon definition + interactive command. // -// Command: LINE β€” H7CAD behaviour: +// Command: LINE β€” OpenCADStudio behaviour: // 1. First click β†’ stores start point, prompts for next point // 2. Each further click β†’ immediately commits an acadrust::Line entity // (startβ†’end) to the document; end becomes the new start point diff --git a/src/modules/insert/solid3d_cmds.rs b/src/modules/insert/solid3d_cmds.rs index 1b72ca75..1ad96ed6 100644 --- a/src/modules/insert/solid3d_cmds.rs +++ b/src/modules/insert/solid3d_cmds.rs @@ -9,7 +9,7 @@ // the mesh because the ACIS data is empty. Full ACIS generation requires // a separate step (out of scope here). // -// Coordinate convention in H7CAD: the viewport is Y-up (OpenGL style), +// Coordinate convention in OpenCADStudio: the viewport is Y-up (OpenGL style), // so screen Xβ†’DXF X, screen Zβ†’DXF Y, screen Yβ†’DXF Z (height). // truck works in standard math coordinates; we map accordingly. @@ -134,7 +134,7 @@ impl CadCommand for BoxCommand { } fn commit_box(p1: Vec3, p2: Vec3, height: f32, color: [f32; 4]) -> CmdResult { - // Map H7CAD coords to truck: xβ†’x, zβ†’y, yβ†’z + // Map OpenCADStudio coords to truck: xβ†’x, zβ†’y, yβ†’z let x0 = p1.x.min(p2.x) as f64; let y0 = p1.z.min(p2.z) as f64; let x1 = p1.x.max(p2.x) as f64; diff --git a/src/patterns.rs b/src/patterns.rs index c26b16bc..5ffd20b4 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -1,4 +1,4 @@ -//! H7CAD hatch pattern catalog β€” loaded from `assets/patterns/H7CAD.pat`. +//! OpenCADStudio hatch pattern catalog β€” loaded from `assets/patterns/OpenCADStudio.pat`. //! //! PAT line format: `angle, x0, y0, dx, dy [, dash1, dash2, ...]` //! - `angle` line direction in degrees @@ -8,7 +8,7 @@ use std::sync::OnceLock; -const PAT_SRC: &str = include_str!("../assets/patterns/H7CAD.pat"); +const PAT_SRC: &str = include_str!("../assets/patterns/OpenCADStudio.pat"); // ── Public types ────────────────────────────────────────────────────────── diff --git a/src/scene/camera.rs b/src/scene/camera.rs index f36877c7..a0b04fcc 100644 --- a/src/scene/camera.rs +++ b/src/scene/camera.rs @@ -9,7 +9,7 @@ // Zoom: adjusts `distance` (exponential feel). // Snap: directly assigns yaw+pitch encoded as a quaternion (for ViewCube). // -// Coordinate convention: Z-up world space (same as the rest of H7CAD). +// Coordinate convention: Z-up world space (same as the rest of OpenCADStudio). use glam::{vec3, Mat4, Quat, Vec3}; use iced::{Point, Rectangle}; diff --git a/src/scene/grip.rs b/src/scene/grip.rs index 5088a765..6be197b8 100644 --- a/src/scene/grip.rs +++ b/src/scene/grip.rs @@ -1,4 +1,4 @@ -//! H7CAD-style grip editing. +//! OpenCADStudio-style grip editing. use acadrust::Handle; use glam::{Mat4, Vec3}; @@ -13,7 +13,7 @@ pub const GRIP_HALF_PX: f32 = 5.0; // ── Active drag state ───────────────────────────────────────────────────── -/// Stored on `H7CAD` while a grip is being dragged. +/// Stored on `OpenCADStudio` while a grip is being dragged. #[derive(Clone, Debug)] pub struct GripEdit { /// Handle of the entity being edited. diff --git a/src/scene/hatch_patterns.rs b/src/scene/hatch_patterns.rs index f9981ac1..d1bb6ef1 100644 --- a/src/scene/hatch_patterns.rs +++ b/src/scene/hatch_patterns.rs @@ -1,4 +1,4 @@ -// H7CAD hatch pattern catalog β€” built from `assets/patterns/H7CAD.pat`. +// OpenCADStudio hatch pattern catalog β€” built from `assets/patterns/OpenCADStudio.pat`. // // Each `PatternEntry` wraps a parsed PAT pattern with: // - `gpu` β€” `HatchPattern::Pattern(families)` for the shader diff --git a/src/scene/mod.rs b/src/scene/mod.rs index bfccc54c..3fce3176 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -3914,7 +3914,7 @@ impl Scene { .document .views .iter() - .find(|v| v.name == "H7CAD_Camera_Model") + .find(|v| v.name == "OpenCADStudio_Camera_Model") .cloned(); if let Some(view) = saved_view { return self.apply_camera_from_view_entry(&view, true); @@ -3978,7 +3978,7 @@ impl Scene { /// Returns true if a valid sheet viewport was found and the camera was set. fn apply_sheet_viewport_camera(&mut self) -> bool { // Prefer our named View entry β€” survives DWG save without being overridden. - let view_name = format!("H7CAD_Camera_{}", self.current_layout); + let view_name = format!("OpenCADStudio_Camera_{}", self.current_layout); let saved_view = self .document .views @@ -4094,7 +4094,7 @@ impl Scene { } // Also write to View table β€” survives DWG save without override. - self.write_camera_view_entry("H7CAD_Camera_Model", target_wcs, vd3, view_height); + self.write_camera_view_entry("OpenCADStudio_Camera_Model", target_wcs, vd3, view_height); true } else { let target_wcs = acadrust::types::Vector3 { @@ -4102,7 +4102,7 @@ impl Scene { y: cam.target.y as f64, z: cam.target.z as f64, }; - let view_name = format!("H7CAD_Camera_{}", self.current_layout); + let view_name = format!("OpenCADStudio_Camera_{}", self.current_layout); // Write back to the sheet viewport entity. let layout_block = self.current_layout_block_handle(); diff --git a/src/scene/pipeline/viewcube.rs b/src/scene/pipeline/viewcube.rs index fa7a2b35..2ba0685f 100644 --- a/src/scene/pipeline/viewcube.rs +++ b/src/scene/pipeline/viewcube.rs @@ -1,4 +1,4 @@ -// ViewCube wgpu pipeline β€” H7CAD-style interactive 3D navigation cube. +// ViewCube wgpu pipeline β€” OpenCADStudio-style interactive 3D navigation cube. // // 26 selectable regions: 6 faces + 12 edges + 8 corners. // Phong shading + hover highlight passed as uniform. diff --git a/src/snap/mod.rs b/src/snap/mod.rs index 0a5f611c..724ac6ac 100644 --- a/src/snap/mod.rs +++ b/src/snap/mod.rs @@ -1,4 +1,4 @@ -//! H7CAD-style object snap (OSNAP) engine. +//! OpenCADStudio-style object snap (OSNAP) engine. //! //! Implemented modes: //! Endpoint, Midpoint, Center, Node, Quadrant, Intersection, @@ -13,7 +13,7 @@ use crate::ui::overlay::CROSSHAIR_ARM; // ── Snap type ───────────────────────────────────────────────────────────── -/// Every OSNAP mode β€” mirrors the H7CAD list. +/// Every OSNAP mode β€” mirrors the OpenCADStudio list. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum SnapType { Endpoint, diff --git a/src/ui/about.rs b/src/ui/about.rs index f86ce9d6..4e2cd461 100644 --- a/src/ui/about.rs +++ b/src/ui/about.rs @@ -57,7 +57,7 @@ pub fn view_window<'a>() -> Element<'a, Message> { let logo = container( column![ - text("H7CAD").size(32).color(ACCENT), + text("Open CAD Studio").size(32).color(ACCENT), text("CAD application for Architecture & Engineering") .size(11) .color(DIM), diff --git a/src/ui/app_menu.rs b/src/ui/app_menu.rs index fa7861ef..9095e99c 100644 --- a/src/ui/app_menu.rs +++ b/src/ui/app_menu.rs @@ -1,4 +1,4 @@ -//! Application menu β€” H7CAD-style dropdown that opens when the H7 logo +//! Application menu β€” OpenCADStudio-style dropdown that opens when the OCS logo //! button is clicked. Overlays the entire viewport as a floating panel. //! //! Layout: @@ -235,7 +235,7 @@ impl AppMenu { let bottom = container( row![ iced::widget::Space::new().width(Length::Fill), - button(text("Exit H7CAD").size(11).color(Color::WHITE)) + button(text("Exit Open CAD Studio").size(11).color(Color::WHITE)) .on_press(Message::Command("EXIT".into())) .style(|_: &Theme, status| button::Style { background: Some(Background::Color(match status { @@ -299,7 +299,7 @@ impl AppMenu { // Backdrop β€” clicking outside closes the menu. let backdrop = button( container(panel) - // Offset so the panel sits just below the ribbon H7 button. + // Offset so the panel sits just below the ribbon OCS button. .padding(iced::Padding { top: 56.0, left: 0.0, @@ -521,7 +521,7 @@ fn recents_file_path() -> Option { p }; let mut p = base; - p.push("H7CAD"); + p.push("OpenCADStudio"); Some(p.join("recent.txt")) } diff --git a/src/ui/command_line.rs b/src/ui/command_line.rs index 41521bac..32ac0fe8 100644 --- a/src/ui/command_line.rs +++ b/src/ui/command_line.rs @@ -1,4 +1,4 @@ -//! H7CAD-style command line β€” bottom panel with input and history +//! OpenCADStudio-style command line β€” bottom panel with input and history use crate::app::Message; use iced::widget::{column, container, row, text, text_input}; @@ -41,7 +41,7 @@ pub enum EntryKind { impl CommandLine { pub fn new() -> Self { let mut cl = Self::default(); - cl.push_info("H7CAD ready."); + cl.push_info("Open CAD Studio ready."); cl.push_info("Type a command or use the ribbon. Open OBJ: INSERT tab."); cl } diff --git a/src/ui/properties.rs b/src/ui/properties.rs index d72c3d3f..71ac2b00 100644 --- a/src/ui/properties.rs +++ b/src/ui/properties.rs @@ -1,4 +1,4 @@ -//! Properties panel β€” H7CAD-style editable object properties. +//! Properties panel β€” OpenCADStudio-style editable object properties. //! //! Shows two sections (General + Geometry) for the selected entity. //! β€’ Layer β†’ combo_box (options from document layer table) diff --git a/src/ui/snap_popup.rs b/src/ui/snap_popup.rs index f9b96d15..a8aef1af 100644 --- a/src/ui/snap_popup.rs +++ b/src/ui/snap_popup.rs @@ -1,4 +1,4 @@ -//! H7CAD-style OSNAP dropdown popup panel. +//! OpenCADStudio-style OSNAP dropdown popup panel. //! //! Rendered as a floating overlay above the status bar. The popup is only //! inserted into the view stack when `snap_popup_open` is true. diff --git a/src/ui/update_notice.rs b/src/ui/update_notice.rs index 5fa8c9c7..92b360c0 100644 --- a/src/ui/update_notice.rs +++ b/src/ui/update_notice.rs @@ -140,7 +140,7 @@ pub fn view_window<'a>(latest: &'a str, body: &'a str) -> Element<'a, Message> { let header = container( column![ text("New Release Available").size(20).color(ACCENT), - text("A newer H7CAD version is published on GitHub.") + text("A newer Open CAD Studio version is published on GitHub.") .size(11) .color(DIM), ] diff --git a/src/update_check.rs b/src/update_check.rs index 87582ffb..58889c84 100644 --- a/src/update_check.rs +++ b/src/update_check.rs @@ -7,9 +7,9 @@ // `None` when up to date / on network failure / on parse error. const RELEASES_API: &str = - "https://api.github.com/repos/HakanSeven12/H7CAD/releases/latest"; + "https://api.github.com/repos/HakanSeven12/open-cad-studio/releases/latest"; pub const RELEASES_PAGE: &str = - "https://github.com/HakanSeven12/H7CAD/releases/latest"; + "https://github.com/HakanSeven12/open-cad-studio/releases/latest"; /// What `check_for_update` reports when a newer release exists. #[derive(Debug, Clone)] @@ -33,7 +33,7 @@ fn fetch_latest_if_outdated() -> Option { .timeout(std::time::Duration::from_secs(5)) .build() .get(RELEASES_API) - .set("User-Agent", concat!("h7cad/", env!("CARGO_PKG_VERSION"))) + .set("User-Agent", concat!("OpenCADStudio/", env!("CARGO_PKG_VERSION"))) .set("Accept", "application/vnd.github+json") .call() .ok()?