27-Bezier球体算法

参考:https://www.bilibili.com/video/BV1cv4y1S7RL

球体用了8个双三次bezier曲面。  双三次Beizer曲面算法 详上一篇

球体八卦限,每个象限内一个曲面。共八个曲面

第一卦限坐标

  

完整代码:

// 27-Bezier球体算法
// 参考 https://www.bilibili.com/video/BV1cv4y1S7RL

#define UNICODE
#include <Windows.h>
#include <Windowsx.h>
#include <math.h>
#define WINDOW_TEXT L"27-Bezier球体算法"
#define ROUND(d) int(floor(d)+0.5)  // 四舍五入
#define PI        3.1415926

struct Point2  // 二维点
{
    double x;
    double y;
    double w;  // 齐次坐标
    Point2() :x(0), y(0), w(1) {}
    Point2(double x, double y) :x(x), y(y), w(1) {}

    friend Point2 operator + (Point2 pt0, Point2 pt1)
    {
        return  Point2(pt0.x + pt1.x, pt0.y + pt1.y);
    }

    friend Point2 operator * (Point2 pt, double n)
    {
        return  Point2(pt.x * n, pt.y * n);
    }

    friend Point2 operator * (double n, Point2 pt)
    {
        return  Point2(pt.x * n, pt.y * n);
    }
};

struct Point3 :Point2
{
    double z;
    Point3() :z(0) {}
    Point3(double x, double y, double z) :Point2(x, y), z(z) {}
    friend Point3 operator + (Point3 pt0, Point3 pt1)
    {
        return  Point3(pt0.x + pt1.x, pt0.y + pt1.y, pt0.z + pt1.z);
    }

    friend Point3 operator * (double scalar, const Point3& pt)
    {
        return  Point3(pt.x * scalar, pt.y * scalar, pt.z * scalar);
    }

    friend Point3 operator * (const Point3& pt, double scalar)
    {
        return  Point3(pt.x * scalar, pt.y * scalar, pt.z * scalar);
    }

    double DotProduct(const Point3& p0, const Point3& p1)   // 向量的点积
    {
        return(p0.x * p1.x + p0.y * p1.y + p0.z * p1.z);
    }

    Point3 CrossProduct(const Point3& v0, const Point3& v1) // 向量的叉积
    {
        return Point3(v0.y * v1.z - v0.z * v1.y,
            v0.z * v1.x - v0.x * v1.z,
            v0.x * v1.y - v0.y * v1.x);
    }
};

class Transform3
{
public:
    Point3* _P;          // 顶点数组
    int     _ptNumber;   // 顶点数量
    double  _M[4][4];    // 变换矩阵
public:
    Transform3() :_P(NULL), _ptNumber(0)
    {
        memset(_M, 0, sizeof(_M));
    };
    ~Transform3() {};

    void MultiplyMatrix()  //矩阵相乘
    {
        Point3* PTemp = new Point3[_ptNumber];
        for (int i = 0; i < _ptNumber; i++)
        {
            PTemp[i] = _P[i];
        }
        for (int i = 0; i < _ptNumber; i++)
        {
            _P[i].x = _M[0][0] * PTemp[i].x + _M[0][1] * PTemp[i].y + _M[0][2] * PTemp[i].z + _M[3][0]; // * PTemp[i].w
            _P[i].y = _M[1][0] * PTemp[i].x + _M[1][1] * PTemp[i].y + _M[1][2] * PTemp[i].z + _M[3][1]; // * PTemp[i].w
            _P[i].z = _M[2][0] * PTemp[i].x + _M[2][1] * PTemp[i].y + _M[2][2] * PTemp[i].z + _M[3][2]; // * PTemp[i].w
            _P[i].w = _M[3][0] * PTemp[i].x + _M[3][1] * PTemp[i].y + _M[3][2] * PTemp[i].z + _M[3][3]; // * PTemp[i].w
        }

        delete[]PTemp;
    }

