public NDArray CalculateAcceleration(NDArray data) { if (Constraints.Count == 0) { return(ForceCalculator.CalculateAcceleration(data)); } var flattenedVelocities = data[Slice.All, ForceCalculator.VelocitySlice].flatten().reshape(-1, 1); var masses = data[Slice.All, ForceCalculator.MassSlice]; var repeated = np.repeat(masses, 2); var massDiag = diag(repeated); var constraintGradient = np.zeros(Constraints.Count, 2 * data.shape[0]); var h = np.zeros(Constraints.Count, 1); for (var i = 0; i < Constraints.Count; i++) { constraintGradient[i] = Constraints[i].gradient(data[Slice.All, ForceCalculator.PositionSlice]); h[i] = np.dot( np.dot(transpose(flattenedVelocities), Constraints[i].hessian(data[Slice.All, ForceCalculator.PositionSlice])), flattenedVelocities); } var forces = masses * ForceCalculator.CalculateAcceleration(data); var a = massDiag.hstack(-transpose(constraintGradient)) .vstack(constraintGradient.hstack(np.zeros(Constraints.Count, Constraints.Count))); var b = forces.flatten().reshape(-1, 1).vstack(-h); var solved = np.dot(inv(a), b); return(solved[new Slice(0, data.shape[0] * 2)].reshape(-1, 2)); }
public virtual void Tick(double time) { // Use runge kutta later if (Data.shape[0] <= 0) { return; } var fParamZeros = np.zeros_like(Data[Slice.All, new Slice(4)]); var k1 = time * Data[Slice.All, VelocitySlice].hstack(ForceCalculator.CalculateAcceleration(Data)); var k1d2 = Data + (k1 / 2).hstack(fParamZeros); var k2 = time * k1d2[Slice.All, VelocitySlice].hstack(ForceCalculator.CalculateAcceleration(k1d2)); var k2d2 = Data + (k2 / 2).hstack(fParamZeros); var k3 = time * k2d2[Slice.All, VelocitySlice].hstack(ForceCalculator.CalculateAcceleration(k2d2)); var k3d4 = Data + k3.hstack(fParamZeros); var k4 = time * k3d4[Slice.All, VelocitySlice].hstack(ForceCalculator.CalculateAcceleration(k3d4)); Data += 1.0 / 6.0 * (k1 + 2 * k2 + 2 * k3 + k4).hstack(fParamZeros); }