Commit a743ae3f authored by DALAB\sjtud's avatar DALAB\sjtud
Browse files

initialize

parent 9814ef6b
#ifndef RIGIDOBJECT_H
#define RIGIDOBJECT_H
#include "BaseObject.h"
/*
* Base class representing a simple rigid object.
*/
class RigidObject : public BaseObject {
public:
RigidObject() {}
RigidObject(const std::string& mesh_path,
const ObjType t = ObjType::DYNAMIC);
virtual ~RigidObject() {}
void applyForceToCOM(const Eigen::Vector3d& f);
/*
* Apply force f at point p.
*/
void applyForce(const Eigen::Vector3d& f, const Eigen::Vector3d& p);
void applyTorque(const Eigen::Vector3d& t);
void printDebug(const std::string& message = "") const;
#pragma region GettersAndSetters
virtual void setType(ObjType t) override;
void setMass(double m);
void setInertia(const Eigen::Matrix3d& I);
void setLinearMomentum(const Eigen::Vector3d& p);
void setAngularMomentum(const Eigen::Vector3d& l);
void setLinearVelocity(const Eigen::Vector3d& v);
void setAngularVelocity(const Eigen::Vector3d& w);
void setForce(const Eigen::Vector3d& f);
void setTorque(const Eigen::Vector3d& t);
void resetForce();
void resetTorque();
double getMass() const;
double getMassInv() const;
Eigen::Matrix3d getInertia() const;
Eigen::Matrix3d getInertiaInv() const;
Eigen::Matrix3d getInertiaInvWorld() const;
Eigen::Matrix3d getInertiaWorld() const;
Eigen::Vector3d getLinearMomentum() const;
Eigen::Vector3d getAngularMomentum() const;
Eigen::Vector3d getLinearVelocity() const;
Eigen::Vector3d getVelocity(const Eigen::Vector3d& point) const;
Eigen::Vector3d getAngularVelocity() const;
Eigen::Vector3d getForce() const;
Eigen::Vector3d getTorque() const;
#pragma endregion GettersAndSetters
protected:
virtual void resetMembers() override;
private:
double m_mass; // Body mass
double m_massInv; // Inverted mass
Eigen::Matrix3d m_inertia; // Intertial Tensor (initially set to cube)
Eigen::Matrix3d m_inertiaInv; // Inverse
Eigen::Vector3d m_v; // Linear velocity
Eigen::Vector3d m_w; // Angular velocity
Eigen::Vector3d m_force; // Force on body
Eigen::Vector3d m_torque; // Torque on body
};
#endif
\ No newline at end of file
#ifndef SIMULATION_H
#define SIMULATION_H
#include <igl/opengl/glfw/Viewer.h>
#include "RigidObject.h"
/*
* Base class for different kinds of simulation. Provides methods for
* controlling the simulation and rendering it in a Gui.
*/
class Simulation {
public:
Simulation() {}
virtual ~Simulation() {}
/*
* Initialize the necessary class variables at the beginning of the
* simulation.
*/
virtual void init() {}
/*
* Reset class variables to reset the simulation.
*/
void reset() {
m_time = 0.0;
m_step = 0;
resetMembers();
}
/*
* Update the rendering data structures. This method will be called in
* alternation with advance(). This method blocks rendering in the
* viewer, so do *not* do extensive computation here (leave it to
* advance()).
*/
virtual void updateRenderGeometry() = 0;
/*
* Performs one simulation step of length m_dt. This method *must* be
* thread-safe with respect to renderRenderGeometry() (easiest is to not
* touch any rendering data structures at all). You have to update the time
* variables at the end of each step if they are necessary for your
* simulation.
* Return true means the simulation is finished.
*/
virtual bool advance() = 0;
/*
* Perform any actual rendering here. This method *must* be thread-safe with
* respect to advance(). This method runs in the same thread as the
* viewer and blocks user IO, so there really should not be any extensive
* computation here or the UI will lag/become unresponsive (the whole reason
* the simulation itself is in its own thread.)
*/
virtual void renderRenderGeometry(igl::opengl::glfw::Viewer &viewer) = 0;
void setTimestep(double t) { m_dt = t; }
double getTime() const { return m_time; }
unsigned long getStep() const { return m_step; }
std::vector<RigidObject> &getObjects() { return m_objects; }
protected:
/*
* Reset class variables specific to a certain simulation. Is called by
* Simulation::reset().
*/
virtual void resetMembers() = 0;
std::vector<RigidObject>
m_objects; // vector of all objects in the simulation
double m_dt = 0.0; // length of timestep
double m_time = 0.0; // current time
unsigned long m_step = 0; // number of performed steps in simulation
};
#endif
\ No newline at end of file
#ifndef SIMULATOR_H
#define SIMULATOR_H
#include "Simulation.h"
#include <igl/opengl/glfw/Viewer.h>
#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
#include <mutex>
#include <queue>
#include <thread>
using namespace std::chrono;
/*
* Class for running a simulation (see Simulation.h) on a separate thread.
* Performs stepping through simulation (including pausing/resuming/killing) and
* updating the rendering in the viewer.
*/
class Simulator {
public:
Simulator(Simulation *sim)
: p_simulator_thread(NULL),
p_simulation(sim),
m_please_pause(false),
m_please_die(false),
m_running(false),
m_started(false),
m_single_iteration(false),
m_recording(false) {}
virtual ~Simulator() {
killSimulatorThread();
delete p_simulation;
p_simulation = NULL;
}
/*
* Runs the simulation, if it has been paused (or never started).
*/
void run(bool single = false) {
m_status_mutex.lock();
if (!m_started) {
p_simulation->reset();
m_started = true;
if (single) {
std::cout << "Single step" << std::endl;
}
else {
std::cout << "Start simulation" << std::endl;
}
}
else if (m_please_pause) {
if (single) {
std::cout << "Single step" << std::endl;
}
else {
std::cout << "Resume simulation" << std::endl;
}
}
if (m_please_pause) {
m_single_iteration = single;
}
if (!single) {
m_please_pause = false;
}
m_status_mutex.unlock();
}
/*
* Resets the p_simulation (and leaves it in a paused state; call run() to
* start it).
*/
void reset() {
killSimulatorThread();
if (m_started) {
std::cout << "Reset simulation" << std::endl;
}
m_please_die = m_running = m_started = false;
m_please_pause = true;
clearRecords();
setRecording(m_recording);
p_simulation->reset();
p_simulation->updateRenderGeometry();
p_simulator_thread = new std::thread(&Simulator::runSimThread, this);
}
/*
* Pause a m_running p_simulation. The p_simulation will pause at the end of
* its current "step"; this method will not interrupt simulateOneStep
* mid-processing.
*/
void pause() {
m_status_mutex.lock();
m_please_pause = true;
m_status_mutex.unlock();
std::cout << "Pause simulation" << std::endl;
}
bool isPaused() {
bool ret = false;
m_status_mutex.lock();
if (m_running && m_please_pause) ret = true;
m_status_mutex.unlock();
return ret;
}
bool hasStarted() const { return m_started; }
void render(igl::opengl::glfw::Viewer &viewer) {
m_render_mutex.lock();
p_simulation->renderRenderGeometry(viewer);
m_render_mutex.unlock();
}
double getDuration() const {
return duration_cast<microseconds>(m_duration).count() * 0.001;
}
double getSimulationTime() const { return p_simulation->getTime(); }
unsigned long getSimulationStep() const { return p_simulation->getStep(); }
void setSimulationSpeed(int speed) {
m_maxTimePerStep = std::round(1000 / speed);
}
// set maximum number of timesteps after which the simulation will stop, -1
// for infinite simulation
void setMaxSteps(int n = -1) { m_maxSteps = n; }
void clearRecords() {
for (size_t i = 0; i < m_record.size(); i++) {
m_record[i] =
std::queue<std::pair<Eigen::MatrixXd, Eigen::MatrixXi>>();
}
}
void setRecording(bool r) {
if (r && m_record.size() == 0) {
m_record.resize(p_simulation->getObjects().size());
}
else {
clearRecords();
}
m_recording = r;
}
bool isRecording() const { return m_recording; }
void setNumRecords(int n) { m_numRecords = n; }
std::vector<std::queue<std::pair<Eigen::MatrixXd, Eigen::MatrixXi>>>
&getRecords() {
return m_record;
}
protected:
void storeRecord() {
auto os = p_simulation->getObjects();
Eigen::MatrixXd V;
Eigen::MatrixXi F;
for (size_t i = 0; i < os.size(); i++) {
os[i].getMesh(V, F);
m_record[i].push(std::make_pair(V, F));
while (m_record[i].size() > (size_t)m_numRecords) {
m_record[i].pop();
}
}
}
void runSimThread() {
m_status_mutex.lock();
m_running = true;
m_status_mutex.unlock();
bool done = false;
while (!done) {
m_status_mutex.lock();
bool pausenow = m_please_pause;
bool single = m_single_iteration;
m_status_mutex.unlock();
if (pausenow && !single) {
// don't use to much CPU time
std::this_thread::sleep_for(milliseconds(10));
}
else {
if (m_maxSteps >= 0 && m_maxSteps <= p_simulation->getStep()) {
pause();
continue;
}
// time execution of one loop (advance + rendering)
high_resolution_clock::time_point start =
high_resolution_clock::now();
done = p_simulation->advance();
if (m_recording) {
storeRecord();
}
m_render_mutex.lock();
p_simulation->updateRenderGeometry();
m_render_mutex.unlock();
high_resolution_clock::time_point end =
high_resolution_clock::now();
m_duration = end - start;
// sleep such that simulation runs at the set iterations per
// second
milliseconds sleepTime =
milliseconds(m_maxTimePerStep) -
duration_cast<milliseconds>(m_duration);
std::this_thread::sleep_for(sleepTime);
}
m_status_mutex.lock();
if (single) m_single_iteration = false;
if (m_please_die) done = true;
m_status_mutex.unlock();
}
m_status_mutex.lock();
m_running = false;
m_status_mutex.unlock();
}
void killSimulatorThread() {
if (p_simulator_thread) {
m_status_mutex.lock();
m_please_die = true;
m_status_mutex.unlock();
p_simulator_thread->join();
delete p_simulator_thread;
p_simulator_thread = NULL;
}
}
std::thread *p_simulator_thread;
Simulation *p_simulation;
duration<double> m_duration;
bool m_please_pause;
bool m_please_die;
bool m_running;
bool m_started;
bool m_single_iteration;
int m_maxTimePerStep;
int m_maxSteps = -1; // max number of steps to perform, -1 for infinite
std::mutex m_render_mutex;
std::mutex m_status_mutex;
bool m_recording;
int m_numRecords;
std::vector<std::queue<std::pair<Eigen::MatrixXd, Eigen::MatrixXi>>>
m_record; // one queue of (vertices, faces)-pairs for every object
};
#endif
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment