定位功能分析,在PlaceFinder类里面
private void buttonGo_Click(object sender, System.EventArgs e)
{
try
{
double lat = double.Parse(this.textBoxLatitude.Text);
double lon = double.Parse(this.textBoxLongitude.Text);
double alt = (double)this.numericUpDownAltitude.Value;
m_WorldWindow.GotoLatLonAltitude(lat, lon, alt);
}
catch{}
}
调用了 m_WorldWindow.GotoLatLonAltitude(lat, lon, alt); 在WorldWindow类里面的GotoLatLonAltitude函数如下:
public void GotoLatLonAltitude(double latitude, double longitude, double altitude)
{
this.drawArgs.WorldCamera.SetPosition(latitude, longitude,
this.drawArgs.WorldCamera.Heading.Degrees,
altitude,
this.drawArgs.WorldCamera.Tilt.Degrees);
}
是WorldWindow对象的drawArgs属性的WorldCamera对象来控制的。而WorldCamera类继承自CameraBase类。在CameraBase类中才是具体的实现功能的代码:
///<summary>
/// Sets camera position.
///</summary>
///<param name="lat">Latitude in decimal degrees</param>
///<param name="lon">Longitude in decimal degrees</param>
///<param name="heading">Heading in decimal degrees</param>
///<param name="_altitude">Altitude above ground level in meters</param>
///<param name="tilt">Tilt in decimal degrees</param>
///<param name="bank">Camera bank (roll) in decimal degrees</param>
public virtual void SetPosition(double lat, double lon, double heading, double _altitude, double tilt, double bank)
{
if (double.IsNaN(lat)) lat = this._latitude.Degrees;
if (double.IsNaN(lon)) lon = this._longitude.Degrees;
if (double.IsNaN(heading)) heading = this._heading.Degrees;
if (double.IsNaN(bank)) bank = this._bank.Degrees;
m_Orientation = Quaternion4d.EulerToQuaternion(
MathEngine.DegreesToRadians(lon),
MathEngine.DegreesToRadians(lat),
MathEngine.DegreesToRadians(heading));
Point3d p = Quaternion4d.QuaternionToEuler(m_Orientation);
_latitude.Radians = p.Y;//位置参数,私有变量赋值
_longitude.Radians = p.X;
_heading.Radians = p.Z;
if (!double.IsNaN(tilt))
Tilt = Angle.FromDegrees(tilt);
if (!double.IsNaN(_altitude))
this.Altitude = _altitude;
this.Bank = Angle.FromDegrees(bank);
}
在上面这个函数里面进行了空值判断后,就开始给私有变量赋值,如经纬度等。但是到此并没有具体的"飞行"操作!查看CameraBase类的代码。发现有Update函数如下:
public virtual void Update(Device device)
{
viewPort = device.Viewport;
Point3d p = Quaternion4d.QuaternionToEuler(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;
ComputeProjectionMatrix(viewPort);
ComputeViewMatrix();
device.Transform.Projection = m_ProjectionMatrix;
device.Transform.View = m_ViewMatrix;
device.Transform.World = m_WorldMatrix;
ViewFrustum.Update(
Matrix.Multiply(m_absoluteWorldMatrix,
Matrix.Multiply(m_absoluteViewMatrix, m_absoluteProjectionMatrix)));
// Old view range (used in quadtile logic)
double factor = (this._altitude) / this._worldRadius;
if(factor > 1)
viewRange = Angle.FromRadians(Math.PI);
else
viewRange = Angle.FromRadians(Math.Abs(Math.Asin((this._altitude) / this._worldRadius))*2);
// True view range
if(factor < 1)
trueViewRange = Angle.FromRadians(Math.Abs(Math.Asin((this._distance) / this._worldRadius))*2);
else
trueViewRange = Angle.FromRadians(Math.PI);
World.Settings.cameraAltitudeMeters = Altitude;
World.Settings.cameraLatitude = _latitude;
World.Settings.cameraLongitude = _longitude;
World.Settings.cameraHeading = _heading;
World.Settings.cameraTilt = _tilt;
}
在里面可以看到ComputeProjectionMatrix(viewPort); 和ComputeViewMatrix();计算了投影变换和视图变换等。 在这2个函数里用了改变后的位置参数(经纬度,高度等)。然后再看一下Update函数在什么地方被调用:WoldWindow类的Render函数中被调用。再看一下Render函数:
1, protected override void OnPaint(PaintEventArgs e)
2,public void OnApplicationIdle(object sender, EventArgs e)
第一个就不用说了,窗体重绘函数。第二个是防止程序过度休眠的消息响应函数里。在程序启动时,就绑定了:
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
MainApplication app = new MainApplication();
好了,绕了一大圈,总结一下:
1,CameraBase类是管理与虚拟相机位置相关信息的类,里面既包括如下:
a,经纬度,高度,视角,角度,倾斜度等等位置/视角变量。
b,各种变化矩阵和计算矩阵的函数,计算的参数由a中变量提供
c,漫游相关的函数,包括平移,放大,缩小,移位(PointGoto)等功能,所做的操作也是依据用户操作修改a中的变量
d,刷新/重置的函数
e,其他
当需要改变位置时,调用的是WorldWindow对象的drawArgs的WorldCamera函数,传入参数即可。在程序窗体Paint函数刷新界面时会自动进行视角变换及相关必须的计算。