gs-json
Version:
gs-JSON is a domain agnostic unifying 3D file format for geometric and semantic modelling (hence the 'gs').
456 lines (437 loc) • 17.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getRenderXYZs = getRenderXYZs;
exports.circleLength = circleLength;
exports.circleEvaluate = circleEvaluate;
exports.circleEvaluatePoint = circleEvaluatePoint;
exports.circleGetRenderXYZs = circleGetRenderXYZs;
exports.ellipseLength = ellipseLength;
exports.ellipseEvaluate = ellipseEvaluate;
exports.ellipseGetRenderXYZs = ellipseGetRenderXYZs;
var _three = require("three");
var three = _interopRequireWildcard(_three);
var _gsJson = require("../../gs-json");
var gs = _interopRequireWildcard(_gsJson);
var _threex = require("../threex/threex");
var threex = _interopRequireWildcard(_threex);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
/**
* 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
*/
function getRenderXYZs(obj, resolution) {
switch (obj.getObjType()) {
case 3 /* circle */:
return circleGetRenderXYZs(obj, resolution);
case 4 /* ellipse */:
return ellipseGetRenderXYZs(obj, resolution);
default:
throw new Error("Invalid object type.");
}
}
/**
* Calculate the length of the circle or arc.
*/
function circleLength(circle) {
var rad = circle.getRadius();
var angles = circle.getAngles();
// calculate the angle of the arc
var arc_angle = void 0;
if (angles === undefined) {
return 2 * Math.PI * rad;
} else if (angles[0] < angles[1]) {
arc_angle = angles[1] - angles[0];
} else {
arc_angle = angles[0] - angles[1];
}
return 2 * Math.PI * rad * (arc_angle / 360);
}
/**
* Calculate the xyz position at parameter t on the circle or arc. The t parameter range is from 0 to 1.
*/
function circleEvaluate(circle, t) {
var rad = circle.getRadius();
var angles = circle.getAngles();
// set arc start and arc end angles, in radians
var ang_start = void 0;
var ang_end = void 0;
if (angles === undefined) {
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
var arc_angle = void 0;
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
var matrix_inv = threex.matrixInv(threex.xformMatrixFromXYZs(circle.getOrigin().getPosition(), circle.getAxes()));
// calculate the point
var alpha = ang_start + t * arc_angle;
var point = new three.Vector3(rad * Math.cos(alpha), rad * Math.sin(alpha), 0);
point.applyMatrix4(matrix_inv);
// return the points
return point.toArray();
}
/**
* Project a point on a circle, and calculate the parameter t.
*/
function circleEvaluatePoint(circle, point) {
var angles = circle.getAngles();
// create matrix to map from the 3D plane for circle into the XY plane
var matrix = threex.xformMatrixFromXYZs(circle.getOrigin().getPosition(), circle.getAxes());
// map the point onto the XY plane
var xyz_2d = threex.multXYZMatrix(point.getPosition(), matrix);
// calculate the angle between the point vector and the x axis, in radians
var 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 === undefined) {
return point_angle / (2 * Math.PI);
}
// convert angles to radians
var ang_start = angles[0] * (Math.PI / 180);
var ang_end = angles[1] * (Math.PI / 180);
// calculate t for an arc
if (ang_start < ang_end) {
// the point is on the arc
if (point_angle >= ang_start && point_angle <= ang_end) {
return (point_angle - ang_start) / (ang_end - ang_start);
} else {
var rotated = point_angle - (ang_start + ang_end) / 2;
if (rotated > Math.PI) {
return 0;
} else {
return 1;
}
}
} else {
// add up the lower and upper angles
var arc_angle_lower = Math.PI * 2 - ang_start;
var arc_angle_upper = ang_end;
var arc_angle = arc_angle_lower + arc_angle_upper;
if (point_angle >= ang_start) {
return (point_angle - ang_start) / arc_angle;
} else if (point_angle <= ang_end) {
return (arc_angle_lower + point_angle) / arc_angle;
} else {
var _rotated = point_angle - (ang_start + ang_end) / 2;
console.log(ang_start, ang_end, point_angle, _rotated);
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
*/
function circleGetRenderXYZs(circle, resolution) {
var rad = circle.getRadius();
var angles = circle.getAngles();
// calculat the arc start angle
var arc_start = void 0;
if (angles === undefined) {
arc_start = 0;
} else {
arc_start = angles[0] * (Math.PI / 180);
}
// calculate the angle of the arc
var arc_angle = void 0;
if (angles === undefined) {
arc_angle = 2 * Math.PI;
} else if (angles[0] < angles[1]) {
arc_angle = (angles[1] - angles[0]) * (Math.PI / 180);
} else {
arc_angle = (angles[0] - angles[1]) * (Math.PI / 180);
}
// calculate number of points
var N = Math.floor(arc_angle / (Math.PI / 36));
if (N < 3) {
N = 3;
}
// create matrix to map from XY plane into the 3D plane for circle
var matrix_inv = threex.matrixInv(threex.xformMatrixFromXYZs(circle.getOrigin().getPosition(), circle.getAxes()));
// main loop to create points
var xyz_points = [];
for (var k = 0; k < N; k++) {
var t = k / (N - 1);
var alpha = arc_start + t * arc_angle;
var 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;
}
/**
* Calculate the length of the conic curve.
*/
function ellipseLength(curve) {
// ConicCurve assumed to be an ellipse or circle;
var vector_x = curve.getAxes()[0];
var vector_y = curve.getAxes()[1];
// Initial vector_x and vector_y require to be (almost) orthogonal
var threshold = 1e-6;
if (Math.abs(vector_x[0] * vector_y[0] + vector_x[1] * vector_y[1] + vector_x[2] * vector_y[2]) >= threshold) {
throw new Error("Orthogonal vectors are required for that Ellipse / Conic length calculation");
}
var a = Math.sqrt(vector_x[0] * vector_x[0] + vector_x[1] * vector_x[1] + vector_x[2] * vector_x[2]);
var b = Math.sqrt(vector_y[0] * vector_y[0] + vector_y[1] * vector_y[1] + vector_y[2] * vector_y[2]);
var u = [a, 0];
var v = [0, b];
var angle_1 = curve.getAngles()[0] * (2 * Math.PI) / 360;
var angle_2 = curve.getAngles()[1] * (2 * Math.PI) / 360;
// Radians, although input angles are expected in Degrees
if (Math.abs(a - b) < threshold) {
return a * Math.abs(angle_2 - angle_1);
}
// Range [x1,x2] for length calculation would provide 2 circle arcs,
// Whereas Angle_1 / Angle_2 provide a unique circle arc.
var eccentricity = null;
if (a > b) {
eccentricity = Math.sqrt(1 - b / a * (b / a));
}
if (b > a) {
eccentricity = Math.sqrt(1 - a / b * (a / b));
}
var K = 1000;
var theta = null;
var d_th = (angle_2 - angle_1) / K;
var distance = 0;
for (var k = 0; k < K; k++) {
theta = angle_1 + k * (angle_2 - angle_1) / K;
distance = distance + d_th * Math.sqrt(1 - eccentricity * Math.sin(theta) * eccentricity * Math.sin(theta));
// distance along the curve assessed and updated at each timestep;
}
distance = Math.max(a, b) * distance;
return distance;
}
/**
* Calculate the xyz position at parameter t. The t parameter range is from 0 to 1.
*/
function ellipseEvaluate(curve, t) {
// ConicCurve assumed to be an ellipse or circle;
var vector_x = curve.getAxes()[0];
var vector_y = curve.getAxes()[1];
// Initial vector_x and vector_y require to be (almost) orthogonal
var threshold = 1e-6;
if (Math.abs(vector_x[0] * vector_y[0] + vector_x[1] * vector_y[1] + vector_x[2] * vector_y[2]) >= threshold) {
throw new Error("Orthogonal vectors are required for that Ellipse / Conic length calculation");
}
var a = Math.sqrt(vector_x[0] * vector_x[0] + vector_x[1] * vector_x[1] + vector_x[2] * vector_x[2]);
var b = Math.sqrt(vector_y[0] * vector_y[0] + vector_y[1] * vector_y[1] + vector_y[2] * vector_y[2]);
var u = [a, 0];
var v = [0, b];
var z_uv = [0, 0, u[0] * v[1] - u[1] * v[0]]; // cross product
var angle_1 = curve.getAngles()[0] * (2 * Math.PI) / 360;
var angle_2 = curve.getAngles()[1] * (2 * Math.PI) / 360;
var l = ellipseLength(curve);
var epsilon = 1;
var theta = null;
var K = 1000; // Does this not depend on the length of the ellipse?
var x = null;
var y = null;
var r = null;
var theta_t = null;
var param = b * b / a;
var m = new gs.Model();
var g = m.getGeom();
var pt = g.addPoint([0, 0, 0]);
var curve_theta = null;
for (var k = 0; k < K; k++) {
while (epsilon >= 0) {
theta = angle_1 + k * (angle_2 - angle_1) / K;
curve_theta = g.addEllipse(curve.getOrigin(), curve.getAxes()[0], curve.getAxes()[1], [curve.getAngles()[0], theta]); // Why is this adding ellipses to the model?
epsilon = t * l - ellipseLength(curve_theta);
if (epsilon < 0) {
theta_t = theta;
}
}
}
var eccentricity = null;
if (a > b) {
eccentricity = Math.sqrt(1 - b / a * (b / a));
}
if (b > a) {
eccentricity = Math.sqrt(1 - a / b * (a / b));
}
r = param / (1 + eccentricity * Math.cos(theta_t));
x = r * Math.cos(theta_t); // expressed in the plan inferred by (u,v)
y = r * Math.sin(theta_t); // expressed in the plan inferred by (u,v)
var U1 = new three.Vector3(curve.getAxes()[0][0], curve.getAxes()[0][1], curve.getAxes()[0][2]);
var V1 = new three.Vector3(curve.getAxes()[1][0], curve.getAxes()[1][1], curve.getAxes()[1][2]);
U1.normalize();
V1.normalize();
var O1O2 = new three.Vector3(curve.getOrigin()[0], curve.getOrigin()[1], curve.getOrigin()[2]);
var O2P = threex.addVectors(U1.multiplyScalar(x), V1.multiplyScalar(y));
var O1P = threex.addVectors(O1O2, O2P);
return [O1P.x, O1P.y, O1P.z]; // Should work..
}
/**
* Calculate a set of xyz position on the ellipse. The number of points = length / resolution.
*/
function ellipseGetRenderXYZs(curve, resolution) {
var O = curve.getOrigin().getPosition();
var renderingXYZs = [];
var renderXYZs = [];
var r = null;
var theta = 0;
var d_theta = 0;
var U1 = new (Function.prototype.bind.apply(three.Vector3, [null].concat(_toConsumableArray(curve.getAxes()[0]))))().normalize();
var V1 = new (Function.prototype.bind.apply(three.Vector3, [null].concat(_toConsumableArray(curve.getAxes()[1]))))().normalize();
var a = new (Function.prototype.bind.apply(three.Vector3, [null].concat(_toConsumableArray(curve.getAxes()[0]))))().length();
var b = new (Function.prototype.bind.apply(three.Vector3, [null].concat(_toConsumableArray(curve.getAxes()[1]))))().length();
var L = Math.PI * Math.sqrt(2 * (a * a + b * b) - (a - b) * (a - b) / 2);
var l = L * resolution;
var param = b * b / a;
var c = Math.sqrt(Math.abs(a * a - b * b));
if (a >= b) {
var e = Math.sqrt(1 - b * b / (a * a));
var N = 0;
var eps = 1;
while (eps > 0) {
theta = theta + d_theta;
eps = Math.PI * 2 - theta;
N++;
r = param / (1 + e * Math.cos(theta));
d_theta = l / r;
}
N--;
theta = 0;
d_theta = 0;
for (var k = 0; k < N; k++) {
theta = theta + d_theta;
r = param / (1 + e * Math.cos(theta));
d_theta = l / r;
renderingXYZs.push([r * Math.cos(theta) + c, r * Math.sin(theta), 0]);
}
}
if (b > a) {
var _e = Math.sqrt(1 - a * a / (b * b));
var _N = 0;
var _eps = 1;
while (_eps > 0) {
theta = theta + d_theta;
_eps = Math.PI * 2 - theta;
_N++;
r = param / (1 + _e * Math.cos(theta));
d_theta = l / r;
}
_N--;
theta = 0;
d_theta = 0;
for (var _k = 0; _k < _N; _k++) {
theta = theta + d_theta;
r = param / (1 + _e * Math.cos(theta));
d_theta = l / r;
renderingXYZs.push([r * Math.cos(theta), r * Math.sin(theta) + c, 0]);
}
}
var results = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = renderingXYZs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var point = _step.value;
results.push(new three.Vector3(point[0], point[1], point[2]));
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var O1 = new three.Vector3(0, 0, 0);
var e1 = new three.Vector3(1, 0, 0);
var e2 = new three.Vector3(0, 1, 0);
var e3 = new three.Vector3(0, 0, 1);
var C1 = new three.Vector3(curve.getOrigin().getPosition()[0], curve.getOrigin().getPosition()[1], curve.getOrigin().getPosition()[2]);
var W1 = threex.crossVectors(U1, V1, true);
var C1O1 = threex.subVectors(O1, C1, false);
var vec_O_1 = new three.Vector3(C1O1.dot(U1), C1O1.dot(V1), C1O1.dot(W1));
var x1 = new three.Vector3(e1.dot(U1), e1.dot(V1), e1.dot(W1));
var y1 = new three.Vector3(e2.dot(U1), e2.dot(V1), e2.dot(W1));
var z1 = new three.Vector3();
z1 = z1.crossVectors(x1, y1);
var m1 = new three.Matrix4();
var o_neg = vec_O_1.clone().negate();
m1.setPosition(o_neg);
var m2 = new three.Matrix4();
m2 = m2.makeBasis(x1.normalize(), y1.normalize(), z1.normalize());
m2 = m2.getInverse(m2);
var m3 = new three.Matrix4();
var rotation1 = m3.multiplyMatrices(m2, m1);
var results_c1 = [];
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = results[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _point = _step2.value;
results_c1.push(threex.multVectorMatrix(_point, rotation1));
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = results_c1[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _point2 = _step3.value;
renderXYZs.push([_point2.x, _point2.y, _point2.z]);
}
// console.log("rendering is ");
// console.log(renderingXYZs);
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
throw new Error("Method not implemented");
// return renderXYZs;
}
//# sourceMappingURL=conics.js.map