Trilateration with distance measurement errors - java

In this link, the process of trilateration is given.
And this is my java code for the localization process:
public static double[] localize(final double[] p1, final double[] p2, final double[] p3, final double[] p4, final double r1, final double r2, final double r3, final double r4)
{
double[] ex = normalize(difference(p2,p1));
double i = dot(ex, difference(p3, p1));
double[] ey = normalize(difference(difference(p3,p1), scalar(i,ex)));
double[] ez = cross(ex, ey);
double d = distance(p2, p1);
if(d - r1 >= r2 || r2 >= d + r1 )
return null;
double j = dot(ey, difference(p3, p1));
double x = ((r1*r1) - (r2*r2) + (d*d)) / (2*d);
double y = (((r1*r1) - (r3*r3) + (i*i) + (j*j)) / (2*j)) - ((i*x) / j);
double z = r1*r1- x*x - y*y;
if(z < 0)
return null;
double z1 = Math.sqrt(z);
double z2 = z1*-1;
double[] result1 = new double[]{p1[0], p1[1], p1[2]};
result1 = add(result1, scalar(x,ex));
result1 = add(result1, scalar(y,ey));
result1 = add(result1, scalar(z1,ez));
double[] result2 = new double[]{p1[0], p1[1], p1[2]};
result2 = add(result2, scalar(x,ex));
result2 = add(result2, scalar(y,ey));
result2 = add(result2, scalar(z2,ez));
double d1 = Math.abs(distance(result1, p4) - r4);
double d2 = Math.abs(distance(result2, p4) - r4);
if(d1<=d2)
return result1;
else
return result2;
}
But now, as shown in this paper, I want to instroduce some errors to distance measurements.
For an error alpha, There will be six spheres intersecting: three inner spheres and three outer spheres.
Their thickness will be amount of alpha(the measurement error).
I will get two areas instead of two points. But how do I estimate the position of a point given two areas?
In order to write such code, I tried this approach:
public static boolean inside(final double[] p, double[] c, final double r, final double error)
{
if(Math.pow(p[0]-c[0],2) + Math.pow(p[1]-c[1],2) + Math.pow(p[2]-c[2],2) >= r-error)
if(Math.pow(p[0]-c[0],2) + Math.pow(p[1]-c[1],2) + Math.pow(p[2]-c[2],2) <= r+error)
return true;
return false;
}
public static double[] localize(final double[] p1, final double[] p2, final double[] p3, final double[] p4, final double r1, final double r2, final double r3, final double r4, final double error)
{
double[][][] result = new double[8][3][3];
result[0] = intersection(p1,p2,p3,r1-error,r2-error,r3-error);
result[1] = intersection(p1,p2,p3,r1-error,r2-error,r3+error);
result[2] = intersection(p1,p2,p3,r1-error,r2+error,r3-error);
result[3] = intersection(p1,p2,p3,r1-error,r2+error,r3+error);
result[4] = intersection(p1,p2,p3,r1+error,r2-error,r3-error);
result[5] = intersection(p1,p2,p3,r1+error,r2-error,r3+error);
result[6] = intersection(p1,p2,p3,r1+error,r2+error,r3-error);
result[7] = intersection(p1,p2,p3,r1+error,r2+error,r3+error);
for(int i=0; i<8; i++)
if(result[i] != null)
for(int j=0; j<2; j++)
if(inside(result[i][j], p4, r4, error))
return result[i][j];
return null;
}
Which gives me null all the times.
Could you help me to get through this?
Edit: The function intersection() is same as localize(). It does not pick any point, but returns both.
Brief summary of the paper:
The paper investigates the 3-D localization by using pairwise distances and the effect of distance measurement errors. The interesting part is, in the paper, the quadratic equations were used to build linear matrices and therefore, the localization was done by using more than four beacons(references). Here, you can search for the keyword error and see how the error was modelled and how the linear equatios were built.
Moreover, I'll refer to this paper for the 2-D version of the problem.

Related

Convert bilaterated x,y point to latitude & longitude?

