/// Sketching is the foundational activity for most KCL programs. A sketch is a two-dimensional
/// drawing made from paths or shapes. A sketch is always drawn on a surface (either an abstract
/// plane of a face of a solid). A sketch can be made into a solid by extruding it (or revolving, etc.).
///
/// This module contains functions for creating and manipulating sketches, and making them into solids.

@no_std
@settings(defaultLengthUnit = mm, kclVersion = 1.0)

/// Start a new 2-dimensional sketch on a specific plane or face.
///
/// ### Sketch on Face Behavior
///
/// There are some important behaviors to understand when sketching on a face:
///
/// The resulting sketch will _include_ the face and thus Solid
/// that was sketched on. So say you were to export the resulting Sketch / Solid
/// from a sketch on a face, you would get both the artifact of the sketch
/// on the face and the parent face / Solid itself.
///
/// This is important to understand because if you were to then sketch on the
/// resulting Solid, it would again include the face and parent Solid that was
/// sketched on. This could go on indefinitely.
///
/// The point is if you want to export the result of a sketch on a face, you
/// only need to export the final Solid that was created from the sketch on the
/// face, since it will include all the parent faces and Solids.
///
/// See [sketch on face](/docs/kcl-lang/sketch-on-face) for more details.
///
/// ### Multiple Profiles
///
/// When creating multiple profiles in a sketch, each profile must be made
/// separately and assigned to a variable. Using one pipeline to create multiple
/// profiles, where one profile is piped into the next, is not currently
/// supported.
///
/// ```kcl,inline
/// // This does NOT work.
/// twoSquares = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
///   |> startProfile(at = [20, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
/// twoCubes = extrude(twoSquares, length = 10)
/// ```
///
/// Instead, use separate pipelines, and extrude an array of them all.
///
/// ```kcl,inline
/// sketch1 = startSketchOn(XY)
/// squareProfile1 = startProfile(sketch1, at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
/// squareProfile2 = startProfile(sketch1, at = [20, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
/// twoCubes = extrude([squareProfile1, squareProfile2], length = 10)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
///
/// exampleSketch002 = startSketchOn(example, face = END)
///   |> startProfile(at = [1, 1])
///   |> line(end = [8, 0])
///   |> line(end = [0, 8])
///   |> line(end = [-8, 0])
///   |> close()
///
/// example002 = extrude(exampleSketch002, length = 5)
///
/// exampleSketch003 = startSketchOn(example002, face = END)
///   |> startProfile(at = [2, 2])
///   |> line(end = [6, 0])
///   |> line(end = [0, 6])
///   |> line(end = [-6, 0])
///   |> close()
///
/// example003 = extrude(exampleSketch003, length = 5)
/// ```
///
/// ```kcl
/// // Sketch on the end of an extruded face by tagging the end face.
///
/// exampleSketch = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 5, tagEnd = $end01)
///
/// exampleSketch002 = startSketchOn(example, face = end01)
///   |> startProfile(at = [1, 1])
///   |> line(end = [8, 0])
///   |> line(end = [0, 8])
///   |> line(end = [-8, 0])
///   |> close()
///
/// example002 = extrude(exampleSketch002, length = 5, tagEnd = $end02)
///
/// exampleSketch003 = startSketchOn(example002, face = end02)
///   |> startProfile(at = [2, 2])
///   |> line(end = [6, 0])
///   |> line(end = [0, 6])
///   |> line(end = [-6, 0])
///   |> close()
///
/// example003 = extrude(exampleSketch003, length = 5)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10], tag = $sketchingFace)
///   |> line(end = [-10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
///
/// exampleSketch002 = startSketchOn(example, face = sketchingFace)
///   |> startProfile(at = [1, 1])
///   |> line(end = [8, 0])
///   |> line(end = [0, 8])
///   |> line(end = [-8, 0])
///   |> close(tag = $sketchingFace002)
///
/// example002 = extrude(exampleSketch002, length = 10)
///
/// exampleSketch003 = startSketchOn(example002, face = sketchingFace002)
///   |> startProfile(at = [-8, 12])
///   |> line(end = [0, 6])
///   |> line(end = [6, 0])
///   |> line(end = [0, -6])
///   |> close()
///
/// example003 = extrude(exampleSketch003, length = 5)
/// ```
///
/// ```kcl
/// 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()
///
/// example = revolve(exampleSketch, axis = Y, angle = 180deg)
///
/// exampleSketch002 = startSketchOn(example, face = END)
///   |> startProfile(at = [4.5, -5])
///   |> line(end = [0, 5])
///   |> line(end = [5, 0])
///   |> line(end = [0, -5])
///   |> close()
///
/// example002 = extrude(exampleSketch002, length = 5)
/// ```
///
/// ```kcl
/// // Sketch on the end of a revolved face by tagging the end face.
///
/// 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()
///
/// example = revolve(exampleSketch, axis = Y, angle = 180deg, tagEnd = $end01)
///
/// exampleSketch002 = startSketchOn(example, face = end01)
///   |> startProfile(at = [4.5, -5])
///   |> line(end = [0, 5])
///   |> line(end = [5, 0])
///   |> line(end = [0, -5])
///   |> close()
///
/// example002 = extrude(exampleSketch002, length = 5)
/// ```
///
/// ```kcl
/// a1 = startSketchOn({
///     origin = { x = 0, y = 0, z = 0 },
///     xAxis = { x = 1, y = 0, z = 0 },
///     yAxis = { x = 0, y = 1, z = 0 },
///     zAxis = { x = 0, y = 0, z = 1 }
///   })
///  |> startProfile(at = [0, 0])
///  |> line(end = [100.0, 0])
///  |> yLine(length = -100.0)
///  |> xLine(length = -100.0)
///  |> yLine(length = 100.0)
///  |> close()
///  |> extrude(length = 3.14)
/// ```
///
/// ```kcl
/// sketch001 = startSketchOn(XY)
///   |> startProfile(at = [-5, -5])
///   |> xLine(length = 10)
///   |> yLine(length = 10, tag = $b)
///   |> xLine(length = -10)
///   |> close()
/// 
/// cube001 = extrude(sketch001, length = 10)
///   |> rotate(roll = 10, pitch = 20, yaw = 30)
/// 
/// sketch002 = startSketchOn(cube001, normalToFace = END, alignAxis = Y)
///   |> circle(radius = 2, center = [0, 0])
/// cube002 = extrude(sketch002, length = 4)
/// 
/// subtract(cube001, tools = cube002)
/// ```
@(impl = std_rust, feature_tree = true)
export fn startSketchOn(
  /// Profile whose start is being used.
  @planeOrSolid: Solid | Plane,
  /// Identify a face of a solid if a solid is specified as the input argument (`planeOrSolid`). Incompatible with `normalToFace`.
  face?: TaggedFace,
  /// Identify a face of a solid if a solid is specified as the input argument. Starts a sketch on the plane orthogonal to this specified face. Incompatible with `face`, requires `alignAxis`.
  normalToFace?: TaggedFace,
  /// If sketching normal to face, this axis will be the new local x axis of the sketch plane. The selected face's normal will be the local y axis. Incompatible with `face`, requires `normalToFace`.
  alignAxis?: Axis2d,
  /// Offset the sketch plane along its normal by the given amount. Incompatible with `face`, requires `normalToFace`.
  normalOffset?: number(Length),
): Plane | Face {}

/// Start a new profile at a given point.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(-XZ)
///   |> startProfile(at = [10, 10])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(-XZ)
///   |> startProfile(at = [-10, 23])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
///
/// ```kcl
/// // Create a sketch plane.
/// mySketch = startSketchOn(XY)
///
/// // Start a profile on the sketch plane.
/// squareProfile1 = startProfile(mySketch, at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
///
/// // Start another profile on the same sketch plane.
/// squareProfile2 = startProfile(mySketch, at = [20, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> close()
/// ```
@(impl = std_rust, feature_tree = false)
export fn startProfile(
  /// What to start the profile on.
  @startProfileOn: Plane | Face,
  /// Where to start the profile. An absolute point.
  @(snippetArray = ["0", "0"])
  at: Point2d,
  /// Tag this first starting point.
  tag?: TagDecl,
): Sketch {}

/// Sketch a rectangle.
///
/// A rectangle can be defined by its width, height, and location. Either the center or corner must be provided, but not both, to specify its location.
///
/// ```
/// exampleSketch = startSketchOn(-XZ)
///   |> rectangle(center = [0, 0], width = 10, height = 5)
//    |> extrude(length = 2)
/// ```
///
/// ```
/// exampleSketch = startSketchOn(-XZ)
///   |> rectangle(corner = [0, 0], width = 10, height = 5)
//    |> extrude(length = 2)
/// ```
@(impl = std_rust, feature_tree = false)
export fn rectangle(
  /// Sketch to extend, or plane or surface to sketch on.
  @sketchOrSurface: Sketch | Plane | Face,
  /// Rectangle's width along X axis.
  width: number(Length),
  /// Rectangle's height along Y axis.
  height: number(Length),
  /// The center of the rectangle.
  /// Either `corner` or `center` is required, but not both.
  @(snippetArray = ["0", "0"])
  center?: Point2d,
  /// The corner of the rectangle.
  /// Either `corner` or `center` is required, but not both.
  /// This will be the corner which is most negative on both X and Y axes.
  @(snippetArray = ["0", "0"])
  corner?: Point2d,
): Sketch {}

/// Construct a 2-dimensional circle, of the specified radius, centered at
/// the provided (x, y) origin point.
///
/// ```
/// exampleSketch = startSketchOn(-XZ)
///   |> circle(center = [0, 0], radius = 10)
///
/// example = extrude(exampleSketch, length = 5)
/// ```
///
/// ```
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [-15, 0])
///   |> line(end = [30, 0])
///   |> line(end = [0, 30])
///   |> line(end = [-30, 0])
///   |> close()
///   |> subtract2d(tool = circle(center = [0, 15], diameter = 10))
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn circle(
  /// Sketch to extend, or plane or surface to sketch on.
  @sketchOrSurface: Sketch | Plane | Face,
  /// The center of the circle.
  /// If not given, defaults to `[0, 0]`.
  @(includeInSnippet = true, snippetArray = ["0", "0"])
  center?: Point2d,
  /// The radius of the circle. Incompatible with `diameter`.
  radius?: number(Length),
  /// The diameter of the circle. Incompatible with `radius`.
  @(includeInSnippet = true)
  diameter?: number(Length),
  /// Create a new tag which refers to this circle.
  tag?: TagDecl,
): Sketch {}

/// Construct a 2-dimensional ellipse, of the specified major/minor radius, centered at the provided (x, y) point.
///
/// ```
/// @settings(experimentalFeatures = allow)
///
/// exampleSketch = startSketchOn(XY)
///   |> ellipse(center = [0, 0], majorRadius = 50, minorRadius = 20)
/// ```
@(impl = std_rust, experimental = true, feature_tree = true)
export fn ellipse(
  /// Sketch to extend, or plane or surface to sketch on.
  @sketchOrSurface: Sketch | Plane | Face,
  /// The center of the ellipse.
  @(snippetArray = ["0", "0"])
  center: Point2d,
  /// The minor radius of the ellipse.
  minorRadius: number(Length),
  /// The major radius of the ellipse. Equivalent to majorAxis = [majorRadius, 0].
  majorRadius?: number(Length),
  /// The major axis of the ellipse.
  majorAxis?: Point2d,
  /// Create a new tag which refers to this ellipse.
  tag?: TagDecl,
): Sketch {}

/// Extend a 2-dimensional sketch through a third dimension in order to
/// create new 3-dimensional volume, or if extruded into an existing volume,
/// cut into an existing solid.
///
/// You can provide more than one sketch to extrude, and they will all be
/// extruded in the same direction.
///
/// When you sketch on a face of a solid, extruding extends or cuts into the
/// existing solid, meaning you don't need to union or subtract the volumes. You
/// can change this behavior by using the `method` parameter. See
/// [sketch on face](/docs/kcl-lang/sketch-on-face) for more details.
///
/// ```kcl
/// example = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> arc(
///     angleStart = 120deg,
///     angleEnd = 0,
///     radius = 5,
///   )
///   |> line(end = [5, 0])
///   |> line(end = [0, 10])
///   |> bezierCurve(
///        control1 = [-10, 0],
///        control2 = [2, 10],
///        end = [-5, 10],
///      )
///   |> line(end = [-5, -2])
///   |> close()
///   |> extrude(length = 10)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [-10, 0])
///   |> arc(
///     angleStart = 120deg,
///     angleEnd = -60deg,
///     radius = 5,
///   )
///   |> line(end = [10, 0])
///   |> line(end = [5, 0])
///   |> bezierCurve(
///        control1 = [-3, 0],
///        control2 = [2, 10],
///        end = [-5, 10],
///      )
///   |> line(end = [-4, 10])
///   |> line(end = [-5, -2])
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [-10, 0])
///   |> arc(
///     angleStart = 120deg,
///     angleEnd = -60deg,
///     radius = 5,
///   )
///   |> line(end = [10, 0])
///   |> line(end = [5, 0])
///   |> bezierCurve(
///        control1 = [-3, 0],
///        control2 = [2, 10],
///        end = [-5, 10],
///      )
///   |> line(end = [-4, 10])
///   |> line(end = [-5, -2])
///   |> close()
///
/// example = extrude(exampleSketch, length = 20, symmetric = true)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [-10, 0])
///   |> arc(
///     angleStart = 120deg,
///     angleEnd = -60deg,
///     radius = 5,
///   )
///   |> line(end = [10, 0])
///   |> line(end = [5, 0])
///   |> bezierCurve(
///        control1 = [-3, 0],
///        control2 = [2, 10],
///        end = [-5, 10],
///      )
///   |> line(end = [-4, 10])
///   |> line(end = [-5, -2])
///   |> close()
///
/// example = extrude(exampleSketch, length = 10, bidirectionalLength = 50)
/// ```
/// ```kcl
/// example = startSketchOn(XZ)
///   |> polygon(radius = 10, numSides = 3, center = [0, 0])
///   |> extrude(length = 10, twistAngle = 120deg)
/// ```
///
/// ```kcl
/// sketch001 = startSketchOn(XY)
/// profile001 = startProfile(sketch001, at = [0, 0])
///   |> yLine(length = 1)
///   |> xLine(length = 1)
///   |> yLine(length = -1)
///   |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///   |> close()
/// cube = extrude(profile001, length = 1)
///
/// sketch002 = startSketchOn(cube, face = END)
/// profile002 = circle(sketch002, center = [0.38, 0.64], radius = 0.13)
/// // When sketching on a face, we can make a new solid instead of merging with
/// // it by using the method parameter.
/// cylinder = extrude(profile002, length = 2, method = NEW)
///
/// // The cylinder is a separate solid that can be translated separately from
/// // the cube.
/// translate(cylinder, x = 1)
/// ```
///
/// ```kcl
/// // You could also use the 'to' parameter if you want extrusions
/// // to end at a reference point, axis, scene geometry, tagged geometry, or plane.
/// 
/// 
/// sketch001 = startSketchOn(XY)
/// profile001 = startProfile(sketch001, at = [2, 2])
///   |> yLine(length = 1)
///   |> xLine(length = 1)
///   |> yLine(length = -1, tag = $facetag0)
///   |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $facetag1)
///   |> close()
/// cube = extrude(profile001, length = 1)
/// 
/// // extrude a circle to a point reference (red cylinder)
/// sketch002 = startSketchOn(XZ)
/// cylinder0 = circle(sketch002, center = [0.5, 0.5], radius = 0.25)
///   |> extrude(to = [-2, -3, -4])
///   |> appearance(color='#FF0000')
/// 
/// // extrude a circle to an axis reference (green cylinder)
/// sketch003 = startSketchOn(offsetPlane(XY, offset = -2))
/// cylinder1 = circle(sketch003, center = [0.5, 0.5], radius = 0.25)
///   |> extrude(to = Y)
///   |> appearance(color ='#00FF00')
/// 
/// // extrude a circle to a solid reference (blue cylinder)
/// sketch004 = startSketchOn(offsetPlane(YZ, offset = -1))
/// cylinder2 = circle(sketch004, center = [0.5, 0.5], radius = 0.25)
///   |> extrude(to = cube)
///   |> appearance(color ='#0000FF')
/// 
/// // extrude a circle to a tagged edge (cyan cylinder)
/// sketch005 = startSketchOn(offsetPlane(YZ, offset = 4))
/// cylinder3 = circle(sketch005, center = [0.5, 0.5], radius = 0.25)
///   |> extrude(to = getCommonEdge(faces = [facetag0, facetag1]))
///   |> appearance(color = '#00FFFF')
/// 
/// // extrude a circle to a plane (magenta cylinder)
/// sketch006 = startSketchOn(cube, face = facetag1)
/// cylinder4 = circle(sketch006, center = [2.5, 0.5], radius = 0.25)
///   |> extrude(to = XZ, method = NEW)
///   |> appearance(color ='#FF00FF')
/// ```
@(impl = std_rust, feature_tree = true)
export fn extrude(
  /// Which sketch or sketches should be extruded.
  @sketches: [Sketch; 1+],
  /// How far to extrude the given sketches. Incompatible with `to`.
  length?: number(Length),
  /// Reference to extrude to. Incompatible with `length` and `twistAngle`.
  to?: Point3d | Axis3d | Plane | Edge | Face | Sketch | Solid | TaggedEdge | TaggedFace,
  /// If true, the extrusion will happen symmetrically around the sketch. Otherwise, the extrusion will happen on only one side of the sketch.
  symmetric?: bool,
  /// If specified, will also extrude in the opposite direction to 'distance' to the specified distance. If 'symmetric' is true, this value is ignored.
  bidirectionalLength?: number(Length),
  /// A named tag for the face at the start of the extrusion, i.e. the original sketch.
  tagStart?: TagDecl,
  /// A named tag for the face at the end of the extrusion, i.e. the new face created by extruding the original sketch.
  tagEnd?: TagDecl,
  /// If given, the sketch will be twisted around this angle while being extruded. Incompatible with `to`.
  twistAngle?: number(Angle),
  /// The size of each intermediate angle as the sketch twists around.
  /// Must be between 4 and 90 degrees.
  /// Only used if `twistAngle` is given, defaults to 15 degrees.
  twistAngleStep?: number(Angle),
  /// The center around which the sketch will be twisted. Relative to the sketch's center.
  /// Only used if `twistAngle` is given, defaults to [0, 0] i.e. sketch's center.
  @(snippetArray = ["0", "0"])
  twistCenter?: Point2d,
  /// The method used during extrusion, either `NEW` or `MERGE`. `NEW` creates a new object. `MERGE` merges the extruded objects together. The default is `MERGE`.
  method?: string,
): [Solid; 1+] {}

