觸摸和去

在 Windows Phone 上探索天體座標

查理斯 · Petzold

下載代碼示例

Charles Petzold
自從我結識了在 Windows Phone 7.1 動作感應器,我知道正是我想要用它做:復活一些 C# 位置天文學代碼我寫了大約五年前和絲它向上動作感應器邏輯到 Windows Phone 的程式。這樣一個程式將允許我點在夜晚的天空要顯示的行星和星座那裡位於就地電話。

該程式 — — 與荒謬名稱 AstroPhone — — 在本專欄的下一部分中來。與此同時,一些概念、 數學和方案的基礎是必要的。

如我上面討論之前的專欄中,動作感應器整合來自羅盤、 加速度計、 陀螺儀和 GPS、 輸入和計算 (除其他外) 描述了這款手機的定位在空間中的 3D 旋轉矩陣。它很方便適用于 3D 向量相對於手機的座標系統的這個矩陣。此轉換的向量指向概念球上的位置。這一領域上的某個位置是水準的座標,組成的海拔高度 — — 角的上方或下方觀眾的視野 — — 的方位,基本上是一個羅盤的方向。

水準座標是類似于熟悉的地理座標標識在地球表面上的位置。類似于緯度的上方或下方地球的赤道的海拔高度高於或低於觀眾的視野。該值指示各地觀眾的地平線的羅盤方向的方位是類似于繞地球赤道經度。正如您所看到的所有類型的球面座標都是從根本上是一樣的最關鍵的不同的上部半球分開較低的平面。

拼合球

在上月的列中 (msdn.microsoft.com/magazine/jj553520),我演示了如何使用水準座標通過改變太空手機的定位掃描大型照片和其它圖像。但是,該程式"騙"有點根本無視球面座標的真正性質。它拒絕承認這一事實的緯度圈變得越來越小的頂部和底部的天體,走向和因此,度的方位成為越來越多地壓縮。

只是一個程式,提供了夜晚的天空類比的查看不能採取這些快捷方式。它必須找到演算法的方式將映射到平板手機的螢幕面積的天體。當然,拼合領域一直是幾百年來遇到的製圖問題。它不能沒有失真,但目標是儘量減少這些扭曲。

圖 1 顯示點綴行的高度和方位每 15 ° 的球體。在內部的球體中心的出發點,紅點表示一個點,它你查看或指向您的電話。此特定點的海拔高度為 25 °。方位角取決於你從哪裡開始計數和在什麼方向。

A Point (in Red) on a Celestial Sphere
圖 1 點 (紅色) 在天球上

讓我們稱之為這點"視圖中心",因為它指出,將映射到手機的螢幕的中心。球面上的哪些行對應于螢幕的邊緣呢?

它很容易承擔的這款手機的螢幕邊緣將對應行的高度和方位。但這只是看起來合理地點靠近地平線。這一概念開始打破視圖中心獲取從地平線,以及完全折疊時您正在查看在兩極的向上或向下。

相反,讓我們來構建視圖中心的正交"大圈"中所示圖 2

Orthogonal Great Circles Crossing the View Center
圖 2 穿越視圖中心的正交大圓圈

大圈是一個球形幾何學中的重要概念。一個大圓是共用相同的半徑和中心作為球體本身的 3D 空間中的一個二維圓。因為他們代表兩個點之間最短的距離,類似于飛機上的直線球上的大圓圈。方位 (和經度) 的線是大圓圈。行的高度 (和緯度) 不 ; 相反,它們是"小圈",除了將劃分成兩球的圓 — — 地平線 (或赤道)。

在紅色大圓圖 2 通過兩極,只是一種方位線。藍色的大圓越過地平線方位角 90 °,從視圖中心的方位。

圍繞該視圖中心一個矩形將被映射到手機的螢幕。從概念上講,此矩形可以大圈的網格。讓我們來構造兩個更大圓藍色,越過地平線,第一個相同的位置。並讓我們構造兩個多個紅色大圓也與第一個共用的兩個點。結果將顯示在圖 3。共用的紅色大圓點作為視圖中心 (或方位加 180 °) 的同一方位但高度偏移旋轉 90 °。

