/// Functions for sketch-solve using constraints. This module's items are for
/// use within sketch blocks.
///
/// ```kcl,inline,sketchSolve
/// triangle = sketch(on = XY) {
///   line1 = line(start = [var -0.05mm, var -0.01mm], end = [var 3.88mm, var 0.81mm])
///   line2 = line(start = [var 3.88mm, var 0.81mm], end = [var 0.92mm, var 4.67mm])
///   coincident([line1.end, line2.start])
///   line3 = line(start = [var 0.92mm, var 4.67mm], end = [var -0.03mm, var -0.04mm])
///   coincident([line2.end, line3.start])
///   coincident([line1.start, line3.end])
///   horizontal(line1)
///   equalLength([line2, line3])
/// }
/// 
/// triangleRegion = region(point = [0.5mm, 0.5mm], sketch = triangle)
/// extrude(triangleRegion, length = 5)
/// ```
///
/// In the above example, the `sketch(on = XY) { ... }` is called the sketch
/// block. Inside the curly braces, all the functions and constants in this
/// module are in scope and available.
///
/// Values introduced with `var` are only initial guesses for the solver.
/// They are starting positions or starting sizes, not locked values, and the
/// solver is free to change them in the final solved sketch.
///
/// For that reason, initial guesses should always be literals. Do not use
/// identifiers, constant references, or computed expressions as initial
/// guesses. For example, use `var 0mm` or `var 10mm`, not `var width`,
/// `var baseRadius`, or `var (plateWidth / 2)`.
///
/// If a value must stay fixed, put that value in the constraint itself.
/// Constants and expressions belong in `distance`, `radius`, `diameter`,
/// `horizontalDistance`, `verticalDistance`, and similar constraint
/// functions, because those are what actually constrain the solved result.

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

import Point2d, Segment from "std::types"

/// The origin point in a sketch.
export ORIGIN = [0mm, 0mm]: Point2d

/// Create a point in a sketch.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   edge2 = line(start = [var 4mm, var 0mm], end = [var 4mm, var 3mm])
///   edge3 = line(start = [var 4mm, var 3mm], end = [var 0mm, var 3mm])
///   edge4 = line(start = [var 0mm, var 3mm], 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])
///   inside = point(at = [var 1mm, var 1mm])
/// }
///
/// solid = extrude(region(point = profile.inside), length = 2)
/// ```
@(impl = std_rust_constrainable, feature_tree = true)
export fn point(
  /// The point's position in the sketch's local 2D coordinate system.
  at: Point2d,
): Segment {}

/// Create a straight line segment in a sketch.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 5mm, var 0mm])
///   edge2 = line(start = [var 5mm, var 0mm], end = [var 5mm, var 3mm])
///   edge3 = line(start = [var 5mm, var 3mm], end = [var 0mm, var 3mm])
///   edge4 = line(start = [var 0mm, var 3mm], 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])
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constrainable, feature_tree = true)
export fn line(
  /// The segment's start point in sketch coordinates.
  start: Point2d,
  /// The segment's end point in sketch coordinates.
  end: Point2d,
  /// Whether this segment is construction geometry rather than part of the modeled profile.
  construction?: bool,
): Segment {}

/// Create a circular arc. The arc segment always sweeps counterclockwise from start to end.
/// To change direction, swap the start and end points.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   base = line(start = [var -5mm, var 0mm], end = [var 5mm, var 0mm])
///   top = arc(start = [var 5mm, var 0mm], end = [var -5mm, var 0mm], center = [var 0mm, var 5mm])
///   coincident([base.end, top.start])
///   coincident([base.start, top.end])
/// }
///
/// solid = extrude(region(point = [0mm, 2mm], sketch = profile), length = 2)
/// ```
/// ```kcl,sketchSolve
/// height = 2
/// profile = sketch(on = XY) {
///   arc1 = arc(start = [0, 0], end = [0, height], center = [0, height/2])
/// }
/// ```
@(impl = std_rust_constrainable, feature_tree = true)
export fn arc(
  /// The point where the arc begins.
  start: Point2d,
  /// The point where the arc ends.
  end: Point2d,
  /// The center of the circle the arc lies on.
  center: Point2d,
  /// Whether this segment is construction geometry rather than part of the modeled profile.
  construction?: bool,
): Segment {}

/// Create a circle in a sketch. The circle segment always has a starting point
/// and sweeps counterclockwise from it.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   circle1 = circle(start = [var 2mm, var 0mm], center = [var 0mm, var 0mm], construction = true)
///   edge1 = line(start = [var -3mm, var -2mm], end = [var 3mm, var -2mm])
///   edge2 = line(start = [var 3mm, var -2mm], end = [var 3mm, var 2mm])
///   edge3 = line(start = [var 3mm, var 2mm], end = [var -3mm, var 2mm])
///   edge4 = line(start = [var -3mm, var 2mm], end = [var -3mm, var -2mm])
///   coincident([edge1.end, edge2.start])
///   coincident([edge2.end, edge3.start])
///   coincident([edge3.end, edge4.start])
///   coincident([edge4.end, edge1.start])
/// }
///
/// solid = extrude(region(point = [0mm, 0mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constrainable, feature_tree = true)
export fn circle(
  /// A point on the circle that sets where the circle starts.
  start: Point2d,
  /// The center of the circle.
  center: Point2d,
  /// Whether this segment is construction geometry rather than part of the modeled profile.
  construction?: bool,
): Segment {}

/// Constrain points, or a point and a segment to be coincident.
///
/// Supports two points, or one point and one segment (line/arc).
/// A single `Point2d` (e.g. `[1mm, 2.5mm]`) can be used to pin a point to a fixed position.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   edge2 = line(start = [var 4mm, var 0mm], end = [var 4mm, var 3mm])
///   edge3 = line(start = [var 4mm, var 3mm], end = [var 0mm, var 3mm])
///   edge4 = line(start = [var 0mm, var 3mm], 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])
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn coincident(
  /// Two points, or one point and one line/arc segment, that should occupy the same location.
  @points: [Segment | Point2d; 2],
) {}

/// Constrain the distance between two points.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   edge2 = line(start = [var 4mm, var 0mm], end = [var 4mm, var 3mm])
///   edge3 = line(start = [var 4mm, var 3mm], end = [var 0mm, var 3mm])
///   edge4 = line(start = [var 0mm, var 3mm], 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])
///   distance([edge1.start, edge2.end]) == 5mm
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn distance(
  /// Two sketch points, or one sketch point and `ORIGIN`, whose separation should match the value set with `==`.
  @points: [Segment | Point2d; 2],
) {}

/// Constrain the radius of an arc segment.
/// Accepts a single arc segment and constrains the distance from its center to its start point.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   base = line(start = [var -4mm, var 0mm], end = [var 4mm, var 0mm])
///   arch = arc(start = [var 4mm, var 0mm], end = [var -4mm, var 0mm], center = [var 0mm, var 0mm])
///   coincident([base.end, arch.start])
///   coincident([base.start, arch.end])
///   radius(arch) == 4mm
/// }
///
/// solid = extrude(region(point = [0mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn radius(
  /// The arc segment whose radius should match the value set with `==`.
  @points: Segment,
) {}

/// Constrain the diameter of an arc or circle segment.
/// Accepts a single arc or circle segment and constrains the distance from its center to its start point.
/// Note: Diameter uses the same solver constraint as radius (distance between two points),
/// but is stored as a separate constraint type for proper UI display.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   guide = circle(start = [var 2mm, var 0mm], center = [var 0mm, var 0mm], construction = true)
///   diameter(guide) == 4mm
///   edge1 = line(start = [var -3mm, var -2mm], end = [var 3mm, var -2mm])
///   edge2 = line(start = [var 3mm, var -2mm], end = [var 3mm, var 2mm])
///   edge3 = line(start = [var 3mm, var 2mm], end = [var -3mm, var 2mm])
///   edge4 = line(start = [var -3mm, var 2mm], end = [var -3mm, var -2mm])
///   coincident([edge1.end, edge2.start])
///   coincident([edge2.end, edge3.start])
///   coincident([edge3.end, edge4.start])
///   coincident([edge4.end, edge1.start])
/// }
///
/// solid = extrude(region(point = [0mm, 0mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn diameter(
  /// The arc or circle segment whose diameter should match the value set with `==`.
  @points: Segment,
) {}

