math_plane.js

import oc from "../opencascade/initializer";
import {Face} from "../modeling";
import {Vector, Axis} from "./index";
import cachedGetters from "../utils/cache";

/**
 * Represents a mathematical plane in 3D space.
 * @memberof math
 * @alias Plane
 */
export class Plane {
  #wrapped;
  #forwardTransformation;
  #inverseTransformation;

  constructor({origin, normal, xDirection}) {
    const originPoint = new oc.gp_Pnt_3(origin.x, origin.y, origin.z);
    const normalDir = new oc.gp_Dir_4(normal.x, normal.y, normal.z);
    const xDir = new oc.gp_Dir_4(xDirection.x, xDirection.y, xDirection.z);
    const ax3 = new oc.gp_Ax3_3(originPoint, normalDir, xDir);
    this.#wrapped = new oc.gp_Pln_2(ax3);

    const globalCoordinateSystem = new oc.gp_Ax3_1();
    this.#forwardTransformation = new oc.gp_Trsf_1();
    this.#forwardTransformation.SetTransformation_1(globalCoordinateSystem, this.#wrapped.Position());

    this.#inverseTransformation = new oc.gp_Trsf_1();
    this.#inverseTransformation.SetTransformation_1(this.#wrapped.Position(), globalCoordinateSystem);
  }

  /**
   * Returns the wrapped OpenCascade object.
   * @private
   */
  get wrapped() {
    return this.#wrapped;
  }

  /**
   * Returns the origin of the plane.
   * @returns {Vector} The origin of the plane.
   */
  get origin() {
    const axis = this.#wrapped.Axis();
    const origin = axis.Location();
    return new Vector({x: origin.X(), y: origin.Y(), z: origin.Z()});
  }

  /**
   * Returns the normal vector of the plane.
   * @returns {Vector} The normal vector of the plane.
   */
  get normal() {
    const axis = this.#wrapped.Axis();
    const direction = axis.Direction();
    return new Vector({x: direction.X(), y: direction.Y(), z: direction.Z()});
  }

  /**
   * Returns the x-direction vector of the plane.
   * @returns {Vector} The x-direction vector of the plane.
   */
  get xDirection() {
    const direction = this.#wrapped.XAxis().Direction();
    return new Vector({x: direction.X(), y: direction.Y(), z: direction.Z()});
  }

  /**
   * Returns the axis of the plane.
   * @returns {Axis} An `Axis` object representing the plane's axis.
   */
  get axis() {
    return new Axis({
      origin: this.origin,
      direction: this.normal,
    });
  }

  /**
   * Transforms the given OpenCascade object to local coordinates of this plane.
   * @private
   * @param {*} transformable - An OpenCascade object that can be transformed.
   * @returns The transformed opencascade object.
   */
  toLocalCoordinates(transformable) {
    return transformable.Transformed(this.#forwardTransformation);
  }

  /**
   * Transforms the given OpenCascade object to world coordinates from local coordinates of this plane.
   * @private
   * @param {*} transformable - An OpenCascade object that can be transformed.
   * @returns The transformed opencascade object.
   */
  toWorldCoordinates(transformable) {
    return transformable.Transformed(this.#inverseTransformation);
  }

  /**
   * Offsets the plane by a given vector.
   * @param {Vector} offset - The offset vector to apply to the plane's origin.
   * @returns {Plane} A new `Plane` object with the origin offset by the given vector.
   */
  offset(offset) {
    return new Plane({
      origin: this.origin.add(offset),
      normal: this.normal,
      xDirection: this.xDirection,
    });
  }

  /**
   * Creates a `Plane` object from a given `Face` object.
   * @param {Face} face - The face from which to create a `Plane` object.
   * @returns {Plane|undefined} A new `Plane` object if the face is a plane, otherwise `undefined`.
   */
  static fromFace(face) {
    if (!(face.type === Face.TYPE.Plane)) {
      return undefined;
    }

    return new Plane({
      origin: face.centerOfMass,
      normal: face.normal,
      xDirection: face.xDirection,
    });
  }

  /**
   * Creates a `Plane` object representing the XY plane.
   * @returns {Plane} A new `Plane` object representing the XY plane.
   */
  static XY = new Plane({
    origin: Vector.ZERO,
    xDirection: Vector.X,
    normal: Vector.Z,
  });

  /**
   * Creates a `Plane` object representing the YX plane.
   * @returns {Plane} A new `Plane` object representing the YX plane.
   */
  static YX = new Plane({
    origin: Vector.ZERO,
    xDirection: Vector.Y,
    normal: Vector.NEGATIVE_Z,
  });

  /**
   * Creates a `Plane` object representing the YZ plane.
   * @returns {Plane} A new `Plane` object representing the YZ plane.
   */
  static YZ = new Plane({
    origin: Vector.ZERO,
    xDirection: Vector.Y,
    normal: Vector.X,
  });

  /**
   * Creates a `Plane` object representing the ZY plane.
   * @returns {Plane} A new `Plane` object representing the ZY plane.
   */
  static ZY = new Plane({
    origin: Vector.ZERO,
    xDirection: Vector.Z,
    normal: Vector.NEGATIVE_X,
  });

  /**
   * Creates a `Plane` object representing the XZ plane.
   * @returns {Plane} A new `Plane` object representing the XZ plane.
   */
  static XZ = new Plane({
    origin: Vector.ZERO,
    xDirection: Vector.X,
    normal: Vector.NEGATIVE_Y,
  });

  /**
   * Creates a `Plane` object representing the ZX plane.
   * @returns {Plane} A new `Plane` object representing the ZX plane.
   */
  static ZX = new Plane({
    origin: Vector.ZERO,
    xDirection: Vector.Z,
    normal: Vector.Y,
  });
}

cachedGetters({
  object: Plane,
  properties: ["origin", "normal", "xDirection", "axis"],
});