Hi I'm currently trying to calculate a longitude/latitude point from 2 longitude/latitude points (bilateration) with distance & I've currenty done that :
double EARTH_RADIUS = 6378137.0;
double longitude1 = 4.062787;
double latitude1 = 49.243828;
double x1 = EARTH_RADIUS * (Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(longitude1)));
double y1 = EARTH_RADIUS *(Math.cos(Math.toRadians(latitude1)) * Math.sin(Math.toRadians(longitude1)));
double longitude2 = 4.062023;
double latitude2 = 49.243851;
double x2 = EARTH_RADIUS * (Math.cos(Math.toRadians(latitude2)) * Math.cos(Math.toRadians(longitude2)));
double y2 = EARTH_RADIUS *(Math.cos(Math.toRadians(latitude2)) * Math.sin(Math.toRadians(longitude2)));
System.out.println(x1 + " " + y1);
System.out.println(x2 + " " + y2);
double[][] positions = new double[][] { { x1, y1 }, { x2, y2 } };
double[] distances = new double[] { 10.0, 10.0};
NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(new TrilaterationFunction(positions, distances), new LevenbergMarquardtOptimizer());
Optimum optimum = solver.solve();
double[] centroid = optimum.getPoint().toArray();
System.out.println(Arrays.toString(centroid));
I'm using this library https://github.com/lemmingapex/trilateration to trilaterate my point.
Converting longitude & latitude points to a cartesian plan & using a library to get a point on it, giving me this output :
[INFO] GCLOUD: 4153447.729890433 295011.4801210027
[INFO] GCLOUD: 4153449.72871882 294955.95932889543
[INFO] GCLOUD: [4153448.7293046266, 294983.7197249491]
So now I'm trying to convert this point into latitude & longitude point to put it on Google Map but I have no clue how to do that & if a Java library already exist for bilateration?
EDIT :
So I've done that :
private static final double EARTH_RADIUS = 6371;
private static final int X = 0;
private static final int Y = 1;
private static final int Z = 2;
public static double[] triangulation(double lat0, double lon0, double r0, double lat1, double lon1, double r1) {
double[] p1 = latlon2cartesian(lat0, lon0);
double[] p2 = latlon2cartesian(lat1, lon1);
double[][] positions = new double[][] { { p1[X], p1[Y], p1[Z] }, { p2[X], p2[Y], p2[Z] } };
double[] distances = new double[] { r0, r1};
NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(new TrilaterationFunction(positions, distances), new LevenbergMarquardtOptimizer());
Optimum optimum = solver.solve();
double[] centroid = optimum.getPoint().toArray();
System.out.println(Arrays.toString(p1));
System.out.println(Arrays.toString(p2));
System.out.println(Arrays.toString(centroid));
return cartesian2latlon(centroid[X], centroid[Y], centroid[Z]);
}
private static double[] latlon2cartesian(double lat, double lon) {
lat = Math.toRadians(lat);
lon = Math.toRadians(lon);
return new double[] { Math.cos(lon) * Math.cos(lat) * EARTH_RADIUS, Math.sin(lon) * Math.cos(lat) * EARTH_RADIUS, Math.sin(lat) * EARTH_RADIUS };
}
private static double[] cartesian2latlon(double x, double y, double z) {
return new double[] { Math.toDegrees(Math.asin(z / EARTH_RADIUS)), Math.toDegrees(Math.atan2(y, x)) };
}
But I don't get correct values with :
System.out.println(Arrays.toString(Bilateration.triangulation(49.243828, 4.062787, 5.0, 49.243851, 4.062023, 6.5)));
I get :
[49.2453096100026, 3.9213007384886387]
Near (2km away) but the point should be around 49.24385234064716, 4.062335368930235.

Struggling to find point of intersection using two lines in y = mx + b form

The method:
public static int[] FindIntersectionPoint(int[] p0, int[] p1, int[] p2, int[] p3) {
//line 1 equation
double m1 = (double) (Math.abs(p0[1] - p1[1])) / (double) (Math.abs(p0[0] - p1[0])); //slope
double b1 = p0[1] - (m1 * p0[0]); //y axis intercept
DC.drawLine(p0[0], p0[1], p1[0], p1[1]);
//line 2 equation
double m2 = (double) (Math.abs(p2[1] - p3[1])) / (double) (Math.abs(p2[0] - p3[0])); //slope
double b2 = p2[1] - (m2 * p2[0]); //y axis intercept
DC.drawLine(p2[0], p2[1], p3[0], p3[1]);
//Intersection points
double intersectX = (double)(b2 - b1) / (double)(m1 - m2);
double intersectY = 0;
System.out.println(intersectX); //is -18.181818181818205 which is way off
return new int[] {(int)intersectX, (int)intersectY};
}
Method call:
int point[] = FindIntersectionPoint(new int[]{200, 100}, new int[]{300, 400}, new int[]{500, 50}, new int[]{200, 400});
I've checked and the m1, m2, b1, b2 variables are all calculated correctly and the formula for the xIntercept: (b2 - b1) / (m1 - m2) worked on paper but the program calculates -18.181818181818205 which is definitely not the answer.
Here is a visualization of whats going on:
Possible bug could be in this line:
double b1 = p0[1] - (m1 * p0[0]); //y axis intercept
You are saving operation on int to double, where the decimal digits will be always 0. You are sure, that this calculation is good?
Cast at least one of the ints to double before dividing.

