Compare commits
	
		
			13 Commits
		
	
	
		
			kcl-71
			...
			mike/engin
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5bea90ad9a | |||
| d23ddc19eb | |||
| e65358f635 | |||
| 0a1201e680 | |||
| 9db013e672 | |||
| 0196d72a2d | |||
| e6af4078bd | |||
| 2b233dc705 | |||
| b11e8af9c7 | |||
| c017847d7b | |||
| 9635eea8c1 | |||
| 5a2df642b1 | |||
| 621e41080e | 
| @ -1,3 +1,4 @@ | ||||
| src/wasm-lib/* | ||||
| src/lib/engine-utils/engine.js | ||||
| *.typegen.ts | ||||
| packages/codemirror-lsp-client/dist/* | ||||
|  | ||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -66,3 +66,7 @@ venv | ||||
|  | ||||
| # electron | ||||
| out/ | ||||
|  | ||||
| # engine wasm utils | ||||
| src/lib/engine-utils/engine.wasm | ||||
| src/lib/engine-utils/engine.js | ||||
|  | ||||
| @ -110,6 +110,7 @@ const initialise = async () => { | ||||
|     const fullUrl = wasmUrl() | ||||
|     const input = await fetch(fullUrl) | ||||
|     const buffer = await input.arrayBuffer() | ||||
|  | ||||
|     return await init(buffer) | ||||
|   } catch (e) { | ||||
|     console.log('Error initialising WASM', e) | ||||
|  | ||||
							
								
								
									
										31
									
								
								src/lib/engineUtils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/lib/engineUtils.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| import EngineUtils from '@engine-utils' | ||||
|  | ||||
| type KCEngineUtilsEvaluatePath = { | ||||
|   (sketch: string, t: number): string | ||||
| } | ||||
| let kcEngineUtilsEvaluatePath: KCEngineUtilsEvaluatePath | ||||
|  | ||||
| export async function init() { | ||||
|   return await new Promise((resolve, reject) => { | ||||
|     try { | ||||
|       EngineUtils().then((module) => { | ||||
|         kcEngineUtilsEvaluatePath = module.cwrap( | ||||
|           'kcEngineUtilsEvaluatePath', | ||||
|           'string', | ||||
|           ['string', 'number'] | ||||
|         ) | ||||
|         resolve(true) | ||||
|       }) | ||||
|     } catch (e) { | ||||
|       reject(e) | ||||
|     } | ||||
|   }) | ||||
| } | ||||
|  | ||||
| export async function getTruePathEndPos(sketch: string) { | ||||
|   if (!kcEngineUtilsEvaluatePath) { | ||||
|     await init() | ||||
|   } | ||||
|  | ||||
|   return kcEngineUtilsEvaluatePath(sketch, 1.0) | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -121,9 +121,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "anyhow" | ||||
| version = "1.0.89" | ||||
| version = "1.0.91" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" | ||||
| checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" | ||||
| dependencies = [ | ||||
|  "backtrace", | ||||
| ] | ||||
| @ -1684,9 +1684,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "kittycad-modeling-cmds" | ||||
| version = "0.2.68" | ||||
| version = "0.2.70" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7e3aedfcc1d8ea9995ec3eb78a6743c585c9380475c48701797f107489b696aa" | ||||
| checksum = "b135696d07a4fab928e5abace4dd05f4976eafab5d73e5747a85dc5a684b936c" | ||||
| dependencies = [ | ||||
|  "anyhow", | ||||
|  "chrono", | ||||
| @ -3005,9 +3005,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "serde_json" | ||||
| version = "1.0.128" | ||||
| version = "1.0.132" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" | ||||
| checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" | ||||
| dependencies = [ | ||||
|  "indexmap 2.6.0", | ||||
|  "itoa", | ||||
|  | ||||
| @ -72,7 +72,7 @@ members = [ | ||||
| [workspace.dependencies] | ||||
| http = "1" | ||||
| kittycad = { version = "0.3.23", default-features = false, features = ["js", "requests"] } | ||||
| kittycad-modeling-cmds = { version = "0.2.68", features = ["websocket"] } | ||||
| kittycad-modeling-cmds = { version = "0.2.70", features = ["websocket"] } | ||||
|  | ||||
| [[test]] | ||||
| name = "executor" | ||||
|  | ||||
| @ -68,7 +68,7 @@ tokio-tungstenite = { version = "0.24.0", features = ["rustls-tls-native-roots"] | ||||
| tower-lsp = { version = "0.20.0", features = ["proposed"] } | ||||
|  | ||||
| [features] | ||||
| default = ["engine"] | ||||
| default = ["engine"]  # add wasm-engine-utils here when we're ready | ||||
| cli = ["dep:clap"] | ||||
| # For the lsp server, when run with stdout for rpc we want to disable println. | ||||
| # This is used for editor extensions that use the lsp server. | ||||
| @ -77,6 +77,10 @@ engine = [] | ||||
| pyo3 = ["dep:pyo3"] | ||||
| # Helper functions also used in benchmarks. | ||||
| lsp-test-util = [] | ||||
| #if enabled, kcl will link directly against a wasm build of the engine utils lib to save latency | ||||
| wasm-engine-utils = [] | ||||
| #if enabled, kcl will link directly against a native build of the engine utils lib to save latency (not yet functional) | ||||
| native-engine-utils = [] | ||||
|  | ||||
| tabled = ["dep:tabled"] | ||||
|  | ||||
|  | ||||
							
								
								
									
										57
									
								
								src/wasm-lib/kcl/src/engine/engine_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/wasm-lib/kcl/src/engine/engine_utils.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| //! Functions for calling into the engine-utils library (a set of C++ utilities containing various logic for client-side CAD processing) | ||||
| //! Note that this binary may not be available to all builds of kcl, so fallbacks that call the engine API should be implemented | ||||
|  | ||||
| use crate::{ | ||||
|     errors::{KclError, KclErrorDetails}, | ||||
|     std::Args, | ||||
| }; | ||||
| use anyhow::Result; | ||||
| use std::ffi::{CString, CStr}; | ||||
| use kittycad_modeling_cmds::{length_unit::LengthUnit, shared::Point3d}; | ||||
|  | ||||
| mod cpp { | ||||
|     use std::os::raw::c_char; | ||||
|  | ||||
|     extern "C" { | ||||
|         pub fn kcEngineUtilsEvaluatePath(sketch: *const c_char, t: f64) -> *const c_char; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| pub fn is_available() -> bool { | ||||
|     true | ||||
| } | ||||
|  | ||||
| pub async fn get_true_path_end_pos(sketch: String, args: &Args) -> Result<Point3d<LengthUnit>, KclError> { | ||||
|     let c_string = CString::new(sketch).map_err(|e| { | ||||
|         KclError::Internal(KclErrorDetails { | ||||
|             message: format!("{:?}", e), | ||||
|             source_ranges: vec![args.source_range], | ||||
|         }) | ||||
|     })?; | ||||
|     let arg = c_string.into_raw(); | ||||
|     let result_string: String; | ||||
|  | ||||
|     unsafe { | ||||
|         let result = cpp::kcEngineUtilsEvaluatePath(arg, 1.0); | ||||
|         let result_cstr = CStr::from_ptr(result); | ||||
|         let str_slice: &str = result_cstr.to_str().map_err(|e| { | ||||
|             KclError::Internal(KclErrorDetails { | ||||
|                 message: format!("{:?}", e), | ||||
|                 source_ranges: vec![args.source_range], | ||||
|             }) | ||||
|         })?; | ||||
|         let str_buf: String = str_slice.to_owned();     | ||||
|         result_string = str_buf.clone(); | ||||
|         let _ = CString::from_raw(arg); | ||||
|     } | ||||
|  | ||||
|     let point: Point3d<f64> = serde_json::from_str(&result_string).map_err(|e| { | ||||
|         KclError::Type(KclErrorDetails { | ||||
|             message: format!("Failed to path position from json: {}", e), | ||||
|             source_ranges: vec![args.source_range], | ||||
|         }) | ||||
|     })?; | ||||
|      | ||||
|     Ok(Point3d::<f64>::from(point).map(LengthUnit)) | ||||
| } | ||||
							
								
								
									
										35
									
								
								src/wasm-lib/kcl/src/engine/engine_utils_api.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/wasm-lib/kcl/src/engine/engine_utils_api.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| //! Functions for calling into the engine-utils library (a set of C++ utilities containing various logic for client-side CAD processing) | ||||
| //! Note that this binary may not be available to all builds of kcl, so fallbacks that call the engine API should be implemented | ||||
|  | ||||
| use crate::{ | ||||
|     errors::{KclError, KclErrorDetails}, | ||||
|     std::Args, | ||||
| }; | ||||
| use crate::engine::kcmc::{each_cmd as mcmd, ModelingCmd}; | ||||
| use anyhow::Result; | ||||
| use kittycad_modeling_cmds::{length_unit::LengthUnit, ok_response::OkModelingCmdResponse, shared::Point3d, websocket::OkWebSocketResponseData}; | ||||
|  | ||||
| pub fn is_available() -> bool { | ||||
|     true | ||||
| } | ||||
|  | ||||
| pub async fn get_true_path_end_pos(sketch: String, args: &Args) -> Result<Point3d<LengthUnit>, KclError> { | ||||
|     let id = uuid::Uuid::new_v4(); | ||||
|      | ||||
|     let resp = args.send_modeling_cmd(id, ModelingCmd::from(mcmd::EngineUtilEvaluatePath { | ||||
|         path_json: sketch, | ||||
|         t: 1.0, | ||||
|     })).await?; | ||||
|  | ||||
|     let OkWebSocketResponseData::Modeling { | ||||
|         modeling_response: OkModelingCmdResponse::EngineUtilEvaluatePath(point), | ||||
|     } = &resp  | ||||
|     else { | ||||
|         return Err(KclError::Engine(KclErrorDetails { | ||||
|             message: format!("mcmd::EngineUtilEvaluatePath response was not as expected: {:?}", resp), | ||||
|             source_ranges: vec![args.source_range], | ||||
|         })); | ||||
|     }; | ||||
|  | ||||
|     Ok(point.pos) | ||||
| } | ||||
							
								
								
									
										56
									
								
								src/wasm-lib/kcl/src/engine/engine_utils_wasm.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/wasm-lib/kcl/src/engine/engine_utils_wasm.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| //! Functions for calling into the engine-utils library (a set of C++ utilities containing various logic for client-side CAD processing) | ||||
| //! Note that this binary may not be available to all builds of kcl, so fallbacks that call the engine API should be implemented | ||||
|  | ||||
| use crate::{ | ||||
|     errors::{KclError, KclErrorDetails}, | ||||
|     std::Args, | ||||
| }; | ||||
| use anyhow::Result; | ||||
| use kittycad_modeling_cmds::{length_unit::LengthUnit, shared::Point3d}; | ||||
| mod cpp { | ||||
|     use wasm_bindgen::prelude::wasm_bindgen; | ||||
|  | ||||
|     #[wasm_bindgen(module = "/../../lib/engineUtils.ts")] | ||||
|     extern "C" { | ||||
|         #[wasm_bindgen(js_name = getTruePathEndPos, catch)] | ||||
|         pub fn get_true_path_end_pos(sketch: String) -> Result<js_sys::Promise, js_sys::Error>; | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn is_available() -> bool { | ||||
|     true | ||||
| } | ||||
|  | ||||
| async fn call_cpp<F>(args: &Args, f: F) -> Result<String, KclError> | ||||
| where | ||||
|     F: FnOnce() -> Result<js_sys::Promise, js_sys::Error>, | ||||
| { | ||||
|     let promise = f().map_err(|e| { | ||||
|         KclError::Internal(KclErrorDetails { | ||||
|             message: format!("{:?}", e), | ||||
|             source_ranges: vec![args.source_range], | ||||
|         }) | ||||
|     })?; | ||||
|  | ||||
|     let result = crate::wasm::JsFuture::from(promise).await.map_err(|e| { | ||||
|         KclError::Internal(KclErrorDetails { | ||||
|             message: format!("{:?}", e), | ||||
|             source_ranges: vec![args.source_range], | ||||
|         }) | ||||
|     })?; | ||||
|  | ||||
|     Ok(result.as_string().unwrap_or_default()) | ||||
| } | ||||
|  | ||||
| pub async fn get_true_path_end_pos(sketch: String, args: &Args) -> Result<Point3d<LengthUnit>, KclError> { | ||||
|     let result_str = call_cpp(args, || cpp::get_true_path_end_pos(sketch.into())).await?; | ||||
|  | ||||
|     let point: Point3d<f64> = serde_json::from_str(&result_str).map_err(|e| { | ||||
|         KclError::Type(KclErrorDetails { | ||||
|             message: format!("Failed to path position from json: {}", e), | ||||
|             source_ranges: vec![args.source_range], | ||||
|         }) | ||||
|     })?; | ||||
|  | ||||
|     Ok(Point3d::<f64>::from(point).map(LengthUnit)) | ||||
| } | ||||
| @ -8,6 +8,17 @@ pub mod conn_mock; | ||||
| #[cfg(feature = "engine")] | ||||
| pub mod conn_wasm; | ||||
|  | ||||
| #[cfg(not(target_arch = "wasm32"))] | ||||
| #[cfg(feature = "native-engine-utils")] | ||||
| pub mod engine_utils; | ||||
| #[cfg(target_arch = "wasm32")] | ||||
| #[cfg(feature = "wasm-engine-utils")] | ||||
| pub mod engine_utils_wasm; | ||||
|  | ||||
| #[cfg(feature = "engine")] | ||||
| #[cfg(any(not(target_arch = "wasm32"), all(not(feature = "native-engine-utils"), not(feature = "wasm-engine-utils"))))] | ||||
| pub mod engine_utils_api; | ||||
|  | ||||
| use std::{ | ||||
|     collections::HashMap, | ||||
|     sync::{Arc, Mutex}, | ||||
|  | ||||
| @ -1601,6 +1601,19 @@ pub enum Path { | ||||
|         #[serde(flatten)] | ||||
|         base: BasePath, | ||||
|     }, | ||||
|     /// An arc (only used for engine-utils arg serialization for now) | ||||
|     Arc { | ||||
|         #[serde(flatten)] | ||||
|         base: BasePath, | ||||
|         /// angle range | ||||
|         #[ts(type = "[number, number]")] | ||||
|         angle_range: [f64; 2], | ||||
|         /// center | ||||
|         #[ts(type = "[number, number]")] | ||||
|         center: [f64; 2], | ||||
|         /// the arc's radius | ||||
|         radius: f64, | ||||
|     }, | ||||
|     /// A arc that is tangential to the last path segment that goes to a point | ||||
|     TangentialArcTo { | ||||
|         #[serde(flatten)] | ||||
| @ -1620,6 +1633,10 @@ pub enum Path { | ||||
|         center: [f64; 2], | ||||
|         /// arc's direction | ||||
|         ccw: bool, | ||||
|         /// the arc's radius | ||||
|         radius: f64, | ||||
|         /// the arc's angle offset | ||||
|         offset: f64, | ||||
|     }, | ||||
|     // TODO: consolidate segment enums, remove Circle. https://github.com/KittyCAD/modeling-app/issues/3940 | ||||
|     /// a complete arc | ||||
| @ -1668,6 +1685,7 @@ impl Path { | ||||
|             Path::TangentialArcTo { base, .. } => base.geo_meta.id, | ||||
|             Path::TangentialArc { base, .. } => base.geo_meta.id, | ||||
|             Path::Circle { base, .. } => base.geo_meta.id, | ||||
|             Path::Arc { base, .. } => base.geo_meta.id, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1680,6 +1698,7 @@ impl Path { | ||||
|             Path::TangentialArcTo { base, .. } => base.tag.clone(), | ||||
|             Path::TangentialArc { base, .. } => base.tag.clone(), | ||||
|             Path::Circle { base, .. } => base.tag.clone(), | ||||
|             Path::Arc { base, .. } => base.tag.clone(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1692,6 +1711,7 @@ impl Path { | ||||
|             Path::TangentialArcTo { base, .. } => base, | ||||
|             Path::TangentialArc { base, .. } => base, | ||||
|             Path::Circle { base, .. } => base, | ||||
|             Path::Arc { base, .. } => base, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1704,6 +1724,7 @@ impl Path { | ||||
|             Path::TangentialArcTo { base, .. } => Some(base), | ||||
|             Path::TangentialArc { base, .. } => Some(base), | ||||
|             Path::Circle { base, .. } => Some(base), | ||||
|             Path::Arc { base, .. } => Some(base), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -256,6 +256,7 @@ pub(crate) async fn do_post_extrude( | ||||
|                         }); | ||||
|                         Some(extrude_surface) | ||||
|                     } | ||||
|                     Path::Arc { .. } => todo!(), | ||||
|                 } | ||||
|             } else if args.ctx.is_mock() { | ||||
|                 // Only pre-populate the extrude surface if we are in mock mode. | ||||
|  | ||||
| @ -6,7 +6,7 @@ use anyhow::Result; | ||||
| use derive_docs::stdlib; | ||||
| use kcmc::shared::Point2d as KPoint2d; // Point2d is already defined in this pkg, to impl ts_rs traits. | ||||
| use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, ModelingCmd}; | ||||
| use kittycad_modeling_cmds as kcmc; | ||||
| use kittycad_modeling_cmds::{self as kcmc, units}; | ||||
| use kittycad_modeling_cmds::shared::PathSegment; | ||||
| use parse_display::{Display, FromStr}; | ||||
| use schemars::JsonSchema; | ||||
| @ -21,13 +21,26 @@ use crate::{ | ||||
|     }, | ||||
|     std::{ | ||||
|         utils::{ | ||||
|             arc_angles, arc_center_and_end, get_tangent_point_from_previous_arc, get_tangential_arc_to_info, | ||||
|             get_x_component, get_y_component, intersection_with_parallel_line, TangentialArcInfoInput, | ||||
|             arc_angles, arc_center_and_end, arc_start_center_and_end, get_tangent_point_from_previous_arc, | ||||
|             get_tangential_arc_to_info, get_x_component, get_y_component, intersection_with_parallel_line, | ||||
|             TangentialArcInfoInput, | ||||
|         }, | ||||
|         Args, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| #[cfg(not(target_arch = "wasm32"))] | ||||
| #[cfg(feature = "native-engine-utils")] | ||||
| use crate::engine::engine_utils; | ||||
|  | ||||
| #[cfg(target_arch = "wasm32")] | ||||
| #[cfg(feature = "wasm-engine-utils")] | ||||
| use crate::engine::engine_utils_wasm as engine_utils; | ||||
|  | ||||
| #[cfg(feature = "engine")] | ||||
| #[cfg(any(not(target_arch = "wasm32"), all(not(feature = "native-engine-utils"), not(feature = "wasm-engine-utils"))))] | ||||
| use crate::engine::engine_utils_api as engine_utils; | ||||
|  | ||||
| /// A tag for a face. | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export)] | ||||
| @ -1495,7 +1508,45 @@ pub(crate) async fn inner_arc( | ||||
|         } => { | ||||
|             let a_start = Angle::from_degrees(*angle_start); | ||||
|             let a_end = Angle::from_degrees(*angle_end); | ||||
|             let (center, end) = arc_center_and_end(from, a_start, a_end, *radius); | ||||
|  | ||||
|             let (_, center, mut end) = arc_start_center_and_end(from, a_start, a_end, *radius); | ||||
|  | ||||
|             if engine_utils::is_available() { | ||||
|                 let mut path_plus_arc = sketch.clone(); | ||||
|                 let to = [0.0, 0.0]; | ||||
|                 let arc = Path::Arc { | ||||
|                     base: BasePath { | ||||
|                         from: from.into(), | ||||
|                         to, | ||||
|                         tag: None, | ||||
|                         geo_meta: GeoMeta { | ||||
|                             id: uuid::Uuid::new_v4(), | ||||
|                             metadata: args.source_range.into(), | ||||
|                         }, | ||||
|                     }, | ||||
|                     angle_range: [*angle_start, *angle_end], | ||||
|                     center: [center.x, center.y], | ||||
|                     radius: *radius, | ||||
|                 }; | ||||
|  | ||||
|                 path_plus_arc.value.push(arc); | ||||
|  | ||||
|                 let sketch_json_value = serde_json::to_string(&path_plus_arc).map_err(|e| { | ||||
|                     KclError::Type(KclErrorDetails { | ||||
|                         message: format!("Failed to convert sketch to json: {}", e), | ||||
|                         source_ranges: vec![args.source_range], | ||||
|                     }) | ||||
|                 })?; | ||||
|  | ||||
|                 //???? someone double check me on this unit conversion - mike | ||||
|                 let units = units::UnitLength::Millimeters; | ||||
|                 let result_end = engine_utils::get_true_path_end_pos(sketch_json_value, &args).await?; | ||||
|                 end = Point2d {  | ||||
|                     x: result_end.x.to_millimeters(units), | ||||
|                     y: result_end.y.to_millimeters(units), | ||||
|                 }; | ||||
|             } | ||||
|  | ||||
|             (center, a_start, a_end, *radius, end) | ||||
|         } | ||||
|         ArcData::CenterToRadius { center, to, radius } => { | ||||
| @ -1616,7 +1667,7 @@ async fn inner_tangential_arc( | ||||
|  | ||||
|     let id = exec_state.id_generator.next_uuid(); | ||||
|  | ||||
|     let (center, to, ccw) = match data { | ||||
|     let (center, to, ccw, radius, offset) = match data { | ||||
|         TangentialArcData::RadiusAndOffset { radius, offset } => { | ||||
|             // KCL stdlib types use degrees. | ||||
|             let offset = Angle::from_degrees(offset); | ||||
| @ -1654,13 +1705,15 @@ async fn inner_tangential_arc( | ||||
|                 }), | ||||
|             ) | ||||
|             .await?; | ||||
|             (center, to.into(), ccw) | ||||
|             (center, to.into(), ccw, radius, offset) | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     let current_path = Path::TangentialArc { | ||||
|         ccw, | ||||
|         center: center.into(), | ||||
|         radius, | ||||
|         offset: offset.to_degrees(), | ||||
|         base: BasePath { | ||||
|             from: from.into(), | ||||
|             to, | ||||
|  | ||||
| @ -221,6 +221,33 @@ pub fn arc_center_and_end(from: Point2d, start_angle: Angle, end_angle: Angle, r | ||||
|     (center, end) | ||||
| } | ||||
|  | ||||
| pub fn arc_start_center_and_end( | ||||
|     from: Point2d, | ||||
|     start_angle: Angle, | ||||
|     end_angle: Angle, | ||||
|     radius: f64, | ||||
| ) -> (Point2d, Point2d, Point2d) { | ||||
|     let start_angle = start_angle.to_radians(); | ||||
|     let end_angle = end_angle.to_radians(); | ||||
|  | ||||
|     let center = Point2d { | ||||
|         x: -1.0 * (radius * start_angle.cos() - from.x), | ||||
|         y: -1.0 * (radius * start_angle.sin() - from.y), | ||||
|     }; | ||||
|  | ||||
|     let start = Point2d { | ||||
|         x: center.x + radius * start_angle.cos(), | ||||
|         y: center.y + radius * start_angle.sin(), | ||||
|     }; | ||||
|  | ||||
|     let end = Point2d { | ||||
|         x: center.x + radius * end_angle.cos(), | ||||
|         y: center.y + radius * end_angle.sin(), | ||||
|     }; | ||||
|  | ||||
|     (start, center, end) | ||||
| } | ||||
|  | ||||
| pub fn arc_angles( | ||||
|     from: Point2d, | ||||
|     to: Point2d, | ||||
|  | ||||
| @ -58,6 +58,7 @@ const config = defineConfig({ | ||||
|   resolve: { | ||||
|     alias: { | ||||
|       '@kittycad/codemirror-lsp-client': '/packages/codemirror-lsp-client/src', | ||||
|       '@engine-utils': '/src/lib/engine-utils/engine.js', | ||||
|     }, | ||||
|   }, | ||||
|   plugins: [react(), viteTsconfigPaths(), eslint(), version(), lezer()], | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	