1

I'm using ilnumerics with C# on a simple WindowsFormsApplication and created some LinePlots in a PlotCube on an ILPanel. Like in:
How to find the 3D coordinates of a surface from the click location of the mouse on the ILNumerics surface plots?
i tried to get the translated coordinates while clicking into the PlotCube to create something similar to the data tips at MATLAB. Instead of a ILSurface I'm using ILLinePlot and my x-Axis is of logarithmic scale. So I adapted the method mentioned at the above link to my setting.

My problem is that I only get correct coordinates when i am clicking exactly at the LinePlot! When clicking right next to the line or anywhere else at the PlotCube the above MouseClick method runs into a NullReferenceException.
My idea for that problem was not to use the MouseClick target to get the transformations if i didn't hit the LinePlot but to set the group to the LinePlot like as if I had clicked on it (see at my example).

But although I now get the same groups in the while-loop and no Exception debugging shows that the transformation matrices of the PlotsData group and the PlotCubeScale group differ in both cases. If I don't hit the LinePlot all transformation matrices are just the identities.

Here comes my short example:

    private void ilPanel1_Load(object sender, EventArgs e)
    {
        ILArray<double> A = new Double[,] {{1,4,0},{10,12,0},{100,10,0},{1000,18,0},{10000,15,0}};
        var scene = new ILScene() {
            new ILPlotCube(twoDMode: true){
                new ILLinePlot(ILMath.tosingle(A))
            }
        };
        scene.First<ILPlotCube>().ScaleModes.XAxisScale = AxisScale.Logarithmic;

        scene.First<ILPlotCube>().MouseEnter += (_s, _a) =>
        {
            if (!_a.DirectionUp)
            {
                //onplot is a global flag which is true if the mouse is over the LinePlot
                Text = "On Plot - Target: " + _a.Target.ToString();
                onplot = true;
            }
        };

        scene.First<ILPlotCube>().MouseLeave += (_s, _a) =>
        {
            if (!_a.DirectionUp)
            {
                Text = "Off Plot - Target: " + _a.Target.ToString();
                onplot = false;
            }
        };
        scene.First<ILPlotCube>().MouseClick += (s, arg) =>
        {
            if (!arg.DirectionUp)
                return;
            var group = arg.Target.Parent;
            // *new part: group holds my LinePlot if I clicked on it
            // else it holds the PlotCube 
            if (!onplot)
            {
                // so I search the LinePlot at set group to it
                foreach (ILLineStrip strip in scene.Find<ILLineStrip>())
                {
                    if (strip.Tag == "LinePlotLine")
                    {
                        group = strip.Parent;
                    }
                }
            }
            if (group != null)
            {
                // walk up to the next camera node 
                Matrix4 trans = group.Transform;
                while (!(group is ILCamera) && group != null)
                {
                    group = group.Parent;
                    // collect all nodes on the path up
                    trans = group.Transform * trans;
                }
                if (group != null && (group is ILCamera))
                {
                    // convert args.LocationF to world coords
                    // The Z coord is not provided by the mouse! -> choose arbitrary value
                    var pos = new Vector3(arg.LocationF.X * 2 - 1, arg.LocationF.Y * -2 + 1, 0);
                    // invert the matrix.
                    trans = Matrix4.Invert(trans);
                    // trans now converts from the world coord system (at the camera) to 
                    // the local coord system in the 'target' group node (surface). 
                    // In order to transform the mouse (viewport) position, we 
                    // left multiply the transformation matrix.
                    pos = trans * pos;
                    // here I take care of the logarithmic scale of the xAxis
                    pos.X = (float)ILMath.pow(10.0, pos.X);
                    // view result in the window title
                    Text = "Model Position: " + pos.ToString();
                }
            }
        };

        ilPanel1.Scene = scene;
    }

Why do the group.Transform-matrices differ depending on my clicking position? The while-loop is exactly the same in both cases.

I hope that anyone can understand my problem. Although searching for weeks I didn't find any answer or different ways to reach my goal which is just to show the user the Coordinates of the Points on the line where he is clicking.

Thank you very much in advance for any help.

Community
  • 1
  • 1
ml1583
  • 23
  • 4
  • Part of the answer is found here: http://ilnumerics.net/scene-management.html. It explains the identity matrices. Also, try to attach the handlers to the ILPlotcubeDatagroup instead of the plotcube. It might simplify things further. Does it help? – Haymo Kutschbach Aug 27 '14 at 06:49
  • Thank you very much for your very fast answer!! Do I get it right that my PlotCube and the LinePlot live on different synchronizations of my global scene and I therefore get different transformations?! when I attach the handlers to the ILPlotcubeDatagroup instead of the plotcube they only seem to fire when I hit the LinePlot. Is that the desired behavior? So this wouldn't make sense for my MouseClick event, right?! Or did I misunderstand something? – ml1583 Aug 27 '14 at 16:07

1 Answers1

1

One work around is to get the lineplot node from the mouse handler's target rather than from the scene directly. That way we always get the right transforms. Replace your logic of identifying the lineplot with the following

 ILGroup plotcubeGroup = e.Target as ILGroup;
 ILGroup group = plotcubeGroup.Children.Where(item => item.Tag == "LinePlot").First() as ILGroup;
 if(group != null)
    {
    // continue with same logic as above
    }

Hope it helps.

Neelima
  • 243
  • 1
  • 8
  • I have to put my if(!onplot) around your first two lines because otherwise the plotcubeGroup would be null if I hit the LinePlot. But with that it works quite perfectly! Thanks a lot!! But now the GridLines are the last problem! When I hit one, I still get wrong coordinates which might be again a problem of the scene-management?! – ml1583 Aug 27 '14 at 15:56
  • All the events are raised on the synchronized copy of the plot scene.The above problem can also be solved by accessing the ILLinePlot from the synchronized copy. That will give right transforms too. For ex: var group = ilPanel1.SceneSyncRoot.First(predicate: Item => Item.Tag == "LinePlotLine").Parent; use sceneSyncRoot, I dont think you will have the gridLines issue. – Neelima Aug 27 '14 at 16:00
  • Yeah! That works fine! Now I only need the sceneSyncRoot line and it works for all cases! Thank you very much! – ml1583 Aug 27 '14 at 16:27