三维图形的几何变换

  • Post author:
  • Post category:其他


原理:马华东老师的课件

代码:参考《计算机图形学原理及算法教程(Visual C++版)》—和青芳

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

typedef  double   array2d[4][4];
typedef  double   array[9];

class Matrix3D
{
public:
    /*
    变换矩阵
    T[0][0]~T[2][2] 对图形进行比例、旋转、对称等变换
    T[3][i]  i=0,1,2 对图形进行平移变换
    T[i][3]  i=0,1,2 对图形做透视投影变换
    T[3][3]  产生整体比例变换
    */
    array2d T;
    //立体顶点齐次坐标
    array XP, YP, ZP, CP;
    //立体顶点经变换后的坐标值
    array XT, YT, ZT;

public:
    void clearT();       //将变换矩阵清零
    void PriXYZ();       //立方体顶点齐次坐标
    void XCalculate();   //立方体顶点齐次坐标乘以变换矩阵T
    void Draw();         //绘制立方体

public:
    void drawOri();       //绘制原始立方体
    void translation(double dx, double dy, double dz);  //平移
    void scaling(double sx, double sy, double sz);      //缩放
    void mirror(int axis);                              //对称
    void rotation(int axis, double theta);  //绕某个轴逆时针旋转theta角度
    void shear(int axis, double a, double b);           //错切
};

//将变换矩阵清零
void Matrix3D::clearT()
{
    for(int i=0; i<4; i++)
        for(int j=0; j<4; j++)
            T[i][j] = 0;
}

//立方体顶点齐次坐标
void Matrix3D::PriXYZ()
{
    double pi = 3.14159;
    double cx = 320;
    double cy = 180;
    int ed = 2000, eh = 100, od = 400, hl = 1; 
    int h=80, r=100, n = 4, flag = 0, nn = 0; 
    double thy = 0.2, thx = 0.2;

    for(double th = 0; th <= 2*pi+0.1; th += 2*pi/n)
    {
        double x = r * cos(th); 
        double y = h; 
        double z = r * sin(th);

        double zw = z; 
        double xw = x;
        x = zw * cos(thy) - xw * sin(thy);
        z = zw * sin(thy) + xw * cos(thy);

        double yw = y;
        zw = z;
        y = yw * cos(thx) - zw * sin(thx);
        z = yw * sin(thx) + zw * cos(thx);

        XP[nn] = x; 
        YP[nn] = y; 
        ZP[nn] = z;
        nn++;
    }

    flag = 0;
    nn = 0;
    for(th=0; th <= 2*pi+0.1; th += 2*pi/n)
    {
        double x = r * cos(th); 
        double y = -h; 
        double z = r * sin(th);

        double zw = z; 
        double xw = x;
        x = zw * cos(thy) - xw * sin(thy);
        z = zw * sin(thy) + xw * cos(thy);

        double yw = y; 
        zw = z;
        y = yw * cos(thx) - zw * sin(thx);
        z = yw * sin(thx) + zw * cos(thx);

        XP[nn+4] = x; 
        YP[nn+4] = y; 
        ZP[nn+4] = z;
        nn++;
    }

    for(int i=0; i<8; i++)
        CP[i] = 1;  
}

//齐次坐标乘以变换矩阵
void  Matrix3D::XCalculate()
{
      PriXYZ();
      for (int i = 0; i < 8; i++ )
      {
         XT[i] = XP[i] * T[0][0] + YP[i] * T[1][0] + ZP[i] * T[2][0] + CP[i] * T[3][0];
         YT[i] = XP[i] * T[0][1] + YP[i] * T[1][1] + ZP[i] * T[2][1] + CP[i] * T[3][1];
         ZT[i] = XP[i] * T[0][2] + YP[i] * T[1][2] + ZP[i] * T[2][2] + CP[i] * T[3][2];
      }
}

//绘制立方体
void  Matrix3D::Draw() 
{
    CFrameWnd* pWnd  =(CFrameWnd*)AfxGetApp()->m_pMainWnd;
    CDC* pDC = pWnd->GetActiveView()->GetDC();
    double cx = 320;
    double cy = 180;
    XCalculate(); 
    array bx, by, bz;
    for (int i = 0; i < 4; i++ )
    {
        bx[i+4] = bx[i] = XT[i+4];
        by[i+4] = by[i] = YT[i+4];
        bz[i+4] = bz[i] = ZT[i+4];
    }
    for ( i = 0; i < 4; i++ )
    {
        XT[i+4] = XT[i];
        YT[i+4] = YT[i];
        ZT[i+4] = ZT[i];
    }

    for(i=0; i < 4; i++)
    {
        pDC->MoveTo(cx + XT[i], cy + YT[i]);
        pDC->LineTo(cx + XT[i], cy + YT[i]);
        pDC->LineTo(cx + XT[i+1], cy + YT[i+1]);
        pDC->LineTo(cx + bx[i+1], cy + by[i+1]);
        pDC->LineTo(cx + bx[i], cy + by[i]);
    }
    pWnd->GetActiveView()->ReleaseDC(pDC);
}

//绘制原始立方体
void Matrix3D::drawOri()
{
    clearT();
    for(int i=0; i<4; i++)
        T[i][i] = 1;
    Draw();
}

//平移
void Matrix3D::translation(double dx, double dy, double dz)
{
    clearT();
    for(int i=0; i<4; i++)
        T[i][i] = 1;
    T[3][0] = dx;    //x轴方向上平移
    T[3][1] = dy;    //y轴方向上平移
    T[3][2] = dz;    //z轴方向上平移
}

//缩放
void Matrix3D::scaling(double sx, double sy, double sz)
{
    clearT();
    T[0][0] = sx;    //x轴方向上缩放
    T[1][1] = sy;    //y轴方向上缩放
    T[2][2] = sz;    //z轴方向上缩放
}

//对称
void Matrix3D::mirror(int axis)
{
    clearT();
    for(int i=0; i<3; i++)
        T[i][i] = 1;
    if(axis == 0)       //关于平面YOZ对称
    {
        T[0][0] = -1;
    }
    else if(axis == 1)  //关于平面XOZ对称
    {
        T[1][1] = -1;
    }
    else if(axis == 2)  //关于平面XOY对称
    {
        T[2][2] = -1;
    }
    else if(axis == 3)  //关于x轴对称
    {
        for(i=1; i<4; i++)
            T[i][i] = -1;
    }
    else if(axis == 4)  //关于y轴对称
    {
        T[0][0] = T[3][3] = -1;
    }
    else if(axis == 5)  //关于z轴对称
    {
        T[0][0] = T[1][1] = -1;
    }
    else if(axis == 6)  //关于原点对称
    {
        for(i=0; i<3; i++)
            T[i][i] = -1;
    }
}

//绕某个轴,逆时针旋转theta度
void Matrix3D::rotation(int axis, double theta)
{
    clearT();
    if(axis == 0)      //绕X轴旋转
    {
        T[0][0] = 1;
        T[1][1] = cos(theta * 3.14 / 180);
        T[1][2] = sin(theta * 3.14 / 180);
        T[2][1] = -sin(theta * 3.14 / 180);
        T[2][2] = cos(theta * 3.14 / 180);
    }
    else if(axis == 1) //绕Y轴旋转
    {
        T[1][1] = 1;
        T[0][0] = cos(theta * 3.14 / 180);
        T[0][2] = -sin(theta * 3.14 / 180);
        T[2][0] = sin(theta * 3.14 / 180);
        T[2][2] = cos(theta * 3.14 / 180);
    }
    else               //绕Z轴旋转
    {
        T[2][2] = 1;
        T[0][0] = cos(theta * 3.14 / 180);
        T[0][1] = sin(theta * 3.14 / 180);
        T[1][0] = -sin(theta * 3.14 / 180);
        T[1][1] = cos(theta * 3.14 / 180);
    }
    T[3][3] = 1;
}

//错切
void Matrix3D::shear(int axis, double a, double b)
{
    clearT();
    for(int i=0; i<4; i++)
        T[i][i] = 1;
    if(axis == 0)         //沿x轴错切
    {
        T[1][0] = a;   //含y错切
        T[2][0] = b;   //含z错切
    }
    else if(axis == 1)    //沿y轴错切
    {
        T[0][1] = a;   //含x错切
        T[2][1] = b;   //含z错切
    }
    else if(axis == 2)    //研z轴错切
    {
        T[0][2] = a;   //含x错切
        T[1][2] = b;   //含y错切
    }
}

void CMy3DchangeView::OnDraw(CDC* pDC)
{
    CMy3DchangeDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here 

    Matrix3D m;
    //原始立方体
    //m.drawOri();

    //平移
    //m.translation(200, 0, 0);

    //缩放
    //m.scaling(2, 1, 2);

    //对称
    //m.mirror(0);  //关于YOZ对称
    //m.mirror(1);  //关于XOZ对称
    //m.mirror(2);  //关于XOY对称

    //旋转
    //m.rotation(0, -60);  //绕x轴顺时针旋转60度
    //m.rotation(1, -60);  //绕y轴顺时针旋转60度
    //m.rotation(2, -60);  //绕z轴顺时针旋转60度

    //错切
    m.shear(0, 2, 0);    //沿x轴含y为2,含z为0的错切
    //m.shear(1, 0, 1.1);  //沿y轴含x为0,含z为1.1的错切
    //m.shear(2, 1.2, 0);  //沿z轴含x为1.2,含y为0的错切---没有变化?

    m.Draw();
}

平移

这里写图片描述

缩放

这里写图片描述

关于YOZ对称

这里写图片描述

绕x轴顺时针旋转60度

这里写图片描述

沿x轴含y为2,含z为0的错切

这里写图片描述



版权声明:本文为u012319493原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。