polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
206 lines (205 loc) • 6.77 kB
JavaScript
import {Vector3 as Vector32} from "three/src/math/Vector3";
import {BufferGeometry as BufferGeometry2} from "three/src/core/BufferGeometry";
import {BufferAttribute as BufferAttribute2} from "three/src/core/BufferAttribute";
import {TypeAssert} from "../../../engine/poly/Assert";
export var PointsCountMode;
(function(PointsCountMode2) {
PointsCountMode2["SEGMENTS_COUNT"] = "segments count";
PointsCountMode2["SEGMENTS_LENGTH"] = "segments length";
})(PointsCountMode || (PointsCountMode = {}));
export const POINTS_COUNT_MODE = [PointsCountMode.SEGMENTS_COUNT, PointsCountMode.SEGMENTS_LENGTH];
export var JoinMode;
(function(JoinMode2) {
JoinMode2["ABC"] = "abc";
JoinMode2["ACB"] = "acb";
JoinMode2["AB"] = "ab";
JoinMode2["BC"] = "bc";
JoinMode2["AC"] = "ac";
})(JoinMode || (JoinMode = {}));
export const JOIN_MODES = [JoinMode.ABC, JoinMode.ACB, JoinMode.AB, JoinMode.AC, JoinMode.BC];
export class Circle3Points {
constructor(params) {
this.params = params;
this.a = new Vector32();
this.b = new Vector32();
this.c = new Vector32();
this.an = new Vector32();
this.bn = new Vector32();
this.cn = new Vector32();
this.ac = new Vector32();
this.ab = new Vector32();
this.ab_x_ac = new Vector32();
this.part0 = new Vector32();
this.part1 = new Vector32();
this.divider = 1;
this.a_center = new Vector32();
this.center = new Vector32();
this.normal = new Vector32();
this.radius = 1;
this.x = new Vector32();
this.y = new Vector32();
this.z = new Vector32();
this.angle_ab = 1;
this.angle_ac = 1;
this.angle_bc = 1;
this.angle = 2 * Math.PI;
this.x_rotated = new Vector32();
this._created_geometries = {};
}
created_geometries() {
return this._created_geometries;
}
create(a, b, c) {
this.a.copy(a);
this.b.copy(b);
this.c.copy(c);
this._compute_axis();
this._create_arc();
this._create_center();
}
_create_arc() {
this._compute_angle();
const points_count = this._points_count();
const positions = new Array(points_count * 3);
const indices = new Array(points_count);
const angle_increment = this.angle / (points_count - 1);
this.x_rotated.copy(this.x).multiplyScalar(this.radius);
let i = 0;
for (i = 0; i < points_count; i++) {
this.x_rotated.copy(this.x).applyAxisAngle(this.normal, angle_increment * i).multiplyScalar(this.radius).add(this.center);
this.x_rotated.toArray(positions, i * 3);
if (i > 0) {
indices[(i - 1) * 2] = i - 1;
indices[(i - 1) * 2 + 1] = i;
}
}
if (this.params.full) {
indices.push(i - 1);
indices.push(0);
}
const geometry = new BufferGeometry2();
geometry.setAttribute("position", new BufferAttribute2(new Float32Array(positions), 3));
geometry.setIndex(indices);
if (this.params.addIdAttribute || this.params.addIdnAttribute) {
const ids = new Array(points_count);
for (let i2 = 0; i2 < ids.length; i2++) {
ids[i2] = i2;
}
if (this.params.addIdAttribute) {
geometry.setAttribute("id", new BufferAttribute2(new Float32Array(ids), 1));
}
const idns = ids.map((id) => id / (points_count - 1));
if (this.params.addIdnAttribute) {
geometry.setAttribute("idn", new BufferAttribute2(new Float32Array(idns), 1));
}
}
this._created_geometries.arc = geometry;
}
_create_center() {
if (!this.params.center) {
return;
}
const geometry = new BufferGeometry2();
const positions = [this.center.x, this.center.y, this.center.z];
geometry.setAttribute("position", new BufferAttribute2(new Float32Array(positions), 3));
this._created_geometries.center = geometry;
}
_compute_axis() {
this.ac.copy(this.c).sub(this.a);
this.ab.copy(this.b).sub(this.a);
this.ab_x_ac.copy(this.ab).cross(this.ac);
this.divider = 2 * this.ab_x_ac.lengthSq();
this.part0.copy(this.ab_x_ac).cross(this.ab).multiplyScalar(this.ac.lengthSq());
this.part1.copy(this.ac).cross(this.ab_x_ac).multiplyScalar(this.ab.lengthSq());
this.a_center.copy(this.part0).add(this.part1).divideScalar(this.divider);
this.radius = this.a_center.length();
this.normal.copy(this.ab_x_ac).normalize();
this.center.copy(this.a).add(this.a_center);
}
_compute_angle() {
if (!this.params.arc) {
return;
}
if (this.params.full) {
this.x.copy(this.a).sub(this.center).normalize();
this.angle = 2 * Math.PI;
} else {
this.an.copy(this.a).sub(this.center).normalize();
this.bn.copy(this.b).sub(this.center).normalize();
this.cn.copy(this.c).sub(this.center).normalize();
this._set_x_from_joinMode();
this.y.copy(this.normal);
this.z.copy(this.x).cross(this.y).normalize();
this.angle_ab = this.an.angleTo(this.bn);
this.angle_ac = this.an.angleTo(this.cn);
this.angle_bc = this.bn.angleTo(this.cn);
this._set_angle_from_joinMode();
}
}
_points_count() {
const mode = this.params.pointsCountMode;
switch (mode) {
case PointsCountMode.SEGMENTS_COUNT: {
return this.params.segmentsCount + 1;
}
case PointsCountMode.SEGMENTS_LENGTH: {
let perimeter = Math.PI * this.radius * this.radius;
if (!this.params.full) {
perimeter *= Math.abs(this.angle) / (Math.PI * 2);
}
return Math.ceil(perimeter / this.params.segmentsLength);
}
}
TypeAssert.unreachable(mode);
}
_set_x_from_joinMode() {
const joinMode = this.params.joinMode;
this.x.copy(this.a).sub(this.center).normalize();
switch (joinMode) {
case JoinMode.ABC: {
return this.x.copy(this.an);
}
case JoinMode.ACB: {
return this.x.copy(this.an);
}
case JoinMode.AB: {
return this.x.copy(this.an);
}
case JoinMode.AC: {
return this.x.copy(this.an);
}
case JoinMode.BC: {
return this.x.copy(this.bn);
}
}
TypeAssert.unreachable(joinMode);
}
_set_angle_from_joinMode() {
const joinMode = this.params.joinMode;
switch (joinMode) {
case JoinMode.ABC: {
this.angle = this.angle_ab + this.angle_bc;
return;
}
case JoinMode.ACB: {
this.angle = this.angle_ac + this.angle_bc;
this.angle *= -1;
return;
}
case JoinMode.AB: {
this.angle = this.angle_ab;
return;
}
case JoinMode.AC: {
this.angle = this.angle_ac;
this.angle *= -1;
return;
}
case JoinMode.BC: {
this.angle = this.angle_bc;
return;
}
}
TypeAssert.unreachable(joinMode);
}
}