BREAKING: Change polygon to keyword args (#6385)

* Change polygon to keyword args

* Update docs

* Update generated output

* Update docs to mention the default for inscribed

* Appease clippy

* Remove tag parameter

* Update docs since removing tag

* Remove inscribed from autocomplete snippet since the default is true
This commit is contained in:
Jonathan Tran
2025-04-21 14:29:32 -04:00
committed by GitHub
parent 7a90d029e1
commit f8ca6ad746
17 changed files with 5386 additions and 698 deletions

View File

@ -13,6 +13,7 @@ use kittycad_modeling_cmds::shared::PathSegment;
use schemars::JsonSchema;
use serde::Serialize;
use super::{args::TyF64, utils::untype_point};
use crate::{
errors::{KclError, KclErrorDetails},
execution::{types::RuntimeType, BasePath, ExecState, GeoMeta, KclValue, Path, Sketch, SketchSurface},
@ -24,8 +25,6 @@ use crate::{
},
};
use super::{args::TyF64, utils::untype_point};
/// A sketch surface or a sketch.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
@ -259,35 +258,24 @@ pub enum PolygonType {
Circumscribed,
}
/// Data for drawing a polygon
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct PolygonData {
/// The radius of the polygon
pub radius: TyF64,
/// The number of sides in the polygon
pub num_sides: u64,
/// The center point of the polygon
pub center: [TyF64; 2],
/// The type of the polygon (inscribed or circumscribed)
#[serde(skip)]
pub polygon_type: PolygonType,
/// Whether the polygon is inscribed (true) or circumscribed (false) about a circle with the specified radius
#[serde(default = "default_inscribed")]
pub inscribed: bool,
}
fn default_inscribed() -> bool {
true
}
/// Create a regular polygon with the specified number of sides and radius.
pub async fn polygon(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch_surface_or_group, tag): (PolygonData, SketchOrSurface, Option<TagNode>) =
args.get_polygon_args()?;
let sketch_surface_or_group = args.get_unlabeled_kw_arg("sketchOrSurface")?;
let radius: TyF64 = args.get_kw_arg_typed("radius", &RuntimeType::length(), exec_state)?;
let num_sides: TyF64 = args.get_kw_arg_typed("numSides", &RuntimeType::count(), exec_state)?;
let center = args.get_kw_arg_typed("center", &RuntimeType::point2d(), exec_state)?;
let inscribed = args.get_kw_arg_opt_typed("inscribed", &RuntimeType::bool(), exec_state)?;
let sketch = inner_polygon(data, sketch_surface_or_group, tag, exec_state, args).await?;
let sketch = inner_polygon(
sketch_surface_or_group,
radius,
num_sides.n as u64,
untype_point(center).0,
inscribed,
exec_state,
args,
)
.await?;
Ok(KclValue::Sketch {
value: Box::new(sketch),
})
@ -298,12 +286,12 @@ pub async fn polygon(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// ```no_run
/// // Create a regular hexagon inscribed in a circle of radius 10
/// hex = startSketchOn('XY')
/// |> polygon({
/// |> polygon(
/// radius = 10,
/// numSides = 6,
/// center = [0, 0],
/// inscribed = true,
/// }, %)
/// )
///
/// example = extrude(hex, length = 5)
/// ```
@ -311,32 +299,44 @@ pub async fn polygon(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// ```no_run
/// // Create a square circumscribed around a circle of radius 5
/// square = startSketchOn('XY')
/// |> polygon({
/// |> polygon(
/// radius = 5.0,
/// numSides = 4,
/// center = [10, 10],
/// inscribed = false,
/// }, %)
/// )
/// example = extrude(square, length = 5)
/// ```
#[stdlib {
name = "polygon",
keywords = true,
unlabeled_first = true,
args = {
sketch_surface_or_group = { docs = "Plane or surface to sketch on" },
radius = { docs = "The radius of the polygon", include_in_snippet = true },
num_sides = { docs = "The number of sides in the polygon", include_in_snippet = true },
center = { docs = "The center point of the polygon", include_in_snippet = true },
inscribed = { docs = "Whether the polygon is inscribed (true, the default) or circumscribed (false) about a circle with the specified radius" },
}
}]
#[allow(clippy::too_many_arguments)]
async fn inner_polygon(
data: PolygonData,
sketch_surface_or_group: SketchOrSurface,
tag: Option<TagNode>,
radius: TyF64,
num_sides: u64,
center: [f64; 2],
inscribed: Option<bool>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Sketch, KclError> {
if data.num_sides < 3 {
if num_sides < 3 {
return Err(KclError::Type(KclErrorDetails {
message: "Polygon must have at least 3 sides".to_string(),
source_ranges: vec![args.source_range],
}));
}
if data.radius.n <= 0.0 {
if radius.n <= 0.0 {
return Err(KclError::Type(KclErrorDetails {
message: "Radius must be greater than 0".to_string(),
source_ranges: vec![args.source_range],
@ -348,21 +348,24 @@ async fn inner_polygon(
SketchOrSurface::Sketch(group) => group.on,
};
let half_angle = std::f64::consts::PI / data.num_sides as f64;
let half_angle = std::f64::consts::PI / num_sides as f64;
let radius_to_vertices = match data.polygon_type {
PolygonType::Inscribed => data.radius.n,
PolygonType::Circumscribed => data.radius.n / half_angle.cos(),
let radius_to_vertices = if inscribed.unwrap_or(true) {
// inscribed
radius.n
} else {
// circumscribed
radius.n / half_angle.cos()
};
let angle_step = 2.0 * std::f64::consts::PI / data.num_sides as f64;
let angle_step = std::f64::consts::TAU / num_sides as f64;
let vertices: Vec<[f64; 2]> = (0..data.num_sides)
let vertices: Vec<[f64; 2]> = (0..num_sides)
.map(|i| {
let angle = angle_step * i as f64;
[
data.center[0].n + radius_to_vertices * angle.cos(),
data.center[1].n + radius_to_vertices * angle.sin(),
center[0] + radius_to_vertices * angle.cos(),
center[1] + radius_to_vertices * angle.sin(),
]
})
.collect();
@ -391,7 +394,7 @@ async fn inner_polygon(
base: BasePath {
from: from.into(),
to: *vertex,
tag: tag.clone(),
tag: None,
units: sketch.units,
geo_meta: GeoMeta {
id,
@ -400,10 +403,6 @@ async fn inner_polygon(
},
};
if let Some(tag) = &tag {
sketch.add_tag(tag, &current_path, exec_state);
}
sketch.paths.push(current_path);
}
@ -427,7 +426,7 @@ async fn inner_polygon(
base: BasePath {
from: from.into(),
to: vertices[0],
tag: tag.clone(),
tag: None,
units: sketch.units,
geo_meta: GeoMeta {
id: close_id,
@ -436,10 +435,6 @@ async fn inner_polygon(
},
};
if let Some(tag) = &tag {
sketch.add_tag(tag, &current_path, exec_state);
}
sketch.paths.push(current_path);
args.batch_modeling_cmd(