Space Engineers

Space Engineers

View Stats:
Lenny Jun 11, 2022 @ 1:22pm
Scripting: Should I Be Using A Matrix?
I'm writing a script that essentially moves a ship to a given location. I'm trying to improve my coding abilities so I want to hardcode this rather than use the remote control block. I don't have any code for this ship yet since right now I'm just trying to figure out the logic behind it. So far, I have the ship coords, the new location coords, and thruster as well as gyro override controls. My idea is that I determine which axis the ship is facing, then using gyro override to point the ship in the correct direction. I'm guessing I would use a Matrix for this, but everything online is out of date and I'm tired of staying up till 6am reading forum after forum trying to figure this out myself.

TL;DR: Ship need to go to new location by gyro override, but unsure how to do so. Don't want remote control, hardcoding make brain bigger.
< >
Showing 1-12 of 12 comments
ShadedMJ Jun 11, 2022 @ 2:38pm 
Theres the algebra routine to get Yaw and Pitch from source and destination. I used that in a test to see if I could aim my ship to a moving target future position. I can provide that script if requested.

But yeah. get the coordinates of ship and destination, gyro override to point ship to destination, thruster override, monitor distance to destination, reverse thruster override some distance before reaching target, maybe fine tune position/orientation a little, and done.

Edit: If you just want hints, then "Yes to matrix". Look into Block.WorldMatrix.Forward
Last edited by ShadedMJ; Jun 11, 2022 @ 2:52pm
Lenny Jun 11, 2022 @ 3:46pm 
Originally posted by ShadedMJ:
Theres the algebra routine to get Yaw and Pitch from source and destination. I used that in a test to see if I could aim my ship to a moving target future position. I can provide that script if requested.

But yeah. get the coordinates of ship and destination, gyro override to point ship to destination, thruster override, monitor distance to destination, reverse thruster override some distance before reaching target, maybe fine tune position/orientation a little, and done.

Edit: If you just want hints, then "Yes to matrix". Look into Block.WorldMatrix.Forward
I would love to take a look at that script you created for that test.
ShadedMJ Jun 11, 2022 @ 3:53pm 
I may have stated that a little incorrectly. Its a subroutine.
void GetDirectionTo(IMyTerminalBlock Source, Vector3D Target, out double PitchD, out double YawD) {
VRageMath.Vector3D SP=Source.GetPosition(); //Get source position
VRageMath.Vector3D SF=Source.GetPosition()+Source.WorldMatrix.Forward; // Get source forward/up/right
VRageMath.Vector3D SU=Source.GetPosition()+Source.WorldMatrix.Up;
VRageMath.Vector3D SR=Source.GetPosition()+Source.WorldMatrix.Right;
double D=(SP-Target).Length(); //Get magnitudes of vectors to target
double P=Math.Acos(((SU-Target).Length()*(SU-Target).Length()-(SU-SP).Length()*(SU-SP).Length()-D*D)/(-2*(SU-SP).Length()*D));
double Y=Math.Acos(((SR-Target).Length()*(SR-Target).Length()-(SR-SP).Length()*(SR-SP).Length()-D*D)/(-2*(SR-SP).Length()*D));
double PitchDeg=90-(P*180/Math.PI); //Radians to degrees
double YawDeg=90-(Y*180/Math.PI);
if (D<(SF-Target).Length()) PitchDeg=180-PitchDeg; //Normalize and convert to degrees
if (PitchDeg>180) PitchDeg=-(360-PitchDeg);
if (D<(SF-Target).Length()) YawDeg=180-YawDeg;
if (YawDeg>180) YawDeg=-(360-YawDeg);
PitchD=PitchDeg; //Outputs
YawD=YawDeg;}

I use the ship cockpit as the source, destination coordinate, and get the return pitch and yaw.
In my test, I set up a target ship on a heading with thrust override set reasonably low so I can retrieve it later. On my ship, I used a camera raycast to determine target ship position and speed, used algebra to determine its location one minute in the future, used that for target position, got the pitch and yaw, oriented my ship for that, waited the minute and target was perfectly passed in front of my ship.
Last edited by ShadedMJ; Jun 11, 2022 @ 5:54pm
Lenny Jun 11, 2022 @ 8:31pm 
Originally posted by ShadedMJ:
I may have stated that a little incorrectly. Its a subroutine.
void GetDirectionTo(IMyTerminalBlock Source, Vector3D Target, out double PitchD, out double YawD) {
VRageMath.Vector3D SP=Source.GetPosition(); //Get source position
VRageMath.Vector3D SF=Source.GetPosition()+Source.WorldMatrix.Forward; // Get source forward/up/right
VRageMath.Vector3D SU=Source.GetPosition()+Source.WorldMatrix.Up;
VRageMath.Vector3D SR=Source.GetPosition()+Source.WorldMatrix.Right;
double D=(SP-Target).Length(); //Get magnitudes of vectors to target
double P=Math.Acos(((SU-Target).Length()*(SU-Target).Length()-(SU-SP).Length()*(SU-SP).Length()-D*D)/(-2*(SU-SP).Length()*D));
double Y=Math.Acos(((SR-Target).Length()*(SR-Target).Length()-(SR-SP).Length()*(SR-SP).Length()-D*D)/(-2*(SR-SP).Length()*D));
double PitchDeg=90-(P*180/Math.PI); //Radians to degrees
double YawDeg=90-(Y*180/Math.PI);
if (D<(SF-Target).Length()) PitchDeg=180-PitchDeg; //Normalize and convert to degrees
if (PitchDeg>180) PitchDeg=-(360-PitchDeg);
if (D<(SF-Target).Length()) YawDeg=180-YawDeg;
if (YawDeg>180) YawDeg=-(360-YawDeg);
PitchD=PitchDeg; //Outputs
YawD=YawDeg;}

I use the ship cockpit as the source, destination coordinate, and get the return pitch and yaw.
In my test, I set up a target ship on a heading with thrust override set reasonably low so I can retrieve it later. On my ship, I used a camera raycast to determine target ship position and speed, used algebra to determine its location one minute in the future, used that for target position, got the pitch and yaw, oriented my ship for that, waited the minute and target was perfectly passed in front of my ship.

This all has some good information in it that could help me for sure, but my question is how do you figure these equations out by yourself? I would love to be self efficient and I know that every coder has to look at references, but I feel as if some people just know these things better than I do and I would love to understand how I could get to that level.
ShadedMJ Jun 11, 2022 @ 10:03pm 
I'm kind of splitting this into two questions. Hope it works for you.

How to figure out the equations? I just search the web because I know others have had the same question. I'm fairly good at knowing which terms to use when searching, and I think these equations came from wikipedia. Its probably in my old textbooks as well. I don't have time or ambition to re-study enough algebra to come up with it myself and it'd be a waste of time. Don't need to recreate the wheel.

How to figure out the values within the equations? This is the hard part. Reading through the Space Engineers block definitions. Some of things are labeled wrong or have an undocumented scale or other problems. Is Block.Angle in degrees or radians? Block.Position is different than Block.GetPosition().
Lenny Jun 13, 2022 @ 1:46pm 
Originally posted by ShadedMJ:
I'm kind of splitting this into two questions. Hope it works for you.

How to figure out the equations? I just search the web because I know others have had the same question. I'm fairly good at knowing which terms to use when searching, and I think these equations came from wikipedia. Its probably in my old textbooks as well. I don't have time or ambition to re-study enough algebra to come up with it myself and it'd be a waste of time. Don't need to recreate the wheel.

How to figure out the values within the equations? This is the hard part. Reading through the Space Engineers block definitions. Some of things are labeled wrong or have an undocumented scale or other problems. Is Block.Angle in degrees or radians? Block.Position is different than Block.GetPosition().

Thanks for all of the help btw. I've been working constantly these past couple of days on this project and I finally got it to work. I have another question for you if you're up for it. I want to calculate the predicted location of a moving target now.
I know I'll need: Distance over a specified time & the directional heading of a target.
I see in the game with Raycasting that velocity is measured by each coordinate grid, but the API doesn't specify the unit of measurement that velocity is measured in.

So that leaves me with two theory's on how I would go about this:

1. Multiply velocity by (Gameticks = 5 seconds) to get distance, then determine the target facing and add that distance to it's directional value
OR
2. Velocity is measured in this format with Raycasting: X: ? Y: ? Z: ?
So, again, multiply velocity by (Gameticks = 5 seconds), then add the new Velocity measurements to the current POS of the "target"

To me it sounds like both of these could work, and I don't expect you have the perfect answer, but your opinion would be well appreciated!
ShadedMJ Jun 13, 2022 @ 3:54pm 
Side note to start: If you haven't found it yet, there's a way to make coding a lot easier. I wrote a little about it a month ago. Here's a link:
https://steamcommunity.com/app/244850/discussions/0/5154944131333685552/#c5154944131333798774

