Finding the coordinates of a point contained by a trapezoid programmatically - math

If I have a trapezoid defined by four points (x1, y1), (x2, y2), (x3, y3), (x4, y4) (chosen as (255, 0), (255, 235), (200, 35), and (200, 235) for the sake of the example), and I divide it arbitrarily in n by m sections like so (pardon the crude drawing):
How could I find the coordinates of (x, y)?
I've tried fooling around with the slopes of the lines, but my math skills are too rusty to figure it out. Any ideas?

For the specific case as per your example it's quite straight forward.
First, the x location is easy. Since the verticals will always be parallel to the y axis, x is simply x width divided by the number of sections:
x = x1+((x2-x1)/a*xa)
where:
x = result coordinate
x1,x2 = edges of the trapezoid
a = number of sections
xa = x coordinate in term of sections
note: I chose a to avoid confusion with the symbol for slope: m.
For y it's a bit more complicated. We first need to find the coordinate that sits on the top and bottom lines of the trapezoid. We use the standard line equation for this:
y = mx+c
Finding m is simple. It's just Dy/Dx:
m = (y2-y1)/(x2-x1)
To get c we just substitute x, y and m into the formula:
c = y-mx
Once we get that, substitute the value of x found earlier into the formula to get the y coordinate. Do this twice to get the points on the top and bottom lines:
1 A 2
x------------x--------------x
| | |
| xC |
| | |
x------------x--------------x
3 B 4
All together (pseudocode):
coordinateFromSection (x1 y1 x2 y2 x3 y3 x4 y4 gridX gridY sectionX sectionY) {
xC = x1+((x2-x1)/gridX*sectionX)
// top line:
m = (y2-y1)/(x2-x1)
c = y1-(m*x1)
yA = m*xC + c
// bottom line:
m = (y4-y3)/(x4-x3)
c = y3-(m*x3)
yB = m*xC + c
// Find yC by dividing line AB by gridY
yC = yA+((yB-yA)/gridY*sectionY)
return (xC yC)
}
All the calculations above assume that (0,0) is the top left of the screen.

Related

Positioning objects parallel with a mesh