Additional Great Circles to Create a Rectangular Area
圖 3 額外大圓圈的創建一個矩形區域

這些額外的大圈到電話,約 19 ° 弧和 32 ° 的弧的高度,寬度的縱向模式螢幕定義一個對應的矩形的邊緣。如果你假設這款手機的螢幕是大約 2 英尺寬和 3.33 英寸高,這些弧度是恰當的當手機的螢幕舉行約 6 英寸從你的臉。這款手機的螢幕是 480 圖元寬和 800 圖元高,所以這些數位還意味著每圓弧度 25 圖元。

推行此投影演算法中,當您需要倒推的工作:想想兩個點為軸,由三個藍色的大圓圈共用和共用的三個紅色大圓圈作為另一個軸的兩個點。與向視圖中心向量,這些構成正交座標系統。

向量代數允許派生的任何其他座標從視圖中心,角度偏移量的 HorizontalCoordinateProjection 類中所示圖 4。類有一個方法來設置視圖中心和另一種方法來獲取角度偏移量相對於該視圖中心的任何其他物件的水準座標。

圖 4 HorizontalCoordinateProjection 類

public class HorizontalCoordinateProjection
{
  Vector3 viewCenterVector, horzAxis, vertAxis;
  public void SetViewCenter(HorizontalCoordinate viewCenterCoord)
  {
    viewCenterVector = viewCenterCoord.ToVector();
    HorizontalCoordinate vertAxisCoord =
      new HorizontalCoordinate(viewCenterCoord.Azimuth + 90, 0);
    vertAxis = vertAxisCoord.ToVector();
    horzAxis = Vector3.Cross(viewCenterVector, vertAxis);
  }
  public void GetAngleOffsets(HorizontalCoordinate objectCoord,
       out double horzAngle, out double vertAngle)
  {
    Vector3 objectVector = objectCoord.ToVector();
    Vector3 horzObjectCross = Vector3.Cross(objectVector, -horzAxis);
    Vector3 vertObjectCross = Vector3.Cross(objectVector, vertAxis);
    horzObjectCross.Normalize();
    vertObjectCross.Normalize();
    double x = Vector3.Dot(horzObjectCross, vertAxis);
    double y = Vector3.Dot(horzObjectCross, viewCenterVector);
    horzAngle = -180 * Math.Atan2(y, x) / Math.PI;
    x = Vector3.Dot(vertObjectCross, horzAxis);
    y = Vector3.Dot(vertObjectCross, viewCenterVector);
    vertAngle = -180 * Math.Atan2(y, x) / Math.PI;
  }
}

若要確定該物件應放置在手機的螢幕上的位置,從 GetAngleOffsets 方法獲得的角度需要乘以一個常數,您選擇的圓弧度每圖元數。 我較早前建議此常數應等於 25,當手機舉行 6 英寸從你的臉,但你可能想要去的東西較低,提供更廣闊的視野。

查看從裡面球

ViewHorizontalCoordinates 程式將其 PIXELS_PER_DEGREE 常數設置為 15 顯示水準座標從裡面找出,如中所示圖 5。 當電話點有點東、 南部有點地平線之上,該特定視圖時發生。

The ViewHorizontalCoordinates Program
圖 5 ViewHorizontalCoordinates 程式

為激發動作感應器的每個 CurrentValueChanged 事件,該事件處理常式開始通過獲取指示如何,地球是面向與手機的旋轉矩陣。 它將,轉換為 HorizontalCoordinate 的值,並設置視圖中心以前創建的 HorizontalCoordinateProjection 物件中:

Microsoft.Xna.Framework.Matrix matrix =
  args.SensorReading.Attitude.RotationMatrix;
HorizontalCoordinate viewCenter =
  HorizontalCoordinate.FromMotionMatrix(matrix);
coordinateProjection.SetViewCenter(viewCenter);
rotate.Angle = -viewCenter.Tilt;

旋轉物件是應用於整個畫布 RotateTransform。 該處理常式然後實現幾個迴圈涉及高度和方位在 15 ° 的增量值。 CurrentValueChanged 事件觸發時,第一次的事件處理常式創建所有必要的線和 TextBlock 元素,並將它們添加到畫布上。 第二次和其後的時間,通過,該處理常式只需訪問現有的線與 TextBlock 元素已經在畫布上,並設置新的點。

