kcl_lib/std/import.rs
1//! Standard library functions involved in importing files.
2
3use anyhow::Result;
4use kcl_derive_docs::stdlib;
5use kcmc::{coord::System, format::InputFormat3d, units::UnitLength};
6use kittycad_modeling_cmds as kcmc;
7
8use crate::{
9 errors::{KclError, KclErrorDetails},
10 execution::{import_foreign, send_import_to_engine, ExecState, ImportedGeometry, KclValue, ZOO_COORD_SYSTEM},
11 std::Args,
12};
13
14/// Import format specifier
15#[derive(serde :: Serialize, serde :: Deserialize, PartialEq, Debug, Clone, schemars :: JsonSchema)]
16#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
17#[serde(tag = "format")]
18pub enum ImportFormat {
19 /// Autodesk Filmbox (FBX) format
20 #[serde(rename = "fbx")]
21 Fbx {},
22 /// Binary glTF 2.0. We refer to this as glTF since that is how our customers refer to
23 /// it, but this can also import binary glTF (glb).
24 #[serde(rename = "gltf")]
25 Gltf {},
26 /// Wavefront OBJ format.
27 #[serde(rename = "obj")]
28 Obj {
29 /// Co-ordinate system of input data.
30 /// Defaults to the [KittyCAD co-ordinate system.
31 coords: Option<System>,
32 /// The units of the input data. This is very important for correct scaling and when
33 /// calculating physics properties like mass, etc.
34 /// Defaults to millimeters.
35 units: UnitLength,
36 },
37 /// The PLY Polygon File Format.
38 #[serde(rename = "ply")]
39 Ply {
40 /// Co-ordinate system of input data.
41 /// Defaults to the [KittyCAD co-ordinate system.
42 coords: Option<System>,
43 /// The units of the input data. This is very important for correct scaling and when
44 /// calculating physics properties like mass, etc.
45 /// Defaults to millimeters.
46 units: UnitLength,
47 },
48 /// SolidWorks part (SLDPRT) format.
49 #[serde(rename = "sldprt")]
50 Sldprt {},
51 /// ISO 10303-21 (STEP) format.
52 #[serde(rename = "step")]
53 Step {},
54 /// *ST**ereo**L**ithography format.
55 #[serde(rename = "stl")]
56 Stl {
57 /// Co-ordinate system of input data.
58 /// Defaults to the [KittyCAD co-ordinate system.
59 coords: Option<System>,
60 /// The units of the input data. This is very important for correct scaling and when
61 /// calculating physics properties like mass, etc.
62 /// Defaults to millimeters.
63 units: UnitLength,
64 },
65}
66
67impl From<ImportFormat> for InputFormat3d {
68 fn from(format: ImportFormat) -> Self {
69 match format {
70 ImportFormat::Fbx {} => InputFormat3d::Fbx(Default::default()),
71 ImportFormat::Gltf {} => InputFormat3d::Gltf(Default::default()),
72 ImportFormat::Obj { coords, units } => InputFormat3d::Obj(kcmc::format::obj::import::Options {
73 coords: coords.unwrap_or(ZOO_COORD_SYSTEM),
74 units,
75 }),
76 ImportFormat::Ply { coords, units } => InputFormat3d::Ply(kcmc::format::ply::import::Options {
77 coords: coords.unwrap_or(ZOO_COORD_SYSTEM),
78 units,
79 }),
80 ImportFormat::Sldprt {} => InputFormat3d::Sldprt(kcmc::format::sldprt::import::Options {
81 split_closed_faces: false,
82 }),
83 ImportFormat::Step {} => InputFormat3d::Step(kcmc::format::step::import::Options {
84 split_closed_faces: false,
85 }),
86 ImportFormat::Stl { coords, units } => InputFormat3d::Stl(kcmc::format::stl::import::Options {
87 coords: coords.unwrap_or(ZOO_COORD_SYSTEM),
88 units,
89 }),
90 }
91 }
92}
93
94/// Import a CAD file.
95/// For formats lacking unit data (STL, OBJ, PLY), the default import unit is millimeters.
96/// Otherwise you can specify the unit by passing in the options parameter.
97/// If you import a gltf file, we will try to find the bin file and import it as well.
98///
99/// Import paths are relative to the current project directory. This only works in the desktop app
100/// not in browser.
101pub async fn import(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
102 let (file_path, options): (String, Option<ImportFormat>) = args.get_import_data()?;
103
104 let imported_geometry = inner_import(file_path, options, exec_state, args).await?;
105 Ok(KclValue::ImportedGeometry(imported_geometry))
106}
107
108/// Import a CAD file.
109///
110/// **DEPRECATED** Prefer to use import statements.
111///
112/// For formats lacking unit data (such as STL, OBJ, or PLY files), the default
113/// unit of measurement is millimeters. Alternatively you may specify the unit
114/// by passing your desired measurement unit in the options parameter. When
115/// importing a GLTF file, the bin file will be imported as well. Import paths
116/// are relative to the current project directory.
117///
118/// Note: The import command currently only works when using the native
119/// Modeling App.
120///
121/// ```no_run
122/// model = import("tests/inputs/cube.obj")
123/// ```
124///
125/// ```no_run
126/// model = import("tests/inputs/cube.obj", {format: "obj", units: "m"})
127/// ```
128///
129/// ```no_run
130/// model = import("tests/inputs/cube.gltf")
131/// ```
132///
133/// ```no_run
134/// model = import("tests/inputs/cube.sldprt")
135/// ```
136///
137/// ```no_run
138/// model = import("tests/inputs/cube.step")
139/// ```
140///
141/// ```no_run
142/// import height, buildSketch from 'common.kcl'
143///
144/// plane = 'XZ'
145/// margin = 2
146/// s1 = buildSketch(plane, [0, 0])
147/// s2 = buildSketch(plane, [0, height() + margin])
148/// ```
149#[stdlib {
150 name = "import",
151 feature_tree_operation = true,
152 deprecated = true,
153 tags = [],
154}]
155async fn inner_import(
156 file_path: String,
157 options: Option<ImportFormat>,
158 exec_state: &mut ExecState,
159 args: Args,
160) -> Result<ImportedGeometry, KclError> {
161 if file_path.is_empty() {
162 return Err(KclError::Semantic(KclErrorDetails {
163 message: "No file path was provided.".to_string(),
164 source_ranges: vec![args.source_range],
165 }));
166 }
167
168 let format = options.map(InputFormat3d::from);
169 send_import_to_engine(
170 import_foreign(
171 std::path::Path::new(&file_path),
172 format,
173 exec_state,
174 &args.ctx,
175 args.source_range,
176 )
177 .await?,
178 &args.ctx,
179 )
180 .await
181}