Intensity Type SurfaceGridSeries3D ??

A forum dedicated to WinForms version of LightningChart Ultimate.

Moderator: Arction_LasseP

Greg9504
Posts: 38
Joined: Fri Dec 06, 2013 4:51 pm

Intensity Type SurfaceGridSeries3D ??

Post by Greg9504 » Wed Dec 18, 2013 4:56 pm

How would I go about colouring a SurfaceGridSeries3D based on values other than the values used for the Y axis?

As an example I have the following data for a rectangular grid:
- depth
- temperature
- pressure

I want to plot the SurfaceGridSeries3D using my depth values for the Y axis, then use a gradient Palette from the temperature values I have for each XZ. I then might even like to show contour lines based on the pressure values I have. Is this possible?

Thanks
Greg.

User avatar
ArctionPasi
Posts: 1366
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland

Re: Intensity Type SurfaceGridSeries3D ??

Post by ArctionPasi » Thu Dec 19, 2013 11:36 am

The palette-coloring is made only by Y value. There's no separate Intensity field in the points, that's a difference to 2D view's Intensity series.

You can however give a color for your data Surface data points.

Set surface.Fill = FromSurfacePoints.

In the data filling loop, set Color field for every point. You can use the ContourPalette to convert the intensity values into colors.

surface.Data[i,j].Y = yValue;
surface.ContourPalette.GetColorByValue(intensityValue, out surface.Data[i,j].Color);
Surface colored by Color fields
Surface colored by Color fields
SurfaceColoringFromSurfacePoints.jpg (116.51 KiB) Viewed 22683 times
You may want to add another SurfaceGridSeries3D with Fill = Paletted to show the legend palette, because setting Fill.FromSurfacePoints legend will be meaningless.

Contour lines is available based on Y value only.


Another approach:
Set surface.Fill = Bitmap. Then create a bitmap based on your intensity colors. The resolution of the bitmap can be different from your surface.SizeX and SizeY. Set the bitmap to surface.BitmapFill.Image property. Bitmap will be stretched to fit.
You may even want to use ViewXY's IntensityGridSeries with contours, and use chart.SaveToFile/SaveToStream methods to export the bitmap. You can use output size parameters with these methods, if you want higher-resolution bitmap than your screen is.
Intensity data as bitmap fill of SurfaceGrid3D
Intensity data as bitmap fill of SurfaceGrid3D
intensityGridOnSurfaceGrid3D.jpg (108.88 KiB) Viewed 22683 times
:)
LightningChart Support Team, PT

Greg9504
Posts: 38
Joined: Fri Dec 06, 2013 4:51 pm

Re: Intensity Type SurfaceGridSeries3D ??

Post by Greg9504 » Wed Mar 12, 2014 4:36 pm

Any chance of adding support for this native to Lightning Chart say with a IntensitySurfaceGridSeries3D type?

This type of visualization is very common in scientific applications, specifically for geology where the user wants to see their data on a surface. In the oil and gas world this is the main type of 3D surface plot made. The "surface" is depth and the colouring is data (temperature, pressure, water saturation, facies (rock type), etc...).

Do you have a code example for your second example above (Intensity data as bitmap fill of SurfaceGrid3D)?

Thanks.
Greg.

User avatar
ArctionPasi
Posts: 1366
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland

Re: Intensity Type SurfaceGridSeries3D ??

Post by ArctionPasi » Wed Mar 12, 2014 7:05 pm

That's definitely in plans during next year or so. It would be very handy.

I'll try to provide you an example by using IntensityGridSeries to compose animated bitmap, and to update that over animated Y-animated SurfaceGridSeries3D.
LightningChart Support Team, PT

User avatar
ArctionPasi
Posts: 1366
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland

Re: Intensity Type SurfaceGridSeries3D ??

Post by ArctionPasi » Sat Mar 15, 2014 5:12 pm

Ok, I made an example project. :ugeek:
IntensityOn3DSurface.zip
VS 2010 .net WinForms project
(880.38 KiB) Downloaded 709 times
It's using 2 charts. 2D intensity chart not visible in the back, and 3D surface chart on the front. 2D chart makes the intensity plot, and exports it to bitmap stream.

3D charts reads the bitmap stream.

