Dieser Artikel wurde maschinell übersetzt.

Touch and Go

Virtuelle Welten mit Windows Phone entdecken

Charles Petzold

Charles PetzoldSeitdem ich den Bewegungssensor Windows Phone 7.1 kennen lernte, habe ich genau das, was ich tun wollte bekannt: c# positionelle Astronomie Code schrieb ich vor etwa fünf Jahren wiederbeleben und Draht, es oben mit Motion Sensor Logik in ein Windows Phone-Programm.Ein solches Programm würde mir das Telefon an einem Ort in den Nachthimmel, die Planeten und Konstellationen, die dort angesiedelten zeigen darauf erlauben.

Das Programm — mit den lächerlichen Namen AstroPhone — kommt in der nächsten Ausgabe dieser Rubrik.Inzwischen ist einige konzeptionelle, mathematischen und programmatischen Grundlagen notwendig.

Wie ich in früheren Artikeln diskutiert habe, der Bewegungsmelder konsolidiert Eingabe von Kompass, Beschleunigungssensor, Gyroskop und GPS und berechnet (unter anderem) eine 3D-Drehung-Matrix, die die Telefon Orientierung im Raum beschreibt.Es ist zweckmäßig, diese Matrix für ein 3D Vektor relativ zum Koordinatensystem des Telefons gelten.Diese transformierten Vektor verweist auf einen Speicherort auf der konzeptionellen Himmelskugel.Eine Position auf diesem Gebiet ist eine horizontale Koordinate, bestehend aus einer Höhe — einen Winkel oberhalb oder unterhalb des Betrachters Horizont — und ein Azimut, das ist im Grunde eine Kompassrichtung.

Horizontale Koordinaten sind analog zu den vertrauten geographischen Koordinaten, die eine Position auf der Oberfläche der Erde zu identifizieren.Die Höhenlage oberhalb oder unterhalb des Betrachters Horizont ist analog zu einem Breitengrad oberhalb oder unterhalb der Erdoberfläche Äquator.Das Azimut, der angibt, eine Kompassrichtung um Horizont des Betrachters ist analog zu den Längengrad um Äquator der Erde.Wie Sie sehen werden, sind alle Arten von Kugelkoordinaten grundlegend identisch, unterscheiden sich die meisten entscheidend durch das Flugzeug, das die obere Hemisphäre von der unteren trennt.

Abflachung der Sphäre

Im Artikel des letzten Monats (msdn.microsoft.com/magazine/jj553520), ich wurde gezeigt, wie Sie mit horizontale Koordinaten großformatige Fotos und andere Bilder durchsuchen durch Ändern des Telefons Orientierung im Raum.Jedoch "betrogen das Programm" ein bisschen von die wahre Natur der Kugelkoordinaten einfach zu ignorieren.Es weigerte sich, bestätigen die Tatsache, dass Kreise Breitengrad zunehmend kleiner zum oberen und unteren Rand der Himmelskugel werden, und Grade der Azimut werden daher zunehmend komprimiert.

Ein Programm, eine simulierte Betrachtung des Sternenhimmels bietet, nehmen Sie können nicht einfach diese Verknüpfungen.Es muss eine algorithmische Weg der Flachbildschirm des Telefons eine Fläche von der Himmelskugel zuordnen finden.Natürlich ist die Abflachung der Kugel ein Problem Mapmaker für Jahrhunderte gewesen.Es kann nicht getan werden, ohne Verzerrung, aber Ziel ist es, diese Störungen zu minimieren.

Abbildung 1 zeigt eine Kugel verziert mit Zeilen Höhe und Azimut jeder 15 °.Von einem Aussichtspunkt in der Mitte der Innenseite der Kugel stellt der red Dot einen Punkt, den Sie anzeigen oder auf mit Ihrem Handy zeigen.Die Höhe dieses bestimmten Punktes ist 25 °.Das Azimut hängt wo Sie zählen beginnen und in welche Richtung.

A Point (in Red) on a Celestial Sphere
Abbildung 1 Punkt (in rot) einer Himmelskugel

Dieser Punkt nennen wir den "Ansichtmittelpunkt", weil es der Punkt ist, der in die Mitte des Telefons Bildschirm zugeordnet werden.Welche Linien auf der Kugel zu den Rändern des Bildschirms entsprechen?