    void SetMatrix(Point3* P, int ptNumber) //顶点数组初始化
    {
        _P = P;
        _ptNumber = ptNumber;
    }
    void Identity()
    {
        _M[0][0] = 1.0, _M[0][1] = 0.0, _M[0][2] = 0.0, _M[0][3] = 0.0;
        _M[1][0] = 0.0, _M[1][1] = 1.0, _M[1][2] = 0.0, _M[1][3] = 0.0;
        _M[2][0] = 0.0, _M[2][1] = 0.0, _M[2][2] = 1.0, _M[2][3] = 0.0;
        _M[3][0] = 0.0, _M[3][1] = 0.0, _M[3][2] = 0.0, _M[3][3] = 1.0;
    }

    void Translate(double tx, double ty, double tz)//平移变换
    {
        Identity();
        _M[3][0] = tx;
        _M[3][1] = ty;
        _M[3][2] = tz;
        MultiplyMatrix();
    }

    void Scale(double sx, double sy, double sz)//缩放变换
    {
        Identity();
        _M[0][0] = sx;
        _M[1][1] = sy;
        _M[2][2] = sz;
        MultiplyMatrix();
    }

    void RotateX(double beta)//绕X轴旋转变换
    {
        Identity();
        beta = beta * PI / 180;
        _M[1][1] = cos(beta), _M[1][2] = -sin(beta);
        _M[2][1] = sin(beta), _M[2][2] = cos(beta);
        MultiplyMatrix();
    }

    void  RotateY(double beta)//绕Y轴旋转变换
    {
        Identity();
        beta = beta * PI / 180;
        _M[0][0] = cos(beta), _M[0][2] = sin(beta);
        _M[2][0] = -sin(beta), _M[2][2] = cos(beta);
        MultiplyMatrix();
    }

};

struct  T2
{
    double u;
    double v;
    T2() :u(0), v(0) {}
    T2(double u, double v) :u(u), v(v) {}

    friend T2 operator+(const T2& t0, const T2& t1)
    {
        return T2(t0.u + t1.u, t0.v + t1.v);
    }

    friend T2 operator/(const T2& t, double n)
    {
        return T2(t.u / n, t.v / n);
    }

};

class Projection  // 透视投影
{
public:
    Point3 Eye;   // 视点
    double R;     // 视点球坐标
    double Phi;   // 
    double Theta; // 
    double D;     // 
    double K[8];  // 透视常数
public:
    Projection()
    {
        R = 1000;
        D = 800;
        Phi = 90;
        Theta = 0;      // 世界坐标z轴正上方 看向原点
        InitialParameter();
    }
    ~Projection() {}

    void InitialParameter() // 初始化参数
    {
        K[0] = sin(PI * Theta / 180);
        K[1] = sin(PI * Phi / 180);
        K[2] = cos(PI * Theta / 180);
        K[3] = cos(PI * Phi / 180);
        K[4] = K[1] * K[2];
        K[5] = K[0] * K[1];
        K[6] = K[2] * K[3];
        K[7] = K[0] * K[3];
        Eye = Point3(R * K[5], R * K[5], R * K[4]);  // 设置视点
    }

    void SetEye(double r, double phi, double theta)   // 设置视点
    {
        R = r;
        Phi = phi;
        Theta = theta;
        InitialParameter();
    }

    Point3 GetEye()
    {
        return Eye;
    }

    Point2 OrthographicProjection(Point3 worldPoint) // 正交投影
    {
        return Point2(worldPoint.x, worldPoint.y);
    }

    Point2 CavalierProjection(Point3 worldPoint)     // 斜等侧投影
    {
        Point2 screenPoint; // 屏幕坐标
        double cota = 1;
        double beta = PI / 4;
        screenPoint.x = worldPoint.x - worldPoint.z * cota * cos(beta);
        screenPoint.y = worldPoint.y - worldPoint.z * cota * cos(beta);
        return screenPoint;
    }

    Point2 CabinetProjection(Point3 worldPoint)      // 斜二侧投影
    {
        Point2 screenPoint; // 屏幕坐标
        double cota = 0.5;
        double beta = PI / 4;
        screenPoint.x = worldPoint.x - worldPoint.z * cota * cos(beta);
        screenPoint.y = worldPoint.y - worldPoint.z * cota * cos(beta);
        return screenPoint;
    }