Both intensity data and surface data are animated, and therefore a bit heavy.
3D winforms Surface with intensity data fill
3D winforms Surface with intensity data fill
surface3DWithIntensityData.png (421.72 KiB) Viewed 21934 times
I hope this helps...
LightningChart Support Team, PT

Greg9504
Posts: 38
Joined: Fri Dec 06, 2013 4:51 pm

Re: Intensity Type SurfaceGridSeries3D ??

Post by Greg9504 » Fri Dec 11, 2015 3:05 pm

Hello Pasi,

In March of 2014 you said:
That's definitely in plans during next year or so. It would be very handy
Any news on adding Intensity 3D surface? Also contours independent of height (Y)?

I tried the bitmap method, using your sample from above. However something seems to have changed in the latest version of LC and I get a bitmap with the axis shown, see attached screen shot.
lcintensityon3dsurface.jpg
lcintensityon3dsurface.jpg (124.01 KiB) Viewed 18918 times
We need to make 4D plots, that is a 3D surface plot that is coloured by another variable. This is very very common plot to make. Colouring by height is almost never done. As mentioned above it would be great if there was a "contour series" so that as with colouring, contours can be added independent of height, based on another variable. Below is a screen shot that we made using commercial plotting software, the colouring and contours are independent of height.
3DSurfaceColouredEffStressContoursTemperature_FromSurfer.png
3DSurfaceColouredEffStressContoursTemperature_FromSurfer.png (223.24 KiB) Viewed 18918 times

User avatar
ArctionPasi
Posts: 1366
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland

Re: Intensity Type SurfaceGridSeries3D ??

Post by ArctionPasi » Fri Dec 11, 2015 3:21 pm

v.7 and its new DirectX11 engine takes majority of our time. I'm sorry we haven't found time to implement 3D intensity surfaces yet. It's still on our to-do list.

Independent intenisity contours in 3D are not in our to-do list, and can't promise that to be implemented. These kind of features take months of programming time.

About capturing the bitmap from ViewXY, set ViewXY.AxisLayout.AutoAdjustMargins = false, and you should get similar bitmap than before.
LightningChart Support Team, PT

Greg9504
Posts: 38
Joined: Fri Dec 06, 2013 4:51 pm

Re: Intensity Type SurfaceGridSeries3D ??

Post by Greg9504 » Thu Jan 28, 2016 4:07 pm

Hi,

For colouring the surface from a value other than the Y value I have used your "FromSurfacePoints" method:
You can however give a color for your data Surface data points.
Set surface.Fill = FromSurfacePoints.
In the data filling loop, set Color field for every point. You can use the ContourPalette to convert the intensity values into colors.
surface.Data[i,j].Y = yValue;
surface.ContourPalette.GetColorByValue(intensityValue, out surface.Data[i,j].Color);
and this seems acceptable. Now I'm trying to get independent contours (contours not related to Y). To do that I am creating a 2D IntensityGridSeries, with transparent background, and calling SaveToStream. I then create a second SurfaceGridSeries3D surface, with same Y values as the first SurfaceGridSeries3D. Then I fill this second surface with the bitmap created by the IntensityGridSeries.

I'm running into two problems with the second SurfaceGridSeries3D:

- the background is not transparent, it appears to be Gray. Not sure where that colour is coming from. I've tried saving the image as both TargetImageFormat.Bmp and TargetImageFormat.Png, same result.
- the contour lines look very stretched on the SurfaceGridSeries3D.

Below are some screen shots to show what is happening

First SurfaceGridSeries3D with colouring FromSurfacePoints, this is OK:
SurfaceGrid3DSeriesFromSurfacePointsColouring.jpg
SurfaceGrid3DSeriesFromSurfacePointsColouring.jpg (89.74 KiB) Viewed 18640 times
IntensityGridSeries just to get contours, all backgrounds set to transparent and Fill None:
IntensityGridSeriesContours.png
IntensityGridSeriesContours.png (27.97 KiB) Viewed 18640 times
Second SurfaceGridSeries3D surface with BitmapFill.Image from above IntensityGridSeries
SurfaceGrid3DSeriesWithSecondSurfaceGrid3DSeriesBitMapFill.jpg
SurfaceGrid3DSeriesWithSecondSurfaceGrid3DSeriesBitMapFill.jpg (155.88 KiB) Viewed 18640 times
Finally if I save the IntensityGridSeries to file using _contourChart.SaveToFile("contour.Png"); I get this (which has transparent background) (in next post as I can only post 3 images)

