UNPKG

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
"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