    Point2 PerspectiveProjection2(Point3 worldPoint) // 二维透视投影
    {
        Point3 viewPoint;  // 观察坐标系
        viewPoint.x = K[2] * worldPoint.x - K[0] * worldPoint.z;
        viewPoint.y = -K[7] * worldPoint.x + K[1] * worldPoint.y - K[6] * worldPoint.z;
        viewPoint.z = -K[5] * worldPoint.x - K[3] * worldPoint.y - K[4] * worldPoint.z + R;

        Point2 screenPoint; // 屏幕坐标
        screenPoint.x = D * viewPoint.x / viewPoint.z;
        screenPoint.y = D * viewPoint.y / viewPoint.z;

        return screenPoint;
    }

};


class  BicubicBezierPatch  // 双三次Bezier曲面
{
public:
    Point3     P[4][4];     // 控制点
    Point3     GridP[4];    // 网格坐标
    Projection Proj;        // 投影

public:
    BicubicBezierPatch() {};
    ~BicubicBezierPatch() {};

    void ReadControlPoint(Point3 p[4][4])      // 读入控制点
    {
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                P[i][j] = p[i][j];
            }
        }


    }

    void DrawCurvedPatch(HDC hdc, int nRecursion) // 绘制递归曲面 nRecursion递归深度
    {
        T2 T[4];
        T[0] = T2(0, 0); T[1] = T2(1, 0);
        T[2] = T2(1, 1); T[3] = T2(0, 1);
        Tessellate(hdc, nRecursion, T);  // 递归函数
    }

    void Draw(HDC hdc) // 绘制四边形
    {

        Point2 point[4];
        for (int i = 0; i < 4; i++)
        {
            point[i] = Proj.PerspectiveProjection2(GridP[i]); // 正投影
        }
        MoveToEx(hdc, ROUND(point[0].x), ROUND(point[0].y), NULL);
        LineTo(hdc, ROUND(point[1].x), ROUND(point[1].y));
        LineTo(hdc, ROUND(point[2].x), ROUND(point[2].y));
        LineTo(hdc, ROUND(point[3].x), ROUND(point[3].y));
        LineTo(hdc, ROUND(point[0].x), ROUND(point[0].y));

    }

    void DrawControlGrid(HDC hdc) // 绘制控制网格
    {

        HPEN redPen = CreatePen(PS_SOLID, 4, RGB(180, 0, 0));
        HPEN bluePen = CreatePen(PS_SOLID, 2, RGB(0, 0, 180));
        HGDIOBJ oldObj = SelectObject(hdc, bluePen);

        Point2 P2[4][4];
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                P2[i][j] = Proj.PerspectiveProjection2(P[i][j]);  // 正投影
            }
        }

        for (int i = 0; i < 4; i++)
        {
            MoveToEx(hdc, ROUND(P2[i][0].x), ROUND(P2[i][0].y), NULL);
            for (int j = 0; j < 4; j++)
            {
                LineTo(hdc, ROUND(P2[i][j].x), ROUND(P2[i][j].y));
            }
        }

        for (int j = 0; j < 4; j++)
        {
            MoveToEx(hdc, ROUND(P2[0][j].x), ROUND(P2[0][j].y), NULL);
            for (int i = 0; i < 4; i++)
            {
                LineTo(hdc, ROUND(P2[i][j].x), ROUND(P2[i][j].y));
            }
        }

        SelectObject(hdc, redPen);
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                Ellipse(hdc, P2[i][j].x + 3, P2[i][j].y + 3, P2[i][j].x - 3, P2[i][j].y - 3);
            }
        }
        SelectObject(hdc, oldObj);
        DeletePen(redPen);
        DeletePen(bluePen);
    }

