Currently I'm generating some tubes in 3D and then trying to show differences between the ideal and a measured one. You can see an example attached.
I'm curious if I can use Surface Mesh 3D for this. I want to define the ideal 3D points and then shade the measured surface mesh depending on how different the measured is (gradient colors, etc). Is this possible?
Surface Mesh 3D Question
Moderator: Queue Moderators
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Surface Mesh 3D Question
Yes, you can do that. Use surface.Fill = FromSurfacePoints, and set the color for each node. You can use e.g. auxiliary, hidden, ViewXY.IntensitySeries' ValueRangePalette.GetColorByValue method to convert each value into a color.
LightningChart Support Team, PT
- blakeadkins
- Posts: 44
- Joined: Tue Feb 25, 2014 7:49 pm
Re: Surface Mesh 3D Question
How I create the Surface Mesh? The way I'm creating the image above is by using a PointLineSeries3D. I start at angle 0 degrees and sweep until 359. Then I step down in the z direction and sweep the other direction. This is repeated the whole way down. I'm confused as to how to convert that to a surface mesh. Any help would be greatly appreciated!
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Surface Mesh 3D Question
By using a code below, you can produce a 3D surface from ring data.
and the same without fill, and using point-colored wireframe instead:
I hope this helps
Code: Select all
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Arction.WPF.LightningChartUltimate;
using Arction.WPF.LightningChartUltimate.Views.View3D;
using Arction.WPF.LightningChartUltimate.Series3D;
namespace WpfSurfaceMesh3DTube
{
public struct RingDataPoint
{
public double X;
public double Y;
public double Z;
public double Value;
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
LightningChartUltimate m_chart;
const int RingCount = 30;
const int PointsInRing = 361; //360 degrees + 1 step to close the ring
const double RingRadius = 10;
RingDataPoint[][] m_rings;
public MainWindow()
{
InitializeComponent();
CreateRings();
CreateChart();
}
void CreateRings()
{
//Create array of rings
m_rings = new RingDataPoint[RingCount][];
Random rand = new Random();
for (int iRing = 0; iRing < RingCount; iRing++)
{
//Create a ring in XZ plane
m_rings[iRing] = new RingDataPoint[PointsInRing];
for (int iPoint = 0; iPoint < PointsInRing; iPoint++)
{
double dAngleRadians = (double)iPoint * Math.PI / 180.0;
m_rings[iRing][iPoint].X = RingRadius * Math.Cos(dAngleRadians);
m_rings[iRing][iPoint].Z = RingRadius * Math.Sin(dAngleRadians);
//Let's use ring index as Y
m_rings[iRing][iPoint].Y = iRing;
//Let's just generate some Value data.
m_rings[iRing][iPoint].Value = 10 + (double)iRing / (double)RingCount * 20.0 * Math.Sin(4 * dAngleRadians)*1.0;
}
}
}
void CreateChart()
{
m_chart = new LightningChartUltimate();
gridMain.Children.Add(m_chart);
m_chart.BeginUpdate();
m_chart.ActiveView = ActiveView.View3D;
//Auxiliary mesh, just to contain a value-range palette that is used for primary mesh coloring
SurfaceMeshSeries3D meshAux = new SurfaceMeshSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
meshAux.ContourPalette = CreatePalette(meshAux, 10, 30);
meshAux.ContourLineType = ContourLineType.None;
meshAux.WireframeType = SurfaceWireframeType.None;
m_chart.View3D.SurfaceMeshSeries3D.Add(meshAux);
//Primary mesh to present the tube
SurfaceMeshSeries3D mesh = new SurfaceMeshSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
mesh.Title.ShowInLegendBox = false; //don't show this series in the legend box
//mesh.WireframeType = SurfaceWireframeType.WireframeSourcePointColored;
mesh.WireframeType = SurfaceWireframeType.None;
mesh.WireframeLineStyle.Width = 1;
mesh.WireframeLineStyle.Color = Colors.Black;
mesh.ContourLineType = ContourLineType.None;
mesh.Fill = SurfaceFillStyle.FromSurfacePoints;
//mesh.Fill = SurfaceFillStyle.None;
mesh.ColorSaturation = 90;
//Set the rings as mesh data
//Create an array of surface points. First dimension PointsInRing, second dimension RingCount
SurfacePoint[,] meshData = new SurfacePoint[PointsInRing, RingCount];
for (int iRing = 0; iRing < RingCount; iRing++)
{
for (int iPoint = 0; iPoint < PointsInRing; iPoint++)
{
meshData[iPoint, iRing].X = m_rings[iRing][iPoint].X;
meshData[iPoint, iRing].Y = m_rings[iRing][iPoint].Y;
meshData[iPoint, iRing].Z = m_rings[iRing][iPoint].Z;
//Use the auxiliary mesh to convert values into colors
meshAux.ContourPalette.GetColorByValue(m_rings[iRing][iPoint].Value, out meshData[iPoint, iRing].Color);
}
}
mesh.Data = meshData;
m_chart.View3D.SurfaceMeshSeries3D.Add(mesh);
//Set axis ranges
m_chart.View3D.XAxisPrimary3D.SetRange(-RingRadius * 2, RingRadius * 2);
m_chart.View3D.YAxisPrimary3D.SetRange(0, RingCount-1);
m_chart.View3D.ZAxisPrimary3D.SetRange(-RingRadius * 2, RingRadius * 2);
//FromSurfacePoints coloring needs adjusting the lights little bit stronger to show the colors nicely.
mesh.Material.DiffuseColor = Color.FromArgb(255, 200, 200, 200);
m_chart.View3D.SetPredefinedLightingScheme(LightingScheme.DirectionalFromCamera);
m_chart.View3D.Lights[0].DiffuseColor = Color.FromArgb(255, 255, 255, 255);
m_chart.EndUpdate();
}
private ValueRangePalette CreatePalette(SeriesBase3D ownerSeries, double minValue, double maxValue)
{
ValueRangePalette palette = new ValueRangePalette(ownerSeries);
palette.MinValue = minValue;
palette.Steps.Clear();
palette.Steps.Add(new PaletteStep(palette, Colors.Blue, minValue + (maxValue-minValue) * 0.0));
palette.Steps.Add(new PaletteStep(palette, Colors.Yellow, minValue + (maxValue-minValue) * 0.5));
palette.Steps.Add(new PaletteStep(palette, Colors.Red, minValue + (maxValue-minValue) * 1.0));
palette.Type = PaletteType.Gradient;
return palette;
}
}
}
I hope this helps
LightningChart Support Team, PT
- blakeadkins
- Posts: 44
- Joined: Tue Feb 25, 2014 7:49 pm
Re: Surface Mesh 3D Question
That is excellent; thank you for the example.
One quick followup question; I notice that you have to add one extra point on the end to "complete the ring". The example still seems to work by taking that extra point out. Does having that extra point ensure that the gradient works properly?
One quick followup question; I notice that you have to add one extra point on the end to "complete the ring". The example still seems to work by taking that extra point out. Does having that extra point ensure that the gradient works properly?
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Surface Mesh 3D Question
If I set PointsInRing = 360, it doesn't make a complete ring. One 'sector' is missing, and there's a gap in the mesh.
Simplified, if you make circle by using 90 degrees interval, first path point is 0, second 90, third 180, fourth 270 and fifth 360 (0). Then it's a closed path.
Great to know this example is useful
Simplified, if you make circle by using 90 degrees interval, first path point is 0, second 90, third 180, fourth 270 and fifth 360 (0). Then it's a closed path.
Great to know this example is useful
LightningChart Support Team, PT