allow for sketching on the face of a chamfer in kcl (#2760)

* updates

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

* cleanup

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

* lots of cleanup

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

* lots more cleanup

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

* updates

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

* more cleaniup

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

* fix typos

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

* add to known issues

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

* fixes

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-06-23 23:04:32 -07:00
committed by GitHub
parent 394653247a
commit 5260bd6820
59 changed files with 990 additions and 278 deletions

View File

@ -31,10 +31,10 @@ use crate::{
docs::StdLibFn,
errors::{KclError, KclErrorDetails},
executor::{
ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, MemoryItem, Metadata, ProgramMemory, SketchGroup,
SketchGroupSet, SketchSurface, SourceRange,
ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, MemoryItem, Metadata, ProgramMemory,
SketchGroup, SketchGroupSet, SketchSurface, SourceRange,
},
std::{kcl_stdlib::KclStdLibFn, sketch::SketchOnFaceTag},
std::{kcl_stdlib::KclStdLibFn, sketch::FaceTag},
};
pub type StdFn = fn(Args) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<MemoryItem, KclError>> + Send>>;
@ -252,12 +252,10 @@ impl Args {
}
/// Flush just the fillets and chamfers for this specific ExtrudeGroupSet.
pub async fn flush_batch_for_extrude_group_set(&self, extrude_group_set: &ExtrudeGroupSet) -> Result<(), KclError> {
let extrude_groups = match extrude_group_set {
ExtrudeGroupSet::ExtrudeGroup(eg) => vec![eg.clone()],
ExtrudeGroupSet::ExtrudeGroups(egs) => egs.clone(),
};
pub async fn flush_batch_for_extrude_group_set(
&self,
extrude_groups: Vec<Box<ExtrudeGroup>>,
) -> Result<(), KclError> {
// Make sure we don't traverse sketch_groups more than once.
let mut traversed_sketch_groups = Vec::new();
@ -641,9 +639,7 @@ impl Args {
}
}
fn get_data_and_optional_tag<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, Option<SketchOnFaceTag>), KclError> {
fn get_data_and_optional_tag<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Option<FaceTag>), KclError> {
let first_value = self
.args
.first()
@ -663,9 +659,9 @@ impl Args {
})?;
if let Some(second_value) = self.args.get(1) {
let tag: SketchOnFaceTag = serde_json::from_value(second_value.get_json_value()?).map_err(|e| {
let tag: FaceTag = serde_json::from_value(second_value.get_json_value()?).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize SketchOnFaceTag from JSON: {}", e),
message: format!("Failed to deserialize FaceTag from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
@ -933,6 +929,57 @@ impl Args {
Ok((data, extrude_group))
}
fn get_data_and_extrude_group_and_tag<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, Box<ExtrudeGroup>, Option<String>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
})
})?;
let extrude_group = if let MemoryItem::ExtrudeGroup(eg) = second_value {
eg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
let tag = if let Some(tag) = self.args.get(2) {
tag.get_json_opt()?
} else {
None
};
Ok((data, extrude_group, tag))
}
fn get_segment_name_to_number_sketch_group(&self) -> Result<(String, f64, Box<SketchGroup>), KclError> {
// Iterate over our args, the first argument should be a UserVal with a string value.
// The second argument should be a number.
@ -1024,6 +1071,59 @@ impl Args {
Ok((number, sketch_set))
}
pub async fn get_adjacent_face_to_tag(
&self,
extrude_group: &ExtrudeGroup,
tag: &str,
must_be_planar: bool,
) -> Result<uuid::Uuid, KclError> {
if tag.is_empty() {
return Err(KclError::Type(KclErrorDetails {
message: "Expected a non-empty tag for the face".to_string(),
source_ranges: vec![self.source_range],
}));
}
if let Some(face_from_surface) = extrude_group
.value
.iter()
.find_map(|extrude_surface| match extrude_surface {
ExtrudeSurface::ExtrudePlane(extrude_plane) if extrude_plane.name == tag => {
Some(Ok(extrude_plane.face_id))
}
// The must be planar check must be called before the arc check.
ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails {
message: format!("Tag `{}` is a non-planar surface", tag),
source_ranges: vec![self.source_range],
}))),
ExtrudeSurface::ExtrudeArc(extrude_arc) if extrude_arc.name == tag => Some(Ok(extrude_arc.face_id)),
ExtrudeSurface::ExtrudePlane(_) | ExtrudeSurface::ExtrudeArc(_) => None,
})
{
return face_from_surface;
}
// A face could also be the result of a chamfer or fillet.
if let Some(face_from_chamfer_fillet) = extrude_group.fillet_or_chamfers.iter().find_map(|fc| {
if fc.tag() == Some(tag) {
Some(Ok(fc.id()))
} else {
None
}
}) {
// We want to make sure we execute the fillet before this operation.
self.flush_batch_for_extrude_group_set(extrude_group.into()).await?;
return face_from_chamfer_fillet;
}
// If we still haven't found the face, return an error.
Err(KclError::Type(KclErrorDetails {
message: format!("Expected a face with the tag `{}`", tag),
source_ranges: vec![self.source_range],
}))
}
}
/// Returns the length of the given leg.