private:

    void Tessellate(HDC hdc, int nRecursion, T2* t) // 细分曲面
    {
        if (0 == nRecursion)
        {
            MeshGrid(hdc, t);
            Draw(hdc);
            return;
        }
        else
        {
            T2 midP = (t[0] + t[1] + t[2] + t[3]) / 4.0;
            T2 subT[4][4]; // 将定义域一分为四 (四叉树)

            // 左下子曲面
            subT[0][0] = t[0];
            subT[0][1] = T2(midP.u, t[0].v);
            subT[0][2] = midP;
            subT[0][3] = T2(t[0].u, midP.v);
            Tessellate(hdc, nRecursion - 1, subT[0]);

            // 右下子曲面
            subT[1][0] = T2(midP.u, t[1].v);
            subT[1][1] = t[1];
            subT[1][2] = T2(t[1].u, midP.v);
            subT[1][3] = midP;
            Tessellate(hdc, nRecursion - 1, subT[1]);

            // 右下子曲面
            subT[2][0] = midP;
            subT[2][1] = T2(t[2].u, midP.v);
            subT[2][2] = t[2];
            subT[2][3] = T2(midP.u, t[2].v);
            Tessellate(hdc, nRecursion - 1, subT[2]);

            // 左上子曲面
            subT[3][0] = T2(t[3].u, midP.v);
            subT[3][1] = midP;
            subT[3][2] = T2(midP.u, t[3].v);
            subT[3][3] = t[3];
            Tessellate(hdc, nRecursion - 1, subT[3]);


        }
    }

    void MeshGrid(HDC hdc, T2 t[4]) // 计算四边形网格
    {
        double M[4][4];   // 系数矩阵
        M[0][0] = -1.0;  M[0][1] = 3.0;  M[0][2] = -3.0;  M[0][3] = 1.0;
        M[1][0] = 3.0;  M[1][1] = -6.0;  M[1][2] = 3.0;  M[1][3] = 0.0;
        M[2][0] = -3.0;  M[2][1] = 3.0;  M[2][2] = 0.0;  M[2][3] = 0.0;
        M[3][0] = 1.0;  M[3][1] = 0.0;  M[3][2] = 0.0;  M[3][3] = 0.0;

        Point3 pTemp[4][4]; // 每次递归 控制点矩阵不变

        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                pTemp[i][j] = P[i][j];
            }
        }

        LeftMultiplyMatrix(M, pTemp);          // 控制顶点矩阵左乘系数矩阵
        TransposeMatrix(M);                   // 系数转置矩阵
        RightMultiplyMatrix(pTemp, M);         // 控制顶点矩阵右乘系数矩阵
        double u0, u1, u2, u3, v0, v1, v2, v3;// u,v 参数的幂
        for (int i = 0; i < 4; i++)
        {
            u3 = pow(t[i].u, 3.0); u2 = pow(t[i].u, 2.0); u1 = t[i].u; u0 = 1.0;
            v3 = pow(t[i].v, 3.0); v2 = pow(t[i].v, 2.0); v1 = t[i].v; v0 = 1.0;

            GridP[i] = (u3 * pTemp[0][0] + u2 * pTemp[1][0] + u1 * pTemp[2][0] + u0 * pTemp[3][0]) * v3
                + (u3 * pTemp[0][1] + u2 * pTemp[1][1] + u1 * pTemp[2][1] + u0 * pTemp[3][1]) * v2
                + (u3 * pTemp[0][2] + u2 * pTemp[1][2] + u1 * pTemp[2][2] + u0 * pTemp[3][2]) * v1
                + (u3 * pTemp[0][3] + u2 * pTemp[1][3] + u1 * pTemp[2][3] + u0 * pTemp[3][3]) * v0;
        }
    }

    void LeftMultiplyMatrix(double m[4][4], Point3 p[4][4]) // 控制顶点矩阵左乘系数矩阵
    {
        Point3 pTemp[4][4];//临时矩阵
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                pTemp[i][j] = m[i][0] * p[0][j] + m[i][1] * p[1][j] + m[i][2] * p[2][j] + m[i][3] * p[3][j];
            }

        }

        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                p[i][j] = pTemp[i][j];
            }
        }

    }

    void TransposeMatrix(double M[4][4])  // 转置矩阵
    {
        double pTemp[4][4];  // 临时矩阵
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                pTemp[j][i] = M[i][j];
            }
        }

        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                M[i][j] = pTemp[i][j];
            }
        }
    }

    void RightMultiplyMatrix(Point3 p[4][4], double m[4][4]) // 控制顶点矩阵右乘系数矩阵
    {
        Point3 pTemp[4][4]; // 临时矩阵
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                pTemp[i][j] = p[i][0] * m[0][j] + p[i][1] * m[1][j] + p[i][2] * m[2][j] + p[i][3] * m[3][j];

            }

        }

        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                p[i][j] = pTemp[i][j];
            }
        }

    }

};

