字母三角形(AlphabetTriangle)

字母三角形(AlphabetTriangle)

更多有趣示例 尽在小红砖社区

示例

HTML

<html lang="en">
<head>
	<title>AlphabetTriangle</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

	<!-- CSS -->
	<link type="text/css" rel="stylesheet" href="main.css">

	<!--  Three.js CDN  -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
	<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/renderers/CSS2DRenderer.js"></script>

</head>
<body>
  <!-- WEB GL RENDERING -->
	<div id="container"></div>
  <!-- MENU BAR -->
	<div id="menu">
		<button id="button_labels">ID</button>
		<button id="button_grid">GRID</button>
		<button id="button_fixed">FIXED</button>
		<button id="button_shuffle">SHUFFLE</button>
		<button id="button_config">CONFIG</button>
	</div>
  <!-- CONFIG BAR -->
	<span id="config" style="display: none;">
		Configuration
		<!-- Examples
		#01r#09r#21r#02l#03m#08m#07r#06l#14r#10r#11r#12r#13r#16l#25l#05r#17m#18l#19l#20r#24l#23r#22l#15m#04l#
		#08r#10m#21r#02l#03m#01m#07r#06r#14r#05m#11r#12r#13r#16m#25l#15l#17m#18l#19l#20r#24l#23m#22l#09l#04l#
		#08r#05l#21r#02l#03m#01m#07r#06r#14r#10m#11r#12r#13r#16m#25l#15l#17m#18l#19l#20r#24l#23m#22l#09l#04l#
		#01r#25r#16r#23m#09m#05r#06l#21r#11l#08m#10l#12r#13l#02m#19r#24m#17m#18l#03l#14r#20m#07l#15r#22r#04l#

		#12l#22m#11r#03l#15r#05l#02l#14m#20m#19l#09m#01l#06l#10r#23l#07r#17m#18l#24r#13r#08m#21r#25m#16m#04l#
		#03m#15l#05r#09r#02l#22m#01l#14m#20m#11l#19m#13r#16r#24m#23l#07r#17m#18l#10m#06r#08r#21l#25l#12l#04l#
		#01r#22r#16r#24m#10l#13r#12l#11m#04m#14l#20l#23r#19l#02r#06m#08m#15r#07l#09r#03m#05l#17r#21m#25l#18m#
		#01r#22r#16r#24m#10l#13r#09r#15m#02r#25r#23m#12r#07m#21l#19l#08m#18r#04r#05r#11r#03l#06l#14l#20l#17r#
		#01r#22r#16r#24m#10l#13r#21m#11r#03m#07m#17r#02r#12m#25r#06r#23l#18r#19l#08l#09m#04m#14r#20m#15m#05m#
		-->
		<input id="input_config" type="text" style="margin-left: 10px; width: 600px;" value="">
		<button id="copy_config">COPY</button>
		<button id="delete_config">DELETE</button>
	</span>
  <!--  AlphabetTriangle Code  -->
	<script src="figures.js"></script>
	<script src="figureBuilder.js"></script>
  <script src="main.js"></script>
</body>
</html>

CSS

#stats {
	position: absolute;
	top: 20px;
	width: 100%;
	text-align: center;
}
#menu {
	position: absolute;
	bottom: 20px;
	width: 100%;
	text-align: center;
	background-color: rgba(70,255,255,0.12);
	color: rgba(127,255,255,0.75);
	font-family: futurama;
}
#config {
	position: absolute;
	top: 20px;
	width: 100%;
	text-align: center;
	background-color: rgba(70,255,255,0.12);
	color: rgba(127,255,255,0.75);
	font-family: futurama;
}
button {
	color: rgba(127,255,255,0.7);
	background: transparent;
	outline: 1px solid rgba(127,255,255,0.75);
	border: 0px;
	padding: 5px 10px;
	cursor: pointer;
	z-index: 100;
}
button:hover {
	background-color: rgba(255,255,255,0.5);
}
button:active {
	color: #000000;
	background-color: rgba(0,255,255,0.75);
}
.label {
	color: #FFF;
	font-family: futurama;
	padding: 2px;
	font-size: 10px;
	background: rgba( 0, 0, 0, .6 );
}

JS

