⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arcobj.cpp

📁 参数化车间设备资源绘制程序
💻 CPP
字号:
#include "StdAfx.h"
#include ".\arcobj.h"
#include "visdrawdoc.h"
#include <math.h>

#include "visdrawview.h"

#define pi 3.1415926
#define DISTANCE_ZERO 10e-6

IMPLEMENT_SERIAL(CArcObj, CCircleObj, 0)

CArcObj::CArcObj(void)
{
}

CArcObj::~CArcObj(void)
{
}
CArcObj::CArcObj(const CRect& position)
		: CCircleObj(position)
{
	ASSERT_VALID(this);	

	m_StartAngle = 0.0;
	m_EndAngle = 0.0;
}

void CArcObj::Draw(CVisDrawView* pView, CDC* pDC)
{
	ASSERT_VALID(this);
	
	//创建画刷
	CBrush brush;
	if (!brush.CreateBrushIndirect(&m_logbrush))
		return;
	//创建画笔
	CPen pen;
	if (!pen.CreatePenIndirect(&m_logpen))
		return;

	//设置DC
	CBrush* pOldBrush;
	CPen* pOldPen;

	if (m_bBrush)
		pOldBrush = pDC->SelectObject(&brush);
	else
		pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);

	if (m_bPen)
		pOldPen = pDC->SelectObject(&pen);
	else
		pOldPen = (CPen*)pDC->SelectStockObject(NULL_PEN);

	//采用逻辑坐标绘制圆弧

	double x1,y1,x2,y2;
	CPoint nCenterPoint;
	long nRadium;
	CPoint nStart, nEnd;

	//得到起点坐标
	x1=m_CenterPointx +m_Radium*cos(m_StartAngle);
	y1=m_CenterPointy+m_Radium*sin(m_StartAngle);

	//得到终点的坐标
	x2=m_CenterPointx +m_Radium*cos(m_EndAngle);
	y2=m_CenterPointy+m_Radium*sin(m_EndAngle);

	pView->WorldToClient(nStart,x1,y1);
	pView->WorldToClient(nEnd,x2,y2);

	//把圆心世界坐标转化为逻辑坐标
	pView->WorldToClient(nCenterPoint,m_CenterPointx,m_CenterPointy);

	//把半径转化为逻辑长度
	nRadium = (long)(pView->WorldToClient(m_Radium));
	
	//绘制圆弧GDI函数
	pDC->Arc((nCenterPoint.x - nRadium),(nCenterPoint.y - nRadium),
		(nCenterPoint.x + nRadium),(nCenterPoint.y + nRadium),
		nStart.x,nStart.y,nEnd.x,nEnd.y);


	//恢复DC
	pDC->SelectObject(pOldBrush);
	pDC->SelectObject(pOldPen);
}

void CArcObj::Serialize(CArchive& ar)
{
	ASSERT_VALID(this);
	//调用基类串行化
	CCircleObj::Serialize(ar);

	if (ar.IsStoring())
	{
		ar << m_StartAngle << m_EndAngle;	
	}
	else
	{
		//WORD wTemp;
		ar >> m_StartAngle >> m_EndAngle;			
	}
}


//计算圆弧上点arcpoint相对于X轴夹角弧度,采用世界坐标计算

double CArcObj::CalcArcAngle(CVisDrawView* pView, CPoint arcpoint)
{
	
	double arcpointx, arcpointy;
	double nCenterPointx, nCenterPointy;
	//得到圆心的世界坐标
	GetCenterPoint(nCenterPointx, nCenterPointy);
    
	//把圆弧上点arcpoint转化为世界坐标
	pView->ClientToWorld(arcpoint, arcpointx, arcpointy);

	double radium;
	//计算世界坐标下的半径
	radium = CalcRadium(arcpointx, arcpointy);
	
	if(radium < DISTANCE_ZERO) 
		return	0 ;


	double dx,dy;
	
	dx = arcpointx - nCenterPointx;
	dy = arcpointy - nCenterPointy;

	double cosv = dx/radium;
	double sinv = dy/radium;

	//通过反余弦函数求得夹角弧度
	if(sinv >= 0)
		return acos(cosv) ;
	else if(sinv < 0)
		return 2.*pi-acos(cosv) ;
	return 0;	
}

