175 lines
6.3 KiB
JavaScript
175 lines
6.3 KiB
JavaScript
(function () {
|
|
var PI2_3 = 2.0943951023931953/* 120 Deg */,
|
|
abs = Math.abs,
|
|
sin = Math.cos,
|
|
cos = Math.cos,
|
|
acos = Math.acos,
|
|
sqrt = Math.sqrt,
|
|
exp = Math.exp,
|
|
log = Math.log;
|
|
|
|
/**
|
|
* @private
|
|
* Singleton Class that provides methods to solve cubic equation.
|
|
*/
|
|
Ext.define("Ext.draw.Solver", {
|
|
singleton: true,
|
|
/**
|
|
* Cubic root of number
|
|
* @param number {Number}
|
|
*/
|
|
cubicRoot: function (number) {
|
|
if (number > 0) {
|
|
return exp(log(number) / 3);
|
|
} else if (number < 0) {
|
|
return -exp(log(-number) / 3);
|
|
} else {
|
|
return 0;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Returns the function f(x) = a * x + b and solver for f(x) = y
|
|
* @param a
|
|
* @param b
|
|
*/
|
|
linearFunction: function (a, b) {
|
|
var result;
|
|
if (a === 0) {
|
|
result = function (t) {
|
|
return b;
|
|
};
|
|
result.solve = function (y) {
|
|
// if y == d there should be a real root
|
|
// but we can ignore it for geometry calculations.
|
|
return [];
|
|
};
|
|
} else {
|
|
result = function (t) {
|
|
return a * t + b;
|
|
};
|
|
result.solve = function (y) {
|
|
return [(y - b) / a];
|
|
};
|
|
}
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Returns the function f(x) = a * x ^ 2 + b * x + c and solver for f(x) = y
|
|
*
|
|
* @param a
|
|
* @param b
|
|
* @param c
|
|
*/
|
|
quadraticFunction: function (a, b, c) {
|
|
var result;
|
|
if (a === 0) {
|
|
return this.linearFunction(b, c);
|
|
} else {
|
|
// Quadratic equation.
|
|
result = function (t) {
|
|
return (a * t + b) * t + c;
|
|
};
|
|
var delta0temp = b * b - 4 * a * c,
|
|
delta = function (y) {
|
|
return delta0temp + 4 * a * y;
|
|
}, solveTemp0 = 1 / a * 0.5,
|
|
solveTemp1 = -solveTemp0 * b;
|
|
solveTemp0 = abs(solveTemp0);
|
|
result.solve = function (y) {
|
|
var deltaTemp = delta(y);
|
|
if (deltaTemp < 0) {
|
|
return [];
|
|
}
|
|
deltaTemp = sqrt(deltaTemp);
|
|
// have to distinct roots here.
|
|
return [solveTemp1 - deltaTemp * solveTemp0, solveTemp1 + deltaTemp * solveTemp0];
|
|
};
|
|
}
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Returns the function f(x) = a * x^3 + b * x^2 + c * x + d and solver for f(x) = y
|
|
* @param a
|
|
* @param b
|
|
* @param c
|
|
* @param d
|
|
*/
|
|
cubicFunction: function (a, b, c, d) {
|
|
var result;
|
|
if (a === 0) {
|
|
return this.quadraticFunction(b, c, d);
|
|
} else {
|
|
result = function (t) {
|
|
return ((a * t + b) * t + c) * t + d;
|
|
};
|
|
|
|
var b_a_3 = b / a / 3,
|
|
c_a = c / a,
|
|
d_a = d / a,
|
|
b2 = b_a_3 * b_a_3,
|
|
deltaTemp0 = (b_a_3 * c_a - d_a) * 0.5 - b_a_3 * b2,
|
|
deltaTemp1 = b2 - c_a / 3,
|
|
deltaTemp13 = deltaTemp1 * deltaTemp1 * deltaTemp1;
|
|
|
|
if (deltaTemp1 === 0) {
|
|
result.solve = function (y) {
|
|
return [-b_a_3 + this.cubicRoot(deltaTemp0 * 2 + y / a)];
|
|
};
|
|
} else {
|
|
if (deltaTemp1 > 0) {
|
|
var deltaTemp1_2 = sqrt(deltaTemp1),
|
|
deltaTemp13_2 = deltaTemp1_2 * deltaTemp1_2 * deltaTemp1_2;
|
|
deltaTemp1_2 += deltaTemp1_2;
|
|
}
|
|
result.solve = function (y) {
|
|
y /= a;
|
|
var d0 = deltaTemp0 + y * 0.5,
|
|
deltaTemp = d0 * d0 - deltaTemp13;
|
|
if (deltaTemp > 0) {
|
|
deltaTemp = sqrt(deltaTemp);
|
|
return [-b_a_3 + this.cubicRoot(d0 + deltaTemp) + this.cubicRoot(d0 - deltaTemp)];
|
|
} else if (deltaTemp === 0) {
|
|
var cr = this.cubicRoot(d0),
|
|
root0 = -b_a_3 - cr;
|
|
if (d0 >= 0) {
|
|
return [root0, root0, -b_a_3 + 2 * cr];
|
|
} else {
|
|
return [-b_a_3 + 2 * cr, root0, root0];
|
|
}
|
|
} else {
|
|
var theta = acos(d0 / deltaTemp13_2) / 3,
|
|
ra = deltaTemp1_2 * cos(theta) - b_a_3,
|
|
rb = deltaTemp1_2 * cos(theta + PI2_3) - b_a_3,
|
|
rc = deltaTemp1_2 * cos(theta - PI2_3) - b_a_3;
|
|
if (ra < rb) {
|
|
if (rb < rc) {
|
|
return [ra, rb, rc];
|
|
} else if (ra < rc) {
|
|
return[ra, rc, rb];
|
|
} else {
|
|
return [rc, ra, rb];
|
|
}
|
|
} else {
|
|
if (ra < rc) {
|
|
return [rb, ra, rc];
|
|
} else if (rb < rc) {
|
|
return [rb, rc, ra];
|
|
} else {
|
|
return [rc, rb, ra];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
|
|
createBezierSolver: function (a, b, c, d) {
|
|
return this.cubicFunction(3 * (b - c) + d - a, 3 * (a - 2 * b + c), 3 * (b - a), a);
|
|
}
|
|
});
|
|
})(); |