<head>
    <style> body { margin: 0; } </style>
    <title>MetaVoxel</title>
    <script src="//unpkg.com/three"></script>
    <script type="text/javascript" src="https://files.mcneel.com/rhino3dm/js/latest/rhino3dm.js"></script>
  
    <script src="../lib/js-colormaps.js"></script>
  
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="//unpkg.com/3d-force-graph"></script>
    <!-- <script src="../lib/3d-force-graph.js"></script> -->
    <script src="//unpkg.com/three-spritetext"></script>


    <script src="../visualization/geometry.js"></script>
    <script src="../visualization/drawFrep.js"></script>

    <script src="../visualization/utils.js"></script>
  </head>
  
  <body>
    <div id="3d-graph"></div>
  
    <script>

      var color1= 0xffffff; /*white*/
      var color2= '#020227';  /*kohly*/
      var color3= 0x1c5c61; /*teal*/
      var color4= "#fa6e70"; //red/orange
      var color5="#380152"; //purple
      var color6="#696767"; //grey
      var color7="#03dbfc"; //blue

      var nodes=[];
      var buildList=[];
      var offset2=12;
      var offset=offset2+8;
		  var buildSize=32;
      var gridSize=buildSize+2*(offset);
      var scale,setup;
      var voxelIndexList=[
        null,
        {
            size:1,
            list:[
                new THREE.Vector3(0,0,0),

            ]
        },
        {
            size:2,
            list:[
                new THREE.Vector3(0,0,0),
                new THREE.Vector3(0,1,0),
                new THREE.Vector3(1,0,0),
                new THREE.Vector3(1,1,0),
                new THREE.Vector3(0,0,1),
                new THREE.Vector3(0,1,1),
                new THREE.Vector3(1,0,1),
                new THREE.Vector3(1,1,1)
            ]

        },
        null,
        {
            size:4,
            list:[
                new THREE.Vector3(0,0,0),
                new THREE.Vector3(0,1,0),
                new THREE.Vector3(0,2,0),
                new THREE.Vector3(0,3,0),

                new THREE.Vector3(1,0,0),
                new THREE.Vector3(1,1,0),
                new THREE.Vector3(1,2,0),
                new THREE.Vector3(1,3,0),

                new THREE.Vector3(2,0,0),
                new THREE.Vector3(2,1,0),
                new THREE.Vector3(2,2,0),
                new THREE.Vector3(2,3,0),

                new THREE.Vector3(3,0,0),
                new THREE.Vector3(3,1,0),
                new THREE.Vector3(3,2,0),
                new THREE.Vector3(3,3,0),


                new THREE.Vector3(0,0,1),
                new THREE.Vector3(0,1,1),
                new THREE.Vector3(0,2,1),
                new THREE.Vector3(0,3,1),

                new THREE.Vector3(1,0,1),
                // new THREE.Vector3(1,1,1),
                // new THREE.Vector3(1,2,1),
                new THREE.Vector3(1,3,1),

                new THREE.Vector3(2,0,1),
                // new THREE.Vector3(2,1,1),
                // new THREE.Vector3(2,2,1),
                new THREE.Vector3(2,3,1),

                new THREE.Vector3(3,0,1),
                new THREE.Vector3(3,1,1),
                new THREE.Vector3(3,2,1),
                new THREE.Vector3(3,3,1),

                new THREE.Vector3(0,0,2),
                new THREE.Vector3(0,1,2),
                new THREE.Vector3(0,2,2),
                new THREE.Vector3(0,3,2),

                new THREE.Vector3(1,0,2),
                // new THREE.Vector3(1,1,2),
                // new THREE.Vector3(1,2,2),
                new THREE.Vector3(1,3,2),

                new THREE.Vector3(2,0,2),
                // new THREE.Vector3(2,1,2),
                // new THREE.Vector3(2,2,2),
                new THREE.Vector3(2,3,2),

                new THREE.Vector3(3,0,2),
                new THREE.Vector3(3,1,2),
                new THREE.Vector3(3,2,2),
                new THREE.Vector3(3,3,2),


                new THREE.Vector3(0,0,3),
                new THREE.Vector3(0,1,3),
                new THREE.Vector3(0,2,3),
                new THREE.Vector3(0,3,3),

                new THREE.Vector3(1,0,3),
                new THREE.Vector3(1,1,3),
                new THREE.Vector3(1,2,3),
                new THREE.Vector3(1,3,3),

                new THREE.Vector3(2,0,3),
                new THREE.Vector3(2,1,3),
                new THREE.Vector3(2,2,3),
                new THREE.Vector3(2,3,3),

                new THREE.Vector3(3,0,3),
                new THREE.Vector3(3,1,3),
                new THREE.Vector3(3,2,3),
                new THREE.Vector3(3,3,3),
                
            ]

        }

      ];
      var opacity=0.9;
      var Graph;


      $.getJSON("../json/asdf/cubeCone4.json", function(json) {
        console.log(json);
        //todo move this to other document
        scale=1/0.1875;
        var shift=gridSize/2.0;
        buildList={
            currentZIndex:0,
            maxZIndex:json.length,
            listZ:[],
            done:false,
            availablePickup:[],
            listToBuild:[]

        };

        setup={};
        setup.nodes=[];
        setup.edges=[];
        setup.viz={};
        setup.viz.colorMaps=[YlGnBu,coolwarm, winter ,jet];

        var countNodes=0;

        // todo multiply by 4 as smallest size in cubeCone is 0.25
        // y is z and z is y
        // shift z by 1 cause sacrificial layer is 0
        // shift x and y to not have negative values

        for(var i=0;i<json.length;i++){ //for each z layer bin
            buildList.listZ.push({
                    layerZ:json[i][0][0][0].origin[1]*scale+1,
                    done:false,
                    currentSizeIndex:0,
                    maxSizeIndex:json[i].length,
                    listSize:[]
                });
            for(var j=0;j<json[i].length;j++){ //for each size bin
                buildList.listZ[i].listSize.push({
                    size:json[i][j][0][0].widths[0]*scale,
                    layerZ:buildList.listZ[i].layerZ,
                    done:false,
                    currentSDFIndex:0,
                    maxSDFIndex:json[i][j].length,
                    listSDF:[]
                    
                });
                for(var k=0;k<json[i][j].length;k++){ //for each sdf bin (signed distance field)
                    buildList.listZ[i].listSize[j].listSDF.push({
                        sdfRank:k,
                        layerZ:buildList.listZ[i].layerZ,
                        size:buildList.listZ[i].listSize[j].size,
                        done:false,
                        currentCubeIndex:0,
                        maxCubeIndex:json[i][j][k].length,
                        listCubes:[]
                        
                        
                    });

                    for(var l=0;l<json[i][j][k].length;l++){ //for each cube add location (todo check if int)
                        var stockBuilt=false;
                        if(buildList.listZ[i].listSize[j].size==1){
                            stockBuilt=true;
                        }
                        buildList.listZ[i].listSize[j].listSDF[k].listCubes.push({
                            layerZ:buildList.listZ[i].layerZ,
                            size:buildList.listZ[i].listSize[j].size,
                            sdfRank:buildList.listZ[i].listSize[j].listSDF[k].sdfRank,
                            done:false,
                            stockBuilt:stockBuilt,
                            stockAssigned:false,
                            stockPickedUp:false,
                            position:new THREE.Vector3(
                                json[i][j][k][l].origin[0]*scale+shift,
                                json[i][j][k][l].origin[2]*scale+shift,
                                json[i][j][k][l].origin[1]*scale+1)
                        });
                        var nomSize=buildList.listZ[i].listSize[j].size;
                        var x=json[i][j][k][l].origin[0]*scale;
                        var y=json[i][j][k][l].origin[1]*scale;
                        var z=json[i][j][k][l].origin[2]*scale;

                        // if(true){
                        if(json[i][j][k][l].origin[2]*scale+nomSize/2.0<0){
                          setup.nodes.push({
                            id:"["+nomSize+","+x+","+y+","+z+"]",
                            position:{
                              x:x+nomSize/2.0,
                              y:y+nomSize/2.0,
                              z:z+nomSize/2.0
                            },
                            displacement:{
                              x:0,
                              y:0,
                              z:0
                            },
                            nomSize:nomSize,
                            orgNomSize:nomSize,
                            viz:opacity
                          });
                          countNodes++;

                          addEdgeHier(setup,nomSize,nomSize,x,y,z,opacity);

                          if(nomSize==2){
                            for(var ii=0;ii<voxelIndexList[2].list.length;ii++){
                              var nomSize1=1;
                              var x1=x+voxelIndexList[2].list[ii].x;
                              var y1=y+voxelIndexList[2].list[ii].y;
                              var z1=z+voxelIndexList[2].list[ii].z;
                    
                              setup.nodes.push({
                                id:"["+nomSize1+","+x1+","+y1+","+z1+"]",
                                position:{
                                  x:x1+nomSize1/2.0,
                                  y:y1+nomSize1/2.0,
                                  z:z1+nomSize1/2.0
                                },
                                displacement:{
                                  x:0,
                                  y:0,
                                  z:0
                                },
                                nomSize:nomSize1,
                                orgNomSize:nomSize,
                                viz:0.0
                              });

                              addEdgeHier(setup,nomSize1,nomSize,x1,y1,z1,0);

                            }
                          }

                          
                          if(nomSize==4){
                            for(var ii=0;ii<voxelIndexList[4].list.length;ii++){
                              var nomSize1=1;
                              var x1=x+voxelIndexList[4].list[ii].x;
                              var y1=y+voxelIndexList[4].list[ii].y;
                              var z1=z+voxelIndexList[4].list[ii].z;
                    
                              setup.nodes.push({
                                id:"["+nomSize1+","+x1+","+y1+","+z1+"]",
                                position:{
                                  x:x1+nomSize1/2.0,
                                  y:y1+nomSize1/2.0,
                                  z:z1+nomSize1/2.0
                                },
                                displacement:{
                                  x:0,
                                  y:0,
                                  z:0
                                },
                                nomSize:nomSize1,
                                orgNomSize:nomSize,
                                viz:0.0
                              });

                              addEdgeHier(setup,nomSize1,nomSize,x1,y1,z1,0);
                            }

                          }
                        }
                    }
                }
            }
        }

        // console.log(buildList);
        console.log(countNodes);
        console.log(setup);


        scale=30.0;
        var stress=0.0;

        function cone(X,Z,Y){
          X-=10;
          Y-=10;
          if(Y>0){
            return -1;
          }
          return Math.min(((16)-Z),(Math.min((Z-(0)),(((10*(16-(Z-(0)))/16)*(10*(16-(Z-(0)))/16)-((X-(0))*(X-(0))+(Y-(0))*(Y-(0))))))));
        }


        

        // Graph=drawGraph1(setup,scale);
        

        
        Graph=drawFromFrep(cone,new THREE.Vector3(0.0,0,0),false);

        
        
        

        


        


      });

      function drawGraph(setup,scale,hierarchical=true){
        function getColor(stress){
          // console.log(stress)
          var val=map(stress,setup.viz.minStress,setup.viz.maxStress,1.0,0.0);
          color=interpolateLinearly(val, setup.viz.colorMaps[setup.viz.colorMap]);
          return new THREE.Color(color[0],color[1],color[2]).getHex();

        }
        const gData = {
          nodes: setup.nodes.map(node => ({ 
            id: node.id,
            px:node.position.x*scale-scale*10,
            py:node.position.y*scale-scale,
            pz:node.position.z*scale-scale*10,
            dx:node.displacement.x*scale,
            dy:node.displacement.y*scale,
            dz:node.displacement.z*scale,
            nomSize:hierarchical? node.nomSize:node.nomSize/4.0,
            viz:node.viz,
          })),
          links: setup.edges
            .filter(edge => edge.id)
            .map(edge => ({
              source: "n"+edge.source,
              target: "n"+edge.target,
              color:getColor(edge.stress)
            }))
        };
        

        Graph = ForceGraph3D({ controlType: 'orbit' }).backgroundColor(color2)
          (document.getElementById('3d-graph'))
          .d3Force('center', null)
          .d3Force('charge', null)
          .linkWidth(hierarchical? 1.0:1.0/4.0)
          .linkOpacity(1.0)
          .nodeThreeObject(({ nomSize,viz }) => new THREE.Mesh(
              new THREE.BoxGeometry(scale*nomSize*0.9, scale*nomSize*0.9, scale*nomSize*0.9),
              new THREE.MeshLambertMaterial({
              color: color3,
              transparent: true,
              opacity: 0.9
            })
          )
          )
          .d3Force('box', () => {

            gData.nodes.forEach(node => {
              node.fx=node.px;
              node.fy=node.py;
              node.fz=node.pz;

            });
          })
          
          .cooldownTime(Infinity)
          .graphData(gData);

        //


        var helper = new THREE.GridHelper( scale*2, scale*2 );
        helper.position.y = 0;
        helper.material.opacity = 0.5;
        helper.material.transparent = true;
        helper.scale.x=2.0*scale
        helper.scale.z=2.0*scale
        Graph.scene().add(helper);

        // Graph.camera().position.y+=15*scale;
        Graph.camera().position.z-=10*scale;
        return Graph;


      }

      function drawGraph1(setup,scale,hierarchical=true){
        function getColor(stress){
          // console.log(stress)
          var val=map(stress,setup.viz.minStress,setup.viz.maxStress,1.0,0.0);
          color=interpolateLinearly(val, setup.viz.colorMaps[setup.viz.colorMap]);
          return new THREE.Color(color[0],color[1],color[2]).getHex();

        }
        const gData = {
          nodes: setup.nodes.map(node => ({ 
            id: node.id,
            px:node.position.x*scale,
            py:node.position.y*scale,
            pz:node.position.z*scale,
            dx:node.displacement.x*scale,
            dy:node.displacement.y*scale,
            dz:node.displacement.z*scale,
            nomSize:hierarchical? node.nomSize:node.nomSize/3.0,
            viz:node.viz,
          })),
          links: setup.edges
            .filter(edge => edge.id)
            .map(edge => ({
              source: edge.source,
              target: edge.target,
              color:getColor(edge.stress)
            }))
        };
        

        Graph = ForceGraph3D({ controlType: 'orbit' }).backgroundColor(color2)
          (document.getElementById('3d-graph'))
          .d3Force('center', null)
          .d3Force('charge', null)
          .linkWidth(1.0)
          .linkOpacity(1.0)
          .nodeThreeObject(({ nomSize,viz }) => new THREE.Mesh(
              new THREE.BoxGeometry(scale*nomSize*0.9, scale*nomSize*0.9, scale*nomSize*0.9),
              new THREE.MeshLambertMaterial({
              color: color3,
              transparent: true,
              opacity: viz
            })
          )
          )
          .d3Force('box', () => {

            gData.nodes.forEach(node => {
              node.fx=node.px;
              node.fy=node.py;
              node.fz=node.pz;

            });
          })
          
          .cooldownTime(Infinity)
          .graphData(gData);

        //


        var helper = new THREE.GridHelper( scale*2, scale*2 );
        helper.position.y = 0;
        helper.material.opacity = 0.5;
        helper.material.transparent = true;
        helper.scale.x=2.0*scale
        helper.scale.z=2.0*scale
        Graph.scene().add(helper);
        Graph.camera().position.z-=10*scale;
        return Graph;

        
        // Graph.camera().rotation.z+=Math.PI/2.0;


      }


      function drawConstraintBoundingBoxes(setup,scene,scale){

          //grid helper
          var helper = new THREE.GridHelper( 100, 100 );
          helper.position.y = -5.0*scale;
          helper.material.opacity = 0.5;
          helper.material.transparent = true;
          helper.scale.x=2.0*scale
          helper.scale.z=2.0*scale
          scene.add(helper);

          let supports=setup.supports;
          let loads=setup.loads;
          let mat=setup.materials;
          let disps=setup.fixedDisplacements;
          if (supports ) {
              for (var i=0;i< supports.length;i++) {
                  let s=supports[i][0];
                  drawBox(s.min,s.max,color4,scene,scale);
              }
          }
          if (loads ) {
              for (var i=0;i< loads.length;i++) {
                  let l=loads[i][0];
                  drawBox(l.min,l.max,color7,scene,scale);
              }
              
          }
          if (disps ) {
              for (var i=0;i< disps.length;i++) {
                  let l=disps[i][0];
                  drawBox(l.min,l.max,color7,scene,scale);
              }
              
          }
          if (mat ) {
              
              for (var i=0;i< mat.length;i++) {
                  let l=mat[i][0];
                  // console.log(l)
                  drawBox(l.min,l.max,color5,scene,scale);
              }
              
          }
          
      };

      function drawBox (min,max,color,scene,scale) {
          var box = new THREE.Box3(new THREE.Vector3(min.x*scale,min.y*scale,min.z*scale),new THREE.Vector3(max.x*scale,max.y*scale,max.z*scale));
          var helper = new THREE.Box3Helper( box, color );
          scene.add( helper );
          // todo add name??
      };

      function getColor(viz,stress){
          // console.log(stress)
          var val=map(stress,viz.minStress,viz.maxStress,1.0,0.0);
          color=interpolateLinearly(val, viz.colorMaps[viz.colorMap]);
          return new THREE.Color(color[0],color[1],color[2]).getHex();

      }

      function addEdgeHier(setup,nomSize,orgNomSize,x,y,z,viz){

        var source="["+nomSize+","+x+","+y+","+z+"]";

        for(var i=-1;i<2;i++){
          for(var j=-1;j<2;j++){
            for(var k=-1;k<2;k++){
              if(((i==0&&j==0)||(i==0&&k==0)||(j==0&&k==0))){ //not same voxel and no diagonals
                if(!(i==0&&j==0&&k==0)){
                  var x1=x+i*nomSize;
                  var y1=y+j*nomSize;
                  var z1=z+k*nomSize;
                  var target="["+nomSize+","+x1+","+y1+","+z1+"]";
                  var node=setup.nodes.find(v => v.id === target);
                  if(node!==undefined){
                    if(!(viz==0&&node.viz==0)){
                      setup.edges.push({ id: 'e'+setup.edges.length, source: source, target: target ,stress:0 });

                    }
                    if(orgNomSize!=node.orgNomSize){
                      setup.edges.push({ id: 'e'+setup.edges.length, source: source, target: target ,stress:0 });
                    }
                  }
                }
              }
            }
          }
        }

      }
    
    
  
  
    </script>
  </body>