65.9K
CodeProject 正在变化。 阅读更多。
Home

轨道力学简介:第二部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2019年1月16日

CPOL

10分钟阅读

viewsIcon

11444

downloadIcon

578

轨道力学简介 - 二体问题 WPF

引言

轨道力学第一部分中,我描述了轨道力学的基础知识,并使用OpenGL渲染3D图形的程序。在第二部分中,我编写了一个类似的程序,使用WPF(Windows Presentation Foundation)进行3D图形渲染。用户界面略有不同,我还添加了另一个轨道参数,即近拱点幅角,它是轨道平面内椭圆的方位,从升交点测量到近拱点,即卫星离行星最近的点。

Using the Code

下载并解压项目,然后用Visual Studio打开OrbitMechWPF.sln。它由一个单独的项目组成。在运行程序之前,您需要首先在app.config中设置纹理文件在您机器上的位置,例如

<setting name="TextureFileLocation" serializeAs="String">
	<value>C:\MyProjects\OrbitMechWPF\Textures\</value>
</setting>

修改并保存app.config后,从Visual Studio主菜单中使用“生成”->“重新生成解决方案”来构建解决方案。使用Ctrl-F5不带调试启动,并显示一个WPF窗体,如上图所示。

轨道参数

使用表单左上角的滑块控件,您可以通过此程序修改的五个轨道参数是

  1. 偏心率 - 轨道椭圆的偏心率
  2. 倾角 - 椭圆相对于轨道平面的垂直倾斜度,在升交点(轨道向上穿过轨道平面的位置)测量
  3. 半长轴 - 轨道椭圆的半长轴
  4. 升交点经度(Omega,Ω) - 水平定向椭圆的升交点
  5. 近拱点幅角 - 定义椭圆在轨道平面内的方位,是从升交点到近拱点测量的角度

当您更改轨道参数时,相应的计算轨道值 - 远地点、近地点、轨道周期和半短轴 - 将显示在滑块下方的标签中。

轨道参数可以按任何顺序设置。让我们首先通过使用“文件”->“打开”打开设置文件SampleOrbitMechWPFSettingsFile.txt(设置文件在下方讨论)将偏心率设置为0.35,半长轴设置为13200公里。接下来,使用滑块或在文本框中输入值将倾角设置为30°。轨道平面将倾斜30°,如下图所示。

接下来,使用滑块或在文本框中输入值将近拱点幅角设置为20°。黄色区域显示轨道椭圆旋转了20°,如下图所示(实际颜色可通过ArgumentOfPeriapsisColorFront设置进行配置,如下方所述)。请注意表示Omega的经度线如何位于0°并与X轴相交。

最后,使用滑块将升交点经度(Omega,Ω)设置为西经40°(Omega的文本框是只读的)。请注意经度线显示在西经40°,大约是巴西佩特罗利纳的经度。西经意味着Omega的值为40;Omega值表示东经。轨道现在应该如下图所示(请注意,我们已经旋转了相机θ并稍微放大了)。

这五个轨道参数封装在OrbitalParameters类中,以及计算出的轨道量(如轨道周期)和WPF坐标中椭圆的半长轴和半短轴,即SemiMajorAxisScaledSemiMinorAxisScaled

public class OrbitalParameters
{
	// the "big five"
	public float Inclination { get; set; }
	public float SemiMajorAxis { get; set; }
	public double Eccentricity { get; set; }
	public float Omega { get; set; } // Longitude of Ascending Node - angle Ω, large Omega
	public float ArgumentOfPeriapsis { get; set; } // angle ω, small omega

	// computed
	public float SemiMinorAxis { get; set; }
	public double Perigee { get; set; }
	public double Apogee { get; set; }
	public double Period { get; set; } // Orbital period [seconds]
		
	// optionally computed if Eccentricity and SemiMajorAxis are -1
	public float MaxAltitude { get; set; }
	public float MinAltitude { get; set; }

	// for actual drawing of ellipse in "GL" or "WPF" units
	public float AxisScaleFactor { get; set; }
	public float SemiMajorAxisScaled { get; set; }
	public float SemiMinorAxisScaled { get; set; }
	public double Focus { get; set; }
	public double PlanetRadiusKM { get; set; }
	public double Mu { get; set; }
}

菜单栏

菜单栏有四个项目:文件视图相机帮助

文件

在“文件”下,有四个选项

  1. 打开...”:允许您打开以前保存的设置文件
  2. 另存为...”:允许您将设置保存到文本文件
  3. 重置”:将轨道参数和颜色设置为Properties.Settings.Default中的设置
  4. 退出”:退出程序

