Extrapolate a line beyond two known points - java

I really suck at math. No, better explanation: I don't know how to interpret mathematical notation. My brain just cant interpret it. That's why I come to the programming community for help "translating" math into a language I do understand.
I have two sets of coordinates in 3d space representing the line of sight.
Vector1(eyes) x=10 y=10 z=4
Vector2(lookingat) x=10 y=8 z=4.785
How do I calculate a point with these double values beyond the looking at value? for example, what lies 2 points beyond the line we are looking it? what location in space would that be?
In short:
How do I extrapolate a given point beyond the line made up by two vectors with given double value along the line.
a known
\
\
\
b known
?
? + 3
?
c what is this value...
Edit
With the help of the answer of #Thrustmaster I came up with this wonderfull solution. Thanks a lot :D
private Vec3 calculateLine(Vec3 x1, Vec3 x2, double distance) {
double length = Math.sqrt(multiply(x2.xCoord - x1.xCoord) + multiply((x2.yCoord - x1.yCoord)) + multiply((x2.zCoord - x1.zCoord)));
double unitSlopeX = (x2.xCoord-x1.xCoord) / length;
double unitSlopeY = (x2.yCoord-x1.yCoord) / length;
double unitSlopeZ = (x2.zCoord-x1.zCoord) / length;
double x = x1.xCoord + unitSlopeX * distance;
double y = x1.yCoord + unitSlopeY * distance;
double z = x1.zCoord + unitSlopeZ * distance;
return Vec3.createVectorHelper(x, y, x);
}
private double multiply(double one) {
return one * one;
}

You need to start looking to basic 3D coordinate geometry.
In 3D, the equation can be written as:
x = x1 + unitSlopeX * distance
y = y1 + unitSlopeY * distance
z = z1 + unitSlopeZ * distance
.. where (x1,y1,z1) can be any point on the line; in this case (10,10,4).
Next set of unknowns is all 3 unitSlopes. To calculate it, simply subtract the two points (this will ive you a vector), and divide by the length of the vector.
length = sqrt((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2)
unitSlopeX = (x2-x1) / length
unitSlopeY = (y2-y1) / length
unitSlopeZ = (z2-z1) / length
Now, to finally, get your third coordinate, simply plug in distance (any value) into the three equations at the beginning of this post.
In vector notation:
V = V1 + t * (V2 - V1) / | V2 - V1 |
.. where t is any real number.

Related

I am trying to calculate sine of an angle without using the Math.sin() in java

I am trying to calculate sine of an angle without using the Math.sin(). I got stuck in it's equation as I keep getting the wrong results
note I have a method that changes the angle from degrees to radians
public static double sin(double x, int precision) {
//this method is simply the sine function
double answer = 1, power = 1;
int n = 2,factorial = 1;
while (n<=precision) {
power = (power * x * x *-1) +1 ;
factorial = (factorial * (n +1))* (n-1);
answer = answer + ((power/factorial ));
n = n + 2;
}
return answer;
}
It looks like you're attempting to calculate the sine of angle given in radians using the Maclaurin series, a special case of Taylor series.
sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
Your initial answer is 1 when it should be x. Your initial power is 1 when it should be x also.
double answer = x, power = x;
For some reason you're adding one to the power part of the result when you shouldn't be.
power = (power * x * x * -1);
You'll also need to fix your factorial calculation. Multiply by n + 1 and n, not n + 1 and n - 1.
factorial = (factorial * (n + 1)) * (n);
With these fixes, testing:
for (double angle = 0; angle <= Math.PI; angle += Math.PI / 4)
{
System.out.println("sin(" + angle + ") = " + sin(angle, 10));
}
The results are pretty good considering the limitations of precision for floating point arithmetic.
sin(0.0) = 0.0
sin(0.7853981633974483) = 0.7071067811796194
sin(1.5707963267948966) = 0.999999943741051
sin(2.356194490192345) = 0.7070959900908971
sin(3.141592653589793) = -4.4516023820965686E-4
Note that this will get more inaccurate as the values of x get larger, not just because of the inaccuracy to represent pi, but also because of the floating point calculations for adding and subtracting large values.

calculating shortest grid distance

Consider a city where the streets are perfectly laid out to form an infinite square grid. In this city finding the shortest path between two given points (an origin and a destination) is much easier than in other more complex cities. As a new Uber developer, you are tasked to create an algorithm that does this calculation.
Given user's departure and destination coordinates, each of them located on some street, find the length of the shortest route between them assuming that cars can only move along the streets. You are guaranteed that at least one of the coordinates is an integer.
I am struggling a little to figure out the logic here. There are many cases and I don't know how to accommodate them all. This is what I have so far
double perfectCity(double[] departure, double[] destination) {
double yDist = Math.abs(destination[1]-departure[1]);
double xDist = Math.abs(departure[1] - departure[0] + departure[1]-destination[0]);
return xDist + yDist;
}
The algorithm is very simple if the inputs are integers, just find the absolute value between the x and y coordinates and then add them together. This is called the Manhattan distance.
int distance = Math.abs(x1 - x2) + Math.abs(y1 - y2);
With doubles, it is almost exactly the same, except for one situation. Here are some possibilities:
Both points have integer coordinates
One point has integer coordinates, and the other point has only one integer coordinate
Both points have only one integer coordinate, but they are on different axes.
Both points have only one integer coordinate, and they are on the same axis.
Possibilities 1-3 all work fine using the same algorithm as for finding distance with integers, except #4 has the possibility of the axis in common being on the same block.
For example, if the inputs were: {x: 0.5, y: 2} and {x: 0.5, y: 3} you would have to travel horizontally, vertically, and then backwards horizontally again in order to reach the destination. This is different from inputs of {x: 0.5, y: 2} and {x: 1.5, y: 3} because there is no need to travel backwards on the same axis.
So you can use the normal algorithm in all cases except for the case of when both of the Xs or Ys have floating-point values and have the same floor-ed value.
Your code should look something like this.
import static java.lang.Math.*;
public static double perfectCity(double x1, double y1, double x2, double y2) {
double xDist = abs(x1 - x2);
double yDist = abs(y1 - y2);
if (floor(x1) != x1 && floor(x2) != x2 && // both Xs are doubles
floor(x1) == floor(x2) && // on the same block
y1 != y2) { // not on the same street
xDist = min(abs(x1 - floor(x1) + x2 - floor(x2)),
abs(x1 - ceil(x1) + x2 - ceil(x2)));
} else if (floor(y1) != y1 && floor(y2) != y2 && // both Ys are doubles
floor(y1) == floor(y2) && // on the same block
x1 != x2) { // not on the same street
yDist = min(abs(y1 - floor(y1) + y2 - floor(y2)),
abs(y1 - ceil(y1) + y2 - ceil(y2)));
}
return xDist + yDist;
}
This can be much further simplified by using a helper function to calculate each axis separately.
public static double perfectCity(double x1, double y1, double x2, double y2) {
return travelOnAxis(x1, x2, y1 == y2) + travelOnAxis(y1, y2, x1 == x2);
}
private static double travelOnAxis(double from, double to, boolean travelIsStraight) {
if (Math.floor(from) == Math.floor(to) && !travelIsStraight) {
double dist = Math.abs((from % 1) + (to % 1));
return Math.min(dist, 2 - dist);
} else {
return Math.abs(from - to);
}
}
I used the trick with 2 - dist here because it's the same as calculating
Math.abs((1 - (from % 1)) + (1 - (to % 1)))
which is the same as
Math.abs(from - Math.ceil(from) + to - Math.ceil(to))
If this is a square grid, you can consider the x and y coordinates separately; the minimum distance is the sum of the minumum distances in the two directions.
In the p-direction (either x or y), you have to move from p1 to p2. From p1, you can either move to floor(p1) or ceil(p1) to get to a road (which may be equal, if p1 is an integer); from there, you can move to either floor(p2) or ceil(p2), the road on which p2 is located; from there, you can move to p2.
So, the minimum distance in the p-direction is
min(abs(p1 - ceil(p1) ) + abs(ceil(p1) - floor(p2)) + abs(floor(p2) - p2), # (1)
abs(p1 - floor(p1)) + abs(floor(p1) - ceil(p2) ) + abs(ceil(p2) - p2), # (2)
abs(p1 - floor(p1)) + abs(floor(p1) - floor(p2)) + abs(floor(p2) - p2), # (3)
abs(p1 - ceil(p1) ) + abs(ceil(p1) - ceil(p2) ) + abs(ceil(p2) - p2)) # (4)
So you can just calculate this independently for the x and y directions, and add.
To illustrate this (abbreviating floor and ceil as f and p respectively):
f(p1) p1 c(p1)
+---O>>>>+>>>>>>>>+
.
.
+>>>O----+
f(p2) p2 c(p2)
--------------------------------> p axis
The shortest route is indicated here with >. The .s are on the shortest route, but since that part of the route is orthogonal to the p direction, it "doesn't count" towards the minimum distance in that direction.
The minimum route shown here, p1 -> c(p1) -> f(p2) -> p2, is Case 1 above.
It should not be hard to visualize swapping p1 and p2, in which case the minimum route is to go from p1 ->f(p1) -> c(p2) -> p2 (Case 2).
The case of pN == f(pN) == c(pN) is not very different; then, the part of the expression abs(pN - f(pN)) or abs(pN - c(pN)) is just zero.
The slightly different case is where f(p1) == f(p2):
f(p1) p1 c(p1) f(p1) p1 c(p1)
+---O>>>>+ +<<<O----+
. .
. .
+-----O<<+ +>>>>>O--+
f(p2) p2 c(p2) f(p2) p2 c(p2)
--------------------------------> p axis
In this case, the minimum route can either be p1 -> f(p1) -> f(p2) -> p2 or p1 -> c(p1) -> c(p2) -> p2 (which are Cases 3 and 4, respectively).
As mentioned by 4castle, the problem is trivial if only integers are considered for input. You would never have to "move back" after having "moved forward" in that case since you would always reach your destinaton in a single move.
But since, at most one floating point number needs to be considered for each of departure/destination, we need to consider 3 cases, (warning: lengthy explanation). Below is a python2 implementation with explanations.
x co-ordinates of both departure and destination are the same and are not floating point numbers. In this case, the shortest distance is simply the absolute difference between y co-ordinates. The same logic applies vice-versa.
import math
class Location():
def __init__(self, cord):
self.x = cord[0]
self.y = cord[1]
def perfectCity(departure, destination):
l1 = Location(departure)
l2 = Location(destination)
if l1.x == l2.x and float(l1.x).is_integer() and float(l2.x).is_integer():
return abs(l1.y-l2.y)
if l1.y == l2.y and float(l1.y).is_integer() and float(l2.y).is_integer():
return abs(l1.x-l2.x)
When one of the co-ordinates in the departure is a floating point, then:
If x co-ordinate is floating point, we can move backwards(round down) or move front(round up).
If y co-ordinate is floating point, we can either move down (round down) or move up (round up).
The above logic should work even when there is no floating point co-ordinate since we move in either direction by zero units.
Once we calculate these, we just choose the minimum among those like below,
return min(calc_round_up_dist(l1, l2), cal_round_down_dist(l1, l2))
Lets take an example of (0.4, 1) and (0.9, 3) for below calculations.
While calculating the round_up we need to calculate 3 distances:
round_up_distance: difference between the rounded up value of the floating point co-ordinate and the original floating point co-ordinate. We return zero if there is no floating point co-ordinate. 1 - 0.4 = 0.6 in the above example
non_floating_point difference: difference between the non floating point co-ordinate of departure and the corresponding co-ordinate of destination ( note that this might be floating point or not a floating point abs(3-1) = 2 in the above example
Difference between departure's floating point counterpart in the destination co-ordinate 0.9 in the above case and the new value of departure's floating point after rounding up, 0.4 + 0.6(this is the round_up distance) = 1.0, i.e. abs(0.9 - 1.0) = 0.1
Adding all the 3 above we get 0.6 + 2 + .1 = 2.7 which is the shortest distance.
Corresponding calculation needs to be done for rounding down. And we pick the minimum among both. The code for round_up and round_down is as below,
import math
class Location():
def __init__(self, cord):
self.x = cord[0]
self.y = cord[1]
def floating_point_round_up(self):
if not float(self.x).is_integer():
return math.ceil(self.x) - self.x
if not float(self.y).is_integer():
return math.ceil(self.y) - self.y
return 0
def floating_point_round_down(self):
if not float(self.x).is_integer():
return self.x - math.floor(self.x)
if not float(self.y).is_integer():
return self.y - math.floor(self.y)
return 0
def non_floating_point_diff(self, obj):
if not float(self.x).is_integer():
return abs(self.y - obj.y)
if not float(self.y).is_integer():
return abs(self.x - obj.x)
return abs(self.y - obj.y)
def floating_point_counterpart(self, obj):
if not float(self.x).is_integer():
return obj.x
if not float(self.y).is_integer():
return obj.y
return obj.x
def floating_point(self):
if not float(self.x).is_integer():
return self.x
if not float(self.y).is_integer():
return self.y
return self.x
Round up and down functions are as below,
def calc_round_up_dist(l1, l2):
dist = l1.floating_point_round_up()
diff = l1.non_floating_point_diff(l2)
floating_point_counterpart = l1.floating_point_counterpart(l2)
new_val = dist + l1.floating_point()
return dist + diff + abs(new_val - floating_point_counterpart)
def cal_round_down_dist(l1, l2):
dist = l1.floating_point_round_down()
diff = l1.non_floating_point_diff(l2)
floating_point_counterpart = l1.floating_point_counterpart(l2)
new_val = l1.floating_point() - dist
return dist + diff + abs(floating_point_counterpart - new_val)
Finally the main function that calls the above methods,
def perfectCity(departure, destination):
l1 = Location(departure)
l2 = Location(destination)
if l1.x == l2.x and float(l1.x).is_integer() and float(l2.x).is_integer():
return abs(l1.y-l2.y)
if l1.y == l2.y and float(l1.y).is_integer() and float(l2.y).is_integer():
return abs(l1.x-l2.x)
return min(calc_round_up_dist(l1, l2), cal_round_down_dist(l1, l2))
This is a practice question on CodeSignal:
https://app.codesignal.com/company-challenges/uber/gsjPcfsuNavxhsQQ7
def solution(departure, destination):
# go to the closest integer
# I can only travel the path of an integer
# if the number is a float I need to travel to an integer first
# then travel to the destination
x1, y1 = departure
x2, y2 = destination
res = 0
# check if the coordinations are integers
a = list(map(isInteger, departure))
b = list(map(isInteger, destination))
# if all are integers or if the corresponding elements are different
if a[0] ^ b[0] or (a[0] and a[1] and b[0] and b[1]):
return abs(x1-x2) + abs(y1-y2)
if a[0]:
res += abs(x2-x1)
# cloest distance from y1 to y2
res += getClosest(y1, y2)
else:
res += abs(y2-y1)
# closes distance from x1 to x2
res += getClosest(x1, x2)
return res
def getClosest(y1, y2):
cand1 = math.floor(y1)
cand2 = math.ceil(y1)
# find the integer closer to y1 to move to
res1 = abs(y1-cand1) + abs(cand1-y2)
res2 = abs(y1-cand2) + abs(cand2-y2)
return min(res1, res2)
def isInteger(n):
return n == round(n)

Error in the return of the intersection points

My algorithm checks the relative position between two lines at this point I'm sure the lines are concurrents and want to return the point of intersection. I'm using this formula to not have linear systems:
My problem is when the input lines are as follows:
r: X= (8,1,9) + λ(2,-1,3) s: X (3,-4,4) + µ(1,-2,2) I hope the output is (-2, 6, -6) but is (7.6, 1.2, 8.4). Does anyone have any idea why this occurs?
My method
public Point3D intersectingLines(Line lineOne, Line lineTwo) {
double x = lineOne.getPoint().getX() - lineTwo.getPoint().getX();
double y = lineOne.getPoint().getY() - lineTwo.getPoint().getY();
double z = lineOne.getPoint().getZ() - lineTwo.getPoint().getZ();
Vector3D pointsDifference = new Vector3D(x, y, z);
Vector3D second = pointsDifference.crossProduct(lineTwo.getVector());
Vector3D first = lineOne.getVector().crossProduct(lineTwo.getVector());
double lambda = first.getNorm() / second.getNorm();
double xIntersectionOne = lineOne.getPoint().getX() + (lambda * lineOne.getVector().getX());
double yIntersectionOne = lineOne.getPoint().getY() + (lambda * lineOne.getVector().getY());
double zIntersectionOne = lineOne.getPoint().getZ() + (lambda * lineOne.getVector().getZ());
double xInLineTwo = (xIntersectionOne - lineTwo.getPoint().getX()) / lineTwo.getVector().getX();
double yInLineTwo = (yIntersectionOne - lineTwo.getPoint().getY()) / lineTwo.getVector().getY();
double zInLineTwo = (zIntersectionOne - lineTwo.getPoint().getZ()) / lineTwo.getVector().getZ();
//Here I check if the point is even correct or lambda must be negative to obtain the correct point
if (xInLineTwo == yInLineTwo && xInLineTwo == zInLineTwo) {
return new Point3D(xIntersectionOne, yIntersectionOne, zIntersectionOne);
} else {
xIntersectionOne = lineOne.getPoint().getX() + (-1 * lambda * lineOne.getVector().getX());
yIntersectionOne = lineOne.getPoint().getY() + (-1 * lambda * lineOne.getVector().getY());
zIntersectionOne = lineOne.getPoint().getZ() + (-1 * lambda * lineOne.getVector().getZ());
return new Point3D(xIntersectionOne, yIntersectionOne, zIntersectionOne);
}
}
The main problem is in the equation the other tests had no difference but that particular equation yes. The equation is in "reverse" order so got lambda = |0,2| and not lambda = |5|.
And another problem was noted in the comment's David Wallace where the condition checks equality of doubles type.
See more

How to draw a smooth line through a set of points using Bezier curves?

I need to draw a smooth line through a set of vertices. The set of vertices is compiled by a user dragging their finger across a touch screen, the set tends to be fairly large and the distance between the vertices is fairly small. However, if I simply connect each vertex with a straight line, the result is very rough (not-smooth).
I found solutions to this which use spline interpolation (and/or other things I don't understand) to smooth the line by adding a bunch of additional vertices. These work nicely, but because the list of vertices is already fairly large, increasing it by 10x or so has significant performance implications.
It seems like the smoothing should be accomplishable by using Bezier curves without adding additional vertices.
Below is some code based on the solution here:
http://www.antigrain.com/research/bezier_interpolation/
It works well when the distance between the vertices is large, but doesn't work very well when the vertices are close together.
Any suggestions for a better way to draw a smooth curve through a large set of vertices, without adding additional vertices?
Vector<PointF> gesture;
protected void onDraw(Canvas canvas)
{
if(gesture.size() > 4 )
{
Path gesturePath = new Path();
gesturePath.moveTo(gesture.get(0).x, gesture.get(0).y);
gesturePath.lineTo(gesture.get(1).x, gesture.get(1).y);
for (int i = 2; i < gesture.size() - 1; i++)
{
float[] ctrl = getControlPoint(gesture.get(i), gesture.get(i - 1), gesture.get(i), gesture.get(i + 1));
gesturePath.cubicTo(ctrl[0], ctrl[1], ctrl[2], ctrl[3], gesture.get(i).x, gesture.get(i).y);
}
gesturePath.lineTo(gesture.get(gesture.size() - 1).x, gesture.get(gesture.size() - 1).y);
canvas.drawPath(gesturePath, mPaint);
}
}
}
private float[] getControlPoint(PointF p0, PointF p1, PointF p2, PointF p3)
{
float x0 = p0.x;
float x1 = p1.x;
float x2 = p2.x;
float x3 = p3.x;
float y0 = p0.y;
float y1 = p1.y;
float y2 = p2.y;
float y3 = p3.y;
double xc1 = (x0 + x1) / 2.0;
double yc1 = (y0 + y1) / 2.0;
double xc2 = (x1 + x2) / 2.0;
double yc2 = (y1 + y2) / 2.0;
double xc3 = (x2 + x3) / 2.0;
double yc3 = (y2 + y3) / 2.0;
double len1 = Math.sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
double len2 = Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
double len3 = Math.sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
double k1 = len1 / (len1 + len2);
double k2 = len2 / (len2 + len3);
double xm1 = xc1 + (xc2 - xc1) * k1;
double ym1 = yc1 + (yc2 - yc1) * k1;
double xm2 = xc2 + (xc3 - xc2) * k2;
double ym2 = yc2 + (yc3 - yc2) * k2;
// Resulting control points. Here smooth_value is mentioned
// above coefficient K whose value should be in range [0...1].
double k = .1;
float ctrl1_x = (float) (xm1 + (xc2 - xm1) * k + x1 - xm1);
float ctrl1_y = (float) (ym1 + (yc2 - ym1) * k + y1 - ym1);
float ctrl2_x = (float) (xm2 + (xc2 - xm2) * k + x2 - xm2);
float ctrl2_y = (float) (ym2 + (yc2 - ym2) * k + y2 - ym2);
return new float[]{ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y};
}
Bezier Curves are not designed to go through the provided points! They are designed to shape a smooth curve influenced by the control points.
Further you don't want to have your smooth curve going through all data points!
Instead of interpolating you should consider filtering your data set:
Filtering
For that case you need a sequence of your data, as array of points, in the order the finger has drawn the gesture:
You should look in wiki for "sliding average".
You should use a small averaging window. (try 5 - 10 points). This works as follows: (look for wiki for a more detailed description)
I use here an average window of 10 points:
start by calculation of the average of points 0 - 9, and output the result as result point 0
then calculate the average of point 1 - 10 and output, result 1
And so on.
to calculate the average between N points:
avgX = (x0+ x1 .... xn) / N
avgY = (y0+ y1 .... yn) / N
Finally you connect the resulting points with lines.
If you still need to interpolate between missing points, you should then use piece - wise cubic splines.
One cubic spline goes through all 3 provided points.
You would need to calculate a series of them.
But first try the sliding average. This is very easy.
Nice question. Your (wrong) result is obvious, but you can try to apply it to a much smaller dataset, maybe by replacing groups of close points with an average point. The appropriate distance in this case to tell if two or more points belong to the same group may be expressed in time, not space, so you'll need to store the whole touch event (x, y and timestamp). I was thinking of this because I need a way to let users draw geometric primitives (rectangles, lines and simple curves) by touch
What is this for? Why do you need to be so accurate? I would assume you only need something around 4 vertices stored for every inch the user drags his finger. With that in mind:
Try using one vertex out of every X to actually draw between, with the middle vertex used for specifying the weighted point of the curve.
int interval = 10; //how many points to skip
gesture.moveTo(gesture.get(0).x, gesture.get(0).y);
for(int i =0; i +interval/2 < gesture.size(); i+=interval)
{
Gesture ngp = gesture.get(i+interval/2);
gesturePath.quadTo(ngp.x,ngp.y, gp.x,gp.y);
}
You'll need to adjust this to actually work but the idea is there.

Calculating the angle between two lines without having to calculate the slope? (Java)

I have two Lines: L1 and L2. I want to calculate the angle between the two lines. L1 has points: {(x1, y1), (x2, y2)} and L2 has points: {(x3, y3), (x4, y4)}.
How can I calculate the angle formed between these two lines, without having to calculate the slopes? The problem I am currently having is that sometimes I have horizontal lines (lines along the x-axis) and the following formula fails (divide by zero exception):
arctan((m1 - m2) / (1 - (m1 * m2)))
where m1 and m2 are the slopes of line 1 and line 2 respectively. Is there a formula/algorithm that can calculate the angles between the two lines without ever getting divide-by-zero exceptions? Any help would be highly appreciated.
This is my code snippet:
// Calculates the angle formed between two lines
public static double angleBetween2Lines(Line2D line1, Line2D line2)
{
double slope1 = line1.getY1() - line1.getY2() / line1.getX1() - line1.getX2();
double slope2 = line2.getY1() - line2.getY2() / line2.getX1() - line2.getX2();
double angle = Math.atan((slope1 - slope2) / (1 - (slope1 * slope2)));
return angle;
}
Thanks.
The atan2 function eases the pain of dealing with atan.
It is declared as double atan2(double y, double x) and converts rectangular coordinates (x,y) to the angle theta from the polar coordinates (r,theta)
So I'd rewrite your code as
public static double angleBetween2Lines(Line2D line1, Line2D line2)
{
double angle1 = Math.atan2(line1.getY1() - line1.getY2(),
line1.getX1() - line1.getX2());
double angle2 = Math.atan2(line2.getY1() - line2.getY2(),
line2.getX1() - line2.getX2());
return angle1-angle2;
}
Dot product is probably more useful in this case. Here you can find a geometry package for Java which provides some useful helpers. Below is their calculation for determining the angle between two 3-d points. Hopefully it will get you started:
public static double computeAngle (double[] p0, double[] p1, double[] p2)
{
double[] v0 = Geometry.createVector (p0, p1);
double[] v1 = Geometry.createVector (p0, p2);
double dotProduct = Geometry.computeDotProduct (v0, v1);
double length1 = Geometry.length (v0);
double length2 = Geometry.length (v1);
double denominator = length1 * length2;
double product = denominator != 0.0 ? dotProduct / denominator : 0.0;
double angle = Math.acos (product);
return angle;
}
Good luck!
dx1 = x2-x1;
dy1 = y2-y1;
dx2 = x4-x3;
dy2 = y4-y3;
d = dx1*dx2 + dy1*dy2; // dot product of the 2 vectors
l2 = (dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2) // product of the squared lengths
angle = acos(d/sqrt(l2));
The dot product of 2 vectors is equal to the cosine of the angle time the length of both vectors. This computes the dot product, divides by the length of the vectors and uses the inverse cosine function to recover the angle.
Maybe my approach for Android coordinates system will be useful for someone (used Android PointF class to store points)
/**
* Calculate angle between two lines with two given points
*
* #param A1 First point first line
* #param A2 Second point first line
* #param B1 First point second line
* #param B2 Second point second line
* #return Angle between two lines in degrees
*/
public static float angleBetween2Lines(PointF A1, PointF A2, PointF B1, PointF B2) {
float angle1 = (float) Math.atan2(A2.y - A1.y, A1.x - A2.x);
float angle2 = (float) Math.atan2(B2.y - B1.y, B1.x - B2.x);
float calculatedAngle = (float) Math.toDegrees(angle1 - angle2);
if (calculatedAngle < 0) calculatedAngle += 360;
return calculatedAngle;
}
It return positive value in degrees for any quadrant: 0 <= x < 360
You can checkout my utility class here
The formula for getting the angle is tan a = (slope1-slope2)/(1+slope1*slope2)
You are using:
tan a = (slope1 - slope2) / (1 - slope1 * slope2)
So it should be:
double angle = Math.atan((slope1 - slope2) / (1 + slope1 * slope2));
First, are you sure the brackets are in the right order? I think (could be wrong) it should be this:
double slope1 = (line1.getY1() - line1.getY2()) / (line1.getX1() - line1.getX2());
double slope2 = (line2.getY1() - line2.getY2()) / (line2.getX1() - line2.getX2());
Second, there are two things you could do for the div by zero: you could catch the exception and handle it
double angle;
try
{
angle = Math.atan((slope1 - slope2) / (1 - (slope1 * slope2)));
catch (DivideByZeroException dbze)
{
//Do something about it!
}
...or you could check that your divisors are never zero before you attempt the operation.
if ((1 - (slope1 * slope2))==0)
{
return /*something meaningful to avoid the div by zero*/
}
else
{
double angle = Math.atan((slope1 - slope2) / (1 - (slope1 * slope2)));
return angle;
}
Check this Python code:
import math
def angle(x1,y1,x2,y2,x3,y3):
if (x1==x2==x3 or y1==y2==y3):
return 180
else:
dx1 = x2-x1
dy1 = y2-y1
dx2 = x3-x2
dy2 = y3-y2
if x1==x2:
a1=90
else:
m1=dy1/dx1
a1=math.degrees(math.atan(m1))
if x2==x3:
a2=90
else:
m2=dy2/dx2
a2=math.degrees(math.atan(m2))
angle = abs(a2-a1)
return angle
print angle(0,4,0,0,9,-6)
dx1=x2-x1 ; dy1=y2-y1 ; dx2=x4-x3 ;dy2=y4-y3.
Angle(L1,L2)=pi()/2*((1+sign(dx1))* (1-sign(dy1^2))-(1+sign(dx2))*(1-sign(dy2^2)))
+pi()/4*((2+sign(dx1))*sign(dy1)-(2+sign(dx2))*sign(dy2))
+sign(dx1*dy1)*atan((abs(dx1)-abs(dy1))/(abs(dx1)+abs(dy1)))
-sign(dx2*dy2)*atan((abs(dx2)-abs(dy2))/(abs(dx2)+abs(dy2)))

Categories