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

📄 clplot.cpp

📁 实时曲线类的改进增加功能: 1)采样数据存盘和加载 2)演示程序中可以实现图形的打印预览和打印功能,曲线从原点开始
💻 CPP
📖 第 1 页 / 共 3 页
字号:


	if(printerDC!=NULL)
		printerDC->SelectObject(oFont);
	else
		dc.SelectObject(oFont);

	

}

//*******************************************************************************************************/
//* Function:		clPlot::OnPaint
//*
//* Description:	This function will create a memory image, call Draw to draw the plot on it, and when
//*					copy the image into memory.
//*
//*					This is fast and provides flicker free plot update.
//*
//* Author:			Jan Vidar Berger
//*******************************************************************************************************/
void clPlot::OnPaint() 
{
        CPaintDC dc(this); // device context for painting
        CMemDC  pdc(&dc);  // non flickering painting

    
		Draw(&pdc);
		// Do not call  for painting messages
}

BOOL clPlot::OnEraseBkgnd(CDC* pDC) 
{
		return FALSE;
}

//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::Draw(CDC * dc)
{
	CFont *oFont;
	CFont newfont;

	newfont.CreateFontIndirect(&m_zoomFont);//以前是将字体指针直接
	//选进设备环境,在打印预览时常导致字体资源丢失错误。故此处改为
	//直接创建字体,字体大小与m_font相同,只不过是重新创建了一次而已。
	oFont = dc->SelectObject(&newfont);

	DrawBasic(dc); //画整个图区的边框和背景
	DrawGrid(dc);  //画网格
	DrawPlot(dc);  //画主曲线
	if(m_bDrawLegend)
		DrawLegend(dc);//画图例
	
	dc->SelectObject(oFont);
	
}


//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::Print(CDC * dc)
{
	Draw(dc);// 在打印机上打印
}


//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::DrawBasic(CDC * dc)
{
	CBrush brushctlBkColor(m_ctlBkColor);

	CRect lrect;
	lrect=m_ctlRect;
	lrect.left-=5;lrect.top-=5;
	//实际过程中不知为何总出现左上边缘不能清除问题,只好将m_ctlRect向左上扩展
	dc->FillRect(lrect,&brushctlBkColor);//清整个图区(包括刻度标示,margin区等)
	

	CBrush  brushPlotBkColor(m_plotBkColor);
	dc->FillRect(m_plotRect,&brushPlotBkColor);//清整个图区(包括刻度标示,margin区等)
	if(dc->IsPrinting())
		dc->Rectangle(m_plotRect);//打印时不用3D线,以使打印清楚
	else
	{
		CRect lr=m_plotRect;
		lr.InflateRect(1,1);
		dc->DrawEdge(lr,EDGE_BUMP, BF_RECT);//(在屏幕上)画3D边框
	}

	if(m_bDrawLegend)
		DrawLegendShadow(dc);//画图例阴影
}

//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::DrawPlot(CDC * dc)//画曲线
{
	for(int s=0;s<MAXSERIES;s++)
	{
		if(m_series[s].m_bIAmInUse)
		{
			DrawSerie(dc, s);//依次画各条曲线
		}
	}
}

//*******************************************************************************************************/
//*******************************************************************************************************/







 //已调试通过,只是曲线采样间隔超过X轴最大时间时不显示 2000.9.21

