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

📄 clplot.cpp

📁 实时曲线类的改进增加功能: 1)采样数据存盘和加载 2)演示程序中可以实现图形的打印预览和打印功能,曲线从原点开始
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//*******************************************************************************************************/
//* FileName:		clPlot.cpp
//*
//* Contents:		Implementation of clPlot, axis, legend, serie and timeaxis
//*
//* NOTE 1:			Only a minimum of parameter validation is implemented to save time since this plot is 
//*					time critical.
//*
//* NOTE 2:			All functionality is not fully implemented.
//*
//* Author:			Jan Vidar Berger
//*******************************************************************************************************/
//* 12.feb.98	Jan Vidar Berger	Implemented flicker free drawing. Thanks to John Kim for providing 
//*									the MemDC and to Keith Rule, the author of CMemDC.
//*******************************************************************************************************/

#include "stdafx.h"
#include "clPlot.h"
#include "MemDC.h"
#include "afx.h"

#include "malloc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

long	clPlot::m_lMaxDataPrSerie;	// max allowed data pr. serie.
long	clPlot::m_lMaxDataTotal;	// max allowed data total.

//*******************************************************************************************************/
//* time axis threshold. contains grid and label intervals to be used within specified
//* seconds pr. pixels thresholds. The array is terminated by a 'bIAmInUse'=FALSE.
//*******************************************************************************************************/
struct{
	BOOL	bIAmInUse;					// indicate valid entry, last=FALSE
	long	lgridinterval;				// grid line interval in seconds
	long	llabelinterval;				// time label interval in seconds
	long	lmodethreshold;				// mode threshold in seconds pr. pixel
}gridsetting[]={
	TRUE, 1, 4,	0,						// 0: pr. second

	FALSE, 1, 1,0,						// last entry in table
};

//*******************************************************************************************************/
//* Function:		serie::serie
//*******************************************************************************************************/
serie::serie()
{
	m_bIAmInUse		= FALSE;
	m_color			= RGB(0,0,0);
	m_iLineStyle	= PS_SOLID;
	m_bRightAxisAlign	= FALSE;
	m_lNoValues		= 0;
	m_lbegin		= 0;
	m_lend			= 0;
	m_pvalues		= NULL;

}

//*******************************************************************************************************/
//* Function:		serie::~serie
//*******************************************************************************************************/
serie::~serie()
{
	if(m_pvalues !=NULL)
		free(m_pvalues);
}

//*******************************************************************************************************/
//* Function:		serie::AddPoint
//*
//* Description:	AddPoint add new data to the end of a data serie. It will simply append the data,
//*					update the list index and get out. 
//*
//*					This function will also call realloc or malloc to re-size or create the plot array as
//*					needed.
//*
//*					The nice thing about circular lists is that they are multi thread enabled as is. You
//*					must however implement a syncronization mechanism if more than one thread is supposed
//*					to enter data into the plot.
//*
//* Parameters:		valuetime		Time (x value).
//*					y				y value
//*
//* Return Value:	-none-
//*
//* Author:			Jan Vidar Berger
//*******************************************************************************************************/
//动态调整缓冲数组空间,然后在数组末尾插入新数据。
void serie::AddPoint(long &valuetime , double &y)
{
	if(m_lNoValues > 0)
	{
		if(m_lNoValues <= clPlot::m_lMaxDataPrSerie)
			m_pvalues = (value*)realloc(m_pvalues, (m_lNoValues+1)*sizeof(value));//重新调整数组大小
	}
	else
		m_pvalues = (value*)malloc((m_lNoValues+1)*sizeof(value));//创建数组

	m_pvalues[m_lend].ValueTime = valuetime;//X axis value
	m_pvalues[m_lend].dValue	= y;        //Y axis value
	m_lNoValues++;  //数据总个数

	TRACE(" begin=%d ,end=%d valueNos=%d \n", m_lbegin,m_lend,m_lNoValues);
	m_lend++;
	//if(m_lend >= clPlot::m_lMaxDataPrSerie)//m_lend最大不超过clPlot::m_lMaxDataPrSerie
	//	m_lend=0;
	
	m_lend =m_lend%( clPlot::m_lMaxDataPrSerie);//m_lend最大不超过clPlot::m_lMaxDataPrSerie
	
	if(m_lbegin == m_lend)
	{
		m_lbegin++;  //此时采取数据个数〉m_lMaxDataPrSerie,数据循环存放在m_pvalues[]中
		if(m_lbegin >= clPlot::m_lMaxDataPrSerie)
			m_lbegin=0;
	}
}

