#include "MassSpringSystemSimulator.h" MassSpringSystemSimulator::MassSpringSystemSimulator() { m_iTestCase = 0; m_fMass = 10; m_fStiffness = 40; int m_iIntegrater = 0; auto first = addMassPoint(Vec3(0, 0, 0), Vec3(-1, 0, 0), true); auto second = addMassPoint(Vec3(0, 2, 0), Vec3(1, 0, 0), true); addSpring(first, second, 1.0); } const char* MassSpringSystemSimulator::getTestCasesStr() { //hier to change the choices return "Euler,LeapFrog,Midpoint"; } void MassSpringSystemSimulator::initUI(DrawingUtilitiesClass* DUC) { this->DUC = DUC; switch (m_iTestCase) { case 0:break; case 1: break; case 2: break; default:break; } } void MassSpringSystemSimulator::reset() { m_mouse.x = m_mouse.y = 0; m_trackmouse.x = m_trackmouse.y = 0; m_oldtrackmouse.x = m_oldtrackmouse.y = 0; } void MassSpringSystemSimulator::drawFrame(ID3D11DeviceContext* pd3dImmediateContext) { for (size_t i = 0; i < springs.size(); i++) { auto sp = springs.at(i); if (!sp.isValid()) { springs.erase(springs.begin() + i); continue; } auto mp1 = sp.mp1.lock(); auto mp2 = sp.mp2.lock(); DUC->setUpLighting(Vec3(), 0.4 * Vec3(1, 1, 1), 100, 0.6 * Vec3(0.97, 0.86, 1)); DUC->drawSphere(mp1->position, Vec3(0.01)); DUC->drawSphere(mp2->position, Vec3(0.01)); DUC->beginLine(); DUC->drawLine(mp1->position, Vec3(1,0,0), mp2->position, Vec3(0,1,0)); DUC->endLine(); } } void MassSpringSystemSimulator::notifyCaseChanged(int testCase) { m_iTestCase = testCase; switch (m_iTestCase) { case 0: cout << "Euler !\n"; //simulateTimestep(1); break; case 1: break; case 2: cout << "Midpoint \n"; //m_iNumSpheres = 100; //m_fSphereSize = 0.05f; break; default: //cout << "Demo4 !\n"; break; } } void MassSpringSystemSimulator::externalForcesCalculations(float timeElapsed) { Point2D mouseDiff; mouseDiff.x = m_trackmouse.x - m_oldtrackmouse.x; mouseDiff.y = m_trackmouse.y - m_oldtrackmouse.y; if (mouseDiff.x != 0 || mouseDiff.y != 0) { Mat4 worldViewInv = Mat4(DUC->g_camera.GetWorldMatrix() * DUC->g_camera.GetViewMatrix()); worldViewInv = worldViewInv.inverse(); Vec3 inputView = Vec3((float)mouseDiff.x, (float)-mouseDiff.y, 0); Vec3 inputWorld = worldViewInv.transformVectorNormal(inputView); // find a proper scale! float inputScale = 0.001f; inputWorld = inputWorld * inputScale; //m_vfMovableObjectPos = m_vfMovableObjectFinalPos + inputWorld; } else { //m_vfMovableObjectFinalPos = m_vfMovableObjectPos; } } void MassSpringSystemSimulator::simulateTimestep(float timeStep) { //update current setup for each frame switch (m_iTestCase) { case 0: //update the masspoint cout << "Euler \n"; Euler(0, 1, 0, timeStep); break; case 1: break; case 2:cout << "midpoint \n"; Midpoint(0, 1, timeStep); break; default: break; } //Euler(0, 1, 0, timeStep); } void MassSpringSystemSimulator::onClick(int x, int y) { m_trackmouse.x = x; m_trackmouse.y = y; } void MassSpringSystemSimulator::onMouse(int x, int y) { m_oldtrackmouse.x = x; m_oldtrackmouse.y = y; m_trackmouse.x = x; m_trackmouse.y = y; } void MassSpringSystemSimulator::setMass(float mass) { m_fMass = mass; } void MassSpringSystemSimulator::setStiffness(float stiffness) { m_fStiffness = stiffness; } void MassSpringSystemSimulator::setDampingFactor(float damping) { m_fDamping = damping; } int MassSpringSystemSimulator::addMassPoint(Vec3 position, Vec3 Velocity, bool isFixed) { MassPoint masspoint; masspoint.position = position; masspoint.velocity = Velocity; masspoint.isFixed = isFixed; masspoints.push_back(std::make_shared(masspoint)); return masspoints.size() - 1; } void MassSpringSystemSimulator::addSpring(int masspoint1, int masspoint2, float initialLength) { auto mp1 = masspoints.at(masspoint1); auto mp2 = masspoints.at(masspoint2); Spring spring; spring.mp1 = mp1; spring.mp2 = mp2; spring.initialLength = initialLength; springs.push_back(spring); } int MassSpringSystemSimulator::getNumberOfMassPoints() { return masspoints.size(); } int MassSpringSystemSimulator::getNumberOfSprings() { return springs.size(); } Vec3 MassSpringSystemSimulator::getPositionOfMassPoint(int index) { auto mp = masspoints.at(index); return mp->position; } Vec3 MassSpringSystemSimulator::getVelocityOfMassPoint(int index) { auto mp = masspoints.at(index); return mp->velocity; } void MassSpringSystemSimulator::applyExternalForce(Vec3 force) { //eine Vorstellung: for all Masspoints, update force } int MassSpringSystemSimulator::LengthCalculator(Vec3 position1, Vec3 position2) { Vec3 PosVector = position1 - position2; //wurzel aus Vektor int length = sqrt(pow(PosVector.x, 2) + pow(PosVector.y, 2) + pow(PosVector.z, 2)); return length; } Vec3 MassSpringSystemSimulator::calculatePositionTimestepEuler(Vec3 oldPosition, float timestep, Vec3 velocity) { return oldPosition + timestep * velocity; } Vec3 MassSpringSystemSimulator::calculateVelocityTimestepEuler(Vec3 oldVelocity, float timestep, Vec3 acceleration) { return oldVelocity + acceleration * timestep; } Vec3 MassSpringSystemSimulator::calculateAcceleration(Vec3 force, float mass) { return force / mass; } void MassSpringSystemSimulator::Midpoint(int index1, int index2, float timestep) { //here some implementation about Midpoint auto massPoint1 = masspoints.at(index1); auto massPoint2 = masspoints.at(index2); //old position auto mp = massPoint1->position; auto mp2 = massPoint2 ->position; //old Velocity auto mOld_v = massPoint1->velocity; auto m2Old_v = massPoint1->velocity; Vec3 PosVector = mp - mp2; //Abstand ausrechnen int d = LengthCalculator(mp, mp2); //normalize Vec3 PosNorm1 = PosVector / d; Vec3 PosNorm2 = -1 * PosNorm1; Vec3 Force = -m_fStiffness * (d - springs.at(0).initialLength) * PosNorm1; Vec3 Force2 = -1 * Force; Vec3 oldAcc = calculateAcceleration(Force,m_fMass); Vec3 oldAcc2 = calculateAcceleration(Force2, m_fMass); //Midpoint calculator //Pos of Midstep Vec3 PosOfMidstep = mp + 0.5 * timestep * mOld_v; Vec3 PosOfMidstep2 = mp2 + 0.5 * timestep * m2Old_v; //Vel at Midstep Vec3 VelAtMidstep = mOld_v + 0.5 * timestep * oldAcc; Vec3 VelAtMidstep2 = m2Old_v + 0.5 * timestep * oldAcc2; Vec3 NewPos = mp + timestep * VelAtMidstep; Vec3 NewPos2 = mp2 + timestep * VelAtMidstep2; Vec3 NewVel = mOld_v + timestep * oldAcc; Vec3 NewVel2 = m2Old_v + timestep * oldAcc2; cout << NewPos; cout << NewVel; massPoint1->position = NewPos; massPoint1->velocity = NewVel; massPoint2->position = NewPos2; massPoint2->velocity = NewVel2; } void MassSpringSystemSimulator::Euler(int index1, int index2, int indexSpring, float timestep) { //take old position and send to calculatePositionTimestepEuler auto mp = masspoints.at(index1); auto mp2 = masspoints.at(index2); Vec3 PosVector = mp->position - mp2->position; auto lengthVector = sqrt(PosVector.x * PosVector.x + PosVector.y * PosVector.y + PosVector.z * PosVector.z); auto normalized = PosVector / lengthVector; // Actual Calculation // Force of spring is -k * (l - L) * normalizedVector [for P2 we can take -F1) auto force = -m_fStiffness * (lengthVector - springs.at(0).initialLength) * normalized; auto foreP2 = -1 * force; auto veloc = calculateVelocityTimestepEuler(mp->velocity, timestep, calculateAcceleration(force, 10.)); auto pos = calculatePositionTimestepEuler(mp->position, timestep, veloc); auto veloc2 = calculateVelocityTimestepEuler(mp2->velocity, timestep, calculateAcceleration(foreP2, 10.)); auto pos2 = calculatePositionTimestepEuler(mp2->position, timestep, veloc2); // Update Positions and Velocity mp->position = pos; mp->velocity = veloc; mp2->position = pos2; mp2->velocity = veloc2; }