• Main Page
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

D:/Projekt/ECF_trunk/examples/GPSpaceFlight/SpaceFlight.Simulation/TestCase.cs

00001 using System;
00002 using System.Collections.Generic;
00003 using System.IO;
00004 
00005 namespace SpaceFlight.Simulation
00006 {
00007   public struct Vector2D
00008   {
00009     public double X { get; set; }
00010     public double Y { get; set; }
00011 
00012     public double Length
00013     {
00014       get { return Math.Sqrt(X * X + Y * Y); }
00015     }
00016 
00017     public static double Angle(Vector2D first, Vector2D second)
00018     {
00019       if (first.Length != 0 && second.Length != 0)
00020       {
00021         double angle = Math.Atan2(second.Y, second.X) - Math.Atan2(first.Y, first.X);
00022         return Math.IEEERemainder(angle, 2 * Math.PI);
00023       }
00024       else
00025       {
00026         return 0;
00027       }
00028     }
00029 
00030     public static Vector2D operator +(Vector2D first, Vector2D second)
00031     {
00032       return new Vector2D
00033       {
00034         X = first.X + second.X,
00035         Y = first.Y + second.Y,
00036       };
00037     }
00038 
00039     public static Vector2D operator -(Vector2D first, Vector2D second)
00040     {
00041       return new Vector2D
00042       {
00043         X = first.X - second.X,
00044         Y = first.Y - second.Y,
00045       };
00046     }
00047 
00048     public static Vector2D operator *(double scalar, Vector2D vector)
00049     {
00050       return new Vector2D
00051       {
00052         X = scalar * vector.X,
00053         Y = scalar * vector.Y,
00054       };
00055     }
00056   }
00057 
00058   public class Planet
00059   {
00060     public Vector2D Position { get; set; }
00061     public double Radius { get; set; }
00062   }
00063 
00064   public class Ship
00065   {
00066     public Vector2D Position { get; set; }
00067     public Vector2D Velocity { get; set; }
00068     public double Angle { get; set; }
00069     public double Turn { get; set; }
00070 
00071     public Vector2D Direction
00072     {
00073       get { return new Vector2D { X = Math.Cos(Angle), Y = Math.Sin(Angle) }; }
00074     }
00075   }
00076 
00077   public interface IShipController
00078   {
00079     void UpdateShip(TestCase testCase, Vector2D gravity);
00080   }
00081 
00082   public class TestCase
00083   {
00084     public IList<Planet> Planets { get; private set; }
00085     public IList<Vector2D> Waypoints { get; private set; }
00086     public Vector2D StartingPosition { get; set; }
00087 
00088     public Ship Ship { get; set; }
00089     public int TimeSteps { get; set; }
00090     public int TargetWaypoint { get; set; }
00091 
00092     public bool IsActive { get; set; }
00093 
00094     public bool TraceMovement { get; set; }
00095     public IList<Vector2D> Trace { get; private set; }
00096 
00097     public TestCase()
00098     {
00099       Planets = new List<Planet>();
00100       Waypoints = new List<Vector2D>();
00101       Trace = new List<Vector2D>();
00102     }
00103 
00104     public void Reset()
00105     {
00106       Ship = new Ship
00107       {
00108         Position = StartingPosition,
00109         Velocity = new Vector2D(),
00110         Angle = Vector2D.Angle(new Vector2D { X = 1 }, Waypoints[0] - StartingPosition)
00111       };
00112       TimeSteps = 0;
00113       TargetWaypoint = 0;
00114       IsActive = true;
00115       Trace.Clear();
00116     }
00117 
00118     public void Simulate(IShipController controller, int steps)
00119     {
00120       for (int i = 0; i < steps && IsActive; ++i)
00121       {
00122         Simulate(controller);
00123       }
00124     }
00125 
00126     private void Simulate(IShipController controller)
00127     {
00128       Vector2D gravity = new Vector2D();
00129       foreach (Planet planet in Planets)
00130       {
00131         Vector2D distance = planet.Position - Ship.Position;
00132         if (distance.Length <= planet.Radius)
00133         {
00134           IsActive = false;
00135         }
00136         gravity += 15 * 0.001 * (Math.Pow(planet.Radius, 3) / Math.Pow(distance.Length, 3)) * distance;
00137       }
00138       Ship.Velocity += gravity;
00139 
00140       controller.UpdateShip(this, gravity);
00141       ++TimeSteps;
00142 
00143       const double MaxTurn = 2 * Math.PI / 25;
00144       Ship.Angle += Math.Max(-MaxTurn, Math.Min(MaxTurn, Ship.Turn));
00145 
00146       Ship.Velocity += 12 * 0.02 * Ship.Direction;
00147       Ship.Position += Ship.Velocity;
00148 
00149       double targetDistance = (Ship.Position - Waypoints[TargetWaypoint]).Length;
00150       if (targetDistance < 20)
00151       {
00152         ++TargetWaypoint;
00153         if (TargetWaypoint == Waypoints.Count)
00154         {
00155           IsActive = false;
00156         }
00157       }
00158       else if (targetDistance > 1500)
00159       {
00160         IsActive = false;
00161       }
00162 
00163       if (TraceMovement)
00164       {
00165         Trace.Add(Ship.Position);
00166       }
00167     }
00168 
00169     public static TestCase Load(string filename)
00170     {
00171       TestCase testCase = new TestCase();
00172       using (var stream = new StreamReader(filename))
00173       {
00174         string line;
00175         while ((line = stream.ReadLine()).Length != 0)
00176         {
00177           string[] parts = line.Split(' ');
00178           if (parts.Length != 3)
00179           {
00180             throw new Exception();
00181           }
00182           testCase.Planets.Add(new Planet
00183           {
00184             Position = new Vector2D { X = double.Parse(parts[0]), Y = double.Parse(parts[1]) },
00185             Radius = double.Parse(parts[2])
00186           });
00187         }
00188 
00189         while ((line = stream.ReadLine()).Length != 0)
00190         {
00191           string[] parts = line.Split(' ');
00192           if (parts.Length != 2)
00193           {
00194             throw new Exception();
00195           }
00196           testCase.Waypoints.Add(new Vector2D { X = double.Parse(parts[0]), Y = double.Parse(parts[1]) });
00197         }
00198 
00199         {
00200           line = stream.ReadLine();
00201           string[] parts = line.Split(' ');
00202           if (parts.Length != 2)
00203           {
00204             throw new Exception();
00205           }
00206           testCase.StartingPosition = new Vector2D { X = double.Parse(parts[0]), Y = double.Parse(parts[1]) };
00207         }
00208 
00209         if (stream.ReadToEnd().Trim().Length != 0)
00210         {
00211           throw new Exception();
00212         }
00213       }
00214 
00215       return testCase;
00216     }
00217 
00218     public static void Save(TestCase testCase, string filename)
00219     {
00220       using (var stream = new StreamWriter(filename))
00221       {
00222         foreach (Planet planet in testCase.Planets)
00223         {
00224           stream.WriteLine("{0:0} {1:0} {2:0}", planet.Position.X, planet.Position.Y, planet.Radius);
00225         }
00226         stream.WriteLine();
00227 
00228         foreach (Vector2D waypoint in testCase.Waypoints)
00229         {
00230           stream.WriteLine("{0:0} {1:0}", waypoint.X, waypoint.Y);
00231         }
00232         stream.WriteLine();
00233 
00234         stream.WriteLine("{0:0} {1:0}", testCase.StartingPosition.X, testCase.StartingPosition.Y);
00235       }
00236     }
00237 
00238     public static TestCase CreateRandom(int numPlanets, int numWaypoints)
00239     {
00240       Random random = new Random();
00241       TestCase testCase = new TestCase();
00242 
00243       testCase.StartingPosition = new Vector2D
00244       {
00245         X = 200 + random.NextDouble() * 600,
00246         Y = 200 + random.NextDouble() * 600
00247       };
00248 
00249       int tries = 0;
00250       while (testCase.Planets.Count != numPlanets && tries < numPlanets * 100)
00251       {
00252         Planet planet = new Planet
00253         {
00254           Position = new Vector2D
00255           {
00256             X = 100 + random.NextDouble() * 800,
00257             Y = 100 + random.NextDouble() * 800
00258           },
00259           Radius = 15 + random.NextDouble() * 15
00260         };
00261         ++tries;
00262 
00263         if (!IsTooClose(planet.Position, testCase, planet.Radius + 200))
00264         {
00265           testCase.Planets.Add(planet);
00266         }
00267       }
00268 
00269       tries = 0;
00270       while (testCase.Waypoints.Count != numWaypoints && tries < numWaypoints * 100)
00271       {
00272         Vector2D waypoint = new Vector2D
00273         {
00274           X = 100 + random.NextDouble() * 800,
00275           Y = 100 + random.NextDouble() * 800
00276         };
00277         ++tries;
00278 
00279         if (!IsTooClose(waypoint, testCase, 50))
00280         {
00281           testCase.Waypoints.Add(waypoint);
00282         }
00283       }
00284 
00285       return testCase;
00286     }
00287 
00288     private static bool IsTooClose(Vector2D position, TestCase testCase, double minDistance)
00289     {
00290       if ((position - testCase.StartingPosition).Length < minDistance)
00291       {
00292         return true;
00293       }
00294 
00295       foreach (Planet planet in testCase.Planets)
00296       {
00297         if ((position - planet.Position).Length - planet.Radius < minDistance)
00298         {
00299           return true;
00300         }
00301       }
00302 
00303       foreach (Vector2D waypoint in testCase.Waypoints)
00304       {
00305         if ((position - waypoint).Length < minDistance)
00306         {
00307           return true;
00308         }
00309       }
00310 
00311       return false;
00312     }
00313   }
00314 }

Generated on Tue Oct 23 2012 11:14:22 for ECF by  doxygen 1.7.1