/// Rotate a sketch around some provided axis, creating a solid from its extent.
///
/// This, like extrude, is able to create a 3-dimensional solid from a
/// 2-dimensional sketch. However, unlike extrude, this creates a solid
/// by using the extent of the sketch as its revolved around an axis rather
/// than using the extent of the sketch linearly translated through a third
/// dimension.
///
/// Revolve occurs around a local sketch axis rather than a global axis.
///
/// You can provide more than one sketch to revolve, and they will all be
/// revolved around the same axis.
///
/// ```kcl
/// part001 = 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()
///     |> revolve(axis = Y) // default angle is 360deg
/// ```
///
/// ```kcl
/// // A donut shape.
/// sketch001 = startSketchOn(XY)
///     |> circle( center = [15, 0], radius = 5 )
///     |> revolve(
///         angle = 360deg,
///         axis = Y,
///     )
/// ```
///
/// ```kcl
/// part001 = 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()
///     |> revolve(axis = Y, angle = 180deg)
/// ```
///
/// ```kcl
/// part001 = 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()
///     |> revolve(axis = Y, angle = 180deg)
///
/// part002 = startSketchOn(part001, face = END)
///     |> startProfile(at = [4.5, -5])
///     |> line(end = [0, 5])
///     |> line(end = [5, 0])
///     |> line(end = [0, -5])
///     |> close()
///     |> extrude(length = 5)
/// ```
///
/// ```kcl
/// box = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, 20])
///     |> line(end = [20, 0])
///     |> line(end = [0, -20])
///     |> close()
///     |> extrude(length = 20)
///
/// sketch001 = startSketchOn(box, face = END)
///     |> circle( center = [10,10], radius = 4 )
///     |> revolve(
///         angle = -90deg,
///         axis = Y
///     )
/// ```
///
/// ```kcl
/// box = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, 20])
///     |> line(end = [20, 0])
///     |> line(end = [0, -20], tag = $revolveAxis)
///     |> close()
///     |> extrude(length = 20)
///
/// sketch001 = startSketchOn(box, face = END)
///     |> circle( center = [10,10], radius = 4 )
///     |> revolve(
///         angle = 90deg,
///         axis = getOppositeEdge(revolveAxis)
///     )
/// ```
///
/// ```kcl
/// box = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, 20])
///     |> line(end = [20, 0])
///     |> line(end = [0, -20], tag = $revolveAxis)
///     |> close()
///     |> extrude(length = 20)
///
/// sketch001 = startSketchOn(box, face = END)
///     |> circle( center = [10,10], radius = 4 )
///     |> revolve(
///         angle = 90deg,
///         axis = getOppositeEdge(revolveAxis),
///         tolerance = 0.0001
///     )
/// ```
///
/// ```kcl
/// sketch001 = startSketchOn(XY)
///   |> startProfile(at = [10, 0])
///   |> line(end = [5, -5])
///   |> line(end = [5, 5])
///   |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///   |> close()
///
/// part001 = revolve(
///    sketch001,
///    axis = {
///      direction = [0.0, 1.0],
///      origin = [0.0, 0.0]
///   }
/// )
/// ```
///
/// ```kcl
/// // Revolve two sketches around the same axis.
///
/// sketch001 = startSketchOn(XY)
/// profile001 = startProfile(sketch001, at = [4, 8])
///     |> xLine(length = 3)
///     |> yLine(length = -3)
///     |> xLine(length = -3)
///     |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///     |> close()
///
/// profile002 = startProfile(sketch001, at = [-5, 8])
///     |> xLine(length = 3)
///     |> yLine(length = -3)
///     |> xLine(length = -3)
///     |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///     |> close()
///
/// revolve(
///     [profile001, profile002],
///     axis = X,
/// )
/// ```
///
/// ```kcl
/// // Revolve around a path that has not been extruded.
///
/// profile001 = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, 20], tag = $revolveAxis)
///     |> line(end = [20, 0])
///     |> line(end = [0, -20])
///     |> close(%)
///
/// sketch001 = startSketchOn(XY)
///     |> circle(center = [-10, 10], radius = 4)
///     |> revolve(angle = 90deg, axis = revolveAxis)
/// ```
///
/// ```kcl
/// // Revolve around a path that has not been extruded or closed.
///
/// profile001 = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, 20], tag = $revolveAxis)
///     |> line(end = [20, 0])
///
/// sketch001 = startSketchOn(XY)
///     |> circle(center = [-10, 10], radius = 4)
///     |> revolve(angle = 90deg, axis = revolveAxis)
/// ```
///
/// ```kcl
/// // Symmetrically revolve around a path.
///
/// profile001 = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, 20], tag = $revolveAxis)
///     |> line(end = [20, 0])
///
/// sketch001 = startSketchOn(XY)
///     |> circle(center = [-10, 10], radius = 4)
///     |> revolve(angle = 90deg, axis = revolveAxis, symmetric = true)
/// ```
///
/// ```kcl
/// // Bidirectional revolve around a path.
///
/// profile001 = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, 20], tag = $revolveAxis)
///     |> line(end = [20, 0])
///
/// sketch001 = startSketchOn(XY)
///     |> circle(center = [-10, 10], radius = 4)
///     |> revolve(angle = 90deg, axis = revolveAxis, bidirectionalAngle = 50)
/// ```
@(impl = std_rust, feature_tree = true)
export fn revolve(
  /// The sketch or set of sketches that should be revolved
  @sketches: [Sketch; 1+],
  /// Axis of revolution.
  axis: Axis2d | Edge,
  /// Angle to revolve (in degrees). Default is 360.
  angle?: number(Angle),
  /// Defines the smallest distance below which two entities are considered coincident, intersecting, coplanar, or similar. For most use cases, it should not be changed from its default value of 10^-7 millimeters.
  tolerance?: number(Length),
  /// If true, the extrusion will happen symmetrically around the sketch. Otherwise, the extrusion will happen on only one side of the sketch.
  symmetric?: bool,
  /// If specified, will also revolve in the opposite direction to 'angle' to the specified angle. If 'symmetric' is true, this value is ignored.
  bidirectionalAngle?: number(Angle),
  /// A named tag for the face at the start of the revolve, i.e. the original sketch.
  tagStart?: TagDecl,
  /// A named tag for the face at the end of the revolve.
  tagEnd?: TagDecl,
): [Solid; 1+] {}

/// Just like `patternTransform`, but works on 2D sketches not 3D solids.
///
/// ```kcl
/// // Each instance will be shifted along the X axis.
/// fn transform(@id) {
///   return { translate = [4 * id, 0] }
/// }
///
/// // Sketch 4 circles.
/// sketch001 = startSketchOn(XZ)
///   |> circle(center = [0, 0], radius = 2)
///   |> patternTransform2d(instances = 4, transform = transform)
/// ```
@(impl = std_rust, feature_tree = false)
export fn patternTransform2d(
  /// The sketch(es) to duplicate.
  @sketches: [Sketch; 1+],
  /// The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect.
  instances: number(Count),
  /// How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples.
  transform: fn(number(Count)): {},
  /// If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid.
  useOriginal?: boolean = false,
): [Sketch; 1+] {}

/// Get the opposite edge to the edge given.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> angledLine(
///        angle = 60deg,
///        length = 10,
///      )
///   |> angledLine(
///        angle = 120deg,
///        length = 10,
///      )
///   |> line(end = [-10, 0])
///   |> angledLine(
///        angle = 240deg,
///        length = 10,
///        tag = $referenceEdge,
///      )
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
///   |> fillet(
///     radius = 3,
///     tags = [getOppositeEdge(referenceEdge)],
///   )
/// ```
@(impl = std_rust, feature_tree = false)
export fn getOppositeEdge(
  /// The tag of the edge you want to find the opposite edge of.
  @edge: TaggedEdge,
): Edge {}