void clPlot::DrawSerie(CDC *dc,int serie)  //画曲线的核心程序
//serie:曲线索引号(从0开始)
{
	
	BOOL bMore=TRUE;
	BOOL bDraw;
	CPoint point;
	int counter;//本图中实际要画的点数
	// lets get some serie parameters now and save the time of indexing during the loop
	
	//实际值从m_series[serie].m_pvalues[m_lbegin]到m_series[serie].m_pvalues[m_lend]画第serie条曲线
	long pointer = m_series[serie].m_lbegin;
	long end = m_series[serie].m_lend;

	long valueNos = m_series[serie].m_lNoValues;//第serie曲线采样的总点数
	BOOL bRightAxis = m_series[serie].m_bRightAxisAlign;//右Y轴


	CPen pen(m_series[serie].m_iLineStyle, 3, m_series[serie].m_color);//画曲线的笔


	
	CPen *old;

	//画实时曲线
	old= dc->SelectObject(&pen); 
	int pLineArrayStart=1;
	int thelastpoint=0;//记录在可视区最后一个点在数组中的位置
	_value * mvalues=m_series[serie].m_pvalues;// 

	while(bMore)
	{
		bDraw=FALSE;
		bMore=FALSE;
		counter=0;
		counter=1;//预留pLineArray[0]为实测数据与左轴的交点
		//while(pointer != end && !bDraw)
		while(pointer != end )
		{
			//Scaling. We do scaling inline to save some time
			long valuetime = mvalues[pointer].ValueTime;
			
			//X轴坐标(像素为单位)

			
			point.x = (int)(m_plotRect.left+ ((valuetime-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));
			
			if(!bRightAxis) //左Y轴
				point.y = (int)(m_plotRect.bottom - ((mvalues[pointer].dValue-m_leftaxis.minrange)/m_leftaxis.m_dValuePrPixel));
				//像素
			else
				point.y = (int)(m_plotRect.bottom - ((mvalues[pointer].dValue-m_rightaxis.minrange)/m_rightaxis.m_dValuePrPixel));		

			//TRACE("counter=%d  point.x=%d  point.y=%d \n",counter,point.x,point.y);
			if(point.x >= m_plotRect.left && point.x <= m_plotRect.right)
			{//采样点落在当前图可视区域

				if(counter==1)//在可视区域画的第一个点
				{
					//到采样起点间的采样点数
					int dist=(pointer-m_series[serie].m_lbegin+clPlot::m_lMaxDataPrSerie)%( clPlot::m_lMaxDataPrSerie)+1;
					if(dist>=2)//当前至少为采样数组第2个点后面的点
					{//计算与左Y轴的交点坐标

						int lastpointer=(pointer-1+clPlot::m_lMaxDataPrSerie)%( clPlot::m_lMaxDataPrSerie);//pointer最大不超过clPlot::m_lMaxDataPrSerie
						long lasttime=mvalues[lastpointer].ValueTime;
						CPoint lastpoint;
						//计算前一个采样点的坐标值
						lastpoint.x = (int)(m_plotRect.left+ ((lasttime-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));
						
						if(bRightAxis) //右Y轴
							lastpoint.y = (int)(m_plotRect.bottom - ((mvalues[lastpointer].dValue-m_rightaxis.minrange)/m_rightaxis.m_dValuePrPixel));		
						else
							lastpoint.y = (int)(m_plotRect.bottom - ((mvalues[lastpointer].dValue-m_leftaxis.minrange)/m_leftaxis.m_dValuePrPixel));

						//与左轴交点的坐标
						pLineArray[0].x =m_plotRect.left;
						if(point.x!=lastpoint.x)
						{
							pLineArray[0].y = (lastpoint.y*(point.x-m_plotRect.left)+point.y*(m_plotRect.left-lastpoint.x))/(point.x-lastpoint.x);
							pLineArrayStart=0;
						}
						else
							point.x=lastpoint.x;
					}//if(pointer>=1)
				}//if(counter==1) end

				
				pLineArray[counter].x = point.x;
				pLineArray[counter].y = point.y;
				thelastpoint=pointer;  //记录在可视区最后一个点在数组中的位置
				counter++;//counter:本图中实际要画的点数
			}
			pointer++;//指向第serie曲线采样值的存储数组

			pointer=pointer%( clPlot::m_lMaxDataPrSerie);//pointer最大不超过clPlot::m_lMaxDataPrSerie

			if(pointer > valueNos)	// wrap list index ?
				pointer=0;
		}//while(pointer != end  end
		

		if(counter-pLineArrayStart>0)
		{
			dc->Polyline(pLineArray+pLineArrayStart, counter-pLineArrayStart);
		}
	}//while(bMore)  end
	dc->SelectObject(old);



}




//*******************************************************************************************************/
//*
//*******************************************************************************************************/
void clPlot::DrawGrid(CDC * dc)
{
	DrawXAxisGrid(dc); //画X轴网格
	DrawYAxisGrid(dc);//画Y轴网格并标Y轴坐标
}

//*******************************************************************************************************/
//*******************************************************************************************************/


void clPlot::DrawXAxisGrid(CDC * dc)//画X轴网格并标X轴坐标
{
	long yGrid = m_timeaxis.m_mintime;
	long delta =(m_timeaxis.m_maxtime-m_timeaxis.m_mintime)/m_iXBigGrids;//X轴分为m_iXBigGrid个大网格(模认为6)
	long d10 = delta / 5;//每大格间又分为5小格
	long diff = ((long)yGrid)%((long)delta);
	CPen *old, pen(PS_DASHDOTDOT, 0, m_gridColor);//竖向的主分割线
	CPen stick(PS_DASH,0,RGB(0,0,0));//坐标轴下的短线
	CPen mline(PS_SOLID,0,RGB(192,192,192));//浅灰(竖向的辅分割线)
	
	int i;

	TRACE("画坐标x轴开始\n");
	
	m_lMaxDataPrSerie;
	
	i=(m_series[0].m_lNoValues-1)%( clPlot::m_lMaxDataPrSerie);
	if(i>=0)
	{
	_value &vv=m_series[0].m_pvalues[i];
	
	TRACE("Nos=%d   array[%d]=%f valtime=%d \n ",m_series[0].m_lNoValues,i,vv.dValue,vv.ValueTime);

	}
	if(m_timeaxis.m_mintime!=0)
	{
		TRACE("    mintime= %d   maxtime=%d  \n",m_timeaxis.m_mintime,m_timeaxis.m_maxtime);

	}
	for( long sx = m_timeaxis.m_mintime; sx < m_timeaxis.m_maxtime; sx+=d10)
	{
		int off=3;
		off=8;
		if((long)sx%(long)delta == 0)
			off=10;
		if(sx > m_timeaxis.m_mintime)
		{
			int x = (int)(m_plotRect.left + ((sx-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));
			old = dc->SelectObject(&stick); 

			TRACE("刻度线:moveto(  %d, %d ) lineto(%d,%d)\n",x,m_plotRect.bottom,x+off,m_plotRect.bottom);
			dc->MoveTo(CPoint(x,m_plotRect.bottom));
			dc->SelectObject(old);

			if(m_bXThinGrid)//竖向的细线
			{
				old = dc->SelectObject(&mline);
				TRACE("xthingrid: moveto(%d,%d) lineto(%d,%d) \n",x,m_plotRect.bottom-1,x,m_plotRect.top+1);
				dc->MoveTo(CPoint(x,m_plotRect.bottom-1));
				dc->LineTo(CPoint(x,m_plotRect.top+1));//竖向的细线
				dc->SelectObject(old);
			}
		}
	}

	
	old = dc->SelectObject(&pen);

	COLORREF oldbkcolor=dc->SetBkColor(m_ctlBkColor);//刻度字符的背景色
	COLORREF oldtxtcolor=dc->SetTextColor(m_txtColor);//刻度字符的颜色

	int ykedu=m_plotRect.bottom+5;//刻度所在Y坐标
	for(yGrid=m_timeaxis.m_mintime,i=0;i<=m_iXBigGrids;i++)
	{
		int x = (int)(m_plotRect.left + ((yGrid-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));

		if(m_bXThickGrid)//竖向的粗线
		{
			if(x>m_plotRect.left && x<m_plotRect.right&&i!=m_iXBigGrids)
			{
				TRACE("竖向粗线:moveto(  %d, %d ) lineto(%d,%d)\n",x,m_plotRect.bottom-1,x,m_plotRect.top+1);
				dc->MoveTo(CPoint(x,m_plotRect.bottom-1));
				dc->LineTo(CPoint(x,m_plotRect.top+1));//竖向粗线
			}
		}


		//标X轴刻度值--时间(s)
		char b[100];
		double  ft=(double)yGrid/1000.0;//时间:s
		sprintf(b, "%.2f", ft);

		CSize size=dc->GetTextExtent(CString("A"));
		CString lstr(b);
		size=dc->GetTextExtent(lstr);
		
		int y=m_clientRect.bottom+(int)(size.cy*1.5)+5;
		
		int len=size.cx;
	
		y=m_plotRect.bottom;
		
		TRACE("刻度 rect(  %d, %d  %d,%d,%s)\n",x-len/2, ykedu,x+len/2,ykedu+size.cy,b);
		
		TRY
		{
			if(!dc->TextOut(x-len/2, ykedu,lstr))
				AfxThrowResourceException();

		}
		CATCH(CResourceException,e)
		{
			CString msgStr("resource error");
			AfxMessageBox((const char*)msgStr);

		}
		AND_CATCH_ALL(e)
		{
			CString msgStr("other error");
			AfxMessageBox((const char*)msgStr);
		}
		END_CATCH_ALL

		

		yGrid += delta;
	}

	//标X轴名称及单位
	CSize size=dc->GetTextExtent(m_timeaxis.m_szTitle);

	int center=(m_plotRect.left+m_plotRect.right)/2;

	TRACE("x轴名称  rect(  %d, %d  %d,%d)\n",center-size.cx/2,m_ctlRect.bottom-size.cy-2,center+size.cx/2,m_ctlRect.bottom-2);


	int y=(m_ctlRect.bottom+ykedu+size.cy)/2-size.cy/2;
	if(y+size.cy>m_ctlRect.bottom)
		y=m_ctlRect.bottom-size.cy-2;

	CRect lrect(center-size.cx/2,m_ctlRect.bottom-size.cy-2,center+size.cx/2,m_ctlRect.bottom-2);
	lrect.NormalizeRect();
	CString lcstr(m_timeaxis.m_szTitle);
	if(m_bDispXTitle)//是否显示x轴名称
		dc->TextOut(center-size.cx/2,y,lcstr);//center display


	TRACE("x轴名称结束 \n");

	dc->SetTextColor(oldtxtcolor);////恢复为字符的原背景色
	dc->SetBkColor(oldbkcolor);////恢复为字符的原背景色
	
	dc->SelectObject(old);
	TRACE("画坐标x轴结束 \n");
}



//*******************************************************************************************************/
//*******************************************************************************************************/


void clPlot::DrawYAxisGrid(CDC * dc)//画Y轴网格并标Y轴坐标
{

	int smallgrids=5;//大栅格间可以有smallgrids个小栅格
	double delta;//大栅格间对应的实际值

	//调整m_leftaxis.minrange为10的倍数
	m_leftaxis.minrange=(double) (  (long)(m_dLeftYSetMinRange/10.0) ) *10.0;
	
	double yGrid = m_leftaxis.minrange;

	
	double di=4.0;//大栅格间对应的刻度时di的倍数 (根据Y轴间代表的实际值调整)


	if(m_dLeftYSetMaxRange-m_leftaxis.minrange>500.0)
		di=50.0;
	else
		if(m_dLeftYSetMaxRange-m_leftaxis.minrange<80.0)
			di=2.0;


	delta=(((long)(m_leftaxis.maxrange-m_leftaxis.minrange+di*m_iYBigGrids-1.0))/(((long)di)*m_iYBigGrids))*((long)di);
	m_leftaxis.maxrange=m_leftaxis.minrange+delta*m_iYBigGrids;


	m_leftaxis.m_dValuePrPixel = ((double)(m_leftaxis.maxrange- m_leftaxis.minrange) / (double)m_plotRect.Height());

	double d10 = delta / 5.0;//小栅格间对应的实际值
	// todo: delta switch
	long diff = ((long)yGrid)%((long)delta);
	//yGrid = yGrid - diff;
	diff=0;


	CPen *oldpen, pen(PS_DASHDOTDOT, 1, m_gridColor);//横向的主分割线
	CPen stick(PS_SOLID,0,RGB(0,0,0));//坐标轴外的短线
	CPen mline(PS_SOLID,0,RGB(192,192,192));//横向的辅分割线

	//画Grid(栅格)细线
	double sy;
	int ii;
	//for( long sy = (long)((long)(m_leftaxis.minrange) - diff); sy <= m_leftaxis.maxrange; sy+=(long)d10)
	//for(sy =m_leftaxis.minrange; sy <= m_leftaxis.maxrange; sy+=d10)
	int off=5;//短线的长度

	for(ii=0;ii<=m_iYBigGrids*smallgrids;ii++)
	{
	
		sy=m_leftaxis.minrange+d10*ii;//d10短线间代表的实际值
	
		off=5;//短线的长度
		//if((long)sy%(long)delta == 0)
		if((ii%smallgrids)==0)
		{
			off=15;
		}

		if(sy >= m_leftaxis.minrange)
		{
			double yy=(sy-m_leftaxis.minrange)/m_leftaxis.m_dValuePrPixel;
 	        int y=m_plotRect.bottom -(int)yy;
			
			oldpen = dc->SelectObject(&stick); 
			dc->MoveTo(CPoint(m_plotRect.left,y));
			//画短线
			dc->LineTo(CPoint(m_plotRect.left-off,y)); //左Y轴栅格坐标外的短线(细线)
			if(m_bUseRightYAxis)
			{
				dc->MoveTo(CPoint(m_plotRect.right,y));
				dc->LineTo(CPoint(m_plotRect.right+off,y));//右Y轴栅格坐标外的短线(细线)
			}
			dc->SelectObject(oldpen);

			if(m_bYThinGrid)//横向的细线
			{
				oldpen = dc->SelectObject(&mline);
				dc->MoveTo(CPoint(m_plotRect.left+1,y));
				dc->LineTo(CPoint(m_plotRect.right-1,y));  //横向的细线
				dc->SelectObject(oldpen);
			}
		}
	}//画Grid(栅格)细线结束

	oldpen = dc->SelectObject(&pen);

	

⌨️ 快捷键说明

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