/// Functions for working with geometric dimensioning and tolerancing (GD&T).

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

/// GD&T datum feature.
///
/// ```kcl,no3d,legacySketch
/// @settings(experimentalFeatures = allow, defaultLengthUnit = in)
///
/// width = 5
///
/// startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [width, 0], tag = $side1)
///   |> line(end = [0, width], tag = $side2)
///   |> line(end = [-width, 0], tag = $side3)
///   |> line(end = [0, -width], tag = $side4)
///   |> close()
///   |> extrude(length = 5, tagStart = $bottom, tagEnd = $top)
///
/// gdt::datum(
///   face = side2,
///   name = "A",
///   framePosition = [5, 0],
///   framePlane = XZ,
/// )
/// ```
///
/// ```kcl,no3d,sketchSolve
/// @settings(experimentalFeatures = allow)
///
/// blockProfile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 8mm, var 0mm])
///   edge2 = line(start = [var 8mm, var 0mm], end = [var 8mm, var 5mm])
///   edge3 = line(start = [var 8mm, var 5mm], end = [var 0mm, var 5mm])
///   edge4 = line(start = [var 0mm, var 5mm], end = [var 0mm, var 0mm])
///   coincident([edge1.end, edge2.start])
///   coincident([edge2.end, edge3.start])
///   coincident([edge3.end, edge4.start])
///   coincident([edge4.end, edge1.start])
///   horizontal(edge1)
///   vertical(edge2)
///   horizontal(edge3)
///   vertical(edge4)
/// }
///
/// block = extrude(region(point = [4mm, 2mm], sketch = blockProfile), length = 4mm, tagEnd = $top)
///
/// gdt::datum(
///   face = top,
///   name = "A",
///   framePosition = [10mm, 0mm],
///   framePlane = XZ,
/// )
/// ```
@(impl = std_rust, experimental = true, feature_tree = true)
export fn datum(
  /// The face to be annotated.
  @(includeInSnippet = true)
  face: TaggedFace,
  /// The name of the datum.
  @(includeInSnippet = true)
  name: string,
  /// The position of the feature control frame relative to the leader arrow. The default is `[100mm, 100mm]`.
  @(snippetArray = ["100", "100"])
  framePosition?: Point2d,
  /// The plane in which to display the feature control frame. The default is `XY`. Other standard planes like `XZ` and `YZ` can also be used. The frame may be displayed in a plane parallel to the given plane.
  @(includeInSnippet = true)
  framePlane?: Plane,
  /// Scale of the leader. The default is `1.0`. Must be greater than `0`.
  leaderScale?: number(Count),
  /// The font point size to use for the annotation text rendering. The default is `36`.
  fontPointSize?: number(Count),
  /// Scale to use for the annotation text after rendering with the point size. The default is `1.0`. Must be greater than `0`.
  fontScale?: number(Count),
): GdtAnnotation {}

/// GD&T annotation specifying how flat faces should be.
///
/// ```kcl,no3d,legacySketch
/// @settings(experimentalFeatures = allow)
///
/// startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> line(end = [0, -10])
///   |> close()
///   |> extrude(length = 5, tagStart = $face1)
/// gdt::flatness(faces = [face1], tolerance = 0.1mm)
/// ```
///
/// ```kcl,no3d,legacySketch
/// @settings(experimentalFeatures = allow)
///
/// startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0])
///   |> line(end = [0, -10])
///   |> close()
///   |> extrude(length = 5, tagEnd = $face1)
/// gdt::flatness(faces = [face1], tolerance = 0.02mm, framePosition = [10mm, 20mm], framePlane = XZ)
/// ```
///
/// ```kcl,no3d,legacySketch
/// @settings(experimentalFeatures = allow)
///
/// startSketchOn(XY)
///   |> startProfile(at = [0, 0])
///   |> line(end = [10, 0])
///   |> line(end = [0, 10])
///   |> line(end = [-10, 0], tag = $face1)
///   |> line(end = [0, -10])
///   |> close()
///   |> extrude(length = 5)
/// gdt::flatness(faces = [face1], tolerance = 0.02mm, framePosition = [10mm, 20mm], framePlane = XZ)
/// ```
///
/// ```kcl,no3d,sketchSolve
/// @settings(experimentalFeatures = allow)
///
/// blockProfile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 10mm, var 0mm])
///   edge2 = line(start = [var 10mm, var 0mm], end = [var 10mm, var 6mm])
///   edge3 = line(start = [var 10mm, var 6mm], end = [var 0mm, var 6mm])
///   edge4 = line(start = [var 0mm, var 6mm], end = [var 0mm, var 0mm])
///   coincident([edge1.end, edge2.start])
///   coincident([edge2.end, edge3.start])
///   coincident([edge3.end, edge4.start])
///   coincident([edge4.end, edge1.start])
///   horizontal(edge1)
///   vertical(edge2)
///   horizontal(edge3)
///   vertical(edge4)
/// }
///
/// block = extrude(region(point = [5mm, 3mm], sketch = blockProfile), length = 4mm, tagEnd = $top)
/// gdt::flatness(faces = [top], tolerance = 0.05mm, framePosition = [12mm, 8mm], framePlane = XZ)
/// ```
@(impl = std_rust, experimental = true, feature_tree = true)
export fn flatness(
  /// The faces to be annotated.
  @(includeInSnippet = true)
  faces: [TaggedFace; 1+],
  /// The amount of deviation from a perfect plane that is acceptable.
  @(includeInSnippet = true)
  tolerance: number(Length),
  /// The number of decimal places to display. The default is `3`. Must be greater than or equal to `0` and less than or equal to `9`.
  @(includeInSnippet = true)
  precision?: number(Count),
  /// The position of the feature control frame relative to the leader arrow. The default is `[100mm, 100mm]`.
  @(snippetArray = ["100", "100"])
  framePosition?: Point2d,
  /// The plane in which to display the feature control frame. The default is `XY`. Other standard planes like `XZ` and `YZ` can also be used. The frame may be displayed in a plane parallel to the given plane.
  @(includeInSnippet = true)
  framePlane?: Plane,
  /// Scale of the leader. The default is `1.0`. Must be greater than `0`.
  leaderScale?: number(Count),
  /// The font point size to use for the annotation text rendering. The default is `36`.
  fontPointSize?: number(Count),
  /// Scale to use for the annotation text after rendering with the point size. The default is `1.0`. Must be greater than `0`.
  fontScale?: number(Count),
): [GdtAnnotation; 1+] {}
