Math: how rotate a 3D point?

Pages: 12
see these image:
https://imgur.com/jAyagnH
1 - i only see half of square;
2 - the 'anglex' is printed using 'cout' i get that results :(

lastchance (6219): "angley and anglez are always 0 in your code, but who knows if that is relevant."
i only change to zero when if the 'angle' is more or igual than 360.

why the radians are too small values... why the square top isn't showed?

Note: when i changed the rotation center to the square center:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    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};
   
//or more or less.
the half square, the top, isn't showed :(
is these code correct:
1
2
3
4
//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);
Last edited on
i only change to zero when if the 'angle' is more or igual than 360.


No, you only change anglex. The other two are always zero. That's why I asked you to use the debugger.

why the radians are too small values... why the square top isn't showed?


Stop making vague statements, what are the values, why you think they are too small?

USE THE DEBUGGER
I think you should study the solution that was given to you (one that works), rather than waste a lot of time trying to see why your code didn't work.

At least do it on your own time, not ours.

I use a very old rotator I translated into c++, the closest I could find to your z/y/z order.
It works with my cube.
(rotator only)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
point RotationPoints(point pt, point Angle, point pivot={0,0,0},point scale={1,1,1})
{
 point p={pt.x-pivot.x,pt.y-pivot.y,pt.z-pivot.z};
 point rot,temp;
 temp={(p.y)*cos(Angle.x)+(-p.z)*sin(Angle.x),(p.z)*cos(Angle.x)+(p.y)*sin(Angle.x)};
 rot.y=temp.x;rot.z=temp.y;
 p.y = rot.y;p.z = rot.z;
 temp={(p.z)*cos(Angle.y)+(-p.x)*sin(Angle.y),(p.x)*cos(Angle.y)+(p.z)*sin(Angle.y)};
 rot.z=temp.x;rot.x=temp.y;
 p.x=rot.x;
 temp={(p.x)*cos(Angle.z)+(-p.y)*sin(Angle.z),(p.y)*cos(Angle.z)+(p.x)*sin(Angle.z)};
 rot.x=temp.x;rot.y=temp.y;
 return {(scale.x*rot.x+pivot.x),(scale.y*rot.y+pivot.y),(scale.z*rot.z+pivot.z)};
}
 

It slots into your code OK.
I just kept the scale in, set at {1,1,1} as default.
@Cambalinho, here's some of your code. Go away and think about it.

angley and anglez are never set to anything other than 0

You haven't decided whether you are adding 1 to anglex or multiplying it by pi/180 ... but you shouldn't be doing both.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    float anglex=0;
    float angley=0;
    float anglez=0;                          // anglex, angley and anglez are initialised to 0
    float PI =3.14159265358979323846;
    int angle=0;
	do
    {
//      Some rotations and drawing

        anglex+=1;                           // You update anglex ... but you don't touch angley or anglez
        angle+=1;
        if (angle>=360)                      // This is pointless
        {
            angle=0;
            anglex=0;
            angley=0;
            anglez=0;
        }

        //Degrees to Radians:
        anglez=anglez*PI/180;                // But anglez is still 0 anyway
        anglex=anglex*PI/180;                // What was the point of adding 1 before doing this?
        angley=angley*PI/180;

//      Other stuff
    }
Last edited on
@lastchance

I think the OP is trying to rotate 1 degree each time through the loop. But the rotation is around the x axis, not the z axis?

Also there were wrong variable names in the rotate function, which caused the wonky display.

The other pointless things were self assignment.

@Cambalinho

I think the big lesson here is naming the variables well, so you don't confuse yourself. Variable and function names should tell a story of what is happening in the code.

The things I mentioned here, you can work out yourself, with the debugger. That is what professional coders do.

now using the oggin (42) code, i get better results:
https://imgur.com/1HDVC3L
been rotation X or Y, i get the same problem: only half of the rectangle is showed.
oggin (42) why only half of the rectangle is showed\drawed correctly?
heres the entire code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include<math.h>
#include<iostream>
#include <windows.h>
#include <vector>

using namespace std;
 const double PI = 3.14159265358979;

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<point> GetPointsLine(point origin,point destination)
{
    point t=origin;
    vector<point> 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<point> 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);
        }
    }
}

