UNPKG

@aladas-org/cryptoshape

Version:

Generates a representation of a Bip39 seed phrase as a 3D scene

519 lines (416 loc) 23.3 kB
// ==================================================================================================== // ====================================== shape_utils.js ====================================== // ==================================================================================================== "use strict"; const BOX_POINTS_MATRIX = [ [ 0, 0, 0], [ 1, 0, 0], [ 1, 1, 0], [ 0, 1, 0], [ 0, 0, 0], [ 0, 0, 0], [ 0, 1, 0], [ 0, 1, 1], [ 0, 0, 1], [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 1], [ 1, 0, 1], [ 1, 0, 0], [ 0, 0, 0], [ 0, 0, 1], [ 1, 0, 1], [ 1, 1, 1], [ 0, 1, 1], [ 0, 0, 1], [ 0, 0, 1], [ 0, 1, 1], [ 1, 1, 1], [ 1, 1, 0], [ 0, 1, 0], ]; const AXIS_LENGTH = 0.85; let LinkCount = 0; let SimpleShapeCount = 0; class ShapeUtils { static Reset() { LinkCount = 0; SimpleShapeCount = 0; } // ShapeUtils.Reset() static PadWithZero(n) { return (n < 10 ? ('0'+n).toString() : n.toString()); } // ShapeUtils.PadWithZero() static CreatePolyline( arg_points, args ) { // console.log(">> createPolyline"); let renderer = Renderer.GetInstance(); let polyline_color = THEMES[renderer.getParameter(THEME_PARAM)][LINK_COLOR][0]; // console.log(" polyline_color: " + polyline_color); let color_rgb = Color.AsVec3( polyline_color ); if ( args != undefined && args["color"] != undefined ) { // Note: color[0] is' Color Name' and 1..3 indexes are RGB components color_rgb = Color.AsVec3( args["color"] ); } const polylines = BABYLON.MeshBuilder.CreateLines( "Polyline_" + LinkCount, { points: arg_points }); polylines.color = color_rgb; renderer.addObject( polylines ); LinkCount++; return polylines; } // ShapeUtils.CreatePolyline() static CreateTruncatedIcosahedron() { let renderer = Renderer.GetInstance(); let scene = renderer.getScene(); let options = { m:1, n: 1, size: .5 }; const goldbergPoly = BABYLON.MeshBuilder.CreateGoldberg("goldberg", options, scene); // scene is optional and defaults to the current scene return goldbergPoly; } // ShapeUtils.CreateTruncatedIcosahedron() static DrawPoint( position, color, point_diameter ) { let renderer = Renderer.GetInstance(); color = ( color != undefined) ? color : GREEN; point_diameter = ( point_diameter != undefined) ? point_diameter : .035; // 0.05 let point_vizject = BABYLON.MeshBuilder.CreateSphere ( "Point_" + SimpleShapeCount, { "segments": 16, "diameter": point_diameter }, renderer.getScene() ); point_vizject.position = position; point_vizject.material = MATERIALS[color]; renderer.addObject( point_vizject ); SimpleShapeCount++; return point_vizject; } // ShapeUtils.DrawPoint() static DrawLine( p0, p1, color ) { let renderer = Renderer.GetInstance(); color = ( color != undefined) ? color : GREY_75; let line_vizject = BABYLON.MeshBuilder.CreateLines ("Line_" + SimpleShapeCount, { points: [ p0, p1 ] }); line_vizject.color = Color.AsVec3(color); renderer.addObject( line_vizject ); SimpleShapeCount++; return line_vizject; } // ShapeUtils.DrawLine() static DrawTriangle( p0, p1, p2, color ) { let renderer = Renderer.GetInstance(); color = ( color != undefined) ? color : ORANGE; let triangle_vizject = BABYLON.MeshBuilder.CreateLines ("Triangle_" + SimpleShapeCount, { points:[ p0, p1, p2, p0 ] }); triangle_vizject.color = Color.AsVec3(color); renderer.addObject( triangle_vizject ); SimpleShapeCount++; return triangle_vizject; } // ShapeUtils.DrawTriangle() static DrawCircle( center, radius, color ) { let renderer = Renderer.GetInstance(); color = ( color != undefined) ? color : ORANGE; let p0 = GeometryUtils.ComputePolarPoint2D( radius, Math.PI/4, center ); let p1 = GeometryUtils.ComputePolarPoint2D( radius, 2 * Math.PI/4, center ); let p2 = GeometryUtils.ComputePolarPoint2D( radius, 3 * Math.PI/4, center ); let arc = BABYLON.Curve3.ArcThru3Points( p0, p1, p2, 32, false, true); let circle_vizject = BABYLON.MeshBuilder.CreateLines ("Circle_" + SimpleShapeCount, { points: arc.getPoints() }); circle_vizject.color = Color.AsVec3(color); renderer.addObject( circle_vizject ); SimpleShapeCount++; return circle_vizject; } // ShapeUtils.DrawCircle() static DrawWireFrameSphere( origin, radius, color ) { if ( color == undefined ) color = GREY_75; ShapeUtils.DrawCircle( origin, radius, color ); const draw_meridian = ( origin, radius, angle, color ) => { let circle_vizject = ShapeUtils.DrawCircle( origin, radius, color ) circle_vizject.rotation.x = angle; } // draw_meridian() const draw_parallel = ( origin, radius, angle, color ) => { let dY = radius * Math.sin(angle); let parallel_radius = radius * Math.cos(angle); let origin_0 = new BABYLON.Vector3( 0, dY, 0 ); ShapeUtils.DrawCircle( origin_0, parallel_radius, color ) let origin_1 = new BABYLON.Vector3( 0, -dY, 0 ); ShapeUtils.DrawCircle( origin_1, parallel_radius, color ) } // draw_parallel() for ( let angle = 0; angle < Math.PI; angle += Math.PI/8 ) { draw_meridian( origin, radius, angle, color ); } for ( let angle = 0; angle < Math.PI; angle += Math.PI/8 ) { draw_parallel( origin, radius, angle, color ); } ShapeUtils.DrawCircle( origin, radius, color ); } // ShapeUtils.DrawWireFrameSphere() // https://babylonjsguide.github.io/snippets/Minimise_Vertices static MinimizeVertices( mesh ) { let _pdata = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind); let _ndata = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind); let _idata = mesh.getIndices(); let _newPdata = []; //new positions array let _newIdata = []; //new indices array let _mapPtr =0; // new index; let _uniquePositions = []; // unique vertex positions for ( let _i=0; _i<_idata.length; _i+=3 ) { let _facet = [_idata[_i], _idata[_i + 1], _idata[_i+2]]; //facet vertex indices let _pstring = []; //lists facet vertex positions (x,y,z) as string "xyz"" for ( let _j = 0; _j<3; _j++ ) { // _pstring[_j] = ""; for ( let _k = 0; _k<3; _k++ ) { // small values make 0 if (Math.abs(_pdata[3*_facet[_j] + _k]) < 0.0001) { _pdata[3*_facet[_j] + _k] = 0; } _pstring[_j] += _pdata[3*_facet[_j] + _k] + "|"; } _pstring[_j] = _pstring[_j].slice(0, -1); } // Check facet vertices to see that none are repeated // do not process any facet that has a repeated vertex, ie is a line if ( !(_pstring[0] == _pstring[1] || _pstring[0] == _pstring[2] || _pstring[1] == _pstring[2]) ) { // For each facet position check if already listed in uniquePositions // if not listed add to uniquePositions and set index pointer // if listed use its index in uniquePositions and new index pointer for ( let _j=0; _j < 3; _j++ ) { let _ptr = _uniquePositions.indexOf(_pstring[_j]) if ( _ptr < 0 ) { _uniquePositions.push(_pstring[_j]); _ptr = _mapPtr++; // Not listed so add individual x, y, z coordinates to new positions array newPdata // and add matching normal data to new normals array newNdata for( let _k = 0; _k<3; _k++ ) { _newPdata.push(_pdata[3*_facet[_j] + _k]); } } // add new index pointer to new indices array newIdata _newIdata.push(_ptr); } } } let _newNdata = []; //new normal data BABYLON.VertexData.ComputeNormals(_newPdata, _newIdata, _newNdata); // Create new vertex data object and update let _vertexData = new BABYLON.VertexData(); _vertexData.positions = _newPdata; _vertexData.indices = _newIdata; _vertexData.normals = _newNdata; _vertexData.applyToMesh( mesh ); } // ShapeUtils.MinimizeVertices() static DrawCircleFrom3Points( p0, p1, p2, color, thickness ) { let renderer = Renderer.GetInstance(); color = ( color != undefined) ? color : ORANGE; let edge_rendering = false; if ( thickness != undefined ) { edge_rendering = true; } let arc = BABYLON.Curve3.ArcThru3Points( p0, p1, p2, 32, false, true); let circle_vizject = BABYLON.MeshBuilder.CreateLines ("Circle_" + SimpleShapeCount, { points: arc.getPoints() }); circle_vizject.color = Color.AsVec3(color); if ( edge_rendering ) { circle_vizject.enableEdgesRendering(); circle_vizject.edgesWidth = thickness; let edges_color = new BABYLON.Color4 ( circle_vizject.color.r, circle_vizject.color.g, circle_vizject.color.b, 1); circle_vizject.edgesColor = edges_color; } renderer.addObject( circle_vizject ); SimpleShapeCount++; return circle_vizject; } // ShapeUtils.DrawCircleFrom3Points() static DrawSphereBox( radius ) { let renderer = Renderer.GetInstance(); if ( radius == undefined ) sphere_radius = 1.55; // X_SCALING_FACTOR * STEP / 2; let sphere_mesh = BABYLON.MeshBuilder.CreateSphere ( "SphereBox", { "segments": 16, "diameter": radius}, renderer.getScene() ); sphere_mesh.origin = new BABYLON.Vector3.Zero(); renderer.addObject( sphere_mesh ); } // ShapeUtils.DrawSphereBox() static DrawCustomCubeWireframe(vizmode) { let VIZMODE_ORIGIN = new BABYLON.Vector3(START, START, START); if (vizmode != undefined ) { VIZMODE_ORIGIN = vizmode.getOrigin(); } console.log(">> ShapeUtils.DrawCustomCubeWireframe"); let renderer = Renderer.GetInstance(); let square_mesh = undefined; const draw_squares = ( pos_index ) => { let positions = []; // 6 planes ( 6 faces of a cube) for ( let plane_idx=0; plane_idx < BOX_POINTS_MATRIX.length; plane_idx+=5 ) { // 5 points for each plane for ( let point_idx=0; point_idx < 5; point_idx++ ) { let point_vector = BOX_POINTS_MATRIX[plane_idx + point_idx]; // console.log("point_vector(" + point_idx + "): " + JSON.stringify(point_vector)); let p1 = new BABYLON.Vector3 ( VIZMODE_ORIGIN.x + STEP * point_vector[0] * pos_index - STEP/2, VIZMODE_ORIGIN.y + STEP * point_vector[1] * pos_index - STEP/2, VIZMODE_ORIGIN.z + STEP * point_vector[2] * pos_index - STEP/2 ); positions.push( p1 ); } } let square_color = THEMES[renderer.getParameter(THEME_PARAM)][BOUNDING_BOX_COLOR][0]; // for ( let i=0; i < positions.length; i++ ) { // // Draw edges with Thickness if 'LINE_THICKNESS' is defined on current 'Theme' // // https://playground.babylonjs.com/#1IYSYD#12 // if ( i > 0 ){ // let line_thickness = THEMES[renderer.getParameter(THEME_PARAM)][LINE_THICKNESS]; // let line_points = [ positions[i], positions[i-1] ]; // // const new_line = BABYLON.MeshBuilder.CreateLines( "bb_line_" + i, { points: line_points }); // if ( line_thickness != undefined ) { // const black3 = new BABYLON.Color3(0, 0, 0); // const black4 = new BABYLON.Color4(0, 0, 0, 1); // new_line.color = square_color; // new_line.enableEdgesRendering(); // new_line.edgesWidth = line_thickness; // new_line.edgeColor = square_color; // new_line.material = MATERIALS[BLACK]; // } // } // } square_mesh = ShapeUtils.CreatePolyline( positions, { "color": square_color } ); renderer.addObject( square_mesh ); // NB: Draw 'BoundingBox' as Cube Mesh with Material.wireframe = true // BUT... it draws also diagonals on Faces 8(( }; // draw_squares() draw_squares( 16 ); return square_mesh; } // ShapeUtils.DrawCustomCubeWireframe() static DrawCubeBox( vizmode, options ) { console.log(">> ShapeUtils.DrawCubeBox"); if ( options == undefined ) options = {}; if ( options[SIZE_ARG] == undefined ) options[SIZE_ARG] = STEP * MAX_UNITS_ON_AXIS; let alpha_faces = ( options[ALPHA_FACES_ARG] != undefined ) ? options[ALPHA_FACES_ARG] : false; if ( options[ORIGIN_ARG] == undefined ) options[ORIGIN_ARG] = new BABYLON.Vector3.Zero(); else { let orig_X = options[ORIGIN_ARG].x; console.log(" --- ShapeUtils.DrawCubeBox: orig_X " + orig_X); let orig_Y = options[ORIGIN_ARG].y; console.log(" --- ShapeUtils.DrawCubeBox: orig_Y " + orig_Y); let orig_Z = options[ORIGIN_ARG].z; console.log(" --- ShapeUtils.DrawCubeBox: orig_Z " + orig_Z); options[ORIGIN_ARG] = new BABYLON.Vector3( START + STEP * options[ORIGIN_ARG].x, START + STEP * options[ORIGIN_ARG].y, START + STEP * options[ORIGIN_ARG].z ); console.log("ShapeUtils.DrawCubeBox: options[ORIGIN_ARG]\n" + JSON.stringify(options[ORIGIN_ARG])); } let renderer = Renderer.GetInstance(); let cube_box = undefined; //let cube_ref = BABYLON.Mesh.CreateBox( "cube_ref", 1, renderer.getScene() ); //cube_ref.material = MATERIALS[YELLOW]; //cube_ref.material.wireframe = true; //cube_ref.origin = new BABYLON.Vector3.Zero(); //renderer.addObject( cube_ref ); let exportable = THEMES[renderer.getParameter(THEME_PARAM)][EXPORTABLE]; if ( exportable == undefined ) exportable = false; // NB: Disable semi-opaque ùaterial for the bounding box exportable = true; if ( alpha_faces ) exportable = true; if ( exportable ) { return ShapeUtils.DrawCustomCubeWireframe(vizmode); } else { let bb_color = Color.AsVec3(THEMES[renderer.getParameter(THEME_PARAM)][BOUNDING_BOX_COLOR][0]); // console.log("bb_color: " + JSON.stringify(bb_color)); // https://www.babylonjs-playground.com/#7HZISY#0 // https://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered let alphamat = new BABYLON.StandardMaterial( 'alphamat', renderer.getScene() ); alphamat.diffuseColor = BABYLON.Color3.Blue(); alphamat.emissiveColor = new BABYLON.Color3(.5, .4, .5); // not necessary artistic decision alphamat.alpha = 0.065; renderer.addObject( alphamat ); // https://doc.babylonjs.com/how_to/how_to_use_edgesrenderer cube_box = BABYLON.Mesh.CreateBox( "bounding_box", options[SIZE_ARG], renderer.getScene() ); cube_box.position = new BABYLON.Vector3.Zero(); // options[ORIGIN_ARG]; cube_box.origin = options[ORIGIN_ARG]; // new BABYLON.Vector3.Zero(); //cube_box.position = new BABYLON.Vector3.Zero(); //let cube_position = STEP * 7; //cube_box.origin = new BABYLON.Vector3( cube_position, cube_position, cube_position ); cube_box.enableEdgesRendering(); // Draw edges with Thickness if 'LINE_THICKNESS' is defined on current 'Theme' let edge_thickness = THEMES[renderer.getParameter(THEME_PARAM)][EDGE_THICKNESS]; if ( edge_thickness == undefined ) edge_thickness = 1.0; cube_box.edgesWidth = edge_thickness; let edges_color = new BABYLON.Color4(bb_color.r, bb_color.g, bb_color.b, 1); cube_box.edgesColor = edges_color; cube_box.material = alphamat; cube_box.convertToFlatShadedMesh(); renderer.addObject( cube_box ); } return cube_box; } // ShapeUtils.DrawCubeBox() static DrawSpring( data ) { // 'data' fields: 'scale_xz', 'scale_y', 'tube_radius', 'range', 'helix_pitch', 'steps_count' let renderer = Renderer.GetInstance(); let scene = renderer.getScene(); if ( data == undefined ) data = {}; let scale_xz = ( data['scale_xz'] != undefined ) ? data['scale_xz']: SCALE_XZ; let scale_y = ( data['scale_y'] != undefined ) ? data['scale_y']: SCALE_Y; let tube_radius = ( data['tube_radius'] != undefined ) ? data['tube_radius']: TUBE_RADIUS; let range = ( data['range'] != undefined ) ? data['range']: RANGE; let helix_pitch = ( data['helix_pitch'] != undefined ) ? data['helix_pitch']: HELIX_PITCH; let steps_count = ( data['steps_count'] != undefined ) ? data['steps_count']: STEPS_COUNT; // https://playground.babylonjs.com/#WW0ALQ#2 let draw_helical_tube = ( scene ) => { const make_curve = ( range, nb_steps ) => { const path = []; const STEP_SIZE = range / nb_steps; for ( let i = -range / 2; i < range / 2; i += STEP_SIZE ) { let x = scale_xz * Math.sin(i * nb_steps * helix_pitch); let y = i * scale_y; let z = scale_xz * Math.cos(i * nb_steps * helix_pitch); path.push( new BABYLON.Vector3( x, y, z) ); } return path; }; // make_curve() const curve = make_curve( range, steps_count ); const tube_mesh = BABYLON.MeshBuilder.CreateTube ( "cylinder_core", { path: curve, radius: TUBE_RADIUS, sideOrientation: BABYLON.Mesh.DOUBLESIDE }, scene); tube_mesh.position = new BABYLON.Vector3.Zero(); tube_mesh.material = MATERIALS[GREY_50]; return tube_mesh; }; // draw_helical_tube() let core_mesh = draw_helical_tube(this.scene); // let data = { [COLOR_ARG]: GREEN, [FACE_COUNT_ARG]: 32, [SIZE_ARG]: 0.75 }; // const core_mesh = BABYLON.MeshBuilder.CreateCylinder("cylinder_core", { height: 1.5, diameter: 0.4} ); return core_mesh; } // ShapeUtils.DrawSpring() static CreateDotGrid( material, scene, scene_objects ) { // scene is optional and defaults to the current scene let start = -0.75; // -3.2; let end = 0.75; // 3.2; let step = 0.1; let x = start; let y = start; let z = start; let dot_size = 0.007; // 0.025; let dot_mesh = undefined; let renderer = Renderer.GetInstance(); let ball_color = THEMES[renderer.getParameter(THEME_PARAM)][NODE_COLOR][0]; for ( y=start; y < end; y+= step ) { for ( z=start; z < end; z+= step ) { for ( x=start; x < end; x+= step ) { let dot_position = new BABYLON.Vector3(x, y, z); // dot_mesh = createDot( material, scene, position, dot_size, { "shape": [SPHERE_DOT] } ); let data = { [MATERIAL_ARG] : MATERIALS[ball_color], [ORIGIN_ARG]: dot_position, [SIZE_ARG]: dot_size, [ARGS_ARG]: { "shape": [SPHERE_DOT] } }; let dot_shape = new BallShape( Renderer.GetInstance(), data ); dot_shape.draw(); // scene_objects.push( dot_mesh ); } } } } // ShapeUtils.CreateDotGrid() // https://playground.babylonjs.com/#FUK3S#8 // https://doc.babylonjs.com/toolsAndResources/utilities/Sector static ShowAngleSector( scene, origin, vector1, vector2, radius ) { const cross = BABYLON.Vector3.Cross(vector1, vector2); const dot = BABYLON.Vector3.Dot(vector1, vector2); const angle = Math.acos(dot / (vector1.length() * vector2.length())); const points = []; const minNb = 16; const factor = 2; let nbPoints = Math.floor(radius * angle * factor); nbPoints = nbPoints < minNb ? minNb : nbPoints; const firstPoint = BABYLON.Vector3.Normalize(vector1).scale(radius); const lastPoint = BABYLON.Vector3.Normalize(vector2).scale(radius); let matrix; let ang = angle / nbPoints; let rotated; for (let i = 0; i < nbPoints; i++) { matrix = BABYLON.Matrix.RotationAxis(cross, ang * i); rotated = BABYLON.Vector3.TransformCoordinates(firstPoint, matrix); points.push(rotated.add(origin)); } points.push(lastPoint.add(origin)); let sector = BABYLON.MeshBuilder.CreateLines("sector", { points }, scene); return sector; } // ShapeUtils.ShowAngleSector() // https://playground.babylonjs.com/#FUK3S#8 // https://doc.babylonjs.com/toolsAndResources/utilities/Sector static DrawArcCircle( scene, origin, p0, p1, radius ) { let points = [origin, p0, p1, origin]; let triangle = BABYLON.Mesh.CreateLines("l", points, scene); // vectors let axis_0 = p0.subtract( origin ); let axis_1 = p0.subtract( p1 ); let axis_2 = p1.subtract( p0 ); // sectors let sector1 = ShapeUtils.ShowAngleSector( scene, origin, axis_0, axis_2, radius ); let sector2 = ShapeUtils.ShowAngleSector( scene, p0, axis_0.scale(-1), axis_1.scale(-1), radius ); let sector3 = ShapeUtils.ShowAngleSector( scene, p1, axis_1, axis_2.scale(-1), radius ); return sector1; } // ShapeUtils.DrawArcCircle() } // ShapeUtils class