diff --git a/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs b/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs index 5c688f7..90eafb1 100644 --- a/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs +++ b/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs @@ -10,9 +10,9 @@ namespace Dto public class GroupJumpRopeContext { public int Index { get; set; } - public Point NormalizedPosition { get; set; } - public SportBase Sport { get; set; } - public SportUserItem User { get; set; } + public List<(double XNorm, double YNorm)> CirclePositions { get; set; } + public List Sports{ get; set; } + public List User { get; set; } public string LastNumberText { get; set; } = ""; public DateTime LastJumpTime { get; set; } = DateTime.MinValue; diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs index 2aa70df..9bc6a4b 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs @@ -45,13 +45,15 @@ namespace Wpf_AiSportsMicrospace.Views private List circleTexts = new(); private List userList = new(); private List userNumberList = ["0", "0", "0", "0", "0", "0"]; - private double[] circlePositionsX = { 0.07, 0.21, 0.36, 0.50, 0.64, 0.78, 0.92 }; private Main _mainWin => Application.Current.MainWindow as Main; private List<(double XNorm, double YNorm)> circlePositions = new(); private MediaPlayer _mediaPlayer = new MediaPlayer(); private bool IsGameStarted = false; List _useName = ["一号位", "四号位", "二号位", "五号位", "三号位", "六号位",]; + + private readonly object _updateLock = new object(); + private readonly Dictionary _jumpStatus = new Dictionary(); public GroupJumpRope() { InitializeComponent(); @@ -271,7 +273,6 @@ namespace Wpf_AiSportsMicrospace.Views } private DateTime? _raiseStartTime; - private DateTime? _wristStartTime; private bool _firstHandTriggered; private int _lastCountdownSecond = 3; private DateTime? _countdownStartTime; @@ -340,93 +341,10 @@ namespace Wpf_AiSportsMicrospace.Views private void ResetRaiseState() { _raiseStartTime = null; - _wristStartTime = null; _countdownStartTime = null; _firstHandTriggered = false; _lastCountdownSecond = 3; } - private Dictionary _lastJumpUpdateTime = new(); // 用于存储最后更新时间 - private Dictionary _lastUIUpdateTime = new(); // 用于防抖处理 - public Human LocateHuman(List humans, double frameWidth, double frameHeight, int circleIndex) - { - if (humans == null || humans.Count == 0) - { - return null; - } - - double circleX = circlePositions[circleIndex].XNorm; - double circleY = circlePositions[circleIndex].YNorm; - double radiusNormX = 0.073; - double radiusNormY = 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 xRightNorm = rightFoot.X / frameWidth; - double xLeftNorm = leftFoot.X / frameWidth; - double yRightNorm = rightFoot.Y / frameHeight; - double yLeftNorm = leftFoot.Y / frameHeight; - - bool outOfCircle = - xRightNorm < (circleX - radiusNormX) || xRightNorm > (circleX + radiusNormX) || - xLeftNorm < (circleX - radiusNormX) || xLeftNorm > (circleX + radiusNormX) || - yRightNorm < (circleY - radiusNormY) || yRightNorm > (circleY + radiusNormY) || - yLeftNorm < (circleY - radiusNormY) || yLeftNorm > (circleY + radiusNormY); - - if (outOfCircle) - { - isOut = true; - } - else if (inCircleHuman == null) - { - inCircleHuman = hu; - } - - } - - if (isOut) - userList[circleIndex].ImageState = "3"; - else - { - //if (userList[circleIndex].ImageState == "3") - //{ - // userList[circleIndex].ImageState = "1"; - //} - - // 检查当前编号是否未变化超过 2 秒 - if (userNumberList[circleIndex] == userList[circleIndex].NumberText) - { - // 获取上次变化时间 - if (!_lastJumpUpdateTime.TryGetValue(circleIndex, out var lastTime)) - lastTime = DateTime.Now; // 默认当前时间 - - var elapsed = (DateTime.Now - lastTime).TotalSeconds; - - if (elapsed > 1) - { - userList[circleIndex].ImageState = "1"; - _lastJumpUpdateTime[circleIndex] = DateTime.Now; - } - // 否则:2 秒内仍在变化,不更新状态 - } - else - { - // 编号发生变化,更新记录,并保持状态不变 - userNumberList[circleIndex] = userList[circleIndex].NumberText; - _lastJumpUpdateTime[circleIndex] = DateTime.Now; - } - } - return inCircleHuman; - } - - private void DrawCirclesWithText() { userBox.Children.Clear(); @@ -480,23 +398,90 @@ namespace Wpf_AiSportsMicrospace.Views } private void UpdateCircleCounts(List humans) { - // 在后台线程运行检测逻辑 - //Parallel.For(0, circlePositions.Count, i => - //{ - // var human = LocateHuman(humans, userBox.ActualWidth, userBox.ActualHeight, i); - // sports[i].Pushing(human); - //}); + double radiusNormX = 0.07; + double radiusNormY = 0.14; for (int i = 0; i < circlePositions.Count; i++) { - var human = LocateHuman(humans, userBox.ActualWidth, userBox.ActualHeight, i); - if (human != null) + var circleX = circlePositions[i].XNorm; + var circleY = circlePositions[i].YNorm; + + Human humanInCircle = null; + + // 找圈内的人 + foreach (var hu in humans) { - sports[i].Pushing(human); + 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 xRightNorm = rightFoot.X / userBox.ActualWidth; + double xLeftNorm = leftFoot.X / userBox.ActualWidth; + double yRightNorm = rightFoot.Y / userBox.ActualHeight; + double yLeftNorm = leftFoot.Y / userBox.ActualHeight; + + bool outOfCircle = + xRightNorm < (circleX - radiusNormX) || xRightNorm > (circleX + radiusNormX) || + xLeftNorm < (circleX - radiusNormX) || xLeftNorm > (circleX + radiusNormX) || + yRightNorm < (circleY - radiusNormY) || yRightNorm > (circleY + radiusNormY) || + yLeftNorm < (circleY - radiusNormY) || yLeftNorm > (circleY + radiusNormY); + + if (!outOfCircle) + { + humanInCircle = hu; + break; // 每圈只处理一个人 + } } + + // 根据是否有人和跳绳数字判断状态 + bool hasHuman = humanInCircle != null; + lock (_updateLock) + { + userList[i].ImageState = GetJumpState(i, hasHuman); + } + + // 推送计数 + if (hasHuman) + sports[i].Pushing(humanInCircle); } } + private string GetJumpState(int circleIndex, bool humanInCircle) + { + if (!humanInCircle) + { + // 无人 → 出圈 + return "3"; + } + string currentNumber = userNumberList[circleIndex]; + + if (!_jumpStatus.ContainsKey(circleIndex)) + { + _jumpStatus[circleIndex] = (currentNumber, DateTime.Now, "1"); // 初始状态先为停止 + return "1"; + } + + var (lastNumber, lastChangeTime, lastState) = _jumpStatus[circleIndex]; + + //if (currentNumber != lastNumber) + //{ + // // 数字变化 → 跳绳中 + // _jumpStatus[circleIndex] = (currentNumber, DateTime.Now, "2"); + // return "2"; + //} + + // 数字未变化,判断是否超过 2 秒 + double elapsed = (DateTime.Now - lastChangeTime).TotalSeconds; + if (elapsed >= 2) + { + // 超过 2 秒未变化 → 停止 + _jumpStatus[circleIndex] = (currentNumber, lastChangeTime, "1"); + return "1"; + } + // 维持上次状态 + return lastState; + } /// /// 添加带渐变光的圆圈(中心红色,边缘蓝色)