共用方式為


本文章是由機器翻譯。

Charles

在您的 Windows Phone 上觀看夜空

Charles Petzold

下載代碼示例

Charles Petzold
在他的經典歷史,"哥白尼革命"(哈佛大學出版社,1957年),Thomas S.的開幕頁中庫恩喚起人們在夜晚的天空會非常熟悉世界許多世紀以前。尚未受人工照明的持久性光照,這些觀察員親身經歷怎樣的星星圓頂似乎旋轉,夜間在北星星周圍長弧中,以及如何通過 12 生肖的步驟每年週期的日出和日落進展的恒星的配置。

他們還觀察到如何幾個明星,沒有遵循這個相同的模式。這些古怪似乎全景的恒星,有時甚至扭轉與天體穹頂的議案中漫步。這些一般規則的例外情況仍然是已知的流浪者古希臘文中:Πλανήτης 或行星。

跟蹤並預測這些行星運動的嘗試是科學的歷史,從宇宙的中心最終推翻原始宇宙和地球的位移的最著名動盪的開始。在人類獲得更好地瞭解在宇宙中的地位的同時,它也開始失去這種特別的關係,夜晚的天空。

使用 AstroPhone

這些天我們大多數人有沒有時間、 耐心或想在盯著夜空足夠長的時間來感受其週期性的模式或檢測流浪行星的寧靜。相反,我們依賴明星圖表或基於電腦的天文工具來幫幫忙。

此列描述體裁,為 Windows Phone 與 AstroPhone 的名字很傻的小程式我自己微薄的貢獻。可下載的應用程式的原始程式碼包含一個名為 AstroPhone,並命名為 Petzold.Astronomy,其中包含很多資料和打號庫 XNA 程式。

此程式已沒有使用者介面除了努力所需手機背面指向夜晚的天空中的位置。這款手機的螢幕然後顯示星、 星座和位於存在的行星。圖 1 顯示了典型的螢幕,在 3:45 下午西飛舉行關於 2012 年 7 月 15 日,該地區紐約城,在手機的本地時間。

A Typical AstroPhone Screen
圖 1 典型 AstroPhone 螢幕

綠線是用指南針點標記的地平線。(通知西 W)。紅線是黃道,這是通過它所有行星約軌道,每 15 ° 的刻度的平面。您可以看到木星和金星適當設置在接下來的 90 分鐘左右。也可見 — — 螢幕上若不在中期-­下午的天空 — — 是金牛座。

要在螢幕上正確放置恒星和行星,該程式需要結合幾個來源的資訊:

  • 資料和演算法派生的恒星和行星 (以下各節中所述) 的位置。
  • 在這些演算法中使用的當前日期和時間。
  • 這款手機的 GPS,這樣該程式知道電話在地球表面上的位置。
  • 手機的動作感應器所以程式知道電話在 3D 空間中的方向如何,因此天葬台的哪一部分球形它指著。

由於嚴重依賴手機的感應器,該程式將無法運行 Windows Phone 模擬器上。

在此列中的幾個前幾期我上面討論的一些使用動作感應器,並將這些資訊轉換為不同的座標系統的概念。這些早期的文章都可用在 MSDN 雜誌 》 網站上 (bit.ly/NoMc8R)。很多我的位置天文學的方法基於這本書"天文演算法"(1998年-貝爾 Willmann),讓 · meeus 雖然我有時使用某種程度上簡化的計算,我已經消除所有錯誤的任何保證。

恒星及星座

如果你看起來在維琪百科上的某個明星,你會發現它的位置就有兩個數字 — — 權利阿森松島和偏差。例如,參宿四星有 5 小時 55 分鐘,10.3053 秒,右阿森松和衰落 7 ° 24 分 25.426 秒。這一立場是相對於赤道的座標系統中,地球的赤道將宇宙劃分為積極角偏角向北和向南的負角偏角。(北極星,也稱為北辰有偏差非常接近 90 °)。

傳統上,右阿森松島是以小時,每小時相當於 15 ° 來衡量。零權阿森松對應于在當地時間的午夜北春分日相同的方向。因為地球的赤道平面仍然在整個一年中 (和整個世紀),大體不變,星星是如此遙遠,因為它們被視為具有相同的赤道座標地球的位置無關。這些恒星的赤道座標指定為一個特定的時期 (例如,2000 年),和小年度調整可以應用於帳戶的星星的輕微運動。

