Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

Automatic Mouse Tracking Cursor

I am trying to have the cursor automatically track the mouse when it enters the plot area. I'm having trouble converting the MouseEventArgs x and y position to be valid WaveformGraph values. This is the closest method I could find, but unfortunately it's only for Zoom and Pan functions:

private void waveformGraph1_PlotAreaMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
PointF p = waveformGraph1.PointToVirtual( new Point( e.X, e.Y ) ) ;
xyCursor1.XPosition = p.X;
xyCursor1.YPosition = p.Y;
}

Any suggestions?

Thanks in advance!
Derek
0 Kudos
Message 1 of 8
(7,938 Views)
To get what you want you can implement a poor man's inverse map. I haven't tested the code below for inverted or log axes(I am sure it won't work for those cases) but it works well with the default setting of a graph. The code is below:


private void OnPlotAreaMouseMove(object sender, MouseEventArgs e)
{
double xValue, yValue;
InverseMap(waveformGraph1.PlotAreaBounds, e.X, e.Y, xAxis1, yAxis1, out xValue, out yValue);
xyCursor1.XPosition = xValue;
xyCursor1.YPosition = yValue;
}

private void InverseMap(Rectangle plotAreaBounds, int x, int y, XAxis xAxis,
YAxis yAxis, out double xValue, out double yValue)
{
xValue = ((xAxis.Range.Maximum - xAxis.Range.Minimum) *
((x - plotAreaBounds.Left) / (double)(plotAreaBounds.Right - plotAreaBounds.Left))) + xAxis.Range.Minimum;
yValue = ((yAxis.Range.Maximum - yAxis.Range.Minimum) *
((plotAreaBounds.Bottom - y)/ (double)(plotAreaBounds.Bottom - plotAreaBounds.Top))) + yAxis.Range.Minimum;
}


I would be interested to see if this works out for you.

Brock
0 Kudos
Message 2 of 8
(7,918 Views)
Hi Brock,

Thanks for the code - it works great for linear, but unfortunately we do almost 99% of our plotting in the logarithmic scale. There must be a way to convert the mouse coordinates to the plot area coordinates like the NationalInstruments.UI.AfterMoveXYCursorEventArgs for the AfterMoveCursor event. Any ideas on this?

Thanks,
Derek
0 Kudos
Message 3 of 8
(7,910 Views)
I worked a solution for you that works with log axis. Here is the code:


private void OnPlotAreaMouseMove(object sender, MouseEventArgs e)
{
double xValue, yValue;
InverseMap(waveformGraph1.PlotAreaBounds, e.X, e.Y, xAxis1, yAxis1, out xValue, out yValue);
xyCursor1.XPosition = xValue;
xyCursor1.YPosition = yValue;
}

private Range GetScaledLogRange(Range range, double logBase)
{
Range scaledRange = range;
if(scaledRange.Minimum <= 0)
scaledRange = new Range(Math.Pow(logBase, -1), scaledRange.Maximum);

scaledRange = new Range(Math.Log(scaledRange.Minimum, logBase), Math.Log(scaledRange.Maximum, logBase));
return scaledRange;
}

private void InverseMap(Rectangle plotAreaBounds, int x, int y, XAxis xAxis, YAxis yAxis,
out double xValue, out double yValue)
{
if(xAxis.ScaleType == ScaleType.Logarithmic)
{
Range scaledRange = GetScaledLogRange(xAxis.Range, xAxis.LogBase);
xValue = Math.Pow(xAxis.LogBase, ((scaledRange.Maximum - scaledRange.Minimum) *
((x - plotAreaBounds.Left) / (double)(plotAreaBounds.Right - plotAreaBounds.Left))) + scaledRange.Minimum);
}
else
{
xValue = ((xAxis.Range.Maximum - xAxis.Range.Minimum) *
((x - plotAreaBounds.Left) / (double)(plotAreaBounds.Right - plotAreaBounds.Left))) + xAxis.Range.Minimum;
}

if(yAxis.ScaleType == ScaleType.Logarithmic)
{
Range scaledRange = GetScaledLogRange(yAxis.Range, yAxis.LogBase);
yValue = Math.Pow(yAxis.LogBase, ((scaledRange.Maximum - scaledRange.Minimum) *
((plotAreaBounds.Bottom - y)/ (double)(plotAreaBounds.Bottom - plotAreaBounds.Top))) + scaledRange.Minimum);
}
else
{
yValue = ((yAxis.Range.Maximum - yAxis.Range.Minimum) *
((plotAreaBounds.Bottom - y)/ (double)(plotAreaBounds.Bottom - plotAreaBounds.Top))) + yAxis.Range.Minimum;
}
}


Hope this does a better job,

Brock
Message 4 of 8
(7,892 Views)
Hi Brock,

Nice work! It seems that this is quite a bit of work to get the NI PlotArea coordinates. It's too bad NI did not provide an API to get these coordinates...

I noticed strange cursor behavior when the CursorSnapMode is set to either NearestPoint or ToPlot. It seems to bounce all over the place. Do you know what's going on here? Not that it really matters since this behavior is not present when set to Fixed or Floating, but I was just curious. I've attached a sample project showing this.

Thanks again!
Derek

Message Edited by dprice on 04-22-2005 07:48 AM

0 Kudos
Message 5 of 8
(7,889 Views)
Thanks for the project. The problem is you are setting the XPosition and then the YPosition of the cursor. Instead use the MoveCursor method. When you set the XPosition the cursor only looks at the x-points of the plot and finds the closet x position to those points and moves there. Same when setting the YPosition, only if looks at the y-points of the plot and moves to the closest y position. MoveCursor looks at both the x and y points of the plot to determine what point to move to on the plot. MoveCursor works great.

Brock
0 Kudos
Message 6 of 8
(7,878 Views)
Thanks again for the solution. I've attached the fixed project for others that may need this functionality.

I just wish that there was a simple API to get these coordinates without having to repeat this code for every application that needs it. I know I could derive my own graph, but you know what I mean! 🙂

Thanks,
Derek
0 Kudos
Message 7 of 8
(7,868 Views)
We did consider adding an API for this and decided against it at the time because of the loss of accuracy. Given only a screen coordinate, there is no way to accurately inverse map that to an exact data coordinate. For example, if you mapped a data coordinate to a screen coordinate, and then inverse mapped that screen coordinate back to a data coordinate, the result would not be what you started with. We can guarantee an accurate inverse mapping if the screen coordinate corresponds to a data point in a plot, and there is an API for this - see the overloads of the GetPlotAt method on the graph.

Having said that, though, we have since seen where it would still be useful (such as in your post and other posts in the forums) to have an API for this despite the lack of accuracy, and we have filed this as a suggestion to consider in a future version of Measurement Studio.

- Elton
0 Kudos
Message 8 of 8
(7,856 Views)