public void TestIReadonlyDictionaryInterface() { var context = new PhysicalContext <int>(1, 2); var entity1 = new PointMass ( new AxisStatus(1, 0), new AxisStatus(1, 0), new AxisStatus(1, 0), 1 ); var entity2 = new PointMass ( new AxisStatus(2, 0), new AxisStatus(2, 0), new AxisStatus(2, 0), 1 ); context.AddEntity(1, entity1); context.AddEntity(2, entity2, c => { double val = 0; foreach (var key in context.Keys) { val += context[key].X.Position; } return(new Force(val, val, val)); }); }
public void TestTickPredicate() { var context = new PhysicalContext <int>(1, 1); var entity = new PointMass ( new AxisStatus(1, 0), new AxisStatus(0, 1), new AxisStatus(0, 0), 1 ); context.AddEntity ( 0, entity ); var source = new System.Threading.CancellationTokenSource(); source.Cancel(); context.Tick(1, _ => !source.IsCancellationRequested); AreEqual(entity, context[0]); AreEqual(0u, context.Ticks); var isGoalReached = context.Tick(10, c => c.Ticks < 5); AreEqual(5u, context.Ticks); IsFalse(isGoalReached); isGoalReached = context.Tick(10, c => true); AreEqual(15u, context.Ticks); IsTrue(isGoalReached); }
public void TestBindedEntities() { var context = new PhysicalContext <int>(1, 2); var entity1 = new PointMass ( new AxisStatus(2, 0), new AxisStatus(0, 0), new AxisStatus(0, 0), 1 ); var entity2 = new PointMass ( new AxisStatus(0, 0), new AxisStatus(3, 0), new AxisStatus(0, 0), 1 ); context.AddEntity ( 1, entity1, c => new Force(c[2].Y.Position, 0, 0) ); context.AddEntity ( 2, entity2, c => new Force(0, c[1].X.Position, 0) ); context.Tick(); AreEqual(entity1.Next(1, new Force(3, 0, 0)), context[1]); AreEqual(entity2.Next(1, new Force(0, 2, 0)), context[2]); }
public void TestZeroForce() { var context = new PhysicalContext <int>(3, 1); var entity = new PointMass ( new AxisStatus(0, 1), new AxisStatus(0, 1), new AxisStatus(0, 1), 1 ); context.AddEntity ( 0, entity, c => new Force(-1, -2, -3), c => new Force(1, 2, 3) ); AreEqual(entity, context[0]); context.Tick(); AreEqual(entity.Next(3), context[0]); context.Tick(); AreEqual(entity.Next(3).Next(3), context[0]); }
public void TestThrowingException() { var context = new PhysicalContext <int>(1, 1); var contextSeq = new PhysicalContext <int>(1, 1, SimulationParams.None); var entity = new PointMass ( new AxisStatus(0, 1), new AxisStatus(0, 1), new AxisStatus(0, 1), 1 ); ThrowsException <UninitializedPhysicalContextException <int> >(() => context.Tick()); ThrowsException <UninitializedPhysicalContextException <int> >(() => contextSeq.Tick()); context.AddEntity ( 0, entity, // Unexisting key {1} is here c => new Force(c[1].X.Position, 0, 0) ); contextSeq.AddEntity ( 0, entity, // Unexisting key {1} is here c => new Force(c[1].X.Position, 0, 0) ); ThrowsException <AggregateException>(() => context.Tick()); ThrowsException <UnexistingEntityException <int> >(() => contextSeq.Tick()); ThrowsException <FilledPhysicalContextException <int> >(() => context.AddEntity(1, entity)); ThrowsException <FilledPhysicalContextException <int> >(() => contextSeq.AddEntity(1, entity)); }
public void TestCheckPoints() { var context = new PhysicalContext <int>(0.5, 1); context.AddEntity(0, new PointMass()); context.Tick(); ThrowsException <ArgumentOutOfRangeException>(() => new ContextProgressTracker <int>(context, 10, 0)); ThrowsException <ArgumentOutOfRangeException>(() => new ContextProgressTracker <int>(context, 10, 12)); context.Tick(); var trackerInt = new ContextProgressTracker <int>(context, 10, 3, 9); var trackerDouble = ContextProgressTracker <int> .FromTime(context, 10, 3, 9); int reachedInt = 0, reachedDouble = 0; trackerInt.OnCheckPoint += (c, _) => reachedInt++; trackerDouble.OnCheckPoint += (c, _) => reachedDouble++; for (int i = 0; i < 12; i++) { context.Tick(); } AreEqual(2, reachedInt); AreEqual(1, reachedDouble); }
public void TestInit1() { var context = new PhysicalContext <int>(0.1, 1); var entity = new PointMass(new AxisStatus(1, 3), new AxisStatus(0, 0), new AxisStatus(0, 0), 1); context.AddEntity(0, entity); var tracker = new ContextTracker <int, double>(context, c => c[0].X.Position); AreEqual(1, tracker[0]); AreEqual(0ul, tracker.ObservationBeginTick); ThrowsException <ArgumentOutOfRangeException>(() => tracker[2]); context.Tick(0.5); AreEqual(1, tracker[0]); var pos05 = context[0].X.Position; AreEqual(pos05, tracker[5]); AreEqual(pos05, tracker.GetApproximately(0.5)); context.Tick(0.5); AreEqual(1, tracker[0]); AreEqual(pos05, tracker.GetApproximately(0.5)); AreEqual(pos05, tracker.GetApproximately(0.478)); AreEqual(pos05, tracker.GetApproximately(0.505)); AreEqual(context[0].X.Position, tracker[context.Ticks]); }
public void TestDispose() { var context = new PhysicalContext <int>(0.1, 2); var entity = new PointMass(0, 0, 0, 1); context.AddEntity(0, entity, c => new Force(1, 0, 0)); context.AddEntity(1, entity, c => new Force(1, 0, 0)); context.Tick(1); var tracker = new ContextTracker <int, int>(context, c => (int)Math.Round(c[0].X.Velocity + c[1].X.Velocity)); AreEqual(2, tracker[context.Ticks]); AreEqual(10ul, tracker.ObservationBeginTick); ThrowsException <ArgumentOutOfRangeException>(() => tracker.GetApproximately(0)); ThrowsException <ArgumentOutOfRangeException>(() => tracker.GetApproximately(2)); context.Tick(1); AreEqual(2, tracker.GetApproximately(1)); AreEqual(1, tracker.ObservationBeginTime); AreEqual(4, tracker[context.Ticks]); AreEqual(20ul, tracker.LastObservedTick); tracker.Dispose(); context.Tick(1); AreEqual(20ul, tracker.LastObservedTick); ThrowsException <ArgumentOutOfRangeException>(() => tracker[context.Ticks]); }
public void TestOnTick() { var context = new PhysicalContext <int>(1, 1); var entity = new PointMass ( new AxisStatus(0, 1), new AxisStatus(0, 1), new AxisStatus(0, 1), 1 ); context.AddEntity ( 0, entity, c => new Force(0, 1, 2) ); var count = 0; context.Tick(); context.OnTick += (c, e) => count++; context.Tick(); AreEqual(1, count); context.OnTick += (c, e) => count++; context.Tick(); AreEqual(3, count); context.OnTick += (c, e) => ((PhysicalContext <int>)c).Tick(); ThrowsException <LockedPhysicalContextException <int> >(() => context.Tick()); }
public void TestTimer() { var context = new PhysicalContext <int>(0.3, 1); context.AddEntity(0, new PointMass()); AreEqual(0, context.Timer); context.Tick(); context.Tick(); AreEqual(0.6, context.Timer); context.Tick(1); AreEqual(1.5, context.Timer); }
public void TestLaw1() { var context = new PhysicalContext <int>(1, 2); context.AddEntity(0, new PointMass(new AxisStatus(0, 1), new AxisStatus(0, -2), new AxisStatus(0, 0), 0)); context.AddEntity(1, new PointMass(3, 4, 0, 0)); var law = StokesDragLaw.GetLaw(0, 10); AreEqual(new Force(-10, 20, 0), law(context)); law = StokesDragLaw.GetLaw(1, 3); AreEqual(new Force(0, 0, 0), law(context)); }
public void TestBindedEntities2() { var context = new PhysicalContext <int>(1, 2); var entity1 = new PointMass ( new AxisStatus(0, 1), new AxisStatus(0, 1), new AxisStatus(0, 1), 1 ); var entity2 = new PointMass ( new AxisStatus(0, 2), new AxisStatus(0, 2), new AxisStatus(0, 2), 1 ); context.AddEntity ( 1, entity1, (c) => new Force(c[2].X.Velocity, c[2].Y.Velocity, c[2].Z.Velocity) ); context.AddEntity ( 2, entity2, c => new Force(c[1].X.Velocity, c[1].Y.Velocity, c[1].Z.Velocity) ); context.Tick(); entity1 = entity1.Next(1, new Force(2, 2, 2)); entity2 = entity2.Next(1, new Force(1, 1, 1)); AreEqual(entity1, context[1]); AreEqual(entity2, context[2]); context.Tick(); entity1 = entity1.Next(1, new Force(3, 3, 3)); entity2 = entity2.Next(1, new Force(3, 3, 3)); AreEqual(entity1, context[1]); AreEqual(entity2, context[2]); context.Tick(); entity1 = entity1.Next(1, new Force(6, 6, 6)); entity2 = entity2.Next(1, new Force(6, 6, 6)); AreEqual(entity1, context[1]); AreEqual(entity2, context[2]); }
public void TestLocking() { var context = new PhysicalContext <int>(1, 1); var entity = new PointMass(); context.AddEntity(0, entity, c => { context.Tick(); return(new Force()); }); try { context.Tick(); } catch (AggregateException e) { IsTrue(e.InnerExceptions.First() is LockedPhysicalContextException <int>); } }
public void TestObserving() { var context = new PhysicalContext <int>(1, 1); var entity = new PointMass(new AxisStatus(3, 0), new AxisStatus(1, 1), new AxisStatus(0, 0), 1); context.AddEntity(0, entity); var max0X = new ContextDependentValue <int, double> ( context[0].X.Position, context, (c, old) => c[0].X.Position > old ? new double?(c[0].X.Position) : null ); context.Tick(); context.Tick(); var max0Y = new ContextDependentValue <int, double> ( context[0].Y.Position, context, (c, old) => c[0].Y.Position > old ? new double?(c[0].Y.Position) : null ); AreEqual(0ul, max0X.ObservationBeginTick); AreEqual(2ul, max0X.LastObservedTick); AreEqual(0ul, max0X.LastValueChangeTick); AreEqual(3ul, max0X.Value); context.Tick(); context.Tick(); AreEqual(2ul, max0Y.ObservationBeginTick); AreEqual(4ul, max0Y.LastObservedTick); AreEqual(4ul, max0Y.LastValueChangeTick); AreEqual(5ul, max0Y.Value); max0Y.Dispose(); context.Tick(); context.Tick(); AreEqual(2ul, max0Y.ObservationBeginTick); AreEqual(4ul, max0Y.LastObservedTick); AreEqual(4ul, max0Y.LastValueChangeTick); AreEqual(5ul, max0Y.Value); }
public void TestLaw2() { var context = new PhysicalContext <int>(1, 2); context.AddEntity(0, new PointMass(1, 1, 1, 0)); context.AddEntity(1, new PointMass(1, 1, 2, 0)); var law = HookesLaw.GetLaw(1, 0, undeformedDistance: 0, elasticityCoefficient: 1); AreEqual(new Force(0, 0, -1), law(context)); law = HookesLaw.GetLaw(1, 0, undeformedDistance: 3, elasticityCoefficient: 2); AreEqual(new Force(0, 0, 4), law(context)); law = HookesLaw.GetLaw(1, 0, undeformedDistance: 12, elasticityCoefficient: 0); AreEqual(new Force(0, 0, 0), law(context)); }
public void TestStoryboard() { var context = new PhysicalContext <int>(1, 1); var entity = new PointMass(new AxisStatus(0, 1), new AxisStatus(1, 0), new AxisStatus(0, 0), 1); context.AddEntity(0, entity); var tracker = new ContextTracker <int, double>(context, c => c[0].X.Position); AreEqual(1, tracker.Count); IsTrue(tracker.Keys.Contains <ulong>(0)); context.Tick(); AreEqual(2, tracker.Count); IsTrue(tracker.Keys.Contains <ulong>(0)); IsTrue(tracker.Keys.Contains <ulong>(1)); IsFalse(tracker.Keys.Contains <ulong>(2)); }
public void TestLaw1() { var context = new PhysicalContext <int>(1, 2); context.AddEntity(0, new PointMass(0, 0, 0, 0)); context.AddEntity(1, new PointMass(3, 4, 0, 0)); var law = HookesLaw.GetLaw(1, 0, undeformedDistance: 5, elasticityCoefficient: 1); AreEqual(new Force(0, 0, 0), law(context)); law = HookesLaw.GetLaw(1, 0, undeformedDistance: 10, elasticityCoefficient: 1); AreEqual(new Force(3, 4, 0), law(context)); law = HookesLaw.GetLaw(1, 0, undeformedDistance: 10, elasticityCoefficient: 2); AreEqual(new Force(6, 8, 0), law(context)); law = HookesLaw.GetLaw(1, 0, undeformedDistance: 0, elasticityCoefficient: 0.1); AreEqual(new Force(-0.3, -0.4, 0), law(context)); }
public void TestLaw1() { var context = new PhysicalContext <int>(1, 2); context.AddEntity(0, new PointMass(0, 0, 0, 0)); context.AddEntity(1, new PointMass(3, 4, 0, 0)); var law = RadialCollisionLaw.GetLaw(1, 0, criticalDistance: 3, elasticityCoefficient: 1); AreEqual(new Force(0, 0, 0), law(context)); law = RadialCollisionLaw.GetLaw(1, 0, criticalDistance: 10, elasticityCoefficient: 1); AreEqual(new Force(3, 4, 0), law(context)); law = RadialCollisionLaw.GetLaw(1, 0, criticalDistance: 5, elasticityCoefficient: 1); AreEqual(new Force(0, 0, 0), law(context)); law = RadialCollisionLaw.GetLaw(1, 0, criticalDistance: 6, elasticityCoefficient: 50); AreEqual(new Force(30, 40, 0), law(context)); }
public void TestInterval() { ulong[] intervals = { 1, 3, 11, 100 }; foreach (var i in intervals) { var context = new PhysicalContext <int>(1, 1); var entity = new PointMass(new AxisStatus(0, 1), new AxisStatus(1, 0), new AxisStatus(0, 0), 1); context.AddEntity(0, entity); var tracker = new ContextTracker <int, double>(context, c => c[0].X.Position, i); context.Tick(42); AreEqual((int)(42 / i + 1), tracker.Count); AreEqual(42 - 42 % i, tracker.LastRecordTick); ThrowsException <ArgumentOutOfRangeException>(() => tracker[43]); if (i > 1) { ThrowsException <ArgumentOutOfRangeException>(() => tracker[i + 1]); } var noException = tracker[0]; } }
public void TestTickSequential() { var context = new PhysicalContext <int>(0.23, 1, SimulationParams.None); var entity = new PointMass ( new AxisStatus(1, 0), new AxisStatus(0, 1), new AxisStatus(0, 0), 1 ); context.AddEntity ( 0, entity, c => new Force(c[0].X.Velocity, c[0].Y.Velocity, c[0].Z.Velocity) ); AreEqual(entity, context[0]); context.Tick(); AreEqual(entity.Next(0.23, new Force(0, 1, 0)), context[0]); }
public void TestUniformForce() { var context = new PhysicalContext <int>(0.1, 1); var entity = new PointMass ( new AxisStatus(1, 2), new AxisStatus(2, 3), new AxisStatus(3, 4), 1 ); context.AddEntity ( 0, entity, c => new Force(3, 4, 5) ); AreEqual(entity, context[0]); context.Tick(); AreEqual(entity.Next(0.1, new Force(3, 4, 5)), context[0]); }
public void TestGoal() { var context = new PhysicalContext <int>(1, 1); context.AddEntity(0, new PointMass()); context.Tick(); context.Tick(); var tracker = new ContextProgressTracker <int>(context, 10); AreEqual(0, tracker.Progress); bool goal = false; tracker.OnGoal += (c, e) => goal = true; context.Tick(4); AreEqual(0.5, tracker.Progress); context.Tick(4); AreEqual(1, tracker.Progress); IsFalse(tracker.IsActive); IsTrue(goal); }
static void Main(string[] args) { //PhysicalContext is the core class represents set of entities and //set of force evaluation laws binded to it. //Type parameter represents the type of keys used to adding and retrieving entities. var context = new PhysicalContext <string> ( timePerTick: dt, //The time, that is considered to be as small, as force values are uniform. //The smaller timePerTick is, the better precision we get. //Be aware, time for evaluating state of entities after certain period of time //is proportional to (timePerTick)^-1. capacity: 1 //Number of entities required to be added to context. ); //Adding entity var freeFallEntity = new PointMass ( x: new AxisStatus(3.4), //Position = 3.4, zero velocity y: new AxisStatus(0, 10), //Zero position, velocity = 10 z: new AxisStatus(1.1, 2), //Position = 1.1, Velocity = 2 mass: 77.7 ); context.AddEntity ( "freeFallEntity", //key freeFallEntity, //entity c => //Only force that have impact on this entity - new Force ( xComponent: 0, yComponent: c["freeFallEntity"].Mass * freeFallAcceleration, zComponent: 0 ) //This force is always vertical and equal to mass of entity multiplied //by free fall acceleration. ); Console.WriteLine($"Start state is \n{context["freeFallEntity"]}"); //Evaluating the state of context after 1 second. context.Tick(timeSpan: 1); Console.WriteLine($"\nState of entity after 1 second is \n{context["freeFallEntity"]}"); //If you want to record some data while context is updating, //you may subscribe to OnTick event or better use class derived from ContextObserver. var yPositionTracker = new ContextTracker <string, double> ( context, c => c["freeFallEntity"].Y.Position ); context.Tick(1); //Context tracker implements IReadonlyDictionary. Console.WriteLine($"\nOn tick 10345 y position is {yPositionTracker[10345]}"); Console.WriteLine($"\nOn time 1.27 y position is {yPositionTracker.GetApproximately(1.27)}"); //Throws exception because tracker has started recording when time is context //was already 1.00. //Console.WriteLine($"On time 0.4 y position is {yPositionTracker.GetApproximately(0.4)}"); //Throws exception because tracker hasn't record data yet because time in context is 2.00. //Console.WriteLine($"On time 2.7 y position is {yPositionTracker.GetApproximately(2.7)}"); //Don't forget to dispose tracker when you don't need it anymore. //It will increase performance because tracker doesn't record data anymore. yPositionTracker.Dispose(); context.Tick(1); //Time is context is 3.0, but tracker is already disposed and doesn't record data anymore. Console.WriteLine ( $"\nTracker records data during time span {yPositionTracker.ObservationBeginTime} - {yPositionTracker.LastObservationTime}" + $"\nAverage y position is {yPositionTracker.Sum(record => record.Value) / yPositionTracker.Count}" ); //However, if you want to record only max, min, average value etc, //better use ContextDependentValue, because it doesn't use a lot of memory //to record value in each tick. var maxYVelocity = new ContextDependentValue <string, double> ( startValue: context["freeFallEntity"].Y.Velocity, observableContext: context, newValueFunc: (c, oldValue) => c["freeFallEntity"].Velocity > oldValue ? new double?(c["freeFallEntity"].Velocity) : null //null value means that there is no reason to change value ); context.Tick(1); Console.WriteLine ( $"\nMax y velocity in time span {maxYVelocity.ObservationBeginTime} - " + $"{maxYVelocity.LastObservationTime} is {maxYVelocity.Value}" ); //So, lets create something more complex. //What about the spring pendulum with air resistance? var pendulumContext = new PhysicalContext <PendulumEntities>(dt, 2); var axis = new PointMass(0, 0, 0, 0); var mass = new PointMass(1, 0, 0, 0); pendulumContext.AddEntity(PendulumEntities.Axis, axis); pendulumContext.AddEntity ( PendulumEntities.Mass, mass, c => new Force(0, c[PendulumEntities.Mass].Mass * freeFallAcceleration, 0), //Gravity HookesLaw.GetLaw //Mechanix.Laws contains amount of static classes to help force evaluating. ( PendulumEntities.Mass, PendulumEntities.Axis, 1, //undeformed length of spring 10 //elasticity coefficient ) ); //Or set of elastic balls. var ballsContext = new PhysicalContext <int>(dt, 100); var random = new Random(); const double radius = 1; const double elasticity = 100; for (int i = 0; i < 100; ++i) { var ball = new PointMass ( new AxisStatus(random.NextDouble(), random.NextDouble()), new AxisStatus(random.NextDouble(), random.NextDouble()), new AxisStatus(random.NextDouble(), random.NextDouble()), random.NextDouble() ); ballsContext.AddEntity ( i, ball, c => { var force = Force.Zero; foreach (var pair in c) { if (pair.Key != i) { force += RadialCollisionLaw.Eval ( c[i], pair.Value, radius, elasticity ); } } return(force); } ); } }
private async void EvalButton_Click(object sender, RoutedEventArgs e) { try { SetPanelEnablity(false); _isCancelationRequested = false; var k = double.Parse(kValBox.Text); var alpha = double.Parse(alphaValueBox.Text); var dt = double.Parse(dtBox.Text); var timeSpan = double.Parse(timeSpanBox.Text); var planetRadius = double.Parse(planetRadiusBox.Text); var interval = ulong.Parse(renderingIntervalBox.Text); var progressBarSteps = uint.Parse(progressBarStepsBox.Text); var context = new PhysicalContext <Entities>(timePerTick: dt, capacity: 2); context.AddEntity ( Entities.Planet, new PointMass(0, 0, 0, 1) ); context.AddEntity ( Entities.Ship, new PointMass ( new AxisStatus(double.Parse(xPosBox.Text), double.Parse(xVelBox.Text)), new AxisStatus(double.Parse(yPosBox.Text), double.Parse(yVelBox.Text)), new AxisStatus(), 1 ), c => ModifiedGravityLaw <Entities>(c[Entities.Ship], c[Entities.Planet], alpha, k) ); var xTracker = new ContextTracker <Entities, double>(context, c => c[Entities.Ship].X.Position, interval); var yTracker = new ContextTracker <Entities, double>(context, c => c[Entities.Ship].Y.Position, interval); var progress = ContextProgressTracker <Entities> .FromTime ( context, timeSpan, Enumerable.Range(1, (int)progressBarSteps).Select(i => timeSpan *i / progressBarSteps).ToArray() ); progress.OnCheckPoint += (c, _) => Dispatcher.Invoke(() => progressBar.Value = progress.Progress); bool isSuccesful = await Task.Run ( () => context.Tick ( timeSpan, c => !_isCancelationRequested && ( c[Entities.Ship].X.Position *c[Entities.Ship].X.Position + c[Entities.Ship].Y.Position *c[Entities.Ship].Y.Position >= planetRadius *planetRadius ), false ) ); if (!isSuccesful && !_isCancelationRequested) { Task.Run(() => MessageBox.Show($"Ship has crashed at {context.Timer}")); } var title = $"Start position = ({xPosBox.Text}; {yPosBox.Text})\n" + $"Start velocity = ({xVelBox.Text}; {yVelBox.Text})\n" + $"dt = {dtBox.Text}, K = {kValBox.Text}, Alpha = {alphaValueBox.Text}"; var xSeries = new LineSeries() { CanTrackerInterpolatePoints = false, Title = title }; var ySeries = new LineSeries() { CanTrackerInterpolatePoints = false, Title = title }; var orbitSeries = new LineSeries() { CanTrackerInterpolatePoints = false, Title = title }; xSeries.Points.AddRange(from p in xTracker select new DataPoint(p.Key * dt, p.Value)); ySeries.Points.AddRange(from p in yTracker select new DataPoint(p.Key * dt, p.Value)); orbitSeries.Points.AddRange(xTracker.Zip(yTracker, (x, y) => new DataPoint(x.Value, y.Value))); plotX.Model.Series.Add(xSeries); plotY.Model.Series.Add(ySeries); orbitPlot.Model.Series.Add(orbitSeries); orbitPlot.Model.PlotType = PlotType.Cartesian; plotX.InvalidatePlot(); plotY.InvalidatePlot(); orbitPlot.InvalidatePlot(); progressBar.Value = 0; SetPanelEnablity(true); } catch (Exception ex) { MessageBox.Show(ex.Message); } }