I have a point on a half circle that needs a line connecting it to the black half circle. The line goes through the origin of the orange circle (perpendicular). When moving along the upper circle, the length of the line changes. Is there a way to calculate a position for the arrow, so the green line has a length of a given value? None of the circles are necessarily at the origin.
No need to check if the green line does intersect the black circle, I already made sure that's the case.
For the length s of the line from the orange centre to the black circle you get the formula:
s^2 = (x + r * cos(a))^2 + (y + r * sin(a))^2
where x is the absolute value of the x-component of the centre of the black circle and y the corresponding y-component. r is the radius of the black circle. a is the angle of the intersection point on the black circle (normally there will be two solutions).
Expanding the given formula leads to:
s^2 = x * x + r * r * cos(a)^2 + 2* r * x * cos(a)
+ y * y + r * r * sin(a)^2 +2 *r * y * sin(a)
As
r * r * cos(a)^2 + r * r * sin(a)^2 = r * r
we have
s^2 - x^2 - y^2 - r^2 = 2 *r * (x * cos(a) + y * sin(a)) (1)
Dividing by 2*r and renaming the left side of the equation p (p contains known values only) results in
p = x * cos(a) + y * sin(a) = SQRT(x * x + y * y) * sin(a + atan(x / y))
==>
a = asin(p /SQRT(x*x + y*y)) + atan(x / y) (2)
Let's have an example with approximate values taken from your drawing:
x = 5
y = -8
r = 4
s = 12
Then (1) will be
144 = 25 + 16 + 64 + 8 * (5 * cos(a) - 8 * sin(a)) ==>
39 / 8 = 5 * cos(a) - 8 * sin(a) =
SQRT(25 + 64) * sin(a + atan(5 / -8)) ==>
0.5167 = sin(a + atan(5 / -8))
asin(0.5167) = a - 212°
asin(0.5167) has two values, the first one is 31.11°, the second one is 148.89°. This leads to the two solutions for a:
a1 = 243.11°
a2 = 360.89° or taking this value modulo 360° ==> 0.89°
I just found a much simpler solution using the Law of cosines:
c * c = a * a + b * b - 2ab * cos(gamma)
You got a triangle defined by three points: the centre points of both circles and the point of intersection on the black circle. The lengths of all three sides are known.
So we get:
cos(gamma) = (a * a + b * b - c * c) / 2ab
If we choose the angle at centre of orange circle to be gamma we get
a = sqrt(89) = 9.434 (distance between the centres of both circles)
b = 12 (distance between centre of orange circle and point if intersection
c = 4 (radius of black circle)
Using this values we get:
cos(gamma) = (89 + 144 - 16) / (2 * sqrt(89) * 12) = 0.9584
gamma = acos(0.9584) = +/- 16.581°
´
Assuming I have a spaceship (source); And an asteroid (target) is somewhere near it.
I know, in 3D space (XYZ vectors):
My ship's position (sourcePos) and velocity (sourceVel).
The asteroid's position (targetPos) and velocity (targetVel).
(eg. sourcePos = [30, 20, 10]; sourceVel = [30, 20, 10]; targetPos = [600, 400, 200]; targetVel = [300, 200, 100]`)
I also know that:
The ship's velocity is constant.
The asteroid's velocity is constant.
My ship's projectile speed (projSpd) is constant.
My ship's projectile trajectory, after being shot, is linear (/straight).
(eg. projSpd = 2000.00)
How can I calculate the interception coordinates I need to shoot at in order to hit the asteroid?
Notes:
This question is based on this Yahoo - Answers page.
I also searched for similar problems on Google and here on SO, but most of the answers are for 2D-space, and, of the few for 3D, neither the explanation nor the pseudo-codes explain what is doing what and/or why, so I couldn't really understand enough to apply them on my code successfully. Here are some of the pages I visited:
Danik Games Devlog, Blitz3D Forums thread, UnityAnswers, StackOverflow #1, StackOverflow #2
I really can't figure out the maths / execution-flow on the linked pages as they are, unless someone dissects it (further) into what is doing what, and why;
Provides a properly-commented pseudo-code for me to follow;
Or at least points me to links that actually explain how the equations work instead of just throwing even more random numbers and unfollowable equations in my already-confused psyche.
I find the easiest approach to these kind of problems to make sense of them first, and have a basic high school level of maths will help too.
Solving this problem is essentially solving 2 equations with 2 variables which are unknown to you:
The vector you want to find for your projectile (V)
The time of impact (t)
The variables you know are:
The target's position (P0)
The target's vector (V0)
The target's speed (s0)
The projectile's origin (P1)
The projectile's speed (s1)
Okay, so the 1st equation is basic. The impact point is the same for both the target and the projectile. It is equal to the starting point of both objects + a certain length along the line of both their vectors. This length is denoted by their respective speeds, and the time of impact. Here's the equation:
P0 + (t * s0 * V0) = P1 + (t * s0 * V)
Notice that there are two missing variables here - V & t, and so we won't be able to solve this equation right now. On to the 2nd equation.
The 2nd equation is also quite intuitive. The point of impact's distance from the origin of the projectile is equal to the speed of the projectile multiplied by the time passed:
We'll take a mathematical expression of the point of impact from the 1st equation:
P0 + (t * s0 * V0) <-- point of impact
The point of origin is P1
The distance between these two must be equal to the speed of the projectile multiplied by the time passed (distance = speed * time).
The formula for distance is: (x0 - x1)^2 + (y0 - y1)^2 = distance^2, and so the equation will look like this:
((P0.x + s0 * t * V0.x) - P1.x)^2 + ((P0.y + s0 * t * V0.y) - P1.y)^2 = (s1 * t)^2
(You can easily expand this for 3 dimensions)
Notice that here, you have an equation with only ONE unknown variable: t!. We can discover here what t is, then place it in the previous equation and find the vector V.
Let me solve you some pain by opening up this formula for you (if you really want to, you can do this yourself).
a = (V0.x * V0.x) + (V0.y * V0.y) - (s1 * s1)
b = 2 * ((P0.x * V0.x) + (P0.y * V0.y) - (P1.x * V0.x) - (P1.y * V0.y))
c = (P0.x * P0.x) + (P0.y * P0.y) + (P1.x * P1.x) + (P1.y * P1.y) - (2 * P1.x * P0.x) - (2 * P1.y * P0.y)
t1 = (-b + sqrt((b * b) - (4 * a * c))) / (2 * a)
t2 = (-b - sqrt((b * b) - (4 * a * c))) / (2 * a)
Now, notice - we will get 2 values for t here.
One or both may be negative or an invalid number. Obviously, since t denotes time, and time can't be invalid or negative, you'll need to discard these values of t.
It could very well be that both t's are bad (in which case, the projectile cannot hit the target since it's faster and out of range). It could also be that both t's are valid and positive, in which case you'll want to choose the smaller of the two (since it's preferable to hit the target sooner rather than later).
t = smallestWhichIsntNegativeOrNan(t1, t2)
Now that we've found the time of impact, let's find out what the direction the projectile should fly is. Back to our 1st equation:
P0 + (t * s0 * V0) = P1 + (t * s0 * V)
Now, t is no longer a missing variable, so we can solve this quite easily. Just tidy up the equation to isolate V:
V = (P0 - P1 + (t * s0 * V0)) / (t * s1)
V.x = (P0.x - P1.x + (t * s0 * V0.x)) / (t * s1)
V.y = (P0.y - P1.y + (t * s0 * V0.y)) / (t * s1)
And that's it, you're done!
Assign the vector V to the projectile and it will go to where the target will be rather than where it is now.
I really like this problem since it takes math equations we learnt in high school where everyone said "why are learning this?? we'll never use it in our lives!!", and gives them a pretty awesome and practical application.
I hope this helps you, or anyone else who's trying to solve this.
If you want a projectile to hit asteroid, it should be shoot at the point interceptionPos that satisfy the equation:
|interceptionPos - sourcePos| / |interceptionPos - targetPos| = projSpd / targetVel
where |x| is a length of vector x.
In other words, it would take equal amount of time for the target and the projectile to reach this point.
This problem would be solved by means of geometry and trigonometry, so let's draw it.
A will be asteroid position, S - ship, I - interception point.
Here we have:
AI = targetVel * t
SI = projSpd * t
AS = |targetPos - sourcePos|
vector AS and AI direction is defined, so you can easily calculate cosine of the SAI angle by means of simple vector math (take definitions from here and here). Then you should use the Law of cosines with the SAI angle. It will yield a quadratic equation with variable t that is easy to solve (no solutions = your projectile is slower than asteroid). Just pick the positive solution t, your point-to-shoot will be
targetPos + t * targetVel
I hope you can write a code to solve it by yourself. If you cannot get something please ask in comments.
I got a solution. Notice that the ship position, and the asteroid line (position and velocity) define a 3D plane where the intercept point lies. In my notation below | [x,y,z] | denotes the magnitude of the vector or Sqrt(x^2+y^2+z^2).
Notice that if the asteroid travels with targetSpd = |[300,200,100]| = 374.17 then to reach the intercept point (still unknown, called hitPos) will require time equal to t = |hitPos-targetPos|/targetSpd. This is the same time the projectile needs to reach the intercept point, or t = |hitPos - sourcePos|/projSpd. The two equations are used to solve for the time to intercept
t = |targetPos-sourcePos|/(projSpd - targetSpd)
= |[600,400,200]-[30,20,10]|/(2000 - |[300,200,100]|)
= 710.81 / ( 2000-374.17 ) = 0.4372
Now the location of the intetception point is found by
hitPos = targetPos + targetVel * t
= [600,400,200] + [300,200,100] * 0.4372
= [731.18, 487.45, 243.73 ]
Now that I know the hit position, I can calculate the direction of the projectile as
projDir = (hitPos-sourcePos)/|hitPos-sourcePos|
= [701.17, 467.45, 233.73]/874.52 = [0.8018, 0.5345, 0.2673]
Together the projDir and projSpd define the projectile velocity vector.
Credit to Gil Moshayof's answer, as it really was what I worked off of to build this. But they did two dimensions, and I did three, so I'll share my Unity code in case it helps anyone along. A little long winded and redundant. It helps me to read it and know what's going on.
Vector3 CalculateIntercept(Vector3 targetLocation, Vector3 targetVelocity, Vector3 interceptorLocation, float interceptorSpeed)
{
Vector3 A = targetLocation;
float Ax = targetLocation.x;
float Ay = targetLocation.y;
float Az = targetLocation.z;
float As = targetVelocity.magnitude;
Vector3 Av = Vector3.Normalize(targetVelocity);
float Avx = Av.x;
float Avy = Av.y;
float Avz = Av.z;
Vector3 B = interceptorLocation;
float Bx = interceptorLocation.x;
float By = interceptorLocation.y;
float Bz = interceptorLocation.z;
float Bs = interceptorSpeed;
float t = 0;
float a = (
Mathf.Pow(As, 2) * Mathf.Pow(Avx, 2) +
Mathf.Pow(As, 2) * Mathf.Pow(Avy, 2) +
Mathf.Pow(As, 2) * Mathf.Pow(Avz, 2) -
Mathf.Pow(Bs, 2)
);
if (a == 0)
{
Debug.Log("Quadratic formula not applicable");
return targetLocation;
}
float b = (
As * Avx * Ax +
As * Avy * Ay +
As * Avz * Az +
As * Avx * Bx +
As * Avy * By +
As * Avz * Bz
);
float c = (
Mathf.Pow(Ax, 2) +
Mathf.Pow(Ay, 2) +
Mathf.Pow(Az, 2) -
Ax * Bx -
Ay * By -
Az * Bz +
Mathf.Pow(Bx, 2) +
Mathf.Pow(By, 2) +
Mathf.Pow(Bz, 2)
);
float t1 = (-b + Mathf.Pow((Mathf.Pow(b, 2) - (4 * a * c)), (1 / 2))) / (2 * a);
float t2 = (-b - Mathf.Pow((Mathf.Pow(b, 2) - (4 * a * c)), (1 / 2))) / (2 * a);
Debug.Log("t1 = " + t1 + "; t2 = " + t2);
if (t1 <= 0 || t1 == Mathf.Infinity || float.IsNaN(t1))
if (t2 <= 0 || t2 == Mathf.Infinity || float.IsNaN(t2))
return targetLocation;
else
t = t2;
else if (t2 <= 0 || t2 == Mathf.Infinity || float.IsNaN(t2) || t2 > t1)
t = t1;
else
t = t2;
Debug.Log("t = " + t);
Debug.Log("Bs = " + Bs);
float Bvx = (Ax - Bx + (t * As + Avx)) / (t * Mathf.Pow(Bs, 2));
float Bvy = (Ay - By + (t * As + Avy)) / (t * Mathf.Pow(Bs, 2));
float Bvz = (Az - Bz + (t * As + Avz)) / (t * Mathf.Pow(Bs, 2));
Vector3 Bv = new Vector3(Bvx, Bvy, Bvz);
Debug.Log("||Bv|| = (Should be 1) " + Bv.magnitude);
return Bv * Bs;
}
I followed the problem formulation as described by Gil Moshayof's answer, but found that there was an error in the simplification of the quadratic formula. When I did the derivation by hand I got a different solution.
The following is what worked for me when finding the intersect in 2D:
std::pair<double, double> find_2D_intersect(Vector3 sourcePos, double projSpd, Vector3 targetPos, double targetSpd, double targetHeading)
{
double P0x = targetPos.x;
double P0y = targetPos.y;
double s0 = targetSpd;
double V0x = std::cos(targetHeading);
double V0y = std::sin(targetHeading);
double P1x = sourcePos.x;
double P1y = sourcePos.y;
double s1 = projSpd;
// quadratic formula
double a = (s0 * s0)*((V0x * V0x) + (V0y * V0y)) - (s1 * s1);
double b = 2 * s0 * ((P0x * V0x) + (P0y * V0y) - (P1x * V0x) - (P1y * V0y));
double c = (P0x * P0x) + (P0y * P0y) + (P1x * P1x) + (P1y * P1y) - (2 * P1x * P0x) - (2 * P1y * P0y);
double t1 = (-b + std::sqrt((b * b) - (4 * a * c))) / (2 * a);
double t2 = (-b - std::sqrt((b * b) - (4 * a * c))) / (2 * a);
double t = choose_best_time(t1, t2);
double intersect_x = P0x + t * s0 * V0x;
double intersect_y = P0y + t * s0 * V0y;
return std::make_pair(intersect_x, intersect_y);
}
I’ve written the below python script. The idea is to calculate the new location of point C after you rotate the globe from point A to point B. I first calculate point P, which is the rotation pole. With calculating point P already something goes wrong. With the following input f.e. I would assume point P to be having latitude 90 or –90.
I asked this question before here: Rotate a sphere from coord1 to coord2, where will coord3 be?
But I figured it's better to ask again with the script included ;)
# GreatCircle can be downloaded from: http://www.koders.com/python/fid0A930D7924AE856342437CA1F5A9A3EC0CAEACE2.aspx?s=coastline
from GreatCircle import *
from math import *
# Points A and B defining the rotation:
LonA = radians(0)
LatA = radians(1)
LonB = radians(45)
LatB = radians(1)
# Point C which will be translated:
LonC = radians(90)
LatC = radians(1)
# The following equation is described here: http://articles.adsabs.harvard.edu//full/1953Metic...1...39L/0000040.000.html
# It calculates the rotation pole at point P of the Great Circle defined by point A and B.
# According to http://www.tutorialspoint.com/python/number_atan2.htm
# atan2(x, y) = atan(y / x)
LonP = atan2(((sin(LonB) * tan(LatA)) - (sin(LonA) * tan(LatB))), ((cos(LonA) * tan(LatB)) - (cos(LonB) * tan(LatA))))
LatP = atan2(-tan(LatA),(cos(LonP - LonA)))
print degrees(LonP), degrees(LatP)
# The equations to calculate the translated point C location were found here: http://www.uwgb.edu/dutchs/mathalgo/sphere0.htm
# The Rotation Angle in radians:
gcAP = GreatCircle(1,1,degrees(LonA),degrees(LatA),degrees(LonP),degrees(LatP))
gcBP = GreatCircle(1,1,degrees(LonB),degrees(LatB),degrees(LonP),degrees(LatP))
RotAngle = abs(gcAP.azimuth12 - gcBP.azimuth12)
# The rotation pole P in Cartesian coordinates:
Px = cos(LatP) * cos(LonP)
Py = cos(LatP) * sin(LonP)
Pz = sin(LatP)
# Point C in Cartesian coordinates:
Cx = cos(radians(LatC)) * cos(radians(LonC))
Cy = cos(radians(LatC)) * sin(radians(LonC))
Cz = sin(radians(LatC))
# The translated point P in Cartesian coordinates:
NewCx = (Cx * cos(RotAngle)) + (1 - cos(RotAngle)) * (Px * Px * Cx + Px * Py * Cy + Px * Pz * Cz) + (Py * Cz - Pz * Cy) * sin(RotAngle)
NewCy = (Cy * cos(RotAngle)) + (1 - cos(RotAngle)) * (Py * Px * Cx + Py * Py * Cy + Py * Pz * Cz) + (Pz * Cx - Px * Cz) * sin(RotAngle)
NewCz = (Cz * cos(RotAngle)) + (1 - cos(RotAngle)) * (Pz * Px * Cx + Pz * Py * Cy + Pz * Pz * Cz) + (Px * Cy - Py * Cx) * sin(RotAngle)
# The following equation I got from http://rbrundritt.wordpress.com/2008/10/14/conversion-between-spherical-and-cartesian-coordinates-systems/
# The translated point P in lat/long:
Cr = sqrt((NewCx*NewCx) + (NewCy*NewCy) + (NewCz*NewCz))
NewCLat = degrees(asin(NewCz/Cr))
NewCLon = degrees(atan2(NewCy, NewCx))
# Output:
print str(NewCLon) + "," + str(NewCLat)
I am trying to calculate the tangent line (needed for bump mapping) for every vertex in my mesh. The v1, v2 and v3 are the vertices in the triangle and the t1, t2 and t3 are the respective texture coords. From what i understand this should output the tangent line for the three vertices of the triangle.
Vec3f va = Vec3f{vertexData[a * 3 + 0], vertexData[a * 3 + 1], vertexData[a * 3 + 2]};
Vec3f vb = Vec3f{vertexData[b * 3 + 0], vertexData[b * 3 + 1], vertexData[b * 3 + 2]};
Vec3f vc = Vec3f{vertexData[c * 3 + 0], vertexData[c * 3 + 1], vertexData[c * 3 + 2]};
Vec2f ta = (Vec2f){texcoordData[a * 2 + 0],texcoordData[a * 2 + 1]};
Vec2f tb = (Vec2f){texcoordData[b * 2 + 0],texcoordData[b * 2 + 1]};
Vec2f tc = (Vec2f){texcoordData[c * 2 + 0],texcoordData[c * 2 + 1]};
Vec3f v1 = subtractVec3f(vb, va);
Vec3f v2 = subtractVec3f(vc, va);
Vec2f t1 = subtractVec2f(tb, ta);
Vec2f t2 = subtractVec2f(tc, ta);
float coef = 1/(t1.u * t2.v - t1.v * t2.u);
Vec3f tangent = Vec3fMake((t2.v * v1.x - t1.v * v2.x) * coef,
(t2.v * v1.y - t1.v * v2.y) * coef,
(t2.v * v1.z - t1.v * v2.z) * coef);
My problem is that the coef variable is sometimes the nan (not a number) value causing the multiplication to be off. My mesh is not super complex, a simple cylinder, but i would like a universal formula to calculate the tangent line to enable bump mapping on all of my meshes.
coef becomming a NaN indicates some numerical problem with your input data, like degenerate triangles or texture coordinates. Make sure that the expression (t1.u * t2.v - t1.v * t2.u) doesn't (nearly) vanish, i.e. its absolute value is larger than some reasonable threshold value.
A good sanity check is |vb-va|>0 ^ |vc-va|>0, |tb-ta|>0 ^ |tc-ta|>0, |normalized(vb-va) . normalized(vc-va)| < 1 and |normalized(tb-ta) . normalized(tc-ta)| < 1.
The length of three sides of the triangle, a, b and c will be given, and I need to find the coordinates of the vertices. The center (probably the circumcenter) can either be the origin or (x,y).
Can anyone point me in the right direction?
I've read brainjam's answer and checked whether his answer is true and he is right.
Calculation:
O(0;0), A(a;0) and B(x;y) are the three points of the triangle. C1 is the circle around A and r1 = c; C2 is the circle around O and r2 = b. B(X;Y) is the intersection of C1 and C2, which means that the point is on both of the circles.
C1: (x - a) * (x - a) + y * y = c * c
C2: x * x + y * y = b * b
y * y = b * b - x * x
(x - a) * (x - a) + b * b - x * x = c * c
x * x - 2 * a * x + a * a + b * b - x * x - c * c = 0
2 * a * x = (a * a + b * b - c * c)
x = (a * a + b * b - c * c) / (2 * a)
y * y = b * b - ((a * a + b * b - c * c) / (2 * a)) * ((a * a + b * b - c * c) / (2 * a))
y = +- sqrt(b * b - ((a * a + b * b - c * c) / (2 * a)) * ((a * a + b * b - c * c) / (2 * a)))
Place the first vertex at the origin (0,0). Place the second vertex at (a,0). To compute the third vertex, find the intersection of the two circles with centers (0,0) and (a,0) and radii b and c.
Update: Lajos Arpad has given the details of computing the location of the third point in this answer. It boils down to (x,y) where x = (b2+a2-c2)/2a and y=±sqrt(b2-x2)
This question and the answers helped me out today in implementing this. It will calculate the unknown vertices, "c" of circle intersections given 2 known points (a, b) and the distances (ac_length, bc_length) to the 3rd unknown vertex, "c".
Here is my resulting python implementation for anyone interested.
I also referenced the following:
http://mathworld.wolfram.com/RadicalLine.html
http://mathworld.wolfram.com/Circle-CircleIntersection.html
Using django's geos module for the Point() object, which could be replaced with shapely, or point objects removed altogether really.
from math import sqrt
from django.contrib.gis.geos import Point
class CirclesSeparate(BaseException):
pass
class CircleContained(BaseException):
pass
def discover_location(point_a, point_b, ac_length, bc_length):
"""
Find point_c given:
point_a
point_b
ac_length
bc_length
point_d == point at which the right-angle to c is formed.
"""
ab_length = point_a.distance(point_b)
if ab_length > (ac_length + bc_length):
raise CirclesSeparate("Given points do not intersect!")
elif ab_length < abs(ac_length - bc_length):
raise CircleContained("The circle of the points do not intersect")
# get the length to the vertex of the right triangle formed,
# by the intersection formed by circles a and b
ad_length = (ab_length**2 + ac_length**2 - bc_length**2)/(2.0 * ab_length)
# get the height of the line at a right angle from a_length
h = sqrt(abs(ac_length**2 - ad_length**2))
# Calculate the mid point (point_d), needed to calculate point_c(1|2)
d_x = point_a.x + ad_length * (point_b.x - point_a.x)/ab_length
d_y = point_a.y + ad_length * (point_b.y - point_a.y)/ab_length
point_d = Point(d_x, d_y)
# get point_c location
# --> get x
c_x1 = point_d.x + h * (point_b.y - point_a.y)/ab_length
c_x2 = point_d.x - h * (point_b.y - point_a.y)/ab_length
# --> get y
c_y1 = point_d.y - h * (point_b.x - point_a.x)/ab_length
c_y2 = point_d.y + h * (point_b.x - point_a.x)/ab_length
point_c1 = Point(c_x1, c_y1)
point_c2 = Point(c_x2, c_y2)
return point_c1, point_c2
When drawing an unknown triangle, it's usually easiest to pick one side (say, the longest) and place it horizontally or vertically. The endpoints of that side make up two of the triangle's vertices, and you can calculate the third by subdividing the triangle into two right triangles (the other two sides are the hypotenuses) and using the inverse sine/cosine functions to figure out the missing angles. By subdividing into right triangles, I mean something that looks like the image here: http://en.wikipedia.org/wiki/File:Triangle.TrigArea.svg Your first side would be AC in that drawing.
Once you have the triangle figured out, it should be easy to calculate it's center and translate it so that it is centered on whatever arbitrary center point you like.
First check the that the triangle is possible:
a+b >= c
b+c >= a
c+a >= b
Then, if it is, solve for the intersection of the two circles. The basic vertices are
{0,0}, {a,0}, {x,y}
where
x = (a^2-b^2+c^2)/(2a)
y = sqrt(c^2-x^2)
Finding the circumcenter is pretty easy from this point.