157 lines
3.4 KiB
Java
157 lines
3.4 KiB
Java
![]() |
var Util = require('../../util/index');
|
||
|
|
||
|
var vec2 = Util.vec2;
|
||
|
|
||
|
function cubicAt(p0, p1, p2, p3, t) {
|
||
|
var onet = 1 - t;
|
||
|
return onet * onet * (onet * p3 + 3 * t * p2) + t * t * (t * p0 + 3 * onet * p1);
|
||
|
}
|
||
|
|
||
|
function cubicDerivativeAt(p0, p1, p2, p3, t) {
|
||
|
var onet = 1 - t;
|
||
|
return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet + (p3 - p2) * t * t);
|
||
|
}
|
||
|
|
||
|
function cubicProjectPoint(x1, y1, x2, y2, x3, y3, x4, y4, x, y, out) {
|
||
|
var t;
|
||
|
var interval = 0.005;
|
||
|
var d = Infinity;
|
||
|
|
||
|
var _t;
|
||
|
|
||
|
var v1;
|
||
|
var d1;
|
||
|
var d2;
|
||
|
var v2;
|
||
|
var prev;
|
||
|
var next;
|
||
|
var EPSILON = 0.0001;
|
||
|
var v0 = [x, y];
|
||
|
|
||
|
for (_t = 0; _t < 1; _t += 0.05) {
|
||
|
v1 = [cubicAt(x1, x2, x3, x4, _t), cubicAt(y1, y2, y3, y4, _t)];
|
||
|
d1 = vec2.squaredDistance(v0, v1);
|
||
|
|
||
|
if (d1 < d) {
|
||
|
t = _t;
|
||
|
d = d1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
d = Infinity;
|
||
|
|
||
|
for (var i = 0; i < 32; i++) {
|
||
|
if (interval < EPSILON) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
prev = t - interval;
|
||
|
next = t + interval;
|
||
|
v1 = [cubicAt(x1, x2, x3, x4, prev), cubicAt(y1, y2, y3, y4, prev)];
|
||
|
d1 = vec2.squaredDistance(v0, v1);
|
||
|
|
||
|
if (prev >= 0 && d1 < d) {
|
||
|
t = prev;
|
||
|
d = d1;
|
||
|
} else {
|
||
|
v2 = [cubicAt(x1, x2, x3, x4, next), cubicAt(y1, y2, y3, y4, next)];
|
||
|
d2 = vec2.squaredDistance(v0, v2);
|
||
|
|
||
|
if (next <= 1 && d2 < d) {
|
||
|
t = next;
|
||
|
d = d2;
|
||
|
} else {
|
||
|
interval *= 0.5;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (out) {
|
||
|
out.x = cubicAt(x1, x2, x3, x4, t);
|
||
|
out.y = cubicAt(y1, y2, y3, y4, t);
|
||
|
}
|
||
|
|
||
|
return Math.sqrt(d);
|
||
|
}
|
||
|
|
||
|
function cubicExtrema(p0, p1, p2, p3) {
|
||
|
var a = 3 * p0 - 9 * p1 + 9 * p2 - 3 * p3;
|
||
|
var b = 6 * p1 - 12 * p2 + 6 * p3;
|
||
|
var c = 3 * p2 - 3 * p3;
|
||
|
var extrema = [];
|
||
|
var t1;
|
||
|
var t2;
|
||
|
var discSqrt;
|
||
|
|
||
|
if (Util.isNumberEqual(a, 0)) {
|
||
|
if (!Util.isNumberEqual(b, 0)) {
|
||
|
t1 = -c / b;
|
||
|
|
||
|
if (t1 >= 0 && t1 <= 1) {
|
||
|
extrema.push(t1);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
var disc = b * b - 4 * a * c;
|
||
|
|
||
|
if (Util.isNumberEqual(disc, 0)) {
|
||
|
extrema.push(-b / (2 * a));
|
||
|
} else if (disc > 0) {
|
||
|
discSqrt = Math.sqrt(disc);
|
||
|
t1 = (-b + discSqrt) / (2 * a);
|
||
|
t2 = (-b - discSqrt) / (2 * a);
|
||
|
|
||
|
if (t1 >= 0 && t1 <= 1) {
|
||
|
extrema.push(t1);
|
||
|
}
|
||
|
|
||
|
if (t2 >= 0 && t2 <= 1) {
|
||
|
extrema.push(t2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return extrema;
|
||
|
}
|
||
|
|
||
|
function base3(t, p1, p2, p3, p4) {
|
||
|
var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4;
|
||
|
var t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
|
||
|
return t * t2 - 3 * p1 + 3 * p2;
|
||
|
}
|
||
|
|
||
|
function cubiclLen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
|
||
|
if (Util.isNil(z)) {
|
||
|
z = 1;
|
||
|
}
|
||
|
|
||
|
z = z > 1 ? 1 : z < 0 ? 0 : z;
|
||
|
var z2 = z / 2;
|
||
|
var n = 12;
|
||
|
var Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, -0.7699, 0.7699, -0.9041, 0.9041, -0.9816, 0.9816];
|
||
|
var Cvalues = [0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472];
|
||
|
var sum = 0;
|
||
|
|
||
|
for (var i = 0; i < n; i++) {
|
||
|
var ct = z2 * Tvalues[i] + z2;
|
||
|
var xbase = base3(ct, x1, x2, x3, x4);
|
||
|
var ybase = base3(ct, y1, y2, y3, y4);
|
||
|
var comb = xbase * xbase + ybase * ybase;
|
||
|
sum += Cvalues[i] * Math.sqrt(comb);
|
||
|
}
|
||
|
|
||
|
return z2 * sum;
|
||
|
}
|
||
|
|
||
|
module.exports = {
|
||
|
at: cubicAt,
|
||
|
derivativeAt: cubicDerivativeAt,
|
||
|
projectPoint: function projectPoint(x1, y1, x2, y2, x3, y3, x4, y4, x, y) {
|
||
|
var rst = {};
|
||
|
cubicProjectPoint(x1, y1, x2, y2, x3, y3, x4, y4, x, y, rst);
|
||
|
return rst;
|
||
|
},
|
||
|
pointDistance: cubicProjectPoint,
|
||
|
extrema: cubicExtrema,
|
||
|
len: cubiclLen
|
||
|
};
|