视图

与第一部分一样,使用菜单栏上的“视图”,您可以切换轴、行星和轨道平面的绘制。在此版本中,您还可以切换背景、椭圆、升交点经度和“手电筒”的绘制。背景是一个应用了纹理的盒子,手电筒显示定向光。背景和手电筒的代码均取自我的WPF 3D 中的裁剪平面项目。

相机

使用菜单栏上的“相机”,您可以

  • 打开相机设置对话框,设置相机的位置(倾斜(Φ)、旋转(ϴ)和缩放距离)。
  • 将相机移动到沿正负X、Y或Z轴方向。

与第一部分一样,作为使用相机设置对话框的替代方法,相机可以通过使用左、右、上、下、加和减键进行移动

  • 上/下箭头:将相机倾斜 phi (Φ) 度
  • 右/左箭头:将相机旋转 theta (ϴ) 度
  • 加/减号:将相机放大/缩小 R 个单位

在第二部分中,您还可以平移相机

  • Ctrl 左箭头:沿 -X 轴平移相机
  • Ctrl 右箭头:沿 +X 轴平移相机
  • Shift 上箭头:沿 +Y 轴平移相机
  • Shift 下箭头:沿 -Y 轴平移相机
  • Shift 左箭头:沿 -Z 轴平移相机
  • Shift 右箭头:沿 +Z 轴平移相机

六个相机设置显示在表单的左上角。phi、theta 和 R 的计算包含在Camera类中,该类使用Media3D PerspectiveCamera类。您可以使用“重置相机”按钮或菜单栏中的“重置相机”将相机重置为默认设置。

帮助

菜单栏上的“帮助”显示一条消息,描述了用于定位相机和显示模型的按键。

3D 图形和 WPF

与OpenGL类似,WPF中的模型由一组三角形构成。这些三角形被添加到Media3D.MeshGeometry3D对象中,网格反过来又用于创建Media3D.GeometryModel3D对象,这是一种Media3D对象。例如,由DrawOrbitalPlane()方法创建的轨道平面是一个由两个直角三角形组成的矩形。该矩形是Rectangle3D类的一个实例,它只是矩形的4个顶点数组,其中每个顶点都是一个Point3D

public class Rectangle3D
{
	public Point3D[] Points;
	public Rectangle3D(Point3D point1, Point3D point2, Point3D point3, Point3D point4)
	{
		Points = new Point3D[] { point1, point2, point3, point4 };
	}
}

第一步是创建包含椭圆的Rectangle3D(请注意,我们将其绘制在XZ平面,因此Y坐标为零)

Rectangle3D rectOrbitalPlane = new Rectangle3D(
	new Point3D(+orbitalParameters.SemiMajorAxisScaled, +0.0, 
                -orbitalParameters.SemiMinorAxisScaled),
	new Point3D(-orbitalParameters.SemiMajorAxisScaled, +0.0, 
                -orbitalParameters.SemiMinorAxisScaled),
	new Point3D(+orbitalParameters.SemiMajorAxisScaled, +0.0, 
                +orbitalParameters.SemiMinorAxisScaled),
	new Point3D(-orbitalParameters.SemiMajorAxisScaled, +0.0, 
                +orbitalParameters.SemiMinorAxisScaled));

下一步是将三角形添加到网格中。3D 图形中的一个关键问题是使三角形顶点的环绕顺序正确(WPF 为逆时针,或“右手定则”)。由于轨道平面有正面和背面颜色,因此很容易看出当环绕顺序与预期相反时会发生什么。要实际查看此效果,请暂时OrbitalPlane.cs中添加第二个三角形的行从

meshPlane.AddTriangle(rectOrbitalPlane.Points[3], 
                      rectOrbitalPlane.Points[2], rectOrbitalPlane.Points[1]);

改为(即,交换最后两个点)

meshPlane.AddTriangle(rectOrbitalPlane.Points[3], 
                      rectOrbitalPlane.Points[1], rectOrbitalPlane.Points[2]);

并重新生成并重新运行解决方案。您将观察到第二个三角形的背面颜色在前,反之亦然。请记住将AddTriangle回调更改为正确的方向并重新生成解决方案!(感谢Rod Stephens的AddTriangle()方法。)

下一步是使用我们刚刚添加了三角形的网格创建一个GeometryModel3D对象。我们将使用接受材质(在此示例中为纯色)的构造函数来使模型可见。

