/////////////
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; }
}
}