use kcmc::each_cmd as mcmd;
use kittycad_modeling_cmds::ModelingCmd;
use kittycad_modeling_cmds::ok_response::OkModelingCmdResponse;
use kittycad_modeling_cmds::shared::PathSegment;
use kittycad_modeling_cmds::shared::Point3d;
use kittycad_modeling_cmds::units::UnitLength;
use kittycad_modeling_cmds::websocket::ModelingCmdReq;
use kittycad_modeling_cmds::websocket::OkWebSocketResponseData;
use kittycad_modeling_cmds::{self as kcmc};
use crate::ExecState;
use crate::errors::KclError;
use crate::exec::KclValue;
use crate::execution::ModelingCmdMeta;
use crate::execution::Solid;
use crate::execution::types::NumericTypeExt;
use crate::execution::types::PrimitiveType;
use crate::execution::types::RuntimeType;
use crate::std::Args;
use crate::std::args::TyF64;
use crate::std::sketch::PlaneData;
use crate::std::sketch::make_sketch_plane_from_orientation;
#[derive(Debug)]
pub struct Move {
end: Point3d<f32>,
point: Option<Point3d<f32>>,
}
pub fn s_curve(
part_width: f32,
part_height: f32,
tool_diameter: f32,
origin: Point3d<f32>,
direction: Point3d<f32>,
stepover: f32,
) -> Vec<Move> {
let overhang = tool_diameter;
let density = tool_diameter * stepover;
let start_point = Point3d {
x: direction.x * origin.x,
y: (-overhang) * direction.y + origin.y,
z: origin.z,
};
let mut moves: Vec<Move> = vec![];
let interval = (part_width / density).ceil() as i32 + 1;
moves.push(Move {
end: Point3d {
x: start_point.x,
y: start_point.y,
z: start_point.z,
},
point: None,
});
for i in 0..interval {
let x_row = (i as f32 * density * direction.x) + start_point.x;
let next_x_row = (((i + 1) as f32 * density) * direction.x) + start_point.x;
let diff_of_x_rows = (next_x_row - x_row) * direction.x / 2.0;
if i % 2 == 0 {
let x = x_row;
let _y = start_point.y;
let end_y = ((part_height + overhang + overhang) * direction.y) + start_point.y;
let arc_middle_y = start_point.y + (direction.y * (part_height + overhang + overhang + diff_of_x_rows));
moves.push(Move {
end: Point3d {
x,
y: end_y,
z: start_point.z,
},
point: None,
});
if i < interval - 1 {
moves.push(Move {
point: Some(Point3d {
x: x_row + diff_of_x_rows,
y: arc_middle_y,
z: start_point.z,
}),
end: Point3d {
x: next_x_row,
y: end_y,
z: start_point.z,
},
});
}
} else {
let x = x_row;
let y = start_point.y;
let arc_middle_y = -diff_of_x_rows * direction.y + start_point.y;
moves.push(Move {
end: Point3d { x, y, z: start_point.z },
point: None,
});
if i < interval - 1 {
moves.push(Move {
point: Some(Point3d {
x: x + diff_of_x_rows,
y: arc_middle_y,
z: start_point.z,
}),
end: Point3d {
x: next_x_row,
y,
z: start_point.z,
},
});
}
}
}
moves
}
pub async fn facing(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solid: Solid = args.get_unlabeled_kw_arg("solid", &RuntimeType::Primitive(PrimitiveType::Solid), exec_state)?;
let tool_diameter: TyF64 = args.get_kw_arg("toolDiameter", &RuntimeType::length(), exec_state)?;
let step_over: TyF64 = args.get_kw_arg("stepOver", &RuntimeType::num_any(), exec_state)?;
let bounding_box_cmd_id = exec_state.next_uuid();
let cmd = ModelingCmd::from(
mcmd::BoundingBox::builder()
.entity_ids(vec![solid.id])
.output_unit(UnitLength::Millimeters)
.build(),
);
let response = exec_state
.send_modeling_cmd(
ModelingCmdMeta::from_args_id(exec_state, &args, bounding_box_cmd_id),
cmd,
)
.await?;
let bounding_box = if let OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::BoundingBox(data),
} = response
{
Some(data)
} else {
None
};
if let Some(bounding_box) = bounding_box {
let aabb = bounding_box.dimensions;
let center = bounding_box.center;
let origin = Point3d {
x: (center.x - (aabb.x / 2.0)) as f32,
y: (center.y - (aabb.y / 2.0)) as f32,
z: (center.z + (aabb.z / 2.0)) as f32,
};
let direction = Point3d { x: 1.0, y: 1.0, z: 1.0 };
let part_width = aabb.x;
let part_height = aabb.y;
let moves = s_curve(
part_width as f32,
part_height as f32,
tool_diameter.to_mm() as f32,
origin,
direction,
step_over.n as f32,
);
let plane = make_sketch_plane_from_orientation(PlaneData::XY, exec_state, &args).await?;
let sketch_surface_id = plane.id;
let enable_sketch_id = exec_state.next_uuid();
let path_id = exec_state.next_uuid();
let disable_sketch_id = exec_state.next_uuid();
let mut cmds = vec![
ModelingCmdReq {
cmd: ModelingCmd::from(
mcmd::EnableSketchMode::builder()
.animated(false)
.ortho(false)
.entity_id(sketch_surface_id)
.adjust_camera(false)
.planar_normal(plane.info.x_axis.axes_cross_product(&plane.info.y_axis).into())
.build(),
),
cmd_id: enable_sketch_id.into(),
},
ModelingCmdReq {
cmd: ModelingCmd::from(mcmd::StartPath::default()),
cmd_id: path_id.into(),
},
ModelingCmdReq {
cmd: ModelingCmd::from(
mcmd::MovePathPen::builder()
.path(path_id.into())
.to(Point3d {
x: kittycad_modeling_cmds::length_unit::LengthUnit(moves[0].end.x as f64),
y: kittycad_modeling_cmds::length_unit::LengthUnit(moves[0].end.y as f64),
z: kittycad_modeling_cmds::length_unit::LengthUnit(moves[0].end.z as f64),
})
.build(),
),
cmd_id: exec_state.next_uuid().into(),
},
];
for move_op in moves {
match move_op.point {
Some(p) => {
cmds.push(ModelingCmdReq {
cmd_id: exec_state.next_uuid().into(),
cmd: ModelingCmd::from(
mcmd::ExtendPath::builder()
.path(path_id.into())
.segment(PathSegment::ArcTo {
interior: Point3d {
x: kittycad_modeling_cmds::length_unit::LengthUnit(p.x as f64),
y: kittycad_modeling_cmds::length_unit::LengthUnit(p.y as f64),
z: kittycad_modeling_cmds::length_unit::LengthUnit(p.z as f64),
},
end: Point3d {
x: kittycad_modeling_cmds::length_unit::LengthUnit(move_op.end.x as f64),
y: kittycad_modeling_cmds::length_unit::LengthUnit(move_op.end.y as f64),
z: kittycad_modeling_cmds::length_unit::LengthUnit(move_op.end.z as f64),
},
relative: false,
})
.build(),
),
});
}
None => {
cmds.push(ModelingCmdReq {
cmd_id: exec_state.next_uuid().into(),
cmd: ModelingCmd::from(
mcmd::ExtendPath::builder()
.path(path_id.into())
.segment(PathSegment::Line {
end: Point3d {
x: kittycad_modeling_cmds::length_unit::LengthUnit(move_op.end.x as f64),
y: kittycad_modeling_cmds::length_unit::LengthUnit(move_op.end.y as f64),
z: kittycad_modeling_cmds::length_unit::LengthUnit(move_op.end.z as f64),
},
relative: false,
})
.build(),
),
});
}
}
}
cmds.push(ModelingCmdReq {
cmd: ModelingCmd::SketchModeDisable(mcmd::SketchModeDisable::default()),
cmd_id: disable_sketch_id.into(),
});
exec_state
.batch_modeling_cmds(ModelingCmdMeta::new(exec_state, &args.ctx, args.source_range), &cmds)
.await?;
}
Ok(KclValue::Number {
value: 4.0,
ty: kcl_api::NumericType::count(),
meta: vec![],
})
}