Color frontColor = Properties.Settings.Default.OrbitPlaneColorFront;
Brush orbitalPlaneBrushFront = new SolidColorBrush(frontColor);
DiffuseMaterial orbitalPlaneMaterialFront = new DiffuseMaterial(orbitalPlaneBrushFront);
GeometryModel3D modelOrbitalPlane = new GeometryModel3D(meshPlane, orbitalPlaneMaterialFront);

这样创建的GeometryModel3DDrawOrbitalPlane()方法返回。

Model类包含程序显示的Media3D.Model3D模型

public static class Model
{
	public static Model3D directionalLightModel1 { get; set; }
	public static Model3D directionalLightModel2 { get; set; }
	public static Model3D[] axesModels { get; set; }
	public static Model3D[] backgroundModels { get; set; }
	public static Model3D[] ellipseModels { get; set; }
	public static Model3D[] lightModels1 { get; set; }
	public static Model3D[] lightModels2 { get; set; }
	public static Model3D orbitalPlaneModel { get; set; }
	public static Model3D planetModel { get; set; }
	public static GeometryModel3D longitude { get; set; }
}

模型在InitScene()方法中创建。(有一个类似的方法可以从保存的设置文件创建模型,InitScene(String settings))。例如,要创建轨道平面模型,调用前面提到的DrawOrbitalPlane()方法

	Model.orbitalPlaneModel = OrbitalPlane.DrawOrbitalPlane(orbitalParameters);

Media3D.Model3DGroup对象是一组被视为单个模型的3D模型。在DrawScene()方法中,通过移除所有模型来初始化Model3DGroup modelGroupmodelGroup.Children.Clear()。然后,根据哪些模型处于开启状态,将它们添加到modelGroupModel3DCollection中。例如,如果轨道平面开启,则将其添加到集合中,如下所示

	if (orbitalPlaneOn)
	{
		modelGroup.Children.Add(Model.orbitalPlaneModel);
	}

一个类似但更复杂的模型是行星(二体问题中质量较大的物体)。与刚刚描述的轨道平面一样,它由三角形、这些三角形的网格和材质构成。将网格(及其包含的许多三角形)和材质与纹理结合起来,DrawPlanet()方法
如果行星开启,则返回一个GeometryModel3D对象,并将其添加到modelGroupModel3DCollection

	Model.planetModel = Planet.DrawPlanet(planetRadiusGLUnits, textureFileDir, textureFile, 180.0);
	...
	if (planetOn)
	{
		modelGroup.Children.Add(Model.planetModel);
	}

可以通过使用表单左上角的行星纹理组合框选择纹理来设置行星的纹理。与第一部分中使用的相同行星纹理位于Textures\Planets目录中。(感谢Rod Stephens绘制球体纹理的代码,MakeSphere()。我通过添加一个额外的参数double axisRotationDeg对其进行了修改。通过将其设置为180°,XYZ轴分别与零度经度、九十度经度和北极对齐。X轴是测量Omega的参考方向。我还添加了一个DrawLongitude()方法来绘制表示Omega的经度线。)

请注意,与OpenGL不同,WPF没有3D线绘制基元。因此,为了绘制椭圆、半长轴和半短轴以及表示Omega的经度线,我使用了长而细的三角形。您可以使用下方描述的LineThickness设置来设置线的粗细。

3D 变换

在我的裁剪平面第三部分项目中,我描述了3D变换矩阵以及如何围绕轴旋转模型。在此项目中,我将旋转变换封装在Utility.cs中一个名为Transform(OrbitalParameters orbitalParameters)static方法中。例如,以下是该方法中用于将轨道平面按轨道倾角旋转的代码片段

	RotateTransform3D xRotateTransform3D = new RotateTransform3D();
	AxisAngleRotation3D xAxisAngleRotation3d = new AxisAngleRotation3D();
	xAxisAngleRotation3d.Axis = new Vector3D(1.0, 0.0, 0.0);
	xAxisAngleRotation3d.Angle = orbitalParameters.Inclination;
	xRotateTransform3D.Rotation = xAxisAngleRotation3d;
	Transform3DGroup orbitTransformGroup = new Transform3DGroup();
	orbitTransformGroup.Children.Add(xRotateTransform3D);
	return orbitTransformGroup;

Omega和近拱点幅角的变换类似。在旋转之前,有一个平移,使椭圆的焦点位于原点(行星和XYZ轴的中心)

	TranslateTransform3D xTranslateTransform3D = new TranslateTransform3D();
	xTranslateTransform3D.OffsetX = -orbitalParameters.Focus;

配置文件