angle ConvertDegreesToRadians(angle Rotation)
{

    double deg2Rad;
    deg2Rad = PI / 180;
    angle ConvertDegrees;
    ConvertDegrees.x = Rotation.x * deg2Rad;
    ConvertDegrees.y = Rotation.y * deg2Rad;
    ConvertDegrees.z = Rotation.z * deg2Rad;
    return ConvertDegrees;
}

point RotationPoints(point pt, angle Angle, point pivot={0,0,0},point scale={1,1,1})
{
    angle radians= ConvertDegreesToRadians(Angle);
    Angle.x =radians.x;
    Angle.y =radians.y;
    Angle.z =radians.z;
    point p={pt.x-pivot.x,pt.y-pivot.y,pt.z-pivot.z};
    point rot,temp;
    temp={(p.y)*cos(Angle.x)+(-p.z)*sin(Angle.x),(p.z)*cos(Angle.x)+(p.y)*sin(Angle.x)};
    rot.y=temp.x;rot.z=temp.y;
    p.y = rot.y;p.z = rot.z;
    temp={(p.z)*cos(Angle.y)+(-p.x)*sin(Angle.y),(p.x)*cos(Angle.y)+(p.z)*sin(Angle.y)};
    rot.z=temp.x;rot.x=temp.y;
    p.x=rot.x;
    temp={(p.x)*cos(Angle.z)+(-p.y)*sin(Angle.z),(p.y)*cos(Angle.z)+(p.x)*sin(Angle.z)};
    rot.x=temp.x;rot.y=temp.y;
    return {(scale.x*rot.x+pivot.x),(scale.y*rot.y+pivot.y),(scale.z*rot.z+pivot.z)};
}

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};//center of rectangle
    float anglex=0;
    float angley=0;
    float anglez=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);


        angley+=1;

        Sleep(100);
        RECT a;
        a.left=0;
        a.right=1000;
        a.top=0;
        a.bottom=1000;
        FillRect(WindowHDC,&a, CreateSolidBrush(RGB(0,0,0)));
    }while(!(GetKeyState(VK_ESCAPE) & 0x8000));//press escape for exit
    cout<<"Press return to end . . ."<<endl;
    cin.get();
}


TheIdeasMan (6574): i thot, in several situations, i was using right variables names.. well.. except the 'a' for 'clean' the screen.
i'm using the Code Blocks IDE.
i can execute the 'debugger', but no debugger window is showed.. is these normal?
the RotationPoint() must be different side a side face rectangle?
Last edited on

You should keep the original points intact and rotate with a separate variable
TopOrigin=RotationPoints(TopOrigin,{anglex,angley,anglez},RotationPoint);
i.e.
someothervariable=RotationPoints(TopOrigin,{anglex,angley,anglez},RotationPoint);
otherwise you get an ever increasing runaway.
i never thot that... so i changed it...
but i need ask: if the rotation Z do it normaly and correctly, why the X and Y rotation only draw half of the rectangle? the rest is arrown the screen :(

You have a lot of conditions in DrawLine.
You could apply perspective there (from my function) and just plot every point as it comes along.
YOUR CODE ADJUSTED:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

#include<math.h>
#include<iostream>
#include <windows.h>
#include <vector>

using namespace std;
 const double PI = 3.14159265358979;

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<point> GetPointsLine(point origin,point destination)
{
    point t=origin;
    vector<point> coordenates;
	float dst=GetLineLength(origin,destination);
	for (int i=0;i<=dst;i++)
    {
        t=lineto(t,destination,1);
        coordenates.push_back(t);
    }
    return coordenates;
}

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};
}
//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<point> coordenates;

    origin.z=-origin.z;
    destination.z=-destination.z;
    coordenates = GetPointsLine(origin,destination);
point eyepoint={250,150,300};
    //now we draw the line with a color and convert the 3D to 2D:
	for (point LinePoints:coordenates)
    {
    	point p=perspective(LinePoints,eyepoint);
    	SetPixel(WindowHDC,p.x,p.y,color);
 //SetPixel(WindowHDC,LinePoints.x,LinePoints.y,color);  // no perspective
 
 
        //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);
        //}
    }
}

angle ConvertDegreesToRadians(angle Rotation)
{

    double deg2Rad;
    deg2Rad = PI / 180;
    angle ConvertDegrees;
    ConvertDegrees.x = Rotation.x * deg2Rad;
    ConvertDegrees.y = Rotation.y * deg2Rad;
    ConvertDegrees.z = Rotation.z * deg2Rad;
    return ConvertDegrees;
}

