Issue
I am trying to calculate 4 points of a square in three dimensional space that is perpendicular to a line formed by two given points. This square must be:
- Perpendicular to the line defined by two given points
- Of thickness (or width/length) 1
- aligned so that two sides are always perpendicular to the Y axis
I have tried coding this myself, and i somewhat succeeded, but it is not exactly what i wanted. Here is a code snippet of what i have:
Note: Vert is a class that stores a coordinate in 3 variables, x, y, and z. FourVert is a class that stores 4 Verts, and the constructor is what i am trying to develop. The two Vert parameters are the given points, and the float t is the thickness or separation required between the output 4 points. Add is a function that add the given Vert's coordinate value as an offset to all 4 points of the FourVert. This is only used to reposition the points on the right place, the first Vert. I might have weird naming conventions, but i write it in a way that i understand it.
EDIT: Added comments as requested
public FourVert(Vert V1, Vert V2, float t)
{
float dx = V2.x - V1.x; //Position our points at the origin to convert into
float dy = V2.y - V1.y; //polar coordinates using Math.atan2();
float dz = V2.z - V1.z;
float d = (float) Math.sqrt(dx*dx+dz*dz); //Get the lateral distance to use
float axz = (float) -Math.atan2(dx, dz); //in relation with the y value to
float ady = (float) Math.atan2(d, dy); //calculate the altitude angle
float px = (float) (Math.cos(axz) * t);
float py = (float) (Math.cos(ady + 1.570796327) * t); //add half PI
float ny = (float) (Math.cos(ady - 1.570796327) * t);
float pz = (float) (Math.sin(axz) * t);
v1 = new Vert(px, py, pz); //Use the calculated values to produce 4 points
v2 = new Vert(-px, py, -pz); //v1, v2, v3, and v4 are our Vert fields of the
v3 = new Vert(-px, ny, -pz); //FourVert class
v4 = new Vert(px, ny, pz);
add(V1); //take our FourVert back to where we want it, not on the origin.
}
I already have the rendering taken care of, and i know it works well because i have tested it with givens.
What works here is the azimuth values, they function perfectly (Lateral movement). The vertical movement, or altitude, or 'pitch' does not function correctly. I have tried many other ways to do this to no avail.
The problem/part that is not working is here I think:
float py = (float) (Math.cos(ady + 1.570796327) * t);
float ny = (float) (Math.cos(ady - 1.570796327) * t);
Solution
I'd avoid all that trigonometry. For one of the edge directions, you want a vector which is at the same time perpendicular to V1 − V2 and to the Y axis. The cross product can be used to obtain a vector which is perpendicular to two given ones. So you compute it like this:
[ 0 ] [ x2 − x1 ] [ z2 − z1 ] [ dz ]
[ 1 ] × [ y2 - y1 ] = [ 0 ] = [ 0 ] = w₁
[ 0 ] [ z2 - z1 ] [ x1 − x2 ] [ −dx ]
For the second edge direction, you want to be perpendicular to that first one, and also perpendicular to V1 − V2 again. So the same story:
[ dz ] [ dx ] [ dx*dy ] [ ex ]
[ 0 ] × [ dy ] = [ − dx² − dz² ] =: [ ey ] = w₂
[ −dx ] [ dz ] [ dz*dy ] [ ez ]
You'll have to normalize these vectors to ensure they have length 1, then you are done. In. fact I'd normalize them to length ½ because then you can use ± that vector to describe positions which are symmetric around the origin, the way your own code does it as well. For the corners you then need ±w1±w2, which gives four possible sign combinations.
public FourVert(Vert V1, Vert V2, float t)
{
float dx = V2.x - V1.x;
float dy = V2.y - V1.y;
float dz = V2.z - V1.z;
float ex = dx*dz;
float ey = -dx*dx-dz*dz;
float ez = dz*dy;
float d = (float)(t/(2*Math.sqrt(dx*dx+dz*dz)));
float e = (float)(t/(2*Math.sqrt(ex*ex+ey*ey+ez*ez)));
dx *= d; dz *= d;
ex *= e; ey *= e; ez *= e;
v1 = new Vert( dz+ex, ey, -dx+ez);
v2 = new Vert( dz-ex, -ey, -dx-ez);
v3 = new Vert(-dz-ex, -ey, dx-ez);
v4 = new Vert(-dz+ex, ey, dx+ez);
add(V1);
}
You probably won't need this now any more, but for the sake of completeness: instead of
float py = (float) (Math.cos(ady + 1.570796327) * t);
float ny = (float) (Math.cos(ady - 1.570796327) * t);
I'd write
float py = (float) (-Math.sin(ady) * t);
float ny = (float) ( Math.sin(ady) * t);
This makes use of the fact that sin and cos differ by a phase of π/2.
Answered By - MvG