create account

How to build your own auto aiming script for torpedoes or missles! by jmillerworks

View this thread on: hive.blogpeakd.comecency.com
· @jmillerworks ·
$85.73
How to build your own auto aiming script for torpedoes or missles!
THE MATH OF AUTO AIMING SCRIPT 
 
# 1 	TRANSFORMATION MATRIX LAYOUT 
 
The game is based on DirectX library then it use Left-Handled coordinate system and row-major matrices format: 
 
<center>  ![](https://steemitimages.com/DQmau6MetaxMTwc8FiQZvLvaYd1LYoaGz6QEJXy1nJHEgDp/image.png)</center>
 
 
Usually i use my school maths knowledge, like OpenGL, where Matrices are in column-major notation : 
 
<center>  ![](https://steemitimages.com/DQmSbcmnsX3HWCBYkeAqYWaEzN4hVWCCXzrYp8hFKpjHhpP/image.png)</center>
 
The conversion between two layouts is simply the transpose. Take care about matrix multiplication because you need to invert the order of matrices 
 
<center>![](https://steemitimages.com/DQmfFcwRzWg6TCxbyDMmWUzsNu6SkcbnhiF6UorVjdqnkjZ/image.png) </center>

A geometric representation of affine transformation matrix is a new coordinate system, the main transformations are Rotation, Scale and Translation. To fuse all transformation in one matrix require three matrix multiplications, the order is important. 
 
In the example I do first Scale , second Rotation and last Translation, in the second image I do first Translate , second Rotation and last Scale. 
 
<center>![fig1.png](https://steemitimages.com/DQmeVgZ1i4tG8bf3LmMdHUmUCrkkjRz89tK89NJ8oc31bTA/fig1.png) </center>

The first way is the commonly used because it's more intuitive, notice that using math notation the order is TRS but in DirectX notation is SRT , more intuitive. 
 
<center> ![](https://steemitimages.com/DQmbCreqDbHYnuUWQBo19GERZsP4u6ZtTi66jeYxJurKfiG/image.png)</center>
  
 
<center> ![](https://steemitimages.com/DQmbYYKh7JCYBfg83SX3iUBuxKHhrZkvJDPFnWYcMGzPjM3/image.png)</center>
 
 
 
To convert each point from untransformed object to transformed object you have to do a simple Vertex-Matrix multiplication, in DirectX notation : 
𝑃 βˆ™ 𝑀 = 𝑃′ 
𝑃′ βˆ™ π‘€βˆ’1 = 𝑃 
  
	 
<center>  ![](https://steemitimages.com/DQmW1xQMFfmVhTGNijbVshw53TwSJ2H1VXM9gcsbcUUbdB8/image.png) ![](https://steemitimages.com/DQmWejMRTVUNgvqFpM2ufQFtM8DGMEdyaFWBJq177ZxagDZ/image.png) </center>
 
 
If you want to do in math notation the formula is        𝑀 βˆ™ 𝑃 = 𝑃′ 
 
These transformation are done by function: 
 
P’ = VRageMath.Vector3.Transform(P, ref M); 
 
To optimize I prefer use always function what contain β€œref” because struct will not be copied. 
 
# 2 	CHANGE COORDINATE SYSTEM 
 
If you want to change the coordinate system of a point you have simply do a vertex transformation, example if P is in M1 system, to convert in M2 system you have to do 
 
𝑃𝑀1 βˆ™ 𝑀2βˆ’1 = 𝑃𝑀2   eq2.1 
 
  ![fig1.png](https://steemitimages.com/DQmWs3aDij2sDaJGUwUC7Lxkre34iR3wTNoZD5ZaAmL7pM5/fig1.png)
 	 
Change the coordinate system of a direction is more simple because we remove Translation and Scale operations. We can use only Rotation part of  matrix,  if matrix is orthogonal the inverse of Rotation is equal to Transpose of Rotation 
  
<center>![](https://steemitimages.com/DQmTP6sTy3aNxr3KSbv41ZDu7poMgHR7yi5RpNLAsLHDhPj/image.png)</center>
 
Inverse of Rotation can be calculate using:   Rot.TransposeRotationInPlace(); 
 
 
When there are a concatenation of transformation you can simply multiply each transformations. Example if M2 transform a point from M1 and M3 from M2 
![](https://steemitimages.com/DQmSsLKbqCwJVyDCozUFjdWMuzC6wuLsp34KtRVwAAxb4Ln/image.png)
 
𝑃𝑀1 = 𝑃𝑀2 βˆ™ 𝑀2 
𝑃𝑀2 = 𝑃𝑀3 βˆ™ 𝑀3 
𝑃𝑀1 = 𝑃𝑀3 βˆ™ 𝑀3 βˆ™ 𝑀2 
 
π‘·π‘΄πŸ βˆ™ (π‘΄πŸ‘ βˆ™ π‘΄πŸ)βˆ’πŸ = π‘·π‘΄πŸ‘ 
π‘·π‘΄πŸ βˆ™ π‘΄βˆ’πŸπŸ βˆ™ π‘΄βˆ’πŸ‘πŸ = π‘·π‘΄πŸ‘ 
 
 
 
 
 
# 3 	COORDINATES SYSTEM 
 
To show the coordinate system in game you can create four GPS points:  
<center>![](https://steemitimages.com/DQmavPNMHk2QGo4koAzU8YwHd8tuPE2FG1gCeskQu8AonLK/image.png)</center>
 
O = {0, 0, 0}  
X = {10, 0, 0}  
Y = {0, 10, 0} Z = {0, 0, 10} 
 
 
 
 
 
 
 
 
 
From VRageMath the definition is: 
 
VRageMath.Vector3 |coordinates
-----------|---------------
Up |	{0, +1, 0} 
Down |	{0, -1, 0} 
Right 	|{+1, 0, 0} 
Left 	|{-1, 0, 0} 
Forward |	{0, 0, -1} 
Backward |	{0, 0, +1} 
 
I define four principal coordinates system: 
 
Global GPS = Matrix Identity. 
Ship = Matrix of floating points, change every time ship move on space. 
Grid = Matrix of integers, generated only first time you create a new ship. 
Block = Matrix of integers, generated only first time you create the block in the ship.  
# 3.1 	FIND COORDINATE SYSTEM OF SHIP 
 
The game use a lot of this concatenations, the first is from GPS coordinate to Ship coordinate. The only way to build this matrix is use the common properties of generic block find in the game lib: 
 
VRageMath.Vector3D PGPS = Sandbox.ModAPI.IMyEntity.GetPosition(); 
 
That return the position of block’s center in the global world coordinates. I suggest you to use 1x1 block to avoid issues. 
The game DON’T APPLY MIRROR OPERATIONS to blocks, in fact you never see mirrored block, example Refineries block have the correct orientation also when you build with symmetric tool. To get the correct matrix I use only two of Right, Up, Backward vectors, and calculate third with Cross product. 
 
 
For a Left-Hand Coordinate System you can use one of these and remember that order of Cross 
Product is important 
 
<center> ![](https://steemitimages.com/DQmS4akD4yiu6q8Xgx3M9sfjTtDgi7SYKAovQZqa4ZfYbET/image.png)![](https://steemitimages.com/DQmdCxhVH5sP9Ar6JHekBR1Jj1rkoWhDNCynKnvEC9jDfjA/image.png)</center>
𝑋 = π‘Œ Γ— 𝑍 
π‘Œ = 𝑍 Γ— 𝑋 
𝑍 = 𝑋 Γ— π‘Œ 
 
 
 
 
 
```
void GetCoordinateSystem(ref Vector3 Backward, ref Vector3 Up, ref Matrix Rotation) { 
Vector3 Right = Vector3.Cross(Up, Backward);  
Right.Normalize(); 
Backward.Normalize(); 
Up.Normalize(); 
Rotation.Right = Right; 
Rotation.Up = Up; 
Rotation.Backward = Backward; } 
 
 ```
 
So I need tree block called VECTOR_BACKWARD ; VECTOR_UP ; VECTOR_ORIGIN, the Right vector can be derived using Cross(Up, BACKWARD) 
 
  
 
         
``` 
Vector3 Backward = blockbackward.GetPosition() - blockcenter.GetPosition(); 
Vector3 Up = blockup.GetPosition() - blockcenter.GetPosition();  
GetCoordinateSystem(ref Backward, ref Up, ref ShipRotation); 
 ```
 
So if the Ship Matrix equal to Identity the ship are in this orientation : 
 
 
<center> ![](https://steemitimages.com/DQmT8Bd7U86F6H69hFQvB8egRvvYFCkvZGWFfDrR3eXjfuo/image.png)</center>
                                                            
 
 
# 3.2 	FIND COORDINATE SYSTEM OF GRID 
 
<center> ![fig32.png](https://steemitimages.com/DQmb1mCBLvnDTATTyAR7FTmEM4HXB661X8RKGPw1ZpGL7Cz/fig32.png)</center>
 
 
The second coordinate system is relative to Grid (local respect the ship) . This coordinate system is aligned to axis and use integer values because is a voxel system, in fact Vector3I use integers and can be implicit convert to Vector3 
 
VRageMath.Vector3I PGRID = Sandbox.ModAPI.IMyCubeBlock.Position; 
 
 
With a simple test (grid rotation is Identity Matrix) I notice that Grid coordinate are not aligned with coloured gizmo that you can see in the image: 
 
![](https://steemitimages.com/DQmU1Ti6TrM9k7TKxS8fxAboSa6TzcPZ7zYY14xk97Kf3X8/image.png)
  
If I write the simple code: 
 ```
PosX = GridTerminalSystem.GetBlockWithName("+X"); 
NegX = GridTerminalSystem.GetBlockWithName("-X"); 
PosY = GridTerminalSystem.GetBlockWithName("+Y"); 
NegY = GridTerminalSystem.GetBlockWithName("-Y"); 
PosZ = GridTerminalSystem.GetBlockWithName("+Z"); 
NegZ = GridTerminalSystem.GetBlockWithName("-Z"); 
Origin = GridTerminalSystem.GetBlockWithName("Origin"); 
Vector3I px = PosX.Position - Origin.Position; 
Vector3I nx = NegX.Position - Origin.Position; 
Vector3I py = PosY.Position - Origin.Position; 
Vector3I ny = NegY.Position - Origin.Position; 
Vector3I pz = PosZ.Position - Origin.Position; Vector3I nz = NegZ.Position - Origin.Position; 
 
text = string.Format("+X {0}\n-X {1}\n+Y {2}\n-Y {3}\n+Z {4}\n-Z 
{5}\n",px.ToString(),nx.ToString(),py.ToString(),ny.ToString(),pz.ToString( ),nz.ToString()); 
 ```
Block In Game |	Vector3I 	|Direction 
---------------|---------------------|---------
   +X (red) |	{+1,0,0} 	| 
   -X 	|{-1,0,0} 	 |
   +Y (green) |	{0,0,-1} |	 
   -Y |	{0,0,+1} 	 |
   +Z (blue) |	{0,+1,0}| 	 
   -Z 	|{0,-1,0} 	 |
 
So the correct calculation for Grid-Coordinates: 
 
 ```
Matrix GridRotation = IDENTITY; GridRotation.Right    = FixCoordiate(px); GridRotation.Up       = FixCoordiate(py); GridRotation.Backward = FixCoordiate(pz); 
 
Vector3 FixCoordiate(Vector3 ingame) {    return new Vector3(ingame.GetDim(0),-ingame.GetDim(2),ingame.GetDim(1)); } 
 ```
Example: if you change the grid orientation you can see that β€œ+X” block is aligned with green line so in the matrix the Right Axis is {0,1,0} and so on… 
 
![](https://steemitimages.com/DQmccEpSdVUR5prjF8uSh4jsK6SB9CdxmwZwFbW1pgtfML2/image.png)
  
3.3 	FIND COORDINATE SYSTEM OF GYROSCOPE 
 
The third coordinate system is of Gyroscope (relative to grid). Same of grid, use voxel system. The problem is that I need to normalize MyOrientation class to default xyz coordinates of grid: 
 
Base6Directions.Direction |	Index |	Vector3 
---------------------------------|--------------------|--------
Forward |	0 |	+Y 
Backward |	1 	|-Y 
Left 	|2 	|-X 
Right |	3 	|+X 
Up 	|4 	|+Z 
Down |	5 |	-Z 
 
To Access to tree vectors without crash: 
 ```
 
void GetCubeBlockMatrix(IMyCubeBlock block, ref Rotation) { 
  MyBlockOrientation orientation = block.Orientation; 
  Base6Directions.Direction L = orientation.TransformDirection(Base6Directions.Direction.Left); 
  Base6Directions.Direction U = orientation.TransformDirection(Base6Directions.Direction.Up); 
  Base6Directions.Direction F = orientation.TransformDirection(Base6Directions.Direction.Forward);   Rotation.Right    = Table[(int)L]; 
  Rotation.Up       = Table[(int)U]; 
  Rotation.Backward = Table[(int)F]; 
} 
 
 ```
Rotation is Identity if : 
 
RightAxis = Direction.Left 
UpAxis = Direction.Up  
BackwardAxis = Direction.Forward 
 
In the image you see the gyroscope in Identity Rotation (aligned with Grid-Coordinate Gizmo) 
 
 ![](https://steemitimages.com/DQmbRgnVtedWcMJCMkB8fAVYFi2NqGgpFxmw3HSHmAS6NYY/image.png)
 
 
 
 
 
 
 
 
 
 
# 4 	FIND ELEVATION AND AZIMUTH 
 
We need to know the rotation that gyroscope have to do to orient Backward vector of Ship to β€œlook” a point in the space. Look vector will be convert in ship coordinate system with equation 2.1  
 
 ![fig32.png](https://steemitimages.com/DQmaxQMifn8TpfhkJXg1MJpZxeJgdT654Kx4iuizBnneisc/fig32.png)
 
 
 
 ```
Vector3 Look = Target - Origin; ShipRotation.TransposeRotationInPlace();    Look = Vector3.Transform(Look , ref ShipRotation); Look.Normalize(); 
 ```
 
![fig34.png](https://steemitimages.com/DQmQL9onuhRwrFhUUqEEb6git8mUVALf9wV8kLhpTyqSfJ8/fig34.png)
 
 
The rotations around a vector is calculated with Atan2 because I need also the sign of angle. The Elevation is X rotation and azimuth is Y rotation. For Twist Z rotation the zero is when Y of ship is aligned with Up vector but when Ship Backward and Z become equal, the twist become unstable. Using System.Math.Atan2(y, x)  I show you for example all positive angles 
<center> ![fig34.png](https://steemitimages.com/DQmWaZrJCqGRCHcLg5X89tHCpp52YNU67XwmfdRJjrz3bVn/fig34.png)</center>
 
	πœƒπ‘‹ = π΄π‘‘π‘Žπ‘›2(𝑇𝑦 ,𝑇𝑧) 	πœƒπ‘Œ = π΄π‘‘π‘Žπ‘›2(βˆ’π‘‡π‘₯ ,𝑇𝑧) 	πœƒπ‘ = π΄π‘‘π‘Žπ‘›2(𝑇π‘₯ ,𝑇𝑦) 
 
To respect the Left-Hand-Rule, I set a negative sign for angle Y and Z. 
 
<center>  ![](https://steemitimages.com/DQmfPDDURUokXFMTeCvRE6gEFcgTjVxLj8YUMmt2iKoJSDV/image.png) </center>
 
This code work when Gyroscope Rotation and Grid Rotation are Identity: 
```
 
 angles.SetDim(0 ,(float)Math.Atan2(Look.GetDim(1), Look.GetDim(2))); angles.SetDim(1 ,(float)Math.Atan2(-Look.GetDim(0), Look.GetDim(2))); angles.SetDim(2 , 0); 
gyro.SetValueFloat("Yaw",   angles.GetDim(2) * -6.0f / 3.14f);  gyro.SetValueFloat("Pitch", angles.GetDim(0) * -6.0f / 3.14f);  gyro.SetValueFloat("Roll",  angles.GetDim(1) * -6.0f / 3.14f);  
 ```
But what happens when Gyroscope isn’t in the default Identity Rotation?  
Example: the target is (0,0,1) so the Gyroscope have to return Zero Y rotation, but you build a gyroscope rotated by  Y+180Β°  respect default. 

![fig34.png](https://steemitimages.com/DQmbjCdtZ927cAqwvLBNU2iTDvYUPEMWckfkvKzHXzp3mZD/fig34.png)

The Atan2 return the angle of Look vector but in Gyroscope coordinate, in this case Z’ = -Z and X’ = -X. 
If the Look vector will be transformed in Gyroscope coordinate the formula will return a rotation of Y+180Β°, and it’s WRONG because the result must the same (Zero Y rotation). So the β€œangle-vector” not depend by Gyroscope rotation (I not investigate in details) 
 
π‘Žπ‘›π‘”π‘™π‘’π‘  = (πœƒπ‘₯,πœƒπ‘¦,πœƒπ‘§) 
 
But angle-vector must be transformed in Gyroscope coordinate 
 	 
π‘Ÿπ‘œπ‘‘π‘Žπ‘‘π‘–π‘œπ‘›π‘  = π‘Žπ‘›π‘”π‘™π‘’π‘  βˆ— πΊπ‘¦π‘Ÿπ‘œπΆπ‘œπ‘œπ‘Ÿπ‘‘βˆ’1 
 
 
 
 ```
GyroRotation.TransposeRotationInPlace(); ShipToGyro = GridRotation * GyroRotation; 
angles = Vector3.Transform(angles , ref ShipToGyro); 
 gyro.SetValueFloat("Yaw",   angles.GetDim(0)); gyro.SetValueFloat("Pitch", angles.GetDim(1)); gyro.SetValueFloat("Roll",  angles.GetDim(2));    
 
 ```
 
This matrix can be precomputed at the beginning for each gyroscope you are using, because don’t change during script, change only if you build a new gyroscope or a new ship  
# 5 	THE LOOP 
 
This script are used to calculate continually gyroscope velocity compensation relative to a Point in the space, can’t run only once. To do a sort of game loop I use this layout: 
I build a TimerBlock, in the action’s list I insert a β€œTrigger_Now” and β€œScript_Run” 
 
  ![](https://steemitimages.com/DQmR9GWEqWVKBUGYDn7NzwTG5igvDEh6GyXzgHTDCrSfHAE/image.png)
 
The script starts with: 
```
int Updates = 0; bool initialized = false;  void Main()   
{   
    if (!initialized) GridBlockScan();        if ((Updates % 10) == 0) 
    { 
        gyroController.UpdateTarghet(Target);  
    }     
    if ((Updates % 50) == 0) 
    { 
         PrintDebugToPanel(); 
    }      
    if (Updates++ > 1000)  
    { 
        Updates = 0; 
    } 
} 
 ```
The initialized flag is used to do preliminaries only once, example get the block of ship. In this case torpedo doesn’t change block during its life. With {Updates % 10 == 0} I can reduce the frequency of updates for some functions, example: I don’t want print the text to panel every time, only sometimes. The time elapsed from a Update and Next Update is define by game’s physic dt (I suppose frame rate aren’t used to update the game’s logics) and I suppose is about 10ms, but is not important know exactly this value, you only have to know that is a faaaaaaaaaster value. 
Using β€œTimer_Start” you can generate a maximum dt of 1 second but is too big for my purpose because torpedo need a fast calculation when speed in space.  
 
 
6 	TESTING 
 
The minimum layout to test, ship and gyroscopes in random orientations. More gyroscopes you use, faster is the velocity. 
 
TODO : remove β€œvector_up” block because is not necessary ?   
 
  ![](https://steemitimages.com/DQmSriEXQo6LKqeaN5ufXzy4CYZMiPHcMo9WprnFHn6Mk1h/image.png)
 
 
 
 ```
// the GPS coordinates
Vector3 Target = new Vector3(0,0,0);  
 string VECTOR_ORIGIN = "VECTOR_ORIGIN"; string VECTOR_BACKWARD = "VECTOR_BACKWARD"; string VECTOR_UP = "VECTOR_UP"; 
 static Matrix IDENTITY = new Matrix( 
    1,0,0,0, 
    0,1,0,0, 
    0,0,1,0, 
    0,0,0,1); 
 
static Vector3[] Table = new Vector3[] 
{     new Vector3( 0, 1, 0),     new Vector3( 0,-1, 0),     new Vector3(-1, 0, 0),     new Vector3( 1, 0, 0),     new Vector3( 0, 0, 1),     new Vector3( 0, 0,-1) 
}; 
static float RadToVel = 6.0f / 3.14f; static float DampCoeff = 2.0f; string error = ""; string textfast = ""; 

string textslow = ""; 
  
int Updates = 0; 
bool initialized = false;  
List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();  
IMyTextPanel mypanel0, mypanel1; 
// Z+ block 
IMyTerminalBlock blockbackward; 
// Y+ block 
IMyTerminalBlock blockup; 
// Origin block 
IMyTerminalBlock blockcenter; 
// rotation of ship respect global GPS coordinates, change every frames 
Matrix ShipRotation = IDENTITY; 
// rotation of grid respect to ship, it's fixed, have only integers values [-1,0,1] 
Matrix GridRotation = IDENTITY; 
 
List<IMyTerminalBlock> gyroscopes_obj = new List<IMyTerminalBlock>(); List<Matrix> gyroscopes_mat = new List<Matrix>();   
void Main()   
{   
    // frequent updates     if ((Updates % 10) == 0) 
    { 
        if (initialized) 
        { 
            textfast = ""; 
            UpdateTarghet(ref Target);  
            PrintDebugToPanel(textslow, textfast); 
        }         else 
        { 
            PrintDebugToPanel(error, error); 
        }             
    }      
    // block scanning are called rarely, or only once if you need to optimize more      if ((Updates % 100) == 0) 
    { 
        textslow = ""; 
        initialized = GridBlockScan(); 
    }      
 
    // reset loop and/or output something     if (Updates++ > 1000)  
    { 
        Updates = 0; 
    } 
}   bool GridBlockScan()  
{  
    IMyTerminalBlock item;     blocks.Clear(); 
     
    // get the panel to debug informations 
    GridTerminalSystem.GetBlocksOfType<IMyTextPanel>(blocks);      if (blocks.Count>0) mypanel0 = blocks[0] as IMyTextPanel;     else mypanel0 = null; 
    if (blocks.Count>1) mypanel1 = blocks[1] as IMyTextPanel;     else mypanel1 = null; 
      
      
    // get the block used to understand orientations 
    blockbackward = GridTerminalSystem.GetBlockWithName(VECTOR_BACKWARD);     if (blockbackward==null) 
    {         error = "Missing block in forward position with name : " + VECTOR_BACKWARD;         return false; 
    } 
    blockup = GridTerminalSystem.GetBlockWithName(VECTOR_UP);     if (blockup==null)  
    {         error = "Missing block in Up position with name : " + VECTOR_UP;         return false; 
    }     blockcenter = GridTerminalSystem.GetBlockWithName(VECTOR_ORIGIN);     if (blockcenter==null) 
    {         error = "Missing block in Origin position with name : " + VECTOR_ORIGIN;         return false; 
    }  
    ComputeGridCoordSystem(ref GridRotation); 
     
    if (mypanel0!=null) textslow+= "Grid:\n" + MatrixToString(ref GridRotation);      
    // get all gyroscopes used to control the orientation     gyroscopes_obj.Clear(); 
    GridTerminalSystem.GetBlocksOfType<IMyGyro>(gyroscopes_obj);      if (gyroscopes_obj.Count == 0) 
    { 

        error = "Missing gyroscopes";         return false; 
    }        else        { 
        gyroscopes_mat.Clear(); 
        for (int i=0;i<gyroscopes_obj.Count;i++) 
        { 
            Matrix ShipToGyro = IDENTITY; 
            ComputeGyroCoordSystem(gyroscopes_obj[i], ref ShipToGyro);             gyroscopes_mat.Add(ShipToGyro); //matrix are passed as copy 
        } 
    }       
    return true; 
}  
  
// Intensive calculation, update every delta-time void UpdateTarghet(ref Vector3 Target) 
{ 
    Vector3 Angles = new Vector3(0,0,0); 
    Vector3 gyrorotations = Angles; 
     
    GetShipAngles(ref Target, ref Angles); 
     
    for (int i=0;i<gyroscopes_obj.Count;i++) 
    { 
        IMyGyro gyro = gyroscopes_obj[i] as IMyGyro;         Matrix ShipToGyro = gyroscopes_mat[i]; 
        gyrorotations = Vector3.Transform(Angles , ref ShipToGyro);   
        ApplyRotationAxis(gyro, ref gyrorotations); 
         
        if (mypanel1!=null) textfast += string.Format("Gyro{0} : {1}\n", i , Vector3ToString(gyrorotations)); 
    } 
} 
  
// Get the 3 angles of target vector relative to ship rotation void GetShipAngles(ref Vector3 Target, ref Vector3 Angles) { 
    // Update the current Ship Matrix 
    Vector3 Origin = blockcenter.GetPosition(); 
    Vector3 Backward = blockbackward.GetPosition() - Origin; 
    Vector3 Up = blockup.GetPosition() - Origin;  
    GetCoordinateSystem(ref Backward, ref Up, ref ShipRotation);     ShipRotation.TransposeRotationInPlace();   
     
    // Get ship direction and conversion from World (GPS) coordinate to Ship's Coordinates     Vector3 Look = Target - Origin; 
    Look = Vector3.Transform(Look , ref ShipRotation); 
    Look.Normalize(); 
     
 
    // elevation = aX = Atan2(Y,Z)    
    Angles.SetDim(0 ,(float)Math.Atan2(Look.GetDim(1), Look.GetDim(2))); 
    // azimuth = aY = Atan2(X,Z) negative sign if not respect left-handle-rule with rotation direction 
    Angles.SetDim(1 ,(float)Math.Atan2(-Look.GetDim(0), Look.GetDim(2)));     // twist = aZ = Atan2(Y,X) 
    //angles.SetDim(2 ,(float)Math.Atan2(Look.GetDim(0), Look.GetDim(1)));     Angles.SetDim(2, 0.0f); 
     
    if (mypanel1!=null) textfast += "Angles: " + Vector3ToString(Angles) + "\n";     
} 
  
// Get grid orientation 
void ComputeGridCoordSystem(ref Matrix Rotation) { 
    Vector3I origin = blockcenter.Position; 
    Vector3 B = AlignGridCoordToXYZ(blockbackward.Position - origin);      Vector3 U = AlignGridCoordToXYZ(blockup.Position - origin); 
 
    if (mypanel0!=null) textslow = string.Format("B {0}\nU {1}", Vector3ToString(B),Vector3ToString(U));        GetCoordinateSystem(ref B, ref U, ref Rotation);     
} 
 
// Get precomputed transformation for gyroscope  
void ComputeGyroCoordSystem(IMyTerminalBlock gyro, ref Matrix GyroRotation) { 
    // Get block orientation 
    GetCubeBlockMatrix(gyro, ref GyroRotation); 
    // Precomputed transformation 
    GyroRotation.TransposeRotationInPlace(); 
    GyroRotation = GridRotation * GyroRotation; } 
 
// update a orientation matrix system 
void GetCoordinateSystem(ref Vector3 Backward, ref Vector3 Up, ref Matrix Rotation) { 
    Vector3 Right = Vector3.Cross(Up, Backward);  
    Right.Normalize(); 
    Backward.Normalize(); 
    Up.Normalize(); 
    Rotation.Right = Right; 
    Rotation.Up = Up;     Rotation.Backward = Backward; 
} 
 
// Get the Rotation Matrix of any blocks in Grid-Coordinates void GetCubeBlockMatrix(IMyCubeBlock block, ref Matrix Rotation) { 
    MyBlockOrientation orientation = block.Orientation; 
    Base6Directions.Direction L = orientation.TransformDirection(Base6Directions.Direction.Left); 
    Base6Directions.Direction U = orientation.TransformDirection(Base6Directions.Direction.Up); 
    Base6Directions.Direction F = orientation.TransformDirection(Base6Directions.Direction.Forward);     Rotation.Right    = Table[(int)L]; 
    Rotation.Up       = Table[(int)U]; 
    Rotation.Backward = Table[(int)F]; 
} 
 
// Set Gyroscope rotation relative to Gyroscope-Coordinates void ApplyRotationAxis(IMyGyro gyro, ref Vector3 rotation) { 
    //interpolate from [-PI,PI]rad to [-6,6]rpm of gyroscope      // TODO : implement a coefficient value to dampen rotations 
    gyro.SetValueFloat("Yaw",   ClampGyroVelocity(rotation.GetDim(1) * RadToVel * DampCoeff));     gyro.SetValueFloat("Pitch", ClampGyroVelocity(rotation.GetDim(0) * RadToVel * DampCoeff));     gyro.SetValueFloat("Roll",  ClampGyroVelocity(-rotation.GetDim(2) * RadToVel * DampCoeff));  } 
 
// Fix game coordinate to respect the "game grid gizmo" Vector3 AlignGridCoordToXYZ(Vector3 ingame) 
{ 
    float y = ingame.GetDim(1);     ingame.SetDim(1, -ingame.GetDim(2)); 
    ingame.SetDim(2, y);     return ingame; 
}  
float ClampGyroVelocity(float vel) 
{     if (vel < -6.0f) return -6.0f;     else if (vel > 6.0f) return 6.0f;     else return vel; 
}  
/////////////////////// DEBUGGER /////////////////////// 
   
// print only rotation part 
string MatrixToString(ref Matrix matrix) 
{ 
    string str = ""; 
    str += Vector3ToString(matrix.Right) + "\n"; //row 1     str += Vector3ToString(matrix.Up) + "\n"; //row 2     str += Vector3ToString(matrix.Backward) + "\n"; //row 3     return str; 
}  
string Vector3ToString(Vector3 vector) 
{ 
    return string.Format("{0:0.00} {1:0.00} {2:0.00}", vector.GetDim(0), vector.GetDim(1), vector.GetDim(2)); 
} string Vector3IToString(Vector3I vector) 
{ 
    return vector.ToString(); 
} 
void PrintDebugToPanel(string testoA, string testoB) 
{ 
    if (mypanel0 != null) 
    {         mypanel0.WritePublicText(testoA);         mypanel0.ShowPublicTextOnScreen(); 
    }     if (mypanel1 != null) 
    {         mypanel1.WritePublicText(testoB);         mypanel1.ShowPublicTextOnScreen();     } 
} 
 
```
πŸ‘  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 3 others
properties (23)
authorjmillerworks
permlinkhow-to-build-your-own-auto-aiming-script-for-torpedoes-or-missles
categoryprogramming
json_metadata{"tags":["programming","technology","creativity","minnowsupport","gaming"],"image":["https://steemitimages.com/DQmau6MetaxMTwc8FiQZvLvaYd1LYoaGz6QEJXy1nJHEgDp/image.png","https://steemitimages.com/DQmSbcmnsX3HWCBYkeAqYWaEzN4hVWCCXzrYp8hFKpjHhpP/image.png","https://steemitimages.com/DQmfFcwRzWg6TCxbyDMmWUzsNu6SkcbnhiF6UorVjdqnkjZ/image.png","https://steemitimages.com/DQmeVgZ1i4tG8bf3LmMdHUmUCrkkjRz89tK89NJ8oc31bTA/fig1.png","https://steemitimages.com/DQmbCreqDbHYnuUWQBo19GERZsP4u6ZtTi66jeYxJurKfiG/image.png","https://steemitimages.com/DQmbYYKh7JCYBfg83SX3iUBuxKHhrZkvJDPFnWYcMGzPjM3/image.png","https://steemitimages.com/DQmW1xQMFfmVhTGNijbVshw53TwSJ2H1VXM9gcsbcUUbdB8/image.png","https://steemitimages.com/DQmWejMRTVUNgvqFpM2ufQFtM8DGMEdyaFWBJq177ZxagDZ/image.png","https://steemitimages.com/DQmWs3aDij2sDaJGUwUC7Lxkre34iR3wTNoZD5ZaAmL7pM5/fig1.png","https://steemitimages.com/DQmTP6sTy3aNxr3KSbv41ZDu7poMgHR7yi5RpNLAsLHDhPj/image.png","https://steemitimages.com/DQmSsLKbqCwJVyDCozUFjdWMuzC6wuLsp34KtRVwAAxb4Ln/image.png","https://steemitimages.com/DQmavPNMHk2QGo4koAzU8YwHd8tuPE2FG1gCeskQu8AonLK/image.png","https://steemitimages.com/DQmS4akD4yiu6q8Xgx3M9sfjTtDgi7SYKAovQZqa4ZfYbET/image.png","https://steemitimages.com/DQmdCxhVH5sP9Ar6JHekBR1Jj1rkoWhDNCynKnvEC9jDfjA/image.png","https://steemitimages.com/DQmT8Bd7U86F6H69hFQvB8egRvvYFCkvZGWFfDrR3eXjfuo/image.png","https://steemitimages.com/DQmb1mCBLvnDTATTyAR7FTmEM4HXB661X8RKGPw1ZpGL7Cz/fig32.png","https://steemitimages.com/DQmU1Ti6TrM9k7TKxS8fxAboSa6TzcPZ7zYY14xk97Kf3X8/image.png","https://steemitimages.com/DQmccEpSdVUR5prjF8uSh4jsK6SB9CdxmwZwFbW1pgtfML2/image.png","https://steemitimages.com/DQmbRgnVtedWcMJCMkB8fAVYFi2NqGgpFxmw3HSHmAS6NYY/image.png","https://steemitimages.com/DQmaxQMifn8TpfhkJXg1MJpZxeJgdT654Kx4iuizBnneisc/fig32.png","https://steemitimages.com/DQmQL9onuhRwrFhUUqEEb6git8mUVALf9wV8kLhpTyqSfJ8/fig34.png","https://steemitimages.com/DQmWaZrJCqGRCHcLg5X89tHCpp52YNU67XwmfdRJjrz3bVn/fig34.png","https://steemitimages.com/DQmfPDDURUokXFMTeCvRE6gEFcgTjVxLj8YUMmt2iKoJSDV/image.png","https://steemitimages.com/DQmbjCdtZ927cAqwvLBNU2iTDvYUPEMWckfkvKzHXzp3mZD/fig34.png","https://steemitimages.com/DQmR9GWEqWVKBUGYDn7NzwTG5igvDEh6GyXzgHTDCrSfHAE/image.png","https://steemitimages.com/DQmSriEXQo6LKqeaN5ufXzy4CYZMiPHcMo9WprnFHn6Mk1h/image.png"],"app":"steemit/0.1","format":"markdown"}
created2017-09-29 00:55:03
last_update2017-09-29 00:55:03
depth0
children3
last_payout2017-10-06 00:55:03
cashout_time1969-12-31 23:59:59
total_payout_value64.335 HBD
curator_payout_value21.398 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length23,959
author_reputation1,679,272,779,087
root_title"How to build your own auto aiming script for torpedoes or missles!"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id16,230,259
net_rshares30,989,234,096,510
author_curate_reward""
vote details (67)
@bitgeek ·
comment
Congratulations @jmillerworks, this post is the  most rewarded post (based on pending payouts) in the last 12 hours written by a Newbie account holder (accounts that hold between 0.01 and 0.1 Mega Vests). The total number of posts by newbie account holders during this period was 1105 and the total pending payments to posts in this category was $630.13. To see the full list of highest paid posts across all accounts categories, [click here](www.steemit.com/steemit/@bitgeek/payout-stats-report-for-29th-september-2017--part-ii). 

If you do not wish to receive these messages in future, please reply stop to this comment.
properties (22)
authorbitgeek
permlinkre-how-to-build-your-own-auto-aiming-script-for-torpedoes-or-missles-20170929t061933
categoryprogramming
json_metadata""
created2017-09-29 06:19:36
last_update2017-09-29 06:19:36
depth1
children0
last_payout2017-10-06 06:19:36
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length624
author_reputation13,049,044,453,787
root_title"How to build your own auto aiming script for torpedoes or missles!"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id16,248,996
net_rshares0
@kharrazi ·
wow, it seems your knowledge is needed now. :)
properties (22)
authorkharrazi
permlinkre-jmillerworks-how-to-build-your-own-auto-aiming-script-for-torpedoes-or-missles-20170929t150057149z
categoryprogramming
json_metadata{"tags":["programming"],"app":"steemit/0.1"}
created2017-09-29 15:00:57
last_update2017-09-29 15:00:57
depth1
children0
last_payout2017-10-06 15:00:57
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length46
author_reputation36,023,252,109,625
root_title"How to build your own auto aiming script for torpedoes or missles!"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id16,287,170
net_rshares0
@maruf121 ·
nice  post @maruf121
properties (22)
authormaruf121
permlinkre-jmillerworks-how-to-build-your-own-auto-aiming-script-for-torpedoes-or-missles-20170929t071706755z
categoryprogramming
json_metadata{"tags":["programming"],"users":["maruf121"],"app":"steemit/0.1"}
created2017-09-29 07:17:00
last_update2017-09-29 07:17:00
depth1
children0
last_payout2017-10-06 07:17:00
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length20
author_reputation87,635,397,886
root_title"How to build your own auto aiming script for torpedoes or missles!"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id16,252,796
net_rshares0