///////////// Xaml Code , CS Code is at the bottm of this file ///////// #882B91 #30BC9A ////////////CS Code///////////// using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; 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 SciChart.Charting3D.Model; using SciChart.Charting3D.RenderableSeries; using SciChart.Data.Model; using DispatcherTimer = System.Windows.Threading.DispatcherTimer; namespace _3DRenderApp { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { private DispatcherTimer _timer; private readonly object _syncRoot = new object(); public MainWindow() { InitializeComponent(); UpdateLayout(); } private void UpdateLayout() { int countU, countV; countU = countV = 1000; var dataSeries = new EllipsoidDataSeries3D(countU, countV) { SeriesName = "Geo Mesh", A = 6.01, B = 6.01, C = 6.01 }; for (int r = 1; r <= 4; r++) { var renerer = r == 1 ? SurfaceRenderer1 : (r == 2 ? SurfaceRenderer2 : (r == 3 ? SurfaceRenderer3 : SurfaceRenderer4)); var pts = Get3DCirclepoints(0.1+ (double)r/25); PlotCircleDataSeries(pts, renerer, 6.1, true); } var dbl = Get3DCirclepoints(30); var locusPoints = PlotCircleDataSeries(dbl, LineRenderer); Random rnd = new Random(0); int frames = 0; _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromMilliseconds(1000); int counter = 1; var geoHeightMap = GetBitMapImage(countU, countV); var frontBuffer = dataSeries.InternalArray; var backBuffer = new GridData(countU, countV).InternalArray; var buf = frontBuffer; Parallel.For(0, countV, i => { for (int j = 0; j < countU; j++) { buf[i][j] = geoHeightMap[i, j]; } }); _timer.Tick += (s, arg) => { lock (_syncRoot) { double heightOffsetsScale = 1; double freq = (Math.Sin(frames++ * 0.1) + 1.0) / 2.0; Parallel.For(0, countV, i => { var buf = frontBuffer; for (int j = 0; j <= countU; j++) { // Rotate (offset) J index int rj = j + frames; if (rj >= countU) { rj -= countU * (rj / countU); } buf[i][j] = geoHeightMap[i, rj] + Math.Pow(geoHeightMap[i, rj], freq * 10.0) * heightOffsetsScale; } counter++; var randomColor = Color.FromArgb(0xFF, (byte)rnd.Next(0, 255), (byte)rnd.Next(0, 255), (byte)rnd.Next(0, 255)); try { if (counter >= 0) { OnProcessCompleted(locusPoints[counter], randomColor); } } catch (Exception ex) { var st = new StackTrace(ex, true); // Get the top stack frame var frame = st.GetFrame(0); // Get the line number from the stack frame var line = frame.GetFileLineNumber(); MessageBox.Show(ex.Message +" Line ->"+line); } if (counter >= 358) counter = 1; }); using (dataSeries.SuspendUpdates(false, true)) { dataSeries.CopyFrom(frontBuffer); var temp = backBuffer; backBuffer = frontBuffer; frontBuffer = temp; } try { PerformPointRotation((EllipsoidDataSeries3D)SurfaceMesh.DataSeries, SurfaceRenderer1); } catch (Exception ex) { var st = new StackTrace(ex, true); // Get the top stack frame var frame = st.GetFrame(0); // Get the line number from the stack frame var line = frame.GetFileLineNumber(); MessageBox.Show(ex.Message + "Line ->"+line); } SurfaceMesh.DataSeries = dataSeries; _timer.Start(); } }; SurfaceMesh.DataSeries = dataSeries; _timer.Start(); } private void PerformPointRotation(EllipsoidDataSeries3D olderCoordinates, PointLineRenderableSeries3D rendererUpdate) { if (olderCoordinates != null) { const int teta = 10; var data = (XyzDataSeries3D)rendererUpdate.DataSeries; var newData = new XyzDataSeries3D(); for (int index = 0; index <= data.Count; index++) { double x, y, z, xd, yd, zd; x = data.XValues[index]; y = data.YValues[index]; z = data.ZValues[index]; xd = x* Math.Cos(teta* Math.PI / 180) + z* Math.Sin(teta* Math.PI / 180); zd = -x* Math.Sin(teta* Math.PI / 180) + z* Math.Cos(teta* Math.PI / 180); newData.Append(xd, y, zd); } using (rendererUpdate.DataSeries.SuspendUpdates()) { rendererUpdate.DataSeries = newData; } } } private static double[,] GetBitMapImage(int countU, int countV) { BitmapImage bitmapImage = new BitmapImage(); // Load image from resources bitmapImage.BeginInit(); bitmapImage.CacheOption = BitmapCacheOption.OnDemand; bitmapImage.CreateOptions = BitmapCreateOptions.DelayCreation; bitmapImage.DecodePixelWidth = countU; bitmapImage.DecodePixelHeight = countV; bitmapImage.UriSource = new Uri(@"d:\globe_heightmap.png"); bitmapImage.EndInit(); var geoHeightMap = new double[countU, countV]; int nStride = (bitmapImage.PixelWidth * bitmapImage.Format.BitsPerPixel + 7) / 8; int bytsPerPixel = bitmapImage.Format.BitsPerPixel / 8; byte[] pixelByteArray = new byte[bitmapImage.PixelWidth * nStride]; bitmapImage.CopyPixels(pixelByteArray, nStride, 0); for (int v = 0; v < countV; v++) { for (var u = 0; u < countU; u++) { int pixelIndex = v * nStride + u * bytsPerPixel; var offset = pixelByteArray[pixelIndex] / 255.0f; geoHeightMap[v, u] = offset; } } return geoHeightMap; } protected void OnProcessCompleted(Tuple locus, Color randomColor) //protected virtual method { var xyzDataSeries3D = new XyzDataSeries3D(); xyzDataSeries3D.Append(locus.Item1, locus.Item2, locus.Item3 , new PointMetadata3D(randomColor)); Dispatcher.BeginInvoke(() => { Satellite.DataSeries = xyzDataSeries3D; }); } private DoubleSeries Get3DCirclepoints(double radius) { var dbl = new DoubleSeries(360); for (int i = 0; i <= 360; i++) { dbl.Add(new XYPoint() { X = radius*Math.Cos(i*Math.PI/180) , Y = radius*Math.Sin(i*Math.PI/180) }); } return dbl; } private List> PlotCircleDataSeries(DoubleSeries dbl, PointLineRenderableSeries3D renderer, double zaxisValue = 0, bool isRedcolor = false) { var random = new Random(0); var xyzDataSeries3D = new XyzDataSeries3D(); var data = dbl; List> locusList = new List>(); for (int i = 0; i < data.Count; i++) { double x = 1.3+data.XData[i]; double y = 1.5+ data.YData[i]; double z = -0.25 + zaxisValue; locusList.Add(new Tuple(x, y, z)); Color? randomColor = !isRedcolor ? Color.FromArgb(0xFF, (byte)random.Next(2, 255), (byte)random.Next(50, 255), (byte)random.Next(50, 255)) : Color.FromRgb(255, 0, 0); float scale = (float)((random.NextDouble() + 0.5) * 3.0); xyzDataSeries3D.Append(x, y, z, new PointMetadata3D(randomColor, scale)); } renderer.DataSeries = xyzDataSeries3D; return locusList; } } public class DoubleSeries : List { public DoubleSeries() { } public DoubleSeries(int capacity) : base(capacity) { } public IList XData { get { return this.Select(x => x.X).ToArray(); } } public IList YData { get { return this.Select(x => x.Y).ToArray(); } } } public class XYPoint { public double X { get; set; } public double Y { get; set; } } }