public void ECEF_Initializes_Without_Exceptions() { Coordinate c = new Coordinate(); ECEF ecef = new ECEF(c); ecef = new ECEF(3194.469, 3194.469, 4487.419); }
public void ECEF_To_Geodetic_Height_Conversion() { //ECEF WITH HEIGHT CHECK double latE = -80.6586; double longE = -152.49; Distance h = new Distance(1500, DistanceType.Meters); Coordinate cE = new Coordinate(latE, longE); cE.ECEF.Set_GeoDetic_Height(cE, h); ECEF ecefE = new ECEF(cE.ECEF.X, cE.ECEF.Y, cE.ECEF.Z); Coordinate rcE = ECEF.ECEFToLatLong(ecefE); Assert.AreEqual(0, rcE.Latitude.ToDouble() - cE.Latitude.ToDouble(), .00001, "Latitude 1 Conversion Outside Limits"); Assert.AreEqual(0, rcE.Longitude.ToDouble() - cE.Longitude.ToDouble(), .00001, "Longitude 1 Conversion Outside Limits"); Assert.AreEqual(0, rcE.ECEF.GeoDetic_Height.Meters - cE.ECEF.GeoDetic_Height.Meters, .00001, "Height 1 Conversion Outside Limits"); ecefE = new ECEF(cE, cE.ECEF.GeoDetic_Height); rcE = ECEF.ECEFToLatLong(ecefE); Assert.AreEqual(0, rcE.Latitude.ToDouble() - cE.Latitude.ToDouble(), .00001, "Latitude 2 Conversion Outside Limits"); Assert.AreEqual(0, rcE.Longitude.ToDouble() - cE.Longitude.ToDouble(), .00001, "Longitude 2 Conversion Outside Limits"); Assert.AreEqual(0, rcE.ECEF.GeoDetic_Height.Meters - cE.ECEF.GeoDetic_Height.Meters, .00001, "Height 2 Conversion Outside Limits"); }
private static void Check_ECEF_Height_Conversions() { //ECEF WITH HEIGHT CHECK Console.WriteLine(); bool passE = true; double latE = -80.6586; double longE = -152.49; Distance h = new Distance(1500, DistanceType.Meters); Coordinate cE = new Coordinate(latE, longE); cE.ECEF.Set_GeoDetic_Height(cE, h); if (Math.Abs(cE.ECEF.X - -921.443) >= .001) { passE = false; Debug.WriteLine("...Setting GeoDetic Height Conversions Outside Limits"); } if (Math.Abs(cE.ECEF.Y - -479.878) >= .001) { passE = false; Debug.WriteLine("...Setting GeoDetic Height Conversions Outside Limits"); } if (Math.Abs(cE.ECEF.Z - -6273.377) >= .001) { passE = false; Debug.WriteLine("...Setting GeoDetic Height Conversions Outside Limits"); } ECEF ecefE = new ECEF(cE.ECEF.X, cE.ECEF.Y, cE.ECEF.Z); Coordinate rcE = ECEF.ECEFToLatLong(ecefE); if (Math.Abs(rcE.Latitude.ToDouble() - cE.Latitude.ToDouble()) >= .00001) { passE = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rcE.Latitude.ToDouble() + " - " + cE.Latitude.ToDouble()); } if (Math.Abs(rcE.Longitude.ToDouble() - cE.Longitude.ToDouble()) >= .00001) { passE = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rcE.Longitude.ToDouble() + " - " + cE.Longitude.ToDouble()); } if (Math.Abs(rcE.ECEF.GeoDetic_Height.Meters - cE.ECEF.GeoDetic_Height.Meters) >= .00001) { passE = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rcE.Longitude.ToDouble() + " - " + cE.Longitude.ToDouble()); } ecefE = new ECEF(cE, cE.ECEF.GeoDetic_Height); rcE = ECEF.ECEFToLatLong(ecefE); if (Math.Abs(rcE.Latitude.ToDouble() - cE.Latitude.ToDouble()) >= .00001) { passE = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rcE.Latitude.ToDouble() + " - " + cE.Latitude.ToDouble()); } if (Math.Abs(rcE.Longitude.ToDouble() - cE.Longitude.ToDouble()) >= .00001) { passE = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rcE.Longitude.ToDouble() + " - " + cE.Longitude.ToDouble()); } if (Math.Abs(rcE.ECEF.GeoDetic_Height.Meters - cE.ECEF.GeoDetic_Height.Meters) >= .00001) { passE = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rcE.ECEF.GeoDetic_Height.Meters + " - " + cE.ECEF.GeoDetic_Height.Meters); } Pass.Write("ECEF WITH HEIGHT CHECK", passE); }
/// <summary> /// Transforms a earth-centered, earth-fixed coordinate point. /// </summary> /// <param name="point">source coordinate</param> public void Transform(ref ECEF point) { if (point.Dimension > 3) { return; } (double X, double Y, double Z) = Transform(point.X, point.Y, point.Z); point.SetCoordinate(X, Y, Z); }
/// <summary> /// Transforms a earth-centered, earth-fixed coordinate point. /// </summary> /// <param name="point">source coordinate</param> /// <returns>converted coordinate</returns> public ECEF Transform(ECEF point) { if (point.Dimension > 3) { return(null); } (double X, double Y, double Z) = Transform(point.X, point.Y, point.Z); return(new ECEF(X, Y, Z)); }
private static void ECEF_Init_Error_Checks() { bool pass = true; try { Coordinate c = new Coordinate(); ECEF ecef = new ECEF(c); ecef = new ECEF(3194.469, 3194.469, 4487.419); } catch { pass = false; } Pass.Write("ECEF Initialization Error Checks", pass); }
public Vector3 ECEFSubtract(ECEF a, ECEF b) { double X = (a.X * scale) - (b.X * scale); double Y = ((a.Y * scale) - (b.Y * scale)) * -1; double Z = (a.Z * scale) - (b.Z * scale); // Unity == ECEF // X == Y * -1 // Y == Z // Z == X // ECEF == Unity // X == Z // Y == X * -1 // Z == Y return(new Vector3((float)Y, (float)Z, (float)X)); }
public void Cartesian_Dutch_Culture() { Thread.CurrentThread.CurrentCulture = new CultureInfo("nl"); var lines = File.ReadAllLines("CoordinateData\\Cartesian.txt"); foreach (string cs in lines) { TryParse_Check(cs); Parse_Check(cs); var vals = cs.Split('#'); //First part of string is value to parse, seconds is expected string value after parse string coordString = vals[0]; Cartesian cart; ECEF ecef; Cartesian.Parse(coordString); Assert.IsTrue(Cartesian.TryParse(coordString, out cart)); ECEF.Parse(coordString); Assert.IsTrue(ECEF.TryParse(coordString, out ecef)); } }
private static void Load_Call_Tests(Coordinate c) { //Check Load_Calls bool pass = true; c.LoadCelestialInfo(); if (c.CelestialInfo == null) { pass = false; } c.LoadUTM_MGRS_Info(); if (c.UTM == null) { pass = false; } if (c.MGRS == null) { pass = false; } c.LoadCartesianInfo(); if (c.Cartesian == null) { pass = false; } c.LoadECEFInfo(); if (c.ECEF == null) { pass = false; } Pass.Write("Load Calls (Celestial, UTM, MGRS, Cartesian, ECEF)", pass); if (pass) { Celestial cel = c.CelestialInfo; MilitaryGridReferenceSystem mgrs = c.MGRS; UniversalTransverseMercator utm = c.UTM; Cartesian cart = c.Cartesian; ECEF ecef = c.ECEF; c.Latitude.DecimalDegree = -45; c.Longitude.DecimalDegree = -75; //Properties should not change. if (!ReflectiveEquals(c.CelestialInfo, cel)) { pass = false; } if (!ReflectiveEquals(c.MGRS, mgrs)) { pass = false; } if (!ReflectiveEquals(c.UTM, utm)) { pass = false; } if (!ReflectiveEquals(c.Cartesian, cart)) { pass = false; } if (!ReflectiveEquals(c.ECEF, ecef)) { pass = false; } //Properties should remain equal as no load calls were made Pass.Write("Property State Hold (Celestial, UTM, MGRS, Cartesian, ECEF)", pass); //Properties should change pass = true; c.LoadCelestialInfo(); c.LoadCartesianInfo(); c.LoadUTM_MGRS_Info(); c.LoadECEFInfo(); if (ReflectiveEquals(c.CelestialInfo, cel)) { pass = false; } if (ReflectiveEquals(c.MGRS, mgrs)) { pass = false; } if (ReflectiveEquals(c.UTM, utm)) { pass = false; } if (ReflectiveEquals(c.Cartesian, cart)) { pass = false; } if (ReflectiveEquals(c.ECEF, ecef)) { pass = false; } //Properties should not be equal as chages have been made Pass.Write("Property State Change (Celestial, UTM, MGRS, Cartesian, ECEF)", pass); } else { //Passes auto fail has properties didn't load when called. Pass.Write("Property State Hold (Celestial, UTM, MGRS, Cartesian, ECEF)", false); Pass.Write("Property State Change (Celestial, UTM, MGRS, Cartesian, ECEF)", false); } }
private static void Run_Conversion_Passes(List <List <string> > Conversions) { //List of coordinates to test conversions against. List <double[]> coords = new List <double[]>(); coords.Add(new double[] { 39.5768, 72.4859 }); coords.Add(new double[] { -15.5768, 100.4859 }); coords.Add(new double[] { 65.25, -15.1859 }); coords.Add(new double[] { -80.659, -152.49 }); for (int x = 0; x < Conversions.Count; x++) { List <string> coordList = Conversions[x]; double lat = coords[x][0]; double lng = coords[x][1]; //0 = Decimal / Signed //1 = Decimal Degree //2 = Degree Decimal Minute //3 = Degree Minutes Seconds //4 = UTM //5 = MGRS //6 = Cartesian //7 = ECEF Coordinate c = new Coordinate(lat, lng); bool pass = true; Coordinate rc = new Coordinate(); for (int y = 0; y < 8; y++) { switch (y) { case 0: c.FormatOptions.Format = CoordinateFormatType.Decimal; if (c.ToString() != coordList[y]) { pass = false; } break; case 1: c.FormatOptions.Format = CoordinateFormatType.Decimal_Degree; if (c.ToString() != coordList[y]) { pass = false; } break; case 2: c.FormatOptions.Format = CoordinateFormatType.Degree_Decimal_Minutes; if (c.ToString() != coordList[y]) { pass = false; } rc = new Coordinate(); rc.Latitude = new CoordinatePart(c.Latitude.Degrees, c.Latitude.DecimalMinute, c.Latitude.Position); rc.Longitude = new CoordinatePart(c.Longitude.Degrees, c.Longitude.DecimalMinute, c.Longitude.Position); if (rc.Latitude.ToDouble() != c.Latitude.ToDouble()) { pass = false; Debug.WriteLine("...Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (rc.Longitude.ToDouble() != c.Longitude.ToDouble()) { pass = false; Debug.WriteLine("...Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } break; case 3: c.FormatOptions.Format = CoordinateFormatType.Degree_Minutes_Seconds; if (c.ToString() != coordList[y]) { pass = false; } rc = new Coordinate(); rc.Latitude = new CoordinatePart(c.Latitude.Degrees, c.Latitude.Minutes, c.Latitude.Seconds, c.Latitude.Position); rc.Longitude = new CoordinatePart(c.Longitude.Degrees, c.Longitude.Minutes, c.Longitude.Seconds, c.Longitude.Position); if (rc.Latitude.ToDouble() != c.Latitude.ToDouble()) { pass = false; Debug.WriteLine("...Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (rc.Longitude.ToDouble() != c.Longitude.ToDouble()) { pass = false; Debug.WriteLine("...Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } break; case 4: if (c.UTM.ToString() != coordList[y]) { pass = false; } UniversalTransverseMercator utm = new UniversalTransverseMercator(c.UTM.LatZone, c.UTM.LongZone, c.UTM.Easting, c.UTM.Northing); rc = UniversalTransverseMercator.ConvertUTMtoLatLong(utm); if (Math.Abs(rc.Latitude.ToDouble() - c.Latitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...UTM Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(rc.Longitude.ToDouble() - c.Longitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...UTM Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } //SIGNED DEGREE METHOD double[] sd = UniversalTransverseMercator.ConvertUTMtoSignedDegree(utm); if (Math.Abs(sd[0] - c.Latitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...UTM Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(sd[1] - c.Longitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...UTM Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } //OVERLOAD METHOD utm = new UniversalTransverseMercator(c.UTM.LongZone + c.UTM.LatZone.ToString(), c.UTM.Easting, c.UTM.Northing); rc = UniversalTransverseMercator.ConvertUTMtoLatLong(utm); if (Math.Abs(rc.Latitude.ToDouble() - c.Latitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...UTM Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(rc.Longitude.ToDouble() - c.Longitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...UTM Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } break; case 5: if (c.MGRS.ToString() != coordList[y]) { pass = false; } MilitaryGridReferenceSystem mgrs = new MilitaryGridReferenceSystem(c.MGRS.LatZone, c.MGRS.LongZone, c.MGRS.Digraph, c.MGRS.Easting, c.MGRS.Northing); rc = MilitaryGridReferenceSystem.MGRStoLatLong(mgrs); if (Math.Abs(rc.Latitude.ToDouble() - c.Latitude.ToDouble()) >= .0001) { pass = false; Debug.WriteLine("...MGRS Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(rc.Longitude.ToDouble() - c.Longitude.ToDouble()) >= .0001) { pass = false; Debug.WriteLine("...MGRS Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } //SIGNED DEGREE METHOD double[] sdM = MilitaryGridReferenceSystem.MGRStoSignedDegree(mgrs); if (Math.Abs(sdM[0] - c.Latitude.ToDouble()) >= .0001) { pass = false; Debug.WriteLine("...MGRS Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(sdM[1] - c.Longitude.ToDouble()) >= .0001) { pass = false; Debug.WriteLine("...MGRS Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } //OVERLOAD METHOD mgrs = new MilitaryGridReferenceSystem(c.MGRS.LongZone + c.MGRS.LatZone.ToString(), c.MGRS.Digraph, c.MGRS.Easting, c.MGRS.Northing); rc = MilitaryGridReferenceSystem.MGRStoLatLong(mgrs); if (Math.Abs(rc.Latitude.ToDouble() - c.Latitude.ToDouble()) >= .0001) { pass = false; Debug.WriteLine("...MGRS Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(rc.Longitude.ToDouble() - c.Longitude.ToDouble()) >= .0001) { pass = false; Debug.WriteLine("...MGRS Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } break; case 6: if (c.Cartesian.ToString() != coordList[y]) { pass = false; } Cartesian cart = new Cartesian(c.Cartesian.X, c.Cartesian.Y, c.Cartesian.Z); rc = Cartesian.CartesianToLatLong(cart); if (Math.Abs(rc.Latitude.ToDouble() - c.Latitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...Cartesian Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(rc.Longitude.ToDouble() - c.Longitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...Cartesian Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } break; case 7: string ec = c.ECEF.ToString().Replace(" km", "").Replace(",", ""); if (ec != coordList[y]) { pass = false; } ECEF ecef = new ECEF(c.ECEF.X, c.ECEF.Y, c.ECEF.Z); rc = ECEF.ECEFToLatLong(ecef); if (Math.Abs(rc.Latitude.ToDouble() - c.Latitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rc.Latitude.ToDouble() + " - " + c.Latitude.ToDouble()); } if (Math.Abs(rc.Longitude.ToDouble() - c.Longitude.ToDouble()) >= .00001) { pass = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } if (Math.Abs(rc.ECEF.GeoDetic_Height.Meters - c.ECEF.GeoDetic_Height.Meters) >= .00001) { pass = false; Debug.WriteLine("...ECEF Conversion Outside Limits: " + rc.Longitude.ToDouble() + " - " + c.Longitude.ToDouble()); } break; default: break; } } Pass.Write("Conversion Pass " + ((int)(x + 1)).ToString() + ": ", pass); } }
public async Task <GameObject> LoadTile(int zoom, int xTile, int yTile) { GameObject tileMesh = new GameObject(); tileMesh.name = xTile + ", " + yTile + " @ " + zoom; MeshRenderer meshRenderer = tileMesh.AddComponent <MeshRenderer>(); meshRenderer.material = new Material(Shader.Find("Standard")); string url = "https://a.tile.openstreetmap.org/" + zoom + "/" + xTile + "/" + yTile + ".png"; meshRenderer.material.mainTexture = await GetRemoteTexture(url); //print(url); MeshFilter meshFilter = tileMesh.AddComponent <MeshFilter>(); Mesh mesh = new Mesh(); double tileBoundingBoxNlat = 0; double tileBoundingBoxWlng = 0; double tileBoundingBoxSlat = 0; double tileBoundingBoxElng = 0; TileNumbersToBoundingBox(xTile, yTile, zoom, out tileBoundingBoxNlat, out tileBoundingBoxSlat, out tileBoundingBoxElng, out tileBoundingBoxWlng); //print(tileBoundingBoxNlat); //print(tileBoundingBoxWlng); //print(tileBoundingBoxSlat); //print(tileBoundingBoxElng); List <Coordinate> coords = new List <Coordinate>(); coords.Add(new Coordinate(tileBoundingBoxNlat, tileBoundingBoxWlng)); coords.Add(new Coordinate(tileBoundingBoxNlat, tileBoundingBoxElng)); coords.Add(new Coordinate(tileBoundingBoxSlat, tileBoundingBoxWlng)); coords.Add(new Coordinate(tileBoundingBoxSlat, tileBoundingBoxElng)); List <Vector3> vertices = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); ECEF tileOriginECEF = coords[0].ECEF; foreach (Coordinate c in coords) { Vector3 vertexNormal = ECEFToVector(c).normalized; Vector3 vertexPosition = ECEFSubtract(c.ECEF, coords[0].ECEF); vertices.Add(vertexPosition); //Debug.DrawLine(vertexPosition, vertexPosition + vertexNormal, Color.red, Mathf.Infinity); normals.Add(vertexNormal); } mesh.vertices = vertices.ToArray(); int[] tris = new int[6] { // lower left triangle 0, 1, 2, // upper right triangle 2, 1, 3 }; mesh.triangles = tris; mesh.normals = normals.ToArray(); Vector2[] uv = new Vector2[4] { new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0) }; mesh.uv = uv; meshFilter.mesh = mesh; if (rootTileECEF == null) { rootTileECEF = tileOriginECEF; } else { Vector3 offset = ECEFSubtract(tileOriginECEF, rootTileECEF); tileMesh.transform.position = offset; } if (!tiles.ContainsKey(new KeyValuePair <int, int>(xTile, yTile))) { tiles.Add(new KeyValuePair <int, int>(xTile, yTile), tileMesh); } return(tileMesh); }
// Unity == ECEF // X == Y * -1 // Y == Z // Z == X // ECEF == Unity // X == Z // Y == X * -1 // Z == Y async void Update() { string text = ""; if (rootTileECEF != null && playerObject != null) { float translation = Input.GetAxis("Vertical") * walkSpeed; translation *= Time.deltaTime; float headingDelta = rotationSpeed * Input.GetAxis("Mouse X"); heading += headingDelta; heading %= 360; // Get the ECEF location of the root tile in ECEF space double X = rootTileECEF.X; double Y = rootTileECEF.Y; double Z = rootTileECEF.Z; // Add the player position relative to the root tile, divide by scale because unity units ate in m and ECEF units are in km Vector3 playerPosition = playerObject.transform.position + (playerObject.transform.forward * translation); X += (playerPosition.z / scale); Y += ((playerPosition.x / scale) * -1); Z += (playerPosition.y / scale); // Get the coordinated of the player location on earth Coordinate playerCoordinates = ECEF.ECEFToLatLong(X, Y, Z); playerCoordinates.FormatOptions = new CoordinateFormatOptions() { Format = CoordinateFormatType.Decimal, Round = 15 }; // Build a new Coordinate object using the lat/long from the previous step // this will assume the coords are on the WGS84 spheroid Coordinate playerCoordinatesSetHeight = new Coordinate(playerCoordinates.Latitude.DecimalDegree, playerCoordinates.Longitude.DecimalDegree); playerCoordinatesSetHeight.FormatOptions = new CoordinateFormatOptions() { Format = CoordinateFormatType.Decimal, Round = 15 }; // Get the ECEF coordinates on the surface of the WGS84 ellipsoid ECEF playerECEF_0m = playerCoordinatesSetHeight.ECEF; Vector3 relativeLocation_0m = ECEFSubtract(playerECEF_0m, rootTileECEF); // Get the ECEF coordinates 1 m up from the WGS84 ellipsoid ECEF playerECEF_1m = new ECEF(playerCoordinatesSetHeight, new Distance(0.001)); Vector3 relativeLocation_1m = ECEFSubtract(playerECEF_1m, rootTileECEF); // Get the ECEF coordinates 2 m up from the WGS84 ellipsoid ECEF playerECEF_2m = new ECEF(playerCoordinatesSetHeight, new Distance(0.002)); Vector3 relativeLocation_2m = ECEFSubtract(playerECEF_2m, rootTileECEF); // Work out the direction of gravity, which way "down" is at this location on the WGS84 ellipsoid Vector3 gravityVector = (relativeLocation_0m - relativeLocation_1m).normalized; Quaternion gravityDirection = Quaternion.FromToRotation(Vector3.up, gravityVector); // put the gravity indicator 1m off the ground, pointing "down" arrowObject.transform.position = relativeLocation_1m; arrowObject.transform.rotation = gravityDirection; // player should be oriented away from gravity Quaternion playerOrientation = Quaternion.FromToRotation(Vector3.up, gravityVector * -1); // the player's origin is in the centre of the 2m tall capsule, so use the location 1m from the surface as the position // this kind of position update breaks physics, so should probably work out some way of shoving the player to this new position // by subtracting the current position from the new, then using addforce? Vector3 delta = relativeLocation_1m - playerObject.transform.position; playerObject.transform.position = relativeLocation_1m; // set the player to point away from gravity // this kind of rotation update breaks physics, so should probably work out some way of shoving the player to this new rotation // by subtracting the current rotation from the new, then using addforce? playerObject.transform.rotation = playerOrientation; // add the left-right rotation to the player's rotation playerObject.transform.Rotate(0, heading, 0); // set the indicators to the surface and 2m lowerPoint.transform.position = relativeLocation_0m; upperPoint.transform.position = relativeLocation_2m; text += playerCoordinates + " @ " + playerCoordinates.ECEF.GeoDetic_Height.Meters + " -> " + playerCoordinates.ECEF + Environment.NewLine; text += playerCoordinatesSetHeight + " @ " + playerECEF_1m.GeoDetic_Height.Meters + " -> " + playerECEF_1m + Environment.NewLine; LoadTilesForPlayerLocation(playerCoordinatesSetHeight.Latitude.DecimalDegree, playerCoordinatesSetHeight.Longitude.DecimalDegree); if (Input.GetKeyDown("space")) { print("space key was pressed"); string f = "" + playerCoordinatesSetHeight; url += f.Replace(" ", ",") + "/"; print(url); } } uiText.text = text; }