void serie::Serialize(CArchive &ar)
{
	if(!m_bIAmInUse) return;

	long  i,j,k;
	int nos;
	if(ar.IsStoring())
	{
		nos=(m_lend-m_lbegin+clPlot::m_lMaxDataPrSerie)%clPlot::m_lMaxDataPrSerie;
		ar<<nos;//数据个数
		for(i=m_lbegin,j=0;j<nos;i++,j++)
		{
			k=i%( clPlot::m_lMaxDataPrSerie);
			ar<<m_pvalues[k].ValueTime<<m_pvalues[k].dValue;//保存采样值(时间,速度)
		}
	}
	else
	{
		ar>>nos;//数据个数

		if(!nos) return;
		m_lbegin=0;
		m_lend=nos;
		if(m_lNoValues >0)
			m_pvalues = (value*)realloc(m_pvalues, (nos+1)*sizeof(value));//重新调整数组大小
		else
		{
			m_pvalues = (value*)malloc((nos+1)*sizeof(value));//创建数组
		}
		m_lNoValues=nos;
		for(i=m_lbegin,j=0;j<nos;i++,j++)
		{
			k=i%( clPlot::m_lMaxDataPrSerie);
			ar>>m_pvalues[k].ValueTime>>m_pvalues[k].dValue;//装入采样值(时间,速度)
		}
	}

}


//*******************************************************************************************************/
//* Function:		serie::Reset
//*
//* Description:	Reset the serie. Remove data and reset indexes and pointers.
//*
//* Parameters:		-none-
//*
//* Return Value:	-none-
//*
//* Author:			Jan Vidar Berger
//*******************************************************************************************************/
void serie::Reset()
{
	m_lNoValues=0;

	if(m_pvalues !=NULL)
		free(m_pvalues);

	m_pvalues = NULL;

	m_lbegin		= 0;
	m_lend			= 0;
}

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

IMPLEMENT_SERIAL(clPlot, CWnd, 0)


clPlot::clPlot()
{
	m_ctlBkColor		= RGB(255,255,255);
	//m_ctlBkColor		= RGB(64,128,128);
	m_plotBkColor		= RGB(64,128,128);
	m_plotBkColor		= RGB(255,255,255);
	m_legendBkColor		= RGB(255,255,255);
	m_gridColor			= RGB(127,127,127);
	m_bctlBorder		= TRUE;
	m_bplotBorder		= TRUE;
	m_blegendBorder		= TRUE;
	m_bPrimaryLegend	= FALSE;
	m_bSecondaryLegend	= FALSE;
	m_bAxisLY			= TRUE;
	m_bAxisRY			= TRUE;
	m_bAxisBX			= TRUE;
	m_bAutoScrollX		= FALSE;
	m_bSimMode			= FALSE;

	m_bXThinGrid=false;//默认方式只画栅格主线,不画辅线
	m_bYThinGrid=false;
	m_bXThickGrid=true;
	m_bYThickGrid=true;
	m_bDrawLegend=false;//默认方式不显示图例
	m_bDispXTitle=true;     //是否显示X轴单位(默认显示)
	m_bDispYTitle=true;     //是否显示Y轴单位(默认显示)
	m_txtColor=RGB(0,0,255);//blue. 标识符(刻度,X,Y轴名称及单位)颜色
	m_bLeftYAutoAdjust=true;//Y轴刻度坐标是否自动调整(默认自动)



	m_lMaxDataPrSerie	= 10000; //单条曲线数组最多容纳的数据个数
	m_lMaxDataTotal		= 100000;//单条曲线最多允许的数据个数(目前改变量没用上)

	//m_lMaxDataPrSerie	= 5; //单条曲线数组最多容纳的数据个数
	//m_lMaxDataTotal		= 10;//单条曲线最多允许的数据个数(目前改变量没用上)
	m_dNoData			= 0.0;

	m_dzoom				= 1.0;
	
	lArraySize			= 1000;	 // only points with differebt x,y will be put into the array

	pLineArray			= new CPoint[lArraySize];
	long totime,fromtime;
	fromtime=0;totime=30000;//ms
	SetBXRange(fromtime,totime);

	m_logFont.lfHeight			= -13;
	m_logFont.lfHeight			= 16;
	m_logFont.lfWidth			= 0;
	m_logFont.lfEscapement		= 0;
	m_logFont.lfOrientation		= 0;
	m_logFont.lfWeight			= 600;
	m_logFont.lfItalic			= FALSE;
	m_logFont.lfUnderline		= FALSE;
	m_logFont.lfStrikeOut		= FALSE;
	m_logFont.lfCharSet			= ANSI_CHARSET;
	//m_logFont.lfCharSet			= GB2312_CHARSET;
	m_logFont.lfOutPrecision	= OUT_DEFAULT_PRECIS;
	m_logFont.lfClipPrecision	= CLIP_DEFAULT_PRECIS;
	m_logFont.lfQuality			= PROOF_QUALITY;
	m_logFont.lfPitchAndFamily	= DEFAULT_PITCH;
	strcpy(m_logFont.lfFaceName,"Arial");

	m_zoomFont.lfHeight			= -13;
	m_zoomFont.lfWidth			= 16;
	m_zoomFont.lfEscapement		= 0;
	m_zoomFont.lfOrientation	= 0;
	m_zoomFont.lfWeight			= 600;
	m_zoomFont.lfItalic			= FALSE;
	m_zoomFont.lfUnderline		= FALSE;
	m_zoomFont.lfStrikeOut		= FALSE;
	m_zoomFont.lfCharSet		= ANSI_CHARSET;
	//m_zoomFont.lfCharSet		=GB2312_CHARSET;
	m_zoomFont.lfOutPrecision	= OUT_DEFAULT_PRECIS;
	m_zoomFont.lfClipPrecision	= CLIP_DEFAULT_PRECIS;
	m_zoomFont.lfQuality			= PROOF_QUALITY;
	m_zoomFont.lfPitchAndFamily	= DEFAULT_PITCH;
	strcpy(m_zoomFont.lfFaceName,"Arial");

	m_bUseRightYAxis=false;//单Y轴
	m_bRightYMargin=true;//右Y轴留空格

	
	//坐标图上当前点距离右轴占整个X轴长度的百分比,这样做便于看到后面曲线的期望值
	m_dMarginPercentOfCurrentPointToRightY=0.15;//默认为0.3




}

