#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); m_fStiffness = 40; } const char* MassSpringSystemSimulator::getTestCasesStr() { return "Demo1,Demo2,Demo3,Demo4"; } 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 << "Demo1 !\n"; //simulateTimestep(1); break; case 1: cout << "Demo2 \n"; //m_iNumSpheres = 100; //m_fSphereSize = 0.05f; break; case 2: cout << "Demo3 !\n"; break; case 3: cout << "Demo 4 !\n"; 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"; cout << "Midpoint\n"; break; case 1:cout << "demo 2 \n"; break; case 2:cout << "demo 3\n"; break; case 3: cout << "demo 4\n"; 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) { } Vec3 MassSpringSystemSimulator::calcualtePositionTimestepEuler(Vec3 oldPosition, float timestep, Vec3 velocity) { return oldPosition + timestep * velocity; } Vec3 MassSpringSystemSimulator::calcualteVelocityTimestepEuler(Vec3 oldVelocity, float timestep, Vec3 acceleration) { return oldVelocity + acceleration * timestep; } Vec3 MassSpringSystemSimulator::calculateAcceleration(Vec3 force, float mass) { return force / mass; } 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 = calcualteVelocityTimestepEuler(mp->velocity, timestep, calculateAcceleration(force, 10.)); auto pos = calcualtePositionTimestepEuler(mp->position, timestep, veloc); auto veloc2 = calcualteVelocityTimestepEuler(mp2->velocity, timestep, calculateAcceleration(foreP2, 10.)); auto pos2 = calcualtePositionTimestepEuler(mp2->position, timestep, veloc2); // Update Positions and Velocity mp->position = pos; mp->velocity = veloc; mp2->position = pos2; mp2->velocity = veloc2; }