|
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
namespace OpenSource.Wpf3D
{
public class Sphere3D : ModelUIElement3D
{
protected override void OnUpdateModel()
{
GeometryModel3D model = new GeometryModel3D();
model.Geometry = Tessellate();
if (Material == null)
model.Material = CreateMaterial(System.Windows.Media.Brushes.Blue);
else
model.Material = Material;
model.BackMaterial = BackMaterial;
Model = model;
}
private Material CreateMaterial(Brush brush)
{
MaterialGroup mg = new MaterialGroup();
mg.Children.Add(new DiffuseMaterial(brush));
mg.Children.Add(new SpecularMaterial(Brushes.White, 80));
return mg;
}
public Brush Fill
{
set
{
Material = CreateMaterial(value);
}
}
public Material Material
{
get { return (Material)GetValue(MaterialProperty); }
set { SetValue(MaterialProperty, value); }
}
public static readonly DependencyProperty MaterialProperty =
DependencyProperty.Register("Material", typeof(Material), typeof(Sphere3D), new UIPropertyMetadata(null));
public Material BackMaterial
{
get { return (Material)GetValue(BackMaterialProperty); }
set { SetValue(BackMaterialProperty, value); }
}
public static readonly DependencyProperty BackMaterialProperty =
DependencyProperty.Register("BackMaterial", typeof(Material), typeof(Sphere3D), new UIPropertyMetadata(null));
public Point3D Center
{
get { return (Point3D)GetValue(CenterProperty); }
set { SetValue(CenterProperty, value); }
}
public static readonly DependencyProperty CenterProperty =
DependencyProperty.Register("Center", typeof(Point3D), typeof(Sphere3D), new PropertyMetadata(new Point3D(0, 0, 0), CenterPropertyChanged));
private static void CenterPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Sphere3D s = (Sphere3D)d;
s.InvalidateModel();
}
// The number of divisions to make in the theta direction on the sphere
public static readonly DependencyProperty ThetaDivProperty =
DependencyProperty.Register("ThetaDiv",
typeof(int),
typeof(Sphere3D),
new PropertyMetadata(30, ThetaDivPropertyChanged));
private static void ThetaDivPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Sphere3D s = (Sphere3D)d;
s.InvalidateModel();
}
public int ThetaDiv
{
get
{
return (int)GetValue(ThetaDivProperty);
}
set
{
SetValue(ThetaDivProperty, value);
}
}
// The number of divisions to make in the phi direction on the sphere
public static readonly DependencyProperty PhiDivProperty =
DependencyProperty.Register("PhiDiv",
typeof(int),
typeof(Sphere3D),
new PropertyMetadata(30, PhiDivPropertyChanged));
private static void PhiDivPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Sphere3D s = (Sphere3D)d;
s.InvalidateModel();
}
public int PhiDiv
{
get
{
return (int)GetValue(PhiDivProperty);
}
set
{
SetValue(PhiDivProperty, value);
}
}
// The radius of the sphere
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register("Radius",
typeof(double),
typeof(Sphere3D),
new PropertyMetadata(1.0, RadiusPropertyChanged));
private static void RadiusPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Sphere3D s = (Sphere3D)d;
s.InvalidateModel();
}
public double Radius
{
get
{
return (double)GetValue(RadiusProperty);
}
set
{
SetValue(RadiusProperty, value);
}
}
// Tesselates the sphere and returns a MeshGeometry3D representing the
// tessellation based on the given parameters
internal MeshGeometry3D Tessellate()
{
int tDiv = ThetaDiv;
int pDiv = PhiDiv;
double radius = Radius;
double dt = 2 * Math.PI / tDiv;
double dp = Math.PI / pDiv;
MeshGeometry3D mesh = new MeshGeometry3D();
for (int pi = 0; pi <= pDiv; pi++)
{
double phi = pi * dp;
for (int ti = 0; ti <= tDiv; ti++)
{
double theta = ti * dt;
// Spherical coordinates
// http://mathworld.wolfram.com/SphericalCoordinates.html
double x = Math.Cos(theta) * Math.Sin(phi);
double y = Math.Sin(theta) * Math.Sin(phi);
double z = Math.Cos(phi);
Point3D p = new Point3D(Center.X + radius * x, Center.Y + radius * y, Center.Z + radius * z);
Vector3D n = new Vector3D(x, y, z);
System.Windows.Point uv = new System.Windows.Point(theta / (2 * Math.PI), phi / (Math.PI));
mesh.Positions.Add(p);
mesh.Normals.Add(n);
mesh.TextureCoordinates.Add(uv);
}
}
for (int pi = 0; pi < pDiv; pi++)
{
for (int ti = 0; ti < tDiv; ti++)
{
int x0 = ti;
int x1 = (ti + 1);
int y0 = pi * (tDiv + 1);
int y1 = (pi + 1) * (tDiv + 1);
mesh.TriangleIndices.Add(x0 + y0);
mesh.TriangleIndices.Add(x0 + y1);
mesh.TriangleIndices.Add(x1 + y0);
mesh.TriangleIndices.Add(x1 + y0);
mesh.TriangleIndices.Add(x0 + y1);
mesh.TriangleIndices.Add(x1 + y1);
}
}
mesh.Freeze();
return mesh;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.