gs-json
Version:
gs-JSON is a domain agnostic unifying 3D file format for geometric and semantic modelling (hence the 'gs').
199 lines • 7.19 kB
JavaScript
import * as three from "three";
import * as threex from "../threex/threex";
/**
* Calculate a set of xyz position on the circle/arc ir ellipse/arc. The number of points = length / resolution.
* With resolution from 0.0001 to 0.5, 0.0001 being a higher resolution than 0.5
*/
export function getRenderXYZs(obj, resolution) {
switch (obj.getObjType()) {
case 3 /* circle */:
return circleGetRenderXYZs(obj, resolution);
default:
throw new Error("Invalid object type.");
}
}
/**
* Calculate the length of the circle or arc.
*/
export function circleLength(circle) {
const rad = circle.getRadius();
const angles = circle.getAngles();
// if circle is closed, then return 2PI * rad
if (angles === null) {
return 2 * Math.PI * rad;
}
// set arc start and arc end angles, in radians
const ang_start = angles[0] * (Math.PI / 180);
const ang_end = angles[1] * (Math.PI / 180);
// calculate the angle of the arc
let arc_angle;
if (ang_start < ang_end) {
arc_angle = ang_end - ang_start;
}
else {
arc_angle = ((Math.PI * 2) - ang_start) + ang_end;
}
// calculate the length, 2PI * rad * (arc_angle/2PI)
return rad * arc_angle;
}
/**
* Calculate the xyz position at parameter t on the circle or arc. The t parameter range is from 0 to 1.
*/
export function circleEvaluate(circle, t) {
const rad = circle.getRadius();
const angles = circle.getAngles();
// set arc start and arc end angles, in radians
let ang_start;
let ang_end;
if (angles === null) {
ang_start = 0;
ang_end = Math.PI * 2;
}
else {
ang_start = angles[0] * (Math.PI / 180);
ang_end = angles[1] * (Math.PI / 180);
}
// calculate the angle of the arc
let arc_angle;
if (ang_start < ang_end) {
arc_angle = ang_end - ang_start;
}
else {
arc_angle = ((Math.PI * 2) - ang_start) + ang_end;
}
// create matrix to map from XY plane into the 3D plane for circle
const matrix_inv = threex.matrixInv(threex.xformMatrixFromXYZs(circle.getOrigin().getPosition(), circle.getAxes()));
// calculate the point
const alpha = ang_start + (t * arc_angle);
const point = new three.Vector3(rad * Math.cos(alpha), rad * Math.sin(alpha), 0);
point.applyMatrix4(matrix_inv);
// return the points
return point.toArray();
}
/**
* Calculate the xyz tangent at parameter t on the circle or arc. The t parameter range is from 0 to 1.
*/
export function circleEvaluateTangent(circle, t) {
const point_xyz = circleEvaluate(circle, t);
if (point_xyz === null) {
return null;
}
const origin_xyz = circle.getOrigin().getPosition();
const normal_xyz = circle.getNormal();
const vec_xyz = threex.subXYZs(point_xyz, origin_xyz);
return threex.crossXYZs(vec_xyz, normal_xyz, true);
}
/**
* Project a point on a circle, and calculate the parameter t.
*/
export function circleEvaluatePoint(circle, point) {
const angles = circle.getAngles();
// create matrix to map from the 3D plane for circle into the XY plane
const matrix = threex.xformMatrixFromXYZs(circle.getOrigin().getPosition(), circle.getAxes());
// map the point onto the XY plane
const xyz_2d = threex.multXYZMatrix(point.getPosition(), matrix);
// calculate the angle between the point vector and the x axis, in radians
let point_angle = Math.atan2(xyz_2d[1], xyz_2d[0]);
if (point_angle < 0) {
point_angle += (2 * Math.PI);
}
// calculate t for a closed circle
if (angles === null) {
return point_angle / (2 * Math.PI);
}
// convert angles to radians
const ang_start = angles[0] * (Math.PI / 180);
const ang_end = angles[1] * (Math.PI / 180);
// calculate t for an arc
if (ang_start < ang_end) {
// calc arc angle
const arc_angle = ang_end - ang_start;
// the point is on the arc
if ((point_angle >= ang_start) && (point_angle <= ang_end)) {
return (point_angle - ang_start) / arc_angle;
}
// the point is not on the arc, so it must be at an end point
else {
let rotated = point_angle - (ang_start + (arc_angle / 2));
if (rotated < 0) {
rotated = rotated + (Math.PI * 2);
}
if (rotated > Math.PI) {
return 0;
}
else {
return 1;
}
}
}
else {
// calc arc angle
const arc_angle_lower = ((Math.PI * 2) - ang_start);
const arc_angle_upper = ang_end;
const arc_angle = arc_angle_lower + arc_angle_upper;
// the point is on the outer arc, below the x axis
if (point_angle >= ang_start) {
return (point_angle - ang_start) / arc_angle;
}
// the point is on the outer arc, above the x axis
else if (point_angle <= ang_end) {
return (arc_angle_lower + point_angle) / arc_angle;
}
// the point is not on the outside arc, so it must be at an end point
else {
const rotated = point_angle + ((arc_angle / 2) - ang_end);
if (rotated > Math.PI) {
return 0;
}
else {
return 1;
}
}
}
}
/**
* Calculate a set of xyz position on the circle or arc. The number of points = length / resolution.
* With resolution from 0.0001 to 0.5, 0.0001 being a higher resolution than 0.5
*/
export function circleGetRenderXYZs(circle, resolution) {
const rad = circle.getRadius();
const angles = circle.getAngles();
// calculat the angles
let ang_start;
let ang_end;
if (angles === null) {
ang_start = 0;
ang_end = Math.PI * 2;
}
else {
ang_start = angles[0] * (Math.PI / 180);
ang_end = angles[1] * (Math.PI / 180);
}
// calculate the angle of the arc
let arc_angle;
if (ang_start < ang_end) {
arc_angle = ang_end - ang_start;
}
else {
arc_angle = ((Math.PI * 2) - ang_start) + ang_end;
}
// calculate number of points
let num_points = Math.floor(arc_angle / (Math.PI / 36));
if (num_points < 3) {
num_points = 3;
}
// create matrix to map from XY plane into the 3D plane for circle
const matrix_inv = threex.matrixInv(threex.xformMatrixFromXYZs(circle.getOrigin().getPosition(), circle.getAxes()));
// main loop to create points
const xyz_points = [];
for (let i = 0; i < num_points; i++) {
const t = i / (num_points - 1);
const alpha = ang_start + (t * arc_angle);
const point = new three.Vector3(rad * Math.cos(alpha), rad * Math.sin(alpha), 0);
point.applyMatrix4(matrix_inv);
xyz_points.push(point.toArray());
}
// return the points
return xyz_points;
}
//# sourceMappingURL=circles.js.map