How would I go about changing points that are 'near' linear (within a threshold), actually linear?
I have some code that checks if 3 points are linear to one another (give or take), and I want to replace those coordinates with new ones that are 100% inline.
double distance = (x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3);
double threshold = 4;
if (Math.abs(distance) <= threshold) {
// is Near line
return true;
}
else
return false;
This is an EXTENSION of another post of mine... This is NOT a repost, simply a related topic:
Java - Average Linear Graph Plots
The technical term for snapping a point to a line is projecting a point to a line(-segment)
The only question that remains: Should the points projected to the line or to the line segment? (A line segment is only between two points, the line has infinity length and goes through both points)
The code below solves both:
To allow also projecting points to th epart of the line that is outside of points A->B, the code would be much simpler, but this is covered in the link below, too.
See http://forums.codeguru.com/showthread.php?194400-Distance-between-point-and-line-segment
The projected point is in the variables (xx,yy):
(xx,yy) is the point on the lineSegment closest to (cx,cy)
Related
I need some algorithm ideas here. I have a big set of data (~100k entries) of two-dimensional Points as objects with a third variable as the "value" at this point of the plane. Now I want to calculate the interpolated Point at some given coordinates.
My only idea so far would be to iterate over the whole dataset and collect a list of the 4 nearest Points to the one I want to calculate, and then to interpolate between them.
How do I interpolate weighted (by the point's distance in this case) between multiple data? So that Points nearer to the cross are more present in the result?
Do you have any other ideas on how to get the interpolated value at a given coordinate in this case? It should be relatively exact (but does not have to be 100%) and should not take ages to calculate, since this has to be done some 10.000 times and I don't want the user to wait too long.
About the data: The Points are nearly in a grid, and the values of the 2dimensional Points are actually height values, so the values of two near points are also nearly equal.
The Data is stored in a HashMap<Vector2f, Float> where Vector2f is a simple class consisting of 2 floats. There is nothing sorted.
This is non-obvious problem. It is a lot easier for 3 points, with 4 points you will get into situations which are ambigous. Imagine (for points surrounding your sample in square) ul and br corners having value 1, and other corners having value 5. It can be interpreted as valley with height 1 going through center, ridge with height 5 going there, or some kind of fancy spline saddle shape. If you add irregularity of grid into account, it becomes even more fun with closest 4 points being on same side of sample (so you cannot just choose 4 closest points, you need to find 4 bounding points).
For 3 point case, please check https://en.wikipedia.org/wiki/Barycentric_coordinate_system#Application:_Interpolation_on_a_triangular_unstructured_grid
For 4 point case on regular grid,you can use https://en.wikipedia.org/wiki/Bilinear_interpolation to generate kind of 'fair' interpolation.
For 4 points on irregular grid, you can look into solution like
http://www.ahinson.com/algorithms_general/Sections/InterpolationRegression/InterpolationIrregularBilinear.pdf
but be careful with finding proper bounding points (as I mentioned, finding closest ones won't work)
Looks like Bilinear interpolation. There are a few general algorithms and if you have constraints on your data you might be able to use them to simplify the algorithms. Since "the Points are nearly in a grid", I made the approximation that they are ("It should be relatively exact (but does not have to be 100%) and should not take ages to calculate").
Given
2 float x, y as the point you want to interpolate.
4 objects of type Vector2f named v1 to v4, and assuming the coordinates of each can be accessed as v1.x and v1.y and that they are approximately on a grid:
v1.x == v3.x, v2.x == v4.x, v1.y == v2.y, v3.y == v4.y
That the value of each Vector2f was retrieved as float h1 = map.get(v1) (h stands for "height"), then you could write something like this:
float n1 = h1 * (v2.x - x) * (v2.y - y);
float n2 = h2 * (x - v1.x) * (v2.y - y);
float n3 = h3 * (v2.x - x) * (y - v1.y);
float n4 = h4 * (x - v1.x) * (y - v1.y);
float den = (v2.x - v1.x) * (v2.y - v1.y);
float height = (n1 + n2 + n3 + n4) / den;
As a side note, you might also want to look into making your class strictfp.
For a Java program I'm making I need to interpolate 4 points, to calculate the y-value of a 5th point, at given x-value.
Say I have the following points:
p1(0, 0)
p2(1, 2)
p3(2, 4)
p4(3, 3)
// The x-values will always be 0, 1, 2, and 3
Now I want to interpolate these points to find what the y-value should be for given x, say x=1.2 (this x value will always be between point 2 and point 3)
Can anyone help me to make a Java method for finding the y coordinate of this fifth point?
Generally given two points (x0,y0) and (x1,y1), for x0 < x < x1, by interpolation,
y = y0 + (x - x0)/(x1 - x0) * (y1 - y0)
Here,
y = 2 + (x-1) * 2
There are an infinite number of lines that can go through all four of your points.
For example, you could assume that at each point the slope is zero and then draw simple s shaped curves between them, or you could assume that the slope is calculated from the neighboring points (with some special decisions about the ends), or you could assume that the slope at the points is 2, etc.
And it doesn't stop there, you could effectively draw a curve that will encapsulate your points and any other point you could imagine while still meeting the requirement of being continuous (as you call, smooth).
I think you need to start off with a formula you wish to fit against the points, and then choose the technique you use to minimize the error of the fit. Without you making more decisions, it is very likely that it will be very hard to give more direction.
I think that the Title of this question does not explain clearly my question, I'll explain it better.
I have a Java program that plot graphs using JFreeChart. Now I need to do something to get these points from the graph:
In these points, the X coordinate is zero. But none of these points I used to create the graph, so I'm confused if its possible to get them.
Can anyone give me some ideas to do it?
assuming that your line is defined by a sequence of (x, y) points, you know that the line crossed x = 0 when two consecutive points have x-values of different sign. Then you can determine the value of y where the line crosses x = 0. Assuming linear interpolation between two consecutive points (x1, y1), (x2, y2), x1 * x2 < 0:
y0 = y2 - x2 * (y1 - y2) / (x1 - x2)
I currently have a bad method for doing this, it just translates the start point by 1/-1 depending on if the x/y coordinate is over or under the current coordinates and adds it to an ArrayList until the start point .equals(end), this is a bad solution because it creates a really bad path that looks like the black path below.
I'm trying to generate a direct path of points between two points (The same kind of line as Graphics.drawLine makes).
I'm guessing I need to use the Math class to get the angle, but I'm not very familiar with the Math API.
One somewhat naive way, is to work out the ratio of the slope, rather than the angle.
Something like:
float ratio = (y2 - y1) / (x2 - x1);
Then:
width = x2 - x1;
for(int i = 0; i < width; i++) {
float x = x1 + i;
float y = y1 + (ratio * i);
points.add(new Point(x,y));
}
If float isn't what you need, you'll need to do some conversion.
You'll also need to handle the special case of x1 == x2, or you'll get divide-by-zero errors.
Using this method, the steeper the line, the fewer points you will generate. If you want the points evenly spaced no matter what the angle, you'll need to break out sin/cos/tan.
Write unit tests for lines in at least the main 8 compass directions, to iron out any glitches.
This is actually more of a math problems than a programming problem. You need to find the vector that goes from start to end and then scale it and add it to start for the number of points that you want.
In pseudo code:
f(start,end,nPoints) -> (path)
delta = (end-start) / nPoints //Find the best difference vector.
current = start //Set the current point to the start.
i = 0
while(|current-end| < epsilon)
current += delta
path[i] = current
i = i + 1
I'm assuming that the points are floating point (due to the division). epslion should be chosen to be a small value (depends on your problem) to check equality (never use != for floating points!).
This is a very simple concept, but you've not been too clear on what exactly you want. By definition, there are an infinite number of points between any two points (and between two of those points, exist an infinite number of points. And so on.)
The simplest solution would be to calculate the formula for the line between point A and point B, and then decide how far apart you want your points to be, and calculate those points using your line formula.
Elementary geometry tells us that the slope between two points in the change in y over the change in x. So m = (y1 - y2)/(x1 - x2), where all of these values are doubles, and x1 and y1 belong to the same point.
Then the formula for the line between two points is y - y1 = m(x - x1). Then all you'd have to do is start plugging in values for, say, x, taking the resultant y, and drawing it.
This is, of course, the idea behind the whole thing. You'd be much better off using vectors.
Check out this previously answered question to calculate the angle. And then use the distance formula to find the distance.
double dist = Math.sqr((x2 - x1)^2 + (y2 - y1)^2); //obviously wont compile but you get the idea.
Original post:
I'm trying to find the outermost vertices of a convex polygon (with relation to a point P outside the polygon). For now, I'm only concerned with rectangles (however, I'd like an algorithm that works with any convex polygon).
My plan is to construct a line from external point P to central point C. From this line of reference, I will construct lines from point P to points 1, 2, 3 and 4. Since points 2 and 4 will have the largest (most positive) and smallest (most negative) angles from the line of reference, they will be identified as the outermost vertices.
Is this the best algorithm for the job? How does one calculate angles from a reference angle (preferably in Java)?
Update for clarification:
I've drawn the lines (line of reference in red). As you can see, the line from P to 2 creates the largest angle on one side of the line of reference, while the line from P to 4 creates the largest angle of the other side. Hence, these are the outermost vertices.
This is pretty much the convex hull problem. You would be looking for a set of vertices (x1, x2) around a polygon. The methodology that would be applied is called "quick-hull", analogous to quicksort (in that we divide our region of points every time we step through). It is also a safe assumption that P can be used as a mid-point between an arbitrary starting point and its parallel ending point, so you would get a convex hull around P.
It would take a while to produce some reliable Java to poke at (from my happenstance), but I think that the Wikipedia entry will give you a great starting point.
The use of trigonometry is extremely slow. You should use another angle comparison.
For an angle between two flat vectors:
cos(OA, OB) = (OAx * OBx + OAy* OBy) / sqrt((OAx2 + OAy2)* (OBx 2 + OBy2))
I think, you can compare angles having cosines.
I solved the problem as follows:
// code simplified for demonstration
double angleBetweenVertices;
double maxAngleBetweenVertices;
vectorA.setStartingPoint(outerPoint);
vectorA.setTerminationPoint(polygonCenter);
vectorB.setStartingPoint(outerPount);
// For each vertex, calculate the angle between the outer point, the polygon's center and the vertex
for (Point2D.Double vertex : vertices) {
vectorB.setTerminationPoint(vertex);
double angleBetweenVertices =
Math.toDegrees(
Math.atan2(
(vectorA.perpDotProduct(vectorB)),
(vectorA.dotProduct(vectorB))
)
);
// Update the min and Max
if (angleBetweenVertices >= maxAngleBetweenVertices) {
maxVertex = vertex;
maxAngleBetweenVertices = angleBetweenVertices;
} else if (angleBetweenVertices <= minAngleBetweenVertices) {
minVertex = vertex;
minAngleBetweenVertices = angleBetweenVertices;
}
}