File diff suppressed because one or more lines are too long
@ -21,8 +21,8 @@ rem(num: i64, divisor: i64) -> i64
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `num` | `i64` | | Yes |
|
||||
| `divisor` | `i64` | | Yes |
|
||||
| `num` | `i64` | The number which will be divided by `divisor`. | Yes |
|
||||
| `divisor` | `i64` | The number which will divide `num`. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
3996
docs/kcl/std.json
3996
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
54
src/wasm-lib/Cargo.lock
generated
54
src/wasm-lib/Cargo.lock
generated
@ -121,9 +121,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.93"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
@ -401,9 +401,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.38"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
@ -1112,7 +1112,7 @@ dependencies = [
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"indexmap 2.7.0",
|
||||
"slab",
|
||||
"tokio",
|
||||
@ -1215,9 +1215,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@ -1242,7 +1242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1253,7 +1253,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"pin-project-lite",
|
||||
]
|
||||
@ -1303,7 +1303,7 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
"itoa",
|
||||
@ -1320,7 +1320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
@ -1340,7 +1340,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.4.1",
|
||||
"pin-project-lite",
|
||||
@ -1706,7 +1706,7 @@ dependencies = [
|
||||
"git_rev",
|
||||
"gltf-json",
|
||||
"handlebars",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"iai",
|
||||
"image",
|
||||
"indexmap 2.7.0",
|
||||
@ -1793,7 +1793,7 @@ dependencies = [
|
||||
"data-encoding",
|
||||
"format_serde_error",
|
||||
"futures",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"mime_guess",
|
||||
@ -1819,9 +1819,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.2.77"
|
||||
version = "0.2.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b77259b37acafa360d98af27431ac394bc8899eeed7037513832ddbee856811"
|
||||
checksum = "10a9cab4476455be70ea57643c31444068b056d091bd348cab6044c0d8ad7fcc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -1829,7 +1829,7 @@ dependencies = [
|
||||
"enum-iterator",
|
||||
"enum-iterator-derive",
|
||||
"euler",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"kittycad-modeling-cmds-macros",
|
||||
"kittycad-unit-conversion-derive",
|
||||
"measurements",
|
||||
@ -2863,7 +2863,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
@ -2905,7 +2905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f67ad7fdf5c0a015763fcd164bee294b13fb7b6f89f1b55961d40f00c3e32d6b"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"reqwest",
|
||||
"reqwest-middleware",
|
||||
]
|
||||
@ -2918,7 +2918,7 @@ checksum = "d1ccd3b55e711f91a9885a2fa6fbbb2e39db1776420b062efc058c6410f7e5e3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"thiserror 1.0.68",
|
||||
@ -2935,7 +2935,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
"getrandom",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"hyper 1.4.1",
|
||||
"parking_lot 0.11.2",
|
||||
"reqwest",
|
||||
@ -2956,7 +2956,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"getrandom",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"matchit",
|
||||
"opentelemetry",
|
||||
"reqwest",
|
||||
@ -3200,9 +3200,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.215"
|
||||
version = "1.0.216"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -3218,9 +3218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.215"
|
||||
version = "1.0.216"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4028,7 +4028,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
|
@ -76,7 +76,7 @@ members = [
|
||||
[workspace.dependencies]
|
||||
http = "1"
|
||||
kittycad = { version = "0.3.28", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.77", features = ["websocket"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.79", features = ["websocket"] }
|
||||
|
||||
[workspace.lints.clippy]
|
||||
assertions_on_result_states = "warn"
|
||||
|
@ -6,6 +6,8 @@
|
||||
mod tests;
|
||||
mod unbox;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use convert_case::Casing;
|
||||
use inflector::Inflector;
|
||||
use once_cell::sync::Lazy;
|
||||
@ -47,6 +49,10 @@ struct StdlibMetadata {
|
||||
/// If false, all arguments require labels.
|
||||
#[serde(default)]
|
||||
unlabeled_first: bool,
|
||||
|
||||
/// Key = argument name, value = argument doc.
|
||||
#[serde(default)]
|
||||
arg_docs: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
@ -282,6 +288,17 @@ fn do_stdlib_inner(
|
||||
|
||||
let ty_string = rust_type_to_openapi_type(&ty_string);
|
||||
let required = !ty_ident.to_string().starts_with("Option <");
|
||||
let description = if let Some(s) = metadata.arg_docs.get(&arg_name) {
|
||||
quote! { #s }
|
||||
} else if metadata.keywords && ty_string != "Args" && ty_string != "ExecState" {
|
||||
errors.push(Error::new_spanned(
|
||||
&arg,
|
||||
"Argument was not documented in the arg_docs block",
|
||||
));
|
||||
continue;
|
||||
} else {
|
||||
quote! { String::new() }
|
||||
};
|
||||
let label_required = !(i == 0 && metadata.unlabeled_first);
|
||||
if ty_string != "ExecState" && ty_string != "Args" {
|
||||
let schema = quote! {
|
||||
@ -294,6 +311,7 @@ fn do_stdlib_inner(
|
||||
schema: #schema,
|
||||
required: #required,
|
||||
label_required: #label_required,
|
||||
description: #description.to_string(),
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -355,6 +373,7 @@ fn do_stdlib_inner(
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
@ -116,6 +116,9 @@ fn test_stdlib_line_to() {
|
||||
let (item, errors) = do_stdlib(
|
||||
quote! {
|
||||
name = "lineTo",
|
||||
arg_docs = {
|
||||
sketch = "the sketch you're adding the line to"
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
/// This is some function.
|
||||
|
@ -91,6 +91,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
schema: generator.root_schema_for::<Foo>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -105,6 +106,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
schema: generator.root_schema_for::<str>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -105,6 +106,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema: generator.root_schema_for::<[f64; 2usize]>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -143,6 +144,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema: generator.root_schema_for::<f64>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -106,6 +107,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,7 @@ impl crate::docs::StdLibFn for MyFunc {
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -144,6 +145,7 @@ impl crate::docs::StdLibFn for MyFunc {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,7 @@ impl crate::docs::StdLibFn for LineTo {
|
||||
schema: generator.root_schema_for::<LineToData>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
},
|
||||
crate::docs::StdLibFnArg {
|
||||
name: "sketch".to_string(),
|
||||
@ -138,6 +139,7 @@ impl crate::docs::StdLibFn for LineTo {
|
||||
schema: generator.root_schema_for::<Sketch>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: "the sketch you're adding the line to".to_string(),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -153,6 +155,7 @@ impl crate::docs::StdLibFn for LineTo {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,7 @@ impl crate::docs::StdLibFn for Min {
|
||||
schema: generator.root_schema_for::<Vec<f64>>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -143,6 +144,7 @@ impl crate::docs::StdLibFn for Min {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema: generator.root_schema_for::<Option<f64>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -106,6 +107,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -106,6 +107,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -106,6 +107,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -106,6 +107,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema: generator.root_schema_for::<Vec<f64>>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new().to_string(),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -106,6 +107,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,7 @@ impl crate::docs::StdLibFn for SomeFunction {
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
description: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,11 @@ impl EngineConnection {
|
||||
uuid_to_cpp(path_id)
|
||||
)
|
||||
}
|
||||
kcmc::ModelingCmd::Extrude(kcmc::Extrude { distance, target }) => {
|
||||
kcmc::ModelingCmd::Extrude(kcmc::Extrude {
|
||||
distance,
|
||||
target,
|
||||
faces: _, // Engine team: start using this once the frontend and engine both use it.
|
||||
}) => {
|
||||
format!(
|
||||
r#"
|
||||
scene->getSceneObject(Utils::UUID("{target}"))->extrudeToSolid3D({} * scaleFactor, true);
|
||||
|
@ -59,6 +59,12 @@ pub struct StdLibFnArg {
|
||||
pub schema: schemars::schema::RootSchema,
|
||||
/// If the argument is required.
|
||||
pub required: bool,
|
||||
/// Additional information that could be used instead of the type's description.
|
||||
/// This is helpful if the type is really basic, like "u32" -- that won't tell the user much about
|
||||
/// how this argument is meant to be used.
|
||||
/// Empty string means this has no docs.
|
||||
#[serde(default, skip_serializing_if = "String::is_empty")]
|
||||
pub description: String,
|
||||
/// Even in functions that use keyword arguments, not every parameter requires a label (most do though).
|
||||
/// Some functions allow one unlabeled parameter, which has to be first in the
|
||||
/// argument list.
|
||||
@ -106,6 +112,11 @@ impl StdLibFnArg {
|
||||
}
|
||||
|
||||
pub fn description(&self) -> Option<String> {
|
||||
// Check if we explicitly gave this stdlib arg a description.
|
||||
if !self.description.is_empty() {
|
||||
return Some(self.description.clone());
|
||||
}
|
||||
// If not, then try to get something meaningful from the schema.
|
||||
get_description_string_from_schema(&self.schema.clone())
|
||||
}
|
||||
}
|
||||
|
@ -2539,6 +2539,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
||||
let initial_unlabeled_arg = opt((expression, comma, opt(whitespace)).map(|(arg, _, _)| arg)).parse_next(i)?;
|
||||
let args = labeled_arguments(i)?;
|
||||
ignore_whitespace(i);
|
||||
opt(comma_sep).parse_next(i)?;
|
||||
let end = close_paren.parse_next(i)?.end;
|
||||
|
||||
Ok(Node {
|
||||
|
@ -133,12 +133,16 @@ impl Args {
|
||||
where
|
||||
T: FromKclValue<'a>,
|
||||
{
|
||||
let Some(ref arg) = self.kw_args.unlabeled else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
let arg = self
|
||||
.kw_args
|
||||
.unlabeled
|
||||
.as_ref()
|
||||
.or(self.args.first())
|
||||
.ok_or(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
|
||||
}));
|
||||
};
|
||||
}))?;
|
||||
|
||||
T::from_kcl_val(&arg.value).ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: arg.source_ranges(),
|
||||
@ -411,13 +415,6 @@ impl Args {
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_sketches_and_data<'a, T>(&'a self) -> Result<(Vec<Sketch>, Option<T>), KclError>
|
||||
where
|
||||
T: FromArgs<'a> + serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
|
||||
{
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_data_and_optional_tag<'a, T>(&'a self) -> Result<(T, Option<FaceTag>), KclError>
|
||||
where
|
||||
T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
|
||||
@ -865,22 +862,6 @@ impl<'a> FromKclValue<'a> for crate::std::polar::PolarCoordsData {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for crate::std::loft::LoftData {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let obj = arg.as_object()?;
|
||||
let_field_of!(obj, v_degree?);
|
||||
let_field_of!(obj, bez_approximate_rational?);
|
||||
let_field_of!(obj, base_curve_index?);
|
||||
let_field_of!(obj, tolerance?);
|
||||
Some(Self {
|
||||
v_degree,
|
||||
bez_approximate_rational,
|
||||
base_curve_index,
|
||||
tolerance,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for crate::std::planes::StandardPlane {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let s = arg.as_str()?;
|
||||
|
@ -113,6 +113,7 @@ async fn inner_extrude(
|
||||
ModelingCmd::from(mcmd::Extrude {
|
||||
target: sketch.id.into(),
|
||||
distance: LengthUnit(length),
|
||||
faces: Default::default(),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! Standard library lofts.
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use anyhow::Result;
|
||||
use derive_docs::stdlib;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
|
||||
use kittycad_modeling_cmds as kcmc;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
@ -15,45 +15,31 @@ use crate::{
|
||||
|
||||
const DEFAULT_V_DEGREE: u32 = 2;
|
||||
|
||||
/// Data for a loft.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LoftData {
|
||||
/// Degree of the interpolation. Must be greater than zero.
|
||||
/// For example, use 2 for quadratic, or 3 for cubic interpolation in the V direction.
|
||||
/// This defaults to 2, if not specified.
|
||||
pub v_degree: Option<std::num::NonZeroU32>,
|
||||
/// Attempt to approximate rational curves (such as arcs) using a bezier.
|
||||
/// This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios
|
||||
/// Over time, this field won't be necessary.
|
||||
#[serde(default)]
|
||||
pub bez_approximate_rational: Option<bool>,
|
||||
/// This can be set to override the automatically determined topological base curve, which is usually the first section encountered.
|
||||
#[serde(default)]
|
||||
pub base_curve_index: Option<u32>,
|
||||
/// Tolerance for the loft operation.
|
||||
#[serde(default)]
|
||||
pub tolerance: Option<f64>,
|
||||
}
|
||||
|
||||
impl Default for LoftData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// This unwrap is safe because the default value is always greater than zero.
|
||||
v_degree: Some(std::num::NonZeroU32::new(DEFAULT_V_DEGREE).unwrap()),
|
||||
bez_approximate_rational: None,
|
||||
base_curve_index: None,
|
||||
tolerance: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a 3D surface or solid by interpolating between two or more sketches.
|
||||
pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (sketches, data): (Vec<Sketch>, Option<LoftData>) = args.get_sketches_and_data()?;
|
||||
let sketches = args.get_unlabeled_kw_arg("sketches")?;
|
||||
let v_degree: NonZeroU32 = args
|
||||
.get_kw_arg_opt("vDegree")
|
||||
.unwrap_or(NonZeroU32::new(DEFAULT_V_DEGREE).unwrap());
|
||||
// Attempt to approximate rational curves (such as arcs) using a bezier.
|
||||
// This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios
|
||||
// Over time, this field won't be necessary.
|
||||
let bez_approximate_rational = args.get_kw_arg_opt("bezApproximateRational").unwrap_or(false);
|
||||
// This can be set to override the automatically determined topological base curve, which is usually the first section encountered.
|
||||
let base_curve_index: Option<u32> = args.get_kw_arg_opt("baseCurveIndex");
|
||||
// Tolerance for the loft operation.
|
||||
let tolerance: Option<f64> = args.get_kw_arg_opt("tolerance");
|
||||
|
||||
let solid = inner_loft(sketches, data, exec_state, args).await?;
|
||||
let solid = inner_loft(
|
||||
sketches,
|
||||
v_degree,
|
||||
bez_approximate_rational,
|
||||
base_curve_index,
|
||||
tolerance,
|
||||
exec_state,
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
Ok(KclValue::Solid(solid))
|
||||
}
|
||||
|
||||
@ -116,28 +102,31 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
/// circleSketch1 = startSketchOn(offsetPlane('XY', 150))
|
||||
/// |> circle({ center = [0, 100], radius = 20 }, %)
|
||||
///
|
||||
/// loft([squareSketch, circleSketch0, circleSketch1], {
|
||||
/// // This can be set to override the automatically determined
|
||||
/// // topological base curve, which is usually the first section encountered.
|
||||
/// loft([squareSketch, circleSketch0, circleSketch1],
|
||||
/// baseCurveIndex = 0,
|
||||
/// // Attempt to approximate rational curves (such as arcs) using a bezier.
|
||||
/// // This will remove banding around interpolations between arcs and non-arcs.
|
||||
/// // It may produce errors in other scenarios Over time, this field won't be necessary.
|
||||
/// bezApproximateRational = false,
|
||||
/// // Tolerance for the loft operation.
|
||||
/// tolerance = 0.000001,
|
||||
/// // Degree of the interpolation. Must be greater than zero.
|
||||
/// // For example, use 2 for quadratic, or 3 for cubic interpolation in
|
||||
/// // the V direction. This defaults to 2, if not specified.
|
||||
/// vDegree = 2,
|
||||
/// })
|
||||
/// )
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "loft",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
arg_docs = {
|
||||
sketches = "Which sketches to loft. Must include at least 2 sketches.",
|
||||
v_degree = "Degree of the interpolation. Must be greater than zero. For example, use 2 for quadratic, or 3 for cubic interpolation in the V direction. This defaults to 2, if not specified.",
|
||||
bez_approximate_rational = "Attempt to approximate rational curves (such as arcs) using a bezier. This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios Over time, this field won't be necessary.",
|
||||
base_curve_index = "This can be set to override the automatically determined topological base curve, which is usually the first section encountered.",
|
||||
tolerance = "Tolerance for the loft operation.",
|
||||
}
|
||||
}]
|
||||
async fn inner_loft(
|
||||
sketches: Vec<Sketch>,
|
||||
data: Option<LoftData>,
|
||||
v_degree: NonZeroU32,
|
||||
bez_approximate_rational: bool,
|
||||
base_curve_index: Option<u32>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
@ -152,20 +141,15 @@ async fn inner_loft(
|
||||
}));
|
||||
}
|
||||
|
||||
// Get the loft data.
|
||||
let data = data.unwrap_or_default();
|
||||
|
||||
let id = exec_state.id_generator.next_uuid();
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::Loft {
|
||||
section_ids: sketches.iter().map(|group| group.id).collect(),
|
||||
base_curve_index: data.base_curve_index,
|
||||
bez_approximate_rational: data.bez_approximate_rational.unwrap_or(false),
|
||||
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
v_degree: data
|
||||
.v_degree
|
||||
.unwrap_or_else(|| std::num::NonZeroU32::new(DEFAULT_V_DEGREE).unwrap()),
|
||||
base_curve_index,
|
||||
bez_approximate_rational,
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
v_degree,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
@ -34,6 +34,10 @@ pub async fn rem(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
tags = ["math"],
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
arg_docs = {
|
||||
num = "The number which will be divided by `divisor`.",
|
||||
divisor = "The number which will divide `num`.",
|
||||
}
|
||||
}]
|
||||
fn inner_rem(num: i64, divisor: i64) -> Result<i64, KclError> {
|
||||
Ok(num % divisor)
|
||||
|
Reference in New Issue
Block a user