/// The KCL standard library /// /// Contains frequently used constants, functions for interacting with the KittyCAD servers to /// create sketches and geometry, and utility functions. /// /// The standard library is organised into modules (listed below), but most things are always available /// in KCL programs. /// /// You might also want the [KCL language reference](/docs/kcl-lang) or the [KCL guide](https://zoo.dev/docs/kcl-book/intro.html). @no_std @settings(defaultLengthUnit = mm, kclVersion = 1.0) // Note that everything in the prelude is treated as exported. export import * from "std::types" export import "std::units" export import * from "std::array" export import * from "std::math" export import * from "std::sketch" export import * from "std::solid" export import * from "std::transform" export import "std::turns" export import "std::sweep" export import "std::appearance" /// An abstract 3d plane aligned with the X and Y axes. Its normal is the positive Z axis. export XY = { origin = { x = 0, y = 0, z = 0 }, xAxis = { x = 1, y = 0, z = 0 }, yAxis = { x = 0, y = 1, z = 0 }, }: Plane /// An abstract 3d plane aligned with the X and Z axes. Its normal is the negative Y axis. export XZ = { origin = { x = 0, y = 0, z = 0 }, xAxis = { x = 1, y = 0, z = 0 }, yAxis = { x = 0, y = 0, z = 1 }, }: Plane /// An abstract 3d plane aligned with the Y and Z axes. Its normal is the positive X axis. export YZ = { origin = { x = 0, y = 0, z = 0 }, xAxis = { x = 0, y = 1, z = 0 }, yAxis = { x = 0, y = 0, z = 1 }, }: Plane /// The X-axis (can be used in both 2d and 3d contexts). export X = { origin = [0, 0, 0], direction = [1, 0, 0], }: Axis3d /// The Y-axis (can be used in both 2d and 3d contexts). export Y = { origin = [0, 0, 0], direction = [0, 1, 0], }: Axis3d /// The 3D Z-axis. export Z = { origin = [0, 0, 0], direction = [0, 0, 1], }: Axis3d /// Identifies the starting face of an extrusion. I.e., the face which is extruded. export START = 'start': TaggedFace /// Identifies the ending face of an extrusion. I.e., the new face created by an extrusion. export END = 'end': TaggedFace /// Create a helix. /// /// ``` /// // Create a helix around the Z axis. /// helixPath = helix( /// angleStart = 0, /// ccw = true, /// revolutions = 5, /// length = 10, /// radius = 5, /// axis = Z, /// ) /// /// // Create a spring by sweeping around the helix path. /// springSketch = startSketchOn(XZ) /// |> circle( center = [5, 0], radius = 0.5) /// |> sweep(path = helixPath) /// ``` /// /// ``` /// // Create a helix around an edge. /// helper001 = startSketchOn(XZ) /// |> startProfile(at = [0, 0]) /// |> line(end = [0, 10], tag = $edge001) /// /// helixPath = helix( /// angleStart = 0, /// ccw = true, /// revolutions = 5, /// length = 10, /// radius = 5, /// axis = edge001, /// ) /// /// // Create a spring by sweeping around the helix path. /// springSketch = startSketchOn(XZ) /// |> circle( center = [5, 0], radius = 0.5 ) /// |> sweep(path = helixPath) /// ``` /// /// ``` /// // Create a helix around a custom axis. /// helixPath = helix( /// angleStart = 0, /// ccw = true, /// revolutions = 5, /// length = 10, /// radius = 5, /// axis = { /// direction = [0, 0, 1.0], /// origin = [0, 0.25, 0] /// } /// ) /// /// // Create a spring by sweeping around the helix path. /// springSketch = startSketchOn(XZ) /// |> circle( center = [5, 0], radius = 1 ) /// |> sweep(path = helixPath) /// ``` /// /// ``` /// // Create a helix on a cylinder. /// /// part001 = startSketchOn(XY) /// |> circle( center = [5, 5], radius= 10 ) /// |> extrude(length = 10) /// /// helix( /// angleStart = 0, /// ccw = true, /// revolutions = 16, /// cylinder = part001, /// ) /// ``` @(impl = std_rust) export fn helix( /// Number of revolutions. revolutions: number(_), /// Start angle. angleStart: number(Angle), /// Is the helix rotation counter clockwise? The default is `false`. ccw?: bool, /// Radius of the helix. @(includeInSnippet = true) radius?: number(Length), /// Axis to use for the helix. @(includeInSnippet = true) axis?: Axis3d | Edge, /// Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used. @(includeInSnippet = true) length?: number(Length), /// Cylinder to create the helix on. cylinder?: Solid, ): Helix {} /// Offset a plane by a distance along its normal. /// /// For example, if you offset the `XZ` plane by 10, the new plane will be parallel to the `XZ` /// plane and 10 units away from it. /// /// ``` /// // Loft a square and a circle on the `XY` plane using offset. /// squareSketch = startSketchOn(XY) /// |> startProfile(at = [-100, 200]) /// |> line(end = [200, 0]) /// |> line(end = [0, -200]) /// |> line(end = [-200, 0]) /// |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) /// |> close() /// /// circleSketch = startSketchOn(offsetPlane(XY, offset = 150)) /// |> circle( center = [0, 100], radius = 50 ) /// /// loft([squareSketch, circleSketch]) /// ``` /// /// ``` /// // Loft a square and a circle on the `XZ` plane using offset. /// squareSketch = startSketchOn(XZ) /// |> startProfile(at = [-100, 200]) /// |> line(end = [200, 0]) /// |> line(end = [0, -200]) /// |> line(end = [-200, 0]) /// |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) /// |> close() /// /// circleSketch = startSketchOn(offsetPlane(XZ, offset = 150)) /// |> circle( center = [0, 100], radius = 50 ) /// /// loft([squareSketch, circleSketch]) /// ``` /// /// ``` /// // Loft a square and a circle on the `YZ` plane using offset. /// squareSketch = startSketchOn(YZ) /// |> startProfile(at = [-100, 200]) /// |> line(end = [200, 0]) /// |> line(end = [0, -200]) /// |> line(end = [-200, 0]) /// |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) /// |> close() /// /// circleSketch = startSketchOn(offsetPlane(YZ, offset = 150)) /// |> circle( center = [0, 100], radius = 50 ) /// /// loft([squareSketch, circleSketch]) /// ``` /// /// ``` /// // Loft a square and a circle on the `-XZ` plane using offset. /// squareSketch = startSketchOn(-XZ) /// |> startProfile(at = [-100, 200]) /// |> line(end = [200, 0]) /// |> line(end = [0, -200]) /// |> line(end = [-200, 0]) /// |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) /// |> close() /// /// circleSketch = startSketchOn(offsetPlane(-XZ, offset = 150)) /// |> circle(center = [0, 100], radius = 50) /// /// loft([squareSketch, circleSketch]) /// ``` /// /// ``` /// // A circle on the XY plane /// startSketchOn(XY) /// |> startProfile(at = [0, 0]) /// |> circle( radius = 10, center = [0, 0] ) /// /// // Triangle on the plane 4 units above /// startSketchOn(offsetPlane(XY, offset = 4)) /// |> startProfile(at = [0, 0]) /// |> line(end = [10, 0]) /// |> line(end = [0, 10]) /// |> close() /// ``` @(impl = std_rust) export fn offsetPlane( /// The plane (e.g. `XY`) which this new plane is created from. @plane: Plane, /// Distance from the standard plane this new plane will be created at. offset: number(Length), ): Plane {} /// Clone a sketch or solid. /// /// This works essentially like a copy-paste operation. It creates a perfect replica /// at that point in time that you can manipulate individually afterwards. /// /// This doesn't really have much utility unless you need the equivalent of a double /// instance pattern with zero transformations. /// /// Really only use this function if YOU ARE SURE you need it. In most cases you /// do not need clone and using a pattern with `instance = 2` is more appropriate. /// /// ```kcl /// // Clone a basic sketch and move it and extrude it. /// exampleSketch = startSketchOn(XY) /// |> startProfile(at = [0, 0]) /// |> line(end = [10, 0]) /// |> line(end = [0, 10]) /// |> line(end = [-10, 0]) /// |> close() /// /// clonedSketch = clone(exampleSketch) /// |> scale( /// x = 1.0, /// y = 1.0, /// z = 2.5, /// ) /// |> translate( /// x = 15.0, /// y = 0, /// z = 0, /// ) /// |> extrude(length = 5) /// ``` /// /// ```kcl /// // Clone a basic solid and move it. /// /// exampleSketch = startSketchOn(XY) /// |> startProfile(at = [0, 0]) /// |> line(end = [10, 0]) /// |> line(end = [0, 10]) /// |> line(end = [-10, 0]) /// |> close() /// /// myPart = extrude(exampleSketch, length = 5) /// clonedPart = clone(myPart) /// |> translate( /// x = 25.0, /// ) /// ``` /// /// ```kcl /// // Translate and rotate a cloned sketch to create a loft. /// /// sketch001 = startSketchOn(XY) /// |> startProfile(at = [-10, 10]) /// |> xLine(length = 20) /// |> yLine(length = -20) /// |> xLine(length = -20) /// |> close() /// /// sketch002 = clone(sketch001) /// |> translate(x = 0, y = 0, z = 20) /// |> rotate(axis = [0, 0, 1.0], angle = 45) /// /// loft([sketch001, sketch002]) /// ``` /// /// ```kcl /// // Translate a cloned solid. Fillet only the clone. /// /// sketch001 = startSketchOn(XY) /// |> startProfile(at = [-10, 10]) /// |> xLine(length = 20) /// |> yLine(length = -20) /// |> xLine(length = -20, tag = $filletTag) /// |> close() /// |> extrude(length = 5) /// /// /// sketch002 = clone(sketch001) /// |> translate(x = 0, y = 0, z = 20) /// |> fillet( /// radius = 2, /// tags = [getNextAdjacentEdge(filletTag)], /// ) /// ``` /// /// ```kcl /// // You can reuse the tags from the original geometry with the cloned geometry. /// /// sketch001 = startSketchOn(XY) /// |> startProfile(at = [0, 0]) /// |> line(end = [10, 0]) /// |> line(end = [0, 10], tag = $sketchingFace) /// |> line(end = [-10, 0]) /// |> close() /// /// sketch002 = clone(sketch001) /// |> translate(x = 10, y = 20, z = 0) /// |> extrude(length = 5) /// /// startSketchOn(sketch002, face = sketchingFace) /// |> startProfile(at = [1, 1]) /// |> line(end = [8, 0]) /// |> line(end = [0, 8]) /// |> line(end = [-8, 0]) /// |> close(tag = $sketchingFace002) /// |> extrude(length = 10) /// ``` /// /// ```kcl /// // You can also use the tags from the original geometry to fillet the cloned geometry. /// /// width = 20 /// length = 10 /// thickness = 1 /// filletRadius = 2 /// /// mountingPlateSketch = startSketchOn(XY) /// |> startProfile(at = [-width/2, -length/2]) /// |> line(endAbsolute = [width/2, -length/2], tag = $edge1) /// |> line(endAbsolute = [width/2, length/2], tag = $edge2) /// |> line(endAbsolute = [-width/2, length/2], tag = $edge3) /// |> close(tag = $edge4) /// /// mountingPlate = extrude(mountingPlateSketch, length = thickness) /// /// clonedMountingPlate = clone(mountingPlate) /// |> fillet( /// radius = filletRadius, /// tags = [ /// getNextAdjacentEdge(edge1), /// getNextAdjacentEdge(edge2), /// getNextAdjacentEdge(edge3), /// getNextAdjacentEdge(edge4) /// ], /// ) /// |> translate(x = 0, y = 50, z = 0) /// ``` /// /// ```kcl /// // Create a spring by sweeping around a helix path from a cloned sketch. /// /// // Create a helix around the Z axis. /// helixPath = helix( /// angleStart = 0, /// ccw = true, /// revolutions = 4, /// length = 10, /// radius = 5, /// axis = Z, /// ) /// /// /// springSketch = startSketchOn(XZ) /// |> circle( center = [0, 0], radius = 1) /// /// // Create a spring by sweeping around the helix path. /// sweepedSpring = clone(springSketch) /// |> translate(x=5) /// |> sweep(path = helixPath) /// ``` /// /// ```kcl /// // A donut shape from a cloned sketch. /// sketch001 = startSketchOn(XY) /// |> circle( center = [15, 0], radius = 5 ) /// /// sketch002 = clone(sketch001) /// |> translate( z = 30) /// |> revolve( /// angle = 360, /// axis = Y, /// ) /// ``` /// /// ```kcl /// // Sketch on the end of a revolved face by tagging the end face. /// // This shows the cloned geometry will have the same tags as the original geometry. /// /// exampleSketch = startSketchOn(XY) /// |> startProfile(at = [4, 12]) /// |> line(end = [2, 0]) /// |> line(end = [0, -6]) /// |> line(end = [4, -6]) /// |> line(end = [0, -6]) /// |> line(end = [-3.75, -4.5]) /// |> line(end = [0, -5.5]) /// |> line(end = [-2, 0]) /// |> close() /// /// example001 = revolve(exampleSketch, axis = Y, angle = 180, tagEnd = $end01) /// /// // example002 = clone(example001) /// // |> translate(x = 0, y = 20, z = 0) /// /// // Sketch on the cloned face. /// // exampleSketch002 = startSketchOn(example002, face = end01) /// // |> startProfile(at = [4.5, -5]) /// // |> line(end = [0, 5]) /// // |> line(end = [5, 0]) /// // |> line(end = [0, -5]) /// // |> close() /// /// // example003 = extrude(exampleSketch002, length = 5) /// ``` /// /// ```kcl /// // Clone an imported model. /// /// import "tests/inputs/cube.sldprt" as cube /// /// myCube = cube /// /// clonedCube = clone(myCube) /// |> translate( /// x = 1020, /// ) /// |> appearance( /// color = "#ff0000", /// metalness = 50, /// roughness = 50 /// ) /// ``` @(impl = std_rust) export fn clone( /// The sketch, solid, or imported geometry to be cloned. @geometry: Sketch | Solid | ImportedGeometry, ): Sketch | Solid | ImportedGeometry {} /// Asserts that a value is the boolean value true. /// /// ```kcl,norun /// kclIsFun = true /// assertIs(kclIsFun) /// ``` @(impl = std_rust) export fn assertIs( /// Value to check. If this is the boolean value true, assert passes. Otherwise it fails.. @actual: bool, /// If the value was false, the program will terminate with this error message error?: string, ) {} /// Check a value meets some expected conditions at runtime. Program terminates with an error if conditions aren't met. /// If you provide multiple conditions, they will all be checked and all must be met. /// /// ```kcl,norun /// n = 10 /// assert(n, isEqualTo = 10) /// assert(n, isGreaterThanOrEqual = 0, isLessThan = 100, error = "number should be between 0 and 100") /// assert(1.0000000000012, isEqualTo = 1, tolerance = 0.0001, error = "number should be almost exactly 1") /// ``` @(impl = std_rust) export fn assert( /// Value to check. If this is the boolean value true, assert passes. Otherwise it fails.. @actual: number, /// Comparison argument. If given, checks the `actual` value is greater than this. isGreaterThan?: number, /// Comparison argument. If given, checks the `actual` value is less than this. isLessThan?: number, /// Comparison argument. If given, checks the `actual` value is greater than or equal to this. isGreaterThanOrEqual?: number, /// Comparison argument. If given, checks the `actual` value is less than or equal to this. isLessThanOrEqual?: number, /// Comparison argument. If given, checks the `actual` value is less than or equal to this. @(includeInSnippet = true) isEqualTo?: number, /// If `isEqualTo` is used, this is the tolerance to allow for the comparison. This tolerance is used because KCL's number system has some floating-point imprecision when used with very large decimal places. tolerance?: number, /// If the value was false, the program will terminate with this error message error?: string, ) {}