point RotationPoints(point pt, angle Angle, point pivot={0,0,0},point scale={1,1,1})
{
    angle radians= ConvertDegreesToRadians(Angle);
    Angle.x =radians.x;
    Angle.y =radians.y;
    Angle.z =radians.z;
    point p={pt.x-pivot.x,pt.y-pivot.y,pt.z-pivot.z};
    point rot,temp;
    temp={(p.y)*cos(Angle.x)+(-p.z)*sin(Angle.x),(p.z)*cos(Angle.x)+(p.y)*sin(Angle.x)};
    rot.y=temp.x;rot.z=temp.y;
    p.y = rot.y;p.z = rot.z;
    temp={(p.z)*cos(Angle.y)+(-p.x)*sin(Angle.y),(p.x)*cos(Angle.y)+(p.z)*sin(Angle.y)};
    rot.z=temp.x;rot.x=temp.y;
    p.x=rot.x;
    temp={(p.x)*cos(Angle.z)+(-p.y)*sin(Angle.z),(p.y)*cos(Angle.z)+(p.x)*sin(Angle.z)};
    rot.x=temp.x;rot.y=temp.y;
    return {(scale.x*rot.x+pivot.x),(scale.y*rot.y+pivot.y),(scale.z*rot.z+pivot.z)};
}



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};//center of rectangle
    float anglex=0;
    float angley=0;
    float anglez=0;
    
	do
    {

        //Top:
       point TopOriginx=RotationPoints(TopOrigin,{anglex,angley,anglez},RotationPoint);
       point TopDestinationx=RotationPoints(TopDestination,{anglex,angley,anglez},RotationPoint);
        DrawLine(WindowHDC,TopOriginx,TopDestinationx);

        //Left:
        point LeftOriginx=RotationPoints(LeftOrigin,{anglex,angley,anglez},RotationPoint);
        point LeftDestinationx=RotationPoints(LeftDestination,{anglex,angley,anglez},RotationPoint);
        DrawLine(WindowHDC,LeftOriginx,LeftDestinationx);

        //Right:
        point RightOriginx=RotationPoints(RightOrigin,{anglex,angley,anglez},RotationPoint);
        point RightDestinationx=RotationPoints(RightDestination,{anglex,angley,anglez},RotationPoint);
        DrawLine(WindowHDC,RightOriginx,RightDestinationx);

        //Bottom:
        point BottomOriginx=RotationPoints(BottomOrigin,{anglex,angley,anglez},RotationPoint);
        point BottomDestinationx=RotationPoints(BottomDestination,{anglex,angley,anglez},RotationPoint);
        DrawLine(WindowHDC,BottomOriginx,BottomDestinationx);


        angley+=1;

        Sleep(10);
        RECT a;
        a.left=0;
        a.right=1000;
        a.top=0;
        a.bottom=1000;
        FillRect(WindowHDC,&a, CreateSolidBrush(RGB(0,0,0)));
    }while(!(GetKeyState(VK_ESCAPE) & 0x8000));//press escape for exit
    cout<<"Press return to end . . ."<<endl;
    cin.get();
}
 
 
@Cambalinho

@oggin is helping you a lot :+)

But for what it's worth, see the inconsistency here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;  // pointless self assignemnt
    RotatedPoint.z=RotatedPoint.y * sin(AngleCoordenate.y)+RotatedPoint.z*cos(AngleCoordenate.y);

    //Third we rotate the X:
    RotatedPoint.x=RotatedPoint.x;   // pointless self assignemnt
    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;
}


Actually I can see what you are doing here, it may not be wrong. But oggin's great suggestion of using all new variable names for the rotated points means one can have consistent naming, which is less confusing for a casual reader.

I still think it is misleading to call the rotations a singular angle, IMO RotationsXYZ would be better. Actually, the rotations could be stored in a std::array or std::vector and refer to them with indexes 0 ,1,2. When I did vector algebra at university, they taught us this because a user coordinate system may not be parallel with a world system, nor with the same origin. So now the variable name would just be Rotations

The use of Origin within variable names is also misleading: in my mind they are vertexes, or corners or points. Origin can mean where something starts, but here it is confusing IMO.