Color - Finding the closest color

I was following the guidelines as described here, but when my android app examines a picture taken in a well-lit room and tries to match every color to the closest basic color (black, red, blue, green, etc.), most of the colors are associated with black. I have no idea why this happens and I have spent 3 hours examining my code to find out where the flaw was. Can anyone suggest where my error is?
Here is my code:
public double getMinEValue(int color1, int color2) {
double result_value = 0;
double[] color1_values = getColorValues(color1);
double[] color2_values = getColorValues(color2);
double delta_L = color1_values[0] - color2_values[0];
double delta_C = Math.sqrt(Math.pow(color1_values[1], 2)+Math.pow(color1_values[2], 2))-Math.sqrt(Math.pow(color2_values[1], 2)+Math.pow(color2_values[2], 2));
double delta_a = color1_values[1]-color2_values[1];
double delta_b = color1_values[2]-color2_values[2];
double delta_H = Math.sqrt(Math.pow(delta_a, 2)+Math.pow(delta_b, 2)+Math.pow(delta_C, 2));
double k_1 = 0.045; double k_2 = 0.015;
double s_c = 1+k_1*Math.sqrt(Math.pow(color1_values[1], 2)+Math.pow(color1_values[2], 2));
double s_h = 1+k_2*Math.sqrt(Math.pow(color1_values[1], 2)+Math.pow(color1_values[2], 2));
result_value = Math.sqrt(Math.pow(delta_L, 2)+Math.pow((delta_C/s_c), 2)+Math.pow((delta_H/s_h), 2));
return result_value;
}
public double[] getColorValues(int color1) {
double[] return_value = new double[3];
double r = Color.red(color1)/255;
double g = Color.green(color1)/255;
double b = Color.blue(color1)/255;
double r_linear = makeLinear(r) * 100;
double g_linear = makeLinear(g) * 100;
double b_linear = makeLinear(b) * 100;
double[][] matrix = {{0.4124, 0.3576, 0.1805}, {0.2126, 0.7152, 0.0722}, {0.0193, 0.1192, 0.9508}};
double[] linear_matrix = {r_linear, g_linear, b_linear};
double[] result_matrix = new double[3];
result_matrix = multiplyMatrices(matrix, linear_matrix);
//double X_n = 109.85; double Y_n = 100.00; double Z_n = 35.58; // Illuminant A
double X_n = 95.047; double Y_n = 100.00; double Z_n = 108.883; // D65
double L_star = 116*f(result_matrix[1]/Y_n)-16;
double a_star = 500*(f(result_matrix[0]/X_n)-f(result_matrix[1]/Y_n));
double b_star = 200*(f(result_matrix[1]/Y_n)-f(result_matrix[2]/Z_n));
return_value[0] = L_star; return_value[1] = a_star; return_value[2] = b_star;
return return_value;
}
private double f(double t) {
double return_value;
if (Double.compare(t, Math.pow((6/29), 3)) > 0) {
return_value = Math.pow(t, (1/3));
} else {
return_value = (1/3)*Math.pow((29/6), 2)*t+(4/29);
}
return return_value;
}
private double makeLinear(double c) {
double return_value = 0;
if (Double.compare(0.04045, c)<=0) {
return_value = c/12.92;
} else {
double a = 0.055;
return_value = Math.pow(((c + a) / (1 + a)), 2.4);
}
return return_value;
}
private double[] multiplyMatrices(double[][] matrix, double[] other_matrix) {
double[] return_matrix = new double[3];
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
return_matrix[i] += matrix[i][j]*other_matrix[j];
}
}
return return_matrix;
}
You've got a whole lot of integer divisions that need to be floating point divisions. You need to cast one of the operands of each division to double, or include a decimal point, to get these to work. For example, you have
Color.red(color1)/255
which should be
Color.red(color1)/255.0
and you also have expressions like
(1/3)*Math.pow((29/6), 2)*t+(4/29);
which needs to be
(1.0/3)*Math.pow((29.0/6), 2)*t+(4.0/29);
and many others. You have made this same mistake several times.

