import oc from "../opencascade/initializer";
import explore from "../utils/explore";
import cachedGetters from "../utils/cache";
import {Vertex} from "./index";
import {Vector} from "../math";
import {DEFAULT_ANGULAR_TOLERANCE} from "../constants";
/**
* Represents an edge in 3D space.
* @memberof modeling
* @alias Edge
*/
export class Edge {
#wrapped;
#curve;
/**
* @hideconstructor
*/
constructor(wrapped) {
this.#wrapped = oc.TopoDS.Edge_1(wrapped);
}
/**
* Returns the wrapped OpenCascade object.
* @private
*/
get wrapped() {
return this.#wrapped;
}
/**
* Retrieves all vertices of the edge.
* @returns {Vertex[]} An array of `Vertex` objects representing the vertices of the edge.
*/
get vertices() {
return explore({shape: this.#wrapped, find: oc.TopAbs_ShapeEnum.TopAbs_VERTEX}).map((shape) => new Vertex(shape));
}
/**
* Calculates the length of the edge.
* @returns {number} The length of the edge.
*/
get length() {
return oc.GCPnts_AbscissaPoint.Length_1(this.#asCurve());
}
/**
* Determines the type of the edge's curve.
* @returns {string} The type of the edge (e.g., "Line", "Circle").
*/
get type() {
switch (this.#asCurve().GetType()) {
case oc.GeomAbs_CurveType.GeomAbs_Line:
return Edge.TYPE.Line;
case oc.GeomAbs_CurveType.GeomAbs_Circle:
return Edge.TYPE.Circle;
case oc.GeomAbs_CurveType.GeomAbs_Ellipse:
return Edge.TYPE.Ellipse;
case oc.GeomAbs_CurveType.GeomAbs_Hyperbola:
return Edge.TYPE.Hyperbola;
case oc.GeomAbs_CurveType.GeomAbs_Parabola:
return Edge.TYPE.Parabola;
case oc.GeomAbs_CurveType.GeomAbs_BezierCurve:
return Edge.TYPE.BezierCurve;
case oc.GeomAbs_CurveType.GeomAbs_BSplineCurve:
return Edge.TYPE.BSplineCurve;
case oc.GeomAbs_CurveType.GeomAbs_OffsetCurve:
return Edge.TYPE.OffsetCurve;
case oc.GeomAbs_CurveType.GeomAbs_OtherCurve:
return Edge.TYPE.OtherCurve;
}
}
/**
* Retrieves the point at a specified normalized distance along the edge.
* @param {number} value - The normalized distance along the edge (between 0 and 1).
* @returns {Vector} A `Vector` object representing the point at the given distance.
*/
pointAt(value) {
const param = this.#parameterAt(value);
const point = this.#asCurve().Value(param);
return new Vector({
x: point.X(),
y: point.Y(),
z: point.Z(),
});
}
/**
* Retrieves the point at a specified distance along the edge.
* @param {number} value - The distance along the edge (between 0 and edge.length()).
* @returns {Vector} A `Vector` object representing the point at the given distance.
*/
pointAtLength(value) {
const param = this.#parameterAtLength(value);
const point = this.#asCurve().Value(param);
return new Vector({
x: point.X(),
y: point.Y(),
z: point.Z(),
});
}
/**
* Retrieves the tangent vector at a specified normalized distance along the edge.
* @param {number} value - The normalized distance along the edge (between 0 and 1).
* @returns {Vector} A `Vector` object representing the tangent vector at the given distance.
*/
tangentAt(value) {
const param = this.#parameterAt(value);
const point = new oc.gp_Pnt_1();
const vector = new oc.gp_Vec_1();
this.#asCurve().D1(param, point, vector);
const tangent = new oc.gp_Dir_2(vector);
return new Vector({
x: tangent.X(),
y: tangent.Y(),
z: tangent.Z(),
}).normalize();
}
/**
* Checks if the edge is parallel to a given direction vector. Only applicable for line edges.
* @param {Vector} direction - The direction vector.
* @returns {boolean|undefined} `true` if the edge is parallel to the direction, `false` otherwise, or `undefined` if not a line.
*/
isParallel(direction) {
if (this.type() !== Edge.TYPE.Line) {
return undefined;
}
const dir = new oc.gp_Dir_4(direction.x, direction.y, direction.z);
return this.#asCurve().Line().Direction().IsParallel(dir, DEFAULT_ANGULAR_TOLERANCE);
}
/**
* Checks if the edge is perpendicular to a given direction vector. Only applicable for line edges.
* @param {Vector} direction - The direction vector.
* @returns {boolean|undefined} `true` if the edge is perpendicular to the direction, `false` otherwise, or `undefined` if not a line.
*/
isPerpendicular(direction) {
if (this.type() !== Edge.TYPE.Line) {
return undefined;
}
const dir = new oc.gp_Dir_4(direction.x, direction.y, direction.z);
return this.#asCurve().Line().Direction().IsNormal(dir, DEFAULT_ANGULAR_TOLERANCE);
}
/**
* Computes the hash code for the solid.
* @returns {number} The hash code.
* @private
*/
hashCode() {
return oc.OCJS.HashCode(this.#wrapped);
}
#parameterAt(value) {
const curve = this.#asCurve();
return new oc.GCPnts_AbscissaPoint_2(curve, value * this.length, curve.FirstParameter()).Parameter();
}
#parameterAtLength(value) {
const curve = this.#asCurve();
return new oc.GCPnts_AbscissaPoint_2(curve, value, curve.FirstParameter()).Parameter();
}
#asCurve() {
if (!this.#curve) {
this.#curve = new oc.BRepAdaptor_Curve_2(this.#wrapped);
}
return this.#curve;
}
static TYPE = Object.freeze({
Line: "Line",
Circle: "Circle",
Ellipse: "Ellipse",
Hyperbola: "Hyperbola",
Parabola: "Parabola",
BezierCurve: "BezierCurve",
BSplineCurve: "BSplineCurve",
OffsetCurve: "OffsetCurve",
OtherCurve: "OtherCurve",
});
}
cachedGetters({object: Edge, properties: ["vertices", "length", "type"]});