matrefeytontias

Stereographic projection

Apr 3rd, 2016
386
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.99 KB | None | 0 0
  1. #include <n2DLib.h> // not important, that's just for display
  2. #include <math.h>
  3.  
  4. typedef struct
  5. {
  6.     float x, y;
  7. } Vec2;
  8.  
  9. typedef struct
  10. {
  11.     float x, y, z;
  12. } Vec3;
  13.  
  14. Vec3 operator+(Vec3 a, Vec3 b)
  15. {
  16.     Vec3 r;
  17.     r.x = a.x + b.x;
  18.     r.y = a.y + b.y;
  19.     r.z = a.z + b.z;
  20.     return r;
  21. }
  22.  
  23. Vec3 operator-(Vec3 a, Vec3 b)
  24. {
  25.     Vec3 r;
  26.     r.x = a.x - b.x;
  27.     r.y = a.y - b.y;
  28.     r.z = a.z - b.z;
  29.     return r;
  30. }
  31.  
  32. Vec3 operator-(Vec3 v)
  33. {
  34.     Vec3 r;
  35.     r.x = -v.x;
  36.     r.y = -v.y;
  37.     r.z = -v.z;
  38.     return r;
  39. }
  40.  
  41. Vec3 operator*(float t, Vec3 v)
  42. {
  43.     Vec3 r;
  44.     r.x = t * v.x;
  45.     r.y = t * v.y;
  46.     r.z = t * v.z;
  47.     return r;
  48. }
  49.  
  50. Vec3 operator/(Vec3 v, float t)
  51. {
  52.     Vec3 r;
  53.     r.x = v.x / t;
  54.     r.y = v.y / t;
  55.     r.z = v.z / t;
  56.     return r;
  57. }
  58.  
  59. float sqlen(Vec3 v)
  60. {
  61.     return v.x * v.x + v.y * v.y + v.z * v.z;
  62. }
  63.  
  64. float dot(Vec3 a, Vec3 b)
  65. {
  66.     return a.x * b.x + a.y * b.y + a.z * b.z;
  67. }
  68.  
  69. Vec3 rotate(Vec3 v, float angle)
  70. {
  71.     Vec3 r;
  72.     r.x = v.x;
  73.     r.y = v.y * cos(angle) + v.z * sin(angle);
  74.     r.z = -v.y * sin(angle) + v.z * cos(angle);
  75.     return r;
  76. }
  77.  
  78. Vec3 projOnSphere(Vec3 v, Vec3 center, float r)
  79. {
  80.     // Direction vector of the line from v to the center of the sphere
  81.     Vec3 u = center - v;
  82.     u = u / sqrt(sqlen(u));
  83.  
  84.     // Calculate the coefficients for the 2nd degree polynomial on t
  85.     float a = sqlen(u);
  86.     float b = 2 * dot(u, v - center);
  87.     float c = sqlen(v - center) - r * r;
  88.     float d = b * b - 4 * a * c; // is always > 0
  89.     // Actual t
  90.     float t1 = (-b - sqrt(d)) / (2 * a), t2 = (-b + sqrt(d)) / (2 * a);
  91.     // The point is always the closest intersection, even if t < 0
  92.     return min(t1, t2) * u + v;
  93. }
  94.  
  95. // v : point to project (must be on the sphere), center : of the sphere, r : radius, n : normal of the plane (must not be 0), p : a point of the plane
  96. Vec3 stereographicProj(Vec3 v, Vec3 center, float r, Vec3 _n, Vec3 p)
  97. {
  98.     // Calculate f, the point of the sphere the farthest from the plane
  99.     Vec3 n = dot(center - p, _n) > 0 ? _n : -_n;
  100.     Vec3 f = r * n + center;
  101.     // Direction vector of the line from f to v
  102.     Vec3 u = v - f;
  103.     u = u / sqrt(sqlen(u));
  104.  
  105.     // Constant of the plane's equation
  106.     float c = dot(p, n);
  107.  
  108.     // Actual t
  109.     if (dot(u, n) == 0) return v;
  110.     float t = (c - dot(f, n)) / dot(u, n);
  111.     return t * u + f;
  112. }
  113.  
  114. Vec2 spaceToScreen(Vec3 v, Vec3 camera, float zoom)
  115. {
  116.     Vec3 tv = v - camera;
  117.     Vec2 p;
  118.     p.x = tv.x * zoom / tv.z + 160;
  119.     p.y = tv.y * zoom / tv.z + 120;
  120.     return p;
  121. }
  122.  
  123. int main(int argc, char *argv[])
  124. {
  125.     Vec3 camera = { 0, 0, -100 };
  126.     Vec3 cube[] = {
  127.             { 30, 30, 30 },
  128.             { 30, -30, 30 },
  129.             { -30, -30, 30 },
  130.             { -30, 30, 30 },
  131.             { 30, 30, -30 },
  132.             { 30, -30, -30 },
  133.             { -30, -30, -30 },
  134.             { -30, 30, -30 },
  135.     };
  136.  
  137.     int lines[] = {
  138.             0, 1, 1, 2, 2, 3, 3, 0,
  139.             4, 5, 5, 6, 6, 7, 7, 4,
  140.             0, 4, 1, 5, 2, 6, 3, 7
  141.     };
  142.  
  143.     Vec3 center = { 0, 0, 0 };
  144.     float r = 20;
  145.     Vec3 u = { 0 };
  146.     float zoom = 100;
  147.     float theta = 0;
  148.     float tx;
  149.  
  150.     initBuffering("Stereographical projection");
  151.  
  152.     clearBufferB();
  153.  
  154.     while (!G_keys[SDLK_ESCAPE] && !updateScreen())
  155.     {
  156.         Vec3 tx = { sin(theta * 3.141592 / 180) * 60, 0, 0 };
  157.         constrainFrameRate(60);
  158.         clearBufferB();
  159.  
  160.         // Draw the sphere first
  161.         Vec3 test = { r, center.y, center.z };
  162.         float pr = spaceToScreen(test, camera, zoom).x - 160;
  163.         Vec2 ps = spaceToScreen(center, camera, zoom);
  164.         fillCircle(ps.x, ps.y, pr, 0xffff);
  165.        
  166.        
  167.         Vec2 pts[8];
  168.         Vec3 ppts[8];
  169.         // Draw the cube
  170.         for (int i = 0; i < 8; i++)
  171.         {
  172.             Vec3 rp = rotate(cube[i], theta * 3.141592 / 180); // rotate by theta degrees around the X axis
  173.             Vec2 sp = spaceToScreen(rp + tx, camera, zoom); // display the actual point
  174.             pts[i] = sp;
  175.             if (rp.z <= center.z || sq(sp.x - 160) + sq(sp.y - 120) >= sq(pr)) // stupid occlusion
  176.                 fillCircle(sp.x, sp.y, 1, 0x07e0);
  177.             Vec3 spherePoint = projOnSphere(rp + tx, center, r); // project on a sphere
  178.             Vec2 spp = spaceToScreen(spherePoint, camera, zoom); // display the projection
  179.             if (spherePoint.z <= center.z)
  180.                 fillCircle(spp.x, spp.y, 1, 0xf800);
  181.             drawLine(sp.x, sp.y, spp.x, spp.y, 0xf800);
  182.             Vec3 planePoint = stereographicProj(spherePoint, center, r, { 0, 1, 0 }, { 0, 80, 0 }); // project the projection on the xOz plane with y = 80
  183.             sp = spaceToScreen(planePoint, camera, zoom); // display it
  184.             ppts[i].x = sp.x;
  185.             ppts[i].y = sp.y;
  186.             ppts[i].z = planePoint.z;
  187.             fillCircle(sp.x, sp.y, 1, 0x001f);
  188.         }
  189.  
  190.         // Draw lines
  191.         for (int i = 0; i < 12; i++)
  192.         {
  193.             drawLine(pts[lines[i * 2]].x, pts[lines[i * 2]].y, pts[lines[i * 2 + 1]].x, pts[lines[i * 2 + 1]].y, 0x07e0);
  194.             if(ppts[lines[i * 2]].z - camera.z > 0 && ppts[lines[i * 2 + 1]].z - camera.z > 0) drawLine(ppts[lines[i * 2]].x, ppts[lines[i * 2]].y, ppts[lines[i * 2 + 1]].x, ppts[lines[i * 2 + 1]].y, 0x001f);
  195.         }
  196.  
  197.         theta += 2;
  198.  
  199.         // Move the sphere
  200.         if (G_keys[SDLK_LEFT]) center.x -= 2;
  201.         if (G_keys[SDLK_RIGHT]) center.x += 2;
  202.         if (G_keys[SDLK_w]) center.z += 2;
  203.         if (G_keys[SDLK_s]) center.z -= 2;
  204.         if (G_keys[SDLK_UP]) center.y -= 2;
  205.         if (G_keys[SDLK_DOWN]) center.y += 2;
  206.     }
  207.  
  208.     deinitBuffering();
  209.  
  210.     return 0;
  211. }
Add Comment
Please, Sign In to add comment