使用黑白颜色填充双三次bezier曲面片

一、实验项目要求

任务1:使用均布网格细分曲面

任务2:使用黑白棋盘颜色填充细分后的小面。

二、理论分析或算法分析

在双三次贝塞尔曲面算法中,绘制出面,双的面颜色设置为黑色,单的面绘制成白色,重新写一个函数来构成面的绘画,因为是间隔的,所以然后设一个i和j,i和j相加对2的求余,如果可以除尽就是填充黑色,如果没有除尽就是填充白色;

使用均布网格细分曲面:

采用非递归,然后实现步长为0.1,将曲面划分为10*10的网格,然后将四个顶点连接成一个曲面;double tStep = 0.1;//步长

设置100个网格,CP2 gridP2[11][11];    //100个平面网格

采用斜投影:gridP2[ROUND(u*10)][ROUND(v*10)] = projection.CavalierProjection(pt);//斜投影

填充颜色设置:黑色:CBrush brushBlack(RGB(0, 0, 0));

           白色: CBrush brushWhite(RGB(255, 255, 255));

绘制网格并填充:for (int i = 0; i < 10; i++)

                  for (int j = 0; j < 10; j++)

                  {

                      if ((i + j) % 2 == 0)

                          pDC->SelectObject(&brushBlack);

                      else

                          pDC->SelectObject(brushWhite);

                      pDC->BeginPath();

                      pDC->MoveTo(ROUND(gridP2[i][j].x), ROUND(gridP2[i][j].y));

                      pDC->LineTo(ROUND(gridP2[i + 1][j].x), ROUND(gridP2[i + 1][j].y));

                      pDC->LineTo(ROUND(gridP2[i + 1][j + 1].x), ROUND(gridP2[i + 1][j + 1].y));

                      pDC->LineTo(ROUND(gridP2[i][j + 1].x), ROUND(gridP2[i][j + 1].y));

                      pDC->LineTo(ROUND(gridP2[i][j].x), ROUND(gridP2[i][j].y));

                      pDC->EndPath();

                      pDC->StrokeAndFillPath();

                  }

在这块为了实现对边界的颜色绘制,这里要使用pDC->StrokeAndFillPath();如果没有使用这个函数,就会出现边界不是框内的颜色;

使用MoveTo和LineTo实现对网格的绘画;

控制网格的绘制:bezier.DrawControlGrid(pDC);

三、实现方法

代码实现:

绘制网格颜色填充:

void CBicubicBezierPatch::DrawCurvedPatch(CDC* pDC)
{
	double M[4][4];//系数矩阵M
	M[0][0]=-1,M[0][1]=3, M[0][2]=-3,M[0][3]=1;
	M[1][0]= 3,M[1][1]=-6,M[1][2]= 3,M[1][3]=0;
	M[2][0]=-3,M[2][1]=3, M[2][2]= 0,M[2][3]=0;
	M[3][0]=1, M[3][1]=0, M[3][2]= 0,M[3][3]=0;
	CP3 P3[4][4];//曲线计算用控制点数组
	for(int i=0;i < 4;i++)
		for(int j = 0;j < 4;j++)
			P3[i][j] = P[i][j];
	LeftMultiplyMatrix(M, P3);//系数矩阵左乘三维点矩阵
	TransposeMatrix(M);//计算转置矩阵
	RightMultiplyMatrix(P3, M);//系数矩阵右乘三维点矩阵
	double tStep = 0.1;//步长
	double u0,u1,u2,u3,v0,v1,v2,v3;//u,v参数的幂
	CP2 gridP2[11][11];    //100个平面网格
	for(double u = 0;u <= 1;u += tStep)    
		for(double v = 0;v <= 1;v += tStep)
		{
			u3 = u * u * u, u2 = u * u, u1 = u, u0 = 1;
			v3 = v * v * v, v2 = v * v, v1 = v, v0 = 1;
			CP3 pt =  (u3 * P3[0][0] + u2 * P3[1][0] + u1 * P3[2][0] + u0 * P3[3][0]) * v3
			         +(u3 * P3[0][1] + u2 * P3[1][1] + u1 * P3[2][1] + u0 * P3[3][1]) * v2
			         +(u3 * P3[0][2] + u2 * P3[1][2] + u1 * P3[2][2] + u0 * P3[3][2]) * v1
			         +(u3 * P3[0][3] + u2 * P3[1][3] + u1 * P3[2][3] + u0 * P3[3][3]) * v0;
			CP2 Point2 = projection.CavalierProjection(pt);//斜投影    
			if (0 == v)
				pDC->MoveTo(ROUND(Point2.x), ROUND(Point2.y));
			else
				pDC->LineTo(ROUND(Point2.x), ROUND(Point2.y));
			gridP2[ROUND(u*10)][ROUND(v*10)] = 
projection.CavalierProjection(pt);//斜投影
			CBrush brushBlack(RGB(0, 0, 0));
			CBrush brushWhite(RGB(255, 255, 255));
			for (int i = 0; i < 10; i++)
				for (int j = 0; j < 10; j++)
				{
					if ((i + j) % 2 == 0)
						pDC->SelectObject(&brushBlack);
					else
						pDC->SelectObject(brushWhite);
					pDC->BeginPath();
					pDC->MoveTo(ROUND(gridP2[i][j].x), 
ROUND(gridP2[i][j].y));
					pDC->LineTo(ROUND(gridP2[i + 1][j].x), 
ROUND(gridP2[i + 1][j].y));
					pDC->LineTo(ROUND(gridP2[i + 1][j + 1].x),
ROUND(gridP2[i + 1][j + 1].y));
					pDC->LineTo(ROUND(gridP2[i][j + 1].x),
 ROUND(gridP2[i][j + 1].y));
					pDC->LineTo(ROUND(gridP2[i][j].x),
 ROUND(gridP2[i][j].y));
					pDC->EndPath();
					pDC->StrokeAndFillPath();
				}
		}		  
	for(double v = 0;v <= 1;v += tStep)
		for(double u = 0;u <= 1;u += tStep)
		{
			u3 = u * u * u; u2 = u * u; u1 = u; u0 = 1; 
			v3 = v * v * v; v2 = v * v; v1 = v; v0 = 1;
			CP3 pt = (u3 * P3[0][0] + u2 * P3[1][0] + u1 * P3[2][0] + u0 * P3[3][0]) * v3
			        +(u3 * P3[0][1] + u2 * P3[1][1] + u1 * P3[2][1] + u0 * P3[3][1]) * v2
			        +(u3 * P3[0][2] + u2 * P3[1][2] + u1 * P3[2][2] + u0 * P3[3][2]) * v1
			        +(u3 * P3[0][3] + u2 * P3[1][3] + u1 * P3[2][3] + u0 * P3[3][3]) * v0;			
			CP2 Point2 = projection.CavalierProjection(pt);//斜投影    
			if(0 == u)
				pDC->MoveTo(ROUND(Point2.x), ROUND(Point2.y));
			else
				pDC->LineTo(ROUND(Point2.x),ROUND(Point2.y));
		}
}

