前面介绍了NI控件和它的绘图控件CWGraph绘图功能,由于COM版本的只能显示,不能在控件上做其他操作,所以一些常用的功能如获取距离鼠标最近点的数据点就需要自己实现。
以捕捉最近点为例:
分析:在绘图的时候一般传入X、Y轴数据,X、Y数据都是同等长度的一维数组,捕捉功能也是再这些数据上做文章,数据有了,只需要对数据进行分析就可以了。根据传入的捕捉点和数组进行分析后,适当的移动鼠标光标当前位置,就可以实现捕捉功能了。
这只是一般情况,当然还有特殊情况,比如,在用PlotY()添加数据,这时候只有Y轴数据而没有X轴数据,如何捕捉呢?仔细想想---由于数据都绘图都是一句坐标系绘制的,而我们知道X轴的起始终止坐标值,这样把X轴依据Y轴数据长度等份分成一个数组,这样就可以得到X轴数据,同样可以得到最近值-----
实现:其主要部分就在于计算。下面是一个写好的捕捉类
/*
* 自动捕捉类,捕捉附近点
* 只有XY坐标
* */
public class SnapNearPoint
{
#region 字段
private List<double> m_XData =null;//X轴数据
private List<double> m_YData =null;//Y轴数据
private double m_XRadio = 0.0;//X方向捕捉半径长度
private double m_YRadio = 0.0;//Y方向捕捉半径长度
private int _SelectIndex = -1;//捕捉到最近点的索引
private SnapMode _Mode =SnapMode.XAndY;//捕捉方式
#endregion
#region 属性
/// <summary>
/// 设置获取绑定X数据
/// </summary>
public List<double> BindXData
{
set { m_XData = value; }
get { return m_XData; }
}
/// <summary>
/// 设置获取绑定Y数据
/// </summary>
public List<double> BindYData
{
set { m_YData = value; }
get { return m_YData; }
}
/// <summary>
/// 获取捕捉到数据索引
/// </summary>
public int SelectIndex
{
get { return _SelectIndex; }
}
/// <summary>
/// 获取或设置捕捉点方式
/// </summary>
public SnapMode Mode
{
set { _Mode = value; }
get { return _Mode; }
}
#endregion
#region 构造函数、捕捉方法
/// <summary>
/// 构造函数
/// </summary>
/// <paramname="XRadio">X捕捉长度</param>
/// <param name="YRadio">Y捕捉长度</param>
public SnapNearPoint(double XRadio,double YRadio)
{
m_XRadio = XRadio;
m_YRadio = YRadio;
}
/// <summary>
/// 获取最近点
/// </summary>
/// <param name="Searchx">用于捕捉最近点的鼠标点X</param>
/// <paramname="Searchy">鼠标点Y</param>
/// <paramname="Returnx">返回捕捉到的点X轴坐标值</param>
/// <paramname="Returny">返回捕捉到的点Y轴坐标值</param>
public void GetNearPoint(doubleSearchx, double Searchy, ref double Returnx, ref double Returny)
{
try
{
if (m_XData != null &&m_YData != null)
{
switch (_Mode)
{
case SnapMode.JustX:
m_XData.Add(m_XData[m_XData.Count - 1] + 1);
//Graph在绘图时候会从数组索引为1的位置开始绘制,如果不再前面+1数据,则结果会出现少一组(第一位)数据
for (int i = 0; i< m_XData.Count - 1; i++)
{
if (Searchx>= (m_XData[i] - (m_XData[i + 1] - m_XData[i]) / 2.0) && Searchx<= (m_XData[i + 1] - (m_XData[i + 1] - m_XData[i]) / 2.0))
{
_SelectIndex = i;
Returnx =m_XData[i];
}
}
m_XData.RemoveAt(m_XData.Count - 1);
break;
case SnapMode.JustY:
m_YData.Add(m_YData[m_YData.Count - 1] + 1);
for (int i = 0; i< m_YData.Count; i++)
{
if (Searchy>= m_YData[i] && Searchy <= m_YData[i + 1])
{
_SelectIndex = i;
Returny =m_YData[i];
}
}
m_YData.RemoveAt(m_YData.Count - 1);
break;
case SnapMode.XAndY:
for (int i = 0; i< m_XData.Count; i++)
{
if (m_XData[i]> (Searchx - m_XRadio) && m_XData[i] < (Searchx + m_XRadio))
{
if(m_YData[i] > (Searchy - m_YRadio) && m_YData[i] < (Searchy +m_YRadio))
{
Do(i,Searchx, Searchy, ref Returnx, ref Returny);
}
}
}
break;
}
}
}
catch (Exception ex)
{
LoggingUtility.ErrorInfo("捕捉点出现错误!",ex);
}
}
private void Do(int i, double Searchx,double Searchy, ref double Returnx, ref double Returny)
{
double Radio = 0;
double Length =Math.Sqrt(Math.Pow(m_XData[i] - Searchx, 2) + Math.Pow(m_YData[i] - Searchy,2));
if (Radio < Length)
{
_SelectIndex = i;
Radio = Length;
Returnx = m_XData[i];
Returny = m_YData[i];
}
}
#endregion
}
public enum SnapMode
{
JustX,//仅仅捕捉X轴方向
JustY,//仅仅捕捉Y轴方向
XAndY,//X、Y轴同时捕捉最近点
}
捕捉主要实在鼠标移动事件中实现,在控件MouseMove时间里面:
在外部声明几个必须的字段:
BoolFirstCal_Margin=false;//主要用来判断计算鼠标位置的次数,这个计算只需要计算一个,多次计算会影响效率
int _leftMap= 0, _topMap = 0, _widthMap = 0, _heightMap = 0;//计算得到的绘图图层的四个顶点
private voidScatter_Form_Occupancy_com_MouseMoveEvent(object sender,AxCWUIControlsLib._DCWGraphEvents_MouseMoveEvent e)
{
if (!FirstCal_Margin) //计算位置只计算一次
{
//Scatter_Form_Occupancy_com CWGraph控件
Scatter_Form_Occupancy_com.GetPlotAreaBounds(ref _leftMap, ref _topMap,ref _widthMap, ref _heightMap);//获取边距和图形的宽高,分别代表4个顶点
FirstCal_Margin = true;
}
OnMouseMoveHelp(e.x, e.y);
}
protected double_PlotXPosition = 0.0;//捕鼠标在绘图控件上对应的X坐标值
protected double _PlotYPosition = 0.0;// 鼠标在绘图控件上对应的Y坐标值
CWPlotm_Default_Plot=null;绘图图层
Bool IsStart=false;//标识是否开始绘图
protected SnapNearPoint snap = null;//捕捉点类
protected CWCursor m_Default_Cursor = null;//默认鼠标
protectedvoid OnMouseMoveHelp(int x,int y)
{
try
{
_PlotXPosition =Convert.ToDouble(_widthMap) / (Convert.ToDouble(m_Default_Plot.XAxis.Maximum) -Convert.ToDouble(m_Default_Plot.XAxis.Minimum));//计算刻度的像素值
_PlotYPosition =Convert.ToDouble(_heightMap) / (Convert.ToDouble(m_Default_Plot.YAxis.Maximum)- Convert.ToDouble(m_Default_Plot.YAxis.Minimum));//用Y轴高度除Y轴坐标起始值差得到Y轴的刻度最小单位长度
_PlotXPosition =Convert.ToDouble(m_Default_Plot.XAxis.Minimum) + ((x - _leftMap) /_PlotXPosition);//反推长度\刻度确定当前鼠标点对应的Y轴坐标值
_PlotYPosition =Convert.ToDouble(m_Default_Plot.YAxis.Minimum) - ((y - _topMap - _heightMap) /_PlotYPosition);
if (!IsStart)
{
this.Cursor =System.Windows.Forms.Cursors.SizeAll;
m_Default_Cursor.XPosition =_PlotXPosition;//设置光标样式
m_Default_Cursor.YPosition= _PlotYPosition;
}
else
{
this.Cursor =System.Windows.Forms.Cursors.Arrow;
}
if (m_YData != null &&m_XData != null && snap != null)
{
snap.BindXData = m_XData;
snap.BindYData = m_YData;
StartSnap();
m_Default_Cursor.XPosition= MouseCenterFreq_X + _XMove;
m_Default_Cursor.YPosition= MouseCenterFreq_Y + _YMove;
}
}
catch (Exception ex)
{
LoggingUtility.ErrorInfo(ex);
}
}
protected double MouseCenterFreq_X =0.0;//捕捉到的点的X坐标
protected double MouseCenterFreq_Y =0.0;//捕捉到最近点的Y坐标
/// <summary>
/// 开始捕捉点
/// </summary>
protected void StartSnap()
{
if (snap.BindXData.Count >= 1)
{
snap.GetNearPoint(_PlotXPosition, _PlotYPosition, ref MouseCenterFreq_X,ref MouseCenterFreq_Y);
if (snap.SelectIndex != -1)
{
SelFreqIndex =snap.SelectIndex;
//GetNearPoint(MouseCenterFreq_X, MouseCenterFreq_Y); //激发事件 用在外部调用时候用事件接受捕捉点,可用可不用
}
}
}
//public delegate voidGetNearPointEventHandle(double x, double y);//捕捉点委托
//public event GetNearPointEventHandleOnGetNearPoint;
/// <summary>
/// 用来激发捕捉到最近点的事件
/// </summary>
/// <paramname="x"></param>
/// <paramname="y"></param>
//protected void GetNearPoint(double x,double y)
//{
// if (OnGetNearPoint != null)
// {
// OnGetNearPoint(x, y);
// }
// }
附加一张效果图吧:光标定位地区就是捕捉到的点值,左上角显示的是数值。
主要计算偏多,思路很简单。代码也比较多,看起来比较繁琐。。。。