Irregular 3D mesh

Need help in implementing some specific function to your LightningChart Ultimate powered application? Post a question and get code snippets from other LightningChart Ultimate community members.

Moderator: Queue Moderators

Post Reply
Streght
Posts: 12
Joined: Mon May 30, 2016 9:29 am

Irregular 3D mesh

Post by Streght » Tue Jun 28, 2016 3:02 pm

Hello there,

I'm still working on my internship and I encountered a new issue.

I have some huge matrix that I want to display in 3D (way more that a billion points). To be able to display them with a minimum impact on performance, I'm realizing an algorithm that should reduce drastically the number of points while respecting the global topology of the surface. I want to keep more points on areas that present discontinuities while reducing the number of points on area with small changes.

I end up with an irregular 3D mesh and I can't figure out a way to display it properly. I ran some tests with the following data :

Code: Select all

SurfacePoint[,] data = new SurfacePoint[iColumnCount, iRowCount];
data[0, 0].Y = 100;
data[199, 0].Y = 100;
data[100, 100].Y = 50;
data[0, 199].Y = 100;
data[199, 199].Y = 100;
data[120, 70].Y = 75;
and I get this result :

Image

I understand that values data[X,Z] that are not affected are set to zero and displayed, I would like to display a mesh with only these 6 points. Is it possible with LightningChart ? Can you provide me with a small example to help me ?

Kind regards !

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

Re: Irregular 3D mesh

Post by ArctionPasi » Wed Jun 29, 2016 7:21 am

From this description it's a little bit hard to understand what you are actually requesting here.

We have an example that would probably suit your purpose, more or less. It's for WinForms, almost same code can be applied to WPF as well if you are using that.

In this example, there's bunch of data points, and based on them, a surface series data is composed. The data points are shown as balls.
Surface series based on data points
Surface series based on data points
SurfaceBasedOnDataPoints.jpg (346.03 KiB) Viewed 15624 times

Code: Select all


namespace HeatmapColorSpreading3D
{
    public partial class Form1 : Form
    {
        LightningChartUltimate m_chart;
        SurfaceGridSeries3D m_surface;
        DataPoint[] m_dataPoints;
        int m_iDataPointCount; 
 
        double MinX = double.MaxValue;
        double MaxX = double.MinValue;
        double MinZ = double.MaxValue;
        double MaxZ = double.MinValue;
        double MinValue = double.MaxValue;
        double MaxValue = double.MinValue;  
 
        const int SizeX = 100;
        const int SizeZ = 100; 
 
        public Form1()
        {
            InitializeComponent();
 
            
            
 
            m_dataPoints = new DataPoint[]
            {
                new DataPoint(7.00,-2.35,79.61),
                new DataPoint(8.25,-2.81,80.08),
                new DataPoint(9.50,-2.36,77.40),
                new DataPoint(12.50,-2.31,79.23),
                new DataPoint(14.25,-2.34,81.42),
                new DataPoint(15.50,-2.61,81.45),
                new DataPoint(17.75,-2.63,81.34),
                new DataPoint(20.38,-2.75,80.81),
                new DataPoint(21.61,-2.84,80.87),
                new DataPoint(22.79,-2.59,77.25),
                new DataPoint(6.78,-1.79,61.79),
                new DataPoint(8.60,-1.40,60.76),
                new DataPoint(9.71,-2.13,63.18),
                new DataPoint(11.49,-2.17,63.29),
                new DataPoint(14.25,-1.29,61.68),
                new DataPoint(15.83,-2.07,61.33),
                new DataPoint(17.76,-1.76,61.08),
                new DataPoint(19.61,-2.22,61.32),
                new DataPoint(19.79,-2.08,60.60),
                new DataPoint(20.38,-1.75,59.54),
                new DataPoint(7.39,-0.61,44.00),
                new DataPoint(8.49,-0.76,43.64),
                new DataPoint(10.43,-1.04,45.80),
                new DataPoint(13.44,-0.33,44.98),
                new DataPoint(14.63,-1.07,41.53),
                new DataPoint(16.12,-0.59,42.88),
                new DataPoint(18.24,-0.73,43.56),
                new DataPoint(21.18,-0.60,45.70),
                new DataPoint(21.72,-0.54,44.27),
                new DataPoint(23.19,-0.26,44.07),
                new DataPoint(7.36,0.51,83.00),
                new DataPoint(9.25,0.51,80.63),
                new DataPoint(10.43,0.95,85.33),
                new DataPoint(12.41,0.65,85.27),
                new DataPoint(15.06,0.62,85.34),
                new DataPoint(15.91,0.45,85.00),
                new DataPoint(18.44,0.64,85.20),
                new DataPoint(20.56,0.55,82.29),
                new DataPoint(19.92,0.19,83.75),
                new DataPoint(21.06,0.02,82.37),
                new DataPoint(8.15,0.53,81.51),
                new DataPoint(8.51,0.87,85.38),
                new DataPoint(11.19,0.76,82.60),
                new DataPoint(13.78,1.02,82.59),
                new DataPoint(15.39,1.03,82.80),
                new DataPoint(16.45,0.06,84.60),
                new DataPoint(18.62,0.70,83.96),
                new DataPoint(21.91,0.60,85.43),
                new DataPoint(22.19,0.42,81.38),
                new DataPoint(23.53,0.70,83.79),
            };
            m_iDataPointCount = m_dataPoints.Length;
            
            //Seek minimums and maximums for all dimensions 
 
            double x,z,value; 
            for (int i = 0; i < m_iDataPointCount; i++)
            {
                x = m_dataPoints[i].X; 
                value = m_dataPoints[i].Value;
                z =  m_dataPoints[i].Z;
 
                if (x > MaxX)
                    MaxX = x;
                if (x < MinX)
                    MinX = x;
                if (z > MaxZ)
                    MaxZ = z;
                if (z < MinZ)
                    MinZ = z;
                if (value > MaxValue)
                    MaxValue = value;
                if (value < MinValue)
                    MinValue = value; 
            }
            CreateChart();
            
        }
 
 
        void CreateChart()
        {
            m_chart = new LightningChartUltimate();
            m_chart.BeginUpdate();
            
            m_chart.Parent = this; 
            m_chart.Dock =  DockStyle.Fill;
            m_chart.ActiveView = ActiveView.View3D; 
 
            View3D v = m_chart.View3D; 
 
 
            
            AxisX3D xAxis = m_chart.View3D.XAxisPrimary3D;
            AxisY3D yAxis = m_chart.View3D.YAxisPrimary3D;
            AxisZ3D zAxis = m_chart.View3D.ZAxisPrimary3D; 
            
 
           
            
            xAxis.SetRange(MinX, MaxX);
            yAxis.SetRange(MinValue, MaxValue); 
            zAxis.SetRange(MinZ, MaxZ);
 
            xAxis.ValueType = AxisValueType.Number; 
 
            //Create heatmap series 
            m_surface = new SurfaceGridSeries3D(v, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
            m_surface.ContourLineType = ContourLineType.ColorLine; 
            m_surface.ContourLineColor =  Color.White;
            m_surface.WireframeType = SurfaceWireframeType.None;
            m_surface.ColorSaturation = 80;
            m_surface.WireframeType = SurfaceWireframeType.WireframePaletted; 
 
            SurfacePoint[,] data = new SurfacePoint[SizeX, SizeZ];
            m_surface.Data = data;
 
            m_surface.ContourPalette = CreatePalette(m_surface);
            
            m_surface.SetRangesXZ(MinX, MaxX, MinZ, MaxZ); 
            
            m_surface.MouseInteraction = false;
 
            v.SurfaceGridSeries3D.Add(m_surface);
 
            //Create invisible point-line series for data point markers 
 
            PointLineSeries3D pls = new PointLineSeries3D(v, Axis3DBinding.Primary,  Axis3DBinding.Primary, Axis3DBinding.Primary);
            pls.PointsVisible = true;
            pls.LineVisible = false;
            pls.PointStyle.Shape = PointShape3D.Sphere;
            pls.PointStyle.Size.SetValues(1, 1, 1);
            pls.ShowInLegendBox = false;
            pls.IndividualPointColors = true; 
            v.PointLineSeries3D.Add(pls);
 
            SeriesPoint3D[] points = new SeriesPoint3D[m_iDataPointCount]; 
            
            for (int i = 0; i < m_iDataPointCount; i++)
            {
                Color c; 
                m_surface.ContourPalette.GetColorByValue(m_dataPoints[i].Value, out c);
                points[i].X = m_dataPoints[i].X;
                points[i].Z = m_dataPoints[i].Z;
                points[i].Y = m_dataPoints[i].Value;
                points[i].Color = c;
                points[i].SizeFactor = 1;
            }
            pls.Points = points;
 
            UpdateHeatmap(); 
 
            m_chart.EndUpdate(); 
        }
 
    
        ValueRangePalette CreatePalette(SurfaceGridSeries3D series)
        {
            ValueRangePalette palette = new ValueRangePalette(series);
            
            palette.Steps.Clear();
            palette.Steps.Add(new PaletteStep(palette, Color.Blue, MinValue));
            palette.Steps.Add(new PaletteStep(palette, Color.Lime, MinValue + (MaxValue - MinValue) * 0.25));
            palette.Steps.Add(new PaletteStep(palette, Color.Yellow, MinValue + (MaxValue - MinValue) * 0.50));
            palette.Steps.Add(new PaletteStep(palette, Color.Red, MinValue + (MaxValue - MinValue) * 0.75));
            palette.Steps.Add(new PaletteStep(palette, Color.White, MinValue + (MaxValue - MinValue) * 1));
            palette.Type = PaletteType.Gradient;
            palette.MinValue = MinValue;
            return palette;
        }
 
       
 
        void UpdateHeatmap()
        {
            m_chart.BeginUpdate();
 
            double dStepX = (MaxX - MinX) / (double)(SizeX - 1);
            double dStepY = (MaxZ - MinZ) / (double)(SizeZ - 1);
 
            double dX;
            double dY;
            SurfacePoint[,] data = m_surface.Data; 
 
            for (int i = 0; i < SizeX; i++)
            {
                for (int j = 0; j < SizeZ; j++)
                {
                    dX = MinX + (double)i * dStepX;
                    dY = MinZ + (double)j * dStepY;
 
 
                    //Calculate combined influence of data points to this heatmap cell 
                    //Use weighted average method 
                    double dSum = 0;
                    double dSumOfWeights = 0;
                    
                    for (int iP = 0; iP < m_iDataPointCount; iP++)
                    {
                        double dDist = m_dataPoints[iP].GetDistanceTo(dX, dY);
                        double dWeight = 0; 
                        if (dDist != 0)
                        {
                            dWeight = 1.0 / Math.Pow(dDist, 3); 
                            
                            dSum += m_dataPoints[iP].Value * dWeight;
                        }
                        else
                            dSum += m_dataPoints[iP].Value;
                        dSumOfWeights += dWeight; 
                    }
                    double dHeatmapValue = dSum / dSumOfWeights;
                    data[i, j].Y = dHeatmapValue; 
                }
            }
 
            m_surface.Data = data; 
 
            m_chart.EndUpdate(); 
        }
 
    }
 
 
    public class DataPoint
    {
        public double X;
        public double Z;
        public double Value;
 
        public DataPoint(double x, double value, double z)
        {
            this.X = x;
            this.Z = z;
            this.Value = value; 
        }
 
        public double GetDistanceTo(double x, double z)
        {
            return Math.Sqrt((x - X) * (x - X) + (z - Z) * (z - Z));
        } 
    }
}
 

LightningChart Support Team, PT

Streght
Posts: 12
Joined: Mon May 30, 2016 9:29 am

Re: Irregular 3D mesh

Post by Streght » Wed Jun 29, 2016 8:55 am

Hello,

Thanks for your help but it's not exactly whant I'm asking, sorry if I wasn't clear. I'm trying to get a mesh like the red one in the following image :

Image

Another example would be that one : we take these points (the top of the spikes represents the points) :

Image

An we link them like this :

Image

On your exemple, you have several points but the mesh you extrapolate from them is regular. What I want it to reduce the number of points to reduce the mesh resolution and therefore the number of points.

The process will be done on data before plotting them with LightningChart. If an part of the surface contains a lot of details, I want to keep all the points there, if the part of the surface is homogenous I want to keep only a few points. The surface resulting from this treatment will therefore be irregular, with much more points on some places than on others.

The I want to be put these points (with their x,y,z coordonates) in LightningChart so it build a mesh only with the points I provided, linking them together.

ArctionKestutis
Posts: 555
Joined: Mon Mar 14, 2016 9:22 am

Re: Irregular 3D mesh

Post by ArctionKestutis » Wed Jun 29, 2016 11:39 am

Hello,

If I understood correctly, your main worry is irregularity of points in space. However, if you use MeshSeries instead of GridSeries, the nodes can be positioned freely in space (e.g. SurfaceMeshSeries3D). You don't need to have 200x200 mesh either. Maybe in your case it is enough 4x4 or 6x6 mesh size. However, I don't see how you could avoid interpolation anyway, because you may have only estimate for corner points and few central points.
Another option, if you don't want to see surface, why not to use PointLineSeries3D.

Kind regards

Streght
Posts: 12
Joined: Mon May 30, 2016 9:29 am

Re: Irregular 3D mesh

Post by Streght » Wed Jun 29, 2016 12:31 pm

Yeah, I've been trying to use the MeshSeries but I couldn't figure out how to place points freely.

If I try to use it like that for example :

Code: Select all

SurfacePoint[] data = new SurfacePoint[3];
data[0].X = 100;
data[0].Z = 100;
data[0].Y = 100;

data[1].X = 0;
data[1].Z = 0;
data[2].Y = 0;

data[2].X = 50;
data[2].Z = 70;
data[2].Y = 3;

surface = new SurfaceMeshSeries3D(chart3D.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
surface.Data = data;
I get an error because surface.Data needs a data of type SurfacePoint[*,*] and not just SurfacePoint[].

ArctionKestutis
Posts: 555
Joined: Mon Mar 14, 2016 9:22 am

Re: Irregular 3D mesh

Post by ArctionKestutis » Wed Jun 29, 2016 1:00 pm

You need to declare as two-dimensional array:

Code: Select all

SurfacePoint[,] data = new SurfacePoint[sizeX,sizeZ];
Or use it like this:

Code: Select all

        
            surface.SizeX = 3;
            surface.SizeZ = 4;

            surface.Data[0, 0].X = 0
            surface.Data[0, 0].Y = 100;
            surface.Data[0, 0].Z = 0

            surface.Data[0, 1].X = 10;
            surface.Data[0, 1].Y = 100.1;
            surface.Data[0, 1].Z = 0;
...

            surface.Data[1, 1].X = 10;
            surface.Data[1, 1].Y = 98;
            surface.Data[1, 1].Z = 10;

Streght
Posts: 12
Joined: Mon May 30, 2016 9:29 am

Re: Irregular 3D mesh

Post by Streght » Wed Jun 29, 2016 1:55 pm

Thanks a lot for your help, we might get soon where I want :) !

So I tried to plot 5 vertex with the following code :

Code: Select all

SurfacePoint[,] data = new SurfacePoint[3,3];

data[0,0].X = 0;
data[0,0].Z = 0;
data[0,0].Y = 100;

data[0, 2].X = 200;
data[0, 2].Z = 0;
data[0, 2].Y = 100;

data[1, 1].X = 100;
data[1, 1].Z = 100;
data[1, 1].Y = 50;

data[2, 0].X = 0;
data[2, 0].Z = 200;
data[2, 0].Y = 100;

data[2, 2].X = 200;
data[2, 2].Z = 200;
data[2, 2].Y = 100;
And I get the following mesh :

Image

Which in not exactly what I though I would get (in red here) :

Image

Do I have to put my vertex in a specific order ? Or maybe my SurfacePoint[3,3] isn't well declared. Any thought ?

ArctionKestutis
Posts: 555
Joined: Mon Mar 14, 2016 9:22 am

Re: Irregular 3D mesh

Post by ArctionKestutis » Thu Jun 30, 2016 6:23 am

Array is created with default values 0. Therefore, if you not set other value then you get {0,0,0} - as you can see your surface point to bottom left corner. As I wrote before, you need to interpolate missing values. Probably first do bilinear interpolation for xz plane, and then estimate surface height (y-axis). The item [0,1] may become:

Code: Select all

data[0,1].X = 100;
data[0,1].Z = 0;
data[0,1].Y = H;

Streght
Posts: 12
Joined: Mon May 30, 2016 9:29 am

Re: Irregular 3D mesh

Post by Streght » Thu Jun 30, 2016 9:49 am

Thanks, that actually answer my question, it's not possible to draw a surface with "missing" values, the mesh primitives have to be rectangles and every member of the array has to have a value.

I wanted to draw a mesh with as few points as possible so that I would have been able to draw a bigger surface with less points and less impact on the GPU. I can't do it with LightningChart, I'll have another approach to filter the data with a minimum impact on the topology.

Thank you very much for your time, have a nice day !

Post Reply