use anyhow::Result;
use derive_docs::stdlib;
use kittycad::types::ModelingCmd;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
ast::types::TagDeclarator,
errors::{KclError, KclErrorDetails},
executor::{ChamferSurface, EdgeCut, ExtrudeGroup, ExtrudeSurface, GeoMeta, KclValue},
std::{fillet::EdgeReference, Args},
};
pub(crate) const DEFAULT_TOLERANCE: f64 = 0.0000001;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct ChamferData {
pub length: f64,
pub tags: Vec<EdgeReference>,
}
pub async fn chamfer(args: Args) -> Result<KclValue, KclError> {
let (data, extrude_group, tag): (ChamferData, Box<ExtrudeGroup>, Option<TagDeclarator>) =
args.get_data_and_extrude_group_and_tag()?;
let extrude_group = inner_chamfer(data, extrude_group, tag, args).await?;
Ok(KclValue::ExtrudeGroup(extrude_group))
}
#[stdlib {
name = "chamfer",
}]
async fn inner_chamfer(
data: ChamferData,
extrude_group: Box<ExtrudeGroup>,
tag: Option<TagDeclarator>,
args: Args,
) -> Result<Box<ExtrudeGroup>, KclError> {
let mut tags = data.tags.clone();
tags.sort();
tags.dedup();
if tags.len() != data.tags.len() {
return Err(KclError::Type(KclErrorDetails {
message: "Duplicate tags are not allowed.".to_string(),
source_ranges: vec![args.source_range],
}));
}
if tag.is_some() && data.tags.len() > 1 {
return Err(KclError::Type(KclErrorDetails {
message: "You can only tag one edge at a time with a tagged chamfer. Either delete the tag for the chamfer fn if you don't need it OR separate into individual chamfer functions for each tag.".to_string(),
source_ranges: vec![args.source_range],
}));
}
let mut extrude_group = extrude_group.clone();
let mut edge_cuts = Vec::new();
for edge_tag in data.tags {
let edge_id = match edge_tag {
EdgeReference::Uuid(uuid) => uuid,
EdgeReference::Tag(edge_tag) => args.get_tag_engine_info(&edge_tag)?.id,
};
let id = uuid::Uuid::new_v4();
args.batch_end_cmd(
id,
ModelingCmd::Solid3DFilletEdge {
edge_id,
object_id: extrude_group.id,
radius: data.length,
tolerance: DEFAULT_TOLERANCE, cut_type: Some(kittycad::types::CutType::Chamfer),
},
)
.await?;
edge_cuts.push(EdgeCut::Chamfer {
id,
edge_id,
length: data.length,
tag: Box::new(tag.clone()),
});
if let Some(ref tag) = tag {
extrude_group.value.push(ExtrudeSurface::Chamfer(ChamferSurface {
face_id: edge_id,
tag: Some(tag.clone()),
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
},
}));
}
}
extrude_group.edge_cuts = edge_cuts;
Ok(extrude_group)
}