Fix units not getting set properly with whole module imports (#5418)

* Add test for whole modules with non-default units

* Update output files since adding test

* Fix to not drop batched commands due to isolated mode

* Update output after fix

* Update other sim test outputs
This commit is contained in:
Jonathan Tran
2025-02-19 00:11:11 -05:00
committed by GitHub
parent 18d87b99bd
commit cd679f4be3
18 changed files with 857 additions and 488 deletions

View File

@ -13,7 +13,7 @@ use kcmc::{
},
ModelingCmd,
};
use kittycad_modeling_cmds::{self as kcmc, ok_response::OkModelingCmdResponse, websocket::ModelingBatch};
use kittycad_modeling_cmds::{self as kcmc};
use tokio::sync::{mpsc, oneshot, RwLock};
use tokio_tungstenite::tungstenite::Message as WsMsg;
use uuid::Uuid;
@ -415,35 +415,6 @@ impl EngineManager for EngineConnection {
cmd: WebSocketRequest,
_id_to_source_range: HashMap<Uuid, SourceRange>,
) -> Result<WebSocketResponse, KclError> {
// In isolated mode, we don't send the command to the engine.
if self.execution_kind().await.is_isolated() {
return match &cmd {
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch { requests, .. }) => {
let mut responses = HashMap::with_capacity(requests.len());
for request in requests {
responses.insert(
request.cmd_id,
BatchResponse::Success {
response: OkModelingCmdResponse::Empty {},
},
);
}
Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::ModelingBatch { responses },
success: true,
}))
}
_ => Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::Empty {},
},
success: true,
})),
};
}
let (tx, rx) = oneshot::channel();
// Send the request to the engine, via the actor.

View File

@ -4,19 +4,12 @@ use std::{collections::HashMap, sync::Arc};
use anyhow::Result;
use indexmap::IndexMap;
use kcmc::{
ok_response::OkModelingCmdResponse,
websocket::{
BatchResponse, ModelingBatch, OkWebSocketResponseData, SuccessWebSocketResponse, WebSocketRequest,
WebSocketResponse,
},
};
use kcmc::websocket::{WebSocketRequest, WebSocketResponse};
use kittycad_modeling_cmds as kcmc;
use tokio::sync::RwLock;
use uuid::Uuid;
use wasm_bindgen::prelude::*;
use crate::engine::EngineManager;
use crate::{
engine::ExecutionKind,
errors::{KclError, KclErrorDetails},
@ -82,35 +75,6 @@ impl EngineConnection {
cmd: WebSocketRequest,
id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
) -> Result<WebSocketResponse, KclError> {
// In isolated mode, we don't send the command to the engine.
if self.execution_kind().await.is_isolated() {
return match &cmd {
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch { requests, .. }) => {
let mut responses = HashMap::with_capacity(requests.len());
for request in requests {
responses.insert(
request.cmd_id,
BatchResponse::Success {
response: OkModelingCmdResponse::Empty {},
},
);
}
Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::ModelingBatch { responses },
success: true,
}))
}
_ => Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::Empty {},
},
success: true,
})),
};
}
let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("Failed to serialize source range: {:?}", e),

View File