Es ist verlockend, die davon ausgehen, dass die Kanten des Telefons Bildschirm Zeilen Höhe und Azimut entspricht.Aber das scheint nur vernünftig an Orten nahe dem Horizont.Das Konzept beginnt zu bröckeln, als der Ansichtmittelpunkt weiter von den Horizont ruft, und insgesamt, wenn reduziert Sie sind gerade nach oben oder unten an den Polen anzeigen.

Stattdessen wollen wir konstruieren orthogonal "große Kreise" in der Mitte der Ansicht, wie in Abbildung 2.

Orthogonal Great Circles Crossing the View Center
Abbildung 2 orthogonale große Kreise überqueren den Ansichtmittelpunkt

Große Kreise sind ein wichtiges Konzept in Sphärische Geometrie.Ein Großkreis ist ein zweidimensionales Kreis im 3D-Raum teilen die gleichen Radius und Zentrum als die Kugel selbst.Große Kreise auf der Kugel sind analog zu geraden Linien auf einer Ebene, da sie die kürzeste Entfernung zwischen zwei Punkten darstellen.Linien der Azimut (und Länge) sind große Kreise.Linien der Höhe (und Breitengrad) sind nicht; Sie sind stattdessen "kleine Kreise," mit Ausnahme der Kreis, der die Kugel in zwei teilt — den Horizont (oder Äquator).

Der rote Kreis Groß in Abbildung 2 verläuft durch die beiden Pole und ist einfach eine Azimut-Linie.Die blauen Großkreis durchquert Horizont bei Azimute 90 ° von der Azimut des Ansicht-Center.

Einem Rechteck, in dieser Ansicht-Zentrum wird die Telefon Bildschirm zugeordnet werden.Dieses Rechteck kann im Prinzip ein Raster von großen Kreise sein.Wir konstruieren zwei weitere große-Kreise in blau, die den Horizont an der gleichen Stelle wie die erste kreuzen.Und lassen Sie uns zwei weitere rote große Kreise, die auch zwei Punkte mit der ersten Teilen zu konstruieren.Das Ergebnis ist in Abbildung 3 dargestellt.Die gemeinsamen Punkte der rote große Kreise haben den gleichen Azimut als den Ansichtmittelpunkt (oder das Azimut plus 180 °), aber die Höhe ist um 90° versetzt.

Additional Great Circles to Create a Rectangular Area
Abbildung 3 zusätzliche große Kreise um einen rechteckigen Bereich erstellen

Die zusätzliche große Kreise definieren die Kanten eines Rechtecks, das entspricht dem Hochformat Bildschirm des Telefons, mit einer Breite von ca. 19 ° Bogen und eine Höhe von 32 ° Bogen.Wenn Sie davon ausgehen, dass die Telefon Bildschirm ca. 2 cm breit und 3,33 Zentimeter hoch ist, sind diese Bogen Grade geeignet, wenn die Handy-Displays etwa 6 Zentimeter von Ihrem Gesicht gehalten wird.Die Handy-Displays ist 480 Pixel breit und 800 Pixel hoch, so dass diese Nummern auch 25 Pixel pro Bogen Grad bedeuten.

Wenn Sie diese Projektion-Regelung in einem Algorithmus implementieren, müssen Sie rückwärts arbeiten: Denken Sie an die beiden Punkte geteilt durch die drei blaue große Kreise als Achse und die beiden Punkte geteilt durch die drei roten großen Kreise als eine andere Achse.Diese bilden zusammen mit der Vektor des Ansicht-Center eine orthonormale-Koordinatensystem.

Vektor-Algebra kann Winkel Offsets von jeder anderen Koordinate aus dem Ansicht-Center, ableiten, wie gezeigt in der HorizontalCoordinateProjection-Klasse in Abbildung 4.Die Klasse verfügt über eine Methode, um den Ansichtmittelpunkt festzulegen, und eine andere Methode, Winkel-Offsets für die horizontale Koordinate eines anderen Objekts relativ zu dieser Ansicht Zentrum zu erhalten.

Abbildung 4 die HorizontalCoordinateProjection-Klasse

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

