Array interpolation - java

Before I start, please accept my apologies that I'm not a mathematician and don't really know the proper names for what I'm trying to do... ;) Pointers to any plain-English explanations that might help would be most appreciated (as I'm purely Googling at the moment based upon what I think the solution might be).
If have a multi-dimensionsal array of source values and wanted to upscale that array by a factor of n, I think that what I'd need to use is Bicubic Interpolation Certainly the image top right on that page is representative of what I'm aiming for - creating a graduated flow of values between the underlying source data points, based upon the value(s) of their surrounding neighbours. I completely accept that by not increasing the volume of data I am not increasing the resolution of the data; merely blurring the edges.
Something akin to going from this;
to this (and beyond);
Following the link within the Wikipedia article gives me a (supposed) example implementation of what I'm striving for, but if it does I fear I'm currently missing the logical leap to get myself there. When I call getValue(source, 0.5, 0.5) on the BicubicInterpolator, what am I getting back? I thought that if I gave an x/y of (0.0,0.0) I would get back the bottom-left value of the grid and if I looked at (1,1) I would get top-right, and any value between would give me the specified position within the interpolated grid.
double[][] source = new double[][] {{1, 1, 1, 2}, {1, 2, 2, 3}, {1, 2, 2, 3}, {1, 1, 3, 3}};
BicubicInterpolator bi = new BicubicInterpolator();
for (double idx = 0; idx <= 1; idx += 0.1) {
LOG.info("Result (" + String.format("%3.1f", idx) + ", " + String.format("%3.1f", idx) + ") : " + bi.getValue(source, idx, idx));
}
The output for a diagonal line across my source grid however is;
Result (0.0, 0.0) : 2.0
Result (0.1, 0.1) : 2.08222625
Result (0.2, 0.2) : 2.128
Result (0.3, 0.3) : 2.13747125
Result (0.4, 0.4) : 2.11424
Result (0.5, 0.5) : 2.06640625
Result (0.6, 0.6) : 2.00672
Result (0.7, 0.7) : 1.9518312500000001
Result (0.8, 0.8) : 1.92064
Result (0.9, 0.9) : 1.93174625
Result (1.0, 1.0) : 2.0
I'm confused because the diagonals go from 1 to 3 and from 1 to 2; there's nothing going from 2 to 2 with very little (overall) variation. Am I completely mis-understanding things?
EDIT : Following Peter's suggestion to expand the boundary for analysis, the grid can now be generated as a quick'n'dirty upscale to a 30x30 matrix;
Now that what's going on is making a bit more sense, I can see that I need to consider a few additional things;
Control the overshoot (seen in the middle of the grid where the source has a block of four cells with a value of 2, but the interpolated value peaks at 2.2)
Cater for blank values in the source grid and have them treated as blanks, rather than zero, so that they don't skew the calculation
Be prepare to be told I'm on a fool's errand and that a different solution is needed
See if this was what the customer thought they actually wanted when they said "make it less blocky"

If you assume the "outside" temperature is the same as the outer most ring of values, and you want to shift which port of the grid you are considering...
public static void main(String... args) {
double[][] source = new double[][]{{1, 1, 1, 2}, {1, 2, 2, 3}, {1, 2, 2, 3}, {1, 1, 3, 3}};
BicubicInterpolator bi = new BicubicInterpolator();
for (int i = 0; i <= 30; i++) {
double idx = i / 10.0;
System.out.printf("Result (%3.1f, %3.1f) : %3.1f%n", idx, idx, bi.getValue(source, idx, idx));
}
}
public static class CubicInterpolator {
public static double getValue(double[] p, double x) {
int xi = (int) x;
x -= xi;
double p0 = p[Math.max(0, xi - 1)];
double p1 = p[xi];
double p2 = p[Math.min(p.length - 1,xi + 1)];
double p3 = p[Math.min(p.length - 1, xi + 2)];
return p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0)));
}
}
public static class BicubicInterpolator extends CubicInterpolator {
private double[] arr = new double[4];
public double getValue(double[][] p, double x, double y) {
int xi = (int) x;
x -= xi;
arr[0] = getValue(p[Math.max(0, xi - 1)], y);
arr[1] = getValue(p[xi], y);
arr[2] = getValue(p[Math.min(p.length - 1,xi + 1)], y);
arr[3] = getValue(p[Math.min(p.length - 1, xi + 2)], y);
return getValue(arr, x+ 1);
}
}
prints
Result (0.0, 0.0) : 1.0
Result (0.1, 0.1) : 1.0
Result (0.2, 0.2) : 1.0
Result (0.3, 0.3) : 1.1
Result (0.4, 0.4) : 1.1
Result (0.5, 0.5) : 1.3
Result (0.6, 0.6) : 1.4
Result (0.7, 0.7) : 1.6
Result (0.8, 0.8) : 1.7
Result (0.9, 0.9) : 1.9
Result (1.0, 1.0) : 2.0
Result (1.1, 1.1) : 2.1
Result (1.2, 1.2) : 2.1
Result (1.3, 1.3) : 2.1
Result (1.4, 1.4) : 2.1
Result (1.5, 1.5) : 2.1
Result (1.6, 1.6) : 2.0
Result (1.7, 1.7) : 2.0
Result (1.8, 1.8) : 1.9
Result (1.9, 1.9) : 1.9
Result (2.0, 2.0) : 2.0
Result (2.1, 2.1) : 2.1
Result (2.2, 2.2) : 2.3
Result (2.3, 2.3) : 2.5
Result (2.4, 2.4) : 2.7
Result (2.5, 2.5) : 2.8
Result (2.6, 2.6) : 2.9
Result (2.7, 2.7) : 3.0
Result (2.8, 2.8) : 3.0
Result (2.9, 2.9) : 3.0
Result (3.0, 3.0) : 3.0
Looking at how this works, you have a 2x2 grid of inside values and a 4x4 square outside it for outside values. the (0.0, 0.0) to (1.0, 1.0) values map the diagonal between 2 (in cell 2,2) and 2 (in cell 3,3) using the outer values to help interpolate the values.
double[][] source = new double[][]{{1, 1, 1, 2}, {1, 2, 2, 3}, {1, 2, 2, 3}, {1, 1, 3, 3}};
BicubicInterpolator bi = new BicubicInterpolator();
for (int i = -10; i <= 20; i++) {
double idx = i / 10.0;
System.out.printf("Result (%3.1f, %3.1f) : %3.1f%n", idx, idx, bi.getValue(source, idx, idx));
}
prints
Result (-1.0, -1.0) : -5.0
Result (-0.9, -0.9) : -2.8
Result (-0.8, -0.8) : -1.2
Result (-0.7, -0.7) : -0.2
Result (-0.6, -0.6) : 0.5
Result (-0.5, -0.5) : 1.0
Result (-0.4, -0.4) : 1.3
Result (-0.3, -0.3) : 1.5
Result (-0.2, -0.2) : 1.7
Result (-0.1, -0.1) : 1.9
Result (0.0, 0.0) : 2.0
Result (0.1, 0.1) : 2.1
Result (0.2, 0.2) : 2.1
Result (0.3, 0.3) : 2.1
Result (0.4, 0.4) : 2.1
Result (0.5, 0.5) : 2.1
Result (0.6, 0.6) : 2.0
Result (0.7, 0.7) : 2.0
Result (0.8, 0.8) : 1.9
Result (0.9, 0.9) : 1.9
Result (1.0, 1.0) : 2.0
Result (1.1, 1.1) : 2.1
Result (1.2, 1.2) : 2.3
Result (1.3, 1.3) : 2.5
Result (1.4, 1.4) : 2.7
Result (1.5, 1.5) : 2.8
Result (1.6, 1.6) : 2.7
Result (1.7, 1.7) : 2.1
Result (1.8, 1.8) : 0.9
Result (1.9, 1.9) : -1.4
Result (2.0, 2.0) : -5.0

Related

What is the range of improved Perlin noise?

I'm trying to find the theoretical output range of improved Perlin noise for 1, 2 and 3 dimensions. I'm aware of existing answers to this question, but they don't seem to accord with my practical findings.
If n is the number of dimensions then according to [1] it should be [-sqrt(n/4), sqrt(n/4)]. According to [2] (which refers to [3]) it should be [-0.5·sqrt(n), 0.5·sqrt(n)] (which amounts to the same thing).
This means that the ranges should be approximately:
Dimensions
Range
1
[-0.5, 0.5]
2
[-0.707, 0.707]
3
[-0.866, 0.866]
However when I run the following code (which uses Ken Perlin's own reference implementation of improved noise from his website), I get higher values for 2 and 3 dimensions, namely approximately:
Dimensions
Range
1
[-0.5, 0.5]
2
[-0.891, 0.999]
3
[-0.997, 0.999]
With different permutations I even sometimes get values slightly over 1.0 for 3 dimensions, and for some strange reason one of the bounds for two dimension always seems to be about 0.89 while the other is about 1.00.
I can't figure out whether this is due to a bug in my code (I don't see how since this is Ken Perlin's own code) or due to those discussions not being correct or not being applicable somehow, in which case I would like to know what the theoretical ranges are for improved Perlin noise.
Can you replicate this? Are the results wrong, or can you point me to a discussion of the theoretical values that accords with this outcome?
The code:
public class PerlinTest {
public static void main(String[] args) {
double lowest1DValue = Double.MAX_VALUE, highest1DValue = -Double.MAX_VALUE;
double lowest2DValue = Double.MAX_VALUE, highest2DValue = -Double.MAX_VALUE;
double lowest3DValue = Double.MAX_VALUE, highest3DValue = -Double.MAX_VALUE;
final Random random = new SecureRandom();
for (int i = 0; i < 10000000; i++) {
double value = noise(random.nextDouble() * 256.0, 0.0, 0.0);
if (value < lowest1DValue) {
lowest1DValue = value;
}
if (value > highest1DValue) {
highest1DValue = value;
}
value = noise(random.nextDouble() * 256.0, random.nextDouble() * 256.0, 0.0);
if (value < lowest2DValue) {
lowest2DValue = value;
}
if (value > highest2DValue) {
highest2DValue = value;
}
value = noise(random.nextDouble() * 256.0, random.nextDouble() * 256.0, random.nextDouble() * 256.0);
if (value < lowest3DValue) {
lowest3DValue = value;
}
if (value > highest3DValue) {
highest3DValue = value;
}
}
System.out.println("Lowest 1D value: " + lowest1DValue);
System.out.println("Highest 1D value: " + highest1DValue);
System.out.println("Lowest 2D value: " + lowest2DValue);
System.out.println("Highest 2D value: " + highest2DValue);
System.out.println("Lowest 3D value: " + lowest3DValue);
System.out.println("Highest 3D value: " + highest3DValue);
}
static public double noise(double x, double y, double z) {
int X = (int)Math.floor(x) & 255, // FIND UNIT CUBE THAT
Y = (int)Math.floor(y) & 255, // CONTAINS POINT.
Z = (int)Math.floor(z) & 255;
x -= Math.floor(x); // FIND RELATIVE X,Y,Z
y -= Math.floor(y); // OF POINT IN CUBE.
z -= Math.floor(z);
double u = fade(x), // COMPUTE FADE CURVES
v = fade(y), // FOR EACH OF X,Y,Z.
w = fade(z);
int A = p[X ]+Y, AA = p[A]+Z, AB = p[A+1]+Z, // HASH COORDINATES OF
B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z; // THE 8 CUBE CORNERS,
return lerp(w, lerp(v, lerp(u, grad(p[AA ], x , y , z ), // AND ADD
grad(p[BA ], x-1, y , z )), // BLENDED
lerp(u, grad(p[AB ], x , y-1, z ), // RESULTS
grad(p[BB ], x-1, y-1, z ))),// FROM 8
lerp(v, lerp(u, grad(p[AA+1], x , y , z-1 ), // CORNERS
grad(p[BA+1], x-1, y , z-1 )), // OF CUBE
lerp(u, grad(p[AB+1], x , y-1, z-1 ),
grad(p[BB+1], x-1, y-1, z-1 ))));
}
static double fade(double t) { return t * t * t * (t * (t * 6 - 15) + 10); }
static double lerp(double t, double a, double b) { return a + t * (b - a); }
static double grad(int hash, double x, double y, double z) {
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
double u = h<8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
v = h<4 ? y : h==12||h==14 ? x : z;
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}
static final int p[] = new int[512], permutation[] = { 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
};
static { for (int i=0; i < 256 ; i++) p[256+i] = p[i] = permutation[i]; }
}
Ken’s not using unit vectors. As [1] says, with my emphasis:
Third, there are many different ways to select the random vectors at the grid cell corners. In Improved Perlin noise, instead of selecting any random vector, one of 12 vectors pointing to the edges of a cube are used instead. Here, I will talk strictly about a continuous range of angles since it is easier – however, the range of value of an implementation of Perlin noise using a restricted set of vectors will never be larger. Finally, the script in this repository assumes the vectors are of unit length. If they not, the range of value should be scaled according to the maximum vector length. Note that the vectors in Improved Perlin noise are not unit length.
For Ken’s improved noise, the maximum vector length is 1 in 1D and √2 in 2D, so the theoretical bounds are [−0.5, 0.5] in 1D and [−1, 1] in 2D. I don’t know why you’re not seeing the full range in 2D; if you shuffled the permutation I bet you would sometimes.
For 3D, the maximum vector length is still √2, but the extreme case identified by [1] isn’t a possible output, so the theoretical range of [−√(3/2), √(3/2)] is an overestimate. These folks tried to work it out exactly, and yes, the maximum absolute value does seem to be strictly greater than 1.

How do I easily implement the Matlab percentile in Java?

I need to replicate the Matlab Percentile ( https://www.mathworks.com/help/stats/prctile.html ) for a simple case
percentile(double[] arr, int percentile) in java. I am unable to find any implementations which give me the same result since it seems to have a percentile along with linear interpolation.
Any help or guidance is appreciated!
By directly applying the definition (you can found in the page you've linked)
// `xs` must be sorted
double percentile(double [] xs, int p) {
// The sorted elements in X are taken as the 100(0.5/n)th, 100(1.5/n)th, ..., 100([n – 0.5]/n)th percentiles.
int i = (int) (p * xs.length / 100.0 - 0.5);
// Linear interpolation uses linear polynomials to find yi = f(xi), the values of the underlying function
// Y = f(X) at the points in the vector or array x. Given the data points (x1, y1) and (x2, y2), where
// y1 = f(x1) and y2 = f(x2), linear interpolation finds y = f(x) for a given x between x1 and x2 as follows:
return xs[i] + (xs[i + 1] - xs[i]) * (p / 100.0 - (i + 0.5) / xs.length) / ((i + 1.5) / xs.length - (i + 0.5) / xs.length);
}
using the example on that page
double [] xs1 = new double[] {6.0753, 8.6678, 0.4823, 6.7243, 5.6375, 2.3846, 4.1328, 5.6852, 12.1568, 10.5389};
Arrays.sort(xs1);
double r = percentile(xs1, 42);
System.out.println("Result: " + r);
System.out.println("Error: " + Math.abs(r - 5.6709));
you get
Result: 5.67089
Error: 9.999999999621423E-6
The #josejuan's answer is very good: but is it not necessary to handle the case in which i is equal to xs.length - 1? I would modify the return formula of percentile function as follows:
return i != (xs.length - 1) ? xs[i] + (xs[i + 1] - xs[i]) * (p / 100.0 - (i + 0.5) / xs.length) / ((i + 1.5) / xs.length - (i + 0.5) / xs.length) : xs[i];

Android - How to customize rounding value?

Hi i really bad at rounding. i am trying to round up a value to the rounding of my country currency.
The rounding example will be :
1.01 > 1.00
1.02 > 1.00
1.03 > 1.05
1.04 > 1.05
1.06 > 1.05
1.07 > 1.05
1.08 > 1.10
1.09 > 1.10
How can i do this kind of rounding? Thanks a lot .
Looks like you're rounding by 0.05 = 1/20th. So the following works:
public static double roundCurrency( double value ) {
return Math.round(value * 20.0 ) / 20.0;
}
This seems to give you the correct mappings - you may need to tweak it when you decide exactly where the cutoffs are.
public void test() {
double [] tests = new double[] {1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9};
for ( double d : tests) {
System.out.println(" "+d + " -> "+round(d, .05, 0.5));
}
}
double round(double d, double fraction, double bias) {
return Math.floor(d / fraction + bias) * fraction;
}
This prints:
1.01 -> 1.0
1.02 -> 1.0
1.03 -> 1.05
1.04 -> 1.05
1.05 -> 1.05
1.06 -> 1.05
1.07 -> 1.05
1.08 -> 1.1
1.09 -> 1.1
double roundedvalue= Math.round( YourValue* 100.0 ) / 100.0;
double roundedvalue= Math.round( YourValue* 2.0 ) / 2.0;
Math.round lets you round a number to the nearest integer. It looks like you're trying to round to the nearest multiple of 0.5. The general way to solve problems like that is
roundedValue = Math.round (X / M) * M;
to round to the nearest multiple of M. So in your case that would be
roundedValue = Math.round (X / 0.5) * 0.5;
which is the same as
roundedValue = Math.round (X * 2.0) / 2.0;
Similarly, if you wanted to round something to the nearest multiple of, say, 0.01, one of these would work:
roundedValue = Math.round (X / 0.01) * 0.01;
roundedValue = Math.round (X * 100.0) / 100.0;
EDIT: It looks like you've changed your question, so what I said earlier about rounding to the nearest multiple of 0.5 isn't correct any more, and now you're rounding to the nearest multiple of 0.05. Anyway, the general method I've discussed still works.
Take a look at the http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html documentation on the Math Class. It lets you perform operations such as Math.round(double x) and
Math.ceil(double x) and Math.floor(double x) . You can use these in combination with an if else statement such as
double value = 1.6;
String valueToString = Double.toString(value);
String [] numbers = valueToString.split(".");
String decimalNums = numbers[1];
int decimal = Integer.parseInt(decimalNums);
if(decimal > 0 && decimal < 5){
decimal = Math.floor(decimal);
}else if(decimal >= 5 && decimal < 8){
decimal = 5;
}else{
decimal = Math.ceil(decimal);
}
This will only work for values that have one decimal place. But its a start. Hope it helps a little.

Check is a point (x,y) is between two points drawn on a straight line

I have drawn a line between two points A(x,y)---B(x,y)
Now I have a third point C(x,y). I want to know that if C lies on the line which is drawn between A and B.
I want to do it in java language. I have found couple of answers similar to this. But, all have some problems and no one is perfect.
if (distance(A, C) + distance(B, C) == distance(A, B))
return true; // C is on the line.
return false; // C is not on the line.
or just:
return distance(A, C) + distance(B, C) == distance(A, B);
The way this works is rather simple. If C lies on the AB line, you'll get the following scenario:
A-C------B
and, regardless of where it lies on that line, dist(AC) + dist(CB) == dist(AB). For any other case, you have a triangle of some description and 'dist(AC) + dist(CB) > dist(AB)':
A-----B
\ /
\ /
C
In fact, this even works if C lies on the extrapolated line:
C---A-------B
provided that the distances are kept unsigned. The distance dist(AB) can be calculated as:
___________________________
/ 2 2
V (A.x - B.x) + (A.y - B.y)
Keep in mind the inherent limitations (limited precision) of floating point operations. It's possible that you may need to opt for a "close enough" test (say, less than one part per million error) to ensure correct functioning of the equality.
ATTENTION! Math-only!
You can try this formula. Put your A(x1, y1) and B(x2, y2) coordinates to formula, then you'll get something like
y = k*x + b; // k and b - numbers
Then, any point which will satisfy this equation, will lie on your line.
To check that C(x, y) is between A(x1, y1) and B(x2, y2), check this: (x1<x<x2 && y1<y<y2) || (x1>x>x2 && y1>y>y2).
Example
A(2,3) B(6,5)
The equation of line:
(y - 3)/(5 - 3) = (x - 2)/(6 - 2)
(y - 3)/2 = (x - 2)/4
4*(y - 3) = 2*(x - 2)
4y - 12 = 2x - 4
4y = 2x + 8
y = 1/2 * x + 2; // equation of line. k = 1/2, b = 2;
Let's check if C(4,4) lies on this line.
2<4<6 & 3<4<5 // C between A and B
Now put C coordinates to equation:
4 = 1/2 * 4 + 2
4 = 2 + 2 // equal, C is on line AB
PS: as #paxdiablo wrote, you need to check if line is horizontal or vertical before calculating. Just check
y1 == y2 || x1 == x2
I believe the simplest is
// is BC inline with AC or visa-versa
public static boolean inLine(Point A, Point B, Point C) {
// if AC is vertical
if (A.x == C.x) return B.x == C.x;
// if AC is horizontal
if (A.y == C.y) return B.y == C.y;
// match the gradients
return (A.x - C.x)*(A.y - C.y) == (C.x - B.x)*(C.y - B.y);
}
You can calculate the gradient by taking the difference in the x values divided by the difference in the y values.
Note: there is a different test to see if C appears on the line between A and B if you draw it on a screen. Maths assumes that A, B, C are infinitely small points. Actually very small to within representation error.
The above answers are unnecessarily complicated. The simplest is as follows.
if (x-x1)/(x2-x1) = (y-y1)/(y2-y1) = alpha (a constant), then the point C(x,y) will lie on the line between pts 1 & 2.
If alpha < 0.0, then C is exterior to point 1.
If alpha > 1.0, then C is exterior to point 2.
Finally if alpha = [0,1.0], then C is interior to 1 & 2.
Hope this answer helps.
I think all the methods here have a pitfall, in that they are not dealing with rounding errors as rigorously as they could. Basically the methods described will tell you if your point is close enough to the line using some straightforward algorithm and that it will be more or less precise.
Why precision is important? Because it's the very problem presented by op. For a computer program there is no such thing as a point on a line, there is only point within an epsilon of a line and what that epsilon is needs to be documented.
Let's illustrate the problem. Using the distance comparison algorithm:
Let's say a segment goes from (0, 0) to (0, 2000), we are using floats in our application (which have around 7 decimal places of precision) and we test whether a point on (1E-6, 1000) is on the line or not.
The distance from either end of the segment to the point is 1000.0000000005 or 1000 + 5E-10, and, thus, the difference with the addition of the distance to and from the point is around 1E-9. But none of those values can be stored on a float with enough precission and the method will return true.
If we use a more precise method like calculating the distance to the closest point in the line, it returns a value that a float has enough precision to store and we could return false depending on the acceptable epsilon.
I used floats in the example but the same applies to any floating point type such as double.
One solution is to use BigDecimal and whichever method you want if incurring in performance and memory hit is not an issue.
A more precise method than comparing distances for floating points, and, more importantly, consistently precise, although at a higher computational cost, is calculating the distance to the closest point in the line.
Shortest distance between a point and a line segment
It looks like I'm splitting hairs but I had to deal with this problem before. It's an issue when chaining geometric operations. If you don't control what kind of precission loss you are dealing with, eventually you will run into difficult bugs that will force you to reason rigorously about the code in order to fix them.
An easy way to do that I believe would be the check the angle formed by the 3 points.
If the angle ACB is 180 degrees (or close to it,depending on how accurate you want to be) then the point C is between A and B.
I think this might help
How to check if a point lies on a line between 2 other points
That solution uses only integers given you only provide integers which removes some pitfalls as well
Here is my C# solution. I believe the Java equivalent will be almost identical.
Notes:
Method will only return true if the point is within the bounds of the line (it does not assume an infinite line).
It will handle vertical or horizontal lines.
It calculates the distance of the point being checked from the line so allows a tolerance to be passed to the method.
/// <summary>
/// Check if Point C is on the line AB
/// </summary>
public static bool IsOnLine(Point A, Point B, Point C, double tolerance)
{
double minX = Math.Min(A.X, B.X) - tolerance;
double maxX = Math.Max(A.X, B.X) + tolerance;
double minY = Math.Min(A.Y, B.Y) - tolerance;
double maxY = Math.Max(A.Y, B.Y) + tolerance;
//Check C is within the bounds of the line
if (C.X >= maxX || C.X <= minX || C.Y <= minY || C.Y >= maxY)
{
return false;
}
// Check for when AB is vertical
if (A.X == B.X)
{
if (Math.Abs(A.X - C.X) >= tolerance)
{
return false;
}
return true;
}
// Check for when AB is horizontal
if (A.Y == B.Y)
{
if (Math.Abs(A.Y - C.Y) >= tolerance)
{
return false;
}
return true;
}
// Check istance of the point form the line
double distFromLine = Math.Abs(((B.X - A.X)*(A.Y - C.Y))-((A.X - C.X)*(B.Y - A.Y))) / Math.Sqrt((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));
if (distFromLine >= tolerance)
{
return false;
}
else
{
return true;
}
}
def DistBetwPoints(p1, p2):
return math.sqrt( (p2[0] - p1[0])**2 + (p2[1] - p1[1])**2 )
# "Check if point C is between line endpoints A and B"
def PointBetwPoints(A, B, C):
dist_line_endp = DistBetwPoints(A,B)
if DistBetwPoints(A,C)>dist_line_endp: return 1
elif DistBetwPoints(B,C)>dist_line_endp: return 1
else: return 0
Here is a JavaScript function I made. You pass it three points (three objects with an x and y property). Points 1 and 2 define your line, and point 3 is the point you are testing.
You will receive an object back with some useful info:
on_projected_line - If pt3 lies anywhere on the line including outside the points.
on_line - If pt3 lies on the line and between or on pt1 and pt2.
x_between - If pt3 is between or on the x bounds.
y_between - If pt3 is between or on the y bounds.
between - If x_between and y_between are both true.
/**
* #description Check if pt3 is on line defined by pt1 and pt2.
* #param {Object} pt1 The first point defining the line.
* #param {float} pt1.x
* #param {float} pt1.y
* #param {Object} pt2 The second point defining the line.
* #param {float} pt2.x
* #param {float} pt2.y
* #param {Object} pt3 The point to test.
* #param {float} pt3.x
* #param {float} pt3.y
*/
function pointOnLine(pt1, pt2, pt3) {
const result = {
on_projected_line: true,
on_line: false,
between_both: false,
between_x: false,
between_y: false,
};
// Determine if on line interior or exterior
const x = (pt3.x - pt1.x) / (pt2.x - pt1.x);
const y = (pt3.y - pt1.y) / (pt2.y - pt1.y);
// Check if on line equation
result.on_projected_line = x === y;
// Check within x bounds
if (
(pt1.x <= pt3.x && pt3.x <= pt2.x) ||
(pt2.x <= pt3.x && pt3.x <= pt1.x)
) {
result.between_x = true;
}
// Check within y bounds
if (
(pt1.y <= pt3.y && pt3.y <= pt2.y) ||
(pt2.y <= pt3.y && pt3.y <= pt1.y)
) {
result.between_y = true;
}
result.between_both = result.between_x && result.between_y;
result.on_line = result.on_projected_line && result.between_both;
return result;
}
console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2}))
console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5}))
if ( (ymid - y1) * (x2-x1) == (xmid - x1) * (y2-y1) ) **is true, Z lies on line AB**
Start Point : A (x1, y1),
End Point : B (x2, y2),
Point That is on Line AB or Not : Z (xmid, ymid)
I just condensed everyone's answers and this formula works the best for me.
It avoids division by zero
No distance calculation required
Simple to implement
Edit: In case you are dealing with floats, which you most probably are,
use this:
if( (ymid - y1) * (x2-x1) - (xmid - x1) * (y2-y1) < DELTA )
where the tolerance DELTA is a value close to zero.
I usually set it to 0.05

