@ -460,6 +460,13 @@ impl Sketch {
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/// Get the path by the curve ID.
|
||||
pub fn get_path_by_curve_id(&self, curve_id: uuid::Uuid) -> Option<Path> {
|
||||
self.paths
|
||||
.iter()
|
||||
.find_map(|path| (path.get_id() == curve_id).then(|| path.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A sketch type.
|
||||
@ -883,6 +890,11 @@ pub enum Path {
|
||||
/// The y coordinate.
|
||||
y: Option<f64>,
|
||||
},
|
||||
/// An angled line.
|
||||
AngledLine {
|
||||
#[serde(flatten)]
|
||||
base: BasePath,
|
||||
},
|
||||
/// A base path.
|
||||
Base {
|
||||
#[serde(flatten)]
|
||||
@ -903,7 +915,7 @@ pub enum Path {
|
||||
|
||||
/// What kind of path is this?
|
||||
#[derive(Display)]
|
||||
enum PathType {
|
||||
pub enum PathType {
|
||||
ToPoint,
|
||||
Base,
|
||||
TangentialArc,
|
||||
@ -912,6 +924,7 @@ enum PathType {
|
||||
CircleThreePoint,
|
||||
Horizontal,
|
||||
AngledLineTo,
|
||||
AngledLine,
|
||||
Arc,
|
||||
}
|
||||
|
||||
@ -925,6 +938,7 @@ impl From<&Path> for PathType {
|
||||
Path::CircleThreePoint { .. } => Self::CircleThreePoint,
|
||||
Path::Horizontal { .. } => Self::Horizontal,
|
||||
Path::AngledLineTo { .. } => Self::AngledLineTo,
|
||||
Path::AngledLine { .. } => Self::AngledLine,
|
||||
Path::Base { .. } => Self::Base,
|
||||
Path::Arc { .. } => Self::Arc,
|
||||
Path::ArcThreePoint { .. } => Self::Arc,
|
||||
@ -938,6 +952,7 @@ impl Path {
|
||||
Path::ToPoint { base } => base.geo_meta.id,
|
||||
Path::Horizontal { base, .. } => base.geo_meta.id,
|
||||
Path::AngledLineTo { base, .. } => base.geo_meta.id,
|
||||
Path::AngledLine { base } => base.geo_meta.id,
|
||||
Path::Base { base } => base.geo_meta.id,
|
||||
Path::TangentialArcTo { base, .. } => base.geo_meta.id,
|
||||
Path::TangentialArc { base, .. } => base.geo_meta.id,
|
||||
@ -953,6 +968,7 @@ impl Path {
|
||||
Path::ToPoint { base } => base.tag.clone(),
|
||||
Path::Horizontal { base, .. } => base.tag.clone(),
|
||||
Path::AngledLineTo { base, .. } => base.tag.clone(),
|
||||
Path::AngledLine { base, .. } => base.tag.clone(),
|
||||
Path::Base { base } => base.tag.clone(),
|
||||
Path::TangentialArcTo { base, .. } => base.tag.clone(),
|
||||
Path::TangentialArc { base, .. } => base.tag.clone(),
|
||||
@ -968,6 +984,7 @@ impl Path {
|
||||
Path::ToPoint { base } => base,
|
||||
Path::Horizontal { base, .. } => base,
|
||||
Path::AngledLineTo { base, .. } => base,
|
||||
Path::AngledLine { base, .. } => base,
|
||||
Path::Base { base } => base,
|
||||
Path::TangentialArcTo { base, .. } => base,
|
||||
Path::TangentialArc { base, .. } => base,
|
||||
@ -990,9 +1007,11 @@ impl Path {
|
||||
/// Length of this path segment, in cartesian plane.
|
||||
pub fn length(&self) -> f64 {
|
||||
match self {
|
||||
Self::ToPoint { .. } | Self::Base { .. } | Self::Horizontal { .. } | Self::AngledLineTo { .. } => {
|
||||
linear_distance(self.get_from(), self.get_to())
|
||||
}
|
||||
Self::ToPoint { .. }
|
||||
| Self::Base { .. }
|
||||
| Self::Horizontal { .. }
|
||||
| Self::AngledLineTo { .. }
|
||||
| Self::AngledLine { .. } => linear_distance(self.get_from(), self.get_to()),
|
||||
Self::TangentialArc {
|
||||
base: _,
|
||||
center,
|
||||
@ -1036,6 +1055,7 @@ impl Path {
|
||||
Path::ToPoint { base } => Some(base),
|
||||
Path::Horizontal { base, .. } => Some(base),
|
||||
Path::AngledLineTo { base, .. } => Some(base),
|
||||
Path::AngledLine { base, .. } => Some(base),
|
||||
Path::Base { base } => Some(base),
|
||||
Path::TangentialArcTo { base, .. } => Some(base),
|
||||
Path::TangentialArc { base, .. } => Some(base),
|
||||
@ -1083,7 +1103,11 @@ impl Path {
|
||||
radius,
|
||||
}
|
||||
}
|
||||
Path::ToPoint { .. } | Path::Horizontal { .. } | Path::AngledLineTo { .. } | Path::Base { .. } => {
|
||||
Path::ToPoint { .. }
|
||||
| Path::Horizontal { .. }
|
||||
| Path::AngledLineTo { .. }
|
||||
| Path::AngledLine { .. }
|
||||
| Path::Base { .. } => {
|
||||
let base = self.get_base();
|
||||
GetTangentialInfoFromPathsResult::PreviousPoint(base.from)
|
||||
}
|
||||
|
||||
@ -209,59 +209,44 @@ pub(crate) async fn do_post_extrude<'a>(
|
||||
};
|
||||
|
||||
// Face filtering attempt in order to resolve https://github.com/KittyCAD/modeling-app/issues/5328
|
||||
// In case of a sectional sweep, empirically it looks that the first n faces that are yielded from the sweep
|
||||
// are the ones that work with GetOppositeEdge and GetNextAdjacentEdge, aka the n sides in the sweep.
|
||||
// So here we're figuring out that n number as yielded_sides_count here,
|
||||
// making sure that circle() calls count but close() don't (no length)
|
||||
let count_of_first_set_of_faces_if_sectional = if sectional {
|
||||
sketch
|
||||
.paths
|
||||
// We need to not run Solid3dGetOppositeEdge and Solid3dGetNextAdjacentEdge because it is too
|
||||
// hard to know when they work or fail.
|
||||
if !sectional {
|
||||
for (curve_id, face_id) in face_infos
|
||||
.iter()
|
||||
.filter(|p| {
|
||||
let is_circle = matches!(p, Path::Circle { .. });
|
||||
let has_length = p.get_base().from != p.get_base().to;
|
||||
is_circle || has_length
|
||||
.filter(|face_info| face_info.cap == ExtrusionFaceCapType::None)
|
||||
.filter_map(|face_info| {
|
||||
if let (Some(curve_id), Some(face_id)) = (face_info.curve_id, face_info.face_id) {
|
||||
Some((curve_id, face_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.count()
|
||||
} else {
|
||||
usize::MAX
|
||||
};
|
||||
{
|
||||
// Batch these commands, because the Rust code doesn't actually care about the outcome.
|
||||
// So, there's no need to await them.
|
||||
// Instead, the Typescript codebases (which handles WebSocket sends when compiled via Wasm)
|
||||
// uses this to build the artifact graph, which the UI needs.
|
||||
args.batch_modeling_cmd(
|
||||
exec_state.next_uuid(),
|
||||
ModelingCmd::from(mcmd::Solid3dGetOppositeEdge {
|
||||
edge_id: curve_id,
|
||||
object_id: sketch.id,
|
||||
face_id,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
for (curve_id, face_id) in face_infos
|
||||
.iter()
|
||||
.filter(|face_info| face_info.cap == ExtrusionFaceCapType::None)
|
||||
.filter_map(|face_info| {
|
||||
if let (Some(curve_id), Some(face_id)) = (face_info.curve_id, face_info.face_id) {
|
||||
Some((curve_id, face_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.take(count_of_first_set_of_faces_if_sectional)
|
||||
{
|
||||
// Batch these commands, because the Rust code doesn't actually care about the outcome.
|
||||
// So, there's no need to await them.
|
||||
// Instead, the Typescript codebases (which handles WebSocket sends when compiled via Wasm)
|
||||
// uses this to build the artifact graph, which the UI needs.
|
||||
args.batch_modeling_cmd(
|
||||
exec_state.next_uuid(),
|
||||
ModelingCmd::from(mcmd::Solid3dGetOppositeEdge {
|
||||
edge_id: curve_id,
|
||||
object_id: sketch.id,
|
||||
face_id,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
args.batch_modeling_cmd(
|
||||
exec_state.next_uuid(),
|
||||
ModelingCmd::from(mcmd::Solid3dGetNextAdjacentEdge {
|
||||
edge_id: curve_id,
|
||||
object_id: sketch.id,
|
||||
face_id,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
args.batch_modeling_cmd(
|
||||
exec_state.next_uuid(),
|
||||
ModelingCmd::from(mcmd::Solid3dGetNextAdjacentEdge {
|
||||
edge_id: curve_id,
|
||||
object_id: sketch.id,
|
||||
face_id,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
let Faces {
|
||||
@ -293,7 +278,11 @@ pub(crate) async fn do_post_extrude<'a>(
|
||||
});
|
||||
Some(extrude_surface)
|
||||
}
|
||||
Path::Base { .. } | Path::ToPoint { .. } | Path::Horizontal { .. } | Path::AngledLineTo { .. } => {
|
||||
Path::Base { .. }
|
||||
| Path::ToPoint { .. }
|
||||
| Path::Horizontal { .. }
|
||||
| Path::AngledLineTo { .. }
|
||||
| Path::AngledLine { .. } => {
|
||||
let extrude_surface = ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane {
|
||||
face_id: *actual_face_id,
|
||||
tag: path.get_base().tag.clone(),
|
||||
|
||||
@ -479,7 +479,7 @@ async fn inner_angled_line(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let current_path = Path::ToPoint {
|
||||
let current_path = Path::AngledLine {
|
||||
base: BasePath {
|
||||
from: from.into(),
|
||||
to,
|
||||
|
||||
@ -140,7 +140,7 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// }, %)
|
||||
/// |> xLine(length = 384.93)
|
||||
///
|
||||
/// sweep([rectangleSketch, circleSketch], path = sweepPath, sectional = false)
|
||||
/// sweep([rectangleSketch, circleSketch], path = sweepPath)
|
||||
/// ```
|
||||
/// ```
|
||||
/// // Sectionally sweep one sketch along the path
|
||||
@ -190,6 +190,8 @@ async fn inner_sweep(
|
||||
SweepPath::Helix(helix) => helix.value.into(),
|
||||
};
|
||||
|
||||
let sectional = sectional.unwrap_or(true);
|
||||
|
||||
let mut solids = Vec::new();
|
||||
for sketch in &sketches {
|
||||
let id = exec_state.next_uuid();
|
||||
@ -198,7 +200,7 @@ async fn inner_sweep(
|
||||
ModelingCmd::from(mcmd::Sweep {
|
||||
target: sketch.id.into(),
|
||||
trajectory,
|
||||
sectional: sectional.unwrap_or(true),
|
||||
sectional,
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(DEFAULT_TOLERANCE)),
|
||||
}),
|
||||
)
|
||||
@ -209,7 +211,7 @@ async fn inner_sweep(
|
||||
sketch,
|
||||
id.into(),
|
||||
0.0,
|
||||
sectional.unwrap_or(false),
|
||||
sectional,
|
||||
&super::extrude::NamedCapTags {
|
||||
start: tag_start.as_ref(),
|
||||
end: tag_end.as_ref(),
|
||||
|
||||
Reference in New Issue
Block a user