//*******************************************************************************************************/
//*******************************************************************************************************/
clPlot::~clPlot()
{
	Reset();
	delete [] pLineArray;
}


//*******************************************************************************************************/
//*******************************************************************************************************/
BEGIN_MESSAGE_MAP(clPlot, CWnd)
	//{{AFX_MSG_MAP(clPlot)
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//*******************************************************************************************************/
//*******************************************************************************************************/
BOOL clPlot::Create(DWORD dwstyle, CRect &rect, CWnd *pParent, UINT id)
{
	DWORD style = dwstyle & (~WS_BORDER);
	if(dwstyle & WS_BORDER)
		m_bctlBorder=TRUE;
	else
		m_bctlBorder=FALSE;

	//m_ctlBkColor=(COLORREF)::GetSysColor(COLOR_3DFACE);//默认方式与背景FACE颜色一致(即:透明)
    CString wndclass = AfxRegisterWndClass(CS_DBLCLKS, LoadCursor(NULL, IDC_ARROW),
      CreateSolidBrush(GetSysColor(COLOR_BTNFACE)), 0);

	//if(!CWnd::Create(wndclass, "long", style, rect, pParent, id, NULL))
	if(!CWnd::Create(NULL, "", style, rect, pParent, id, NULL))
	{
		AfxMessageBox("创建窗口失败");
		return FALSE;
	}

	m_ctlRect = rect;//(父窗口的)逻辑坐标
	pParent->ClientToScreen(m_ctlRect);//(父窗口的)设备坐标
	ScreenToClient(m_ctlRect);//(当前窗口的)逻辑坐标

	ComputeRects(TRUE);//
	return TRUE;
}