class  Patch
{
public:
    int ptIndex[4][4];// 16个控制点索引号
};


class Sphere // 球
{
public:
    Point3 V[62];             // 球控制点
    Patch  P[8];              // 球曲面
    BicubicBezierPatch Patch; // Bezier曲面
public:
    Sphere() {};
    ~Sphere () {};
    void ReadPoint()  // 读取球控制点
    {
        const  double m = 0.5523;// 魔术常数 (绘制圆)
        // 第1卦限控制点
        V[ 0].x = 0;     V[ 0].y = 1;    V[ 0].z = 0;
        V[ 1].x = 0;     V[ 1].y = 1;    V[ 1].z = m;
        V[ 2].x = 0;     V[ 2].y = m;    V[ 2].z = 1;
        V[ 3].x = 0;     V[ 3].y = 0;    V[ 3].z = 1;
        V[ 4].x = m*m;   V[ 4].y = 1;    V[ 4].z = m;
        V[ 5].x = m;     V[ 5].y = m;    V[ 5].z = 1;
        V[ 6].x = m;     V[ 6].y = 0;    V[ 6].z = 1;
        V[ 7].x = m;     V[ 7].y = 1;    V[ 7].z = m*m;
        V[ 8].x = 1;     V[ 8].y = m;    V[ 8].z = m;
        V[ 9].x = 1;     V[ 9].y = 0;    V[ 9].z = m;
        V[10].x = m;     V[10].y = 1;    V[10].z = 0;
        V[11].x = 1;     V[11].y = m;    V[11].z = 0;
        V[12].x = 1;     V[12].y = 0;    V[12].z = 0;
                                         
        // 第2卦限控制点                   
        V[13].x = m;     V[13].y = 1;    V[13].z = -m*m;
        V[14].x = 1;     V[14].y = m;    V[14].z = -m;
        V[15].x = 1;     V[15].y = 0;    V[15].z = -m;
        V[16].x = m*m;   V[16].y = 1;    V[16].z = -m;
        V[17].x = m;     V[17].y = m;    V[17].z = -1;
        V[18].x = m;     V[18].y = 0;    V[18].z = -1;
        V[19].x = 0;     V[19].y = 1;    V[19].z = -m;
        V[20].x = 0;     V[20].y = m;    V[20].z = -1;
        V[21].x = 0;     V[21].y = 0;    V[21].z = -1;                                        
                                         
        // 第3卦限控制点                   
        V[22].x = -m*m;  V[22].y = 1;    V[22].z = -m;
        V[23].x = -m;    V[23].y = m;    V[23].z = -1;
        V[24].x = -m;    V[24].y = 0;    V[24].z = -1;
        V[25].x = -m;    V[25].y = 1;    V[25].z = -m*m;
        V[26].x = -1;    V[26].y = m;    V[26].z = -m;
        V[27].x = -1;    V[27].y = 0;    V[27].z = -m;
        V[28].x = -m;    V[28].y = 1;    V[28].z = 0;
        V[29].x = -1;    V[29].y = m;    V[29].z = 0;
        V[30].x = -1;    V[30].y = 0;    V[30].z = 0;       

        // 第4卦限控制点
        V[31].x = -m;     V[31].y = 1;   V[31].z = m * m;
        V[32].x = -1;     V[32].y = m;   V[32].z = m;
        V[33].x = -1;     V[33].y = 0;   V[33].z = m;
        V[34].x = -m * m; V[34].y = 1;   V[34].z = m;
        V[35].x = -m;     V[35].y = m;   V[35].z = 1;
        V[36].x = -m;     V[36].y = 0;   V[36].z = 1;                                        
                                         
        // 第5卦限控制点                   
        V[37].x = 0;     V[37].y = -m;   V[37].z = 1;
        V[38].x = 0;     V[38].y = -1;   V[38].z = m;
        V[39].x = m;     V[39].y = -m;   V[39].z = 1;
        V[40].x = m*m;   V[40].y = -1;   V[40].z = m;
        V[41].x = 1;     V[41].y = -m;   V[41].z = m;
        V[42].x = m;     V[42].y = -1;   V[42].z = m*m;
        V[43].x = 1;     V[43].y = -m;   V[43].z = 0;
        V[44].x = m;     V[44].y = -1;   V[44].z = 0;                                         
                                         
        // 第6卦限控制点                   
        V[45].x = 1;     V[45].y = -m;   V[45].z = -m;
        V[46].x = m;     V[46].y = -1;   V[46].z = -m*m;
        V[47].x = m;     V[47].y = -m;   V[47].z = -1;
        V[48].x = m*m;   V[48].y = -1;   V[48].z = -m;
        V[49].x = 0;     V[49].y = -m;   V[49].z = -1;
        V[50].x = 0;     V[50].y = -1;   V[50].z = -m;       

        // 第7卦限控制点                   
        V[51].x = -m;     V[51].y = -m;  V[51].z = -1;
        V[52].x = -m * m; V[52].y = -1;  V[52].z = -m;
        V[53].x = -1;     V[53].y = -m;  V[53].z = -m;
        V[54].x = -m;     V[54].y = -1;  V[54].z = -m * m;
        V[55].x = -1;     V[55].y = -m;  V[55].z = 0;
        V[56].x = -m;     V[56].y = -1;  V[56].z = 0;       

        // 第8卦限控制点
        V[57].x = -1;     V[57].y = -m;  V[57].z = m;
        V[58].x = -m;     V[58].y = -1;  V[58].z = m*m;
        V[59].x = -m;     V[59].y = -m;  V[59].z = 1;
        V[60].x = -m*m;   V[60].y = -1;  V[60].z = m;
        V[61].x = 0;      V[61].y = -1;  V[61].z = 0;
      
    }
    void ReadPath()   // 读取球面曲面片
    {
        // 第1卦限面片
        P[0].ptIndex[0][0] = 3;   P[0].ptIndex[0][1] = 2;   P[0].ptIndex[0][2] = 1;   P[0].ptIndex[0][3] = 0;
        P[0].ptIndex[1][0] = 6;   P[0].ptIndex[1][1] = 5;   P[0].ptIndex[1][2] = 4;   P[0].ptIndex[1][3] = 0;
        P[0].ptIndex[2][0] = 9;   P[0].ptIndex[2][1] = 8;   P[0].ptIndex[2][2] = 7;   P[0].ptIndex[2][3] = 0;
        P[0].ptIndex[3][0] = 12;  P[0].ptIndex[3][1] = 11;  P[0].ptIndex[3][2] = 10;  P[0].ptIndex[3][3] = 0;

        // 第2卦限面片
        P[1].ptIndex[0][0] = 12;  P[1].ptIndex[0][1] = 11;  P[1].ptIndex[0][2] = 10;  P[1].ptIndex[0][3] = 0;
        P[1].ptIndex[1][0] = 15;  P[1].ptIndex[1][1] = 14;  P[1].ptIndex[1][2] = 13;  P[1].ptIndex[1][3] = 0;
        P[1].ptIndex[2][0] = 18;  P[1].ptIndex[2][1] = 17;  P[1].ptIndex[2][2] = 16;  P[1].ptIndex[2][3] = 0;
        P[1].ptIndex[3][0] = 21;  P[1].ptIndex[3][1] = 20;  P[1].ptIndex[3][2] = 19;  P[1].ptIndex[3][3] = 0;

        // 第3卦限面片
        P[2].ptIndex[0][0] = 21;  P[2].ptIndex[0][1] = 20;  P[2].ptIndex[0][2] = 19;  P[2].ptIndex[0][3] = 0;
        P[2].ptIndex[1][0] = 24;  P[2].ptIndex[1][1] = 23;  P[2].ptIndex[1][2] = 22;  P[2].ptIndex[1][3] = 0;
        P[2].ptIndex[2][0] = 27;  P[2].ptIndex[2][1] = 26;  P[2].ptIndex[2][2] = 25;  P[2].ptIndex[2][3] = 0;
        P[2].ptIndex[3][0] = 30;  P[2].ptIndex[3][1] = 29;  P[2].ptIndex[3][2] = 28;  P[2].ptIndex[3][3] = 0;

        // 第4卦限面片
        P[3].ptIndex[0][0] = 30;  P[3].ptIndex[0][1] = 29;  P[3].ptIndex[0][2] = 28;  P[3].ptIndex[0][3] = 0;
        P[3].ptIndex[1][0] = 33;  P[3].ptIndex[1][1] = 32;  P[3].ptIndex[1][2] = 31;  P[3].ptIndex[1][3] = 0;
        P[3].ptIndex[2][0] = 36;  P[3].ptIndex[2][1] = 35;  P[3].ptIndex[2][2] = 34;  P[3].ptIndex[2][3] = 0;
        P[3].ptIndex[3][0] = 3;   P[3].ptIndex[3][1] = 2;   P[3].ptIndex[3][2] = 1;   P[3].ptIndex[3][3] = 0;

        // 第5卦限面片
        P[4].ptIndex[0][0] = 61;  P[4].ptIndex[0][1] = 38;  P[4].ptIndex[0][2] = 37;  P[4].ptIndex[0][3] = 3;
        P[4].ptIndex[1][0] = 61;  P[4].ptIndex[1][1] = 40;  P[4].ptIndex[1][2] = 39;  P[4].ptIndex[1][3] = 6;
        P[4].ptIndex[2][0] = 61;  P[4].ptIndex[2][1] = 42;  P[4].ptIndex[2][2] = 41;  P[4].ptIndex[2][3] = 9;
        P[4].ptIndex[3][0] = 61;  P[4].ptIndex[3][1] = 44;  P[4].ptIndex[3][2] = 43;  P[4].ptIndex[3][3] = 12;

        // 第6卦限面片
        P[5].ptIndex[0][0] = 61;  P[5].ptIndex[0][1] = 44;  P[5].ptIndex[0][2] = 43;  P[5].ptIndex[0][3] = 12;
        P[5].ptIndex[1][0] = 61;  P[5].ptIndex[1][1] = 46;  P[5].ptIndex[1][2] = 45;  P[5].ptIndex[1][3] = 15;
        P[5].ptIndex[2][0] = 61;  P[5].ptIndex[2][1] = 48;  P[5].ptIndex[2][2] = 47;  P[5].ptIndex[2][3] = 18;
        P[5].ptIndex[3][0] = 61;  P[5].ptIndex[3][1] = 50;  P[5].ptIndex[3][2] = 49;  P[5].ptIndex[3][3] = 21;

        // 第7卦限面片
        P[6].ptIndex[0][0] = 61;  P[6].ptIndex[0][1] = 50;  P[6].ptIndex[0][2] = 49;  P[6].ptIndex[0][3] = 21;
        P[6].ptIndex[1][0] = 61;  P[6].ptIndex[1][1] = 52;  P[6].ptIndex[1][2] = 51;  P[6].ptIndex[1][3] = 24;
        P[6].ptIndex[2][0] = 61;  P[6].ptIndex[2][1] = 54;  P[6].ptIndex[2][2] = 53;  P[6].ptIndex[2][3] = 27;
        P[6].ptIndex[3][0] = 61;  P[6].ptIndex[3][1] = 56;  P[6].ptIndex[3][2] = 55;  P[6].ptIndex[3][3] = 30;
        
        // 第8卦限面片
        P[7].ptIndex[0][0] = 61;  P[7].ptIndex[0][1] = 56;  P[7].ptIndex[0][2] = 55;  P[7].ptIndex[0][3] = 30;
        P[7].ptIndex[1][0] = 61;  P[7].ptIndex[1][1] = 58;  P[7].ptIndex[1][2] = 57;  P[7].ptIndex[1][3] = 33;
        P[7].ptIndex[2][0] = 61;  P[7].ptIndex[2][1] = 60;  P[7].ptIndex[2][2] = 59;  P[7].ptIndex[2][3] = 36;
        P[7].ptIndex[3][0] = 61;  P[7].ptIndex[3][1] = 38;  P[7].ptIndex[3][2] = 37;  P[7].ptIndex[3][3] = 3;
    }
    void Draw(HDC hdc) // 绘制
    {
        Point3 point[4][4];
        int n = 3;//递归深度
        for (int nPatch = 0; nPatch < 8; nPatch++)
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {                   
                    point[i][j] = V[P[nPatch].ptIndex[i][j]];
                }
            }

