123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- import 'dart:io';
- import 'dart:math';
- import 'package:amap_flutter_base/amap_flutter_base.dart';
- import 'package:amap_flutter_map/amap_flutter_map.dart';
- import 'package:flutter/material.dart';
- import 'package:sport/pages/run/location.dart';
- import 'package:sport/pages/run/run_page.dart';
- import 'package:sport/widgets/circular_percent_indicator.dart';
- const Color COLOR_RUN = Color(0xffFF5B1D);
- const Color COLOR_RUN_SLOW = Color(0xff00DC42);
- const Color COLOR_RUN_MIDDLE = Color(0xffFFDD00);
- const Color COLOR_RUN_FAST = Color(0xffFF5B1D);
- const SPORT_TYPE = [
- {"name": "跑步", "met": 11.5, "unit": "公里", "v": 12.1, "i":"pop_icon_run"},
- {"name": "骑行", "met": 6.8, "unit": "公里", "v": 17.7, "i":"pop_icon_ride"},
- {"name": "跳绳", "met": 19.5, "unit": "次", "v": 200.0 * 60.0, "fix": 0, "i":"pop_icon_skip"},
- {"name": "步行", "met": 4.3, "unit": "公里", "v": 5.6, "i":"pop_icon_walk"},
- ];
- extension Iterables<E> on Iterable<E> {
- Map<K, List<E>> groupBy<K>(K Function(E) keyFunction) => fold(<K, List<E>>{}, (Map<K, List<E>> map, E element) => map..putIfAbsent(keyFunction(element), () => <E>[]).add(element));
- }
- class SportUtils {
- static String numToStr(num? v,{int asFixed = -1}) {
- if (v == null) return "0";
- if (v > 10000) {
- return "${(v / 10000).toStringAsFixed(1)}W";
- }
- return asFixed == -1 ? v.toString() : v.toStringAsFixed(asFixed);
- }
- static String calSportStr(int sportType, double data) {
- var map = SPORT_TYPE[sportType];
- int fixed = map['fix'] == null ? 2 : map['fix'] as int;
- return "${map['name']} ${formatNum(data, fixed)}${map['unit']}";
- }
- static String calSportType(int sportType, int consume, double weight) {
- var map = SPORT_TYPE[sportType];
- double result = (consume * 1.0 / (map['met']! as double) / weight) * (map['v']! as double);
- return calSportStr(sportType, result);
- }
- static String calSportTypeDataStr(int sportType, double data) {
- var map = SPORT_TYPE[sportType];
- int fixed = map['fix'] == null ? 2 : map['fix'] as int;
- return "${formatNum(data, fixed)}";
- }
- static double calSportTypeData(int sportType, int consume, double weight) {
- var map = SPORT_TYPE[sportType];
- double result = (consume * 1.0 / (map['met']! as double) / weight) * (map['v']! as double);
- return result;
- }
- static LatLng toLatLng(Location location) {
- return LatLng(location.latitude, location.longitude);
- }
- static String toDateTime(DateTime? time, {String join = "-"}) {
- if (time == null) return "";
- // return "${time.year}$join${time.month.toString().padLeft(2, "0")}$join${time.day.toString().padLeft(2, "0")}";
- return "${time.month.toString().padLeft(2, "0")}月${time.day.toString().padLeft(2, "0")}日";
- }
- static String toDateTimeFull(DateTime? time) {
- if (time == null) return "";
- return "${time.year}-${time.month.toString().padLeft(2, "0")}-${time.day.toString().padLeft(2, "0")} ${time.hour.toString().padLeft(2, "0")}:${time.minute.toString().padLeft(2, "0")}";
- }
- static String toDateTimeFullCh(DateTime? time) {
- if (time == null) return "";
- return "${time.year}年${time.month.toString().padLeft(2, "0")}月${time.day.toString().padLeft(2, "0")}日 ${time.hour.toString().padLeft(2, "0")}:${time.minute.toString().padLeft(2, "0")}";
- }
- static String toDateTimeFullDay(DateTime? time, {String join = "."}) {
- if (time == null) return "";
- return "${time.year}$join${time.month.toString().padLeft(2, "0")}$join${time.day.toString().padLeft(2, "0")}";
- }
- static String toDateTimeDay(DateTime? time, {String join = "."}) {
- if (time == null) return "";
- DateTime now = DateTime.now();
- if (now.day - time.day == 0) {
- return "今日";
- } else if (now.day - time.day == 1) {
- return "昨日";
- }
- return "${time.year}$join${time.month.toString().padLeft(2, "0")}$join${time.day.toString().padLeft(2, "0")}";
- }
- static String toEndTime(DateTime? time) {
- if (time == null) return "";
- return "${time.hour.toString().padLeft(2, "0")}:${time.minute.toString().padLeft(2, "0")}";
- }
- static int calorie4run(double weight, int second, int step) {
- final double k = 671.1;
- double stepRate = 1.0;
- if (step > 0) {
- stepRate = step / second * 60.0;
- }
- // return 用户体重kg/95 * 运动时间h * K(运动类型系数;
- return (weight / 95.0 * (second / 3600) * (k * (stepRate / 150.0))).toInt();
- }
- static double speedToMet(double speed) {
- if (speed == 0) return 0;
- final List<double> mets = [6.0, 8.3, 9.0, 9.8, 10.5, 11.0, 11.5, 11.8, 12.3, 12.8, 14.5, 16.0, 19.0, 19.8, 23.0];
- final List<double> speeds = [6.4, 8.0, 8.4, 9.7, 10.8, 11.3, 12.1, 12.9, 13.8, 14.5, 16.1, 17.7, 19.3, 20.9, 22.5];
- double met = mets.first;
- try {
- for (var i = 0; i < speeds.length; i++) {
- double s = speeds[i];
- if (speed < s) {
- if (i == 0) {
- met = mets.first;
- } else {
- double percent = (speed - speeds[i - 1]) / (speeds[i] - speeds[i - 1]);
- met = (mets[i] - mets[i - 1]) * percent + mets[i - 1];
- }
- break;
- }
- }
- } catch (e) {
- print(e);
- }
- return met;
- }
- static int calorie4runByMet(double weight, double distance, int second) {
- final double speed = (distance / 1000.0) / (second / 3600);
- double met = speedToMet(speed);
- // 卡路里消耗(大卡)=MET值× 0.0167 ×时间h(min)×体重(kg)
- return consume(met, (second / 60.0), weight);
- }
- static int consume(double met, double minute, double weight){
- return (met * 0.0167 * minute * weight).round();
- }
- static int consumeToMinute(int consume, double met, double weight){
- return (consume / (met * 0.0167 * weight)).round();
- }
- static int calorie(double weight, int difficulty, int costTime) {
- return weight * 1.0 * difficulty * costTime ~/ 3600000;
- }
- static double calPace(int second, double kilometre) {
- double pace = 0;
- if (kilometre != 0) {
- pace = second / kilometre;
- }
- return pace;
- }
- static String pace(double pace, {String join = ""}) {
- return "${(pace ~/ 60).toString().padLeft(2, "0")}′$join${(pace.toInt() % 60).toString().padLeft(2, "0")}″";
- }
- static String pace11(double pace, {String join = ""}) {
- return "${(pace ~/ 60).toString().padLeft(2, "0")}";
- }
- static String pace12(double pace, {String join = ""}) {
- return "${(pace.toInt() % 60).toString().padLeft(2, "0")}";
- }
- static String pace4(int second, int kilometre) {
- return pace(calPace(second, kilometre / 1000));
- }
- static String paceToMinute(int second, int kilometre) {
- String _p = pace(calPace(second, kilometre / 1000));
- return _p.substring(0, _p.indexOf("′"));
- }
- static String paceToSecond(int second, int kilometre) {
- String _p = pace(calPace(second, kilometre / 1000));
- return _p.substring(_p.indexOf("′"), _p.length);
- }
- static String sound(int number) {
- return number == 2 ? "run/two" : "number/$number";
- }
- static List<String> timeToAudio(int totalSecond) {
- final List<String> audios = [];
- int second = totalSecond;
- int hour = 0, min = 0, sec = 0;
- sec = second % 60;
- second = second ~/ 60;
- min = second % 60;
- hour = second ~/ 60;
- if (hour > 0) {
- audios.add(sound(hour));
- audios.add("run/hour");
- }
- if (min > 0) {
- audios.add(sound(min));
- audios.add("run/m");
- }
- if (sec > 0) {
- audios.add(sound(sec));
- audios.add("run/s");
- }
- return audios;
- }
- static List<List<Location>> split(List<Location> items) {
- List<List<Location>> result = [];
- List<Location> part = [];
- int state = 0;
- for (var e in items) {
- if (e.state != state) {
- if (part.length > 1) result.add(part);
- part = [];
- state = e.state!;
- }
- part.add(e);
- }
- if (part.length > 1) result.add(part);
- return result;
- }
- static Set<Polyline> splitRunLine(List<Location> items, {double speed = 0.0}) {
- List<Polyline> result = [];
- if (items.length > 1) {
- List<LatLng> part = [];
- int state = 0;
- for (var i = 0; i < items.length; i++) {
- var e = items[i];
- var latLng = LatLng(e.latitude, e.longitude);
- part.add(latLng);
- if (e.state != state) {
- result.add(createRunLine(part, state));
- part = [];
- state = e.state ?? 0;
- }
- }
- if (part.isNotEmpty == true) {
- result.add(createRunLine(part, state));
- }
- }
- return Set.of(result);
- }
- static double lineWidth = 5;
- static Polyline createRunLine(List<LatLng> part, int state) {
- final double _width = lineWidth;
- if (Platform.isAndroid) {
- return Polyline(points: part, color: COLOR_RUN, width: _width, capType: CapType.round, dashLineType: state == 0 ? DashLineType.none : DashLineType.circle);
- } else {
- return Polyline(points: part, color: COLOR_RUN, colorList: [COLOR_RUN.value, COLOR_RUN.value], capType: CapType.round, width: _width, dashLineType: state == 0 ? DashLineType.none : DashLineType.circle);
- }
- }
- static Set<Polyline> splitLine(List<Location> items, {double speed = 0.0}) {
- List<Polyline> result = [];
- final double _speedWeight = 0.92;
- final double _speedMax = speed / _speedWeight;
- final double _speedMin = speed * _speedWeight;
- final double _width = lineWidth;
- List<List<Location>> splitList = split(items);
- for (var list in splitList) {
- var first = list.first;
- int state = first.state ?? 0;
- if (state == 1) {
- result.add(createRunLine(list.map((e) => LatLng(e.latitude, e.longitude)).toList(), 1));
- } else {
- Color color = COLOR_RUN_SLOW;
- int size = 100;
- for (var i = 0; i < list.length; i += size) {
- var start = list[i];
- List<LatLng> part = [];
- List<int> colors = [];
- colors.add(color.value);
- int _j = i;
- double speed = 0;
- var end = min(list.length, i + size + 2);
- for (var j = i; j < end; j++) {
- var e = list[j];
- part.add(LatLng(e.latitude, e.longitude));
- speed += e.speed ?? 0;
- }
- speed /= part.length;
- // print("1111111111111111 $speed $_speedMax $_speedMin");
- color = speed > _speedMax
- ? COLOR_RUN_FAST
- : speed < _speedMin
- ? COLOR_RUN_SLOW
- : COLOR_RUN_MIDDLE;
- colors.add(color.value);
- result.add(Polyline(points: part, width: _width, dashLineType: state == 0 ? DashLineType.none : DashLineType.circle, gradient: true, colorList: colors, color: COLOR_RUN));
- }
- }
- }
- return Set.of(result);
- }
- }
- final double radius = 6378137;
- LatLng navigationTrack(LatLng last, double bearing, int count) {
- double lat = last.latitude;
- double lon = last.longitude;
- final double step = 1.02;
- double _bearing = bearing % 360;
- if (_bearing > 180) _bearing = _bearing - 360;
- double azimut = radians(_bearing);
- for (var i = 0; i < count; i++) {
- lat += step * cos(azimut) * 180 / radius / pi;
- lon += step * sin(azimut) * 180 / radius / cos(pi * lat / 180) / pi;
- }
- return LatLng(lat, lon);
- }
- /**
- * 根据两点算斜率
- */
- double getSlope(LatLng fromPoint, LatLng toPoint) {
- if (fromPoint == null || toPoint == null) {
- return 0;
- }
- if (toPoint.longitude == fromPoint.longitude) {
- return double.maxFinite;
- }
- double slope = ((toPoint.latitude - fromPoint.latitude) / (toPoint.longitude - fromPoint.longitude));
- return slope;
- }
- /**
- * 根据两点算取图标转的角度
- */
- double getAngle(LatLng fromPoint, LatLng toPoint) {
- if (fromPoint == null || toPoint == null) {
- return 0;
- }
- double slope = getSlope(fromPoint, toPoint);
- if (slope == double.maxFinite) {
- if (toPoint.latitude > fromPoint.latitude) {
- return 0;
- } else {
- return 180;
- }
- }
- double deltAngle = 0;
- if ((toPoint.latitude - fromPoint.latitude) * slope < 0) {
- deltAngle = 180;
- }
- double radio = atan(slope);
- double angle = 180 * (radio / pi) + deltAngle - 90;
- return angle;
- }
- class LatLngBoundsBuilder {
- double mSouth = 1.0 / 0.0;
- double mNorth = -1.0 / 0.0;
- double mWest = 0.0 / 0.0;
- double mEast = 0.0 / 0.0;
- include(LatLng var1) {
- if (var1 == null) {
- return this;
- } else {
- this.mSouth = min(this.mSouth, var1.latitude);
- this.mNorth = max(this.mNorth, var1.latitude);
- double var2 = var1.longitude;
- if (this.mWest.isNaN) {
- this.mWest = var2;
- this.mEast = var2;
- } else if (!this.a(var2)) {
- if (c(this.mWest, var2) < d(this.mEast, var2)) {
- this.mWest = var2;
- } else {
- this.mEast = var2;
- }
- }
- return this;
- }
- }
- static double c(double var0, double var2) {
- return (var0 - var2 + 360.0) % 360.0;
- }
- static double d(double var0, double var2) {
- return (var2 - var0 + 360.0) % 360.0;
- }
- bool a(double var1) {
- if (this.mWest <= this.mEast) {
- return this.mWest <= var1 && var1 <= this.mEast;
- } else {
- return this.mWest <= var1 || var1 <= this.mEast;
- }
- }
- static LatLngBounds? fromList(List<LatLng> list) {
- LatLngBoundsBuilder builder = LatLngBoundsBuilder();
- for (var e in list) {
- builder.include(e);
- }
- return builder.build();
- }
- LatLngBounds? build() {
- if (this.mWest.isNaN) {
- return null;
- } else {
- if (this.mWest > this.mEast) {
- double var1 = this.mWest;
- this.mWest = this.mEast;
- this.mEast = var1;
- }
- if (this.mSouth > this.mNorth) {
- double var3 = this.mSouth;
- this.mSouth = this.mNorth;
- this.mNorth = var3;
- }
- LatLngBounds bounds = LatLngBounds(southwest: LatLng(this.mSouth, this.mWest), northeast: LatLng(this.mNorth, this.mEast));
- return bounds;
- }
- }
- }
|