/// Constrain the horizontal distance between two points.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 6mm, var 0mm])
///   edge2 = line(start = [var 6mm, var 0mm], end = [var 6mm, var 4mm])
///   edge3 = line(start = [var 6mm, var 4mm], end = [var 0mm, var 4mm])
///   edge4 = line(start = [var 0mm, var 4mm], 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])
///   horizontalDistance([edge4.start, edge2.start]) == 6mm
/// }
///
/// solid = extrude(region(point = [3mm, 2mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn horizontalDistance(
  /// Two sketch points, or one sketch point and `ORIGIN`, whose X-axis separation should match the value set with `==`.
  @points: [Segment | Point2d; 2],
) {}

/// Constrain the vertical distance between two points.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   edge2 = line(start = [var 4mm, var 0mm], end = [var 4mm, var 5mm])
///   edge3 = line(start = [var 4mm, 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])
///   verticalDistance([edge1.start, edge4.start]) == 5mm
/// }
///
/// solid = extrude(region(point = [2mm, 2mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn verticalDistance(
  /// Two sketch points, or one sketch point and `ORIGIN`, whose Y-axis separation should match the value set with `==`.
  @points: [Segment | Point2d; 2],
) {}

/// Constrain lines to have equal length.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   base = line(start = [var -3mm, var 0mm], end = [var 3mm, var 0mm])
///   side1 = line(start = [var 3mm, var 0mm], end = [var 0mm, var 4mm])
///   side2 = line(start = [var 0mm, var 4mm], end = [var -3mm, var 0mm])
///   coincident([base.end, side1.start])
///   coincident([side1.end, side2.start])
///   coincident([side2.end, base.start])
///   horizontal(base)
///   equalLength([side1, side2])
/// }
///
/// solid = extrude(region(point = [0mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn equalLength(
  /// Two or more line segments that should all share the same length.
  @lines: [Segment; 2+],
) {}

/// Constrain circular segments to have equal radius.
///
/// ```kcl,sketchSolve
/// sketch1 = sketch(on = XY) {
///   circle1 = circle(start = [var -2mm, var 0mm], center = [var -6mm, var 0mm])
///   circle2 = circle(start = [var 10mm, var 0mm], center = [var 6mm, var 0mm])
///   equalRadius([circle1, circle2])
///   tangent([circle1, circle2])
/// }
///
/// solid1 = extrude(region(point = sketch1.circle1.center, sketch = sketch1), length = 2)
/// solid2 = extrude(region(point = sketch1.circle2.center, sketch = sketch1), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn equalRadius(
  /// Two or more arc or circle segments that should share the same radius.
  @input: [Segment; 2+],
) {}

/// Constrain lines to be parallel.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   base = line(start = [var 0mm, var 0mm], end = [var 5mm, var 0mm])
///   right = line(start = [var 5mm, var 0mm], end = [var 4mm, var 3mm])
///   top = line(start = [var 4mm, var 3mm], end = [var 1mm, var 3mm])
///   left = line(start = [var 1mm, var 3mm], end = [var 0mm, var 0mm])
///   coincident([base.end, right.start])
///   coincident([right.end, top.start])
///   coincident([top.end, left.start])
///   coincident([left.end, base.start])
///   parallel([base, top])
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn parallel(
  /// The line segments that should remain parallel.
  @input: [Segment; 2+],
) {}

/// Constrain lines to be perpendicular.
///
/// Currently limited to two lines.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   edge2 = line(start = [var 4mm, var 0mm], end = [var 4mm, var 3mm])
///   edge3 = line(start = [var 4mm, var 3mm], end = [var 0mm, var 3mm])
///   edge4 = line(start = [var 0mm, var 3mm], 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])
///   perpendicular([edge1, edge2])
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn perpendicular(
  /// The line segments that should remain perpendicular. Currently limited to two lines.
  @input: [Segment; 2+],
) {}

/// Constrain lines to meet at a given angle.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   line1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   line2 = line(start = [var 0mm, var 0mm], end = [var 2mm, var 3.464mm])
///   line3 = line(start = [var 2mm, var 3.464mm], end = [var 4mm, var 0mm])
///   coincident([line1.start, line2.start])
///   coincident([line2.end, line3.start])
///   coincident([line3.end, line1.end])
///   angle([line1, line2]) == 60deg
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn angle(
  /// The two line segments whose relative angle should match the value set with `==`.
  @input: [Segment; 2],
) {}