Using least square method with Commons Math and fitting

I was trying to use commons math to figure out the constants in a polynomial. It looks like the routine exists but I got this error. Does anyone see the issue?
I was trying to convert this question to commons-math:
https://math.stackexchange.com/questions/121212/how-to-find-curve-equation-from-data
From plotting you data (Wolfram|Alpha link), it does not look linear. So it better be fit by a polynomial. I assume you want to fit the data:
X Y
1 4
2 8
3 13
4 18
5 24
..
using a quadratic polynomial y=ax2+bx+c.
And wolfram alpha provided a great utility. I wish I could get the same answers like from wolfram.
http://www.wolframalpha.com/input/?i=fit+4%2C+8%2C+13%2C
E.g. By entering that data, I would get : 4.5 x-0.666667 (linear)
Here is the code and error:
import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;
import org.apache.commons.math3.stat.regression.SimpleRegression;
final OLSMultipleLinearRegression regression2 = new OLSMultipleLinearRegression();
double[] y = {
4.0,
8,
13,
};
double[][] x2 =
{
{ 1.0, 1, 1 },
{ 1.0, 2, 4 },
{ 0.0, 3, 9 },
};
regression2.newSampleData(y, x2);
regression2.setNoIntercept(true);
regression2.newSampleData(y, x2);
double[] beta = regression2.estimateRegressionParameters();
for (double d : beta) {
System.out.println("D: " + d);
}
Exception in thread "main" org.apache.commons.math3.exception.MathIllegalArgumentException: not enough data (3 rows) for this many predictors (3 predictors)
at org.apache.commons.math3.stat.regression.AbstractMultipleLinearRegression.validateSampleData(AbstractMultipleLinearRegression.java:236)
at org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression.newSampleData(OLSMultipleLinearRegression.java:70)
at org.berlin.bot.algo.BruteForceSort.main(BruteForceSort.java:108)
The javadoc for validateSampleData() states that the two-dimensional array must have at least one more row than it has columns.
http://commons.apache.org/proper/commons-math/javadocs/api-3.3/org/apache/commons/math3/stat/regression/AbstractMultipleLinearRegression.html
Rcook was right. I provided an additional row (test case) and that generated the same answer as from wolfram/alpha.
D: 0.24999999999999822
D: 3.4500000000000033
D: 0.24999999999999914
Or 0.25x^2 + 3.45x + 0.25
final OLSMultipleLinearRegression regression2 = new OLSMultipleLinearRegression();
double[] y = {
4,
8,
13,
18
};
double[][] x2 =
{
{ 1, 1, 1 },
{ 1, 2, 4 },
{ 1, 3, 9 },
{ 1, 4, 16 },
};
regression2.newSampleData(y, x2);
regression2.setNoIntercept(true);
regression2.newSampleData(y, x2);
double[] beta = regression2.estimateRegressionParameters();
for (double d : beta) {
System.out.println("D: " + d);
}

Categories