Trilateration in 3-D Algorithm Returns NaN

I tried to code the steps provided in this article.
public static double[] localize(final double[] P1, final double[] P2, final double[] P3, final double[] P4, final double r1, final double r2, final double r3, final double r4)
{
Point3d p1 = new Point3d(P1);
Point3d p2 = new Point3d(P2);
Point3d p3 = new Point3d(P3);
Point3d p4 = new Point3d(P4);
Vector3d ex = new Vector3d();
ex.sub(p2,p1);
ex.normalize();
Vector3d p3p1 = new Vector3d();
p3p1.sub(p3,p1);
double i = ex.dot(p3p1);
Vector3d iex = new Vector3d();
iex.scale(i,ex);
Vector3d ey = new Vector3d(p3p1);
ey.sub(iex);
ey.normalize();
Vector3d ez = new Vector3d();
ez.cross(ex, ey);
double d = p2.distance(p1);
if(d - r1 < r2)
System.out.println("d - r1 < r2");
if(r2 < d + r1)
System.out.println("r2 < d+r1");
double j = ey.dot(p3p1);
double x = (Math.pow(r1,2) - Math.pow(r2,2) + Math.pow(d,2))/(2*d);
Vector3d exx = new Vector3d();
exx.scale(x, ex);
double y = ((Math.pow(r1,2) - Math.pow(r3,2) + Math.pow(i,2) + Math.pow(j,2)) / ((2*j)) - ((i/j)*x));
Vector3d eyy = new Vector3d();
eyy.scale(y, ey);
double z1 = Math.pow(r1,2) - Math.pow(x,2) - Math.pow(y,2);
z1 = Math.sqrt(z1);
double z2 = z1*-1;
Vector3d ezz1 = new Vector3d();
Vector3d ezz2 = new Vector3d();
ezz1.scale(z1, ez);
ezz2.scale(z2, ez);
Point3d result1 = new Point3d();
result1.add(p1);
result1.add(exx);
result1.add(eyy);
result1.add(ezz1);
Point3d result2 = new Point3d();
result2.add(p1);
result2.add(exx);
result2.add(eyy);
result2.add(ezz2);
if((result1.distance(p4) - r4) <= (result2.distance(p4) - r4))
return new double[]{round(result1.x), round(result1.y), round(result1.z)};
else
return new double[]{round(result2.x), round(result2.y), round(result2.z)};
}
Afterz1 is always negative after z1 = Math.pow(r1,2) - Math.pow(x,2) - Math.pow(y,2) step. Hence, taking square root makes it NaN.
Is this possible? Maybe I'm choosing the wrong points to do localization.
Could you please tell me where I'm mistaken?
A negative value for z1 would indicate no real solution, e.g. the intersection of the first and second sphere falls entirely inside or outside of the the third sphere. If your test values do not include at least one set for which a real solution exists, z1 will always be negative.

Class method calls run fine first time, but very slow after exiting activity and trying to run the computation second time