Greg9504
Posts: 38
Joined: Fri Dec 06, 2013 4:51 pm

Re: Intensity Type SurfaceGridSeries3D ??

Post by Greg9504 » Thu Jan 28, 2016 4:16 pm

Finally if I save the IntensityGridSeries to file using _contourChart.SaveToFile("contour.Png"); I get this (which has transparent background)
contour.SaveToFile.Png.Png
contour.SaveToFile.Png.Png (3.41 KiB) Viewed 18640 times
Here is the code to create the first SurfaceGridSeries3D

Code: Select all

//Create new chart 
            m_chart = new LightningChartUltimate(LicenseKeys.LicenseKeyStrings.LightningChartUltimate);

            //Disable rendering, strongly recommended before updating chart properties
            m_chart.BeginUpdate();

            //Set 3D as active view
            m_chart.ActiveView = ActiveView.View3D;

            //Chart parent must be set
            m_chart.Parent = this.splitContainer1.Panel1;

            //Fill parent area with chart
            m_chart.Dock = DockStyle.Fill;
           
            //Chart name
            m_chart.Name = title;
            m_chart.Title.Text = title;

            //Set x-rotation
           // m_chart.View3D.Camera.RotationX = 38;
            m_chart.View3D.Camera.OrthographicCamera = true;
            //scale X and Y (X and Z on lightning chart) for correct aspect ratio
            double lX = ((nY - 1) * dy);
            double lZ = ((nX - 1) * dx);
            
            
            double maxdie = lZ;
            if (lX > lZ) maxdie = lX;
            m_chart.View3D.Dimensions.X = Convert.ToSingle(lX * 100.0 / maxdie);
            m_chart.View3D.Dimensions.Z = Convert.ToSingle(lZ * 100.0 / maxdie);
            
            m_chart.View3D.Dimensions.Y = m_yscale;
            
           
            //Set transparent walls 
            List<WallBase> walls = m_chart.View3D.GetWalls();
            foreach (WallBase wall in walls)
            {
                wall.Material.DiffuseColor = Color.FromArgb(30, wall.Material.DiffuseColor);
                wall.SetGridStripColor1(Color.FromArgb(60, wall.GetGridStripColor1()));
                wall.SetGridStripColor2(Color.FromArgb(60, wall.GetGridStripColor2()));
            }
            //Lightning Chart coords, our X = their Z, our Y = their X, our Z = their Y on 3D plots
            m_chart.View3D.XAxisPrimary3D.SetRange(orgY, orgY + ((nY - 1) * dy));
            m_chart.View3D.XAxisPrimary3D.Title.Text = "Y Axis";
            m_chart.View3D.XAxisPrimary3D.Reversed = true;
            m_chart.View3D.ZAxisPrimary3D.SetRange(orgX, orgX + ((nX - 1) * dx));
            m_chart.View3D.ZAxisPrimary3D.Title.Text = "X Axis";

            float[] fz = Z.Where(z => !Double.IsNaN(z)).ToArray();//filter out NaNs before getting Z (depth) min/max
            m_chart.View3D.YAxisPrimary3D.SetRange(fz.Min(), fz.Max());
            //m_chart.View3D.YAxisPrimary3D.Reversed = true;//depths are positive values "Below Sea Level", so reverse
            m_chart.View3D.YAxisPrimary3D.Title.Text = "Burial Depth";

            //this doesn't seem to work as expected with reversed axis, seems to be lit from bottom
            //m_chart.View3D.SetPredefinedLightingScheme(LightingScheme.Default);
            m_chart.View3D.ZoomPanOptions.AxisMouseWheelAction = AxisMouseWheelAction.ZoomAll;
            //Add 3D surface grid
            SurfaceGridSeries3D gridSeries = new SurfaceGridSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
            IntensityGridSeries gridColourSeries = new IntensityGridSeries(m_chart.ViewXY, m_chart.ViewXY.XAxes[0], m_chart.ViewXY.YAxes[0]);

            gridSeries.Title.Text = title;
            float[] fcz = Z.Where(z => !Double.IsNaN(z)).ToArray();
            float[] fcolourz = zColour.Where(z => !Double.IsNaN(z)).ToArray();
            
            gridSeries.ContourPalette = CreatePalette(gridSeries, fcolourz.Min(), fcolourz.Max()); 
            gridSeries.ContourLineType = ContourLineType.None;
            gridSeries.ContourPalette.Type = PaletteType.Gradient;
            gridSeries.WireframeType = SurfaceWireframeType.None;
            gridSeries.Fill = SurfaceFillStyle.FromSurfacePoints;

            gridSeries.SetRangesXZ(orgY, orgY + ((nY - 1) * dy), orgX, orgX + ((nX - 1) * dx));
            gridSeries.SetSize(nY, nX);

            gridColourSeries.SetRangesXY(orgX, orgX + ((nX - 1) * dx), orgY, orgY + ((nY - 1) * dy));
            gridColourSeries.SetSize(nY, nX);
            gridSeries.ColorSaturation = 65;
            
            m_chart.View3D.SurfaceGridSeries3D.Add(gridSeries);
            //Lightning Chart coords, our X = their Z, our Y = their X, our Z = their Y on 3D plots            
            for (int iNodeX = 0; iNodeX < nY; iNodeX++)
            {
                for (int iNodeZ = 0; iNodeZ < nX; iNodeZ++)
                {
                    gridSeries.Data[(nY - 1) - iNodeX, iNodeZ].Y = (Z[iNodeZ * nY + iNodeX]);//stored column major                    
                    gridSeries.ContourPalette.GetColorByValue(zColour[iNodeZ * nY + iNodeX], out gridSeries.Data[(nY - 1) - iNodeX, iNodeZ].Color);                    
                }
            }
            
            //Notify new values are ready
            gridSeries.InvalidateData();
            
            Create2DContourChart(gridColourSeries, zContour);
            Create3DContourSurfaceChart(m_chart, gridSeries);
            //Allow chart rendering
            m_chart.EndUpdate();
