Guest User

Untitled

a guest
Aug 11th, 2018
4
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * 4D Hypercube
  3.  */
  4.  
  5. (function(Hypercube) {
  6.  
  7.     //constants
  8.     DEFAULT_STARTING_SCALE = 2;
  9.     MIN_SCALE = 1.5;
  10.     MAX_SCALE = 10;
  11.     DEFAULT_STARTING_LINE_WIDTH = 4;
  12.  
  13.     Hypercube.Shape = function() {
  14.         return new Shape(Array.prototype.slice.call(arguments, 0));
  15.     };
  16.  
  17.     function Shape(args) {
  18.         var self        = this;
  19.         var vertices    = args[0];
  20.         var edges       = args[1];
  21.  
  22.         // Rotate relative to the original shape to avoid rounding errors, also dragons
  23.         var rotatedVertices = new Array(vertices.length);
  24.         clone_vertices();
  25.  
  26.         // This is where we store the current rotations about each axis.
  27.         var rotations = { xy: 0, xz: 0, xw: 0, yz: 0, yw: 0, zw: 0 };
  28.  
  29.         var rotation_order = {
  30.             yz: 1,
  31.             xw: 1,
  32.             yw: 1,
  33.             zw: 1,
  34.             xy: 1,
  35.             xz: 1,
  36.         };
  37.  
  38.         // Multiplication by vector rotation matrices of dimension 4
  39.         var rotate_vertex= {
  40.             xy: function(v, s, c) {
  41.                 tmp = c * v.x + s * v.y;
  42.                 v.y = -s * v.x + c * v.y;
  43.                 v.x = tmp;
  44.             },
  45.             xz: function(v, s, c) {
  46.                 tmp = c * v.x + s * v.z;
  47.                 v.z = -s * v.x + c * v.z;
  48.                 v.x = tmp;
  49.             },
  50.             xw: function(v, s, c) {
  51.                 tmp = c * v.x + s * v.w;
  52.                 v.w = -s * v.x + c * v.w;
  53.                 v.x = tmp;
  54.             },
  55.             yz: function(v, s, c) {
  56.                 tmp = c * v.y + s * v.z;
  57.                 v.z = -s * v.y + c * v.z;
  58.                 v.y = tmp;
  59.             },
  60.             yw: function(v, s, c) {
  61.                 tmp = c * v.y - s * v.w;
  62.                 v.w = s * v.y + c * v.w;
  63.                 v.y = tmp;
  64.             },
  65.             zw: function(v, s, c) {
  66.                 tmp = c * v.z - s * v.w;
  67.                 v.w = s * v.z + c * v.w;
  68.                 v.z = tmp;
  69.             }
  70.         };
  71.  
  72.         var eventCallbacks = {};
  73.  
  74.         self.getVertices = function() {
  75.             return rotatedVertices;
  76.         };
  77.  
  78.         self.getEdges = function() {
  79.             return edges;
  80.         };
  81.  
  82.         self.getRotations = function() {
  83.             return rotations;
  84.         };
  85.  
  86.         // This will copy the original shape and put a rotated version into rotatedVertices
  87.         self.rotate = function(axis, theta)  {
  88.             addToRotation(axis, theta);
  89.             apply_rotations();
  90.             triggerEventCallbacks('rotate');
  91.         };
  92.  
  93.         self.on = function(eventName, callback) {
  94.             if (eventCallbacks[eventName] === undefined) {
  95.                 eventCallbacks[eventName] = [];
  96.             }
  97.             eventCallbacks[eventName].push(callback);
  98.         };
  99.  
  100.         function triggerEventCallbacks(eventName) {
  101.             if (eventCallbacks[eventName] !== undefined) {
  102.                 for (index in eventCallbacks[eventName]) {
  103.                     eventCallbacks[eventName][index].call(self);
  104.                 }
  105.             }
  106.         }
  107.  
  108.         function addToRotation(axis, theta) {
  109.             rotations[axis] = (rotations[axis] + theta) % (2 * Math.PI);
  110.         }
  111.  
  112.         function apply_rotations() {
  113.             clone_vertices();
  114.  
  115.             for (var axis in rotation_order) {
  116.  
  117.                 var s = Math.sin(rotations[axis]);
  118.                 var c = Math.cos(rotations[axis]);
  119.  
  120.                 for (var i in vertices)
  121.                 {
  122.                     rotate_vertex[axis](rotatedVertices[i], s, c);
  123.                 }
  124.             }
  125.         }
  126.  
  127.         function clone_vertices() {
  128.             for (var i in vertices) {
  129.                 rotatedVertices[i] = {
  130.                     x: vertices[i].x,
  131.                     y: vertices[i].y,
  132.                     z: vertices[i].z,
  133.                     w: vertices[i].w
  134.                 };
  135.             }
  136.         }
  137.     }
  138.  
  139.     Hypercube.Viewport = function() {
  140.         return new Viewport(Array.prototype.slice.call(arguments, 0));
  141.     };
  142.  
  143.     function Viewport(args) {
  144.         var self    = this;
  145.         var shape   = args[0];
  146.         var canvas  = args[1][0];
  147.         var options = args[2];
  148.  
  149.         options = options || {};
  150.  
  151.         var scale = options.scale || DEFAULT_STARTING_SCALE;
  152.         var bound = Math.min(canvas.width, canvas.height) / 2;
  153.  
  154.         var context = canvas.getContext('2d');
  155.         context.lineWidth = options.lineWidth || DEFAULT_STARTING_LINE_WIDTH;
  156.         context.lineJoin = 'round';
  157.  
  158.         var start_mouse;
  159.  
  160.         self.render = function() {
  161.             var vertices = shape.getVertices();
  162.             var edges = shape.getEdges();
  163.  
  164.             context.clearRect(0, 0, canvas.width, canvas.height);
  165.  
  166.             //calculate vertices
  167.             var transformed = [];
  168.             for (var i in vertices) {
  169.                 var z_ratio = vertices[i].z / scale;
  170.                 transformed[i] = {
  171.                     x: Math.floor(canvas.width / 2 + (0.90 + z_ratio * 0.30) * bound * (vertices[i].x / scale)) + 0.5,
  172.                     y: Math.floor(canvas.height / 2 - (0.90 + z_ratio * 0.30) * bound * (vertices[i].y / scale)) + 0.5,
  173.                     z: 0.60 + 0.40 * z_ratio,
  174.                     w: 96 + Math.floor(96 * vertices[i].w / scale)
  175.                 };
  176.             }
  177.  
  178.             //render edges
  179.             for (var i in edges) {
  180.                 var x = [transformed[edges[i][0]].x, transformed[edges[i][1]].x];
  181.                 var y = [transformed[edges[i][0]].y, transformed[edges[i][1]].y];
  182.                 var z = [transformed[edges[i][0]].z, transformed[edges[i][1]].z];
  183.                 var w = [transformed[edges[i][0]].w, transformed[edges[i][1]].w];
  184.                 context.beginPath();
  185.                 context.moveTo(x[0], y[0]);
  186.                 context.lineTo(x[1], y[1]);
  187.                 context.closePath();
  188.                 var gradient = context.createLinearGradient(x[0], y[0], x[1], y[1]);
  189.                 gradient.addColorStop(0, 'rgba(0, ' + w[0] + ', 0, 1)'); //could use z for alpha
  190.                 gradient.addColorStop(1, 'rgba(0, ' + w[1] + ', 0, 1)');
  191.                 context.strokeStyle = gradient;
  192.                 context.stroke();
  193.             }
  194.  
  195.         };
  196.  
  197.         var mouseLBDown = false;
  198.  
  199.         $(document).mousedown(function(e) {
  200.             if(e.which === 1) mouseLBDown = true;
  201.         })
  202.  
  203.  
  204.         $(document).mouseup(function(e) {
  205.             if(e.which === 1) mouseLBDown = false;
  206.         })
  207.  
  208.         //Bind Events
  209.         $(document).mousemove(function(e) {
  210.  
  211.             if (mouseLBDown) {
  212.  
  213.             if (start_mouse == null) {
  214.                 start_mouse = mouseCoords(e, canvas);
  215.                 start_mouse.x -= Math.floor(canvas.width / 2);
  216.                 start_mouse.y = Math.floor(canvas.height / 2) - start_mouse.y;
  217.             }
  218.  
  219.             var current_mouse = mouseCoords(e, canvas);
  220.             current_mouse.x -= Math.floor(canvas.width / 2);
  221.             current_mouse.y = Math.floor(canvas.height / 2) - current_mouse.y;
  222.             var motion = { 'x': current_mouse.x - start_mouse.x, 'y': current_mouse.y - start_mouse.y };
  223.  
  224.             if (e.shiftKey && (e.altKey || e.ctrlKey)) {
  225.                 shape.rotate('xy', Math.PI * motion.x / bound);
  226.                 shape.rotate('zw', Math.PI * motion.y / bound);
  227.             }
  228.             else if (e.shiftKey) {
  229.                 shape.rotate('xw', Math.PI * motion.x / bound);
  230.                 shape.rotate('yw', Math.PI * motion.y / bound);
  231.             }
  232.             else {
  233.                 shape.rotate('xz', Math.PI * motion.x / bound);
  234.                 shape.rotate('yz', Math.PI * motion.y / bound);
  235.             }
  236.  
  237.             start_mouse = current_mouse;
  238.  
  239.             }
  240.  
  241.             self.render();
  242.         });
  243.  
  244.  
  245.         $(canvas)
  246.             //when the mousewheel spins reset scale and line width for a "zoom" effect
  247.             .mousewheel(function(event, delta) {
  248.                 scale += (delta / 10.0);
  249.                 if (scale < MIN_SCALE)
  250.                     scale = MIN_SCALE;
  251.                 else if (scale > MAX_SCALE)
  252.                     scale = MAX_SCALE;
  253.  
  254.                 context.lineWidth = 8 / scale;
  255.  
  256.                 self.render();
  257.             });
  258.  
  259.         var $window = $(window);
  260.  
  261.         function wResize(){
  262.             canvas.width = $window.width();
  263.             canvas.height = $window.height();
  264.             bound = Math.min(canvas.width, canvas.height) / 2;
  265.  
  266.             self.render();
  267.         }
  268.  
  269.         $window.resize(wResize);
  270.         wResize();
  271.  
  272.         function mouseCoords(e, element) { // http://answers.oreilly.com/topic/1929-how-to-use-the-canvas-and-draw-elements-in-html5/
  273.             var x;
  274.             var y;
  275.             if (e.pageX || e.pageY) {
  276.                 x = e.pageX;
  277.                 y = e.pageY;
  278.             }
  279.             else {
  280.                 x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
  281.                 y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
  282.             }
  283.             x -= element.offsetLeft;
  284.             y -= element.offsetTop;
  285.             return { 'x': x, 'y': y };
  286.         }
  287.     }
  288.  
  289. })(window.Hypersolid = window.Hypersolid || {});
  290.  
  291. $(document).ready(function(){
  292.     $('#instructions, #link-back').fadeIn(2000);
  293.  
  294.     Hypersolid.Viewport(
  295.         Hypersolid.Hypercube(),
  296.         $('#hypercube-canvas'))
  297.         .render();
  298.  
  299. });
Advertisement
Add Comment
Please, Sign In to add comment