@ -227,6 +227,11 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
source_range: SourceRange,
cmd: &ModelingCmd,
) -> Result<(), crate::errors::KclError> {
// In isolated mode, we don't send the command to the engine.
if self.execution_kind().await.is_isolated() {
return Ok(());
}
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
cmd: cmd.clone(),
cmd_id: id.into(),
@ -247,6 +252,11 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
source_range: SourceRange,
cmd: &ModelingCmd,
) -> Result<(), crate::errors::KclError> {
// In isolated mode, we don't send the command to the engine.
if self.execution_kind().await.is_isolated() {
return Ok(());
}
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
cmd: cmd.clone(),
cmd_id: id.into(),

View File

@ -1720,13 +1720,12 @@ impl JsonSchema for FunctionParam<'_> {
#[cfg(test)]
mod test {
use super::*;
use crate::{
execution::{memory::ProgramMemory, parse_execute},
parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
};
use super::*;
#[test]
fn test_assign_args_to_params() {
// Set up a little framework for this test.

View File

@ -949,6 +949,28 @@ mod import_foreign {
super::execute(TEST_NAME, false).await
}
}
mod assembly_non_default_units {
const TEST_NAME: &str = "assembly_non_default_units";
/// Test parsing KCL.
#[test]
fn parse() {
super::parse(TEST_NAME)
}
/// Test that parsing and unparsing KCL produces the original KCL input.
#[test]
fn unparse() {
super::unparse(TEST_NAME)
}
/// Test that KCL is executed correctly.
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_execute() {
super::execute(TEST_NAME, true).await
}
}
mod array_elem_push_fail {
const TEST_NAME: &str = "array_elem_push_fail";

View File

@ -0,0 +1,556 @@
---
source: kcl/src/simulation_tests.rs
description: Artifact commands assembly_non_default_units.kcl
---
[
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "plane_set_color",
"plane_id": "[uuid]",
"color": {
"r": 0.7,
"g": 0.28,
"b": 0.28,
"a": 0.4
}
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "plane_set_color",
"plane_id": "[uuid]",
"color": {
"r": 0.28,
"g": 0.7,
"b": 0.28,
"a": 0.4
}
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "plane_set_color",
"plane_id": "[uuid]",
"color": {
"r": 0.28,
"g": 0.28,
"b": 0.7,
"a": 0.4
}
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": -1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 0.0,
"y": -1.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": -1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "edge_lines_visible",
"hidden": false
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "object_visible",
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "object_visible",
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
33,
0
],
"command": {
"type": "set_scene_units",
"unit": "in"
}
},
{
"cmdId": "[uuid]",
"range": [
0,
33,
1
],
"command": {
"type": "set_scene_units",
"unit": "in"
}
},
{
"cmdId": "[uuid]",
"range": [
172,
191,
1
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 60.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
197,
239,
1
],
"command": {
"type": "enable_sketch_mode",
"entity_id": "[uuid]",
"ortho": false,
"animated": false,
"adjust_camera": false,
"planar_normal": {
"x": 0.0,
"y": -1.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
197,
239,
1
],
"command": {
"type": "start_path"
}
},
{
"cmdId": "[uuid]",
"range": [
197,
239,
1
],
"command": {
"type": "move_path_pen",
"path": "[uuid]",
"to": {
"x": 1.0,
"y": 0.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
197,
239,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "arc",
"center": {
"x": 0.0,
"y": 0.0
},
"radius": 1.0,
"start": {
"unit": "degrees",
"value": 0.0
},
"end": {
"unit": "degrees",
"value": 360.0
},
"relative": false
}
}
},
{
"cmdId": "[uuid]",
"range": [
197,
239,
1
],
"command": {
"type": "close_path",
"path_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [
0,
33,
2
],
"command": {
"type": "set_scene_units",
"unit": "in"
}
},
{
"cmdId": "[uuid]",
"range": [
89,
108,
2
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 60.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
114,
156,
2
],
"command": {
"type": "enable_sketch_mode",
"entity_id": "[uuid]",
"ortho": false,
"animated": false,
"adjust_camera": false,
"planar_normal": {
"x": 0.0,
"y": -1.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
114,
156,
2
],
"command": {
"type": "start_path"
}
},
{
"cmdId": "[uuid]",
"range": [
114,
156,
2
],
"command": {
"type": "move_path_pen",
"path": "[uuid]",
"to": {
"x": 1.0,
"y": 2.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
114,
156,
2
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "arc",
"center": {
"x": 0.0,
"y": 2.0
},
"radius": 1.0,
"start": {
"unit": "degrees",
"value": 0.0
},
"end": {
"unit": "degrees",
"value": 360.0
},
"relative": false
}
}
},
{
"cmdId": "[uuid]",
"range": [
114,
156,
2
],
"command": {
"type": "close_path",
"path_id": "[uuid]"
}
}
]

View File

@ -0,0 +1,6 @@
---
source: kcl/src/simulation_tests.rs
description: Artifact graph flowchart assembly_non_default_units.kcl
extension: md
snapshot_kind: binary
---

View File

@ -0,0 +1,21 @@
```mermaid
flowchart LR
subgraph path2 [Path]
2["Path<br>[197, 239, 1]"]
3["Segment<br>[197, 239, 1]"]
4[Solid2d]
end
subgraph path6 [Path]
6["Path<br>[114, 156, 2]"]
7["Segment<br>[114, 156, 2]"]
8[Solid2d]
end
1["Plane<br>[172, 191, 1]"]
5["Plane<br>[89, 108, 2]"]
1 --- 2
2 --- 3
2 --- 4
5 --- 6
6 --- 7
6 --- 8
```

View File

@ -0,0 +1,143 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing assembly_non_default_units.kcl
---
{
"Ok": {
"body": [
{
"end": 172,
"path": {
"type": "Kcl",
"filename": "other1.kcl"
},
"selector": {
"type": "None",
"alias": null
},
"start": 153,
"type": "ImportStatement",
"type": "ImportStatement"
},
{
"end": 192,
"path": {
"type": "Kcl",
"filename": "other2.kcl"
},
"selector": {
"type": "None",
"alias": null
},
"start": 173,
"type": "ImportStatement",
"type": "ImportStatement"
},
{
"end": 200,
"expression": {
"end": 200,
"name": "other1",
"start": 194,
"type": "Identifier",
"type": "Identifier"
},
"start": 194,
"type": "ExpressionStatement",
"type": "ExpressionStatement"
},
{
"end": 207,
"expression": {
"end": 207,
"name": "other2",
"start": 201,
"type": "Identifier",
"type": "Identifier"
},
"start": 201,
"type": "ExpressionStatement",
"type": "ExpressionStatement"
}
],
"end": 208,
"innerAttrs": [
{
"end": 33,
"name": {
"end": 9,
"name": "settings",
"start": 1,
"type": "Identifier"
},
"properties": [
{
"end": 32,
"key": {
"end": 27,
"name": "defaultLengthUnit",
"start": 10,
"type": "Identifier"
},
"start": 10,
"type": "ObjectProperty",
"value": {
"end": 32,
"name": "in",
"start": 30,
"type": "Identifier",
"type": "Identifier"
}
}
],
"start": 0,
"type": "Annotation"
}
],
"nonCodeMeta": {
"nonCodeNodes": {
"1": [
{
"end": 194,
"start": 192,
"type": "NonCodeNode",
"value": {
"type": "newLine"
}
}
]
},
"startNodes": [
{
"end": 36,
"start": 33,
"type": "NonCodeNode",
"value": {
"type": "newLine"
}
},
{
"end": 87,
"start": 36,
"type": "NonCodeNode",
"value": {
"type": "blockComment",
"value": "Use a default unit that isn't the default of mm.",
"style": "line"
}
},
{
"end": 152,
"start": 88,
"type": "NonCodeNode",
"value": {
"type": "blockComment",
"value": "This should look like two circles barely touching each other.",
"style": "line"
}
}
]
},
"start": 0
}
}

View File

@ -0,0 +1,3 @@
@settings(defaultLengthUnit = in)
export radius = 1

View File

@ -0,0 +1,10 @@
@settings(defaultLengthUnit = in)
// Use a default unit that isn't the default of mm.
// This should look like two circles barely touching each other.
import "other1.kcl"
import "other2.kcl"
other1
other2

View File

@ -0,0 +1,5 @@
---
source: kcl/src/simulation_tests.rs
description: Operations executed assembly_non_default_units.kcl
---
[]

View File

@ -0,0 +1,8 @@
@settings(defaultLengthUnit = in)
// This is not used, but it triggers the problem.
import radius from "globals.kcl"
// Use the same units as in the main importing file.
startSketchOn('XZ')
|> circle({ center = [0, 0], radius = 1 }, %)

View File

@ -0,0 +1,6 @@
@settings(defaultLengthUnit = in)
// Use the same units as in the main importing file.
startSketchOn('XZ')
|> circle({ center = [0, 2], radius = 1 }, %)

View File

@ -0,0 +1,64 @@
---
source: kcl/src/simulation_tests.rs
description: Variables in memory after executing assembly_non_default_units.kcl
---
{
"HALF_TURN": {
"type": "Number",
"value": 180.0,
"ty": {
"type": "Unknown"
},
"__meta": []
},
"QUARTER_TURN": {
"type": "Number",
"value": 90.0,
"ty": {
"type": "Unknown"
},
"__meta": []
},
"THREE_QUARTER_TURN": {
"type": "Number",
"value": 270.0,
"ty": {
"type": "Unknown"
},
"__meta": []
},
"ZERO": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Unknown"
},
"__meta": []
},
"other1": {
"type": "Module",
"value": 1,
"__meta": [
{
"sourceRange": [
153,
172,
0
]
}
]
},
"other2": {
"type": "Module",
"value": 2,
"__meta": [
{
"sourceRange": [
173,
192,
0
]
}
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -292,305 +292,5 @@ description: Artifact commands import_function_not_sketch.kcl
"type": "set_scene_units",
"unit": "in"
}
},
{
"cmdId": "[uuid]",
"range": [
52,
71,
1
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 60.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
77,
103,
1
],
"command": {
"type": "enable_sketch_mode",
"entity_id": "[uuid]",
"ortho": false,
"animated": false,
"adjust_camera": false,
"planar_normal": {
"x": 0.0,
"y": 0.0,
"z": 1.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
77,
103,
1
],
"command": {
"type": "start_path"
}
},
{
"cmdId": "[uuid]",
"range": [
77,
103,
1
],
"command": {
"type": "move_path_pen",
"path": "[uuid]",
"to": {
"x": 4.0,
"y": 12.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
109,
127,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 2.0,
"y": 0.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [
133,
152,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 0.0,
"y": -6.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [
158,
177,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 4.0,
"y": -6.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [
183,
202,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 0.0,
"y": -6.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [
208,
233,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": -3.75,
"y": -4.5,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [
239,
260,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 0.0,
"y": -5.5,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [
266,
285,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": -2.0,
"y": 0.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [
291,
298,
1
],
"command": {
"type": "close_path",
"path_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [
291,
298,
1
],
"command": {
"type": "sketch_mode_disable"
}
},
{
"cmdId": "[uuid]",
"range": [
304,
330,
1
],
"command": {
"type": "revolve",
"target": "[uuid]",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"axis_is_2d": true,
"angle": {
"unit": "degrees",
"value": 360.0
},
"tolerance": 0.0000001
}
},
{
"cmdId": "[uuid]",
"range": [
304,
330,
1
],
"command": {
"type": "object_bring_to_front",
"object_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [
304,
330,
1
],
"command": {
"type": "solid3d_get_extrusion_face_info",
"object_id": "[uuid]",
"edge_id": "[uuid]"
}
}
]

View File

@ -1,7 +1,6 @@
---
source: kcl/src/simulation_tests.rs
description: Artifact commands import_side_effect.kcl
snapshot_kind: text
---
[
{
@ -281,123 +280,5 @@ snapshot_kind: text
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [
81,
100,
1
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 60.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
106,
149,
1
],
"command": {
"type": "enable_sketch_mode",
"entity_id": "[uuid]",
"ortho": false,
"animated": false,
"adjust_camera": false,
"planar_normal": {
"x": 0.0,
"y": 0.0,
"z": 1.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
106,
149,
1
],
"command": {
"type": "start_path"
}
},
{
"cmdId": "[uuid]",
"range": [
106,
149,
1
],
"command": {
"type": "move_path_pen",
"path": "[uuid]",
"to": {
"x": 10.0,
"y": 0.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [
106,
149,
1
],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "arc",
"center": {
"x": 0.0,
"y": 0.0
},
"radius": 10.0,
"start": {
"unit": "degrees",
"value": 0.0
},
"end": {
"unit": "degrees",
"value": 360.0
},
"relative": false
}
}
},
{
"cmdId": "[uuid]",
"range": [
106,
149,
1
],
"command": {
"type": "close_path",
"path_id": "[uuid]"
}
}
]