/// Get the next adjacent edge to the edge given.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> angledLine(
///        angle = 60deg,
///        length = 10,
///      )
///   |> angledLine(
///        angle = 120deg,
///        length = 10,
///      )
///   |> line(end = [-10, 0])
///   |> angledLine(
///        angle = 240deg,
///        length = 10,
///        tag = $referenceEdge,
///      )
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
///   |> fillet(
///     radius = 3,
///     tags = [getNextAdjacentEdge(referenceEdge)],
///   )
/// ```
@(impl = std_rust, feature_tree = false)
export fn getNextAdjacentEdge(
  /// The tag of the edge you want to find the next adjacent edge of.
  @edge: TaggedEdge,
): Edge {}

/// Get the previous adjacent edge to the edge given.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> angledLine(
///        angle = 60deg,
///        length = 10,
///      )
///   |> angledLine(
///        angle = 120deg,
///        length = 10,
///      )
///   |> line(end = [-10, 0])
///   |> angledLine(
///        angle = 240deg,
///        length = 10,
///        tag = $referenceEdge,
///      )
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
///   |> fillet(
///     radius = 3,
///     tags = [getPreviousAdjacentEdge(referenceEdge)],
///   )
/// ```
@(impl = std_rust, feature_tree = false)
export fn getPreviousAdjacentEdge(
  /// The tag of the edge you want to find the previous adjacent edge of.
  @edge: TaggedEdge,
): Edge {}

/// Get the shared edge between two faces.
///
/// ```kcl
/// // Get an edge shared between two faces, created after a chamfer.
///
/// scale = 20
/// part001 = startSketchOn(XY)
///     |> startProfile(at = [0, 0])
///     |> line(end = [0, scale])
///     |> line(end = [scale, 0])
///     |> line(end = [0, -scale])
///     |> close(tag = $line0)
///     |> extrude(length = 20, tagEnd = $end0)
///     // We tag the chamfer to reference it later.
///     |> chamfer(length = 10, tags = [getOppositeEdge(line0)], tag = $chamfer0)
///
/// // Get the shared edge between the chamfer and the extrusion.
/// commonEdge = getCommonEdge(faces = [chamfer0, end0])
///
/// // Chamfer the shared edge.
/// // TODO: uncomment this when ssi for fillets lands
/// // chamfer(part001, length = 5, tags = [commonEdge])
/// ```
@(impl = std_rust, feature_tree = false)
export fn getCommonEdge(
  /// The tags of the faces you want to find the common edge between.
  faces: [TaggedFace; 2],
): Edge {}

/// Construct a circle derived from 3 points.
///
/// ```kcl
/// exampleSketch = startSketchOn(XY)
///   |> circleThreePoint(p1 = [10,10], p2 = [20,8], p3 = [15,5])
///   |> extrude(length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn circleThreePoint(
  /// Plane or surface to sketch on.
  @sketchOrSurface: Sketch | Plane | Face,
  /// 1st point to derive the circle.
  p1: Point2d,
  /// 2nd point to derive the circle.
  p2: Point2d,
  /// 3rd point to derive the circle.
  p3: Point2d,
  /// Identifier for the circle to reference elsewhere.
  tag?: TagDecl,
): Sketch {}

/// Create a regular polygon with the specified number of sides that is either inscribed or circumscribed around a circle of the specified radius.
///
/// ```kcl
/// // Create a regular hexagon inscribed in a circle of radius 10
/// hex = startSketchOn(XY)
///   |> polygon(
///     radius = 10,
///     numSides = 6,
///     center = [0, 0],
///     inscribed = true,
///   )
///
/// example = extrude(hex, length = 5)
/// ```
///
/// ```kcl
/// // Create a square circumscribed around a circle of radius 5
/// square = startSketchOn(XY)
///   |> polygon(
///     radius = 5.0,
///     numSides = 4,
///     center = [10, 10],
///     inscribed = false,
///   )
/// example = extrude(square, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn polygon(
  /// Plane or surface to sketch on.
  @sketchOrSurface: Sketch | Plane | Face,
  /// The radius of the polygon.
  radius: number(Length),
  /// The number of sides in the polygon.
  numSides: number(Count),
  /// The center point of the polygon.
  @(snippetArray = ["0", "0"])
  center: Point2d,
  /// Whether the polygon is inscribed (true, the default) or circumscribed (false) about a circle with the specified radius.
  inscribed?: bool = true,
): Sketch {}

/// Extrude a sketch along a path.
///
/// This, like extrude, is able to create a 3-dimensional solid from a
/// 2-dimensional sketch. However, unlike extrude, this creates a solid
/// by using the extent of the sketch as its path. This is useful for
/// creating more complex shapes that can't be created with a simple
/// extrusion.
///
/// You can provide more than one sketch to sweep, and they will all be
/// swept along the same path.
///
/// ```kcl
/// // Create a pipe using a sweep.
///
/// // Create a path for the sweep.
/// sweepPath = startSketchOn(XZ)
///     |> startProfile(at = [0.05, 0.05])
///     |> line(end = [0, 7])
///     |> tangentialArc(angle = 90deg, radius = 5)
///     |> line(end = [-3, 0])
///     |> tangentialArc(angle = -90deg, radius = 5)
///     |> line(end = [0, 7])
///
/// // Create a hole for the pipe.
/// pipeHole = startSketchOn(XY)
///     |> circle(
///         center = [0, 0],
///         radius = 1.5,
///     )
///
/// sweepSketch = startSketchOn(XY)
///     |> circle(
///         center = [0, 0],
///         radius = 2,
///         )              
///     |> subtract2d(tool = pipeHole)
///     |> sweep(path = sweepPath)   
/// ```
///
/// ```kcl
/// // Create a spring by sweeping around a helix path.
///
/// // Create a helix around the Z axis.
/// helixPath = helix(
///     angleStart = 0,
///     ccw = true,
///     revolutions = 4,
///     length = 10,
///     radius = 5,
///     axis = Z,
///  )
///
///
/// // Create a spring by sweeping around the helix path.
/// springSketch = startSketchOn(XZ)
///     |> circle( center = [5, 0], radius = 1)
///     |> sweep(path = helixPath)
/// ```
///
/// ```kcl
/// // Sweep two sketches along the same path.
///
/// sketch001 = startSketchOn(XY)
/// rectangleSketch = startProfile(sketch001, at = [-200, 23.86])
///     |> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001)
///     |> angledLine(
///         angle = segAng(rectangleSegmentA001) - 90deg,
///         length = 50.61,
///     )
///     |> angledLine(
///         angle = segAng(rectangleSegmentA001),
///         length = -segLen(rectangleSegmentA001),
///     )
///     |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///     |> close()
///
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
///
/// sketch002 = startSketchOn(YZ)
/// sweepPath = startProfile(sketch002, at = [0, 0])
///     |> yLine(length = 231.81)
///     |> tangentialArc(radius = 80, angle = -90deg)
///     |> xLine(length = 384.93)
///
/// sweep([rectangleSketch, circleSketch], path = sweepPath)
/// ```
///
/// ```kcl
/// // Sectionally sweep one sketch along the path
///
/// sketch001 = startSketchOn(XY)
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
///
/// sketch002 = startSketchOn(YZ)
/// sweepPath = startProfile(sketch002, at = [0, 0])
///     |> yLine(length = 231.81)
///     |> tangentialArc(radius = 80, angle = -90deg)
///     |> xLine(length = 384.93)
///
/// sweep(circleSketch, path = sweepPath, sectional = true)
/// ```
@(impl = std_rust, feature_tree = true)
export fn sweep(
  /// The sketch or set of sketches that should be swept in space.
  @sketches: [Sketch; 1+],
  /// The path to sweep the sketch along.
  path: Sketch | Helix,
  /// If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components.
  sectional?: bool,
  /// Defines the smallest distance below which two entities are considered coincident, intersecting, coplanar, or similar. For most use cases, it should not be changed from its default value of 10^-7 millimeters.
  tolerance?: number(Length),
  /// What is the sweep relative to? Can be either 'sketchPlane' or 'trajectoryCurve'.
  relativeTo?: string = 'trajectoryCurve',
  /// A named tag for the face at the start of the sweep, i.e. the original sketch.
  tagStart?: TagDecl,
  /// A named tag for the face at the end of the sweep.
  tagEnd?: TagDecl,
): [Solid; 1+] {}