/// Constrain two segments to be tangent.
///
/// Supported input type pairs (unordered):
/// - `Line` / `Circle`
/// - `Line` / `CircularArc`
/// - `Circle` / `Circle`
/// - `Circle` / `CircularArc`
/// - `CircularArc` / `CircularArc`
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   guideArc = arc(start = [var 0mm, var 2mm], end = [var 2mm, var 0mm], center = [var 2mm, var 2mm])
///   tangentLine = line(start = [var 0mm, var 2mm], end = [var 0mm, var 4mm])
///   tangent([tangentLine, guideArc])
///   coincident([tangentLine.start, guideArc.start])
///   line1 = line(start = [var 0mm, var 4mm], end = [var 2mm, var 0mm])
///   coincident([guideArc.end, line1.end])
///   coincident([tangentLine.end, line1.start])
/// }
///
/// solid = extrude(region(point = [1mm, 1mm], sketch = profile), length = 2)
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn tangent(
  /// Two supported line/arc/circle segments that should touch without crossing.
  @input: [Segment; 2],
) {}

/// Constrain a point to be fixed to a position.
///
/// `fixed()` is an alias for `coincident()`. By convention, `fixed()` is used when one of the points is a known location, not solved with constraints and not another point in the sketch.
///
/// See [coincident()](/docs/kcl-std/functions/std-sketch2-coincident) for more info.
@(doc_category = "functions")
export fixed = coincident

/// Constrain a line, or a list of points, to be horizontal.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   edge2 = line(start = [var 4mm, var 0mm], end = [var 4mm, var 3mm])
///   edge3 = line(start = [var 4mm, var 3mm], end = [var 0mm, var 3mm])
///   edge4 = line(start = [var 0mm, var 3mm], 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)
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
/// ```kcl
/// profile = sketch(on = XY) {
///   p0 = [var 0mm, var 0mm]
///   p1 = [var 4mm, var 0mm]
///   horizontal([p0, p1])
/// }
/// ```
/// ```kcl
/// sketch001 = sketch(on = XY) {
///   p0 = point(at = [var -0.04mm, var 2.3mm])
///   horizontal([p0, ORIGIN])
/// }
/// ```
/// ```
/// sketch001 = sketch(on = XY) {
///   p0 = point(at = [var -2.23mm, var 3.1mm])
///   p1 = point(at = [var -3.05mm, var -1.89mm])
///   pf = point(at = [4, 4])
///   horizontal([p0, p1, pf])
/// }
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn horizontal(
  /// Either
  /// - A single line segment that should remain horizontal.
  /// - A list of points which should all be horizontal.
  @input: Segment | [Segment | Point2d; 2+],
) {}

/// Constrain a line, or a list of points, to be vertical.
///
/// ```kcl,sketchSolve
/// profile = sketch(on = XY) {
///   edge1 = line(start = [var 0mm, var 0mm], end = [var 4mm, var 0mm])
///   edge2 = line(start = [var 4mm, var 0mm], end = [var 4mm, var 3mm])
///   edge3 = line(start = [var 4mm, var 3mm], end = [var 0mm, var 3mm])
///   edge4 = line(start = [var 0mm, var 3mm], 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])
///   vertical(edge2)
/// }
///
/// solid = extrude(region(point = [2mm, 1mm], sketch = profile), length = 2)
/// ```
/// ```kcl
/// profile = sketch(on = XY) {
///   p0 = [var 0mm, var 0mm]
///   p1 = [var 4mm, var 0mm]
///   vertical([p0, p1])
/// }
/// ```
/// ```kcl
/// sketch001 = sketch(on = XY) {
///   p0 = point(at = [var 2.1mm, var -0.03mm])
///   vertical([p0, ORIGIN])
/// }
/// ```
@(impl = std_rust_constraint, feature_tree = true)
export fn vertical(
  /// Either
  /// - A single line segment that should remain vertical.
  /// - A list of points which should all be vertical.
  @input: Segment | [Segment | Point2d; 2+],
) {}