許多明星目錄存在,最的與許多更多明星比我想要在我的程式中顯示它們。我決定要使用的一個目錄,起源于 100 多年前的更新的版本:光明之星目錄中,第 5 次修訂本,我從 FTP 網站維護的斯特拉斯堡天文資料中心取得 (bit.ly/T51GE5)。

甚至提供更多的資訊,不是我需要此目錄,也有點少。大部分想要我的程式來顯示僅與現代天文學中使用的 88 標準星座相關主要星星。這是很簡單的因為星星有型號 (開發的第一個小約翰 · 拜耳 400 多年前),指示明星與三個字母的縮寫詞和唯一的希臘文字母屬於哪個星座。

但我還想要提高每個星座與恒星所以,Leo 的本來面目如棒圖獅子之間那些熟悉線路連接。星座的星星的連線不標準,而且我不知道明星的目錄,其中包括他們。

所以我添加了他們自己。我寫了一個小小的 Windows 演示文稿基金會 (WPF) 程式訪問光明之星目錄中並顯示每個 88 星座的星星。該程式回應滑鼠按一下對兩個星星,並記錄結果。一般我根據線路的連接,貸記國際天文學聯合會和天空上維琪百科,星座圖 & 望遠鏡雜誌。

WPF 程式合併到一個名為 Constellations.xml,您可以找到 Petzold.Astronomy 庫專案的資料目錄中檔的資料。每個星座標記包含星標記的集合。每顆星是從光明明星目錄編號標識。在每個星座的星標記之後,定義行編號明星對之間的連接器標記的集合。

行星

作為實現甚至是原始觀星,行星的位置是比星星的複雜得多。行星圍繞太陽的橢圓軌道但相互引力相互作用產生的違規行為。一種演算法,在某一特定時間確定地球上的位置是通常稱為"理論",和通常基於傅裡葉系列。

我用的行星理論稱為 VSOP87,變化 Séculaires des Orbites Planétaires 1987 版,由主席團在巴黎 des 經度維護。包含的 VSOP87 部分資料的檔還包括 Petzold.Astronomy 專案的資料目錄中。VsopCruncher 類中的時間為每個行星為某一特定點執行計算。

行星的位置通常計算在黃道座標,但與太陽的中心 — — 也就是說,金星的日心,而不是地心。對於每個星球,這些座標包含的內容:

  • 在其某一年度期間是從 0 ° 到 360 ° 作為地球黃道經度使得完成繞太陽軌道
  • 是接近于零,因為所有的行星軌道在大致相同的平面中的太陽黃道緯度
  • 半徑是地球離太陽的距離。

這些座標是偉大繪製行星圍繞太陽的運動。不過,如果您要計算從地球看作為地球上的位置,很方便,將這些球面座標轉換成三維矩形座標,其中 X 指示行星的位置,Y 和 Z 值與佔領中心處 (0,0,0) 的原點的太陽。減去直角座標任何從矩形座標的地球的星球,你一個 3D 向量從地球到那的星球上,然後可以轉換為右阿森松島和地心黃道座標的偏差值 — — 用於星星的相同座標系統。

月球的運動比恒星、 行星、 複雜得多,並已作為單獨的案例來處理。我選擇不包括在此版本的 AstroPhone 程式的月亮。此外,如果我是以包括月球,我會覺得要顯示的當前階段,,將使更多的工作複雜化。

鏈的計算

要有條理的方式執行必要的計算,我定義類層次的結構:

CelestialBody
        Constellation
        Star
            SolarSystemBody
                Sun
                Planet
                    Earth

星和星座類也發揮作為 Constellations.xaml 檔反序列化物件的雙重角色。

如中所示圖 2,CelestialBody 類負責計算從 EquatorialCoordinate HorizontalCoordinate 基於電話的當前日期和時間的地理位置。子代類計算中的 EquatorialCoordinate 屬性的 OnTimeChanged 方法將重寫。

圖 2 父 CelestialBody 類

