2024-06-17 12:13:19 -07:00
//! Standard library chamfers.
use anyhow ::Result ;
2024-09-19 14:06:29 -07:00
use kcmc ::{ each_cmd as mcmd , length_unit ::LengthUnit , shared ::CutType , ModelingCmd } ;
2024-09-18 17:04:04 -05:00
use kittycad_modeling_cmds as kcmc ;
2024-06-17 12:13:19 -07:00
2025-04-26 21:21:26 -07:00
use super ::args ::TyF64 ;
2024-06-17 12:13:19 -07:00
use crate ::{
errors ::{ KclError , KclErrorDetails } ,
2025-03-17 17:57:26 +13:00
execution ::{
2025-03-21 10:56:55 +13:00
types ::{ PrimitiveType , RuntimeType } ,
ChamferSurface , EdgeCut , ExecState , ExtrudeSurface , GeoMeta , KclValue , Solid ,
2025-03-17 17:57:26 +13:00
} ,
2024-12-05 17:56:49 +13:00
parsing ::ast ::types ::TagNode ,
2024-06-24 14:45:07 -07:00
std ::{ fillet ::EdgeReference , Args } ,
2024-06-17 12:13:19 -07:00
} ;
pub ( crate ) const DEFAULT_TOLERANCE : f64 = 0.0000001 ;
/// Create chamfers on tagged paths.
2024-09-16 15:10:33 -04:00
pub async fn chamfer ( exec_state : & mut ExecState , args : Args ) -> Result < KclValue , KclError > {
2025-03-17 17:57:26 +13:00
let solid = args . get_unlabeled_kw_arg_typed ( " solid " , & RuntimeType ::Primitive ( PrimitiveType ::Solid ) , exec_state ) ? ;
2025-04-14 05:58:19 -04:00
let length : TyF64 = args . get_kw_arg_typed ( " length " , & RuntimeType ::length ( ) , exec_state ) ? ;
2025-03-12 11:24:27 -05:00
let tags = args . kw_arg_array_and_source ::< EdgeReference > ( " tags " ) ? ;
2025-02-21 14:41:25 -06:00
let tag = args . get_kw_arg_opt ( " tag " ) ? ;
2024-06-17 12:13:19 -07:00
2025-03-12 11:24:27 -05:00
super ::fillet ::validate_unique ( & tags ) ? ;
let tags : Vec < EdgeReference > = tags . into_iter ( ) . map ( | item | item . 0 ) . collect ( ) ;
2025-02-21 14:41:25 -06:00
let value = inner_chamfer ( solid , length , tags , tag , exec_state , args ) . await ? ;
2025-01-22 09:42:09 +13:00
Ok ( KclValue ::Solid { value } )
2024-06-17 12:13:19 -07:00
}
async fn inner_chamfer (
2024-09-27 15:44:44 -07:00
solid : Box < Solid > ,
2025-04-14 05:58:19 -04:00
length : TyF64 ,
2025-02-21 14:41:25 -06:00
tags : Vec < EdgeReference > ,
2024-10-30 16:52:17 -04:00
tag : Option < TagNode > ,
2024-09-16 15:10:33 -04:00
exec_state : & mut ExecState ,
2024-06-17 12:13:19 -07:00
args : Args ,
2024-09-27 15:44:44 -07:00
) -> Result < Box < Solid > , KclError > {
2024-06-23 23:04:32 -07:00
// If you try and tag multiple edges with a tagged chamfer, we want to return an
// error to the user that they can only tag one edge at a time.
2025-02-21 14:41:25 -06:00
if tag . is_some ( ) & & tags . len ( ) > 1 {
2025-05-19 14:13:10 -04:00
return Err ( KclError ::Type ( KclErrorDetails ::new (
" 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 ( ) ,
vec! [ args . source_range ] ,
) ) ) ;
2024-06-23 23:04:32 -07:00
}
2024-09-27 15:44:44 -07:00
let mut solid = solid . clone ( ) ;
2025-02-21 14:41:25 -06:00
for edge_tag in tags {
2024-06-23 23:04:32 -07:00
let edge_id = match edge_tag {
2024-06-17 12:13:19 -07:00
EdgeReference ::Uuid ( uuid ) = > uuid ,
2024-09-16 15:10:33 -04:00
EdgeReference ::Tag ( edge_tag ) = > args . get_tag_engine_info ( exec_state , & edge_tag ) ? . id ,
2024-06-17 12:13:19 -07:00
} ;
2025-02-13 11:59:57 +13:00
let id = exec_state . next_uuid ( ) ;
2024-06-22 14:31:37 -07:00
args . batch_end_cmd (
2024-06-23 19:19:24 -07:00
id ,
2024-09-18 17:04:04 -05:00
ModelingCmd ::from ( mcmd ::Solid3dFilletEdge {
2025-05-07 14:10:18 -07:00
edge_id : None ,
edge_ids : vec ! [ edge_id ] ,
extra_face_ids : vec ! [ ] ,
strategy : Default ::default ( ) ,
2024-09-27 15:44:44 -07:00
object_id : solid . id ,
2025-04-23 10:58:35 +12:00
radius : LengthUnit ( length . to_mm ( ) ) ,
2024-09-18 17:04:04 -05:00
tolerance : LengthUnit ( DEFAULT_TOLERANCE ) , // We can let the user set this in the future.
cut_type : CutType ::Chamfer ,
} ) ,
2024-06-17 12:13:19 -07:00
)
. await ? ;
2024-06-23 19:19:24 -07:00
2024-09-27 15:44:44 -07:00
solid . edge_cuts . push ( EdgeCut ::Chamfer {
2024-06-23 19:19:24 -07:00
id ,
edge_id ,
2025-04-14 05:58:19 -04:00
length : length . clone ( ) ,
2024-07-09 12:24:42 -04:00
tag : Box ::new ( tag . clone ( ) ) ,
2024-06-23 19:19:24 -07:00
} ) ;
2024-07-28 00:30:04 -07:00
if let Some ( ref tag ) = tag {
2024-09-27 15:44:44 -07:00
solid . value . push ( ExtrudeSurface ::Chamfer ( ChamferSurface {
2024-09-12 16:13:11 -07:00
face_id : id ,
2024-07-28 00:30:04 -07:00
tag : Some ( tag . clone ( ) ) ,
geo_meta : GeoMeta {
id ,
metadata : args . source_range . into ( ) ,
} ,
} ) ) ;
}
2024-06-17 12:13:19 -07:00
}
2024-09-27 15:44:44 -07:00
Ok ( solid )
2024-06-17 12:13:19 -07:00
}