/// Create a 3D surface or solid by interpolating between two or more sketches.
///
/// The sketches need to be closed and on different planes that are parallel.
///
/// ```kcl
/// // Loft a square and a triangle.
/// squareSketch = startSketchOn(XY)
///     |> startProfile(at = [-100, 200])
///     |> line(end = [200, 0])
///     |> line(end = [0, -200])
///     |> line(end = [-200, 0])
///     |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///     |> close()
///
/// triangleSketch = startSketchOn(offsetPlane(XY, offset = 75))
///     |> startProfile(at = [0, 125])
///     |> line(end = [-15, -30])
///     |> line(end = [30, 0])
///     |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///     |> close()
///
/// loft([triangleSketch, squareSketch])
/// ```
///
/// ```kcl
/// // Loft a square, a circle, and another circle.
/// squareSketch = startSketchOn(XY)
///     |> startProfile(at = [-100, 200])
///     |> line(end = [200, 0])
///     |> line(end = [0, -200])
///     |> line(end = [-200, 0])
///     |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///     |> close()
///
/// circleSketch0 = startSketchOn(offsetPlane(XY, offset = 75))
///     |> circle( center = [0, 100], radius = 50 )
///
/// circleSketch1 = startSketchOn(offsetPlane(XY, offset = 150))
///     |> circle( center = [0, 100], radius = 20 )
///
/// loft([squareSketch, circleSketch0, circleSketch1])
/// ```
///
/// ```kcl
/// // Loft a square, a circle, and another circle with options.
/// squareSketch = startSketchOn(XY)
///     |> startProfile(at = [-100, 200])
///     |> line(end = [200, 0])
///     |> line(end = [0, -200])
///     |> line(end = [-200, 0])
///     |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
///     |> close()
///
/// circleSketch0 = startSketchOn(offsetPlane(XY, offset = 75))
///     |> circle( center = [0, 100], radius = 50 )
///
/// circleSketch1 = startSketchOn(offsetPlane(XY, offset = 150))
///     |> circle( center = [0, 100], radius = 20 )
///
/// loft([squareSketch, circleSketch0, circleSketch1],
///     baseCurveIndex = 0,
///     bezApproximateRational = false,
///     tolerance = 0.000001,
///     vDegree = 2,
/// )
/// ```
@(impl = std_rust, feature_tree = true)
export fn loft(
  /// Which sketches to loft. Must include at least 2 sketches.
  @sketches: [Sketch; 2+],
  /// Degree of the interpolation. Must be greater than zero. For example, use 2 for quadratic, or 3 for cubic interpolation in the V direction.
  vDegree?: number(Count) = 2,
  /// Attempt to approximate rational curves (such as arcs) using a bezier. This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios. Over time, this field won't be necessary.
  bezApproximateRational?: bool = false,
  /// This can be set to override the automatically determined topological base curve, which is usually the first section encountered.
  baseCurveIndex?: number(Count),
  /// Defines the smallest distance below which two entities are considered coincident, intersecting, coplanar, or similar. For most use cases, it should not be changed from its default value of 10^-7 millimeters.
  tolerance?: number(Length),
  /// A named tag for the face at the start of the loft, i.e. the original sketch.
  tagStart?: TagDecl,
  /// A named tag for the face at the end of the loft.
  tagEnd?: TagDecl,
): Solid {}

/// Repeat a 2-dimensional sketch along some dimension, with a dynamic amount
/// of distance between each repetition, some specified number of times.
///
/// ```kcl
/// /// Pattern using a named axis.
///
/// exampleSketch = startSketchOn(XZ)
///   |> circle(center = [0, 0], radius = 1)
///   |> patternLinear2d(
///        axis = X,
///        instances = 7,
///        distance = 4
///      )
///
/// example = extrude(exampleSketch, length = 1)
/// ```
///
/// ```kcl
/// /// Pattern using a raw axis.
///
/// exampleSketch = startSketchOn(XZ)
///   |> circle(center = [0, 0], radius = 1)
///   |> patternLinear2d(
///        axis = [1, 0],
///        instances = 7,
///        distance = 4
///      )
///
/// example = extrude(exampleSketch, length = 1)
/// ```
@(impl = std_rust, feature_tree = false)
export fn patternLinear2d(
  /// The sketch(es) to duplicate.
  @sketches: [Sketch; 1+],
  /// The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect.
  instances: number(Count),
  /// Distance between each repetition. Also known as 'spacing'.
  distance: number(Length),
  /// The axis of the pattern. A 2D vector.
  @(snippetArray = ["1", "0"])
  axis: Axis2d | Point2d,
  /// If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid.
  useOriginal?: bool = false,
): [Sketch; 1+] {}

/// Repeat a 2-dimensional sketch some number of times along a partial or
/// complete circle some specified number of times. Each object may
/// additionally be rotated along the circle, ensuring orientation of the
/// solid with respect to the center of the circle is maintained.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [.5, 25])
///   |> line(end = [0, 5])
///   |> line(end = [-1, 0])
///   |> line(end = [0, -5])
///   |> close()
///   |> patternCircular2d(
///        center = [0, 0],
///        instances = 13,
///        arcDegrees = 360,
///        rotateDuplicates = true
///      )
///
/// example = extrude(exampleSketch, length = 1)
/// ```
@(impl = std_rust, feature_tree = false)
export fn patternCircular2d(
  /// The sketch(es) to duplicate.
  @sketches: [Sketch; 1+],
  /// The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect.
  instances: number(Count),
  /// The center about which to make the pattern. This is a 2D vector.
  @(snippetArray = ["0", "0"])
  center: Point2d,
  /// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
  arcDegrees?: number(Angle) = 360deg,
  /// Whether or not to rotate the duplicates as they are copied.
  rotateDuplicates?: bool = true,
  /// If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid.
  useOriginal?: bool = false,
): [Sketch; 1+] {}

/// Compute the ending point of the provided line segment.
///
/// ```kcl
/// w = 15
/// cube = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [w, 0], tag = $line1)
///   |> line(end = [0, w], tag = $line2)
///   |> line(end = [-w, 0], tag = $line3)
///   |> line(end = [0, -w], tag = $line4)
///   |> close()
///   |> extrude(length = 5)
///
/// fn cylinder(radius, tag) {
///   return startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> circle(radius = radius, center = segEnd(tag) )
///   |> extrude(length = radius)
/// }
///
/// cylinder(radius = 1, tag = line1)
/// cylinder(radius = 2, tag = line2)
/// cylinder(radius = 3, tag = line3)
/// cylinder(radius = 4, tag = line4)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segEnd(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): Point2d {}

/// Compute the ending point of the provided line segment along the 'x' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [20, 0], tag = $thing)
///   |> line(end = [0, 5])
///   |> line(end = [segEndX(thing), 0])
///   |> line(end = [-20, 10])
///   |> close()
///  
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segEndX(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): number(Length) {}

/// Compute the ending point of the provided line segment along the 'y' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [20, 0])
///   |> line(end = [0, 3], tag = $thing)
///   |> line(end = [-10, 0])
///   |> line(end = [0, segEndY(thing)])
///   |> line(end = [-10, 0])
///   |> close()
///  
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segEndY(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): number(Length) {}

/// Compute the starting point of the provided line segment.
///
/// ```kcl
/// w = 15
/// cube = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [w, 0], tag = $line1)
///   |> line(end = [0, w], tag = $line2)
///   |> line(end = [-w, 0], tag = $line3)
///   |> line(end = [0, -w], tag = $line4)
///   |> close()
///   |> extrude(length = 5)
///
/// fn cylinder(radius, tag) {
///   return startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> circle( radius = radius, center = segStart(tag) )
///   |> extrude(length = radius)
/// }
///
/// cylinder(radius = 1, tag = line1)
/// cylinder(radius = 2, tag = line2)
/// cylinder(radius = 3, tag = line3)
/// cylinder(radius = 4, tag = line4)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segStart(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): Point2d {}

/// Compute the starting point of the provided line segment along the 'x' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [20, 0], tag = $thing)
///   |> line(end = [0, 5])
///   |> line(end = [20 - segStartX(thing), 0])
///   |> line(end = [-20, 10])
///   |> close()
///  
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segStartX(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): number(Length) {}

/// Compute the starting point of the provided line segment along the 'y' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [20, 0])
///   |> line(end = [0, 3], tag = $thing)
///   |> line(end = [-10, 0])
///   |> line(end = [0, 20-segStartY(thing)])
///   |> line(end = [-10, 0])
///   |> close()
///  
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segStartY(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): number(Length) {}

/// Extract the 'x' axis value of the last line segment in the provided 2-d sketch.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [5, 0])
///   |> line(end = [20, 5])
///   |> line(end = [lastSegX(%), 0])
///   |> line(end = [-15, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn lastSegX(
  /// The sketch whose line segment is being queried.
  @sketch: Sketch,
): number(Length) {}

/// Extract the 'y' axis value of the last line segment in the provided 2-d sketch.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [5, 0])
///   |> line(end = [20, 5])
///   |> line(end = [0, lastSegY(%)])
///   |> line(end = [-15, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn lastSegY(
  /// The sketch whose line segment is being queried.
  @sketch: Sketch,
): number(Length) {}

/// Compute the length of the provided line segment.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> angledLine(
///     angle = 60deg,
///     length = 10,
///     tag = $thing,
///   )
///   |> tangentialArc(angle = -120deg, radius = 5)
///   |> angledLine(
///     angle = -60deg,
///     length = segLen(thing),
///   )
///   |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segLen(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): number(Length) {}

/// Compute the angle (in degrees) of the provided line segment.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [5, 10], tag = $seg01)
///   |> line(end = [-10, 0])
///   |> angledLine(angle = segAng(seg01), length = 10)
///   |> line(end = [-10, 0])
///   |> angledLine(angle = segAng(seg01), length = -15)
///   |> close()
///
/// example = extrude(exampleSketch, length = 4)
/// ```
@(impl = std_rust, feature_tree = false)
export fn segAng(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): number(Angle) {}