            Patch.ReadControlPoint(point);   // 读取控制点
            Patch.DrawCurvedPatch(hdc, n);   // 绘制曲面
            //Patch.DrawControlGrid(hdc);      // 绘制控制点
        }
    }
};


static bool     m_Play = false;
static wchar_t* m_str = L"左键旋转";

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static double alpha;
    static double beta;

    switch (uMsg)
    {
    case WM_TIMER:
        alpha += 1;
        beta += 1;
        InvalidateRect(hwnd, NULL, FALSE);
        return 0;

    case WM_LBUTTONDOWN:
        m_Play = !m_Play;
        if (m_Play)
        {
            SetTimer(hwnd, 0, 0, NULL);
        }
        else
        {
            KillTimer(hwnd, 0);
        }
        return 0;

    case WM_PAINT:
    {
        hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);

        SetMapMode(hdc, MM_ANISOTROPIC);
        SetWindowExtEx(hdc, rect.right, rect.bottom, NULL);
        SetViewportExtEx(hdc, rect.right, -rect.bottom, NULL);
        SetViewportOrgEx(hdc, rect.right / 2, rect.bottom / 2, NULL);

        // 内存DC
        HDC     memDC = CreateCompatibleDC(hdc);                                   // 创建兼容DC 画板
        HBITMAP newBitmap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);  // 创建画布
        HGDIOBJ oldBitmap = SelectObject(memDC, newBitmap);                        // 将画布选入画板
        FillRect(memDC, &rect, (HBRUSH)(COLOR_WINDOW + 1));
        DrawText(memDC, m_str, wcslen(m_str), &rect, NULL);

        SetMapMode(memDC, MM_ANISOTROPIC);
        SetWindowExtEx(memDC, rect.right, rect.bottom, NULL);
        SetViewportExtEx(memDC, rect.right, -rect.bottom, NULL);
        SetViewportOrgEx(memDC, rect.right / 2, rect.bottom / 2, NULL);

        // 绘制图形
        {
            Sphere sphere;
            Transform3 transform;
            sphere.ReadPoint();
            sphere.ReadPath();

            transform.SetMatrix(sphere.V,62);     // 设置顶点
            double scale = 300;
            transform.Scale(scale, scale, scale); // 放大顶点坐标
           
            if (m_Play)   // 旋转动画
            {
                transform.RotateX(alpha);
                transform.RotateY(beta);
            }
            sphere.Draw(memDC);
        }

        // 内存dc复制到设备
        BitBlt(hdc, ROUND(-rect.right / 2), ROUND(-rect.bottom / 2), rect.right, rect.bottom, memDC, ROUND(-rect.right / 2), ROUND(-rect.bottom / 2), SRCCOPY);

        SelectObject(memDC, oldBitmap);

        DeleteObject(newBitmap);
        DeleteDC(memDC);

        EndPaint(hwnd, &ps);
    }
    return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
    const wchar_t CLASS_NAME[] = L"CAG";
    WNDCLASS wc = { };

    wc.style = CS_HREDRAW | CS_VREDRAW; // 重新绘制整个工作区
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        WINDOW_TEXT,                    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL)
    {
        return 0;
    }
    ShowWindow(hwnd, nCmdShow);
    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值