Guest User

Untitled

a guest
Aug 30th, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var orthoCamera, perspectiveCamera, scene, renderer, mesh, sphere, orthoControls, perspectiveControls;
  2.  
  3. var scaleFactor;
  4. var doDraw;
  5. var direction;
  6. var lines = [[], [], [], [], [], [], [], []];
  7. var head;
  8. var done=true;
  9. var frameID;
  10. var fpsInterval;
  11.  
  12. const ZOOM = 500;
  13.  
  14. var unPauseTemp;
  15. const pause = function () {
  16.   done = true;
  17.   guiOptions.simulate.pauseUnpause = unPause;
  18.   gui.__folders.Simulate.__controllers[0].name("Go")
  19. }
  20. unPauseTemp = function () {
  21.   cancelAnimationFrame(frameID);
  22.   done = false;
  23.   guiOptions.simulate.pauseUnpause = pause;
  24.   gui.__folders.Simulate.__controllers[0].name("Pause");
  25.   startAnimating(guiOptions.simulate.fps, guiOptions.simulate.iterations)
  26. }
  27. const unPause = unPauseTemp;
  28. delete unPauseTemp;
  29.  
  30. let guiOptions = {
  31.   iteration: 0,
  32.   dimensions: {
  33.     width: 2,
  34.     height:3,
  35.     depth: 5
  36.   },
  37.   display: {
  38.     orthoCamera:true,
  39.     showOutline: true,
  40.     outlineColor: 0xffb3,
  41.     showHead: true,
  42.     headColor: 0xff00,
  43.     lineColor: 0xff0000
  44.   },
  45.   simulate: {
  46.     pauseUnpause: unPause,
  47.     reset: function () {
  48.       //remove all lines from memory
  49.       lines = [[], [], [], [], [], [], [], []];
  50.       //remove all objects from scene
  51.       while (scene.children.length > 0){scene.remove(scene.children[0])}
  52.       //put everything we need back
  53.       outline = new THREE.LineSegments(
  54.         new THREE.EdgesGeometry(
  55.           new THREE.BoxBufferGeometry(
  56.             guiOptions.dimensions.width,
  57.             guiOptions.dimensions.height,
  58.             guiOptions.dimensions.depth
  59.           )
  60.         ),
  61.         new THREE.LineBasicMaterial({color: guiOptions.display.outlineColor})
  62.       );
  63.       outline.visible=guiOptions.display.showOutline;
  64.       outline.position.set(
  65.         guiOptions.dimensions.width / 2,
  66.         guiOptions.dimensions.height / 2,
  67.         guiOptions.dimensions.depth / 2
  68.       );
  69.       scene.add(outline);
  70.       orthoControls.target.set(
  71.         guiOptions.dimensions.width / 2,
  72.         guiOptions.dimensions.height / 2,
  73.         guiOptions.dimensions.depth / 2
  74.       );
  75.       perspectiveControls.target.set(
  76.         guiOptions.dimensions.width / 2,
  77.         guiOptions.dimensions.height / 2,
  78.         guiOptions.dimensions.depth / 2
  79.       );
  80.       sphere = new THREE.Mesh(
  81.         new THREE.SphereGeometry(scaleFactor / 50, 16, 16),
  82.         new THREE.MeshBasicMaterial({color: guiOptions.display.headColor})
  83.       );
  84.       sphere.visible=guiOptions.display.showHead;
  85.       scene.add(sphere);
  86.       arrowHelper = new THREE.ArrowHelper(
  87.         new THREE.Vector3(1, 1, 1).normalize(),
  88.         new THREE.Vector3(0, 0, 0), scaleFactor / 3,
  89.         guiOptions.display.headColor
  90.       );
  91.       arrowHelper.visible=guiOptions.display.showHead;
  92.       scene.add(arrowHelper);
  93.       guiOptions.iteration = 0;
  94.       gui.__controllers[0].name(0);
  95.       head = [0, 0, 0];
  96.       direction = 0;
  97.       doDraw = true
  98.     },
  99.     fps: 60,
  100.     iterations: 0
  101.   }
  102. };
  103.  
  104. //set
  105. gui = new dat.GUI();
  106. scaleFactor = (guiOptions.dimensions.width * guiOptions.dimensions.depth * guiOptions.dimensions.height) ** (1 / 3);
  107. gui.add(guiOptions, "iteration").name(0);
  108. gui.__controllers[0].domElement.hidden = true;
  109. document.getElementsByClassName("property-name")[0].style = "background-color:#2c2c2c;color:#2fa1d6";
  110. document.getElementsByClassName("cr number")[0].style = "background-color:#2c2c2c;padding-left:82.5px;font:400 13.3333px Arial;height:17px;text-align:center";
  111. let dimensions = gui.addFolder("Dimensions");
  112. dimensions.add(guiOptions.dimensions, "width", 1).name("Width").step(1).onChange(function () {
  113.   guiOptions.dimensions.width = Math.max(.1, guiOptions.dimensions.width);
  114.   onNewDimensions();
  115. }).onFinishChange(function () {
  116.   orthoControls.target.x=      guiOptions.dimensions.width/2;
  117.   perspectiveControls.target.x=guiOptions.dimensions.width/2;
  118. });
  119. dimensions.add(guiOptions.dimensions, "height", 1).name("Height").step(1).onChange(function () {
  120.   guiOptions.dimensions.height = Math.max(.1, guiOptions.dimensions.height);
  121.   onNewDimensions();
  122. }).onFinishChange(function () {
  123.   orthoControls.target.y=      guiOptions.dimensions.height/2;
  124.   perspectiveControls.target.y=guiOptions.dimensions.height/2;
  125.  
  126. });
  127. dimensions.add(guiOptions.dimensions, "depth", 1).name("Depth").step(1).onChange(function () {
  128.   guiOptions.dimensions.depth = Math.max(.1, guiOptions.dimensions.depth);
  129.   onNewDimensions();
  130. }).onFinishChange(function () {
  131.   orthoControls.target.z=      guiOptions.dimensions.depth/2;
  132.   perspectiveControls.target.z=guiOptions.dimensions.depth/2;
  133. });
  134.  
  135. let display = gui.addFolder("Display");
  136. display.add(guiOptions.display,"orthoCamera").name("Orthographic Camera");
  137. display.add(guiOptions.display, "showOutline").name("Show box outline").onChange(function () {
  138.   outline.visible = guiOptions.display.showOutline;
  139. });
  140. display.addColor(guiOptions.display, "outlineColor").name("Outline color").onChange(function () {
  141.   outline.material.color = new THREE.Color(guiOptions.display.outlineColor);
  142. })
  143. display.add(guiOptions.display, "showHead").name("Show direction").onChange(function () {
  144.   sphere.visible = guiOptions.display.showHead;
  145.   arrowHelper.visible = guiOptions.display.showHead;
  146. });
  147. display.addColor(guiOptions.display, "headColor").name("Direction color").onChange(function () {
  148.   sphere.material.color = new THREE.Color(guiOptions.display.headColor);
  149.   arrowHelper.setColor(new THREE.Color(guiOptions.display.headColor));
  150. });
  151. display.addColor(guiOptions.display, "lineColor").name("Line color");
  152. display.open();
  153.  
  154. let simulate = gui.addFolder("Simulate");
  155. simulate.add(guiOptions.simulate, "pauseUnpause").name("Go");
  156. simulate.add(guiOptions.simulate, "reset").name("Reset");
  157. simulate.add(guiOptions.simulate, "fps", Number.MIN_VALUE).step(.1).onChange(function () {
  158.   fpsInterval = 1000 / guiOptions.simulate.fps;
  159. });
  160. simulate.add(guiOptions.simulate, "iterations", 0).step(1).name("Iterations");
  161. simulate.open();
  162.  
  163. //init rendering stuff and objects
  164.  
  165. scene = new THREE.Scene();
  166. var orthoCamera = new THREE.OrthographicCamera(
  167.   -window.innerWidth / (ZOOM / scaleFactor),
  168.   window.innerWidth / (ZOOM / scaleFactor),
  169.   window.innerHeight / (ZOOM / scaleFactor),
  170.   -window.innerHeight / (ZOOM / scaleFactor),
  171.   -Number.MAX_VALUE, Number.MAX_VALUE
  172. );
  173. var perspectiveCamera = new THREE.PerspectiveCamera(
  174.   115,
  175.   window.innerWidth / window.innerHeight,
  176.   0.0001, Number.MAX_SAFE_INTEGER
  177. );
  178. orthoCamera.position.set(
  179.   -guiOptions.dimensions.width/2,
  180.   guiOptions.dimensions.height*.75,
  181.   -guiOptions.dimensions.depth/4
  182. );
  183. perspectiveCamera.position.set(
  184.   -guiOptions.dimensions.width/2,
  185.   guiOptions.dimensions.height*.75,
  186.   -guiOptions.dimensions.depth/4
  187. );
  188.  
  189. renderer = new THREE.WebGLRenderer();
  190. renderer.setSize(window.innerWidth, window.innerHeight);
  191. document.body.appendChild(renderer.domElement);
  192. orthoControls=new THREE.TrackballControls(orthoCamera,renderer.domElement);
  193. orthoControls.dynamicDampingFactor = .15;
  194. perspectiveControls=new THREE.TrackballControls(perspectiveCamera,renderer.domElement);
  195. perspectiveControls.dynamicDampingFactor = .15;
  196.  
  197. guiOptions.simulate.reset();
  198.  
  199. window.addEventListener('resize', function () {
  200.   let width = window.innerWidth;
  201.   let height = window.innerHeight;
  202.   renderer.setSize(width, height);
  203.   orthoCamera.left = -width / (ZOOM / scaleFactor);
  204.   orthoCamera.right = width / (ZOOM / scaleFactor);
  205.   orthoCamera.top = height / (ZOOM / scaleFactor);
  206.   orthoCamera.bottom = -height / (ZOOM / scaleFactor);
  207.   orthoCamera.updateProjectionMatrix();
  208.   perspectiveCamera.aspect=width/height;
  209.   perspectiveCamera.updateProjectionMatrix();
  210.   orthoControls.update();
  211.   perspectiveControls.update()
  212. })
  213.  
  214. function onNewDimensions() {
  215.   scaleFactor = (guiOptions.dimensions.width * guiOptions.dimensions.depth * guiOptions.dimensions.height) ** (1 / 3);
  216.   scene.remove(outline, sphere, arrowHelper);
  217.   sphere = new THREE.Mesh(
  218.     new THREE.SphereGeometry(scaleFactor / 50, 16, 16),
  219.     new THREE.MeshBasicMaterial({color: guiOptions.display.headColor})
  220.   );
  221.   scene.visible=guiOptions.display.showHead;
  222.   scene.add(sphere);
  223.   arrowHelper = new THREE.ArrowHelper(
  224.     new THREE.Vector3(1, 1, 1).normalize(),
  225.     new THREE.Vector3(0, 0, 0), scaleFactor / 3,
  226.     guiOptions.display.headColor
  227.   );
  228.   arrowHelper.visible=guiOptions.display.showHead;
  229.   scene.add(arrowHelper);
  230.   outline = new THREE.LineSegments(
  231.     new THREE.EdgesGeometry(
  232.       new THREE.BoxBufferGeometry(
  233.         guiOptions.dimensions.width,
  234.         guiOptions.dimensions.height,
  235.         guiOptions.dimensions.depth
  236.       )
  237.     ),
  238.     new THREE.LineBasicMaterial({
  239.       color: guiOptions.display.outlineColor
  240.     })
  241.   );
  242.   outline.visible=guiOptions.display.showOutline;
  243.   outline.position.set(
  244.     guiOptions.dimensions.width / 2,
  245.     guiOptions.dimensions.height / 2,
  246.     guiOptions.dimensions.depth / 2
  247.   );
  248.   scene.add(outline);
  249. }
  250.  
  251. //returns the end point and new direction of the head given its current position and direction
  252. function getEndPointAndDirection(head, direction) {
  253.   const map = { 1: -1, 0: 1 };
  254.   var t, tx, ty, tz;
  255.   tx = direction & 0b100 ? head[0] : guiOptions.dimensions.width  - head[0];
  256.   ty = direction & 0b10  ? head[1] : guiOptions.dimensions.height - head[1];
  257.   tz = direction & 1     ? head[2] : guiOptions.dimensions.depth  - head[2];
  258.   t = Math.min(tx, ty, tz);
  259.  
  260.   var newDirection = direction;
  261.   newDirection = tx == t ? newDirection ^ 0b100 : newDirection;
  262.   newDirection = ty == t ? newDirection ^ 0b10  : newDirection;
  263.   newDirection = tz == t ? newDirection ^ 1     : newDirection;
  264.  
  265.   return [
  266.     [
  267.       head[0] + map[(direction & 0b100) >> 2] * t,
  268.       head[1] + map[(direction & 0b10) >> 1] * t,
  269.       head[2] + map[direction & 1] * t
  270.     ],
  271.     newDirection
  272.   ];
  273. }
  274.  
  275. function posTo0NegTo1(n) {
  276.   return !(n > 0) & 1
  277. }
  278.  
  279. //solve the equations b0+c0*t=b3+c3*u and b1+c1*t=b4*c4*u for t and u. returns t and u
  280. function solveEquations(b0, c0, b3, c3, b1, c1, b4, c4) {
  281.   const map = { 1: -1, 0: 1 }
  282.   var t;
  283.   //if no division by 0
  284.   if (map[c3] * map[c1] / map[c4] - map[c0]) {
  285.     t = (b0 - b3 - map[c3] * ((b1 - b4) / map[c4])) / (map[c3] * map[c1] / map[c4] - map[c0]);
  286.     return [
  287.       t,
  288.       (b1 - b4 + map[c1] * t) / map[c4]
  289.     ]
  290.   }
  291. }
  292.  
  293. function getIntersectionAndT(head, direction, line) {
  294.   const map = {1: -1, 0: 1};
  295.   var t, u, myCalc, theirCalc;
  296.   var dx = line[1][0] - line[0][0];
  297.   var dy = line[1][1] - line[0][1];
  298.   var dz = line[1][2] - line[0][2];
  299.   var theirDirection = 4 * posTo0NegTo1(dx) + 2 * posTo0NegTo1(dy) + posTo0NegTo1(dz);
  300.   var theirHead = line[0];
  301.  
  302.   var b0 = head[0];
  303.   var c0 = direction >> 2;
  304.   var b1 = head[1];
  305.   var c1 = (direction & 0b10) >> 1;
  306.   var b2 = head[2];
  307.   var c2 = direction & 1;
  308.   var b3 = theirHead[0];
  309.   var c3 = theirDirection >> 2;
  310.   var b4 = theirHead[1];
  311.   var c4 = (theirDirection & 0b10) >> 1;
  312.   var b5 = theirHead[2];
  313.   var c5 = theirDirection & 1;
  314.  
  315.   //this part has way too much repetitive coede but I don't know what to do to fix it
  316.   tAndU = solveEquations(b0, c0, b3, c3, b1, c1, b4, c4);
  317.   if (tAndU) {
  318.     [t, u] = tAndU;
  319.     myCalc = [
  320.       head[0] + map[direction >> 2] * t,
  321.       head[1] + map[(direction >> 1) & 1] * t,
  322.       head[2] + map[direction & 1] * t
  323.     ];
  324.     theirCalc = [
  325.       theirHead[0] + map[theirDirection >> 2] * u,
  326.       theirHead[1] + map[(theirDirection >> 1) & 1] * u,
  327.       theirHead[2] + map[theirDirection & 1] * u
  328.     ];
  329.     if (t && myCalc[0] >= 0 && myCalc[0] <= guiOptions.dimensions.width && myCalc[1] >= 0 && myCalc[1] <= guiOptions.dimensions.height && myCalc[2] >= 0 && myCalc[2] <= guiOptions.dimensions.depth && myCalc[2] == theirCalc[2]) {
  330.       return [
  331.         [
  332.           head[0] + map[direction >> 2] * t,
  333.           head[1] + map[(direction & 0b10) >> 1] * t,
  334.           head[2] + map[direction & 1] * t
  335.         ],
  336.         t
  337.       ]
  338.     }
  339.   }
  340.   tAndU = solveEquations(b0, c0, b3, c3, b2, c2, b5, c5);
  341.   if (tAndU) {
  342.     [t, u] = tAndU;
  343.     myCalc = [head[0] + map[direction >> 2] * t, head[1] + map[(direction >> 1) & 1] * t, head[2] + map[direction & 1] * t];
  344.     theirCalc = [theirHead[0] + map[theirDirection >> 2] * u, theirHead[1] + map[(theirDirection >> 1) & 1] * u, theirHead[2] + map[theirDirection & 1] * u];
  345.     if (t && myCalc[0] >= 0 && myCalc[0] <= guiOptions.dimensions.width && myCalc[1] >= 0 && myCalc[1] <= guiOptions.dimensions.height && myCalc[2] >= 0 && myCalc[2] <= guiOptions.dimensions.depth && myCalc[1] == theirCalc[1]) {
  346.       return [
  347.         [
  348.           head[0] + map[direction >> 2] * t,
  349.           head[1] + map[(direction & 0b10) >> 1] * t,
  350.           head[2] + map[direction & 1] * t
  351.         ],
  352.         t
  353.       ]
  354.     }
  355.   }
  356.   tAndU = solveEquations(b1, c1, b4, c4, b2, c2, b5, c5);
  357.   if (tAndU) {
  358.     [t, u] = tAndU;
  359.     myCalc = [head[0] + map[direction >> 2] * t, head[1] + map[(direction >> 1) & 1] * t, head[2] + map[direction & 1] * t];
  360.     theirCalc = [theirHead[0] + map[theirDirection >> 2] * u, theirHead[1] + map[(theirDirection >> 1) & 1] * u, theirHead[2] + map[theirDirection & 1] * u];
  361.     if (t && myCalc[0] >= 0 && myCalc[0] <= guiOptions.dimensions.width && myCalc[1] >= 0 && myCalc[1] <= guiOptions.dimensions.height && myCalc[2] >= 0 && myCalc[2] <= guiOptions.dimensions.depth && myCalc[0] == theirCalc[0]) {
  362.       return [
  363.         [
  364.           head[0] + map[direction >> 2] * t,
  365.           head[1] + map[(direction & 0b10) >> 1] * t,
  366.           head[2] + map[direction & 1] * t
  367.         ],
  368.         t
  369.       ]
  370.     }
  371.   }
  372. }
  373.  
  374. //does the simulation. Adds to the scene, updates relevant variables
  375. function main() {
  376.   guiOptions.iteration++;
  377.   gui.__controllers[0].name(guiOptions.iteration);
  378.   const map = { 1: -1, 0: 1 };
  379.   [endPoint, nextDirection] = getEndPointAndDirection(head, direction);
  380.   //remove parralel lines from the list of lines to be tested against
  381.   toTest = [0,1,2,3,4,5,6,7,8];
  382.   toTest.splice(direction, 1);
  383.   toTest.splice(toTest.indexOf(direction ^ 0b111), 1);
  384.  
  385.   //get all intersections
  386.   var intersections = {};
  387.   for (var theirDirection in toTest) {
  388.     for (var line in lines[toTest[theirDirection]]) {
  389.       var intersectionAndT = getIntersectionAndT(head, direction, lines[toTest[theirDirection]][line]);
  390.       if (intersectionAndT) {
  391.         var [intersection, t] = intersectionAndT
  392.       }
  393.       if (intersection && t > 0 && intersection[0] > 0 && intersection[0] < guiOptions.dimensions.width && intersection[1] > 0 && intersection[1] < guiOptions.dimensions.height && intersection[2] > 0 && intersection[2] < guiOptions.dimensions.depth) {
  394.         intersections[t] = intersection;
  395.       }
  396.     }
  397.   }
  398.   intersections[0] = head;
  399.   var lastIntersection = intersections[Object.keys(intersections)[Object.keys(intersections).length - 1]];
  400.   //i'd like to do if (!(lastIntersection==endPoint)){...}, but for some reason that doesn't work
  401.   if (!(lastIntersection[0] == endPoint[0] && lastIntersection[1] == endPoint[1] && lastIntersection[2] == endPoint[2])) {
  402.     //get the greatest key, add one, and set that to the endpoint. This is done to insure the last itnersection is actually the last intersection
  403.     intersections[Math.max(...Object.keys(intersections)) + 1] = endPoint;
  404.   }
  405.   intersections = Object.keys(intersections).reduce((a, b) => (a[b] = intersections[b], a), {});//black box. Sorts the intersections by t in ascending order
  406.   //draw and store the lines
  407.   var i = 0;
  408.   if (!doDraw) {
  409.     doDraw = true;
  410.     i = 1;
  411.   }
  412.   for (i; i + 1 < Object.keys(intersections).length; i += 2) {
  413.     lines[direction].push([
  414.       intersections[Object.keys(intersections)[i]],
  415.       intersections[Object.keys(intersections)[i + 1]]
  416.     ]);
  417.     geometry = new THREE.Geometry();
  418.     geometry.vertices.push(
  419.       new THREE.Vector3(...intersections[Object.keys(intersections)[i]])
  420.     );
  421.     geometry.vertices.push(
  422.       new THREE.Vector3(...intersections[Object.keys(intersections)[i + 1]])
  423.     );
  424.     let line = new THREE.Line(
  425.       geometry,
  426.       new THREE.LineBasicMaterial({color: guiOptions.display.lineColor})
  427.     );
  428.     scene.add(line);
  429.   }
  430.   doDraw = (Object.keys(intersections).length - i) % 2 ? doDraw : !doDraw;
  431.   head = endPoint;
  432.   arrowHelper.position.set(...head);
  433.   sphere.position.set(...head);
  434.   direction = nextDirection;
  435.   arrowHelper.setDirection(
  436.     new THREE.Vector3(
  437.       map[direction >> 2],
  438.       map[(direction >> 1) & 1],
  439.       map[direction & 1]
  440.     ).normalize()
  441.   );
  442.   //if the head has reached a corner
  443.   if ((head[0] == 0 || head[0] == guiOptions.dimensions.width) && (head[1] == 0 || head[1] == guiOptions.dimensions.height) && (head[2] == 0 || head[2] == guiOptions.dimensions.depth)) {
  444.     return true;
  445.   }
  446. }
  447.  
  448. //animates howMany iterations of the game
  449. function animate(howMany) {
  450.   //the stuff regarding time is used to render at a specific fps
  451.   now = Date.now();
  452.   elapsed = now - then;
  453.   if (elapsed > fpsInterval) {
  454.     then = now - (elapsed % fpsInterval);
  455.     if (howMany && !done) {
  456.       if (main()) {
  457.         guiOptions.simulate.pauseUnpause()
  458.       }
  459.       howMany--
  460.     }
  461.     else if (!done){
  462.       guiOptions.simulate.pauseUnpause()
  463.     }
  464.   }
  465.   frameID = requestAnimationFrame(function(){animate(howMany)});
  466.   orthoControls.update();
  467.   perspectiveControls.update();
  468.   if (guiOptions.display.orthoCamera){
  469.     renderer.render(scene, orthoCamera)
  470.   }
  471.   else{
  472.     renderer.render(scene, perspectiveCamera)
  473.   }
  474. }
  475.  
  476. //simplifies starting animations
  477. function startAnimating(fps, howMany) {
  478.   fpsInterval = 1000 / fps;
  479.   then = Date.now();
  480.   if (!howMany) {
  481.     howMany = Infinity;
  482.   }
  483.   animate(howMany);
  484. }
  485.  
  486. startAnimating(guiOptions.simulate.fps);
Advertisement
Add Comment
Please, Sign In to add comment