Fengist Posted July 4, 2016 Share Posted July 4, 2016 (edited) For my next stupid noob plugin maker's question. I'm trying to get two pieces of information. A heading and an elevation, both in degrees. I have vessel 1 which is mostly stationary and on the ground referred to in the code at this.part.vessel. Vessel 2 is flying around, the flightglobals.activevessel. Vessel 1 is pointed east aimed at the 90 degree mark. I'm trying to get the degrees in elevation that vessel 2 is from vessel 1 assuming horizontal is 0. Next, I'm trying to get the bearing in degrees from vessel 1, to vessel 2. Now, I've tried LOTS of examples on the Unity forums and I spent HOURS with a trig website checking my results before I realized that C# does radians, not degrees, when working with angles. So I've burnt out a few brain cells on this already. So far, what I have works but it's... well, it works, that's all I'll say. So, for the angle of elevation I have this working: double upangle = (FlightGlobals.ActiveVessel.altitude-this.part.vessel.altitude) / distanceFromPartVessel; double asinangle = Math.Asin(upangle); MPLog.Writelog("Up Angle: " + MPFunctions.ToDegrees(asinangle)); Again, that's simple geometry but I spent hours trying to get vectors to work. Basically I'm finding the angle of a right triangle when 2 sides are known. Altitude and distance. Next, the bearing, and this one is a mess double bearing = MPFunctions.DegreeBearing(this.part.vessel, MPFunctions.GetLat(FlightGlobals.ActiveVessel, 1), MPFunctions.GetLong(FlightGlobals.ActiveVessel, 1)); public static double DegreeBearing(Vessel v, double lat1, double lon1) { double R = v.orbitDriver.orbit.referenceBody.Radius;//Radius of current body var dLon = ToRad(lon1 - v.longitude); var dPhi = Math.Log( Math.Tan(ToRad(lat1) / 2 + Math.PI / 4) / Math.Tan(ToRad(v.latitude) / 2 + Math.PI / 4)); if (Math.Abs(dLon) > Math.PI) dLon = dLon > 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon); return ToBearing(Math.Atan2(dLon, dPhi)); } public static double ToRad(double degrees) { return degrees * (Math.PI / 180); } public static double ToDegrees(double radians) { return radians * 180 / Math.PI; } public static double ToBearing(double radians) { // convert radians to degrees (as bearing: 0...360) return (ToDegrees(radians) + 360) % 360; } public static double GetLat(Vessel v, int which) { double lat = 0.00; switch (which) { case 1: lat = Math.Round(v.latitude, 2); break; case 2: lat = v.latitude; break; } return lat; } public static double GetLong(Vessel v, int which) { double thislong = 0.00; switch (which) { case 1: thislong = Math.Round(((v.longitude + 180) % 360) - 180, 2); break; case 2: thislong = v.longitude; break; } return thislong; } Yea, you're reading that right. I'm getting the latitude and longitude of the target vessel and getting a bearing to it. Why? Because it works like it should. If I have vessel 1 pointed at 90 degrees east, and that aircraft is flying west toward vessel 1 at a heading of 270 degrees, bearing 90 degrees, that mess above says... 90 degrees. If it files over top of vessel 1 and continues west, the bearing changes to 270 degrees. Which is exactly what I want it to do. Of all the others I've screwed with today, none of them come up with THAT answer. But, as you can see, it's stupid to have to go to that length to get a proper bearing. The problem with that, I'm guessing lat and long don't get updated as often as some other stats. I've the log output from FixedUpdate reading the same exact same bearing for a full second or more. So, seeing the mess I have, does ANYONE have a method to do what I'm wanting to (that works) without having to jump through all these hoops? Thanks. Edited July 6, 2016 by Fengist Link to comment Share on other sites More sharing options...
Crzyrndm Posted July 4, 2016 Share Posted July 4, 2016 (edited) Be aware with your elevation that it assumes that the ground is flat (ie. the flying vessel is relatively close to the grounded vessel). If you wanted the elevation with respect to the grounded vessel, it would be more accurate to find the angle between a vector pointing straight up, and one pointing to the active vessel Vector3 ToFlyingVect = (FlightGlobals.ActiveVessel.transform.position - this.vessel.transform.position).normalised; // A vector pointing toward the flying vessel with length 1 Vector3 UpVect = (this.vessel.transform.position - this.vessel.mainbody.transform.position).normalised; // A vector from the center of the current planet through the root part of your vessel with length 1 float elevation = 90 - Vector3.Angle(upVect, toFlyingVect); // 90 (vertical) less angle from vertical Bearing is a little more complex. We need a vector pointing north that is parallel to the ground at this.vessel, and a vector pointing towards the other vessel also parallel to the ground at this.vessel // using up and east (assumed direction of planetary rotation) I can calculate a north vector Vector3 UpVect = (this.vessel.transform.position - this.vessel.mainBody.position).normalized; Vector3 EastVect = this.vessel.mainBody.getRFrmVel(this.vessel.findWorldCenterOfMass()).normalized; Vector3 NorthVect = Vector3.Cross(EastVect, UpVect).normalized; // projecting a vector that points at the active vessel so its parallel with the ground Vector3 TargetVect = ActiveVessel.transform.position - this.vessel.transform.position; Vector3 SurfTargetVect = TargetVect - Vector3.Dot(UpVect, TargetVect) * UpVect; // removing the vertical component float heading = Vector3.Angle(SurfTargetVect, NorthVect); if (Math.Sign(Vector3.Dot(SurfTargetVect, EastVect)) < 0) { heading = 360 - heading; // westward headings become angles greater than 180 } I'm fairly confident I wrote this down all correctly, but if anyone spots an error... Edited July 4, 2016 by Crzyrndm Link to comment Share on other sites More sharing options...
Fengist Posted July 4, 2016 Author Share Posted July 4, 2016 @Crzyrndm Thanks! That works close enough that I'll use it. It's very likely less CPU insensitive than my round-about method, which was what I was aiming for. Ran some test and usually, the method I was using and your method are within just a couple degrees of each other which is acceptable. 7/4/2016 9:11:55 AM: [CVFlightDeck] My Angle: 40.4050898332723 7/4/2016 9:11:55 AM: [CVFlightDeck] My Bearing: 263.374102877198 7/4/2016 9:11:55 AM: [CVFlightDeck] Your Angle: 38.19789 7/4/2016 9:11:55 AM: [CVFlightDeck] Your Bearing: 265.6635 And the distance is close enough that planet curvature it's irrelevant. 500m - 2000m is what I'm planning on. Basically, I'm working on arresting gear and landing assist for an aircraft carrier. What I'm trying to do with these calculations is to create a pyramid with the apex being the aircraft carrier and the pyramid extending directly out the aft end of the ship. The carrier will basically check any aircraft within range it to see if they fall within the area of that pyramid and if they're flying toward the carrier. If so, then it'll assume they're coming in for a landing on the carrier and attempt to get the pilot on a glide slope for a landing. I probably tried half a dozen methods suggested on the Unity forums yesterday and all of them were way off. Thanks again. Oh, and just some minor syntax errors on the elevation code. Here's a corrected version: Vector3 ToFlyingVect = (FlightGlobals.ActiveVessel.transform.position - this.vessel.transform.position).normalized; // A vector pointing toward the flying vessel with length 1 UpVect = (this.vessel.transform.position - this.vessel.mainBody.transform.position).normalized; // A vector from the center of the current planet through the root part of your vessel with length 1 float elevation = 90 - Vector3.Angle(UpVect, ToFlyingVect); // 90 (vertical) less angle from vertical Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now