Flutter天文计算插件sweph的使用
Flutter天文计算插件sweph的使用
Sweph
跨平台的Swiss Ephemeris API绑定,适用于Dart和Flutter。 使用该库可以创建天文学和占星学应用程序。
- 100% API覆盖
- Dart友好的参数和返回值
- 支持所有平台。非Web平台使用ffi,Web平台使用wasm_ffi
- 使用的原始Swiss Ephemeris版本作为构建号参考
参考资料
使用示例
import 'package:flutter/material.dart';
import 'package:sweph/sweph.dart';
import 'web_helper.dart' if (dart.library.ffi) 'io_helper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final stopwatch = Stopwatch()..start();
// 只加载所需的资产。默认情况下将加载无
// 某些资产与Sweph捆绑在一起
await initSweph([
'packages/sweph/assets/ephe/seas_18.se1', // 用于房屋计算
'packages/sweph/assets/ephe/sefstars.txt', // 用于星星位置
'packages/sweph/assets/ephe/seasnam.txt', // 用于小行星
]);
runApp(MyApp(
timeToLoad: stopwatch.elapsed,
));
}
class MyApp extends StatefulWidget {
final Duration timeToLoad;
const MyApp({super.key, required this.timeToLoad});
[@override](/user/override)
// ignore: library_private_types_in_public_api
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String swephVersion = Sweph.swe_version();
String moonPosition = getMoonPosition();
String starDistance = getStarPosition();
String asteroidName = getAstroidName();
HouseCuspData houseSystemAscmc = getHouseSystemAscmc();
CoordinatesWithSpeed chironPosition = getChironPosition();
DegreeSplitData degreeSplitData = Sweph.swe_split_deg(
100,
SplitDegFlags.SE_SPLIT_DEG_ZODIACAL |
SplitDegFlags.SE_SPLIT_DEG_ROUND_SEC |
SplitDegFlags.SE_SPLIT_DEG_KEEP_SIGN |
SplitDegFlags.SE_SPLIT_DEG_KEEP_DEG,
);
HouseCuspData houseCuspData = Sweph.swe_houses_ex2(
Sweph.swe_julday(2000, 1, 1, 12, CalendarType.SE_GREG_CAL),
SwephFlag.SEFLG_TROPICAL,
30,
60,
Hsys.B,
);
List<double> utcJds = Sweph.swe_utc_to_jd(
2000,
1,
1,
12,
0,
0,
CalendarType.SE_GREG_CAL,
);
AltitudeRefracInfo altInfo =
Sweph.swe_refrac(80, 1013.25, 15, RefractionMode.SE_APP_TO_TRUE);
AltitudeRefracInfo altInfoEx = Sweph.swe_refrac_extended(
100, 200, 1013.25, 15, 0.0065, RefractionMode.SE_APP_TO_TRUE);
[@override](/user/override)
void initState() {
super.initState();
}
static String getMoonPosition() {
final jd =
Sweph.swe_julday(2022, 6, 29, (2 + 52 / 60), CalendarType.SE_GREG_CAL);
final pos =
Sweph.swe_calc_ut(jd, HeavenlyBody.SE_MOON, SwephFlag.SEFLG_SWIEPH);
return 'lat=${pos.latitude.toStringAsFixed(3)} lon=${pos.longitude.toStringAsFixed(3)}';
}
static String getStarPosition() {
final jd =
Sweph.swe_julday(2022, 6, 29, (2 + 52 / 60), CalendarType.SE_GREG_CAL);
try {
return Sweph.swe_fixstar2_ut('Rohini', jd, SwephFlag.SEFLG_SWIEPH)
.coordinates
.distance
.toStringAsFixed(3);
} catch (e) {
return e.toString();
}
}
static String getAstroidName() {
return Sweph.swe_get_planet_name(HeavenlyBody.SE_AST_OFFSET + 16);
}
static HouseCuspData getHouseSystemAscmc() {
const year = 1947;
const month = 8;
const day = 15;
const hour = 16 + (0.0 / 60.0) - 5.5;
const longitude = 81 + 50 / 60.0;
const latitude = 25 + 57 / 60.0;
final julday =
Sweph.swe_julday(year, month, day, hour, CalendarType.SE_GREG_CAL);
Sweph.swe_set_sid_mode(SiderealMode.SE_SIDM_LAHIRI,
SiderealModeFlag.SE_SIDBIT_NONE, 0.0 /* t0 */, 0.0 /* ayan_t0 */);
return Sweph.swe_houses(julday, latitude, longitude, Hsys.P);
}
static CoordinatesWithSpeed getChironPosition() {
final now = DateTime.now();
final jd = Sweph.swe_julday(now.year, now.month, now.day,
(now.hour + now.minute / 60), CalendarType.SE_GREG_CAL);
Sweph.swe_julday(2022, 6, 29, (2 + 52 / 60), CalendarType.SE_GREG_CAL);
return Sweph.swe_calc_ut(
jd, HeavenlyBody.SE_CHIRON, SwephFlag.SEFLG_SWIEPH);
}
void _addText(List<Widget> children, String text) {
const textStyle = TextStyle(fontSize: 25);
const spacerSmall = SizedBox(height: 10);
children.add(spacerSmall);
children.add(Text(
text,
style: textStyle,
textAlign: TextAlign.center,
));
}
Widget _getContent(BuildContext context) {
List<Widget> children = [
const Text(
'Swiss Ephemeris Example',
style: TextStyle(fontSize: 30),
textAlign: TextAlign.center,
),
const SizedBox(height: 10)
];
_addText(children,
'Time taken to load Sweph: ${widget.timeToLoad.inMilliseconds} ms');
_addText(children, 'Sweph Version: $swephVersion');
_addText(
children, 'Moon position on 2022-06-29 02:52:00 UTC: $moonPosition');
_addText(children, 'Distance of star Rohini: $starDistance AU');
_addText(children, 'Name of Asteroid 16: $asteroidName');
_addText(children, 'Position of Chiron: $chironPosition');
_addText(children,
'House System ASCMC[0] for custom time: ${houseSystemAscmc.ascmc[0]}');
_addText(children, 'Degree Split Data: $degreeSplitData');
_addText(children, 'House Cusp Data: ${houseCuspData.cusps.sublist(0, 6)}');
_addText(children,
'TT: ${utcJds[0]} UT1: ${utcJds[1]} UTC: ${Sweph.swe_julday(2000, 1, 1, 12, CalendarType.SE_GREG_CAL)}}');
_addText(children, 'AltInfo: $altInfo');
_addText(children, 'AltInfoEx: $altInfoEx');
return Column(children: children);
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Native Packages'),
),
body: SingleChildScrollView(
child: Center(
child: Container(
padding: const EdgeInsets.all(10), child: _getContent(context)),
),
),
),
);
}
}
更多关于Flutter天文计算插件sweph的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter天文计算插件sweph的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,关于在Flutter项目中使用sweph
(Swiss Ephemeris Wrapper for Python)进行天文计算,虽然sweph
本身是一个Python库,但我们可以通过一些方法来在Flutter中调用Python代码。通常,这可以通过使用平台通道(Platform Channels)来实现。以下是一个基本的示例,展示如何在Flutter中调用Python脚本进行天文计算。
由于Flutter原生不支持直接运行Python代码,我们需要一个中介层,比如使用Flutter
的MethodChannel
与原生代码(如Android的Java/Kotlin或iOS的Swift/Objective-C)进行通信,而这些原生代码再调用Python脚本。
步骤 1: 设置Flutter项目
首先,确保你已经创建了一个Flutter项目。如果还没有,可以使用以下命令创建一个新项目:
flutter create astro_app
cd astro_app
步骤 2: 在Android平台上调用Python脚本
2.1 添加依赖
在android/app/build.gradle
文件中,添加对chaquopy
的依赖,这是一个允许在Android应用中运行Python代码的插件:
dependencies {
implementation 'com.chaquo.python:gradle:10.1.0'
}
然后在android/build.gradle
的buildscript
部分添加Chaquopy的仓库和插件:
buildscript {
repositories {
google()
jcenter()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.chaquo.python:gradle:10.1.0'
}
}
2.2 配置Chaquopy
在android/app/src/main/python
目录下创建一个Python脚本,比如sweph_wrapper.py
,这个脚本将调用sweph
库进行天文计算。
# sweph_wrapper.py
import sweph
def get_planet_position(planet, julian_date):
# 假设sweph已经正确安装并配置
# 这里是一个简单的示例,实际调用可能需要更多参数
res = sweph.swe_calc(julian_date, planet, 0)
return res
2.3 创建MethodChannel
在android/app/src/main/kotlin/com/example/astro_app/MainActivity.kt
(对于Kotlin)或android/app/src/main/java/com/example/astro_app/MainActivity.java
(对于Java)中,创建一个MethodChannel来与Flutter通信。
Kotlin示例:
package com.example.astro_app
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import com.chaquo.python.PyObject
import com.chaquo.python.Python
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.astro_app/channel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getPlanetPosition") {
val planet = call.argument<String>("planet") ?: return@setMethodCallHandler result.error("INVALID_ARGUMENT", "Planet argument is missing", null)
val julianDate = call.argument<Double>("julianDate") ?: return@setMethodCallHandler result.error("INVALID_ARGUMENT", "Julian Date argument is missing", null)
val py = Python.getInstance()
val module = py.getModule("sweph_wrapper")
val position = module.callAttr("get_planet_position", planet, julianDate)
result.success(position.toString())
} else {
result.notImplemented()
}
}
}
}
Java示例:
package com.example.astro_app;
import android.os.Bundle;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import com.chaquo.python.PyObject;
import com.chaquo.python.Python;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.astro_app/channel";
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("getPlanetPosition")) {
String planet = call.argument("planet");
if (planet == null) {
result.error("INVALID_ARGUMENT", "Planet argument is missing", null);
return;
}
Double julianDate = call.argument("julianDate");
if (julianDate == null) {
result.error("INVALID_ARGUMENT", "Julian Date argument is missing", null);
return;
}
Python py = Python.getInstance();
PyObject module = py.getModule("sweph_wrapper");
PyObject position = module.callAttr("get_planet_position", planet, julianDate);
result.success(position.toString());
} else {
result.notImplemented();
}
}
);
}
}
步骤 3: 在Flutter中调用MethodChannel
在lib/main.dart
中,使用MethodChannel
来调用Android端的Python脚本。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
static const platform = MethodChannel('com.example.astro_app/channel');
String _planetPosition = 'Unknown';
Future<void> _getPlanetPosition(String planet, double julianDate) async {
try {
final String result = await platform.invokeMethod('getPlanetPosition', {'planet': planet, 'julianDate': julianDate});
setState(() {
_planetPosition = result;
});
} on PlatformException catch (e) {
setState(() {
_planetPosition = "Failed to get planet position: '${e.message}'.";
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Astronomy App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Planet Position:'),
Text(_planetPosition),
ElevatedButton(
onPressed: () {
_getPlanetPosition('MERCURY', 2459100.5); // 示例:获取水星在特定儒略日的位置
},
child: Text('Get Planet Position'),
),
],
),
),
),
);
}
}
注意
- 上述示例仅展示了如何在Android平台上集成Python脚本。对于iOS,你需要使用其他方法,比如使用
PythonKit
(如果可行)或者通过其他中介服务。 sweph
库的安装和配置可能比较复杂,确保你已经按照sweph
的文档正确安装并配置了它。- 本示例中的
get_planet_position
函数是一个占位符,实际调用sweph
可能需要更多的参数和处理。
这个示例提供了一个基本的框架,你可以在此基础上根据具体需求进行扩展和修改。