Gotcha. Need a camera for raycast if that wasn't obvious. I prefer to get my raycast as center of camera going out as a line, but you can tilt a bit with camera settings. Its in a line, not a cone. Detected entity has a timestamp on it, but is unreliable so you'll have to make your own time stamp or use the one in the example I'm providing. This is what I use as a disorganized bunch and might not be the most optimal, but I like it.

MyDetectedEntityInfo TARGET=new MyDetectedEntityInfo(); // Save target data between runs
long TIMESTAMP=0; // Time stamp of last scanned target

public void Main(string argument, UpdateType updateSource) {
IMyCameraBlock CAM=GridTerminalSystem.GetBlockWithName("Camera") as IMyCameraBlock;
double MaxDesiredRange=15000.0; // Max range you want to scan in meters
CAM.EnableRaycast=(!CAM.CanScan(MaxDesiredRange)); // Enables/disables charging of raycast at 2000m per second to MaxDesiredRange
Echo("Camera raycast available range is "+CAM.AvailableScanRange.ToString("0"));
if (argument=="SCAN") {
//float Pitch=0, Yaw=0;
//TARGET=CAM.Raycast(CAM.AvailableScanRange,Pitch,Yaw); // Raycast with pitch and yaw
TARGET=CAM.Raycast(CAM.AvailableScanRange); // Do a raycast and get result
TIMESTAMP=System.DateTime.UtcNow.Ticks; }
if (TARGET.IsEmpty()) {
Echo("No target"); }
else {
Echo("Target "+TARGET.Name);
// Calculate current position by (old target position + (target speed * time since scanned)
Vector3D POSITION=TARGET.Position+TARGET.Velocity*((System.DateTime.UtcNow.Ticks-TIMESTAMP)/10000000); // Projected position
Echo("Current Position X="+POSITION.X.ToString("0")+" Y="+POSITION.Y.ToString("0")+" Z="+POSITION.Z.ToString("0")); } }

Of course, I can provide explanations or more detail if requested.
Lenny Jun 14, 2022 @ 12:53pm 
Originally posted by ShadedMJ:
Side note to start: If you haven't found it yet, there's a way to make coding a lot easier. I wrote a little about it a month ago. Here's a link:
https://steamcommunity.com/app/244850/discussions/0/5154944131333685552/#c5154944131333798774

Gotcha. Need a camera for raycast if that wasn't obvious. I prefer to get my raycast as center of camera going out as a line, but you can tilt a bit with camera settings. Its in a line, not a cone. Detected entity has a timestamp on it, but is unreliable so you'll have to make your own time stamp or use the one in the example I'm providing. This is what I use as a disorganized bunch and might not be the most optimal, but I like it.

MyDetectedEntityInfo TARGET=new MyDetectedEntityInfo(); // Save target data between runs
long TIMESTAMP=0; // Time stamp of last scanned target

public void Main(string argument, UpdateType updateSource) {
IMyCameraBlock CAM=GridTerminalSystem.GetBlockWithName("Camera") as IMyCameraBlock;
double MaxDesiredRange=15000.0; // Max range you want to scan in meters
CAM.EnableRaycast=(!CAM.CanScan(MaxDesiredRange)); // Enables/disables charging of raycast at 2000m per second to MaxDesiredRange
Echo("Camera raycast available range is "+CAM.AvailableScanRange.ToString("0"));
if (argument=="SCAN") {
//float Pitch=0, Yaw=0;
//TARGET=CAM.Raycast(CAM.AvailableScanRange,Pitch,Yaw); // Raycast with pitch and yaw
TARGET=CAM.Raycast(CAM.AvailableScanRange); // Do a raycast and get result
TIMESTAMP=System.DateTime.UtcNow.Ticks; }
if (TARGET.IsEmpty()) {
Echo("No target"); }
else {
Echo("Target "+TARGET.Name);
// Calculate current position by (old target position + (target speed * time since scanned)
Vector3D POSITION=TARGET.Position+TARGET.Velocity*((System.DateTime.UtcNow.Ticks-TIMESTAMP)/10000000); // Projected position
Echo("Current Position X="+POSITION.X.ToString("0")+" Y="+POSITION.Y.ToString("0")+" Z="+POSITION.Z.ToString("0")); } }

Of course, I can provide explanations or more detail if requested.

My idea worked, I can predict target locations now over time. I have a question for you about your code from earlier.

