sketch_sketch.js

import {Axis, Plane, Vector} from "../math";
import {Line, BezierCurve, ThreePointsArc, TangentArc} from "../primitives-1d";
import {Face, Wire} from "../modeling";

/**
 * Represents a 2D sketch on a specified plane.
 * @memberof sketch
 * @alias Sketch
 */
export class Sketch {
  #plane;
  #pointer;
  #edges = [];

  /**
   * Creates a new Sketch on the given plane.
   * @param {Plane} [plane=Plane.XY] - The sketch plane.
   */
  constructor(plane = Plane.XY) {
    this.#plane = plane;
    this.#pointer = plane.origin;
  }

  /**
   * Returns the current pointer position.
   * @returns {Vector} The pointer position.
   */
  get pointer() {
    return this.#pointer;
  }

  /**
   * Moves the pointer to a given point (only if no edges exist).
   * @param {Vector} point - The new pointer position.
   * @returns {Sketch} The current `Sketch` instance.
   */
  movePointerTo(point) {
    if (!this.#edges.length) {
      this.#pointer = point;
    }
    return this;
  }

  /**
   * Adds a line from the current pointer to the given point.
   * @param {Vector} point - The end point of the line.
   * @returns {Sketch} The current `Sketch` instance.
   */
  lineTo(point) {
    const line = Line({plane: this.#plane, start: this.#pointer, end: point});
    this.#edges.push(line);
    this.#pointer = point;
    return this;
  }

  /**
   * Adds a line from the pointer by the given offset.
   * @param {Vector} offset - The offset vector.
   * @returns {Sketch} The current `Sketch` instance.
   */
  line(offset) {
    return this.lineTo(this.#pointer.add(offset));
  }

  /**
   * Adds a line at a given angle and length from the pointer.
   * @param {Object} params - Parameters.
   * @param {number} params.length - The line length.
   * @param {number} params.angle - The angle in radians.
   * @returns {Sketch} The current `Sketch` instance.
   */
  lineAtAngle({length, angle}) {
    return this.lineTo(
      this.#pointer
        .add(this.#plane.xDirection.scale(length))
        .rotate({axis: new Axis({origin: this.#pointer, direction: this.#plane.normal}), angle: angle})
    );
  }

  /**
   * Adds a line tangent to the last edge, with the given length.
   * @param {number} length - The tangent line length.
   * @returns {Sketch} The current `Sketch` instance.
   */
  tangentLine(length) {
    const tangent = this.#edges[this.#edges.length - 1].tangentAt(1);
    return this.lineTo(this.#pointer.add(tangent.scale(length)));
  }

  /**
   * Adds a tangent arc from the last edge to the given point.
   * @param {Vector} point - The arc end point.
   * @returns {Sketch} The current `Sketch` instance.
   */
  tangentArcTo(point) {
    const previousEdge = this.#edges[this.#edges.length - 1];
    const arc = TangentArc({plane: this.#plane, start: previousEdge.pointAt(1), tangent: previousEdge.tangentAt(1), end: point});
    this.#edges.push(arc);
    this.#pointer = point;
    return this;
  }

  /**
   * Adds a tangent arc from the pointer by the given offset.
   * @param {Vector} offset - The offset vector.
   * @returns {Sketch} The current `Sketch` instance.
   */
  tangentArc(offset) {
    return this.tangentArcTo(this.#pointer.add(offset));
  }

  /**
   * Adds a three-point arc from the pointer, through a point, to an end point.
   * @param {Object} params - Parameters.
   * @param {Vector} params.through - The through point.
   * @param {Vector} params.end - The arc end point.
   * @returns {Sketch} The current `Sketch` instance.
   */
  threePointsArcTo({through, end}) {
    const arc = ThreePointsArc({plane: this.#plane, start: this.#pointer, through: through, end: end});
    this.#edges.push(arc);
    this.#pointer = end;
    return this;
  }

  /**
   * Adds a Bezier curve from the pointer through the given points.
   * @param {Vector[]} points - Control points (excluding start).
   * @returns {Sketch} The current `Sketch` instance.
   */
  bezierCurveTo(points) {
    const curve = BezierCurve({plane: this.#plane, points: [this.#pointer, ...points]});
    this.#edges.push(curve);
    this.#pointer = points[points.length - 1];
    return this;
  }

  /**
   * Converts the sketch to a planar face.
   * @returns {Face} The resulting `Face`.
   */
  toFace() {
    return Face.fromWire(Wire.fromEdges(...this.#edges));
  }

  /**
   * Converts the sketch to a Wire.
   * @returns {Wire} The resulting `Wire`.
   */
  toWire() {
    return Wire.fromEdges(...this.#edges);
  }
}