HorizontalCoordinate 的每個值需要轉換為螢幕座標。 這就是工作中的 CalculateScreenPoint 方法的圖 6,HorizontalCoordinateProjection 在調用 GetAngleOffsets 方法和相乘的 PIXELS_PER_DEGREE 常數的角度。

圖 6 計算水準座標從螢幕點

Point CalculateScreenPoint(HorizontalCoordinate horizontalCoordinate)
{
  double horzAngle, vertAngle;
  coordinateProjection.GetAngleOffsets(horizontalCoordinate,
                                       out horzAngle, out vertAngle);
  // Use NaN to indicate points clearly out of range of the screen
  float x = float.NaN;
  float y = float.NaN;
  if (horzAngle > -90 && horzAngle < 90 && 
     vertAngle > -90 && vertAngle < 90)
  {
    x = (float)(width / 2 + PIXELS_PER_DEGREE * horzAngle);
    y = (float)(height / 2 + PIXELS_PER_DEGREE * vertAngle);
  }
  return new Point(x, y);
}

GetAngleOffsets 方法總是返回角度範圍介於-180 ° 到 180 °。 有時線跨越這些限制,這將創建一個自動換行的問題。 例如,一條線可能 (在理論上) 從擴展-175 ° 到 175 度。 該行應僅 10 ° 的長度,但計算的長度會 380 ° ! CalculateScreenPoint 涉及 NaN ("不是數位") 中的邏輯更正此標記的角度偏移量小於-90 ° 的所有點的問題或大於 90 °,超出螢幕的範圍。

我想要顯示的海拔高度角可見的方位,無論文字標籤和你那些顯示指南針點可見無論怎樣高或低點的電話。 海拔高度標籤的顯示幕幕點從視圖中心方位,計算和羅盤的標籤顯示幕幕點從視圖的中心高度,所以他們不要所有群集在一起當您指向電話直接向上或向下的小調整計算。 這個小把戲有助於保持在螢幕上,或許有點旋轉中心內的標籤。

切換到新華社

下個月了工作上配合此列具有 AstroPhone 的程式,我開始注意到某些性能問題。 ViewHorizontalCoordinates 程式只能管理約 10 幀每秒對我發展的電話,這個問題似乎更多在 Silverlight 佈局系統中,而不是在我的代碼。

有些不情願,我決定的其它程式將目標 Windows Phone XNA 框架而不是 Silverlight。 這是 ViewThreeCoordinates 專案,它是與 ViewHorizontalCoordinates 類似,但書面新華社,而不是 Silverlight 的理由。

庫預覽

ViewThreeCoordinates 專案還揭示了一些我會為全面爆發天文學程式使用的策略。 它使用一個名為 Petzold.Astronomy 的大庫的一部分。 在構建此庫,我主參照已由讓 · Meeus (蟎鈴,1998年)"天文演算法"的經典著作的第二版。

位置天文學需要大量的三角。 在 Petzold.Astronomy 庫中,我試著通過實施一個名為角的結構避免混亂和度和弧度之間的轉換。 您可以創建從學位或使用 FromDegree 或 FromRadian 的靜態方法,弧度的角度值,並得到學位或弧度為單位),但它沒有又往往是必要的因為角度還實現了所有必要的三角功能作為屬性。

例如,如果您有一個名為 myAngle 的角度值,您可以獲得該角度的余弦值如下所示:

double x = myAngle.Cosine;

如果您認為正弦和余弦切線作為"屬性"的角度,這完全合乎情理。 但通知的余弦值屬性如何實施:

public double Cosine
{
  get { return Math.Cos(radians); }
  set { radians = Math.Acos(value); }
}

Set 訪問器是反余弦函數,這意味著您可以將現有的角度值設置為使用這樣的語句數的反余弦值:

myAngle.Cosine = x;

這一過程並不十分工作的地方唯一的地方是在執行基本的 Atan2 方法。 我開始用一個靜態方法,它創建一個角度值:

