From dcbeed1ea8eb76fa9c41f07c62d3a04d0ac01be0 Mon Sep 17 00:00:00 2001 From: tanglong <842690096@qq.com> Date: Tue, 14 Oct 2025 09:46:14 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dto/GroupJumpRopeState.cs | 33 ++- .../Views/JumpRope/GroupJumpRope.xaml.cs | 244 +++++++----------- 2 files changed, 121 insertions(+), 156 deletions(-) diff --git a/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeState.cs b/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeState.cs index 9ba854e..11b0cef 100644 --- a/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeState.cs +++ b/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeState.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using Wpf_AiSportsMicrospace.MyUserControl; +using Wpf_AiSportsMicrospace.Views; using Yztob.AiSports.Postures.Sports; namespace Dto @@ -13,9 +14,14 @@ namespace Dto public List<(double XNorm, double YNorm)> CirclePositions { get; private set; } public List UserList { get; private set; } public List UserNumberList { get; private set; } - public List Sports { get; private set; } // ✅ 新增运动对象 - public Dictionary LastJumpUpdateTime { get; private set; } - public List UseNameList = ["四号位", "一号位", "五号位", "二号位", "六号位", "三号位", "七号位",]; + public List Sports { get; private set; } + public CircleState[] CircleStates { get; private set; } + + public List UseNameList { get; private set; } = new() + { + "四号位", "一号位", "五号位", "二号位", "六号位", "三号位", "七号位" + }; + public GroupJumpRopeState() { CirclePositions = new List<(double XNorm, double YNorm)> @@ -31,8 +37,17 @@ namespace Dto UserList = new List(); UserNumberList = new List(); - Sports = new List(); // ✅ 初始化 - LastJumpUpdateTime = new Dictionary(); + Sports = new List(); + + InitializeCircleStates(); + } + + private void InitializeCircleStates() + { + int count = CirclePositions.Count; + CircleStates = new CircleState[count]; + for (int i = 0; i < count; i++) + CircleStates[i] = new CircleState(); } public void Safe(Action action) @@ -47,4 +62,12 @@ namespace Dto return func(); } } + public class CircleState + { + public string LastNumberText { get; set; } = ""; + public DateTime LastJumpTime { get; set; } = DateTime.MinValue; + public DateTime LastUIUpdateTime { get; set; } = DateTime.MinValue; + public string ImageState { get; set; } = "1"; // 初始静止 + } + } diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs index 52eec7e..b90711a 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs @@ -342,119 +342,13 @@ namespace Wpf_AiSportsMicrospace.Views _firstHandTriggered = false; _lastCountdownSecond = 3; } - private Dictionary _lastJumpUpdateTime = new(); - private Dictionary _lastUIUpdateTime = new(); - // 状态缓存类 - class CircleState - { - public string LastNumberText = ""; - public DateTime LastActiveTime = DateTime.MinValue; // 最近跳动时间 - public DateTime LastUIUpdateTime = DateTime.MinValue; // 最近UI更新时间 - } - private CircleState[] _circleStates; - - private void InitializeCircleStates() - { - int count = _groupJumpRopeState.CirclePositions.Count; - _circleStates = new CircleState[count]; - for (int i = 0; i < count; i++) - _circleStates[i] = new CircleState(); - } - - // 安全访问状态并更新 - private Human LocateHumanSafe(List humans, double frameWidth, double frameHeight, int index) - { - var state = _circleStates[index]; - var user = _groupJumpRopeState.UserList[index]; - - if (humans == null || humans.Count == 0) - { - // 没人时,判断是否切回静止 - if ((DateTime.Now - state.LastActiveTime).TotalSeconds >= 2) - user.ImageState = "1"; - return null; - } - - var circle = _groupJumpRopeState.CirclePositions[index]; - double radiusX = 0.073; - double radiusY = 0.135; - - Human inCircleHuman = null; - bool isOut = false; - - foreach (var hu in humans) - { - var right = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle"); - var left = hu.Keypoints.FirstOrDefault(k => k.Name == "left_ankle"); - if (right == null || left == null) continue; - - double xR = right.X / frameWidth; - double yR = right.Y / frameHeight; - double xL = left.X / frameWidth; - double yL = left.Y / frameHeight; - - bool outOfCircle = - xR < (circle.XNorm - radiusX) || xR > (circle.XNorm + radiusX) || - xL < (circle.XNorm - radiusX) || xL > (circle.XNorm + radiusX) || - yR < (circle.YNorm - radiusY) || yR > (circle.YNorm + radiusY) || - yL < (circle.YNorm - radiusY) || yL > (circle.YNorm + radiusY); - - if (outOfCircle) - isOut = true; - else if (inCircleHuman == null) - inCircleHuman = hu; - } - - // 决定目标状态 - string targetState; - DateTime now = DateTime.Now; - - if (isOut) - { - targetState = "3"; // 出圈 - } - else if (inCircleHuman != null) - { - targetState = "2"; // 运动中 - state.LastActiveTime = now; - } - else - { - // 圈内无人,根据上次活跃时间判断是否切回静止 - targetState = (now - state.LastActiveTime).TotalSeconds >= 2 ? "1" : "2"; - } - - // UI 防抖:每 500ms 更新一次 - if ((now - state.LastUIUpdateTime).TotalMilliseconds > 500 && user.ImageState != targetState) - { - user.ImageState = targetState; - state.LastUIUpdateTime = now; - } - - return inCircleHuman; - } - private void UpdateCircleCounts(List humans) - { - double frameWidth = userBox.ActualWidth; - double frameHeight = userBox.ActualHeight; - - for (int i = 0; i < _groupJumpRopeState.CirclePositions.Count; i++) - { - var human = LocateHumanSafe(humans, frameWidth, frameHeight, i); - if (human != null) - { - _groupJumpRopeState.Sports[i].Pushing(human); - } - } - } private void DrawCirclesWithText() { userBox.Children.Clear(); _groupJumpRopeState.Sports.Clear(); - _groupJumpRopeState.UserNumberList.Clear(); - _groupJumpRopeState.UserList.Clear(); // ✅ 别忘了清空 + _groupJumpRopeState.UserList.Clear(); double imgWidth = userBox.ActualWidth; double imgHeight = userBox.ActualHeight; @@ -466,8 +360,6 @@ namespace Wpf_AiSportsMicrospace.Views double y = pos.YNorm * imgHeight; var userItem = AddUserItem(x, y, i); - _groupJumpRopeState.UserList.Add(userItem); - _groupJumpRopeState.UserNumberList.Add("0"); var sport = SportBase.Create("rope-skipping"); int indexCopy = i; @@ -479,10 +371,101 @@ namespace Wpf_AiSportsMicrospace.Views if (currentItem.ImageState != "2") currentItem.ImageState = "2"; }; + + sport.PointThreshold = 0.03f; sport.Start(); _groupJumpRopeState.Sports.Add(sport); + _groupJumpRopeState.UserList.Add(userItem); + } + } + public Human LocateHuman(List humans, double frameWidth, double frameHeight, int index) + { + if (humans == null || humans.Count == 0) + return null; + + return _groupJumpRopeState.Safe(() => + { + var circle = _groupJumpRopeState.CirclePositions[index]; + var user = _groupJumpRopeState.UserList[index]; + var state = _groupJumpRopeState.CircleStates[index]; + double radiusX = 0.073; + double radiusY = 0.135; + + Human inCircleHuman = null; + bool isOut = false; + + foreach (var hu in humans) + { + var rightFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle"); + var leftFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "left_ankle"); + if (rightFoot == null || leftFoot == null) continue; + + double xR = rightFoot.X / frameWidth; + double xL = leftFoot.X / frameWidth; + double yR = rightFoot.Y / frameHeight; + double yL = leftFoot.Y / frameHeight; + + bool outOfCircle = xR < circle.XNorm - radiusX || xR > circle.XNorm + radiusX || + xL < circle.XNorm - radiusX || xL > circle.XNorm + radiusX || + yR < circle.YNorm - radiusY || yR > circle.YNorm + radiusY || + yL < circle.YNorm - radiusY || yL > circle.YNorm + radiusY; + + if (outOfCircle) isOut = true; + else if (inCircleHuman == null) inCircleHuman = hu; + } + + var now = DateTime.Now; + + // 更新状态 + if (isOut) + { + if (state.ImageState != "3" && (now - state.LastUIUpdateTime).TotalMilliseconds > 500) + { + Application.Current.Dispatcher.Invoke(() => user.ImageState = "3"); + state.ImageState = "3"; + state.LastUIUpdateTime = now; + } + } + else + { + if (state.LastNumberText == user.NumberText) + { + var elapsed = (now - state.LastJumpTime).TotalSeconds; + if (elapsed > 2 && (now - state.LastUIUpdateTime).TotalMilliseconds > 500) + { + Application.Current.Dispatcher.Invoke(() => user.ImageState = "1"); + state.ImageState = "1"; + state.LastUIUpdateTime = now; + } + } + else + { + state.LastNumberText = user.NumberText; + state.LastJumpTime = now; + + if (state.ImageState != "2" && (now - state.LastUIUpdateTime).TotalMilliseconds > 500) + { + Application.Current.Dispatcher.Invoke(() => user.ImageState = "2"); + state.ImageState = "2"; + state.LastUIUpdateTime = now; + } + } + } + + return inCircleHuman; + }); + } + private void UpdateCircleCounts(List humans) + { + for (int i = 0; i < _groupJumpRopeState.CirclePositions.Count; i++) + { + var human = LocateHuman(humans, userBox.ActualWidth, userBox.ActualHeight, i); + if (human != null) + { + // 推动运动对象 + _groupJumpRopeState.Safe(() => _groupJumpRopeState.Sports[i].Pushing(human)); + } } - InitializeCircleStates(); } /// @@ -502,46 +485,5 @@ namespace Wpf_AiSportsMicrospace.Views _groupJumpRopeState.UserList.Add(userItem); return userItem; // } - - private readonly ConcurrentDictionary _uiUpdateCache - = new ConcurrentDictionary(); - - private void SetImageStateSafe(int index, string state) - { - if (index < 0 || index >= _groupJumpRopeState.UserList.Count) return; - - var now = DateTime.Now; - - if (_uiUpdateCache.TryGetValue(index, out var cache)) - { - // 如果状态没变或更新太频繁(<300ms),跳过 - if (cache.lastState == state && (now - cache.lastUpdate).TotalMilliseconds < 300) - return; - } - - _uiUpdateCache[index] = (state, now); - - if (Application.Current.Dispatcher.CheckAccess()) - { - _groupJumpRopeState.UserList[index].ImageState = state; - } - else - { - Application.Current.Dispatcher.BeginInvoke(new Action(() => - { - if (index >= 0 && index < _groupJumpRopeState.UserList.Count) - _groupJumpRopeState.UserList[index].ImageState = state; - })); - } - } } - - class CircleState - { - public string ImageState = "1"; // 当前显示状态 - public string LastNumberText = ""; // 上一次的 NumberText - public DateTime LastActiveTime = DateTime.MinValue; // 上次活动时间(运动中) - public DateTime LastUIUpdateTime = DateTime.MinValue; // UI 防抖时间 - } - }