CCreateArc类

CCreateArc类描述如何交互绘制圆弧。本程序采用圆心、起点和终点三点绘制圆弧,所以用鼠标交互绘图时需要确定这3个点的位置。其大体思路是:前两次单击鼠标左键分别定义圆心和起点,这两点定义以后是不会变的;然后定义圆弧的终点。终点不能直接定义,因为在绘图区我们基本上不能直接获得终点的准确位置,但可以间接得到终点坐标。具体方法是根据第3点的方位角和由前两点得到的半径,计算出终点的准确位置。所以我们说的用圆心、起点和终点绘制圆弧从本质上讲应该是用圆心、起点和第3点绘制圆弧。

与前面的CCreateLine类和CCreateCircle类一样,CCreateArc类也实现了ICommand 接口。类中用到4个局部变量,m_Step定义鼠标左键的单击次数,m_Center、m_Begin和m_End分别记录圆弧的圆心、起点和终点的坐标。

LButonDown方法实现了 Command接口的LButondown方法。第一次单击鼠标左键时,定义圆心的位置,将当前点的坐标赋给m_Center。第2次单击鼠标左键时,确定圆弧起点的位置,并将该位置也赋给m_End对象,作为终点。所以,在初始情况下,圆弧的起点和终点是重合的。然后代码中用前面定义的3个点构造了一个暂时的CArc对象,并用拖曳模式绘制了该对象,然后注销。为什么要这样做,将在介绍MouseMove方法时介绍。第3次单击鼠标左键时,清除圆心到起点的橡皮线、圆心到终点的橡皮线和橡皮弧,以正常模式绘制最后生成的圆弧。将m_Step归0。

code.vc#.net
	public class CCreateArc:ICommand
	{
		private int m_Step;
		private PointF m_Center;
		private PointF m_Begin;
		private PointF m_End;
		public CCreateArc()
		{
			//
			// TODO: 在此处添加构造函数逻辑
			//
		}
		public void LButtonDown(Graphics g,PointF aPos,ArrayList ges,ArrayList geSels)
		{
			//记录鼠标左键的单击次数
			m_Step+=1;
			switch(m_Step)
			{
				case 1:               //第1次单击鼠标左键
					m_Center=aPos;
					break;
				case 2:
					m_Begin=aPos;
					m_End=aPos;
					CArc tempArc1=new CArc(m_Center, aPos, aPos);
					tempArc1.Draw(g, DrawMode.Drag);
					tempArc1 =null;
					break;
				case 3:
					//清除最后一次拖动时圆心到起点的橡皮线
					CLine tempLine1=new CLine(m_Center,m_Begin);
					tempLine1.Draw(g,DrawMode.Drag);
					tempLine1=null;
					//清除最后一次拖动时圆心到终点的橡皮线
					CLine tempLine2=new CLine(m_Center,m_End);
					tempLine2.Draw(g,DrawMode.Drag);
					tempLine2=null;
					//清除最后一次拖动时显示的橡皮弧
					CArc tempArc=new CArc(m_Center,m_Begin,m_End);
					tempArc.Draw(g,DrawMode.Drag );
					tempArc=null;
					//绘当前位置的圆弧
					CArc newArc=new CArc(m_Center,m_Begin,aPos);
					newArc.Draw(g,DrawMode.Normal);
					ges.Add(newArc);
					m_Step=0;
					break;
			}
		}
    }

MouseMove 方法实现了ICommand接口的MouseMove方法,用于描述鼠标在绘图区移动时的绘图行为。鼠标移动时,需要不断地清除上一条圆心到终点的橡皮线、上一条橡皮弧,并绘制当前的圆心到终点的橡皮线和橡皮弧。需要注意的是,在介绍LButtonDown 方法时说过,在初始状态下,圆弧的起点和终点是重合的。既然是重合的,那么,绘出的是一个点还是一个圆呢?读者朋友不妨测试一下,结果是一个圆。但绘制橡皮弧时,首先要清除上一个橡皮弧,由于在鼠标第1次移动以前并没有绘圆弧,所以没有上一个橡皮弧可供清除。结果如何呢?由于采用拖曳模式绘制,它不但没有清除,实际上还绘了一个圆。这样,后面的橡皮弧绘制将全部反向,实际上是逆时针方向绘制的,显示在屏幕上却是顺时针方向绘制。所以,在前面的LButtonDown方法中,在第2次单击以后就根据给定的3个点以拖曳模式绘了一个圆,等着MouseMove方法来清除。当前橡皮线和橡皮弧绘制完毕以后,不要忘了将当前点设置为m_End。

code.vc#.net
		public void MouseMove(Graphics g,PointF aPos)
		{
			switch(m_Step)
			{
				case 2:
					PointF prePos=new PointF();
					PointF curPos=new PointF();
					prePos=m_End;
					curPos=aPos;
					//清除上一条圆心到终点的橡皮线
					CLine tempLine1=new CLine(m_Center,prePos);
					tempLine1.Draw(g,DrawMode.Drag);
					tempLine1=null;
					//清除上一条橡皮弧
					CArc tempArc1=new CArc(m_Center,m_Begin,prePos);
					tempArc1.Draw(g,DrawMode.Drag);
					tempArc1=null;
					//绘当前圆心到终点的橡皮线
					CLine tempLine2=new CLine(m_Center,curPos);
					tempLine2.Draw(g,DrawMode.Drag);
					tempLine2=null;
					//绘当前位置的橡皮弧
					CArc tempArc2=new CArc(m_Center, m_Begin, curPos);
					tempArc2.Draw(g, DrawMode.Drag);
					tempArc2 = null;
					m_End=curPos;
					break;
			}
		}

RButtonDown方法实现了ICommand接口的RButtonDown方法,它实现对当前未完成工作的取消。取消操作需要从屏幕上清除圆心到起点的橡皮线、圆心到终点的橡皮线和橡皮弧,并将m_Step的值设为0。

code.vc#.net
		//单击鼠标右键时的绘图行为
		public void RButtonDown(Graphics g,PointF aPos)
		{
			if(m_Step==2)
			{
				//清除圆心到起点的橡皮线
				CLine tempLine1=new CLine(m_Center,m_Begin);
				tempLine1.Draw(g,DrawMode.Drag);
				tempLine1=null;
				//清除圆心到终点的橡皮线
				CLine tempLine2=new CLine(m_Center,m_End);
				tempLine2.Draw(g,DrawMode.Drag);
				tempLine2=null;
				//清除橡皮弧
				CArc tempArc=new CArc(m_Center,m_Center,m_End);
				tempArc.Draw(g,DrawMode.Drag);
				tempArc=null;
			}
			m_Step=0;
		}