// helper static SpatialVectorDouble calcImpulse(SpatialVectorDouble relativeVelocity, double mass) { // e = 1/2 * m * v² double velocityMagnitude = relativeVelocity.length; if (velocityMagnitude < double.Epsilon) { return(new SpatialVectorDouble(new double[] { 0, 0, 0 })); } else { return(relativeVelocity.normalized().scale(0.5 * mass * velocityMagnitude * velocityMagnitude)); } }
// useful for acceleration with radiation or a shockwave public static void accelerateByRadialPressure(SpatialVectorDouble energySourcePosition, double energyInJoules, IList <FracturedParticle> particles) { foreach (FracturedParticle iParticle in particles) { SpatialVectorDouble diff = iParticle.relativePosition - energySourcePosition; double distance = diff.length; if (distance > 0.0) { double surfaceAreaOfRadiationSphereAtDistance = Area.ofSphere(distance); double surfaceAreaOfProjectedSphere = ProjectedArea.ofSphere(iParticle.radius); double absorbedEnergyRatio = System.Math.Min(surfaceAreaOfProjectedSphere / surfaceAreaOfRadiationSphereAtDistance, 1.0); double absolvedEnergyInJoules = absorbedEnergyRatio * energyInJoules; iParticle.accelerateByEnergyInJoules(diff.normalized(), absolvedEnergyInJoules); } } }
// generalized way to rotate in a specific direction public void controlSolve(PhysicsComponent @object, float roll, float pitch, float yaw) { IList <ThrusterResponsibility.ThrusterBinding> thrusterBindings; if (!thrusterResponsibility.physicsObjectIdToThrusters.TryGetValue(@object.id, out thrusterBindings)) { return; } SpatialVectorDouble rotationTargetVector = new SpatialVectorDouble(new double[] { roll, yaw, pitch }); // vulkan coordinate system rotation double maximalAngularAccelerationMagnitude = 0.0; foreach (var iThrusterBinding in thrusterBindings) { maximalAngularAccelerationMagnitude = System.Math.Max(maximalAngularAccelerationMagnitude, iThrusterBinding.additionalInformation.cachedAngularAccelerationOnObject.length); } foreach (var iThrusterBinding in thrusterBindings) { SpatialVectorDouble normalizedAngularAccelerationOnObject; if (iThrusterBinding.additionalInformation.cachedAngularAccelerationOnObject.length < double.Epsilon) { normalizedAngularAccelerationOnObject = new SpatialVectorDouble(new double[] { 0, 0, 0 }); } else { SpatialVectorDouble cachedAngularAccelerationOnObject = iThrusterBinding.additionalInformation.cachedAngularAccelerationOnObject; double normalizedMangitude = cachedAngularAccelerationOnObject.length / maximalAngularAccelerationMagnitude; normalizedAngularAccelerationOnObject = cachedAngularAccelerationOnObject.normalized().scale(normalizedMangitude); } // calculate the relative thrust by the dot product because we want to rotate the best way in the wished rotation acceleration (given by roll, pitch, yaw) double relativeThrust = SpatialVectorDouble.dot(normalizedAngularAccelerationOnObject, rotationTargetVector); relativeThrust = System.Math.Max(relativeThrust, 0); // thruster can only thrust positivly iThrusterBinding.relative += (float)relativeThrust; // now we add to not cancel away the effects of the other thrusters } }
// calculates the gravitational forces and coresponding accelerations public void calcForcesAndAccelerationsForPhysicsComponents(IEnumerable <PhysicsComponent> physicsComponents) { foreach (PhysicsComponent iPhysicsComponent in physicsComponents) { SpatialVectorDouble sumOfForce = new SpatialVectorDouble(new double[] { 0, 0, 0 }); foreach (CelestialObjectWithPosition iCelestialObject in celestialObjects) { SpatialVectorDouble extrapolatedPosition = iPhysicsComponent.rungeKutta4State.x + iPhysicsComponent.rungeKutta4State.v.scale(PhysicsEngine.dt); SpatialVectorDouble difference = iCelestialObject.position - extrapolatedPosition; SpatialVectorDouble direction = difference.normalized(); double distanceSquared = difference.lengthSquared; double forceMagnitude = Orbit.calculateForceBetweenObjectsByDistance(iPhysicsComponent.mass, iCelestialObject.celestialObject.mass, distanceSquared); sumOfForce += direction.scale(forceMagnitude); } SpatialVectorDouble acceleration = sumOfForce.scale(iPhysicsComponent.invMass); iPhysicsComponent.linearAcceleration += acceleration; } }
static void applyForceToLinearAndAngularVelocity(PhysicsComponent physicsComponent, SpatialVectorDouble localForce, SpatialVectorDouble objectLocalPositionOfForce) { { // linear part // to calculate the linear component we use the dot product double scaleOfLinearForce = 0.0; if (localForce.length > double.Epsilon) { double dotOfForceAndLocalPosition = SpatialVectorDouble.dot(localForce.normalized(), objectLocalPositionOfForce.normalized()); scaleOfLinearForce = System.Math.Abs(dotOfForceAndLocalPosition); } // the linear force (and resulting acceleration) is the force scaled by the dot product Matrix rotationMatrix = physicsComponent.calcLocalToGlobalRotationMatrix(); Matrix globalForceAsMatrix = rotationMatrix * SpatialVectorUtilities.toVector4(localForce).asMatrix; SpatialVectorDouble globalForce = SpatialVectorUtilities.toVector3(new SpatialVectorDouble(globalForceAsMatrix)); physicsComponent.linearAcceleration += globalForce.scale(scaleOfLinearForce * physicsComponent.invMass); } { // angular part physicsComponent.eulerAngularAcceleration += physicsComponent.calcAngularAccelerationOfRigidBodyForAppliedForce(objectLocalPositionOfForce, localForce); } }