ILNumerics plot a plane at specific location

2019-07-01 17:43发布

问题:

I'm currently playing around with the ILNumerics API and started to plot a few points in a cube. Then I calculated a regression plane right through those points. Now I'd like to plot the plane in the same scene plot but only with the same size than the point cloud.

I got the paramters of the plane (a,b,c): f(x,y) = a*x + b*y + c; I know that only z is interesting for plotting a plane but I've got no clue how pass the right coodinates to the scene so that the plane size is about the same size than the maximum and minimum area of the points.

Could you guys give me a simple example of plotting a plane and a little suggetion how to set the bounds of that plane right?

Here is what I got so far:

        private void ilPanel1_Load(object sender, EventArgs e)
    {
           // get the X and Y bounds and calculate Z with parameters

           // plot it!
            var scene = new ILScene {
              new ILPlotCube(twoDMode: false) {
                new ILSurface( ??? ) {
                }
              }
            };

           // view angle etc
            scene.First<ILPlotCube>().Rotation = Matrix4.Rotation(
            new Vector3(1f, 0.23f, 1), 0.7f);

        ilPanel1.Scene = scene; 
    }

I hope that someone can help me ... Thanks in advance !!!

回答1:

You could take the Limits of the plotcube.Plots group and derive the coords from the bounding box from it. This gives you the min and max x and y coord for the plane. Use them to get the corresponding z values by evaluating you plane equation.

Once you have x,y and z of the plane, use them with ILSurface to plot the plane.

If you need more help, I can try to add an example.

@Edit: the following Example plots a plane through 3 arbitrary points. The planes orientation and position is computed by help of a plane function zEval. Its coefficients a,b,c are computed here from the 3 (concrete) points. You will have to compute your own equation coefficients here.

The plane is realized with a surface. One might as well take the 4 coords computed in 'P' and use an ILTriangleFan and an ILLineStrip to create the plane and the border. But the surface already comes with a Fill and a Wireframe, so we take this as a quick solution.

private void ilPanel1_Load(object sender, EventArgs e) {
    // 3 arbitrary points 
    float[,] A = new float[3, 3] { 
        { 1.0f, 2.0f, 3.0f }, 
        { 2.0f, 2.0f, 4.0f }, 
        { 2.0f, -2.0f, 2.0f } 
    };
    // construct a new plotcube and plot the points
    var scene = new ILScene {
        new ILPlotCube(twoDMode: false) {
            new ILPoints {
                Positions = A,
                Size = 4,
            }
        }
    };
    // Plane equation: this is derived from the concrete example points. In your 
    // real world app you will have to adopt the weights a,b and c to your points. 
    Func<float, float, float> zEval = (x, y) => {
        float a = 1, b = 0.5f, c = 1;
        return a * x + b * y + c; 
    }; 
    // find bounding box of the plot contents 
    scene.Configure(); 
    var limits = scene.First<ILPlotCube>().Plots.Limits; 

    // Construct the surface / plane to draw
    // The 'plane' will be a surface constructed from a 2x2 mesh only. 
    // The x/y coordinates of the corners / grid points of the surface are taken from 
    // the limits of the plots /points. The corresponding Z coordinates are computed 
    // by the zEval function. So we give the ILSurface constructor not only Z coordinates 
    // as 2x2 matrix - but an Z,X,Y Array of size 2x2x3
    ILArray<float> P = ILMath.zeros<float>(2, 2, 3);
    Vector3 min = limits.Min, max = limits.Max; 
    P[":;:;1"] = new float[,] { { min.X, min.X }, { max.X, max.X } };
    P[":;:;2"] = new float[,] { { max.Y, min.Y }, { max.Y, min.Y } };
    P[":;:;0"] = new float[,] { 
        { zEval(min.X, max.Y) , zEval(min.X, min.Y) }, 
        { zEval(max.X, max.Y) , zEval(max.X, min.Y) }, 
    };
    // create the surface, make it semitransparent and modify the colormap
    scene.First<ILPlotCube>().Add(new ILSurface(P) {
        Alpha = 0.6f, 
        Colormap = Colormaps.Prism
    }); 
    // give the scene to the panel
    ilPanel1.Scene = scene;
}

This would create an image similar to this one:

@Edit2: you asked, how to disable the automatic scaling of the plot cube while adding the surface:

// before adding the surface: 
var plotCube = scene.First<ILPlotCube>(); 
plotCube.AutoScaleOnAdd = false; 

Alternatively, you can set the limits of the cube manually:

plotCube.Limits.Set(min,max); 

You probably will want to disable some mouse interaction as well, since they would allow the user to rescale the cube in a similar (unwanted?) way:

plotCube.AllowZoom = false;    // disables the mouse wheel zoom
plotCube.MouseDoubleClick += (_,arg) => {
        arg.Cancel = true;     // disable the double click - resetting for the plot cube
};