注意这里的成员变量Points,这是一个指向BCPoint对象数组的指针,容易理解,这里BCPoint指针标识了一个多边形的所有顶点,成员变量PointNum标识了顶点数目。注意这里的顶点是按照外表面的顺时针排列的,这样我们可以计算出一个多边形的法向量进而判断某个多边形是否为不可见的“背面”(对于背面,可以不予显示,甚至不用计算二文坐标,这样我们就完成了简单的消隐效果),这个计算的功能由成员函数IfBack()完成。
多边形类比较重要的成员函数还有Get2Dview()和User2Device(),分别用于将三文用户坐标转化为二文用户坐标,以及将二文用户坐标转化为屏幕设备坐标。Draw()函数相对简单一些,仅仅是将计算出的二文屏幕设备坐标显示出来。
关键技术和类的实现
CMatrix类的实现
.构造函数
CMatrix::CMatrix(int RowNumber,int ColumnNumber)
{
data=new TYPE[RowNumber*ColumnNumber];
this->RowNumber=RowNumber;
this->ColumnNumber =ColumnNumber;
}
这里我们动态生成了一个二文数组,用于存储矩阵数据,数组类型已定义为double型。当然,在析构函数中要释放堆空间。
(2).operator[]的作用
TYPE* CMatrix::operator[](int Row)
{
return &(data[ColumnNumber*Row]);
}
这个函数返回一个指针,它的作用是允许我们用matrix[i][j]的形式直接对矩阵中的某个元素进行操作。这种写法显然比matrix.data[i*ColumnNumber+j]的形式来的直观。
BCPoint类的实现
(1).得到二文用户坐标
void BCPoint::Get2DView(double ViewerX, double ViewerY, double ViewerZ)
{
User2D[0][0]=(ViewerX*User3D[0][2]-iewerZ*User3D[0][0])/(User3D[0][2]- ViewerZ);
User2D[0][1]=(ViewerY*User3D[0][2]-iewerZ*User3D[0][1])/(User3D[0][2]-ViewerZ);
User2D[0][2]=1;
}
这个函数实际上是照搬书上381页的透视投影公式,其中三个参数表示视点坐标。
(2).点的移动
void BCPoint::Move(CMatrix *MoveMatrix)
{
User3D=User3D*(*MoveMatrix);
if(fabs(User3D[0][3]-1)>0.001) //浮点数的“相等”
{
User3D[0][0]/=User3D[0][3]; //这里修正用户坐标令User3D[0][3]=1
User3D[0][1]/=User3D[0][3];
User3D[0][2]/=User3D[0][3];
}
}
这个函数也相当简单,只是一个矩阵的相乘,变换矩阵由CView派生类给出(我们将在后文详述),矩阵相乘由CMatrix类完成。
CPolygon类的实现
(1).构造函数
CPolygon::CPolygon(int PointNumber)
{
Back=FALSE;
this->Points=new BCPoint[PointNum=PointNumber];
}
这里我们首先根据给出的多边形顶点数目动态在堆中生成各点的对象,当然在析构函数里要释放内存。
(2).用户坐标向设备坐标的转换
void CPolygon::User2Device(double a, double b, double c, double d)
{
if(Back)
return; //如果是背面,无需变换
int i;
for(i=0;i<this->PointNum;i++)
{
Points[i].Device.x=(int)(a*Points[i].User2D[0][0]+b);
Points[i].Device.y=(int)(c*Points[i].User2D[0][1]+d);
}
}
这里实际上也是套用书上363页的公式,a,b,c,d四个参数由CView派生类给出,和书上四个参数的含义完全相同。为了便于理解,我们现在提前看CView派生类中Draw()函数(不是OnDraw函数)的部分实现。
void CGraphicView::Draw()
{
double a,b,c,d;
CRect rect;
this->GetWindowRect(rect);
a=rect.Width()/4;
b=2*a;
c=-rect.Width()/4;
d=(rect.Width()+rect.Height())/2+2*c;
int i;
for(i=0;i<Polygons.GetCount();i++) //对于所有的多边形进行计算
{
Polygons.GetAt(Polygons.FindIndex(i)).Get2DView(ViewPoint[0],ViewPoint[1],ViewPoint[2]); //这里的Polygons是一个链表
Polygons.GetAt(Polygons.FindIndex(i)).User2Device(a,b,c,d);
}
我们可以看出这里a,b,c,d四个参数的计算过程,用户域我们取-2<x<2,-2<y<2的区域,设备域我们取0<x<窗口宽,0<y<窗口宽的区域,注意这里 0<y<窗口宽 而不是0<y<窗口高 的原因是我们需要一个正方形的设备窗口以免图形产生变形。
(3).背面删除算法的实现
首先我们得到法向量,保存在成员变量RuleVertex中
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] 下一页