///////////////////////////////////////////////////////////////////////////
// CLASS Figure         																     //////////////
// containing all 25 figures         												 //////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Figure {
  constructor() {
    this.figures = new Array(26);
    for(var i = 0; i<26; i+=1){
      this.figures[i] = new Array(2);
    }

    this.figures[ 0][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,0,0,0,0,0,
                          0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 1][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            1,1,1,1,1,0,0,
                          0,1,1,1,1,1,1,0,0,
                        0,0,0,1,1,1,1,1,1,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 2][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,0,0,0,0,1,
                          0,0,0,0,0,0,1,1,1,
                        0,0,0,0,0,0,0,1,1,1,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]

    this.figures[ 3][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            1,0,0,0,0,0,0,
                          0,1,1,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 4][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            1,0,0,0,0,0,0,
                          1,1,0,0,0,0,0,0,0,
                        1,1,1,1,1,1,1,1,1,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 5][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,0,0,0,0,0,
                          0,0,0,0,0,0,0,0,0,
                        0,0,1,1,1,1,1,1,1,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 6][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,1,1,1,1,1,
                          0,0,1,1,1,1,1,1,0,
                        0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 7][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,0,1,1,1,1,
                          1,1,1,1,1,1,1,1,0,
                        0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 8][0] = [       0,
                                0,0,0,
                              1,1,1,1,1,
                            1,1,1,1,1,1,0,
                          0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[ 9][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,1,1,1,1,1,
                          0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[10][0] = [       0,
                                0,0,0,
                              1,0,0,0,0,
                            1,1,0,0,0,0,0,
                          0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[11][0] = [       0,
                                0,0,0,
                              0,0,0,0,1,
                            0,0,0,0,0,1,1,
                          0,0,1,0,0,0,0,0,0,
                        0,0,1,1,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[12][0] = [       0,
                                1,0,0,
                              1,1,0,0,0,
                            1,1,0,0,0,0,0,
                          1,1,1,0,0,0,0,0,0,
                        1,1,1,1,0,0,0,0,1,0,0,
                      0,0,0,0,0,0,0,0,1,1,0,0,0
    ]
    this.figures[13][0] = [       0,
                                0,0,0,
                              1,1,1,1,1,
                            0,1,1,1,1,1,1,
                          1,0,0,0,0,0,0,0,0,
                        0,1,1,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[14][0] = [       0,
                                1,1,1,
                              0,1,1,1,1,
                            1,1,1,1,1,1,1,
                          1,1,1,1,0,0,0,0,0,
                        1,1,1,1,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[15][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,1,0,0,0,0,
                          0,0,1,1,0,0,0,0,0,
                        0,0,1,1,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[16][0] = [       0,
                                0,0,0,
                              1,1,1,1,1,
                            1,1,1,1,1,1,0,
                          1,1,1,1,1,1,0,0,0,
                        1,1,1,1,1,1,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[17][0] = [       0,
                                0,0,0,
                              0,0,1,1,1,
                            0,0,1,1,1,1,0,
                          0,0,1,1,1,1,0,0,0,
                        0,0,1,1,1,1,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[18][0] = [       0,
                                0,0,0,
                              1,0,0,0,0,
                            1,1,0,0,0,0,0,
                          1,1,0,0,0,0,0,0,0,
                        1,1,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[19][0] = [       0,
                                0,0,0,
                              1,0,0,0,0,
                            1,1,1,0,0,0,0,
                          1,1,0,0,1,0,0,0,0,
                        0,1,1,0,1,1,1,0,0,0,0,
                      0,0,0,0,0,1,1,1,1,0,0,0,0
    ]
    this.figures[20][0] = [       0,
                                1,0,0,
                              1,1,0,0,0,
                            1,1,0,0,0,0,0,
                          0,0,1,1,1,0,0,0,0,
                        1,0,1,1,1,1,1,0,0,0,0,
                      0,0,0,1,1,1,1,1,1,0,0,0,0
    ]
    this.figures[21][0] = [       0,
                                1,0,0,
                              1,1,1,0,0,
                            1,1,1,1,0,0,0,
                          1,1,1,1,0,0,0,0,0,
                        0,1,1,1,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0
    ]
    this.figures[22][0] = [       0,
                                0,0,0,
                              0,0,0,0,0,
                            0,0,1,0,0,0,0,
                          0,0,0,1,1,0,0,0,0,
                        0,0,0,0,0,1,1,0,0,0,0,
                      0,0,0,0,0,0,0,1,1,0,0,0,0
    ]
    this.figures[23][0] = [       0,
                                0,0,0,
                              0,0,0,0,1,
                            0,0,0,0,1,1,1,
                          0,0,0,0,1,1,1,1,1,
                        0,0,0,0,0,1,1,1,1,1,0,
                      0,0,0,0,0,0,0,1,1,1,0,0,0
    ]
    this.figures[24][0] = [       0,
                                0,0,0,
                              1,0,0,0,0,
                            0,1,1,0,0,0,0,
                          0,0,0,1,1,0,0,0,0,
                        0,0,0,0,0,1,1,0,0,0,0,
                      0,0,0,0,0,0,0,1,1,0,0,0,0
    ]
    this.figures[25][0] = [       0,
                                1,0,0,
                              1,1,1,0,0,
                            0,1,1,1,1,0,0,
                          0,0,0,1,1,1,1,0,0,
                        0,0,0,0,0,1,1,1,1,0,0,
                      0,0,0,0,0,0,0,1,1,1,0,0,0
    ]

    this.figures[ 0][1] = "EMPTY";
    this.figures[ 1][1] = "tg";
    this.figures[ 2][1] = "tj";
    this.figures[ 3][1] = "lg";
    this.figures[ 4][1] = "kg/tp"
    this.figures[ 5][1] = "tq";
    this.figures[ 6][1] = "lj";
    this.figures[ 7][1] = "hg/kj";
    this.figures[ 8][1] = "fg";
    this.figures[ 9][1] = "hj";
    this.figures[10][1] = "dg";
    this.figures[11][1] = "fj/lp";
    this.figures[12][1] = "bg/kp/lq/ty";
    this.figures[13][1] = "dj/kq";
    this.figures[14][1] = "bj/hp";
    this.figures[15][1] = "hq";
    this.figures[16][1] = "fp";
    this.figures[17][1] = "fq";
    this.figures[18][1] = "dp";
    this.figures[19][1] = "dq/ly";
    this.figures[20][1] = "bp/ky";
    this.figures[21][1] = "bq";
    this.figures[22][1] = "hy";
    this.figures[23][1] = "fy";
    this.figures[24][1] = "dy";
    this.figures[25][1] = "by";
  }

    rotate(id){
      var o = this.figures[id][0];
      var r = [
                                                    o[48],
                                              o[35],o[47],o[46],
                                        o[24],o[34],o[33],o[45],o[44],
                                  o[15],o[23],o[22],o[32],o[31],o[43],o[42],
                            o[ 8],o[14],o[13],o[21],o[20],o[30],o[29],o[41],o[40],
                      o[ 3],o[ 7],o[ 6],o[12],o[11],o[19],o[18],o[28],o[27],o[39],o[38],
                o[ 0],o[ 2],o[ 1],o[ 5],o[ 4],o[10],o[ 9],o[17],o[16],o[26],o[25],o[37],o[36]
      ]
      return r;
    }

    getFigure(id, rot, flip){
      var figure = this.figures[id][0];
      if(rot == -1){
        figure = this.rotate(id);
      }
      if(rot ==  1){
        figure = this.rotate(id);
        figure = this.rotate(id);
      }
      return figure;
    }

    getFigureName(id){
      var name = this.figures[id][1];
      return name;
    }
  }


///////////////////////////////////////////////////////////////////////////
// CLASS FigureBuilder         															 //////////////
// organize figures in list-form and pyramide-form     			 //////////////
// create Mesh-Data                                          //////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class FigureBuilder {
  constructor(size, f_color, bg_color) {
    var tri_height      =  866025403784;
    var tri_height      = tri_height;
    var tri_side        = 1000000000000;
    var tri_side_half   = tri_side/2;
    this.tri            = new THREE.Vector2();
    this.tri.x          = tri_side_half;
    this.tri.y          = tri_height;
    this.tri.normalize();

    this.SIZE     = size * 25/100;
    this.F_COLOR  = f_color;
    this.BG_COLOR = bg_color;

    //Construction of 1 single figure out of alternating triangles
    this.idMap = [
                                                                               [0,0,0],
                                                                      [1,0,0], [1,0,1], [1,1,0],
                                                             [2,0,0], [2,0,1], [2,1,0], [2,1,1], [2,2,0],
                                                    [3,0,0], [3,0,1], [3,1,0], [3,1,1], [3,2,0], [3,2,1], [3,3,0],
                                           [4,0,0], [4,0,1], [4,1,0], [4,1,1], [4,2,0], [4,2,1], [4,3,0], [4,3,1], [4,4,0],
                                  [5,0,0], [5,0,1], [5,1,0], [5,1,1], [5,2,0], [5,2,1], [5,3,0], [5,3,1], [5,4,0], [5,4,1], [5,5,0],
                         [6,0,0], [6,0,1], [6,1,0], [6,1,1], [6,2,0], [6,2,1], [6,3,0], [6,3,1], [6,4,0], [6,4,1], [6,5,0], [6,5,1], [6,6,0],
                [7,0,0], [7,0,1], [7,1,0], [7,1,1], [7,2,0], [7,2,1], [7,3,0], [7,3,1], [7,4,0], [7,4,1], [7,5,0], [7,5,1], [7,6,0], [7,6,1], [7,7,0]
    ]

    this.flippedSlots = [3,6,8,11,13,15,18,20,22,24];

    this.figure_collection  = new Figure();

    this.figurePositions    = this.createFigurePositions();
    this.figureRotations	  = this.createFigureRotations();
    this.slotToPositionMap  = this.createSlotToPositionMap();
    this.positionMapForList = this.createPositionMapForList();
    this.listOfFigures      = this.createListOfFigures();
    this.pyramideOfFigures  = this.createPyramideOfFigures();
  }

  //Returns:  [(x1,y1),(x2,y2),(x2,y2)]
  getTriangleCoords(row, col, mir, size, flip){
    var vector_l = new THREE.Vector2();
    var vector_r = new THREE.Vector2();
    var vector_s = new THREE.Vector2();

    var point_1 = new THREE.Vector2();
    var point_2 = new THREE.Vector2();
    var point_3 = new THREE.Vector2();

    vector_l.x  = -this.tri.x*size*flip;
    vector_l.y  = -this.tri.y*size*flip;
    vector_r.x  =  this.tri.x*size*flip;
    vector_r.y  = -this.tri.y*size*flip;
    vector_s.x  = 2*this.tri.x*size*flip;
    vector_s.y  = 0*flip;

    point_1.x   = vector_l.x*row + vector_s.x*col;                             //Top            (or if mirrored)    Left Top
    point_1.y   = vector_l.y*row + vector_s.y*col;
    point_2.x   = point_1.x+vector_l.x  + (vector_s.x-vector_l.x)*mir;         //Left Bottom    (or if mirrored)    Right Top
    point_2.y   = point_1.y+vector_l.y  + (vector_s.y-vector_l.y)*mir;
    point_3.x   = point_1.x+vector_r.x;                                        //Right Bottom   (or if mirrored)    Bottom
    point_3.y   = point_1.y+vector_r.y;

  var points  = [point_1, point_2, point_3];
  return points;
}

//returns triangles[ triangle1, triangle2, triangle3, ...  ]
//with     triangle[ x1,y1, x2,y2, x3,y3 , color ]
createFigure(fig_id, size, x, y, rot, flip){
  var triangles   = [];

  var figure     = this.figure_collection.getFigure(fig_id, rot, flip);
  var vector_pos = new THREE.Vector2();
  vector_pos.x   = x;
  vector_pos.y   = y;
  var vector_h   = new THREE.Vector2();
  vector_h.x     = 0;
  vector_h.y     = this.tri.y*7*size;

  var tri_center_vector = new THREE.Vector2();
  tri_center_vector.x = 0;
  tri_center_vector.y = (0 + vector_h.y + vector_h.y)/3;

  for (var id = 0; id < 49; id++) {
    var idMapEl = this.idMap[id];
    var points  = this.getTriangleCoords(idMapEl[0],idMapEl[1],idMapEl[2], size, flip);
    var point1 = new THREE.Vector2();
    var point2 = new THREE.Vector2();
    var point3 = new THREE.Vector2();

    // tri_center_vector centers the Figure to its barycenter
    if(flip==1){
      point1.x = points[0].x + vector_pos.x;
      point1.y = points[0].y + vector_pos.y + tri_center_vector.y;
      point2.x = points[1].x + vector_pos.x;
      point2.y = points[1].y + vector_pos.y + tri_center_vector.y;
      point3.x = points[2].x + vector_pos.x;
      point3.y = points[2].y + vector_pos.y + tri_center_vector.y;
    }else{
      point1.x = points[0].x + vector_pos.x;
      point1.y = points[0].y + vector_pos.y - tri_center_vector.y;
      point2.x = points[1].x + vector_pos.x;
      point2.y = points[1].y + vector_pos.y - tri_center_vector.y;
      point3.x = points[2].x + vector_pos.x;
      point3.y = points[2].y + vector_pos.y - tri_center_vector.y;
    }

    var value = figure[id];
    var color = this.F_COLOR;
    if(value == 0){ color = this.BG_COLOR; }

    var triangle = [];
    triangle.push(point1.x);
    triangle.push(point1.y);
    triangle.push(point2.x);
    triangle.push(point2.y);
    triangle.push(point3.x);
    triangle.push(point3.y);
    triangle.push(color);

    triangles.push(triangle);
  }
  return triangles;
}

createOutline(size, x, y, rot, flip){
  var triangles   = [];

  var vector_pos = new THREE.Vector2();
  vector_pos.x   = x;
  vector_pos.y   = y;
  var vector_h   = new THREE.Vector2();
  vector_h.x     = 0;
  vector_h.y     = this.tri.y*7*size;
  var side       = this.tri.x*3.5;

  var tri_center_vector = new THREE.Vector2();
  tri_center_vector.x = 0;
  tri_center_vector.y = (0 + vector_h.y + vector_h.y)/3;

  var idMapEl = this.idMap[0];
  var points  = this.getTriangleCoords(idMapEl[0],idMapEl[1],idMapEl[2], size*7, flip);
  var point1 = new THREE.Vector2();
  var point2 = new THREE.Vector2();
  var point3 = new THREE.Vector2();

  // tri_center_vector centers the Figure to its barycenter
  if(flip==1){
    point1.x = points[0].x + vector_pos.x;
    point1.y = points[0].y + vector_pos.y + tri_center_vector.y;
    point2.x = points[1].x + vector_pos.x;
    point2.y = points[1].y + vector_pos.y + tri_center_vector.y;
    point3.x = points[2].x + vector_pos.x;
    point3.y = points[2].y + vector_pos.y + tri_center_vector.y;
  }else{
    point1.x = points[0].x + vector_pos.x;
    point1.y = points[0].y + vector_pos.y - tri_center_vector.y;
    point2.x = points[1].x + vector_pos.x;
    point2.y = points[1].y + vector_pos.y - tri_center_vector.y;
    point3.x = points[2].x + vector_pos.x;
    point3.y = points[2].y + vector_pos.y - tri_center_vector.y;
  }

  var color = 0.90;

  var triangle = [];
  triangle.push(point1.x);
  triangle.push(point1.y);
  triangle.push(point2.x);
  triangle.push(point2.y);
  triangle.push(point3.x);
  triangle.push(point3.y);
  triangle.push(color);
  triangles.push(triangle);

  return triangles;
}

//returns  figures[ triangles1, triangles2, triangles3, ...  ]
//with     triangles[ triangle1, triangle2, triangle3, ...  ]
//with     triangle[ x1,y1, x2,y2, x3,y3 , color ]
createListOfFigures(){ //Local Positions for each Figure -> must be transformed to right positions
var figure_list = [];
var center_x     = 0;
var center_y     = 0;
for(var id = 1; id <= 25; id++){
  figure_list.push(this.createFigure( id, this.SIZE, center_x, center_y, 0, 1));
}
return figure_list;
}

createPositionMapForList(){
var positionMapForList = new Array(25);
var center_x     = -4*8*this.SIZE / 2;
var center_y     = 4*8*this.SIZE / 2;
for(var fig_id = 1; fig_id <= 25; fig_id++){
   positionMapForList[fig_id-1] = [center_x + ((fig_id-1)%5) * 8 * this.SIZE, center_y - (parseInt((fig_id-1)/5)) * 8 * this.SIZE, 0];
}
return positionMapForList;
}

//Pyramide of Figures
createPyramideOfFigures(){
var figure_pyramide = new Array(25);
for(var id = 1; id <= 25; id++){
  var layers = new Array();
  layers.push( this.createFigure( this.getFigureForSlot(id), this.SIZE, 0, 0, this.getFigureRotation(id), 1) );
  layers.push( this.createOutline( this.SIZE, 0, 0, this.getFigureRotation(id), 1) );
  figure_pyramide[id-1] = layers;
}
return figure_pyramide;
}

createSlotToPositionMap(){
var side         = 7*(this.tri.x)*this.SIZE;
var fside        = 2*side;
var height       = 7*(this.tri.y)*this.SIZE;
var flipoffset   = -(0 + height + height)/3 + height;
var center_x     = 0;
var center_y     = 5*height/2;
var slotToPositionMap = new Array(25);
slotToPositionMap[ 0] = [ center_x - side*0 + fside*0  , center_y - height*0 ]; // #row 0   #Slot 1
slotToPositionMap[ 1] = [ center_x - side*1 + fside*0  , center_y - height*1 ]; // #row 1   #Slot 2
slotToPositionMap[ 3] = [ center_x - side*1 + fside*1  , center_y - height*1 ]; //          #Slot 4
slotToPositionMap[ 4] = [ center_x - side*2 + fside*0  , center_y - height*2 ]; // #row 2   #Slot 5
slotToPositionMap[ 6] = [ center_x - side*2 + fside*1  , center_y - height*2 ]; //          #Slot 7
slotToPositionMap[ 8] = [ center_x - side*2 + fside*2  , center_y - height*2 ]; //          #Slot 9
slotToPositionMap[ 9] = [ center_x - side*3 + fside*0  , center_y - height*3 ]; // #row 3   #Slot 10
slotToPositionMap[11] = [ center_x - side*3 + fside*1  , center_y - height*3 ]; //          #Slot 12
slotToPositionMap[13] = [ center_x - side*3 + fside*2  , center_y - height*3 ]; //          #Slot 14
slotToPositionMap[15] = [ center_x - side*3 + fside*3  , center_y - height*3 ]; //          #Slot 16
slotToPositionMap[16] = [ center_x - side*4 + fside*0  , center_y - height*4 ]; // #row 4   #Slot 17
slotToPositionMap[18] = [ center_x - side*4 + fside*1  , center_y - height*4 ]; //          #Slot 19
slotToPositionMap[20] = [ center_x - side*4 + fside*2  , center_y - height*4 ]; //          #Slot 21
slotToPositionMap[22] = [ center_x - side*4 + fside*3  , center_y - height*4 ]; //          #Slot 23
slotToPositionMap[24] = [ center_x - side*4 + fside*4  , center_y - height*4 ]; //          #Slot 25
//#MIRROR
slotToPositionMap[ 2] = [ center_x - side*1 +  side*1  , center_y - height*1 + flipoffset ]; // #row 1   #Slot 3
slotToPositionMap[ 5] = [ center_x - side*2 +  side*1  , center_y - height*2 + flipoffset ]; // #row 2   #Slot 6
slotToPositionMap[ 7] = [ center_x - side*2 +  side*3  , center_y - height*2 + flipoffset ]; //          #Slot 8
slotToPositionMap[10] = [ center_x - side*3 +  side*1  , center_y - height*3 + flipoffset ]; // #row 3   #Slot 11
slotToPositionMap[12] = [ center_x - side*3 +  side*3  , center_y - height*3 + flipoffset ]; //          #Slot 13
slotToPositionMap[14] = [ center_x - side*3 +  side*5  , center_y - height*3 + flipoffset ]; //          #Slot 15
slotToPositionMap[17] = [ center_x - side*4 +  side*1  , center_y - height*4 + flipoffset ]; // #row 4   #Slot 18
slotToPositionMap[19] = [ center_x - side*4 +  side*3  , center_y - height*4 + flipoffset ]; //          #Slot 20
slotToPositionMap[21] = [ center_x - side*4 +  side*5  , center_y - height*4 + flipoffset ]; //          #Slot 22
slotToPositionMap[23] = [ center_x - side*4 +  side*7  , center_y - height*4 + flipoffset ]; //          #Slot 24

return slotToPositionMap;
}

slotXPosition(slot){ return this.slotToPositionMap[slot-1][0]; }
slotYPosition(slot){ return this.slotToPositionMap[slot-1][1]; }
getFigureForSlot(slot){ return this.figurePositions[slot-1]; }
setFigureForSlot(slot, fig_id){ this.figurePositions[slot-1] = fig_id; }
getFigureRotation(fig_id){ return this.figureRotations[fig_id-1]; }
setFigureRotation(fig_id, fig_rot){ this.figureRotations[fig_id-1] = fig_rot; }
getIfFlipped(slot){ return this.flippedSlots.includes(slot); }

getSlotForFigure(fig_id){
for(var slot = 1; slot<=25; slot+=1){
  if(this.getFigureForSlot(slot) == fig_id){
    return slot;
  }
}
return 1; //ERROR
}

rotateFigure(slot){
var rot = this.getFigureRotation(slot);
rot -= 1;
if(rot == -2){ rot = 1; }
this.setFigureRotation(slot,rot);
}

switchSlotFigures(slot1, slot2){
var sf1 = this.getFigureForSlot(slot1);
var sf2 = this.getFigureForSlot(slot2);
this.setFigureForSlot(slot1, sf2);
this.setFigureForSlot(slot2, sf1);
}

//https://stackoverflow.com/questions/2464902/determine-if-a-point-is-inside-a-triangle-formed-by-3-points-with-given-latitude
pointInTriange(P, A, B, C) {
// Compute vectors
function vec(from, to) {  return [to[0] - from[0], to[1] - from[1]];  }
var v0 = vec(A, C);
var v1 = vec(A, B);
var v2 = vec(A, P);
// Compute dot products
function dot(u, v) {  return u[0] * v[0] + u[1] * v[1];  }
var dot00 = dot(v0, v0);
var dot01 = dot(v0, v1);
var dot02 = dot(v0, v2);
var dot11 = dot(v1, v1);
var dot12 = dot(v1, v2);
// Compute barycentric coordinates
var invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// Check if point is in triangle
return (u >= 0) && (v >= 0) && (u + v < 1);
}

getCorners(slot) {
//var corners = [[0.0, 0.0],[0.5, 0.0],[0.0, 0.5]];
var cx = this.slotXPosition(slot);
var cy     = this.slotYPosition(slot);
var side   = 7*(this.tri.x)*this.SIZE;
var fside  = 2*side;
var height = 7*(this.tri.y)*this.SIZE;
var tri_center_vector = new THREE.Vector2();
//tri_center_vector.x = 0;
//tri_center_vector.y = (0 + height + height)/3;
tri_center_vector.y = 0;
var x1 = 0 + cx;
var y1 = 0 + cy + tri_center_vector.y;
var x2 = -fside + cx;
var y2 = height + cy + tri_center_vector.y;
var x3 =  fside + cx;
var y3 = height + cy + tri_center_vector.y;

var corners = [[x1,y1],[x2,y2],[x3,y3]];
return corners;
}

getSlotForXY(x,y) {
for(var slot = 1; slot <= 25; slot += 1){
  var P = [x, y];
  var corners = this.getCorners(slot);
  var A = [corners[0][0],corners[0][1]];
  var B = [corners[1][0],corners[1][1]];
  var C = [corners[2][0],corners[2][1]];
  if(this.pointInTriange(P, A, B, C)){
    return slot;
  }
}
return null;
}

createFigurePositions(){
var p01 =  1; var p02 =  2; var p03 =  3; var p04 =  4; var p05 =  5;
var p06 =  6; var p07 =  7; var p08 =  8; var p09 =  9; var p10 = 10;
var p11 = 11; var p12 = 12; var p13 = 13; var p14 = 14; var p15 = 15;
var p16 = 16; var p17 = 17; var p18 = 18; var p19 = 19; var p20 = 20;
var p21 = 21; var p22 = 22; var p23 = 23; var p24 = 24; var p25 = 25;

var FigurePositions = [
                              p01,
                          p02,p03,p04,
                      p05,p06,p07,p08,p09,
                  p10,p11,p12,p13,p14,p15,p16,
              p17,p18,p19,p20,p21,p22,p23,p24,p25
];

return FigurePositions;
}

setConfiguration(positions, rotations){
this.figurePositions = positions;
this.figureRotations = rotations;
}

getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}

getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}

shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
  // Pick a remaining element...
  randomIndex = Math.floor(Math.random() * currentIndex);
  currentIndex -= 1;
  // And swap it with the current element.
  temporaryValue = array[currentIndex];
  array[currentIndex] = array[randomIndex];
  array[randomIndex] = temporaryValue;
}
return array;
}

setRandomConfiguration(){
var ids = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
this.figurePositions = this.shuffle(ids);
}

permuteConfiguration(){
}

createFigureRotations(){
var figureRotations = new Array();
for(var i = 0; i<25; i+=1){
  figureRotations.push(0);
}
return figureRotations;
}

getCoord(array_ref, fig_id, layer, triangle_index, coord_index){
  var coord;
  if(array_ref==0){ coord = this.listOfFigures[fig_id-1][triangle_index][coord_index]; }
  if(array_ref==1){ coord = this.pyramideOfFigures[fig_id-1][layer][triangle_index][coord_index]; }
  return parseFloat(coord);
}

getName(fig_id){
 return this.figure_collection.getFigureName(fig_id);
}

//Mesh_Group 0 -> List of Figures
//Mesh_Group 1 -> Pyramide of Figures - Grid
//Mesh_Group 2 -> Pyramide of Figures - Outline
toPositionBuffer(fig_id, mesh_group){
var triangles, array_ref, layer;
if(mesh_group == 0){ triangles = 49; array_ref = 0; layer = null;}
if(mesh_group == 1){ triangles = 49; array_ref = 1; layer = 0;}
if(mesh_group == 2){ triangles = 1;  array_ref = 1; layer = 1;}
var positions = new Float32Array( triangles * 3 * 3 );
for ( var t = 0; t < triangles; t += 1 ) {
  var i = t*9;
  positions[ i + 0 ] = this.getCoord(array_ref, fig_id, layer, t, 0); //Point 1 -> x
  positions[ i + 1 ] = this.getCoord(array_ref, fig_id, layer, t, 1); //Point 1 -> y
  positions[ i + 2 ] = parseFloat(0);                                 //Point 1 -> z
  positions[ i + 3 ] = this.getCoord(array_ref, fig_id, layer, t, 2); //Point 2 -> x
  positions[ i + 4 ] = this.getCoord(array_ref, fig_id, layer, t, 3); //Point 2 -> y
  positions[ i + 5 ] = parseFloat(0);                                 //Point 2 -> z
  positions[ i + 6 ] = this.getCoord(array_ref, fig_id, layer, t, 4); //Point 3 -> x
  positions[ i + 7 ] = this.getCoord(array_ref, fig_id, layer, t, 5); //Point 3 -> y
  positions[ i + 8 ] = parseFloat(0);                                 //Point 3 -> z
}
return positions;
}

toNormalBuffer(fig_id){
var normals = new Float32Array( 49 * 3 * 3 );
for ( var t = 0; t < 49; t += 1 ) {
  var i = t*9;
  normals[ i + 0 ] = parseFloat(0);
  normals[ i + 1 ] = parseFloat(0);
  normals[ i + 2 ] = parseFloat(1);
  normals[ i + 3 ] = parseFloat(0);
  normals[ i + 4 ] = parseFloat(0);
  normals[ i + 5 ] = parseFloat(1);
  normals[ i + 6 ] = parseFloat(0);
  normals[ i + 7 ] = parseFloat(0);
  normals[ i + 8 ] = parseFloat(1);
}
return normals;
}

toColorBuffer(fig_id){
var colors = new Float32Array(49 * 3 * 3 );
var color = new THREE.Color();
for ( var t = 0; t < 49; t += 1 ) {
  var i = t*9;
  var c = this.listOfFigures[fig_id-1][t][6];
  color.setRGB(c[0], c[1], c[2]);
  colors[ i + 0 ] = color.r;
  colors[ i + 1 ] = color.g;
  colors[ i + 2 ] = color.b;
  colors[ i + 3 ] = color.r;
  colors[ i + 4 ] = color.g;
  colors[ i + 5 ] = color.b;
  colors[ i + 6 ] = color.r;
  colors[ i + 7 ] = color.g;
  colors[ i + 8 ] = color.b;
}
return colors;
}
}


///////////////////////////////////////////////////////////////////////////
// MAIN CODE         															           //////////////
// Use Mesh-Data from FigureBuilder                          //////////////
// Rendering   &  	Program Logic	                           //////////////
// Interaction with Figures                                  //////////////
// "Saving/Loading" via Config Button                        //////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

//Size of All Figures
var SIZE = 100;
//Background
var HEX_BACKGROUND    = 0x151515;
//Scene Light
var HEX_AMBIENT_LIGHT = 0xff00ff;
var HEX_DIRECT_LIGHT  = 0x000000;
//Front and Background Colors of Figure
var BG_COLOR  = [0,20,20];
var F_COLOR = [200,200,200];

var HEX_FIGURE_AREA_COLOR    = 0x011010; //0x333333;
var HEX_FIGURE_AREA_HOVERED  = 0x333333; //0xff6666; //Color when hovered
var HEX_FIGURE_AREA_EMISSIVE = 0x000000;
var HEX_FIGURE_OUTLINE       = 0x333333;
var HEX_FIGURE_GRID          = 0x101010;

//Button Colors
var BUTTON_INACTIVE_COLOR = "transparent";
var BUTTON_ACTIVE_COLOR   = "rgba(0,255,255,0.5)";
//Button States
var GRID_ACTIVE    = true;
var FIXED_ACTIVE   = true;
var SHUFFLE_ACTIVE = false;
var LABELS_ACTIVE  = false;
var CONFIG_ACTIVE  = false;

var CONTAINER;
var STATS;
var button_labels  = document.getElementById( 'button_labels' );
var button_grid    = document.getElementById( 'button_grid' );
var button_fixed   = document.getElementById( 'button_fixed' );
var button_shuffle = document.getElementById( 'button_shuffle' );
var button_config  = document.getElementById( 'button_config' );
var config_span    = document.getElementById( 'config' );
var input_config   = document.getElementById( 'input_config' );
var copy_config    = document.getElementById( 'copy_config' );
var delete_config  = document.getElementById( 'delete_config' );
var menu           = document.getElementById( 'menu' );

var CAMERA, SCENE;
var RENDERER, LABEL_RENDERER;
var RAYCASTER;
var MOUSE, MOUSE_PYR;

var ARRAY_LF = [];
var GROUP_L, GROUP_P, GROUP_LABEL_NR_L, GROUP_LABEL_NR_P, GROUP_LABEL_NAME;
var FB;

init();
animate();
function init() {
CONTAINER = document.getElementById( 'container' );
////////////////////////////////////////////////////////////////////////////////////////
// Scene Creation
////////////////////////////////////////////////////////////////////////////////////////
CAMERA = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 3500 );
CAMERA.position.z = 2750;
SCENE = new THREE.Scene();
SCENE.background = new THREE.Color( HEX_BACKGROUND );
SCENE.fog = new THREE.Fog( 0x050505, 2000, 3500 );
SCENE.add( new THREE.AmbientLight( HEX_AMBIENT_LIGHT ) );
var light1 = new THREE.DirectionalLight( HEX_DIRECT_LIGHT, 0.5 );
light1.position.set( 1, 1, 1 );
SCENE.add( light1 );
////////////////////////////////////////////////////////////////////////////////////
// Init Figures
////////////////////////////////////////////////////////////////////////////////////
FB = new FigureBuilder(SIZE, F_COLOR, BG_COLOR);
////////////////////////////////////////////////////////////////////////////////////
// Set Materials
////////////////////////////////////////////////////////////////////////////////////
var MATERIAL_AREA = new THREE.MeshPhongMaterial( {
  color: HEX_FIGURE_AREA_COLOR,
  specular: 0xffffff,
  shininess: 250,
  side: THREE.DoubleSide,
  vertexColors: THREE.VertexColors,
  emissive: HEX_FIGURE_AREA_EMISSIVE
} );

var MATERIAL_GRID = new THREE.LineBasicMaterial( {
  color: HEX_FIGURE_GRID
} );

var MATERIAL_OUTLINE = new THREE.LineBasicMaterial( {
  color: HEX_FIGURE_OUTLINE
} );
////////////////////////////////////////////////////////////////////////////////////
// Helper Function for Creating Meshes
////////////////////////////////////////////////////////////////////////////////////
function createMesh(buffer_positions, buffer_normals, buffer_colors, material){
  var geometry         = new THREE.BufferGeometry();
  geometry.addAttribute( 'position', new THREE.BufferAttribute( buffer_positions, 3 ) );
  geometry.addAttribute( 'normal',   new THREE.BufferAttribute( buffer_normals,   3 ) );
  geometry.addAttribute( 'color',    new THREE.BufferAttribute( buffer_colors,    3 ) );
  return new THREE.Mesh( geometry, material);
}

function createLine(buffer_positions, material){
  var geometry         = new THREE.BufferGeometry();
  geometry.addAttribute( 'position', new THREE.BufferAttribute( buffer_positions, 3 ) );
  return new THREE.Line( geometry, material);
}

////////////////////////////////////////////////////////////////////////////////////////
//																																									////
//    +   +   +   +   +																															////
//    +   +   +   +   +																															////
//    +   +   +   +   +																															////
//    +   +   +   +   +																															////
//    +   +   +   +   +																															////
//																																									////
////////////////////////////////////////////////////////////////////////////////////////
GROUP_L           = new THREE.Group();
GROUP_LABEL_NR_L  = new THREE.Group();
GROUP_LABEL_NR_P  = new THREE.Group();
GROUP_LABEL_NAME  = new THREE.Group();

for(var fig_id = 1; fig_id<=25; fig_id+=1){
  var GROUP_LF         = new THREE.Group();

  var MESH_LF_AREA = createMesh(
    FB.toPositionBuffer(fig_id, 0),
    FB.toNormalBuffer(fig_id),
    FB.toColorBuffer(fig_id),
    MATERIAL_AREA
  );

  var MESH_LF_GRID = createLine(
    FB.toPositionBuffer(fig_id, 0),
    MATERIAL_GRID
  );

  var local_pos = FB.positionMapForList[fig_id-1];
  MESH_LF_AREA.position.set(local_pos[0],local_pos[1],local_pos[2]);
  MESH_LF_GRID.position.set(local_pos[0],local_pos[1],local_pos[2]);
  GROUP_LF.add( MESH_LF_AREA );
  GROUP_LF.add( MESH_LF_GRID );
  GROUP_L.add( GROUP_LF );

  var PF_LABEL_DIV = document.createElement( 'div' );
  PF_LABEL_DIV.className = 'label';
  PF_LABEL_DIV.textContent = fig_id;
  PF_LABEL_DIV.style.marginTop = '-1em';
  var PF_LABEL = new THREE.CSS2DObject( PF_LABEL_DIV );
  GROUP_LABEL_NR_L.add( PF_LABEL );
  //Position depending on Slot
  PF_LABEL.position.set(local_pos[0],local_pos[1]-FB.SIZE*4/12,local_pos[2]);

  var pf_nameDiv = document.createElement( 'div' );
  pf_nameDiv.className = 'label';
  pf_nameDiv.textContent = "Figure "+FB.getName(fig_id);
  pf_nameDiv.style.marginTop = '-1em';
  var pf_name = new THREE.CSS2DObject( pf_nameDiv );
  GROUP_LABEL_NAME.add( pf_name );
  //Position depending on Slot
  pf_name.position.set(local_pos[0],local_pos[1]-FB.SIZE*12/4,local_pos[2]);
}

////////////////////////////////////////////////////////////////////////////////////////
//																																									////
//            +																																			////
//          + + +																																		////
//        + + + + +																																	////
//      + + + + + + +																																////
//    + + + + + + + + +																															////
//																																									////
////////////////////////////////////////////////////////////////////////////////////////
GROUP_P = new THREE.Group();

for(var slot = 1; slot<=25; slot+=1){
  var GROUP_PF = new THREE.Group();
  var fig_id = FB.getFigureForSlot(slot);

  var MATERIAL_PF = new THREE.MeshPhongMaterial( {
    color: HEX_FIGURE_AREA_COLOR,
    specular: 0xffffff,
    shininess: 250,
    side: THREE.DoubleSide,
    vertexColors: THREE.VertexColors,
    opacity: 1.0,
    transparent: true,
    emissive: HEX_FIGURE_AREA_EMISSIVE
  } );
  var MESH_PF_AREA = createMesh(
    FB.toPositionBuffer(fig_id, 1),
    FB.toNormalBuffer(fig_id),
    FB.toColorBuffer(fig_id),
    MATERIAL_PF
  );

  var MESH_PF_GRID = createLine(
    FB.toPositionBuffer(fig_id, 1),
    MATERIAL_GRID
  );
  //Position in front of Area
  MESH_PF_GRID.position.set( 0,0,1 );

  var MESH_PF_OUTLINE = createLine(
    FB.toPositionBuffer(fig_id, 2),
    MATERIAL_OUTLINE
  );

  GROUP_PF.add( MESH_PF_AREA );
  GROUP_PF.add( MESH_PF_GRID );
  GROUP_PF.add( MESH_PF_OUTLINE );
  GROUP_PF.scale.set(0.99,0.99,0.99);
  GROUP_PF.position.set(FB.slotXPosition(slot), FB.slotYPosition(slot), 0 );
  var flipped = FB.getIfFlipped(slot);
  if( flipped ){ GROUP_PF.rotation.z = Math.PI; } else { GROUP_PF.rotation.z = 0; }
  GROUP_PF.name = slot;
  GROUP_P.add( GROUP_PF );

  var PF_LABEL_DIV = document.createElement( 'div' );
  PF_LABEL_DIV.className = 'label';
  PF_LABEL_DIV.textContent = fig_id;
  PF_LABEL_DIV.style.marginTop = '-1em';
  var PF_LABEL = new THREE.CSS2DObject( PF_LABEL_DIV );
  PF_LABEL.position.set(FB.slotXPosition(slot), FB.slotYPosition(slot)-20, 0 );
  GROUP_LABEL_NR_P.add( PF_LABEL );
}

var POS_X_LIST    = -FB.SIZE * 100 * 3/15;
var POS_Y_LIST    = 0;
var POS_X_PYR     =  FB.SIZE * 100 * 3/15;
var POS_Y_PYR     = 0;
GROUP_L.position.set( POS_X_LIST, POS_Y_LIST, 0 );
GROUP_LABEL_NR_L.position.set( POS_X_LIST, POS_Y_LIST, 0 );
GROUP_LABEL_NAME.position.set( POS_X_LIST, POS_Y_LIST, 0 );
GROUP_LABEL_NR_P.position.set( POS_X_PYR, POS_Y_PYR, 0 );
GROUP_P.position.set( POS_X_PYR, POS_Y_PYR, 0 );

//GROUP_P.rotation.z = Math.PI*2/3;
SCENE.add( GROUP_L );
SCENE.add( GROUP_P );
SCENE.add( GROUP_LABEL_NR_L );
SCENE.add( GROUP_LABEL_NR_P );
SCENE.add( GROUP_LABEL_NAME );

//Shortcut
ARRAY_LF = GROUP_L.children;

////////////////////////////////////////////////////////////////////////////////////////
// Raycasting & Mouse
////////////////////////////////////////////////////////////////////////////////////////
RAYCASTER = new THREE.Raycaster();
MOUSE     = new THREE.Vector2();
MOUSE_PYR = new THREE.Vector2();
////////////////////////////////////////////////////////////////////////////////////////
// RENDERER
////////////////////////////////////////////////////////////////////////////////////////
RENDERER = new THREE.WebGLRenderer();
RENDERER.setPixelRatio( window.devicePixelRatio );
RENDERER.setSize( window.innerWidth, window.innerHeight );
CONTAINER.appendChild( RENDERER.domElement );
STATS = new Stats();
CONTAINER.appendChild( STATS.domElement );
STATS.domElement.id = "stats";
////////////////////////////////////////////////////////////////////////////////////////
// LABEL RENDERER
////////////////////////////////////////////////////////////////////////////////////////
LABEL_RENDERER = new THREE.CSS2DRenderer();
LABEL_RENDERER.setSize( window.innerWidth, window.innerHeight );
LABEL_RENDERER.domElement.style.position = 'absolute';
LABEL_RENDERER.domElement.style.top = 0;
CONTAINER.appendChild( LABEL_RENDERER.domElement );
////////////////////////////////////////////////////////////////////////////////////////
// Event Listener
////////////////////////////////////////////////////////////////////////////////////////
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
////////////////////////////////////////////////////////////////////////////////////////
// Init Button CSS
////////////////////////////////////////////////////////////////////////////////////////
updateButtonCSS(GRID_ACTIVE, button_grid);
updateButtonCSS(FIXED_ACTIVE, button_fixed);
updateButtonCSS(SHUFFLE_ACTIVE, button_shuffle);
updateButtonCSS(LABELS_ACTIVE, button_labels);
updateButtonCSS(CONFIG_ACTIVE, button_config);

for(var i = 0; i<GROUP_LABEL_NR_L.children.length; i+=1){ GROUP_LABEL_NR_L.children[i].element.hidden = !(LABELS_ACTIVE); }
for(var i = 0; i<GROUP_LABEL_NR_P.children.length; i+=1){ GROUP_LABEL_NR_P.children[i].element.hidden = !(LABELS_ACTIVE); }
for(var i = 0; i<GROUP_LABEL_NAME.children.length; i+=1){ GROUP_LABEL_NAME.children[i].element.hidden = true; }
if(CONFIG_ACTIVE){ config_span.style.display = "inherit";
}else{             config_span.style.display = "none";  }

updatePyramide();
}

////////////////////////////////////////////////////////////////////////////////////////
// Update Button CSS
////////////////////////////////////////////////////////////////////////////////////////
function updateButtonCSS(status, button) {
if(status){ button.style.background = ""+BUTTON_ACTIVE_COLOR;
}else{      button.style.background = ""+BUTTON_INACTIVE_COLOR; }
}

////////////////////////////////////////////////////////////////////////////////////////
// UPDATE MESHES from changed LOGIC
////////////////////////////////////////////////////////////////////////////////////////
function updatePyramide() {
for(var fig_id = 1; fig_id <= 25; fig_id += 1){
  var figure_in_slot = GROUP_P.children[fig_id-1]; //GROUP_P.children = [figure1, figure2, figure3, ...]
  var label_in_slot  = GROUP_LABEL_NR_P.children[fig_id-1];
  var slot     = FB.getSlotForFigure(fig_id);
  var flipped  = FB.getIfFlipped(slot);
  var rotation = FB.getFigureRotation(fig_id);
  var totalr   = 0;
  if(flipped){ totalr = Math.PI; }
  totalr += rotation * Math.PI*2/3;
  figure_in_slot.rotation.z = totalr;
  figure_in_slot.position.set(FB.slotXPosition(slot), FB.slotYPosition(slot), 0); //slotXPosition and slotYPosition are fixed constants for each slot
  figure_in_slot.position.z = 0;

  label_in_slot.position.set(FB.slotXPosition(slot), FB.slotYPosition(slot), 0);
}
setConfig();
}



////////////////////////////////////////////////////////////////////////////////////////
// WINDOW
////////////////////////////////////////////////////////////////////////////////////////
function onWindowResize() {
CAMERA.aspect = window.innerWidth / window.innerHeight;
CAMERA.updateProjectionMatrix();
RENDERER.setSize( window.innerWidth, window.innerHeight );
LABEL_RENDERER.setSize( window.innerWidth, window.innerHeight );
//centerFigures();
}

////////////////////////////////////////////////////////////////////////////////////////
// BUTTONS / INPUTS
////////////////////////////////////////////////////////////////////////////////////////
button_grid.addEventListener( 'click', function () {
GRID_ACTIVE = !GRID_ACTIVE;
updateButtonCSS(GRID_ACTIVE, button_grid);
for(var i = 0; i<GROUP_P.children.length; i+=1){ GROUP_P.children[i].children[1].visible = GRID_ACTIVE; } //Show or Hide: PYRAMIDE GRID
for(var i = 0; i<GROUP_L.children.length; i+=1){ GROUP_L.children[i].children[1].visible = GRID_ACTIVE; } //Show or Hide: LIST GRID
}, false );

button_labels.addEventListener( 'click', function () {
LABELS_ACTIVE = !LABELS_ACTIVE;
updateButtonCSS(LABELS_ACTIVE, button_labels);
for(var i = 0; i<GROUP_LABEL_NR_L.children.length; i+=1){ GROUP_LABEL_NR_L.children[i].element.hidden = !(LABELS_ACTIVE); }
for(var i = 0; i<GROUP_LABEL_NR_P.children.length; i+=1){ GROUP_LABEL_NR_P.children[i].element.hidden = !(LABELS_ACTIVE); }
}, false );

button_fixed.addEventListener( 'click', function () {
FIXED_ACTIVE = !FIXED_ACTIVE;
if(FIXED_ACTIVE){ button_fixed.style.background = ""+BUTTON_ACTIVE_COLOR;
                  updatePyramide();
}else{            button_fixed.style.background = ""+BUTTON_INACTIVE_COLOR;}                               //Change GRID-BUTTON CSS
}, false );

button_shuffle.addEventListener( 'click', function () {
SHUFFLE_ACTIVE = !SHUFFLE_ACTIVE;
if(SHUFFLE_ACTIVE){ button_shuffle.style.background = ""+BUTTON_ACTIVE_COLOR;
                    updatePyramide();
}else{              button_shuffle.style.background = ""+BUTTON_INACTIVE_COLOR;}
}, false );

button_config.addEventListener( 'click', function () {
CONFIG_ACTIVE = !CONFIG_ACTIVE;
updateButtonCSS(CONFIG_ACTIVE, button_config);
if(CONFIG_ACTIVE){ config_span.style.display = "inherit";
}else{             config_span.style.display = "none";  }
}, false );

// Default
// #1m#2m#3m#4m#5m#6m#7m#8m#9m#10m#11m#12m#13m#14m#15m#16m#17m#18m#19m#20m#21m#22m#23m#24m#25m
function loadConfig(string){
var regex = /^([#][0-9][0-9][l|m|r]){25}$/;
var figures = string.split(/['#']+/);
var config_p = Array(25);
var config_r = Array(25);
for(var slot = 1; slot<=25; slot+=1){
  var figure = figures[slot];
  var fig_id = figure.substring(0,figure.length-1);
  fig_id = parseInt(fig_id);
  var fig_rotation = figure.substring(figure.length-1,figure.length);
  switch(fig_rotation){
    case 'l': fig_rotation = -1; break;
    case 'm': fig_rotation = 0; break;
    case 'r': fig_rotation = 1; break;
    default: return;
  }
  config_p[slot-1]   = fig_id;
  config_r[fig_id-1] = fig_rotation;
}

if(new Set(config_p).size !== config_p.length ){return;}
for(var i=0; i<config_p.length; i+=1){
  var x = config_p[i];
  if(x<1||x>25){return;}
}

FB.setConfiguration(config_p, config_r);
updatePyramide();
}

function setConfig(){
var string = "#";
for(var slot = 1; slot <= 25; slot+=1){
  var fig_id  = FB.getFigureForSlot(slot);
  var fig_rot = FB.getFigureRotation(fig_id);
  if(fig_id<=9){ string += "0"+fig_id; }else{ string += fig_id; }
  switch(fig_rot){
    case -1: string += "l"; break;
    case  0: string += "m"; break;
    case  1: string += "r"; break;
  }
  string += "#";
}
input_config.value = string;
}

input_config.addEventListener( 'keydown', function (e) {
if (e.keyCode == 13) {
  loadConfig(input_config.value);
}
}, false );

input_config.addEventListener( 'click', function (e) {
input_config.select();
}, false );

copy_config.addEventListener( 'click', function () {
var copyText = document.getElementById("input_config"); // Get the text field
copyText.select();  // Select the text field
copyText.setSelectionRange(0, 99999); // For mobile devices
document.execCommand("copy");  // Copy the text inside the text field
}, false );

delete_config.addEventListener( 'click', function () {
var deleteField = document.getElementById("input_config");
deleteField.value = "";
}, false );


////////////////////////////////////////////////////////////////////////////////////////
// MOUSE FIGURE INTERACTION
////////////////////////////////////////////////////////////////////////////////////////
function getPickedFigure(){ return parseInt(PICKED.name, 10); }
function getHoveredFigure(){ return parseInt(HOVERED.name, 10); }
function getPickedSlot(){ return FB.getSlotForFigure(getPickedFigure()); }

////////////////////////////////////////////////////////////////////////////////////////
// MOUSE ACTIONS
////////////////////////////////////////////////////////////////////////////////////////
var MOUSE_DOWN = false;
var DRAGGED = false;
var PICKED = null;
var HOVERED = null;

function updateMousePyr(){
var vector = new THREE.Vector3(MOUSE.x, MOUSE.y, 0.5);
vector.unproject( CAMERA );
var dir = vector.sub( CAMERA.position ).normalize();
var distance = - CAMERA.position.z / dir.z;
var pos = CAMERA.position.clone().add( dir.multiplyScalar( distance ) );
pos.sub(PICKED.parent.position);  //Position of Pyramide
MOUSE_PYR = pos;
}

function onDocumentMouseMove( event ) {
if(SHUFFLE_ACTIVE){ return; }
event.preventDefault();
MOUSE.x = ( event.clientX / window.innerWidth ) * 2 - 1;
MOUSE.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// Dragging
DRAGGED = false;
if (MOUSE_DOWN){
  if (PICKED){
    updateMousePyr();
    //Move Picked Figure
    PICKED.position.x = MOUSE_PYR.x;
    PICKED.position.y = MOUSE_PYR.y;
    PICKED.position.z = 1;
    PICKED.children[0].material.opacity = 0.7;
    //Move Assigned NR Label
    GROUP_LABEL_NR_P.children[getPickedFigure()-1].position.set(MOUSE_PYR.x, MOUSE_PYR.y, 0 );
    DRAGGED = true;
  }
}
// Hovering
RAYCASTER.setFromCamera( MOUSE, CAMERA );
var intersects = RAYCASTER.intersectObjects(GROUP_P.children, true);   	                //--> RAYCASTING ON PYRAMIDE FIGURES
if ( intersects.length > 0 ) {                                                          //--> SOMETHING WAS HOVERED
  var new_hovered = intersects[intersects.length-1].object.parent;                      //Pick farest Layer
  if(HOVERED != new_hovered){                                                           //HOVERED Object has changed
    if(HOVERED){ HOVERED.children[0].material.color.setHex(HEX_FIGURE_AREA_COLOR); }    //Reset old HOVERED Object's color
    HOVERED = new_hovered;                                                              //Set new HOVERED Object
    HOVERED.children[0].material.color.setHex(HEX_FIGURE_AREA_HOVERED);                 //Set new HOVERED Object's color
  }
}else{																																									//--> NOTHING WAS HOVERED
  if(HOVERED){                                                                          //Reset old HOVERED Object's color
    HOVERED.children[0].material.color.setHex(HEX_FIGURE_AREA_COLOR);
    HOVERED = null;
  }
}
}

function onDocumentMouseDown( event ) {
if(SHUFFLE_ACTIVE){ return; }
RAYCASTER.setFromCamera( MOUSE, CAMERA );
var intersects = RAYCASTER.intersectObjects(GROUP_P.children, true);
if ( intersects.length > 0 ) {
  PICKED = intersects[0].object.parent; //GROUP_Pf
}
MOUSE_DOWN = true;
}

function onDocumentMouseUp( event ) {
if(SHUFFLE_ACTIVE){ return; }
//ONE CLICK -> ROTATE (Save to LOGIC)
if(DRAGGED == false){
  if(PICKED){
    FB.rotateFigure(getPickedFigure());
    updatePyramide();
  }
}
if(FIXED_ACTIVE){
  //DRAG CLICK -> SWITCH (Save to LOGIC)
  if(DRAGGED == true){
    var slot_picked = getPickedSlot();
    var slot_hover = FB.getSlotForFigure(getHoveredFigure());
    if(slot_hover){ FB.switchSlotFigures(slot_picked,slot_hover); }
    updatePyramide();
  }
}
MOUSE_DOWN = false;
if(PICKED){
  PICKED.children[0].material.opacity = 1.0; //Reset Opacity After PICKED dropped
  PICKED = null;
}
if(HOVERED){
  HOVERED.children[0].material.color.setHex(HEX_FIGURE_AREA_COLOR); //Reset HOVERED
  HOVERED = null;
}
DRAGGED = false;
}



var t = 0;
var START = true;
function animate() {
  requestAnimationFrame( animate );
  if(START){
    renderStart();
  }else{
    render();
  }
  STATS.update();
}

var t_s = 0.0;
function renderStart() {
  var zoom    = t_s;
  var opacity = t_s;
  if(t_s >= 1){
    //Show Labels
    for(var i = 0; i<GROUP_LABEL_NAME.children.length; i+=1){ GROUP_LABEL_NAME.children[i].element.hidden = false; }
    //Leave Start-Animation
    t_s = 0.0;
    START = false;
  }
  //Fade in Scene and Menu
  SCENE.scale.set(zoom,zoom,zoom);
  menu.style.opacity = ""+opacity;
  RENDERER.render( SCENE, CAMERA );
  t_s += 0.01;
}

function render() {
  var time = Date.now() * 0.0001;
  for (var m = 0; m < ARRAY_LF.length; m+=1) {
    var amp = 0.004;
    var t = time + m;
    ARRAY_LF[m].rotation.z = amp - Math.abs((t * 0.05) % (2*amp) - amp);
  }

  if(SHUFFLE_ACTIVE){
    t += 0.1;
    if(t>=1){
      FB.setRandomConfiguration();
      updatePyramide();
      t=0;
    }
  }

  RENDERER.render( SCENE, CAMERA );
  LABEL_RENDERER.render( SCENE, CAMERA );
}

猜你喜欢

转载自blog.csdn.net/weixin_45544796/article/details/107342195