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(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 imageList = {}; @override SkyPlotPage() { controller = Get.find(tag: 'gnss'); } Future 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; }