Calculate transform of object, to make it line up with another - math

Say I have two rectangles, each with a 'connector' that points in a certain direction. The transform (location and angle) of the link is specified relative to the centre of its parent rectangle.
In the example below, rectangle A's link is (x: 0, y: -0.5, rotation: 0) while B's is (x: 0.5, y: 0, rotation: 45).
Two rectangles can 'plug in' to eachother by rotating such that their links have the same coordinates and face opposite directions.
I'm trying to figure out how to calculate the transform of rectangle B relative to rectangle A after they are linked.
In this case, rectangle A is (0, 0, 0), A's link is (0, 0.5, 0), B's link is (0, 0.5, 180) and B is (~0.3, ~-0.8, 135).
Does anyone know how to calculate B's final position in the above example?

So you have base points A0 and B0 and link points AL and BL
At first you move B0 by difference of AL and BL, so
B0' = B0 + AL - BL
Then you have to rotate this point around AL to provide final position
B0''.X = AL.X + (B0.X - BL.X) * Cos(D) - (B0.Y - BL.Y) * Sin(D)
B0''.Y = AL.Y + (B0.X - BL.X) * Sin(D) + (B0.Y - BL.Y) * Cos(D)
where D is angle of rotation
D = Pi - A_rotation - B_rotation

Related

How to find 3D points coordinates in a perpendicular plane to a given vector

I have two points in a 3d space, one point is (x,0,z) and the other one is the origin (0,0,0), through those points there is a passing line with length L that is starting from the first point and continuing after the origin point, in the end of this line there is a perpendicular (to the line) flat board with dimensions of W x H, the line ends in the middle of this board.
Assume that x,z,L,H,W are given, I need a way to find all the 3D points coordinates where those points forming a pixels image over the board (meaning each point has a distance of 1 from its left, right, top, bottom neighboring points).
Attached a pretty ugly drawing :) I made trying to illustrate the problem (I marked the pixels points with two question marks but I need them all).
Thanks.
It is possible to define that plane. But there is no selected direction to build a grid uniquelly.
Let we choose OY direction as base (because normal has zero Y-component).
So we have:
Normal vector N = (xx, 0, zz) //I renamed values to avoid confusion with coordinate
variables
Unit normal vector n = (nx, 0, nz), where
nx = xx / Sqrt(xx*xx+zz*zz)
nz = zz / Sqrt(xx*xx+zz*zz)
Base point
B = (bx, 0, bz) = (xx - nx * L, 0, zz - nz * L)
Unit base vector in the plane
dy = (0, 1, 0)
Another base vector
dc = dy x n //vector product
= (-bz, 0, bx)
Now it is possible to generate a grid, using integer indexes i, j in ranges (-W/2..W/2) and (-H/2.. H/2). Grid nodes coordinates:
x(i, j) = bx - j * bz
y(i, j) = 0 + i
z(i, j) = bz + j * bx

How to find points along arc if given initial point, ending point, random point + precision?

