ruudfaessen Posted March 22, 2015 Report Posted March 22, 2015 Hi, I'm currently developing an application with Pete Dowson's DLL. I just upgraded to Client 3.0 beta, which works for now as expected. sidenote - I upgraded because I needed the WeatherServices, however I'm getting errors on that: 'METAR for xxxx is not available now'. - But that is not the issue for this topic :) My issue is, that I'm trying to make use of the FsLatLonQuadrilateral interface, and just like the UserGuide.pdf, I am creating 4 FsLatLonPoints, but there is the issue: I'm doing this on another thread (backgroundworker c#) and it takes about 30 seconds (25 seconds to be exact) to create them, after which the backgroundworker kind of crashes, without error, just exitcode 259. I believe this is because it is trying to access the main thread or something to process the FsLatLonPoints? Like it is really 'creating' points in fsx? In the main thread they just work fine. The reason I use it on a background worker is because it does some processes which require information from an database and work with that data... Basically I have a list of points and I want to check if they are within a distance of the airplane. Suggestions? Can I find the source code on this somewhere?
Paul Henty Posted March 22, 2015 Report Posted March 22, 2015 HI, The FSLonLatPoints are only local-memory structs and all the calculations are done by locally by the DLL. Nothing is created in FSX/FSUIPC. It certainly shouldn't take 25 seconds to new up 4 instances of these. I'll try it here on a background thread and see if I can see the problem. It does sound like some kind of cross-threading blocking. I'll get back to you with my findings and hopefully a fix. Paul
Paul Henty Posted March 22, 2015 Report Posted March 22, 2015 I've replicated what you are doing (as far as I can tell) and I can't see any problems. Below is the short test form I set up that creates a quad using FSLatLonPoints and then tests the player's position. There are two buttons, one runs on the main thread and the other on a background worker thread. Both come back instantly. I think there is something else in your code that is causing the issues; the DLL itself seems quite happy with being called from other threads. using FSUIPC; using System.Threading; // Form is called 'frmBackgroundThread' // Two button on the form called 'btnMainThread' and 'btnBackgroundThread' // Test will return 'true' when on runway at EGJJ private Offset<long> playerLatitude = new Offset<long>(0x0560); private Offset<long> playerLongitude = new Offset<long>(0x0568); public frmBackgroundThread() { InitializeComponent(); } private void frmBackgroundThread_Load(object sender, EventArgs e) { FSUIPCConnection.Open(); } private void frmBackgroundThread_FormClosing(object sender, FormClosingEventArgs e) { FSUIPCConnection.Close(); } private void btnMainThread_Click(object sender, EventArgs e) { bool testResult = createAndTestQuad(); MessageBox.Show("result on main thread was: " + testResult.ToString()); } private void btnBackgroundThread_Click(object sender, EventArgs e) { BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += bw_DoWork; bw.RunWorkerCompleted += bw_RunWorkerCompleted; bw.RunWorkerAsync(); } void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { MessageBox.Show("result from background thread was: " + e.Result.ToString()); } private void bw_DoWork(object sender, DoWorkEventArgs e) { e.Result = createAndTestQuad(); } private bool createAndTestQuad() { FsLatLonPoint NE = new FsLatLonPoint(new FsLatitude(49, 20d), new FsLongitude(-2, -10d)); FsLatLonPoint NW = new FsLatLonPoint(new FsLatitude(49, 20d), new FsLongitude(-2, -20d)); FsLatLonPoint SE = new FsLatLonPoint(new FsLatitude(49, 10d), new FsLongitude(-2, -10d)); FsLatLonPoint SW = new FsLatLonPoint(new FsLatitude(49, 10d), new FsLongitude(-2, -20d)); FsLatLonQuadrilateral quad = new FsLatLonQuadrilateral(NE, NW, SE, SW); FSUIPCConnection.Process(); FsLatitude testLat = new FsLatitude(this.playerLatitude.Value); FsLongitude testLon = new FsLongitude(this.playerLongitude.Value); FsLatLonPoint testPoint = new FsLatLonPoint(testLat, testLon); return quad.ContainsPoint(testPoint); } If you need any more help with this let me know, Regards, Paul
ruudfaessen Posted March 22, 2015 Author Report Posted March 22, 2015 (edited) private bool createAndTestQuad() { FsLatLonPoint NE = new FsLatLonPoint(new FsLatitude(49, 20d), new FsLongitude(-2, -10d)); FsLatLonPoint NW = new FsLatLonPoint(new FsLatitude(49, 20d), new FsLongitude(-2, -20d)); FsLatLonPoint SE = new FsLatLonPoint(new FsLatitude(49, 10d), new FsLongitude(-2, -10d)); FsLatLonPoint SW = new FsLatLonPoint(new FsLatitude(49, 10d), new FsLongitude(-2, -20d)); FsLatLonQuadrilateral quad = new FsLatLonQuadrilateral(NE, NW, SE, SW); FSUIPCConnection.Process(); FsLatitude testLat = new FsLatitude(this.playerLatitude.Value); FsLongitude testLon = new FsLongitude(this.playerLongitude.Value); FsLatLonPoint testPoint = new FsLatLonPoint(testLat, testLon); return quad.ContainsPoint(testPoint); } Why you have a FSUIPCConnection.Process() there? What I should add is that, while that is working on the background, a timer, with interval 200, is also running at the same time. (processing data back and fort to/from fsx) In the meantime I already got it fixed. by I re-creating the Quadrilateral class a bit and got away with it. I think, somehow, the FsLatLonPoint still wants to be processed or something, it is probably waiting in queue it looks like, I don't know,, after doing this I've got my results within a milliseconds. Oh and btw, why do you do +90.0 and +180.0 on the lat/lon Degrees inside ContainsPoint() Method? Thanks for your time though, well done on that DLL, very useful. Edited March 22, 2015 by ruudfaessen
Paul Henty Posted March 22, 2015 Report Posted March 22, 2015 The process() call in my test form is just to update the player location (this.playerLatitude and this.playerLongitude). I just wanted to check that it was okay calling Process() and accessing offsets on a different thread. Most of the internal trigonometry involving lon/lat uses values that are offset by 180 (lon) or 90 (lat) degrees so that there are no negative values to deal with. So for example the longitude runs from 0 to 360 degrees instead of -180 to +180. It's many years since I wrote this but I'm guessing it kept the maths formulas more simple. Glad to hear you've sorted your problem. Paul
ruudfaessen Posted March 29, 2015 Author Report Posted March 29, 2015 Paul, altrough you have solved my problem for this, I have a more off-topic question regarding the WeatherServices, it doesn't work, I get back the error: FSUIPC Error #11: FSUIPC_ERR_TIMEOUT. Weather station xxxx is currently unavailable or is invalid. Where xxx is a valid airport where my aircraft was parked at that moment. I've tried it in two ways: FSUIPC.FSUIPCConnection.Process(); WeatherServices ws = FSUIPCConnection.WeatherServices; string weather1 = ws.GetMetarAtLocation("LSZH"); FsWeather weather = ws.GetWeatherAtLocation(Convert.ToDouble(airport.Latitude_deg), Convert.ToDouble(airport.Longitude_deg)); foreach (FsWindLayer wl in weather.WindLayers) { double direction = wl.Direction; double speed = wl.SpeedKnots; }
Paul Henty Posted March 29, 2015 Report Posted March 29, 2015 The error is thrown because FSUIPC did not receive the weather from SimConnect within the time limit. The default time limit is only 1 second. This was okay on the airports I tested on, but it seems some stations take much much longer to respond. To increase the waiting time set ws.LocationReadTimeout to the number of milliseconds to wait. I found 20 seconds was a better setting, but you can go higher if you want. Just remember that if the station really is out of range it will keep trying for the whole timeout. FSUIPC.FSUIPCConnection.Process(); WeatherServices ws = FSUIPCConnection.WeatherServices; ws.LocationReadTimeout = 20000; // try 20 seconds. string weather1 = ws.GetMetarAtLocation("LSZH"); FsWeather weather = ws.GetWeatherAtLocation(Convert.ToDouble(airport.Latitude_deg), Convert.ToDouble(airport.Longitude_deg)); foreach (FsWindLayer wl in weather.WindLayers) { double direction = wl.Direction; double speed = wl.SpeedKnots; } Paul
forstmeier Posted April 9, 2015 Report Posted April 9, 2015 I've replicated what you are doing (as far as I can tell) and I can't see any problems. Below is the short test form I set up that creates a quad using FSLatLonPoints and then tests the player's position. There are two buttons, one runs on the main thread and the other on a background worker thread. Both come back instantly. I think there is something else in your code that is causing the issues; the DLL itself seems quite happy with being called from other threads. If you need any more help with this let me know, Regards, Paul Hi, i would like to ask you why there is a difference, for example with distances and Bearing, between your DLL functions you are using with the FSUIPCClientExample and the real world Mathe calculation that is giving the right result. Aircraft world position Lat/Lon from FSUipc offsets (single offsets) or with Simconnect Destination Lat/Lon from a external dBase Example Difference: LOWG to EGLL Distance in nm = 677 - Km = 1255 - BRG 296° initial Your FS-DLL calculation is: Distance in nm = 732 - Km = 1356 - BRG 289° initial I checked my data with some Web distance calculators that confirmed my results. I think that the difference is due to a different conversion from N/W/E to a lat / lon with 6 decimals, let us say less accurate. The real world distance calculation Function distance(ByVal lat1, ByVal lon1, ByVal lat2, ByVal lon2, ByVal unit ) As Double ''lat1, lat2 - Double values with 6 decimals Dim theta As Double = 0 Dim dist As Double = 0 theta = lon1 - lon2 dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta)) dist = acos(dist) dist = rad2deg(dist) distance = dist * 60 * 1.1515 Select Case UCase(unit) Case "K" distance = distance * 1.609344 Case "N" distance = distance * 0.8684 End Select End Function THE BEARING FUNCTION (all Mathe as per ED Williams Pilot Mathe) http://williams.best.vwh.net/avform.htm 'get distance into d d = distance_radians(d) 'calc bearing If Math.Sin(BlonRad - AlonRad) < 0 Then dn = (Math.Sin(d) * Math.Cos(AlatRad)) If dn = 0 Then dn = 1 'not the correct way but it helps otherwhise stop calc. tc1 = acos((Math.Sin(BlatRad) - Math.Sin(AlatRad) * Math.Cos(d)) / dn) Else dn = (Math.Sin(d) * Math.Cos(AlatRad)) If dn = 0 Then dn = 1 tc1 = 2 * pi - acos((Math.Sin(BlatRad) - Math.Sin(AlatRad) * Math.Cos(d)) / dn) End If 'rad into degrees tc1 = rad2deg(tc1) 'RESULT <= 0 = 360° ''''convert to what we need '' 'Course deviation from actual aircraft position '' adjust HeadingDifference '' less MagVariation Appreciate you kind comments. Many thanks and best regards, Raimund .
Paul Henty Posted April 10, 2015 Report Posted April 10, 2015 Hi Raimund, I'm pretty sure I'm using different formulas than you posted. It's likely that the current formulas are either fundamentally inaccurate or, as you suggest, there could be a rounding problem. Let me check it out over the next few days and I'll get back to you with a fix or further comments. Regards, Paul
Paul Henty Posted April 11, 2015 Report Posted April 11, 2015 Hi Raimund, The formula I was using for distance and bearing were not the 'great circle' ones you posted and linked to. I'm not sure how you got my DLL to say the distance between LOWG and EGLL is 732NM. I tried with this code and it came back only 3 NM over. FsLatLonPoint LOWG = new FsLatLonPoint(new FsLatitude(46.991067), new FsLongitude(15.439628)); FsLatLonPoint EGLL = new FsLatLonPoint(new FsLatitude(51.4775), new FsLongitude(-0.461388)); double distance = LOWG.DistanceFromInNauticalMiles(EGLL); I only mention this in case you've got something wrong in your code. Anyway, I've replaced the formulas with those from the web page you linked to. New version is attached. Using the same code above it now reports 677NM and 299 degrees, which is consistent with this web page: http://www.ig.utexas.edu/outreach/googleearth/latlong.html Thanks for reporting this and linking to the formulas. Paul FSUIPCClient3.0_BETA.zip FSUIPCClient3.0_BETA.zip
forstmeier Posted April 12, 2015 Report Posted April 12, 2015 Hi Raimund, The formula I was using for distance and bearing were not the 'great circle' ones you posted and linked to. I'm not sure how you got my DLL to say the distance between LOWG and EGLL is 732NM. I tried with this code and it came back only 3 NM over. FsLatLonPoint LOWG = new FsLatLonPoint(new FsLatitude(46.991067), new FsLongitude(15.439628)); FsLatLonPoint EGLL = new FsLatLonPoint(new FsLatitude(51.4775), new FsLongitude(-0.461388)); double distance = LOWG.DistanceFromInNauticalMiles(EGLL); I only mention this in case you've got something wrong in your code. Anyway, I've replaced the formulas with those from the web page you linked to. New version is attached. Using the same code above it now reports 677NM and 299 degrees, which is consistent with this web page: http://www.ig.utexas.edu/outreach/googleearth/latlong.html Thanks for reporting this and linking to the formulas. Paul Hi Paul, I did not use your DLL for calculating as i'm only using the Mathe Formulas by Ed Williams for all calculations. I noticed the difference using your FSUIPCClientExample.VB that is using your DLL. Sitting at LOWG your example program is calculating distance + Bearing to EGLL. As far as the Bearing is concerned (296 / 299) the difference is the MagVariation, depending on what we want as result. In fact, as example, the RWY-Heading(35C) of LOWG is 349 considering the MagVariation or 346(less MagV). There is a "lateral deviation formula" that could be very useful for calculating a "restricted" deviation result, example to a Rwy or else. crs_AD = Heading in Rad crs_AB = Back-Course (example of a Rwy) in Rad XTD_Dev = Math.Asin(Math.Sin(Distance) * Math.Sin(crs_AB - crs_AD)) XTD_Dev = rad2deg(XTD_Dev) 'Restrict area / result If XTD_Dev < 0.6 And XTD_Dev > -0.6 then 'do something 'also a ILS signal would be within this result even if not aligned but heading towards Else 'do something End If This formula should not be used for calculating a Fly-To Bearing Difference. To mention that there is a big difference in calculating a Bearing-To and calculating for example a Rwy-Approach that would need more calculation for getting the Bearing-Difference. 'calc Position/Wpt aligned with Heading/Rwy at same distance of Apl to Rwy tc = RunwayBackCourse + MagVariation tc = deg2rad(tc) d2 = distance in Km lat = Math.Asin(Math.Sin(lat2) * Math.Cos(d2 / EarthR) + Math.Cos(lat2) * Math.Sin(d2 / EarthR) * Math.Cos(tc)) lon = lon2 + Atan2((Math.Sin(tc) * Math.Sin(d2 / EarthR) * Math.Cos(lat2)), (Math.Cos(d2 / EarthR) - Math.Sin(lat2) * Math.Sin(lat2))) In fact a Rwy-Approach, example a FS-ILS Autopilot Appr is moving the Apl more "lateral" L/R while the pure Mathe-Calc is moving the Apl along a smooth angle to the Center Approach-Heading. Considering the speed and change of the actual apl position the difference is quite obvious and requesting to start alignmend at a certain distance for any system in use. Your contribution is really great. Thanks. regards, Raimund .
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