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(feature = "ts-rs", derive(ts_rs::TS))]
83#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
84pub enum InputFormat3d {
85    /// Autodesk Filmbox (FBX) format.
86    #[display("{}: {0}")]
87    Fbx(fbx::import::Options),
88    /// Binary glTF 2.0.
89    /// We refer to this as glTF since that is how our customers refer to it,
90    /// but this can also import binary glTF (glb).
91    #[display("{}: {0}")]
92    Gltf(gltf::import::Options),
93    /// Wavefront OBJ format.
94    #[display("{}: {0}")]
95    Obj(obj::import::Options),
96    /// The PLY Polygon File Format.
97    #[display("{}: {0}")]
98    Ply(ply::import::Options),
99    /// SolidWorks part (SLDPRT) format.
100    #[display("{}: {0}")]
101    Sldprt(sldprt::import::Options),
102    /// ISO 10303-21 (STEP) format.
103    #[display("{}: {0}")]
104    Step(step::import::Options),
105    /// **ST**ereo**L**ithography format.
106    #[display("{}: {0}")]
107    Stl(stl::import::Options),
108}
109
110/// Data item selection.
111#[derive(Clone, Debug, Default, Display, Eq, FromStr, Hash, PartialEq, JsonSchema, Deserialize, Serialize)]
112#[display(style = "snake_case")]
113#[serde(rename_all = "snake_case", tag = "type")]
114#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
115#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
116pub enum Selection {
117    /// Visit the default scene.
118    #[default]
119    DefaultScene,
120
121    /// Visit the indexed scene.
122    #[display("{}: {index}")]
123    SceneByIndex {
124        /// The index.
125        index: usize,
126    },
127
128    /// Visit the first scene with the given name.
129    #[display("{}: {name}")]
130    SceneByName {
131        /// The name.
132        name: String,
133    },
134
135    /// Visit the indexed mesh.
136    #[display("{}: {index}")]
137    MeshByIndex {
138        /// The index.
139        index: usize,
140    },
141
142    /// Visit the first mesh with the given name.
143    #[display("{}: {name}")]
144    MeshByName {
145        /// The name.
146        name: String,
147    },
148}
149
150/// Represents an in-memory file with an associated potentially foreign file path.
151#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
152pub struct VirtualFile {
153    /// Original file path.
154    pub path: std::path::PathBuf,
155    /// File payload.
156    pub data: Vec<u8>,
157}
158
159impl VirtualFile {
160    /// Returns true if the file name has the given extension.
161    pub fn has_extension(&self, required_extension: &str) -> bool {
162        self.path
163            .extension()
164            .and_then(std::ffi::OsStr::to_str)
165            .map(|extension| extension.eq_ignore_ascii_case(required_extension))
166            .unwrap_or(false)
167    }
168
169    fn read_fs_impl(path: std::path::PathBuf) -> std::io::Result<Self> {
170        let data = std::fs::read(&path)?;
171        Ok(Self { path, data })
172    }
173
174    /// Read from file system.
175    pub fn read_fs<P>(path: P) -> std::io::Result<Self>
176    where
177        P: Into<std::path::PathBuf>,
178    {
179        Self::read_fs_impl(path.into())
180    }
181}
182
183impl From<OutputFormat3d> for FileExportFormat {
184    fn from(output_format: OutputFormat3d) -> Self {
185        match output_format {
186            OutputFormat3d::Fbx(_) => Self::Fbx,
187            OutputFormat3d::Gltf(_) => Self::Gltf,
188            OutputFormat3d::Obj(_) => Self::Obj,
189            OutputFormat3d::Ply(_) => Self::Ply,
190            OutputFormat3d::Step(_) => Self::Step,
191            OutputFormat3d::Stl(_) => Self::Stl,
192        }
193    }
194}
195
196impl From<OutputFormat2d> for FileExportFormat2d {
197    fn from(output_format: OutputFormat2d) -> Self {
198        match output_format {
199            OutputFormat2d::Dxf(_) => Self::Dxf,
200        }
201    }
202}
203
204impl From<FileExportFormat2d> for OutputFormat2d {
205    fn from(export_format: FileExportFormat2d) -> Self {
206        match export_format {
207            FileExportFormat2d::Dxf => OutputFormat2d::Dxf(Default::default()),
208        }
209    }
210}
211
212impl From<FileExportFormat> for OutputFormat3d {
213    fn from(export_format: FileExportFormat) -> Self {
214        match export_format {
215            FileExportFormat::Fbx => OutputFormat3d::Fbx(Default::default()),
216            FileExportFormat::Glb => OutputFormat3d::Gltf(gltf::export::Options {
217                storage: gltf::export::Storage::Binary,
218                ..Default::default()
219            }),
220            FileExportFormat::Gltf => OutputFormat3d::Gltf(gltf::export::Options {
221                storage: gltf::export::Storage::Embedded,
222                presentation: gltf::export::Presentation::Pretty,
223            }),
224            FileExportFormat::Obj => OutputFormat3d::Obj(Default::default()),
225            FileExportFormat::Ply => OutputFormat3d::Ply(Default::default()),
226            FileExportFormat::Step => OutputFormat3d::Step(Default::default()),
227            FileExportFormat::Stl => OutputFormat3d::Stl(stl::export::Options {
228                storage: stl::export::Storage::Ascii,
229                ..Default::default()
230            }),
231        }
232    }
233}
234
235impl From<InputFormat3d> for FileImportFormat {
236    fn from(input_format: InputFormat3d) -> Self {
237        match input_format {
238            InputFormat3d::Fbx(_) => Self::Fbx,
239            InputFormat3d::Gltf(_) => Self::Gltf,
240            InputFormat3d::Obj(_) => Self::Obj,
241            InputFormat3d::Ply(_) => Self::Ply,
242            InputFormat3d::Sldprt(_) => Self::Sldprt,
243            InputFormat3d::Step(_) => Self::Step,
244            InputFormat3d::Stl(_) => Self::Stl,
245        }
246    }
247}
248
249impl From<FileImportFormat> for InputFormat3d {
250    fn from(import_format: FileImportFormat) -> Self {
251        match import_format {
252            FileImportFormat::Fbx => InputFormat3d::Fbx(Default::default()),
253            FileImportFormat::Gltf => InputFormat3d::Gltf(Default::default()),
254            FileImportFormat::Obj => InputFormat3d::Obj(Default::default()),
255            FileImportFormat::Ply => InputFormat3d::Ply(Default::default()),
256            FileImportFormat::Sldprt => InputFormat3d::Sldprt(Default::default()),
257            FileImportFormat::Step => InputFormat3d::Step(Default::default()),
258            FileImportFormat::Stl => InputFormat3d::Stl(Default::default()),
259        }
260    }
261}