Um festzustellen, wo das Objekt auf dem Bildschirm positioniert werden soll, müssen die Winkel, gewonnen aus der GetAngleOffsets-Methode mit einer Konstanten multipliziert werden, die Sie für die Anzahl der Pixel pro Bogen Grad auswählen. Ich schlug bereits, dass diese Konstante 25 gleich sollte, wenn das Telefon ist 6 Zentimeter von Ihrem Gesicht gehalten, aber vielleicht gehen mit etwas niedrigeren eine breitere Ansicht bereitstellen möchten.

Anzeigen der Sphäre von innen

Das ViewHorizontalCoordinates-Programm legt die PIXELS_PER_DEGREE-Konstante auf 15 horizontale Koordinaten von innen anzeigen suchen Sie heraus, wie in Abbildung 5. Dass bestimmte Ansicht tritt auf, wenn das Telefon ein wenig südlich von Osten, ein wenig über dem Horizont zeigt.

The ViewHorizontalCoordinates Program
Abbildung 5 das ViewHorizontalCoordinates-Programm

Für jedes CurrentValueChanged-Ereignis von der Bewegungsmelder ausgelöst beginnt der Ereignishandler durch den Erhalt der Drehmatrix, der angibt, wie die Erde relativ zu dem Telefon ausgerichtet ist. Es konvertiert, die in einen HorizontalCoordinate-Wert und setzt den Ansichtmittelpunkt in ein zuvor erstelltes HorizontalCoordinateProjection-Objekt:

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

Das Drehen-Objekt ist ein RotateTransform angewendet auf die gesamte Leinwand. Der Handler implementiert dann mehrere Schleifen, die Werte für Höhe und Azimut in 15 °-Schritten. Zum ersten Mal das CurrentValueChanged-Ereignis ausgelöst wird, der Ereignishandler erstellt alle notwendigen Linie und TextBlock-Elemente und fügt sie auf die Leinwand. Die zweiten und nachfolgenden Zeiten durch, der Handler einfach greift auf die bestehende Linie und TextBlock-Elemente bereits im Canvas und legt neue Punkte.

Jeder HorizontalCoordinate-Wert muss eine Bildschirmkoordinate konvertiert werden. Das ist die Aufgabe der CalculateScreenPoint Methode in Abbildung 6, die Ruft die GetAngleOffsets-Methode in HorizontalCoordinateProjection und die Winkel durch die PIXELS_PER_DEGREE-Konstante multipliziert.

Abbildung 6 Berechnung einen Bildschirm Punkt von einer horizontalen Koordinate

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);
}

Die GetAngleOffsets-Methode gibt immer Winkel im Bereich von-180 ° bis 180°. Manchmal Zeilen überspannen diese Grenzen und dadurch entsteht eine umlaufende Problem. Eine Linie kann z. B. (in der Theorie) von-175 ° bis 175 ° verlängern. Diese Zeile sollte nur 10 ° Länge, aber die berechnete Länge 380 ° wäre! Die Logik in CalculateScreenPoint einschließlich NaN ("not a Number") behebt dieses Problem – kennzeichnen Sie alle Punkte mit Versatz der Winkel kleiner als 90° oder größer als 90 °, die außerhalb des Bereichs des Bildschirms ist.

Ich wollte die Textbezeichnungen anzeigen die Höhe Winkel unabhängig von der Azimut angezeigt werden, und mit der Kompass-Punkte sichtbar, egal wie hoch oder niedrig sein, Sie zeigen das Telefon. Die Höhe-Bezeichnungen sind mit einem Bildschirm Punkt berechnet aus der Ansicht Zentrum Azimut angezeigt, und die Kompass Etiketten werden mit einem Bildschirm Punkt berechnet aus der Ansicht Zentrum Höhe, mit ein wenig Anpassung, so dass sie nicht alle Cluster zusammen, wenn Sie das Telefon gerade nach oben oder unten zeigen angezeigt. Dieser kleine Trick hilft die Bezeichnungen innerhalb der Bildschirm, vielleicht ein bisschen gedreht Weg von der Mitte zu halten.

Ein Wechsel zu XNA

Da ich an die Programme für diese Spalte in Verbindung mit AstroPhone für nächsten Monat arbeitete, begann ich zu bemerken, einige Performance-Probleme. Das ViewHorizontalCoordinates-Programm kann nur etwa 10 Frames pro Sekunde auf meinem Handy Entwicklung verwalten, und das Problem scheint eher in der Silverlight-Layoutsystem anstatt in meinem Code.

Mit etwas Widerwillen habe ich beschlossen, dass die restlichen Programme anstelle von Silverlight die Windows Phone XNA-Framework abzielen würde. Dies ist der Fall für das ViewThreeCoordinates-Projekt, das ähnlich wie ViewHorizontalCoordinates aber für XNA anstatt Silverlight geschrieben ist.

Bibliothek-Vorschau

Das ViewThreeCoordinates-Projekt zeigt auch einige Strategien, die ich für das ausgewachsene Astronomie-Programm verwenden werde. Es nutzt Teil einer größeren Bibliothek namens Petzold.Astronomy. Beim Bau dieser Bibliothek, wurde meine primäre Referenz die zweite Auflage des klassischen Buches "Astronomischen Algorithmen" von Jean Meeus (Willmann-Bell, 1998).

Positionelle Astronomie erfordert viel Trigonometrie. Ich versuche in der Petzold.Astronomy Bibliothek Verwirrung und Konvertierungen zwischen Grad und Bogenmaß zu vermeiden, indem Sie implementieren eine Struktur namens Winkel. Sie können einen Winkelwert aus entweder einen Abschluss oder eine Radian mithilfe der statischen Methoden FromDegree oder FromRadian erstellen und erhalten den Grad oder Bogenmaß heraus, aber es ist nicht oft notwendig, da Winkel auch alle notwendigen trigonometrische Funktionen als Eigenschaften implementiert.

Beispielsweise wenn Sie einen Angle-Wert mit dem Namen MyAngle haben, erhalten Sie den Kosinus dieses Winkels wie folgt:

double x = myAngle.Cosine;

Wenn Sie als "Eigenschaften" der Winkel der Sinus, Kosinus und Tangente denken, macht dies durchaus Sinn. Aber beachten Sie wie die Kosinus-Eigenschaft implementiert wird:

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

Der Set-Accessor ist die inverse Kosinus-Funktion, was bedeutet, dass Sie einen vorhandenen Winkel zu den Arkuskosinus einer Zahl mit einer Anweisung wie folgt festlegen können:

myAngle.Cosine = x;

Der einzige Ort, wo dieser Prozess nicht ganz funktionierte, war die wesentliche Atan2-Methode implementieren. Ich habe es mit einer statischen Methode, die einen Winkelwert erstellt:

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

Äquatoriale Koordinaten

Das ViewThreeCoordinates-Programm zeigt horizontale Koordinaten in grün, sowie zwei andere Koordinatensysteme in positionellen Astronomie sehr nützlich: Äquatoriale Koordinaten in blau und ekliptikale Koordinaten in rot. Abbildung 7zeigt eine typische Anzeige mit dem Telefon zeigen Nord- und einer Höhe von 25 Grad. (Ja, ich weiß der Bildschirm ist unübersichtlich, aber Sie können den Bildschirm, um nur ein oder zwei Sätze von Koordinaten anzeigen tippen.)

The ViewThreeCoordinates Display
Abbildung 7 die ViewThreeCoordinates anzeigen

Wie die Erde um die eigene Achse dreht und dreht sich um die Sonne, bleibt der Erde Äquator ziemlich genau in der gleichen Ebene. Die Ebene des Äquators der Erde ist die grundlegende Ebene Äquatoriale Koordinaten zugeordnet. Äquatoriale Koordinaten bestehen aus einer Deklination — über dem Äquator positive und negative unten — und eine Rektaszension gehen um den Äquator. Die Rektaszension wird in der Regel angegeben in Stunden anstatt in Grad, wo jede Stunde 15 ° entspricht.

Natürlich geographische Koordinaten (Längen- und Breitengrad) basieren ebenfalls auf der Erde Äquator, aber geografische Koordinaten mit der Erde drehen, während Äquatoriale Koordinaten im Vergleich zum Rest des Universums fixiert sind, und folglich scheinen machen, wie die Erde um die eigene Achse dreht. Die Positionen der Sterne in Äquatoriale Koordinaten angegeben sind und sie nicht viel im Laufe der Zeit ändern.

ViewThreeCoordinates zeigt ein Raster von Äquatoriale Koordinaten von Rückkonvertierung in horizontalen Koordinaten. Diese Konvertierung wird hängt von seiner geographischen Lage (Längen- und Breitengrad) und die aktuelle Uhrzeit, und in der HorizontalCoordinate-Struktur.