public abstract class CelestialBody
{
  // Only used internally
  private GeographicCoordinate Location { set; get; }
  // Set here, used by descendant classes
  protected Time Time { private set; get; }
  // Set by descendant classes, used here
  protected EquatorialCoordinate EquatorialCoordinate { set; private get; }
  // Set here, used external to library
  public HorizontalCoordinate HorizontalCoordinate { private set; get; }
  // Used externally to retain screen location
  public float ScreenX;
  public float ScreenY;
  // Called external to update HorizontalCoordinate
  public void Update(Time time, GeographicCoordinate location)
  {
    bool needsUpdate = false;
    if (!this.Time.Equals(time))
    {
      this.Time = time;
      needsUpdate = true;
      OnTimeChanged();
    }
    if (!this.Location.Equals(location))
    {
      this.Location = location;
      needsUpdate = true;
    }
    if (needsUpdate)
    {
      this.HorizontalCoordinate =
        HorizontalCoordinate.From(this.EquatorialCoordinate,
                                  this.Location, this.Time);
    }
  }
  // Overridden by descendant classes to update EquatorialCoordinate
  protected virtual void OnTimeChanged()
  {
  }
}

中所示的 SolarSystemBody 類圖 3 計算從及其子代的類和示的星球類提供的 HeliocentricLocation 向量的 EquatorialCoordinate 屬性圖 4,HeliocentricLocation 基於對 VsopCruncher 的調用,計算。

圖 3 SolarSystemBody 類

public class SolarSystemBody : CelestialBody
{
  protected SolarSystemBody()
  {
  }
  protected SolarSystemBody(string name, Color color)
  {
    this.Name = name;
    this.Color = color;
  }
  public string Name { protected set; get; }
  public Color Color { protected set; get; }
  // Set by descendant classes, used here
  protected Vector3 HeliocentricLocation { set; private get; }
  protected override void OnTimeChanged()
  {
    // Calculate geocentric coordinates
    Vector3 bodyLocation = this.HeliocentricLocation -
                           Earth.Instance.HeliocentricLocation;
    EclipticCoordinate geocentricCoordinate =
      new EclipticCoordinate(bodyLocation);
    this.EquatorialCoordinate =
      EquatorialCoordinate.From(geocentricCoordinate, this.Time);
    base.OnTimeChanged();
  }
}

圖 4 星球類