I don't know about windows graphics (so what I say here may be totally wrong), does it have a concept of a projection plane? In other systems, if points or lines in 3D are moved in front of the projection plane they are not displayed. There is a similar concept of a back plane. It may be possible this is happening by rotating around the X or Y axes, and it is happening before projection to the 2d surface. If so the solution would be to move the projection plane and back plane further away from the objects being drawn.

My other suggestion to try Qt, they have a lot of 3D graphics stuff. Don't worry about the license, it's free for personal use.

Another option which may cost money, is to use a CAD program, program it in C++. That way there are all kinds of options, like easily moving the viewpoint without having to do low level redraw every entity again.
Last edited on
Can't say that I've used Windows GDI before, but you can try this in a Windows command window.

g++ test.cpp -l gdi32

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <vector>
#include <utility>
#include <cmath>
#include <windows.h>
using namespace std;

const double PI = 4.0 * atan( 1.0 );
const double degToRad = PI / 180.0;

using matrix = vector< vector<double> >;

//======================================================================

struct Point
{
   double x, y, z;
   Point( double x = 0, double y = 0, double z = 0 ) : x( x ), y( y ), z( z ) {}
};

Point operator + ( const Point &a, const Point &b ){ return { a.x + b.x, a.y + b.y, a.z + b.z }; }
Point operator - ( const Point &a, const Point &b ){ return { a.x - b.x, a.y - b.y, a.z - b.z }; }
Point operator / ( const Point &a, double d       ){ return { a.x / d, a.y / d, a.z / d }; }
Point operator * ( double d      , const Point &a ){ return { d * a.x, d * a.y, d * a.z }; }
Point cross      ( const Point &a, const Point &b ){ return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }; }
double dot       ( const Point &a, const Point &b ){ return a.x * b.x + a.y * b.y + a.z * b.z; }
double normsq    ( const Point &a                 ){ return dot( a, a ); }
double len       ( const Point &a                 ){ return sqrt( normsq( a ) ); }
Point unit       ( const Point &a                 ){ return a / len( a ); }
ostream & operator << ( ostream &out, const Point a ){ return out << a.x << " " << a.y << " " << a.z << " "; }
                                                                                                                     
Point perspective( const Point &p, const Point &focus, double eye )
{
   double f = ( p.z - focus.z ) / ( eye - focus.z );
   return { focus.x + f * ( p.x - focus.x ), focus.y + f * ( p.y - focus.y ), p.z };
}
                                                                                                                     
Point operator * ( const matrix &M, const Point &v )
{
   return { M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z,
            M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z,
            M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z };
}

matrix operator * ( const matrix &M, const matrix &N )
{
   matrix R( M.size(), vector<double>( N[0].size(), 0.0 ) );
   for ( int i = 0; i < M.size(); i++ )
   {
      for ( int j = 0; j < N[0].size(); j++ )
      {
         for ( int k = 0; k < N.size(); k++ ) R[i][j] += M[i][k] * N[k][j];
      }
   }
   return R;
}

//======================================================================

matrix rotationMatrix( const Point &axis, double radians )              // Rotation matrix from axis and angle
{
   matrix result( 3, vector<double>( 3 ) );
   Point n = unit( axis );
   double cosA = cos( radians ), sinA = sin( radians ), cosA1 = 1.0 - cosA;
   result[0][0] = cosA + n.x * n.x * cosA1;
   result[0][1] =      + n.x * n.y * cosA1 - n.z * sinA;
   result[0][2] =      + n.x * n.z * cosA1 + n.y * sinA;
   result[1][0] =      + n.y * n.x * cosA1 + n.z * sinA;
   result[1][1] = cosA + n.y * n.y * cosA1;
   result[1][2] =      + n.y * n.z * cosA1 - n.x * sinA;
   result[2][0] =      + n.z * n.x * cosA1 - n.y * sinA;
   result[2][1] =      + n.z * n.y * cosA1 + n.x * sinA;
   result[2][2] = cosA + n.z * n.z * cosA1;
   return result;
}

//======================================================================

matrix rotationMatrix( const Point &EulerAngles )                       // Rotation matrix from Euler angles
{
   return rotationMatrix( { 0.0, 0.0, 1.0 }, EulerAngles.z )
        * rotationMatrix( { 0.0, 1.0, 0.0 }, EulerAngles.y )
        * rotationMatrix( { 1.0, 0.0, 0.0 }, EulerAngles.x );
}

//======================================================================

int main()
{
   vector<Point> vertices = { { 200, 100, 0 }, { 300, 100, 0 }, { 300, 200, 0 }, { 200, 200, 0 },
                              { 200, 100, 100 }, { 300, 100, 100 }, { 300, 200, 100 }, { 200, 200, 100 } };
   vector<pair<int,int>> lines = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 },
                                   { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } };
   Point centre = { 250, 150, 50 };
   Point focus  = centre - Point{ 0, 0, 300 };
   const double eye = 0.0;

   HDC WindowHDC = GetDC( GetConsoleWindow() );
   HPEN hpen = CreatePen( PS_SOLID, 1, RGB( 255, 0, 0 ) );
   HBRUSH background = CreateSolidBrush( RGB( 0, 0, 0 ) );
   
   double angley = 0.0;

   do
   {
      SelectObject( WindowHDC, hpen );
      for ( auto pr : lines )
      {
         matrix R = rotationMatrix( { 0.0, 1.0, 0.0 }, angley );
         Point p = perspective( centre + R * ( vertices[pr.first ] - centre ), focus, eye );
         Point q = perspective( centre + R * ( vertices[pr.second] - centre ), focus, eye );

         MoveToEx( WindowHDC, p.x, p.y, nullptr );
         LineTo  ( WindowHDC, q.x, q.y );
      }

      Sleep(10);
      RECT a;   a.left=0, a.right=1000, a.top=0, a.bottom=1000;
      FillRect( WindowHDC, &a, background );

      angley += 1.0 * degToRad;
   } while ( !( GetKeyState( VK_ESCAPE ) & 0x8000 ) );              //press escape for exit
}

Last edited on
@TheIdeasMan (6576):
on line 12:
RotatedPoint.y=RotatedPoint.y; // pointless self assignemnt
yes you have right.. here i can change the values without notice :(
some mistakes that we don't notice. maybe that was the problem why i was getting only half of the image.
thanks so much for speaking about my mistakes.


@oggin (44): i tested the otimizade code. and it's great.. thanks.
did you tested the code?
see the image. the line isn't completed, i know... it was the print time ;)
https://imgur.com/mmlEk5L
what i need understand is: why the bottom line is drawed dot\point yes and dot\point not.

@lastchance (6222): for all to all.. thank you

Cambalinho
It would be better to draw a line at a time (as per lastchance)
MoveToEx( WindowHDC, p.x, p.y, nullptr );
LineTo ( WindowHDC, q.x, q.y );

The way you do it is of course -- get every pixel around the shape and plot.
This way, the perspective function squeezes in the pixels at the far away side and stretches them out at the near side, thus showing gaps in the line at the near side.
Also if you use 4 lines you only need to rotate the four corners and apply perspective to them, so greatly optimised.
Also, in my first post I use a separate struct for angle, and in each loop I do
construct(A,ang);
This does all the sin(), cos() calculations and A is passed to the rotator which does not now need to process sin() or cos().
For many points this optimisation saves CPU and time.




i draw 1 line point by point because i will draw an image using these way.
unless theres another function much more faster?
bitblt() don't draw using some points
i need understand, on rotation or perspective: why i get several wholes on image\fillrectangle?
heres the entire code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <iostream>
#include <string>
#include <string.h>
#include <windows.h>
#include <math.h>
#include <vector>
#include <gdiplus.h>
#include <stdlib.h>
#include <algorithm>
#include<thread>
using namespace Gdiplus;
using namespace std;

const double PI = 3.14159265358979;

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<point> GetPointsLine(point origin,point destination)
{
    point t=origin;
    vector<point> coordenates;
	float dst=GetLineLength(origin,destination);
	for (int i=0;i<=dst;i++)
    {
        t=lineto(t,destination,1);
        coordenates.push_back(t);
    }
    return coordenates;
}

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};
}

//Draw a Line:
void DrawLine(HDC WindowHDC,point origin,point destination,COLORREF color=RGB(255,0,0) )
{


    //Getting the Points of a line:
    vector<point> coordenates;

    origin.z=-origin.z;
    destination.z=-destination.z;
    coordenates = GetPointsLine(origin,destination);
    point eyepoint={250,150,300};
    //now we draw the line with a color and convert the 3D to 2D:
	for (point LinePoints:coordenates)
    {
    	point p=perspective(LinePoints,eyepoint);
    	SetPixel(WindowHDC,p.x,p.y,color);
    }
}