//圆弧上三点计算圆弧参数,采用世界坐标
void CArcObj::CalculateArcParameterbytp(CVisDrawView* pView, CPoint startpoint,CPoint middlepoint,CPoint endpoint)
{
	double an1,an2,an3;
	double x1,y1,x2,y2,x3,y3;
	double xx1,xx2,yy1,yy2,xx,yy,rr;
	double k1,k2;

	//确保两条直线不为水平线

	int dy;
	dy = middlepoint.y - startpoint.y;
	if(fabs((float)dy)< DISTANCE_ZERO)middlepoint.y +=1;
	dy = endpoint.y - middlepoint.y;
	if(fabs((float)dy) < DISTANCE_ZERO)endpoint.y +=1;
	
	//把逻辑坐标转化为世界坐标

	pView->ClientToWorld(startpoint,x1,y1);
	pView->ClientToWorld(middlepoint,x2,y2);
	pView->ClientToWorld(endpoint,x3,y3);

	
	//得到顺三点方向两直线中点坐标
	xx1=(x1+x2)/2;
	yy1=(y1+y2)/2; 
	xx2=(x2+x3)/2; 
	yy2=(y2+y3)/2;

	if(fabs(y2-y1)>DISTANCE_ZERO)			//如果第一条直线段的垂线不是垂直线
		k1=-(x2-x1)/(y2-y1);				//得到第一条直线段垂线的斜率
	
	if(fabs(y3-y2)>DISTANCE_ZERO)			//如果第二条直线段的垂线不是垂直线
		k2=-(x3-x2)/(y3-y2);				//得到第二条直线段垂线的斜率
  

	//如果两条直线段都不是水平线
	
	if(k1==k2)			//如果两条直线段平行
	{
		//圆心坐标
		xx=x2+(double)(10000/sqrt(1+k1*k1));
		yy=y2+(double)(10000/sqrt((1+k1*k1)/(k1*k1)));
		rr=10000;
	}
	else				//如果两条直线段不平行
	{
		//圆心坐标,半径
		xx=(yy2-yy1+k1*xx1-k2*xx2)/(k1-k2);
		yy=yy1+k1*(xx-xx1);
		rr=(double)sqrt((xx-x1)*(xx-x1)+(yy-y1)*(yy-y1)); //
	}


	SetCenterPoint(xx,yy);
	SetRadium( rr);

	
	//得到第一个点相对于圆心的弧度
	an1=(double)acos((x1-xx)/rr);
	if(y1-yy<0)   an1=(double)(pi*2-an1);
	
	//得到第二个点相对于圆心的弧度
	an2=(double)acos((x2-xx)/rr);
	if(y2-yy<0)     an2=(double)(pi*2-an2);
	
	//得到第三个点相对于圆心的弧度
	an3=(double)acos((x3-xx)/rr);
	if(y3-yy<0) an3=(double)(pi*2-an3);

	

	//如果圆弧是逆时针方向画的
	if(an2>an1&&an2<an1+pi||an2<an1&&an2+pi<an1) 
	{
		m_StartAngle=an1;	//起始弧度
		m_EndAngle=an3;		//终止弧度
	}
	
	//如果圆弧是逆时针方向画的
	

	//如果圆弧是顺时针方向画的
	else    
	{
		m_StartAngle=an3;	//起始弧度
		m_EndAngle=an1;		//终止弧度
	}
}

//计算矩形图形元边界矩形,以逻辑坐标表示
CRect CArcObj::CalcBounds(CVisDrawView* pView)
{
	ASSERT_VALID(this);

	double MinX, MinY, MaxX, MaxY ,tempX, tempY;
	int pb = 0 ;

	double m_beginx, m_beginy, m_endx, m_endy;

	m_beginx = m_CenterPointx + m_Radium*cos(m_StartAngle);
	m_beginy = m_CenterPointy + m_Radium*sin(m_StartAngle);

	m_endx = m_CenterPointx + m_Radium*cos(m_EndAngle);
	m_endy = m_CenterPointy + m_Radium*sin(m_EndAngle);



	MinX = min( m_beginx, m_endx );
	MinY = min( m_beginy, m_endy );
	MaxX = max( m_beginx, m_endx );
	MaxY = max( m_beginy, m_endy );

	if(m_StartAngle < m_EndAngle) pb = 1 ;
	else
	{
		MinX = min(MinX, m_CenterPointx + m_Radium) ;
		MinY = min(MinY, m_CenterPointy) ;
		MaxX = max(MaxX, m_CenterPointx + m_Radium) ;
		MaxY = max(MaxY, m_CenterPointy) ;
		tempX = MaxX ;
		tempY = MaxY ;
		pb = 2 ;
	}
	for(int i=0 ;i<4 ;i++)
	{
		if(pb==1 &&pi*i/2.>m_StartAngle &&pi*i/2.<m_EndAngle||
			pb==2 &&!(pi*i/2.>m_EndAngle &&pi*i/2.<m_StartAngle))

		{
			if(i==1)
			{
				tempX = m_CenterPointx  ; tempY = m_CenterPointy  + m_Radium;
			}
			if(i==2)
			{
				tempX = m_CenterPointx - m_Radium ; tempY = m_CenterPointy ;
			}
			if(i==3)
			{
				tempX = m_CenterPointx ; tempY = m_CenterPointy - m_Radium ;
			}
			MinX = min(MinX, tempX) ;
			MinY = min(MinY, tempY) ;
			MaxX = max(MaxX, tempX) ;
			MaxY = max(MaxY, tempY) ;
		}
	}

	CPoint pt1,pt2;
	pView->WorldToClient(pt1,MinX,MinY);
	pView->WorldToClient(pt2,MaxX,MaxY);
	m_position.TopLeft() = pt1;
	m_position.BottomRight() = pt2;	

	return m_position;
}

//图元被选择判断
BOOL CArcObj::IsSelected(CVisDrawView* pView, const CPoint& point)
{
	//参数point是鼠标的逻辑坐标
	CPoint local = point;

	//参数point是鼠标的逻辑坐标
	double distance,radium;
	int nSelectDistance;
	
	//鼠标点的设备坐标
	pView->DocToClient(local);

	//识别精度值
	nSelectDistance = pView->GetDocument()->GetSetectDistance()/2;
	
	CPoint pt;
	//把圆心坐标转化为逻辑坐标
	pView->WorldToClient(pt, m_CenterPointx, m_CenterPointy);

	//把圆心坐标由逻辑坐标转化为设备坐标
	pView->DocToClient(pt);

	//计算鼠标点point与圆心之间的像素距离

	distance = PointToPoint(pt,local);

	radium = pView->WorldToClient(m_Radium);

	distance = fabs(distance - radium);

	//如果拾取点到圆弧距离小于识别精度,则继续判断弧度范围
	if(distance > nSelectDistance) return false;
	else
	{
		//拾取点与圆心中心连线与X轴正向夹角弧度
		double angle;

		//函数参数local为逻辑坐标
		angle = CalcArcAngle(pView, local);

		if((m_StartAngle < m_EndAngle && angle < m_EndAngle && angle > m_StartAngle)
		||m_StartAngle > m_EndAngle && angle < m_StartAngle && angle > m_EndAngle)
			return TRUE;
		else
			return FALSE;
	}

}

//返回手柄个数
int CArcObj::GetHandleCount()
{
	ASSERT_VALID(this);

	return 4;
}

// 返回手柄中心逻辑坐标
CPoint CArcObj::GetHandle(CVisDrawView* pView, int nHandle)
{
	ASSERT_VALID(this);

	CPoint point;
	double pointx,pointy;
	double angle;
    
	switch(nHandle)
	{
	case 1:
		//起点
		pointx = m_CenterPointx + m_Radium*cos(m_StartAngle);
		pointy = m_CenterPointy + m_Radium*sin(m_StartAngle);
		break;

	case 2:
		//终点
		pointx = m_CenterPointx + m_Radium*cos(m_EndAngle);
		pointy = m_CenterPointy + m_Radium*sin(m_EndAngle);
		break;

	case 3:
		//中点		
		angle = (m_StartAngle + m_EndAngle)/2.0;
		pointx = m_CenterPointx + m_Radium*cos(angle);
		pointy = m_CenterPointy + m_Radium*sin(angle);
		break;

	case 4:
		//圆弧中心
		pointx = m_CenterPointx;
		pointy = m_CenterPointy;
		break;
	}

	//把手柄世界坐标转化为逻辑坐标
	pView->WorldToClient(point,pointx,pointy);

	return point;
}
//移动手柄
void CArcObj::MoveHandleTo(int nHandle, CPoint point, CVisDrawView* pView)
{
	ASSERT_VALID(this);

	//圆弧上三点逻辑坐标
	CPoint pt1, pt2, pt3;

	pt1 = GetHandle(pView, 1);
	pt2 = GetHandle(pView, 2);
	pt3 = GetHandle(pView, 3);

	switch (nHandle)
	{
	default:
		ASSERT(FALSE);

	case 1:
		CalculateArcParameterbytp(pView, point,pt2,pt3);	
		break;

	case 2:
		CalculateArcParameterbytp(pView, pt1,point,pt3);		
		break;

	case 3:
		CalculateArcParameterbytp(pView, pt1,pt2,point);		
		break;
	}

	CalcBounds(pView);	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -