Meilleur auteur de réponses
Application visé de satellites en réalité augmenté

Question
-
Bonjour à tous,
Je développe une application qui permet de "voir" (viser) les satellites dans le ciel en utilisant la caméra de votre wp7. Le principe est simple, selon vos coordonnées GPS, mon application calcul l'azimut (orientation Nord Sud Est Ouest) et l’élévation (par rapport à l'horizon, levez les yeux ^^) du satellite.
J'ai d'abord essayer d'utiliser l'API Motion de façon brute mais j'ai rencontrer un problème dû aux axes de rotation du téléphone. Je m'explique.
Dans l'API Motion, il y a les propriétés Pitch, Yaw et Roll, qui représente les 3 axes possibles de rotation. Je me sert du Yaw comme d'une boussole pour obtenir la direction vers laquelle regarde l'utilisateur mais en tenant le téléphone en mode paysage la moindre rotation trompe la "boussole" du téléphone.
Par la suite j'ai trouver un tuto vidéo (Windows Phone Mango Augmented Reality Tutorial) qui explique comment utiliser "viewport et matrix" de XNA afin d'obtenir un affichage bien plus réaliste. Mon problème cette fois, est que je n'arrive pas définir l’élévation de mon satellite. Il reste sur l'horizon. Et la direction n'est pas convaincante non plus, bien que le problème de boussole n'apparait plus.
Ma question est la suivante :
Je voudrai un moyen de placer mon image de satellite en fonction de l'azimut (la direction 168°S par exemple) et l'élévation (33°, 0° étant l'horizon et 90° le pigeon placer juste au dessus de votre tête prêt à faire la grosse commission).
Si quelqu'un à une idée, une piste, quelque chose, plz help me...
Voici mon code :
using System; using System.Collections.Generic; using System.Device.Location; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using AppsLah; using Microsoft.Devices; using Microsoft.Devices.Sensors; using Microsoft.Phone.Controls; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Satellite.Models; using Matrix = Microsoft.Xna.Framework.Matrix; namespace Satellite.Views.Tools { public partial class Page : PhoneApplicationPage { PhotoCamera camera; GeoCoordinateWatcher geoWatcher; Motion motion; Viewport viewport; Matrix projection; Matrix view; int WCSRadius = 10; // je ne sais pas à quoi cela sert List<Vector3> pointsC; // liste des points cardineaux List<UIElement> POIs; // liste des objets graphique des points cardineaux List<Vector3> pointsS; // liste des points satellites List<UIElement> SATs; // liste des objets graphique des points satellites bool MotionIsStart = false; Data data; // regroupe les infos dont j'ai besoin UserCoordinates userCoord; // coordonnées GPS de l'utilisateur List<SatelliteParameters> listSatParam = null; // liste de satellites avec les parametres azimut elevation... public Page() { InitializeComponent(); pointsC = new List<Vector3>(); POIs = new List<UIElement>(); data = new Data(); userCoord = new UserCoordinates(); listSatParam = new List<SatelliteParameters>(); pointsS = new List<Vector3>(); SATs = new List<UIElement>(); } public void InitViewport() { viewport = new Viewport(0, 0, (int)this.ActualWidth, (int)this.ActualHeight); float aspect = viewport.AspectRatio; projection = Matrix.CreatePerspectiveFieldOfView(1, aspect, 1, 200); view = Matrix.CreateLookAt(Vector3.UnitZ, Vector3.Zero, Vector3.UnitX); } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { camera = new PhotoCamera(); ViewfinderBrush.SetSource(camera); SetGeoWatcher(); base.OnNavigatedTo(e); } void SetGeoWatcher() { geoWatcher = new GeoCoordinateWatcher(); geoWatcher.MovementThreshold = 20; geoWatcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(geoWatcher_PositionChanged); geoWatcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(geoWatcher_StatusChanged); try { geoWatcher.Start(); } catch (Exception ex){} } void geoWatcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e) { Dispatcher.BeginInvoke(() => { if (e.Status == GeoPositionStatus.Ready) { // quand j'ai une position, plus besoin du GPS geoWatcher.Stop(); } }); } void geoWatcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) { // je récupere les coordonnées userCoord.uLatitude = e.Position.Location.Latitude; userCoord.uLongitude = e.Position.Location.Longitude; // en fonction des coordonnées, je calcul les parametres des satellites listSatParam = CalculateAllSatellitePosition(userCoord, data.satList); if (!MotionIsStart) SetMotion(); } void SetMotion() { if (Motion.IsSupported) { motion = new Motion(); motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20); motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged); motion.Start(); addSatPosts(); } else { MessageBox.Show("Motion api not supported"); NavigationService.Navigate(Satellite.MainPage.GetUri()); } } void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e) { Dispatcher.BeginInvoke(() => { if (viewport.Width == 0) InitViewport(); // comme le telephone est en mode payasage, on applique une rotation de 90° // sur les les valeurs retourner par le telephone Matrix attitude = Matrix.CreateRotationX(MathHelper.PiOver2) * e.SensorReading.Attitude.RotationMatrix; // pour les points cardineaux for (int i = 0; i < pointsC.Count; i++) { // for each of WCS points, wa need to convert it to XNA coordinates Matrix world = Matrix.CreateWorld(pointsC[i], Vector3.UnitZ, Vector3.UnitX); //need to project it from 3D space in wcs to 2D space on the screen coordinates //need to rotate back for phone Vector3 projected = viewport.Project(Vector3.Zero, projection, view, world * attitude); // est-ce que l'objet est visible à l'écran // mais pourquoi projected.Z ?? if (projected.Z > 1 || projected.Z < 0) { POIs[i].Visibility = System.Windows.Visibility.Collapsed; } else { POIs[i].Visibility = System.Windows.Visibility.Visible; //on veut centrer l'objet graphique à afficher TranslateTransform tt = new TranslateTransform(); tt.X = projected.X - (POIs[i].RenderSize.Width / 2); tt.Y = projected.Y - (POIs[i].RenderSize.Height / 2); POIs[i].RenderTransform = tt; } } // pour les satellites for (int i = 0; i < pointsS.Count; i++) { // for each of WCS points, wa need to convert it to XNA coordinates Matrix world = Matrix.CreateWorld(pointsS[i], Vector3.UnitZ, Vector3.UnitX); //need to project it from 3D space in wcs to 2D space on the screen coordinates //need to rotate back for phone Vector3 projected = viewport.Project(Vector3.Zero, projection, view, world * attitude); // est-ce que l'objet est visible à l'écran // mais pourquoi projected.Z ?? if (projected.Z > 1 || projected.Z < 0) { SATs[i].Visibility = System.Windows.Visibility.Collapsed; } else { SATs[i].Visibility = System.Windows.Visibility.Visible; //on veut centrer l'objet graphique à afficher TranslateTransform tt = new TranslateTransform(); tt.X = projected.X - (SATs[i].RenderSize.Width / 2); tt.Y = projected.Y - (SATs[i].RenderSize.Height / 2); SATs[i].RenderTransform = tt; } } }); } void addSatPosts() { // on ajoute les points cardineaux à la liste à afficher // à quoi sert le WCSRadius ? // comment fonction cette méthode AngleToVector(inRadian, inRadius) addLabel(ARHelper.AngleToVector(0, WCSRadius), "N"); addLabel(ARHelper.AngleToVector(90, WCSRadius), "E"); addLabel(ARHelper.AngleToVector(180, WCSRadius), "S"); addLabel(ARHelper.AngleToVector(270, WCSRadius), "W"); // meme chose mais de manière plus décomposé for (int i=0; i<listSatParam.Count; i++) { // la je place l'azimuth, mais comment faire pour l'élévation ? pointsS.Add(ARHelper.AngleToVector(listSatParam[i].azimuth, 10)); } SATs.Add(AstraView); SATs.Add(HotbirdView); SATs.Add(AtlanticbirdView); } void addLabel(Vector3 position, string name) { TextBlock tb = new TextBlock(); Border b = new Border(); b.Child = tb; tb.Text = name; b.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; b.VerticalAlignment = System.Windows.VerticalAlignment.Top; tb.FontSize = 30; tb.Foreground = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 255, 255, 255)); b.Background = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 0, 0, 0)); b.SetValue(Canvas.ZIndexProperty, 2); b.Visibility = System.Windows.Visibility.Collapsed; LayoutRoot.Children.Add(b); pointsC.Add(position); POIs.Add(b); } } }
Les commentaires en anglais sont les parties de code que je ne comprends pas réellement, en français c'est de moi et là où il n'y a pas de commentaire c'est que ce n'est pas nécessaire.
Mon problème encore une fois, afficher les satellites en utilisant l'azimut (la direction au sol, rotation droite gauche, tourner sur soi-même) l'élévation (l'inclinaison du téléphone, il pointe vers le ciel ou au sol).
J'espere avoir été clair dans mon explication, n'hésitez pas à me poser des question s'il y a des points incompris.
Merci d'avance.
Un jeune développeur WP7
- Type modifié Ciprian Duduiala lundi 28 mai 2012 06:44 pas de solution complète
- Type modifié Snake007 lundi 16 juillet 2012 14:40 trompé
lundi 21 mai 2012 14:18
Réponses
-
J'ai matté un peu le framework, voila ce que je pense
public static Vector3 AngleToVector(double inAngle, double inRadius) { double num = ARHelper.DegreeToRadian(inAngle - 90.0); return new Vector3((float)Math.Round(inRadius * Math.Cos(num)), 0.0f, (float)Math.Round(inRadius * Math.Sin(num))); }
Ton attitude est juste ici : 0.0f, à toi d'ajouter un paramètre à AngleToVector avec l'altitude et de trouver le bon ratio pour convertir ta données (sachant que la terre est ronde, il faudra prendre en compte le différenciel d'altitude selon la distance.
public static Vector3 AngleToVector(double inAngle, double inRadius,double altitude) { double num = ARHelper.DegreeToRadian(inAngle - 90.0); return new Vector3((float)Math.Round(inRadius * Math.Cos(num)), ComputeAltitude(inRadius,altitude), (float)Math.Round(inRadius * Math.Sin(num))); }
a toi d'implémenter ComputeAltitude maintenant
S'il vous plaît n'oublier pas de marquer la ou les réponses qui aident à résoudre votre problème. Pour que la discussion puisse être marquée comme résolue
- Modifié rudyhuynMVP lundi 21 mai 2012 23:47
- Proposé comme réponse Ciprian Duduiala mardi 22 mai 2012 07:02
- Marqué comme réponse Snake007 lundi 16 juillet 2012 14:41
lundi 21 mai 2012 23:46
Toutes les réponses
-
Bonjour,
Il existe une librairie vraiment bien pour la réalité augmentée, elle est prévue pour les choses autour de soit, mais en regardant de plus pret ou en bidouillant un peu tu dois pouvoir regarder des satelites en l'air : http://gart.codeplex.com/
lundi 21 mai 2012 15:20 -
Tu ne trouveras pas ton bonheur, ni dans ton sample, ni dans gart que te conseille benjamin.
Ces frameworks sont orienté "map" sans gestion de l'altitude, la composante Y sert dans ces toolkit à représenter la distance (plus un objet est loin, plus il sera affiché haut, plus il est près, plus il est bas), on est nullement dans une problématique d'altitude.
Je ne vois pas d'autre alternative pour toi que de rentrer vraiment dans le code et de réviser tes espaces vectoriels, bon courage à toi!
S'il vous plaît n'oublier pas de marquer la ou les réponses qui aident à résoudre votre problème. Pour que la discussion puisse être marquée comme résolue
lundi 21 mai 2012 23:39 -
J'ai matté un peu le framework, voila ce que je pense
public static Vector3 AngleToVector(double inAngle, double inRadius) { double num = ARHelper.DegreeToRadian(inAngle - 90.0); return new Vector3((float)Math.Round(inRadius * Math.Cos(num)), 0.0f, (float)Math.Round(inRadius * Math.Sin(num))); }
Ton attitude est juste ici : 0.0f, à toi d'ajouter un paramètre à AngleToVector avec l'altitude et de trouver le bon ratio pour convertir ta données (sachant que la terre est ronde, il faudra prendre en compte le différenciel d'altitude selon la distance.
public static Vector3 AngleToVector(double inAngle, double inRadius,double altitude) { double num = ARHelper.DegreeToRadian(inAngle - 90.0); return new Vector3((float)Math.Round(inRadius * Math.Cos(num)), ComputeAltitude(inRadius,altitude), (float)Math.Round(inRadius * Math.Sin(num))); }
a toi d'implémenter ComputeAltitude maintenant
S'il vous plaît n'oublier pas de marquer la ou les réponses qui aident à résoudre votre problème. Pour que la discussion puisse être marquée comme résolue
- Modifié rudyhuynMVP lundi 21 mai 2012 23:47
- Proposé comme réponse Ciprian Duduiala mardi 22 mai 2012 07:02
- Marqué comme réponse Snake007 lundi 16 juillet 2012 14:41
lundi 21 mai 2012 23:46 -
Merci Rudyhuyn,
C'est une bonne piste que tu viens de me fournir. A force d'avoir le nez dans le code, je n'y voyais plus très clair.
J'ai encore quelques questions.
public static Vector3 AngleToVector(double inAngle, double inRadius) { double num = ARHelper.DegreeToRadian(inAngle - 90.0); // soustraction ? mode portrait à paysage ? return new Vector3((float)Math.Round(inRadius * Math.Cos(num)), 0.0f, (float)Math.Round(inRadius * Math.Sin(num))); }
Pourquoi soustraire 90° à l'angle ? Est-ce pour compenser l'utilisation du téléphone en mode paysage ?
A quoi correspond la variable inRadius ?Merci
mardi 22 mai 2012 08:33 -
oui tout à fait !
S'il vous plaît n'oublier pas de marquer la ou les réponses qui aident à résoudre votre problème. Pour que la discussion puisse être marquée comme résolue
mardi 22 mai 2012 08:41