diff --git a/docs/kcl/std.json b/docs/kcl/std.json index 4a2248351..b80f789a4 100644 --- a/docs/kcl/std.json +++ b/docs/kcl/std.json @@ -12958,225 +12958,652 @@ "args": [ { "name": "hole_sketch_group", - "type": "SketchGroup", + "type": "SketchGroupSet", "schema": { - "description": "A sketch group is a collection of paths.", - "type": "object", - "required": [ - "__meta", - "id", - "position", - "rotation", - "start", - "value", - "xAxis", - "yAxis", - "zAxis" - ], - "properties": { - "__meta": { - "description": "Metadata.", - "type": "array", - "items": { - "description": "Metadata.", - "type": "object", - "required": [ - "sourceRange" - ], - "properties": { - "sourceRange": { - "description": "The source range.", - "type": "array", - "items": { - "type": "integer", - "format": "uint", - "minimum": 0.0 - }, - "maxItems": 2, - "minItems": 2 - } - } - } - }, - "id": { - "description": "The id of the sketch group.", - "type": "string", - "format": "uuid" - }, - "planeId": { - "description": "The plane id of the sketch group.", - "type": "string", - "format": "uuid", - "nullable": true - }, - "position": { - "description": "The position of the sketch group.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 3, - "minItems": 3 - }, - "rotation": { - "description": "The rotation of the sketch group base plane.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 4, - "minItems": 4 - }, - "start": { - "description": "The starting path.", + "description": "A sketch group or a group of sketch groups.", + "oneOf": [ + { + "description": "A sketch group is a collection of paths.", "type": "object", "required": [ - "__geoMeta", - "from", - "name", - "to" + "__meta", + "id", + "position", + "rotation", + "start", + "type", + "value", + "xAxis", + "yAxis", + "zAxis" ], "properties": { - "__geoMeta": { + "__meta": { "description": "Metadata.", + "type": "array", + "items": { + "description": "Metadata.", + "type": "object", + "required": [ + "sourceRange" + ], + "properties": { + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + } + }, + "id": { + "description": "The id of the sketch group.", + "type": "string", + "format": "uuid" + }, + "planeId": { + "description": "The plane id of the sketch group.", + "type": "string", + "format": "uuid", + "nullable": true + }, + "position": { + "description": "The position of the sketch group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation of the sketch group base plane.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "start": { + "description": "The starting path.", "type": "object", "required": [ - "id", - "sourceRange" + "__geoMeta", + "from", + "name", + "to" ], "properties": { - "id": { - "description": "The id of the geometry.", - "type": "string", - "format": "uuid" + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } }, - "sourceRange": { - "description": "The source range.", + "from": { + "description": "The from point.", "type": "array", "items": { - "type": "integer", - "format": "uint", - "minimum": 0.0 + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" }, "maxItems": 2, "minItems": 2 } } }, - "from": { - "description": "The from point.", + "type": { + "type": "string", + "enum": [ + "sketchGroup" + ] + }, + "value": { + "description": "The paths in the sketch group.", + "type": "array", + "items": { + "description": "A path.", + "oneOf": [ + { + "description": "A path that goes to a point.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "ToPoint" + ] + } + } + }, + { + "description": "A arc that is tangential to the last path segment that goes to a point", + "type": "object", + "required": [ + "__geoMeta", + "ccw", + "center", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "ccw": { + "description": "arc's direction", + "type": "boolean" + }, + "center": { + "description": "the arc's center", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "TangentialArcTo" + ] + } + } + }, + { + "description": "A path that is horizontal.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type", + "x" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Horizontal" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double" + } + } + }, + { + "description": "An angled line to.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "AngledLineTo" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double", + "nullable": true + }, + "y": { + "description": "The y coordinate.", + "type": "number", + "format": "double", + "nullable": true + } + } + }, + { + "description": "A base path.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Base" + ] + } + } + } + ] + } + }, + "xAxis": { + "description": "The x-axis of the sketch group base plane in the 3D space", "type": "array", "items": { "type": "number", "format": "double" }, - "maxItems": 2, - "minItems": 2 + "maxItems": 3, + "minItems": 3 }, - "name": { - "description": "The name of the path.", - "type": "string" - }, - "to": { - "description": "The to point.", + "yAxis": { + "description": "The y-axis of the sketch group base plane in the 3D space", "type": "array", "items": { "type": "number", "format": "double" }, - "maxItems": 2, - "minItems": 2 + "maxItems": 3, + "minItems": 3 + }, + "zAxis": { + "description": "The z-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 } } }, - "value": { - "description": "The paths in the sketch group.", - "type": "array", + { + "type": [ + "object", + "array" + ], "items": { - "description": "A path.", - "oneOf": [ - { - "description": "A path that goes to a point.", - "type": "object", - "required": [ - "__geoMeta", - "from", - "name", - "to", - "type" - ], - "properties": { - "__geoMeta": { - "description": "Metadata.", - "type": "object", - "required": [ - "id", - "sourceRange" - ], - "properties": { - "id": { - "description": "The id of the geometry.", - "type": "string", - "format": "uuid" + "description": "A sketch group is a collection of paths.", + "type": "object", + "required": [ + "__meta", + "id", + "position", + "rotation", + "start", + "value", + "xAxis", + "yAxis", + "zAxis" + ], + "properties": { + "__meta": { + "description": "Metadata.", + "type": "array", + "items": { + "description": "Metadata.", + "type": "object", + "required": [ + "sourceRange" + ], + "properties": { + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 }, - "sourceRange": { - "description": "The source range.", - "type": "array", - "items": { - "type": "integer", - "format": "uint", - "minimum": 0.0 - }, - "maxItems": 2, - "minItems": 2 - } + "maxItems": 2, + "minItems": 2 } - }, - "from": { - "description": "The from point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "name": { - "description": "The name of the path.", - "type": "string" - }, - "to": { - "description": "The to point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "type": { - "type": "string", - "enum": [ - "ToPoint" - ] } } }, - { - "description": "A arc that is tangential to the last path segment that goes to a point", + "id": { + "description": "The id of the sketch group.", + "type": "string", + "format": "uuid" + }, + "planeId": { + "description": "The plane id of the sketch group.", + "type": "string", + "format": "uuid", + "nullable": true + }, + "position": { + "description": "The position of the sketch group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation of the sketch group base plane.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "start": { + "description": "The starting path.", "type": "object", "required": [ "__geoMeta", - "ccw", - "center", "from", "name", - "to", - "type" + "to" ], "properties": { "__geoMeta": { @@ -13205,20 +13632,6 @@ } } }, - "ccw": { - "description": "arc's direction", - "type": "boolean" - }, - "center": { - "description": "the arc's center", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, "from": { "description": "The from point.", "type": "array", @@ -13242,274 +13655,442 @@ }, "maxItems": 2, "minItems": 2 - }, - "type": { - "type": "string", - "enum": [ - "TangentialArcTo" - ] } } }, - { - "description": "A path that is horizontal.", - "type": "object", - "required": [ - "__geoMeta", - "from", - "name", - "to", - "type", - "x" - ], - "properties": { - "__geoMeta": { - "description": "Metadata.", - "type": "object", - "required": [ - "id", - "sourceRange" - ], - "properties": { - "id": { - "description": "The id of the geometry.", - "type": "string", - "format": "uuid" - }, - "sourceRange": { - "description": "The source range.", - "type": "array", - "items": { - "type": "integer", - "format": "uint", - "minimum": 0.0 + "value": { + "description": "The paths in the sketch group.", + "type": "array", + "items": { + "description": "A path.", + "oneOf": [ + { + "description": "A path that goes to a point.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } }, - "maxItems": 2, - "minItems": 2 + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "ToPoint" + ] + } + } + }, + { + "description": "A arc that is tangential to the last path segment that goes to a point", + "type": "object", + "required": [ + "__geoMeta", + "ccw", + "center", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "ccw": { + "description": "arc's direction", + "type": "boolean" + }, + "center": { + "description": "the arc's center", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "TangentialArcTo" + ] + } + } + }, + { + "description": "A path that is horizontal.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type", + "x" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Horizontal" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double" + } + } + }, + { + "description": "An angled line to.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "AngledLineTo" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double", + "nullable": true + }, + "y": { + "description": "The y coordinate.", + "type": "number", + "format": "double", + "nullable": true + } + } + }, + { + "description": "A base path.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Base" + ] + } } } - }, - "from": { - "description": "The from point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "name": { - "description": "The name of the path.", - "type": "string" - }, - "to": { - "description": "The to point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "type": { - "type": "string", - "enum": [ - "Horizontal" - ] - }, - "x": { - "description": "The x coordinate.", - "type": "number", - "format": "double" - } + ] } }, - { - "description": "An angled line to.", - "type": "object", - "required": [ - "__geoMeta", - "from", - "name", - "to", - "type" - ], - "properties": { - "__geoMeta": { - "description": "Metadata.", - "type": "object", - "required": [ - "id", - "sourceRange" - ], - "properties": { - "id": { - "description": "The id of the geometry.", - "type": "string", - "format": "uuid" - }, - "sourceRange": { - "description": "The source range.", - "type": "array", - "items": { - "type": "integer", - "format": "uint", - "minimum": 0.0 - }, - "maxItems": 2, - "minItems": 2 - } - } - }, - "from": { - "description": "The from point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "name": { - "description": "The name of the path.", - "type": "string" - }, - "to": { - "description": "The to point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "type": { - "type": "string", - "enum": [ - "AngledLineTo" - ] - }, - "x": { - "description": "The x coordinate.", - "type": "number", - "format": "double", - "nullable": true - }, - "y": { - "description": "The y coordinate.", - "type": "number", - "format": "double", - "nullable": true - } - } + "xAxis": { + "description": "The x-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 }, - { - "description": "A base path.", - "type": "object", - "required": [ - "__geoMeta", - "from", - "name", - "to", - "type" - ], - "properties": { - "__geoMeta": { - "description": "Metadata.", - "type": "object", - "required": [ - "id", - "sourceRange" - ], - "properties": { - "id": { - "description": "The id of the geometry.", - "type": "string", - "format": "uuid" - }, - "sourceRange": { - "description": "The source range.", - "type": "array", - "items": { - "type": "integer", - "format": "uint", - "minimum": 0.0 - }, - "maxItems": 2, - "minItems": 2 - } - } - }, - "from": { - "description": "The from point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "name": { - "description": "The name of the path.", - "type": "string" - }, - "to": { - "description": "The to point.", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 2, - "minItems": 2 - }, - "type": { - "type": "string", - "enum": [ - "Base" - ] - } - } + "yAxis": { + "description": "The y-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "zAxis": { + "description": "The z-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 } - ] + } + }, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "sketchGroups" + ] + } } - }, - "xAxis": { - "description": "The x-axis of the sketch group base plane in the 3D space", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 3, - "minItems": 3 - }, - "yAxis": { - "description": "The y-axis of the sketch group base plane in the 3D space", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 3, - "minItems": 3 - }, - "zAxis": { - "description": "The z-axis of the sketch group base plane in the 3D space", - "type": "array", - "items": { - "type": "number", - "format": "double" - }, - "maxItems": 3, - "minItems": 3 } - } + ] }, "required": true }, @@ -18413,6 +18994,1499 @@ "unpublished": false, "deprecated": false }, + { + "name": "patternLinear", + "summary": "A linear pattern.", + "description": "", + "tags": [], + "args": [ + { + "name": "data", + "type": "LinearPatternData", + "schema": { + "description": "Data for a linear pattern.", + "type": "object", + "required": [ + "axis", + "distance", + "repetitions" + ], + "properties": { + "axis": { + "description": "The axis of the pattern. This is a 3D vector.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "distance": { + "description": "The distance between each repetition. This can also be referred to as spacing.", + "type": "number", + "format": "double" + }, + "repetitions": { + "description": "The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.", + "type": "integer", + "format": "uint", + "minimum": 0.0 + } + } + }, + "required": true + }, + { + "name": "geometry", + "type": "Geometry", + "schema": { + "description": "A geometry.", + "oneOf": [ + { + "description": "A sketch group is a collection of paths.", + "type": "object", + "required": [ + "__meta", + "id", + "position", + "rotation", + "start", + "type", + "value", + "xAxis", + "yAxis", + "zAxis" + ], + "properties": { + "__meta": { + "description": "Metadata.", + "type": "array", + "items": { + "description": "Metadata.", + "type": "object", + "required": [ + "sourceRange" + ], + "properties": { + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + } + }, + "id": { + "description": "The id of the sketch group.", + "type": "string", + "format": "uuid" + }, + "planeId": { + "description": "The plane id of the sketch group.", + "type": "string", + "format": "uuid", + "nullable": true + }, + "position": { + "description": "The position of the sketch group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation of the sketch group base plane.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "start": { + "description": "The starting path.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "type": { + "type": "string", + "enum": [ + "SketchGroup" + ] + }, + "value": { + "description": "The paths in the sketch group.", + "type": "array", + "items": { + "description": "A path.", + "oneOf": [ + { + "description": "A path that goes to a point.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "ToPoint" + ] + } + } + }, + { + "description": "A arc that is tangential to the last path segment that goes to a point", + "type": "object", + "required": [ + "__geoMeta", + "ccw", + "center", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "ccw": { + "description": "arc's direction", + "type": "boolean" + }, + "center": { + "description": "the arc's center", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "TangentialArcTo" + ] + } + } + }, + { + "description": "A path that is horizontal.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type", + "x" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Horizontal" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double" + } + } + }, + { + "description": "An angled line to.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "AngledLineTo" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double", + "nullable": true + }, + "y": { + "description": "The y coordinate.", + "type": "number", + "format": "double", + "nullable": true + } + } + }, + { + "description": "A base path.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Base" + ] + } + } + } + ] + } + }, + "xAxis": { + "description": "The x-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "yAxis": { + "description": "The y-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "zAxis": { + "description": "The z-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + } + } + }, + { + "description": "An extrude group is a collection of extrude surfaces.", + "type": "object", + "required": [ + "__meta", + "height", + "id", + "position", + "rotation", + "type", + "value" + ], + "properties": { + "__meta": { + "description": "Metadata.", + "type": "array", + "items": { + "description": "Metadata.", + "type": "object", + "required": [ + "sourceRange" + ], + "properties": { + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + } + }, + "height": { + "description": "The height of the extrude group.", + "type": "number", + "format": "double" + }, + "id": { + "description": "The id of the extrude group.", + "type": "string", + "format": "uuid" + }, + "position": { + "description": "The position of the extrude group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation of the extrude group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "type": { + "type": "string", + "enum": [ + "ExtrudeGroup" + ] + }, + "value": { + "description": "The extrude surfaces.", + "type": "array", + "items": { + "description": "An extrude surface.", + "oneOf": [ + { + "description": "An extrude plane.", + "type": "object", + "required": [ + "id", + "name", + "position", + "rotation", + "sourceRange", + "type" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "name": { + "description": "The name.", + "type": "string" + }, + "position": { + "description": "The position.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "extrudePlane" + ] + } + } + } + ] + } + } + } + } + ] + }, + "required": true + } + ], + "returnValue": { + "name": "", + "type": "Geometries", + "schema": { + "description": "A set of geometry.", + "oneOf": [ + { + "type": [ + "object", + "array" + ], + "items": { + "description": "A sketch group is a collection of paths.", + "type": "object", + "required": [ + "__meta", + "id", + "position", + "rotation", + "start", + "value", + "xAxis", + "yAxis", + "zAxis" + ], + "properties": { + "__meta": { + "description": "Metadata.", + "type": "array", + "items": { + "description": "Metadata.", + "type": "object", + "required": [ + "sourceRange" + ], + "properties": { + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + } + }, + "id": { + "description": "The id of the sketch group.", + "type": "string", + "format": "uuid" + }, + "planeId": { + "description": "The plane id of the sketch group.", + "type": "string", + "format": "uuid", + "nullable": true + }, + "position": { + "description": "The position of the sketch group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation of the sketch group base plane.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "start": { + "description": "The starting path.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "value": { + "description": "The paths in the sketch group.", + "type": "array", + "items": { + "description": "A path.", + "oneOf": [ + { + "description": "A path that goes to a point.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "ToPoint" + ] + } + } + }, + { + "description": "A arc that is tangential to the last path segment that goes to a point", + "type": "object", + "required": [ + "__geoMeta", + "ccw", + "center", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "ccw": { + "description": "arc's direction", + "type": "boolean" + }, + "center": { + "description": "the arc's center", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "TangentialArcTo" + ] + } + } + }, + { + "description": "A path that is horizontal.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type", + "x" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Horizontal" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double" + } + } + }, + { + "description": "An angled line to.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "AngledLineTo" + ] + }, + "x": { + "description": "The x coordinate.", + "type": "number", + "format": "double", + "nullable": true + }, + "y": { + "description": "The y coordinate.", + "type": "number", + "format": "double", + "nullable": true + } + } + }, + { + "description": "A base path.", + "type": "object", + "required": [ + "__geoMeta", + "from", + "name", + "to", + "type" + ], + "properties": { + "__geoMeta": { + "description": "Metadata.", + "type": "object", + "required": [ + "id", + "sourceRange" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + }, + "from": { + "description": "The from point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "name": { + "description": "The name of the path.", + "type": "string" + }, + "to": { + "description": "The to point.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "Base" + ] + } + } + } + ] + } + }, + "xAxis": { + "description": "The x-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "yAxis": { + "description": "The y-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "zAxis": { + "description": "The z-axis of the sketch group base plane in the 3D space", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + } + } + }, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "SketchGroups" + ] + } + } + }, + { + "type": [ + "object", + "array" + ], + "items": { + "description": "An extrude group is a collection of extrude surfaces.", + "type": "object", + "required": [ + "__meta", + "height", + "id", + "position", + "rotation", + "value" + ], + "properties": { + "__meta": { + "description": "Metadata.", + "type": "array", + "items": { + "description": "Metadata.", + "type": "object", + "required": [ + "sourceRange" + ], + "properties": { + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + } + } + } + }, + "height": { + "description": "The height of the extrude group.", + "type": "number", + "format": "double" + }, + "id": { + "description": "The id of the extrude group.", + "type": "string", + "format": "uuid" + }, + "position": { + "description": "The position of the extrude group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation of the extrude group.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "value": { + "description": "The extrude surfaces.", + "type": "array", + "items": { + "description": "An extrude surface.", + "oneOf": [ + { + "description": "An extrude plane.", + "type": "object", + "required": [ + "id", + "name", + "position", + "rotation", + "sourceRange", + "type" + ], + "properties": { + "id": { + "description": "The id of the geometry.", + "type": "string", + "format": "uuid" + }, + "name": { + "description": "The name.", + "type": "string" + }, + "position": { + "description": "The position.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 3, + "minItems": 3 + }, + "rotation": { + "description": "The rotation.", + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "maxItems": 4, + "minItems": 4 + }, + "sourceRange": { + "description": "The source range.", + "type": "array", + "items": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "maxItems": 2, + "minItems": 2 + }, + "type": { + "type": "string", + "enum": [ + "extrudePlane" + ] + } + } + } + ] + } + } + } + }, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "ExtrudeGroups" + ] + } + } + } + ] + }, + "required": true + }, + "unpublished": false, + "deprecated": false + }, { "name": "pi", "summary": "Return the value of `pi`. Archimedes’ constant (π).", diff --git a/docs/kcl/std.md b/docs/kcl/std.md index 598e7fef8..9867267a0 100644 --- a/docs/kcl/std.md +++ b/docs/kcl/std.md @@ -40,6 +40,7 @@ * [`log2`](#log2) * [`max`](#max) * [`min`](#min) + * [`patternLinear`](#patternLinear) * [`pi`](#pi) * [`pow`](#pow) * [`segAng`](#segAng) @@ -2430,12 +2431,12 @@ Use a sketch to cut a hole in another sketch. ``` -hole(hole_sketch_group: SketchGroup, sketch_group: SketchGroup) -> SketchGroup +hole(hole_sketch_group: SketchGroupSet, sketch_group: SketchGroup) -> SketchGroup ``` #### Arguments -* `hole_sketch_group`: `SketchGroup` - A sketch group is a collection of paths. +* `hole_sketch_group`: `SketchGroupSet` - A sketch group or a group of sketch groups. ``` { // The id of the sketch group. @@ -2455,6 +2456,7 @@ hole(hole_sketch_group: SketchGroup, sketch_group: SketchGroup) -> SketchGroup // The to point. to: [number, number], }, + type: string, // The paths in the sketch group. value: [{ // The from point. @@ -2517,6 +2519,9 @@ hole(hole_sketch_group: SketchGroup, sketch_group: SketchGroup) -> SketchGroup yAxis: [number, number, number], // The z-axis of the sketch group base plane in the 3D space zAxis: [number, number, number], +} | +{ + type: string, } ``` * `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. @@ -3475,6 +3480,154 @@ min(args: [number]) -> number +### patternLinear + +A linear pattern. + + + +``` +patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries +``` + +#### Arguments + +* `data`: `LinearPatternData` - Data for a linear pattern. +``` +{ + // The axis of the pattern. This is a 3D vector. + axis: [number, number, number], + // The distance between each repetition. This can also be referred to as spacing. + distance: number, + // The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once. + repetitions: number, +} +``` +* `geometry`: `Geometry` - A geometry. +``` +{ + // The id of the sketch group. + id: uuid, + // The plane id of the sketch group. + planeId: uuid, + // The position of the sketch group. + position: [number, number, number], + // The rotation of the sketch group base plane. + rotation: [number, number, number, number], + // The starting path. + start: { + // The from point. + from: [number, number], + // The name of the path. + name: string, + // The to point. + to: [number, number], +}, + type: string, + // The paths in the sketch group. + value: [{ + // The from point. + from: [number, number], + // The name of the path. + name: string, + // The to point. + to: [number, number], + type: string, +} | +{ + // arc's direction + ccw: string, + // the arc's center + center: [number, number], + // The from point. + from: [number, number], + // The name of the path. + name: string, + // The to point. + to: [number, number], + type: string, +} | +{ + // The from point. + from: [number, number], + // The name of the path. + name: string, + // The to point. + to: [number, number], + type: string, + // The x coordinate. + x: number, +} | +{ + // The from point. + from: [number, number], + // The name of the path. + name: string, + // The to point. + to: [number, number], + type: string, + // The x coordinate. + x: number, + // The y coordinate. + y: number, +} | +{ + // The from point. + from: [number, number], + // The name of the path. + name: string, + // The to point. + to: [number, number], + type: string, +}], + // The x-axis of the sketch group base plane in the 3D space + xAxis: [number, number, number], + // The y-axis of the sketch group base plane in the 3D space + yAxis: [number, number, number], + // The z-axis of the sketch group base plane in the 3D space + zAxis: [number, number, number], +} | +{ + // The height of the extrude group. + height: number, + // The id of the extrude group. + id: uuid, + // The position of the extrude group. + position: [number, number, number], + // The rotation of the extrude group. + rotation: [number, number, number, number], + type: string, + // The extrude surfaces. + value: [{ + // The id of the geometry. + id: uuid, + // The name. + name: string, + // The position. + position: [number, number, number], + // The rotation. + rotation: [number, number, number, number], + // The source range. + sourceRange: [number, number], + type: string, +}], +} +``` + +#### Returns + +* `Geometries` - A set of geometry. +``` +{ + type: string, +} | +{ + type: string, +} +``` + + + ### pi Return the value of `pi`. Archimedes’ constant (π). diff --git a/e2e/playwright/flow-tests.spec.ts b/e2e/playwright/flow-tests.spec.ts index 12392a923..eea3105e9 100644 --- a/e2e/playwright/flow-tests.spec.ts +++ b/e2e/playwright/flow-tests.spec.ts @@ -810,3 +810,42 @@ const part002 = startSketchOn('XY') |> line([-47.44, 0], %)`.replace(/\s/g, '') ) }) + +test('ProgramMemory can be serialised', async ({ page, context }) => { + const u = getUtils(page) + await context.addInitScript(async (token) => { + localStorage.setItem( + 'persistCode', + `const part = startSketchOn('XY') + |> startProfileAt([0, 0], %) + |> line([0, 1], %) + |> line([1, 0], %) + |> line([0, -1], %) + |> close(%) + |> extrude(1, %) + |> patternLinear({ + axis: [1, 0, 1], + repetitions: 3, + distance: 6 + }, %)` + ) + }) + await page.setViewportSize({ width: 1000, height: 500 }) + await page.goto('/') + const messages: string[] = [] + + // Listen for all console events and push the message text to an array + page.on('console', (message) => messages.push(message.text())) + await u.waitForAuthSkipAppStart() + + // wait for execution done + await u.openDebugPanel() + await u.expectCmdLog('[data-message-type="execution-done"]') + + const forbiddenMessages = ['cannot serialize tagged newtype variant'] + forbiddenMessages.forEach((forbiddenMessage) => { + messages.forEach((message) => { + expect(message).not.toContain(forbiddenMessage) + }) + }) +}) diff --git a/src/lang/std/engineConnection.ts b/src/lang/std/engineConnection.ts index b862f555d..18bc574a6 100644 --- a/src/lang/std/engineConnection.ts +++ b/src/lang/std/engineConnection.ts @@ -1075,7 +1075,7 @@ export class EngineCommandManager { if (command && command.type === 'pending') { const resolve = command.resolve - this.artifactMap[id] = { + const artifact = { type: 'result', range: command.range, pathToNode: command.pathToNode, @@ -1083,6 +1083,13 @@ export class EngineCommandManager { parentId: command.parentId ? command.parentId : undefined, data: modelingResponse, raw: message, + } as const + this.artifactMap[id] = artifact + if (command.commandType === 'entity_linear_pattern') { + const entities = (modelingResponse as any)?.data?.entity_ids + entities?.forEach((entity: string) => { + this.artifactMap[entity] = artifact + }) } resolve({ id, @@ -1194,12 +1201,14 @@ export class EngineCommandManager { // this fact is very opaque in the api and docs (as to what should can be deleted). // Using an array is the list is likely to grow. 'start_path', + 'entity_linear_pattern', ] - if (!artifactTypesToDelete.includes(artifact.commandType)) return - artifactsToDelete[id] = artifact + if (artifactTypesToDelete.includes(artifact.commandType)) { + artifactsToDelete[id] = artifact + } }) Object.keys(artifactsToDelete).forEach((id) => { - const deletCmd: EngineCommand = { + const deleteCmd: EngineCommand = { type: 'modeling_cmd_req', cmd_id: uuidv4(), cmd: { @@ -1207,7 +1216,7 @@ export class EngineCommandManager { object_ids: [id], }, } - this.engineConnection?.send(deletCmd) + this.engineConnection?.send(deleteCmd) }) } addCommandLog(message: CommandLog) { diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index 05d8a057b..353599689 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -147,6 +147,7 @@ export const _executor = async ( ) return memory } catch (e: any) { + console.log(e) const parsed: RustKclError = JSON.parse(e.toString()) const kclError = new KCLError( parsed.kind, diff --git a/src/lib/selections.ts b/src/lib/selections.ts index 6b291435a..a92b72c4a 100644 --- a/src/lib/selections.ts +++ b/src/lib/selections.ts @@ -352,7 +352,7 @@ export function processCodeMirrorRanges({ } }) const idBasedSelections: SelectionToEngine[] = codeBasedSelections - .map(({ type, range }): null | SelectionToEngine => { + .flatMap(({ type, range }): null | SelectionToEngine[] => { // TODO #868: loops over all artifacts will become inefficient at a large scale const entriesWithOverlap = Object.entries( engineCommandManager.artifactMap || {} @@ -362,8 +362,7 @@ export function processCodeMirrorRanges({ : false }) if (entriesWithOverlap.length) { - const [id, artifact] = entriesWithOverlap?.[0] - return { + return entriesWithOverlap.map(([id, artifact]) => ({ type, id: type === 'line-end' && @@ -371,7 +370,7 @@ export function processCodeMirrorRanges({ artifact.headVertexId ? artifact.headVertexId : id, - } + })) } return null }) diff --git a/src/wasm-lib/Cargo.toml b/src/wasm-lib/Cargo.toml index 0b2e60cf9..2226c9554 100644 --- a/src/wasm-lib/Cargo.toml +++ b/src/wasm-lib/Cargo.toml @@ -52,9 +52,9 @@ debug = true [workspace] members = [ "derive-docs", - "grackle", + "grackle", "kcl", - "kcl-macros", + "kcl-macros", ] [workspace.dependencies] @@ -75,4 +75,4 @@ path = "tests/modify/main.rs" # Example: how to point modeling-api at a different repo (e.g. a branch or a local clone) # [patch."https://github.com/KittyCAD/modeling-api"] # kittycad-execution-plan = { path = "../../../modeling-api/execution-plan" } -# kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" } \ No newline at end of file +# kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" } diff --git a/src/wasm-lib/derive-docs/Cargo.toml b/src/wasm-lib/derive-docs/Cargo.toml index a0703d1eb..f22ffcd62 100644 --- a/src/wasm-lib/derive-docs/Cargo.toml +++ b/src/wasm-lib/derive-docs/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" license = "MIT" repository = "https://github.com/KittyCAD/modeling-app" rust-version = "1.73" - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] diff --git a/src/wasm-lib/grackle/Cargo.toml b/src/wasm-lib/grackle/Cargo.toml index 8561f4539..d70fa8b53 100644 --- a/src/wasm-lib/grackle/Cargo.toml +++ b/src/wasm-lib/grackle/Cargo.toml @@ -3,7 +3,6 @@ name = "grackle" version = "0.1.0" edition = "2021" description = "A new executor for KCL which compiles to Execution Plans" - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -14,7 +13,6 @@ kittycad-modeling-session = { workspace = true } thiserror = "1.0.57" tokio = { version = "1.36.0", features = ["macros", "rt"] } - [dev-dependencies] pretty_assertions = "1" serde_json = "1.0.113" diff --git a/src/wasm-lib/grackle/src/binding_scope.rs b/src/wasm-lib/grackle/src/binding_scope.rs index f5daf401a..32b133f15 100644 --- a/src/wasm-lib/grackle/src/binding_scope.rs +++ b/src/wasm-lib/grackle/src/binding_scope.rs @@ -1,14 +1,10 @@ -use kcl_lib::ast::types::LiteralIdentifier; -use kcl_lib::ast::types::LiteralValue; - -use crate::CompileError; -use crate::KclFunction; - -use super::native_functions; -use super::Address; - use std::collections::HashMap; +use kcl_lib::ast::types::{LiteralIdentifier, LiteralValue}; + +use super::{native_functions, Address}; +use crate::{CompileError, KclFunction}; + /// KCL values which can be written to KCEP memory. /// This is recursive. For example, the bound value might be an array, which itself contains bound values. #[derive(Debug, Clone)] diff --git a/src/wasm-lib/grackle/src/lib.rs b/src/wasm-lib/grackle/src/lib.rs index f4ae506f4..3a581a318 100644 --- a/src/wasm-lib/grackle/src/lib.rs +++ b/src/wasm-lib/grackle/src/lib.rs @@ -17,9 +17,11 @@ use kittycad_execution_plan_traits as ept; use kittycad_execution_plan_traits::{Address, NumericPrimitive}; use kittycad_modeling_session::Session; -use self::binding_scope::{BindingScope, EpBinding, GetFnResult}; -use self::error::{CompileError, Error}; -use self::kcl_value_group::SingleValue; +use self::{ + binding_scope::{BindingScope, EpBinding, GetFnResult}, + error::{CompileError, Error}, + kcl_value_group::SingleValue, +}; /// Execute a KCL program by compiling into an execution plan, then running that. pub async fn execute(ast: Program, session: Option) -> Result { diff --git a/src/wasm-lib/kcl-macros/Cargo.toml b/src/wasm-lib/kcl-macros/Cargo.toml index b84eabd41..10c93e1da 100644 --- a/src/wasm-lib/kcl-macros/Cargo.toml +++ b/src/wasm-lib/kcl-macros/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" edition = "2021" license = "MIT" repository = "https://github.com/KittyCAD/modeling-app" - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] diff --git a/src/wasm-lib/kcl/Cargo.toml b/src/wasm-lib/kcl/Cargo.toml index 8776c9ba0..510491432 100644 --- a/src/wasm-lib/kcl/Cargo.toml +++ b/src/wasm-lib/kcl/Cargo.toml @@ -8,7 +8,6 @@ repository = "https://github.com/KittyCAD/modeling-app" rust-version = "1.73" authors = ["Jess Frazelle", "Adam Chalmers", "KittyCAD, Inc"] keywords = ["kcl", "KittyCAD", "CAD"] - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/src/wasm-lib/kcl/src/ast/types.rs b/src/wasm-lib/kcl/src/ast/types.rs index 641404a63..25edf2f26 100644 --- a/src/wasm-lib/kcl/src/ast/types.rs +++ b/src/wasm-lib/kcl/src/ast/types.rs @@ -10,8 +10,7 @@ use serde::{Deserialize, Serialize}; use serde_json::{Map, Value as JValue}; use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, DocumentSymbol, Range as LspRange, SymbolKind}; -pub use self::literal_value::LiteralValue; -pub use self::none::KclNone; +pub use self::{literal_value::LiteralValue, none::KclNone}; use crate::{ docs::StdLibFn, errors::{KclError, KclErrorDetails}, diff --git a/src/wasm-lib/kcl/src/ast/types/none.rs b/src/wasm-lib/kcl/src/ast/types/none.rs index eeb06ceba..958a296bb 100644 --- a/src/wasm-lib/kcl/src/ast/types/none.rs +++ b/src/wasm-lib/kcl/src/ast/types/none.rs @@ -4,9 +4,8 @@ use databake::*; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::executor::{MemoryItem, SourceRange, UserVal}; - use super::ConstraintLevel; +use crate::executor::{MemoryItem, SourceRange, UserVal}; /// KCL value for an optional parameter which was not given an argument. /// (remember, parameters are in the function declaration, diff --git a/src/wasm-lib/kcl/src/engine/conn.rs b/src/wasm-lib/kcl/src/engine/conn.rs index 0ff96c0e6..ec987e824 100644 --- a/src/wasm-lib/kcl/src/engine/conn.rs +++ b/src/wasm-lib/kcl/src/engine/conn.rs @@ -69,13 +69,13 @@ impl EngineConnection { async fn start_write_actor(mut tcp_write: WebSocketTcpWrite, mut engine_req_rx: mpsc::Receiver) { while let Some(req) = engine_req_rx.recv().await { let ToEngineReq { req, request_sent } = req; - let res = if let kittycad::types::WebSocketRequest::ModelingCmdReq { cmd, cmd_id: _ } = &req { - if let kittycad::types::ModelingCmd::ImportFiles { .. } = cmd { - // Send it as binary. - Self::inner_send_to_engine_binary(req, &mut tcp_write).await - } else { - Self::inner_send_to_engine(req, &mut tcp_write).await - } + let res = if let kittycad::types::WebSocketRequest::ModelingCmdReq { + cmd: kittycad::types::ModelingCmd::ImportFiles { .. }, + cmd_id: _, + } = &req + { + // Send it as binary. + Self::inner_send_to_engine_binary(req, &mut tcp_write).await } else { Self::inner_send_to_engine(req, &mut tcp_write).await }; diff --git a/src/wasm-lib/kcl/src/executor.rs b/src/wasm-lib/kcl/src/executor.rs index 3e7c6332b..6286103e2 100644 --- a/src/wasm-lib/kcl/src/executor.rs +++ b/src/wasm-lib/kcl/src/executor.rs @@ -102,6 +102,7 @@ impl ProgramReturn { } } +/// A memory item. #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[ts(export)] #[serde(tag = "type")] @@ -109,7 +110,13 @@ pub enum MemoryItem { UserVal(UserVal), Plane(Box), SketchGroup(Box), + SketchGroups { + value: Vec>, + }, ExtrudeGroup(Box), + ExtrudeGroups { + value: Vec>, + }, #[ts(skip)] ExtrudeTransform(Box), #[ts(skip)] @@ -122,6 +129,42 @@ pub enum MemoryItem { }, } +/// A geometry. +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] +#[ts(export)] +#[serde(tag = "type")] +pub enum Geometry { + SketchGroup(Box), + ExtrudeGroup(Box), +} + +impl Geometry { + pub fn id(&self) -> uuid::Uuid { + match self { + Geometry::SketchGroup(s) => s.id, + Geometry::ExtrudeGroup(e) => e.id, + } + } +} + +/// A set of geometry. +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] +#[ts(export)] +#[serde(tag = "type")] +pub enum Geometries { + SketchGroups(Vec>), + ExtrudeGroups(Vec>), +} + +/// A sketch group or a group of sketch groups. +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] +#[ts(export)] +#[serde(tag = "type", rename_all = "camelCase")] +pub enum SketchGroupSet { + SketchGroup(Box), + SketchGroups(Vec>), +} + /// A plane. #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[ts(export)] @@ -212,7 +255,15 @@ impl From for Vec { match item { MemoryItem::UserVal(u) => u.meta.iter().map(|m| m.source_range).collect(), MemoryItem::SketchGroup(s) => s.meta.iter().map(|m| m.source_range).collect(), + MemoryItem::SketchGroups { value } => value + .iter() + .flat_map(|sg| sg.meta.iter().map(|m| m.source_range)) + .collect(), MemoryItem::ExtrudeGroup(e) => e.meta.iter().map(|m| m.source_range).collect(), + MemoryItem::ExtrudeGroups { value } => value + .iter() + .flat_map(|eg| eg.meta.iter().map(|m| m.source_range)) + .collect(), MemoryItem::ExtrudeTransform(e) => e.meta.iter().map(|m| m.source_range).collect(), MemoryItem::Function { meta, .. } => meta.iter().map(|m| m.source_range).collect(), MemoryItem::Plane(p) => p.meta.iter().map(|m| m.source_range).collect(), @@ -1040,9 +1091,8 @@ fn assign_args_to_params( mod tests { use pretty_assertions::assert_eq; - use crate::ast::types::{Identifier, Parameter}; - use super::*; + use crate::ast::types::{Identifier, Parameter}; pub async fn parse_execute(code: &str) -> Result { let tokens = crate::token::lexer(code); @@ -1703,4 +1753,13 @@ show(bracket) ); } } + + #[test] + fn test_serialize_memory_item() { + let mem = MemoryItem::ExtrudeGroups { + value: Default::default(), + }; + let json = serde_json::to_string(&mem).unwrap(); + assert_eq!(json, r#"{"type":"ExtrudeGroups","value":[]}"#); + } } diff --git a/src/wasm-lib/kcl/src/std/extrude.rs b/src/wasm-lib/kcl/src/std/extrude.rs index a59835cb4..ba45aa7c1 100644 --- a/src/wasm-lib/kcl/src/std/extrude.rs +++ b/src/wasm-lib/kcl/src/std/extrude.rs @@ -47,7 +47,10 @@ async fn inner_extrude(length: f64, sketch_group: Box, args: Args) .await?; Ok(Box::new(ExtrudeGroup { - id, + // Ok so you would think that the id would be the id of the extrude group, + // that we passed in to the function, but it's actually the id of the + // sketch group. + id: sketch_group.id, // TODO, this is just an empty array now, should be deleted. This // comment was originally in the JS code. value: Default::default(), diff --git a/src/wasm-lib/kcl/src/std/mod.rs b/src/wasm-lib/kcl/src/std/mod.rs index cca0cf447..87bf49d8f 100644 --- a/src/wasm-lib/kcl/src/std/mod.rs +++ b/src/wasm-lib/kcl/src/std/mod.rs @@ -3,6 +3,7 @@ pub mod extrude; pub mod kcl_stdlib; pub mod math; +pub mod patterns; pub mod segment; pub mod shapes; pub mod sketch; @@ -24,7 +25,9 @@ use crate::{ docs::StdLibFn, engine::EngineManager, errors::{KclError, KclErrorDetails}, - executor::{ExecutorContext, ExtrudeGroup, MemoryItem, Metadata, Plane, SketchGroup, SourceRange}, + executor::{ + ExecutorContext, ExtrudeGroup, Geometry, MemoryItem, Metadata, Plane, SketchGroup, SketchGroupSet, SourceRange, + }, }; pub type StdFn = fn(Args) -> std::pin::Pin>>>; @@ -67,6 +70,7 @@ lazy_static! { Box::new(crate::std::sketch::TangentialArcTo), Box::new(crate::std::sketch::BezierCurve), Box::new(crate::std::sketch::Hole), + Box::new(crate::std::patterns::PatternLinear), Box::new(crate::std::math::Cos), Box::new(crate::std::math::Sin), Box::new(crate::std::math::Tan), @@ -284,7 +288,7 @@ impl Args { Ok((segment_name, sketch_group)) } - fn get_sketch_groups(&self) -> Result<(Box, Box), KclError> { + fn get_sketch_groups(&self) -> Result<(SketchGroupSet, Box), KclError> { let first_value = self.args.first().ok_or_else(|| { KclError::Type(KclErrorDetails { message: format!("Expected a SketchGroup as the first argument, found `{:?}`", self.args), @@ -292,11 +296,16 @@ impl Args { }) })?; - let sketch_group = if let MemoryItem::SketchGroup(sg) = first_value { - sg.clone() + let sketch_set = if let MemoryItem::SketchGroup(sg) = first_value { + SketchGroupSet::SketchGroup(sg.clone()) + } else if let MemoryItem::SketchGroups { value } = first_value { + SketchGroupSet::SketchGroups(value.clone()) } else { return Err(KclError::Type(KclErrorDetails { - message: format!("Expected a SketchGroup as the first argument, found `{:?}`", self.args), + message: format!( + "Expected a SketchGroup or Vector of SketchGroups as the first argument, found `{:?}`", + self.args + ), source_ranges: vec![self.source_range], })); }; @@ -308,7 +317,7 @@ impl Args { }) })?; - let second_sketch_group = if let MemoryItem::SketchGroup(sg) = second_value { + let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value { sg.clone() } else { return Err(KclError::Type(KclErrorDetails { @@ -317,7 +326,7 @@ impl Args { })); }; - Ok((sketch_group, second_sketch_group)) + Ok((sketch_set, sketch_group)) } fn get_sketch_group(&self) -> Result, KclError> { @@ -400,6 +409,49 @@ impl Args { Ok((data, sketch_group)) } + fn get_data_and_geometry(&self) -> Result<(T, Geometry), KclError> { + let first_value = self + .args + .first() + .ok_or_else(|| { + KclError::Type(KclErrorDetails { + message: format!("Expected a struct as the first argument, found `{:?}`", self.args), + source_ranges: vec![self.source_range], + }) + })? + .get_json_value()?; + + let data: T = serde_json::from_value(first_value).map_err(|e| { + KclError::Type(KclErrorDetails { + message: format!("Failed to deserialize struct from JSON: {}", e), + source_ranges: vec![self.source_range], + }) + })?; + + let second_value = self.args.get(1).ok_or_else(|| { + KclError::Type(KclErrorDetails { + message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args), + source_ranges: vec![self.source_range], + }) + })?; + + let geometry = if let MemoryItem::SketchGroup(sg) = second_value { + Geometry::SketchGroup(sg.clone()) + } else if let MemoryItem::ExtrudeGroup(eg) = second_value { + Geometry::ExtrudeGroup(eg.clone()) + } else { + return Err(KclError::Type(KclErrorDetails { + message: format!( + "Expected a SketchGroup or ExtrudeGroup as the second argument, found `{:?}`", + self.args + ), + source_ranges: vec![self.source_range], + })); + }; + + Ok((data, geometry)) + } + fn get_data_and_plane(&self) -> Result<(T, Box), KclError> { let first_value = self .args @@ -741,8 +793,6 @@ mod tests { buf.push_str(&fn_docs); } - // uncomment to update - // std::fs::write("../../../docs/kcl/std.md", &buf).expect("Unable to write to file"); expectorate::assert_contents("../../../docs/kcl/std.md", &buf); } @@ -756,8 +806,6 @@ mod tests { let internal_fn = stdlib.fns.get(key).unwrap(); json_data.push(internal_fn.to_json().unwrap()); } - // uncomment to update - // std::fs::write("../../../docs/kcl/std.json", json_output).expect("Unable to write to file"); expectorate::assert_contents( "../../../docs/kcl/std.json", &serde_json::to_string_pretty(&json_data).unwrap(), diff --git a/src/wasm-lib/kcl/src/std/patterns.rs b/src/wasm-lib/kcl/src/std/patterns.rs new file mode 100644 index 000000000..f47a391c4 --- /dev/null +++ b/src/wasm-lib/kcl/src/std/patterns.rs @@ -0,0 +1,101 @@ +//! Standard library patterns. + +use anyhow::Result; +use derive_docs::stdlib; +use kittycad::types::ModelingCmd; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::{ + errors::{KclError, KclErrorDetails}, + executor::{Geometries, Geometry, MemoryItem}, + std::Args, +}; + +/// Data for a linear pattern. +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct LinearPatternData { + /// The number of repetitions. Must be greater than 0. + /// This excludes the original entity. For example, if `repetitions` is 1, + /// the original entity will be copied once. + pub repetitions: usize, + /// The distance between each repetition. This can also be referred to as spacing. + pub distance: f64, + /// The axis of the pattern. This is a 3D vector. + pub axis: [f64; 3], +} + +/// A linear pattern. +pub async fn pattern_linear(args: Args) -> Result { + let (data, geometry): (LinearPatternData, Geometry) = args.get_data_and_geometry()?; + + if data.axis == [0.0, 0.0, 0.0] { + return Err(KclError::Semantic(KclErrorDetails { + message: + "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place." + .to_string(), + source_ranges: vec![args.source_range], + })); + } + + let new_geometries = inner_pattern_linear(data, geometry, args).await?; + match new_geometries { + Geometries::SketchGroups(sketch_groups) => Ok(MemoryItem::SketchGroups { value: sketch_groups }), + Geometries::ExtrudeGroups(extrude_groups) => Ok(MemoryItem::ExtrudeGroups { value: extrude_groups }), + } +} + +/// A linear pattern. +#[stdlib { + name = "patternLinear", +}] +async fn inner_pattern_linear(data: LinearPatternData, geometry: Geometry, args: Args) -> Result { + let id = uuid::Uuid::new_v4(); + + let resp = args + .send_modeling_cmd( + id, + ModelingCmd::EntityLinearPattern { + axis: data.axis.into(), + entity_id: geometry.id(), + num_repetitions: data.repetitions as u32, + spacing: data.distance, + }, + ) + .await?; + + let kittycad::types::OkWebSocketResponseData::Modeling { + modeling_response: kittycad::types::OkModelingCmdResponse::EntityLinearPattern { data: pattern_info }, + } = &resp + else { + return Err(KclError::Engine(KclErrorDetails { + message: format!("EntityLinearPattern response was not as expected: {:?}", resp), + source_ranges: vec![args.source_range], + })); + }; + + let geometries = match geometry { + Geometry::SketchGroup(sketch_group) => { + let mut geometries = vec![sketch_group.clone()]; + for id in pattern_info.entity_ids.iter() { + let mut new_sketch_group = sketch_group.clone(); + new_sketch_group.id = *id; + geometries.push(new_sketch_group); + } + Geometries::SketchGroups(geometries) + } + Geometry::ExtrudeGroup(extrude_group) => { + let mut geometries = vec![extrude_group.clone()]; + for id in pattern_info.entity_ids.iter() { + let mut new_extrude_group = extrude_group.clone(); + new_extrude_group.id = *id; + geometries.push(new_extrude_group); + } + Geometries::ExtrudeGroups(geometries) + } + }; + + Ok(geometries) +} diff --git a/src/wasm-lib/kcl/src/std/sketch.rs b/src/wasm-lib/kcl/src/std/sketch.rs index 7ab28a3e0..9d5edb712 100644 --- a/src/wasm-lib/kcl/src/std/sketch.rs +++ b/src/wasm-lib/kcl/src/std/sketch.rs @@ -1,6 +1,5 @@ //! Functions related to sketching. -use crate::std::utils::{get_tangent_point_from_previous_arc, get_tangential_arc_to_info, TangentialArcInfoInput}; use anyhow::Result; use derive_docs::stdlib; use kittycad::types::{Angle, ModelingCmd, Point3D}; @@ -8,14 +7,17 @@ use kittycad_execution_plan_macros::ExecutionPlanValue; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::executor::SourceRange; use crate::{ errors::{KclError, KclErrorDetails}, executor::{ BasePath, GeoMeta, MemoryItem, Path, Plane, PlaneType, Point2d, Point3d, Position, Rotation, SketchGroup, + SketchGroupSet, SourceRange, }, std::{ - utils::{arc_angles, arc_center_and_end, get_x_component, get_y_component, intersection_with_parallel_line}, + 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, + }, Args, }, }; @@ -1419,7 +1421,7 @@ async fn inner_bezier_curve( /// Use a sketch to cut a hole in another sketch. pub async fn hole(args: Args) -> Result { - let (hole_sketch_group, sketch_group): (Box, Box) = args.get_sketch_groups()?; + let (hole_sketch_group, sketch_group): (SketchGroupSet, Box) = args.get_sketch_groups()?; let new_sketch_group = inner_hole(hole_sketch_group, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) @@ -1430,31 +1432,57 @@ pub async fn hole(args: Args) -> Result { name = "hole", }] async fn inner_hole( - hole_sketch_group: Box, + hole_sketch_group: SketchGroupSet, sketch_group: Box, args: Args, ) -> Result, KclError> { //TODO: batch these (once we have batch) - args.send_modeling_cmd( - uuid::Uuid::new_v4(), - ModelingCmd::Solid2DAddHole { - object_id: sketch_group.id, - hole_id: hole_sketch_group.id, - }, - ) - .await?; - - //suggestion (mike) - //we also hide the source hole since its essentially "consumed" by this operation - args.send_modeling_cmd( - uuid::Uuid::new_v4(), - ModelingCmd::ObjectVisible { - object_id: hole_sketch_group.id, - hidden: true, - }, - ) - .await?; + match hole_sketch_group { + SketchGroupSet::SketchGroup(hole_sketch_group) => { + args.send_modeling_cmd( + uuid::Uuid::new_v4(), + ModelingCmd::Solid2DAddHole { + object_id: sketch_group.id, + hole_id: hole_sketch_group.id, + }, + ) + .await?; + // suggestion (mike) + // we also hide the source hole since its essentially "consumed" by this operation + args.send_modeling_cmd( + uuid::Uuid::new_v4(), + ModelingCmd::ObjectVisible { + object_id: hole_sketch_group.id, + hidden: true, + }, + ) + .await?; + } + SketchGroupSet::SketchGroups(hole_sketch_groups) => { + for hole_sketch_group in hole_sketch_groups { + println!("hole_sketch_group: {:?} {}", hole_sketch_group.id, sketch_group.id); + args.send_modeling_cmd( + uuid::Uuid::new_v4(), + ModelingCmd::Solid2DAddHole { + object_id: sketch_group.id, + hole_id: hole_sketch_group.id, + }, + ) + .await?; + // suggestion (mike) + // we also hide the source hole since its essentially "consumed" by this operation + args.send_modeling_cmd( + uuid::Uuid::new_v4(), + ModelingCmd::ObjectVisible { + object_id: hole_sketch_group.id, + hidden: true, + }, + ) + .await?; + } + } + } // TODO: should we modify the sketch group to include the hole data, probably? diff --git a/src/wasm-lib/kcl/src/std/utils.rs b/src/wasm-lib/kcl/src/std/utils.rs index 0a811d88a..389ab7d99 100644 --- a/src/wasm-lib/kcl/src/std/utils.rs +++ b/src/wasm-lib/kcl/src/std/utils.rs @@ -638,9 +638,10 @@ pub fn get_tangential_arc_to_info(input: TangentialArcInfoInput) -> TangentialAr #[cfg(test)] mod get_tangential_arc_to_info_tests { - use super::*; use approx::assert_relative_eq; + use super::*; + fn round_to_three_decimals(num: f64) -> f64 { (num * 1000.0).round() / 1000.0 } diff --git a/src/wasm-lib/kcl/src/token/tokeniser.rs b/src/wasm-lib/kcl/src/token/tokeniser.rs index f44d31bc8..673ab2aec 100644 --- a/src/wasm-lib/kcl/src/token/tokeniser.rs +++ b/src/wasm-lib/kcl/src/token/tokeniser.rs @@ -4,7 +4,7 @@ use winnow::{ error::{ContextError, ParseError}, prelude::*, stream::{Location, Stream}, - token::{any, none_of, one_of, take_till1, take_until0}, + token::{any, none_of, one_of, take_till, take_until}, Located, }; @@ -47,13 +47,13 @@ pub fn token(i: &mut Located<&str>) -> PResult { } fn block_comment(i: &mut Located<&str>) -> PResult { - let inner = ("/*", take_until0("*/"), "*/").recognize(); + let inner = ("/*", take_until(0.., "*/"), "*/").recognize(); let (value, range) = inner.with_span().parse_next(i)?; Ok(Token::from_range(range, TokenType::BlockComment, value.to_string())) } fn line_comment(i: &mut Located<&str>) -> PResult { - let inner = (r#"//"#, take_till1(['\n', '\r'])).recognize(); + let inner = (r#"//"#, take_till(1.., ['\n', '\r'])).recognize(); let (value, range) = inner.with_span().parse_next(i)?; Ok(Token::from_range(range, TokenType::LineComment, value.to_string())) } diff --git a/src/wasm-lib/tests/executor/main.rs b/src/wasm-lib/tests/executor/main.rs index 073cf5884..8de4381a0 100644 --- a/src/wasm-lib/tests/executor/main.rs +++ b/src/wasm-lib/tests/executor/main.rs @@ -481,10 +481,10 @@ async fn optional_params() { |> startProfileAt(pos, %) |> arc({angle_end: 360, angle_start: 0, radius: radius}, %) |> close(%) - + return sg } - + show(circle([2, 2], 20)) "#; let result = execute_and_snapshot(code).await.unwrap(); @@ -559,3 +559,136 @@ circle([0,0], 22) |> extrude(14, %)"#; let result = execute_and_snapshot(code).await.unwrap(); twenty_twenty::assert_image("tests/executor/outputs/top_level_expression.png", &result, 0.999); } + +#[tokio::test(flavor = "multi_thread")] +async fn serial_test_patterns_linear_basic() { + let code = r#"fn circle = (pos, radius) => { + const sg = startSketchOn('XY') + |> startProfileAt([pos[0] + radius, pos[1]], %) + |> arc({ + angle_end: 360, + angle_start: 0, + radius: radius + }, %) + |> close(%) + return sg +} + +const part = circle([0,0], 2) + |> patternLinear({axis: [0,0,1], repetitions: 12, distance: 2}, %) +"#; + + let result = execute_and_snapshot(code).await.unwrap(); + twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic.png", &result, 0.999); +} + +#[tokio::test(flavor = "multi_thread")] +async fn serial_test_patterns_linear_basic_3d() { + let code = r#"fn circle = (pos, radius) => { + const sg = startSketchOn('XY') + |> startProfileAt([pos[0] + radius, pos[1]], %) + |> arc({ + angle_end: 360, + angle_start: 0, + radius: radius + }, %) + |> close(%) + return sg +} + +const part = startSketchOn('XY') + |> startProfileAt([0, 0], %) + |> line([0,1], %) + |> line([1, 0], %) + |> line([0, -1], %) + |> close(%) + |> extrude(1, %) + |> patternLinear({axis: [1, 0,1], repetitions: 3, distance: 6}, %) +"#; + + let result = execute_and_snapshot(code).await.unwrap(); + twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_3d.png", &result, 0.999); +} + +#[tokio::test(flavor = "multi_thread")] +async fn serial_test_patterns_linear_basic_negative_distance() { + let code = r#"fn circle = (pos, radius) => { + const sg = startSketchOn('XY') + |> startProfileAt([pos[0] + radius, pos[1]], %) + |> arc({ + angle_end: 360, + angle_start: 0, + radius: radius + }, %) + |> close(%) + return sg +} + +const part = circle([0,0], 2) + |> patternLinear({axis: [0,0,1], repetitions: 12, distance: -2}, %) +"#; + + let result = execute_and_snapshot(code).await.unwrap(); + twenty_twenty::assert_image( + "tests/executor/outputs/patterns_linear_basic_negative_distance.png", + &result, + 0.999, + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn serial_test_patterns_linear_basic_negative_axis() { + let code = r#"fn circle = (pos, radius) => { + const sg = startSketchOn('XY') + |> startProfileAt([pos[0] + radius, pos[1]], %) + |> arc({ + angle_end: 360, + angle_start: 0, + radius: radius + }, %) + |> close(%) + return sg +} + +const part = circle([0,0], 2) + |> patternLinear({axis: [0,0,-1], repetitions: 12, distance: 2}, %) +"#; + + let result = execute_and_snapshot(code).await.unwrap(); + twenty_twenty::assert_image( + "tests/executor/outputs/patterns_linear_basic_negative_axis.png", + &result, + 0.999, + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn serial_test_patterns_linear_basic_holes() { + let code = r#"fn circle = (pos, radius) => { + const sg = startSketchOn('XY') + |> startProfileAt([pos[0] + radius, pos[1]], %) + |> arc({ + angle_end: 360, + angle_start: 0, + radius: radius + }, %) + |> close(%) + return sg +} + +const circles = circle([5, 5], 1) + |> patternLinear({axis: [1,1,0], repetitions: 12, distance: 3}, %) + +const rectangle = startSketchOn('XY') + |> startProfileAt([0, 0], %) + |> line([0, 50], %) + |> line([50, 0], %) + |> line([0, -50], %) + |> close(%) + |> hole(circles, %) + +"#; + + let result = execute_and_snapshot(code).await.unwrap(); + twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_holes.png", &result, 0.999); +} diff --git a/src/wasm-lib/tests/executor/outputs/different_planes_same_drawing.png b/src/wasm-lib/tests/executor/outputs/different_planes_same_drawing.png index c22597eb0..9c1987ad5 100644 Binary files a/src/wasm-lib/tests/executor/outputs/different_planes_same_drawing.png and b/src/wasm-lib/tests/executor/outputs/different_planes_same_drawing.png differ diff --git a/src/wasm-lib/tests/executor/outputs/patterns_linear_basic.png b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic.png new file mode 100644 index 000000000..b5e6cca26 Binary files /dev/null and b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic.png differ diff --git a/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_3d.png b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_3d.png new file mode 100644 index 000000000..0deb03869 Binary files /dev/null and b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_3d.png differ diff --git a/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_holes.png b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_holes.png new file mode 100644 index 000000000..770e2b4ea Binary files /dev/null and b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_holes.png differ diff --git a/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_negative_axis.png b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_negative_axis.png new file mode 100644 index 000000000..0f6e47dee Binary files /dev/null and b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_negative_axis.png differ diff --git a/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_negative_distance.png b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_negative_distance.png new file mode 100644 index 000000000..0f6e47dee Binary files /dev/null and b/src/wasm-lib/tests/executor/outputs/patterns_linear_basic_negative_distance.png differ