Allerdings ist eine sehr grobe Konvertierung der Rektaszension in Azimut möglich: Um eine lokale Zeit Mitternacht auf der Frühlingstagundnachtgleiche (20. März oder so ungefähr), 0 Stunden, die richtige Ascension Norden ist (0 ° der Azimut). Der helle Stern Arcturus hat eine Rektaszension von etwa 14 Stunden, usw. dahin zu diesem Zeitpunkt müssen Sie schwingen westwärts von 210 ° (oder ostwärts von 150 °) zu sehen. Oder, Sie können nur warten, zwei Stunden, bis 02 und Arcturus ist Süden geschuldet.

Durch Subtraktion der Rektaszension aus der Anzahl der Stunden seit Mitternacht nach lokaler Zeit können Sie den lokalen Stunde Winkel eines Sterns berechnen. Konvertieren in Grad durch Multiplikation mit 15, und fügen Sie die Anzahl der Tage seit März 21, und dass das Azimut des Sterns gemessen nach Osten von Norden.

Wenn Sie ViewThreeCoordinates und halten Sie das Telefon bis zu den Nachthimmel, den nördlichen äquatorialen Pol (sichtbar an der Spitze der Abbildung 7) wird durch den Speicherort von Polaris, die North Star, hat eine Deklination von fast 90 ° und fällt somit mit der Vektor der Erdachse entsprechen. Beachten Sie, wie die Azimut-Linie von Norden, dass Pol schneidet.

Ekliptikale Koordinaten

Die Umlaufbahnen der Planeten des Sonnensystems sind ungefähr in der gleichen Ebene. Dieses Flugzeug wird Ekliptik genannt, und es ist die Grundlage der ekliptikale Koordinaten (auch bekannt als Himmelskoordinaten), die von ViewThreeCoordinates in rot angezeigt werden. Eine Ekliptik-Koordinate besteht aus einer Ekliptik Längen- und Breitengrad der Ekliptik.

Ekliptikale Koordinaten werden meist verwendet, wenn die Positionen von Sonne, Mond und Planeten zu berechnen. Da die Sonne und die Planeten in etwa der gleichen Ebene liegen, ist der Ekliptik Breitengrad dieser Objekte in der Regel nahe Null. Die Ekliptik selbst ist mit einer dicken roten Linie in ViewThreeCoordinates angezeigt. Wenn Sie halten sollte das Telefon am Tag oder Nacht-Himmel, die Sonne und Planeten mit dieser Zeile übereinstimmen.

Äquatoriale Koordinaten und ekliptikale Koordinaten unterscheiden sich nur aufgrund der Erde Neigung von ca. 23 ° gegenüber der Ekliptik. Eine Äquatoriale Koordinate 0 Stunden Rektaszension und 0 ° Deklination ist das gleiche wie eine Äquatoriale Koordinate 0 ° Längen- und Breitengrad 0 °, und die beiden Systeme auch bei 180° zusammenfallen.

Auf der Frühlingstagundnachtgleiche hat die Sonne eine ekliptikale Länge 0°. Längengrad erhöht sich um ca. 1 ° pro Tag im Laufe des Jahres. Daher ist die ekliptikale Länge der Sonne in Grad ungefähr gleich der Anzahl der Tage seit dem 21. März.

Ekliptik Längengrade werden oft mit den Zeichen des Tierkreises, beginnend mit Widder für 0 °-30 °, Taurus für 30 °-60 °, Gemini für 60 °-90 °, usw. durch Fische für 330 °-360 ° gekennzeichnet. Ich habe dies auch getan, in ViewThreeCoordinates. Diese Zeichen des Tierkreises sind Sternbilder, die etwa am diese Ekliptik Längengrade mit Ekliptik Breitengraden in der Nähe von NULL befinden. So, die Sonne steht "Widder" (d. h., die Aries jenseits der Sonne) im Laufe des Monats ab 21. März.

Genug Theorie. In der nächsten Darstellung dieser Spalte werden die Rasterlinien der sphärische Koordinatensysteme mit Sonne, Mond, Planeten, Sterne und Sternbilder ersetzt.

Charles Petzold ist eine langjährige Mitarbeit beim MSDN Magazin und ist derzeit sein klassisches Buch "Programming Windows" (Microsoft Press, 1998) für Windows 8 aktualisieren. Seiner Website lautet charlespetzold.com.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Donn Morse