protected void SlerpToTargetOrientation(double percent) { double c = Quaternion4d.Dot(this.m_Orientation, this._targetOrientation); if (c > 1.0) { c = 1.0; } else if (c < -1.0) { c = -1.0; } this.angle = Angle.FromRadians(Math.Acos(c)); this.m_Orientation = Quaternion4d.Slerp(this.m_Orientation, this._targetOrientation, percent); this._tilt += (this._targetTilt - this._tilt) * percent; this._bank += (this._targetBank - this._bank) * percent; this._distance += (this._targetDistance - this._distance) * percent; this.ComputeAltitude(this._distance + this._headZoom, this._tilt + this._headTilt, this._swivel + this._headSwivel); this._fov += (this._targetFov - this._fov) * percent; }
/// <summary> /// Find the intersection of a ray with the terrain. /// </summary> /// <param name="p1">Cartesian coordinate of starting point</param> /// <param name="p2">Cartesian coordinate of end point</param> /// <param name="samplingPrecision">Sample length in meter</param> /// <param name="resultPrecision">Final sampling length in meter</param> /// <param name="latitude">Out : intersection latitude</param> /// <param name="longitude">Out : intersection longitude</param> /// <param name="world">Current world</param> /// <returns>NaN if no intersection found</returns> public static void RayIntersectionWithTerrain( Point3d p1, Point3d p2, double samplingPrecision, double resultPrecision, out Angle latitude, out Angle longitude, World world) { // Check for sphere intersection first // Note : checks for world radius + highest possible elevation float vertEx = World.Settings.VerticalExaggeration; double maxRadius = world.EquatorialRadius + 9000 * vertEx; // Max altitude for earth - should be dependant on world double a = (p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y) + (p2.Z - p1.Z) * (p2.Z - p1.Z); double b = 2.0 * ((p2.X - p1.X) * (p1.X) + (p2.Y - p1.Y) * (p1.Y) + (p2.Z - p1.Z) * (p1.Z)); double c = p1.X * p1.X + p1.Y * p1.Y + p1.Z * p1.Z - maxRadius * maxRadius; double discriminant = b * b - 4 * a * c; if (discriminant <= 0) { // No intersection with sphere latitude = Angle.NaN; longitude = Angle.NaN; return; } // Factor to intersection // Note : if t1 > 0 intersection is forward, < 0 is behind us double t1 = ((-1.0) * b - Math.Sqrt(discriminant)) / (2 * a); Point3d p1LatLon = MathEngine.CartesianToSphericalD(p1.X, p1.Y, p1.Z); if (t1 > 0 && p1LatLon.X > maxRadius) { // Looking from above max altitude : move p1 forward to intersection with max alt sphere p1 = new Point3d(p1.X + t1 * (p2.X - p1.X), p1.Y + t1 * (p2.Y - p1.Y), p1.Z + t1 * (p2.Z - p1.Z)); } // Ray sample Vector3 sample = new Vector3((float)(p2.X - p1.X), (float)(p2.Y - p1.Y), (float)(p2.Z - p1.Z)); double maxLength = sample.Length(); // Max length for ray tracing double sampleLength = samplingPrecision; // Sampling steps length sample.Normalize(); sample.Scale((float)sampleLength); // Casting Point3d ray = p1; double rayLength = 0; while (rayLength < maxLength) { Point3d rayLatLon = MathEngine.CartesianToSphericalD(ray.X, ray.Y, ray.Z); // Altitude at ray position double rayAlt = rayLatLon.X - world.EquatorialRadius; // Altitude at terrain position - from cached data (no download) double terrainAlt = world.TerrainAccessor.GetCachedElevationAt(MathEngine.RadiansToDegrees(rayLatLon.Y), MathEngine.RadiansToDegrees(rayLatLon.Z)); // best loaded data if (double.IsNaN(terrainAlt)) { terrainAlt = 0; } terrainAlt *= vertEx; if (terrainAlt > rayAlt) { // Intersection found if (sampleLength > resultPrecision) { // Go back one step ray.X -= sample.X; ray.Y -= sample.Y; ray.Z -= sample.Z; rayLength -= sampleLength; // and refine sampling sampleLength /= 10; sample.Normalize(); sample.Scale((float)sampleLength); } else { // return location latitude = Angle.FromRadians(rayLatLon.Y); longitude = Angle.FromRadians(rayLatLon.Z); return; } } // Move forward ray.X += sample.X; ray.Y += sample.Y; ray.Z += sample.Z; rayLength += sampleLength; } // No intersection with terrain found latitude = Angle.NaN; longitude = Angle.NaN; }
public virtual void Update(Device device) { this.viewPort = device.Viewport; Point3d p = Quaternion4d.QuaternionToEuler(this.m_Orientation); if (!double.IsNaN(p.Y)) { this._latitude.Radians = p.Y; } if (!double.IsNaN(p.X)) { this._longitude.Radians = p.X; } if (!double.IsNaN(p.Z)) { this._heading.Radians = p.Z; } // Compute matrices this.ComputeProjectionMatrix(this.viewPort); this.ComputeViewMatrix(); device.SetTransform(TransformState.Projection, this.m_ProjectionMatrix); device.SetTransform(TransformState.View, this.m_ViewMatrix); device.SetTransform(TransformState.World, this.m_WorldMatrix); this.ViewFrustum.Update( Matrix.Multiply(this.m_absoluteWorldMatrix, Matrix.Multiply(this.m_absoluteViewMatrix, this.m_absoluteProjectionMatrix))); // Old view range (used in quadtile logic) double factor = (this._altitude) / this._worldRadius; if (factor > 1) { this.viewRange = Angle.FromRadians(Math.PI); } else { this.viewRange = Angle.FromRadians(Math.Abs(Math.Asin((this._altitude) / this._worldRadius)) * 2); } // True view range if (factor < 1) { this.trueViewRange = Angle.FromRadians(Math.Abs(Math.Asin((this._distance + this._headZoom) / this._worldRadius)) * 2); } else { this.trueViewRange = Angle.FromRadians(Math.PI); } World.Settings.cameraAltitudeMeters = this.Altitude; World.Settings.cameraLatitude = this._latitude; World.Settings.cameraLongitude = this._longitude; World.Settings.cameraHeading = this._heading; World.Settings.cameraTilt = this._tilt; World.Settings.cameraSwivel = this._swivel; if (World.Settings.cameraHeadTracking != this._headTracking) { this._headTracking = World.Settings.cameraHeadTracking; if (!this._headTracking) { this._headTilt = Angle.Zero; this._headSwivel = Angle.Zero; this._headZoom = 0.0; World.Settings.cameraHeadTilt = this._headTilt; World.Settings.cameraHeadSwivel = this._headSwivel; World.Settings.cameraHeadZoom = this._headZoom; } } if (this._headTracking) { World.Settings.cameraHeadTilt = this._headTilt; World.Settings.cameraHeadSwivel = this._headSwivel; World.Settings.cameraHeadZoom = this._headZoom; } }
public virtual void ComputeViewMatrix() { // Compute camera elevation if (World.Settings.ElevateCameraLookatPoint) { int minStep = 10; this.targetCameraElevation = this.TerrainElevation * World.Settings.VerticalExaggeration; float stepToTarget = this.targetCameraElevation - this.curCameraElevation; if (Math.Abs(stepToTarget) > minStep) { float step = 0.05f * stepToTarget; if (Math.Abs(step) < minStep) { step = step > 0 ? minStep : -minStep; } this.curCameraElevation = this.curCameraElevation + step; } else { this.curCameraElevation = this.targetCameraElevation; } } else { this.curCameraElevation = 0; } // Absolute matrices this.ComputeAbsoluteMatrices(); // needs to be double precsion double radius = this.WorldRadius + this.curCameraElevation; double radCosLat = radius * Math.Cos(this._latitude.Radians); LookFrom = new Point3d(radCosLat * Math.Cos(this._longitude.Radians), radCosLat * Math.Sin(this._longitude.Radians), radius * Math.Sin(this._latitude.Radians)); // this constitutes a local tri-frame hovering above the sphere Point3d zAxis = LookFrom.normalize(); // on sphere the normal vector and position vector are the same Point3d xAxis = Point3d.cross(cameraUpVector, zAxis).normalize(); Point3d yAxis = Point3d.cross(zAxis, xAxis); this.ReferenceCenter = MathEngine.SphericalToCartesianD( Angle.FromRadians(Convert.ToSingle(this._latitude.Radians)), Angle.FromRadians(Convert.ToSingle(this._longitude.Radians)), this.WorldRadius); // Important step !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // In order to use single precsion rendering, we need to define a local frame (i.e. center of center tile, etc.) // Vector3d LocalCenter should be defined & initialized in the CameraBase class // Each time the camera moves, a new local center could be defined // The local center also has to be subtracted from all the terrain vertices!!!! relCameraPos = LookFrom - this.ReferenceCenter; // Important step: construct the single precision m_ViewMatrix by hand // We can build the m_ViewMatrix by hand this.m_ViewMatrix.M11 = (float)xAxis.X; this.m_ViewMatrix.M21 = (float)xAxis.Y; this.m_ViewMatrix.M31 = (float)xAxis.Z; this.m_ViewMatrix.M12 = (float)yAxis.X; this.m_ViewMatrix.M22 = (float)yAxis.Y; this.m_ViewMatrix.M32 = (float)yAxis.Z; this.m_ViewMatrix.M13 = (float)zAxis.X; this.m_ViewMatrix.M23 = (float)zAxis.Y; this.m_ViewMatrix.M33 = (float)zAxis.Z; this.m_ViewMatrix.M41 = -(float)(xAxis.X * relCameraPos.X + xAxis.Y * relCameraPos.Y + xAxis.Z * relCameraPos.Z); this.m_ViewMatrix.M42 = -(float)(yAxis.X * relCameraPos.X + yAxis.Y * relCameraPos.Y + yAxis.Z * relCameraPos.Z); this.m_ViewMatrix.M43 = -(float)(zAxis.X * relCameraPos.X + zAxis.Y * relCameraPos.Y + zAxis.Z * relCameraPos.Z); this.m_ViewMatrix.M14 = (float)0.0; this.m_ViewMatrix.M24 = (float)0.0; this.m_ViewMatrix.M34 = (float)0.0; this.m_ViewMatrix.M44 = (float)1.0; double cameraDisplacement = this._distance + this._headZoom; //if(cameraDisplacement < targetCameraElevation + minimumAltitude) // cameraDisplacement = targetCameraElevation + minimumAltitude; this.m_ViewMatrix *= Matrix.RotationYawPitchRoll( (float)-(this._swivel.Radians + this._headSwivel.Radians), (float)-(this._tilt.Radians + this._headTilt.Radians), (float)this._heading.Radians); //m_ViewMatrix *= Matrix.Translation(0, 0, (float)(-cameraDisplacement + curCameraElevation)); this.m_ViewMatrix *= Matrix.Translation(0, 0, (float)(-cameraDisplacement)); this.m_ViewMatrix *= Matrix.RotationZ((float)this._bank.Radians); // Extract camera position Matrix cam = Matrix.Invert(this.m_absoluteViewMatrix); this._position = new Vector3(cam.M41, cam.M42, cam.M43); }
WorldWindWFSPlacenameFile[] GetWFSFiles(double north, double south, double west, double east) { double tileSize = 0; //base the tile size on the max viewing distance double maxDistance = Math.Sqrt(this.m_maximumDistanceSq); double factor = maxDistance / this.m_parentWorld.EquatorialRadius; // True view range if (factor < 1) { tileSize = Angle.FromRadians(Math.Abs(Math.Asin(maxDistance / this.m_parentWorld.EquatorialRadius)) * 2).Degrees; } else { tileSize = Angle.FromRadians(Math.PI).Degrees; } tileSize = (180 / (int)(180 / tileSize)); if (tileSize == 0) { tileSize = 0.1; } //Log.Write(Log.Levels.Debug, string.Format("TS: {0} -> {1}", name, tileSize)); //not working for some reason... //int startRow = MathEngine.GetRowFromLatitude(south, tileSize); //int endRow = MathEngine.GetRowFromLatitude(north, tileSize); //int startCol = MathEngine.GetColFromLongitude(west, tileSize); //int endCol = MathEngine.GetColFromLongitude(east, tileSize); ArrayList placenameFiles = new ArrayList(); double currentSouth = -90; //for (int row = 0; row <= endRow; row++) while (currentSouth < 90) { double currentNorth = currentSouth + tileSize; if (currentSouth > north || currentNorth < south) { currentSouth += tileSize; continue; } double currentWest = -180; while (currentWest < 180) // for (int col = startCol; col <= endCol; col++) { double currentEast = currentWest + tileSize; if (currentWest > east || currentEast < west) { currentWest += tileSize; continue; } WorldWindWFSPlacenameFile placenameFile = new WorldWindWFSPlacenameFile(this.m_name, this.m_placenameBaseUrl, this.m_typename, this.m_labelfield, currentNorth, currentSouth, currentWest, currentEast, this.m_parentWorld, this.m_cache); int key = placenameFile.GetHashCode(); if (!this.m_fileHash.Contains(key)) { this.m_fileHash.Add(key, placenameFile); } else { placenameFile = (WorldWindWFSPlacenameFile)this.m_fileHash[key]; } placenameFiles.Add(placenameFile); currentWest += tileSize; } currentSouth += tileSize; } return((WorldWindWFSPlacenameFile[])placenameFiles.ToArray(typeof(WorldWindWFSPlacenameFile))); }
public static Point3d GetGeocentricPosition(System.DateTime utcDateTime) { if (World.Settings.SunSynchedWithTime) { // Sun synched with time and date double JD = getJulianDay(utcDateTime); double T = (JD - 2451545.0) / 36525; // number of Julian centuries since Jan 1, 2000, 12 UT double k = Math.PI / 180.0; double M = 357.52910 + 35999.05030 * T - 0.0001559 * T * T - 0.00000048 * T * T * T; // mean anomaly, degree double L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T * T; // mean longitude, degree double DL = (1.914600 - 0.004817 * T - 0.000014 * T * T) * Math.Sin(k * M) + (0.019993 - 0.000101 * T) * Math.Sin(k * 2 * M) + 0.000290 * Math.Sin(k * 3 * M); double L = L0 + DL; // true longitude, degree L = L % 360; // obliquity eps of ecliptic: double eps = 23.0 + 26.0 / 60.0 + 21.448 / 3600.0 - (46.8150 * T + 0.00059 * T * T - 0.001813 * T * T * T) / 3600; double X = Math.Cos(k * L); double Y = Math.Cos(k * eps) * Math.Sin(k * L); double Z = Math.Sin(k * eps) * Math.Sin(k * L); double R = Math.Sqrt(1.0 - Z * Z); double dec = (180 / Math.PI) * Math.Atan(Z / R); // in degrees double RA = (24 / Math.PI) * Math.Atan(Y / (X + R)); // in hours double theta0 = 280.46061837 + 360.98564736629 * (JD - 2451545.0) + 0.000387933 * T * T - T * T * T / 38710000.0; // Greenwich Sidereal Time theta0 = theta0 % 360; RA *= 15; // convert from hours to degrees double tau = theta0 - RA; Point3d pos = MathEngine.SphericalToCartesianD( Angle.FromDegrees(-dec), Angle.FromDegrees(-(tau - 180)), 1); return(pos); } else { // Fixed sun heading and elevation double worldRadius = 6378137; // Earth meter Vector3 position = MathEngine.SphericalToCartesian(World.Settings.CameraLatitude, World.Settings.CameraLongitude, worldRadius); return(GetGeocentricPosition(position, Angle.FromRadians(World.Settings.SunHeading), Angle.FromRadians(World.Settings.SunElevation), World.Settings.SunDistance)); } }
/// <summary> /// Returns the absolute value of the specified angle /// </summary> public static Angle Abs( Angle a ) { return Angle.FromRadians(Math.Abs(a.Radians)); }
public static Angle operator /(Angle a, double divisor) { return Angle.FromRadians(a.Radians / divisor); }
public static Angle operator *(double times, Angle a) { return Angle.FromRadians(a.Radians * times); }
public static Angle operator -(Angle a, Angle b) { double res = a.Radians - b.Radians; return Angle.FromRadians(res); }
public static Angle operator /(double divisor, Angle a) { return(Angle.FromRadians(a.Radians / divisor)); }
public static Angle operator *(Angle a, double times) { return(Angle.FromRadians(a.Radians * times)); }
public static Angle operator +(Angle a, Angle b) { double res = a.Radians + b.Radians; return(Angle.FromRadians(res)); }