/// Returns the angle coming out of the end of the segment in degrees.
///
/// ```kcl
/// // Horizontal pill.
/// pillSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [20, 0])
///   |> tangentialArc(end = [0, 10], tag = $arc1)
///   |> angledLine(
///     angle = tangentToEnd(arc1),
///     length = 20,
///   )
///   |> tangentialArc(end = [0, -10])
///   |> close()
///
/// pillExtrude = extrude(pillSketch, length = 10)
/// ```
///
/// ```kcl
/// // Vertical pill.  Use absolute coordinate for arc.
/// pillSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [0, 20])
///   |> tangentialArc(endAbsolute = [10, 20], tag = $arc1)
///   |> angledLine(
///     angle = tangentToEnd(arc1),
///     length = 20,
///   )
///   |> tangentialArc(end = [-10, 0])
///   |> close()
///
/// pillExtrude = extrude(pillSketch, length = 10)
/// ```
///
/// ```kcl
/// rectangleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0], tag = $seg1)
///   |> angledLine(
///     angle = tangentToEnd(seg1),
///     length = 10,
///   )
///   |> line(end = [0, 10])
///   |> line(end = [-20, 0])
///   |> close()
///
/// rectangleExtrude = extrude(rectangleSketch, length = 10)
/// ```
///
/// ```kcl
/// bottom = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> arc(
///        endAbsolute = [10, 10],
///        interiorAbsolute = [5, 1],
///        tag = $arc1,
///      )
///   |> angledLine(angle = tangentToEnd(arc1), length = 20)
///   |> close()
/// ```
///
/// ```kcl
/// circSketch = startSketchOn(XY)
///   |> circle(center = [0, 0], radius= 3, tag = $circ)
///
/// triangleSketch = startSketchOn(XY)
///   |> startProfile(at = [-5, 0])
///   |> angledLine(angle = tangentToEnd(circ), length = 10)
///   |> line(end = [-15, 0])
///   |> close()
/// ```
@(impl = std_rust, feature_tree = false)
export fn tangentToEnd(
  /// The line segment being queried by its tag.
  @tag: TaggedEdge,
): number(Angle) {}

/// Extract the provided 2-dimensional sketch's profile's origin value.
///
/// ```kcl
/// sketch001 = startSketchOn(XY)
///  |> startProfile(at = [5, 2])
///  |> angledLine(angle = 120deg, length = 50 , tag = $seg01)
///  |> angledLine(angle = segAng(seg01) + 120deg, length = 50 )
///  |> line(end = profileStart(%))
///  |> close()
///  |> extrude(length = 20)
/// ```
@(impl = std_rust, feature_tree = false)
export fn profileStart(
  /// Profile whose start is being used.
  @profile: Sketch,
): Point2d {}

/// Extract the provided 2-dimensional sketch's profile's origin's 'x' value.
///
/// ```kcl
/// sketch001 = startSketchOn(XY)
///  |> startProfile(at = [5, 2])
///  |> angledLine(angle = -26.6deg, length = 50)
///  |> angledLine(angle = 90deg, length = 50)
///  |> angledLine(angle = 30deg, endAbsoluteX = profileStartX(%))
/// ```
@(impl = std_rust, feature_tree = false)
export fn profileStartX(
  /// Profile whose start is being used.
  @profile: Sketch,
): number(Length) {}

/// Extract the provided 2-dimensional sketch's profile's origin's 'y' value.
///
/// ```kcl
/// sketch001 = startSketchOn(XY)
///  |> startProfile(at = [5, 2])
///  |> angledLine(angle = -60deg, length = 14 )
///  |> angledLine(angle = 30deg, endAbsoluteY =  profileStartY(%))
/// ```
@(impl = std_rust, feature_tree = false)
export fn profileStartY(
  /// Profile whose start is being used.
  @profile: Sketch,
): number(Length) {}

