#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
inline float degToRad(float angle) { return 3.141593f * angle / 180.f; }
struct Vec2 {
float x, y;
Vec2(float x, float y): x(x), y(y) { }
};
ostream& operator<<(ostream &out, const Vec2 &v)
{
return out << "( " << v.x << ", " << v.y << " )";
}
struct Vec3 {
float x, y, z;
Vec3(float x, float y, float z): x(x), y(y), z(z) { }
Vec3(const Vec2 &xy, float z): x(xy.x), y(xy.y), z(z) { }
};
ostream& operator<<(ostream &out, const Vec3 &v)
{
return out << "( " << v.x << ", " << v.y << ", " << v.z << " )";
}
enum ArgInitRotX { InitRotX };
enum ArgInitRotY { InitRotY };
struct Mat3x3 {
union {
float comp[3 * 3];
struct {
float _00, _01, _02, _10, _11, _12, _20, _21, _22;
};
};
// constructor to build a matrix by elements
Mat3x3(
float _00, float _01, float _02,
float _10, float _11, float _12,
float _20, float _21, float _22)
{
this->_00 = _00; this->_01 = _01; this->_02 = _02;
this->_10 = _10; this->_11 = _11; this->_12 = _12;
this->_20 = _20; this->_21 = _21; this->_22 = _22;
}
// constructor to build a matrix for rotation about x axis
Mat3x3(ArgInitRotX, float angle)
{
this->_00 = 1.0f; this->_01 = 0.0f; this->_02 = 0.0f;
this->_10 = 0.0f; this->_11 = cos(angle); this->_12 = sin(angle);
this->_20 = 0.0f; this->_21 = -sin(angle); this->_22 = cos(angle);
}
// constructor to build a matrix for rotation about y axis
Mat3x3(ArgInitRotY, float angle)
{
this->_00 = cos(angle); this->_01 = 0.0f; this->_02 = -sin(angle);
this->_10 = 0.0f; this->_11 = 1.0f; this->_12 = 0.0f;
this->_20 = sin(angle); this->_21 = 0.0f; this->_22 = cos(angle);
}
// multiply matrix with matrix -> matrix
Mat3x3 operator * (const Mat3x3 &mat) const
{
return Mat3x3(
_00 * mat._20 + _01 * mat._10 + _02 * mat._20,
_00 * mat._21 + _01 * mat._11 + _02 * mat._21,
_00 * mat._22 + _01 * mat._12 + _02 * mat._22,
_10 * mat._20 + _11 * mat._10 + _12 * mat._20,
_10 * mat._21 + _11 * mat._11 + _12 * mat._21,
_10 * mat._22 + _11 * mat._12 + _12 * mat._22,
_20 * mat._20 + _21 * mat._10 + _22 * mat._20,
_20 * mat._21 + _21 * mat._11 + _22 * mat._21,
_20 * mat._22 + _21 * mat._12 + _22 * mat._22);
}
// multiply matrix with vector -> vector
Vec3 operator * (const Vec3 &vec) const
{
return Vec3(
_00 * vec.x + _01 * vec.y + _02 * vec.z,
_10 * vec.x + _11 * vec.y + _12 * vec.z,
_20 * vec.x + _21 * vec.y + _22 * vec.z);
}
};
ostream& operator<<(ostream &out, const Mat3x3 &mat)
{
return out
<< mat._20 << ", " << mat._21 << ", " << mat._22 << endl
<< mat._10 << ", " << mat._11 << ", " << mat._12 << endl
<< mat._20 << ", " << mat._21 << ", " << mat._22;
}
int main()
{
// some 2D vector samples (for a quad)
Vec2 quad[] = {
{ 0.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }
};
/* Something like this:
* ^ y
* |
* v[3] ---- v[2]
* | |
* | |
* | |
* v[0] ---- v[1] --> x
*/
// the rotation matrix for isometric view build by multiplying the rotations
Mat3x3 matIso = Mat3x3(InitRotX, degToRad(30.0)) * Mat3x3(InitRotY, degToRad(45.0));
// prepare output formatting
cout << fixed << setprecision(5);
// the rotation matrix for isometric view:
cout << "The matrix for isometric projection:" << endl
<< matIso << endl;
// prepare output formatting
cout << fixed << setprecision(3);
// do it for all sample 2D vectors:
cout << "Isometric projection of the 2d quad:" << endl;
for (const Vec2 &v : quad) {
// 2D vector -> 3D vector
Vec3 v_(v, 0.0f);
// project v_ to iso view
v_ = matIso * v_;
// print the result:
cout << v << " -> " << v_ << endl;
}
// doing it again with a 3d cube (centered)
Vec3 cube[] = {
{ -0.5f, -0.5f, -0.5f }, { +0.5f, -0.5f, -0.5f }, { +0.5f, +0.5f, -0.5f }, { -0.5f, +0.5f, -0.5f },
{ -0.5f, -0.5f, +0.5f }, { +0.5f, -0.5f, +0.5f }, { +0.5f, +0.5f, +0.5f }, { -0.5f, +0.5f, +0.5f }
};
cout << "Isometric projection of the centered 3d cube:" << endl;
for (const Vec3 &v : cube) {
// project v to iso view
Vec3 v_ = matIso * v;
// print the result:
cout << v << " -> " << v_ << endl;
}
// done
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8aW9tYW5pcD4KI2luY2x1ZGUgPGNtYXRoPgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCmlubGluZSBmbG9hdCBkZWdUb1JhZChmbG9hdCBhbmdsZSkgeyByZXR1cm4gMy4xNDE1OTNmICogYW5nbGUgLyAxODAuZjsgfQoKc3RydWN0IFZlYzIgewogIGZsb2F0IHgsIHk7CiAgVmVjMihmbG9hdCB4LCBmbG9hdCB5KTogeCh4KSwgeSh5KSB7IH0KfTsKCm9zdHJlYW0mIG9wZXJhdG9yPDwob3N0cmVhbSAmb3V0LCBjb25zdCBWZWMyICZ2KQp7CiAgcmV0dXJuIG91dCA8PCAiKCAiIDw8IHYueCA8PCAiLCAiIDw8IHYueSA8PCAiICkiOwp9CgpzdHJ1Y3QgVmVjMyB7CiAgZmxvYXQgeCwgeSwgejsKICBWZWMzKGZsb2F0IHgsIGZsb2F0IHksIGZsb2F0IHopOiB4KHgpLCB5KHkpLCB6KHopIHsgfQogIFZlYzMoY29uc3QgVmVjMiAmeHksIGZsb2F0IHopOiB4KHh5LngpLCB5KHh5LnkpLCB6KHopIHsgfQp9OwoKb3N0cmVhbSYgb3BlcmF0b3I8PChvc3RyZWFtICZvdXQsIGNvbnN0IFZlYzMgJnYpCnsKICByZXR1cm4gb3V0IDw8ICIoICIgPDwgdi54IDw8ICIsICIgPDwgdi55IDw8ICIsICIgPDwgdi56IDw8ICIgKSI7Cn0KCmVudW0gQXJnSW5pdFJvdFggeyBJbml0Um90WCB9OwplbnVtIEFyZ0luaXRSb3RZIHsgSW5pdFJvdFkgfTsKCnN0cnVjdCBNYXQzeDMgewogIHVuaW9uIHsKICAgIGZsb2F0IGNvbXBbMyAqIDNdOwogICAgc3RydWN0IHsKICAgICAgZmxvYXQgXzAwLCBfMDEsIF8wMiwgXzEwLCBfMTEsIF8xMiwgXzIwLCBfMjEsIF8yMjsKICAgIH07CiAgfTsKCiAgLy8gY29uc3RydWN0b3IgdG8gYnVpbGQgYSBtYXRyaXggYnkgZWxlbWVudHMKICBNYXQzeDMoCiAgICBmbG9hdCBfMDAsIGZsb2F0IF8wMSwgZmxvYXQgXzAyLAogICAgZmxvYXQgXzEwLCBmbG9hdCBfMTEsIGZsb2F0IF8xMiwKICAgIGZsb2F0IF8yMCwgZmxvYXQgXzIxLCBmbG9hdCBfMjIpCiAgewogICAgdGhpcy0+XzAwID0gXzAwOyB0aGlzLT5fMDEgPSBfMDE7IHRoaXMtPl8wMiA9IF8wMjsKICAgIHRoaXMtPl8xMCA9IF8xMDsgdGhpcy0+XzExID0gXzExOyB0aGlzLT5fMTIgPSBfMTI7CiAgICB0aGlzLT5fMjAgPSBfMjA7IHRoaXMtPl8yMSA9IF8yMTsgdGhpcy0+XzIyID0gXzIyOwogIH0KICAvLyBjb25zdHJ1Y3RvciB0byBidWlsZCBhIG1hdHJpeCBmb3Igcm90YXRpb24gYWJvdXQgeCBheGlzCiAgTWF0M3gzKEFyZ0luaXRSb3RYLCBmbG9hdCBhbmdsZSkKICB7CiAgICB0aGlzLT5fMDAgPSAxLjBmOyB0aGlzLT5fMDEgPSAwLjBmOyAgICAgICAgdGhpcy0+XzAyID0gMC4wZjsKICAgIHRoaXMtPl8xMCA9IDAuMGY7IHRoaXMtPl8xMSA9IGNvcyhhbmdsZSk7ICB0aGlzLT5fMTIgPSBzaW4oYW5nbGUpOwogICAgdGhpcy0+XzIwID0gMC4wZjsgdGhpcy0+XzIxID0gLXNpbihhbmdsZSk7IHRoaXMtPl8yMiA9IGNvcyhhbmdsZSk7CiAgfQogIC8vIGNvbnN0cnVjdG9yIHRvIGJ1aWxkIGEgbWF0cml4IGZvciByb3RhdGlvbiBhYm91dCB5IGF4aXMKICBNYXQzeDMoQXJnSW5pdFJvdFksIGZsb2F0IGFuZ2xlKQogIHsKICAgIHRoaXMtPl8wMCA9IGNvcyhhbmdsZSk7IHRoaXMtPl8wMSA9IDAuMGY7IHRoaXMtPl8wMiA9IC1zaW4oYW5nbGUpOwogICAgdGhpcy0+XzEwID0gMC4wZjsgICAgICAgdGhpcy0+XzExID0gMS4wZjsgdGhpcy0+XzEyID0gMC4wZjsKICAgIHRoaXMtPl8yMCA9IHNpbihhbmdsZSk7IHRoaXMtPl8yMSA9IDAuMGY7IHRoaXMtPl8yMiA9IGNvcyhhbmdsZSk7CiAgfQogIC8vIG11bHRpcGx5IG1hdHJpeCB3aXRoIG1hdHJpeCAtPiBtYXRyaXgKICBNYXQzeDMgb3BlcmF0b3IgKiAoY29uc3QgTWF0M3gzICZtYXQpIGNvbnN0CiAgewogICAgcmV0dXJuIE1hdDN4MygKICAgICAgXzAwICogbWF0Ll8yMCArIF8wMSAqIG1hdC5fMTAgKyBfMDIgKiBtYXQuXzIwLAogICAgICBfMDAgKiBtYXQuXzIxICsgXzAxICogbWF0Ll8xMSArIF8wMiAqIG1hdC5fMjEsCiAgICAgIF8wMCAqIG1hdC5fMjIgKyBfMDEgKiBtYXQuXzEyICsgXzAyICogbWF0Ll8yMiwKICAgICAgXzEwICogbWF0Ll8yMCArIF8xMSAqIG1hdC5fMTAgKyBfMTIgKiBtYXQuXzIwLAogICAgICBfMTAgKiBtYXQuXzIxICsgXzExICogbWF0Ll8xMSArIF8xMiAqIG1hdC5fMjEsCiAgICAgIF8xMCAqIG1hdC5fMjIgKyBfMTEgKiBtYXQuXzEyICsgXzEyICogbWF0Ll8yMiwKICAgICAgXzIwICogbWF0Ll8yMCArIF8yMSAqIG1hdC5fMTAgKyBfMjIgKiBtYXQuXzIwLAogICAgICBfMjAgKiBtYXQuXzIxICsgXzIxICogbWF0Ll8xMSArIF8yMiAqIG1hdC5fMjEsCiAgICAgIF8yMCAqIG1hdC5fMjIgKyBfMjEgKiBtYXQuXzEyICsgXzIyICogbWF0Ll8yMik7CiAgfQogIC8vIG11bHRpcGx5IG1hdHJpeCB3aXRoIHZlY3RvciAtPiB2ZWN0b3IKICBWZWMzIG9wZXJhdG9yICogKGNvbnN0IFZlYzMgJnZlYykgY29uc3QKICB7CiAgICByZXR1cm4gVmVjMygKICAgICAgXzAwICogdmVjLnggKyBfMDEgKiB2ZWMueSArIF8wMiAqIHZlYy56LAogICAgICBfMTAgKiB2ZWMueCArIF8xMSAqIHZlYy55ICsgXzEyICogdmVjLnosCiAgICAgIF8yMCAqIHZlYy54ICsgXzIxICogdmVjLnkgKyBfMjIgKiB2ZWMueik7CiAgfQp9OwoKb3N0cmVhbSYgb3BlcmF0b3I8PChvc3RyZWFtICZvdXQsIGNvbnN0IE1hdDN4MyAmbWF0KQp7CiAgcmV0dXJuIG91dAogICAgPDwgbWF0Ll8yMCA8PCAiLCAiIDw8IG1hdC5fMjEgPDwgIiwgIiA8PCBtYXQuXzIyIDw8IGVuZGwKICAgIDw8IG1hdC5fMTAgPDwgIiwgIiA8PCBtYXQuXzExIDw8ICIsICIgPDwgbWF0Ll8xMiA8PCBlbmRsCiAgICA8PCBtYXQuXzIwIDw8ICIsICIgPDwgbWF0Ll8yMSA8PCAiLCAiIDw8IG1hdC5fMjI7Cn0KCmludCBtYWluKCkKewogIC8vIHNvbWUgMkQgdmVjdG9yIHNhbXBsZXMgKGZvciBhIHF1YWQpCiAgVmVjMiBxdWFkW10gPSB7CiAgICB7IDAuMGYsIDAuMGYgfSwgeyAwLjBmLCAxLjBmIH0sIHsgMS4wZiwgMS4wZiB9LCB7IDEuMGYsIDAuMGYgfQogIH07CiAgLyogU29tZXRoaW5nIGxpa2UgdGhpczoKICAgKiBeIHkKICAgKiB8CiAgICogdlszXSAtLS0tIHZbMl0KICAgKiB8ICAgICAgICAgfAogICAqIHwgICAgICAgICB8CiAgICogfCAgICAgICAgIHwKICAgKiB2WzBdIC0tLS0gdlsxXSAtLT4geAogICAqLwogIC8vIHRoZSByb3RhdGlvbiBtYXRyaXggZm9yIGlzb21ldHJpYyB2aWV3IGJ1aWxkIGJ5IG11bHRpcGx5aW5nIHRoZSByb3RhdGlvbnMKICBNYXQzeDMgbWF0SXNvID0gTWF0M3gzKEluaXRSb3RYLCBkZWdUb1JhZCgzMC4wKSkgKiBNYXQzeDMoSW5pdFJvdFksIGRlZ1RvUmFkKDQ1LjApKTsKICAvLyBwcmVwYXJlIG91dHB1dCBmb3JtYXR0aW5nCiAgY291dCA8PCBmaXhlZCA8PCBzZXRwcmVjaXNpb24oNSk7CiAgLy8gdGhlIHJvdGF0aW9uIG1hdHJpeCBmb3IgaXNvbWV0cmljIHZpZXc6CiAgY291dCA8PCAiVGhlIG1hdHJpeCBmb3IgaXNvbWV0cmljIHByb2plY3Rpb246IiA8PCBlbmRsCiAgICA8PCBtYXRJc28gPDwgZW5kbDsKICAvLyBwcmVwYXJlIG91dHB1dCBmb3JtYXR0aW5nCiAgY291dCA8PCBmaXhlZCA8PCBzZXRwcmVjaXNpb24oMyk7CiAgLy8gZG8gaXQgZm9yIGFsbCBzYW1wbGUgMkQgdmVjdG9yczoKICBjb3V0IDw8ICJJc29tZXRyaWMgcHJvamVjdGlvbiBvZiB0aGUgMmQgcXVhZDoiIDw8IGVuZGw7CiAgZm9yIChjb25zdCBWZWMyICZ2IDogcXVhZCkgewogICAgLy8gMkQgdmVjdG9yIC0+IDNEIHZlY3RvcgogICAgVmVjMyB2Xyh2LCAwLjBmKTsKICAgIC8vIHByb2plY3Qgdl8gdG8gaXNvIHZpZXcKICAgIHZfID0gbWF0SXNvICogdl87CiAgICAvLyBwcmludCB0aGUgcmVzdWx0OgogICAgY291dCA8PCB2IDw8ICIgLT4gIiA8PCB2XyA8PCBlbmRsOwogIH0KICAvLyBkb2luZyBpdCBhZ2FpbiB3aXRoIGEgM2QgY3ViZSAoY2VudGVyZWQpCiAgVmVjMyBjdWJlW10gPSB7CiAgICB7IC0wLjVmLCAtMC41ZiwgLTAuNWYgfSwgeyArMC41ZiwgLTAuNWYsIC0wLjVmIH0sIHsgKzAuNWYsICswLjVmLCAtMC41ZiB9LCB7IC0wLjVmLCArMC41ZiwgLTAuNWYgfSwKICAgIHsgLTAuNWYsIC0wLjVmLCArMC41ZiB9LCB7ICswLjVmLCAtMC41ZiwgKzAuNWYgfSwgeyArMC41ZiwgKzAuNWYsICswLjVmIH0sIHsgLTAuNWYsICswLjVmLCArMC41ZiB9CiAgfTsKICBjb3V0IDw8ICJJc29tZXRyaWMgcHJvamVjdGlvbiBvZiB0aGUgY2VudGVyZWQgM2QgY3ViZToiIDw8IGVuZGw7CiAgZm9yIChjb25zdCBWZWMzICZ2IDogY3ViZSkgewogICAgLy8gcHJvamVjdCB2IHRvIGlzbyB2aWV3CiAgICBWZWMzIHZfID0gbWF0SXNvICogdjsKICAgIC8vIHByaW50IHRoZSByZXN1bHQ6CiAgICBjb3V0IDw8IHYgPDwgIiAtPiAiIDw8IHZfIDw8IGVuZGw7CiAgfQogIC8vIGRvbmUKICByZXR1cm4gMDsKfQ==
The matrix for isometric projection:
0.61237, -0.50000, 0.61237
0.35355, 0.86603, 0.35355
0.61237, -0.50000, 0.61237
Isometric projection of the 2d quad:
( 0.000, 0.000 ) -> ( 0.000, 0.000, 0.000 )
( 0.000, 1.000 ) -> ( 0.000, 0.866, -0.500 )
( 1.000, 1.000 ) -> ( 0.707, 1.220, 0.112 )
( 1.000, 0.000 ) -> ( 0.707, 0.354, 0.612 )
Isometric projection of the centered 3d cube:
( -0.500, -0.500, -0.500 ) -> ( -0.707, -0.787, -0.362 )
( 0.500, -0.500, -0.500 ) -> ( 0.000, -0.433, 0.250 )
( 0.500, 0.500, -0.500 ) -> ( 0.000, 0.433, -0.250 )
( -0.500, 0.500, -0.500 ) -> ( -0.707, 0.079, -0.862 )
( -0.500, -0.500, 0.500 ) -> ( -0.000, -0.433, 0.250 )
( 0.500, -0.500, 0.500 ) -> ( 0.707, -0.079, 0.862 )
( 0.500, 0.500, 0.500 ) -> ( 0.707, 0.787, 0.362 )
( -0.500, 0.500, 0.500 ) -> ( -0.000, 0.433, -0.250 )