You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.8 KiB

3 months ago
// David Eberly, Geometric Tools, Redmond WA 98052
// Copyright (c) 1998-2021
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
// Version: 4.0.2019.08.13
#pragma once
#include <Mathematics/ParticleSystem.h>
namespace gte
{
template <int N, typename Real>
class MassSpringCurve : public ParticleSystem<N, Real>
{
public:
// Construction and destruction. This class represents a set of N-1
// springs connecting N masses that lie on a curve.
virtual ~MassSpringCurve() = default;
MassSpringCurve(int numParticles, Real step)
:
ParticleSystem<N, Real>(numParticles, step),
mConstant(numParticles - 1),
mLength(numParticles - 1)
{
std::fill(mConstant.begin(), mConstant.end(), (Real)0);
std::fill(mLength.begin(), mLength.end(), (Real)0);
}
// Member access. The parameters are spring constant and spring
// resting length.
inline int GetNumSprings() const
{
return this->mNumParticles - 1;
}
inline void SetConstant(int i, Real constant)
{
mConstant[i] = constant;
}
inline void SetLength(int i, Real length)
{
mLength[i] = length;
}
inline Real const& GetConstant(int i) const
{
return mConstant[i];
}
inline Real const& GetLength(int i) const
{
return mLength[i];
}
// The default external force is zero. Derive a class from this one
// to provide nonzero external forces such as gravity, wind, friction,
// and so on. This function is called by Acceleration(...) to compute
// the impulse F/m generated by the external force F.
virtual Vector<N, Real> ExternalAcceleration(int, Real,
std::vector<Vector<N, Real>> const&,
std::vector<Vector<N, Real>> const&)
{
return Vector<N, Real>::Zero();
}
protected:
// Callback for acceleration (ODE solver uses x" = F/m) applied to
// particle i. The positions and velocities are not necessarily
// mPosition and mVelocity, because the ODE solver evaluates the
// impulse function at intermediate positions.
virtual Vector<N, Real> Acceleration(int i, Real time,
std::vector<Vector<N, Real>> const& position,
std::vector<Vector<N, Real>> const& velocity)
{
// Compute spring forces on position X[i]. The positions are not
// necessarily mPosition, because the RK4 solver in ParticleSystem
// evaluates the acceleration function at intermediate positions.
// The endpoints of the curve of masses must be handled
// separately, because each has only one spring attached to it.
Vector<N, Real> acceleration = ExternalAcceleration(i, time, position, velocity);
Vector<N, Real> diff, force;
Real ratio;
if (i > 0)
{
int iM1 = i - 1;
diff = position[iM1] - position[i];
ratio = mLength[iM1] / Length(diff);
force = mConstant[iM1] * ((Real)1 - ratio) * diff;
acceleration += this->mInvMass[i] * force;
}
int iP1 = i + 1;
if (iP1 < this->mNumParticles)
{
diff = position[iP1] - position[i];
ratio = mLength[i] / Length(diff);
force = mConstant[i] * ((Real)1 - ratio) * diff;
acceleration += this->mInvMass[i] * force;
}
return acceleration;
}
std::vector<Real> mConstant, mLength;
};
}