OK, so here's the problem:
I'm making a game with randomly generated terrain. The terrain is generated once and saved to disk/SD card. It does this quite nicely :)
To do this, I run a SplashScreenActivity which runs my opening splashscreen, the world creation or the world loading, depending on how it is started.
The actual procedural generation is done using 4D Simplex Noise using a class written by Stefan Gustavson and ptimised by Peter Eastman (and optimised and speeded up by at least 50% by myself, pulling variables out and making them static ... but the problem I'm about to describe happened before those changes).
Basically I use their noise function to fill tiles with noise. In my world creation loop I loop through all the tiles and per tile I run through all the pixels, calling the SimplexNoise4D.noise(x,y,z,w) function of the class to fill each pixel (I'm planning on sending a xyzw-per-pixel collection to the class so it can run the method on that for faster access).
Anyway, this all works great. But when I exit my game activity and return to the main menu, if I try to run the world creation again, accessing the SimplexNoise class methods (the .noise method and the internal methods it uses) is SLOW!!!
The only way to get the calls to run at normal speed is to exit the whole application (kill it using a task manager) and restart the application. Then, the first time I run it, tile creation is as fast as it should be.
Using debugging/method profilling ect, it seems the calls to the .noise method and it's calls to the dot methods take a huge amount of time the second time I try to run the whole world creation thing.
So, again, The first time I loop through and access using SimplexNoise.noise(xyzw), it runs fine. Accessing it for all pixels in all the tiles a second time however (after being ingame), and all method calls to the class take FOREVER.
Does anyone know why this happens and how I can stop it from happening?
-EDIT-
Just to clear things up, the application works like this:
mainmenuActivity ->chooseWorldSizeActivity->Splashscreen which creates world with a lot of calls to SimplexNoise.noise(xywz)->exit splashscreen->start game Activity.
This works fine and at speed.
If, however, I then quit the gameActivity (which goes to main menu), then ->selectWordlSizeActivity->splashscreenActivity, now the calls to SimplexNoise.noise(xyzw) take forever to complete.
If I stop the whole application (using a atskkiller), then world creation takes the normal time to run again. And I can't really find out why!
-/EDIT-
The calling loop (in the doInBackground() of an ASyncTask) just is:
for(loop over rows of tiles)
for(loop over column tiles)
for(each pixel)
create x, y, z, w;
SimplexNoise.noise(xyzw);
The Simplex Noise class looks like this:
`
public final class SimplexNoise4D { // Simplex noise in 2D, 3D and 4D
private static final Grad grad3[] = {new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0),
new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1),
new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)};
private static final Grad grad4[]= {new Grad(0,1,1,1),new Grad(0,1,1,-1),new Grad(0,1,-1,1),new Grad(0,1,-1,-1),
new Grad(0,-1,1,1),new Grad(0,-1,1,-1),new Grad(0,-1,-1,1),new Grad(0,-1,-1,-1),
new Grad(1,0,1,1),new Grad(1,0,1,-1),new Grad(1,0,-1,1),new Grad(1,0,-1,-1),
new Grad(-1,0,1,1),new Grad(-1,0,1,-1),new Grad(-1,0,-1,1),new Grad(-1,0,-1,-1),
new Grad(1,1,0,1),new Grad(1,1,0,-1),new Grad(1,-1,0,1),new Grad(1,-1,0,-1),
new Grad(-1,1,0,1),new Grad(-1,1,0,-1),new Grad(-1,-1,0,1),new Grad(-1,-1,0,-1),
new Grad(1,1,1,0),new Grad(1,1,-1,0),new Grad(1,-1,1,0),new Grad(1,-1,-1,0),
new Grad(-1,1,1,0),new Grad(-1,1,-1,0),new Grad(-1,-1,1,0),new Grad(-1,-1,-1,0)};
private static final short p[] = {151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180};
// To remove the need for index wrapping, double the permutation table length
private static short perm[] = new short[512];
private static short permMod12[] = new short[512];
static {
for(int i=0; i<512; i++)
{
perm[i]=p[i & 255];
permMod12[i] = (short)(perm[i] % 12);
}
}
// Skewing and unskewing factors for 2, 3, and 4 dimensions
private static final double F2 = 0.5*(Math.sqrt(3.0)-1.0);
private static final double G2 = (3.0-Math.sqrt(3.0))/6.0;
private static final double F3 = 1.0/3.0;
private static final double G3 = 1.0/6.0;
private static final double F4 = (Math.sqrt(5.0)-1.0)/4.0;
private static final double G4 = (5.0-Math.sqrt(5.0))/20.0;
// This method is a *lot* faster than using (int)Math.floor(x)
private static int fastfloor(double x) {
int xi = (int)x;
return x<xi ? xi-1 : xi;
}
private static double dot(Grad g, double x, double y) {
return g.x*x + g.y*y; }
private static double dot(Grad g, double x, double y, double z) {
return g.x*x + g.y*y + g.z*z; }
private static double dot(Grad g, double x, double y, double z, double w) {
return g.x*x + g.y*y + g.z*z + g.w*w; }
private static double n0, n1, n2, n3, n4; // Noise contributions from the five corners
private static double s;// Factor for 4D skewing
private static int i;
private static int j;
private static int k;
private static int l;
private static double t; // Factor for 4D unskewing
private static double X0; // Unskew the cell origin back to (x,y,z,w) space
private static double Y0;
private static double Z0;
private static double W0;
private static double x0; // The x,y,z,w distances from the cell origin
private static double y0;
private static double z0;
private static double w0;
private static int rankx;
private static int ranky;
private static int rankz;
private static int rankw;
private static int i1, j1, k1, l1; // The integer offsets for the second simplex corner
private static int i2, j2, k2, l2; // The integer offsets for the third simplex corner
private static int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
private static double x1; // Offsets for second corner in (x,y,z,w) coords
private static double y1;
private static double z1;
private static double w1;
private static double x2; // Offsets for third corner in (x,y,z,w) coords
private static double y2;
private static double z2;
private static double w2;
private static double x3; // Offsets for fourth corner in (x,y,z,w) coords
private static double y3;
private static double z3;
private static double w3;
private static double x4; // Offsets for last corner in (x,y,z,w) coords
private static double y4;
private static double z4;
private static double w4;
// Work out the hashed gradient indices of the five simplex corners
private static int ii;
private static int jj;
private static int kk;
private static int ll;
private static int gi0;
private static int gi1;
private static int gi2;
private static int gi3;
private static int gi4;
private static double t0;
private static double t1;
private static double t2;
private static double t3;
private static double t4;
// 4D simplex noise, better simplex rank ordering method 2012-03-09
public static double noise(double x, double y, double z, double w) {
////double n0, n1, n2, n3, n4; // Noise contributions from the five corners
// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
////double s = (x + y + z + w) * F4; // Factor for 4D skewing
s = (x + y + z + w) * F4; // Factor for 4D skewing
/*int i = fastfloor(x + s);
int j = fastfloor(y + s);
int k = fastfloor(z + s);
int l = fastfloor(w + s);
double t = (i + j + k + l) * G4; // Factor for 4D unskewing
double X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
double Y0 = j - t;
double Z0 = k - t;
double W0 = l - t;
double x0 = x - X0; // The x,y,z,w distances from the cell origin
double y0 = y - Y0;
double z0 = z - Z0;
double w0 = w - W0;*/
i = fastfloor(x + s);
j = fastfloor(y + s);
k = fastfloor(z + s);
l = fastfloor(w + s);
t = (i + j + k + l) * G4; // Factor for 4D unskewing
X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
Y0 = j - t;
Z0 = k - t;
W0 = l - t;
x0 = x - X0; // The x,y,z,w distances from the cell origin
y0 = y - Y0;
z0 = z - Z0;
w0 = w - W0;
// For the 4D case, the simplex is a 4D shape I won't even try to describe.
// To find out which of the 24 possible simplices we're in, we need to
// determine the magnitude ordering of x0, y0, z0 and w0.
// Six pair-wise comparisons are performed between each possible pair
// of the four coordinates, and the results are used to rank the numbers.
/*int rankx = 0;
int ranky = 0;
int rankz = 0;
int rankw = 0;
if(x0 > y0) rankx++; else ranky++;
if(x0 > z0) rankx++; else rankz++;
if(x0 > w0) rankx++; else rankw++;
if(y0 > z0) ranky++; else rankz++;
if(y0 > w0) ranky++; else rankw++;
if(z0 > w0) rankz++; else rankw++;
int i1, j1, k1, l1; // The integer offsets for the second simplex corner
int i2, j2, k2, l2; // The integer offsets for the third simplex corner
int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner*/
rankx = 0;
ranky = 0;
rankz = 0;
rankw = 0;
if(x0 > y0) rankx++; else ranky++;
if(x0 > z0) rankx++; else rankz++;
if(x0 > w0) rankx++; else rankw++;
if(y0 > z0) ranky++; else rankz++;
if(y0 > w0) ranky++; else rankw++;
if(z0 > w0) rankz++; else rankw++;
// simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
// Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
// impossible. Only the 24 indices which have non-zero entries make any sense.
// We use a thresholding to set the coordinates in turn from the largest magnitude.
// Rank 3 denotes the largest coordinate.
i1 = rankx >= 3 ? 1 : 0;
j1 = ranky >= 3 ? 1 : 0;
k1 = rankz >= 3 ? 1 : 0;
l1 = rankw >= 3 ? 1 : 0;
// Rank 2 denotes the second largest coordinate.
i2 = rankx >= 2 ? 1 : 0;
j2 = ranky >= 2 ? 1 : 0;
k2 = rankz >= 2 ? 1 : 0;
l2 = rankw >= 2 ? 1 : 0;
// Rank 1 denotes the second smallest coordinate.
i3 = rankx >= 1 ? 1 : 0;
j3 = ranky >= 1 ? 1 : 0;
k3 = rankz >= 1 ? 1 : 0;
l3 = rankw >= 1 ? 1 : 0;
// The fifth corner has all coordinate offsets = 1, so no need to compute that.
/*double x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
double y1 = y0 - j1 + G4;
double z1 = z0 - k1 + G4;
double w1 = w0 - l1 + G4;
double x2 = x0 - i2 + 2.0*G4; // Offsets for third corner in (x,y,z,w) coords
double y2 = y0 - j2 + 2.0*G4;
double z2 = z0 - k2 + 2.0*G4;
double w2 = w0 - l2 + 2.0*G4;
double x3 = x0 - i3 + 3.0*G4; // Offsets for fourth corner in (x,y,z,w) coords
double y3 = y0 - j3 + 3.0*G4;
double z3 = z0 - k3 + 3.0*G4;
double w3 = w0 - l3 + 3.0*G4;
double x4 = x0 - 1.0 + 4.0*G4; // Offsets for last corner in (x,y,z,w) coords
double y4 = y0 - 1.0 + 4.0*G4;
double z4 = z0 - 1.0 + 4.0*G4;
double w4 = w0 - 1.0 + 4.0*G4;
// Work out the hashed gradient indices of the five simplex corners
int ii = i & 255;
int jj = j & 255;
int kk = k & 255;
int ll = l & 255;
int gi0 = perm[ii+perm[jj+perm[kk+perm[ll]]]] % 32;
int gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]] % 32;
int gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]] % 32;
int gi3 = perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]] % 32;
int gi4 = perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]] % 32;*/
x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
y1 = y0 - j1 + G4;
z1 = z0 - k1 + G4;
w1 = w0 - l1 + G4;
x2 = x0 - i2 + 2.0*G4; // Offsets for third corner in (x,y,z,w) coords
y2 = y0 - j2 + 2.0*G4;
z2 = z0 - k2 + 2.0*G4;
w2 = w0 - l2 + 2.0*G4;
x3 = x0 - i3 + 3.0*G4; // Offsets for fourth corner in (x,y,z,w) coords
y3 = y0 - j3 + 3.0*G4;
z3 = z0 - k3 + 3.0*G4;
w3 = w0 - l3 + 3.0*G4;
x4 = x0 - 1.0 + 4.0*G4; // Offsets for last corner in (x,y,z,w) coords
y4 = y0 - 1.0 + 4.0*G4;
z4 = z0 - 1.0 + 4.0*G4;
w4 = w0 - 1.0 + 4.0*G4;
// Work out the hashed gradient indices of the five simplex corners
ii = i & 255;
jj = j & 255;
kk = k & 255;
ll = l & 255;
gi0 = perm[ii+perm[jj+perm[kk+perm[ll]]]] % 32;
gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]] % 32;
gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]] % 32;
gi3 = perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]] % 32;
gi4 = perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]] % 32;
// Calculate the contribution from the five corners
/*double t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0;
if(t0<0) n0 = 0.0;
else {
t0 *= t0;
n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
}
double t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1;
if(t1<0) n1 = 0.0;
else {
t1 *= t1;
n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
}
double t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2;
if(t2<0) n2 = 0.0;
else {
t2 *= t2;
n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
}
double t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3;
if(t3<0) n3 = 0.0;
else {
t3 *= t3;
n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
}
double t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4;
if(t4<0) n4 = 0.0;
else {
t4 *= t4;
n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
}*/
t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0;
if(t0<0) n0 = 0.0;
else {
t0 *= t0;
n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
}
t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1;
if(t1<0) n1 = 0.0;
else {
t1 *= t1;
n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
}
t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2;
if(t2<0) n2 = 0.0;
else {
t2 *= t2;
n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
}
t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3;
if(t3<0) n3 = 0.0;
else {
t3 *= t3;
n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
}
t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4;
if(t4<0) n4 = 0.0;
else {
t4 *= t4;
n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
}
// Sum up and scale the result to cover the range [-1,1]
return 27.0 * (n0 + n1 + n2 + n3 + n4);
}
// Inner class to speed up gradient computations
// (array access is a lot slower than member access)
private static class Grad
{
double x, y, z, w;
Grad(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
Grad(double x, double y, double z, double w)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
}
}
`

Categories

Resources