//Draw a DrawFillRectangle:
void DrawFillRectangle(HDC WindowHDC,point TopLeft,point TopRight, point BottomLeft, point BottomRight,COLORREF color=RGB(255,0,0) )
{

    point LeftLineOrigin=TopLeft;
    point LeftLineDestination=BottomLeft;

    point RightLineOrigin=TopRight;
    point RightLineDestination=BottomRight;

    vector<point> LeftLineDots=GetPointsLine(TopLeft,BottomLeft);
    vector<point> RightLineDots=GetPointsLine(TopRight, BottomRight);



    //now we draw the line with a color and convert the 3D to 2D:
	for (int Y=0; Y<LeftLineDots.size(); Y++)
    {

        point CenterLineOrigin=LeftLineDots[Y];
        point CenterLineDestination=RightLineDots[Y];
        vector<point> CenterLine=GetPointsLine(CenterLineOrigin,CenterLineDestination);
        for(point points:CenterLine)
        {
            point eyepoint={250.0,150.0,300.0};
            point p=perspective(points,eyepoint);
            SetPixel(WindowHDC,p.x,p.y,color);
        }

    }
}

angle ConvertDegreesToRadians(angle Rotation)
{

    double deg2Rad;
    deg2Rad = PI / 180;
    angle ConvertDegrees;
    ConvertDegrees.x = Rotation.x * deg2Rad;
    ConvertDegrees.y = Rotation.y * deg2Rad;
    ConvertDegrees.z = Rotation.z * deg2Rad;
    return ConvertDegrees;
}

point RotationPoints(point pt, angle Angle, point pivot={0,0,0},point scale={1,1,1})
{
    angle radians= ConvertDegreesToRadians(Angle);
    Angle.x =radians.x;
    Angle.y =radians.y;
    Angle.z =radians.z;
    point p={pt.x-pivot.x,pt.y-pivot.y,pt.z-pivot.z};
    point rot,temp;
    temp={(p.y)*cos(Angle.x)+(-p.z)*sin(Angle.x),(p.z)*cos(Angle.x)+(p.y)*sin(Angle.x)};
    rot.y=temp.x;rot.z=temp.y;
    p.y = rot.y;p.z = rot.z;
    temp={(p.z)*cos(Angle.y)+(-p.x)*sin(Angle.y),(p.x)*cos(Angle.y)+(p.z)*sin(Angle.y)};
    rot.z=temp.x;rot.x=temp.y;
    p.x=rot.x;
    temp={(p.x)*cos(Angle.z)+(-p.y)*sin(Angle.z),(p.y)*cos(Angle.z)+(p.x)*sin(Angle.z)};
    rot.x=temp.x;rot.y=temp.y;
    return {(scale.x*rot.x+pivot.x),(scale.y*rot.y+pivot.y),(scale.z*rot.z+pivot.z)};
}



int main()
{
     //getting the HDC Console Window:
    HDC WindowHDC=GetDC(GetConsoleWindow());
    point TopLeft={0.0,0.0};
    point TopRight={100.0,0.0};
    point BottomLeft={0.0,100.0};
    point BottomRight={100.0,100.0};

    angle angles;
	do
    {
        angles.z+=.1;
        TopLeft=RotationPoints(TopLeft,angles,{50.0,50.0});
        TopRight=RotationPoints(TopRight,angles,{50.0,50.0});
        BottomLeft=RotationPoints(BottomLeft,angles,{50.0,50.0});
        BottomRight=RotationPoints(BottomRight,angles,{50.0,50.0});


        DrawFillRectangle(WindowHDC,TopLeft,TopRight,BottomLeft,BottomRight);


        Sleep(100);
        RECT a;
        a.left=0;
        a.right=1000;
        a.top=0;
        a.bottom=1000;
        FillRect(WindowHDC,&a, CreateSolidBrush(RGB(0,0,0)));
    }while(!(GetKeyState(VK_ESCAPE) & 0x8000));//press escape for exit
    cout<<"Press return to end . . ."<<endl;
    cin.get();
}

image result: https://imgur.com/ocxbTfK
Last edited on
Topic archived. No new replies allowed.
Pages: 12