在浩瀚的宇宙中,星星、行星、月亮和太阳的运行遵循着一定的规律。本文介绍的天文软件,能够根据开普勒定律计算这些天体在任意地点、任意日期和时间的位置,帮助用户在夜空中识别这些天体。尽管软件生成的星空图并非完美准确,但它对于定位夜空中的天体仍然非常有用。
几年前,将这款软件移植到了诺基亚的Series60 2nd Edition手机上。最近,决定将其代码移植到Windows Mobile平台。尽管已经有了C++代码,但决定使用.NET Compact Framework 2.0版本来开发这款应用,目标平台是Smartphone。这款应用可以在Windows Mobile 5和Windows Mobile 6设备上运行。
在Windows Mobile移植版本中,添加了一些有趣的功能,以增强用户体验:
要安装这款应用,只需解压zip文件,并将其中的文件复制到设备中的文件夹即可。
尽管相信用户可以在不阅读任何说明的情况下运行这款应用,但还是列出了一些常见操作。
当第一次运行这款应用时,它会从手机读取时区信息,并选择时区中最大的城市。可以通过“设置”菜单中的“位置”选项选择新的城市。只有时区中的城市会被列出。或者,可以使用面板微调位置。
默认情况下,应用会绘制与当前时间对应的天空图像,这是从手机读取的。天空图像每分钟更新一次。如果想构建过去或未来的某个时间的图像,可以在首选项对话框中取消选中“自动更新”框(通过选择“设置”菜单中的“首选项”来显示对话框)。然后使用面板选择时间。
默认情况下,应用会从手机读取这些信息。如果想手动设置,可以在“时间设置”对话框中取消选中自动框。当应用推断出夏令时生效时(无论是从手机还是手动设置),它会从当前时间中减去一个小时。这并不100%准确,但对于大多数情况来说是足够的。
当微调位置时,可能希望将其保存以供将来参考。可以通过选择“设置”菜单中的“位置”,然后选择“添加”来实现。需要为新位置定义名称、经度、纬度和时区。
应用从GPS中间驱动程序读取GPS信息。遗憾的是,并非所有智能手机都提供所需的GPS控制面板。在这种情况下,需要做一些额外的工作。建议参考一些外部链接(例如“配置设备以使用GPS”的MSDN文章和“在Windows Mobile 5上设置GPS”的博客文章)以获取信息。要开始使用GPS数据,请从菜单中选择GPS。一个显示从GPS接收器读取的信息的框将被显示。一旦GPS信号足够好以提取经度、纬度和时间,该框将消失,并将显示当前位置的天空图像。要停止使用GPS,请再次从菜单中选择GPS。如果GPS读取的信息有效,那么应用将继续使用相同的经度和纬度。然后可以继续使用这些值创建位置。
应用主要在夜间使用,与通常情况相反,背光可能并不理想。原因是在看向一个明亮的光源后,很难再去看夜空并定位星星和行星。因此,认为给用户提供禁用背光操作的选项是个好主意。可以通过首选项对话框来实现这一点,通过选中“背光关闭”框。请注意,这是一个实验性功能,可能不会在所有手机上工作。此外,即使在应用最小化后,更改也会应用,但不会在退出应用或软重置后保留。
这款应用是在Visual Studio 2005中使用Windows Mobile 5.0 SDK开发的。使用了Windows Mobile 6.0 SDK中的GPS示例。
真的不能说太多关于PlanetFinder引擎的事情,因为在移植时并没有试图完全理解背后的天文概念。然而,验证了Windows Mobile移植的结果与原始小程序的结果相匹配。
用户界面部分是一个标准的Mobile Windows Forms应用程序。尝试使用尽可能多的编程技术(在注册表中持久化用户的首选项,读取和写入位置到文件,切换到纬度和经度控件的数字输入),以给应用带来更专业的基调。
背光是通过调用DevicePowerNotify函数来控制的。创建了一个具有单个静态方法的类来启用/禁用背光,代码如下所示。调用Backlight.Enable(false);后,即使用户按下一些键,背光也会保持关闭状态。正如之前所说,这段代码可能不会在所有手机上工作。Windows Mobile规定背光驱动程序被称为"BKL1:",然而不同的驱动程序可能会以不同的方式处理电源状态,或者驱动程序可能不完全支持此操作。
public class Backlight {
static public void Enable(bool enable) {
if (enable) {
DevicePowerNotify("BKL1:", CEDevicePowerState.D0, 1);
} else {
DevicePowerNotify("BKL1:", CEDevicePowerState.D4, 1);
}
}
private enum CEDevicePowerState {
PwrDeviceUnspecified = -1,
D0 = 0,
D1 = 1,
D2 = 2,
D3 = 3,
D4 = 4,
PwrDeviceMaximum = 5
}
[DllImport("coredll.dll", SetLastError = true)]
extern private static IntPtr DevicePowerNotify(string pvDevice, CEDevicePowerState DeviceState, UInt32 StateFlags);
}