leios / simuleios

Simulations for LeiosOS
https://www.youtube.com/user/LeiosOS
MIT License
198 stars 45 forks source link

Proper matrix class #11

Closed zsparal closed 8 years ago

zsparal commented 9 years ago

So, this is somewhat close to how a proper matrix class should look like. It's only for square matrices (it would be really easy to change it to arbitrary sizes).

A few things to note here:

  1. matrix.h is actually commented for you, trying to explain the reasoning behind some of the stuff. Feel free to ask in this PR is you don't get something
  2. This also demonstrates that you should probably write unit tests for your code. Now I can be reasonably sure that my matrix class actually works. These aren't terrific tests, but they are better than nothing. This would also help you catch bugs really early in developement (the MD code would've benefited from this quite a bit).
  3. Ignore the catch.hpp header. It's a 3rd party library I used for creating the unit tests.

Instructions to compile:

  1. Unit tests: g++ -std=c++11 -Wall -Wextra -Werror test.cpp -o test
  2. Examples: g++ -std=c++11 -Wall -Wextra -Werror example.cpp -o example

Then run the tests with ./test and the examples with ./example.

leios commented 9 years ago

Hey man, thanks again. I'll take a look! =)

zsparal commented 9 years ago

An additional advantage that I didn't already mention. Structs get you type safety. You know how a point - point = vector? You can actually represent this kind of relationship if you have a point and vector class. If you're only using arrays or individual coordinates, this is not so apparent.

I'm back to the example I brought up on stream: using structs in programming is the same as using vectors or matrices in math or physics:

s = v * t;

sx = vx * t;
sy = vy * t;
sz = vz * t;

The latter is more explicit, but I think you'd agree that you'd rather use the first form when writing out some equations.

They also make bugs harder to make:

v -= 2.0 * dot(v, n) * n;
auto v2 = cross(v, n);
// -----------------------------------------------
auto vn = vx * nx + vy * n + vz * nz;
vx -= 2.0 * vn * nx;
vy -= 2.0 * vn * ny;
vz -= 2.0 * vn * ny;

auto v2x = vx * ny - vy * nx;
auto v2y = vy * nz - vz * ny;
auto v2z = vz * nx - vx * nz;

Did you notice both bugs in the second example just by looking at it? A vector class makes these kinds of bugs much, much harder to make.

Toeger commented 9 years ago

@Gustorn Good stuff. @leios consider giving this a chance, it is worth it.

zsparal commented 9 years ago

@Toeger I was debating doing NxM matrices, but I felt like the complexity is enough as it is. Also the tests are pretty abysmal, but at least they're there to showcase how it's done.

I could've also switched storage from array to vector based on the size, but it would've been pretty std::enable_if heavy.

zsparal commented 8 years ago

Not relevant anymore