双三次贝塞尔曲面的实现:

#pragma once
#include "Projection.h"

class CBicubicBezierPatch
{
public:
	CBicubicBezierPatch(void);
	virtual ~CBicubicBezierPatch(void);
	void ReadControlPoint(CP3 P[4][4]);//读入16个控制点
	void DrawCurvedPatch(CDC* pDC);//绘制双三次Bezier曲面片
	//void DrawControlGrid(CDC* pDC);//绘制控制网格
private:
	void LeftMultiplyMatrix(double M[4][4],CP3 P[4][4]);//左乘顶点矩阵
	void RightMultiplyMatrix(CP3 P[4][4],double M[4][4]);//右乘顶点矩阵
	void TransposeMatrix(double M[4][4]);//转置矩阵
public:
	CP3 P[4][4];//三维控制点
	CProjection projection;//投影对象
};
#include "pch.h"
#include "BicubicBezierPatch.h"
#define ROUND(d) int(d + 0.5)

CBicubicBezierPatch::CBicubicBezierPatch(void)
{

}

CBicubicBezierPatch::~CBicubicBezierPatch(void)
{

}

void CBicubicBezierPatch::ReadControlPoint(CP3 P[4][4])
{
   for(int i = 0;i < 4;i++)
	   for(int j = 0;j < 4;j++)
   			this->P[i][j]  = P[i][j];
}
void CBicubicBezierPatch::DrawCurvedPatch(CDC* pDC)
{
	double M[4][4];//系数矩阵M
	M[0][0]=-1,M[0][1]=3, M[0][2]=-3,M[0][3]=1;
	M[1][0]= 3,M[1][1]=-6,M[1][2]= 3,M[1][3]=0;
M[2][0]=-3,M[2][1]=3, M[2][2]= 0,M[2][3]=0;
	M[3][0]=1, M[3][1]=0, M[3][2]= 0,M[3][3]=0;
	CP3 P3[4][4];//曲线计算用控制点数组
	for(int i=0;i < 4;i++)
		for(int j = 0;j < 4;j++)
			P3[i][j] = P[i][j];
	LeftMultiplyMatrix(M, P3);//系数矩阵左乘三维点矩阵
	TransposeMatrix(M);//计算转置矩阵
	RightMultiplyMatrix(P3, M);//系数矩阵右乘三维点矩阵
	double tStep = 0.1;//步长
	double u0,u1,u2,u3,v0,v1,v2,v3;//u,v参数的幂
	CP2 gridP2[11][11];    //100个平面网格
	for(double u = 0;u <= 1;u += tStep)    
		for(double v = 0;v <= 1;v += tStep)
		{
			u3 = u * u * u, u2 = u * u, u1 = u, u0 = 1;
			v3 = v * v * v, v2 = v * v, v1 = v, v0 = 1;
			CP3 pt =  (u3 * P3[0][0] + u2 * P3[1][0] + u1 * P3[2][0] + u0 * P3[3][0]) * v3
			         +(u3 * P3[0][1] + u2 * P3[1][1] + u1 * P3[2][1] + u0 * P3[3][1]) * v2
			         +(u3 * P3[0][2] + u2 * P3[1][2] + u1 * P3[2][2] + u0 * P3[3][2]) * v1
			         +(u3 * P3[0][3] + u2 * P3[1][3] + u1 * P3[2][3] + u0 * P3[3][3]) * v0;
			CP2 Point2 = projection.CavalierProjection(pt);//斜投影    
			if (0 == v)
				pDC->MoveTo(ROUND(Point2.x), ROUND(Point2.y));
			else
				pDC->LineTo(ROUND(Point2.x), ROUND(Point2.y));
			gridP2[ROUND(u*10)][ROUND(v*10)] = projection.CavalierProjection(pt);//斜投影
			CBrush brushBlack(RGB(0, 0, 0));
			CBrush brushWhite(RGB(255, 255, 255));
			for (int i = 0; i < 10; i++)
				for (int j = 0; j < 10; j++)
				{
					if ((i + j) % 2 == 0)
						pDC->SelectObject(&brushBlack);
					else
						pDC->SelectObject(brushWhite);
					pDC->BeginPath();
					pDC->MoveTo(ROUND(gridP2[i][j].x), ROUND(gridP2[i][j].y));
					pDC->LineTo(ROUND(gridP2[i + 1][j].x), ROUND(gridP2[i +

1][j].y));
					pDC->LineTo(ROUND(gridP2[i + 1][j + 1].x), ROUND(gridP2[i + 1][j + 1].y));
					pDC->LineTo(ROUND(gridP2[i][j + 1].x), ROUND(gridP2[i][j + 1].y));
					pDC->LineTo(ROUND(gridP2[i][j].x), ROUND(gridP2[i][j].y));
					pDC->EndPath();
					pDC->StrokeAndFillPath();
				}
		}		  
	for(double v = 0;v <= 1;v += tStep)
		for(double u = 0;u <= 1;u += tStep)
		{
			u3 = u * u * u; u2 = u * u; u1 = u; u0 = 1; 
			v3 = v * v * v; v2 = v * v; v1 = v; v0 = 1;
			CP3 pt = (u3 * P3[0][0] + u2 * P3[1][0] + u1 * P3[2][0] + u0 * P3[3][0]) * v3
			        +(u3 * P3[0][1] + u2 * P3[1][1] + u1 * P3[2][1] + u0 * P3[3][1]) * v2
			        +(u3 * P3[0][2] + u2 * P3[1][2] + u1 * P3[2][2] + u0 * P3[3][2]) * v1
			        +(u3 * P3[0][3] + u2 * P3[1][3] + u1 * P3[2][3] + u0 * P3[3][3]) * v0;			
			CP2 Point2 = projection.CavalierProjection(pt);//斜投影    
			if(0 == u)
				pDC->MoveTo(ROUND(Point2.x), ROUND(Point2.y));
			else
				pDC->LineTo(ROUND(Point2.x),ROUND(Point2.y));
		}
}

