Intersection points of oval and line - math

Using this function to draw a "Circle", I really come up with something of an oval. This is because of malformed pixels I am working with that aren't really relevant other than they make this function necessary.
local function drawCircle( centerX, centerY, radius, col, solid )
solid = solid or false
local isAdvanced = term.isColor and term.isColor()
local char = isAdvanced and " " or "|"
if isAdvanced then term.setBackgroundColor( col ) end
local radStep = 1/(1.5*radius)
for angle = 1, math.pi+radStep, radStep do
local pX = math.cos( angle ) * radius * 1.5
local pY = math.sin( angle ) * radius
if solid then
local chord = 2*math.abs(pX)
term.setCursorPos( centerX - chord/2, centerY - pY )
write( char:rep( chord ) )
term.setCursorPos( centerX - chord/2, centerY + pY )
write( char:rep( chord ) )
else
for i=-1,1,2 do
for j=-1,1,2 do
term.setCursorPos( centerX + i*pX, centerY + j*pY )
write( char )
end
end
end
end
end
Now, I'm making a game that involves planets (ei the circle), but because of limitations I can only run it at 10 FPS. I end up with so much acceleration in the game that the ship can move faster per 10th of a second than the diameter of the "circle", so I'm looking for a simple (and hopefully fast) way to calculate if the ship will hit the planet when it magically teleports between point A and point B.
As an example, lets say I have my ship at 75, 100 and it's momentum will move it +80, -50. It'll end up at 155, 50. Between those two points is my planet, but how do I detect it?
I've googled a bit, but didn't come up with anything I could comprehend. I'm in 11th grade math, just solving systems of equations, although I'm also in engineering classes, where I learned force vectors.
If it helps, the planet doesn't move.

You have two equations:
(1) The circle:
(k*x)^2 + y^2 = r^2
(The 'k' squeezes the graph to achieve an oval. In your case k = 2/3. There's a site "Purple Math" with a chapter on "Transformations". Read it.)
(2) The line:
a*x + b*y = c
Now, you'll notice that, for simplicity, I assumed the circle's center is at the origin. In your case it usually isn't, so you'll simply shift the line's start and end points to match it. (It doesn't matter where objects are: it only matters where they're in relation to each other. So we're allowed to move objects as a group up/down right/left however we want.)
So we have two equations. "Solving them" = "finding the points where they touch" = "collision". So we need to solve them. To solve them you find y from equation (2) and replace it in equation (1). You get an equation with only x (and x^2):
.... x ... x^2 .... = ....
You arrange ("factor") this equation on x:
x^2(b^2 k^2 + a^2) + x(-2ac) + c^2 - r^2 b^2 = 0
That's a quadratic formula.
Now, you're asking whether the oval and line intersect ("calculate if the ship will hit the planet"). In other words, you're asking whether there's any solution to this equation (you're not asking for the solutions themselves). There's a solution if the discriminant is greater/equal to zero. The discriminant is "B^2 - 4AC", where:
A = b^2 k^2 + a^2
B = -2ac
C = c^2 - r^2 b^2
So "B^2 - 4AC" is:
4*b^2*(a^2*r^2+b^2*r^2*k^2-k^2*c^2)
That's all!
It's a simple expression.
You know b,a,r,k,c, so you put them in that expression and if it's greater/equal to zero you know there's a collision.
If you don't understand my explanation, install GeoGebra, then type into it:
k = 0.5
r = 1
circ: (k x)² + y² = r²
a = 5
b = -2.5
c = 4
line: a x + b y = c
dis = 4a² b² r² + 4b⁴ k² r² - 4b² c² k²
Now, make k/r/a/b/c sliders and change their values with your mouse. You'll notice that when there's a collision, "dis" (the discriminant) is negative.
Finally, what you've left to do:
You need to write a function that gets the circle and line and tells if there's a collision:
function do_collide(
-- the circle:
centerX, centerY, radius,
-- the line:
x1, y1, x2, y2)
-- Step 1:
-- You already know r and k.
-- Step 2:
-- Shift the coordinates (x1,x2) and (x2,y2) by (centerX, centerY).
-- Find the line equation and you have a,b,c.
-- Step 3:
return 4*b^2*(a^2*r^2+b^2*r^2*k^2-k^2*c^2) >= 0
end

Related

How to efficiently compute the future position of a point that will move in a box and bounce on its walls (2D)?

I have a simple maths/physics problem here: In a Cartesian coordinate system, I have a point that moves in time with a known velocity. The point is inside a box, and bounces orthognally on its walls.
Here is a quick example I did on paint:
What we know: The red point position, and its velocity which is defined by an angle θ and a speed. Of course we know the dimensions of the green box.
On the example, I've drawn in yellow its approximate trajectory, and let's say that after a determined period of time which is known, the red point is on the blue point. What would be the most efficient way to compute the blue point position?
I've tought about computing every "bounce point" with trigonometry and vector projection, but I feel like it's a waste of resources because trigonometric functions are usually very processor hungry. I'll have more than a thousand points to compute like that so I really need to find a more efficient way to do it.
If anyone has any idea, I'd be very grateful.
Apart from programming considerations, it has an interesting solution from geometric point of view. You can find the position of the point at a specific time T without considering its temporal trajectory during 0<t<T
For one minute, forget the size and the boundaries of the box; and assume that the point can move on a straight line for ever. Then the point has constant velocity components vx = v*cos(θ), vy = v*sin(θ) and at time T its virtual porition will be x' = x0 + vx * T, y' = y0 + vy * T
Now you need to map the virtual position (x',y') into the actual position (x,y). See image below
You can recursively reflect the virtual point w.r.t the borders until the point comes back into the reference (initial) box. And this is the actual point. Now the question is how to do these mathematics? and how to find (x,y) knowing (x',y')?
Denote by a and b the size of the box along x and y respectively. Then nx = floor(x'/a) and ny = floor(y'/b) indicates how far is the point from the reference box in terms of the number of boxes. Also dx = x'-nx*a and dy = y'-ny*b introduces the relative position of the virtual point inside its virtual box.
Now you can find the true position (x,y): if nx is even, then x = dx else x = a-dx; similarly if ny is even, then y = dy else y = b-dy. In other words, even number of reflections in each axis x and y, puts the true point and the virtual point in the same relative positions, while odd number of reflections make them different and complementary.
You don't need to use trigonometric function all the time. Instead get normalized direction vector as (dx, dy) = (cos(θ), sin(θ))
After bouncing from vertical wall x-component changes it's sign dx = -dx, after bouncing from horizontal wall y-component changes it's sign dy = -dy. You can see that calculations are blazingly simple.
If you (by strange reason) prefer to use angles, use angle transformations from here (for ball with non-zero radius)
if ((ball.x + ball.radius) >= window.width || (ball.x - ball.radius) <= 0)
ball.theta = M_PI - ball.theta;
else
if ((ball.y + ball.radius) >= window.height || (ball.y - ball.radius) <= 0)
ball.theta = - ball.theta;
To get point of bouncing:
Starting point (X0, Y0)
Ray angle Theta, c = Cos(Theta), s = Sin(Theta);
Rectangle coordinates: bottom left (X1,Y1), top right (X2,Y2)
if c >= 0 then //up
XX = X2
else
XX = X1
if s >= 0 then //right
YY = Y2
else
YY = Y1
if c = 0 then //vertical ray
return Intersection = (X0, YY)
if s = 0 then //horizontal ray
return Intersection = (XX, Y0)
tx = (XX - X0) / c //parameter when vertical edge is met
ty = (YY - Y0) / s //parameter when horizontal edge is met
if tx <= ty then //vertical first
return Intersection = (XX, Y0 + tx * s)
else //horizontal first
return Intersection = (X0 + ty * c, YY)

what am I doing wrong in this equation?

I am trying to make a function that if a point is outside a certain circle, the point move to the point where the line passing by the center of the circle and the point collide. the code:
def inside_circle(self, pos):
if ((pos[0]-self.pos[0])**2 + (pos[1]-self.pos[1])**2) <= teleport_range**2:
return "inside"#pos
else:
pente = (pos[1]-self.pos[1])/(pos[0]-self.pos[0])
origine = pos[1]-pente*pos[0]
A = pente**2 + 1
B = 2 * -self.pos[0] + (origine+self.pos[1])*pente*2
C = self.pos[0]**2 + (origine+self.pos[1])**2 - teleport_range**2
if pos[0] > self.pos[0]:
X = (-B + math.sqrt(B**2 - 4*A*C))/(2*A)
Y = pente * X + origine
return "outside bot"#(X,Y)
elif pos[0] < self.pos[0]:
X = (-B - math.sqrt(B**2 - 4*A*C))/(2*A)
Y = pente * X + origine
return "outside top"#(X,Y)
self.pos is the center of the circle, pos is where the point I wanna check is, both are tuple
pente is the tilt of the line (its in french sorry)
origine is the Y origin of the line (french also)
teleport_range is the radius, being a constant 300
the actual return I want are commented for testing purposes
When I run it, if it is inside the circle, everythings fine but if it is outside, an error show up because it is trying to square root a negative
X = (-B + math.sqrt(B**2 - 4*A*C))/(2*A)
ValueError: math domain error
the square root in the quadratic equation is only negative when there is no collide point between the line and the circle, however, the line pass by the center of the circle and a point, so there should be two collide point.
I know there can be only one collide point when the line is a constant but I will fix that when I understand why (B**2 - 4*A*C) is negative when it shouldnt
I am not good in math, if someone could help me please, also dont hesitate to tell me if the code could be simplified without loosing clarity
thanks :)
Here is an easier, shorter, clearer way to get your desired point on the circle.
theta = math.atan2(pos[0] - self.pos[0], pos[1] - self.pos[1])
X = self.pos[0] + teleport_range * math.cos(theta)
Y = self.pos[1] + teleport_range * math.sin(theta)
This code first finds the angle of inclination of the ray from the circle's center to the point. It then uses that angle to find a point on the circle with the same angle.
Note that this code even works for points inside the circle: it finds the point on the circle with the same angle from the center. If the point is the circle's center, the desired point is ambiguous but the code returns one particular point.

Position of a point in a circle

Hello again first part is working like a charm, thank you everyone.
But I've another question...
As I've no interface, is there a way to do the same thing with out not knowing the radius of the circle?
Should have refresh the page CodeMonkey solution is exactly what I was looking for...
Thank you again.
============================
First I'm not a developer, I'm a simple woodworker that left school far too early...
I'm trying to make one of my tool to work with an autonomous robot.
I made them communicate by reading a lot of tutorials.
But I have one problem I cant figure out.
Robot expect position of the tool as (X,Y) but tool's output is (A,B,C)
A is the distance from tool to north
B distance to east
C distance at 120 degree clockwise from east axe
the border is a circle, radius may change, and may or may not be something I know.
I've been on that for 1 month, and I can't find a way to transform those value into the position.
I made a test with 3 nails on a circle I draw on wood, and if I have the distance there is only one position possible, so I guess its possible.
But how?
Also, if someone as an answer I'd love pseudo code not code so I can practice.
If there is a tool to make a drawing I can use to make it clearer can you point it out to me?
Thank you.
hope it helps :
X, Y are coordinate from center, Da,Db, Dc are known.
Trying to make it more clear (sorry its so clear in my head).
X,Y are the coordinate of the point where is the tool (P).
Center is at 0,0
A is the point where vertical line cut the circle from P, with Da distance P to A;
B is the point where horizontal line cuts the circle fom P, with Db distance P to B.
C is the point where the line at 120 clockwise from horizontal cuts the circle from P, with Dc distance P to C.
Output from tool is an array of int (unit mm): A=123, B=114, C=89
Those are the only informations I have
thanks for all the ideas I'll try them at home later,
Hope it works :)
Basic geometry. I decided to give up having the circle at the origin. We don't know the center of the circle yet. What you do have, is three points on that circle. Let's try having the tool's position, given as P, as the new (0,0). This thus resolves to finding a circle given three points: (0, Da); (Db,0), and back off at 120° at Dc distance.
Pseudocode:
Calculate a line from A to B: we'll call it AB. Find AB's halfway point. Calculate a line perpendicular to AB, through that midpoint (e.g. the cross product of AB and a unit Z axis finds the perpendicular vector).
Calculate a line from B to C (or C to A works just as well): we'll call it BC. Find BC's halfway point. Calculate a line perpendicular to BC, through that midpoint.
Calculate where these two lines cross. This will be the origin of your circle.
Since P is at (0,0), the negative of your circle's origin will be your tool's coordinates relative to the circle's origin. You should be able to calculate anything you need relative to that, now.
Midpoint between two points: X=(X1+X2)/2. Y=(Y1+Y2)/2.
The circle's radius can be calculated using, e.g. point A and the circle's origin: R=sqrt(sqr((Ax-CirX)+sqr(Ay-CirY))
Distance from the edge: circle's radius - tool's distance from the circle's center via Pythagorean Theorem again.
Assume you know X and Y. R is the radius of the circle.
|(X, Y + Da)| = R
|(X + Db, Y)| = R
|(X - cos(pi/3) * Dc, Y - cos(pi/6) * Dc)| = R
Assuming we don't know the radius R. We can still say
|(X, Y + Da)|^2 = |(X + Db, Y)|^2
=> X^2 + (Y+Da)^2 = (X+Db)^2 + Y^2
=> 2YDa + Da^2 = 2XDb + Db^2 (I)
and denoting cos(pi/3)*Dc as c1 and cos(pi/6)*Dc as c2:
|(X, Y + Da)|^2 = |(X - c1, Y - c2)|^2
=> X^2 + Y^2 + 2YDa + Da^2 = X^2 - 2Xc1 + c1^2 + Y^2 - 2Yc2 + c2^2
=> 2YDa + Da^2 = - 2Xc1 + c1^2 - 2Yc2 + c2^2
=> Y = (-2Xc1 + c1^2 + c2^2 - Da^2) / 2(c2+Da) (II)
Putting (II) back in the equation (I) we get:
=> (-2Xc1 + c1^2 + c2^2 - Da^2) Da / (c2+Da) + Da^2 = 2XDb + Db^2
=> (-2Xc1 + c1^2 + c2^2 - Da^2) Da + Da^2 * (c2+Da) = 2XDb(c2+Da) + Db^2 * (c2+Da)
=> (-2Xc1 + c1^2 + c2^2) Da + Da^2 * c2 = 2XDb(c2+Da) + Db^2 * (c2+Da)
=> X = ((c1^2 + c2^2) Da + Da^2 * c2 - Db^2 * (c2+Da)) / (2Dbc2 + 2Db*Da + 2Dac1) (III)
Knowing X you can get Y by calculating (II).
You can also make some simplifications, e.g. c1^2 + c2^2 = Dc^2
Putting this into Python (almost Pseudocode):
import math
def GetXYR(Da, Db, Dc):
c1 = math.cos(math.pi/3) * Dc
c2 = math.cos(math.pi/6) * Dc
X = ((c1**2 + c2**2) * Da + Da**2 * c2 - Db * Db * (c2 + Da)) / (2 * Db * c2 + 2 * Db * Da + 2 * Da * c1)
Y = (-2*X*c1 + c1**2 + c2**2 - Da**2) / (2*(c2+Da))
R = math.sqrt(X**2 + (Y+Da)**2)
R2 = math.sqrt(Y**2 + (X+Db)**2)
R3 = math.sqrt((X - math.cos(math.pi/3) * Dc)**2 + (Y - math.cos(math.pi/6) * Dc)**2)
return (X, Y, R, R2, R3)
(X, Y, R, R2, R3) = GetXYR(123.0, 114.0, 89.0)
print((X, Y, R, R2, R3))
I get the result (X, Y, R, R2, R3) = (-8.129166703588021, -16.205081335032794, 107.1038654949096, 107.10386549490958, 107.1038654949096)
Which seems reasonable if both Da and Db are longer than Dc, then both coordinates are probably negative.
I calculated the Radius from three equations to cross check whether my calculation makes sense. It seems to fulfill all three equations we set up in the beginning.
Your problem is know a "circumscribed circle". You have a triangle define by 3 distances at given angles from your robot position, then you can construct the circumscribed circle from these three points (see Circumscribed circle from Wikipedia - section "Other properties"). So you know the diameter (if needed).
It is also known that the meeting point of perpendicular bisector of triangle sides is the center of the circumscribed circle.
Let's a=Da, b=Db. The we can write a system for points A and B at the circumference:
(x+b)^2 + y^2 = r^2
(y+a)^2 + x^2 = r^2
After transformations we have quadratic equation
y^2 * (4*b^2+4*a^2) + y * (4*a^3+4*a*b^2) + b^4-4*b^2*r^2+a^4+2*a^2*b^2 = 0
or
AA * y^2 + BB * y + CC = 0
where coefficients are
AA = (4*b^2+4*a^2)
BB = (4*a^3+4*a*b^2)
CC = b^4-4*b^2*r^2+a^4+2*a^2*b^2
So calculate AA, BB, CC coefficients, find solutions y1,y2 of quadratic eqiation, then get corresponding x1, x2 values using
x = (a^2 - b^2 + 2 * a * y) / (2 * b)
and choose real solution pair (where coordinate is inside the circle)
Quick checking:
a=1,b=1,r=1 gives coordinates 0,0, as expected (and false 1,-1 outside the circle)
a=3,b=4,r=5 gives coordinates (rough) 0.65, 1.96 at the picture, distances are about 3 and 4.
Delphi code (does not check all possible errors) outputs x: 0.5981 y: 1.9641
var
a, b, r, a2, b2: Double;
aa, bb, cc, dis, y1, y2, x1, x2: Double;
begin
a := 3;
b := 4;
r := 5;
a2 := a * a;
b2:= b * b;
aa := 4 * (b2 + a2);
bb := 4 * a * (a2 + b2);
cc := b2 * b2 - 4 * b2 * r * r + a2 * a2 + 2 * a2 * b2;
dis := bb * bb - 4 * aa * cc;
if Dis < 0 then begin
ShowMessage('no solutions');
Exit;
end;
y1 := (- bb - Sqrt(Dis)) / (2 * aa);
y2 := (- bb + Sqrt(Dis)) / (2 * aa);
x1 := (a2 - b2 + 2 * a * y1) / (2 * b);
x2 := (a2 - b2 + 2 * a * y2) / (2 * b);
if x1 * x1 + y1 * y1 <= r * r then
Memo1.Lines.Add(Format('x: %6.4f y: %6.4f', [x1, y1]))
else
if x2 * x2 + y2 * y2 <= r * r then
Memo1.Lines.Add(Format('x: %6.4f y: %6.4f', [x2, y2]));
From your diagram you have point P that you need it's X & Y coordinate. So we need to find Px and Py or (Px,Py). We know that Ax = Px and By = Py. We can use these for substitution if needed. We know that C & P create a line and all lines have slope in the form of y = mx + b. Where the slope is m and the y intercept is b. We don't know m or b at this point but they can be found. We know that the angle of between two vectors where the vectors are CP and PB gives an angle of 120°, but this does not put the angle in standard position since this is a CW rotation. When working with circles and trig functions along with linear equations of slope within them it is best to work in standard form. So if this line of y = mx + b where the points C & P belong to it the angle above the horizontal line that is parallel to the horizontal axis that is made by the points P & B will be 180° - 120° = 60° We also know that the cos angle between two vectors is also equal to the dot product of those vectors divided by the product of their magnitudes.
We don't have exact numbers yet but we can construct a formula: Since theta = 60° above the horizontal in the standard position we know that the slope m is also the tangent of that angle; so the slope of this line is tan(60°). So let's go back to our linear equation y = tan(60°)x + b. Since b is the y intercept we need to find what x is when y is equal to 0. Since we still have three undefined variables y, x, and b we can use the points on this line to help us here. We know that the points C & P are on this line. So this vector of y = tan(60°)x + b is constructed from (Px, Py) - (Cx, Cy). The vector is then (Px-Cx, Py-Cy) that has an angle of 60° above the horizontal that is parallel to the horizontal axis. We need to use another form of the linear equation that involves the points and the slope this time which happens to be y - y1 = m(x - x1) so this then becomes y - Py = tan(60°)(x - Px) well I did say earlier that we could substitute so let's go ahead and do that: y - By = tan(60°)(x - Ax) then y - By = tan(60°)x - tan(60°)Ax. And this becomes known if you know the actual coordinate points of A & B. The only thing here is that you have to convert your angle of 120° to standard form. It all depends on what your known and unknowns are. So if you need P and you have both A & B are known from your diagram the work is easy because the points you need for P will be P(Ax,By). And since you already said that you know Da, Db & Dc with their lengths then its just a matter of apply the correct trig functions with the proper angle and or using the Pythagorean Theorem to find the length of another leg of the triangle. It shouldn't be all that hard to find what P(x,y) is from the other points. You can use the trig functions, linear equations, the Pythagorean theorem, vector calculations etc. If you can find the equation of the line that points C & P knowing that P has A's x value and has B's y value and having the slope of that line that is defined by the tangent above the horizontal which is 180° - phi where phi is the angle you are giving that is CW rotation and theta would be the angle in standard position or above the horizontal you have a general form of y - By = tan(180° - phi)(x - Ax) and from this equation you can find any point on that line.
There are other methods such as using the existing points and the vectors that they create between each other and then generate an equilateral triangle using those points and then from that equilateral if you can generate one, you can use the perpendicular bisectors of that triangle to find the centroid of that triangle. That is another method that can be done. The only thing you may have to consider is the linear translation of the line from the origin. Thus you will have a shift in the line of (Ax - origin, By - origin) and to find one set the other to 0 and vise versa. There are many different methods to find it.
I just showed you several mathematical techniques that can help you to find a general equation based on your known(s) and unknown(s). It just a matter of recognizing which equations work in which scenario. Once you recognize the correct equations for the givens; the rest is fairly easy. I hope this helps you.
EDIT
I did forget to mention one thing; and that is the line of CP has a point on the edge of the circle defined by (cos(60°), sin(60°)) in the 1st quadrant. In the third quadrant you will have a point on this line and the circle defined by (-cos(60°), -sin(60°)) provided that this line goes through the origin (0,0) where there is no y nor x intercepts and if this is the case then the point on the circle at either end and the origin will be the radius of that circle.

axes separated by angles

I'm trying to generate some axis vectors from parameters commonly used to specify crystallographic unit cells. These parameters consist of the length of the three axes: a,b,c and the angles between them: alpha,beta,gamma. By convention alpha is the angle between the b and c axes, beta is between a and c, and gamma between a and b.
Now getting vector representations for the first two is easy. I can arbitrarily set the the a axis to the x axis, so a_axis = [a,0,0]. I then need to rotate b away from a by the angle gamma, so I can stay in the x-y plane to do so, and b_axis = [b*cos(gamma),b*sin(gamma),0].
The problem is the third vector. I can't figure out a nice clean way to determine it. I've figured out some different interpretations but none of them have panned out. One is imagining the there are two cones around the axes axis_a and axis_b whose sizes are specified by the angles alpha and beta. The intersection of these cones create two lines, the one in the positive z direction can be used as the direction for axis_c, of length c.
Does someone know how I should go about determining the axis_c?
Thanks.
The angle alpha between two vectors u,v of known length can be found from their inner (dot) product <u,v>:
cos(alpha) = <u,v>/(||u|| ||v||)
That is, the cosine of alpha is the inner product of the two vectors divided by the product of their lengths.
So the z-component of your third can be any nonzero value. Scaling any or all of the axis vectors after you get the angles right won't change the angles, so let's assume (say) Cz = 1.
Now the first two vectors might as well be A = (1,0,0) and B = (cos(gamma),sin(gamma),0). Both of these have length 1, so the two conditions to satisfy with choosing C are:
cos(alpha) = <B,C>/||C||
cos(beta) = <A,C>/||C||
Now we have only two unknowns, Cx and Cy, to solve for. To keep things simple I'm going to just refer to them as x and y, i.e. C = (x,y,1). Thus:
cos(alpha) = [cos(gamma)*x + sin(gamma)*y]/sqrt(x^2 + y^2 + 1)
cos(beta) = x/(sqrt(x^2 + y^2 + 1)
Dividing the first equation by the second (assuming beta not a right angle!), we get:
cos(alpha)/cos(beta) = cos(gamma) + sin(gamma)*(y/x)
which is a linear equation to solve for the ratio r = y/x. Once you have that, substituting y = rx in the second equation above and squaring gives a quadratic equation for x:
cos^2(beta)*((1+r^2)x^2 + 1) = x^2
cos^2(beta) = (1 - cos^2(beta)*(1 + r^2))x^2
x^2 = cos^2(beta)/[(1 - cos^2(beta)*(1 + r^2))]
By squaring the equation we introduced an artifact root, corresponding to choosing the sign of x. So check the solutions for x you get from this in the "original" second equation to make sure you get the right sign for cos(beta).
Added:
If beta is a right angle, things are simpler than the above. x = 0 is forced, and we have only to solve the first equation for y:
cos(alpha) = sin(gamma)*y/sqrt(y^2 + 1)
Squaring and multiplying away the denominator gives a quadratic for y, similar to what we did before. Remember to check your choice of a sign for y:
cos^2(alpha)*(y^2 + 1) = sin^2(gamma)*y^2
cos^2(alpha) = [sin^2(gamma) - cos^2(alpha)]*y^2
y^2 = cos^2(alpha)/[sin^2(gamma) - cos^2(alpha)]
Actually if one of the angles alpha, beta, gamma is a right angle, it might be best to label that angle gamma (between the first two vectors A,B) to simplify the computation.
Here is a way to find all Cx, Cy, Cz (first two are the same as in the other answer), given that A = (Ax,0,0), B = (Bx, By, 0), and assuming that |C| = 1
1) cos(beta) = AC/(|A||C|) = AxCx/|A| => Cx = |A|cos(beta)/Ax = cos(beta)
2) cos(alpha) = BC/(|B||C|) = (BxCx+ByCy)/|B| => Cy = (|B|cos(alpha)-Bx cos(beta))/By
3) To find Cz let O be the point at (0,0,0), T the point at (Cx,Cy,Cz), P be the projection of T on Oxy and Q be the projection of T on Ox. So P is the point at (Cx,Cy,0) and Q is the point at (Cx,0,0). Thus from the right angle triangle OQT we get
tan(beta) = |QT|/||OQ| = |QT|/Cx
and from the right triangle TPQ we get |TP|^2 + |PQ|^2 = |QT|^2. So
Cz = |TP| = sqrt(|QT|^2 - |PQ|^2) = sqrt( Cx^2 tan(beta)^2 - Cy^2 )
I'm not sure if this is correct but I might as well take a shot. Hopefully I won't get a billion down votes...
I'm too lazy to scale the vectors by the necessary amounts, so I'll assume they are all normalized to have a length of 1. You can make some simple modifications to the calculation to account for the varying sizes. Also, I'll use * to represent the dot product.
A = (1, 0, 0)
B = (cos(g), sin(g), 0)
C = (Cx, Cy, Cz)
A * C = cos(beta) //This is just a definition of the dot product. I'm assuming that the magnitudes are 1, so I can skip that portion, and you said that beta was the angle between A and C.
A * C = Cx //I did this by multiplying each corresponding value, and the Cy and Cz were ignored because they were being multiplied by 0
cos(beta) = Cx //Combine the previous two equations
B * C = cos(alpha)
B * C = Cx*cos(g) + Cy*sin(g) = cos(beta) * cos(g) + Cy*sin(g)
(cos(alpha) - cos(beta) * cos(g))/(sin(g)) = Cy
To be honest, I'm not sure how to get the z component of vector C, but I would expect it to be one more relatively easy step. If I can figure it out, I'll edit my post.

transforming coordinates from one distorted coordinate system to another

the problem is best explained with an example:
http://dl.dropbox.com/u/1013446/distortedcoordinatespace.exe
drag and drop the little red square inside the small square on the right.
it corresponds to the red square in the big quadrilateral on the left.
you can also drag the 4 corners of the big quadrilateral on the left to see how it occupies a distorted version of the space within the square.
given the absolute coordinates for the 4 points of a square and the coordinates of an arbitrary point within the square, it's simple matter to remap the point's coordinates to an arbitrary quadrilateral.
what I want is to be able to start off with an arbitrary quadrilateral, and be able to do the same thing, transforming the quadrilateral to any other 4 sided shape, but maintaining the relative distorted position of the point,
so given the 4 absolute coordinates of each of 2 irregular quadrilaterals, A and B, how can I convert the coordinates of point C given it's absolute coordinates?
also helpful, would be any terminology that I'm missing here for what these transformations would be called, because I'd like to look into them more
ok, I'm attempting to implement btilly's solution, and here's what I have so far:
#include<complex>
#define cf complex<float>
cf i=sqrt(complex<float>(-1));
cf GetZ(float x,float y)
{
return cf(x)+(cf(y)*i);
}
cf GetPathIntegral(cf p1,cf p2,cf q1,cf q2, int n)
{
cf sum;
for (int index=0;index<=n;index++)
{
cf s=cf(float(index)/float(n));
cf weight;
if (index==0||index==n)
weight=1;
else if(index%2)
weight=4;
else weight =2;
sum+=(((cf(1)-s)*q1)+(s*q2))*(p2-p1)*weight;
}
return sum/cf((3.0*(n-1.0)));
}
before I move on from here, I want to make sure I'm right so far...
also, this paragraph confused me a bit:
OK, so we can do path integrals. What
is the value of that? Well suppose we
take a random point z0 = x + iy
somewhere in our region. Suppose that
f(z) is defined on the path. Then the
Cauchy Integral Formula says that the
integral around our region (which is
the sum of 4 piecewise integrals that
we know how to do) of f(z)/(2 * π * i
* (z - z0)) is a really nice function that is going to match our original
function on the boundary.
what does the function do exactly?
(My first pass was a complicated derivation of a natural seeming formula for this. But then I realized that there is a far, far better solution. Which I would have remembered earlier if I had used Complex Analysis in the last 20 years.)
The right way to do this is to apply the Cauchy Integral Formula. With this you can map any polygon to any other polygon. If the polygons don't self-intersect, it will send the boundary to the boundary and the interior to the interior. The mapping will also have the excellent property that it is conformal, meaning that angles are preserved. By that I mean that if a pair of curves intersect in your region, then they will be mapped to a pair of curves that intersect at the same angle. (Many of Escher's drawings are based on conformal mappings.)
Enough hype. How do you do it? I'll explain it, assuming that you know absolutely nothing about complex analysis. I'll use some Calculus terms, but you should be able to follow my directions even if you don't know any Calculus at all. Since I am assuming so little, the explanation has to be kind of long. I'm sorry for that.
Every point (x, y) in the real plane can be viewed as a complex number z = x + iy. We can add and multiply complex numbers using the usual rules of algebra and the fact that i * i = -1. Furthermore note that 1 = (x + iy) * (x - iy)/(x2 + y2) so we can divide if we let 1/z = (x - iy)/(x2 + y2). We therefore have all of the usual rules of arithmetic.
But we can do better than that. We can do Calculus. In particular we can do path integrals around curves. An integral of a function along a curve is a kind of weighted average of that function over the points in that curve. You can read up on how to do it in general. But here is how to do it in this case.
Suppose that the starting region has corners P1, P2, P3, P4. The path around the region is defined by the four line segments (P1, P2), (P2, P3), (P3, P4), (P4, P1). I'll talk about how to handle the first line segment. The others are similar.
The path integral of f(z) over (P1, P2) is the integral from 0 to 1 of f((1-s)P1 + sP2)(P2 - P1). To evaluate that integral, the easiest thing to do is numerical integration using Simpson's Rule. To do this pick an odd number n and for the values s = 0, 1/n, 2/n, ..., (n-1)/n, 1 assign them weights in the pattern 1, 4, 2, 4, 2, ..., 2, 4, 1. (The end points are 1, everything else alternates between 4 and 2.) Now for each point calculate f((1-s)P1 + sP2)(P2 - P1), multiply by the weight, and add them all together. Then divide by the magic value 3 * (n-1). The result is approximately your integral. (As n grows, the error in this approximation is O(1/n4). In your case if you take n = 21 then the approximation should wind up good enough to map pixels to the right pixel, except for some pixels near the boundary. Make it a little larger, and the problematic area will get smaller. Right at the edge you'll want some multiple of the number of pixels on a side to make the error small .)
OK, so we can do path integrals. What is the value of that? Well suppose we take a random point z0 = x + iy somewhere in our region. Suppose that f(z) is defined on the path. Then the Cauchy Integral Formula says that the integral around our region (which is the sum of 4 piecewise integrals that we know how to do) of f(z)/(2 * π * i * (z - z0)) is a really nice function that is going to match our original function on the boundary. I won't get into all of the "really nice" things about it, but what I was saying above about conformal is part of it.
Now what function f do we use? Well suppose that our region is being mapped to a region with corners Q1, Q2, Q3, Q4. We want the first path piece to map to the second path piece. So we want f((1-s)P1 + sP2) to be (1-s)Q1 + sQ2. That tells us how to calculate f at all of the points we need to do our integral.
Now, you ask, how do you reverse it? That's simple. Just reverse the role of the two polygons, and calculate the reverse transformation! Which brings a really good unit test. You should define a couple of weird regions, pick a point in the middle, and verify that if you map from the first to the second and back again that you wind up close to where you started. If you pass that test, then you probably have made no mistakes.
And finally what about my general polygon claim that I made? Well we defined our path as four pieces we traversed linearly. A higher degree polygon just has more pieces to its path, but otherwise the calculation is done in exactly the same way.
found the solution. I have to say, it's much more complicated than I had expected:
assuming a square or quadrilateral has the four corners:
AB
CD
you need an interpolation factor: xt for the x axis, and yt for the y axis, so that
if you define a linear interpolation formula:
lerp(j,k,t)
{
return (t*(k-j))+j;
}
a point p within the ABCD quad is defined as:
p.x=lerp(lerp(a.x,b.x,xt),lerp(c.x,d.x,xt),yt)
and
p.y=lerp(lerp(a.y,c.y,yt),lerp(b.y,d.y,yt),xt)
then the values you need to define are xt and yt
xt= ((2* c.x* a.y) - (d.x* a.y) - (2
*a.x c.y) + (b.x c.y) - (c.x* b.y) + (a.x* d.y) - (a.y* p.x) + (c.y* p.x )+
(b.y p.x) - (d.y p.x) + (a.x p.y)
- (b.x p.y) - (c.x* p.y) + (d.x* p.y) - Sqrt(-4* ((c.x* a.y) - (d.x*
a.y) - (a.x* c.y) + (b.x* c.y) - (c.x*
b.y) + (d.x* b.y) + (a.x d.y) -
(b.x d.y))* ((c.x* a.y) - (a.x* c.y)
- (a.y* p.x) + (c.y* p.x) + (a.x* p.y) - (c.x* p.y)) + ((-2 *c.x a.y) + (d.x a.y) + (2 *a.x c.y) - (b.x
c.y) + (c.x* b.y) - (a.x* d.y) + (a.y*
p.x) - (c.y* p.x) - (b.y* p.x) + (d.y*
p.x) - (a.x* p.y) + (b.x* p.y) +
(c.x* p.y) - (d.x p.y))^2))/(2
((c.x* a.y) - (d.x* a.y) - (a.x* c.y)
+ (b.x* c.y) - (c.x* b.y) + (d.x *b.y) + (a.x *d.y) - ( b.x *d.y)))
and once you have that
yt=(p.x-lerp(a.x,b.x,('xt')))/(lerp(c.x,d.x,('xt'))-lerp(a.x,b.x,('xt')))

Resources