/// 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"

/// 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'

/// Identifies the ending face of an extrusion. I.e., the new face created by an extrusion.
export END = 'end'

/// 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.
  @(include_in_snippet = true)
  radius?: number(Length),
  /// Axis to use for the helix.
  @(include_in_snippet = 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.
  @(include_in_snippet = 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 {}
