zoukankan      html  css  js  c++  java
  • [WorldWind学习]9.WW的屏幕坐标到经纬度坐标计算

     CameraBase类方法PickingRayIntersection:

    View Code
     1 /// <summary>
     2         /// Calculates latitude/longitude for given screen coordinate.
     3         /// </summary>
     4         public virtual void PickingRayIntersection(
     5             int screenX, 
     6             int screenY,
     7             out Angle latitude,
     8             out Angle longitude)
     9         {
    10             Vector3 v1 = new Vector3();
    11             v1.X = screenX;
    12             v1.Y = screenY;
    13             v1.Z = viewPort.MinZ;
    14             v1.Unproject(viewPort, m_absoluteProjectionMatrix, m_absoluteViewMatrix, m_absoluteWorldMatrix);
    15 
    16             Vector3 v2 = new Vector3();
    17             v2.X = screenX;
    18             v2.Y = screenY;
    19             v2.Z = viewPort.MaxZ;
    20             v2.Unproject(viewPort, m_absoluteProjectionMatrix, m_absoluteViewMatrix, m_absoluteWorldMatrix);
    21 
    22             Point3d p1 = new Point3d(v1.X, v1.Y, v1.Z);
    23             Point3d p2 = new Point3d(v2.X, v2.Y, v2.Z);
    24 
    25             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);
    26             double b = 2.0*((p2.X - p1.X)*(p1.X) + (p2.Y - p1.Y)*(p1.Y) + (p2.Z - p1.Z)*(p1.Z));
    27             double c = p1.X*p1.X + p1.Y*p1.Y + p1.Z*p1.Z - _worldRadius * _worldRadius;
    28 
    29             double discriminant = b*b - 4 * a * c;
    30             if(discriminant <= 0)
    31             {
    32                 latitude = Angle.NaN;
    33                 longitude = Angle.NaN;
    34                 return;
    35             }
    36 
    37             //    float t0 = ((-1.0f) * b + (float)Math.Sqrt(b*b - 4 * a * c)) / (2*a);
    38             double t1 = ((-1.0) * b - Math.Sqrt(b*b - 4 * a * c)) / (2*a);
    39 
    40             //    Vector3 i0 = new Vector3(p1.X + t0*(p2.X - p1.X), p1.Y + t0*(p2.Y - p1.Y), p1.Z + t0 *(p2.Z - p1.Z));
    41             Point3d i1 = new Point3d(p1.X + t1*(p2.X - p1.X), p1.Y + t1*(p2.Y - p1.Y), p1.Z + t1 *(p2.Z - p1.Z));
    42 
    43             //    Vector3 i0t = MathEngine.CartesianToSpherical(i0.X, i0.Y, i0.Z);
    44             Point3d i1t = MathEngine.CartesianToSphericalD(i1.X, i1.Y, i1.Z);
    45             Point3d mousePointer = i1t;
    46 
    47             latitude = Angle.FromRadians(mousePointer.Y);
    48             longitude = Angle.FromRadians(mousePointer.Z);
    49         }

    如下代码解释:

    1 Vector3 v1 = new Vector3();
    2 v1.X = screenX;
    3 v1.Y = screenY;
    4 v1.Z = viewPort.MinZ;
    5 v1.Unproject(viewPort, m_absoluteProjectionMatrix, m_absoluteViewMatrix, m_absoluteWorldMatrix);
    //屏幕坐标到世界坐标转换,取近截面
    1 Vector3 v2 = new Vector3();
    2 v2.X = screenX;
    3 v2.Y = screenY;
    4 v2.Z = viewPort.MaxZ;
    5 v2.Unproject(viewPort, m_absoluteProjectionMatrix, m_absoluteViewMatrix, m_absoluteWorldMatrix);
    //屏幕坐标到世界坐标转换,取远截面

    Point3d i1为计算得到的相交点。

    Point3d i1t = MathEngine.CartesianToSphericalD(i1.X, i1.Y, i1.Z);将世界坐标转换为经纬度。

    MathEngine
    using System;
    using Microsoft.DirectX;
    
    namespace WorldWind
    {
        /// <summary>
        /// Commonly used mathematical functions.
        /// </summary>
        public sealed class MathEngine
        {
            /// <summary>
            /// This class has only static methods.
            /// </summary>
            private MathEngine()
            {
            }
    
            /// <summary>
            /// Converts position in spherical coordinates (lat/lon/altitude) to cartesian (XYZ) coordinates.
            /// </summary>
            /// <param name="latitude">Latitude in decimal degrees</param>
            /// <param name="longitude">Longitude in decimal degrees</param>
            /// <param name="radius">Radius (OBS: not altitude)</param>
            /// <returns>Coordinates converted to cartesian (XYZ)</returns>
            public static Vector3 SphericalToCartesian(
                double latitude,
                double longitude,
                double radius
                )
            {
                latitude *= System.Math.PI / 180.0;
                longitude *= System.Math.PI /180.0;
    
                double radCosLat = radius * Math.Cos(latitude);
    
                return new Vector3(
                    (float)(radCosLat * Math.Cos(longitude)),
                    (float)(radCosLat * Math.Sin(longitude)),
                    (float)(radius * Math.Sin(latitude)) );
            }
    
            /// <summary>
            /// Converts position in spherical coordinates (lat/lon/altitude) to cartesian (XYZ) coordinates.
            /// </summary>
            /// <param name="latitude">Latitude (Angle)</param>
            /// <param name="longitude">Longitude (Angle)</param>
            /// <param name="radius">Radius (OBS: not altitude)</param>
            /// <returns>Coordinates converted to cartesian (XYZ)</returns>
            public static Vector3 SphericalToCartesian(
                Angle latitude,
                Angle longitude,
                double radius )
            {
                double latRadians = latitude.Radians;
                double lonRadians = longitude.Radians;
    
                double radCosLat = radius * Math.Cos(latRadians);
    
                return new Vector3(
                    (float)(radCosLat * Math.Cos(lonRadians)),
                    (float)(radCosLat * Math.Sin(lonRadians)),
                    (float)(radius * Math.Sin(latRadians)));
            }
    
            /// <summary>
            /// Converts position in spherical coordinates (lat/lon/altitude) to cartesian (XYZ) coordinates.
            /// </summary>
            /// <param name="latitude">Latitude (Angle)</param>
            /// <param name="longitude">Longitude (Angle)</param>
            /// <param name="radius">Radius (OBS: not altitude)</param>
            /// <returns>Coordinates converted to cartesian (XYZ)</returns>
            public static Point3d SphericalToCartesianD(
                Angle latitude,
                Angle longitude,
                double radius )
            {
                double latRadians = latitude.Radians;
                double lonRadians = longitude.Radians;
    
                double radCosLat = radius * Math.Cos(latRadians);
    
                return new Point3d(
                    radCosLat * Math.Cos(lonRadians),
                    radCosLat * Math.Sin(lonRadians),
                    radius * Math.Sin(latRadians));
            }
    
            /// <summary>
            /// Converts position in cartesian coordinates (XYZ) to spherical (lat/lon/radius) coordinates in radians.
            /// </summary>
            /// <returns>Coordinates converted to spherical coordinates.  X=radius, Y=latitude (radians), Z=longitude (radians).</returns>
            public static Vector3 CartesianToSpherical(float x, float y, float z)
            {
                double rho = Math.Sqrt((double)(x * x + y * y + z * z));
                float longitude = (float)Math.Atan2(y,x);
                float latitude = (float)(Math.Asin(z / rho));
                
                return new Vector3((float)rho, latitude, longitude);
            }
    
            public static Point3d CartesianToSphericalD(double x, double y, double z)
            {
                double rho = Math.Sqrt((double)(x * x + y * y + z * z));
                double longitude = Math.Atan2(y,x);
                double latitude = (Math.Asin(z / rho));
                
                return new Point3d(rho, latitude, longitude);
            }
            
            /// <summary>
            /// Converts an angle in decimal degrees to angle in radians
            /// </summary>
            /// <param name="degrees">Angle in decimal degrees (0-360)</param>
            /// <returns>Angle in radians (0-2*Pi)</returns>
            public static double DegreesToRadians(double degrees)
            {
                return Math.PI * degrees / 180.0;
            }
    
            /// <summary>
            /// Converts an angle in radians to angle in decimal degrees 
            /// </summary>
            /// <param name="radians">Angle in radians (0-2*Pi)</param>
            /// <returns>Angle in decimal degrees (0-360)</returns>
            public static double RadiansToDegrees(double radians)
            {
                return  radians * 180.0 / Math.PI;
            }
    
            /// <summary>
            /// Computes the angle (seen from the center of the sphere) between 2 sets of latitude/longitude values.
            /// </summary>
            /// <param name="latA">Latitude of point 1 (decimal degrees)</param>
            /// <param name="lonA">Longitude of point 1 (decimal degrees)</param>
            /// <param name="latB">Latitude of point 2 (decimal degrees)</param>
            /// <param name="lonB">Longitude of point 2 (decimal degrees)</param>
            /// <returns>Angle in decimal degrees</returns>
            public static double SphericalDistanceDegrees(double latA, double lonA, double latB, double lonB)
            {
                double radLatA = MathEngine.DegreesToRadians(latA);
                double radLatB = MathEngine.DegreesToRadians(latB);
                double radLonA = MathEngine.DegreesToRadians(lonA);
                double radLonB = MathEngine.DegreesToRadians(lonB);
    
                return MathEngine.RadiansToDegrees(
                    Math.Acos(Math.Cos(radLatA)*Math.Cos(radLatB)*Math.Cos(radLonA-radLonB)+Math.Sin(radLatA)*Math.Sin(radLatB)));
            }
    
            /// <summary>
            /// Computes the angular distance between two pairs of lat/longs.
            /// Fails for distances (on earth) smaller than approx. 2km. (returns 0)
            /// </summary>
            public static Angle SphericalDistance(Angle latA, Angle lonA, Angle latB, Angle lonB)
            {
                double radLatA = latA.Radians;
                double radLatB = latB.Radians;
                double radLonA = lonA.Radians;
                double radLonB = lonB.Radians;
    
                return Angle.FromRadians( Math.Acos(
                    Math.Cos(radLatA)*Math.Cos(radLatB)*Math.Cos(radLonA-radLonB)+
                    Math.Sin(radLatA)*Math.Sin(radLatB)) );
            }
    
            /// <summary>
            /// Calculates the azimuth from latA/lonA to latB/lonB
            /// Borrowed from http://williams.best.vwh.net/avform.htm
            /// </summary>
            public static Angle Azimuth( Angle latA, Angle lonA, Angle latB, Angle lonB )
            {
                double cosLatB = Math.Cos(latB.Radians);
                Angle tcA = Angle.FromRadians( Math.Atan2(
                    Math.Sin(lonA.Radians - lonB.Radians) * cosLatB,
                    Math.Cos(latA.Radians) * Math.Sin(latB.Radians) - 
                    Math.Sin(latA.Radians) * cosLatB * 
                    Math.Cos(lonA.Radians - lonB.Radians)));
                if(tcA.Radians < 0) 
                    tcA.Radians = tcA.Radians + Math.PI*2;
                tcA.Radians = Math.PI*2 - tcA.Radians;
    
                return tcA;
            }
    
            /// <summary>
            /// Transforms a set of Euler angles to a quaternion
            /// </summary>
            /// <param name="yaw">Yaw (radians)</param>
            /// <param name="pitch">Pitch (radians)</param>
            /// <param name="roll">Roll (radians)</param>
            /// <returns>The rotation transformed to a quaternion.</returns>
            public static Quaternion EulerToQuaternion(double yaw, double pitch, double roll)
            {
                double cy = Math.Cos(yaw * 0.5);
                double cp = Math.Cos(pitch * 0.5);
                double cr = Math.Cos(roll * 0.5);
                double sy = Math.Sin(yaw * 0.5);
                double sp = Math.Sin(pitch * 0.5);
                double sr = Math.Sin(roll * 0.5);
    
                double qw = cy*cp*cr + sy*sp*sr;
                double qx = sy*cp*cr - cy*sp*sr;
                double qy = cy*sp*cr + sy*cp*sr;
                double qz = cy*cp*sr - sy*sp*cr;
    
                return new Quaternion((float)qx, (float)qy, (float)qz, (float)qw);
            }
    
            /// <summary>
            /// Transforms a rotation in quaternion form to a set of Euler angles 
            /// </summary>
            /// <returns>The rotation transformed to Euler angles, X=Yaw, Y=Pitch, Z=Roll (radians)</returns>
            public static Vector3 QuaternionToEuler(Quaternion q)
            {
                double q0 = q.W;
                double q1 = q.X;
                double q2 = q.Y;
                double q3 = q.Z;
    
                double x = Math.Atan2( 2 * (q2*q3 + q0*q1), (q0*q0 - q1*q1 - q2*q2 + q3*q3));
                double y = Math.Asin( -2 * (q1*q3 - q0*q2));
                double z = Math.Atan2( 2 * (q1*q2 + q0*q3), (q0*q0 + q1*q1 - q2*q2 - q3*q3));
    
                return new Vector3((float)x, (float)y, (float)z);
            }
    
            /// <summary>
            /// Compute the tile number (used in file names) for given latitude and tile size.
            /// </summary>
            /// <param name="latitude">Latitude (decimal degrees)</param>
            /// <param name="tileSize">Tile size  (decimal degrees)</param>
            /// <returns>The tile number</returns>
            public static int GetRowFromLatitude(double latitude, double tileSize)
            {
                return (int)System.Math.Round((System.Math.Abs(-90.0 - latitude)%180)/tileSize, 1);
            }
    
            /// <summary>
            /// Compute the tile number (used in file names) for given latitude and tile size.
            /// </summary>
            /// <param name="latitude">Latitude (decimal degrees)</param>
            /// <param name="tileSize">Tile size  (decimal degrees)</param>
            /// <returns>The tile number</returns>
            public static int GetRowFromLatitude(Angle latitude, double tileSize)
            {
                return (int)System.Math.Round((System.Math.Abs(-90.0 - latitude.Degrees)%180)/tileSize, 1);
            }
    
            /// <summary>
            /// Compute the tile number (used in file names) for given longitude and tile size.
            /// </summary>
            /// <param name="longitude">Longitude (decimal degrees)</param>
            /// <param name="tileSize">Tile size  (decimal degrees)</param>
            /// <returns>The tile number</returns>
            public static int GetColFromLongitude(double longitude, double tileSize)
            {
                return (int)System.Math.Round((System.Math.Abs(-180.0 - longitude)%360)/tileSize, 1);
            }
    
            /// <summary>
            /// Compute the tile number (used in file names) for given longitude and tile size.
            /// </summary>
            /// <param name="longitude">Longitude (decimal degrees)</param>
            /// <param name="tileSize">Tile size  (decimal degrees)</param>
            /// <returns>The tile number</returns>
            public static int GetColFromLongitude(Angle longitude, double tileSize)
            {
                return (int)System.Math.Round((System.Math.Abs(-180.0 - longitude.Degrees)%360)/tileSize, 1);
            }
    
            /// <summary>
            /// Computes the distance between a point and a plane.
            /// </summary>
            /// <param name="p">Plane</param>
            /// <param name="v">Point (XYZ coordinates)</param>
            /// <returns>The shortest distance between the point and the plane.</returns>
            public static float DistancePlaneToPoint(Plane p, Vector3 v)
            {
                return p.A * v.X + p.B * v.Y + p.C + v.Z + p.D;
            }
    
            /// <summary>
            /// Computes the hypotenuse (sqrt(x?y?).
            /// </summary>
            public static double Hypot( double x, double y )
            {
                return Math.Sqrt(x*x + y*y);
            }
    
    /*
            public static Quaternion GetWorldQuaternion(double latitude, double longitude)
            {
                return Quaternion.RotationYawPitchRoll((float)-MathEngine.DegreesToRadians(latitude),0.0f, (float)-MathEngine.DegreesToRadians(longitude));
            }
    
            public static Quaternion GetViewQuaternion(float eyeTilt, float eyeDirection)
            {
                Quaternion q1 = Quaternion.RotationAxis(new Vector3(0,0,-1), eyeDirection * (float)Math.PI / 180.0f);
                Quaternion q2 = Quaternion.RotationAxis(new Vector3(1,0,0), eyeTilt * (float)Math.PI / 180.0f);
                return Quaternion.Multiply(q1, q2);
            }
    */
        }
    }

     

    d·(P-C) 和(P-C)·(P-C)是向量数量积。求出来的t实际是一个比例的概念,或者说长度,距离起点P的长度。

    文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。 欢迎大家留言交流,转载请注明出处。
  • 相关阅读:
    three.js中 用 鼠标点击+呼吸灯
    socket.io学习以及在vuehtml使用,node搭建的后台
    网路在线古诗文免费阅读网站
    vue-element-admin默认加载Dashboard更改
    vue-element-admin后台框架侧边蓝图标添加自定义
    吸顶操作vue
    对图片进行裁剪(vueCropper)图片不显示
    ucharts使用内容
    文字转换为语音在线免费工具连接
    tree.js外部骨骼动画
  • 原文地址:https://www.cnblogs.com/yhlx125/p/3017300.html
Copyright © 2011-2022 走看看