I'll be talking about this line specifically since it's the only line I don't understand:
double P=Math.Acos(((SU-Target).Length()*(SU-Target).Length()-(SU-SP).Length()*(SU-SP).Length()-D*D)/(-2*(SU-SP).Length()*D));

(Use this link for a triangle reference on the sides and angles I will be talking about :
https://i.stack.imgur.com/YfkK5.jpg)

I see you are basically drawing a right triangle from each position of the IMyTerminalBlock to the target's position by subtracting each way and then squaring it. I also know your end goal is to get Angle a, which is why you use cosine.
But here is where I get confused.
If I were to label the whole equation down to it's simplest form,
The Numerator would end up looking like : c^2 - b^2 - a^2
The Denominator would end up looking like : (-2)(b)(a)
And the whole thing would be inside of angular cos.

For the Numerator, you're using Pythagorean Theorem by what I can see. Except, wouldn't the numerator = 0 no matter what since a^2 + b^2 = c^2, meaning c^2 - b^2 - a^2 would have to equal 0? Which means no matter what the denominator is, the equation would always be equal to 0? I must be wrong since it make's no sense to do all that math for it to just always be 0.
For the Denominator, I just simply don't know why we ended up doing (-2)(b)(a) lol.

I tried finding a similar equation online, but couldn't. If you care to go into detail, I would love to learn about this equation. Sorry for the absolute wall chunk
Lenny Jun 14, 2022 @ 1:09pm 
Originally posted by TheLennyMeister:
Originally posted by ShadedMJ:
Side note to start: If you haven't found it yet, there's a way to make coding a lot easier. I wrote a little about it a month ago. Here's a link:
https://steamcommunity.com/app/244850/discussions/0/5154944131333685552/#c5154944131333798774

Gotcha. Need a camera for raycast if that wasn't obvious. I prefer to get my raycast as center of camera going out as a line, but you can tilt a bit with camera settings. Its in a line, not a cone. Detected entity has a timestamp on it, but is unreliable so you'll have to make your own time stamp or use the one in the example I'm providing. This is what I use as a disorganized bunch and might not be the most optimal, but I like it.

MyDetectedEntityInfo TARGET=new MyDetectedEntityInfo(); // Save target data between runs
long TIMESTAMP=0; // Time stamp of last scanned target

public void Main(string argument, UpdateType updateSource) {
IMyCameraBlock CAM=GridTerminalSystem.GetBlockWithName("Camera") as IMyCameraBlock;
double MaxDesiredRange=15000.0; // Max range you want to scan in meters
CAM.EnableRaycast=(!CAM.CanScan(MaxDesiredRange)); // Enables/disables charging of raycast at 2000m per second to MaxDesiredRange
Echo("Camera raycast available range is "+CAM.AvailableScanRange.ToString("0"));
if (argument=="SCAN") {
//float Pitch=0, Yaw=0;
//TARGET=CAM.Raycast(CAM.AvailableScanRange,Pitch,Yaw); // Raycast with pitch and yaw
TARGET=CAM.Raycast(CAM.AvailableScanRange); // Do a raycast and get result
TIMESTAMP=System.DateTime.UtcNow.Ticks; }
if (TARGET.IsEmpty()) {
Echo("No target"); }
else {
Echo("Target "+TARGET.Name);
// Calculate current position by (old target position + (target speed * time since scanned)
Vector3D POSITION=TARGET.Position+TARGET.Velocity*((System.DateTime.UtcNow.Ticks-TIMESTAMP)/10000000); // Projected position
Echo("Current Position X="+POSITION.X.ToString("0")+" Y="+POSITION.Y.ToString("0")+" Z="+POSITION.Z.ToString("0")); } }

Of course, I can provide explanations or more detail if requested.

My idea worked, I can predict target locations now over time. I have a question for you about your code from earlier.

I'll be talking about this line specifically since it's the only line I don't understand:
double P=Math.Acos(((SU-Target).Length()*(SU-Target).Length()-(SU-SP).Length()*(SU-SP).Length()-D*D)/(-2*(SU-SP).Length()*D));

(Use this link for a triangle reference on the sides and angles I will be talking about :
https://i.stack.imgur.com/YfkK5.jpg)

I see you are basically drawing a right triangle from each position of the IMyTerminalBlock to the target's position by subtracting each way and then squaring it. I also know your end goal is to get Angle a, which is why you use cosine.
But here is where I get confused.
If I were to label the whole equation down to it's simplest form,
The Numerator would end up looking like : c^2 - b^2 - a^2
The Denominator would end up looking like : (-2)(b)(a)
And the whole thing would be inside of angular cos.

For the Numerator, you're using Pythagorean Theorem by what I can see. Except, wouldn't the numerator = 0 no matter what since a^2 + b^2 = c^2, meaning c^2 - b^2 - a^2 would have to equal 0? Which means no matter what the denominator is, the equation would always be equal to 0? I must be wrong since it make's no sense to do all that math for it to just always be 0.
For the Denominator, I just simply don't know why we ended up doing (-2)(b)(a) lol.

I tried finding a similar equation online, but couldn't. If you care to go into detail, I would love to learn about this equation. Sorry for the absolute wall chunk

Scratch that, you're using the Cosine Rule to find the angle I see that now. My only ACTUAL question now is why you used (-2)(b)(a) in the Denominator instead of positive 2
ShadedMJ Jun 14, 2022 @ 4:59pm 
I put the code in a ship in a game. It works the way I expect it to work. I also displayed various values.

I don't think I'm using (-2)(b)(a) in the way you think I am. In order for the result to be (+2) the product of (b)(a) would have to be (-1) and that is never the case in my displayed values. I've done a full circle in pitch and yaw and a 45 degree.

I do now see where I'm probably overdoing some calculations, which I have tagged for later study. I'm pleased with it the way it is for now though.
ShadedMJ Jun 16, 2022 @ 6:46am 
@TheLennyMeister : I reviewed that routine and found ways to simplify it. Thank you for your input.

void GetDirectionTo(IMyTerminalBlock Source, VRageMath.Vector3D Target, out double Pitch, out double Yaw) {
VRageMath.Vector3D SF=Source.GetPosition()+Source.WorldMatrix.Forward; // Get direction references
VRageMath.Vector3D SU=Source.GetPosition()+Source.WorldMatrix.Up;
VRageMath.Vector3D SR=Source.GetPosition()+Source.WorldMatrix.Right;
double Dist=(Source.GetPosition()-Target).Length(); //Get magnitudes of vectors.
double DistF=(SF-Target).Length();
double DistU=(SU-Target).Length();
double DistR=(SR-Target).Length();
double PitchRad=Math.Acos((DistU*DistU-1-Dist*Dist)/(-2*Dist)); //Use law of cosines to determine angles.
double YawRad=Math.Acos((DistR*DistR-1-Dist*Dist)/(-2*Dist));
double PitchDeg=90-(PitchRad*180/Math.PI); //Radians to degrees.
double YawDeg=90-(YawRad*180/Math.PI);
if (Dist<DistF) PitchDeg=180-PitchDeg; //Normalize angles
if (PitchDeg>180) PitchDeg=-(360-PitchDeg);
if (Dist<DistF) YawDeg=180-YawDeg;
if (YawDeg>180) YawDeg=-(360-YawDeg);
Pitch=PitchDeg; //Outputs
Yaw=YawDeg; }
ZombieHunter Jun 19, 2022 @ 8:42pm 
Can't you just move the ship to the new position with the existing yaw, pitch, roll? You don't need to know where the ship is facing. It isn't facing anywhere. The only time facing would matter is if you wanted it to point at a specific object. Otherwise facing in 3D is undefined without having an object 'to face'.

The matrix for the new orientation and position will be calculated for you from the yaw, pitch, roll and position. If you must calculate the matrix this is pretty simple to do. Rows 0, 1 and 2 should be X, Y and Z and row 4 is translation. Transform your base vectors by axis angle matrices formed from which axis to rotate around for yaw (up), pitch (right) and roll (look). Put these vectors into rows 0, 1 and 2 with column 0 being 0. Then translation goes into row 4 and the 4th value (or W) in row 4 is 1.0f.

X Right,X, Right.Y, Right.Z, 0.0f
Y Up.X, Up.Y, Up.Z, 0.0f
Z Look.X, Look.Y, Look.Z, 0.0f
W Translation.X, Translation.Y, Translation.Z, 1.0f

Again the handedness of the coordinate system matters. I do not know what SE uses. DX uses a right hand system. Right is +X, Up is +Y and Look is +Z or into the screen.
Last edited by ZombieHunter; Jun 19, 2022 @ 8:52pm
< >
Showing 1-12 of 12 comments
Per page: 1530 50

Date Posted: Jun 11, 2022 @ 1:22pm
Posts: 12