Advertisement
SpaceEngineersAddict

Untitled

Apr 3rd, 2016
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 17.78 KB | None | 0 0
  1. int max_GFD = 3; // 3 is the minimum required for now. You can set it higher, but it may tax the server.
  2. int max_targets = 100; // this does not do anything for now. Be aware that having a high number of grids will lag  
  3. int asteroid_check = 18000; // check an asteroid every 15 minutes. Usually it will be hit by a random beam sooner.
  4. float max_dist = 100000; // this is a very long range, but it works. If you are afraid this causes lag, set it lower.
  5. double max_v = 120; //  this is used on a hit, to guess wether a target is the same target you were tracking.
  6.                                      // I set it to 120, because it seems possible to go over the 100 m/s limit.  
  7. double max_acc = 10; // This number is the maximum acceleration a ship is expected to have. Any higher than this
  8.                                      //and the lock may be lost when making a quick velocity change in the transverse direction.  
  9. int max_loop = 100;
  10. float max_beam_width = 1000;
  11.  
  12. void Main(string argument)  
  13. {  
  14.     if (argument == "reset") Storage = "";  
  15.     var gts = GridTerminalSystem;  
  16.     IMyRemoteControl rc = (IMyRemoteControl)gts.GetBlockWithName("Tracker Remote");  
  17.     IMyTextPanel asteroid_panel = (IMyTextPanel)gts.GetBlockWithName("Asteroid LCD");  
  18.     IMyTextPanel grid_panel = (IMyTextPanel)gts.GetBlockWithName("Grid LCD");  
  19.     IMyTextPanel target_panel = (IMyTextPanel)gts.GetBlockWithName("Target LCD");  
  20.     IMyTimerBlock timer = (IMyTimerBlock)gts.GetBlockWithName("Tracker Timer");  
  21.     IMyCockpit cockpit = (IMyCockpit)gts.GetBlockWithName("Cockpit");  
  22.     Vector3D rc_pos = rc.GetPosition();  
  23.  
  24.     double radius;  
  25.     Vector3D center = rc_pos;  
  26.     Matrix or, world_or;
  27.     // we use the orientation vectors below to print the target arrows on the target LCD
  28.     cockpit.Orientation.GetMatrix(out or);  
  29.     world_or = cockpit.WorldMatrix.GetOrientation();  
  30.    
  31.         Vector3D c_fwd  = Vector3D.Transform(or.Forward, MatrixD.Transpose(or));  
  32.         Vector3D c_up  = Vector3D.Transform(or.Up, MatrixD.Transpose(or));  
  33.         Vector3D c_right  = Vector3D.Transform(or.Right, MatrixD.Transpose(or));  
  34.  
  35.     Vector3D fwd_wrld = Vector3D.Transform(c_fwd, world_or);  
  36.         Vector3D up_wrld  = Vector3D.Transform(c_up, world_or);  
  37.         Vector3D right_wrld  = Vector3D.Transform(c_right, world_or);
  38.  
  39.     int GFD_tick = 0;  
  40.  
  41.     string[] target_strings = LoadStorage();  
  42.  
  43.     List<Target> targets = new List<Target>();  
  44.     char[] delim = {';'};  
  45.  
  46.     for (int i = 0; i < target_strings.Length; i++) {  
  47.         string[] tar = target_strings[i].Split(delim);  
  48.         targets.Add(new Target{time = int.Parse(tar[0])+1, countdown = int.Parse(tar[1])-1,  
  49.         radius = double.Parse(tar[2]), velocity = GetVector3D(tar[3]), coords = GetVector3D(tar[4]),  
  50.         stat = bool.Parse(tar[5]), grid = bool.Parse(tar[6])});    
  51.     }  
  52.    
  53.     for (int i = targets.Count-1; i > -1; i--) {  
  54.         if (targets[i].countdown < 1 && GFD_tick < max_GFD) { //we check if one of the tracked targets needs updating
  55.             Vector3D target = targets[i].coords + targets[i].velocity * targets[i].time - rc_pos;  
  56.             // we use the velocity to predict where the target has travelled across the sky.
  57.             target.Normalize();  
  58.             center = Lock3GFD(rc,rc_pos+target, max_dist, 0f, out radius);    
  59.             if (!center.IsValid()) { // if something went wrong and we get a bad result,  
  60.                                              // we count it as 3 GFD calls and remove the target from our list.  
  61.                 GFD_tick += 3;    
  62.                 targets.RemoveAt(i);  
  63.             }
  64.             else {  
  65.                 if (center == rc_pos) GFD_tick += 1; //the Lock3GFD method returns after 1 GFD call if it misses
  66.                 else {
  67.                     GFD_tick += 3;  //if Lock3GF hits, we count it a 3 GFD calls
  68.                     update_targetlist (targets,  rc_pos, center, radius);  // we only update when something is hit.
  69.                 }
  70.                 if (Math.Abs(radius- targets[i].radius) > 0.1 || (center-rc_pos).Length() < 1) targets.RemoveAt(i);
  71.                 // when the target is too close to be right or its radius is not correct, we remove the target.
  72.             }
  73.         }    
  74.     }  
  75.  
  76.     Random rnd = new Random();  
  77.  
  78.     //The while loop below shoots GFD beams into random directions to find new targets.  
  79.     //It uses spherical coördinates.  
  80.  
  81.     int loop_count = 0;
  82.  
  83.     while (GFD_tick < max_GFD-2 && loop_count < max_loop) { // we loop over the allowed number of GFD
  84.         loop_count++;                             // we take a maximum of 100 loops to prevent problems with the script
  85.         double theta = rnd.NextDouble() * 2 * Math.PI;  // theta is between 0 and 2 pi
  86.         double z = 2* rnd.NextDouble() -1;        // z is between -1 and 1
  87.         double z_fac = Math.Sqrt(1- Sq(z)); //the squareroot of 1 minus z-square    
  88.         double x = z_fac * Math.Cos(theta);
  89.         double y = z_fac * Math.Sin(theta);
  90.  
  91.         Vector3D rel_target = new Vector3D(x,y,z); //spherical coordinates transformed to cartesian.
  92.  
  93.         float beam_width = max_beam_width;
  94.         for(int i = 0; i < targets.Count; i++) { //this checks how wide the beam can be without crossing known targets
  95.             Vector3D target_dir = targets[i].coords - rc_pos;
  96.             float target_beam_width = (float)(rel_target.Cross(target_dir)).Length();
  97.             target_beam_width -=(float)targets[i].radius - 1;
  98.             if (target_beam_width < beam_width) beam_width = target_beam_width;
  99.             if (target_beam_width < 0) break;
  100.         }
  101.  
  102.         if (beam_width > 0) { // if the beam_width is negative it will hit a known target even with beam_width 0;
  103.             Vector3D target = rc_pos + rel_target; // we don't need to normalize because the length of rel_target = 1.  
  104.             center = Lock3GFD(rc, target, max_dist, beam_width, out radius);    
  105.  
  106.             if (center == rc_pos) GFD_tick += 1;  //the Lock3GFD method returns after 1 GFD call if it misses
  107.             else {  
  108.                 GFD_tick += 3; //if Lock3GF hits, we count it a 3 GFD calls
  109.                 update_targetlist (targets,  rc_pos, center, radius); // we only update when something is hit.
  110.             }
  111.         }
  112.     }  
  113.  
  114.     // the three panels titles are written below.
  115.  
  116.     grid_panel.WritePublicText("Grids \nRadius - Coördinates - Speed - Distance  \n\n");  
  117.     asteroid_panel.WritePublicText("Asteroids  \nRadius - Coördinates - Distance  \n\n");  
  118.     target_panel.WritePublicText("Total targets: " + targets.Count.ToString() + " Aiming at:\n\n");
  119.  
  120.     // the messy for loop below creates the target information on the LCD screens.
  121.  
  122.     for(int i = 0; i < targets.Count; i++) {  
  123.         Vector3D coords = targets[i].coords;  
  124.         if (!targets[i].stat) {            
  125.             grid_panel.WritePublicText(Math.Round(targets[i].radius/Math.Sqrt(3),1).ToString()+"m  "+  
  126.             Math.Round(coords.GetDim(0),0)+":"+Math.Round(coords.GetDim(1),0)+":"+Math.Round(coords.GetDim(2),0)+  
  127.             "   "+Math.Round(60*targets[i].velocity.Length(),1).ToString()+"m/s   "+  
  128.             (Math.Round((targets[i].coords - rc_pos).Length(),0)).ToString()+"m\n", true);  
  129.         }  
  130.         else {  
  131.             asteroid_panel.WritePublicText(Math.Round(targets[i].radius/Math.Sqrt(3),1).ToString()+"m  "+  
  132.             Math.Round(coords.GetDim(0),0)+":"+Math.Round(coords.GetDim(1),0)+":"+Math.Round(coords.GetDim(2),0)+  
  133.             "   "+(Math.Round((targets[i].coords - rc_pos).Length(),0)).ToString()+"m\n", true);  
  134.         }  
  135.     }  
  136.  
  137.     double dotprod = -1;
  138.     int target_index = -1;
  139.  
  140.     // The for loop blow cycles through targets and finds the one closest to your target reticule with dotproducts.
  141.  
  142.     for(int i = 0; i < targets.Count; i++) {    
  143.         Vector3D target_vec = Vector3D.Normalize(targets[i].coords - rc_pos);  
  144.         double dotprod_target =  fwd_wrld.Dot(target_vec);
  145.         if (dotprod_target > dotprod) {
  146.             dotprod = dotprod_target;
  147.             target_index = i;
  148.         }
  149.     }  
  150.  
  151.     // The string stuff below fills the target panel.
  152.  
  153.     if (target_index > -1) {
  154.         char c = '\\';
  155.         int i = target_index;
  156.         Vector3D coords = targets[i].coords;  
  157.         Vector3D target_vec = Vector3D.Normalize(targets[i].coords - rc_pos);  
  158.         if (targets[i].stat) target_panel.WritePublicText("Target Type: Asteroid\n", true);
  159.         else  target_panel.WritePublicText("Target Type: Grid\n", true);
  160.          
  161.         target_panel.WritePublicText("Radius: " + Math.Round(targets[i].radius/Math.Sqrt(3),1).ToString()+" m\n"+
  162.         "Distance: "+ (Math.Round((coords - rc_pos).Length(),0))+" m\n" +  
  163.         "Speed: " + Math.Round(60*targets[i].velocity.Length(),1).ToString() + " m/s\n" +  
  164.         "Coördinates: " + Math.Round(coords.GetDim(0),0)+":"+Math.Round(coords.GetDim(1),0)+":"+
  165.         Math.Round(coords.GetDim(2),0)+ "\n\n", true);  
  166.  
  167.         // the part below creates right/left and up/down arrows pointing in the direction of the projection of  
  168.         //the target on your cockpit view. You can use this to find out which target you are getting information on.
  169.  
  170.         if (right_wrld.Dot(target_vec) > 0) target_panel.WritePublicText("              --->\n\n", true);
  171.         else target_panel.WritePublicText("              <---\n\n", true);
  172.  
  173.          if (up_wrld.Dot(target_vec) > 0) {
  174.             target_panel.WritePublicText("          /" + c +"\n"+ "           |" +"\n" + "           |", true);  
  175.         }
  176.         else target_panel.WritePublicText("           |" +"\n"+ "           |" +"\n" + "          "+c+"/", true);
  177.     }
  178.  
  179.     Storage = "";  
  180.     StringBuilder builder = new StringBuilder();  
  181.  
  182.     for(int j = 0; j < targets.Count; j++) {  
  183.         builder.Append(targets[j].ToString());  
  184.         if (j < targets.Count - 1) builder.Append("\n");  
  185.     }  
  186.  
  187.     Storage = builder.ToString();  
  188.     timer.GetActionWithName("TriggerNow").Apply(timer);  
  189. }  
  190.  
  191. Vector3D GetVector3D(string rString){  // convert String to Vector3D                  
  192.     if (rString == "0") rString = "(X:0 Y:0 Z:0)";                  
  193.     string[] temp = rString.Substring(1,rString.Length-2).Split(' ');                    
  194.     double x = double.Parse(temp[0].Substring(2,temp[0].Length-2));                  
  195.     double y = double.Parse(temp[1].Substring(2,temp[1].Length-2));                    
  196.     double z = double.Parse(temp[2].Substring(2,temp[2].Length-2));                      
  197.     Vector3D rValue = new Vector3D(x,y,z);          
  198.     return rValue;                  
  199.   }                                                        
  200.  
  201. Vector3D Lock3GFD (IMyRemoteControl rc, Vector3D target, float max_dist, float beam_width, out double radius) {  
  202.     // this method is commented on the Keen forums except the radius part at the bottom.  
  203.     // I did not come up with this myself, exept the radius calculation. That part is mine.
  204.     Vector3D R = rc.GetPosition();  
  205.     Vector3D F1 = rc.GetFreeDestination(target, max_dist, beam_width);  // F,O and R refer to PennyWise's pictures
  206.     Vector3D RF1 = F1-R;
  207.     if (RF1.Length() < 1) {
  208.         radius = 0;
  209.         return R;
  210.     }
  211.     Vector3D RO_norm = Vector3D.Normalize(target-R);  
  212.     Vector3D O1 = R + (F1-R).Length()*RO_norm;    
  213.     Vector3D dO = Vector3D.Normalize(F1-O1);  //named differently in Pennywise's pictures  
  214.     Vector3D O2 = O1 - dO;  // shift the points to the inside of the sphere instead of the outside to avoid miss      
  215.     Vector3D O3 = O2 - dO;    
  216.     Vector3D F2 = rc.GetFreeDestination(O2, max_dist, beam_width);    
  217.     Vector3D F3 = rc.GetFreeDestination(O3, max_dist, beam_width);    
  218.     Vector3D circle_norm = Vector3D.Cross(F1-O1,O1-R);    
  219.     Vector3D F12 = (F1+F2)/2;    
  220.     Vector3D F23 = (F2+F3)/2;    
  221.  
  222.     Vector3D FC12 = circle_norm.Cross(F2-F1);    
  223.     Vector3D FC23 = circle_norm.Cross(F3-F2);    
  224.     Vector3D T = Intersect(F12,FC12, F23,FC23);  
  225.     Vector3D RT = T-R;    
  226.     Vector3D RT_RF1 = RT + RF1;  
  227.  
  228.     // getting line parameter "k" to find O along the line through R and O. We use that FO and TO are perpendicular.  
  229.      
  230.     double k = (RT_RF1.Dot(RO_norm) - Math.Sqrt(Sq(RT_RF1.Dot(RO_norm))-4*RT.Dot(RF1)))/2;  
  231.     radius = (T- R - k * RO_norm).Length() - beam_width;  
  232.     if (double.IsNaN(radius)) T = R;
  233.    
  234.     return T;  
  235. }  
  236.    
  237. Vector3D Intersect(Vector3D Pos1, Vector3D Vec1, Vector3D Pos2, Vector3D Vec2)    
  238. {    
  239.   // this method intersects two vectors that start at pos 1 and pos 2 and point in the direction of vec1 and vec2  
  240.     Vec1.Normalize();  
  241.     Vec2.Normalize();  
  242.     double D11, D22, D12, DP1, DP2, C12, S1, S2;    
  243.    
  244.     Vector3D Pos_change = Pos2 - Pos1;    
  245.     Vector3D Cross12 = Vec1.Cross(Vec2);    
  246.    
  247.     D11 = Vec1.LengthSquared();    
  248.     D22= Vec2.LengthSquared();    
  249.     D12 = Vec1.Dot(Vec2);    
  250.     DP1= Pos_change.Dot(Vec1);      
  251.     DP2= Pos_change.Dot(Vec2);    
  252.     C12 = Cross12.LengthSquared();    
  253.    
  254.     S1= (D22*DP1 - DP2*D12) / C12;      
  255.     S2= (D12*DP1 - DP2*D11) / C12;    
  256.    
  257.     Vector3D P1 = Pos1 + S1 * Vec1;    
  258.     Vector3D P2 = Pos2 + S2 *Vec2;    
  259.      
  260.     return (P1+P2)/2;    
  261. }  
  262.  
  263. double Sq(double number) {              // just for squaring stuff.  
  264.         double squared = number*number;  
  265.         return squared;  
  266. }  
  267.  
  268. string[] LoadStorage()                      
  269. {                                                
  270.     char[] delim = {'\n'};        
  271.     string[] data= Storage.Split(delim);                              
  272.     if (Storage == "") return new string[0];                                      
  273.     else return data;                      
  274. }                      
  275.                        
  276. public class Target { // this class describes a datapoint (target) with all the information that goes with it.
  277.     public int time;    // time since last scan (ticks)
  278.     public int countdown; // countdown to next scan
  279.     public double radius; // radius of the target, used for identification
  280.     public Vector3D velocity; // velocity of the target  
  281.     public Vector3D coords;  // the GPS coords of the target
  282.     public bool stat; // this is true when a target has velocity 0 and is of a radius that an asteroid may have
  283.     public bool grid; // this is true when a "supposed" asteroid has ever gotten a velocity.  
  284.  
  285.     public override string ToString()  
  286.     {  
  287.        return time + ";" + countdown + ";" + radius + ";" + velocity + ";"+ coords + ";" + stat + ";" + grid;  
  288.     }  
  289. }  
  290.  
  291. List<Target> update_targetlist (List<Target> targets,  Vector3D rc_pos, Vector3D center, double radius)  
  292. {  
  293.     if (center.IsValid() && (center - rc_pos).Length() > 1) {    
  294.         bool new_target = true;    // if this is true we have a new target, it may be made false below.
  295.         for (int i = 0; i<targets.Count; i++) {      
  296.             Vector3D offset = center - targets[i].coords; // we find out if the target is close to another known target
  297.  
  298.             // the complicated "if" below checks two situations. If the target is a grid, it checks if a target with the
  299.             // same radius exists at a location within a sphere of radius "possible distance travelled since last check"
  300.  
  301.             // if the target is an asteroid it simply checks if the radius is correct and it has the same location
  302.  
  303.              if ((!targets[i].stat && Math.Abs(radius - targets[i].radius) < 0.1 &&  
  304.                 offset.Length() < Math.Max(targets[i].time,1) * max_v/60) || (targets[i].stat &&  
  305.                 Math.Abs(radius - targets[i].radius) < 0.2 && offset.Length() < 1)) {    
  306.  
  307.                     new_target = false;    
  308.                     if (targets[i].time > 0) {  
  309.                         targets[i].radius = radius;    
  310.                         targets[i].velocity = (center-targets[i].coords)/targets[i].time;  
  311.  
  312.                         if ((targets[i].velocity).Length() > 1) { // if a target has ever moved, it is not considered an asteroid
  313.                             targets[i].grid = true;  
  314.                             targets[i].stat = false;
  315.                         }
  316.  
  317.                         if (targets[i].stat) targets[i].countdown = asteroid_check;  
  318.                         else targets[i].countdown = (int)Math.Floor(Math.Sqrt(radius/max_acc)*60);  
  319.  
  320.                         targets[i].time = 0;    
  321.                         targets[i].coords = center;    
  322.                         double real_radius = radius/Math.Sqrt(3);    
  323.                          
  324.                         bool asteroid = false;    
  325.                         if (targets[i].grid == false) {      
  326.                             for (int j = 0; j < 7; j++) {    
  327.                             if (Math.Abs(real_radius - 8* Math.Pow(2,j)) < 0.2 && (targets[i].velocity).Length() < 1) {
  328.                                 targets[i].stat = true;
  329.                             // this checks whether the radius is the same as a possible asteroids radius and if it moves.
  330.                             // if so, then it is considered a stationary target (possibly asteroid)
  331.                             // if it ever does move, this check will never be made again. Asteroids never move.
  332.                             }
  333.                              
  334.                         }        
  335.                     }        
  336.                 }    
  337.             }    
  338.         }  
  339.  
  340.         if (new_target) {    
  341.             targets.Add(new Target{time = 0, countdown = 1, radius = radius,  velocity = new Vector3D(0,0,0), coords = center,    
  342.             stat = false, grid = false});        
  343.         }    
  344.     }  
  345.     return targets;  
  346. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement