<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>visIdeal</title> 
      <link href="css/bootstrap.min.css" rel="stylesheet">
      <link href="css/BootSideMenu.css" rel="stylesheet">
      <link href="css/nouislider.min.css" rel="stylesheet">
     <style>
      canvas { width: 100%; height: 100% }
      #key {
        position: absolute;
        margin-left: 20px;
        width: 100px;
        height:100px;
        background-color: #eee;
      }
      #key .text {
        margin-top: 10px;
        clear: right;

      }
      #key .section {
        clear: both;
        margin-bottom: 10px;
        margin-top: 10px;
        width: 100%;
      }
      .key {
        margin-left: 10px;
        margin-right: 10px;
        /* margin-top: 10px; */
        /* margin-bottom: 30px; */
        float:left;
        width: 20px;
        height: 20px;
      }

      #xkey {
        background-color: green;
      }
      #ykey {
        background-color: red;
      }
      #zkey {
        background-color: blue;
      }
    </style> 
    <script type="text/javascript">
      //global variables
      //for some reason visArray is every monomial in R/I
      data = visArray;
      dataGenz = newVisArray;
    </script>
  </head> 
  <body>
  <div id="side">
          <h2>&#8202;&#8202;Menu</h2>
          <div class="list-group" id="menuList">
            </div>
            <a id="idealGens" href="#" class="list-group-item">Ideal Generators</a>
            <div id="key">
      <div class="section"><div class="key" id="xkey"></div><div class='text'>XXX axis</div></div>
      <div class="section"><div class="key" id="ykey"></div><div class='text'>YYY axis</div></div>
      <div class="section"><div class="key" id="zkey"></div><div class='text'>ZZZ axis</div></div>
    </div>
  
            <!-- we can put these options in later
            <a id="exportTikz" href="#" class="list-group-item">Generate TikZ code</a>
            <a id="endSession" href="#" class="list-group-item">End session</a>            
            -->
          </div>
        </div>



    
  <script src="js/jquery-1.11.3.min.js"></script>
  <script src="js/BootSideMenu.js"></script>
  <script src="js/d3.v3.min.js"></script>
  <script src="js/bootstrap.min.js"></script>
  <script src="js/three.min.js"></script> 
  <script src="js/underscore.js"></script> 
		

<script type="text/javascript">

    $('#side').BootSideMenu({side:"right", closeOnClick: false, width: "230px"});

    $(document).ready(function(){

    // show the ideal generators when clicked
    $("#idealGens").on("click", function(){
          $(this).html("Ideal Generators: "  + labels);
      });
    });

    var makeXYZstring = function(x,y,z) {
                if (x === 0) { xstr = ""; }
                else if (x === 1) { xstr = "x"; }
                else { xstr = "x<sup>" + x.toString() + "</sup>"; }
                if (y === 0) { ystr = ""; }
                else if (y === 1) { ystr = "y"; }
                else { ystr = "y<sup>" + y.toString() + "</sup>"; }
                if (z === 0) { zstr = ""; }
                else if (z === 1) { zstr = "z"; }
                else { zstr = "z<sup>" + z.toString() + "</sup>"; }
                xyzstr = xstr + ystr + zstr;
                return xyzstr;
        }



      var labels = []
        for (i = 0; i < dataGenz.length; i++) {
                labels.push(makeXYZstring(dataGenz[i][0],dataGenz[i][1],dataGenz[i][2]));
        }    
    </script>

    <script type="x-shader/x-vertex" id="vertexShader">

			attribute vec4 center;
			varying vec4 vCenter;

			void main() {

				vCenter = center;
				gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

			}

		</script>

		<script type="x-shader/x-fragment" id="fragmentShader">

			#extension GL_OES_standard_derivatives : enable

			varying vec4 vCenter;

			float edgeFactorTri() {

				vec3 d = fwidth( vCenter.xyz );
				vec3 a3 = smoothstep( vec3( 0.0 ), d * 1.5, vCenter.xyz );
				return min( min( a3.x, a3.y ), a3.z );

			}

			float edgeFactorQuad1() {

				vec2 d = fwidth( vCenter.xy );
				vec2 a2 = smoothstep( vec2( 0.0 ), d * 1.5, vCenter.xy );

				return min( a2.x, a2.y );

			}

			float edgeFactorQuad2() {

				vec2 d = fwidth( 1.0 - vCenter.xy );
				vec2 a2 = smoothstep( vec2( 0.0 ), d * 1.5, 1.0 - vCenter.xy );

				return min( a2.x, a2.y );
			}

			void main() {

				if ( vCenter.w == 0.0 ) {

					gl_FragColor.rgb = mix( vec3( 1.0 ), vec3( 0.2 ), edgeFactorTri() );

				} else {

					gl_FragColor.rgb = mix( vec3( 1.0 ), vec3( 0.2 ), min( edgeFactorQuad1(), edgeFactorQuad2() ) );

				}

				gl_FragColor.a = 1.0;

			}

      


		</script>

  <script> 
    var camera, scene, renderer;
    var geometry, material, mesh, ideal;
    var group;

    var targetYRotation = targetXRotation = 0;
    var targetYRotationOnMouseDown = targetXRotationOnMouseDown = 0;

    var mouseX = 0, mouseY = 0;
    var mouseXOnMouseDown = 0;
    var zoomFactor = 1;

    var windowHalfX = window.innerWidth / 2;
    var windowHalfY = window.innerHeight / 2;

    // var data = [[4, 0, 0], [0, 6, 0], [0, 0, 4]];
    // var data = [[4,0,0],[2,3,0],[1,6,1],[0,0,4],[0,8,0]];
    // var data = visArray;

	var maxX = _.max(data, function(d) { return d[0]; })[0];
    maxX = maxX == 0 ? 1 : maxX;
    
	var maxY = _.max(data, function(d) { return d[1]; })[1];
    maxY = maxY == 0 ? 1 : maxY;
    
	var maxZ = _.max(data, function(d) { return d[2]; })[2];
    maxZ = maxZ == 0 ? 1 : maxZ;
	
	var maxExponent = _.max([maxX,maxY,maxZ]);

    function newMesh(point, geometry, materials) {
      var mesh;
      if (geometry.type == "BoxGeometry") {
        mesh = new THREE.Mesh(geometry, materials);
      } else {
        mesh = new THREE.LineSegments(geometry, materials);
      }
      mesh.position.x = point[0] - 1/2;
      mesh.position.y = point[1] - 1/2;
      mesh.position.z = point[2] - 1/2;
      mesh.updateMatrix();
      return mesh;
    }

    function processCubes(data) {
      var cubes = [];
      data.forEach(function(d) {
        cubes.push([d[1],d[2],d[0]]);
      })
      return cubes;
    }

  function expand(data) {
    var cubes = [];
    // Is this a good way to add squares?
    // Probably not...
    // var maxX = _.max(data, function(d) { return d[0]; })[0];
    // maxX = maxX == 0 ? 1 : maxX;
    // var maxZ = _.max(data, function(d) { return d[2]; })[2];
    // maxZ = maxZ == 0 ? 1 : maxZ;
    console.log(maxX);
    console.log(maxZ);
    var previousMin = 1;
    // var k = 0;
    for(var i = 1; i < maxX + 1; i++) {
      for(var k = 1; k < maxZ + 1; k++) {
        // for(var k = maxZ + 1; k >0; k--) {
          var colPoints = _.filter(data, function(d) { return d[0] == (i - 1) && d[2] ==  (k - 1); });
          var maxColY = _.max(colPoints, function(d) { return d[1]; })[1];
          // console.log(maxColY);
          if(!maxColY) {
            // console.log(previousMax);
            maxColY = previousMin;
          } 
          else {
            // console.log(maxColY);
            previousMin = _.min(colPoints, function(d) { return d[1]; })[1];
          }

          console.log("max: " + maxColY);
          for(var j = maxColY ; j > 0; j--) {
            cubes.push([i,j,k]);
            // var mesh = newMesh([i,j,k], cube, material);
          }
        }
      }
      return cubes;
    }

    function init() {
      scene = new THREE.Scene();
      scene.background = new THREE.Color(0xffffff);
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
      // camera.position.set(7,10,15);
	  camera.position.set(maxExponent*2,10,15);
      camera.lookAt(new THREE.Vector3(0,2,0));

      renderer = new THREE.WebGLRenderer({antialias : true});
      // renderer = new THREE.CanvasRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);

      document.body.appendChild(renderer.domElement);

      line_material = new THREE.LineBasicMaterial({linewidth: 3});
      material = new THREE.MeshBasicMaterial({color: 0x333333});
      group = new THREE.Object3D();
      geometry = new THREE.Geometry();
      geometry.vertices.push(new THREE.Vector3(0,0,0));
      var s = 1
      var cube = new THREE.CubeGeometry( s, s, s );
      var edges = new THREE.EdgesGeometry(cube);
      var vertexShader = document.getElementById( 'vertexShader' ).textContent;
      var fragmentShader = document.getElementById( 'fragmentShader' ).textContent;

      // wireframe using gl.TRIANGLES (interpreted as quads)

      var attributesQuads = { center: { type: 'v4', boundTo: 'faceVertices', value: [] } };
      var valuesQuads = attributesQuads.center.value;

      setupAttributes( cube, valuesQuads );
      cubes_data = processCubes(data);

      cubes_data.forEach(function(cube_data) {
        var mesh = newMesh(cube_data, cube, material);
        group.add(mesh);
        mesh = newMesh(cube_data, edges, line_material);
        group.add(mesh);
      });


      /* var shape  = new THREE.Shape(points); */

      ideal = new THREE.Line(geometry, line_material);
      group.add(ideal);
      /* geometry = new THREE.CubeGeometry(1,1,1); */
      /* cube = new THREE.Mesh(geometry, material); */

      maxX = _.max(cubes_data, function(d) { return d[2] })[2];
      maxY = _.max(cubes_data, function(d) { return d[0] })[0];
      maxZ = _.max(cubes_data, function(d) { return d[1] })[1];


      var lwidth = 3;
      var lineMaterial = new THREE.LineBasicMaterial({color: 0x044000, opacity: 0.8, linewidth: lwidth });

      var lineGeometry = new THREE.Geometry();
      lineGeometry.vertices.push(new THREE.Vector3(-1, -1, -1));
      lineGeometry.vertices.push(new THREE.Vector3(-1, -1, maxX + 3));
      var line = new THREE.Line(lineGeometry, lineMaterial);
      group.add(line);
      lineMaterial = new THREE.LineBasicMaterial({color: 0xAA0000, opacity: 0.8, linewidth: lwidth });
      lineGeometry = new THREE.Geometry();
      lineGeometry.vertices.push(new THREE.Vector3(-1, -1, -1));
      lineGeometry.vertices.push(new THREE.Vector3(maxY + 3, -1,-1));
      line = new THREE.Line(lineGeometry, lineMaterial);
      group.add(line);
      lineMaterial = new THREE.LineBasicMaterial({color: 0x0000DD, opacity: 0.8, linewidth: lwidth });
      lineGeometry = new THREE.Geometry();
      lineGeometry.vertices.push(new THREE.Vector3(-1, -1, -1));
      lineGeometry.vertices.push(new THREE.Vector3(-1, maxZ + 3,-1));
      line = new THREE.Line(lineGeometry, lineMaterial);
      group.add(line);
      /* lineGeometry.vertices.push(new THREE.Vector3(10, 0, 0)); */

      var line = new THREE.Line(lineGeometry, lineMaterial);
      group.add(line);
      scene.add(group);
      /* camera.position.z = 5; */

      document.addEventListener( 'mousedown', onDocumentMouseDown, false );
      document.addEventListener( 'touchstart', onDocumentTouchStart, false );
      document.addEventListener( 'touchmove', onDocumentTouchMove, false );
      document.addEventListener( 'mousewheel', onMouseWheel, false );

      //

      window.addEventListener( 'resize', onWindowResize, false );
    }

    function setupAttributes( geometry, values ) {

      for( var f = 0; f < geometry.faces.length; f ++ ) {

        var face = geometry.faces[ f ];

        if ( face instanceof THREE.Face3 ) {

          values[ f ] = [ new THREE.Vector4( 1, 0, 0, 0 ), new THREE.Vector4( 0, 1, 0, 0 ), new THREE.Vector4( 0, 0, 1, 0 ) ];

          } else {

          values[ f ] = [ new THREE.Vector4( 1, 0, 0, 1 ), new THREE.Vector4( 1, 1, 0, 1 ), new THREE.Vector4( 0, 1, 0, 1 ), new THREE.Vector4( 0, 0, 0, 1 ) ];

        }

      }

    }


    function animate() {
      requestAnimationFrame(animate);

      render();
    }

    function render() {

      group.rotation.x = group.rotation.x += ( targetXRotation - group.rotation.x ) * 0.05;
      group.rotation.y = group.rotation.y += ( targetYRotation - group.rotation.y ) * 0.05;

      renderer.render( scene, camera );

    }

    init();
    animate();
    function onWindowResize() {

      windowHalfX = window.innerWidth / 2;
      windowHalfY = window.innerHeight / 2;

      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();

      renderer.setSize( window.innerWidth, window.innerHeight );

    }

    //

    function onDocumentMouseDown( event ) {

      //event.preventDefault();

      document.addEventListener( 'mousemove', onDocumentMouseMove, false );
      document.addEventListener( 'mouseup', onDocumentMouseUp, false );
      document.addEventListener( 'mouseout', onDocumentMouseOut, false );

      mouseXOnMouseDown = event.clientX - windowHalfX;
      mouseYOnMouseDown = event.clientY - windowHalfY;
      targetYRotationOnMouseDown = targetYRotation;
      targetXRotationOnMouseDown = targetXRotation;

    }

    function onDocumentMouseMove( event ) {

      mouseX = event.clientX - windowHalfX;
      mouseY = event.clientY - windowHalfY;

      targetYRotation = targetYRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
      targetXRotation = targetXRotationOnMouseDown + ( mouseY - mouseYOnMouseDown ) * 0.02;

    }

    function onDocumentMouseUp( event ) {

      document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
      document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
      document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
    }

    function onDocumentMouseOut( event ) {

      document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
      document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
      document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
    }

    function onDocumentTouchStart( event ) {

      if ( event.touches.length == 1 ) {

        event.preventDefault();

        mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
        targetRotationOnMouseDown = targetRotation;

      }
    }

    function onDocumentTouchMove( event ) {

      if ( event.touches.length == 1 ) {

        event.preventDefault();

        mouseX = event.touches[ 0 ].pageX - windowHalfX;
        targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;

      }
    }

    function onMouseWheel( event ) {
      event = event ? event : window.event;
      var wheelData = event.detail ? event.detail : event.wheelDelta;
      console.log(event);

      /* if ( event.touches.length == 1 ) { */

        /* 	event.preventDefault(); */

        /* 	mouseX = event.touches[ 0 ].pageX - windowHalfX; */
        /* 	targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; */

        /* } */
    }

  </script> 
</body> 
</html>