/// Extend the current sketch with a new involute circular curve.
///
/// ```kcl
/// a = 10
/// b = 14
/// startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> involuteCircular(startRadius = a, endRadius = b, angle = 60deg)
///   |> involuteCircular(startRadius = a, endRadius = b, angle = 60deg, reverse = true)
/// ```
/// ```kcl
/// // Example: a gear that uses an involute circular profile for the teeth.
/// @settings(defaultLengthUnit = mm)
///
/// /// // Define gear parameters
/// nTeeth = 21
/// module = 1.5
/// pressureAngle = 14deg
/// gearHeight = 6
/// pitchDiameter = module * nTeeth
/// addendum = module
/// deddendum = 1.25 * module
/// baseDiameter = pitchDiameter * cos(pressureAngle)
/// tipDiameter = pitchDiameter + 2 * module
///
/// // Using the gear parameters, sketch an involute tooth spanning from the base diameter to the tip diameter
/// gearSketch = startSketchOn(XY)
///   |> startProfile(at = polar(angle = 0, length = baseDiameter / 2))
///   |> involuteCircular(
///        startDiameter = baseDiameter,
///        endDiameter = tipDiameter,
///        angle = 0,
///        tag = $seg01,
///      )
///   |> line(endAbsolute = polar(angle = 160deg / nTeeth, length = tipDiameter / 2))
///   |> involuteCircular(
///        startDiameter = baseDiameter,
///        endDiameter = tipDiameter,
///        angle = -atan(segEndY(seg01) / segEndX(seg01)) - (180deg / nTeeth),
///        reverse = true,
///      )
///   // Position the end line of the sketch at the start of the next tooth
///   |> line(endAbsolute = polar(angle = 360deg / nTeeth, length = baseDiameter / 2))
///   // Pattern the sketch about the center by the specified number of teeth, then close the sketch
///   |> patternCircular2d(
///        instances = nTeeth,
///        center = [0, 0],
///        arcDegrees = 360deg,
///        rotateDuplicates = true,
///      )
///   |> close()
///   // Extrude the gear to the specified height
///   |> extrude(length = gearHeight)
/// ```
@(impl = std_rust, feature_tree = false)
export fn involuteCircular(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// The angle to rotate the involute by. A value of zero will produce a curve with a tangent along the x-axis at the start point of the curve.
  angle: number(Angle),
  /// The involute is described between two circles, startRadius is the radius of the inner circle.
  /// Either `startRadius` or `startDiameter` must be given (but not both).
  startRadius?: number(Length),
  /// The involute is described between two circles, endRadius is the radius of the outer circle.
  /// Either `endRadius` or `endDiameter` must be given (but not both).
  endRadius?: number(Length),
  /// The involute is described between two circles, startDiameter describes the inner circle.
  /// Either `startRadius` or `startDiameter` must be given (but not both).
  startDiameter?: number(Length),
  /// The involute is described between two circles, endDiameter describes the outer circle.
  /// Either `endRadius` or `endDiameter` must be given (but not both).
  endDiameter?: number(Length),
  /// If reverse is true, the segment will start from the end of the involute, otherwise it will start from that start.
  reverse?: bool = false,
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Extend the current sketch with a new straight line.
///
/// ```kcl
/// triangle = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   // The END argument means it ends at exactly [10, 0].
///   // This is an absolute measurement, it is NOT relative to
///   // the start of the sketch.
///   |> line(endAbsolute = [10, 0])
///   |> line(endAbsolute = [0, 10])
///   |> line(endAbsolute = [-10, 0], tag = $thirdLineOfTriangle)
///   |> close()
///   |> extrude(length = 5)
///
/// box = startSketchOn(XZ)
///   |> startProfile(at = [10, 10])
///   // The 'to' argument means move the pen this much.
///   // So, [10, 0] is a relative distance away from the current point.
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0], tag = $thirdLineOfBox)
///   |> close()
///   |> extrude(length = 5)
/// ```
@(impl = std_rust, feature_tree = false)
export fn line(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// Which absolute point should this line go to? Incompatible with `end`.
  endAbsolute?: Point2d,
  /// How far away (along the X and Y axes) should this line go? Incompatible with `endAbsolute`.
  @(includeInSnippet = true)
  end?: Point2d,
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Draw a line relative to the current origin to a specified distance away
/// from the current position along the 'x' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> xLine(length = 15)
///   |> angledLine(
///     angle = 80deg,
///     length = 15,
///   )
///   |> line(end = [8, -10])
///   |> xLine(length = 10)
///   |> angledLine(
///     angle = 120deg,
///     length = 30,
///   )
///   |> xLine(length = -15)
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn xLine(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// How far away along the X axis should this line go? Incompatible with `endAbsolute`.
  @(includeInSnippet = true)
  length?: number(Length),
  /// Which absolute X value should this line go to? Incompatible with `length`.
  endAbsolute?: number(Length),
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Draw a line relative to the current origin to a specified distance away
/// from the current position along the 'y' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> yLine(length = 15)
///   |> angledLine(
///     angle = 30deg,
///     length = 15,
///   )
///   |> line(end = [8, -10])
///   |> yLine(length = -5)
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn yLine(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// How far away along the Y axis should this line go? Incompatible with `endAbsolute`.
  @(includeInSnippet = true)
  length?: number(Length),
  /// Which absolute Y value should this line go to? Incompatible with `length`.
  endAbsolute?: number(Length),
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Draw a line segment relative to the current origin using the polar
/// measure of some angle and distance.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> yLine(endAbsolute = 15)
///   |> angledLine(
///     angle = 30deg,
///     length = 15,
///   )
///   |> line(end = [8, -10])
///   |> yLine(endAbsolute = 0)
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn angledLine(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// Which angle should the line be drawn at?
  angle: number(Angle),
  /// Draw the line this distance along the given angle. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given.
  length?: number(Length),
  /// Draw the line this distance along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given.
  lengthX?: number(Length),
  /// Draw the line this distance along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given.
  lengthY?: number(Length),
  /// Draw the line along the given angle until it reaches this point along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given.
  endAbsoluteX?: number(Length),
  /// Draw the line along the given angle until it reaches this point along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given.
  endAbsoluteY?: number(Length),
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Draw an angled line from the current origin, constructing a line segment
/// such that the newly created line intersects the desired target line
/// segment.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(endAbsolute = [5, 10])
///   |> line(endAbsolute = [-10, 10], tag = $lineToIntersect)
///   |> line(endAbsolute = [0, 20])
///   |> angledLineThatIntersects(
///        angle = 80deg,
///        intersectTag = lineToIntersect,
///        offset = 10,
///      )
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn angledLineThatIntersects(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// Which angle should the line be drawn at?
  angle: number(Angle),
  /// The tag of the line to intersect with.
  intersectTag: TaggedEdge,
  /// The offset from the intersecting line.
  offset?: number(Length) = 0mm,
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Construct a line segment from the current origin back to the profile's
/// origin, ensuring the resulting 2-dimensional sketch is not open-ended.
///
/// If you want to perform some 3-dimensional operation on a sketch, like
/// extrude or sweep, you must `close` it first. `close` must be called even
/// if the end point of the last segment is coincident with the sketch
/// starting point.
///
/// ```kcl
/// startSketchOn(XZ)
///    |> startProfile(at = [0, 0])
///    |> line(end = [10, 10])
///    |> line(end = [10, 0])
///    |> close()
///    |> extrude(length = 10)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(-XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn close(
  /// The sketch you want to close.
  @sketch: Sketch,
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Draw a curved line segment along an imaginary circle.
///
/// The arc is constructed such that the current position of the sketch is
/// placed along an imaginary circle of the specified radius, at angleStart
/// degrees. The resulting arc is the segment of the imaginary circle from
/// that origin point to angleEnd, radius away from the center of the imaginary
/// circle.
///
/// Unless this makes a lot of sense and feels like what you're looking
/// for to construct your shape, you're likely looking for tangentialArc.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> arc(
///        angleStart = 0,
///        angleEnd = 280deg,
///        radius = 16
///      )
///   |> close()
/// example = extrude(exampleSketch, length = 10)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> arc(
///         endAbsolute = [10,0],
///         interiorAbsolute = [5,5]
///      )
///   |> close()
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn arc(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// Where along the circle should this arc start?
  @(includeInSnippet = true)
  angleStart?: number(Angle),
  /// Where along the circle should this arc end?
  @(includeInSnippet = true)
  angleEnd?: number(Angle),
  /// How large should the circle be? Incompatible with `diameter`.
  radius?: number(Length),
  /// How large should the circle be? Incompatible with `radius`.
  @(includeInSnippet = true)
  diameter?: number(Length),
  /// Any point between the arc's start and end? Requires `endAbsolute`. Incompatible with `angleStart` or `angleEnd`.
  interiorAbsolute?: Point2d,
  /// Where should this arc end? Requires `interiorAbsolute`. Incompatible with `angleStart` or `angleEnd`.
  endAbsolute?: Point2d,
  /// Create a new tag which refers to this arc.
  tag?: TagDecl,
): Sketch {}

/// Starting at the current sketch's origin, draw a curved line segment along
/// some part of an imaginary circle until it reaches the desired (x, y)
/// coordinates.
///
/// When using radius and angle, draw a curved line segment along part of an
/// imaginary circle. The arc is constructed such that the last line segment is
/// placed tangent to the imaginary circle of the specified radius. The
/// resulting arc is the segment of the imaginary circle from that tangent point
/// for 'angle' degrees along the imaginary circle.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> angledLine(
///     angle = 45deg,
///     length = 10,
///   )
///   |> tangentialArc(end = [0, -10])
///   |> line(end = [-10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> angledLine(
///     angle = 60deg,
///     length = 10,
///   )
///   |> tangentialArc(endAbsolute = [15, 15])
///   |> line(end = [10, -15])
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> angledLine(
///     angle = 60deg,
///     length = 10,
///   )
///   |> tangentialArc(radius = 10, angle = -120deg)
///   |> angledLine(
///     angle = -60deg,
///     length = 10,
///   )
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn tangentialArc(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// Which absolute point should this arc go to? Incompatible with `end`, `radius`, and `offset`.
  endAbsolute?: Point2d,
  /// How far away (along the X and Y axes) should this arc go? Incompatible with `endAbsolute`, `radius`, and `offset`.
  @(includeInSnippet = true)
  end?: Point2d,
  /// Radius of the imaginary circle. `angle` must be given. Incompatible with `end` and `endAbsolute` and `diameter`.
  radius?: number(Length),
  /// Diameter of the imaginary circle. `angle` must be given. Incompatible with `end` and `endAbsolute` and `radius`.
  diameter?: number(Length),
  /// Offset of the arc. `radius` must be given. Incompatible with `end` and `endAbsolute`.
  angle?: number(Angle),
  /// Create a new tag which refers to this arc.
  tag?: TagDecl,
): Sketch {}

/// Draw a smooth, continuous, curved line segment from the current origin to
/// the desired (x, y), using a number of control points to shape the curve's
/// shape.
///
/// ```kcl
/// // Example using relative control points.
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> line(end = [0, 10])
///   |> bezierCurve(
///        control1 = [5, 0],
///        control2 = [5, 10],
///        end = [10, 10],
///      )
///   |> line(endAbsolute = [10, 0])
///   |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
///
/// ```kcl
/// // Example using absolute control points.
/// startSketchOn(XY)
///   |> startProfile(at = [300, 300])
///   |> bezierCurve(control1Absolute = [600, 300], control2Absolute = [-300, -100], endAbsolute = [600, 600])
///   |> close()
///   |> extrude(length = 10)
/// ```
@(impl = std_rust, feature_tree = false)
export fn bezierCurve(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// First control point for the cubic.
  control1?: Point2d,
  /// Second control point for the cubic.
  control2?: Point2d,
  /// How far away (along the X and Y axes) should this line go?
  end?: Point2d,
  /// First control point for the cubic. Absolute point.
  control1Absolute?: Point2d,
  /// Second control point for the cubic. Absolute point.
  control2Absolute?: Point2d,
  /// Coordinate on the plane at which this line should end.
  endAbsolute?: Point2d,
  /// Create a new tag which refers to this line.
  tag?: TagDecl,
): Sketch {}

/// Use a 2-dimensional sketch to cut a hole in another 2-dimensional sketch.
///
/// ```kcl
/// exampleSketch = startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [0, 5])
///   |> line(end = [5, 0])
///   |> line(end = [0, -5])
///   |> close()
///   |> subtract2d(tool =circle( center = [1, 1], radius = .25 ))
///   |> subtract2d(tool =circle( center = [1, 4], radius = .25 ))
///
/// example = extrude(exampleSketch, length = 1)
/// ```
///
/// ```kcl
/// fn squareHoleSketch() {
///   squareSketch = startSketchOn(-XZ)
///     |> startProfile(at = [-1, -1])
///     |> line(end = [2, 0])
///     |> line(end = [0, 2])
///     |> line(end = [-2, 0])
///     |> close()
///   return squareSketch
/// }
///
/// exampleSketch = startSketchOn(-XZ)
///     |> circle( center = [0, 0], radius = 3 )
///     |> subtract2d(tool = squareHoleSketch())
/// example = extrude(exampleSketch, length = 1)
/// ```
@(impl = std_rust, feature_tree = true)
export fn subtract2d(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// The shape(s) which should be cut out of the sketch.
  tool: [Sketch; 1+],
): Sketch {}

/// Add a conic section to an existing sketch.
///
/// ```kcl
/// @settings(experimentalFeatures = allow)
///
/// exampleSketch = startSketchOn(XZ)
///   |> startProfile(at = [0, 0])
///   |> conic(
///         end = [20,0],
///         endTangent = [1,1],
///         interior = [5,5],
///         startTangent = [0, -1],
///      )
///   |> close()
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, experimental = true, feature_tree = true)
export fn conic(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// Any point between the segment's start and end. Requires `endAbsolute`. Incompatible with `interior` or `end`.
  interiorAbsolute?: Point2d,
  /// Where should this segment end? Requires `interiorAbsolute`. Incompatible with `interior` or `end`.
  endAbsolute?: Point2d,
  /// Any point between the segment's start and end. This point is relative to the start point. Requires `end`. Incompatible with `interiorAbsolute` or `endAbsolute`.
  interior?: Point2d,
  /// Where should this segment end? This point is relative to the start point. Requires `interior`. Incompatible with `interiorAbsolute` or `endAbsolute`.
  end?: Point2d,
  /// The coefficients [a, b, c, d, e, f] of the generic conic equation ax^2 + by^2 + cxy + dx + ey + f = 0. If provided the start and end tangents will be calculated using this equation. Incompatible with `startTangent` and `endTangent`.
  coefficients?: [number; 6],
  /// The tangent of the conic section at the start. If not provided the tangent of the previous path segment is used. Incompatible with `coefficients`.
  startTangent?: Point2d,
  /// The tangent of the conic section at the end. Incompatible with `coefficients`.
  endTangent?: Point2d,
  /// Create a new tag which refers to this segment.
  tag?: TagDecl,
  ): Sketch {}

/// Add a parabolic segment to an existing sketch.
///
/// ```kcl
/// @settings(experimentalFeatures = allow)
///
/// exampleSketch = startSketchOn(XY)
///   |> startProfile(at = [0,0])
///   |> parabolic(
///         end = [10,0],
///         coefficients = [2, 0, 0],
///   )
///   |>close()
///```
@(impl = std_rust, experimental = true, feature_tree = true)
export fn parabolic(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// Where should the path end? Relative to the start point. Incompatible with `interiorAbsolute` or `endAbsolute`.
  end: Point2d,
  /// Where should this segment end? Requires `interiorAbsolute`. Incompatible with `interior` or `end`.
  endAbsolute?: Point2d,
  /// The coefficients [a, b, c] of the parabolic equation y = ax^2 + bx + c. Incompatible with `interior`.
  coefficients?: [number; 3],
  /// A point between the segment's start and end that lies on the parabola. Incompatible with `coefficients` or `interiorAbsolute` or `endAbsolute`.
  interior?: Point2d,
  /// Any point between the segment's start and end. Requires `endAbsolute`. Incompatible with `coefficients` or `interior` or `end`.
  interiorAbsolute?: Point2d,
  /// Create a new tag which refers to this segment.
  tag?: TagDecl,
): Sketch {}
 
/// Calculate the point (x, y) on a parabola given x or y and the coefficients [a, b, c] of the parabola.
///
/// ```kcl
/// point001 = parabolicPoint(x = 5, coefficients = [0.1, 0, 0])
/// point002 = parabolicPoint(y = 2.5, coefficients = [0.1, 0, 0])
/// assert(point001[0], isEqualTo = point002[0])
/// assert(point001[1], isEqualTo = point002[1])
///```
@(impl = std_rust, feature_tree = false)
export fn parabolicPoint(
  /// The coefficients [a, b, c] of the parabolic equation y = ax^2 + bx + c.
  coefficients: [number; 3],
  /// The x value. Calculates y and returns (x, y). Incompatible with `y`.
  x?: number(Length),
  /// The y value. Calculates x and returns (x, y). Incompatible with `x`.
  y?: number(Length),
): Point2d {}

/// Add a hyperbolic section to an existing sketch.
/// 
/// ```kcl
/// @settings(experimentalFeatures = allow)
///
/// exampleSketch = startSketchOn(XY)
///   |> startProfile(at = [0,0])
///   |> hyperbolic(
///         end = [10,0],
///         semiMajor = 2,
///         semiMinor = 1,
///         interior = [0,0]
///   )
///   |>close()
///```
@(impl = std_rust, experimental = true, feature_tree = true)
export fn hyperbolic(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// The semi major value, a, of the hyperbolic equation x^2 / a ^ 2 - y^2 / b^2 = 1.
  semiMajor: number(Length),
  ///  The semi minor value, b, of the hyperbolic equation x^2 / a ^ 2 - y^2 / b^2 = 1.
  semiMinor: number(Length),
  /// Any point between the segment's start and end. Requires `endAbsolute`. Incompatible with `interior` or `end`.
  interiorAbsolute?: Point2d,
  /// Where should this segment end? Requires `interiorAbsolute`. Incompatible with `interior` or `end`.
  endAbsolute?: Point2d,
  /// Any point between the segment's start and end. This point is relative to the start point. Requires `end`. Incompatible with `interiorAbsolute` or `endAbsolute`.
  interior?: Point2d,
  /// Where should this segment end? This point is relative to the start point. Requires `interior`. Incompatible with `interiorAbsolute` or `endAbsolute`.
  end?: Point2d,
  /// Create a new tag which refers to this arc.
  tag?: TagDecl,
): Sketch {}

/// Calculate the point (x, y) on a hyperbola given x or y and the semi major/minor values of the hyperbolic.
///
/// ```kcl
/// point = hyperbolicPoint(x = 5, semiMajor = 2, semiMinor = 1)
///```
@(impl = std_rust, feature_tree = false)
export fn hyperbolicPoint(
  /// The semi major value, a, of the hyperbolic equation x^2 / a ^ 2 - y^2 / b^2 = 1.
  semiMajor: number,
  ///  The semi minor value, b, of the hyperbolic equation x^2 / a ^ 2 - y^2 / b^2 = 1.
  semiMinor: number,
  /// The x value. Calculates y and returns (x, y). Incompatible with `y`.
  x?: number(Length),
  /// The y value. Calculates x and returns (x, y). Incompatible with `x`.
  y?: number(Length),
): Point2d {}

/// Add an elliptic section to an existing sketch.
///
/// ```kcl
/// @settings(experimentalFeatures = allow)
///
/// majorRadius = 2
/// minorRadius = 1
/// ellip = ellipticPoint(majorRadius, minorRadius, x = 2)
///
/// exampleSketch = startSketchOn(XY)
///    |> startProfile(at = ellip, tag = $start)
///    |> elliptic(center = [0, 0], angleStart = segAng(start), angleEnd = 160deg, majorRadius, minorRadius)
///    |> close()
/// example = extrude(exampleSketch, length = 10)
/// ```
@(impl = std_rust, experimental = true, feature_tree = true)
export fn elliptic(
  /// Which sketch should this path be added to?
  @sketch: Sketch,
  /// The center of the ellipse.
  @(snippetArray = ["0", "0"])
  center: Point2d,
  /// Where along the ellptic should this segment start?
  @(includeInSnippet = true)
  angleStart: number(Angle),
  /// Where along the ellptic should this segment end?
  @(includeInSnippet = true)
  angleEnd: number(Angle),
  /// The minor radius, b, of the elliptic equation x^2 / a^2 + y^2 / b^2 = 1.
  @(includeInSnippet = true)
  minorRadius: number(Length),
  /// The major radius, a, of the elliptic equation x^2 / a^2 + y^2 / b^2 = 1. Equivalent to majorAxis = [majorRadius, 0].
  majorRadius?: number(Length),
  /// The major axis of the elliptic.
  @(includeInSnippet = true)
  majorAxis?: Point2d,
  /// Create a new tag which refers to this arc.
  tag?: TagDecl,
): Sketch {}

/// Calculate the point (x, y) on an ellipse given x or y and the center and major/minor radii of the ellipse.
///
/// ```kcl
/// point001 = ellipticPoint(x = 2, majorRadius = 2, minorRadius = 1)
/// point002 = ellipticPoint(y = 0, majorRadius = 2, minorRadius = 1)
/// assert(point001[0], isEqualTo = point002[0])
/// assert(point001[1], isEqualTo = point002[1])
///```
@(impl = std_rust, feature_tree = false)
export fn ellipticPoint(
  /// The major radius, a, of the elliptic equation x^2 / a ^ 2 + y^2 / b^2 = 1.
  majorRadius: number,
  ///  The minor radius, b, of the hyperbolic equation x^2 / a ^ 2 + y^2 / b^2 = 1.
  minorRadius: number,
  /// The x value. Calculates y and returns (x, y). Incompatible with `y`.
  x?: number(Length),
  /// The y value. Calculates x and returns (x, y). Incompatible with `x`.
  y?: number(Length),
): Point2d {}

/// Find the plane a face lies on.
/// Returns an error if the face doesn't lie on any plane (for example, the curved face of a cylinder)
///```kcl
/// triangle = startSketchOn(XY)
/// |> polygon(radius = 3, numSides = 3, center = [0, 0])
/// |> extrude(length = 2)
/// 
/// // Find the plane of the triangle's top face.
/// topPlane = planeOf(triangle, face = END)
/// 
/// // Create a new plane, above the triangle's top face.
/// startSketchOn(offsetPlane(topPlane, offset = 2))
/// |> circle(radius = 1, center = [0,0])
/// |> extrude(length = 1)
/// ```
@(impl = std_rust, feature_tree = false)
export fn planeOf(
  /// The solid whose face is being queried.
  @solid: Solid,
  /// Find the plane which this face lies on.
  face: TaggedFace,
): Plane {}
