Solveurs, problèmes de perf
This commit is contained in:
parent
65b6524520
commit
847964fd1e
|
@ -137,7 +137,7 @@ namespace gti320 {
|
||||||
* Constructeur de copie
|
* Constructeur de copie
|
||||||
*/
|
*/
|
||||||
DenseStorage(const DenseStorage &other)
|
DenseStorage(const DenseStorage &other)
|
||||||
: m_data(new _Scalar[m_size]), m_size(other.m_size) {
|
: m_data(new _Scalar[other.m_size]), m_size(other.m_size) {
|
||||||
memcpy(m_data, other.m_data, m_size * sizeof(_Scalar));
|
memcpy(m_data, other.m_data, m_size * sizeof(_Scalar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace gti320 {
|
||||||
operator*(const Matrix<_Scalar, RowsA, ColsA, StorageA> &A, const Matrix<_Scalar, RowsB, ColsB, StorageB> &B) {
|
operator*(const Matrix<_Scalar, RowsA, ColsA, StorageA> &A, const Matrix<_Scalar, RowsB, ColsB, StorageB> &B) {
|
||||||
assert(A.cols() == B.rows());
|
assert(A.cols() == B.rows());
|
||||||
|
|
||||||
auto result = Matrix<_Scalar, Dynamic, Dynamic>(A.rows(), B.cols());
|
auto result = Matrix<_Scalar, RowsA, ColsB>(A.rows(), B.cols());
|
||||||
|
|
||||||
for (int col = 0; col < B.cols(); col++) {
|
for (int col = 0; col < B.cols(); col++) {
|
||||||
for (int row = 0; row < A.rows(); row++) {
|
for (int row = 0; row < A.rows(); row++) {
|
||||||
|
|
|
@ -27,16 +27,14 @@
|
||||||
|
|
||||||
using namespace gti320;
|
using namespace gti320;
|
||||||
|
|
||||||
namespace
|
namespace {
|
||||||
{
|
|
||||||
static const float deltaT = 0.01667f;
|
static const float deltaT = 0.01667f;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée un système masse-ressort qui simule un tissu suspendu
|
* Crée un système masse-ressort qui simule un tissu suspendu
|
||||||
*/
|
*/
|
||||||
static inline void createHangingCloth(ParticleSystem& particleSystem, float k)
|
static inline void createHangingCloth(ParticleSystem &particleSystem, float k) {
|
||||||
{
|
|
||||||
particleSystem.clear();
|
particleSystem.clear();
|
||||||
|
|
||||||
const int N = 16;
|
const int N = 16;
|
||||||
|
@ -46,10 +44,8 @@ namespace
|
||||||
const int dy = 32;
|
const int dy = 32;
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int i = 0; i < N; ++i)
|
for (int i = 0; i < N; ++i) {
|
||||||
{
|
for (int j = 0; j < N; ++j) {
|
||||||
for (int j = 0; j < N; ++j)
|
|
||||||
{
|
|
||||||
const int x = x_start + j * dx;
|
const int x = x_start + j * dx;
|
||||||
const int y = y_start + i * dy;
|
const int y = y_start + i * dy;
|
||||||
|
|
||||||
|
@ -58,20 +54,17 @@ namespace
|
||||||
if (j == (N - 1) && i == (N - 1)) particle.fixed = true;
|
if (j == (N - 1) && i == (N - 1)) particle.fixed = true;
|
||||||
particleSystem.addParticle(particle);
|
particleSystem.addParticle(particle);
|
||||||
|
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
{
|
Spring s(index - N, index, k, (float) dy);
|
||||||
Spring s(index - N, index, k, (float)dy);
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
}
|
}
|
||||||
if (j > 0)
|
if (j > 0) {
|
||||||
{
|
Spring s(index - 1, index, k, (float) dx);
|
||||||
Spring s(index - 1, index, k, (float)dx);
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i > 0 && j > 0)
|
if (i > 0 && j > 0) {
|
||||||
{
|
Spring s(index - N - 1, index, k, std::sqrt((float) dx * dx + (float) dy * dy));
|
||||||
Spring s(index - N - 1, index, k, std::sqrt((float)dx * dx + (float)dy * dy));
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
|
@ -84,8 +77,7 @@ namespace
|
||||||
/**
|
/**
|
||||||
* Crée un système masse-ressort qui simule un grand tissu suspendu
|
* Crée un système masse-ressort qui simule un grand tissu suspendu
|
||||||
*/
|
*/
|
||||||
static inline void createLargeHangingCloth(ParticleSystem& particleSystem, float k)
|
static inline void createLargeHangingCloth(ParticleSystem &particleSystem, float k) {
|
||||||
{
|
|
||||||
particleSystem.clear();
|
particleSystem.clear();
|
||||||
|
|
||||||
const int N = 32;
|
const int N = 32;
|
||||||
|
@ -95,10 +87,8 @@ namespace
|
||||||
const int dy = 16;
|
const int dy = 16;
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int i = 0; i < N; ++i)
|
for (int i = 0; i < N; ++i) {
|
||||||
{
|
for (int j = 0; j < N; ++j) {
|
||||||
for (int j = 0; j < N; ++j)
|
|
||||||
{
|
|
||||||
const int x = x_start + j * dx;
|
const int x = x_start + j * dx;
|
||||||
const int y = y_start + i * dy;
|
const int y = y_start + i * dy;
|
||||||
|
|
||||||
|
@ -106,20 +96,17 @@ namespace
|
||||||
if (j == 0 && i == (N - 1)) particle.fixed = true;
|
if (j == 0 && i == (N - 1)) particle.fixed = true;
|
||||||
if (j == (N - 1) && i == (N - 1)) particle.fixed = true;
|
if (j == (N - 1) && i == (N - 1)) particle.fixed = true;
|
||||||
particleSystem.addParticle(particle);
|
particleSystem.addParticle(particle);
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
{
|
Spring s(index - N, index, k, (float) dy);
|
||||||
Spring s(index - N, index, k, (float)dy);
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
}
|
}
|
||||||
if (j > 0)
|
if (j > 0) {
|
||||||
{
|
Spring s(index - 1, index, k, (float) dx);
|
||||||
Spring s(index - 1, index, k, (float)dx);
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i > 0 && j > 0)
|
if (i > 0 && j > 0) {
|
||||||
{
|
Spring s(index - N - 1, index, k, std::sqrt((float) dx * dx + (float) dy * dy));
|
||||||
Spring s(index - N - 1, index, k, std::sqrt((float)dx * dx + (float)dy * dy));
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
|
@ -132,8 +119,7 @@ namespace
|
||||||
* Crée un système masse-ressort qui simule une corde suspendu par ses
|
* Crée un système masse-ressort qui simule une corde suspendu par ses
|
||||||
* extrémités.
|
* extrémités.
|
||||||
*/
|
*/
|
||||||
static inline void createHangingRope(ParticleSystem& particleSystem, float k)
|
static inline void createHangingRope(ParticleSystem &particleSystem, float k) {
|
||||||
{
|
|
||||||
particleSystem.clear();
|
particleSystem.clear();
|
||||||
|
|
||||||
const int N = 20;
|
const int N = 20;
|
||||||
|
@ -141,17 +127,15 @@ namespace
|
||||||
const int dx = 32;
|
const int dx = 32;
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int j = 0; j < N; ++j)
|
for (int j = 0; j < N; ++j) {
|
||||||
{
|
|
||||||
const int x = x_start + j * dx;
|
const int x = x_start + j * dx;
|
||||||
const int y = 480;
|
const int y = 480;
|
||||||
|
|
||||||
Particle particle(Vector2f(x, y), Vector2f(0, 0), Vector2f(0, 0), 1.0);
|
Particle particle(Vector2f(x, y), Vector2f(0, 0), Vector2f(0, 0), 1.0);
|
||||||
particle.fixed = (index == 0) || (index == N - 1);
|
particle.fixed = (index == 0) || (index == N - 1);
|
||||||
particleSystem.addParticle(particle);
|
particleSystem.addParticle(particle);
|
||||||
if (j > 0)
|
if (j > 0) {
|
||||||
{
|
Spring s(index - 1, index, k, (float) dx);
|
||||||
Spring s(index - 1, index, k, (float)dx);
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
|
@ -162,8 +146,7 @@ namespace
|
||||||
/**
|
/**
|
||||||
* Crée un système masse-ressort qui simule une poutre flexible
|
* Crée un système masse-ressort qui simule une poutre flexible
|
||||||
*/
|
*/
|
||||||
static inline void createBeam(ParticleSystem& particleSystem, float k)
|
static inline void createBeam(ParticleSystem &particleSystem, float k) {
|
||||||
{
|
|
||||||
particleSystem.clear();
|
particleSystem.clear();
|
||||||
|
|
||||||
const int N = 20;
|
const int N = 20;
|
||||||
|
@ -173,8 +156,7 @@ namespace
|
||||||
const int dy = 32;
|
const int dy = 32;
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int j = 0; j < N; ++j)
|
for (int j = 0; j < N; ++j) {
|
||||||
{
|
|
||||||
const int x = x_start + j * dx;
|
const int x = x_start + j * dx;
|
||||||
|
|
||||||
// Bottom particle
|
// Bottom particle
|
||||||
|
@ -182,11 +164,10 @@ namespace
|
||||||
Particle particle(Vector2f(x, y_start), Vector2f(0, 0), Vector2f(0, 0), 1.0);
|
Particle particle(Vector2f(x, y_start), Vector2f(0, 0), Vector2f(0, 0), 1.0);
|
||||||
particle.fixed = (j == 0);
|
particle.fixed = (j == 0);
|
||||||
particleSystem.addParticle(particle);
|
particleSystem.addParticle(particle);
|
||||||
if (j > 0)
|
if (j > 0) {
|
||||||
{
|
Spring s(index - 1, index, k, (float) sqrt((float) dx * dx + (float) dy * dy));
|
||||||
Spring s(index - 1, index, k, (float)sqrt((float)dx * dx + (float)dy * dy));
|
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
Spring s2(index - 2, index, k, (float)dx);
|
Spring s2(index - 2, index, k, (float) dx);
|
||||||
particleSystem.addSpring(s2);
|
particleSystem.addSpring(s2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -199,13 +180,12 @@ namespace
|
||||||
Particle particle(Vector2f(x, y_start + dy), Vector2f(0, 0), Vector2f(0, 0), 1.0);
|
Particle particle(Vector2f(x, y_start + dy), Vector2f(0, 0), Vector2f(0, 0), 1.0);
|
||||||
particle.fixed = (j == 0);
|
particle.fixed = (j == 0);
|
||||||
particleSystem.addParticle(particle);
|
particleSystem.addParticle(particle);
|
||||||
Spring s(index - 1, index, k, (float)dy);
|
Spring s(index - 1, index, k, (float) dy);
|
||||||
particleSystem.addSpring(s);
|
particleSystem.addSpring(s);
|
||||||
if (j > 0)
|
if (j > 0) {
|
||||||
{
|
Spring s2(index - 2, index, k, (float) dx);
|
||||||
Spring s2(index - 2, index, k, (float)dx);
|
|
||||||
particleSystem.addSpring(s2);
|
particleSystem.addSpring(s2);
|
||||||
Spring s3(index - 3, index, k, (float)sqrt((float)dx * dx + (float)dy * dy));
|
Spring s3(index - 3, index, k, (float) sqrt((float) dx * dx + (float) dy * dy));
|
||||||
particleSystem.addSpring(s3);
|
particleSystem.addSpring(s3);
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
|
@ -218,8 +198,7 @@ namespace
|
||||||
/**
|
/**
|
||||||
* TODO Créez votre propre exemple
|
* TODO Créez votre propre exemple
|
||||||
*/
|
*/
|
||||||
static inline void createVotreExemple(ParticleSystem& particleSystem, float k)
|
static inline void createVotreExemple(ParticleSystem &particleSystem, float k) {
|
||||||
{
|
|
||||||
particleSystem.clear();
|
particleSystem.clear();
|
||||||
|
|
||||||
// TODO Amusez-vous. Rendu ici, vous le méritez.
|
// TODO Amusez-vous. Rendu ici, vous le méritez.
|
||||||
|
@ -229,9 +208,11 @@ namespace
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParticleSimApplication::ParticleSimApplication() : nanogui::Screen(nanogui::Vector2i(1280, 720), "GTI320 Labo Physique lineaire", true, false, true, true, false, 4, 1)
|
ParticleSimApplication::ParticleSimApplication() : nanogui::Screen(nanogui::Vector2i(1280, 720),
|
||||||
, m_particleSystem(), m_stepping(false), m_fpsCounter(0), m_fpsTime(0.0), m_maxIter(10), m_solverType(kGaussSeidel)
|
"GTI320 Labo Physique lineaire", true, false, true,
|
||||||
{
|
true, false, 4, 1), m_particleSystem(),
|
||||||
|
m_stepping(false), m_fpsCounter(0), m_fpsTime(0.0), m_maxIter(10),
|
||||||
|
m_solverType(kGaussSeidel) {
|
||||||
initGui();
|
initGui();
|
||||||
|
|
||||||
createBeam(m_particleSystem, m_stiffness); // le modèle "poutre" est sélectionné à l'initialisation
|
createBeam(m_particleSystem, m_stiffness); // le modèle "poutre" est sélectionné à l'initialisation
|
||||||
|
@ -241,8 +222,7 @@ ParticleSimApplication::ParticleSimApplication() : nanogui::Screen(nanogui::Vect
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleSimApplication::initGui()
|
void ParticleSimApplication::initGui() {
|
||||||
{
|
|
||||||
// Initialisation de la fenêtre
|
// Initialisation de la fenêtre
|
||||||
m_window = new nanogui::Window(this, "Particle sim");
|
m_window = new nanogui::Window(this, "Particle sim");
|
||||||
m_window->set_position(nanogui::Vector2i(8, 8));
|
m_window->set_position(nanogui::Vector2i(8, 8));
|
||||||
|
@ -250,16 +230,16 @@ void ParticleSimApplication::initGui()
|
||||||
|
|
||||||
// initialisation du canvas où est affiché le système de particules
|
// initialisation du canvas où est affiché le système de particules
|
||||||
m_canvas = new ParticleSimGLCanvas(this);
|
m_canvas = new ParticleSimGLCanvas(this);
|
||||||
m_canvas->set_background_color({ 255, 255, 255, 255 });
|
m_canvas->set_background_color({255, 255, 255, 255});
|
||||||
m_canvas->set_size({ 1000, 600 });
|
m_canvas->set_size({1000, 600});
|
||||||
m_canvas->set_draw_border(false);
|
m_canvas->set_draw_border(false);
|
||||||
|
|
||||||
// Initialisation de la fenêtre de contrôle
|
// Initialisation de la fenêtre de contrôle
|
||||||
nanogui::Window* controls = new nanogui::Window(this, "Controls");
|
nanogui::Window *controls = new nanogui::Window(this, "Controls");
|
||||||
controls->set_position(nanogui::Vector2i(960, 10));
|
controls->set_position(nanogui::Vector2i(960, 10));
|
||||||
controls->set_layout(new nanogui::GroupLayout());
|
controls->set_layout(new nanogui::GroupLayout());
|
||||||
|
|
||||||
Widget* tools = new Widget(controls);
|
Widget *tools = new Widget(controls);
|
||||||
tools->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 20));
|
tools->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 20));
|
||||||
|
|
||||||
// Intervalles des curseur
|
// Intervalles des curseur
|
||||||
|
@ -276,7 +256,8 @@ void ParticleSimApplication::initGui()
|
||||||
|
|
||||||
// Affichage du numéro de frame
|
// Affichage du numéro de frame
|
||||||
m_panelFrames = new Widget(tools);
|
m_panelFrames = new Widget(tools);
|
||||||
m_panelFrames->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 5));
|
m_panelFrames->set_layout(
|
||||||
|
new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 5));
|
||||||
m_labelFrames = new nanogui::Label(m_panelFrames, "Frame :");
|
m_labelFrames = new nanogui::Label(m_panelFrames, "Frame :");
|
||||||
m_textboxFrames = new nanogui::TextBox(m_panelFrames);
|
m_textboxFrames = new nanogui::TextBox(m_panelFrames);
|
||||||
m_textboxFrames->set_fixed_width(60);
|
m_textboxFrames->set_fixed_width(60);
|
||||||
|
@ -286,7 +267,7 @@ void ParticleSimApplication::initGui()
|
||||||
m_panelSolver = new Widget(tools);
|
m_panelSolver = new Widget(tools);
|
||||||
m_panelSolver->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5));
|
m_panelSolver->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5));
|
||||||
new nanogui::Label(m_panelSolver, "Solver : ");
|
new nanogui::Label(m_panelSolver, "Solver : ");
|
||||||
nanogui::Button* b = new nanogui::Button(m_panelSolver, "Gauss-Seidel");
|
nanogui::Button *b = new nanogui::Button(m_panelSolver, "Gauss-Seidel");
|
||||||
b->set_flags(nanogui::Button::RadioButton);
|
b->set_flags(nanogui::Button::RadioButton);
|
||||||
b->set_pushed(true);
|
b->set_pushed(true);
|
||||||
b->set_callback([this] { m_solverType = kGaussSeidel; });
|
b->set_callback([this] { m_solverType = kGaussSeidel; });
|
||||||
|
@ -301,115 +282,106 @@ void ParticleSimApplication::initGui()
|
||||||
b->set_flags(nanogui::Button::RadioButton);
|
b->set_flags(nanogui::Button::RadioButton);
|
||||||
|
|
||||||
// Curseur de rigidité
|
// Curseur de rigidité
|
||||||
Widget* panelSimControl = new Widget(tools);
|
Widget *panelSimControl = new Widget(tools);
|
||||||
panelSimControl->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5));
|
panelSimControl->set_layout(
|
||||||
|
new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5));
|
||||||
m_panelStiffness = new Widget(panelSimControl);
|
m_panelStiffness = new Widget(panelSimControl);
|
||||||
m_panelStiffness->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 5));
|
m_panelStiffness->set_layout(
|
||||||
|
new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 5));
|
||||||
m_labelStiffness = new nanogui::Label(m_panelStiffness, "Stiffness : ");
|
m_labelStiffness = new nanogui::Label(m_panelStiffness, "Stiffness : ");
|
||||||
m_sliderStiffness = new nanogui::Slider(m_panelStiffness);
|
m_sliderStiffness = new nanogui::Slider(m_panelStiffness);
|
||||||
m_sliderStiffness->set_range(stiffnessMinMax);
|
m_sliderStiffness->set_range(stiffnessMinMax);
|
||||||
m_textboxStiffness = new nanogui::TextBox(m_panelStiffness);
|
m_textboxStiffness = new nanogui::TextBox(m_panelStiffness);
|
||||||
m_sliderStiffness->set_callback([this](float value)
|
m_sliderStiffness->set_callback([this](float value) {
|
||||||
{
|
m_stiffness = std::exp(value);
|
||||||
m_stiffness = std::exp(value);
|
onStiffnessSliderChanged();
|
||||||
onStiffnessSliderChanged();
|
});
|
||||||
});
|
|
||||||
m_sliderStiffness->set_value(std::log(300.f));
|
m_sliderStiffness->set_value(std::log(300.f));
|
||||||
|
|
||||||
// Curseur du nombre maximum d'itération pour Jacobi et Gauss-Seidel
|
// Curseur du nombre maximum d'itération pour Jacobi et Gauss-Seidel
|
||||||
Widget* panelMaxIter = new Widget(panelSimControl);
|
Widget *panelMaxIter = new Widget(panelSimControl);
|
||||||
panelMaxIter->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 5));
|
panelMaxIter->set_layout(
|
||||||
|
new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 5));
|
||||||
new nanogui::Label(panelMaxIter, "Max iterations : ");
|
new nanogui::Label(panelMaxIter, "Max iterations : ");
|
||||||
nanogui::Slider* sliderMaxIter = new nanogui::Slider(panelMaxIter);
|
nanogui::Slider *sliderMaxIter = new nanogui::Slider(panelMaxIter);
|
||||||
sliderMaxIter->set_range(iterMinMax);
|
sliderMaxIter->set_range(iterMinMax);
|
||||||
nanogui::TextBox* textboxMaxIter = new nanogui::TextBox(panelMaxIter);
|
nanogui::TextBox *textboxMaxIter = new nanogui::TextBox(panelMaxIter);
|
||||||
textboxMaxIter->set_value(std::to_string(m_maxIter));
|
textboxMaxIter->set_value(std::to_string(m_maxIter));
|
||||||
sliderMaxIter->set_value(m_maxIter);
|
sliderMaxIter->set_value(m_maxIter);
|
||||||
sliderMaxIter->set_callback([this, textboxMaxIter](float value)
|
sliderMaxIter->set_callback([this, textboxMaxIter](float value) {
|
||||||
{
|
m_maxIter = (int) value;
|
||||||
m_maxIter = (int)value;
|
textboxMaxIter->set_value(std::to_string(m_maxIter));
|
||||||
textboxMaxIter->set_value(std::to_string(m_maxIter));
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Bouton «Simulate»
|
// Bouton «Simulate»
|
||||||
nanogui::Button* startStopButton = new nanogui::Button(panelSimControl, "Simulate");
|
nanogui::Button *startStopButton = new nanogui::Button(panelSimControl, "Simulate");
|
||||||
startStopButton->set_flags(nanogui::Button::ToggleButton);
|
startStopButton->set_flags(nanogui::Button::ToggleButton);
|
||||||
startStopButton->set_change_callback([this](bool val)
|
startStopButton->set_change_callback([this](bool val) {
|
||||||
{
|
m_stepping = val;
|
||||||
m_stepping = val;
|
if (val) {
|
||||||
if (val)
|
m_prevTime = glfwGetTime();
|
||||||
{
|
draw_all();
|
||||||
m_prevTime = glfwGetTime();
|
}
|
||||||
draw_all();
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Bouton «Step»
|
// Bouton «Step»
|
||||||
nanogui::Button* stepButton = new nanogui::Button(panelSimControl, "Step");
|
nanogui::Button *stepButton = new nanogui::Button(panelSimControl, "Step");
|
||||||
stepButton->set_callback([this]
|
stepButton->set_callback([this] {
|
||||||
{
|
if (!m_stepping)
|
||||||
if (!m_stepping)
|
step(deltaT);
|
||||||
step(deltaT);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Bouton «Reset»
|
// Bouton «Reset»
|
||||||
nanogui::Button* resetButton = new nanogui::Button(panelSimControl, "Reset");
|
nanogui::Button *resetButton = new nanogui::Button(panelSimControl, "Reset");
|
||||||
resetButton->set_callback([this]
|
resetButton->set_callback([this] {
|
||||||
{
|
reset();
|
||||||
reset();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Boutons pour le choix du modèle
|
// Boutons pour le choix du modèle
|
||||||
Widget* panelExamples = new Widget(tools);
|
Widget *panelExamples = new Widget(tools);
|
||||||
panelExamples->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5));
|
panelExamples->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5));
|
||||||
new nanogui::Label(panelExamples, "Examples : ");
|
new nanogui::Label(panelExamples, "Examples : ");
|
||||||
nanogui::Button* loadClothButton = new nanogui::Button(panelExamples, "Cloth");
|
nanogui::Button *loadClothButton = new nanogui::Button(panelExamples, "Cloth");
|
||||||
loadClothButton->set_callback([this]
|
loadClothButton->set_callback([this] {
|
||||||
{
|
createHangingCloth(m_particleSystem, m_stiffness);
|
||||||
createHangingCloth(m_particleSystem, m_stiffness);
|
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
||||||
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
reset();
|
||||||
reset();
|
});
|
||||||
});
|
nanogui::Button *loadLargeClothButton = new nanogui::Button(panelExamples, "Large cloth");
|
||||||
nanogui::Button* loadLargeClothButton = new nanogui::Button(panelExamples, "Large cloth");
|
loadLargeClothButton->set_callback([this] {
|
||||||
loadLargeClothButton->set_callback([this]
|
createLargeHangingCloth(m_particleSystem, m_sliderStiffness->value());
|
||||||
{
|
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
||||||
createLargeHangingCloth(m_particleSystem, m_sliderStiffness->value());
|
reset();
|
||||||
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
});
|
||||||
reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
nanogui::Button* loadBeamButton = new nanogui::Button(panelExamples, "Beam");
|
nanogui::Button *loadBeamButton = new nanogui::Button(panelExamples, "Beam");
|
||||||
loadBeamButton->set_callback([this]
|
loadBeamButton->set_callback([this] {
|
||||||
{
|
createBeam(m_particleSystem, m_stiffness);
|
||||||
createBeam(m_particleSystem, m_stiffness);
|
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
||||||
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
reset();
|
||||||
reset();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
nanogui::Button* loadRopeButton = new nanogui::Button(panelExamples, "Rope");
|
nanogui::Button *loadRopeButton = new nanogui::Button(panelExamples, "Rope");
|
||||||
loadRopeButton->set_callback([this]
|
loadRopeButton->set_callback([this] {
|
||||||
{
|
createHangingRope(m_particleSystem, m_stiffness);
|
||||||
createHangingRope(m_particleSystem, m_stiffness);
|
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
||||||
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
reset();
|
||||||
reset();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
nanogui::Button* loadVotreExemple = new nanogui::Button(panelExamples, "Le vôtre");
|
nanogui::Button *loadVotreExemple = new nanogui::Button(panelExamples, "Le vôtre");
|
||||||
loadVotreExemple->set_callback([this]
|
loadVotreExemple->set_callback([this] {
|
||||||
{
|
createVotreExemple(m_particleSystem, m_stiffness);
|
||||||
createVotreExemple(m_particleSystem, m_stiffness);
|
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
||||||
m_particleSystem.pack(m_p0, m_v0, m_f0);
|
reset();
|
||||||
reset();
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Réaction aux événements déclenchés par le clavier
|
* Réaction aux événements déclenchés par le clavier
|
||||||
*/
|
*/
|
||||||
bool ParticleSimApplication::keyboard_event(int key, int scancode, int action, int modifiers)
|
bool ParticleSimApplication::keyboard_event(int key, int scancode, int action, int modifiers) {
|
||||||
{
|
|
||||||
if (Screen::keyboard_event(key, scancode, action, modifiers))
|
if (Screen::keyboard_event(key, scancode, action, modifiers))
|
||||||
return true;
|
return true;
|
||||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||||
|
@ -427,12 +399,10 @@ bool ParticleSimApplication::keyboard_event(int key, int scancode, int action, i
|
||||||
* `step` est appelée pour faire avancer le système d'un intervalle de temps
|
* `step` est appelée pour faire avancer le système d'un intervalle de temps
|
||||||
* DELTA_T. Ensuite, l'affichage est mis à jour.
|
* DELTA_T. Ensuite, l'affichage est mis à jour.
|
||||||
*/
|
*/
|
||||||
void ParticleSimApplication::draw_contents()
|
void ParticleSimApplication::draw_contents() {
|
||||||
{
|
|
||||||
Screen::draw_contents();
|
Screen::draw_contents();
|
||||||
|
|
||||||
if (m_stepping)
|
if (m_stepping) {
|
||||||
{
|
|
||||||
auto now = glfwGetTime();
|
auto now = glfwGetTime();
|
||||||
float dt = now - m_prevTime;
|
float dt = now - m_prevTime;
|
||||||
|
|
||||||
|
@ -442,9 +412,8 @@ void ParticleSimApplication::draw_contents()
|
||||||
//
|
//
|
||||||
m_fpsTime += dt;
|
m_fpsTime += dt;
|
||||||
++m_fpsCounter;
|
++m_fpsCounter;
|
||||||
if (m_fpsCounter > 30)
|
if (m_fpsCounter > 30) {
|
||||||
{
|
const float fps = (float) m_fpsCounter / m_fpsTime;
|
||||||
const float fps = (float)m_fpsCounter / m_fpsTime;
|
|
||||||
char buf[64];
|
char buf[64];
|
||||||
snprintf(buf, sizeof(buf), "%3.1f", fps);
|
snprintf(buf, sizeof(buf), "%3.1f", fps);
|
||||||
m_fpsCounter = 0;
|
m_fpsCounter = 0;
|
||||||
|
@ -463,11 +432,9 @@ void ParticleSimApplication::draw_contents()
|
||||||
* Appelée lorsque le curseur de rigidité est modifié. La nouvelle rigidité est
|
* Appelée lorsque le curseur de rigidité est modifié. La nouvelle rigidité est
|
||||||
* affectée à tous les ressorts
|
* affectée à tous les ressorts
|
||||||
*/
|
*/
|
||||||
void ParticleSimApplication::onStiffnessSliderChanged()
|
void ParticleSimApplication::onStiffnessSliderChanged() {
|
||||||
{
|
|
||||||
// Update all springs with the slider value
|
// Update all springs with the slider value
|
||||||
for (Spring& s : getParticleSystem().getSprings())
|
for (Spring &s: getParticleSystem().getSprings()) {
|
||||||
{
|
|
||||||
s.k = m_stiffness;
|
s.k = m_stiffness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,8 +446,7 @@ void ParticleSimApplication::onStiffnessSliderChanged()
|
||||||
/**
|
/**
|
||||||
* Effectue un pas de simulation de taille dt.
|
* Effectue un pas de simulation de taille dt.
|
||||||
*/
|
*/
|
||||||
void ParticleSimApplication::step(float dt)
|
void ParticleSimApplication::step(float dt) {
|
||||||
{
|
|
||||||
// Construction des matrices de masse et de rigidité
|
// Construction des matrices de masse et de rigidité
|
||||||
//
|
//
|
||||||
m_particleSystem.buildMassMatrix(m_M);
|
m_particleSystem.buildMassMatrix(m_M);
|
||||||
|
@ -520,33 +486,32 @@ void ParticleSimApplication::step(float dt)
|
||||||
// Version 2 utilise un seul constructeur et aucune copie
|
// Version 2 utilise un seul constructeur et aucune copie
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
const Matrix<float, Dynamic, Dynamic> A;
|
const Matrix<float, Dynamic, Dynamic> A = m_M + -1.0f * std::pow(deltaT, 2.0f) * m_dfdx;
|
||||||
const Vector<float, Dynamic> b;
|
const Vector<float, Dynamic> b = deltaT * m_f + m_v;
|
||||||
|
|
||||||
// Résolution du système d'équations `A*v_plus = b`.
|
// Résolution du système d'équations `A*v_plus = b`.
|
||||||
//
|
//
|
||||||
Vector<float, Dynamic> v_plus;
|
Vector<float, Dynamic> v_plus;
|
||||||
Vector<float, Dynamic> acc; // vecteur d'accélérations
|
Vector<float, Dynamic> acc; // vecteur d'accélérations
|
||||||
switch (m_solverType)
|
switch (m_solverType) {
|
||||||
{
|
case kGaussSeidel:
|
||||||
case kGaussSeidel:
|
gaussSeidel(A, b, v_plus, m_maxIter);
|
||||||
gaussSeidel(A, b, v_plus, m_maxIter);
|
break;
|
||||||
break;
|
case kColorGaussSeidel:
|
||||||
case kColorGaussSeidel:
|
gaussSeidelColor(A, b, v_plus, m_graphColor.getPartitions(), m_maxIter);
|
||||||
gaussSeidelColor(A, b, v_plus, m_graphColor.getPartitions(), m_maxIter);
|
break;
|
||||||
break;
|
case kCholesky:
|
||||||
case kCholesky:
|
cholesky(A, b, v_plus);
|
||||||
cholesky(A, b, v_plus);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
case kNone:
|
||||||
case kNone:
|
// N'utilise pas de solveur, il s'agit de l'implémentation naive de
|
||||||
// N'utilise pas de solveur, il s'agit de l'implémentation naive de
|
// l'intégration d'Euler.
|
||||||
// l'intégration d'Euler.
|
acc.resize(m_M.rows()); // vecteur d'accélérations
|
||||||
acc.resize(m_M.rows()); // vecteur d'accélérations
|
for (int i = 0; i < m_M.rows(); ++i)
|
||||||
for (int i = 0; i < m_M.rows(); ++i)
|
acc(i) = (1.0 / m_M(i, i)) * m_f(i);
|
||||||
acc(i) = (1.0 / m_M(i, i)) * m_f(i);
|
v_plus = m_v + dt * acc;
|
||||||
v_plus = m_v + dt * acc;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Mise à jour du vecteur d'état de position via l'intégration d'Euler
|
// TODO Mise à jour du vecteur d'état de position via l'intégration d'Euler
|
||||||
|
@ -563,8 +528,7 @@ void ParticleSimApplication::step(float dt)
|
||||||
/**
|
/**
|
||||||
* Réinitialisation du système de particules
|
* Réinitialisation du système de particules
|
||||||
*/
|
*/
|
||||||
void ParticleSimApplication::reset()
|
void ParticleSimApplication::reset() {
|
||||||
{
|
|
||||||
m_frameCounter = 0;
|
m_frameCounter = 0;
|
||||||
m_particleSystem.unpack(m_p0, m_v0);
|
m_particleSystem.unpack(m_p0, m_v0);
|
||||||
m_graphColor.color(m_particleSystem);
|
m_graphColor.color(m_particleSystem);
|
||||||
|
@ -575,8 +539,7 @@ void ParticleSimApplication::reset()
|
||||||
/**
|
/**
|
||||||
* Mise à jour du compteur de frames
|
* Mise à jour du compteur de frames
|
||||||
*/
|
*/
|
||||||
void ParticleSimApplication::updateFrameCounter()
|
void ParticleSimApplication::updateFrameCounter() {
|
||||||
{
|
|
||||||
++m_frameCounter;
|
++m_frameCounter;
|
||||||
char buf[16];
|
char buf[16];
|
||||||
snprintf(buf, sizeof(buf), "%d", m_frameCounter);
|
snprintf(buf, sizeof(buf), "%d", m_frameCounter);
|
||||||
|
|
|
@ -95,7 +95,7 @@ void ParticleSystem::unpack(const Vector<float, Dynamic> &_pos,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construction de la matirce de masses.
|
* Construction de la matrice de masses.
|
||||||
*/
|
*/
|
||||||
void ParticleSystem::buildMassMatrix(Matrix<float, Dynamic, Dynamic> &M) {
|
void ParticleSystem::buildMassMatrix(Matrix<float, Dynamic, Dynamic> &M) {
|
||||||
const int numParticles = m_particles.size();
|
const int numParticles = m_particles.size();
|
||||||
|
@ -131,6 +131,9 @@ void ParticleSystem::buildDfDx(Matrix<float, Dynamic, Dynamic> &dfdx) {
|
||||||
dfdx.resize(dim, dim);
|
dfdx.resize(dim, dim);
|
||||||
dfdx.setZero();
|
dfdx.setZero();
|
||||||
|
|
||||||
|
auto identity = Matrix<float, 2, 2>();
|
||||||
|
identity.setIdentity();
|
||||||
|
|
||||||
// Pour chaque ressort...
|
// Pour chaque ressort...
|
||||||
for (const Spring &spring: m_springs) {
|
for (const Spring &spring: m_springs) {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -141,6 +144,20 @@ void ParticleSystem::buildDfDx(Matrix<float, Dynamic, Dynamic> &dfdx) {
|
||||||
// Astuce: créer une matrice de taille fixe 2 par 2 puis utiliser la classe SubMatrix pour accumuler
|
// Astuce: créer une matrice de taille fixe 2 par 2 puis utiliser la classe SubMatrix pour accumuler
|
||||||
// les modifications sur la diagonale (2 endroits) et pour mettre à jour les blocs non diagonale (2 endroits).
|
// les modifications sur la diagonale (2 endroits) et pour mettre à jour les blocs non diagonale (2 endroits).
|
||||||
|
|
||||||
|
auto p0 = m_particles[spring.index0];
|
||||||
|
auto p1 = m_particles[spring.index1];
|
||||||
|
|
||||||
|
Vector<float, 2> distance = p1.x - p0.x;
|
||||||
|
Matrix<float, 2, 1> distance_m = distance.as_matrix();
|
||||||
|
Matrix<float, 1, 2> distance_t = distance_m.transpose<float, 1, 2, ColumnStorage>();
|
||||||
|
float l = distance.norm();
|
||||||
|
Matrix<float, 2, 2> l2_m = std::pow(l, 2.0f) * identity;
|
||||||
|
float l3 = std::pow(l, 3.0f);
|
||||||
|
|
||||||
|
Matrix<float, 2, 2> dd = -1.0f * (distance_m * distance_t);
|
||||||
|
Matrix<float, 2, 2> term1 = spring.k * identity;
|
||||||
|
Matrix<float, 2, 2> term2 = -1.0f * (1 / l3) * spring.k * spring.l0 * (l2_m + dd);
|
||||||
|
|
||||||
|
dfdx.block(spring.index0, spring.index1, 2, 2) = term1 + term2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,11 @@
|
||||||
|
|
||||||
#include "Math3D.h"
|
#include "Math3D.h"
|
||||||
|
|
||||||
namespace gti320
|
namespace gti320 {
|
||||||
{
|
|
||||||
// Identification des solveurs
|
// Identification des solveurs
|
||||||
enum eSolverType { kNone, kGaussSeidel, kColorGaussSeidel, kCholesky };
|
enum eSolverType {
|
||||||
|
kNone, kGaussSeidel, kColorGaussSeidel, kCholesky
|
||||||
|
};
|
||||||
|
|
||||||
// Paramètres de convergences pour les algorithmes itératifs
|
// Paramètres de convergences pour les algorithmes itératifs
|
||||||
static const float eps = 1e-4f;
|
static const float eps = 1e-4f;
|
||||||
|
@ -26,21 +27,54 @@ namespace gti320
|
||||||
/**
|
/**
|
||||||
* Résout Ax = b avec la méthode Gauss-Seidel
|
* Résout Ax = b avec la méthode Gauss-Seidel
|
||||||
*/
|
*/
|
||||||
static void gaussSeidel(const Matrix<float, Dynamic, Dynamic>& A,
|
static void gaussSeidel(const Matrix<float, Dynamic, Dynamic> &A,
|
||||||
const Vector<float, Dynamic>& b,
|
const Vector<float, Dynamic> &b,
|
||||||
Vector<float, Dynamic>& x, int k_max)
|
Vector<float, Dynamic> &x, int k_max) {
|
||||||
{
|
|
||||||
// TODO
|
// TODO
|
||||||
//
|
//
|
||||||
// Implémenter la méthode de Gauss-Seidel
|
// Implémenter la méthode de Gauss-Seidel
|
||||||
|
int n = b.size();
|
||||||
|
|
||||||
|
x.resize(n);
|
||||||
|
x.setZero();
|
||||||
|
|
||||||
|
bool converged = false;
|
||||||
|
int k = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
Vector<float, Dynamic> nx = x;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
nx(i) = b(i);
|
||||||
|
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
nx(i) = nx(i) - A(i, j) * nx(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = i + 1; j < n; j++) {
|
||||||
|
nx(i) = nx(i) - A(i, j) * x(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
nx(i) = nx(i) / A(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
k++;
|
||||||
|
Vector<float, Dynamic> r = A * x - b;
|
||||||
|
|
||||||
|
converged = k >= k_max ||
|
||||||
|
(nx - x).norm() / nx.norm() < tau ||
|
||||||
|
r.norm() / b.norm() < eps;
|
||||||
|
|
||||||
|
x = nx;
|
||||||
|
} while (!converged);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* Résout Ax = b avec la méthode Gauss-Seidel (coloration de graphe)
|
* Résout Ax = b avec la méthode Gauss-Seidel (coloration de graphe)
|
||||||
*/
|
*/
|
||||||
static void gaussSeidelColor(const Matrix<float, Dynamic, Dynamic>& A, const Vector<float, Dynamic>& b, Vector<float, Dynamic>& x, const Partitions& P, const int maxIter)
|
static void gaussSeidelColor(const Matrix<float, Dynamic, Dynamic> &A, const Vector<float, Dynamic> &b,
|
||||||
{
|
Vector<float, Dynamic> &x, const Partitions &P, const int maxIter) {
|
||||||
// TODO
|
// TODO
|
||||||
//
|
//
|
||||||
// Implémenter la méthode de Gauss-Seidel avec coloration de graphe.
|
// Implémenter la méthode de Gauss-Seidel avec coloration de graphe.
|
||||||
|
@ -51,31 +85,63 @@ namespace gti320
|
||||||
/**
|
/**
|
||||||
* Résout Ax = b avec la méthode de Cholesky
|
* Résout Ax = b avec la méthode de Cholesky
|
||||||
*/
|
*/
|
||||||
static void cholesky(const Matrix<float, Dynamic, Dynamic>& A,
|
static void cholesky(const Matrix<float, Dynamic, Dynamic> &A,
|
||||||
const Vector<float, Dynamic>& b,
|
const Vector<float, Dynamic> &b,
|
||||||
Vector<float, Dynamic>& x)
|
Vector<float, Dynamic> &x) {
|
||||||
{
|
int n = A.rows();
|
||||||
|
x.resize(n);
|
||||||
|
x.setZero();
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
//
|
//
|
||||||
// Calculer la matrice L de la factorisation de Cholesky
|
// Calculer la matrice L de la factorisation de Cholesky
|
||||||
|
auto L = Matrix<float, Dynamic, Dynamic>(n, n);
|
||||||
|
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
for (int i = j; i < n; i++) {
|
||||||
|
float s = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < j; k++) {
|
||||||
|
s += L(i, k) * L(j, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == j) {
|
||||||
|
L(i, i) = std::sqrt(A(i, i) - s);
|
||||||
|
} else {
|
||||||
|
L(i, j) = (A(i, j) - s) / L(j, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
//
|
//
|
||||||
// Résoudre Ly = b
|
// Résoudre Ly = b
|
||||||
|
auto y = Vector<float, Dynamic>(n);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
y(i) = b(i);
|
||||||
|
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
y(i) -= L(i, j) * y(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
y(i) /= L(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
//
|
//
|
||||||
// Résoudre L^t x = y
|
// Résoudre L^t x = y
|
||||||
//
|
//
|
||||||
// Remarque : ne pas caculer la transposer de L, c'est inutilement
|
// Remarque : ne pas calculer la transposée de L, c'est inutilement
|
||||||
// coûteux.
|
// coûteux.
|
||||||
|
for (int i = n - 1; i >= 0; i--) {
|
||||||
|
x(i) = y(i);
|
||||||
|
|
||||||
|
for (int j = i + 1; j < n; j++) {
|
||||||
|
x(i) -= L(j, i) * x(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
x(i) /= L(i, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Matrix.h"
|
||||||
#include "Math3D.h"
|
#include "Math3D.h"
|
||||||
|
|
||||||
namespace gti320
|
namespace gti320
|
||||||
|
@ -102,6 +103,13 @@ namespace gti320
|
||||||
{
|
{
|
||||||
return sqrt(dot(*this));
|
return sqrt(dot(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix<_Scalar, 2, 1> as_matrix() const {
|
||||||
|
Matrix<_Scalar, 2, 1> mat;
|
||||||
|
mat(0, 0) = (*this)(0);
|
||||||
|
mat(1, 0) = (*this)(1);
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Vector<float, 2> Vector2f;
|
typedef Vector<float, 2> Vector2f;
|
||||||
|
|
Loading…
Reference in New Issue