调试
This commit is contained in:
parent
553bde932c
commit
dcfd9c6268
@ -1,26 +1,30 @@
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:gnss/gnss.dart';
|
||||
|
||||
class GnssController extends GetxController {
|
||||
late Gnss gnss;
|
||||
late final Gnss gnss;
|
||||
LocationData? locationData;
|
||||
SignalData? signalData;
|
||||
var locationUpdate = 0.obs;
|
||||
|
||||
var singnalUpdate = 0.obs;
|
||||
// var _selectedSignal = [];
|
||||
Map<String, bool> selectedSignal = {};
|
||||
// List<String> get selectedSignal => _selectedSignal;
|
||||
// set selectedSignal(Set<String> value) {
|
||||
// _selectedSignal = value;
|
||||
// update();
|
||||
// }
|
||||
|
||||
// Map<String, bool> selectedSignal = {
|
||||
// "GPS": true,
|
||||
// "GLONASS": true,
|
||||
// "GALILEO": true,
|
||||
// "BEIDOU": true,
|
||||
// "QZSS": true,
|
||||
// "SBAS": true,
|
||||
// }.obs;
|
||||
final selectedSignal = <bool>[true, true, true, true, true, true].obs;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
gnss = Gnss(port: "/dev/ttysWK2", baudrate: 115200);
|
||||
// gnss = Gnss(port: "/dev/ttysWK2", baudrate: 115200);
|
||||
gnss = Gnss(port: "COM1", baudrate: 115200);
|
||||
gnss.start();
|
||||
gnss.locationStream.listen((location) {
|
||||
locationData = location;
|
||||
@ -34,7 +38,6 @@ class GnssController extends GetxController {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
gnss.dispose();
|
||||
super.dispose();
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:gnss/gnss.dart';
|
||||
// import 'package:gnss/gnss.dart';
|
||||
|
||||
import 'sky/skyplot.dart';
|
||||
import 'Controller/gnssController.dart'; // Import the correct file location for GnssController
|
||||
import 'sky/sky_plot.dart';
|
||||
import 'sky/sky_info.dart';
|
||||
import 'Controller/gnss_controller.dart'; // Import the correct file location for GnssController
|
||||
|
||||
// void main() {
|
||||
// Get.lazyPut<GnssController>(() => GnssController(), tag: 'gnss');
|
||||
@ -44,7 +43,7 @@ import 'Controller/gnssController.dart'; // Import the correct file location for
|
||||
// }
|
||||
|
||||
void main() {
|
||||
Get.lazyPut<GnssController>(() => GnssController(), tag: 'gnss');
|
||||
Get.put<GnssController>(GnssController());
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
@ -71,13 +70,13 @@ class _MyAppState extends State<MyApp> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final con = Get.find<GnssController>(tag: 'gnss');
|
||||
// final con = Get.find<GnssController>();
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('天空图'),
|
||||
),
|
||||
body: SkyPlotPage(),
|
||||
body: SkyInfo(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SingleButton extends StatefulWidget {
|
||||
final controller = Get.find(tag: 'gnss');
|
||||
// final controller = Get.find(tag: 'gnss');
|
||||
final List<Color> colors;
|
||||
final Function(Color) onSelectionChanged;
|
||||
|
||||
|
@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class MulButton extends StatefulWidget {
|
||||
final controller = Get.find(tag: 'gnss');
|
||||
// final controller = Get.find(tag: 'gnss');
|
||||
final List<Color> colors;
|
||||
final Function(List<Color>) onSelectionChanged;
|
||||
final Function(int, bool) onSelectionChanged;
|
||||
|
||||
MulButton({
|
||||
required this.colors,
|
||||
@ -27,13 +27,13 @@ class _MulButtonState extends State<MulButton> {
|
||||
void updateSelection(int index, bool value) {
|
||||
setState(() {
|
||||
selectedColors[index] = value;
|
||||
List<Color> selected = [];
|
||||
for (int i = 0; i < selectedColors.length; i++) {
|
||||
if (selectedColors[i]) {
|
||||
selected.add(widget.colors[i]);
|
||||
}
|
||||
}
|
||||
widget.onSelectionChanged(selected); // 通知父组件
|
||||
// List<Color> selected = [];
|
||||
// for (int i = 0; i < selectedColors.length; i++) {
|
||||
// if (selectedColors[i]) {
|
||||
// selected.add(widget.colors[i]);
|
||||
// }
|
||||
// }
|
||||
widget.onSelectionChanged(index, value); // 通知父组件
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,120 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:gnssview/sky/device_type.dart';
|
||||
import '../Controller/gnssController.dart';
|
||||
import 'mulbutton.dart';
|
||||
|
||||
class SkyInfo extends StatelessWidget {
|
||||
late GnssController controller;
|
||||
// final String lat; // 纬度
|
||||
// final String lon; // 经度
|
||||
// final String hdop; // 高程
|
||||
// final int status; // 定位状态
|
||||
// final int view; // 可见
|
||||
// final int use; // 使用
|
||||
// final String time; // 时间
|
||||
|
||||
SkyInfo() {
|
||||
controller = Get.find<GnssController>(tag: 'gnss');
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isPortrait =
|
||||
MediaQuery.of(context).orientation == Orientation.portrait;
|
||||
|
||||
return Theme(
|
||||
data: ThemeData(
|
||||
textTheme: const TextTheme(
|
||||
titleLarge: TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(left: 5),
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
alignment: Alignment.centerLeft,
|
||||
child:
|
||||
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
// 创建行项的函数
|
||||
rowItem(context, "北纬:", '${controller.locationData?.latitude} '),
|
||||
rowItem(context, "东经:", '${controller.locationData?.longitude}'),
|
||||
rowItem(context, "高程:", '${controller.locationData?.altitude}'),
|
||||
rowItem(context, "水平定位精度:", '${controller.locationData?.hdop}'),
|
||||
rowItem(context, "垂直定位精度:", '${controller.locationData?.vdop}'),
|
||||
rowItem(context, "定位状态:", '${controller.locationData?.fixQuality}'),
|
||||
rowItem(context, "可见卫星数:", '${controller.locationData?.numberSv}'),
|
||||
rowItem(context, "使用卫星数:", '${controller.locationData?.numberSa}'),
|
||||
rowItem(context, "时间:", '${controller.locationData?.time}'),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
MulButton(
|
||||
colors: const [
|
||||
Colors.blue,
|
||||
Colors.red,
|
||||
Colors.green,
|
||||
Colors.orange
|
||||
],
|
||||
onSelectionChanged: (selectedColors) {
|
||||
// 处理选中的颜色
|
||||
print('选中的颜色: $selectedColors');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
]),
|
||||
));
|
||||
}
|
||||
|
||||
Widget rowItem(BuildContext context, String title, String text) => Row(
|
||||
children: [
|
||||
FixedWidthTextWidget(
|
||||
width: 80,
|
||||
text: title,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class FixedWidthTextWidget extends StatelessWidget {
|
||||
final String text;
|
||||
final double width;
|
||||
final TextStyle? style;
|
||||
|
||||
FixedWidthTextWidget({
|
||||
super.key,
|
||||
required this.text,
|
||||
this.width = 80,
|
||||
this.style,
|
||||
});
|
||||
TextStyle? textStyle;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final deviceType = getDeviceType(context);
|
||||
double dynamicWidth = deviceType == DeviceType.mobile ? 0 : 50;
|
||||
|
||||
if (style != null) {
|
||||
textStyle =
|
||||
style!.copyWith(fontSize: deviceType == DeviceType.mobile ? 16 : 20);
|
||||
} else {
|
||||
textStyle =
|
||||
TextStyle(fontSize: deviceType == DeviceType.mobile ? 16 : 20);
|
||||
}
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 3),
|
||||
width: width + dynamicWidth,
|
||||
child: Text(
|
||||
text,
|
||||
style: textStyle,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,250 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:gnss/gnss.dart';
|
||||
|
||||
import '../Controller/gnssController.dart';
|
||||
|
||||
class DrawSkyPlot {
|
||||
double width = 500;
|
||||
double height = 500;
|
||||
late Canvas ctx;
|
||||
Map legend = {};
|
||||
final Paint _paint = Paint();
|
||||
Path path = Path();
|
||||
bool isPortrait = false;
|
||||
late LocationData locationData;
|
||||
late SignalData signalData;
|
||||
late GnssController controller;
|
||||
// final GnssController controller;
|
||||
|
||||
final bool isDarkMode;
|
||||
Color color = Colors.black;
|
||||
DrawSkyPlot(op, this.isDarkMode, this.controller) {
|
||||
// controller = Get.find<GnssController>(tag: 'gnss');
|
||||
ctx = op['ctx']; // canvas dom 对象
|
||||
height = op['height']; // 画布高
|
||||
width = op['width']; // 画布宽
|
||||
if (isDarkMode) {
|
||||
color = Colors.white;
|
||||
} else {
|
||||
color = Colors.black;
|
||||
}
|
||||
_paint
|
||||
..color = color
|
||||
..strokeWidth = 3
|
||||
..style = PaintingStyle.stroke;
|
||||
MediaQueryData mediaQueryData =
|
||||
MediaQueryData.fromView(WidgetsBinding.instance.window);
|
||||
final orientation = mediaQueryData.orientation;
|
||||
// 横屏竖屏宽高重新设置
|
||||
if (orientation == Orientation.portrait) {
|
||||
height = op['width'];
|
||||
isPortrait = true;
|
||||
} else {
|
||||
width = op['height'];
|
||||
isPortrait = false;
|
||||
}
|
||||
}
|
||||
|
||||
//外圈
|
||||
drawSkyPlotCircle() {
|
||||
double x = (width / 2) + 50;
|
||||
double y = (height / 2) - 15;
|
||||
double r = height / 2.5;
|
||||
ctx.drawCircle(Offset(x, y), r, _paint);
|
||||
ctx.drawCircle(Offset(x, y), r * 2 / 3, _paint);
|
||||
ctx.drawCircle(Offset(x, y), r / 3, _paint);
|
||||
path.moveTo(x - r, y);
|
||||
path.lineTo(x + r, y);
|
||||
path.moveTo(x, y - r);
|
||||
path.lineTo(x, y + r);
|
||||
path.moveTo(x + cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r);
|
||||
path.lineTo(x - cos(30 * (pi / 180)) * r, y - sin(30 * (pi / 180)) * r);
|
||||
path.moveTo(x + cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r);
|
||||
path.lineTo(x - cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r);
|
||||
path.moveTo(x + cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r);
|
||||
path.lineTo(x - cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r);
|
||||
path.moveTo(x - cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r);
|
||||
path.lineTo(x + cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r);
|
||||
path.moveTo(x + cos(30 * (pi / 180)) * r, y - sin(30 * (pi / 180)) * r);
|
||||
path.lineTo(x - cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r);
|
||||
path.moveTo(x - cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r);
|
||||
path.lineTo(x + cos(30 * (pi / 180)) * r, y - sin(30 * (pi / 180)) * r);
|
||||
ctx.drawPath(path, _paint);
|
||||
|
||||
Map textList = {
|
||||
'0': Offset(x, y - r - 25),
|
||||
'30': Offset(
|
||||
x + cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r - 25),
|
||||
'60': Offset(
|
||||
x + cos(30 * (pi / 180)) * r + 10, y - sin(30 * (pi / 180)) * r - 10),
|
||||
'90': Offset(x + r + 10, y - 5),
|
||||
'120': Offset(
|
||||
x + cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r + 5),
|
||||
'150': Offset(
|
||||
x + cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r + 5),
|
||||
'180': Offset(x - 10, y + r),
|
||||
'210': Offset(
|
||||
x - cos(60 * (pi / 180)) * r - 20, y + sin(60 * (pi / 180)) * r + 10),
|
||||
'240': Offset(
|
||||
x - cos(30 * (pi / 180)) * r - 30, y + sin(30 * (pi / 180)) * r + 5),
|
||||
'270': Offset(x - r - 35, y - 5),
|
||||
'300': Offset(
|
||||
x - cos(30 * (pi / 180)) * r - 37, y - sin(30 * (pi / 180)) * r - 20),
|
||||
'330': Offset(
|
||||
x - cos(60 * (pi / 180)) * r - 30, y - sin(60 * (pi / 180)) * r - 25)
|
||||
};
|
||||
textList.forEach((key, offset) {
|
||||
TextPainter(
|
||||
text: TextSpan(text: key, style: TextStyle(color: color, fontSize: 20)),
|
||||
textDirection: TextDirection.ltr,
|
||||
)
|
||||
..layout()
|
||||
..paint(ctx, offset);
|
||||
});
|
||||
}
|
||||
|
||||
getCircles() {
|
||||
legend = {};
|
||||
double radius = height / 2.5;
|
||||
double r = 15;
|
||||
if (controller.signalData == null) {
|
||||
return;
|
||||
}
|
||||
var signalData = controller.signalData!;
|
||||
if (controller.selectedSignal['GPS'] == true) {
|
||||
for (int i = 0; i < signalData.GPS.length; i++) {
|
||||
SignalGPS item = controller.signalData!.GPS![i];
|
||||
double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
_paint.color = Colors.blue;
|
||||
_paint.style = PaintingStyle.fill;
|
||||
|
||||
// 绘制卫星位置
|
||||
ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
}
|
||||
} else if (controller.selectedSignal['BDS'] == true) {
|
||||
for (int i = 0; i < signalData.BDS.length; i++) {
|
||||
SignalBDS item = controller.signalData!.BDS![i];
|
||||
double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
_paint.color = Colors.red;
|
||||
_paint.style = PaintingStyle.fill;
|
||||
// 绘制卫星位置
|
||||
ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
}
|
||||
} else if (controller.selectedSignal['GLO'] == true) {
|
||||
for (int i = 0; i < signalData.GLO.length; i++) {
|
||||
SignalGLO item = controller.signalData!.GLO![i];
|
||||
double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
_paint.color = Colors.green;
|
||||
_paint.style = PaintingStyle.fill;
|
||||
// 绘制卫星位置
|
||||
ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
}
|
||||
} else if (controller.selectedSignal['ALS'] == true) {
|
||||
for (int i = 0; i < signalData.GAL.length; i++) {
|
||||
SignalGAL item = controller.signalData!.GAL![i];
|
||||
double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
_paint.color = Colors.orange;
|
||||
_paint.style = PaintingStyle.fill;
|
||||
// 绘制卫星位置
|
||||
ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SkyPlotPage extends StatelessWidget {
|
||||
late final GnssController controller;
|
||||
// Map<String, ui.Image> imageList = {};
|
||||
@override
|
||||
SkyPlotPage() {
|
||||
controller = Get.find<GnssController>(tag: 'gnss');
|
||||
}
|
||||
Future<ui.Image> loadImage(String path) async {
|
||||
ByteData data = await rootBundle.load(path);
|
||||
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
|
||||
ui.FrameInfo fi = await codec.getNextFrame();
|
||||
return fi.image;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Obx(() {
|
||||
controller.singnalUpdate;
|
||||
return CustomPaint(
|
||||
painter: DrawSky(controller, context, isDarkMode),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class DrawSky extends CustomPainter {
|
||||
final BuildContext context;
|
||||
final GnssController controller;
|
||||
final bool isDarkMode;
|
||||
// late SignalData signalData;
|
||||
DrawSky(this.controller, this.context, this.isDarkMode);
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
canvas.translate(0, -15);
|
||||
final bool isPortrait =
|
||||
MediaQuery.of(context).orientation == Orientation.portrait;
|
||||
DrawSkyPlot skyPlot = DrawSkyPlot({
|
||||
'ctx': canvas,
|
||||
'height': size.height,
|
||||
'width': size.width,
|
||||
}, isDarkMode, controller);
|
||||
if (!isPortrait) {
|
||||
canvas.translate(-30, 0);
|
||||
}
|
||||
skyPlot.drawSkyPlotCircle();
|
||||
// if (controller.chartData.value.time != 0) {
|
||||
if (isPortrait) {
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
} else {
|
||||
canvas.translate(size.width / 2, size.height / 2);
|
||||
}
|
||||
|
||||
skyPlot.getCircles();
|
||||
if (isPortrait) {
|
||||
canvas.translate(-size.width / 2, -size.height / 2);
|
||||
} else {
|
||||
canvas.translate(-size.width / 2, -size.height / 2);
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
||||
}
|
122
lib/sky/sky_info.dart
Normal file
122
lib/sky/sky_info.dart
Normal file
@ -0,0 +1,122 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:gnssview/sky/device_type.dart';
|
||||
import '../Controller/gnss_controller.dart';
|
||||
import 'mulbutton.dart';
|
||||
|
||||
class SkyInfo extends StatelessWidget {
|
||||
late final GnssController controller;
|
||||
|
||||
SkyInfo({super.key}) {
|
||||
controller = Get.find<GnssController>();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isPortrait =
|
||||
MediaQuery.of(context).orientation == Orientation.portrait;
|
||||
|
||||
return Theme(
|
||||
data: ThemeData(
|
||||
textTheme: const TextTheme(
|
||||
titleLarge: TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(left: 5),
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Obx(() {
|
||||
controller.locationUpdate.value;
|
||||
final location = controller.locationData;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 创建行项的函数
|
||||
rowItem(context, "纬度:", '${location?.latitude}'),
|
||||
rowItem(context, "经度:", '${location?.longitude}'),
|
||||
rowItem(context, "高程:", '${location?.altitude}'),
|
||||
rowItem(context, "水平精度:", '${location?.hdop}'),
|
||||
rowItem(context, "垂直精度:", '${location?.vdop}'),
|
||||
rowItem(context, "定位状态:", '${location?.fixQuality}'),
|
||||
rowItem(context, "可见卫星数:", '${location?.numberSv}'),
|
||||
rowItem(context, "使用卫星数:", '${location?.numberSa}'),
|
||||
rowItem(
|
||||
context,
|
||||
"时间:",
|
||||
location == null
|
||||
? 'null'
|
||||
: DateFormat('yyyy-MM-dd HH:mm:ss')
|
||||
.format(location.time)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
MulButton(
|
||||
colors: const [
|
||||
Colors.blue,
|
||||
Colors.red,
|
||||
Colors.green,
|
||||
Colors.orange
|
||||
],
|
||||
onSelectionChanged: (int index, bool value) {
|
||||
controller.selectedSignal[index] = value;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
]);
|
||||
})));
|
||||
}
|
||||
|
||||
Widget rowItem(BuildContext context, String title, String text) => Row(
|
||||
children: [
|
||||
FixedWidthText(
|
||||
width: 80,
|
||||
text: title,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class FixedWidthText extends StatelessWidget {
|
||||
final String text;
|
||||
final double width;
|
||||
final TextStyle? style;
|
||||
const FixedWidthText({
|
||||
super.key,
|
||||
required this.text,
|
||||
this.width = 80,
|
||||
this.style,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final deviceType = getDeviceType(context);
|
||||
double dynamicWidth = deviceType == DeviceType.mobile ? 0 : 50;
|
||||
TextStyle textStyle;
|
||||
if (style != null) {
|
||||
textStyle =
|
||||
style!.copyWith(fontSize: deviceType == DeviceType.mobile ? 16 : 20);
|
||||
} else {
|
||||
textStyle =
|
||||
TextStyle(fontSize: deviceType == DeviceType.mobile ? 16 : 20);
|
||||
}
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 3),
|
||||
width: width + dynamicWidth,
|
||||
child: Text(
|
||||
text,
|
||||
style: textStyle,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
336
lib/sky/sky_plot.dart
Normal file
336
lib/sky/sky_plot.dart
Normal file
@ -0,0 +1,336 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:gnss/gnss.dart';
|
||||
|
||||
import '../Controller/gnss_controller.dart';
|
||||
|
||||
const signalNameList = <String>["GPS", "GLONASS", "GALILEO", "BEIDOU", "QZSS"];
|
||||
const List<Color> signalColorList = [
|
||||
Color.fromARGB(255, 255, 0, 0),
|
||||
Color.fromARGB(255, 0, 255, 0),
|
||||
Color.fromARGB(255, 0, 0, 255),
|
||||
Color.fromARGB(255, 255, 255, 0),
|
||||
Color.fromARGB(255, 0, 255, 255)
|
||||
];
|
||||
|
||||
// class DrawSkyPlot {
|
||||
// double width = 500;
|
||||
// double height = 500;
|
||||
// late Canvas ctx;
|
||||
// Map legend = {};
|
||||
// final Paint _paint = Paint();
|
||||
// Path path = Path();
|
||||
// bool isPortrait = false;
|
||||
// late LocationData locationData;
|
||||
// late SignalData signalData;
|
||||
// late GnssController controller;
|
||||
// // final GnssController controller;
|
||||
|
||||
// final bool isDarkMode;
|
||||
// Color color = Colors.black;
|
||||
// DrawSkyPlot(op, this.isDarkMode, this.controller) {
|
||||
// // controller = Get.find<GnssController>(tag: 'gnss');
|
||||
// ctx = op['ctx']; // canvas dom 对象
|
||||
// height = op['height']; // 画布高
|
||||
// width = op['width']; // 画布宽
|
||||
// if (isDarkMode) {
|
||||
// color = Colors.white;
|
||||
// } else {
|
||||
// color = Colors.black;
|
||||
// }
|
||||
// _paint
|
||||
// ..color = color
|
||||
// ..strokeWidth = 3
|
||||
// ..style = PaintingStyle.stroke;
|
||||
// MediaQueryData mediaQueryData =
|
||||
// MediaQueryData.fromView(WidgetsBinding.instance.window);
|
||||
// final orientation = mediaQueryData.orientation;
|
||||
// // 横屏竖屏宽高重新设置
|
||||
// if (orientation == Orientation.portrait) {
|
||||
// height = op['width'];
|
||||
// isPortrait = true;
|
||||
// } else {
|
||||
// width = op['height'];
|
||||
// isPortrait = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// //外圈
|
||||
// drawSkyPlotCircle() {
|
||||
// double x = (width / 2) + 50;
|
||||
// double y = (height / 2) - 15;
|
||||
// double r = height / 2.5;
|
||||
// ctx.drawCircle(Offset(x, y), r, _paint);
|
||||
// ctx.drawCircle(Offset(x, y), r * 2 / 3, _paint);
|
||||
// ctx.drawCircle(Offset(x, y), r / 3, _paint);
|
||||
// path.moveTo(x - r, y);
|
||||
// path.lineTo(x + r, y);
|
||||
// path.moveTo(x, y - r);
|
||||
// path.lineTo(x, y + r);
|
||||
// path.moveTo(x + cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r);
|
||||
// path.lineTo(x - cos(30 * (pi / 180)) * r, y - sin(30 * (pi / 180)) * r);
|
||||
// path.moveTo(x + cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r);
|
||||
// path.lineTo(x - cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r);
|
||||
// path.moveTo(x + cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r);
|
||||
// path.lineTo(x - cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r);
|
||||
// path.moveTo(x - cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r);
|
||||
// path.lineTo(x + cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r);
|
||||
// path.moveTo(x + cos(30 * (pi / 180)) * r, y - sin(30 * (pi / 180)) * r);
|
||||
// path.lineTo(x - cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r);
|
||||
// path.moveTo(x - cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r);
|
||||
// path.lineTo(x + cos(30 * (pi / 180)) * r, y - sin(30 * (pi / 180)) * r);
|
||||
// ctx.drawPath(path, _paint);
|
||||
|
||||
// Map textList = {
|
||||
// '0': Offset(x, y - r - 25),
|
||||
// '30': Offset(
|
||||
// x + cos(60 * (pi / 180)) * r, y - sin(60 * (pi / 180)) * r - 25),
|
||||
// '60': Offset(
|
||||
// x + cos(30 * (pi / 180)) * r + 10, y - sin(30 * (pi / 180)) * r - 10),
|
||||
// '90': Offset(x + r + 10, y - 5),
|
||||
// '120': Offset(
|
||||
// x + cos(30 * (pi / 180)) * r, y + sin(30 * (pi / 180)) * r + 5),
|
||||
// '150': Offset(
|
||||
// x + cos(60 * (pi / 180)) * r, y + sin(60 * (pi / 180)) * r + 5),
|
||||
// '180': Offset(x - 10, y + r),
|
||||
// '210': Offset(
|
||||
// x - cos(60 * (pi / 180)) * r - 20, y + sin(60 * (pi / 180)) * r + 10),
|
||||
// '240': Offset(
|
||||
// x - cos(30 * (pi / 180)) * r - 30, y + sin(30 * (pi / 180)) * r + 5),
|
||||
// '270': Offset(x - r - 35, y - 5),
|
||||
// '300': Offset(
|
||||
// x - cos(30 * (pi / 180)) * r - 37, y - sin(30 * (pi / 180)) * r - 20),
|
||||
// '330': Offset(
|
||||
// x - cos(60 * (pi / 180)) * r - 30, y - sin(60 * (pi / 180)) * r - 25)
|
||||
// };
|
||||
// textList.forEach((key, offset) {
|
||||
// TextPainter(
|
||||
// text: TextSpan(text: key, style: TextStyle(color: color, fontSize: 20)),
|
||||
// textDirection: TextDirection.ltr,
|
||||
// )
|
||||
// ..layout()
|
||||
// ..paint(ctx, offset);
|
||||
// });
|
||||
// }
|
||||
|
||||
// getCircles() {
|
||||
// legend = {};
|
||||
// double radius = height / 2.5;
|
||||
// double r = 15;
|
||||
// if (controller.signalData == null) {
|
||||
// return;
|
||||
// }
|
||||
// var signalData = controller.signalData!;
|
||||
// if (controller.selectedSignal['GPS'] == true) {
|
||||
// for (int i = 0; i < signalData.GPS.length; i++) {
|
||||
// SignalGPS item = controller.signalData.GPS[i];
|
||||
// double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
// double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
// double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
// double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
// double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
// _paint.color = Colors.blue;
|
||||
// _paint.style = PaintingStyle.fill;
|
||||
|
||||
// // 绘制卫星位置
|
||||
// ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
// }
|
||||
// } else if (controller.selectedSignal['BDS'] == true) {
|
||||
// for (int i = 0; i < signalData.BDS.length; i++) {
|
||||
// SignalBDS item = controller.signalData!.BDS![i];
|
||||
// double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
// double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
// double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
// double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
// double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
// _paint.color = Colors.red;
|
||||
// _paint.style = PaintingStyle.fill;
|
||||
// // 绘制卫星位置
|
||||
// ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
// }
|
||||
// } else if (controller.selectedSignal['GLO'] == true) {
|
||||
// for (int i = 0; i < signalData.GLO.length; i++) {
|
||||
// SignalGLO item = controller.signalData!.GLO![i];
|
||||
// double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
// double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
// double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
// double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
// double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
// _paint.color = Colors.green;
|
||||
// _paint.style = PaintingStyle.fill;
|
||||
// // 绘制卫星位置
|
||||
// ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
// }
|
||||
// } else if (controller.selectedSignal['ALS'] == true) {
|
||||
// for (int i = 0; i < signalData.GAL.length; i++) {
|
||||
// SignalGAL item = controller.signalData!.GAL![i];
|
||||
// double elev = item.elevation * pi / 180; // 将仰角转换为弧度
|
||||
// double maxr = radius * cos(elev); // 计算该点到圆心的距离
|
||||
|
||||
// double azi = (90 - item.azimuth) * pi / 180; // 将方位角转换为弧度
|
||||
// double cx = (maxr) * cos(azi); // 计算 x 坐标
|
||||
// double cy = -(maxr) * sin(azi); // 计算 y
|
||||
|
||||
// _paint.color = Colors.orange;
|
||||
// _paint.style = PaintingStyle.fill;
|
||||
// // 绘制卫星位置
|
||||
// ctx.drawCircle(Offset(cx, cy), r, _paint);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
class SkyPlotPage extends StatelessWidget {
|
||||
late final GnssController controller;
|
||||
// Map<String, ui.Image> imageList = {};
|
||||
@override
|
||||
SkyPlotPage({super.key}) {
|
||||
controller = Get.find<GnssController>();
|
||||
}
|
||||
Future<ui.Image> loadImage(String path) async {
|
||||
ByteData data = await rootBundle.load(path);
|
||||
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
|
||||
ui.FrameInfo fi = await codec.getNextFrame();
|
||||
return fi.image;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return Obx(() {
|
||||
controller.singnalUpdate;
|
||||
final signalGNSS = [
|
||||
controller.signalData?.GPS,
|
||||
controller.signalData?.GLO,
|
||||
controller.signalData?.GAL,
|
||||
controller.signalData?.BDS,
|
||||
controller.signalData?.QZSS,
|
||||
];
|
||||
return CustomPaint(
|
||||
painter: SkyPlotPainter(signalGNSS, controller.selectedSignal),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// class DrawSky extends CustomPainter {
|
||||
// final BuildContext context;
|
||||
// final GnssController controller;
|
||||
// final radius = 20.0;
|
||||
|
||||
// final bool isDarkMode;
|
||||
// // late SignalData signalData;
|
||||
// DrawSky(this.controller, this.context, this.isDarkMode);
|
||||
// @override
|
||||
// void paint(Canvas canvas, Size size) {
|
||||
// canvas.translate(0, -15);
|
||||
// final bool isPortrait =
|
||||
// MediaQuery.of(context).orientation == Orientation.portrait;
|
||||
// DrawSkyPlot skyPlot = DrawSkyPlot({
|
||||
// 'ctx': canvas,
|
||||
// 'height': size.height,
|
||||
// 'width': size.width,
|
||||
// }, isDarkMode, controller);
|
||||
// if (!isPortrait) {
|
||||
// canvas.translate(-30, 0);
|
||||
// }
|
||||
// skyPlot.drawSkyPlotCircle();
|
||||
// // if (controller.chartData.value.time != 0) {
|
||||
// if (isPortrait) {
|
||||
// canvas.translate(size.width / 2, size.height / 2);
|
||||
// } else {
|
||||
// canvas.translate(size.width / 2, size.height / 2);
|
||||
// }
|
||||
|
||||
// skyPlot.getCircles();
|
||||
// if (isPortrait) {
|
||||
// canvas.translate(-size.width / 2, -size.height / 2);
|
||||
// } else {
|
||||
// canvas.translate(-size.width / 2, -size.height / 2);
|
||||
// }
|
||||
// // }
|
||||
// }
|
||||
|
||||
// @override
|
||||
// bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
||||
// }
|
||||
|
||||
class SkyPlotPainter extends CustomPainter {
|
||||
final List<List<SignalGNSS>?> signalGNSS;
|
||||
final List<bool> selectedSignal;
|
||||
final satelliteRadius = 20.0;
|
||||
SkyPlotPainter(this.signalGNSS, this.selectedSignal);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = Colors.blue
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
final double radius = min(size.width / 2, size.height / 2);
|
||||
final Offset center = Offset(size.width / 2, size.height / 2);
|
||||
|
||||
// Draw concentric circles for different elevation angles
|
||||
for (int i = 0; i <= 90; i += 30) {
|
||||
double r = radius * (90 - i) / 90;
|
||||
canvas.drawCircle(center, r, paint);
|
||||
}
|
||||
|
||||
// Draw lines for different azimuth angles
|
||||
for (int i = 0; i < 360; i += 30) {
|
||||
double radians = i * pi / 180;
|
||||
double x = center.dx + radius * cos(radians);
|
||||
double y = center.dy + radius * sin(radians);
|
||||
canvas.drawLine(center, Offset(x, y), paint);
|
||||
}
|
||||
|
||||
// Draw satellite positions
|
||||
final satellitePaint = Paint()..style = PaintingStyle.fill;
|
||||
|
||||
for (int i = 0; i < signalGNSS.length; i++) {
|
||||
final signalData = signalGNSS[i];
|
||||
if (!selectedSignal[i] || signalData == null) {
|
||||
continue;
|
||||
}
|
||||
satellitePaint.color = signalColorList[i];
|
||||
drawGnssSignal(canvas, center, radius, signalData, satellitePaint);
|
||||
}
|
||||
}
|
||||
|
||||
void drawGnssSignal(
|
||||
Canvas canvas,
|
||||
Offset center,
|
||||
double radius,
|
||||
List<SignalGNSS> signals,
|
||||
Paint paint,
|
||||
) {
|
||||
for (final signal in signals) {
|
||||
final int el = signal.elevation;
|
||||
final double az = signal.azimuth * pi / 180;
|
||||
|
||||
final double r = radius * (90 - el) / 90;
|
||||
final double x = center.dx + r * cos(az);
|
||||
final double y = center.dy + r * sin(az);
|
||||
|
||||
canvas.drawCircle(Offset(x, y), satelliteRadius, paint);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
||||
return false;
|
||||
}
|
||||
}
|
10
pubspec.lock
10
pubspec.lock
@ -120,10 +120,18 @@ packages:
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "6e4c9b35dc86d027a0f0bfbc65747a4813d92a2c"
|
||||
resolved-ref: "05b6cd1985ad7f13a487820f4cfa1e9622e2daae"
|
||||
url: "https://git.mcxa.cn:89/flutter/gnss.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.17.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -34,7 +34,7 @@ dependencies:
|
||||
git:
|
||||
url: https://git.mcxa.cn:89/flutter/gnss.git
|
||||
ref: main
|
||||
|
||||
intl: ^0.17.0
|
||||
# libserialport:
|
||||
# path: plugins/libserialport
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user