2009-08-11 40 views
1

我想用3D WPF中的一些顶点和边缘绘制正常图形。这意味着顶点将成为一个球体,边缘将成为一个圆柱体。用WPF中的圆柱体加入两个球体3D

我想先绘制一些球体,然后用气缸连接那些球体。我可以使用实际WPF图形编程文本中的示例在空闲空间中分别绘制球体和圆柱体。我没有得到任何帮助。 这怎么办?

+0

我想你的意思是 '球' – epotter 2009-08-11 00:46:35

+1

原位,当你说 “矛”,你的意思是像“轮球”?如果是这样,正确的拼写是“球体”。或者你的意思是一个长而粗的箭头(在这种情况下“矛”是正确的)? – 2009-08-11 00:48:25

+0

谢谢安德鲁和波特你们是对的(球体)。 对此感到抱歉。 – SituStarz 2009-08-11 17:24:56

回答

5

这里有两个球体,通过圆柱体连接,在3D空间中旋转。 Init方法需要两点,但是如果你想让球体正确连接,恐怕只能改变Z轴。

代码有点混乱,从许多来源编译,包括您在另一个问题中发布的自己的球体代码。

XAML与视口:

<Window x:Class="wpfspin.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Height="300"> 
      <Viewport3D.Camera> 
       <PerspectiveCamera 
        LookDirection="0,0,-20" 
        UpDirection="0,1,0" 
        Position="0,0,100" 
        /> 
      </Viewport3D.Camera> 
      <ModelVisual3D> 
       <ModelVisual3D.Content> 
        <Model3DGroup x:Name="group3d"> 

         <SpotLight Position="30,30,30" x:Name="mySpotLight" Color="Yellow" InnerConeAngle="100" OuterConeAngle="1000" Range="100" /> 
        </Model3DGroup> 
       </ModelVisual3D.Content> 
      </ModelVisual3D> 
     </Viewport3D> 
    </StackPanel> 
</Window> 

和代码隐藏:

using System; 
using System.Collections.Generic; 
using System.Timers; 
using System.Windows; 
using System.Windows.Media; 
using System.Windows.Media.Media3D; 
using System.Windows.Threading; 

