### Math: how rotate a 3D point?

Pages: 12
from these image i did a rotation function:
https://imgur.com/mNWt6GR
 ``1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556`` ``````struct point { float x,y,z; } ; struct angle { float x,y,z; } ; point RotationPoints(point Coordenate, angle AngleCoordenate) { point RotatedPoint; //First we rotate the Z: RotatedPoint.x=Coordenate.x * cos(AngleCoordenate.z)-Coordenate.y*sin(AngleCoordenate.z); RotatedPoint.y=Coordenate.x * sin(AngleCoordenate.z)+Coordenate.y*cos(AngleCoordenate.z); RotatedPoint.z=Coordenate.z; //Second we rotate the Y: RotatedPoint.x=RotatedPoint.x * cos(AngleCoordenate.y)+RotatedPoint.z*sin(AngleCoordenate.y); RotatedPoint.y=RotatedPoint.y; RotatedPoint.z=RotatedPoint.y * sin(AngleCoordenate.y)+RotatedPoint.z*cos(AngleCoordenate.y); //Third we rotate the X: RotatedPoint.x=RotatedPoint.x; RotatedPoint.y=RotatedPoint.y * cos(AngleCoordenate.x)-RotatedPoint.z*sin(AngleCoordenate.x); RotatedPoint.z=RotatedPoint.y * sin(AngleCoordenate.x)+RotatedPoint.z*cos(AngleCoordenate.x); return RotatedPoint; } //using it: //getting the HDC Console Window: HDC WindowHDC=GetDC(GetConsoleWindow()); point origin ={100,50,0}; point destination ={500,50,0}; //destination=RotationPoints(origin,{0,0,10}); float anglez=0; do { origin=RotationPoints(origin,{0,0,anglez}); DrawLine(WindowHDC,origin,destination); anglez+=1; if(anglez>=1000) anglez=0; //cout << "\t"<

but the angle seems limited for 75º or something:
https://imgur.com/9VQfn2q
what i'm doing wrong with my rotation calculation?
i miss two important things:
1 - the computer use Radians and not Degrees:
 ``12`` ``````//Degrees to Radians: anglez=anglez*3.24/180;``````

2 - how i add a rotation origin? by default is zero, but i need from it point
Last edited on
https://en.wikipedia.org/wiki/Rotation_matrix

what you generally have to do ends up being shorthand for 'move to the origin, rotate, move back'.
https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin

you need the first link to fully comprehend the second, though.
Last edited on
jonnin (9974): i'm sorry, but i need ask 1 thing: why i have 'scare' when i found, several searchs, use Matrix?

the links get you where you need to be. Getting there isn't easy; I remember spending some real time with these back when. But they actually just give you the answer -- its a fill in the blank 3x3 grid, you just need to trig of the angle and the offset point.
Last edited on
Cambalinho wrote:
 ``12`` ``````//Degrees to Radians: anglez=anglez*3.24/180;``````

Pi to 2 decimal places is 3.14. It would be better IMO to have 6 decimal places for a float.

C++20 has numeric constants https://en.cppreference.com/w/cpp/numeric/constants
Feature testing https://en.cppreference.com/w/cpp/feature_test

So it could be written :

 ``12345678`` ``````#if __cpp_lib_math_constants < 201907L // check for suitable compiler version requires c++20 #error "Requires C++20 for numeric constants" // compiler error if wrong version of compiler is used #include using namespace std::numbers; constexpr double DegToRad {pi/ 180.0} float anglezAsrad = anglez * DegToRad; // new variable name instead of overwriting the existing one. ``````

If you don't have c++20:

`const double DegToRad {std::acos(-1.0) / 180.0}`

I used `double` it doesn't hurt to have too much precision, the constant is calculated once at compile time. I guess one could have it as a `float` if is really going to be a worry. Change the 1.0 to `1.0f` and 180.0 to `180.0f` as well.

I always put floating point numbers with a figure after the decimal point, as in `180.0` not 180. If nothing else, it reinforces the idea the value is floating point, not an integer. It helps prevent errors such as integer division.
Last edited on
.0174533 is good enough for anything short of nasa levels.
@jonnin

As long as there are no typos, my method helps with that.

And as long as it is not applied to world coordinates. I routinely work with coordinates in the range of `10'000'000.000` , ideally one should calc accurately with the world coordinates before transforming to screen coordinates.

If the OP is just using screen coordinates throughout, then that is probably fine.
@jonnin: you said: "what you generally have to do ends up being shorthand for 'move to the origin, rotate, move back'."
but see these sample: a line have 1 points(origin and destination)... imagine if the origin rotation center is the destination point.... how i add the rotation point to the origin?
the RotationPoints() functions have the rotation calculations, but i don't know add the rotation center.. you said right, i did that on past... but i'm using a different rotation center.

@TheIdeasMan: i was doing faster, that's why i used '3.14' and not 6 decimals places. but i can change it ;)
Last edited on
sorry, that did not make much sense. you have 2 or more points to make a line, not 1.
you don't add the destination to the origin; its handled in the matrix multiply, so you fill in the blanks in the matrix.
if you wanted to do it by hand, you subtract every point ... point-destination puts the new origin at destination, rotate, and then add destination back. points are added component wise:
p3.x = p.x + p2.x
p3.y = p.y + p2.y
p3.z = p.z + p2.z

so the whole thing is
p3 = p-destination //OOP point class
p4 = rotate p3 (sin & cos of your angle find the new locations)
p3 = p4+destination;

p3 is now the rotated point in the original space.

Last edited on
 ``12345678910111213141516171819202122232425262728293031323334`` ``````point RotationPoints(point Coordenate, angle AngleCoordenate, point RotationCenter={0,0,0}) { point RotatedPoint; //for add the Rotation Point //we must sub the Rotation point with rotation center: Coordenate.x-=RotationCenter.x; Coordenate.y-=RotationCenter.y; Coordenate.z-=RotationCenter.z; //First we rotate the Z: RotatedPoint.x=Coordenate.x * cos(AngleCoordenate.z)-Coordenate.y*sin(AngleCoordenate.z); RotatedPoint.y=Coordenate.x * sin(AngleCoordenate.z)+Coordenate.y*cos(AngleCoordenate.z); RotatedPoint.z=Coordenate.z; //Second we rotate the Y: RotatedPoint.x=RotatedPoint.x * cos(AngleCoordenate.y)+RotatedPoint.z*sin(AngleCoordenate.y); RotatedPoint.y=RotatedPoint.y; RotatedPoint.z=RotatedPoint.y * sin(AngleCoordenate.y)+RotatedPoint.z*cos(AngleCoordenate.y); //Third we rotate the X: RotatedPoint.x=RotatedPoint.x; RotatedPoint.y=RotatedPoint.y * cos(AngleCoordenate.x)-RotatedPoint.z*sin(AngleCoordenate.x); RotatedPoint.z=RotatedPoint.y * sin(AngleCoordenate.x)+RotatedPoint.z*cos(AngleCoordenate.x); //after rotate the point //we add the rotation center: RotatedPoint.x+=RotationCenter.x; RotatedPoint.y+=RotationCenter.y; RotatedPoint.z+=RotationCenter.z; return RotatedPoint; }``````

now seems to work.
- the line is horizontal;
- the Z rotation make the line rotate like a clock(by it's rotation center);
- the X and Y rotation is ignored.... correct me: is these normal?
Cambalinho wrote:
- the X and Y rotation is ignored.... correct me: is these normal?

Of course it's not normal - but then neither is your approach.

You specified AngleCoordenate.x and AngleCoordenate.y both to be 0, so it will make a zero rotation about either of these axes.

Just use a rotation matrix to rotate about the origin. There's one here:
https://www.cplusplus.com/forum/beginner/268330/#msg1154590

If you want to rotate about a point other than the origin, then (as @jonnin explained):
- subtract the rotation centre (so that you get a relative displacement)
- rotate
- add back the vector describing the rotation centre.

BTW, you have largely ignored most of the advice given to you in both this thread and your previous one.

Edit: didn't see lastchance post

 - the X and Y rotation is ignored.... correct me: is these normal?

What values did you have for the angles? Can you prove with the debugger they haven't changed?

Or are you just looking at the graphics?

Show us what you called the function with.

By the way, the angles are not coordinates, IMO the variable would less confusing if it was named `XYZrotations`
Last edited on
using these values:
 ``12345678910111213141516171819202122`` ``````point origin ={200,100,0}; point destination ={200,200,0}; //destination=RotationPoints(origin,{0,0,10}); float anglez=0; do { //Degrees to Radians: anglez=anglez*3.24/180; origin=RotationPoints(origin,{0,0,anglez},destination); DrawLine(WindowHDC,origin,destination); anglez+=1; if(anglez>=360) anglez=0; //cout << "\t"<

rotate like a clock:
https://imgur.com/ocaF3vM
is a line... so isn't good test the X and Y rotation.... the best for test is a rectangle.
see the difference on main:
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263`` ``````int main() { //getting the HDC Console Window: HDC WindowHDC=GetDC(GetConsoleWindow()); point TopOrigin ={200,100,0}; point TopDestination ={300,100,0}; point LeftOrigin ={200,100,0}; point LeftDestination ={200,200,0}; point RightOrigin ={300,100,0}; point RightDestination ={300,200,0}; point BottomOrigin ={200,200,0}; point BottomDestination ={300,200,0}; point RotationPoint={250,150,0}; float anglex=0; float angley=0; float anglez=0; do { //Degrees to Radians: anglez=anglez*3.24/180; anglex=anglex*3.24/180; angley=angley*3.24/180; //Top: TopOrigin=RotationPoints(TopOrigin,{anglex,angley,anglez},RotationPoint); TopDestination=RotationPoints(TopDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,TopOrigin,TopDestination); //Left: LeftOrigin=RotationPoints(LeftOrigin,{anglex,angley,anglez},RotationPoint); LeftDestination=RotationPoints(LeftDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,LeftOrigin,LeftDestination); //Right: RightOrigin=RotationPoints(RightOrigin,{anglex,angley,anglez},RotationPoint); RightDestination=RotationPoints(RightDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,RightOrigin,RightDestination); //Bottom: BottomOrigin=RotationPoints(BottomOrigin,{anglex,angley,anglez},RotationPoint); BottomDestination=RotationPoints(BottomDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,BottomOrigin,BottomDestination); anglex+=1; if(anglex>=360) anglex=0; //cout << "\t"<

the rest of code is the same.
i'm changing the x angle: the rotation is done... but the rectangle top isn't showed :(
the rotation center it's rectangle center
https://imgur.com/kIToVjq
i fix that, but i need more help: using float i can't control the angle :(
https://imgur.com/TRzEjQa
after, thinking on what i see, 180º, i get that red lines outside the rectangle :(
but you see that float value angle :(
Last edited on

Here is my rotate with perspective.
I use g++ 64 bits.
Command line (needed in g++ to access Gdi)
-std=c++17 -l Gdi32 -l Gdiplus
Rotate the corners of a cube using a very basic Gdi graphics screen.
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124`` `````` #include #include #include #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c) using namespace std; using namespace Gdiplus; struct point { float x,y,z; } ; struct angle { float sx,sy,sz; float cx,cy,cz; } ; void construct(angle &res,const point &a) { res={sin(a.x),sin(a.y),sin(a.z),cos(a.x),cos(a.y),cos(a.z)}; } point rotate(const point &c,const point &p,const angle &a,const point &scale={1,1,1}) { float dx=p.x-c.x,dy=p.y-c.y,dz=p.z-c.z; return{(scale.x)*((a.cy*a.cz)*dx+(-a.cx*a.sz+a.sx*a.sy*a.cz)*dy+(a.sx*a.sz+a.cx*a.sy*a.cz)*dz)+c.x, (scale.y)*((a.cy*a.sz)*dx+(a.cx*a.cz+a.sx*a.sy*a.sz)*dy+(-a.sx*a.cz+a.cx*a.sy*a.sz)*dz)+c.y, (scale.z)*((-a.sy)*dx+(a.sx*a.cy)*dy+(a.cx*a.cy)*dz)+c.z}; } point perspective(const point &p,const point &eyepoint) { float w=1+(p.z/eyepoint.z); return {(p.x-eyepoint.x)/w+eyepoint.x, (p.y-eyepoint.y)/w+eyepoint.y, (p.z-eyepoint.z)/w+eyepoint.z}; } void bubblesort(point p[]) { for (int i=0;i<=6;i++) { for(int j=i+1;j<=7;j++) { if(p[i].z to end.",WS_OVERLAPPEDWINDOW | WS_VISIBLE,200,200,800,600,0,0,0,0); PAINTSTRUCT ps; HDC hdc2; hdc2=BeginPaint(mainwin, &ps); initpaint(hdc2); point ang; angle A; while (!(GetKeyState(VK_ESCAPE) & 0x8000)) { while (PeekMessage (&emsg, NULL, 0, 0, PM_REMOVE) > 0) { TranslateMessage (&emsg); DispatchMessage (&emsg); } // do the graphics BitBlt(GetDC(mainwin), 0,0, 800,600, 0,0,0, WHITENESS); ang.x+=.01; ang.y+=.01/2; ang.z+=.01/3; construct(A,ang); for(int n=0;n<=7;n++) { rot[n]=rotate({400,300,0},pts[n],A,{.5,.5,.5}); rot[n]=perspective(rot[n],{400,300,600}); } bubblesort(rot); draw(hdc2,rot); Sleep(1); } } ``````
- why my rotation isn't working correctly? i don't understand what i miss :(
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192`` ``````#include #include #include #include using namespace std; struct point { float x,y,z; } ; struct angle { float x,y,z; } ; float GetLineLength(point p1,point p2) { return sqrt( (p1.x-p2.x)* (p1.x-p2.x) + (p1.y-p2.y)* (p1.y-p2.y) + (p1.z-p2.z)* (p1.z-p2.z)); } //Get Points Line: point lineto(point fp,point p,float length) { point res; float L=GetLineLength(fp,p); res.x=fp.x+length*(p.x-fp.x)/L; res.y=fp.y+length*(p.y-fp.y)/L; res.z=fp.z+length*(p.z-fp.z)/L; return res; } vector GetPointsLine(point origin,point destination) { point t=origin; vector coordenates; float dst=GetLineLength(origin,destination); for (int i=0;i<=dst;i++) { t=lineto(t,destination,1); coordenates.push_back(t); } return coordenates; } //Draw a Line: void DrawLine(HDC WindowHDC,point origin,point destination,COLORREF color=RGB(255,0,0) ) { //for convert 3D to 2D we must: //have Focal Distance, in these case is 100 //2D.X = 3D.X * FocalDistance / 3D.Z //2D.Y = 3D.Y * FocalDistance / 3D.Z float FocalDistance =100; //Getting the Points of a line: vector coordenates; origin.z=-origin.z; destination.z=-destination.z; coordenates = GetPointsLine(origin,destination); //now we draw the line with a color and convert the 3D to 2D: for (point LinePoints:coordenates) { if(LinePoints.z> 0) { float Coordenate2DX=LinePoints.x/LinePoints.z*FocalDistance; float Coordenate2DY=LinePoints.y/LinePoints.z*FocalDistance; if((Coordenate2DX>=0 || Coordenate2DY>=0) || (Coordenate2DX<=100 || Coordenate2DY<=100)) SetPixel(WindowHDC,Coordenate2DX,Coordenate2DY,color); } else { if((LinePoints.x>=0 || LinePoints.y>=0) || (LinePoints.x<=100 || LinePoints.y<=0)) SetPixel(WindowHDC,LinePoints.x,LinePoints.y,color); } } } point RotationPoints(point Coordenate, angle AngleCoordenate, point RotationCenter={0,0,0}) { point RotatedPoint; //for add the Rotation Point //we must sub the Rotation point with rotation center: Coordenate.x-=RotationCenter.x; Coordenate.y-=RotationCenter.y; Coordenate.z-=RotationCenter.z; //First we rotate the Z: RotatedPoint.x=Coordenate.x * cos(AngleCoordenate.z)-Coordenate.y*sin(AngleCoordenate.z); RotatedPoint.y=Coordenate.x * sin(AngleCoordenate.z)+Coordenate.y*cos(AngleCoordenate.z); RotatedPoint.z=Coordenate.z; //Second we rotate the Y: RotatedPoint.x=RotatedPoint.x * cos(AngleCoordenate.y)+RotatedPoint.z*sin(AngleCoordenate.y); RotatedPoint.y=RotatedPoint.y; RotatedPoint.z=-RotatedPoint.x * sin(AngleCoordenate.y)+RotatedPoint.z*cos(AngleCoordenate.y); //Third we rotate the X: RotatedPoint.x=RotatedPoint.x; RotatedPoint.y=RotatedPoint.y * cos(AngleCoordenate.x)-RotatedPoint.z*sin(AngleCoordenate.x); RotatedPoint.z=RotatedPoint.y * sin(AngleCoordenate.x)+RotatedPoint.z*cos(AngleCoordenate.x); //after rotate the point //we add the rotation center: RotatedPoint.x+=RotationCenter.x; RotatedPoint.y+=RotationCenter.y; RotatedPoint.z+=RotationCenter.z; return RotatedPoint; } int main() { //getting the HDC Console Window: HDC WindowHDC=GetDC(GetConsoleWindow()); point TopOrigin ={200,200,0}; point TopDestination ={300,200,0}; point LeftOrigin ={200,200,0}; point LeftDestination ={200,300,0}; point RightOrigin ={300,200,0}; point RightDestination ={300,300,0}; point BottomOrigin ={200,300,0}; point BottomDestination ={300,300,0}; point RotationPoint={250,250,0}; float anglex=0; float angley=0; float anglez=0; float PI =3.14159265358979323846; int angle=0; do { //Top: TopOrigin=RotationPoints(TopOrigin,{anglex,angley,anglez},RotationPoint); TopDestination=RotationPoints(TopDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,TopOrigin,TopDestination); //Left: LeftOrigin=RotationPoints(LeftOrigin,{anglex,angley,anglez},RotationPoint); LeftDestination=RotationPoints(LeftDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,LeftOrigin,LeftDestination); //Right: RightOrigin=RotationPoints(RightOrigin,{anglex,angley,anglez},RotationPoint); RightDestination=RotationPoints(RightDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,RightOrigin,RightDestination); //Bottom: BottomOrigin=RotationPoints(BottomOrigin,{anglex,angley,anglez},RotationPoint); BottomDestination=RotationPoints(BottomDestination,{anglex,angley,anglez},RotationPoint); DrawLine(WindowHDC,BottomOrigin,BottomDestination); anglex+=1; angle+=1; if (angle>=360) { angle=0; anglex=0; angley=0; anglez=0; } //Degrees to Radians: anglez=anglez*PI/180; anglex=anglex*PI/180; angley=angley*PI/180; cout << anglex; //cout << "\t"<
"isn't working correctly" isn't much help when it's difficult to see what you want.

angley and anglez are always 0 in your code, but who knows if that is relevant.
You really should be able to use the debugger by this stage. What is changing? What is not changing?

Edit:

I mentioned this before, it's not related to your problem. PI/180 is being calculated 3 times every time the code loops. Put this before the loop:

`constexpr float DegToRad = PI / 180.0;`
Last edited on
Pages: 12