Code to create Contours:

Code: Select all

 private ValueRangePalette CreateContourPalette(Arction.LightningChartUltimate.SeriesXY.SeriesBaseXY ownerSeries, double ymin, double YRange)
        {
            ValueRangePalette palette = new ValueRangePalette(ownerSeries);
            palette.Type = PaletteType.Gradient;
            double yRange = YRange - ymin;
            palette.Steps.Clear();
            palette.MinValue = ymin;

            palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin));
            palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin + 33 * yRange / 100.0));
            palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin + 66 * yRange / 100.0));
            palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin + 100.0 * yRange / 100.0));

            palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin - 10)); //Aux step
            palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), -1E9)); //Aux step


            return palette;
        }
        /// <summary>
        /// Intensity chart renders intensity data from given data set, and exports a bitmap image. 
        /// </summary>
        void Create2DContourChart(IntensityGridSeries gridColourSeries, float[] contourData)
        {
            _contourChart = new LightningChartUltimate();

            _contourChart.BeginUpdate();

            this.splitContainer1.Panel2.BackColor = Color.Blue;
            this.BackColor = Color.Red;
            _contourChart.Parent = this.splitContainer1.Panel2;
            _contourChart.Dock = DockStyle.Fill;
            _contourChart.Width = gridColourSeries.SizeX;
            _contourChart.Height = gridColourSeries.SizeY;
            _contourChart.RenderOptions.AntiAliasLevel = 4;
            _contourChart.Background.Color = Color.Transparent;
            //_contourChart.Background.GradientColor = Color.Transparent;
            //_contourChart.Background.GradientFill = GradientFill.Solid;
            _contourChart.Background.Style = RectFillStyle.None;
            //_contourChart.ViewXY.GraphBackground.Color = Color.DarkMagenta;
            //_contourChart.ViewXY.GraphBackground.GradientColor = Color.DarkGreen;
            _contourChart.ViewXY.GraphBackground.Style = RectFillStyle.None;
            
            _contourChart.ActiveView = ActiveView.ViewXY;
            _contourChart.Title.Visible = false;

            ViewXY v = _contourChart.ViewXY;
            v.LegendBox.Visible = false;

            //Remove all margins 
            v.Margins = new System.Windows.Forms.Padding(0);
            v.GraphBorderColor = Color.Transparent;

            IntensityGridSeries grid = new IntensityGridSeries(v, v.XAxes[0], v.YAxes[0]);

            grid.SetRangesXY(gridColourSeries.RangeMinX, gridColourSeries.RangeMaxX, gridColourSeries.RangeMinY, gridColourSeries.RangeMaxY);
            grid.SetSize(gridColourSeries.SizeX, gridColourSeries.SizeY);
            grid.ContourLineType = ContourLineType.ColorLine;
            grid.ContourLineStyle.Color = Color.Black;
            grid.ContourLineStyle.Pattern = LinePattern.Solid;
            grid.ContourLineStyle.Width = 2;
            v.AxisLayout.AutoAdjustMargins = false;
            float[] fz = contourData.Where(z => !Double.IsNaN(z)).ToArray();//filter out NaNs before getting contour data
            grid.ValueRangePalette = CreateContourPalette(grid, fz.Min(), fz.Max());
            v.IntensityGridSeries.Add(grid);
 
            //Set axis ranges sow that intensity grid fills it. Minimums same and Maximums same. 
            v.XAxes[0].SetRange(gridColourSeries.RangeMinX, gridColourSeries.RangeMaxX);
            v.YAxes[0].SetRange(gridColourSeries.RangeMinY, gridColourSeries.RangeMaxY);


            for (int iNodeX = 0; iNodeX < gridColourSeries.SizeX; iNodeX++)
            {
                for (int iNodeZ = 0; iNodeZ < gridColourSeries.SizeY; iNodeZ++)
                {
                    grid.Data[(gridColourSeries.SizeX - 1) - iNodeX, iNodeZ].Value = (contourData[iNodeZ * gridColourSeries.SizeX + iNodeX]);//stored column major        
                }
            }
            _contourChart.EndUpdate();
            _contourChart.SaveToStream(_bitmapStream, TargetImageFormat.Png);
            _contourChart.SaveToFile("contour.Png");
        }
Code to create second SurfaceGridSeries3D

Code: Select all

void Create3DContourSurfaceChart(LightningChartUltimate _surface3DChart, SurfaceGridSeries3D depthSurface)
        {           
           
            View3D v = _surface3DChart.View3D;

            v.LegendBox.Visible = false;

            SurfaceGridSeries3D surface = new SurfaceGridSeries3D(v, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);

            surface.SetRangesXZ(depthSurface.RangeMinX, depthSurface.RangeMaxX, depthSurface.RangeMinZ, depthSurface.RangeMaxZ);
            surface.SetSize(depthSurface.SizeX, depthSurface.SizeZ);
            surface.BitmapFill.Image = Bitmap.FromStream(_bitmapStream);
            surface.Fill = SurfaceFillStyle.Bitmap;
            //surface.ToneColor = Color.Beige;
            surface.ContourLineType = ContourLineType.None;
            surface.WireframeType = SurfaceWireframeType.None;
            surface.ColorSaturation = 75;
            surface.BaseColor = Color.Transparent;
            surface.ToneColor = Color.Transparent;
            surface.ContourPalette = depthSurface.ContourPalette;
        
            for (int i = 0; i < depthSurface.SizeX; i++)
            {
                for (int j = 0; j < depthSurface.SizeZ; j++)
                {
                    surface.Data[i, j].Y = depthSurface.Data[i, j].Y + 500.0;//add some constant to Y so this surface is distinct from first, just for testing
                }
            }
            v.SurfaceGridSeries3D.Add(surface);
            
            surface.InvalidateData();
              
        }

Any ideas to get this to work?
I will post the project file...

Greg9504
Posts: 38
Joined: Fri Dec 06, 2013 4:51 pm

Re: Intensity Type SurfaceGridSeries3D ??

Post by Greg9504 » Thu Jan 28, 2016 4:30 pm

Attached test project, note I removed my LicenseKeyStrings.cs
LightningChartTest.zip
(217.39 KiB) Downloaded 506 times

User avatar
ArctionPasi
Posts: 1366
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland

Re: Intensity Type SurfaceGridSeries3D ??

Post by ArctionPasi » Thu Jan 28, 2016 4:45 pm

We have made a lot of work to get this working in approx 7.1 version, developed new contouring 3D algorithms etc. So eventually it will find its way to final product.

We can provide you a demo application with these contouring algorithms, but we can't put them visible here in the forums. The algorithms are considered proprietary. Please contact our support by e-mail with declaration of confidentiality (pdf), that you won't spread the code or algorithm around and write your signature in there. Also put your company and subscription ID in the document.

Thanks :-)
LightningChart Support Team, PT