I'm trying to align multiple line objects along a human body circumference depending on the orientation of the triangles from the mesh. I would like to put the lines parallel to the mesh. I correctly assign the position for the lines along the circumference, but I also need to add the rotation of the lines such that to be parallel with the body.
The body is a mesh formed by multiple triangles and every line is "linked" with a triangle.
All I have is:
3 points for the closest triangle from the mesh for every line
The normal of the triangle
The positions for the instantiated lines (2 points, start and end)
I need to calculate the angle for every X, Y, Z axes for the line such that the normal of the triangle is perpendicular with the line mesh. I don't know how to get the desired angle. I really appreciate if someone would like to help me.
input:
FVector TrianglePoints[3];
FVector Triangle_Normal; //Calculated as (B-A)^(C-A), where A,B,C are the points of the triangle
FVector linePosition; //I also have the start line and the endLine position if that helps
ouput:
//FRotator rotation(x,y,z), such that the triangle normal and the line object to be perpendicular.
An overview of the circumference line construction. Now the rotation is calculated using the Start position and End position for each line. When we cross some irregular parts of the mesh we want to rotate the lines correctly. Now the rotation is fixed, depending just on the line start and end position.
If I have understood correctly your goal, here is some related vector geometry:
A,B,C are the vertices of the triangle:
A = [xA, yA, zA],
B = [xB, yB, zB]
C = [xC, yC, zC]
K,L are the endpoints of the line-segment:
K = [xK, yK, zK]
L = [xL, yL, zL]
vectors are interpreted as row-vectors
by . I denote matrix multiplication
by x I denote cross product of 3D vectors
by t() I denote the transpose of a matrix
by | | I denote the norm (magnitude) of a vector
Goal: find the rotation matrix and rotation transformation of segment KL
around its midpoint, so that after rotation KL is parallel to the plane ABC
also, the rotation is the "minimal" angle rotation by witch we need to
rotate KL in order to make it parallel to ABC
AB = B - A
AC = C - A
KL = L - K
n = AB x AC
n = n / |n|
u = KL x n
u = u / |u|
v = n x u
cos = ( KL . t(v) ) / |KL|
sin = ( KL . t(n) ) / |KL|
U = [[ u[0], u[1], u[2] ],
[ v[0], v[1], v[2] ],
[ n[0], n[1], n[2] ],
R = [[1, 0, 0],
[0, cos, sin],
[0, -sin, cos]]
ROT = t(U).R.U
then, one can rotate the segment KL around its midpoint
M = (K + L)/2
Y = M + ROT (X - M)
Here is a python script version
A = np.array([0,0,0])
B = np.array([3,0,0])
C = np.array([2,3,0])
K = np.array([ -1,0,1])
L = np.array([ 2,2,2])
KL = L-K
U = np.empty((3,3), dtype=float)
U[2,:] = np.cross(B-A, C-A)
U[2,:] = U[2,:] / np.linalg.norm(U[2,:])
U[0,:] = np.cross(KL, U[2,:])
U[0,:] = U[0,:] / np.linalg.norm(U[0,:])
U[1,:] = np.cross(U[2,:], U[0,:])
norm_KL = np.linalg.norm(KL)
cos_ = KL.dot(U[1,:]) / norm_KL
sin_ = KL.dot(U[2,:]) / norm_KL
R = np.array([[1, 0, 0],
[0, cos_, sin_],
[0,-sin_, cos_]])
ROT = (U.T).dot(R.dot(U))
M = (K+L) / 2
K_rot = M + ROT.dot( K - M )
L_rot = M + ROT.dot( L - M )
print(L_rot)
print(K_rot)
print(L_rot-K_rot)
print((L_rot-K_rot).dot(U[2,:]))
A more inspired solution was to use a procedural mesh, generated at runtime, that have all the requirements that I need:
Continuously along multiple vertices
Easy to apply a UV map for texture tiling
Can be updated at runtime
Isn't hard to compute/work with it

Get vertex value that shapes 90 degrees with triangle centroid

I have this triangle:
I'm trying to get the vertex value highlighted in the green circle in order to draw that red line. Is there any equation that I can use to extract that value?
The centroid vertex G = (x=5.5, y=1.5)
The other vertex B = (x=0, y=1)
and the last vertex C = (x=7, y=0)
Any help would be appreciated. I know it might be a 5th grade math but I can't think of a way to calculate this point.
If you throw away the majority of the triangle and just keep the vector B->G and the vector B->C then this problem shows itself to be a "vector projection" problem.
These are solved analytically using the dot product of the 2 vectors and are well documented elsewhere.
Took me 2 days to figure this out, you basically need to get the slopes for the base vector and the altitude vector (centroid), then solve this equation: y = m * x + b for both vectors (the base + altitude). Then you'll get 2 different equations that you need to use substitution to get the x first then apply that value to the 2nd equation to get the y. For more information watch this youtube tutorial:
https://www.youtube.com/watch?v=VuEbWkF5lcM
Here's the solution in PHP (pseudo) if anyone is interested:
//slope of base
$m1 = getSlope(baseVector);
//slope of altitude (invert and divide it by 1)
$m2 = 1/-$m1;
//points
$x1 = $baseVector->x;
$y1 = $baseVector->y;
//Centroid vertex
$x2 = $center['x'];
$y2 = $center['y'];
//altitude equation: y = m * x + b
//eq1: y1 = (m1 * x1) + b1 then find b1
$b1 = -($m1 * $x1) + $y1;
//equation: y = ($m1 * x) + $b1
//eq2: y2 = (m2 * x2) + b2 then find b2
$b2 = -($m2 * $x2) + $y2;
//equation: y = ($m2 * x) + $b2;
//substitute eq1 into eq2 and find x
//merge the equations (move the Xs to the left side and numbers on the right side)
$Xs = $m1 - $m2; //left side (number of Xs)
$Bs = $b2 - $b1; //right side
$x = $Bs / $Xs; //get x number
$y = ($m2 * $x) + $b2; //get y number

how do i transform between a static and a dynamic coordinate system

i have a setup like this:
2 coordinate systems. (x,y) is the main coordinate system and (x',y') is a coordinate system that lives inside (x,y). The system (x',y') is defined by the points x1 or x2 and if i move these 2 points around then (x',y') moves accordingly. The origin of (x',y') is defined as the middle of the vector going from x1 to x2, and the y' axis is the normal vector on x1->x2 going through the origin. If i have a point x3 defined in (x',y') and i move either of x1 or x2 to make the origin shift place, how do i then move x3 accordingly such that it maintains its position in the new (x',y') ?
And how do i make a transformation which always converts a point in (x,y) to a point in (x',y') nomatter how x1 and x2 have been set?
I was thinking that if i had more points than just the one i am moving (x1 or x2) i guess i could try to estimate theta, tx, ty of the transformation
[x2'] [cos(theta) , sin(theta), tx][x2]
[y2'] = [-sin(theta), cos(theta), ty][y2]
[ 1 ]  [ 0 , 0 , 1 ][1 ]
and just apply that estimated transformation to x3 and i would be good...mmm but i think i would need 3 points in order to estimate theta, tx and ty right?
I mean i could estimate using some least squares approach...but 3 unknowns requires 3 coordinate sets right?
I tried to implement this and calculate an example. I hope you understand the syntax. Its not really giving me what i expect:
import math
import numpy as np
x1=[ 0,10]
x2=[10,20]
rx = x2[0] - x1[0]
ry = x2[1] - x1[1]
rlen = math.sqrt(rx*rx+ry*ry)
c = rx / rlen
s = ry / rlen
dx = - ( x1[0] + x2[0] )/2 # changing the sign to be negative seems to
dy = - ( x1[1] + x2[1] )/2 # rectify translation. Rotation still is wrong
M = np.array([[c, -s, 0],[s, c, 0],[dx, dy, 1]])
print( np.dot(x2 + [1],M) )
# Yields -> [ 15.92031022 -8.63603897 1. ] and should yield [5,0,1]
Since I am trying to transform the x2 coordinate, should the result then not have the value 0 in the y-component since its located in the x-axis?
Ok, I tried doing the implementation for x3 from dynamic1 to dynamic2 which the check is that x3 should end up with the same coordinate in both d1 and d2. I did that as you suggested, but I do not get the same coordinate in both d1 and d2. Did i misunderstand something?
import math
import numpy as np
x1=[ 1,1]
x2=[ 7,9]
x3=[4,3]
rx = (x2[0] - x1[0])
ry = (x2[1] - x1[1])
rlen = math.sqrt( rx*rx + ry*ry )
c = rx / rlen
s = ry / rlen
dx = ( x1[0] + x2[0] )/2
dy = ( x1[1] + x2[1] )/2
M = np.array([[c, -s, 0],[s, c, 0],[-dx*c-dy*s, dx*s-dy*c, 1]])
Minv = np.array([[c, s, 0],[-s, c, 0],[dx, dy, 1]])
x1new=[ 1,1]
x2new=[ 17,4]
rxnew = (x2new[0] - x1new[0])
rynew = (x2new[1] - x1new[1])
rlennew = math.sqrt( rxnew*rxnew + rynew*rynew )
cnew = rxnew / rlennew
snew = rynew / rlennew
dxnew = ( x1new[0] + x2new[0] )/2
dynew = ( x1new[1] + x2new[1] )/2
Mnew = np.array([[cnew, -snew, 0],[snew, cnew, 0],[-dxnew*cnew-dynew*snew, dxnew*snew-dynew*cnew, 1]])
Mnewinv = np.array([[cnew, snew, 0],[-snew, cnew, 0],[dxnew, dynew, 1]])
M_dyn1_to_dyn2 = np.dot(Minv,Mnew)
print( np.dot(x3 + [1], M) )
print( np.dot(x3 + [1], M_dyn1_to_dyn2))
#yields these 2 outputs which should be the same:
[-1.6 -1.2 1. ]
[-3.53219692 8.29298408 1. ]
Edit. Matrix correction.
To translate coordinates from static system to (x1,x2) defined one, you have to apply affine transformation.
Matrix of this transformation M consists of shift matrix S and rotation about origin R.
Matrix M is combination of S and R:
c -s 0
M = s c 0
-dx*c-dy*s dx*s-dy*c 1
Here c and s are cosine and sine of rotation angle, their values are respectively x- and y- components of unit (normalized) vector x1x2.
rx = x2.x - x1.x
ry = x2.y - x1.y
len = Sqrt(rx*rx+ry*ry)
c = rx / Len
s = ry / Len
And shift components:
dx = (x1.x + x2.x)/2
dy = (x1.y + x2.y)/2
To translate (xx,yy) coordinates from static system to rotate one, we have to find
xx' = xx*c+yy*s-dx*c-dy*s = c*(xx-dx) + s*(yy-dy)
yy' = -xx*s+yy*c+dx*s-dy*c = -s*(xx-dx) + c*(yy-dy)
Quick check:
X1 = (1,1)
X2 = (7,9)
dx = 4
dy = 5
rx = 6
ry = 8
Len = 10
c = 0.6
s = 0.8
for point (4,5):
xx-dx = 0
yy-dy = 0
xx',yy' = (0, 0) - right
for point X2 =(7,9):
xx-dx = 3
yy-dy = 4
xx' = 0.6*3 + 0.8*4 = 5 -right
yy' = -0.8*3 + 0.6*4 = 0 -right
P.S. Note that matrix to transform dyn.coordinates to static ones is inverse of M and it is simpler:
c s 0
M' = -s c 0
dx dy 1
P.P.S. You need three pairs of corresponding points to define general affine transformations. It seems here you don't need scaling and sheer, so you may determine needed transform with your x1,x2 points
I think you need double dimension array to save and set your value in that
the structure gonna be like this
=============|========|========|
index number |x |y |
=============|========|========|
first point | [0][0] | [0][1] |
second point | [1][0] | [1][1] |
third point | [2][0] | [2][1] |
=============|========|========|
I will use java in my answer
//declare the double dimension array
double matrix[][] = new double[3][2];
//setting location first point, x
matrix[0][0] = 1;
//setting location first point, y
matrix[0][1] = 1;
//fill with your formula, i only give example
//fill second point with first point and plus 1
//setting location second point, x
matrix[1][0] = matrix[0][0] + 1;
//setting location second point, y
matrix[1][1] = matrix[0][1] + 1;
//fill with your formula, i only give example
//fill third point with second point and plus 1
//setting location third point, x
matrix[2][0] = matrix[1][0] + 1;
//setting location third point, y
matrix[2][1] = matrix[1][1] + 1;

Calculation of a perspective transformation matrix

Given a point in 3D space, how can I calculate a matrix in homogeneous coordinates which will project that point into the plane z == d, where the origin is the centre of projection.
OK, let's try to sort this out, expanding on Emmanuel's answer.
Assuming that your view vector is directly along the Z axis, all dimensions must be scaled by the ratio of the view plane distance d to the original z coordinate. That ratio is trivially d / z, giving:
x' = x * (d / z)
y' = y * (d / z)
z' = z * (d / z) ( = d)
In homogenous coordinates, it's usual to start with P = [x, y, z, w] where w == 1 and the transformation is done thus:
P' = M * P
The result will have w != 1, and to get the real 3D coordinates we normalise the homogenous vector by dividing the whole thing by its w component.
So, all we need is a matrix that given [x, y, z, 1] gives us [x * d, y * d, z * d, z], i.e.
| x' | = | d 0 0 0 | * | x |
| y' | = | 0 d 0 0 | * | y |
| z' | = | 0 0 d 0 | * | z |
| w' | = | 0 0 1 0 | * | 1 |
which once normalised (by dividing by w' == z) gives you:
[ x * d / z, y * d / z, d, 1 ]
per the first set of equations above
I guess the projection you mean, as Beta says, consists in the intersection between:
the line formed by the origin O(0, 0, 0) and the point P(a, b, c) to be transformed
and the plane z=d
If I'm right, then let's have a look at the equation of this line, given by the vectorial product OP ^ OM = 0 (let's remind that the equation of a line between 2 given points A and B is given by AB ^ AM = 0, with M(x, y, z); this is a vectorial product, so all are vectors: 0 represents the null vector, AB is the vector AB, etc):
bz - cy = 0
cx - az = 0
cz - bx = 0
With z = d, we then have only 2 linearily independent equations:
bd = cy
cx = ad
So this projection converts a point P(a, b, c) into a point P'(ad/c, bd/c, d). For homogeneous coordinates that gives:
P'(ad/c, bd/c, d) = P'(ad/c, bd/c, cd/c)
= P'(ad/c: bd/c: cd/c: 1)
= P'(a: b: c: d/c)
EDIT : the matrix I 1st found was:
1, 0, 0, 0
0, 1, 0, 0
A = 0, 0, 1, 0
0, 0, 0, d/c
but it uses c which is the a coordinate of the point P !! This is nonsense, I couldn't find an expression of A that does not use these coordinates. I may not be familiar enough with homogeneous coordinates.
the homogeneous transformation matrix is (Euler roll-pitch-yaw):
|r1 r2 r3 dx|
|r4 r5 r6 dy|
|r7 r8 r9 dz|
|px py pz sf|
r1-9 are the elements of the combined rotation matrix: Rx*Ry*Rz (work it out)
dx dy and dz are displacement vector (d) elements
px py and pz are the perspective vector (p) elements
sf is the scaling factor
from here on, if you use the inverse of this, you get your projection as a perspective in any arbitrary plane by feeding rotations of your target plane, as well as it's position of origin wrt the reference one in (keep perspective vector at 0 0 0 and sf=1 for pure kinematics), you get T->T* = T1. Get T1^-1 (for kinematics, this is simply R' (transposed,), horizontal concatenated by -R'*d, then vertical concatenated simply by 0 0 0 1).
can have multiple planes e.g. a,b,c as a chain, in which case T1 = Ta*Tb*Tc*...
then, v(new) = (T1^-1)*v(old), job done.

Code or formula for intersection of two parabolas in any rotation

I am working on a geometry problem that requires finding the intersection of two parabolic arcs in any rotation. I was able to intesect a line and a parabolic arc by rotating the plane to align the arc with an axis, but two parabolas cannot both align with an axis. I am working on deriving the formulas, but I would like to know if there is a resource already available for this.
I'd first define the equation for the parabolic arc in 2D without rotations:
x(t) = ax² + bx + c
y(t) = t;
You can now apply the rotation by building a rotation matrix:
s = sin(angle)
c = cos(angle)
matrix = | c -s |
| s c |
Apply that matrix and you'll get the rotated parametric equation:
x' (t) = x(t) * c - s*t;
y' (t) = x(t) * s + c*t;
This will give you two equations (for x and y) of your parabolic arcs.
Do that for both of your rotated arcs and subtract them. This gives you an equation like this:
xa'(t) = rotated equation of arc1 in x
ya'(t) = rotated equation of arc1 in y.
xb'(t) = rotated equation of arc2 in x
yb'(t) = rotated equation of arc2 in y.
t1 = parametric value of arc1
t2 = parametric value of arc2
0 = xa'(t1) - xb'(t2)
0 = ya'(t1) - yb'(t2)
Each of these equation is just a order 2 polynomial. These are easy to solve.
To find the intersection points you solve the above equation (e.g. find the roots).
You'll get up to two roots for each axis. Any root that is equal on x and y is an intersection point between the curves.
Getting the position is easy now: Just plug the root into your parametric equation and you can directly get x and y.
Unfortunately, the general answer requires solution of a fourth-order polynomial. If we transform coordinates so one of the two parabolas is in the standard form y=x^2, then the second parabola satisfies (ax+by)^2+cx+dy+e==0. To find the intersection, solve both simultaneously. Substituting in y=x^2 we see that the result is a fourth-order polynomial: (ax+bx^2)^2+cx+dx^2+e==0. Nils solution therefore won't work (his mistake: each one is a 2nd order polynomial in each variable separately, but together they're not).
It's easy if you have a CAS at hand.
See the solution in Mathematica.
Choose one parabola and change coordinates so its equation becomes y(x)=a x^2 (Normal form).
The other parabola will have the general form:
A x^2 + B x y + CC y^2 + DD x + EE y + F == 0
where B^2-4 A C ==0 (so it's a parabola)
Let's solve a numeric case:
p = {a -> 1, A -> 1, B -> 2, CC -> 1, DD -> 1, EE -> -1, F -> 1};
p1 = {ToRules#N#Reduce[
(A x^2 + B x y + CC y^2 + DD x + EE y +F /. {y -> a x^2 } /. p) == 0, x]}
{{x -> -2.11769}, {x -> -0.641445},
{x -> 0.379567- 0.76948 I},
{x -> 0.379567+ 0.76948 I}}
Let's plot it:
Show[{
Plot[a x^2 /. p, {x, -10, 10}, PlotRange -> {{-10, 10}, {-5, 5}}],
ContourPlot[(A x^2 + B x y + CC y^2 + DD x + EE y + F /. p) ==
0, {x, -10, 10}, {y, -10, 10}],
Graphics[{
PointSize[Large], Pink, Point[{x, x^2} /. p /. p1[[1]]],
PointSize[Large], Pink, Point[{x, x^2} /. p /. p1[[2]]]
}]}]
The general solution involves calculating the roots of:
4 A F + 4 A DD x + (4 A^2 + 4 a A EE) x^2 + 4 a A B x^3 + a^2 B^2 x^4 == 0
Which is done easily in any CAS.

Resources