Skip to content

Instantly share code, notes, and snippets.

@escamoteur
Created December 24, 2020 08:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save escamoteur/a76fd4be7406228153ef4e9f813bce0e to your computer and use it in GitHub Desktop.
Save escamoteur/a76fd4be7406228153ef4e9f813bce0e to your computer and use it in GitHub Desktop.
AntennaWidget
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' show radians;
/// Used to display Antennas on the Map as well as
/// the compass in aiming mode
class AntennaWidget extends StatelessWidget {
const AntennaWidget({
Key key,
@required this.radius,
@required this.azimuth,
@required this.segments,
this.showAntennaGrid = true,
this.color,
this.isAimingCompass = false,
// currently not used
// this.children,
}) : super(key: key);
final double radius;
/// This is currently ignored
final List<double> segments;
final bool showAntennaGrid;
// final List<AntennaPoint> children;
final double azimuth;
final Color color;
final bool isAimingCompass;
@override
Widget build(BuildContext context) {
final size = radius * 2;
return SizedBox(
width: size,
height: size,
child: CustomPaint(
painter: _AntennaGraphPainter(
azimuth: azimuth,
showAntennaGrid: showAntennaGrid,
isAimingCompass: isAimingCompass,
color: color),
size: Size(size, size),
// child: children != null
// ? Flow(
// delegate: _AntennaGraphFlowDelegate(this),
// children: children,
// )
// : null,
),
);
}
}
enum AntennaSizes { big, medium, small, min }
class _AntennaGraphPainter extends CustomPainter {
final double azimuth;
final bool showAntennaGrid;
final Color color;
final bool isAimingCompass;
_AntennaGraphPainter(
{@required this.showAntennaGrid,
@required this.azimuth,
this.isAimingCompass,
this.color = Colors.white}) {
_text = TextPainter(
textDirection: TextDirection.ltr,
);
}
TextPainter _text;
@override
void paint(Canvas canvas, Size size) {
const numberOfSegments = 12;
final double segmentSize = radians(360 / numberOfSegments);
final outerRadius = size.shortestSide * 0.5;
double antennaCenterRadius = 10.0;
double innerRadius;
double rings = 1;
double textSize;
AntennaSizes antennaSize;
/// depending on the antenna size we draw it with
/// different levels of details
if (outerRadius >= 160) {
antennaCenterRadius = 20.0;
rings = 4;
antennaSize = AntennaSizes.big;
textSize = 14;
} else if (outerRadius >= 100) {
antennaCenterRadius = 15.0;
rings = 3;
antennaSize = AntennaSizes.medium;
textSize = 12;
} else if (outerRadius >= 50) {
rings = 2;
antennaSize = AntennaSizes.small;
textSize = 10;
} else {
rings = 2;
antennaSize = AntennaSizes.min;
}
innerRadius = math.max(
antennaCenterRadius + outerRadius / (rings + 2), outerRadius * 0.2);
final double ringDistance = (outerRadius - innerRadius) * 0.9 / rings;
final segmentPaint = Paint()
..color = color.withOpacity(0.7)
..style = PaintingStyle.stroke
..strokeWidth = 1.2;
final edgePaint = Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = 2.5;
final centerEdgePaint = Paint()
..color = color
..strokeWidth = 2
..style = PaintingStyle.stroke;
final centerFillPaint = Paint()
..color = isAimingCompass ? Colors.green : color
..style = PaintingStyle.fill;
canvas.save();
final center = size.center(Offset.zero);
canvas.translate(center.dx, center.dy);
if (showAntennaGrid) {
// Antenna segments
// draw circles
for (double circleRadius = innerRadius;
circleRadius <= outerRadius - ringDistance;
circleRadius += ringDistance) {
canvas.drawCircle(Offset.zero, circleRadius, segmentPaint);
}
canvas.drawCircle(Offset.zero, innerRadius, segmentPaint);
canvas.drawCircle(Offset.zero, outerRadius, edgePaint);
final segmentStart = Offset(innerRadius - 6.0, 0.0);
final segmentEnd = Offset(outerRadius * 0.8, 0.0);
// Draw Antenna segments
for (int i = 0; i < numberOfSegments; i++) {
canvas.drawLine(segmentStart, segmentEnd, segmentPaint);
canvas.rotate(segmentSize);
}
if (antennaSize != AntennaSizes.min) {
// Draw small units every 10 degrees
for (int i = 0; i < 360 / 10; i++) {
canvas.drawLine(Offset(outerRadius - 6.0, 0.0),
Offset(outerRadius, 0), edgePaint);
canvas.rotate(radians(10));
}
// draw 90° marker lines
for (int i = 0; i < 4; i++) {
canvas.rotate(radians(90));
canvas.drawLine(Offset(innerRadius, 0.0),
Offset(outerRadius - ringDistance, 0), edgePaint);
}
if (outerRadius >= 50.0) {
for (int i = 0; i < 12; i++) {
final angle = i * 30.0;
_drawText(canvas, angle, outerRadius - 16.0,
angle.toStringAsFixed(0), textSize);
}
}
}
}
// draw antenna center
if (!isAimingCompass) {
final rect =
Rect.fromCircle(center: Offset.zero, radius: antennaCenterRadius);
canvas.drawArc(rect, radians(90.0) - azimuth, radians(-180.0), true,
centerFillPaint);
} else {
canvas.drawCircle(Offset.zero, antennaCenterRadius, centerFillPaint);
}
canvas.drawCircle(Offset.zero, antennaCenterRadius, centerEdgePaint);
canvas.restore();
}
/// used to draw the degrees around the Antenna
void _drawText(Canvas canvas, double angle, double radius, String text,
double textSize) {
_text.text = TextSpan(text: text, style: TextStyle(fontSize: textSize));
_text.layout();
final center = _text.size.center(Offset.zero);
final x = math.cos(radians(-90 + angle)) * radius - center.dx;
final y = math.sin(radians(-90 + angle)) * radius - center.dy;
_text.paint(canvas, Offset(x, y));
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
/// This would draw the Small arrows on the bearing lines iside the antenna
/// Currently not used becaus the antennas get to small
// class BearingIndicator extends StatelessWidget implements AntennaPoint {
// const BearingIndicator({
// Key key,
// this.heading,
// }) : super(key: key);
// @override
// final double heading;
// @override
// Widget build(BuildContext context) {
// return Row(
// mainAxisSize: MainAxisSize.min,
// children: <Widget>[
// Icon(
// Icons.arrow_right,
// size: 48.0,
// color: Colors.white,
// ),
// Container(
// width: 8.0,
// height: 8.0,
// color: Colors.blue,
// ),
// ],
// );
// }
// }
// abstract class AntennaPoint implements Widget {
// double get heading;
// }
// class _AntennaGraphFlowDelegate extends FlowDelegate {
// _AntennaGraphFlowDelegate(this.widget);
// final AntennaWidget widget;
// @override
// BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) =>
// constraints.loosen();
// @override
// void paintChildren(FlowPaintingContext context) {
// final center = context.size.center(Offset.zero);
// final centerMatrix = Matrix4.translationValues(center.dx, center.dy, 0.0);
// final radius = widget.radius;
// for (int i = 0; i < context.childCount; i++) {
// final heading = widget.children[i].heading;
// final childSize = context.getChildSize(i);
// context.paintChild(i,
// transform: centerMatrix *
// Matrix4.rotationZ(radians(-90 + heading)) *
// Matrix4.translationValues(
// radius - childSize.width, -childSize.height * 0.5, 0.0));
// }
// }
// @override
// bool shouldRepaint(FlowDelegate oldDelegate) {
// return true;
// }
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment