/// <summary> /// /// </summary> /// <param name="f"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="eps"></param> /// <returns></returns> private static Complex32 falpo(IComplex f, Complex32 a, Complex32 b, float eps = 1e-8f) { Complex32 x1 = a; Complex32 x2 = b; Complex32 fb = f(b); int n = 0; while (Maths.Abs(x2 - x1) > eps && n < short.MaxValue) { Complex32 xpoint = x2 - (x2 - x1) * f(x2) / (f(x2) - f(x1)); Complex32 fxpoint = f(xpoint); float s = fb.Real * fxpoint.Real; // sign if (s > 0) { x2 = xpoint; } else { x1 = xpoint; } if (Maths.Abs(fxpoint) < eps) { break; } n++; } return(x2 - (x2 - x1) * f(x2) / (f(x2) - f(x1))); }
/// <summary> /// Domain transform filter. /// </summary> /// <param name="I">Input signal</param> /// <param name="sigma_s">High sigma</param> /// <param name="sigma_r">Low sigma</param> /// <param name="iterations">Number of iterations</param> internal static void domainfilter(Complex32[] I, float sigma_s, float sigma_r, int iterations = 3) { // params int h = I.GetLength(0); float sigma_H_i; int i; // get differences Complex32[] dIcdy = Matrice.Diff(I, 1); // shift patterns Complex32[] dIdy = new Complex32[h]; for (i = 1; i < h; i++) { dIdy[i] = Maths.Abs(dIcdy[i - 1]); } // sigma patterns and result image for (i = 0; i < h; i++) { dIdy[i] = 1 + sigma_s / sigma_r * dIdy[i]; } // iterations for (i = 0; i < iterations; i++) { sigma_H_i = sigma_s * Maths.Sqrt(3) * Maths.Pow(2, (iterations - (i + 1))) / Maths.Sqrt(Maths.Pow(4, iterations) - 1); // 1D filter tdrf(I, dIdy, sigma_H_i); } return; }
public static Generator Filter(this Generator gen, params FilterType[] types) { foreach (var type in types) { var tempGen = gen; switch (type) { case FilterType.Invert: gen = new Function( x => 1 - tempGen.Get(x), xy => 1 - tempGen.Get(xy), xyz => 1 - tempGen.Get(xyz)); break; case FilterType.Billow: gen = new Function( x => Maths.Abs((2 * tempGen.Get(x)) - 1), xy => Maths.Abs((2 * tempGen.Get(xy)) - 1), xyz => Maths.Abs((2 * tempGen.Get(xyz)) - 1)); break; case FilterType.Ridged: gen = gen.Filter(FilterType.Billow, FilterType.Invert); break; case FilterType.Sin: gen = new Function( x => (Maths.Sin(2 * math.PI * tempGen.Get(x)) / 2) + .5f, xy => (Maths.Sin(2 * math.PI * tempGen.Get(xy)) / 2) + .5f, xyz => (Maths.Sin(2 * math.PI * tempGen.Get(xyz)) / 2) + .5f); break; case FilterType.Asin: gen = new Function( x => (Maths.Asin((2 * tempGen.Get(x)) - 1) / math.PI) + .5f, xy => (Maths.Asin((2 * tempGen.Get(xy)) - 1) / math.PI) + .5f, xyz => (Maths.Asin((2 * tempGen.Get(xyz)) - 1) / math.PI) + .5f); break; case FilterType.Atan: gen = new Function( x => (2 * Maths.Atan((2 * tempGen.Get(x)) - 1) / math.PI) + .5f, xy => (2 * Maths.Atan((2 * tempGen.Get(xy)) - 1) / math.PI) + .5f, xyz => (2 * Maths.Atan((2 * tempGen.Get(xyz)) - 1) / math.PI) + .5f); break; case FilterType.Tanh: gen = new Function( x => 2 * Maths.Tanh(2 * tempGen.Get(x) - 1) / 2 + .5f, xy => 2 * Maths.Tanh(2 * tempGen.Get(xy) - 1) / 2 + .5f, xyz => 2 * Maths.Tanh(2 * tempGen.Get(xyz) - 1) / 2 + .5f); break; default: throw new ArgumentException($"Invalid filter type: '{type.ToString()}'"); } } return(gen); }
/// <summary> /// Apply filter. /// </summary> /// <param name="data">Matrix</param> public void Apply(Complex32[,] data) { int width = data.GetLength(1); int height = data.GetLength(0); int i, j; if (this.type == ThresholdType.Abs) { for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if (Maths.Abs(data[i, j]) < threshold) { data[i, j] = 0; } } } } else if (this.type == ThresholdType.Over) { for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if (data[i, j].Real > threshold) { data[i, j] = 0; } if (data[i, j].Imag > threshold) { data[i, j] = 0; } } } } else { for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if (data[i, j].Real < threshold) { data[i, j] = 0; } if (data[i, j].Imag < threshold) { data[i, j] = 0; } } } } return; }
/// <summary> /// Domain transform filter. /// </summary> /// <param name="I">Input signal</param> /// <param name="sigma_s">High sigma</param> /// <param name="sigma_r">Low sigma</param> /// <param name="iterations">Number of iterations</param> internal static void domainfilter(Complex32[,] I, float sigma_s, float sigma_r, int iterations = 3) { // params int h = I.GetLength(0); int w = I.GetLength(1); float sigma_H_i; int i, j; // get differences Complex32[,] dIcdx = Matrice.Diff(I, 1, Direction.Horizontal); Complex32[,] dIcdy = Matrice.Diff(I, 1, Direction.Vertical); // shift patterns Complex32[,] dIdx = new Complex32[h, w]; Complex32[,] dIdy = new Complex32[h, w]; for (i = 0; i < h; i++) { for (j = 1; j < w; j++) { dIdx[i, j] = Maths.Abs(dIcdx[i, j - 1]); } } for (i = 1; i < h; i++) { for (j = 0; j < w; j++) { dIdy[i, j] = Maths.Abs(dIcdy[i - 1, j]); } } // sigma patterns and result image for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { dIdx[i, j] = 1 + sigma_s / sigma_r * dIdx[i, j]; dIdy[i, j] = 1 + sigma_s / sigma_r * dIdy[i, j]; } } // iterations for (i = 0; i < iterations; i++) { sigma_H_i = sigma_s * Maths.Sqrt(3) * Maths.Pow(2, (iterations - (i + 1))) / Maths.Sqrt(Maths.Pow(4, iterations) - 1); // 2D filter tdrf_h(I, dIdx, sigma_H_i); tdrf_v(I, dIdy, sigma_H_i); } return; }
/// <summary> /// Implements a wavelet filter. /// </summary> /// <param name="data">Matrix</param> public void Apply(Complex32[,] data) { var B = WaveletDecomposition.Forward(data); int n, m; for (int i = 1; i < B.Length; i++) { var b = B[i]; n = b.GetLength(0); m = b.GetLength(1); if (!Maths.IsEven(n)) { n--; // ? } if (!Maths.IsEven(m)) { m--; // ? } // visu_shrink var bb = Matrice.Reshape(b, b.Length).ToAbs(); Array.Sort(bb); var median = Math.Sqrt(bb[bb.Length / 2]) * Math.Sqrt(Maths.Log2(n * m)); for (int y = 0; y < n; y++) { for (int x = 0; x < m; x++) { b[y, x] = Maths.Abs(b[y, x]) > median ? b[y, x] : 0; } } B[i] = b; } var output = WaveletDecomposition.Backward(B); float factor = 1 + Factor; n = data.GetLength(0); m = data.GetLength(1); for (int y = 0; y < n; y++) { for (int x = 0; x < m; x++) { // pass filtering data[y, x] = output[y, x] + factor * (data[y, x] - output[y, x]); } } }
/// <summary> /// /// </summary> /// <param name="f"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="eps"></param> /// <returns></returns> private static Complex32 chord(IComplex f, Complex32 a, Complex32 b, float eps = 1e-8f) { int n = 0; Complex32 x0 = (b - a) / 2.0; Complex32 x; while (Maths.Abs(f(x0) / b) > eps && n < short.MaxValue) { x = x0; x0 = x - (f(x) * (a - x)) / (f(a) - f(x)); n++; } return(x0); }
/// <summary> /// Apply filter. /// </summary> /// <param name="data">Array</param> public void Apply(Complex32[] data) { int length = data.Length; int i; if (this.type == ThresholdType.Abs) { for (i = 0; i < length; i++) { if (Maths.Abs(data[i]) < threshold) { data[i] = 0; } } } else if (this.type == ThresholdType.Over) { for (i = 0; i < length; i++) { if (data[i].Real > threshold) { data[i].Real = 0; } if (data[i].Imag > threshold) { data[i].Imag = 0; } } } else { for (i = 0; i < length; i++) { if (data[i].Real < threshold) { data[i].Real = 0; } if (data[i].Imag < threshold) { data[i].Imag = 0; } } } return; }
/// <summary> /// /// </summary> /// <param name="f"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="eps"></param> /// <returns></returns> private static Complex32 secan(IComplex f, Complex32 a, Complex32 b, float eps = 1e-8f) { Complex32 x1 = a; Complex32 x2 = b; Complex32 fb = f(b); Complex32 mpoint; int n = 0; while (Maths.Abs(f(x2)) > eps && n < short.MaxValue) { mpoint = x2 - (x2 - x1) * fb / (fb - f(x1)); x1 = x2; x2 = mpoint; fb = f(x2); n++; } return(x2); }
internal static void AssertEqualOrNegatedWithinReason(Quaternion a, Quaternion b) { Boolean pass1 = Maths.Abs(a.I - b.I) <= MathsTests.TestTolerance && Maths.Abs(a.J - b.J) <= MathsTests.TestTolerance && Maths.Abs(a.K - b.K) <= MathsTests.TestTolerance && Maths.Abs(a.U - b.U) <= MathsTests.TestTolerance; Quaternion c; Quaternion.Negate(ref b, out c); Boolean pass2 = Maths.Abs(a.I - c.I) <= MathsTests.TestTolerance && Maths.Abs(a.J - c.J) <= MathsTests.TestTolerance && Maths.Abs(a.K - c.K) <= MathsTests.TestTolerance && Maths.Abs(a.U - c.U) <= MathsTests.TestTolerance; Assert.That(pass1 || pass2, Is.EqualTo(true)); }
/// <summary> /// /// </summary> /// <param name="f"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="iterations"></param> /// <param name="eps"></param> /// <returns></returns> private static Complex32 romb(IComplex f, Complex32 a, Complex32 b, int iterations, float eps = 1e-8f) { int n = 2; Complex32 h = b - a; Complex32 sum = 0.0; int j = 0; Complex32[,] R = new Complex32[iterations, iterations]; R[1, 1] = h * (f(a) + f(b)) / 2.0; h = h / 2; R[2, 1] = R[1, 1] / 2 + h * f(a + h); R[2, 2] = (4 * R[2, 1] - R[1, 1]) / 3; for (j = 3; j <= iterations; j++) { n = 2 * n; h = h / 2; sum = 0.0; for (int k = 1; k <= n; k += 2) { sum += f(a + k * h); } R[j, 1] = R[j - 1, 1] / 2 + h * sum; float factor = 4.0f; for (int k = 2; k <= j; k++) { R[j, k] = (factor * R[j, k - 1] - R[j - 1, k - 1]) / (factor - 1); factor = factor * 4.0f; } if (Maths.Abs(R[j, j] - R[j, j - 1]) < eps * Maths.Abs(R[j, j])) { sum = R[j, j]; return(sum); } } sum = R[n, n]; return(sum); }
/// <summary>Called when new data is received</summary> public override void Step() { // Only on new candles Position = FindLivePosition(Position); if (!Instrument.NewCandle) { return; } if (Debugger.IsAttached) { Debugging.Dump(Instrument, high_res: 20.0, emas: new[] { 100 }); if (Instrument.Count == 230) { Debug.WriteLine("Break"); } } var sym = Instrument.Symbol; var mcs = Instrument.MedianCandleSize(-10, 0); var C0 = Instrument[0]; var C1 = Instrument[-1]; var C2 = Instrument[-2]; // One at a time if (Position == null) { TradeType tt; string msg; // Look for a reversal int reversal_direction; QuoteCurrency target_entry; if (!Instrument.IsCandlePattern(0, out reversal_direction, out target_entry)) { return; } var preceeding_trend = Instrument.MeasureTrend(-10, 0); var tt_confirmation = C1.Bullish ? TradeType.Buy : TradeType.Sell; const double EmaSlopeToMCS = 20; var ema = Bot.Indicators.ExponentialMovingAverage(Bot.MarketSeries.Close, 100); var ema_slope = ema.Result.FirstDerivative(ema.Result.Count - 1) * EmaSlopeToMCS / mcs; // If the EMA slope is flat, look for ranging if (Math.Abs(ema_slope) < 1.0) { // Side of the EMA. Must be significantly to one side of the EMA var dist = C1.Close - ema.Result.LastValue; if (Math.Abs(dist) < mcs) { return; } tt = C1.Close < ema.Result.LastValue ? TradeType.Buy : TradeType.Sell; msg = "{0} - ranging EMA. Slope = {1}, Distance = {2}".Fmt(tt, ema_slope, dist); } // Otherwise look for indecision near the EMA else { var dist = C1.Close - ema.Result.LastValue; if (Maths.Abs(dist) > mcs) { return; } tt = ema_slope > 0.0 ? TradeType.Buy : TradeType.Sell; msg = "{0} - trending EMA. Slope = {1}, Dist = {2}".Fmt(tt, ema_slope, dist); } // Check the candle confirms the direction if (tt != tt_confirmation) { return; } var sign = tt.Sign(); var rtr = new RangeF(1.0, 2.0); var trade = new Trade(Bot, Instrument, tt, Label, rtr_range: rtr); Bot.Print(msg); Position = Bot.Broker.CreateOrder(trade); PositionManager = new PositionManager(Instrument, Position); } else { PositionManager.Step(); } }
public void GenerateRoom(Room parent, Room child) { IntVector2 direction = child.node.position - parent.node.position; IntVector2 orthogonal_direction = direction.RotateHalfPi(); Vector2 parent_center = parent.Center; Vector2 parent_border = parent.GetBorderCenter(direction); IntVector2 parent_orthogonal_dimension_minus_one_vector = parent.GetDimensionMinusOneVector(orthogonal_direction); int parent_orthogonal_dimension = parent.GetDimension(orthogonal_direction); IntVector2 child_orthogonal_dimension_vector = child.GetDimensionVector(orthogonal_direction); IntVector2 child_orthogonal_dimension_minus_one_vector = child.GetDimensionMinusOneVector(orthogonal_direction); int child_orthogonal_dimension = child.GetDimension(orthogonal_direction); IntVector2 child_dimension_minus_one_vector = child.GetDimensionMinusOneVector(direction); int wall_width = 1; int useful_parent_width = parent_orthogonal_dimension - 2 * wall_width; int useful_child_width = child_orthogonal_dimension - 2 * wall_width; Assert.That( useful_child_width >= options.min_hallway_width && useful_parent_width >= options.min_hallway_width, "Cannot be less" ); int min_orthogonal_offset = -useful_child_width + options.min_hallway_width; int max_orthogonal_offset = useful_parent_width - options.min_hallway_width; Queue <int> offsets_queue = Functions.ShuffledRangeQueue( min_orthogonal_offset, max_orthogonal_offset, rng); while (offsets_queue.Count != 0) { int current_orthogonal_offset = offsets_queue.Dequeue(); int current_useful_parent_width = useful_parent_width; int current_useful_child_width = useful_child_width; if (current_orthogonal_offset > 0) { current_useful_parent_width -= current_orthogonal_offset; } else { current_useful_child_width += current_orthogonal_offset; } int min_useful_width = Maths.Min(current_useful_parent_width, current_useful_child_width); int max_hallway_width = Maths.Min(options.max_hallway_width, min_useful_width); int min_hallway_width = options.min_hallway_width; int min_hallway_length = options.min_hallway_length; int max_hallway_length = options.max_hallway_length; int current_hallway_width = rng.Next(min_hallway_width, max_hallway_width + 1); int current_hallway_length = rng.Next(min_hallway_length, max_hallway_length + 1); int min_hallway_offset = 0; int max_hallway_offset = min_useful_width - current_hallway_width; int current_hallway_offset = rng.Next(min_hallway_offset, max_hallway_offset + 1); Vector2 child_corner = parent_border + ((Vector2)parent_orthogonal_dimension_minus_one_vector) / 2 + direction * (current_hallway_length + 1) + orthogonal_direction * current_orthogonal_offset; if (child_corner.IsWhole() == false) { throw new System.Exception("Must be whole. Review the algo"); } Vector2 child_center = child_corner - ((Vector2)child_orthogonal_dimension_minus_one_vector) / 2 + ((Vector2)child_dimension_minus_one_vector) / 2; child.SetPositionFromCenter(child_center); if (!IntersectsRooms(child)) { // child.roomStuff = new RoomStuff // { // hallway_length = current_hallway_length, // hallway_width = current_hallway_width, // wall_width = wall_width, // hallway_coord // }; Vector2 hallway_start = parent_border + ((Vector2)parent_orthogonal_dimension_minus_one_vector) / 2 - orthogonal_direction * wall_width - orthogonal_direction * current_hallway_offset; if (current_orthogonal_offset < 0) { hallway_start += orthogonal_direction * current_orthogonal_offset; } IntVector2 hallway_start_int = (IntVector2)hallway_start; IntVector2 hallway_dims = direction * Maths.Abs(current_hallway_length + 2) + orthogonal_direction * Maths.Abs(current_hallway_width + 2); Vector2 hallway_center = hallway_start + (Vector2)direction * (((float)current_hallway_length + 1) / 2); Room hallway = new Room(hallway_dims, null); hallway.SetPositionFromCenter(hallway_center); if (!IntersectsRooms(hallway)) { WriteRoom(child); WriteHallway( current_hallway_length + 2, current_hallway_width, direction, hallway_start_int); rooms.Add(hallway); offsets_queue.Clear(); } } } }
/// <summary> /// Returns the value of the probability density function. /// </summary> /// <param name="x">Value</param> /// <returns>float precision floating point number</returns> public float Function(float x) { return(a / 2.0f * Maths.Exp(-a * Maths.Abs(x - b))); }
void CollisionResponse(float deltaTime) { for (int i = 0; i < intersections.Length; i++) { Intersection intersection = intersections[i]; PhysicsBodyComponent p1 = intersection.Object1; PhysicsBodyComponent p2 = intersection.Object2; AxisAlignedBoundingBox p1Collider = p1.GetCollider(); AxisAlignedBoundingBox p1DeltaCollider = p1.GetColliderAt(p1.Delta.FinalPosition); AxisAlignedBoundingBox p2Collider = p2.GetCollider(); AxisAlignedBoundingBox p2DeltaCollider = p2.GetColliderAt(p2.Delta.FinalPosition); if (intersection.Type == IntersectionType.Rigid) { // Update the intersection data, so that previous updates for // these objects are applied intersection.UpdateFromDelta(); // If both entry times are invalid, the objects aren't intersecting anymore, // so ignore the collision. if (intersection.Object1EntryTime == 1 && intersection.Object2EntryTime == 1) { continue; } // Handle the collision based on static states if (intersection.Object2.IsStatic) { // If we are past the first sweep pass for this object, // and this intersection is no longer valid, then ignore it. if (p1.Delta.DeltaPass > 0) { if (!p1DeltaCollider.Intersects(p2Collider)) { continue; } } // Gather intersection data Vector3 surfaceNormal = intersection.Object2Normal; float collisionTime = intersection.Object1EntryTime; float remainingTime = 1f - collisionTime; float stepDist = intersection.Resolver.StepDistance(p1DeltaCollider, p2Collider); //if (surfaceNormal.Y == 0) // Diagnostics.DashCMD.WriteLine("{0} | {1}", stepDist.ToString(), Math.Min(p1.Delta.MaxStep, p1.MaxStep)); //Diagnostics.DashCMD.WriteLine(surfaceNormal); // Try to step on object if (p1.CanStep && p2.CanBeSteppedOn && surfaceNormal.Y == 0 && stepDist >= 0 && stepDist <= Math.Min(p1.Delta.MaxStep, p1.MaxStep)) { // Step onto object p1.Delta.FinalPosition.Y += stepDist + 0.001f; p1.Delta.FinalVelocity.Y = 0; p1.Delta.IsGrounded = p1.Delta.IsGrounded || true; p1.Delta.Stepped = true; } else // Normal collision resolve { // Calculate the compensation in position from the collision Vector3 compensation = surfaceNormal * (Maths.Abs(p1.Delta.FinalVelocity * deltaTime)) * remainingTime; p1.Delta.FinalPosition += compensation; // If this normal moved the object anywhere upward, // that object is now considered grounded if (surfaceNormal.Y > 0) { p1.Delta.IsGrounded = p1.Delta.IsGrounded || true; } // Fix the velocity if (p1.BounceOnWallCollision || p1.BounceOnVerticalCollision) { if ((surfaceNormal.X != 0 || surfaceNormal.Z != 0) && p1.BounceOnWallCollision) { if (surfaceNormal.X != 0) { p1.Delta.FinalVelocity.X *= -(1f - p1.HorizontalBounceFalloff); } if (surfaceNormal.Z != 0) { p1.Delta.FinalVelocity.Z *= -(1f - p1.HorizontalBounceFalloff); } } else if (surfaceNormal.Y != 0 && p1.BounceOnVerticalCollision) { p1.Delta.FinalVelocity.Y *= -(1f - p1.VerticalBounceFalloff); p1.Delta.FinalVelocity.X *= p1.InverseFriction; p1.Delta.FinalVelocity.Z *= p1.InverseFriction; } else { intersection.Resolver.FixVelocity(ref p1.Delta.FinalVelocity, surfaceNormal); } } else { intersection.Resolver.FixVelocity(ref p1.Delta.FinalVelocity, surfaceNormal); } } // Another delta pass has occured p1.Delta.DeltaPass++; p1.OnCollide(p2); p2.OnCollide(p1); } else if (intersection.Object1.IsStatic) { // If we are past the first sweep pass for this object, // and this intersection is no longer valid, then ignore it. if (p2.Delta.DeltaPass > 0) { if (!p2DeltaCollider.Intersects(p1Collider)) { continue; } } // Gather intersection data Vector3 surfaceNormal = intersection.Object1Normal; float collisionTime = intersection.Object2EntryTime; float remainingTime = 1f - collisionTime; float stepDist = intersection.Resolver.StepDistance(p2DeltaCollider, p1Collider); // Try to step on object if (p2.CanStep && p1.CanBeSteppedOn && surfaceNormal.Y == 0 && stepDist >= 0 && stepDist <= Math.Min(p2.Delta.MaxStep, p2.MaxStep)) { // Step onto object p2.Delta.FinalPosition.Y += stepDist + 0.001f; p2.Delta.FinalVelocity.Y = 0; p2.Delta.IsGrounded = p2.Delta.IsGrounded || true; p2.Delta.Stepped = true; } else // Normal collision resolve { // Calculate the compensation in position from the collision Vector3 compensation = surfaceNormal * (Maths.Abs(p2.Delta.FinalVelocity * deltaTime)) * remainingTime; p2.Delta.FinalPosition += compensation; // If this normal moved the object anywhere upward, // that object is now considered grounded if (surfaceNormal.Y > 0) { p2.Delta.IsGrounded = p2.Delta.IsGrounded || true; } // Fix the velocity if (p2.BounceOnWallCollision || p2.BounceOnVerticalCollision) { if ((surfaceNormal.X != 0 || surfaceNormal.Z != 0) && p2.BounceOnWallCollision) { if (surfaceNormal.X != 0) { p2.Delta.FinalVelocity.X *= -(1f - p2.HorizontalBounceFalloff); } if (surfaceNormal.Z != 0) { p2.Delta.FinalVelocity.Z *= -(1f - p2.HorizontalBounceFalloff); } } else if (surfaceNormal.Y != 0 && p2.BounceOnVerticalCollision) { p2.Delta.FinalVelocity.Y *= -(1f - p2.VerticalBounceFalloff); p1.Delta.FinalVelocity.X *= p1.InverseFriction; p1.Delta.FinalVelocity.Z *= p1.InverseFriction; } else { intersection.Resolver.FixVelocity(ref p2.Delta.FinalVelocity, surfaceNormal); } } else { intersection.Resolver.FixVelocity(ref p2.Delta.FinalVelocity, surfaceNormal); } } // Another delta pass has occured p2.Delta.DeltaPass++; p1.OnCollide(p2); p2.OnCollide(p1); } } else { // If we are past the first sweep pass for this object, // and this intersection is no longer valid, then ignore it. if ((!p1DeltaCollider.Intersects(p2Collider)) && (!p2DeltaCollider.Intersects(p1Collider))) { continue; } float p1DeltaMiddleX = p1.Delta.FinalPosition.X + p1.Size.X / 2f; float p2DeltaMiddleX = p2.Delta.FinalPosition.X + p2.Size.X / 2f; float p1DeltaMiddleZ = p1.Delta.FinalPosition.Z + p1.Size.Z / 2f; float p2DeltaMiddleZ = p2.Delta.FinalPosition.Z + p2.Size.Z / 2f; Vector3 p1Move = new Vector3((p2DeltaMiddleX - p1DeltaMiddleX), 0, (p2DeltaMiddleZ - p1DeltaMiddleZ)); Vector3 p2Move = new Vector3((p1DeltaMiddleX - p2DeltaMiddleX), 0, (p1DeltaMiddleZ - p2DeltaMiddleZ)); if (p1Move.X == p2Move.X) { p1Move.X += Maths.Random.Next((int)-p2.Size.X, (int)p2.Size.X) / deltaTime; } Vector2 masses = new Vector2((p2.Mass / p1.Mass), (p1.Mass / p2.Mass)) * 0.5f; if (p1.CanBePushedBySoft) { p1.Delta.FinalVelocity -= p1Move * masses.X; p1.Delta.FinalPosition = p1.Transform.Position + p1.Delta.FinalVelocity * deltaTime; } if (p2.CanBePushedBySoft) { p2.Delta.FinalVelocity -= p2Move * masses.Y; p2.Delta.FinalPosition = p2.Transform.Position + p2.Delta.FinalVelocity * deltaTime; } p1.OnCollide(p2); p2.OnCollide(p1); } } }