/// <summary> /// Determines the new P and V for each body in the universe /// </summary> /// <param name="universe">The Universe to update</param> /// <param name="dt">the timestep of the update</param> internal void CalcBodyTrajectory(Universe universe, double dt) { if (parallel) { Parallel.ForEach(universe.GetBodies(), body => { UpdateEuler(universe, body, dt); }); } else { if (universe.useRelative) { foreach (Body body in universe.GetBodies()) { UpdateEulerV(universe, body, dt); } CorrectForMovingReferenceFrames(universe, dt); foreach (Body body in universe.GetBodies()) { UpdateEulerP(body, dt); } } else { foreach (Body body in universe.GetBodies()) { UpdateEuler(universe, body, dt); } } } }
public void BaseScaleForUniverse(Form form, Universe universe, double correction = 1.0) { if (form == null) { return; } double maxD = 0; if (universe.useRelative) { foreach (RelativeBody body in universe.GetBodies()) { double bodyD = body.GetAbsP().Mag(); maxD = bodyD > maxD ? bodyD : maxD; } } else { foreach (RelativeBody body in universe.GetBodies()) { double bodyD = body.p.Mag(); maxD = bodyD > maxD ? bodyD : maxD; } } double smallerSide = Math.Min(form.ClientRectangle.Width / 2.0, form.ClientRectangle.Height / 2.0); scale = smallerSide / maxD / correction; }
public void focusNext(Universe universe) { if (focus == null) { focus = universe.GetBodies().First(); } int ind = universe.GetBodies().IndexOf(focus); ind++; focus = ind >= universe.GetBodies().Count ? null : universe.GetBodies()[ind]; Debug.WriteLine($"New Focus: {(focus == null ? "Barycenter" : focus.ToString())}"); }
internal void CheckCollision(Universe universe) { //TODO: rework, verify, and find a way to intelligently use spatial partitioning List <Body> allBodies = universe.GetBodies(); for (int i = 0; i < allBodies.Count(); i++) { Body a = allBodies[i]; if (a.deletionFlag) { continue; } for (int j = i + 1; j < allBodies.Count(); j++) { Body b = allBodies[j]; if (b.deletionFlag) { continue; } Vector pRel = a.pNext - b.pNext; double r = a.r + b.r; if (pRel.Mag() < r) { b.deletionFlag = true; a.vNext = (a.m * a.vNext + b.m * b.vNext) / (a.m + b.m); a.rho = (a.m + b.m) / ((a.m / a.rho) + (b.m / b.rho)); a.m += b.m; a.EstR(); } } } }
/// <summary> /// For each body in universe, set the current P and V values to be the calculated 'next' values /// </summary> /// <param name="universe">Universe to update</param> internal void UpdateBodies(Universe universe) { foreach (Body body in universe.GetBodies()) { body.UpdateBodyPV(); } }
/// <summary> /// When using reference frame modes, the fact that reference frames can accelerate needs to be corrected for /// </summary> /// <param name="universe">universe to correct</param> /// <param name="dt">timestep used</param> internal void CorrectForMovingReferenceFrames(Universe universe, double dt) { // need to adjust the position/velocity vectors to account for the fact that reference frames are moving and accelerating. RelativeBody center = (RelativeBody)universe.GetBodies().First(); //TODO: rewrite to handle binary-style cases center.correctForMovingReferenceFrames(dt); }
/// <summary> /// Adjusts the position of all bodies in universe such that the barycenter is kept as close to the origin as possible /// </summary> /// <param name="universe"></param> internal void FixBarycenter(Universe universe) { //TODO: consider setting 'barycenter velocity' to zero here as well foreach (Body body in universe.GetBodies()) { if (body.pinned) { return; //if there are any pinned bodies, then we shouldn't need to do this (?) } } if (universe.useRelative) { Vector weightedP = new Vector(); Body center = universe.GetBodies().First(); //TODO: Fix for cases where multiple bodies have "null" as parent e.g binary stars Vector barycenter = (center as RelativeBody).GetFamilyBarycenter(); //Debug.WriteLine($"bary: {barycenter.ToString()}"); center.p = -barycenter; } else { Vector weightedP = new Vector(); double mass = 0; foreach (Body body in universe.GetBodies()) { weightedP += body.m * body.p; mass += body.m; } weightedP /= mass; //Debug.WriteLine($"bary: {weightedP.ToString()}"); foreach (Body body in universe.GetBodies()) { body.p -= weightedP; } } }
/// <summary> /// Calculate the acceleration vector of a given body due to the other bodies in a given universe /// </summary> /// <param name="universe">the universe containing the bodies imparting gravitational force</param> /// <param name="body">the body to calculate acceleration for</param> /// <returns>the calculated acceleration vector</returns> internal Vector Acceleration(Universe universe, Body body) { Vector a = new Vector(0, 0, 0); foreach (Body other in universe.GetBodies()) { if (other == body) { continue; } Vector dist = Distance(body, other, universe.useRelative); a += universe.G * other.m * dist.Normal() / (Math.Pow(dist.Mag(), 2)); } return(a); }
internal void RenderUniverseFromFocus(Graphics dc, Pen pen, Universe universe, RelativeBody focus) { RelativeBody center = (RelativeBody)universe.GetBodies().First(); // TODO: better handle binary-type cases Pen childPen = new Pen(Color.Blue, 1); if (focus == null && center != null) { RecursiveRenderChildren(dc, childPen, center, center.p); } else { RecursiveRenderChildren(dc, childPen, focus, Vector.zeroVect); RecursiveRenderParents(dc, pen, focus, Vector.zeroVect); } }
internal void renderBodies(Graphics dc, Universe universe) { if (universe == null) { return; } Pen BodyPen = new Pen(Color.Black, 1); if (universe.useRelative) { RenderUniverseFromFocus(dc, BodyPen, universe, focus as RelativeBody); } else { foreach (Body body in universe.GetBodies()) { renderBody(dc, BodyPen, body); } } }
/// <summary> /// Determine if any Bodies have moved far enough away from their parent, or close enough to a 'better' parent to justify updating their reference frame /// </summary> /// <param name="universe">The universe to consider for required reference frame updates</param> internal void UpdateReferenceFramesIfNecessary(Universe universe) { if (!universe.useRelative) { return; //non-relative mode doesn't use reference frames } foreach (RelativeBody body in universe.GetBodies()) { // If body leaves Hill sphere of parent, set reference frame to grandparent. // TODO: Look into precomputing hill sphere radius if (body.parent != null && body.parent.parent != null) { double hillRad = body.parent.p.Mag() * Math.Pow(body.parent.m / 3.0 / body.parent.parent.m, 1.0 / 3.0); if (body.p.Mag() > hillRad) { body.p += body.parent.p; body.v += body.parent.v; (body.parent.parent as RelativeBody).AdoptChild(body); } } // TODO: check to see if body has entered hill sphere of any more-massive siblings. } }
public static Universe GenPseudoRandomUniverse( bool relative = true, int seed = 0, int count = 20, int nestFactor = 2, double mScale = 100.0, double mRatio = 1000.0, double dScale = 500.0) { Random random = seed == 0 ? new Random() : new Random(seed); Universe uni = new Universe(relative); double avgSplitFactor = Math.Log(count, nestFactor); int total = 1; if (relative) { RelativeBody center = new RelativeBody(mScale, "0_*"); uni.AddBody(center); int continues = 0; while (total < count) { RelativeBody host = (RelativeBody)uni.GetBodies()[random.Next(0, uni.GetBodies().Count())]; if (host.parentDepth() > nestFactor - 1) { continues++; if (continues < 4) { continue; } host = center; } continues = 0; double mass = (host.m / mRatio) * Math.Pow(2, -host.children.Count()); //double mag = random.NextDouble() * dScale * host.m / mScale; double mag; if (host == center) { mag = dScale; } else { mag = host.p.Mag() * Math.Pow(host.m / (3 * host.parent.m), 0.333) / 4.0; } mag *= random.NextDouble(); double theta = random.NextDouble() * Math.PI * 2; Vector distance = new Vector(mag * Math.Cos(theta), mag * Math.Sin(theta), 0); string name; if (host == center) { name = $"{center.children.Count() + 1}_*"; } else if (host.parentDepth() == 1) { name = $"{host.name.Substring(0, host.name.Length - 1)}{host.children.Count() + 1}"; } else { name = $"{host.name}_{host.children.Count() + 1}"; } RelativeBody addition = new RelativeBody(distance, host, mass, lbl: $"{name}"); uni.AddBody(addition); total++; } } uni.HeirarchicalSort(); return(uni); }