import { Vector3 , Euler } from 'three' ; import { PositionNode , Direction , invertDirection } from './PositionNode' ; export type CubeMap = PositionNode [ ] ; export const buildCubeMap = ( size ) : CubeMap => { const zSide = buildSide ( size , Direction . Z ) ; const ySide = buildSide ( size , Direction . Y ) ; const _zSide = buildSide ( size , Direction . _Z ) ; const _ySide = buildSide ( size , Direction . _Y ) ; const xSide = buildSide ( size , Direction . X ) ; const _xSide = buildSide ( size , Direction . _X ) ; const edgeMemo = { } ; attach ( edgeMemo , xSide , ySide , _ySide , zSide , _zSide ) ; attach ( edgeMemo , _xSide , ySide , _ySide , zSide , _zSide ) ; attach ( edgeMemo , ySide , _xSide , xSide , _zSide , zSide ) ; attach ( edgeMemo , _ySide , _xSide , xSide , _zSide , zSide ) ; attach ( edgeMemo , zSide , ySide , _ySide , _xSide , xSide ) ; attach ( edgeMemo , _zSide , ySide , _ySide , _xSide , xSide ) ; let index = 0 ; const cube = [ ... zSide , ... ySide , ... _ySide , ... xSide , ... _xSide , ... _zSide ] . map ( node => { node . index = index ++ ; return node ; } ) ; return cube ; } ; const attach = ( edgeMemo , main , ... sides ) => { sides . forEach ( side => connectEdge ( edgeMemo , main , side ) ) ; } ; const connectEdge = ( memo , node1 , node2 ) => { const direction1 = node1 [ 0 ] . direction ; const direction2 = node2 [ 0 ] . direction ; const memoVal = [ direction1 , direction2 ] . sort ( ) . toString ( ) ; if ( memo [ memoVal ] ) return ; memo [ memoVal ] = true ; let r1 = relativeCoordsMap [ direction1 ] ; let r2 = relativeCoordsMap [ direction2 ] ; r1 = r1 . concat ( r1 . map ( invertDirection ) ) ; r2 = r2 . concat ( r2 . map ( invertDirection ) ) ; let i = 0 ; while ( ! r1 . includes ( r2 [ i ] ) ) i ++ ; const sharedDirection = r2 [ i ] ; let tempNode1 = node1 [ 0 ] ; while ( tempNode1 [ direction2 ] != undefined ) { tempNode1 = tempNode1 [ direction2 ] ! ; } while ( tempNode1 [ sharedDirection ] != undefined && tempNode1 [ sharedDirection ] . direction == direction1 ) { tempNode1 = tempNode1 [ sharedDirection ] ! ; } let tempNode2 = node2 [ 0 ] ; while ( tempNode2 [ direction1 ] != undefined ) { tempNode2 = tempNode2 [ direction1 ] ! ; } while ( tempNode2 [ sharedDirection ] != undefined && tempNode2 [ sharedDirection ] . direction == direction2 ) { tempNode2 = tempNode2 [ sharedDirection ] ! ; } const endDirection = invertDirection ( sharedDirection ) ; while ( tempNode1 != undefined && tempNode2 != undefined && tempNode1 . direction == direction1 && tempNode2 . direction == direction2 ) { tempNode1 [ direction2 ] = tempNode2 ; tempNode2 [ direction1 ] = tempNode1 ; tempNode1 = tempNode1 [ endDirection ] ; tempNode2 = tempNode2 [ endDirection ] ; } return ; } ; const buildSide = ( size , direction ) => { const panel = [ ] ; const shift = ( size - 1 ) * - 0.5 ; const perimeter = size / 2 ; for ( let col = 0 ; col < size ; col ++ ) { for ( let row = 0 ; row < size ; row ++ ) { const vec = new Vector3 ( row , col , perimeter ) ; vec . add ( new Vector3 ( shift , shift , 0 ) ) ; const euler = directionToEulerMap [ direction ] ; vec . applyEuler ( euler ) ; panel . push ( new PositionNode ( vec , direction , euler ) ) ; } } const [ rx , ry ] = relativeCoordsMap [ direction ] ; for ( let col = 0 ; col < size ; col ++ ) { for ( let row = 0 ; row < size ; row ++ ) { const current = row + size * col ; const x = row + 1 + size * col ; const y = row + size * ( col + 1 ) ; if ( row + 1 < size ) { panel [ current ] [ rx ] = panel [ x ] ; panel [ x ] [ invertDirection ( rx ) ] = panel [ current ] ; } if ( col + 1 < size ) { panel [ current ] [ ry ] = panel [ y ] ; panel [ y ] [ invertDirection ( ry ) ] = panel [ current ] ; } } } return panel ; } ; const relativeCoordsMap = { x : [ '_z' , 'y' ] , y : [ 'x' , '_z' ] , z : [ 'x' , 'y' ] , _x : [ 'z' , 'y' ] , _y : [ 'x' , 'z' ] , _z : [ '_x' , 'y' ] } ; export const directionToEulerMap = { x : new Euler ( 0 , Math . PI / 2 , 0 ) , y : new Euler ( Math . PI / - 2 , 0 , 0 ) , z : new Euler ( 0 , 0 , 0 ) , _x : new Euler ( 0 , Math . PI / - 2 , 0 ) , _y : new Euler ( Math . PI / 2 , 0 , 0 ) , _z : new Euler ( 0 , Math . PI , 0 ) } ;