void CBicubicBezierPatch::LeftMultiplyMatrix(double M[4][4],CP3 P[4][4])//左乘矩阵M*P
{
	CP3 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 CBicubicBezierPatch::RightMultiplyMatrix(CP3 P[4][4],double M[4][4])//右乘矩阵P*M
{
	CP3 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];
}

void CBicubicBezierPatch::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 CBicubicBezierPatch::DrawControlGrid(CDC* pDC)//绘制控制网格
//{
//	CP2 P2[4][4];//二维控制点
//	for(int i = 0;i < 4;i++)
//		for(int j = 0;j < 4;j++)
//			P2[i][j] = projection.CavalierProjection(P[i][j]);
//	CPen NewPen,*pOldPen;
//	NewPen.CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
//	pOldPen=pDC->SelectObject(&NewPen);
//	for(int i = 0; i < 4; i++)
//	{
//		pDC->MoveTo(ROUND(P2[i][0].x), ROUND(P2[i][0].y));
//		for(int j = 1;j < 4;j++)
//			pDC->LineTo(ROUND(P2[i][j].x), ROUND(P2[i][j].y));
//	}
//	for(int j = 0;j < 4;j++)
//	{
//		pDC->MoveTo(ROUND(P2[0][j].x), ROUND(P2[0][j].y));
//		for(int i = 1;i < 4;i++)
//			pDC->LineTo(ROUND(P2[i][j].x), ROUND(P2[i][j].y));

//	}
//	pDC->SelectObject(pOldPen);
//	NewPen.DeleteObject();
//}

四、实验结果分析

实验结果

出现的问题

1.命名不正确,导致出现问题,这是细节问题

2.刚开始进行填充颜色的时候,没有懂要将一个曲面细分为10*10的网格,到后来看了视频之后,要使用步长来构造一个闭合的四边形,然后使用路径层填充,在这里需要注意的是pDC->BeginPath();pDC->EndPath();是成对出现,最后要使用这个函数pDC->StrokeAndFillPath();,否则会出现线上不是它要填充的颜色,会出现分界线;

3.在进行填充颜色的使用for循环来判断单个来填充黑色,双个来填充白色,这是一个逻辑问题;

4.曲面的形状是由控制网格的控制点的来控制的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值