app.config中有几个设置可以自定义OrbitMechWPF。如前所述,在运行程序之前,您必须首先设置Texture文件在您机器上的位置,例如

<setting name="TextureFileLocation" serializeAs="String">
	<value>C:\MyProjects\OrbitMechWPF\Textures\</value>
</setting>

这些设置分为以下几类

  1. 视图设置
  2. 相机设置
  3. 轨道参数
  4. 颜色和纹理

配置文件 - 视图设置

<setting name="AxesOn" serializeAs="String">
	<value>True</value>
</setting>
<setting name="BackgroundOn" serializeAs="String">
	<value>True</value>
</setting>
<setting name="EllipseOn" serializeAs="String">
	<value>True</value>
</setting>
<setting name="FlashlightsVisible" serializeAs="String">
	<value>False</value>
</setting>
<setting name="OrbitalPlaneOn" serializeAs="String">
	<value>True</value>
</setting>
<setting name="PlanetOn" serializeAs="String">
	<value>True</value>
</setting>
<setting name="LongitudeOn" serializeAs="String">
	<value>True</value>
</setting>

配置文件 - 相机

相机参数可以按如下所示设置

<setting name="CameraTheta" serializeAs="String">
	<value>70</value>
</setting>
<setting name="CameraPhi" serializeAs="String">
	<value>10</value>
</setting>
<setting name="CameraR" serializeAs="String">
	<value>27</value>
</setting>

配置文件 - 轨道参数

轨道参数可以按如下所示设置(如果您对其中任何一个不熟悉,可能需要参考轨道力学第一部分

<setting name="Eccentricity" serializeAs="String">
	<value>0.35</value>
</setting>
<setting name="Inclination" serializeAs="String">
	<value>30</value>
</setting>
<setting name="Omega" serializeAs="String">
	<value>-80</value>
</setting>
<setting name="ArgumentOfPeriapsis" serializeAs="String">
	<value>20</value>
</setting>
<setting name="SemiMajorAxis" serializeAs="String">
	<value>13200</value>
</setting>
<setting name="MaxAltitude" serializeAs="String">
	<value>297</value>
</setting>
<setting name="MinAltitude" serializeAs="String">
	<value>111</value>
</setting>
<setting name="PlanetRadiusKM" serializeAs="String">
	<value>6371.1</value>
</setting>
<setting name="Mu" serializeAs="String">
	<value>398600.8</value>
</setting>

配置文件 - 颜色、纹理、线宽

颜色、纹理和线宽可以按如下所示设置

<setting name="TextureFileLocation" serializeAs="String">
	<value>C:\MtProjects\OrbitMechWPF\Textures\</value>
</setting>
<setting name="PlanetTexture" serializeAs="String">
	<value>earth.jpg</value>
</setting>
<setting name="OrbitPlaneColorFront" serializeAs="String">
	<value>#04787878</value>
</setting>
<setting name="OrbitPlaneColorBack" serializeAs="String">
	<value>#44FF0000</value>
</setting>
<setting name="BackgroundColor" serializeAs="String">
	<value>#FF808080</value>
</setting>
<setting name="EllipseColorBack" serializeAs="String">
	<value>#BB00EEEE</value>
</setting>
<setting name="EllipseColorFront" serializeAs="String">
	<value>#FF0000FF</value>
</setting>
<setting name="LineThickness" serializeAs="String">
	<value>0.05</value>
</setting>
<setting name="LongitudeColor" serializeAs="String">
	<value>#FF000000</value>
</setting>
<setting name="ArgumentOfPeriapsisColorFront" serializeAs="String">
	<value>#55F5FF44</value>
</setting>
<setting name="ArgumentOfPeriapsisColorBack" serializeAs="String">
	<value>#55FFC61C</value>
</setting>

设置文件

您可以保存您的

  • 当前视图(轴开/关、背景开/关、椭圆开/关、手电筒可见/不可见、经度开/关、轨道平面开/关以及行星开/关)
  • 轨道参数(偏心率、倾角、半长轴、Omega 和近拱点幅角)
  • 相机设置(CameraTheta、CameraPhi 和 CameraR)
  • 为行星选择的纹理文件的名称
  • 手电筒位置和颜色

通过菜单栏中的“文件”->“另存为...”将其保存到文本文件中。该文件包含一个逗号分隔的值列表,前面带有一个Md5哈希。稍后启动OrbitMechWPF时,您可以通过使用“文件”->“打开...”并指定文本文件的名称来从该文件恢复您的设置。

历史

  • 版本 2.2.0.1
© . All rights reserved.