- 添加变量以及函数
1.1变量
private:
CPoint m_ptStart, m_ptEnd;
UINT m_mode;//模态
COLORREF m_color;//声明
CArray<CPoint, CPoint>m_ptArray;
int m_width;
double r;
CPoint m_ptLT, m_ptRB;//拉框的左上和右下
int m_ist;//记录鼠标左键按下的状态
1.2函数
public:
void DDALine(CDC* pDC, int x0, int y0, int x1, int y1, COLORREF color,int width);
void DDADashLine(CDC* pDC, int x0, int y0, int x1, int y1, COLORREF color,int width);
void MidLine(CDC* pDC, int x0, int y0, int x1, int y1, COLORREF color,int width);
void BHLine(CDC* pDC, int x1, int y1, int x2, int y2, COLORREF color,int width);
void DDAWidthLine(CDC* pDC, int x1, int y1, int x2, int y2, COLORREF color, int width);
void BHCircle(CDC* pDC, int x0, int y0, int R, COLORREF color,int width);
void SeadFill(CDC* pDC, int x, int y, COLORREF boundarycolor, COLORREF newcolor);
void Pentagon(CDC* pDC, double r,int width);//空心五角星
void CorrectRect();
BOOL Intersection(double p, double q, double& t0, double &t1);
void Liang_Barsky(CPoint& BPoint, CPoint& EPoint);
void ClearScreen();
- 变量的初始化
m_ptStart = m_ptEnd = CPoint(0, 0);
m_mode = 0;//默认为0
m_color = RGB(0, 0, 0);
m_width = 1;
m_ist = 0;
m_ptLT = m_ptRB = CPoint(0,0);
- 编写函数
3.1 DDALine
void CFinalExamView::DDALine(CDC* pDC, int x0, int y0, int x1, int y1, COLORREF color, int width)
{
double dx, dy, e, x, y;
dx = x1 - x0;
dy = y1 - y0;
e = (fabs(dx) > fabs(dy)) ? fabs(dx) : fabs(dy);//#include<math.h>
x = x0;
y = y0;
dx /= e;
dy /= e;
for (int i = 1;i <= e;i++)
{
pDC->SetPixel((int)(x + 0.5), (int)(y + 0.5), color);
x += dx;
y += dy;
}
}
3.2 DDADashLine
void CFinalExamView::DDADashLine(CDC* pDC, int x0, int y0, int x1, int y1, COLORREF color, int width)
{
{
double dx, dy, e, x, y;
dx = x1 - x0;
dy = y1 - y0;
e = fabs(dx) > fabs(dy) ? fabs(dx) : fabs(dy);
x = x1; y = y1;
dx /= e;
dy /= e;
for (int i = 1; i <= e; i++)
{
/*pDC->SetPixel(int(x + 0.5), int(y + 0.5), color);
x += dx;
y += dy;*/
if ((i % 40) < 15)
{
pDC->SetPixel(int(x + 0.5), int(y + 0.5), color);
}
else if ((i % 40) < 20)
{
pDC->SetPixel(int(x + 0.5), int(y + 0.5), pDC->GetBkColor());
}
else if (i == 20)
{
pDC->SetPixel(int(x + 0.5), int(y + 0.5), color);
}
else if ((i % 40) < 30)
{
pDC->SetPixel(int(x + 0.5), int(y + 0.5), pDC->GetBkColor());
}
else
{
pDC->SetPixel(int(x + 0.5), int(y + 0.5), color);
}
x += dx;
y += dy;
}
}
}
3.3 MIdLine
void CFinalExamView::MidLine(CDC* pDC, int x0, int y0, int x1, int y1, COLORREF color, int width)
{
int a, b, d, delta1, delta2, x, y;
//两个端点x值相等
if (x0 == x1)
{
if (y0 < y1)
{
for (int i = y0; i < y1; i++)
pDC->SetPixel(x0, i, color);
}
else
{
for (int i = y1; i <= y0; i++)
pDC->SetPixel(x0, i, color);
}
}
//判定斜率,如绝对值大于1,则m为false,否则为true
BOOL m = (fabs(y1 - y0) <= fabs(x1 - x0));
if (x0 > x1)
{
d = x0; y0 = x1; x1 = d;
d = y0; y0 = y1; y1 = d;
}
a = y0 - y1;
b = x1 - x0;
x = x0;
y = y0;
pDC->SetPixel(x, y, color);
//斜率绝对值小于等于1
if (m)
{
//推导的第一种情况(y值递增)
if (y0 <= y1)
{
d = 2 * a + b;
delta1 = 2 * a;
delta2 = 2 * (a + b);
while (x < x1)
{
//如果d<0,取p2(xp+1,yp+1)右上,否则取p1(xp+1,yp)右边
if (d < 0)
{
x++; y++;
d += delta2;
}
else
{
x++;
d += delta1;
}
pDC->SetPixel(x, y, color);
}
}
//推导的第三种情况(y值递减)
else
{
d = 2 * a - b;
delta1 = 2 * a;
delta2 = 2 * (a - b);
while (x < x1)
{
//推导的第二种情况
//若d<0,取p1(xp+1,yp),否则取p2(xp+1,yp-1)
if (d < 0)
{
x++;
d += delta1;
}
else
{
x++; y--;
d += delta2;
}
pDC->SetPixel(x, y, color);
}
}
}
//斜率绝对值大于1
else
{
if (y0 < y1)
{
d = a + 2 * b;
delta1 = 2 * b;
delta2 = 2 * (a + b);
while (y < y1)
{
//若d<0,取p1(xp,yp+1),否则取p1(xp+1,yp+1)
if (d < 0)
{
y++;
d += delta1;
}
else
{
y++; x++;
d += delta2;
}
pDC->SetPixel(x, y, color);
}
}
//课堂推导的第四种情况
else
{
d = a - 2 * b;
delta1 = -2 * b;
delta2 = 2 * (a + -b);
while (y > y1)
{
//若d<0,取p2(xp+1,yp-1),否则取p2(xp,yp-1)
if (d < 0)
{
y--; x++;
d += delta2;
}
else
{
y--;
d += delta1;
}
pDC->SetPixel(x, y, color);
}
}
}
}
3.4 BHLine
void CFinalExamView::BHLine(CDC* pDC, int x1, int y1, int x2, int y2, COLORREF color, int width)
{
int x, y, dx, dy, p;
if (x1 == x2)
{
if (y1 < y2)
{
for (int i = y1; i <= y2; i++)
{
pDC->SetPixel(x1, i, color);
}
}
else
{
for (int i = y2; i <= y1; i++)
{
pDC->SetPixel(x1, i, color);
}
}
return;
}
//斜率>1为FALSE,否则为true
BOOL m = (fabs(y2 - y1) <= fabs(x2 - x1));
//如果x2>x1,交换坐标
if (x1 > x2)
{
p = x1; x1 = x2; x2 = p;
p = y1; y1 = y2; y2 = p;
}
//变量赋初值
x = x1;
y = y1;
dx = x2 - x1;
dy = y2 - y1;
//斜率绝对值<=1
if (m)
{
//第一种情况,Y递增
if (y1 <= y2)
{
p = (dy << 1) - dx;
while (x <= x2)
{
pDC->SetPixel(x, y, color);
if (p < 0) {
x++;
p = p + (dy << 1);
}
else
{
x++; y++;
p = p + ((dy - dx) << 1);
}
}
}
//第三种情况,y递减
else
{
p = dx - (dy << 1);
while (x <= x2)
{
pDC->SetPixel(x, y, color);
if (p < 0)
{
x++;
p = p - (dy << 1);
}
else
{
x++; y--;
p = p - ((dy + dx) << 1);
}
}
}
}
//斜率绝对值大于1
else {
//理论课讨论的第二种情况
if (y1 <= y2)
{
p = (dx << 1) - dy;
while (y <= y2)
{
pDC->SetPixel(x, y, color);
if (p < 0)
{
y++;
p = p + (dx << 1);
}
else
{
y++; x++;
p = p + ((dx - dy) << 1);
}
}
}
//第四种情况,y递减
else
{
p = (dx << 1) + dy;
while (y >= y2)
{
pDC->SetPixel(x, y, color);
if (p < 0)
{
y--;
p = p + (dx << 1);
}
else
{
y--; x++;
p = p + ((dx + dy) << 1);
}
}
}
}
}
3.5 DDAWidthLine
void CFinalExamView::DDAWidthLine(CDC* pDC, int x1, int y1, int x2, int y2, COLORREF color, int width)
{
double dx, dy, e, x, y;
dx = x2 - x1;
dy = y2 - y1;
e = (fabs(dx) > fabs(dy)) ? fabs(dx) : fabs(dy);
x = x1;
y = y1;
dx /= e;
dy /= e;
for (int i = 1;i <= e;i++)
{
//pDC->SetPixel(int(x + 0.5), int(y + 0.5), color);
for (int j = (1 - width) / 2;j <= width / 2;j++)
{
for (int k = (1 - width) / 2;k <= width / 2;k++)
{
pDC->SetPixel(int(x + 0.5) + j, int(y + 0.5) + k, color);
}
x += dx;
y += dy;
}
}
}
3.6 BHCircle
void CFinalExamView::BHCircle(CDC* pDC, int x0, int y0, int R, COLORREF color, int width)
{
int x, y, p;
x = 0;
y = R;
p = 3 - (R << 1);
for (;x <= y;x++)
{
pDC->SetPixel(x + x0, y + y0, color);
pDC->SetPixel(-x + x0, y + y0, color);
pDC->SetPixel(x + x0, -y + y0, color);
pDC->SetPixel(-x + x0, -y + y0, color);
pDC->SetPixel(y + x0, x + y0, color);
pDC->SetPixel(-y + x0, x + y0, color);
pDC->SetPixel(y + x0, -x + y0, color);
pDC->SetPixel(-y + x0, -x + y0, color);
if (p < 0)
{
p += ((x << 2) + 6);
}
else
{
p = (((x - y) << 2) + 10);
y--;
}
}
}
3.7 SeedFill
void CFinalExamView::SeedFill(CDC* pDC, int x, int y, COLORREF boundarycolor, COLORREF newcolor)
{
//首先定义一些变量
//然后是栈,压栈弹栈
//从栈里面取出一个点,判定是否填充,一直填充到边界(一行一行)
//检查上下两行,如果不是新颜色,就把种子填充进去
//第一行是最特殊的行,上下两行搜索的方式都是从右边向左边填充(用while循环做)
int x0, y0, xr, xl, xid;
int flag, xnextspan;//span像素段,flag一般用1或者0两种状态(逻辑变量:true or false)
stack<CPoint> s;//栈对象
CPoint p;
s.push(CPoint(x, y));//第一颗种子
while (!s.empty())
{//如果不是空的就开始绘制
p = s.top(); s.pop();//首先得到的要素,取出来之后就不需要了
pDC->SetPixel(p.x, p.y, newcolor);//给种子填充新的颜色
x = p.x;y = p.y;//把xy初始化,后面使用就偏离
x0 = x + 1;//开始向右边填充
while (pDC->GetPixel(x0, y) != boundarycolor)//不是边界色就填充
{
pDC->SetPixel(x0, y, newcolor);
x0++;//开始循环,到边界时候跳出循环
}
xr = x0 - 1;//最右边的点,如果上一行也是xr就压栈
x0 = x - 1;//开始向左边
while (pDC->GetPixel(x0, y) != boundarycolor)
{
pDC->SetPixel(x0, y, newcolor);
x0--;//左边循环
}
xl = x0 + 1;//一行搞定后,就开始上下两行
//-----------以下只是判定种子要不要入栈-------------
y0 = y;//种子所在的行
for (int i = 1;i >= -1;i -= 2)
{
//当前的线为1,减二开始循环,大于-1就退出循环
//先检查的是上面的一行,然后-2是下面的一行
x0 = xr;//从右边开始上下两行
y = y0 + i;//得到点后根据四连通性进行判定
while (x0 >= xl)
{
flag = 0;
while ((pDC->GetPixel(x0, y) != boundarycolor)
&& (pDC->GetPixel(x0, y) != newcolor)
&& (x0 > xl))
{
if (0 == flag)
{
flag = 1;
xid = x0;//记录
}
x0--;//跳出循环
}//判定一下,要不要入栈
if (1 == flag)
{
s.push(CPoint(xid, y));
flag = 0;//压进去后,还需要进行清理
}
//记录最左侧的点
xnextspan = x0;//相等就偏移,然后退出循环
while ((pDC->GetPixel(x0, y) == boundarycolor) ||
(pDC->GetPixel(x0, y) == newcolor) && (x0 > xl))
x0--;
if (xnextspan == x0) x0--;
}
}
}
}
3.8 Pentagon
void CFinalExamView::Pentagon(CDC* pDC, double r, int width)
{
//颜色填充可以使用seedfill
CPoint pts[5];//五个顶点
r = 55;
for (int i = 0;i < 5;i++)
{
pts[i].x = (long)(150 - r * sin((i * 72 + 36) * 2 * 3 * 3.14 / 360));
pts[i].y = (long)(150 + r * cos((i * 72 + 36) * 2 * 3 * 3.14 / 360));
}//先将笔移动到第一个点,将其与第二个点连接
for (int i = 0;i < 5;i++)
{
pDC->MoveTo(pts[i]);//线段起点
pDC->LineTo(pts[(i + 2) % 5]);//线段终点
}
}
3.9 CorrectRect
void CFinalExamView::CorrectRect()
{
int x, y;
if (m_ptLT.x > m_ptRB.x)
{
x = m_ptLT.x;
m_ptLT.x = m_ptRB.x;
m_ptRB.x = x;
}
if (m_ptLT.y < m_ptRB.y)
{
y = m_ptLT.y;
m_ptLT.y = m_ptRB.y;
m_ptRB.y = y;
}
}
3.10 Intersection
BOOL CFinalExamView::Intersection(double p, double q, double& t0, double& t1)
{
double u;
if (p < 0)
{
u = q / p;
if (u > t1)//线段不在裁剪框内
return FALSE;
else if (u > t0)
t0 = u; //入边取大
}
else if (p > 0)
{
u = q / p;
if (u < t0)//线段不在裁剪框内
return FALSE;
else if (u < t1)
t1 = u;//出边取小
}
else if (q < 0)
return FALSE;
return TRUE;
}
3.11 Liang_Barsky
void CFinalExamView::Liang_Barsky(CPoint& BPoint, CPoint& EPoint)
{
double t0, t1, dx, dy;
t0 = 0.0;
t1 = 1.0;
dx = EPoint.x - BPoint.x;
if (!Intersection(-dx, BPoint.x - m_ptLT.x, t0, t1))
return;
if (!Intersection(dx, m_ptRB.x - BPoint.x, t0, t1))
return;
dy = EPoint.y - BPoint.y;
if (!Intersection(-dy,BPoint.y - m_ptRB.y,t0,t1))
return;
if (!Intersection(dy, m_ptLT.y - BPoint.y, t0, t1))
return;
EPoint.x = (int)(BPoint.x + t1 * dx);
EPoint.y = (int)(BPoint.y + t1 * dy);
BPoint.x = (int)(BPoint.x + t0 * dx);
BPoint.y = (int)(BPoint.y + t0 * dy);
}
3.12 ClearScrean
void CFinalExamView::ClearScreen()
{
CClientDC dc(this);
CRect window;
GetClientRect(window);//讲绘制区域设置城客户区
dc.SelectStockObject(WHITE_PEN);
dc.SelectStockObject(WHITE_BRUSH);
dc.Rectangle(window);
}
- 消息处理函数
4.1线宽
void CFinalExamView::OnWidth()
{
CWidthDialog dlg;
if (IDOK == dlg.DoModal())
{
m_width = dlg.m_widthDlg;
}
}
4.2颜色
void CFinalExamView::OnColor()
{
CColorDialog dlg;
if (IDOK == dlg.DoModal())
{
m_color = dlg.GetColor();
}
}
4.3鼠标左键摁下
void CFinalExamView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_ptStart = point;
m_ptArray.Add(point);
}
4.4鼠标左键抬起
void CFinalExamView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_ptEnd = point;
CDC* pDC = GetDC();
switch (m_mode)
{
case 1://DDALine
DDALine(pDC, m_ptStart.x, m_ptStart.y,
m_ptEnd.x, m_ptEnd.y, m_color,m_width);
break;
case 2://MidLine
MidLine(pDC, m_ptStart.x, m_ptStart.y,
m_ptEnd.x, m_ptEnd.y, m_color, m_width);
break;
case 3://BHLine
BHLine(pDC, m_ptStart.x, m_ptStart.y,
m_ptEnd.x, m_ptEnd.y, m_color, m_width);
break;
case 4://DDADashLine
DDADashLine(pDC, m_ptStart.x, m_ptStart.y,
m_ptEnd.x, m_ptEnd.y, m_color, m_width);
break;
case 5://BHCircle
{int R = int(sqrt((m_ptEnd.x - m_ptStart.x) * (m_ptEnd.x - m_ptStart.x) +
(m_ptEnd.y - m_ptStart.y) * (m_ptEnd.y - m_ptStart.y)));
BHCircle(pDC, m_ptStart.x, m_ptStart.y,
R, m_color, m_width);
}
break;
case 6://Rectangle
pDC->Rectangle(m_ptStart.x, m_ptStart.y, m_ptEnd.x, m_ptEnd.y);
break;
case 7://Polygon
for (int i = 0;i <= m_ptArray.GetSize() - 2;i++)
{
CPoint p1, p2;
p1 = m_ptArray.GetAt(i);
p2 = m_ptArray.GetAt(i + 1);
pDC->MoveTo(p1);
pDC->LineTo(p2);
}
break;
case 8://Polyline
{
for (int i = 0;i <= m_ptArray.GetSize() - 2;i++)
{
CPoint p1, p2;
p1 = m_ptArray.GetAt(i);
p2 = m_ptArray.GetAt(i + 1);
pDC->LineTo(p2);
}
}
break;
case 9://SeedFill
SeadFill(pDC, point.x, point.y, RGB(0, 0, 0), RGB(0, 255, 255));
break;
case 10: // DDAWidthLine
DDAWidthLine(pDC, m_ptStart.x, m_ptStart.y,
m_ptEnd.x, m_ptEnd.y, m_color, m_width);
break;
case 11://pentagon
Pentagon(pDC, r, m_width);
break;
case 12:
m_ptLT = m_ptStart;
m_ptRB = m_ptEnd;
CorrectRect();
pDC->Rectangle(m_ptLT.x,m_ptLT.y,
m_ptRB.x,m_ptRB.y);
break;
case 13:
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
int nDrawmode = pDC->SetROP2(R2_NOT);
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
Liang_Barsky(m_ptStart, m_ptEnd);
pDC->SetROP2(nDrawmode);
CPen penRed(PS_SOLID, 1, RGB(255, 0, 0));
CPen* oldPen = pDC->SelectObject(&penRed);
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
pDC->SelectObject(oldPen);
break;
}
ReleaseDC(pDC);
CView::OnLButtonUp(nFlags, point);
}
4.4鼠标双击
void CFinalExamView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CView::OnLButtonDblClk(nFlags, point);
m_ptArray.Add(point);
m_ptArray.Add(m_ptEnd);
CDC* pDC = GetDC();
for (int i = 0;i <= m_ptArray.GetSize() - 2;i++)
{
CPoint p1, p2;
p1 = m_ptArray.GetAt(i);
p2 = m_ptArray.GetAt(i + 2);
DDALine(pDC, p1.x, p1.y, p2.x, p2.y, m_color, m_width);
}
if (7 == m_mode)
Invalidate();
m_ptArray.RemoveAll();
}
4.5鼠标移动
void CFinalExamView::OnMouseMove(UINT nFlags, CPoint point)
{
//橡皮筋技术
CDC* pDC = GetDC();
int nDrawmode = pDC->SetROP2(R2_NOT);
pDC->SelectStockObject(NULL_BRUSH);
if (1 == m_ist)
{
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
m_ptEnd = point;
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
}
pDC->SetROP2(nDrawmode);
ReleaseDC(pDC);
}
结果展示