/// <summary> /// Execute the maneuver. Called automatically by Gravity Engine for maneuvers that /// have been added to the GE via AddManeuver(). /// /// Unusual to call this method directly. /// </summary> /// <param name="ge"></param> public void Execute(GravityEngine ge) { Vector3 vel = ge.GetVelocity(nbody); switch (mtype) { case Mtype.vector: vel += velChange; break; case Mtype.scalar: // scalar: adjust existing velocity by dV Vector3 change = Vector3.Normalize(vel) * dV; vel += change; break; case Mtype.circularize: // find velocity vector perpendicular to r for circular orbit // Since we could be mid-integration need to get exact position from GE double[] r_ship = new double[3]; double[] v_ship = new double[3]; ge.GetPositionVelocityScaled(nbody, ref r_ship, ref v_ship); double[] r_center = new double[3]; double[] v_center = new double[3]; ge.GetPositionVelocityScaled(centerBody, ref r_center, ref v_center); Vector3 pos_ship = new Vector3((float)r_ship[0], (float)r_ship[1], (float)r_ship[2]); Vector3 vel_ship = new Vector3((float)v_ship[0], (float)v_ship[1], (float)v_ship[2]); Vector3 pos_center = new Vector3((float)r_center[0], (float)r_center[1], (float)r_center[2]); Vector3 r = pos_ship - pos_center; // to get axis of orbit, can take v x r Vector3 axis = Vector3.Normalize(Vector3.Cross(vel_ship, pos_ship)); // vis visa for circular orbit float mu = nbody.mass * ge.massScale; float v_mag = Mathf.Sqrt(mu / Vector3.Magnitude(r)); // positive v is counter-clockwise Vector3 v_dir = Vector3.Normalize(Vector3.Cross(axis, r)); Vector3 v_circular = v_mag * v_dir; ge.SetVelocity(nbody, v_circular); break; } #pragma warning disable 162 // disable unreachable code warning if (GravityEngine.DEBUG) { Debug.Log("Applied manuever: " + LogString() + " engineRef.index=" + nbody.engineRef.index + " engineRef.bodyType=" + nbody.engineRef.bodyType + " timeError=" + (worldTime - ge.GetPhysicalTime())); Debug.Log("r= " + Vector3.Magnitude(nbody.transform.position)); } #pragma warning restore 162 // enable unreachable code warning ge.SetVelocity(nbody, vel); }
/// <summary> /// Take the Nbody objects in the nbodies list set them inactive and make them children of a new /// NBody object moving as the CM of the nbodies. This allows RigidBody mechanics during close /// encounters. /// </summary> private void Activate() { if (nbodies.Length < 2) { Debug.LogError("Need two or more nbodies"); return; } GravityEngine ge = GravityEngine.Instance(); // Step 1: calculate CM position and velocity Vector3d cmPos = new Vector3d(0, 0, 0); Vector3d cmVel = new Vector3d(0, 0, 0); float mass = 0f; rigidBodies = new Rigidbody[nbodies.Length]; // RigidBody is assumed to be attached to one of the children (to keep model scale independent) int i = 0; foreach (NBody nbody in nbodies) { rigidBodies[i] = nbody.GetComponentInChildren <Rigidbody>(); //rigidBodies[i] = nbody.GetComponent<Rigidbody>(); if (rigidBodies[i] == null) { Debug.LogError("Abort - No rigidbody detected on " + nbody.gameObject.name); return; } mass += rigidBodies[i].mass; cmPos += rigidBodies[i].mass * ge.GetPositionDoubleV3(nbody); cmVel += rigidBodies[i].mass * ge.GetVelocityDoubleV3(nbody); i++; } cmPos /= mass; cmVel /= mass; Debug.LogFormat("CM p={0} v={1} mass={2}", cmPos.ToVector3(), cmVel.ToVector3(), mass); // Step2: Inactivate the NBodies and make children of a new NBody object priorParents = new Transform[nbodies.Length]; cmObject = new GameObject("DockingGroupCM"); cmNbody = cmObject.AddComponent <NBody>(); // Set cm pos/vel // NBody InitPosition will use transform or initialPos base on units. Set both. cmNbody.initialPos = cmPos.ToVector3() * ge.physToWorldFactor; cmNbody.transform.position = cmNbody.initialPos; ge.AddBody(cmObject); ge.SetVelocity(cmNbody, cmVel.ToVector3()); Debug.LogFormat("set pos={0} actual={1}", cmPos.ToVector3(), ge.GetPhysicsPosition(cmNbody)); i = 0; foreach (NBody nbody in nbodies) { Vector3d pos = ge.GetPositionDoubleV3(nbody); Vector3d vel = ge.GetVelocityDoubleV3(nbody); priorParents[i] = nbody.gameObject.transform.parent; ge.InactivateBody(nbody.gameObject); nbody.gameObject.transform.parent = cmObject.transform; // position wrt to CM. Need to convert to Unity scene units from GE Internal pos = (pos - cmPos) * ge.physToWorldFactor; vel = GravityScaler.ScaleVelPhysToScene(vel - cmVel); nbody.transform.localPosition = pos.ToVector3(); rigidBodies[i].velocity = vel.ToVector3(); // rigidBodies[i].isKinematic = false; i++; Debug.LogFormat("body {0} p={1} v={2}", nbody.gameObject.name, pos.ToVector3(), vel.ToVector3()); } // activate any RCS elements foreach (ReactionControlSystem r in rcs) { if (r != null) { r.SetRigidBodyEnabled(true); } } }