sketching on a mirror2d thats been extruded fixed! (#6149)

* updates

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

* snap

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

* fixes

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

* add sample

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

* updates

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

* updates

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

* updates

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

* fixes

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

* snap

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2025-04-04 12:55:21 -07:00
committed by GitHub
parent 4d31fb890d
commit bfdf8babed
17 changed files with 891 additions and 443 deletions

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,6 @@ import pipeInnerDiameter, pipeOuterDiameter, pipeLength from "parameters.kcl"
// Create a function to make the pipe. Export // Create a function to make the pipe. Export
export fn pipe() { export fn pipe() {
// Create the pipe base // Create the pipe base
pipeBase = startSketchOn(XZ) pipeBase = startSketchOn(XZ)
|> circle(%, center = [0, 0], radius = pipeOuterDiameter / 2) |> circle(%, center = [0, 0], radius = pipeOuterDiameter / 2)

View File

@ -9,7 +9,6 @@ import pipeDiameter, mountingHoleDiameter, mountingHolePlacementDiameter, flange
// Create a function to create the flange. We must create a function since we are using multiple flanges. // Create a function to create the flange. We must create a function since we are using multiple flanges.
export fn flange() { export fn flange() {
// Sketch the mounting hole pattern // Sketch the mounting hole pattern
mountingHoles = startSketchOn(XY) mountingHoles = startSketchOn(XY)
|> circle(%, center = [0, mountingHolePlacementDiameter / 2], radius = mountingHoleDiameter / 2) |> circle(%, center = [0, mountingHolePlacementDiameter / 2], radius = mountingHoleDiameter / 2)

View File

@ -9,7 +9,6 @@ import hexNutDiameter, hexNutFlatToFlat, hexNutThickness, hexNutFlatLength from
// Create a function to make the hex nut. Must be a function since multiple hex nuts are used // Create a function to make the hex nut. Must be a function since multiple hex nuts are used
export fn hexNut() { export fn hexNut() {
// Create the base of the hex nut // Create the base of the hex nut
hexNutBase = startSketchOn(XY) hexNutBase = startSketchOn(XY)
|> startProfileAt([ |> startProfileAt([

View File

@ -8,7 +8,7 @@
import * from "parameters.kcl" import * from "parameters.kcl"
// Import parts // Import parts
import '9472k188-gasket.kcl' as gasket import "9472k188-gasket.kcl" as gasket
import flange from "68095k348-flange.kcl" import flange from "68095k348-flange.kcl"
import washer from "98017a257-washer.kcl" import washer from "98017a257-washer.kcl"
import bolt from "91251a404-bolt.kcl" import bolt from "91251a404-bolt.kcl"

View File

@ -418,6 +418,9 @@ pub struct Sketch {
pub artifact_id: ArtifactId, pub artifact_id: ArtifactId,
#[ts(skip)] #[ts(skip)]
pub original_id: uuid::Uuid, pub original_id: uuid::Uuid,
/// If the sketch includes a mirror.
#[serde(skip)]
pub mirror: Option<uuid::Uuid>,
pub units: UnitLen, pub units: UnitLen,
/// Metadata. /// Metadata.
#[serde(skip)] #[serde(skip)]

View File

@ -13,7 +13,7 @@ use kcmc::{
websocket::{ModelingCmdReq, OkWebSocketResponseData}, websocket::{ModelingCmdReq, OkWebSocketResponseData},
ModelingCmd, ModelingCmd,
}; };
use kittycad_modeling_cmds as kcmc; use kittycad_modeling_cmds::{self as kcmc};
use uuid::Uuid; use uuid::Uuid;
use crate::{ use crate::{
@ -168,6 +168,9 @@ pub(crate) async fn do_post_extrude<'a>(
) )
.await?; .await?;
let any_edge_id = if let Some(edge_id) = sketch.mirror {
edge_id
} else {
// The "get extrusion face info" API call requires *any* edge on the sketch being extruded. // The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
// So, let's just use the first one. // So, let's just use the first one.
let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else { let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else {
@ -176,6 +179,8 @@ pub(crate) async fn do_post_extrude<'a>(
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
})); }));
}; };
any_edge_id
};
let mut sketch = sketch.clone(); let mut sketch = sketch.clone();

View File

@ -2,10 +2,13 @@
use anyhow::Result; use anyhow::Result;
use kcmc::{each_cmd as mcmd, ModelingCmd}; use kcmc::{each_cmd as mcmd, ModelingCmd};
use kittycad_modeling_cmds::{self as kcmc, length_unit::LengthUnit, shared::Point3d}; use kittycad_modeling_cmds::{
self as kcmc, length_unit::LengthUnit, ok_response::OkModelingCmdResponse, output::EntityGetAllChildUuids,
shared::Point3d, websocket::OkWebSocketResponseData,
};
use crate::{ use crate::{
errors::KclError, errors::{KclError, KclErrorDetails},
execution::{ execution::{
types::{PrimitiveType, RuntimeType}, types::{PrimitiveType, RuntimeType},
ExecState, KclValue, Sketch, ExecState, KclValue, Sketch,
@ -31,13 +34,21 @@ pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValu
Ok(sketches.into()) Ok(sketches.into())
} }
/// Mirror a sketch.
///
/// Only works on unclosed sketches for now.
async fn inner_mirror_2d( async fn inner_mirror_2d(
sketches: Vec<Sketch>, sketches: Vec<Sketch>,
axis: Axis2dOrEdgeReference, axis: Axis2dOrEdgeReference,
exec_state: &mut ExecState, exec_state: &mut ExecState,
args: Args, args: Args,
) -> Result<Vec<Sketch>, KclError> { ) -> Result<Vec<Sketch>, KclError> {
let starting_sketches = sketches; let mut starting_sketches = sketches.clone();
// Update all to have a mirror.
starting_sketches.iter_mut().for_each(|sketch| {
sketch.mirror = Some(exec_state.next_uuid());
});
if args.ctx.no_engine_commands().await { if args.ctx.no_engine_commands().await {
return Ok(starting_sketches); return Ok(starting_sketches);
@ -77,5 +88,40 @@ async fn inner_mirror_2d(
} }
}; };
// After the mirror, get the first child uuid for the path.
// The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
// But if you mirror2d a sketch these IDs might change so we need to get the children versus
// using the IDs we already have.
// We only do this with mirrors because otherwise it is a waste of a websocket call.
for sketch in &mut starting_sketches {
let response = args
.send_modeling_cmd(
exec_state.next_uuid(),
ModelingCmd::from(mcmd::EntityGetAllChildUuids { entity_id: sketch.id }),
)
.await?;
let OkWebSocketResponseData::Modeling {
modeling_response:
OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }),
} = response
else {
return Err(KclError::Internal(KclErrorDetails {
message: "Expected a successful response from EntityGetAllChildUuids".to_string(),
source_ranges: vec![args.source_range],
}));
};
if child_ids.len() >= 2 {
// The first child is the original sketch, the second is the mirrored sketch.
let child_id = child_ids[1];
sketch.mirror = Some(child_id);
} else {
return Err(KclError::Type(KclErrorDetails {
message: "Expected child uuids to be >= 2".to_string(),
source_ranges: vec![args.source_range],
}));
}
}
Ok(starting_sketches) Ok(starting_sketches)
} }

View File

@ -1343,6 +1343,7 @@ pub(crate) async fn inner_start_profile_at(
on: sketch_surface.clone(), on: sketch_surface.clone(),
paths: vec![], paths: vec![],
units: sketch_surface.units(), units: sketch_surface.units(),
mirror: Default::default(),
meta: vec![args.source_range.into()], meta: vec![args.source_range.into()],
tags: if let Some(tag) = &tag { tags: if let Some(tag) = &tag {
let mut tag_identifier: TagIdentifier = tag.into(); let mut tag_identifier: TagIdentifier = tag.into();

View File

@ -96,6 +96,25 @@ export fn circle(
/// ///
/// example = extrude(sketch001, length = 10) /// example = extrude(sketch001, length = 10)
/// ``` /// ```
///
/// ```
/// // Sketch on the face of a mirrored sketch, that has been extruded.
/// sketch0011 = startSketchOn(XY)
/// |> startProfileAt([6.77, 0], %)
/// |> yLine(length = 1.27)
/// |> tangentialArcTo([5.96, 2.37], %)
/// |> tangentialArcTo([-6.2, 2.44], %)
/// |> tangentialArcTo([-6.6, 1.82], %)
/// |> yLine(length = -1.82)
/// |> mirror2d( axis = X )
/// |> extrude(length = 10)
///
/// sketch002 = startSketchOn(sketch0011, 'END')
/// |> circle( center = [-0.01, 1.58], radius = 1.2 )
/// |> extrude(length = 1.2)
///
/// shell([sketch002], faces = ['end'], thickness = .1 )
/// ```
@(impl = std_rust) @(impl = std_rust)
export fn mirror2d( export fn mirror2d(
/// The sketch or sketches to be reflected. /// The sketch or sketches to be reflected.

View File

@ -209,6 +209,14 @@ description: Artifact commands i-beam.kcl
} }
} }
}, },
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "entity_get_all_child_uuids",
"entity_id": "[uuid]"
}
},
{ {
"cmdId": "[uuid]", "cmdId": "[uuid]",
"range": [], "range": [],
@ -229,6 +237,14 @@ description: Artifact commands i-beam.kcl
} }
} }
}, },
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "entity_get_all_child_uuids",
"entity_id": "[uuid]"
}
},
{ {
"cmdId": "[uuid]", "cmdId": "[uuid]",
"range": [], "range": [],
@ -278,5 +294,345 @@ description: Artifact commands i-beam.kcl
"object_id": "[uuid]", "object_id": "[uuid]",
"edge_id": "[uuid]" "edge_id": "[uuid]"
} }
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
} }
] ]

View File

@ -215,8 +215,8 @@ description: Variables in memory after executing i-beam.kcl
} }
}, },
"height": 72.00000000000001, "height": 72.00000000000001,
"startCapId": null, "startCapId": "[uuid]",
"endCapId": null, "endCapId": "[uuid]",
"units": { "units": {
"type": "Inches" "type": "Inches"
} }

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB