Calculating the coordinates of the third point of a triangle - graphics

OK, I know this sounds like it should be asked on math.stackoverflow.com, but this is embarrassingly simple maths that I've forgotten from high-school, rather than advanced post-graduate stuff!
I'm doing some graphics programming, and I have a triangle. Incidentally, two of this triangle's sides are equal, but I'm not sure if that's relevant. I have the coordinates of two of the corners (vertices), but not the third (these coordinates are pixels on the screen, in case that's relevant). I know the lengths of all three sides.
How do I determine the coordinates of the unknown vertex?

for oblique triangles: c^2 = a^2 + b^2 - 2ab * cos(C)
where a, b, c are the lengths of the sides (regardless of length)
and A, B, C are the angles opposite the side with the same letter.
Use the above to figure out the angle from one of the endpoints you know, then use the angle, the position of the vertex, and the angle between the adjacent sides to determine where the unknown vertex is.
And the complexity of the problem doesn't determine which site it should go on, only the subject matter. So you should move this to math.

EDIT: I had a serious brainfart previously, but this should work.
Use the law of cosines
/* use the law of cosines to get the angle of CAB */
c² = a² + b² - 2ab cos(Cangle)
cos(Cangle) = (a²+b²-c²) / 2ab
Cangle = acos((a²+b²-c²) / 2ab)
AB = B.xy - A.xy;
normalize(AB);
len = length(AC)
C.x = len*AB.x* cos(Cangle) * len*AB.y*sin(Cangle);
C.y = len*AB.x*-sin(Cangle) * len*AB.y*cos(Cangle);

Related

Making a Bezier curve based on 3 points the line will intersect

A quadratic bezier curve needs these three points, but I do not have an ordered pair of p1. Instead, I have the ordered pair of points here
The middle point (P1) is the highest point of the parabola.
The parabola is equal in both sides
How do I get the 3 points from image 1 using the points from image 2?
Apply the knowledge explained in https://pomax.github.io/bezierinfo/#abc and you should be good to go. You'll need to decide which time value that "somewhere on the curve" point has, and then you can use the formula for the projection ratio to find the actual control point coordinate.
However, at t=0.5 the ratio is just "1:1" so things get even easier because your point projects onto the midpoint of the line that connects that first and last point, and the real control point is the same distance "above" your point as the point is above that line:
So you just compute the midpoint:
m =
x: (p1.x + p2.x) / 2
y: (p1.y + p2.y) / 2
and the x and y distance to the midpoint from the "p2 you have" point:
d =
x: (p2.x - m.x)
y: (p2.y - m.y)
and then the real p2 is simply that distance away from the "p2 you have":
real2 =
x: p2.x + d.x
y: p2.y + d.y
However, note that this only works for t=0.5: both that projected point on the start--end line and the distance ratios will be (possibly very) different for any other t value and you should use the formula that the Bezier primer talks about.
Also note that what you call "the peak" is in no way guaranteed to be at t=0.5... for example, have a look at this curve:
The point that is marked as belonging to t=0.5 is certainly not where you would say the "peak" of the curve is (in fact, that's closer to t=0.56), so if all you have is three points, you technically always have incomplete information and you're going to have to invent some rule for deciding how to fill in the missing bits. In this case "what t value do I consider my somewhere-on-the-curve point to be?".

Determine if an arc represents an reflex or acute angle

I have this seemingly simple but very confusing problem.
Given I have a set of vertices (x1,y1), (x2,y2), (x3,y3)...... representing an arc. The points can either be clockwise or counter clockwise, but are all similarly ordered.
And I know the center of the arc (xc,yc).
How can I tell if the arc subtends an acute/obtuse or reflex angle?
One obvious solution is to take the difference of atan2((last_pt)-(center)) and atan2((first_pt)-(center))). But if the arc goes through the point where PI become -PI, this method breaks down.
Also, since the arc points are derived from a rather noisy pixelated picture, the vertices are not exactly smooth.
Picture of a acute and reflex arc
I cant wrap my brain around solving this problem.
Thanks for your help!
Working with 2D angles is a pain for the reason you described, so it's better to work with vector math instead, which is rotationally invariant.
Define the 2D cross-product, A ^ B = Ax * By - Ay * Bx. This is positive if A is clockwise rotated relative to B, and vice versa.
The logic:
Compute C = (last_pt - center) ^ (first_pt - center)
If C = 0, the arc is either closed or 180-degree (forgot the name for this)
If C > 0, the arc must either be (i) clockwise and acute/obtuse or (ii) anti-clockwise and reflex
If C < 0, the opposite applies
Pseudocode:
int arc_type(Point first, Point last, Point center, bool clockwise)
{
// cross-product
float C = (last.x - center.x) * (first.y - center.y)
- (last.y - center.y) * (first.x - center.x);
if (Math.abs(C) < /* small epsilon */)
return 0; // 180-degree
return ((C > 0) ^ clockwise) ? 1 // reflex
: -1; // acute / obtuse
}
Note that if you don't have prior knowledge of whether the arc is clockwise or anti-, you can use the same cross-product method on adjacent points. You need to ensure that the order of the points is consistent - if not you can, again using the cross-product, sort them by (relative) angle.

Finding most distant point in circle from point

I'm trying to find the best way to get the most distant point of a circle from a specified point in 2D space. What I have found so far, is how to get the distance between the point and the circle position, but I'm not entirely sure how to expand this to find the most distant point of the circle.
The known variables are:
Point a
Point b (circle position)
Radius r (circle radius)
To find the distance between the point and the circle position, I have found this:
xd = x2 - x1
yd = y2 - y1
Distance = SquareRoot(xd * xd + yd * yd)
It seems to me, this is part of the solution. How would this be expanded to get the position of Point x in the below image?
As an additional but optional part of the question: I have read in some places that it would be possible to get the distance portion without using the Square Root, which is very performance intensive and should be avoided if fast code is necessary. In my case, I would be doing this calculation quite often; Any comments on this within the context of the main question would be welcome too.
What about this?
Calculate A-B.
We now have a vector pointing from the center of the circle towards A (if B is the origin, skip this and just consider point A a vector).
Normalize.
Now we have a well defined length (the length is 1)
If the circle is not of unit radius, multiply by radius. If it is unit radius, skip this.
Now we have the correct length.
Invert sign (can be done in one step with 3., just multiply with the negative radius)
Now our vector points in the correct direction.
Add B (if B is the origin, skip this).
Now our vector is offset correctly so its endpoint is the point we want.
(Alternatively, you could calculate B-A to save the negation, but then you have to do one more operation to offset the origin correctly.)
By the way, it works the same in 3D, except the circle would be a sphere, and the vectors would have 3 components (or 4, if you use homogenous coords, in this case remember -- for correctness -- setting w to 0 when "turning points into vectors" and to 1 at the end when making a point from the vector).
EDIT:
(in reply of pseudocode)
Assuming you have a vec2 class which is a struct of two float numbers with operators for vector subtraction and scalar multiplicaion (pretty trivial, around a dozen lines of code) and a function normalize which needs to be no more than a shorthand for multiplying with inv_sqrt(x*x+y*y), the pseudocode (my pseudocode here is something like a C++/GLSL mix) could look something like this:
vec2 most_distant_on_circle(vec2 const& B, float r, vec2 const& A)
{
vec2 P(A - B);
normalize(P);
return -r * P + B;
}
Most math libraries that you'd use should have all of these functions and types built-in. HLSL and GLSL have them as first type primitives and intrinsic functions. Some GPUs even have a dedicated normalize instruction.

How to calculate angle between two direction vectors that form a closed/open shape?

I am trying to figure out the correct trig. eq./function to determine the following:
The Angle-change (in DEGREES) between two DIRECTION VECTORS(already determined), that represent two line-segment.
This is used in the context of SHAPE RECOGTNITION (hand drawn by user on screen).
SO basically,
a) if the user draws a (rough) shape, such as a circle, or oval, or rectangle etc - the lines that makes up that shape are broken down in to say.. 20 points(x-y pairs).
b) I have the DirectionVector for each of these LINE SEGMENTS.
c) So the BEGINNING of a LINE SEGMENT(x0,y0), will the END points of the previous line(so as to form a closed shape like a rectangle, let's say).
SO, my question is , given the context(i.e. determinign the type of a polygon), how does one find the angle-change between two DIRECTION VECTORS(available as two floating point values for x and y) ???
I have seen so many different trig. equations and I'm seeking clarity on this.
Thanks so much in advance folks!
If (x1,y1) is the first direction vector and (x2,y2) is the second one, it holds:
cos( alpha ) = (x1 * x2 + y1 * y2) / ( sqrt(x1*x1 + y1*y1) * sqrt(x2*x2 + y2*y2) )
sqrt means the square root.
Look up http://en.wikipedia.org/wiki/Dot_product
Especially the section "Geometric Representation".
You could try atan2:
float angle = atan2(previousY-currentY, previousX-currentY);
but also, as the previous answers mentioned, the
angle between two verctors = acos(first.dotProduct(second))
I guess you have the vector as three points (x_1, y_1), (x_2, y_2) and (x_3, y_3).
Then you can move the points so that (x_1, y_1) == (0, 0) by
(x_1, y_1) = (x_2, y_2) - (x_1, y_1)
(x_2, y_2) = (x_3, y_3) - (x_1, y_1)
Now you have this situation:
Think of this triangle as two right-angled triangles. The first one has the angle alpha and a part of beta, the second right-angled triangle has the other part of beta.
Then you can apply:
You can calculate alpha like this:
If I understand you correctly, you may just evaluate the dot product between two vectors and take the appropriate arccos to retrieve the angle between these vectors.

Projective transformation

Given two image buffers (assume it's an array of ints of size width * height, with each element a color value), how can I map an area defined by a quadrilateral from one image buffer into the other (always square) image buffer? I'm led to understand this is called "projective transformation".
I'm also looking for a general (not language- or library-specific) way of doing this, such that it could be reasonably applied in any language without relying on "magic function X that does all the work for me".
An example: I've written a short program in Java using the Processing library (processing.org) that captures video from a camera. During an initial "calibrating" step, the captured video is output directly into a window. The user then clicks on four points to define an area of the video that will be transformed, then mapped into the square window during subsequent operation of the program. If the user were to click on the four points defining the corners of a door visible at an angle in the camera's output, then this transformation would cause the subsequent video to map the transformed image of the door to the entire area of the window, albeit somewhat distorted.
Using linear algebra is much easier than all that geometry! Plus you won't need to use sine, cosine, etc, so you can store each number as a rational fraction and get the exact numerical result if you need it.
What you want is a mapping from your old (x,y) co-ordinates to your new (x',y') co-ordinates. You can do it with matrices. You need to find the 2-by-4 projection matrix P such that P times the old coordinates equals the new co-ordinates. We'll assume that you're mapping lines to lines (not, for instance, straight lines to parabolas). Because you have a projection (parallel lines don't stay parallel) and translation (sliding), you need a factor of (xy) and (1), too. Drawn as matrices:
[x ]
[a b c d]*[y ] = [x']
[e f g h] [x*y] [y']
[1 ]
You need to know a through h so solve these equations:
a*x_0 + b*y_0 + c*x_0*y_0 + d = i_0
a*x_1 + b*y_1 + c*x_1*y_1 + d = i_1
a*x_2 + b*y_2 + c*x_2*y_2 + d = i_2
a*x_3 + b*y_3 + c*x_3*y_3 + d = i_3
e*x_0 + f*y_0 + g*x_0*y_0 + h = j_0
e*x_1 + f*y_1 + g*x_1*y_1 + h = j_1
e*x_2 + f*y_2 + g*x_2*y_2 + h = j_2
e*x_3 + f*y_3 + g*x_3*y_3 + h = j_3
Again, you can use linear algebra:
[x_0 y_0 x_0*y_0 1] [a e] [i_0 j_0]
[x_1 y_1 x_1*y_1 1] * [b f] = [i_1 j_1]
[x_2 y_2 x_2*y_2 1] [c g] [i_2 j_2]
[x_3 y_3 x_3*y_3 1] [d h] [i_3 j_3]
Plug in your corners for x_n,y_n,i_n,j_n. (Corners work best because they are far apart to decrease the error if you're picking the points from, say, user-clicks.) Take the inverse of the 4x4 matrix and multiply it by the right side of the equation. The transpose of that matrix is P. You should be able to find functions to compute a matrix inverse and multiply online.
Where you'll probably have bugs:
When computing, remember to check for division by zero. That's a sign that your matrix is not invertible. That might happen if you try to map one (x,y) co-ordinate to two different points.
If you write your own matrix math, remember that matrices are usually specified row,column (vertical,horizontal) and screen graphics are x,y (horizontal,vertical). You're bound to get something wrong the first time.
EDIT
The assumption below of the invariance of angle ratios is incorrect. Projective transformations instead preserve cross-ratios and incidence. A solution then is:
Find the point C' at the intersection of the lines defined by the segments AD and CP.
Find the point B' at the intersection of the lines defined by the segments AD and BP.
Determine the cross-ratio of B'DAC', i.e. r = (BA' * DC') / (DA * B'C').
Construct the projected line F'HEG'. The cross-ratio of these points is equal to r, i.e. r = (F'E * HG') / (HE * F'G').
F'F and G'G will intersect at the projected point Q so equating the cross-ratios and knowing the length of the side of the square you can determine the position of Q with some arithmetic gymnastics.
Hmmmm....I'll take a stab at this one. This solution relies on the assumption that ratios of angles are preserved in the transformation. See the image for guidance (sorry for the poor image quality...it's REALLY late). The algorithm only provides the mapping of a point in the quadrilateral to a point in the square. You would still need to implement dealing with multiple quad points being mapped to the same square point.
Let ABCD be a quadrilateral where A is the top-left vertex, B is the top-right vertex, C is the bottom-right vertex and D is the bottom-left vertex. The pair (xA, yA) represent the x and y coordinates of the vertex A. We are mapping points in this quadrilateral to the square EFGH whose side has length equal to m.
Compute the lengths AD, CD, AC, BD and BC:
AD = sqrt((xA-xD)^2 + (yA-yD)^2)
CD = sqrt((xC-xD)^2 + (yC-yD)^2)
AC = sqrt((xA-xC)^2 + (yA-yC)^2)
BD = sqrt((xB-xD)^2 + (yB-yD)^2)
BC = sqrt((xB-xC)^2 + (yB-yC)^2)
Let thetaD be the angle at the vertex D and thetaC be the angle at the vertex C. Compute these angles using the cosine law:
thetaD = arccos((AD^2 + CD^2 - AC^2) / (2*AD*CD))
thetaC = arccos((BC^2 + CD^2 - BD^2) / (2*BC*CD))
We map each point P in the quadrilateral to a point Q in the square. For each point P in the quadrilateral, do the following:
Find the distance DP:
DP = sqrt((xP-xD)^2 + (yP-yD)^2)
Find the distance CP:
CP = sqrt((xP-xC)^2 + (yP-yC)^2)
Find the angle thetaP1 between CD and DP:
thetaP1 = arccos((DP^2 + CD^2 - CP^2) / (2*DP*CD))
Find the angle thetaP2 between CD and CP:
thetaP2 = arccos((CP^2 + CD^2 - DP^2) / (2*CP*CD))
The ratio of thetaP1 to thetaD should be the ratio of thetaQ1 to 90. Therefore, calculate thetaQ1:
thetaQ1 = thetaP1 * 90 / thetaD
Similarly, calculate thetaQ2:
thetaQ2 = thetaP2 * 90 / thetaC
Find the distance HQ:
HQ = m * sin(thetaQ2) / sin(180-thetaQ1-thetaQ2)
Finally, the x and y position of Q relative to the bottom-left corner of EFGH is:
x = HQ * cos(thetaQ1)
y = HQ * sin(thetaQ1)
You would have to keep track of how many colour values get mapped to each point in the square so that you can calculate an average colour for each of those points.
I think what you're after is a planar homography, have a look at these lecture notes:
http://www.cs.utoronto.ca/~strider/vis-notes/tutHomography04.pdf
If you scroll down to the end you'll see an example of just what you're describing. I expect there's a function in the Intel OpenCV library which will do just this.
There is a C++ project on CodeProject that includes source for projective transformations of bitmaps. The maths are on Wikipedia here. Note that so far as i know, a projective transformation will not map any arbitrary quadrilateral onto another, but will do so for triangles, you may also want to look up skewing transforms.
If this transformation has to look good (as opposed to the way a bitmap looks if you resize it in Paint), you can't just create a formula that maps destination pixels to source pixels. Values in the destination buffer have to be based on a complex averaging of nearby source pixels or else the results will be highly pixelated.
So unless you want to get into some complex coding, use someone else's magic function, as smacl and Ian have suggested.
Here's how would do it in principle:
map the origin of A to the origin of B via a traslation vector t.
take unit vectors of A (1,0) and (0,1) and calculate how they would be mapped onto the unit vectors of B.
this gives you a transformation matrix M so that every vector a in A maps to M a + t
invert the matrix and negate the traslation vector so for every vector b in B you have the inverse mapping b -> M-1 (b - t)
once you have this transformation, for each point in the target area in B, find the corresponding in A and copy.
The advantage of this mapping is that you only calculate the points you need, i.e. you loop on the target points, not the source points. It was a widely used technique in the "demo coding" scene a few years back.

Resources