Globe.xaml.cs
上传用户:huazai0421
上传日期:2008-05-30
资源大小:405k
文件大小:7k
源码类别:

SilverLight

开发平台:

C#

  1. // Silver.Globe, version 0.11 for Silverlight 1.1 Alpha
  2. // Copyright © Florian Krüsch (xaml-kru.com)
  3. // xaml-kru.com/silverglobe
  4. // This source is subject to the Microsoft Public License (Ms-PL).
  5. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx.
  6. // All other rights reserved.
  7. #define CLIP
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Media;
  15. using System.Windows.Shapes;
  16. using Path = System.Windows.Shapes.Path;
  17. using SilverGlobe.Data;
  18. using SilverGlobe.Math3D;
  19. using System.Windows.Input;
  20. namespace SilverGlobe
  21. {
  22.     public partial class Globe : Canvas, IPositionProvider
  23.     {
  24.         #region Members
  25.         private Quaternion _orientation;
  26.         private Double _radius = 0.5;
  27.         private Double _zDistance = 1.5;
  28.         private Double _fieldOfView = 35 * Math.PI / 180d;
  29.         private Double _screenRadius;
  30.         private Double _clipZ;
  31.         private Matrix3D _projection;
  32.         private Matrix3D _rotation;
  33.         private IDictionary<String, PathGeometry> _continentGeometry;
  34.         private ContinentShape[] _continents;
  35.         #endregion
  36.         #region Constructor
  37.         public Globe()
  38.         {
  39.             InitializeComponent();
  40.             Cursor = Cursors.Stylus;
  41.             _orientation = Quaternion.ForRotation(Vector3D.YAxis, 0)
  42.                          * Quaternion.ForRotation(Vector3D.XAxis, 0);
  43.             UpdateMatrix();
  44.             UpdateDisplayRadius();
  45.         }
  46.         #endregion
  47.         #region Properties
  48.         public Quaternion Orientation
  49.         {
  50.             get { return _orientation; }
  51.             set { _orientation = value; }
  52.         }
  53.         public Double ScreenRadius
  54.         {
  55.             get { return _screenRadius; }
  56.         }
  57.         public Double ZDistance
  58.         {
  59.             get { return _zDistance; }
  60.             set
  61.             {
  62.                 _zDistance = value;
  63.                 UpdateMatrix();
  64.                 UpdateDisplayRadius();
  65.             }
  66.         }
  67.         #endregion
  68.         #region Methods
  69.         /// <summary>
  70.         /// Initialize the globe with the geographical shapes.
  71.         /// </summary>
  72.         public void InitShapes(params ContinentShape[] continents)
  73.         {
  74.             if (continents == null)
  75.                 throw new ArgumentNullException("continents");
  76.             _continents = continents;
  77.             _continentGeometry = new Dictionary<String, PathGeometry>(continents.Length);
  78.             foreach (ContinentShape c in continents)
  79.             {
  80.                 PathGeometry pathData = new PathGeometry
  81.                 {
  82.                     FillRule = FillRule.Nonzero,
  83.                     Figures = new PathFigureCollection()
  84.                 };
  85.                 for (int i = 0; i < c.Shapes.Count; i++)
  86.                 {
  87.                     PathFigure figure = new PathFigure
  88.                     {
  89.                         IsClosed = true,
  90.                         Segments = new PathSegmentCollection()
  91.                     };
  92.                     figure.Segments.Add(new PolyLineSegment());
  93.                     pathData.Figures.Add(figure);
  94.                 }
  95.                 Path p = (Path)_shapes.FindName(c.Name);
  96.                 p.Data = pathData;
  97.                 _continentGeometry.Add(c.Name, pathData);
  98.             }
  99.         }
  100.         /// <summary>
  101.         /// Update the visual display of the globe.
  102.         /// </summary>
  103.         public void Update()
  104.         {
  105.             _rotation = _orientation.ToMatrix();
  106.             for (int i = 0; i < _continents.Length; i++)
  107.             {
  108.                 // continent data
  109.                 ContinentShape c = _continents[i];
  110.                 // xaml element for the continent
  111.                 PathGeometry geometry = _continentGeometry[c.Name];
  112.                 var o = geometry.Figures;
  113.                 // setup rotation matrix
  114.                 Matrix3D rotation = Matrix3D.Identity
  115.                                             .Scale(new Vector3D(1, 1, 1) * _radius)
  116.                                             * _rotation;
  117.                 // render the continent shapes
  118.                 for (int j = 0; j < c.Shapes.Count; j++)
  119.                 {
  120.                     Point3D[] shapePoints = c.Shapes[j];
  121.                     // do 3D projection and clipping
  122.                     Point[] renderPoints = shapePoints.Transform(rotation)          // rotate
  123.                                                       .Clip(_radius, _clipZ)        // clip
  124.                                                       .Transform(_projection)       // project
  125.                                                       .Select(p3 => p3.ToPoint())   // convert
  126.                                                       .ToArray();
  127.                     // set the path geometry
  128.                     PathFigure figure = (PathFigure)geometry.Figures[j];
  129.                     PolyLineSegment segment = (PolyLineSegment)figure.Segments[0];
  130.                     PointCollection segmentPoints = new PointCollection();
  131.                     if (renderPoints.Length > 1)
  132.                     {
  133.                         figure.StartPoint = renderPoints[0];
  134.                         for (int k=1; k<renderPoints.Length; k++)
  135.                         {
  136.                             segmentPoints.Add(renderPoints[k]);
  137.                         }
  138.                         segment.Points = segmentPoints;
  139.                     }
  140.                     segment.Points = segmentPoints; 
  141.                 }
  142.             }
  143.         }
  144.         /// <summary>
  145.         /// Calculate the position of a geographical position for the current state of the globe.
  146.         /// </summary>
  147.         Point3D IPositionProvider.ProjectPosition(GeoPosition geoPos)
  148.         {
  149.             Point3D p = geoPos.ToSphere(_radius * 1.02)
  150.                               .Transform(_rotation);
  151.             Double z = p.Z;
  152.             p = p.Transform(_projection);
  153.             return new Point3D(p.X, p.Y, z > _clipZ ? 1 : -1);
  154.         }
  155.         #endregion
  156.         #region Implementation
  157.         private void UpdateMatrix()
  158.         {
  159.             Matrix3D projection = new Matrix3D
  160.             {
  161.                 M11 = Math.PI * 0.5 - _fieldOfView,
  162.                 M22 = Math.PI * 0.5 - _fieldOfView,
  163.                 M33 = 1d,
  164.                 M34 = 1d,
  165.                 OffsetZ = 0
  166.             };
  167.             _projection = Matrix3D.Identity
  168.                                    .Translate(new Vector3D(0, 0, -_zDistance))
  169.                                     * projection
  170.                                    .Translate(new Vector3D(0.5, 0.5, 0))
  171.                                    .Scale(new Vector3D(160, 160, 1));
  172.         }
  173.         private void UpdateDisplayRadius()
  174.         {
  175.             Double alpha = Math.Asin(_radius / _zDistance);
  176.             Point3D p = new Point3D(_radius * Math.Cos(alpha), 0, _radius * Math.Sin(alpha));
  177.             Point3D topLeft = _projection * p;
  178.             _screenRadius = 80d - topLeft.X;
  179.             _clipZ = p.Z;
  180. #if CLIP
  181.             _clip.RadiusX = _screenRadius;
  182.             _clip.RadiusY = _screenRadius;
  183. #endif
  184.             _glossScale.ScaleX = _glossScale.ScaleY = _screenRadius / 80d;
  185.         }
  186.         #endregion
  187.     }
  188. }