public static Angle ArcTangent(double y, double x)
{
  return Angle.FromRadians(Math.Atan2(y, x));
}

赤道座標

ViewThreeCoordinates 程式在綠色,再加上兩個位置天文學中非常有用其它坐標系中顯示水準座標:在紅色的藍色和黃道座標中的赤道座標。 圖 7典型顯示指向北和海拔為 25 ° 的電話。 (是的我知道螢幕很混亂,但是您可以點擊螢幕顯示只有一個或兩個集的座標。

The ViewThreeCoordinates Display
圖 7 ViewThreeCoordinates 顯示

隨著地球繞軸自轉和繞著太陽,地球的赤道呆差不多在同一平面。 地球平面是赤道的赤道座標與相關聯的基本平面。 赤道座標組成的衰落 — — 赤道上空正值和負值下面 — — 與在赤道周圍會權提升。 右阿森松通常被指定的時間,而不是度,每小時等於 15 °。

當然,地理座標 (經度和緯度) 也基於地球的赤道,但地理座標旋轉與地球赤道座標是相對於宇宙,其餘固定和因此似乎把地球在旋轉的軸上。 恒星的位置被指定在赤道座標中,他們不能改變很多隨著時間的推移。

ViewThreeCoordinates 通過將它們轉換為水準座標顯示赤道座標的網格。 這種轉換取決於觀察者的地理位置 (經度和緯度) 和目前時間,並在 HorizontalCoordinate 結構中實施。

然而,權利提升到方位非常粗糙轉換是可行的:春分日午夜當地時間 (3 月 20 日左右)、 0 小時右提升是北 (方位的 0 °)。 明亮的星昴赤經約 14 個小時,等該日期,那時候,你需要擺動西進 210 ° (或由 150 ° 東) 以查看它。 或者,您可以只是等待直到 2 上午兩個小時 和昴南將到期。

您可以通過減去其權提升從當地時間的午夜以來的小時數來計算的一顆星的地方時角。 轉換度乘以 15,並添加的天數,自 3 月 21,和該測量從北東恒星的方位。

如果您運行 ViewThreeCoordinates 和赤道北極的夜晚天空握手機 (可見非常頂部的圖 7) 將對應的北極星,北明星,已經非常接近 90 ° 的偏差,因此相符的地球中軸向量的位置。 請注意如何北的方位線相交的極點。

黃道座標

所有的太陽系的行星的軌道大致在同一平面。 這架飛機被稱為黃道,,它是黃道座標 (也稱為天體座標),以紅色顯示的 ViewThreeCoordinates 的基礎。 黃道座標由黃道經度和緯度黃道組成。

黃道座標大多用於計算太陽、 行星和月亮的位置時。 因為太陽和行星躺在大約同一平面,這些物件的黃道緯度通常是接近于零。 黃道本身將顯示一條厚厚的在 ViewThreeCoordinates 中的紅線。 如果你拿到白天或夜晚的天空、 太陽和行星電話應配合那條線。

赤道座標和黃道座標純粹由於地球傾斜的約 23 ° 與黃道面而有所不同。 0 小時右阿森松和 0 ° 赤緯赤道座標 0 ° 經度和緯度 0 °,赤道座標相同,這兩個系統也正好在 180 °。

在春分點,太陽已 0 ° 黃道經度。 那經度增加大約 1 ° 每日過去的一年。 因此,以度為單位,太陽的黃道經度是大約等於自 3 月 21 日的天數。

黃道經度通常標有星座,開始為 0 °-30 ° 的白羊座、 金牛座為 30 ° 60 °、 60 °-90 °,等等通過為 330 °-360 ° 的雙魚座的雙子星座。 我也做過這在 ViewThreeCoordinates 中。 這些星座是零的大約位於黃道附近緯度與這些黃道經度的星座。 因此,太陽就是"在白羊座 」 (白羊座是超越太陽的意思) 在 3 月 21 日開始的一個月。

理論已經足夠。 在此列中的下一個外觀中的格線的球面座標系統將替換為太陽、 月亮、 行星、 恒星和星座。

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

由於下面的技術專家,檢討這篇文章:音莫爾斯