the precision is the number of points I want for my vector, from 0, the initial point of my arc, to the precision I want minus 1.
Code example in c++:
int precision = 20;
double pointInit[3] = {2,5,2};
double pointRandom[3] = {3,7,1};
double pointInit[3] = {0,-3,1};
std::vector<std::array<double,3>> pointArc;
std::array<double, 3> currentPoint;
// Fill the pointArc vector, from 0 (initial point) to precision -1 (ending point)
for (int i = 0 ; i < precision; i++)
{
// Find the value of the current point
// currentPoint[0] = ????;
// currentPoint[1] = ????;
// currentPoint[2] = ????;
pointArc.push_back(currentPoint);
}
EDIT : The arc I'm looking for is a circular arc
Use atan2() to find the angles of the endpoints with respect to the center, subtend the angle between them precision - 1 times, and convert the polar coordinates (use one of the endpoints to get the distance from the center) to rectangular form.
1) translate the three points so that P0 comes to the origin
2) consider the vectors P0P1 and P0P2 and form an orthonormal basis by the Gram-Schmidt process (this is easy)
3) in this new basis, the coordinates of the three points are (0, 0, 0), (X1, 0, 0), (X2, Y2, 0), and you have turned the 3D problem to 2D. (Actually X1=d(P0,P1) and X2, Y2 are obtained from the dot and cross products of P0P2 with P0P1 / X1)
The equation of a 2D circle through the origin is
x² + y² = 2Xc.x + 2Yc.y
Plugging the above coordinates, you easily solve the 2x2 system for Xc and Yc.
X1² = 2Xc.X1
X2² + Y2² = 2Xc.X2 + 2Yc.Y2
4) The parametric equation of the circle is
x = Xc + R cos(t)
y = Yc + R sin(t)
where R²=Xc²+Yc².
You can find the angles t0 and t2 corresponding to the endpoints with tan(t) = (y - Yc) / (x - Xc).
5) interpolate on the angle t0.(1-i/n) + t2.i/n, compute the reduced coordinates x, y from the parametric equation and apply the inverse transforms of 2) and 1).

Find Corners of Rectangle, Given Plane equation, height and width

Essentially I want to make a rectangular plane face an object at all times.
1) I have found my plane equation (ax + by + cz + d = 0)
2) I have the center point of the rectangle (P0 = (x0,y0,z0)), which lays on the plane.
3) I have the width and Height of the rectangle. (W, H)
4) I know that the top two corners of the rectangle will have equal Y values, this goes for bottom 2 corners also. (Y is my up and down axis, the rectangle top and bottom lines will always be parallel to the x,z plane)
Does anyone know how to find the x,y,z values of the four corners C1,C2,C3,C4?
Compute the vector from your plane center to the object you want to face. Call that vector V. Then normalize(V) = (a, b, c) and d = - a*x0 - b*y0 - c*z0. You have the equation for your plane.
Now you can rotate the plane however you want. If you to have the plane to have 0 roll (that is, only ever modify yaw and pitch), you can take the normalized cross product of the world "up" vector (0,0,1) and normalize(V) to get the horizontal vector U for the rectangle. Take the normalized cross product of normalize(V) and U to get the vertical vector W for the rectangle.
The corners of your rectangle are now:
C1 = P0 + (width / 2) * U + (height / 2) * W
C2 = P0 + (width / 2) * U - (height / 2) * W
C3 = P0 - (width / 2) * U + (height / 2) * W
C4 = P0 - (width / 2) * U - (height / 2) * W
Note that this approach has a singularity when the rectangle is directly above or below the object it is supposed to face. You should check for that if appropriate and handle it however makes sense in your scenario.

How to find point along arc in 3D given center, start & end points + radius + center angle?

If I have three points, let's say:
start: (14.5, 10.1, 2.8)
end: (-12.3, 6.4, 7.7)
center: (0, 0, 0)
And the following additional information that has been determined:
Radius: 15
Center Angle: 109 degrees
Arc (from Pt A - Pt B): 29
How can I approach finding points along the arc between the starting and ending points?
UPDATE: Vectors are marked with a °.
The normal n° of the plane p in which the circle (or the arc) lies is
n° = cross product of start°, end°
p contains all points X° satisfying the equation
dot product of n° and X° = 0
// ^^^ This is only for completeness, you needn't calculate it.
Now we want two orthogonal unit vectors X°, Y° lying in p:
X° = start° / norm(start°)
Y° = cross_prod(n°, start°) / norm(cross_prod(n°, start°))
(where norm(X°) is sqrt(x[1]^2 + x[2]^2 + x[3]^2),
and by dividing a vector V° by a scalar S I mean dividing each vector component by S:
V° / S := (V°[1]/S, V°[2]/S, V°[3]/S)
)
In 2d coordinates, we could draw a circle with the parametrization
t -> 15*(cos(t), sin(t)) = 15*cos(t) * X° + 15*sin(t) * Y°
where X° = (1, 0) and Y° = (0, 1).
Now in 3d in plane p, having two orthogonal unit vectors X° and Y°, we can analogically do
t -> 15*cos(t) * X° + 15*sin(t) * Y°
where X°, Y° as defined before, and t goes from 0 to 109 degrees.
For t=0, we get point start°. For t=109, we should get end°. If that goes wrong, change Y° to -Y°. For t between 0 and 109, we get the arc between start° and end°.
Depending on your sin/cos implementation, you need to specify the angles in radians, not degrees.

