2009-08-11 20 views
1

Ich möchte eine normale Grafik mit einigen Ecken und Kanten in 3D WPF zeichnen. Das bedeutet, dass Scheitelpunkte Kugeln und Kanten Zylinder sind.Verbinden Sie zwei Kugeln mit einem Zylinder in WPF 3D

Ich möchte zuerst einige der Kugeln zeichnen und dann diese mit Zylindern verbinden. Ich bin in der Lage, die Sphären und Zylinder separat in einem freien Raum zu zeichnen, indem ich die Beispiele im Text "Praktische WPF-Grafikprogrammierung" verwende. Ich habe keine Hilfe bekommen, wenn ich mich zu ihnen gesellt habe. Wie kann das gemacht werden?

+0

Ich denke du meinst – epotter

+1

Situ 'Sphären', wenn Sie "Speere" sagen, meinen Sie, wie „Runde Bälle "? Wenn ja, ist die korrekte Schreibweise "Sphären". Oder meinst du einen langen, dicken Pfeil (in welchem ​​Fall "Speere" richtig sind)? –

+0

Danke andrew und potter ihr habt recht, es ist (Spheres). Sorry wegen der Verwirrung. – SituStarz

Antwort

5

Hier sind zwei Kugeln, durch einen Zylinder verbunden, im 3D-Raum drehen. Die Methode Init nimmt zwei Punkte, aber ich fürchte, Sie können die Z-Achse nur ändern, wenn Sie möchten, dass die Kugeln richtig verbunden sind.

Der Code ist ein wenig unordentlich, zusammengestellt aus einer Reihe von Quellen, einschließlich Ihrer eigenen Sphäre Generation Code, den Sie in einer anderen Frage geschrieben.

XAML mit Viewport:

<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> 

Und der Code-behind:

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; 
     } 
    } 
} 
Verwandte Themen