MFC绘制双有理Bezier曲面

双有理Bezier曲面可以精确表示任意二次曲面,如球面、柱面及圆锥面等,下面给出1/8球面的绘制类。
参考《计算几何算法与实现》–孔令德
#pragma once
#include"P3.h"
#include"P2.h"
#include"math.h"
#define ROUND(h) int(h+0.5)
/**************************************************
*function:绘制1/8球面片,双有理二次Bezier曲线绘制
**************************************************/
class CRationalBiquadraticBezierPatch
{
public:
CRationalBiquadraticBezierPatch(void);
~CRationalBiquadraticBezierPatch(void);
public:
void ReadControlPoint(void);//读入控制点
void SetWeightValue(void);//设置权重
private:
CP3 controlPoint[3][3];
double weight[3][3];
public:
void DrawPatch(CDC*pDC);
void LeftMultiplyMatrix(double m[][3],CP3 pm[][3]);//矩阵左乘
void LeftMultiplyMatrix(double m[][3],double w[][3]);
void RightMultiplyMatrix(CP3 pm[][3],double m[][3]);//矩阵右乘
void RightMultiplyMatrix(double w[][3],double m[][3]);
void Transpose(double m[][3]);//矩阵转置
CP2 ObliqueProjection(CP3 Point);//斜二次投影
void DrawControlPoint(CDC*pDC);
};
#include "StdAfx.h"
#include "RationalBiquadraticBezierPatch.h"
CRationalBiquadraticBezierPatch::CRationalBiquadraticBezierPatch(void)
{
ReadControlPoint();
SetWeightValue();
}
CRationalBiquadraticBezierPatch::~CRationalBiquadraticBezierPatch(void)
{
}
void CRationalBiquadraticBezierPatch::ReadControlPoint(void)
{
controlPoint[0][0].SetValue(0,100,0),controlPoint[0][1].SetValue(0,100,0),controlPoint[0][2].SetValue(0,100,0);
controlPoint[1][0].SetValue(0,100,100),controlPoint[1][1].SetValue(100,100,100),controlPoint[1][2].SetValue(100,100,0);
controlPoint[2][0].SetValue(0,0,100),controlPoint[2][1].SetValue(100,0,100),controlPoint[2][2].SetValue(100,0,0);
}
void CRationalBiquadraticBezierPatch::SetWeightValue(void)
{
weight[0][0]=1,weight[0][1]=sqrt(2.0)/2,weight[0][2]=1;
weight[1][0]=sqrt(2.0)/2,weight[1][1]=1/2,weight[1][2]=sqrt(2.0)/2;
weight[2][0]=1,weight[2][1]=sqrt(2.0)/2,weight[2][2]=1;
}
void CRationalBiquadraticBezierPatch::DrawPatch(CDC*pDC)
{
DrawControlPoint(pDC);
double m[3][3];
m[0][0]=1,m[0][1]=-2,m[0][2]=1;
m[1][0]=-2,m[1][1]=2,m[1][2]=0;
m[2][0]=1,m[2][1]=0,m[2][2]=0;
CP3 ctrPW[3][3];//控制点乘以权重
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
ctrPW[i][j]=controlPoint[i][j]*weight[i][j];
}
}
LeftMultiplyMatrix(m,ctrPW);
RightMultiplyMatrix(ctrPW,m);
LeftMultiplyMatrix(m,weight);
RightMultiplyMatrix(weight,m);
double step=0.1;//步长
double u0,u1,u2,v0,v1,v2;
for(double u=0;u<=1.0;u+=step)
{
for(double v=0;v<=1.0;v+=step)
{
u2=u*u,u1=u,u0=1;
v2=v*v,v1=v,v0=1;
CP3 numerator=(u2*ctrPW[0][0]+u1*ctrPW[1][0]+u0*ctrPW[2][0])*v2
+(u2*ctrPW[0][1]+u1*ctrPW[1][1]+u0*ctrPW[2][1])*v1
+(u2*ctrPW[0][2]+u1*ctrPW[1][2]+u0*ctrPW[2][2])*v0;
double denominator=(u2*weight[0][0]+u1*weight[1][0]+u0*weight[2][0])*v2
+(u2*weight[0][1]+u1*weight[1][1]+u0*weight[2][1])*v1
+(u2*weight[0][2]+u1*weight[1][2]+u0*weight[2][2])*v0;
CP3 pt=numerator/denominator;
CP2 point2=ObliqueProjection(pt);
if(v==0)
pDC->MoveTo(ROUND(point2.x),ROUND(point2.y));
else
pDC->LineTo(ROUND(point2.x),ROUND(point2.y));
}
}
for(double v=0;v<=1.0;v+=step)
{
for(double u=0;u<=1.0;u+=step)
{
u2=u*u,u1=u,u0=1;
v2=v*v,v1=v,v0=1;
CP3 numerator=(u2*ctrPW[0][0]+u1*ctrPW[1][0]+u0*ctrPW[2][0])*v2
+(u2*ctrPW[0][1]+u1*ctrPW[1][1]+u0*ctrPW[2][1])*v1
+(u2*ctrPW[0][2]+u1*ctrPW[1][2]+u0*ctrPW[2][2])*v0;
double denominator=(u2*weight[0][0]+u1*weight[1][0]+u0*weight[2][0])*v2
+(u2*weight[0][1]+u1*weight[1][1]+u0*weight[2][1])*v1
+(u2*weight[0][2]+u1*weight[1][2]+u0*weight[2][2])*v0;
CP3 pt=numerator/denominator;
CP2 point2=ObliqueProjection(pt);
if(u==0)
pDC->MoveTo(ROUND(point2.x),ROUND(point2.y));
else
pDC->LineTo(ROUND(point2.x),ROUND(point2.y));
}
}
}
void CRationalBiquadraticBezierPatch::LeftMultiplyMatrix(double m[][3],CP3 pm[][3])
{
CP3 T[3][3];
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
T[i][j]=m[i][0]*pm[0][j]+m[i][1]*pm[1][j]+m[i][2]*pm[2][j];
}
}
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
pm[i][j]=T[i][j];
}
}
}
//重载左乘
void CRationalBiquadraticBezierPatch::LeftMultiplyMatrix(double m[][3],double w[][3])
{
double T[3][3];
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
T[i][j]=m[i][0]*w[0][j]+m[i][1]*w[1][j]+m[i][2]*w[2][j];
}
}
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
w[i][j]=T[i][j];
}
}
}
void CRationalBiquadraticBezierPatch::RightMultiplyMatrix(CP3 pm[][3],double m[][3])
{
CP3 T[3][3];
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
T[i][j]=pm[i][0]*m[0][j]+pm[i][1]*m[1][j]+pm[i][2]*m[2][j];
}
}
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
pm[i][j]=T[i][j];
}
}
}
//重载右乘函数
void CRationalBiquadraticBezierPatch::RightMultiplyMatrix(double w[][3],double m[][3])
{
double T[3][3];
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
T[i][j]=w[i][0]*m[0][j]+w[i][1]*m[1][j]+w[i][2]*m[2][j];
}
}
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
w[i][j]=T[i][j];
}
}
}
void CRationalBiquadraticBezierPatch::Transpose(double m[][3])
{
double T[3][3];
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
T[i][j]=m[j][i];
}
}
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
m[i][j]=T[i][j];
}
}
}
CP2 CRationalBiquadraticBezierPatch::ObliqueProjection(CP3 Point)
{
CP2 Point2;
Point2.x=Point.x-Point.z*sqrt(2.0)/2.0;
Point2.y=Point.y-Point.z*sqrt(2.0)/2.0;
//Point2.x=Point.x;
//Point2.y=Point.y;
return Point2;
}
void CRationalBiquadraticBezierPatch::DrawControlPoint(CDC*pDC)
{
CP2 P2[3][3];
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
P2[i][j]=ObliqueProjection(controlPoint[i][j]);
}
}
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_SOLID,3,RGB(0,0,0));
pOldPen=pDC->SelectObject(&NewPen);
for(int i=0;i<3;i++)
{
pDC->MoveTo(ROUND(P2[i][0].x),ROUND(P2[i][0].y));
for(int j=0;j<3;j++)
{
pDC->LineTo(ROUND(P2[i][j].x),ROUND(P2[i][j].y));
}
}
for(int i=0;i<3;i++)
{
pDC->MoveTo(ROUND(P2[0][i].x),ROUND(P2[0][i].y));
for(int j=0;j<3;j++)
{
pDC->LineTo(ROUND(P2[j][i].x),ROUND(P2[j][i].y));
}
}
pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
}