public class Planet : SolarSystemBody
{
  VsopCruncher vsop;
  public Planet(string strPlanetAbbreviation, 
    string name, Color color) :
    this(strPlanetAbbreviation)
  {
    this.Name = name;
    this.Color = color;
  }
  protected Planet(string strPlanetAbbreviation)
  {
    vsop = new VsopCruncher(strPlanetAbbreviation);
  }
  protected override void OnTimeChanged()
  {
    Angle latitude = Angle.FromRadians(vsop.GetLatitude(this.Time.Tau));
    Angle longitude = Angle.FromRadians(vsop.GetLongitude(this.Time.Tau));
    double radius = vsop.GetRadius(this.Time.Tau);
    this.HeliocentricLocation =
      new EclipticCoordinate(longitude, 
          latitude, radius).RectangularCoordinates;
    base.OnTimeChanged();
  }

明星類是更簡單,因為它可以計算赤道幾內亞­只是小的調整,到 2000 年的立場與協調。

XNA 前端

我開始寫使用 Silverlight,工作得非常棒與第一個幾個星座的 AstroPhone 程式。但更多的星座補充,它變得越慢。

請記住時使用此類程式的 Silverlight,所有文本、 線條和點都是在面板中的某種 TextBlock、 線和路徑元素。要得到流體的運動,如弧掃電話,這需要將只是一個面板,和那在它擁有的一切。性能降低更多如果你開始刪除專案或使他們當他們不是在視圖中不可見。

我花了很多時間試圖改善此 Silverlight 程式的性能。我發現使用畫布比單個儲存格網格更好地工作。我發現當顯示多行元素,您可以通過將一個座標的行設置為點 (0,0)、 調整其他座標的金額和使用 TranslateTransform 將其移動到的位置提高性能。

但與所有 88 星座中的地方,掉到單個幀每秒的視頻畫面播放速率和根本沒有選擇除要放棄 Silverlight。這就是為什麼 AstroPhone 是一個 XNA 程式。

有趣的是,AstroPhone 的最慢部分根本不是圖形。反序列化該 Constellations.xml 檔,這會發生在 OnActivated 的遊戲類重寫它。該程式然後生成更新和呈現天體物體的幾個集合。用於更新座標的主要集合稱為 celestialBodies。顧名思義,這是從 CelestialBody,派生的類的實例的集合,它包含 832 物件 — — 735 物件的類型明星的 88 鍵入星座,一個太陽和地球上的所有八個物件。(冥王星不是列入 VSOP87)。

在 Windows Phone XNA 程式中,在遊戲類的更新和繪製覆蓋稱為每秒 30 倍的速度。負責從感應器 (GPS 和議案,在本例中的) 獲取輸入和準備用於繪製方法的資料更新。

為了實現對流動電話的平滑回應,更新覆蓋整個 celestialBodies 集合的迴圈、 從每個物件,獲取的 HorizontalCoordinate 屬性並使用當前議案矩陣,轉換為二維的點,在螢幕上,然後將存儲在 ScreenX 和 ScreenY 的 CelestialBody 物件的屬性。然後繪製方法訪問這些 ScreenX 和 ScreenY 的屬性,以在螢幕上繪製物件。

但是,計算只是占螢幕的運動。它也是有必要為每個 CelestialBody 物件定期更新其 HorizontalCoordinate 屬性,隨著時間的推移和地球和其他行星移一點。仍然,此更新不是該程式的順利運作的關鍵。HorizontalCoordinate 屬性基於當前日期和時間以及使用者的地理位置,但不能對這些專案的更改速度不夠快,在短期內影響恒星和行星的位置。

為此,遊戲類的更新替代慢悠悠地處理 CelestialBody 物件的更新方法。CelestialBodies 集合中的只有一項被更新遊戲類更新重寫中,需要約 28 秒 832 物件的整個集合中迴圈週期的每個調用。

為了呈現,其他集合維護因為不同類型的天體在以不同的方式呈現。VisibleStars 集合中包含螢幕呈現 735 明星物件、 星座集合了 88 星座和 systemBodies 集合了太陽和七個行星,包括地球。

像是從 CelestialBody 派生的每個其他類,星座類設置 EquatorialCoordinate 屬性,但這是僅用於定位的星座名稱。每個星座實例以彌補星座的連接星星的平均計算這一立場。

連接線條本身是相當棘手。每個星座物件具有的連接器物件的集合,每個引用明星星座中一對。但這些連接器物件來自原始的 Constellations.xml 檔,而它們引用連接明星 ID 號的一對。加快線繪圖,該程式花費補充每對 StarConnector 物件時,這是一對實際明星物件的 ID 號的初始化過程的一部分。因此,該程式可以通過引用實際的明星物件的 ScreenX 和 ScreenY 屬性繪製連接線線條。

圖 5 顯示呈現星座名稱、 連接線條和恒星本身的繪製方法的一部分。

圖 5 繪製方法來呈現星座和星星

protected override void Draw(GameTime gameTime)
{
  // Dark blue sky
  GraphicsDevice.Clear(new Color(0, 0, 0x20));
  spriteBatch.Begin(SpriteSortMode.Immediate, 
    null, null, null, null, null,
    displayMatrix);
  ...
// Loop through constellations
  foreach (Constellation constellation in 
    constellations.ConstellationList)
  {
    if (!float.IsNaN(constellation.ScreenX))
    {
      // Display constellation name
      Vector2 textSize = 
        labelFont.MeasureString(constellation.LongName);
      spriteBatch.DrawString(labelFont, constellation.LongName,
        new Vector2(constellation.ScreenX - textSize.X / 2,
        constellation.ScreenY - textSize.Y / 2), Color.Gray);
    }
    // Display constellation connectors
    if (constellation.StarConnectors != null)
    {
      foreach (StarConnector starConnector in 
        constellation.StarConnectors)
      {
        Vector2 point1 = new Vector2((float)starConnector.From.ScreenX,
          (float)starConnector.From.ScreenY);
        Vector2 point2 = new Vector2((float)starConnector.To.ScreenX,
          (float)starConnector.To.ScreenY);
        if (!float.IsNaN(point1.X) && !float.IsNaN(point2.X))
          lineRenderer.Draw(spriteBatch, point1, point2, 
           1, Color.White);
      }
    }
  }
  // Now display the stars themselves
  foreach (Star star in visibleStars)
    if (!float.IsNaN(star.ScreenX))
      starDotRenderer.Draw(spriteBatch,
        new Vector2(star.ScreenX, star.ScreenY), Color.White);
  ...
spriteBatch.End();
  base.Draw(gameTime);
}

雖然程式如 AstroPhone 提供的恒星和行星的説明指南,都沒有在現實生活中其實看看他們的經驗。也許隨著人們獲得更多的知識,這類程式的説明下,他們將再一次制定夜晚的天空會非常熟悉。

Charles Petzold 是 MSDN 雜誌長期貢獻和目前正在更新他的經典著作"程式設計視窗"(微軟出版社,1998 年),Windows 8. 他的網站是 charlespetzold.com

由於以下的技術專家對本文的審閱:音為摩斯