/*
*/
import java.awt.*;
public class ik
{
//-------- SOLVE TWO LINK INVERSE KINEMATICS -------------
// Given a two link joint from [0,0,0] to end effector position P,
// let link lengths be a and b, and let norm |P| = c. Clearly a+b >= c.
//
// Problem: find a "knee" position Q such that |Q| = a and |P-Q| = b.
//
// In the case of a point on the x axis R = [c,0,0], there is a
// closed form solution S = [d,e,0], where |S| = a and |R-S| = b:
//
// d2+e2 = a2 -- because |S| = a
// (c-d)2+e2 = b2 -- because |R-S| = b
//
// c2-2cd+d2+e2 = b2 -- combine the two equations
// c2-2cd = b2 - a2
// c-2d = (b2-a2)/c
// d - c/2 = (a2-b2)/c / 2
//
// d = (c + (a2-b2/c) / 2 -- to solve for d and e.
// e = sqrt(a2-d2)
static double findD(double a, double b, double c) {
return Math.max(0, Math.min(a, (c + (a*a-b*b)/c) / 2));
}
static double findE(double a, double d) { return Math.sqrt(a*a-d*d); }
// This leads to a solution to the more general problem:
//
// (1) R = Mfwd(P) -- rotate P onto the x axis
// (2) Solve for S
// (3) Q = Minv(S) -- rotate back again
static double[][] Mfwd = new double[3][3], Minv = new double[3][3];
static public boolean solve(double A, double B, double[] P, double[] D, double[] Q) {
double[] R = new double[3];
defineM(P,D);
rot(Minv,P,R);
double d = findD(A,B,norm(R));
double e = findE(A,d);
double[] S = {d,e,0};
rot(Mfwd,S,Q);
return d > 0 && d < A;
}
// If "knee" position Q needs to be as close as possible to some point D,
// then choose M such that M(D) is in the y>0 half of the z=0 plane.
//
// Given that constraint, define the forward and inverse of M as follows:
static void defineM(double[] P, double[] D) {
double[] X = Minv[0], Y = Minv[1], Z = Minv[2];
// Minv defines a coordinate system whose x axis contains P, so X = unit(P).
for (int i = 0 ; i < 3 ; i++)
X[i] = P[i];
normalize(X);
// The y axis of Minv is perpendicular to P, so Y = unit( D - X(D·X) ).
double dDOTx = dot(D,X);
for (int i = 0 ; i < 3 ; i++)
Y[i] = D[i] - dDOTx * X[i];
normalize(Y);
// The z axis of Minv is perpendicular to both X and Y, so Z = X×Y.
cross(X,Y,Z);
// Mfwd = (Minv)T, since transposing inverts a rotation matrix.
for (int i = 0 ; i < 3 ; i++) {
Mfwd[i][0] = Minv[0][i];
Mfwd[i][1] = Minv[1][i];
Mfwd[i][2] = Minv[2][i];
}
}
//------------ GENERAL VECTOR MATH SUPPORT -----------
static double norm(double[] v) { return Math.sqrt( dot(v,v) ); }
static void normalize(double[] v) {
double norm = norm(v);
for (int i = 0 ; i < 3 ; i++)
v[i] /= norm;
}
static double dot(double[] a, double[] b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
static void cross(double[] a, double[] b, double[] c) {
c[0] = a[1] * b[2] - a[2] * b[1];
c[1] = a[2] * b[0] - a[0] * b[2];
c[2] = a[0] * b[1] - a[1] * b[0];
}
static void rot(double[][] M, double[] src, double[] dst) {
for (int i = 0 ; i < 3 ; i++)
dst[i] = dot(M[i],src);
}
}