Knowing two points of a rectangle, how can I figure out the other two?

Hey there guys, I'm learning processing.js, and I've come across a mathematical problem, which I can't seem to solve with my limited geometry and trigonometry knowledge or by help of Wikipedia.
I need to draw a rectangle. To draw this rectangle, I need to know the coordinate points of each corner. All I know is x and y for the midpoints of the top and bottom of the box, and the length of all four sides.
There is no guarantee on the orientation of the box.
Any help? This seems like it should be easy, but it is really stumping me.
If this quadrilateral is a rectangle (all four angles are 90 degrees), then it can be solved. (if it could be any quadrilateral, then it is not solvable)
if the points are (x1,y1), and (x2, y2), and if the two points are not perfectly vertical (x1 = x2) or horizontal (y1 = y2), then the slope of one edge of the rectangle is
m1 = (y2-y1) / (x2-x1)
and the slope of the other edge is:
m2 = - 1 / m1
If you know the lengths of the sides, and the midpoints of two opposite sides, then the corrner points are easily determined by adding dx, dy to the midpoints: (if L is length of the sides that the midpoints are on)
dx = Sqrt( L^2 / (1 + m2^2) ) / 2
and
dy = m2 * dx
NOTE: if the points are vertically or horizontally aligned, this technique will not work, although the obvious solution for those degenerative cases is much simpler.
If you know your quadrilateral is a rectangle, then you can use some simple vector maths to find the coordinates of the corners. The knowns are:
(x1,y1) - the coordinate of the midpoint on the top line
(x2,y2) - the coordinate of the midpoint on the bottom line
l1 - the length of the top and bottom lines
l2 - the length of the other two lines
First, we find the vector between the two known points. This vector is parallel to the side lines:
(vx, vy) = (x2 - x1, y2 - y1)
We need to normalize this vector (i.e. make it length 1) so we can use it later as a basis to find our coordinates.
vlen = sqrt(vx*vx + vy*vy)
(v1x, v1y) = (vx / vlen, vy / vlen)
Next, we rotate this vector anticlockwise by 90 degrees. The rotated vector will be parallel to the top and bottom lines. 90 degree rotation turns out to just be swapping the coordinates and negating one of them. You can see this just by trying it out on paper. Or take at look at the equations for 2D rotations and substitute in 90 degrees.
(u1x, u1y) = (-v1y, v1x)
Now we have enough information to find the 'top-left' corner. We simply start at our point (x1, y1) and move back along that side by half the side length:
(p1x, p1y) = (x1 - u1x * l1 / 2, y1 - u1y * l1 / 2)
From here we can find the remaining points just by adding the appropriate multiples of our basis vectors. When implementing this you can obviously speed it up by only calculating each unique multiplication a single time:
(p2x, p2y) = (p1x + u1x * l1, p1y + u1y * l1)
(p3x, p3y) = (p1x + v1x * l2, p1y + v1y * l2)
(p4x, p4y) = (p3x + u1x * l1, p3y + u1y * l1)
function getFirstPoint(x1,y1,x2,y2,l1,l2)
distanceV = {x2 - x1, y2 - y1}
vlen = math.sqrt(distanceV[1]^2 + distanceV[2]^2)
normalized = {distanceV[1] / vlen, distanceV[2] / vlen}
rotated = {-normalized[2], normalized[1]}
p1 = {x1 - rotated[1] * l1 / 2, y1 - rotated[2] * l1 / 2}
p2 = {p1[1] + rotated[1] * l1, p1[2] + rotated[2] * l1}
p3 = {p1[1] + normalized[1] * l2, p1[2] + normalized[2] * l2}
p4 = {p3[1] + rotated[1] * l1, p3[2] + rotated[2] * l1}
points = { p1 , p2 , p3 , p4}
return p1
end
It's definitely a rectangle? Then you know the orientation of the short sides (they're parallel to the line between your points), and hence the orientation of the long sides.
You know the orientation and length of the long sides, and you know their midpoints, so it's straightforward to find the corners from there.
Implementation is left as an exercise to the reader.
This means that there will be two lines parallel to the line between the two points you have. Get the corners by translating the line you have 1/2 the length of the top side in each direction perpendicular to the line you have.
If you know the midpoint for the top, and the length of the top, then you know that the y will stay the same for both top corners, and the x will be the midpoint plus/minus the width of the rectangle. This will also be true for the bottom.
Once you have the four corners, there is no need to worry about the side lengths, as their points are the same as those used for the top and bottom.
midpoint
x,10 10,10 x,10
*--------------------------------------------*
width = 30
mx = midpoint x.
top left corner = (w/2) - mx or 15 - 10
top left corner coords = -5,10
mx = midpoint x.
top right corner = (w/2) + mx or 15 + 10
top left corner coords = 25,10
There's a difference between a "quadrilateral" and a "rectangle".
If you have the midpoint of the top and bottom, and the sides lengths, the rest is simple.
Given:
(x1, y1) -- (top_middle_x, top_middle_y) -- (x2, y1)
(x1, y2) -- (btm_middle_x, btm_middle_y) -- (x2, y2)
and top/bottom length along with right/left length.
x1 = top_middle_x - top/bottom_length / 2;
x2 = x1 + top/bottom_length;
y1 = top_middle_y
y2 = bottom_middle_y
Obviously, that's the simplest case and assuming that the line of (tmx, tmy) (bmx, bmy) is solely along the Y axis.
We'll call that line the "mid line".
The next trick is to take the mid line, and calculate it's rotational offset off the Y axis.
Now, my trig is super rusty.
dx = tmx - bmx, dy = tmy - bmy.
So, the tangent of the angle is dy / dx. The arctangent(dy / dx) is the angle of the line.
From that you can get your orientation.
(mind, there's some games with quadrants, and signs, and stuff to get this right -- but this is the gist of it.)
Once you have the orientation, you can "rotate" the line back to the Y axis. Look up 2D graphics for the math, it's straight forward.
That gets you your normal orientation. Then calculate the rectangles points, in this new normal form, and finally, rotate them back.
Viola. Rectangle.
Other things you can do is "rotate" a line that's half the length of the "top" line to where it's 90 deg of the mid line. So, say you have a mid line that's 45 degrees. You would start this line at tmx, tmy, and rotate this line 135 degrees (90 + 45). That point would be your "top left" corner. Rotate it -45 (45 - 90) to get the "top right" point. Then do something similar with the lower points.
Calculate the angle of the line joining the two midpoints using an arc-tangent function applied to the vector you get between them.
Subtract 90 degrees from that angle to get the direction of the top edge
Starting from the top-center point, move relative (1/2 top width x sin(angle), 1/2 top width x cos(angle)) - that gets the top right corner point.
Continue around the rectangle using the sin and cos of the angles and widths as appropriate
As a test: Check you made it back to the starting point
/* rcx = center x rectangle, rcy = center y rectangle, rw = width rectangle, rh = height rectangle, rr = rotation in radian from the rectangle (around it's center point) */
function toRectObjectFromCenter(rcx, rcy, rw, rh, rr){
var a = {
x: rcx+(Math.sin((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2)),
y: rcy-(Math.cos((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2))
};
var b = {
x: a.x+Math.cos(rr)*rw,
y: a.y+Math.sin(rr)*rw
};
var c = {
x: b.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
y: b.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
};
var d = {
x: a.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
y: a.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
};
return {a:a,b:b,c:c,d:d};
}

Resources