Fix circle (#1715)

* start of circle

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixews

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix all samples

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* bump version;

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-03-13 17:16:57 -07:00
committed by GitHub
parent d3d2612a3b
commit c571b15318
9 changed files with 1519 additions and 344 deletions

View File

@ -1,155 +1,83 @@
//! Standard library shapes.
use anyhow::Result;
use derive_docs::stdlib;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use super::kcl_stdlib::KclStdLibFn;
use crate::{
ast::types::{FunctionExpression, Program},
docs::StdLibFn,
errors::KclError,
executor::MemoryItem,
std::{Args, SketchGroup, SketchSurface},
};
pub const CIRCLE_FN: &str = r#"
(center, radius, surface, tag?) => {
const sg = startProfileAt([center[0] + radius, center[1]], surface)
|> arc({
angle_end: 360,
angle_start: 0,
radius: radius,
tag: tag
}, %)
|> close(%)
return sg
}
"#;
#[derive(Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
pub struct Circle {
function: FunctionExpression,
program: Program,
/// A sketch surface or a sketch group.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(untagged)]
pub enum SketchSurfaceOrGroup {
SketchSurface(SketchSurface),
SketchGroup(Box<SketchGroup>),
}
impl Default for Circle {
fn default() -> Self {
// TODO in https://github.com/KittyCAD/modeling-app/issues/1018
// Don't unwrap here, parse it at compile-time.
let (src, function) = super::kcl_stdlib::extract_function(CIRCLE_FN).unwrap();
Self {
function: *function,
program: src,
}
}
/// Sketch a circle.
pub async fn circle(args: Args) -> Result<MemoryItem, KclError> {
let (center, radius, sketch_surface_or_group, tag): ([f64; 2], f64, SketchSurfaceOrGroup, Option<String>) =
args.get_circle_args()?;
let sketch_group = inner_circle(center, radius, tag, sketch_surface_or_group, args).await?;
Ok(MemoryItem::SketchGroup(sketch_group))
}
impl std::fmt::Debug for Circle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
"circle".fmt(f)
}
}
/// TODO: Parse the KCL in a macro and generate these
impl StdLibFn for Circle {
fn name(&self) -> String {
"circle".to_owned()
}
fn summary(&self) -> String {
"Sketch a circle on the given plane".to_owned()
}
fn description(&self) -> String {
String::new()
}
fn tags(&self) -> Vec<String> {
Vec::new()
}
fn args(&self) -> Vec<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let mut args = Vec::new();
for parameter in &self.function.params {
match parameter.identifier.name.as_str() {
"center" => {
args.push(crate::docs::StdLibFnArg {
name: parameter.identifier.name.to_owned(),
type_: "[number, number]".to_string(),
schema: <[f64; 2]>::json_schema(&mut generator),
required: true,
});
}
"radius" => {
args.push(crate::docs::StdLibFnArg {
name: parameter.identifier.name.to_owned(),
type_: "number".to_string(),
schema: <f64>::json_schema(&mut generator),
required: true,
});
}
"surface" => {
args.push(crate::docs::StdLibFnArg {
name: parameter.identifier.name.to_owned(),
type_: "SketchSurface".to_string(),
schema: <crate::executor::SketchSurface>::json_schema(&mut generator),
required: true,
});
}
"tag" => {
args.push(crate::docs::StdLibFnArg {
name: parameter.identifier.name.to_owned(),
type_: "String".to_string(),
schema: <String>::json_schema(&mut generator),
required: false,
});
}
_ => panic!("Unknown parameter: {:?}", parameter.identifier.name),
}
}
args
}
fn return_value(&self) -> Option<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
Some(crate::docs::StdLibFnArg {
name: "SketchGroup".to_owned(),
type_: "SketchGroup".to_string(),
schema: <crate::executor::SketchGroup>::json_schema(&mut generator),
required: true,
})
}
fn unpublished(&self) -> bool {
false
}
fn deprecated(&self) -> bool {
false
}
fn examples(&self) -> Vec<String> {
vec![]
}
fn std_lib_fn(&self) -> crate::std::StdFn {
todo!()
}
fn clone_box(&self) -> Box<dyn StdLibFn> {
Box::new(self.to_owned())
}
}
impl KclStdLibFn for Circle {
fn function(&self) -> &FunctionExpression {
&self.function
}
fn program(&self) -> &Program {
&self.program
}
fn kcl_clone_box(&self) -> Box<dyn KclStdLibFn> {
Box::new(self.clone())
}
/// Sketch a circle.
///
/// ```no_run
/// const circles = startSketchOn('XY')
/// |> circle([5, 5], 1, %)
/// |> patternLinear2d({axis: [1,1], repetitions: 12, distance: 3}, %)
///
/// const rectangle = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([0, 50], %)
/// |> line([50, 0], %)
/// |> line([0, -50], %)
/// |> close(%)
/// |> hole(circles, %)
/// ```
#[stdlib {
name = "circle",
}]
async fn inner_circle(
center: [f64; 2],
radius: f64,
tag: Option<String>,
sketch_surface_or_group: SketchSurfaceOrGroup,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let sketch_surface = match sketch_surface_or_group {
SketchSurfaceOrGroup::SketchSurface(surface) => surface,
SketchSurfaceOrGroup::SketchGroup(group) => group.on,
};
let mut sketch_group = crate::std::sketch::inner_start_profile_at(
crate::std::sketch::LineData::Point([center[0] + radius, center[1]]),
sketch_surface,
args.clone(),
)
.await?;
// Call arc.
sketch_group = crate::std::sketch::inner_arc(
crate::std::sketch::ArcData::AnglesAndRadius {
angle_start: 0.0,
angle_end: 360.0,
radius,
tag,
},
sketch_group,
args.clone(),
)
.await?;
// Call close.
crate::std::sketch::inner_close(sketch_group, None, args).await
}