@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering.
765 lines • 31.3 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Curve = void 0;
var point_1 = require("./point");
var line_1 = require("./line");
var rectangle_1 = require("./rectangle");
var polyline_1 = require("./polyline");
var geometry_1 = require("./geometry");
var Curve = /** @class */ (function (_super) {
__extends(Curve, _super);
function Curve(start, controlPoint1, controlPoint2, end) {
var _this = _super.call(this) || this;
_this.PRECISION = 3;
_this.start = point_1.Point.create(start);
_this.controlPoint1 = point_1.Point.create(controlPoint1);
_this.controlPoint2 = point_1.Point.create(controlPoint2);
_this.end = point_1.Point.create(end);
return _this;
}
Object.defineProperty(Curve.prototype, Symbol.toStringTag, {
get: function () {
return Curve.toStringTag;
},
enumerable: false,
configurable: true
});
Curve.prototype.bbox = function () {
var start = this.start;
var controlPoint1 = this.controlPoint1;
var controlPoint2 = this.controlPoint2;
var end = this.end;
var x0 = start.x;
var y0 = start.y;
var x1 = controlPoint1.x;
var y1 = controlPoint1.y;
var x2 = controlPoint2.x;
var y2 = controlPoint2.y;
var x3 = end.x;
var y3 = end.y;
var points = []; // local extremes
var tvalues = []; // t values of local extremes
var bounds = [[], []];
var a;
var b;
var c;
var t;
var t1;
var t2;
var b2ac;
var sqrtb2ac;
for (var i = 0; i < 2; i += 1) {
if (i === 0) {
b = 6 * x0 - 12 * x1 + 6 * x2;
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
c = 3 * x1 - 3 * x0;
}
else {
b = 6 * y0 - 12 * y1 + 6 * y2;
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
c = 3 * y1 - 3 * y0;
}
if (Math.abs(a) < 1e-12) {
if (Math.abs(b) < 1e-12) {
continue;
}
t = -c / b;
if (t > 0 && t < 1)
tvalues.push(t);
continue;
}
b2ac = b * b - 4 * c * a;
sqrtb2ac = Math.sqrt(b2ac);
if (b2ac < 0)
continue;
t1 = (-b + sqrtb2ac) / (2 * a);
if (t1 > 0 && t1 < 1)
tvalues.push(t1);
t2 = (-b - sqrtb2ac) / (2 * a);
if (t2 > 0 && t2 < 1)
tvalues.push(t2);
}
var x;
var y;
var mt;
var j = tvalues.length;
var jlen = j;
while (j) {
j -= 1;
t = tvalues[j];
mt = 1 - t;
x =
mt * mt * mt * x0 +
3 * mt * mt * t * x1 +
3 * mt * t * t * x2 +
t * t * t * x3;
bounds[0][j] = x;
y =
mt * mt * mt * y0 +
3 * mt * mt * t * y1 +
3 * mt * t * t * y2 +
t * t * t * y3;
bounds[1][j] = y;
points[j] = { X: x, Y: y };
}
tvalues[jlen] = 0;
tvalues[jlen + 1] = 1;
points[jlen] = { X: x0, Y: y0 };
points[jlen + 1] = { X: x3, Y: y3 };
bounds[0][jlen] = x0;
bounds[1][jlen] = y0;
bounds[0][jlen + 1] = x3;
bounds[1][jlen + 1] = y3;
tvalues.length = jlen + 2;
bounds[0].length = jlen + 2;
bounds[1].length = jlen + 2;
points.length = jlen + 2;
var left = Math.min.apply(null, bounds[0]);
var top = Math.min.apply(null, bounds[1]);
var right = Math.max.apply(null, bounds[0]);
var bottom = Math.max.apply(null, bounds[1]);
return new rectangle_1.Rectangle(left, top, right - left, bottom - top);
};
Curve.prototype.closestPoint = function (p, options) {
if (options === void 0) { options = {}; }
return this.pointAtT(this.closestPointT(p, options));
};
Curve.prototype.closestPointLength = function (p, options) {
if (options === void 0) { options = {}; }
var opts = this.getOptions(options);
return this.lengthAtT(this.closestPointT(p, opts), opts);
};
Curve.prototype.closestPointNormalizedLength = function (p, options) {
if (options === void 0) { options = {}; }
var opts = this.getOptions(options);
var cpLength = this.closestPointLength(p, opts);
if (!cpLength) {
return 0;
}
var length = this.length(opts);
if (length === 0) {
return 0;
}
return cpLength / length;
};
Curve.prototype.closestPointT = function (p, options) {
if (options === void 0) { options = {}; }
var precision = this.getPrecision(options);
var subdivisions = this.getDivisions(options);
var precisionRatio = Math.pow(10, -precision); // eslint-disable-line
var investigatedSubdivision = null;
var investigatedSubdivisionStartT = 0;
var investigatedSubdivisionEndT = 0;
var distFromStart = 0;
var distFromEnd = 0;
var chordLength = 0;
var minSumDist = null;
var count = subdivisions.length;
var piece = count > 0 ? 1 / count : 0;
subdivisions.forEach(function (division, i) {
var startDist = division.start.distance(p);
var endDist = division.end.distance(p);
var sumDist = startDist + endDist;
if (minSumDist == null || sumDist < minSumDist) {
investigatedSubdivision = division;
investigatedSubdivisionStartT = i * piece;
investigatedSubdivisionEndT = (i + 1) * piece;
distFromStart = startDist;
distFromEnd = endDist;
minSumDist = sumDist;
chordLength = division.endpointDistance();
}
});
// Recursively divide investigated subdivision, until distance between
// baselinePoint and closest path endpoint is within `10^(-precision)`,
// then return the closest endpoint of that final subdivision.
// eslint-disable-next-line
while (true) {
// check if we have reached at least one required observed precision
// - calculated as: the difference in distances from point to start and end divided by the distance
// - note that this function is not monotonic = it doesn't converge stably but has "teeth"
// - the function decreases while one of the endpoints is fixed but "jumps" whenever we switch
// - this criterion works well for points lying far away from the curve
var startPrecisionRatio = distFromStart
? Math.abs(distFromStart - distFromEnd) / distFromStart
: 0;
var endPrecisionRatio = distFromEnd != null
? Math.abs(distFromStart - distFromEnd) / distFromEnd
: 0;
var hasRequiredPrecision = startPrecisionRatio < precisionRatio ||
endPrecisionRatio < precisionRatio;
// check if we have reached at least one required minimal distance
// - calculated as: the subdivision chord length multiplied by precisionRatio
// - calculation is relative so it will work for arbitrarily large/small curves and their subdivisions
// - this is a backup criterion that works well for points lying "almost at" the curve
var hasMiniStartDistance = distFromStart
? distFromStart < chordLength * precisionRatio
: true;
var hasMiniEndDistance = distFromEnd
? distFromEnd < chordLength * precisionRatio
: true;
var hasMiniDistance = hasMiniStartDistance || hasMiniEndDistance;
if (hasRequiredPrecision || hasMiniDistance) {
return distFromStart <= distFromEnd
? investigatedSubdivisionStartT
: investigatedSubdivisionEndT;
}
// otherwise, set up for next iteration
var divided = investigatedSubdivision.divide(0.5);
piece /= 2;
var startDist1 = divided[0].start.distance(p);
var endDist1 = divided[0].end.distance(p);
var sumDist1 = startDist1 + endDist1;
var startDist2 = divided[1].start.distance(p);
var endDist2 = divided[1].end.distance(p);
var sumDist2 = startDist2 + endDist2;
if (sumDist1 <= sumDist2) {
investigatedSubdivision = divided[0];
investigatedSubdivisionEndT -= piece;
distFromStart = startDist1;
distFromEnd = endDist1;
}
else {
investigatedSubdivision = divided[1];
investigatedSubdivisionStartT += piece;
distFromStart = startDist2;
distFromEnd = endDist2;
}
}
};
Curve.prototype.closestPointTangent = function (p, options) {
if (options === void 0) { options = {}; }
return this.tangentAtT(this.closestPointT(p, options));
};
Curve.prototype.containsPoint = function (p, options) {
if (options === void 0) { options = {}; }
var polyline = this.toPolyline(options);
return polyline.containsPoint(p);
};
Curve.prototype.divideAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (ratio <= 0) {
return this.divideAtT(0);
}
if (ratio >= 1) {
return this.divideAtT(1);
}
var t = this.tAt(ratio, options);
return this.divideAtT(t);
};
Curve.prototype.divideAtLength = function (length, options) {
if (options === void 0) { options = {}; }
var t = this.tAtLength(length, options);
return this.divideAtT(t);
};
Curve.prototype.divide = function (t) {
return this.divideAtT(t);
};
Curve.prototype.divideAtT = function (t) {
var start = this.start;
var controlPoint1 = this.controlPoint1;
var controlPoint2 = this.controlPoint2;
var end = this.end;
if (t <= 0) {
return [
new Curve(start, start, start, start),
new Curve(start, controlPoint1, controlPoint2, end),
];
}
if (t >= 1) {
return [
new Curve(start, controlPoint1, controlPoint2, end),
new Curve(end, end, end, end),
];
}
var dividerPoints = this.getSkeletonPoints(t);
var startControl1 = dividerPoints.startControlPoint1;
var startControl2 = dividerPoints.startControlPoint2;
var divider = dividerPoints.divider;
var dividerControl1 = dividerPoints.dividerControlPoint1;
var dividerControl2 = dividerPoints.dividerControlPoint2;
return [
new Curve(start, startControl1, startControl2, divider),
new Curve(divider, dividerControl1, dividerControl2, end),
];
};
Curve.prototype.endpointDistance = function () {
return this.start.distance(this.end);
};
Curve.prototype.getSkeletonPoints = function (t) {
var start = this.start;
var control1 = this.controlPoint1;
var control2 = this.controlPoint2;
var end = this.end;
// shortcuts for `t` values that are out of range
if (t <= 0) {
return {
startControlPoint1: start.clone(),
startControlPoint2: start.clone(),
divider: start.clone(),
dividerControlPoint1: control1.clone(),
dividerControlPoint2: control2.clone(),
};
}
if (t >= 1) {
return {
startControlPoint1: control1.clone(),
startControlPoint2: control2.clone(),
divider: end.clone(),
dividerControlPoint1: end.clone(),
dividerControlPoint2: end.clone(),
};
}
var midpoint1 = new line_1.Line(start, control1).pointAt(t);
var midpoint2 = new line_1.Line(control1, control2).pointAt(t);
var midpoint3 = new line_1.Line(control2, end).pointAt(t);
var subControl1 = new line_1.Line(midpoint1, midpoint2).pointAt(t);
var subControl2 = new line_1.Line(midpoint2, midpoint3).pointAt(t);
var divideLine = new line_1.Line(subControl1, subControl2).pointAt(t);
return {
startControlPoint1: midpoint1,
startControlPoint2: subControl1,
divider: divideLine,
dividerControlPoint1: subControl2,
dividerControlPoint2: midpoint3,
};
};
Curve.prototype.getSubdivisions = function (options) {
if (options === void 0) { options = {}; }
var precision = this.getPrecision(options);
var subdivisions = [
new Curve(this.start, this.controlPoint1, this.controlPoint2, this.end),
];
if (precision === 0) {
return subdivisions;
}
var previousLength = this.endpointDistance();
var precisionRatio = Math.pow(10, -precision); // eslint-disable-line
// Recursively divide curve at `t = 0.5`, until the difference between
// observed length at subsequent iterations is lower than precision.
var iteration = 0;
var _loop_1 = function () {
iteration += 1;
var divisions = [];
subdivisions.forEach(function (c) {
// dividing at t = 0.5 (not at middle length!)
var divided = c.divide(0.5);
divisions.push(divided[0], divided[1]);
});
// measure new length
var length_1 = divisions.reduce(function (memo, c) { return memo + c.endpointDistance(); }, 0);
// check if we have reached required observed precision
// sine-like curves may have the same observed length in iteration 0 and 1 - skip iteration 1
// not a problem for further iterations because cubic curves cannot have more than two local extrema
// (i.e. cubic curves cannot intersect the baseline more than once)
// therefore two subsequent iterations cannot produce sampling with equal length
var ratio = length_1 !== 0 ? (length_1 - previousLength) / length_1 : 0;
if (iteration > 1 && ratio < precisionRatio) {
return { value: divisions };
}
subdivisions = divisions;
previousLength = length_1;
};
// eslint-disable-next-line
while (true) {
var state_1 = _loop_1();
if (typeof state_1 === "object")
return state_1.value;
}
};
Curve.prototype.length = function (options) {
if (options === void 0) { options = {}; }
var divisions = this.getDivisions(options);
return divisions.reduce(function (memo, c) {
return memo + c.endpointDistance();
}, 0);
};
Curve.prototype.lengthAtT = function (t, options) {
if (options === void 0) { options = {}; }
if (t <= 0) {
return 0;
}
var precision = options.precision === undefined ? this.PRECISION : options.precision;
var subCurve = this.divide(t)[0];
return subCurve.length({ precision: precision });
};
Curve.prototype.pointAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (ratio <= 0) {
return this.start.clone();
}
if (ratio >= 1) {
return this.end.clone();
}
var t = this.tAt(ratio, options);
return this.pointAtT(t);
};
Curve.prototype.pointAtLength = function (length, options) {
if (options === void 0) { options = {}; }
var t = this.tAtLength(length, options);
return this.pointAtT(t);
};
Curve.prototype.pointAtT = function (t) {
if (t <= 0) {
return this.start.clone();
}
if (t >= 1) {
return this.end.clone();
}
return this.getSkeletonPoints(t).divider;
};
Curve.prototype.isDifferentiable = function () {
var start = this.start;
var control1 = this.controlPoint1;
var control2 = this.controlPoint2;
var end = this.end;
return !(start.equals(control1) &&
control1.equals(control2) &&
control2.equals(end));
};
Curve.prototype.tangentAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (!this.isDifferentiable())
return null;
if (ratio < 0) {
ratio = 0; // eslint-disable-line
}
else if (ratio > 1) {
ratio = 1; // eslint-disable-line
}
var t = this.tAt(ratio, options);
return this.tangentAtT(t);
};
Curve.prototype.tangentAtLength = function (length, options) {
if (options === void 0) { options = {}; }
if (!this.isDifferentiable()) {
return null;
}
var t = this.tAtLength(length, options);
return this.tangentAtT(t);
};
Curve.prototype.tangentAtT = function (t) {
if (!this.isDifferentiable()) {
return null;
}
if (t < 0) {
t = 0; // eslint-disable-line
}
if (t > 1) {
t = 1; // eslint-disable-line
}
var skeletonPoints = this.getSkeletonPoints(t);
var p1 = skeletonPoints.startControlPoint2;
var p2 = skeletonPoints.dividerControlPoint1;
var tangentStart = skeletonPoints.divider;
var tangentLine = new line_1.Line(p1, p2);
// move so that tangent line starts at the point requested
tangentLine.translate(tangentStart.x - p1.x, tangentStart.y - p1.y);
return tangentLine;
};
Curve.prototype.getPrecision = function (options) {
if (options === void 0) { options = {}; }
return options.precision == null ? this.PRECISION : options.precision;
};
Curve.prototype.getDivisions = function (options) {
if (options === void 0) { options = {}; }
if (options.subdivisions != null) {
return options.subdivisions;
}
var precision = this.getPrecision(options);
return this.getSubdivisions({ precision: precision });
};
Curve.prototype.getOptions = function (options) {
if (options === void 0) { options = {}; }
var precision = this.getPrecision(options);
var subdivisions = this.getDivisions(options);
return { precision: precision, subdivisions: subdivisions };
};
Curve.prototype.tAt = function (ratio, options) {
if (options === void 0) { options = {}; }
if (ratio <= 0) {
return 0;
}
if (ratio >= 1) {
return 1;
}
var opts = this.getOptions(options);
var total = this.length(opts);
var length = total * ratio;
return this.tAtLength(length, opts);
};
Curve.prototype.tAtLength = function (length, options) {
if (options === void 0) { options = {}; }
var fromStart = true;
if (length < 0) {
fromStart = false;
length = -length; // eslint-disable-line
}
var precision = this.getPrecision(options);
var subdivisions = this.getDivisions(options);
var opts = { precision: precision, subdivisions: subdivisions };
var investigatedSubdivision = null;
var investigatedSubdivisionStartT;
var investigatedSubdivisionEndT;
var baselinePointDistFromStart = 0;
var baselinePointDistFromEnd = 0;
var memo = 0;
var count = subdivisions.length;
var piece = count > 0 ? 1 / count : 0;
for (var i = 0; i < count; i += 1) {
var index = fromStart ? i : count - 1 - i;
var division = subdivisions[i];
var dist = division.endpointDistance();
if (length <= memo + dist) {
investigatedSubdivision = division;
investigatedSubdivisionStartT = index * piece;
investigatedSubdivisionEndT = (index + 1) * piece;
baselinePointDistFromStart = fromStart
? length - memo
: dist + memo - length;
baselinePointDistFromEnd = fromStart
? dist + memo - length
: length - memo;
break;
}
memo += dist;
}
if (investigatedSubdivision == null) {
return fromStart ? 1 : 0;
}
// note that precision affects what length is recorded
// (imprecise measurements underestimate length by up to 10^(-precision) of the precise length)
// e.g. at precision 1, the length may be underestimated by up to 10% and cause this function to return 1
var total = this.length(opts);
var precisionRatio = Math.pow(10, -precision); // eslint-disable-line
// recursively divide investigated subdivision:
// until distance between baselinePoint and closest path endpoint is within 10^(-precision)
// then return the closest endpoint of that final subdivision
// eslint-disable-next-line
while (true) {
var ratio = void 0;
ratio = total !== 0 ? baselinePointDistFromStart / total : 0;
if (ratio < precisionRatio) {
return investigatedSubdivisionStartT;
}
ratio = total !== 0 ? baselinePointDistFromEnd / total : 0;
if (ratio < precisionRatio) {
return investigatedSubdivisionEndT;
}
// otherwise, set up for next iteration
var newBaselinePointDistFromStart = void 0;
var newBaselinePointDistFromEnd = void 0;
var divided = investigatedSubdivision.divide(0.5);
piece /= 2;
var baseline1Length = divided[0].endpointDistance();
var baseline2Length = divided[1].endpointDistance();
if (baselinePointDistFromStart <= baseline1Length) {
investigatedSubdivision = divided[0];
investigatedSubdivisionEndT -= piece;
newBaselinePointDistFromStart = baselinePointDistFromStart;
newBaselinePointDistFromEnd =
baseline1Length - newBaselinePointDistFromStart;
}
else {
investigatedSubdivision = divided[1];
investigatedSubdivisionStartT += piece;
newBaselinePointDistFromStart =
baselinePointDistFromStart - baseline1Length;
newBaselinePointDistFromEnd =
baseline2Length - newBaselinePointDistFromStart;
}
baselinePointDistFromStart = newBaselinePointDistFromStart;
baselinePointDistFromEnd = newBaselinePointDistFromEnd;
}
};
Curve.prototype.toPoints = function (options) {
if (options === void 0) { options = {}; }
var subdivisions = this.getDivisions(options);
var points = [subdivisions[0].start.clone()];
subdivisions.forEach(function (c) { return points.push(c.end.clone()); });
return points;
};
Curve.prototype.toPolyline = function (options) {
if (options === void 0) { options = {}; }
return new polyline_1.Polyline(this.toPoints(options));
};
Curve.prototype.scale = function (sx, sy, origin) {
this.start.scale(sx, sy, origin);
this.controlPoint1.scale(sx, sy, origin);
this.controlPoint2.scale(sx, sy, origin);
this.end.scale(sx, sy, origin);
return this;
};
Curve.prototype.rotate = function (angle, origin) {
this.start.rotate(angle, origin);
this.controlPoint1.rotate(angle, origin);
this.controlPoint2.rotate(angle, origin);
this.end.rotate(angle, origin);
return this;
};
Curve.prototype.translate = function (tx, ty) {
if (typeof tx === 'number') {
this.start.translate(tx, ty);
this.controlPoint1.translate(tx, ty);
this.controlPoint2.translate(tx, ty);
this.end.translate(tx, ty);
}
else {
this.start.translate(tx);
this.controlPoint1.translate(tx);
this.controlPoint2.translate(tx);
this.end.translate(tx);
}
return this;
};
Curve.prototype.equals = function (c) {
return (c != null &&
this.start.equals(c.start) &&
this.controlPoint1.equals(c.controlPoint1) &&
this.controlPoint2.equals(c.controlPoint2) &&
this.end.equals(c.end));
};
Curve.prototype.clone = function () {
return new Curve(this.start, this.controlPoint1, this.controlPoint2, this.end);
};
Curve.prototype.toJSON = function () {
return {
start: this.start.toJSON(),
controlPoint1: this.controlPoint1.toJSON(),
controlPoint2: this.controlPoint2.toJSON(),
end: this.end.toJSON(),
};
};
Curve.prototype.serialize = function () {
return [
this.start.serialize(),
this.controlPoint1.serialize(),
this.controlPoint2.serialize(),
this.end.serialize(),
].join(' ');
};
return Curve;
}(geometry_1.Geometry));
exports.Curve = Curve;
(function (Curve) {
Curve.toStringTag = "X6.Geometry." + Curve.name;
function isCurve(instance) {
if (instance == null) {
return false;
}
if (instance instanceof Curve) {
return true;
}
var tag = instance[Symbol.toStringTag];
var curve = instance;
if ((tag == null || tag === Curve.toStringTag) &&
point_1.Point.isPoint(curve.start) &&
point_1.Point.isPoint(curve.controlPoint1) &&
point_1.Point.isPoint(curve.controlPoint2) &&
point_1.Point.isPoint(curve.end) &&
typeof curve.toPoints === 'function' &&
typeof curve.toPolyline === 'function') {
return true;
}
return false;
}
Curve.isCurve = isCurve;
})(Curve = exports.Curve || (exports.Curve = {}));
exports.Curve = Curve;
(function (Curve) {
function getFirstControlPoints(rhs) {
var n = rhs.length;
var x = []; // `x` is a solution vector.
var tmp = [];
var b = 2.0;
x[0] = rhs[0] / b;
// Decomposition and forward substitution.
for (var i = 1; i < n; i += 1) {
tmp[i] = 1 / b;
b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
x[i] = (rhs[i] - x[i - 1]) / b;
}
for (var i = 1; i < n; i += 1) {
// Backsubstitution.
x[n - i - 1] -= tmp[n - i] * x[n - i];
}
return x;
}
function getCurveControlPoints(points) {
var knots = points.map(function (p) { return point_1.Point.clone(p); });
var firstControlPoints = [];
var secondControlPoints = [];
var n = knots.length - 1;
// Special case: Bezier curve should be a straight line.
if (n === 1) {
// 3P1 = 2P0 + P3
firstControlPoints[0] = new point_1.Point((2 * knots[0].x + knots[1].x) / 3, (2 * knots[0].y + knots[1].y) / 3);
// P2 = 2P1 – P0
secondControlPoints[0] = new point_1.Point(2 * firstControlPoints[0].x - knots[0].x, 2 * firstControlPoints[0].y - knots[0].y);
return [firstControlPoints, secondControlPoints];
}
// Calculate first Bezier control points.
// Right hand side vector.
var rhs = [];
// Set right hand side X values.
for (var i = 1; i < n - 1; i += 1) {
rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
}
rhs[0] = knots[0].x + 2 * knots[1].x;
rhs[n - 1] = (8 * knots[n - 1].x + knots[n].x) / 2.0;
// Get first control points X-values.
var x = getFirstControlPoints(rhs);
// Set right hand side Y values.
for (var i = 1; i < n - 1; i += 1) {
rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
}
rhs[0] = knots[0].y + 2 * knots[1].y;
rhs[n - 1] = (8 * knots[n - 1].y + knots[n].y) / 2.0;
// Get first control points Y-values.
var y = getFirstControlPoints(rhs);
// Fill output arrays.
for (var i = 0; i < n; i += 1) {
// First control point.
firstControlPoints.push(new point_1.Point(x[i], y[i]));
// Second control point.
if (i < n - 1) {
secondControlPoints.push(new point_1.Point(2 * knots[i + 1].x - x[i + 1], 2 * knots[i + 1].y - y[i + 1]));
}
else {
secondControlPoints.push(new point_1.Point((knots[n].x + x[n - 1]) / 2, (knots[n].y + y[n - 1]) / 2));
}
}
return [firstControlPoints, secondControlPoints];
}
function throughPoints(points) {
if (points == null || (Array.isArray(points) && points.length < 2)) {
throw new Error('At least 2 points are required');
}
var controlPoints = getCurveControlPoints(points);
var curves = [];
for (var i = 0, ii = controlPoints[0].length; i < ii; i += 1) {
var controlPoint1 = new point_1.Point(controlPoints[0][i].x, controlPoints[0][i].y);
var controlPoint2 = new point_1.Point(controlPoints[1][i].x, controlPoints[1][i].y);
curves.push(new Curve(points[i], controlPoint1, controlPoint2, points[i + 1]));
}
return curves;
}
Curve.throughPoints = throughPoints;
})(Curve = exports.Curve || (exports.Curve = {}));
exports.Curve = Curve;
//# sourceMappingURL=curve.js.map