public BankStepInfo ComputeStep(IBallInternal ball) { BankStepInfo res = new BankStepInfo(double.PositiveInfinity, Coordinates.Zero, Coordinates.Zero); foreach (var bank in c_Banks) { var tmp = ComponentManager.Cache.Get(bank, ball.Position, ball.Velocity, ball.Friction); if (tmp != null) { res = new BankStepInfo(tmp.Step, tmp.Normal, tmp.Tangent); } else { UpdateStep(ref res, bank, ball); ComponentManager.Cache.Add(res.Step, res.NormalVersor, res.TangentVersor, bank, ball.Position, ball.Velocity, ball.Friction); } } foreach (var corner in c_BankCorners.Where((c, i) => IsCornerValidForCollision(i))) { var tmp = ComponentManager.Cache.Get(corner, ball.Position, ball.Velocity, ball.Friction); if (tmp != null) { res = new BankStepInfo(tmp.Step, tmp.Normal, tmp.Tangent); } else { UpdateStep(ref res, corner, ball); ComponentManager.Cache.Add(res.Step, res.NormalVersor, res.TangentVersor, corner, ball.Position, ball.Velocity, ball.Friction); } } return(res); }
private void SetVelocity(Coordinates newVelocity, bool calcStep) { if (newVelocity.Module < m_PhysicsData.FrictionCoefficient) { m_Velocity = Coordinates.Zero; } else { m_DirectionUpdated = !(m_Velocity.Phase % 360.0).ToleranceEqual(newVelocity.Phase % 360.0); m_Velocity = newVelocity; } if (calcStep && m_Velocity.Module > 0) { m_BankStep = m_Table.ComputeStep(this); } }
private void UpdateStep(ref BankStepInfo info, ICoordinates corner, IBallInternal ball) { double distance = double.PositiveInfinity; int N = -1; while (distance > ball.Radius) { N++; double newDistance = GeometryUtils.Distance(ball.ForeseenPosition(N), corner); if (newDistance >= distance) { return; } else { distance = newDistance; } } N--; var p = ball.ForeseenPosition(N); var v = ball.ForeseenVelocity(N); double a = v.X * (corner.X - p.X) + v.Y * (corner.Y - p.Y); double c = Math.Pow(v.X, 2) + Math.Pow(v.Y, 2); double b = Math.Sqrt(Math.Pow(a, 2) - c * (Math.Pow(corner.X - p.X, 2) + Math.Pow(corner.Y - p.Y, 2) - Math.Pow(ball.Radius, 2))); double t1 = (a + b) / c; double t2 = (a - b) / c; double t = (t1.Between(0, 1) ? (t2.Between(0, 1) ? Math.Min(t1, t2) : t1) : (t2.Between(0, 1) ? t2 : double.PositiveInfinity)); var ballCenter = Coordinates.Add(p, t * v); var contactPoint = Coordinates.Add(ballCenter, Coordinates.Sub(corner, ballCenter)); if (!CheckCenterPoint(ballCenter, ball.Radius) || !CheckContactPoint(contactPoint)) { return; } double step = N + t; if (!step.ToleranceEqual(0) && step.ToleranceLessEqual(info.Step)) { if (step < info.Step) { var normal = Coordinates.Normalize(Coordinates.Sub(p, corner)); var tangent = new Coordinates(module: 1, phase: normal.Phase + 90); info = new BankStepInfo(step, normal, tangent); } } }
private void UpdateStep(ref BankStepInfo info, Line2 bank, IBallInternal ball) { double distance = double.PositiveInfinity; int N = -1; while (distance > ball.Radius) { N++; double newDistance = GeometryUtils.Distance(ball.ForeseenPosition(N), bank); if (newDistance >= distance) { return; } else { distance = newDistance; } } N--; var p = ball.ForeseenPosition(N); var v = ball.ForeseenVelocity(N); double a = bank.A * p.X + bank.B * p.Y + bank.C; double b = ball.Radius * Math.Sqrt(Math.Pow(bank.A, 2) + Math.Pow(bank.B, 2)); double c = bank.A * v.X + bank.B * v.Y; double t1 = (-a + b) / c; double t2 = (-a - b) / c; double t = (t1.Between(0, 1) ? (t2.Between(0, 1) ? Math.Min(t1, t2) : t1) : (t2.Between(0, 1) ? t2 : double.PositiveInfinity)); var ballCenter = Coordinates.Add(p, t * v); var contactPoint = Coordinates.Add(ballCenter, -ball.Radius * bank.NormalVersor); if (!CheckCenterPoint(ballCenter, ball.Radius) || !CheckContactPoint(contactPoint)) { return; } double step = N + t; if (!step.ToleranceEqual(0) && step.ToleranceLessEqual(info.Step)) { if (step < info.Step) { info = new BankStepInfo(step, bank.NormalVersor, bank.Versor); } } }