kittycad_modeling_cmds/format/
mod.rs

1use parse_display_derive::{Display, FromStr};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4
5use crate::shared::{FileExportFormat, FileExportFormat2d, FileImportFormat};
6
7/// AutoCAD drawing interchange format.
8pub mod dxf;
9/// Autodesk Filmbox (FBX) format.
10pub mod fbx;
11/// glTF 2.0.
12/// We refer to this as glTF since that is how our customers refer to it, although by default
13/// it will be in binary format and thus technically (glb).
14/// If you prefer ASCII output, you can set that option for the export.
15pub mod gltf;
16/// Wavefront OBJ format.
17pub mod obj;
18/// The PLY Polygon File Format.
19pub mod ply;
20/// ISO 10303-21 (STEP) format.
21pub mod step;
22/// **ST**ereo**L**ithography format.
23pub mod stl;
24
25/// SolidWorks part (SLDPRT) format.
26pub mod sldprt;
27
28/// Output 2D format specifier.
29#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema, Display, FromStr)]
30#[serde(tag = "type", rename_all = "snake_case")]
31#[display(style = "snake_case")]
32#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
33#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
34pub enum OutputFormat2d {
35    /// AutoCAD drawing interchange format.
36    #[display("{}: {0}")]
37    Dxf(dxf::export::Options),
38}
39
40/// Alias for backward compatibility.
41#[deprecated(since = "0.2.96", note = "use `OutputFormat3d` instead")]
42pub type OutputFormat = OutputFormat3d;
43
44/// Output 3D format specifier.
45#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema, Display, FromStr)]
46#[serde(tag = "type", rename_all = "snake_case")]
47#[display(style = "snake_case")]
48#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
49#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
50pub enum OutputFormat3d {
51    /// Autodesk Filmbox (FBX) format.
52    #[display("{}: {0}")]
53    Fbx(fbx::export::Options),
54    /// glTF 2.0.
55    /// We refer to this as glTF since that is how our customers refer to it, although by default
56    /// it will be in binary format and thus technically (glb).
57    /// If you prefer ASCII output, you can set that option for the export.
58    #[display("{}: {0}")]
59    Gltf(gltf::export::Options),
60    /// Wavefront OBJ format.
61    #[display("{}: {0}")]
62    Obj(obj::export::Options),
63    /// The PLY Polygon File Format.
64    #[display("{}: {0}")]
65    Ply(ply::export::Options),
66    /// ISO 10303-21 (STEP) format.
67    #[display("{}: {0}")]
68    Step(step::export::Options),
69    /// **ST**ereo**L**ithography format.
70    #[display("{}: {0}")]
71    Stl(stl::export::Options),
72}
73
74/// Alias for backward compatibility.
75#[deprecated(since = "0.2.96", note = "use `InputFormat3d` instead")]
76pub type InputFormat = InputFormat3d;
77
78/// Input format specifier.
79#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema, Display, FromStr)]
80#[serde(tag = "type", rename_all = "snake_case")]
81#[display(style = "snake_case")]
82#[cfg_attr(
83    feature = "python",
84    pyo3::pyclass,
85    pyo3_stub_gen::derive::gen_stub_pyclass_complex_enum
86)]
87#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
88#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
89pub enum InputFormat3d {
90    /// Autodesk Filmbox (FBX) format.
91    #[display("{}: {0}")]
92    Fbx(fbx::import::Options),
93    /// Binary glTF 2.0.
94    /// We refer to this as glTF since that is how our customers refer to it,
95    /// but this can also import binary glTF (glb).
96    #[display("{}: {0}")]
97    Gltf(gltf::import::Options),
98    /// Wavefront OBJ format.
99    #[display("{}: {0}")]
100    Obj(obj::import::Options),
101    /// The PLY Polygon File Format.
102    #[display("{}: {0}")]
103    Ply(ply::import::Options),
104    /// SolidWorks part (SLDPRT) format.
105    #[display("{}: {0}")]
106    Sldprt(sldprt::import::Options),
107    /// ISO 10303-21 (STEP) format.
108    #[display("{}: {0}")]
109    Step(step::import::Options),
110    /// **ST**ereo**L**ithography format.
111    #[display("{}: {0}")]
112    Stl(stl::import::Options),
113}
114
115/// Data item selection.
116#[derive(Clone, Debug, Default, Display, Eq, FromStr, Hash, PartialEq, JsonSchema, Deserialize, Serialize)]
117#[display(style = "snake_case")]
118#[serde(rename_all = "snake_case", tag = "type")]
119#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
120#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
121pub enum Selection {
122    /// Visit the default scene.
123    #[default]
124    DefaultScene,
125
126    /// Visit the indexed scene.
127    #[display("{}: {index}")]
128    SceneByIndex {
129        /// The index.
130        index: usize,
131    },
132
133    /// Visit the first scene with the given name.
134    #[display("{}: {name}")]
135    SceneByName {
136        /// The name.
137        name: String,
138    },
139
140    /// Visit the indexed mesh.
141    #[display("{}: {index}")]
142    MeshByIndex {
143        /// The index.
144        index: usize,
145    },
146
147    /// Visit the first mesh with the given name.
148    #[display("{}: {name}")]
149    MeshByName {
150        /// The name.
151        name: String,
152    },
153}
154
155/// Represents an in-memory file with an associated potentially foreign file path.
156#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
157pub struct VirtualFile {
158    /// Original file path.
159    pub path: std::path::PathBuf,
160    /// File payload.
161    pub data: Vec<u8>,
162}
163
164impl VirtualFile {
165    /// Returns true if the file name has the given extension.
166    pub fn has_extension(&self, required_extension: &str) -> bool {
167        self.path
168            .extension()
169            .and_then(std::ffi::OsStr::to_str)
170            .map(|extension| extension.eq_ignore_ascii_case(required_extension))
171            .unwrap_or(false)
172    }
173
174    fn read_fs_impl(path: std::path::PathBuf) -> std::io::Result<Self> {
175        let data = std::fs::read(&path)?;
176        Ok(Self { path, data })
177    }
178
179    /// Read from file system.
180    pub fn read_fs<P>(path: P) -> std::io::Result<Self>
181    where
182        P: Into<std::path::PathBuf>,
183    {
184        Self::read_fs_impl(path.into())
185    }
186}
187
188impl From<OutputFormat3d> for FileExportFormat {
189    fn from(output_format: OutputFormat3d) -> Self {
190        match output_format {
191            OutputFormat3d::Fbx(_) => Self::Fbx,
192            OutputFormat3d::Gltf(_) => Self::Gltf,
193            OutputFormat3d::Obj(_) => Self::Obj,
194            OutputFormat3d::Ply(_) => Self::Ply,
195            OutputFormat3d::Step(_) => Self::Step,
196            OutputFormat3d::Stl(_) => Self::Stl,
197        }
198    }
199}
200
201impl From<OutputFormat2d> for FileExportFormat2d {
202    fn from(output_format: OutputFormat2d) -> Self {
203        match output_format {
204            OutputFormat2d::Dxf(_) => Self::Dxf,
205        }
206    }
207}
208
209impl From<FileExportFormat2d> for OutputFormat2d {
210    fn from(export_format: FileExportFormat2d) -> Self {
211        match export_format {
212            FileExportFormat2d::Dxf => OutputFormat2d::Dxf(Default::default()),
213        }
214    }
215}
216
217impl From<FileExportFormat> for OutputFormat3d {
218    fn from(export_format: FileExportFormat) -> Self {
219        match export_format {
220            FileExportFormat::Fbx => OutputFormat3d::Fbx(Default::default()),
221            FileExportFormat::Glb => OutputFormat3d::Gltf(gltf::export::Options {
222                storage: gltf::export::Storage::Binary,
223                ..Default::default()
224            }),
225            FileExportFormat::Gltf => OutputFormat3d::Gltf(gltf::export::Options {
226                storage: gltf::export::Storage::Embedded,
227                presentation: gltf::export::Presentation::Pretty,
228            }),
229            FileExportFormat::Obj => OutputFormat3d::Obj(Default::default()),
230            FileExportFormat::Ply => OutputFormat3d::Ply(Default::default()),
231            FileExportFormat::Step => OutputFormat3d::Step(Default::default()),
232            FileExportFormat::Stl => OutputFormat3d::Stl(stl::export::Options {
233                storage: stl::export::Storage::Ascii,
234                ..Default::default()
235            }),
236        }
237    }
238}
239
240impl From<InputFormat3d> for FileImportFormat {
241    fn from(input_format: InputFormat3d) -> Self {
242        match input_format {
243            InputFormat3d::Fbx(_) => Self::Fbx,
244            InputFormat3d::Gltf(_) => Self::Gltf,
245            InputFormat3d::Obj(_) => Self::Obj,
246            InputFormat3d::Ply(_) => Self::Ply,
247            InputFormat3d::Sldprt(_) => Self::Sldprt,
248            InputFormat3d::Step(_) => Self::Step,
249            InputFormat3d::Stl(_) => Self::Stl,
250        }
251    }
252}
253
254impl From<FileImportFormat> for InputFormat3d {
255    fn from(import_format: FileImportFormat) -> Self {
256        match import_format {
257            FileImportFormat::Fbx => InputFormat3d::Fbx(Default::default()),
258            FileImportFormat::Gltf => InputFormat3d::Gltf(Default::default()),
259            FileImportFormat::Obj => InputFormat3d::Obj(Default::default()),
260            FileImportFormat::Ply => InputFormat3d::Ply(Default::default()),
261            FileImportFormat::Sldprt => InputFormat3d::Sldprt(Default::default()),
262            FileImportFormat::Step => InputFormat3d::Step(Default::default()),
263            FileImportFormat::Stl => InputFormat3d::Stl(Default::default()),
264        }
265    }
266}