//*******************************************************************************************************/
//* Function        : clPlot::ComputeRects
//*
//* Description	    : Compute rects used for internal possitioning of different objects. This function is 
//*					  called when the plot is created or sized.
//*
//* Return type	    : void 
//*
//* Parameter(s)    : bInitialization		indicate wherever parameters that can be changed abu the user
//*											also should be computed.
//*
//* Author          : Jan Vidar Berger
//*******************************************************************************************************/
void clPlot::ComputeRects(BOOL bInitialization,CDC *printerDC)
{
	// adjust the client rect for borders

	CClientDC dc(this);

	int w = 0;
	int n=0;
	CSize z;
	if(printerDC!=NULL)
	{
		z=printerDC->GetTextExtent(CString("A"));
		m_dzoom = ((double)m_ctlRect.Height()/(double)z.cy) / 15.0;
	}
	else
	{
		z=dc.GetTextExtent(CString("A"));
		m_dzoom = ((double)m_ctlRect.Height()/(double)z.cy) / 25.0;
	}



	m_zoomFont.lfWidth = (int)(m_logFont.lfWidth * m_dzoom);
	m_zoomFont.lfHeight = (int)(m_logFont.lfHeight * m_dzoom);

	CFont *oFont;
	CFont newfont;

	if(printerDC!=NULL)
	{
		if(!newfont.CreateFontIndirect(&m_zoomFont))
		{
			MessageBox("create font failed");
		}
	}


	if(printerDC!=NULL)
	{
		oFont = printerDC->SelectObject(&newfont);
		z=printerDC->GetTextExtent(CString("A"));
	}
	else
	{
		oFont = dc.SelectObject(&newfont);
		z=dc.GetTextExtent(CString("A"));
	}
	m_TextHeight = z.cy;

	if(m_bctlBorder)
	{
		m_clientRect.left = m_ctlRect.left+2;
		m_clientRect.right = m_ctlRect.right-2;
		m_clientRect.top = m_ctlRect.top+2;
		m_clientRect.bottom = m_ctlRect.bottom-2;
	}
	else
	{
		m_clientRect = m_ctlRect;
	}

	if(bInitialization)
	{
		m_iMtop =  m_clientRect.Height()/10;
		m_iMbottom = m_clientRect.Height()/8;
		m_iMleft = m_clientRect.Width()/10;
		
		if(m_bUseRightYAxis|m_bRightYMargin)
			m_iMright = m_clientRect.Width()/10;
		else
			m_iMright = m_clientRect.Width()/15;

	}

	// compute plot rect.

	m_plotRect.left= m_clientRect.left + m_iMleft;
	m_plotRect.right= m_clientRect.right - m_iMright;
	m_plotRect.top= m_clientRect.top + m_iMtop;
	m_plotRect.bottom= m_clientRect.bottom - m_iMbottom;

	

	// compute default legend possition

	if(bInitialization)
	{
		m_legendRect.left = m_plotRect.left + (m_iMleft/5);
		m_legendRect.right = m_plotRect.left + (m_plotRect.Width()/5);
		m_legendRect.top = m_plotRect.top - (m_iMtop/2);
		m_legendRect.bottom = m_plotRect.top + (m_iMtop);

		int w = 0;
		int n=0;
		for(int x = 0; x< MAXLEGENDS;x++){
			if(m_primarylegends[x].m_bIAmInUse){
				n++;
				z=dc.GetTextExtent(CString(m_primarylegends[x].m_szTitle));
				if(z.cx > w )
					w=z.cx;
//				m_TextHeight = z.cy;
			}
		}

		m_legendRect.right = m_legendRect.left + 40 + w;
		m_legendRect.bottom = m_legendRect.top + 10 + (m_TextHeight*n);
	}

	// compute left axis area
	m_axisLYRect.left = m_clientRect.left + (m_iMleft/5);
	m_axisLYRect.right = m_plotRect.left;
	m_axisLYRect.top = m_plotRect.top;
	m_axisLYRect.bottom = m_plotRect.bottom;

	// compute right axis area
	m_axisRYRect.left =  m_plotRect.left;
	m_axisRYRect.right = m_clientRect.right - (m_iMright/5);
	m_axisRYRect.top = m_plotRect.top;
	m_axisRYRect.bottom = m_plotRect.bottom;

	// compute bottom axis area
	m_axisBXRect.left = m_plotRect.left;
	m_axisBXRect.right = m_plotRect.right;
	m_axisBXRect.top = m_plotRect.bottom;
	m_axisBXRect.bottom = m_clientRect.bottom - (m_iMbottom/5);

	//if(bInitialization)
	{
		

		//屏幕上X轴每象素代表的时间(秒)
	    //m_timeaxis.m_dMilliSecondsPrPixel = ((double)(m_timeaxis.m_maxtime.GetTime() - m_timeaxis.m_mintime.GetTime())) / (double)m_plotRect.Width();
	    m_timeaxis.m_dMilliSecondsPrPixel = ((double)(m_timeaxis.m_maxtime - m_timeaxis.m_mintime)) / (double)m_plotRect.Width();
	    //m_timeaxis.m_dMilliSecondsPrPixel = (m_timeaxis.m_maxtime - m_timeaxis.m_mintime) / m_plotRect.Width();
		
		//屏幕上左Y轴每象素代表的实际值
		m_leftaxis.m_dValuePrPixel   = ((double)(m_leftaxis.maxrange- m_leftaxis.minrange) / (double)m_plotRect.Height());

		//屏幕上右Y轴每象素代表的实际值
		m_rightaxis.m_dValuePrPixel   = ((double)(m_rightaxis.maxrange- m_rightaxis.minrange) / (double)m_plotRect.Height());

	}

	m_iXBigGrids=6;   //X轴分为m_iXBigGrid个大网格(模认为6)
	m_iYBigGrids=5;   //Y轴分为m_iYBigGrid个大网格(模认为5)

⌨️ 快捷键说明

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