What is the Correct Way to Scale then Rotate a set of Points? - scale

I have 4 points, point A(x1, y1), point B(x2, y1), and point C(x2, y2), point D(x2, y3) creating two scales: Scale1 yRange(B, D), Scale2 yRange(B, C).
I want to scale the y axis only, so that point D is scaled down to point C, so that the angle between CAB is a certain degree. Then I want to rotate the scaled point C around point B a certain degree, obtaining point E. Then I want to find the real value of point E on the un-scaled coordinate grid where original point D is located. I think I need to use affine transformations, but all examples are rotate first, then scale. But I need to scale first, then rotate. How do I find this new value? I know how to perform rotations alone and a bit of scaling alone, but not together.
Maybe I am confused, after I perform the scaling and rotation, I would not need to scale back, because the new value of E equates to F? I know there are plenty of examples, but I can not wrap my head around this...
Here is my objective. I have the 3 points A, B and D. I want to scale so that DAB equates to let's say 60 degrees, creating point C, then perform several point rotations on C inside the scaled grid. I ultimately want to find the value of F, and the other rotated points, which lies in geometrical positions inside the original unscaled grid that I can not calculate unless I scale the 3 original points to said degree first. The scaled grid contains the correct ratio I need in order to rotate my points. I need to do all my rotations inside the scaled grid, without losing values, but changing aspect ratio, and then take those new points inside the scaled grid and plot them in the unscaled grid, which will then lose correct aspect ratios, which is fine.
Coding in python.

Here's a Python3 program that I think does what you want:
import math
# Use a negative angle since we're rotating clockwise
rotate_C_angle = math.radians(-60)
A = [0, 0]
B = [100, 0]
D = [100, 250]
# Create point D such that angle CAB = target_angle_CAB
target_angle_CAB = math.radians(60)
C = [B[0], B[0] * math.tan(target_angle_CAB)]
# What do we scale B by in order to get C
scale_factor = C[1] / D[1]
# Rotate C around B by rotate_C_angle
# (translate C by -Bx, then rotate, then translate back)
E = [
C[0] - C[1] * math.sin(rotate_C_angle),
C[1] * math.cos(rotate_C_angle)
]
# Scale E back
F = [E[0], E[1] / scale_factor]
This is assuming that A is at the origin. If it isn't then subtract Ax from all the x coordinates and Ay from the y coordinates, then do the calculations before translating back again.
Whether you need to scale back E to F depends on what you're doing. What happens here assumes that the scaling transformation along y does not get rotated.

Related

Compute 3D angle given 2D vectors and their magnitude ratio

I have been trying to figure out whether the following problem has a solution. Almost having given up, I would like to ask whether someone can confirm that there is no solution, or maybe give me a hint.
We have two vectors v and w in 3D space and know that the ratio of their magnitudes is ||v|| / ||w|| = 0.8019.
in 3D space an observer would see that they form an angle of 27.017 degrees.
on the other side, an observer in 2D (only seeing the x and z axis), observes an angle of 7.125 degrees between the vectors.
From their view, the vector coordinates are v = (x: 2, z: 1) and w = (x: 3, z: 2).
Is there somehow a way that the 2D observer can calculate the actual angle between these vectors in 3D space?
I would be more than happy for any input. All my tries have failed so far and I just want to know whether there could be a possible solution.
I have solved this problem and get that the values of y1 and y2 are given by this function:
eq1: 0.6439*y2^(2)-y1^(2)=9.785.
Therefore real angle can practically any value, the factor that would narrow this problem down to an actual solution would be the information about where the observer is in the 3d space so that he sees the angle of 27.017º, however, if this is the whole problem, then I can share my solution and process.
Some graphs that I created from my calculations:
The side view of the vectors is directly from the point of view of the x and z axis of the graph, therefore the coordinates of the (x1,z1) and (x2,z2) points(terminal points of the vectors), appear authentic, and not augmented, hence you can use them in your calculations to calculate the coordinates of z1 and z2, which you need to calculate the angle.
V = (x1, y1, z1) V = (2, y1, 1)
W = (x2, y2, z2) W = (3, y2, 2)
Since ||v|| / ||w|| = 0.8019
∴Then sqrt((x1^2)+(y1^2)+(z1^2))/sqrt((x2^2)+(y2^2)+(z2^2)) = 0.8019
∴(x1^2)+(y1^2)+(z1^2)/(x2^2)+(y2^2)+(z2^2) = 0.6430
∴4+(y1^2)+1/9+(y2^2)+4 = 0.6430
∴5+(y1^2) = 8.359 + 0.6430(y2^2)
∴13.359 = 0.6430(y2^2)-(y1^2)
This gives you therefore a function that calculates the other value of y given the some input y.
You can then graph this function using Geogebra.
For all the pairs of values on the curve, together with the fixed values of x and z for both of the vectors you can calculate that the ratio between the magnitudes of the two vectors is equal to 0.8019.
This problem has therefore infinitely many solutions for the angle as there are infinitely many values of z1 and z2 that satisfy the ratio; ||v|| / ||w|| = 0.8019.
Therefore the answer to this problem can be expressed as:
∀Θº∈R:Θº≥0