namespace wpfspin 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
      Init(new Point3D(0, 0, 30), new Point3D(0, 0, -30)); 
     } 

     private Timer _timer; 
     private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>(); 
     private double _angle; 


     public void Init(Point3D firstPoint, Point3D secondPoint) 
     { 
      var midPoint = firstPoint - secondPoint; 

      _models.Add(CreateSphere(firstPoint, 10, 10, 10, Colors.AliceBlue)); 
      _models.Add(CreateSphere(secondPoint, 10, 10, 10, Colors.AliceBlue)); 
      _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z)); 

      _models.ForEach(x => mainViewport.Children.Add(x)); 
      _timer = new Timer(10); 
      _timer.Elapsed += TimerElapsed; 
      _timer.Enabled = true; 
     } 


     void TimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d); 
     } 


     public MaterialGroup GetSurfaceMaterial(Color colour) 
     { 
      var materialGroup = new MaterialGroup(); 
      var emmMat = new EmissiveMaterial(new SolidColorBrush(colour)); 
      materialGroup.Children.Add(emmMat); 
      materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour))); 
      var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30); 
      materialGroup.Children.Add(specMat); 
      return materialGroup; 
     } 


     public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size) 
     { 
      var farPoint = new Point3D(point.X - (size.X/2), point.Y - (size.Y/2), point.Z - (size.Z/2)); 
      var nearPoint = new Point3D(point.X + (size.X/2), point.Y + (size.Y/2), point.Z + (size.Z/2)); 

      var cube = new Model3DGroup(); 
      var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z); 
      var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z); 
      var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z); 
      var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z); 
      var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z); 
      var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z); 
      var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z); 
      var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z); 
      //front side triangles 
      cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6)); 
      cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7)); 
      //right side triangles 
      cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5)); 
      cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6)); 
      //back side triangles 
      cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4)); 
      cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5)); 
      //left side triangles 
      cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7)); 
      cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4)); 
      //top side triangles 
      cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5)); 
      cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4)); 
      //bottom side triangles 
      cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0)); 
      cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1)); 
      var model = new ModelVisual3D(); 
      model.Content = cube; 
      return model; 
     } 


     private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle) 
     { 
      return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2); 
     } 


     private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2) 
     { 
      var mesh = new MeshGeometry3D(); 
      mesh.Positions.Add(p0); 
      mesh.Positions.Add(p1); 
      mesh.Positions.Add(p2); 
      mesh.TriangleIndices.Add(0); 
      mesh.TriangleIndices.Add(1); 
      mesh.TriangleIndices.Add(2); 
      var normal = CalculateNormal(p0, p1, p2); 
      mesh.Normals.Add(normal); 
      mesh.Normals.Add(normal); 
      mesh.Normals.Add(normal); 

      var model = new GeometryModel3D(mesh, material); 

      var group = new Model3DGroup(); 
      group.Children.Add(model); 
      return group; 
     } 


     private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2) 
     { 
      var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z); 
      var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z); 
      return Vector3D.CrossProduct(v0, v1); 
     } 


     void Transform(double adjustBy) 
     { 
      _angle += adjustBy; 

      var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 }; 
      var axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle }; 
      rotateTransform3D.Rotation = axisAngleRotation3D; 
      var myTransform3DGroup = new Transform3DGroup(); 
      myTransform3DGroup.Children.Add(rotateTransform3D); 
      _models.ForEach(x => x.Transform = myTransform3DGroup); 
     } 


     public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth) 
     { 
      var cylinder = new Model3DGroup(); 
      var nearCircle = new CircleAssitor(); 
      var farCircle = new CircleAssitor(); 

      var twoPi = Math.PI * 2; 
      var firstPass = true; 

      double x; 
      double y; 

      var increment = 0.1d; 
      for (double i = 0; i < twoPi + increment; i = i + increment) 
      { 
       x = (radius * Math.Cos(i)); 
       y = (-radius * Math.Sin(i)); 

       farCircle.CurrentTriangle.P0 = midPoint; 
       farCircle.CurrentTriangle.P1 = farCircle.LastPoint; 
       farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z); 

       nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true); 

       if (!firstPass) 
       { 
        cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle)); 
        cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle)); 

        cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2)); 
        cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2)); 
       } 
       else 
       { 
        farCircle.FirstPoint = farCircle.CurrentTriangle.P1; 
        nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1; 
        firstPass = false; 
       } 
       farCircle.LastPoint = farCircle.CurrentTriangle.P2; 
       nearCircle.LastPoint = nearCircle.CurrentTriangle.P2; 
      } 
      var model = new ModelVisual3D { Content = cylinder }; 
      return model; 
     } 


     public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color) 
     { 
      Model3DGroup spear = new Model3DGroup(); 

      if (u < 2 || v < 2) 
       return null; 
      Point3D[,] pts = new Point3D[u, v]; 
      for (int i = 0; i < u; i++) 
      { 
       for (int j = 0; j < v; j++) 
       { 
        pts[i, j] = GetPosition(radius, 
        i * 180/(u - 1), j * 360/(v - 1)); 
        pts[i, j] += (Vector3D)center; 
       } 
      } 

      Point3D[] p = new Point3D[4]; 
      for (int i = 0; i < u - 1; i++) 
      { 
       for (int j = 0; j < v - 1; j++) 
       { 
        p[0] = pts[i, j]; 
        p[1] = pts[i + 1, j]; 
        p[2] = pts[i + 1, j + 1]; 
        p[3] = pts[i, j + 1]; 
        spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color)); 
        spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color)); 
       } 
      } 
      ModelVisual3D model = new ModelVisual3D(); 
      model.Content = spear; 
      return model; 
     } 


     private Point3D GetPosition(double radius, double theta, double phi) 
     { 
      Point3D pt = new Point3D(); 
      double snt = Math.Sin(theta * Math.PI/180); 
      double cnt = Math.Cos(theta * Math.PI/180); 
      double snp = Math.Sin(phi * Math.PI/180); 
      double cnp = Math.Cos(phi * Math.PI/180); 
      pt.X = radius * snt * cnp; 
      pt.Y = radius * cnt; 
      pt.Z = -radius * snt * snp; 
      return pt; 
     } 


     public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color) 
     { 
      MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(p0); mesh.Positions.Add(p1); mesh.Positions.Add(p2); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2); 

      Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2); 
      mesh.Normals.Add(normal); 
      mesh.Normals.Add(normal); 
      mesh.Normals.Add(normal); 

      Material material = new DiffuseMaterial(
       new SolidColorBrush(color)); 
      GeometryModel3D model = new GeometryModel3D(
       mesh, material); 
      Model3DGroup group = new Model3DGroup(); 
      group.Children.Add(model); 
      return group; 
     } 


     private class VectorHelper 
     { 
      public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2) 
      { 
       Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z); 
       Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z); 
       return Vector3D.CrossProduct(v0, v1); 
      } 
     } 
    } 

    public class CircleAssitor 
    { 
     public CircleAssitor() 
     { 
      CurrentTriangle = new Triangle(); 
     } 

     public Point3D FirstPoint { get; set; } 
     public Point3D LastPoint { get; set; } 
     public Triangle CurrentTriangle { get; set; } 
    } 

    public class Triangle 
    { 
     public Point3D P0 { get; set; } 
     public Point3D P1 { get; set; } 
     public Point3D P2 { get; set; } 

     public Triangle Clone(double z, bool switchP1andP2) 
     { 
      var newTriangle = new Triangle(); 
      newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z)); 

      var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z)); 
      var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z)); 

      if (!switchP1andP2) 
      { 
       newTriangle.P1 = point1; 
       newTriangle.P2 = point2; 
      } 
      else 
      { 
       newTriangle.P1 = point2; 
       newTriangle.P2 = point1; 
      } 
      return newTriangle; 
     } 

     private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy) 
     { 
      var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z }; 
      newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z); 
      return newPoint; 
     } 
    } 
}