Import FreeCAD and Rhino files through cadmpeg (#1435)
FreeCAD .FCStd and Rhino .3dm files open, insert and drop like STEP and IGES: cadmpeg (Apache-2.0, pinned =0.6.1, native builds only) detects the format, decodes it under its service resource caps, validates the model and writes it as STEP AP214, which becomes an Import feature in a new component named after the file, with the up and names options. Only the fcstd, rhino and step codecs are compiled in (no default features). ACIS is left out: cadmpeg's sat codec is a ShapeManager stream decoder. native_cad.rs is the single importer seam. Self-made FreeCAD and Rhino box fixtures, hostile-input, ZIP-bomb and cap tests, engine tests for the component path; the browser build reports these formats as not supported. A note under design format 23 says an Import's file can name these formats. Co-authored-by: Jacob Oursland <jacob.oursland@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2b45635d73
commit
78242d67d1
23 files changed
+1585
-328
No files matched your search
+16
-10
@@ -1,8 +1,8 @@
|
||||
//! File formats. Designs use JSON or versioned containers (`.solidcraft`); the authoritative
|
||||
//! document rebuilds on load and optional display caches remain provisional. Bodies export
|
||||
//! as STL (binary or ASCII), OBJ, STEP and 3MF, and assemblies as URDF ([`urdf()`]); STEP
|
||||
//! files import as a base feature (see [`step_import_feature`]), 3MF and STL files as mesh bodies
|
||||
//! (see [`mesh_import_feature`]).
|
||||
//! as STL (binary or ASCII), OBJ, STEP and 3MF, and assemblies as URDF ([`urdf()`]); STEP, IGES,
|
||||
//! FreeCAD and Rhino files import as a base feature (see [`step_import_feature`]), 3MF and
|
||||
//! STL files as mesh bodies (see [`mesh_import_feature`]).
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
@@ -18,6 +18,8 @@ pub use design::{
|
||||
write_design_container_with_thumbnail,
|
||||
};
|
||||
mod legacy_dir;
|
||||
mod native_cad;
|
||||
pub use native_cad::{NATIVE_CAD_EXTS, is_native_cad_path, native_cad_to_step};
|
||||
pub mod safe_write;
|
||||
mod sketch2d;
|
||||
mod svg;
|
||||
@@ -78,13 +80,14 @@ pub type Result<T> = std::result::Result<T, IoError>;
|
||||
/// Largest STEP file we read.
|
||||
pub const MAX_STEP_BYTES: usize = 512 << 20;
|
||||
|
||||
/// Is this a CAD exchange file read as an Import base feature: STEP (`.step` / `.stp`) or IGES
|
||||
/// (`.igs` / `.iges`), any case?
|
||||
/// Is this a CAD file read as an Import base feature: STEP (`.step` / `.stp`), IGES
|
||||
/// (`.igs` / `.iges`) or a format read through cadmpeg ([`is_native_cad_path`]), any case?
|
||||
pub fn is_step_path(path: &str) -> bool {
|
||||
std::path::Path::new(path)
|
||||
.extension()
|
||||
.and_then(|e| e.to_str())
|
||||
.is_some_and(|e| ["step", "stp", "igs", "iges"].iter().any(|x| e.eq_ignore_ascii_case(x)))
|
||||
|| is_native_cad_path(path)
|
||||
}
|
||||
|
||||
/// Is this an IGES file name (`.igs` / `.iges`, any case)?
|
||||
@@ -162,11 +165,14 @@ pub fn step_import_feature_named(bytes: &[u8], file: &str, names: StepNames) ->
|
||||
if bytes.len() > MAX_STEP_BYTES {
|
||||
return Err(IoError::Invalid(format!("STEP file too large ({} MB, limit {} MB)", bytes.len() >> 20, MAX_STEP_BYTES >> 20)));
|
||||
}
|
||||
// STEP is 7-bit text with escapes; tolerate stray 8-bit bytes. IGES is restated as STEP
|
||||
// (the feature keeps that STEP text).
|
||||
let text = String::from_utf8_lossy(bytes).into_owned();
|
||||
let (text, iges_warnings) =
|
||||
if is_iges_path(file) { solidcraft_kernel::iges_to_step(&text).map_err(IoError::Invalid)? } else { (text, Vec::new()) };
|
||||
// STEP is 7-bit text with escapes; tolerate stray 8-bit bytes. IGES and the cadmpeg formats
|
||||
// are restated as STEP (the feature keeps that STEP text).
|
||||
let (text, iges_warnings) = if is_native_cad_path(file) {
|
||||
native_cad_to_step(bytes, file).map_err(IoError::Invalid)?
|
||||
} else {
|
||||
let text = String::from_utf8_lossy(bytes).into_owned();
|
||||
if is_iges_path(file) { solidcraft_kernel::iges_to_step(&text).map_err(IoError::Invalid)? } else { (text, Vec::new()) }
|
||||
};
|
||||
let imp = solidcraft_kernel::step_import_shared(&text)?;
|
||||
let stem = std::path::Path::new(file)
|
||||
.file_stem()
|
||||
|
||||
Reference in new issue
Block a user