-
Posts
1157 -
Joined
-
Last visited
-
Days Won
2
Content Type
Profiles
Forums
Events
Everything posted by Moa
-
Yes I see your point. However, is this historically accurate or not? My understanding is that Swedish aircraft have been able to exchange contacts for a long time (they were the first IIRC). Western aircraft could also do it for a long time, as far as I know, but not all aircraft were fitted with it. These days Link-16 allows just about anything to give target data to anything else in the latest US/NATO gear (tested several months ago) - between infantry, hummers, tanks, choppers, aircraft, UAVs and ships.
-
Blatant cheat? Doesnt this do for the F15 what already is present on the Russian aircraft? Sure, it modifies 'game balance' in the F15s favour but historically this is accurate (not all F15s had datalink in 1990 but a few did). A realistic game is not necessarily a 'balanced game', yeah?
-
Ok, I've been looking at the source code of LEAVU and there is nothing in there that gives you information you don't have already. It just presents it in a different (more realistic for F15) way. Similar to how LockOn Virtual Panel did for the Russian birds. That said if you wanted to cheat then LEAVU is not the way to do it. I have a Java program that can read TacView data in real time ('encrypted' or not) and project on a Google Map for my points scoring system. I choose not to use it when flying (which is obvious, my kill-to-death ain't so flash and the good pilots sneak up on me all the time) since using it would not be realistic. My point is, LEAVU does not tip the balance in any way over what it possible, In fact, LEAVU is carefully designed to not allow cheating. We've also been discussing adding a SOAP webservice interface to LEAVU that would make it easier for other developers to add Russian birds. Given the limited amount of time we have to develop this (we have real jobs/careers and it's just what we can squeeze in our limited spare time) the F15 is a realistic first goal - so there is no Western Imperialist Conspiracy to deny the fans of the Russian birds, it's just a matter of priorities of what we get done in our free time.
-
DTED = Digital Terrain Elevation Data IFAIK as far as the search algorithm. Could do two 2-D Bresenham's to first get approx lat,long and then beam altitude at that lat long and compare to heightmap.
-
Or the TacView elevation data.
-
Will do. Would be nice to have both options yeah?
-
Ok. That's big-endian XDR over the socket with some extra markers (IIRC that's what Java uses for binary serialization). Downside is Serialization changes with major JVM releases (and Java 7 is due soonish) and clients and server must have same version. Edit: also, since the SOAP messages are small they're probably still below the MTU for Ethernet. So unless you are streaming stuff it won't be any slower to use a simple @WebService SOAP service.
-
Yoda, any chance of using SOAP webservice for comms rather than socket? (also posted this suggestion on leavu kenai chat). I can show you how to do, its much more flexible than doing socket client-server (you can easily send structured objects if you want). Allows clients (pit-modders etc) to access the LEAVU interfaces using .NET, Python, PHP, Lua etc. (if they haven't yet come around to the awesomness of platform-independent and fast Java). > [Crunch] Looking great! Nice update to your original 1.0. Are there any issues with textures fading out in game now that you switched to Java? See, told ya Java+JoGL good :) Offtopic: LMAO! Nice one Sven! 3Sqn - Largest distributor of Flanker, Fulcrum and Frogfoot parts in the Black Sea Region
-
Interview with Andrey Chizh of Eagle Dynamics
Moa replied to EvilBivol-1's topic in Lock On: Flaming Cliffs 1 & 2
An excellent read. Thanks for taking the time to post Andrey. I hope we also get to hear some of the other team members - despite them working hard on getting FC 2.0 out the door. -
According to this wikipedia article describing the Israeli airstrike on the Iraqi Osirak reactor (which the Israelis concluded was just about to begin plutonium production for nuclear weapons) the F16s flew along the desert at 30m. I believe this was considered insanely low and was not performed for the whole flght (other segments being at 800 feet and 12,200 m) http://en.wikipedia.org/wiki/Operation_Opera ps. Any flying below 500 feet is considered low flying and is restricted to specially designated areas in peacetime. There are a lot of cables, towers, buildings, trees and other stuff that can kill you low down and that is not even taking into account effects like microcell downbursts etc which would ruin your day and the extreme turbulence at the surface boundary layer (which is very fatiguing on pilots).
-
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Further points: 1) We should always be storing degrees (and fractional degrees) rather than x,y since the later depends on the projection used and will almost certainly change in DCS:A10 from the values used in Flaming Cliffs (I haven't looked at the Black Shark coordinate system yet). 2) Use doubles in preference to floats for degrees. While floats can be faster there is no point if you are losing precision in the calculation (and we need quite a few significant digits to represent lat/long down to sub-meter). 3) The calculation to get location given range and bearing from a current location is a simple one using x,y. The logical place to put this is in MapProjection (which is why I offered to do it and write the unit tests to check all the boundary cases, degree wrap-around etc.). 4) Always use the latest and greatest JDK if you can. For example, JDK after 1.6.0_14 have the G1 ('garbage first') collector built in. This collector has reduced pausing and reduced CPU overhead so is definitely worth using for LEAVU (which has a soft-realtime requirement). The brilliant thing about Java is even though Sun have made this massive improvement (similar to the massive internal change to get fully-hardware accelerated Java2D) you code doesn't usually even know the difference (it is a shame Microsoft's offerings don't work like this). -
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
I can do this calculation for you. Will do tonight. The code I gave to you is under GPL v2 or later with me holding individual copyright and I'd also like to assign joint copyright to the LEAVU project (sorry I didn't put the notice in). This is similar to what GNU does. So you can do with it what you wish. Also I suggest LEAVU be placed under GPL v3 or later rather than GPL v2 or later. As it protects LEAVU and downstream developers from later patent assertions. Also, you must use Java 1.6.0_10 or later to get good hardware acceleration. With Java 1.4 you would always get slow benchmarks. It might be worth trying the newer JVM and re-testing the speed. You will get the higher speed without having to deal with horrid AWT etc. I usually have the leavu kenai chat window open when at work so that might be easier than MSN (well for me, since I never remember my MSN password :doh:). -
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
t OpenGL doesn't have to anti-alias lines when you give the anti-alias 'hint', and quite often it doesnt. Use Java2d and you will get hardware antialiasing and especially anti-aliased text (which you can then texture map onto your surface). I personally prefer Swing over AWT because it has more controls, renders more consistently, and is easy to change the Look&Feel (meaning re-skinning your app can be easy). The latest versions of Swing have the correct z-ordering of controls and JoGL surfaces. This is not the case with AWT where you can have issues with popup menus appearing below the drawing surface. There is also the Matisse tool in Netbeans that makes working with Swing much easier. It is worth checking out if you have the time. Swing is certainly a complicated beast for some stuff (tables) but is simpler in many areas than other toolkits, and is also far more powerful than any other toolkit I've tried (WinForms, Gtk+, Qt, Wx, MFC, Xlib, XForms, AWT ...). -
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Don't forget to have your holiday. Thanks for letting me know it works. Will look into it. Does sound useful. No worries. At least you have this amazing code working, even if limited functionality. I'm happy to help with Javadoc and test cases with the time I have available. It is very interesting that your text rendering is slow. In JRE after 1.6.0_u10 *all* of Java2D is implemented as shaders on your graphics card (that is DirectX/Direct3D on Windows and OpenGL everywhere else). There shouldn't be any software rendering. So it is curious your text is slowing you down. nb. since Java2D is now fully accelerated Swing and the Swing JOGL panel should be faster than their AWT equivalents (and look fantastic using the Nimbus Look&Feel). -
I think it is exceedingly reasonable given the amount of work that goes into a patch. Ok, $15 is quite a bit less than one developer's time. A senior developer gets many times this and when you add in the overhead of project management, holiday pay, sick pay, facilities, workstations, licenses etc. So lets assume the real cost to develop a patch is more like $200/hour when you factor in multiple developers and the infrastructure required to support them. That means around 100 people have to buy the patch for each day ED spends working on it. A month of work and two thousand people have to buy the product in order for ED to break even. Given the community is so small there just aren't that many buyers to cover the cost. While there are many who might think USD $14.99 is too much for an upgrade I say that it is very reasonable once you start working out the development costs and the effort involved.
-
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Oh yeah, the atan() vs atan2() stuff. atan2() computes the same result but can handle better input range without failing, therefore I use atan2() for all my work in preference to atan(). -
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
I hope it is some use to you. If you find an error I can collect test data using the LockOn mission editor tool and we can create a unit test for that (I test coordinate conversion using all the airbases but only test range and distance between Sukhumi and Krasnodar-Central). For one Black Sea Showdown last year I created a program that did bearings and distances between various targets and bases and it printed out a table of these (we were defending ships and it is very easy to get lost at sea and not defend the correct ship). This had the bearing error you mentioned as I was treating the Earth as a sphere. Not only is it an oblate spheroid (as Case pointed out) but ED use the gnomonic projection which introduces distortions away from the central projection point. By using the same projection we will have the same distortions (relative to the true Earth) but we should be consistent with the in-game distances and bearings. I'm an observer on the kenai leavu2 project now. I do have some ideas on how to make a single bundle work on all platforms (by re-organising the native libraries a bit). Eventually I'd like to be able to commit code but I don't want to tread on your toes. I'm really keen to get a moving map going (hence the coordinate conversion work). Mostly I want it for a Java Tacview replacement (so I can view Tacviews on Linux, which is where I mostly live) but I thought it would be handy for Leavu as well. I have a high-res map from LockOn files but I think Crunch might get a better one for me (from a CDDS somewhere). Initially I won't use these maps but will use the JXMapKit component with Google Maps (I've used Google Maps before with Google Web Toolkit, but not with Swing so a bit of adaption required for me). While you work on the F15C cockpit I might try hacking up equivalent stuff for the F/A-18, since I'm trying the VNAO Hornet out. I intend running your Leavu on Linux on a separate computer so might be able eventually use Leavu for my cockpit instruments (which is where leavu is brilliant) rather than just a texture-map replacement of the Su-33 cockpit. Ambitious yes, will take a while yes, but worth it (especially with FC 2.0 coming out, since everything will have a longer lease-of-life now). S! Moa -
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
Last but not least, the utility class LatLong.java which represents a location by spherical (lat, long) or gnomonic (x,y) coordinates. This class is not called 'Location' since I use that name elsewhere. Hope the code helps anyone implementing map projections/coordinate conversions in Lockon. S! Moa /** * Represents a location specified by a latitude and a longitude. * * @author Mike "Moa" Reid. */ public class LatLong { /** * A description of the location (eg. "Novorossiysk"). */ private String description; /** * The latitude of the location (in degrees). Latitude is measured in a * positive direction North of the Equator. */ private double latitude; /** * The east longitude of the location (in degrees). East longitude is * measured in a positive direction East of the Prime Meridian (Greenwich). */ private double longitude; /** * The gnomonic projection x coordinate (corresponds to longitude) */ private double x; /** * The gnomonic projection z coordinate (corresponds to latitude) */ private double z; /** * Creates a location with no associated description, latitude or longitude. */ public LatLong() { } /** * Creates a location with an associated description, latitude and longitude. * * @param description the description of the location (eg. "Sochi-Adler"). * @param latitude the latitude of the location (in degrees). * @param longitude the longitude of the location (in degrees). * @param x the gnomonic projection x coordinate (corresponds to longitude). * @param z the gnomonic projection y coordinate (corresponds to latitude). */ public LatLong(String description, double latitude, double longitude, double x, double z) { this.description = description; this.latitude = latitude; this.longitude = longitude; this.x = x; this.z = z; } /** * Converts an angle specified as integer degrees, minutes and seconds * into a decimal representation of degrees. * * @param degrees the arc-degrees of the angle (from 0 to 359). * @param minutes the arc-minutes of the angle (from 0 to 59). * @param seconds the arc-seconds of the angle (from 0 to 59). * * @return the angle in a decimal representation. * * @throws IllegalArgumentException if degrees is outside the range 0 to 359. * @throws IllegalArgumentException if minutes is outside the range 0 to 59. * @throws IllegalArgumentException if seconds is outside the range 0 to 59. */ public static double toDegrees(int degrees, int minutes, int seconds) { if ((degrees < 0) || (degrees > 359)) { throw new IllegalArgumentException("Cannot convert from degree components to decimal degrees as the degrees value given was in valid, the value given was " + degrees); } if ((minutes < 0) || (minutes > 59)) { throw new IllegalArgumentException("Cannot convert from degree components to decimal degrees as the minutes value given was in valid, the value given was " + minutes); } if ((seconds < 0) || (seconds > 59)) { throw new IllegalArgumentException("Cannot convert from degree components to decimal degrees as the seconds value given was in valid, the value given was " + seconds); } final double arcsecondsPerDegree = 3600.0; final double arcminutesPerDegree = 60.0; double value = seconds / arcsecondsPerDegree + minutes / arcminutesPerDegree + degrees; return value; } /** * Converts an angle in degrees to a string showing the components in HTML. * * @param degrees the angle to convert into an HTML representation. * * @return a String representing the angle that is suitable for display in HTML. */ public static String toDegreeComponentsHtml(double degrees) { while (degrees < 0.0) { degrees += 360.0; } int degree = (int) Math.floor(degrees); int minutes = (int) Math.floor(degrees * 60 % 60); int seconds = (int) Math.floor(degrees * 3600 % 60); String html = String.format("%02d", degree) + "° " + String.format("%02d", minutes) + "' " + String.format("%02d", seconds) + """; return html; } /** * A description of the location (eg. "Novorossiysk"). * @return the description */ public String getDescription() { return description; } /** * A description of the location (eg. "Novorossiysk"). * @param description the description to set */ public void setDescription(String description) { this.description = description; } /** * The latitude of the location (in degrees). Latitude is measured in a * positive direction North of the Equator. * @return the latitude */ public double getLatitude() { return latitude; } /** * The latitude of the location (in degrees). Latitude is measured in a * positive direction North of the Equator. * @param latitude the latitude to set */ public void setLatitude(double latitude) { this.latitude = latitude; } /** * The east longitude of the location (in degrees). East longitude is * measured in a positive direction East of the Prime Meridian (Greenwich). * @return the longitude */ public double getLongitude() { return longitude; } /** * The east longitude of the location (in degrees). East longitude is * measured in a positive direction East of the Prime Meridian (Greenwich). * @param longitude the longitude to set */ public void setLongitude(double longitude) { this.longitude = longitude; } /** * The gnomonic projection x coordinate (corresponds to longitude) * @return the x */ public double getX() { return x; } /** * The gnomonic projection x coordinate (corresponds to longitude) * @param x the x to set */ public void setX(double x) { this.x = x; } /** * The gnomonic projection z coordinate (corresponds to latitude) * @return the z */ public double getZ() { return z; } /** * The gnomonic projection z coordinate (corresponds to latitude) * @param z the z to set */ public void setZ(double z) { this.z = z; } } -
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
The JUnit test class MapProjectionTest.java (with test data useful for people writing the algorithm in languages other than Java): import java.util.ArrayList; import java.util.List; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * Tests the MapProjection class. * * @author Mike "Moa" Reid */ public class MapProjectionTest { public MapProjectionTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } /** * Test of getGnomonicCoordinates method, of class MapProjection. */ @Test public void testGetGnomonicCoordinates() { double distanceTolerance = 35.0; // tolerance in meters, due to source data rounded to nearest arcsecond. List<LatLong> data = getLatLongTestData(); for (LatLong datum : data) { double latitudeDegrees = datum.getLatitude(); double longitudeDegrees = datum.getLongitude(); double[] result = MapProjection.getGnomonicCoordinates(latitudeDegrees, longitudeDegrees); double x = result[0]; double z = result[1]; double expectedX = datum.getX(); double expectedZ = datum.getZ(); if (Math.abs(expectedX - x) > distanceTolerance) { fail("Expected gnomonic x coordinate bigger than expected for location '" + datum.getDescription() + "', expected = " + expectedX + ", projected = " + x + ", difference = " + (x - expectedX)); } if (Math.abs(expectedZ - z) > distanceTolerance) { fail("Expected gnomonic z coordinate bigger than expected for location '" + datum.getDescription() + "', expected = " + expectedZ + ", projected = " + z + ", difference = " + (z - expectedZ)); } } } /** * Test of getSphericalCoordinates method, of class MapProjection. */ @Test public void testGetSphericalCoordinates() { double distanceTolerance = 1.0; // tolerance in meters. double angularTolerance = 0.2; // tolerance in bearing (n degrees). List<LatLong> data = getLatLongTestData(); for (LatLong datum : data) { double x = datum.getX(); double z = datum.getZ(); double[] result = MapProjection.getSphericalCoordinates(x, z); double longitude = result[0]; double latitude = result[1]; double expectedLongitude = datum.getLongitude(); double expectedLatitude = datum.getLatitude(); if (Math.abs(expectedLongitude - longitude) > distanceTolerance) { fail("Expected gnomonic longitude coordinate for location '" + datum.getDescription() + "', expected = " + expectedLongitude + ", projected = " + longitude + ", difference = " + (longitude - expectedLongitude)); } if (Math.abs(expectedLatitude - latitude) > angularTolerance) { fail("Expected gnomonic latitude coordinate bigger than expected for location '" + datum.getDescription() + "', expected = " + expectedLatitude + ", projected = " + latitude + ", difference = " + (latitude - expectedLatitude)); } } } /** * Test of getRangeAndBearing method, of class MapProjection. */ @Test public void testGetRangeAndBearing() { LatLong sukhumiLatLong = new LatLong("Sukhumi airbase", LatLong.toDegrees(42, 51, 39), LatLong.toDegrees(41, 8, 25), 0.0, 0.0); LatLong krasnodarCentralLatLong = new LatLong("Krasnodar central airbase", LatLong.toDegrees(45, 5, 1), LatLong.toDegrees(38, 57, 01), 0.0, 0.0); double latitude1 = sukhumiLatLong.getLatitude(); double longitude1 = sukhumiLatLong.getLongitude(); double latitude2 = krasnodarCentralLatLong.getLatitude(); double longitude2 = krasnodarCentralLatLong.getLongitude(); // Calculate the range and bearing from Sukhumi airbase to Krasnodar Central airbase. double expectedBearing = 320.0; // In degrees. double expectedRange = 304365; // In meters. double distanceTolerance = 35.0; // In meters. double bearingTolerance = 0.2; // In degrees. double[] result = MapProjection.getRangeAndBearing(latitude1, longitude1, latitude2, longitude2); assertNotNull(result); double range = result[0]; double bearing = result[1]; assertEquals(expectedRange, range, distanceTolerance); assertEquals(expectedBearing, bearing, bearingTolerance); } /** * Get LatLong objects that can be used for testing. * * @return an array of LatLong objects that are useful for testing. */ public List<LatLong> getLatLongTestData() { List<LatLong> data = new ArrayList<LatLong>(); // This test data was obtained in LockOn: Flaming Cliffs 1.12b using // the F11 view to move between airbases and then using the ALT+y key // to switch between polar and gnomonic coordinates (shown in the // bottom right of the screen). // Ukrainian (Crimean) locations. data.add(new LatLong("Khersones", LatLong.toDegrees(44, 34, 34), LatLong.toDegrees(33, 24, 6), -61729.2, -68106.5)); data.add(new LatLong("Saki", LatLong.toDegrees(45, 4, 52), LatLong.toDegrees(33, 35, 58), -5163.5, -52801.5)); data.add(new LatLong("Simferopol", LatLong.toDegrees(45, 2, 34), LatLong.toDegrees(33, 58, 55), -9154.2, -22654.1)); data.add(new LatLong("Razdolnoye", LatLong.toDegrees(45, 44, 4), LatLong.toDegrees(33, 31, 30), 67870.8, -59135.1)); data.add(new LatLong("Dzhankoy", LatLong.toDegrees(45, 41, 23), LatLong.toDegrees(34, 25, 15), 63676.9, 10661.5)); data.add(new LatLong("Kirovskoye", LatLong.toDegrees(45, 9, 38), LatLong.toDegrees(35, 11, 27), 5855.0, 72211.5)); data.add(new LatLong("Kerch-Bagerovo", LatLong.toDegrees(45, 23, 13), LatLong.toDegrees(36, 15, 35), 33940.6, 155181.1)); data.add(new LatLong("Belbek", LatLong.toDegrees(44, 41, 5), LatLong.toDegrees(33, 34, 9), -49501.4, -54885.1)); data.add(new LatLong("Krasnogvardeyskoye", LatLong.toDegrees(45, 34, 10), LatLong.toDegrees(34, 17, 35), 50080.5, 925.9)); data.add(new LatLong("Oktyabrskoye", LatLong.toDegrees(45, 19, 11), LatLong.toDegrees(34, 5, 49), 21939.8, -14006.7)); data.add(new LatLong("Gvardeyskoye", LatLong.toDegrees(45, 6, 19), LatLong.toDegrees(33, 58, 25), -2157.5, -23384.6)); // Southern Russia & Georgia. data.add(new LatLong("Anapa", LatLong.toDegrees(45, 0, 19), LatLong.toDegrees(37, 20, 59), -4737.0, 242694.9)); data.add(new LatLong("Krasnodar-Center", LatLong.toDegrees(45, 4, 34), LatLong.toDegrees(38, 56, 50), 11046.8, 367780.8)); data.add(new LatLong("Novorossiysk", LatLong.toDegrees(44, 40, 6), LatLong.toDegrees(37, 47, 11), -40432.2, 279253.6)); data.add(new LatLong("Krymsk", LatLong.toDegrees(44, 57, 40), LatLong.toDegrees(38, 0, 27), -6715.0, 294749.5)); data.add(new LatLong("Maykop", LatLong.toDegrees(44, 40, 27), LatLong.toDegrees(40, 3, 4), -26871.4, 458253.9)); data.add(new LatLong("Gelendzhik", LatLong.toDegrees(44, 34, 13), LatLong.toDegrees(38, 1, 3), -50287.0, 298195.6)); data.add(new LatLong("Sochi-Adler", LatLong.toDegrees(43, 26, 50), LatLong.toDegrees(39, 57, 2), -164274.3, 461912.7)); data.add(new LatLong("Krasnodar-Pashkovskiy", LatLong.toDegrees(45, 2, 12), LatLong.toDegrees(39, 10, 53), 8014.1, 386493.8)); data.add(new LatLong("Sukhumi", LatLong.toDegrees(42, 52, 0), LatLong.toDegrees(41, 8, 30), -220014.7, 564311.1)); data.add(new LatLong("Gudautu", LatLong.toDegrees(43, 6, 52), LatLong.toDegrees(40, 34, 36), -196846.7, 515809.8)); return data; } } -
Calculating bearing between two points
Moa replied to RvEYoda's topic in Lock On: Flaming Cliffs 1 & 2
I've implemented this for a moving map I'm making. Not only have I implemented the original algorithm to get gnomonic coordinates from spherical I've also derived and implemented the inverse operation (to derive you need to use the trigonometric identity sin^2 + cos^2 = 1, I'm glad that the PhD and $60k wasn't entirely wasted). Here is the Java code (unit tests with test data and a utility class will follow) which belongs in a class called MapProjection.java. It has JavaDoc that corrects some misleading names in the original C++ implementation (where 'Grad' was used which implies angular units of gradians, when the units actually appear to be degrees): /** * Utility class for doing projection in the LockOn map coordinate system. * LockOn Flaming Clifss 1.12b uses a Gnomonic Projection to obtain * gnomonic planar coordinates (x,z) from spherical coordinates: * * For more information see: * http://forums.eagle.ru/showpost.php?p=53829&postcount=7 * http://forums.eagle.ru/showthread.php?t=44427 * http://en.wikipedia.org/wiki/Gnomonic_projection * * @author Mike "Moa" Reid */ public class MapProjection { public MapProjection() { } final static float zeroX = 5000000.0f; // Real coordinates beginning final static float zeroZ = 6600000.0f; final static float centerX = 11465000.0f - zeroX; // Circle center final static float centerZ = 6500000.0f - zeroZ; final static float pn40x24_X = 4468608.57f - zeroX; // point 40dgN : 24dgE final static float pn40x24_Z = 5730893.72f - zeroZ; final static float pn48x24_X = 5357858.31f - zeroX; // point 48dgN : 24dgE final static float pn48x24_Z = 5828649.53f - zeroZ; final static float pn40x42_X = 4468608.57f - zeroX; // point 40dgN : 42dgE final static float pn40x42_Z = 7269106.20f - zeroZ; final static float pn48x42_X = 5357858.31f - zeroX; // точка 48dgN : 42dgE final static float pn48x42_Z = 7171350.00f - zeroZ; // distances from the circle center to 48dgN and 40dgN final static double lenNorth = Math.sqrt((pn48x24_X-centerX)*(pn48x24_X-centerX) + (pn48x24_Z-centerZ)*(pn48x24_Z-centerZ)); final static double lenSouth = Math.sqrt((pn40x24_X-centerX)*(pn40x24_X-centerX) + (pn40x24_Z-centerZ)*(pn40x24_Z-centerZ)); final static double lenN_S = lenSouth - lenNorth; final static double RealAngleMaxLongitude = Math.atan (((double)pn40x24_Z - centerZ)/(pn40x24_X - centerX)) * 180.0f / Math.PI; // Map bounds. Degrees! final static float EndWest = 24.0f; final static float EndEast = 42.0f; final static float EndNorth = 48.0f; final static float EndSouth = 40.0f; final static float MiddleLongitude = (EndWest + EndEast) / 2.0f; final static float ToLengthN_S = (float)((EndNorth - EndSouth) / lenN_S); final static double ToAngleW_E = (MiddleLongitude - EndWest) / RealAngleMaxLongitude; final static double degreesPerRadian = 180.0 / Math.PI; /** * Obtain the x,z LockOn map coordinates for a given latitude and longitude. * * @param latitude the input longitude (in degrees). * @param longitude the input latitude (in degrees). * * @return an array with the (x,z) coordinates in meters in (x in element 0, z in element 1). */ public static double[] getGnomonicCoordinates(double latitude, double longitude) { double angleRadians = (longitude - MiddleLongitude) / (ToAngleW_E * degreesPerRadian); double realLen = lenSouth - (latitude - EndSouth) / ToLengthN_S; double x = centerX - realLen * Math.cos(angleRadians); double z = centerZ + realLen * Math.sin(angleRadians); double[] destination = new double[2]; destination[0] = x; destination[1] = z; return destination; } /** * Obtain the longitude,latitude LockOn map coordinates for a given x,z gnomonic * projection coordinates. * * @param x the gnomonic x coordinate (in meters). * @param z the gnomonic y coordinate (in meters). * * @return an array with the (longitude,latitde) coordinates in degrees in (longitude in element 0, latitude in element 1). */ public static double[] getSphericalCoordinates(double x, double z) { double realLength = Math.sqrt((centerX - x)*(centerX - x) + (z - centerZ)*(z - centerZ)); double angleRadians = Math.acos((centerX - x) / realLength); double longitude = angleRadians * ToAngleW_E * degreesPerRadian + MiddleLongitude; double latitude = EndSouth - ToLengthN_S * (realLength - lenSouth); double[] destination = new double[2]; destination[0] = longitude; destination[1] = latitude; return destination; } /** * Determines the range and bearing from one location to another. * * @param latitude1 the longitude of the first location (in units of degrees). * @param longitude1 the latitude of the first location (in units of degrees). * * @param latitude2 the longitude of the second location (in units of degrees). * @param longitude2 the latitude of the second location (in units of degrees). * * @return an array containing the range in meters and bearing in degrees from * the first location to the second location. */ public static double[] getRangeAndBearing(double latitude1, double longitude1, double latitude2, double longitude2) { double[] coords1 = getGnomonicCoordinates(latitude1, longitude1); double[] coords2 = getGnomonicCoordinates(latitude2, longitude2); double deltaX = coords2[0] - coords1[0]; double deltaY = coords2[1] - coords1[1]; double rangeMeters = Math.sqrt(deltaX*deltaX + deltaY*deltaY); double bearingDegrees = Math.toDegrees(Math.atan2(deltaY, deltaX)); final double degreesInCircle = 360.0; while (bearingDegrees < 0.0) { bearingDegrees += degreesInCircle; } while (bearingDegrees >= degreesInCircle) { bearingDegrees -= degreesInCircle; } double[] rangeAndBearing = new double[2]; rangeAndBearing[0] = rangeMeters; rangeAndBearing[1] = bearingDegrees; return rangeAndBearing; } } -
Excellent! A big thanks to Wags, the hard-working ED crew, and the all the testers who have their work cut out for them before release.
-
Glad to see you r using Java. What would you specifically like a hand with Yoda? I could try converting the JNI to JNA so you don't have to copy the DLL around and set the javca.library.path
-
Those pictures really are superb, fantastic job Viper. I've posted them to my x-box playing friends so they can be jealous for once.
-
Patch 1.13 Requested Features/Fixes List (*Merged)
Moa replied to Colt40Five's topic in Lock On: Flaming Cliffs 1 & 2
Can't remember if I mentioned this on this thread already. Having timestamps (in the server time system) on each line of the log files (mp_log and AsyncNet) would make life a bit easier for us parsing the file.s At the moment only the game time is reported and it is a pain for us who parse the logs and try and get times out of them. (Having times in the files makes it very easy to determine duplicates if the same log is parsed again). I don't think adding server timestamps to these files would be a great deal of effort for a 1.13 patch. The headless server idea is also very good. At the moment I'm pricing up server gear and the need to have a video card in the server makes the hosting options very limited and extremely expensive: $1500 rackmount cost with low-profile video card plus monthly co-location fee: vs. monthly hosting fee on one of the many 'headless' servers out there. This expense and limited options means there are few LockOn servers compared to other games - fewer servers mean that players lose interest in the game more quickly (and turn to other games instead). Fewer servers means there is less geographic distribution, giving bad latency for many players. -
Thanks for the pointers. Will take a look. There used to be a project that gave DirectInput access, called "jinput" although it seems abandoned at the moment. Even when I looked at it a few years ago it had some issues (throwing NullPointerExceptions which should not happen in any decent code). I'm also interested in having some Java code working alongside LockOn/DCS (besides LEAVU) so am keen to find a way to make it work - even if it takes a while.