Triangulating coordinates with an equation

Ok, I know this sounds really daft to be asking here, but it is programming related.
I'm working on a game, and I'm thinking of implementing a system that allows users to triangulate their 3D coordinates to locate something (eg for a task).
I also want to be able to let the user make the coordinates of the points they are using for triangulation have user-determined coordinates (so the location's coordinate is relative, probably by setting up a beacon or something).
I have a method in place for calculating the distance between the points, so essentially I can calculate the lengths of the sides of the triangle/pyramid as well as all but the coordinate I am after.
It has been a long time since I have done any trigonometry and I am rusty with the sin, cos and tan functions, I have a feeling they are required but have no clue how to implement them.
Can anyone give me a demonstration as to how I would go about doing this in a mathematical/programatical way?
extra info:
My function returns the exact distance between the two points, so say you set two points to 0,0,0 and 4,4,0 respectively, and those points are set to scale(the game world is divided into a very large 3d grid, with each 'block' area being represented by a 3d coordinate) then it would give back a value at around 5.6.
The key point about it varying is that the user can set the points, so say they set a point to read 0,0,0, the actual location could be something like 52, 85, 93. However, providing they then count the blocks and set their other points correctly (eg, set a point 4,4,0 at the real point 56, 89, 93) then the final result will return the relative position (eg the object they are trying to locate is at real point 152, 185, 93, it will return the relative value 100,100,0). I need to be able to calculate it knowing every point but the one it's trying to locate, as well as the distances between all points.
Also, please don't ask why I can't just calculate it by using the real coordinates, I'm hoping to show the equation up on screen as it calculates the result.7
Example:
Here is a diagram
Imagine these are points in my game on a flat plain.
I want to know the point f.
I know the values of points d and e, and the sides A,B and C.
Using only the data I know, I need to find out how to do this.
Answered Edit:
After many days of working on this, Sean Kenny has provided me with his time, patience and intellect, and thus I have now got a working implementation of a triangulation method.
I hope to place the different language equivalents of the code as I test them so that future coders may use this code and not have the same problem I have had.
I spent a bit of time working on a solution but I think the implementer, i.e you, should know what it's doing, so any errors encountered can be tackled later on. As such, I'll give my answer in the form of strong hints.
First off, we have a vector from d to e which we can work out: if we consider the coordinates as position vectors rather than absolute coordinates, how can we determine what the vector pointing from d to e is? Think about how you would determine the displacement you had moved if you only knew where you started and where you ended up? Displacement is a straight line, point A to B, no deviation, not: I had to walk around that house so I walked further. A straight line. If you started at the point (0,0) it would be easy.
Secondly, the cosine rule. Do you know what it is? If not, read up on it. How can we rearrange the form given in the link to find the angle d between vectors DE and DF? Remember you need the angle, not a function of the angle (cos is a function remember).
Next we can use a vector 'trick' called the scalar product. Notice there is a cos function in there. Now, you may be thinking, we've just found the angle, why are we doing it again?
Define DQ = [1,0]. DQ is a vector of length 1, a unit vector, along the x-axis. Which other vector do we know? Do we know of two position vectors?
Once we have two vectors (I hope you worked out the other one) we can use the scalar product to find the angle; again, just the angle, not a function of it.
Now, hopefully, we have 2 angles. Could we take one from the other to get yet another angle to our desired coordinate DF? The choice of using a unit vector earlier was not arbitrary.
The scalar product, after some cancelling, gives us this : cos(theta) = x / r
Where x is the x ordinate for F and r is the length of side A.
The end result being:
theta = arccos( xe / B ) - arccos( ( (A^2) + (B^2) - (C^2) ) / ( 2*A*B ) )
Where theta is the angle formed between a unit vector along the line y = 0 where the origin is at point d.
With this information we can find the x and y coordinates of point f relative to d. How?
Again, with the scalar product. The rest is fairly easy, so I'll give it to you.
x = r.cos(theta)
y = r.sin(theta)
From basic trigonometry.
I wouldn't advise trying to code this into one value.
Instead, try this:
//pseudo code
dx = 0
dy = 0 //initialise coordinates somehow
ex = ex
ey = ey
A = A
B = B
C = C
cosd = ex / B
cosfi = ((A^2) + (B^2) - (C^2)) / ( 2*A*B)
d = acos(cosd) //acos is a method in java.math
fi = acos(cosfi) //you will have to find an equivalent in your chosen language
//look for a method of inverse cos
theta = fi - d
x = A cos(theta)
y = A sin(theta)
Initialise all variables as those which can take decimals. e.g float or double in Java.
The green along the x-axis represents the x ordinate of f, and the purple the y ordinate.
The blue angle is the one we are trying to find because, hopefully you can see, we can then use simple trig to work out x and y, given that we know the length of the hypotenuse.
This yellow line up to 1 is the unit vector for which scalar products are taken, this runs along the x-axis.
We need to find the black and red angles so we can deduce the blue angle by simple subtraction.
Hope this helps. Extensions can be made to 3D, all the vector functions work basically the same for 3D.
If you have the displacements from an origin, regardless of whether this is another user defined coordinate or not, the coordinate for that 3D point are simply (x, y, z).
If you are defining these lengths from a point, which also has a coordinate to take into account, you can simply write (x, y, z) + (x1, y1, z1) = (x2, y2, z2) where x2, y2 and z2 are the displacements from the (0, 0, 0) origin.
If you wish to find the length of this vector, i.e if you defined the line from A to B to be the x axis, what would the x displacement be, you can use Pythagoras for 3D vectors, it works just the same as with 2D:
Length l = sqrt((x^2) + (y^2) + (z^2))
EDIT:
Say you have a user defined point A (x1, y1, z1) and you want to define this as the origin (0,0,0). You have another user chosen point B (x2, y2, z2) and you know the distance from A to B in the x, y and z plane. If you want to work out what this point is, in relation to the new origin, you can simply do
B relative to A = (x2, y2, z2) - (x1, y1, z1) = (x2-x1, y2-y1, z2-z1) = C
C is the vector A>B, a vector is a quantity which has a magnitude (the length of the lines) and a direction (the angle from A which points to B).
If you want to work out the position of B relative to the origin O, you can do the opposite:
B relative to O = (x2, y2, z2) + (x1, y1, z1) = (x1+x2, y1+y2, z1+z2) = D
D is the vector O>B.
Edit 2:
//pseudo code
userx = x;
usery = y;
userz = z;
//move origin
for (every block i){
xi = xi-x;
yi = yi - y;
zi = zi -z;
}

3D rotations of a plane

I'm doing something where I have a plane in a coord sys A with a set of points already on it. I also have a normal vector in space N. How can I rotate the points on coord sys A so that the underlying plane will have the same normal direction as N?
Wondering if any one has a good idea on how to do this. Thanks
If you have, or can easily compute, the normal vector to the plane that your points are currently in, I think the easiest way to do this will be to rotate around the axis common to the two planes. Here's how I'd go about it:
Let M be the vector normal to your current plane, and N be the vector normal to the plane you want to rotate into. If M == N you can stop now and leave the original points unchanged.
Calculate the rotation angle as
costheta = dot(M,N)/(norm(M)*norm(N))
Calculate the rotation axis as
axis = unitcross(M, N)
where unitcross is a function that performs the cross product and normalizes it to a unit vector, i.e. unitcross(a, b) = cross(a, b) / norm(cross(a, b)). As user1318499 pointed out in a comment, this step can cause an error if M == N, unless your implementation of unitcross returns (0,0,0) when a == b.
Compute the rotation matrix from the axis and angle as
c = costheta
s = sqrt(1-c*c)
C = 1-c
rmat = matrix([ x*x*C+c x*y*C-z*s x*z*C+y*s ],
[ y*x*C+z*s y*y*C+c y*z*C-x*s ]
[ z*x*C-y*s z*y*C+x*s z*z*C+c ])
where x, y, and z are the components of axis. This formula is described on Wikipedia.
For each point, compute its corresponding point on the new plane as
newpoint = dot(rmat, point)
where the function dot performs matrix multiplication.
This is not unique, of course; as mentioned in peterk's answer, there are an infinite number of possible rotations you could make that would transform the plane normal to M into the plane normal to N. This corresponds to the fact that, after you take the steps described above, you can then rotate the plane around N, and your points will be in different places while staying in the same plane. (In other words, each rotation you can make that satisfies your conditions corresponds to doing the procedure described above followed by another rotation around N.) But if you don't care where in the plane your points wind up, I think this rotation around the common axis is the simplest way to just get the points into the plane you want them in.
If you don't have M, but you do have the coordinates of the points in your starting plane relative to an origin in that plane, you can compute the starting normal vector from two points' positions x1 and x2 as
M = cross(x1, x2)
(you can also use unitcross here but it doesn't make any difference). If you have the points' coordinates relative to an origin that is not in the plane, you can still do it, but you'll need three points' positions:
M = cross(x3-x1, x3-x2)
A single vector (your normal - N) will not be enough. You will need another two vectors for the other two dimensions. (Imagine that your 3D space could still rotate/spin around the normal vector, and you need another 2 vectors to nail it down). Once you have the normal and another one on the plane, the 3rd one should be easy to find (left- or right-handed depending on your system).
Make sure all three are normalized (length of 1) and put them in a matrix; use that matrix to transform any point in your 3D space (use matrix multiplication). This should give you the new coordinates.
I'm thinking make a unit vector [0,0,1] and use the dot-product along two planes to find the angle of difference, and shift all your points by those angles. This is assuming you want the z-axis to align with the normal vector, else just use [1,0,0] or [0,1,0] for x and y respectively.

Finding Projection and z distance

I have an image that represents a projection. I am going to explain the problem with an example:
In the screen, there is a line from one point E(100,200) to another point
H (150,100). A represent one point
that in the real world is at 200 cm of
distance while B is a point that in
real world is at 300 cm of distance.
The thing that I would like to know is this:
Given one point of the line that passes for these two points, is there a way to calculate the z distance data that it should have?
What if the z distance is not a linear function but is some logarithmic function?
If it's not clear ask me everything,
Cheers
I think what you're getting at is perspective correct interpolation. If you know the depth at E and a depth at H, and B is on the line (in the image) joining these two points, solve for the depth at B with:
1/Zb = s * 1/Ze + (1-s) * 1/Zh
where s is the normalized distance/interpolation parameter (between 0 and 1) along the line in screen space, meaning B = s * E + (1-s) * H
Use homogeneous coordinates, which can be linearly interpolated in screen space (for depth and texture): http://www.cs.unc.edu/~olano/papers/2dh-tri/

How can I find the rotation of a quad in 3D?

I have coordinates for 4 vectors defining a quad and another one for it's normal. I am trying to get the rotation of the quad. I get good results for rotation on X and Y just using the normal, but I got stuck getting the Z, since I've used just 1 vector.
Here's my basic test using Processing and toxiclibs(Vec3D and heading methods):
import toxi.geom.*;
Vec3D[] face = {new Vec3D(1.1920928955078125e-07, 0.0, 1.4142135381698608),new Vec3D(-1.4142134189605713, 0.0, 5.3644180297851562e-07),new Vec3D(-2.384185791015625e-07, 0.0, -1.4142135381698608),new Vec3D(1.4142136573791504, 0.0, 0.0),};
Vec3D n = new Vec3D(0.0, 1.0, 0.0);
print("xy: " + degrees(n.headingXY())+"\t");
print("xz: " + degrees(n.headingXZ())+"\t");
print("yz: " + degrees(n.headingYZ())+"\n");
println("angleBetween x: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween y: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween z: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("atan2 x: " + degrees(atan2(n.z,n.y)));
println("atan2 y: " + degrees(atan2(n.z,n.x)));
println("atan2 z: " + degrees(atan2(n.y,n.x)));
And here is the output:
xy: 90.0 xz: 0.0 yz: 90.0
angleBetween x: 90.0
angleBetween y: 90.0
angleBetween z: 90.0
atan2 x: 0.0
atan2 y: 0.0
atan2 z: 90.0
How can I get the rotation(around it's centre/normal) for Z of my quad ?
OK. I am frankly still not really clear on what it is you're looking for, but let me try to clarify the problem and then address my best guess as to what you really want and see if that helps.
As mentioned in the comment thread, a rotation is a transformation that maps one set of stuff (eg, vectors A, B, C...) to a different set of stuff (A', B', C'...). We can fully define this transformation in terms of an angle (call it θ) and an axis of rotation we'll call R.
Note that R is not a vector, it is a line. That means it has a location as well as a direction -- it is anchored somewhere in space -- and so you need either two points or a point and a direction vector to define it. For simplicity we might assume that the anchor point is the origin (0,0,0), since the question talks about the major axes X, Y and Z. In general, however, this need not be the case - if you want to determine rotation about arbitrary lines you will usually need to translate everything first so that the axis passes through the origin. (If all you care about is the orientation of your objects, rather than its position, then you can probably gloss over this issue.)
Given a start position A, end position A' and an axis R, it is conceptually straightforward to determine the angle θ (or an angle θ, since rotation is periodic and there are infinitely many θs that will take A to A'), though it can be a little fiddly for general R. In the simplest case, where R is one of the major axes, you can do something like this (for R = Z):
theta0 = atan2(A.x, A.y);
theta1 = atan2(A_prime.x, A_prime.y);
theta = theta1 - theta0;
In any case, it looks from your code as if you have the tools to do this already -- I'm not familiar with toxiclibs, but I would imagine the Vec3D angleBetween method ought to take you most of the way to the answer you want.
However, that presupposes that you know A, A' and R, and it seems like this is the real sticking point with your question. In the first place, you mention only a single set of points, defining an arbitrary quad. In the second, you talk about the normal as defining the centre of rotation. Both of these indicate that you haven't properly specified the problem.
As I have repeated tediously several times, a rotation is from one thing to another. A single set of quad vertices may define either the first state or the second, but not both (unless θ is 0, in which case the question is trivial). If you want to determine "the rotation of the quad", you need also to say "from an earlier position P" or "to a subsequent position Q", which you have not done.
Given that the particular quad in question is a square, you might think that there's an intuitive other position involved, to wit: with the sides axis-aligned. And we can indeed rather easily determine the angle of rotation required to get to that orientation, if we can assume that the quad is a rectangle:
// A and B are adjacent corners of the square
// B - A is the direction of the edge joining them
// theta is the angle between that side and the X axis
// (rotating by -theta around Z should align the square)
theta = atan2(B.x - A.x, B.y - A.y);
But, you made a point of stating that you might be looking at any arbitrary quad, for which there would be no "natural" base position to compare against. And even in the square case it is frankly not good practice to presume a baseline without explicitly declaring it.
Which brings us back to my original question: what do you mean? If you can actually pin that down properly I suspect you will find the problem itself relatively easy to solve.
EDIT: Based on your comments below, what you really want to do is to find a rotation that aligns your quad with one of the major planes. This is equivalent to rotating the quad's normal to align with the axis perpendicular to that plane: eg, to get the quad parallel to the XY plane, align its normal with the Z axis.
This can notionally be done with a single rotation about some calculated axis, but in practice you will decompose it into two rotations about major axes. The first rotates about the target axis until the vector is in the plane containing that axis and one of the others; then rotate around the third axis to get the normal to its final alignment. A verbal description is inevitably clunky, so let's formalise a bit:
Let's say you have a planar object Q, with vertices {v1, v2, v3, ...} (in your quad case there will be four of these, but it could be any number as long as all the points are coplanar), with unit normal n = (x y z)T. For the sake of explanation, let's arbitrarily assume that we want to align the object with the XY plane, and hence to rotate n to the Z axis -- the process would be essentially the same for XZ/Y or YZ/X.
Rotate around Z to get n into the XZ plane. We can calculate the angle required like this:
theta1 = -atan2(x,y);
However, we only need the sine and cosine to build a rotation matrix, and we can calculate these directly without knowing the angle:
hypoXY = sqrt(x*x + y*y);
c1 = x/hypoXY;
s1 = y/hypoXY;
(Obviously, if hypoXY is 0 this fails, but in that case n is already aligned with Z.)
Our first rotation matrix R1 looks like this:
[ c1 s1 0 ]
[ -s1 c1 0 ]
[ 0 0 1 ]
Next, rotate around Y to get n parallel to Z. Note that the previous rotation has moved x to a new position x' = sqrt(x2 + y2), so we need to account for this in calculating our second angle:
theta2 = -atan2(z, sqrt(x*x + y*y));
Again, we don't actually need theta2. And because we defined n to be a unit vector, our next calculations are easy:
c2 = z;
s2 = hypoXY;
Our second rotation matrix R2 looks like this:
[ c2 0 -s2 ]
[ 0 1 0 ]
[ s2 0 c2 ]
Compose the two together to get R = R2.R1:
[ c2c1 c2s1 -s2 ]
[ -s1 c1 0 ]
[ s2c1 s2s1 c2 ]
If you apply this matrix to n, you should get the normal aligned with the Z axis. (If not, check the signs first -- this is all a bit back of an envelope and I could easily have got some of the directions wrong. I don't have time to code it up and check right now, but will try to give it a go later. I'll also try to look over your sketch code then.)
Once that works, apply the same transformation to all the points in your object Q and it should become parallel to (although likely offset from) the XY plane.
Here is the rotation matrix for the z axis
cos(theta) sin(theta) 0
-sin(theta) cos(theta) 0
0 0 1
your vector
the result is the rotated vector

Resources