diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/index.html b/3MF_test/Web3D-Vue/Web3D_viewer/index.html index 551f1e1..43f11ea 100644 --- a/3MF_test/Web3D-Vue/Web3D_viewer/index.html +++ b/3MF_test/Web3D-Vue/Web3D_viewer/index.html @@ -21,23 +21,30 @@ let options ={ _dimX : X, _dimY: Y, - _fileName: "Cubo.3mf", - _showLimitedGrid: true, + _fileName: "ProjectSlice.3mf", + _showGrid: true, + _showInfiniteGrid: false, _isOrtographic: true, - _modelsDir: "./src/test3/" + _modelsDir: "./src/test3/", + _fileType: '3MF', + _showFrame: true, + _frameType: 2, + _frameLen: 150, //mm + _frameFat: 4 //mm } + console.log(options._modelsDir + options._fileName) WGL.initcall(options); - //document.getElementById("refre_slider").oninput = function() { - // myFunction() - //}; + document.getElementById("refre_slider").oninput = function() { + myFunction() + }; - //function myFunction() { - // var val = document.getElementById("refre_slider").value //gets the oninput value - // console.log(val) - // WGL.refreshcall(1, val) - //} + function myFunction() { + var val = document.getElementById("refre_slider").value //gets the oninput value + console.log(val) + WGL.refreshcall(1, val) + } document.getElementById('btnRef').onclick = function() { @@ -62,6 +69,12 @@ WGL.setCameraType(); } + + document.getElementById('ck_print').onclick = function(){ + var val = document.getElementById('ck_print').checked; + WGL.showPrintDirection(val); + } + - + diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/package-lock.json b/3MF_test/Web3D-Vue/Web3D_viewer/package-lock.json index 2b52b38..85ff671 100644 --- a/3MF_test/Web3D-Vue/Web3D_viewer/package-lock.json +++ b/3MF_test/Web3D-Vue/Web3D_viewer/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "vue": "^2.5.11", - "webgl-visualizer": "^1.2.231005-beta.942" + "webgl-visualizer": "^1.2.231023-beta.1106" }, "devDependencies": { "babel-core": "^6.26.0", @@ -9296,9 +9296,9 @@ } }, "node_modules/webgl-visualizer": { - "version": "1.2.231005-beta.942", - "resolved": "https://nexus.steamware.net/repository/npm-group/webgl-visualizer/-/webgl-visualizer-1.2.231005-beta.942.tgz", - "integrity": "sha512-Fbx6Ogvo6g7lbuqQaQX33toQcoLmCbpH3c6spOwg16t02JYW+F75IUbzyUvi1FW5HM5/yNqku6ci8yOYzroJQQ==", + "version": "1.2.231023-beta.1106", + "resolved": "https://nexus.steamware.net/repository/npm-group/webgl-visualizer/-/webgl-visualizer-1.2.231023-beta.1106.tgz", + "integrity": "sha512-sEA/GbeshPuIKnDDDfZGdS91QhnJsy8Vi/k/az57J2Wv9Ahx7DMhjF5S7EhI33JxQ0ZXJQYCSaoBe3eTOwgZ3A==", "license": "ISC" }, "node_modules/webpack": { diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/package.json b/3MF_test/Web3D-Vue/Web3D_viewer/package.json index c3525b6..c8bd512 100644 --- a/3MF_test/Web3D-Vue/Web3D_viewer/package.json +++ b/3MF_test/Web3D-Vue/Web3D_viewer/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "vue": "^2.5.11", - "webgl-visualizer": "^1.2.231005-beta.942" + "webgl-visualizer": "^1.2.231023-beta.1106" }, "browserslist": [ "> 1%", diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/App.vue b/3MF_test/Web3D-Vue/Web3D_viewer/src/App.vue index cfb04fd..a58ae63 100644 --- a/3MF_test/Web3D-Vue/Web3D_viewer/src/App.vue +++ b/3MF_test/Web3D-Vue/Web3D_viewer/src/App.vue @@ -1,7 +1,7 @@ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/assets/LogoClassic_NoText.png b/3MF_test/Web3D-Vue/Web3D_viewer/src/assets/LogoClassic_NoText.png new file mode 100644 index 0000000..665805f Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/assets/LogoClassic_NoText.png differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/E1.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/E1.3dm new file mode 100644 index 0000000..4e67b63 Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/E1.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/E45.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/E45.3dm new file mode 100644 index 0000000..a1d03aa Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/E45.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex1.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex1.3dm new file mode 100644 index 0000000..6731db6 Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex1.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex1.3mf b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex1.3mf new file mode 100644 index 0000000..323cd1c Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex1.3mf differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex2.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex2.3dm new file mode 100644 index 0000000..ab2cf20 Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex2.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex2.3mf b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex2.3mf new file mode 100644 index 0000000..8015b60 Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex2.3mf differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex3.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex3.3dm new file mode 100644 index 0000000..a22848a Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex3.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex4.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex4.3dm new file mode 100644 index 0000000..339be6e Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex4.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex5.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex5.3dm new file mode 100644 index 0000000..34ee6db Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex5.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex6.3dm b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex6.3dm new file mode 100644 index 0000000..1722020 Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Ex6.3dm differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/ProjectSlice.3mf b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/ProjectSlice.3mf new file mode 100644 index 0000000..b0e3a0f Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/ProjectSlice.3mf differ diff --git a/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Test3MF2.3mf b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Test3MF2.3mf new file mode 100644 index 0000000..9b3be74 Binary files /dev/null and b/3MF_test/Web3D-Vue/Web3D_viewer/src/test3/Test3MF2.3mf differ diff --git a/WebGl/draw/webgl_draw.js b/WebGl/draw/webgl_draw.js index 8100234..3521d86 100644 --- a/WebGl/draw/webgl_draw.js +++ b/WebGl/draw/webgl_draw.js @@ -1,23 +1,44 @@ import * as THREE from '../threeJsLib/three.module.js'; import { OrbitControls } from '../jsm/controls/OrbitControls.js'; import { ThreeMFLoader } from '../jsm/loaders/3MFLoader.js'; +import { Rhino3dmLoader } from '../jsm/addons/loaders/3DMLoader.js'; // VARIABILI DI CONTROLLO + +// *** div dimensions *** var m_divStartDimX = 500; var m_divStartDimY = 400; + var fName = "Cubo.3mf"; -var m_fileSource = ''; +//var fileType = "3MF"; + +// *** camera settings *** var m_bZoom = true; var m_bPan = true; var m_bRot = true; -var m_bAutoRot = false; -var m_bGrid_v1 = true ; -var m_nCameraStartPos = 8 ; -//var useInSlider = false; var m_nCamPos = 0; +var m_nCameraStartPos = 8 ; +var m_bIsOrtographic = true ; +// *** index blender *** var m_nStartL = 0; var m_nEndL = 0; -var m_bIsOrtographic = true ; + +// *** frame settings *** +var m_bShowFrame = true ; +var m_lFrameLen = 100 ; +var m_dFrameFat = 2; // raggio del cilindro +var m_bFrameType = 2 ; + +var m_bAutoRot = false; + +// *** grid settings *** +var m_bShowGrid = true ; +var m_bInfGrid = true ; + +// *** Direction Arrows *** +var m_bShowPrintDir = true ; + +//var useInSlider = false; var counter = 0; @@ -26,14 +47,25 @@ var layer_list = []; const GLBox3D = new THREE.Box3(); // Box3D globale delle geometrie //init(); class webgl_original { - async initcall({ _dimX, _dimY, _fileName, _showInfiniteGrid}) { + async initcall({ _dimX, _dimY, _fileName, _showInfiniteGrid, _fileType}) { m_divStartDimX = _dimX; m_divStartDimY = _dimY; fName = _fileName; - m_bGrid_v1 = _showInfiniteGrid; + m_bInfGrid = _showInfiniteGrid; //console.log(fName) setLoaders(); - await init(); + if(_fileType.toUpperCase() == '3MF') + { + await init3mf(); + } + else if(_fileType.toUpperCase() == '3DM') + { + await init3dm(); + } + else + { + console.log('File type not supported') + } } setCameraType(){ @@ -184,8 +216,8 @@ function setLoaders() { } -function init() { - const manager = new THREE.LoadingManager(); +function init3mf() { + const manager = new THREE.LoadingManager(); const loader = new ThreeMFLoader(manager); let startTime = performance.now(); return new Promise(() => { @@ -205,169 +237,199 @@ function init() { // Adapting Scene to contest let endTime = performance.now(); let timeElapsed = endTime - startTime; - console.log('init in : ' + timeElapsed) + console.log('init3mf in : ' + timeElapsed) }); }, 0); }); } -function AdaptSeceneToContest() { - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - //if (useInSlider) { - - document.getElementById("refre_slider").max = layer_list[layer_list.length - 1].children[0].nLayer; - document.getElementById("refre_slider").value = layer_list[layer_list.length - 1].children[0].nLayer; - document.getElementById("refre_slider").removeAttribute('hidden'); - //} - - for (var i = 0; i < layer_list.length; ++i) { - const Objbox = new THREE.Box3().setFromObject(layer_list[i]); - GLBox3D.union(Objbox); - layer_list[i].children[0].material.side = THREE.DoubleSide; - if (typeof layer_list[i].children[0].nLayer !== "undefined") { - scene.add(layer_list[i]); - } - } - const BoxHelper = new THREE.Box3Helper(GLBox3D, 0xffff00); - // setting camera position - const vtCenter = new THREE.Vector3(0, 0, 0); - GLBox3D.getCenter(vtCenter); - const vtPosition = vtCenter.clone().multiplyScalar(5); - const vtBoxDim = new THREE.Vector3(0, 0, 0); - GLBox3D.getSize(vtBoxDim); - - - - // camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 30000); - // camera.position.set(2 * vtBoxDim.x, 2 * vtBoxDim.y, 2 * vtBoxDim.z); - // camera.lookAt(vtCenter.x, vtCenter.y, vtCenter.z); - // scene.add(camera); - - perspectiveCamera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 300000 ); - //perspectiveCamera.up = new THREE.Vector3( 0, 0, 1) ; - orthographicCamera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, - window.innerHeight / 2, window.innerHeight / - 2, - -300000, 300000) ; - //orthographicCamera.up = new THREE.Vector3( 0, 0, 1) ; - if ( ! m_bIsOrtographic) - activeCamera = perspectiveCamera ; - else - activeCamera = orthographicCamera ; - activeCamera.position.set( 2 * vtBoxDim.x, 2 * vtBoxDim.y, 2 * vtBoxDim.z) ; - activeCamera.lookAt( vtCenter.x, vtCenter.y, vtCenter.z) ; - scene.add( activeCamera) ; - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d); - hemiLight.position.set(vtCenter.x, vtCenter.y + 2 * vtBoxDim.y, vtCenter.z); - scene.add(hemiLight); - var HemisphereLightHelper = new THREE.Mesh(new THREE.SphereGeometry(15, 30, 15), - new THREE.MeshStandardMaterial({ color: 0xffffff, emissive: 0x404040 })); - HemisphereLightHelper.position.set(vtCenter.x, vtCenter.y + 2 * vtBoxDim.y, vtCenter.z); - - - const dirLight = new THREE.DirectionalLight(0xffffff); - dirLight.position.set(vtPosition.x, vtPosition.y, vtPosition.z); - dirLight.castShadow = true; - dirLight.shadow.camera.top = 50; - dirLight.shadow.camera.bottom = - 25; - dirLight.shadow.camera.left = - 25; - dirLight.shadow.camera.right = 25; - dirLight.shadow.camera.near = 0.1; - dirLight.shadow.camera.far = 200; - dirLight.shadow.mapSize.set(1024, 1024); - scene.add(dirLight); - const DirLighthelper = new THREE.DirectionalLightHelper(dirLight, 100); - - - const ground = new THREE.Mesh(new THREE.PlaneGeometry(10000, 10000), - new THREE.MeshPhongMaterial({ color: 0x36454F, depthWrite: true, })); - ground.rotation.x = - Math.PI / 2; - ground.position.y = -0.5; - ground.receiveShadow = true; - ground.material.opacity = 0.25; - ground.material.transparent = true; - ground.material.side = THREE.DoubleSide; - //scene.add( ground); - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - - var container = document.getElementById('WebGL-3mfExport'); - - container.style.height = '100%'; - container.style.width = '100%'; - - renderer.setSize(m_divStartDimX, m_divStartDimY); - renderer.shadowMap.enabled = true; - renderer.shadowMap.type = THREE.PCFSoftShadowMap; - - container.appendChild(renderer.domElement); - - var cont = document.getElementById('spinContainer'); - container.removeChild(cont); - - - controls = new OrbitControls(activeCamera, renderer.domElement); - controls.addEventListener('change', render); - - controls.update(); - - window.addEventListener('resize', onWindowResize); - -// calcolo origine - const points_array = [ new THREE.Vector3( 0, 0, 0)] ; - var ORIG_Geometry = new THREE.BufferGeometry() ; - ORIG_Geometry.setFromPoints( points_array) ; - var ORIG_Material = new THREE.PointsMaterial({ size: 5, sizeAttenuation : true, color : new THREE.Color( 0x000000)}); - ORIG = new THREE.Points( ORIG_Geometry, ORIG_Material) ; - SetOrig( ORIG) ; - - // creazione sistema di riferimento nell'origine - const axesHelper = new THREE.AxesHelper( 75 ) ; - axesHelper.rotation.set( -Math.PI/2, 0 ,0) ; - axesHelper.position.set( ORIG.position.x, ORIG.position.y, ORIG.position.z) ; - scene.add( axesHelper ); - - // creazione della griglia (V1 = finita, V2 = infinita) - const size = 1000000 ; - const divisions = 10000 ; - if ( ! m_bGrid_v1) { - // GRIGLIA INFINITA - const gridHelper = new THREE.GridHelper( size, divisions) ; - gridHelper.position.set( ORIG.position.x, ORIG.position.y, ORIG.position.z) ; - gridHelper.material.transparent = true ; - gridHelper.material.opacity = 0.25 ; - setFog() ; - scene.add( gridHelper) ; - } - else { - // GRIGLIA FINITA - // prendo dimensione del Box - var dDimX = Math.abs( GLBox3D.max.x - GLBox3D.min.x) ; - var dDimY = Math.abs( GLBox3D.max.y - GLBox3D.min.y) ; - var dDimZ = Math.abs( GLBox3D.max.z - GLBox3D.min.z) ; - var dDim = 1.5 * Math.sqrt( dDimX * dDimX + dDimY * dDimY + dDimZ * dDimZ) ; - const gridHelper = new THREE.GridHelper( dDim, Math.ceil( 0.1 * dDim)) ; - gridHelper.position.set( ORIG.position.x + 0.5 * dDim , ORIG.position.y, ORIG.position.z - 0.5 * dDim) ; - gridHelper.material.transparent = true ; - gridHelper.material.opacity = 0.45 ; - scene.add( gridHelper) ; +function init3dm(){ + return new Promise(() => { + setTimeout(() => { + loader.setLibraryPath( 'https://cdn.jsdelivr.net/npm/rhino3dm@7.15.0/' ) ; + loader.load( './models/3dm/Ex' + FileNumber + '.3dm', m_nApproxIndex, function ( object ) { + object.traverse( function( child) { + child.castShadow = true ; + }) ; - } + // Ref systems + const Mat_GlobToLoc = new THREE.Matrix4() ; //<---- rotations for XY plane from Extrusion + const Mat_LocToGlob = new THREE.Matrix4() ; //<---- rotations for Extrusion from XY plane + const Mat_ThreeJs_Frame = new THREE.Matrix4() ; // <----- rotations from XYZ ref system to ThreeJS system + Mat_ThreeJs_Frame.set( 1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1) ; + var Mat_ToScene = new THREE.Matrix4() ; + // Extrusion settings for curves + const extrudeSettings = { + steps: 1, + depth: 0, + bevelEnabled: false, + bevelThickness: 1, + bevelSize: 1, + bevelOffset: 0, + bevelSegments: 1 + } ; + // loading entities... + for ( var i = 0 ; i < object.children.length ; ++ i) { + // getting i-th object + var child = object.children[i] ; + //console.log( child); - render(); + // READING A POINT TYPE ----------------------------------------------------------------- + if ( child.type == 'Points') { + try { + if ( child.name != 'Orig') { + console.log( 'Not a valid origin') ; + return false ; + } + // start layer + nStartLayer = parseInt( child.userData.attributes.layerIndex) ; + // ORIGIN ------------------------ + var coord = child.userData.attributes.geometry.location ; + var orig_x = parseFloat( coord[0]) ; + var orig_y = parseFloat( coord[2]) ; + var orig_z = - parseFloat( coord[1]) ; + ORIG = new THREE.Vector3( orig_x, orig_y, orig_z) ; + // EXTRUSION --------------------- + var bOk_ext = false ; + if ( child.userData.attributes.userStrings[1][0] == 'SlicingDir') { + var sExtr = child.userData.attributes.userStrings[1][1] ; + if ( sExtr != "" ) { + let sExtr_arr = sExtr.split(',') ; + if ( sExtr_arr.length == 3) { + var dExtr_x = parseFloat( sExtr_arr[0]) ; + var dExtr_y = parseFloat( sExtr_arr[1]) ; + var dExtr_z = parseFloat( sExtr_arr[2]) ; + vtExtr = new THREE.Vector3( dExtr_x, dExtr_y, dExtr_z) ; + bOk_ext = true ; + } + } + } + if ( ! bOk_ext) { + console.log( ' Not a valid Extrusion') ; + return false ; + } + var Z_AX = new THREE.Vector3( vtExtr.x, vtExtr.y, vtExtr.z) ; + var X_AX = new THREE.Vector3() ; + var Y_AX = new THREE.Vector3() ; + if ( ! Z_AX.equals( new THREE.Vector3( 0, 0, 1))) { + X_AX.crossVectors( new THREE.Vector3( 0, 0, 1), Z_AX) ; + Y_AX.crossVectors( Z_AX, X_AX) ; + } + else { + X_AX = new THREE.Vector3( 1, 0, 0) ; + Y_AX = new THREE.Vector3( 0, 1, 0) ; + } + Mat_GlobToLoc.set( X_AX.x, X_AX.y, X_AX.z, 0, + Y_AX.x, Y_AX.y, Y_AX.z, 0, + Z_AX.x, Z_AX.y, Z_AX.z, 0, + 0, 0, 0, 1) ; + Mat_LocToGlob.copy( Mat_GlobToLoc) ; + Mat_LocToGlob.invert() ; + Mat_ToScene.multiplyMatrices( Mat_ThreeJs_Frame, Mat_LocToGlob) ; + // STRAND ------------------------- + if ( child.userData.attributes.userStrings[0][0] == 'StrandH') { + dStrand = - parseFloat( child.userData.attributes.userStrings[0][1]) ; + extrudeSettings.depth = dStrand ; + } + else { + console.log( ' Not a valid Strand') ; + return false ; + } + } + catch( error) { + console.log( 'Orig, Extrusion or Strand missing or not implemented') ; + return false ; + } + } + // READING A LINE ----------------------------------------------------------------------- + else if ( child.type == 'Line') { + // Parsing the extrusion and the Layer of the curve + try { + var nLayer = parseInt( child.userData.attributes.layerIndex) - nStartLayer ; + if ( nLayer < 0) + return false ; + + var points_array = child.geometry.attributes.position.array ; + //var ptPrec ; + const shape = new THREE.Shape() ; + for ( var v = 0 ; v < points_array.length ; v += 3) { + var Zact ; + var vtCoord = new THREE.Vector4( points_array[v], points_array[v+1], points_array[v+2], 1) ; + vtCoord.applyMatrix4( Mat_GlobToLoc) ; + //if ( v != 0 && v < points_array.length - 3 && + // (( vtCoord.x - ptPrec.x) * ( vtCoord.x - ptPrec.x) + + // ( vtCoord.y - ptPrec.y) * ( vtCoord.y - ptPrec.y) + + // ( vtCoord.z - ptPrec.z) * ( vtCoord.z - ptPrec.z)) < 10) + // continue ; + if ( v == 0) { + shape.moveTo( vtCoord.x, vtCoord.y) ; + Zact = vtCoord.z ; + } + else + shape.lineTo( vtCoord.x, vtCoord.y) ; + //ptPrec = new THREE.Vector4( vtCoord.x, vtCoord.y, vtCoord.z, 1) ; + } + var cCol = child.material.color.clone() ; + if ( nLayer%2 == 0) { + cCol.lerp( new THREE.Color( 0x000000 ), 0.25) ; + } + const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings) ; + const material = new THREE.MeshLambertMaterial({ color: cCol, + wireframe : false, + shadowSide : THREE.DoubleSide}) ; + const mesh = new THREE.Mesh( geometry, material) ; + mesh.translateZ( Zact) ; + //mesh.applyMatrix4( Mat_LocToGlob) ; + //mesh.applyMatrix4( Mat_ThreeJs_Frame) ; + mesh.applyMatrix4( Mat_ToScene) ; + mesh.nLayer = nLayer ; + mesh.isArrow = false ; + layer_list.push( mesh) ; + + } catch( err) { + console.log( ' Not a valid Layer for paths') ; + return false ; + } + } + // READING ARROW'S MESH + else if ( child.type == 'Mesh') { + + try { + if ( child.name != 'Arrow') { + //console.log( 'Not a valid Arrow direction') ; + //return false ; + child.nLayer = 1 ; + layer_list.push( child) ; + continue ; + } + var nLayer = parseInt( child.userData.attributes.layerIndex) - nStartLayer ; + if ( nLayer < 0) + return false ; + child.isArrow = true ; + child.applyMatrix4( Mat_ThreeJs_Frame) ; + child.nLayer = nLayer ; + child.material.color = new THREE.Color( 0xff0000) ; + layer_list.push( child) ; + + } catch( e) { + console.log( 'Not a valid Arrow direction') ; + return false ; + } + } + // READING OTHER ENTITY -------------------- + else + continue ; - - // TEST =================================== - setCameraZoom(m_bZoom); - setCameraPan(m_bPan); - setCameraRot(m_bRot); - setCameraAutoRot(m_bAutoRot); - SetCameraPos( m_nCameraStartPos, ORIG) ; - // ========================================= - - //console.log('aggiunto 1'); + } + AdaptSeceneToContest() ; + console.log(new Date()) ; + }) ; + }, 0) + }) } function refreshElement(nStart, nEnd) { @@ -478,8 +540,124 @@ function SetOrig( ORIG) { // ----------------------- //scene.add( ORIG) ; } + function setFog() { - var dNear = GLBox3D.max.x + 3 * ( GLBox3D.max.x - GLBox3D.min.x) ; - var dFar = 10000 ; - scene.fog = new THREE.Fog( 0xa0a0a0, 20000, 30000); -} \ No newline at end of file + // var dNear = GLBox3D.max.x + 3 * ( GLBox3D.max.x - GLBox3D.min.x) ; + // var dFar = 10000 ; + // scene.fog = new THREE.Fog( 0xa0a0a0, 20000, 30000); +} + +function AddFrame( ptORIG) { + + if ( ! m_bShowFrame) + return ; + + if ( m_bFrameType == 0) { + const axesHelper = new THREE.AxesHelper( m_lFrameLen) ; + axesHelper.rotation.set( -Math.PI/2, 0 , 0) ; + axesHelper.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + scene.add( axesHelper ) ; + } + else if ( m_bFrameType == 1) { + var vtDirs = [ new THREE.Vector3( 1, 0, 0), new THREE.Vector3( 0, 0, -1), new THREE.Vector3( 0, 1, 0)] ; + var vtCols = [ new THREE.Color( 0xff0000), new THREE.Color( 0x00ff00), new THREE.Color( 0x0000ff)] ; + var vtORIG = new THREE.Vector3( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + for ( var i = 0 ; i < 3 ; ++ i) { + const arrowHelper = new THREE.ArrowHelper( vtDirs[i], vtORIG, m_lFrameLen, vtCols[i]) ; + scene.add( arrowHelper ) ; + } + } + else if ( m_bFrameType == 2) { + var vtCols = [ new THREE.Color( 0x0000ff), new THREE.Color( 0xff0000), new THREE.Color( 0x00ff00)] ; + for ( var i = 0 ; i < 3 ; ++ i) { + // cylinder ---- + const fr_geometry_cyl = new THREE.CylinderGeometry( m_dFrameFat, m_dFrameFat, 0.8 * m_lFrameLen, 32) ; + const fr_material = new THREE.MeshBasicMaterial({color: vtCols[i]}) ; + const fr_cylinder = new THREE.Mesh( fr_geometry_cyl, fr_material) ; + fr_cylinder.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + if ( i == 1) + fr_cylinder.rotation.set( 0, 0, -Math.PI/2) ; + if ( i == 2) + fr_cylinder.rotation.set( -Math.PI/2, 0, 0) ; + scene.add( fr_cylinder) ; + fr_cylinder.translateY( 0.4 * m_lFrameLen) ; + // pyramid + const fr_geometry_cone = new THREE.CylinderGeometry( 0, 2 * m_dFrameFat, 0.2 * m_lFrameLen, 32) ; + const fr_cone = new THREE.Mesh( fr_geometry_cone, fr_material) ; + fr_cone.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + if ( i == 1) + fr_cone.rotation.set( 0, 0, -Math.PI/2) ; + if ( i == 2) + fr_cone.rotation.set( -Math.PI/2, 0, 0) ; + scene.add( fr_cone) ; + fr_cone.translateY( 0.9 * m_lFrameLen) ; + } + // Origin + const fr_orig_geometry = new THREE.SphereGeometry( 2 * m_dFrameFat, 32, 16) ; + const fr_orig_material = new THREE.MeshBasicMaterial( {color: 0x00000}) ; + const fr_sphere = new THREE.Mesh( fr_orig_geometry, fr_orig_material) ; + fr_sphere.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + scene.add( fr_sphere) ; + } + else + console.log( 'Frame type not defined') ; +} + +function AddGrid( ptORIG) { + + if ( ! m_bShowGrid) + return ; + + const size = 1000000 ; + const divisions = 10000 ; + if ( m_bInfGrid) { + const gridHelper = new THREE.GridHelper( size, divisions) ; + gridHelper.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + gridHelper.material.transparent = true ; + gridHelper.material.opacity = 0.25 ; + setFog() ; + scene.add( gridHelper) ; + } + else { + var dDimX = Math.abs( GLBox3D.max.x - GLBox3D.min.x) ; + var dDimY = Math.abs( GLBox3D.max.y - GLBox3D.min.y) ; + var dDimZ = Math.abs( GLBox3D.max.z - GLBox3D.min.z) ; + var dDim = 1.5 * Math.sqrt( dDimX * dDimX + dDimY * dDimY + dDimZ * dDimZ) ; + const gridHelper = new THREE.GridHelper( dDim, Math.ceil( 0.1 * dDim)) ; + gridHelper.position.set( ptORIG.position.x + 0.5 * dDim , ptORIG.position.y, ptORIG.position.z - 0.5 * dDim) ; + gridHelper.material.transparent = true ; + gridHelper.material.opacity = 0.45 ; + scene.add( gridHelper) ; + } +} + +function ManageSceneElements( e) { + if ( e.srcElement.id == 'bt_refresh') { + nLayerStart = parseInt( document.getElementById('Layer_Start').value) ; + nLayerEnd = parseInt( document.getElementById('Layer_End').value) ; + for ( var i = 0 ; i < layer_list.length ; ++ i) { + if ( parseInt( layer_list[i].nLayer) >= nLayerStart && + parseInt( layer_list[i].nLayer) <= nLayerEnd) { + if ( layer_list[i].isArrow) + layer_list[i].visible = document.getElementById( 'ck_dir').checked ; + else + layer_list[i].visible = true ; + } + else { + layer_list[i].visible = false ; + } + } + } + else if ( e.srcElement.id = 'ck_dir') { + for ( var i = 0 ; i < layer_list.length ; ++ i) { + if ( layer_list[i].isArrow) { + if ( layer_list[i].nLayer >= nLayerStart && + layer_list[i].nLayer <= nLayerEnd) + layer_list[i].visible = document.getElementById( 'ck_dir').checked ; + else + layer_list[i].visible = false ; + } + } + } + render() ; + } \ No newline at end of file diff --git a/WebGl/draw/webgl_drawVue.js b/WebGl/draw/webgl_drawVue.js index 3466693..1ee54ae 100644 --- a/WebGl/draw/webgl_drawVue.js +++ b/WebGl/draw/webgl_drawVue.js @@ -1,41 +1,75 @@ import * as THREE from '../threeJsLib/three.module.js'; import { OrbitControls } from '../jsm/controls/OrbitControls.js'; import { ThreeMFLoader } from '../jsm/loaders/3MFLoader.js'; +import { Rhino3dmLoader } from '../jsm/loaders/3DMLoader.js'; // VARIABILI DI CONTROLLO + +// *** div dimensions *** var m_divStartDimX = 500; var m_divStartDimY = 400; -var fName = "Cubo.3mf"; -var m_fileSource = ''; + +var fName = ""; +//var fileType = "3MF"; + +var fileType = '3DM'; + +var m_nApproxIndex = 5; + +var m_bShowDir = true; + +// *** camera settings *** var m_bZoom = true; var m_bPan = true; var m_bRot = true; -var m_bAutoRot = false; -var m_bGrid_v1 = true; -var m_nCameraStartPos = 8; -//var useInSlider = false; -var m_nCamPos = 0; -var m_nStartL = 0; -var m_nEndL = 0; +var m_nCameraStartPos = 8 ; var m_bIsOrtographic = true ; +// *** index blender *** +var m_nStartL = 0; +var m_nEndL = 1000000; + +// *** frame settings *** +var m_bShowFrame = true ; +var m_lFrameLen = 100 ; +var m_dFrameFat = 2; // raggio del cilindro +var m_bFrameType = 2 ; + +var m_bAutoRot = false; + +// *** grid settings *** +var m_bShowGrid = true ; +var m_bInfGrid = true ; + +// *** Direction Arrows *** +var m_bShowPrintDir = true ; + +var modelsDir = '' ; + +//var useInSlider = false; var counter = 0; -var modelsDir = ""; +var nStartLayer = -100000 ; +var ORIG = new THREE.Vector3( 0, 0, 0), vtExtr = new THREE.Vector3( 0, 1, 0), dStrand ; -let activeCamera, scene, renderer, controls, ORIG, perspectiveCamera, orthographicCamera; +let activeCamera, scene, renderer, controls, perspectiveCamera, orthographicCamera; var layer_list = []; const GLBox3D = new THREE.Box3(); // Box3D globale delle geometrie //init(); class webgl_original { - async initcall({ _dimX, _dimY, _fileName, _showLimitedGrid, _isOrtographic, _modelsDir}) { + async initcall({ _dimX, _dimY, _fileName, _showInfiniteGrid, _fileType, _modelsDir, _showGrid, _showFrame, _frameType, _frameLen, _frameFat}) { m_divStartDimX = _dimX; m_divStartDimY = _dimY; + m_bShowGrid = _showGrid; fName = _fileName; - m_bGrid_v1 = _showLimitedGrid; - m_bIsOrtographic = _isOrtographic; + m_bInfGrid = _showInfiniteGrid; modelsDir = _modelsDir; + fileType = _fileType; + m_bShowFrame = _showFrame; + m_bFrameType = _frameType; + m_lFrameLen = _frameLen; + m_dFrameFat = _frameFat; //console.log(fName) - //setLoaders(); + setLoaders(); await init(); } @@ -50,41 +84,23 @@ class webgl_original { resetCamera() { SetCameraPos( m_nCameraStartPos, ORIG) ; } + + showPrintDirection(showDir) { + ShowPrintDir(showDir) ; + } } export { webgl_original } -function toggleCamera( perspectiveCamera, orthographicCamera) { // <----------------- - var cameraPosition = activeCamera.position.clone() ; - var cameraMatrix = activeCamera.matrix.clone() ; - var ControlsTarget = controls.target.clone() ; - var ControlsPosition = controls.position0.clone() ; - - if ( m_bIsOrtographic == true) { - m_bIsOrtographic = false ; - activeCamera = perspectiveCamera ; - activeCamera.position.copy( cameraPosition) ; - activeCamera.matrix.copy( cameraMatrix) ; - } else { - m_bIsOrtographic = true ; - activeCamera = orthographicCamera ; - activeCamera.position.copy( cameraPosition) ; - activeCamera.matrix.copy( cameraMatrix) ; - } - - activeCamera.updateProjectionMatrix() ; - controls.object = activeCamera ; - controls.target = ControlsTarget ; - controls.position0 = ControlsPosition ; - controls.update() ; - render() ; -} - function setLoaders() { // - const mother = document.getElementById('WebGL-3mfExport'); + let mother = document.getElementById('WebGL-Export'); + if(fileType.toUpperCase() == '3DM') + { + mother = document.getElementById('WebGL-Export') + } const spinContainer = document.createElement('div'); const sliderInput = document.createElement('input'); @@ -99,11 +115,11 @@ function setLoaders() { //if (useInSlider) { - //mother.appendChild(sliderInput); - //sliderInput.setAttribute('id', 'refre_slider'); - //sliderInput.setAttribute('hidden', true); - //sliderInput.type = 'range'; - //sliderInput.min = '0'; + mother.appendChild(sliderInput); + sliderInput.setAttribute('id', 'refre_slider'); + sliderInput.setAttribute('hidden', true); + sliderInput.type = 'range'; + sliderInput.min = '0'; //} mother.appendChild(spinContainer); //document.body.appendChild(spinContainer); @@ -168,6 +184,7 @@ function setLoaders() { cDiv[i].style.width = '100%'; cDiv[i].style.border = '#afc5d6'; cDiv[i].style.backgroundSize = 'contain'; + // cDiv[i].style.backgroundColor = '#000'; cDiv[i].style.backgroundImage = 'url(../node_modules/webgl-visualizer/styles/LogoClassic_NoText.png)' } @@ -187,73 +204,310 @@ function setLoaders() { } -function init() { - const manager = new THREE.LoadingManager(); - const loader = new ThreeMFLoader(manager); - let startTime = performance.now(); +function init3mf() { + const manager = new THREE.LoadingManager() ; + const loader = new ThreeMFLoader( manager) ; + let startTime = performance.now(); return new Promise(() => { setTimeout(() => { - loader.load(modelsDir + fName, function (object) { - object.rotation.set(-Math.PI / 2, 0, 0); - object.traverse(function (child) { - child.castShadow = true; - }); - for (var i = 0; i < object.children.length; ++i) { - var child = object.children[i]; - child.rotation.set(-Math.PI / 2, 0, 0); - layer_list.push(child); + loader.load( modelsDir + fName, function ( object) { + object.rotation.set( -Math.PI / 2, 0, 0) ; + console.log( object) ; + for ( var i = 0 ; i < object.children.length ; ++ i) { + var child = object.children[i] ; + child.rotation.set( -Math.PI/2, 0 ,0) ; + layer_list.push( child) ; } - //console.log(layer_list); - AdaptSceneToContest(); - // Adapting Scene to contest + // Adapting Scene to contest + AdaptSeceneToContest() ; let endTime = performance.now(); let timeElapsed = endTime - startTime; - console.log('init in : ' + timeElapsed) - }); + console.log('init3mf in : ' + timeElapsed) + console.log( new Date()) ; + }) ; }, 0); }); } -function AdaptSceneToContest() { - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - //if (useInSlider) { +function init3dm(){ + const loader = new Rhino3dmLoader() ; + let startTime = performance.now(); + return new Promise(() => { + setTimeout(() => { + loader.setLibraryPath( 'https://cdn.jsdelivr.net/npm/rhino3dm@7.15.0/' ) ; + loader.load( modelsDir + fName, m_nApproxIndex, function ( object ) { + object.traverse( function( child) { + child.castShadow = true ; + }) ; + + // Ref systems + const Mat_GlobToLoc = new THREE.Matrix4() ; //<---- rotations for XY plane from Extrusion + const Mat_LocToGlob = new THREE.Matrix4() ; //<---- rotations for Extrusion from XY plane + const Mat_ThreeJs_Frame = new THREE.Matrix4() ; // <----- rotations from XYZ ref system to ThreeJS system + Mat_ThreeJs_Frame.set( 1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1) ; + var Mat_ToScene = new THREE.Matrix4() ; + // Extrusion settings for curves + const extrudeSettings = { + steps: 1, + depth: 0, + bevelEnabled: false, + bevelThickness: 1, + bevelSize: 1, + bevelOffset: 0, + bevelSegments: 1 + } ; + // loading entities... + for ( var i = 0 ; i < object.children.length ; ++ i) { + // getting i-th object + var child = object.children[i] ; + //console.log( child); - //document.getElementById("refre_slider").max = layer_list[layer_list.length - 1].children[0].nLayer; - //document.getElementById("refre_slider").value = layer_list[layer_list.length - 1].children[0].nLayer; - //document.getElementById("refre_slider").removeAttribute('hidden'); - //} + // READING A POINT TYPE ----------------------------------------------------------------- + if ( child.type == 'Points') { + try { + if ( child.name != 'Orig') { + console.log( 'Not a valid origin') ; + return false ; + } + // start layer + nStartLayer = parseInt( child.userData.attributes.layerIndex) ; + // ORIGIN ------------------------ + var coord = child.userData.attributes.geometry.location ; + var orig_x = parseFloat( coord[0]) ; + var orig_y = parseFloat( coord[2]) ; + var orig_z = - parseFloat( coord[1]) ; + ORIG = new THREE.Vector3( orig_x, orig_y, orig_z) ; + // EXTRUSION --------------------- + var bOk_ext = false ; + if ( child.userData.attributes.userStrings[1][0] == 'SlicingDir') { + var sExtr = child.userData.attributes.userStrings[1][1] ; + if ( sExtr != "" ) { + let sExtr_arr = sExtr.split(',') ; + if ( sExtr_arr.length == 3) { + var dExtr_x = parseFloat( sExtr_arr[0]) ; + var dExtr_y = parseFloat( sExtr_arr[1]) ; + var dExtr_z = parseFloat( sExtr_arr[2]) ; + vtExtr = new THREE.Vector3( dExtr_x, dExtr_y, dExtr_z) ; + bOk_ext = true ; + } + } + } + if ( ! bOk_ext) { + console.log( ' Not a valid Extrusion') ; + return false ; + } + var Z_AX = new THREE.Vector3( vtExtr.x, vtExtr.y, vtExtr.z) ; + var X_AX = new THREE.Vector3() ; + var Y_AX = new THREE.Vector3() ; + if ( ! Z_AX.equals( new THREE.Vector3( 0, 0, 1))) { + X_AX.crossVectors( new THREE.Vector3( 0, 0, 1), Z_AX) ; + Y_AX.crossVectors( Z_AX, X_AX) ; + } + else { + X_AX = new THREE.Vector3( 1, 0, 0) ; + Y_AX = new THREE.Vector3( 0, 1, 0) ; + } + Mat_GlobToLoc.set( X_AX.x, X_AX.y, X_AX.z, 0, + Y_AX.x, Y_AX.y, Y_AX.z, 0, + Z_AX.x, Z_AX.y, Z_AX.z, 0, + 0, 0, 0, 1) ; + Mat_LocToGlob.copy( Mat_GlobToLoc) ; + Mat_LocToGlob.invert() ; + Mat_ToScene.multiplyMatrices( Mat_ThreeJs_Frame, Mat_LocToGlob) ; + // STRAND ------------------------- + if ( child.userData.attributes.userStrings[0][0] == 'StrandH') { + dStrand = - parseFloat( child.userData.attributes.userStrings[0][1]) ; + extrudeSettings.depth = dStrand ; + } + else { + console.log( ' Not a valid Strand') ; + return false ; + } + } + catch( error) { + console.log( 'Orig, Extrusion or Strand missing or not implemented') ; + return false ; + } + } + // READING A LINE ----------------------------------------------------------------------- + else if ( child.type == 'Line') { + // Parsing the extrusion and the Layer of the curve + try { + var nLayer = parseInt( child.userData.attributes.layerIndex) - nStartLayer ; + if ( nLayer < 0) + return false ; + + var points_array = child.geometry.attributes.position.array ; + //var ptPrec ; + const shape = new THREE.Shape() ; + for ( var v = 0 ; v < points_array.length ; v += 3) { + var Zact ; + var vtCoord = new THREE.Vector4( points_array[v], points_array[v+1], points_array[v+2], 1) ; + vtCoord.applyMatrix4( Mat_GlobToLoc) ; + //if ( v != 0 && v < points_array.length - 3 && + // (( vtCoord.x - ptPrec.x) * ( vtCoord.x - ptPrec.x) + + // ( vtCoord.y - ptPrec.y) * ( vtCoord.y - ptPrec.y) + + // ( vtCoord.z - ptPrec.z) * ( vtCoord.z - ptPrec.z)) < 10) + // continue ; + if ( v == 0) { + shape.moveTo( vtCoord.x, vtCoord.y) ; + Zact = vtCoord.z ; + } + else + shape.lineTo( vtCoord.x, vtCoord.y) ; + //ptPrec = new THREE.Vector4( vtCoord.x, vtCoord.y, vtCoord.z, 1) ; + } + var cCol = child.material.color.clone() ; + if ( nLayer%2 == 0) { + cCol.lerp( new THREE.Color( 0x000000 ), 0.25) ; + } + const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings) ; + const material = new THREE.MeshLambertMaterial({ color: cCol, + wireframe : false, + shadowSide : THREE.DoubleSide}) ; + const mesh = new THREE.Mesh( geometry, material) ; + mesh.translateZ( Zact) ; + //mesh.applyMatrix4( Mat_LocToGlob) ; + //mesh.applyMatrix4( Mat_ThreeJs_Frame) ; + mesh.applyMatrix4( Mat_ToScene) ; + mesh.nLayer = nLayer ; + mesh.isArrow = false ; + layer_list.push( mesh) ; + + } catch( err) { + console.log( ' Not a valid Layer for paths') ; + return false ; + } + } + // READING ARROW'S MESH + else if ( child.type == 'Mesh') { + + try { + if ( child.name != 'Arrow') { + //console.log( 'Not a valid Arrow direction') ; + //return false ; + child.nLayer = 1 ; + layer_list.push( child) ; + continue ; + } + var nLayer = parseInt( child.userData.attributes.layerIndex) - nStartLayer ; + if ( nLayer < 0) + return false ; + child.isArrow = true ; + child.applyMatrix4( Mat_ThreeJs_Frame) ; + child.nLayer = nLayer ; + child.material.color = new THREE.Color( 0xff0000) ; + layer_list.push( child) ; + + } catch( e) { + console.log( 'Not a valid Arrow direction') ; + return false ; + } + } + // READING OTHER ENTITY -------------------- + else + continue ; - for (var i = 0; i < layer_list.length; ++i) { - const Objbox = new THREE.Box3().setFromObject(layer_list[i]); - GLBox3D.union(Objbox); - layer_list[i].children[0].material.side = THREE.DoubleSide; - if (typeof layer_list[i].children[0].nLayer !== "undefined") { - scene.add(layer_list[i]); + } + AdaptSeceneToContest() ; + console.log(new Date()) ; + }) ; + let endTime = performance.now(); + let timeElapsed = endTime - startTime; + console.log('init3dm in : ' + timeElapsed) + }, 0) + }) + +} + +function refreshElement(nStart, nEnd) { + //console.log(parseInt(nStart)); + + m_nStartL = nStart; + m_nEndL = nEnd; + + if(fileType == "3DM"){ + for ( var i = 0 ; i < layer_list.length ; ++ i) { + if ( parseInt( layer_list[i].nLayer) >= nStart && + parseInt( layer_list[i].nLayer) <= nEnd) { + if ( layer_list[i].isArrow) + layer_list[i].visible = m_bShowDir ; + else + layer_list[i].visible = true ; + } + else { + layer_list[i].visible = false ; + } + } + + } + else if (fileType == "3MF"){ + + for ( var i = 0 ; i < layer_list.length ; ++ i) { + if ( parseInt( layer_list[i].children[0].nLayer) >= nStart && + parseInt( layer_list[i].children[0].nLayer) <= nEnd) { + if ( layer_list[i].children[0].isArrow) + layer_list[i].visible = m_bShowDir ; + else + layer_list[i].visible = true ; + } + else { + layer_list[i].visible = false ; + } } } - const BoxHelper = new THREE.Box3Helper(GLBox3D, 0xffff00); - // setting camera position - const vtCenter = new THREE.Vector3(0, 0, 0); - GLBox3D.getCenter(vtCenter); - const vtPosition = vtCenter.clone().multiplyScalar(5); - const vtBoxDim = new THREE.Vector3(0, 0, 0); - GLBox3D.getSize(vtBoxDim); + render(); +} +function AdaptSeceneToContest() { + + scene = new THREE.Scene(); + scene.background = new THREE.Color( 0xa0a0a0) ; + + // Global Box ---------- + if(fileType == "3DM"){ + for ( var i = 0 ; i < layer_list.length ; ++ i) { + const Objbox = new THREE.Box3().setFromObject( layer_list[i]); + GLBox3D.union( Objbox) ; + layer_list[i].material.side = THREE.DoubleSide ; + layer_list[i].castShadow = true + if ( ! layer_list[i].isArrow || m_bShowPrintDir) + scene.add( layer_list[i]) ; + } + } + else if(fileType == "3MF"){ + for ( var i = 0 ; i < layer_list.length ; ++ i) { + if ( layer_list[i].children[0].type == 'Mesh') { + const Objbox = new THREE.Box3().setFromObject( layer_list[i]); + GLBox3D.union( Objbox) ; + layer_list[i].children[0].material.side = THREE.DoubleSide ; + if ( typeof layer_list[i].children[0].nLayer !== "undefined") { + if ( parseInt( layer_list[i].children[0].nLayer)%2 == 0) + layer_list[i].children[0].material.color.lerp( new THREE.Color( 0x000000 ), 0.25) ; + layer_list[i].children[0].isArrow = ( layer_list[i].children[0].name == 'Arrow') + scene.add( layer_list[i]) ; + } + } + else if ( layer_list[i].type == 'Vector3') + ORIG = layer_list[i].children[0].clone() ; + } + } + const vtCenter = new THREE.Vector3( 0, 0, 0) ; + GLBox3D.getCenter( vtCenter) ; + const vtPosition = vtCenter.clone().multiplyScalar( 5) ; + const vtBoxDim = new THREE.Vector3( 0, 0, 0) ; + - // camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 30000); - // camera.position.set(2 * vtBoxDim.x, 2 * vtBoxDim.y, 2 * vtBoxDim.z); - // camera.lookAt(vtCenter.x, vtCenter.y, vtCenter.z); - // scene.add(camera); - - perspectiveCamera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 300000 ); - //perspectiveCamera.up = new THREE.Vector3( 0, 0, 1) ; + // orthographic and perspective camera ------ + perspectiveCamera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 10, 300000 ) ; orthographicCamera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - -300000, 300000) ; - //orthographicCamera.up = new THREE.Vector3( 0, 0, 1) ; + -300000, 300000) ; if ( ! m_bIsOrtographic) activeCamera = perspectiveCamera ; else @@ -261,17 +515,15 @@ function AdaptSceneToContest() { activeCamera.position.set( 2 * vtBoxDim.x, 2 * vtBoxDim.y, 2 * vtBoxDim.z) ; activeCamera.lookAt( vtCenter.x, vtCenter.y, vtCenter.z) ; scene.add( activeCamera) ; - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d); - hemiLight.position.set(vtCenter.x, vtCenter.y + 2 * vtBoxDim.y, vtCenter.z); - scene.add(hemiLight); - var HemisphereLightHelper = new THREE.Mesh(new THREE.SphereGeometry(15, 30, 15), - new THREE.MeshStandardMaterial({ color: 0xffffff, emissive: 0x404040 })); - HemisphereLightHelper.position.set(vtCenter.x, vtCenter.y + 2 * vtBoxDim.y, vtCenter.z); - - - const dirLight = new THREE.DirectionalLight(0xffffff); - dirLight.position.set(vtPosition.x, vtPosition.y, vtPosition.z); + + // Hemisphere light -------- + const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d ); + hemiLight.position.set( vtCenter.x, vtCenter.y + 2 * vtBoxDim.y, vtCenter.z); + scene.add( hemiLight ); + + // direction light -------- + const dirLight = new THREE.DirectionalLight( 0xffffff ); + dirLight.position.set( vtPosition.x, vtPosition.y, vtPosition.z); dirLight.castShadow = true; dirLight.shadow.camera.top = 50; dirLight.shadow.camera.bottom = - 25; @@ -279,140 +531,99 @@ function AdaptSceneToContest() { dirLight.shadow.camera.right = 25; dirLight.shadow.camera.near = 0.1; dirLight.shadow.camera.far = 200; - dirLight.shadow.mapSize.set(1024, 1024); - scene.add(dirLight); - const DirLighthelper = new THREE.DirectionalLightHelper(dirLight, 100); - - - const ground = new THREE.Mesh(new THREE.PlaneGeometry(10000, 10000), - new THREE.MeshPhongMaterial({ color: 0x36454F, depthWrite: true, })); - ground.rotation.x = - Math.PI / 2; - ground.position.y = -0.5; - ground.receiveShadow = true; - ground.material.opacity = 0.25; - ground.material.transparent = true; - ground.material.side = THREE.DoubleSide; - //scene.add( ground); - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - - var container = document.getElementById('WebGL-3mfExport'); - - container.style.height = '100%'; - container.style.width = '100%'; - - renderer.setSize(m_divStartDimX, m_divStartDimY); + dirLight.shadow.mapSize.set( 1024, 1024 ); + scene.add( dirLight ); + + // render settings --------- + renderer = new THREE.WebGLRenderer( { antialias: true }); + renderer.setPixelRatio( window.devicePixelRatio ); + var container = document.getElementById( 'WebGL-Export') ; + container.style.height = m_divStartDimY + "px"; + container.style.width = m_divStartDimX + "px"; + document.body.appendChild( container ); + renderer.setSize( m_divStartDimX, m_divStartDimY) ; renderer.shadowMap.enabled = true; - renderer.shadowMap.type = THREE.PCFSoftShadowMap; + renderer.shadowMap.type = THREE.PCFSoftShadowMap ; + container.appendChild( renderer.domElement) ; + var cont = document.getElementById('spinContainer'); + container.removeChild(cont); - container.appendChild(renderer.domElement); + // orbit controls ------- + controls = new OrbitControls( activeCamera, renderer.domElement ); + controls.addEventListener( 'change', render ); + controls.update() ; - //var cont = document.getElementById('spinContainer'); - //container.removeChild(cont); + // Orig conversion ----- + if(fileType == "3DM"){ - - controls = new OrbitControls(activeCamera, renderer.domElement); - controls.addEventListener('change', render); - - controls.update(); - - window.addEventListener('resize', onWindowResize); - -// calcolo origine - const points_array = [ new THREE.Vector3( 0, 0, 0)] ; - var ORIG_Geometry = new THREE.BufferGeometry() ; - ORIG_Geometry.setFromPoints( points_array) ; - var ORIG_Material = new THREE.PointsMaterial({ size: 5, sizeAttenuation : true, color : new THREE.Color( 0x000000)}); - ORIG = new THREE.Points( ORIG_Geometry, ORIG_Material) ; - SetOrig( ORIG) ; - - // creazione sistema di riferimento nell'origine - const axesHelper = new THREE.AxesHelper( 75 ) ; - axesHelper.rotation.set( -Math.PI/2, 0 ,0) ; - axesHelper.position.set( ORIG.position.x, ORIG.position.y, ORIG.position.z) ; - scene.add( axesHelper ); - - // creazione della griglia (V1 = finita, V2 = infinita) - const size = 1000000 ; - const divisions = 10000 ; - if ( ! m_bGrid_v1) { - // GRIGLIA INFINITA - const gridHelper = new THREE.GridHelper( size, divisions) ; - gridHelper.position.set( ORIG.position.x, ORIG.position.y, ORIG.position.z) ; - gridHelper.material.transparent = true ; - gridHelper.material.opacity = 0.25 ; - setFog() ; - scene.add( gridHelper) ; - } - else { - // GRIGLIA FINITA - // prendo dimensione del Box - var dDimX = Math.abs( GLBox3D.max.x - GLBox3D.min.x) ; - var dDimY = Math.abs( GLBox3D.max.y - GLBox3D.min.y) ; - var dDimZ = Math.abs( GLBox3D.max.z - GLBox3D.min.z) ; - var dDim = 1.5 * Math.sqrt( dDimX * dDimX + dDimY * dDimY + dDimZ * dDimZ) ; - const gridHelper = new THREE.GridHelper( dDim, Math.ceil( 0.1 * dDim)) ; - gridHelper.position.set( ORIG.position.x + 0.5 * dDim , ORIG.position.y, ORIG.position.z - 0.5 * dDim) ; - gridHelper.material.transparent = true ; - gridHelper.material.opacity = 0.45 ; - scene.add( gridHelper) ; - - } - - render(); - - - // TEST =================================== - setCameraZoom(m_bZoom); - setCameraPan(m_bPan); - setCameraRot(m_bRot); - setCameraAutoRot(m_bAutoRot); - SetCameraPos( m_nCameraStartPos, ORIG) ; - // ========================================= - - //console.log('aggiunto 1'); -} - -function refreshElement(nStart, nEnd) { - //console.log(parseInt(nStart)); - for (var i = 0; i < layer_list.length; ++i) { - if (parseInt(layer_list[i].children[0].nLayer) >= parseInt(nStart) && - parseInt(layer_list[i].children[0].nLayer) <= parseInt(nEnd)) { - layer_list[i].visible = true; - } - else { - layer_list[i].visible = false; - } + const points_array = [ new THREE.Vector3( ORIG.x, ORIG.y, ORIG.z)] ; + var ORIG_Geometry = new THREE.BufferGeometry() ; + ORIG_Geometry.setFromPoints( points_array) ; + var ORIG_Material = new THREE.PointsMaterial({ size: 5, sizeAttenuation : true, color : new THREE.Color( 0x000000)}) ; + var ptORIG = new THREE.Points( ORIG_Geometry, ORIG_Material) ; + ptORIG.position.x = ORIG.x ; + ptORIG.position.y = ORIG.y ; + ptORIG.position.z = ORIG.z ; + } - render(); + else if(fileType == "3MF"){ + + const points_array = [ new THREE.Vector3( 0, 0, 0)] ; + var ORIG_Geometry = new THREE.BufferGeometry() ; + ORIG_Geometry.setFromPoints( points_array) ; + var ORIG_Material = new THREE.PointsMaterial({ size: 5, sizeAttenuation : true, color : new THREE.Color( 0x000000)}); + var ptORIG = new THREE.Points( ORIG_Geometry, ORIG_Material) ; + ptORIG.position.x = ORIG.x ; + ptORIG.position.y = ORIG.z ; + ptORIG.position.z = - ORIG.y ; + } + + + + // inputs -------------- + setCameraZoom( m_bZoom) ; + setCameraPan( m_bPan) ; + setCameraRot( m_bRot) ; + SetCameraPos( m_nCameraStartPos, ORIG) ; + + // Frame + AddFrame( ptORIG) ; + + // Grid + AddGrid( ptORIG) ; + + // render + render() ; } -// Utility functions -function onWindowResize() { -} function render() { - renderer.render(scene, activeCamera); + renderer.render( scene, activeCamera) ; +} +function SetOrig( ORIG) { + // qui in qualche modo imposto l'origine, ora impostata secondo il BozHelper + // ---- codice da cambiare + var posX = GLBox3D.min.x - 0.3 * ( GLBox3D.max.x - GLBox3D.min.x) ; + var posY = 0 ; + var posZ = GLBox3D.min.z + 1.3 * ( GLBox3D.max.z - GLBox3D.min.z) ; + //ORIG.geometry.translate( posX, posY, posZ) ; + ORIG.position.set( posX, posY, posZ) ; + // ----------------------- + //scene.add( ORIG) ; + } +function setCameraZoom( bZoom) { + controls.enableZoom = bZoom ; } -function setCameraZoom(bZoom) { - controls.enableZoom = bZoom; +function setCameraPan( bPan) { + controls.enablePan = bPan ; } -function setCameraPan(bPan) { - controls.enablePan = bPan; +function setCameraRot( bRot) { + controls.enableRotate = bRot ; } - -function setCameraRot(bRot) { - controls.enableRotate = bRot; -} - -function setCameraAutoRot(bAutoRot) { - controls.autoRotate = bAutoRot; -} - -function SetCameraPos( nPos, ORIG) { - var nTraslFactor = 3.5 ; +function SetCameraPos( nPos, ptORIG) { + var nTraslFactor = 20 ; var x ; var y ; var z ; y = GLBox3D.max.y ; // fixed switch( nPos) { @@ -449,8 +660,8 @@ function SetCameraPos( nPos, ORIG) { z = GLBox3D.min.z ; break ; case 8 : // optimal - x = ( ORIG.position.x + 1.0 * Math.abs( GLBox3D.max.x - GLBox3D.min.x)) ; - z = ( ORIG.position.z + 1.0 * Math.abs( GLBox3D.max.z - GLBox3D.min.z)) ; + x = ( ORIG.x + 1.0 * Math.abs( GLBox3D.max.x - GLBox3D.min.x)) ; + z = ( ORIG.z + 1.0 * Math.abs( GLBox3D.max.z - GLBox3D.min.z)) ; break ; default : return ; @@ -460,29 +671,146 @@ function SetCameraPos( nPos, ORIG) { const vtCenter = new THREE.Vector3( 0, 0, 0) ; GLBox3D.getCenter( vtCenter) ; var vtDirOut = new THREE.Vector3( vtPos.x - vtCenter.x, vtPos.y - vtCenter.y, vtPos.z - vtCenter.z) ; vtDirOut.x *= nTraslFactor ; vtDirOut.y *= nTraslFactor ; vtDirOut.z *= nTraslFactor ; - //vtDirOut *= nTraslFactor ; - //x *= nTraslFactor ; - //y *= nTraslFactor ; - //z *= nTraslFactor ; activeCamera.position.set( x + vtDirOut.x, y + vtDirOut.y, z + vtDirOut.z) ; controls.target.set( vtCenter.x, vtCenter.y, vtCenter.z) ; - console.log( controls) ; + controls.minZoom = 0.25 ; + controls.maxDistance = 1.1 * activeCamera.position.distanceTo( controls.target) ; controls.update() ; } -function SetOrig( ORIG) { - // qui in qualche modo imposto l'origine, ora impostata secondo il BozHelper - // ---- codice da cambiare - var posX = GLBox3D.min.x - 0.3 * ( GLBox3D.max.x - GLBox3D.min.x) ; - var posY = 0 ; - var posZ = GLBox3D.min.z + 1.3 * ( GLBox3D.max.z - GLBox3D.min.z) ; - //ORIG.geometry.translate( posX, posY, posZ) ; - ORIG.position.set( posX, posY, posZ) ; - // ----------------------- - //scene.add( ORIG) ; +function toggleCamera( perspectiveCamera, orthographicCamera) { + var cameraPosition = activeCamera.position.clone() ; + var cameraMatrix = activeCamera.matrix.clone() ; + var ControlsTarget = controls.target.clone() ; + var ControlsPosition = controls.position0.clone() ; + + if ( m_bIsOrtographic == true) { + m_bIsOrtographic = false ; + activeCamera = perspectiveCamera ; + activeCamera.position.copy( cameraPosition) ; + activeCamera.matrix.copy( cameraMatrix) ; + } else { + m_bIsOrtographic = true ; + activeCamera = orthographicCamera ; + activeCamera.position.copy( cameraPosition) ; + activeCamera.matrix.copy( cameraMatrix) ; + } + + activeCamera.updateProjectionMatrix() ; + controls.object = activeCamera ; + controls.target = ControlsTarget ; + controls.position0 = ControlsPosition ; + controls.update() ; + render() ; +} +function AddFrame( ptORIG) { + + if ( ! m_bShowFrame) + return ; + + if ( m_bFrameType == 0) { + const axesHelper = new THREE.AxesHelper( m_lFrameLen) ; + axesHelper.rotation.set( -Math.PI/2, 0 , 0) ; + axesHelper.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + scene.add( axesHelper ) ; + } + else if ( m_bFrameType == 1) { + var vtDirs = [ new THREE.Vector3( 1, 0, 0), new THREE.Vector3( 0, 0, -1), new THREE.Vector3( 0, 1, 0)] ; + var vtCols = [ new THREE.Color( 0xff0000), new THREE.Color( 0x00ff00), new THREE.Color( 0x0000ff)] ; + var vtORIG = new THREE.Vector3( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + for ( var i = 0 ; i < 3 ; ++ i) { + const arrowHelper = new THREE.ArrowHelper( vtDirs[i], vtORIG, m_lFrameLen, vtCols[i]) ; + scene.add( arrowHelper ) ; + } + } + else if ( m_bFrameType == 2) { + var vtCols = [ new THREE.Color( 0x0000ff), new THREE.Color( 0xff0000), new THREE.Color( 0x00ff00)] ; + for ( var i = 0 ; i < 3 ; ++ i) { + // cylinder ---- + const fr_geometry_cyl = new THREE.CylinderGeometry( m_dFrameFat, m_dFrameFat, 0.8 * m_lFrameLen, 32) ; + const fr_material = new THREE.MeshBasicMaterial({color: vtCols[i]}) ; + const fr_cylinder = new THREE.Mesh( fr_geometry_cyl, fr_material) ; + fr_cylinder.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + if ( i == 1) + fr_cylinder.rotation.set( 0, 0, -Math.PI/2) ; + if ( i == 2) + fr_cylinder.rotation.set( -Math.PI/2, 0, 0) ; + scene.add( fr_cylinder) ; + fr_cylinder.translateY( 0.4 * m_lFrameLen) ; + // pyramid + const fr_geometry_cone = new THREE.CylinderGeometry( 0, 2 * m_dFrameFat, 0.2 * m_lFrameLen, 32) ; + const fr_cone = new THREE.Mesh( fr_geometry_cone, fr_material) ; + fr_cone.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + if ( i == 1) + fr_cone.rotation.set( 0, 0, -Math.PI/2) ; + if ( i == 2) + fr_cone.rotation.set( -Math.PI/2, 0, 0) ; + scene.add( fr_cone) ; + fr_cone.translateY( 0.9 * m_lFrameLen) ; + } + // Origin + const fr_orig_geometry = new THREE.SphereGeometry( 2 * m_dFrameFat, 32, 16) ; + const fr_orig_material = new THREE.MeshBasicMaterial( {color: 0x00000}) ; + const fr_sphere = new THREE.Mesh( fr_orig_geometry, fr_orig_material) ; + fr_sphere.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + scene.add( fr_sphere) ; + } + else + console.log( 'Frame type not defined') ; +} +function AddGrid( ptORIG) { + + if ( ! m_bShowGrid) + return ; + + const size = 1000000 ; + const divisions = 10000 ; + if ( m_bInfGrid) { + const gridHelper = new THREE.GridHelper( size, divisions) ; + gridHelper.position.set( ptORIG.position.x, ptORIG.position.y, ptORIG.position.z) ; + gridHelper.material.transparent = true ; + gridHelper.material.opacity = 0.25 ; + setFog() ; + scene.add( gridHelper) ; + } + else { + var dDimX = Math.abs( GLBox3D.max.x - GLBox3D.min.x) ; + var dDimY = Math.abs( GLBox3D.max.y - GLBox3D.min.y) ; + var dDimZ = Math.abs( GLBox3D.max.z - GLBox3D.min.z) ; + var dDim = 1.5 * Math.sqrt( dDimX * dDimX + dDimY * dDimY + dDimZ * dDimZ) ; + const gridHelper = new THREE.GridHelper( dDim, Math.ceil( 0.1 * dDim)) ; + gridHelper.position.set( ptORIG.position.x + 0.5 * dDim , ptORIG.position.y, ptORIG.position.z - 0.5 * dDim) ; + gridHelper.material.transparent = true ; + gridHelper.material.opacity = 0.45 ; + scene.add( gridHelper) ; + } +} + +function ShowPrintDir(showDir){ + console.log(showDir); + m_bShowDir = showDir; + if(fileType == "3DM"){ + + for ( var i = 0 ; i < layer_list.length ; ++ i) { + if ( layer_list[i].isArrow) { + if ( layer_list[i].nLayer >= m_nStartL && + layer_list[i].nLayer <= m_nEndL) + layer_list[i].visible = m_bShowDir ; + else + layer_list[i].visible = false ; + } + } + } + else if(fileType == "3MF"){ + for ( var i = 0 ; i < layer_list.length ; ++ i) { + if ( layer_list[i].children[0].isArrow) { + if ( parseInt( layer_list[i].children[0].nLayer) >= m_nStartL && + parseInt( layer_list[i].children[0].nLayer) <= m_nEndL) + layer_list[i].visible = m_bShowDir ; + else + layer_list[i].visible = false ; + } + } + } + render() ; } -function setFog() { - var dNear = GLBox3D.max.x + 3 * ( GLBox3D.max.x - GLBox3D.min.x) ; - var dFar = 10000 ; - scene.fog = new THREE.Fog( 0xa0a0a0, 20000, 30000); -} \ No newline at end of file diff --git a/WebGl/jsm/loaders/3DMLoader.js b/WebGl/jsm/loaders/3DMLoader.js new file mode 100644 index 0000000..2d003e6 --- /dev/null +++ b/WebGl/jsm/loaders/3DMLoader.js @@ -0,0 +1,1517 @@ +import { + BufferGeometryLoader, + FileLoader, + Loader, + Object3D, + MeshStandardMaterial, + Mesh, + Color, + Points, + Vector3, + PointsMaterial, + Line, + LineBasicMaterial, + Matrix4, + DirectionalLight, + PointLight, + SpotLight, + RectAreaLight, + Sprite, + SpriteMaterial, + CanvasTexture, + LinearFilter, + ClampToEdgeWrapping, + RepeatWrapping, + TextureLoader, + DoubleSide +} from '../../threeJsLib/three.module.js'; + +const _taskCache = new WeakMap(); + +class Rhino3dmLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + this.libraryPath = ''; + this.libraryPending = null; + this.libraryBinary = null; + this.libraryConfig = {}; + + this.url = ''; + + this.workerLimit = 4; + this.workerPool = []; + this.workerNextTaskID = 1; + this.workerSourceURL = ''; + this.workerConfig = {}; + + this.materials = []; + this.warnings = []; + + this.approxIndex = 0 ; + + } + + setLibraryPath( path ) { + + this.libraryPath = path; + + return this; + + } + + setWorkerLimit( workerLimit ) { + + this.workerLimit = workerLimit; + + return this; + + } + + load( url, nIndAppr, onLoad, onProgress, onError ) { + + const loader = new FileLoader( this.manager ); + + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + + this.url = url; + this.approxIndex = nIndAppr ; + + loader.load( url, ( buffer ) => { + + // Check for an existing task using this buffer. A transferred buffer cannot be transferred + // again from this thread. + if ( _taskCache.has( buffer ) ) { + + const cachedTask = _taskCache.get( buffer ); + + return cachedTask.promise.then( onLoad ).catch( onError ); + + } + + this.decodeObjects( buffer, url ) + .then( result => { + + result.userData.warnings = this.warnings; + onLoad( result ); + + } ) + .catch( e => onError( e ) ); + + }, onProgress, onError ); + + } + + debug() { + + console.log( 'Task load: ', this.workerPool.map( ( worker ) => worker._taskLoad ) ); + + } + + decodeObjects( buffer, url ) { + + let worker; + let taskID; + + const taskCost = buffer.byteLength; + + const objectPending = this._getWorker( taskCost ) + .then( ( _worker ) => { + + worker = _worker; + taskID = this.workerNextTaskID ++; + + return new Promise( ( resolve, reject ) => { + + worker._callbacks[ taskID ] = { resolve, reject }; + + worker.postMessage( { type: 'decode', id: taskID, buffer }, [ buffer ] ); + + // this.debug(); + + } ); + + } ) + .then( ( message ) => this._createGeometry( message.data ) ) + .catch( e => { + + throw e; + + } ); + + // Remove task from the task list. + // Note: replaced '.finally()' with '.catch().then()' block - iOS 11 support (#19416) + objectPending + .catch( () => true ) + .then( () => { + + if ( worker && taskID ) { + + this._releaseTask( worker, taskID ); + + //this.debug(); + + } + + } ); + + // Cache the task result. + _taskCache.set( buffer, { + + url: url, + promise: objectPending + + } ); + + return objectPending; + + } + + parse( data, onLoad, onError ) { + + this.decodeObjects( data, '' ) + .then( result => { + + result.userData.warnings = this.warnings; + onLoad( result ); + + } ) + .catch( e => onError( e ) ); + + } + + _compareMaterials( material ) { + + const mat = {}; + mat.name = material.name; + mat.color = {}; + mat.color.r = material.color.r; + mat.color.g = material.color.g; + mat.color.b = material.color.b; + mat.type = material.type; + + const json = JSON.stringify( mat ); + + for ( let i = 0; i < this.materials.length; i ++ ) { + + const m = this.materials[ i ]; + const _mat = {}; + _mat.name = m.name; + _mat.color = {}; + _mat.color.r = m.color.r; + _mat.color.g = m.color.g; + _mat.color.b = m.color.b; + _mat.type = m.type; + + if ( JSON.stringify( _mat ) === json ) { + + return m; + + } + + } + + this.materials.push( material ); + + return material; + + } + + _createMaterial( material ) { + + if ( material === undefined ) { + + return new MeshStandardMaterial( { + color: new Color( 1, 1, 1 ), + metalness: 0.8, + name: Loader.DEFAULT_MATERIAL_NAME, + side: DoubleSide + } ); + + } + + const _diffuseColor = material.diffuseColor; + + const diffusecolor = new Color( _diffuseColor.r / 255.0, _diffuseColor.g / 255.0, _diffuseColor.b / 255.0 ); + + if ( _diffuseColor.r === 0 && _diffuseColor.g === 0 && _diffuseColor.b === 0 ) { + + diffusecolor.r = 1; + diffusecolor.g = 1; + diffusecolor.b = 1; + + } + + // console.log( material ); + + const mat = new MeshStandardMaterial( { + color: diffusecolor, + name: material.name, + side: DoubleSide, + transparent: material.transparency > 0 ? true : false, + opacity: 1.0 - material.transparency + } ); + + const textureLoader = new TextureLoader(); + + for ( let i = 0; i < material.textures.length; i ++ ) { + + const texture = material.textures[ i ]; + + if ( texture.image !== null ) { + + const map = textureLoader.load( texture.image ); + + switch ( texture.type ) { + + case 'Diffuse': + + mat.map = map; + + break; + + case 'Bump': + + mat.bumpMap = map; + + break; + + case 'Transparency': + + mat.alphaMap = map; + mat.transparent = true; + + break; + + case 'Emap': + + mat.envMap = map; + + break; + + } + + map.wrapS = texture.wrapU === 0 ? RepeatWrapping : ClampToEdgeWrapping; + map.wrapT = texture.wrapV === 0 ? RepeatWrapping : ClampToEdgeWrapping; + map.repeat.set( texture.repeat[ 0 ], texture.repeat[ 1 ] ); + + } + + } + + return mat; + + } + + _createGeometry( data ) { + + // console.log(data); + + const object = new Object3D(); + const instanceDefinitionObjects = []; + const instanceDefinitions = []; + const instanceReferences = []; + + object.userData[ 'layers' ] = data.layers; + object.userData[ 'groups' ] = data.groups; + object.userData[ 'settings' ] = data.settings; + object.userData[ 'objectType' ] = 'File3dm'; + object.userData[ 'materials' ] = null; + object.name = this.url; + + let objects = data.objects; + const materials = data.materials; + + for ( let i = 0; i < objects.length; i ++ ) { + + const obj = objects[ i ]; + const attributes = obj.attributes; + + switch ( obj.objectType ) { + + case 'InstanceDefinition': + + instanceDefinitions.push( obj ); + + break; + + case 'InstanceReference': + + instanceReferences.push( obj ); + + break; + + default: + + let _object; + + if ( attributes.materialIndex >= 0 ) { + + const rMaterial = materials[ attributes.materialIndex ]; + let material = this._createMaterial( rMaterial ); + material = this._compareMaterials( material ); + _object = this._createObject( obj, material ); + + } else { + + const material = this._createMaterial(); + _object = this._createObject( obj, material ); + + } + + if ( _object === undefined ) { + + continue; + + } + + const layer = data.layers[ attributes.layerIndex ]; + + _object.visible = layer ? data.layers[ attributes.layerIndex ].visible : true; + + if ( attributes.isInstanceDefinitionObject ) { + + instanceDefinitionObjects.push( _object ); + + } else { + + object.add( _object ); + + } + + break; + + } + + } + + for ( let i = 0; i < instanceDefinitions.length; i ++ ) { + + const iDef = instanceDefinitions[ i ]; + + objects = []; + + for ( let j = 0; j < iDef.attributes.objectIds.length; j ++ ) { + + const objId = iDef.attributes.objectIds[ j ]; + + for ( let p = 0; p < instanceDefinitionObjects.length; p ++ ) { + + const idoId = instanceDefinitionObjects[ p ].userData.attributes.id; + + if ( objId === idoId ) { + + objects.push( instanceDefinitionObjects[ p ] ); + + } + + } + + } + + // Currently clones geometry and does not take advantage of instancing + + for ( let j = 0; j < instanceReferences.length; j ++ ) { + + const iRef = instanceReferences[ j ]; + + if ( iRef.geometry.parentIdefId === iDef.attributes.id ) { + + const iRefObject = new Object3D(); + const xf = iRef.geometry.xform.array; + + const matrix = new Matrix4(); + matrix.set( ...xf ); + + iRefObject.applyMatrix4( matrix ); + + for ( let p = 0; p < objects.length; p ++ ) { + + iRefObject.add( objects[ p ].clone( true ) ); + + } + + object.add( iRefObject ); + + } + + } + + } + + object.userData[ 'materials' ] = this.materials; + return object; + + } + + _createObject( obj, mat ) { + + const loader = new BufferGeometryLoader(); + + const attributes = obj.attributes; + + let geometry, material, _color, color; + + switch ( obj.objectType ) { + + case 'Point': + case 'PointSet': + + geometry = loader.parse( obj.geometry ); + + if ( geometry.attributes.hasOwnProperty( 'color' ) ) { + + material = new PointsMaterial( { vertexColors: true, sizeAttenuation: false, size: 2 } ); + + } else { + + _color = attributes.drawColor; + color = new Color( _color.r / 255.0, _color.g / 255.0, _color.b / 255.0 ); + material = new PointsMaterial( { color: color, sizeAttenuation: false, size: 2 } ); + + } + + material = this._compareMaterials( material ); + + const points = new Points( geometry, material ); + points.userData[ 'attributes' ] = attributes; + points.userData[ 'objectType' ] = obj.objectType; + + if ( attributes.name ) { + + points.name = attributes.name; + + } + + return points; + + case 'Mesh': + case 'Extrusion': + case 'SubD': + case 'Brep': + + if ( obj.geometry === null ) return; + + geometry = loader.parse( obj.geometry ); + + if ( geometry.attributes.hasOwnProperty( 'color' ) ) { + + mat.vertexColors = true; + + } + + if ( mat === null ) { + + mat = this._createMaterial(); + mat = this._compareMaterials( mat ); + + } + + const mesh = new Mesh( geometry, mat ); + mesh.castShadow = attributes.castsShadows; + mesh.receiveShadow = attributes.receivesShadows; + mesh.userData[ 'attributes' ] = attributes; + mesh.userData[ 'objectType' ] = obj.objectType; + + if ( attributes.name ) { + + mesh.name = attributes.name; + + } + + return mesh; + + case 'Curve': + + geometry = loader.parse( obj.geometry ); + + var points_array = geometry.attributes.position.array ; + var simplified_points_array = [] ; + var ptPrec = [] ; + for ( var v = 0 ; v < points_array.length ; v += 3) { + if ( v != 0 && v < points_array.length - 3 && + (( points_array[v] - ptPrec[0]) * ( points_array[v] - ptPrec[0]) + + ( points_array[v+1] - ptPrec[1]) * ( points_array[v+1] - ptPrec[1]) + + ( points_array[v+2] - ptPrec[2]) * ( points_array[v+2] - ptPrec[2])) < this.approxIndex * this.approxIndex) + continue ; + simplified_points_array.push( points_array[v], points_array[v+1], points_array[v+2]) ; + ptPrec[0] = points_array[v] ; + ptPrec[1] = points_array[v+1] ; + ptPrec[2] = points_array[v+2] ; + } + geometry.attributes.position.array = simplified_points_array ; + + _color = attributes.drawColor; + color = new Color( _color.r / 255.0, _color.g / 255.0, _color.b / 255.0 ); + + material = new LineBasicMaterial( { color: color } ); + material = this._compareMaterials( material ); + + const lines = new Line( geometry, material ); + lines.userData[ 'attributes' ] = attributes; + lines.userData[ 'objectType' ] = obj.objectType; + + if ( attributes.name ) { + + lines.name = attributes.name; + + } + + return lines; + + case 'TextDot': + + geometry = obj.geometry; + + const ctx = document.createElement( 'canvas' ).getContext( '2d' ); + const font = `${geometry.fontHeight}px ${geometry.fontFace}`; + ctx.font = font; + const width = ctx.measureText( geometry.text ).width + 10; + const height = geometry.fontHeight + 10; + + const r = window.devicePixelRatio; + + ctx.canvas.width = width * r; + ctx.canvas.height = height * r; + ctx.canvas.style.width = width + 'px'; + ctx.canvas.style.height = height + 'px'; + ctx.setTransform( r, 0, 0, r, 0, 0 ); + + ctx.font = font; + ctx.textBaseline = 'middle'; + ctx.textAlign = 'center'; + color = attributes.drawColor; + ctx.fillStyle = `rgba(${color.r},${color.g},${color.b},${color.a})`; + ctx.fillRect( 0, 0, width, height ); + ctx.fillStyle = 'white'; + ctx.fillText( geometry.text, width / 2, height / 2 ); + + const texture = new CanvasTexture( ctx.canvas ); + texture.minFilter = LinearFilter; + texture.wrapS = ClampToEdgeWrapping; + texture.wrapT = ClampToEdgeWrapping; + + material = new SpriteMaterial( { map: texture, depthTest: false } ); + const sprite = new Sprite( material ); + sprite.position.set( geometry.point[ 0 ], geometry.point[ 1 ], geometry.point[ 2 ] ); + sprite.scale.set( width / 10, height / 10, 1.0 ); + + sprite.userData[ 'attributes' ] = attributes; + sprite.userData[ 'objectType' ] = obj.objectType; + + if ( attributes.name ) { + + sprite.name = attributes.name; + + } + + return sprite; + + case 'Light': + + geometry = obj.geometry; + + let light; + + switch ( geometry.lightStyle.name ) { + + case 'LightStyle_WorldPoint': + + light = new PointLight(); + light.castShadow = attributes.castsShadows; + light.position.set( geometry.location[ 0 ], geometry.location[ 1 ], geometry.location[ 2 ] ); + light.shadow.normalBias = 0.1; + + break; + + case 'LightStyle_WorldSpot': + + light = new SpotLight(); + light.castShadow = attributes.castsShadows; + light.position.set( geometry.location[ 0 ], geometry.location[ 1 ], geometry.location[ 2 ] ); + light.target.position.set( geometry.direction[ 0 ], geometry.direction[ 1 ], geometry.direction[ 2 ] ); + light.angle = geometry.spotAngleRadians; + light.shadow.normalBias = 0.1; + + break; + + case 'LightStyle_WorldRectangular': + + light = new RectAreaLight(); + const width = Math.abs( geometry.width[ 2 ] ); + const height = Math.abs( geometry.length[ 0 ] ); + light.position.set( geometry.location[ 0 ] - ( height / 2 ), geometry.location[ 1 ], geometry.location[ 2 ] - ( width / 2 ) ); + light.height = height; + light.width = width; + light.lookAt( geometry.direction[ 0 ], geometry.direction[ 1 ], geometry.direction[ 2 ] ); + + break; + + case 'LightStyle_WorldDirectional': + + light = new DirectionalLight(); + light.castShadow = attributes.castsShadows; + light.position.set( geometry.location[ 0 ], geometry.location[ 1 ], geometry.location[ 2 ] ); + light.target.position.set( geometry.direction[ 0 ], geometry.direction[ 1 ], geometry.direction[ 2 ] ); + light.shadow.normalBias = 0.1; + + break; + + case 'LightStyle_WorldLinear': + // not conversion exists, warning has already been printed to the console + break; + + default: + break; + + } + + if ( light ) { + + light.intensity = geometry.intensity; + _color = geometry.diffuse; + color = new Color( _color.r / 255.0, _color.g / 255.0, _color.b / 255.0 ); + light.color = color; + light.userData[ 'attributes' ] = attributes; + light.userData[ 'objectType' ] = obj.objectType; + + } + + return light; + + } + + } + + _initLibrary() { + + if ( ! this.libraryPending ) { + + // Load rhino3dm wrapper. + const jsLoader = new FileLoader( this.manager ); + jsLoader.setPath( this.libraryPath ); + const jsContent = new Promise( ( resolve, reject ) => { + + jsLoader.load( 'rhino3dm.js', resolve, undefined, reject ); + + } ); + + // Load rhino3dm WASM binary. + const binaryLoader = new FileLoader( this.manager ); + binaryLoader.setPath( this.libraryPath ); + binaryLoader.setResponseType( 'arraybuffer' ); + const binaryContent = new Promise( ( resolve, reject ) => { + + binaryLoader.load( 'rhino3dm.wasm', resolve, undefined, reject ); + + } ); + + this.libraryPending = Promise.all( [ jsContent, binaryContent ] ) + .then( ( [ jsContent, binaryContent ] ) => { + + //this.libraryBinary = binaryContent; + this.libraryConfig.wasmBinary = binaryContent; + + const fn = Rhino3dmWorker.toString(); + + const body = [ + '/* rhino3dm.js */', + jsContent, + '/* worker */', + fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) ) + ].join( '\n' ); + + this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) ); + + } ); + + } + + return this.libraryPending; + + } + + _getWorker( taskCost ) { + + return this._initLibrary().then( () => { + + if ( this.workerPool.length < this.workerLimit ) { + + const worker = new Worker( this.workerSourceURL ); + + worker._callbacks = {}; + worker._taskCosts = {}; + worker._taskLoad = 0; + + worker.postMessage( { + type: 'init', + libraryConfig: this.libraryConfig + } ); + + worker.onmessage = e => { + + const message = e.data; + + switch ( message.type ) { + + case 'warning': + this.warnings.push( message.data ); + console.warn( message.data ); + break; + + case 'decode': + worker._callbacks[ message.id ].resolve( message ); + break; + + case 'error': + worker._callbacks[ message.id ].reject( message ); + break; + + default: + console.error( 'THREE.Rhino3dmLoader: Unexpected message, "' + message.type + '"' ); + + } + + }; + + this.workerPool.push( worker ); + + } else { + + this.workerPool.sort( function ( a, b ) { + + return a._taskLoad > b._taskLoad ? - 1 : 1; + + } ); + + } + + const worker = this.workerPool[ this.workerPool.length - 1 ]; + + worker._taskLoad += taskCost; + + return worker; + + } ); + + } + + _releaseTask( worker, taskID ) { + + worker._taskLoad -= worker._taskCosts[ taskID ]; + delete worker._callbacks[ taskID ]; + delete worker._taskCosts[ taskID ]; + + } + + dispose() { + + for ( let i = 0; i < this.workerPool.length; ++ i ) { + + this.workerPool[ i ].terminate(); + + } + + this.workerPool.length = 0; + + return this; + + } + +} + +/* WEB WORKER */ + +function Rhino3dmWorker() { + + let libraryPending; + let libraryConfig; + let rhino; + let taskID; + + onmessage = function ( e ) { + + const message = e.data; + + switch ( message.type ) { + + case 'init': + + // console.log(message) + libraryConfig = message.libraryConfig; + const wasmBinary = libraryConfig.wasmBinary; + let RhinoModule; + libraryPending = new Promise( function ( resolve ) { + + /* Like Basis Loader */ + RhinoModule = { wasmBinary, onRuntimeInitialized: resolve }; + + rhino3dm( RhinoModule ); // eslint-disable-line no-undef + + } ).then( () => { + + rhino = RhinoModule; + + } ); + + break; + + case 'decode': + + taskID = message.id; + const buffer = message.buffer; + libraryPending.then( () => { + + try { + + const data = decodeObjects( rhino, buffer ); + self.postMessage( { type: 'decode', id: message.id, data } ); + + } catch ( error ) { + + self.postMessage( { type: 'error', id: message.id, error } ); + + } + + } ); + + break; + + } + + }; + + function decodeObjects( rhino, buffer ) { + + const arr = new Uint8Array( buffer ); + const doc = rhino.File3dm.fromByteArray( arr ); + + const objects = []; + const materials = []; + const layers = []; + const views = []; + const namedViews = []; + const groups = []; + const strings = []; + + //Handle objects + + const objs = doc.objects(); + const cnt = objs.count; + + for ( let i = 0; i < cnt; i ++ ) { + + const _object = objs.get( i ); + + const object = extractObjectData( _object, doc ); + + _object.delete(); + + if ( object ) { + + objects.push( object ); + + } + + } + + // Handle instance definitions + // console.log( `Instance Definitions Count: ${doc.instanceDefinitions().count()}` ); + + for ( let i = 0; i < doc.instanceDefinitions().count(); i ++ ) { + + const idef = doc.instanceDefinitions().get( i ); + const idefAttributes = extractProperties( idef ); + idefAttributes.objectIds = idef.getObjectIds(); + + objects.push( { geometry: null, attributes: idefAttributes, objectType: 'InstanceDefinition' } ); + + } + + // Handle materials + + const textureTypes = [ + // rhino.TextureType.Bitmap, + rhino.TextureType.Diffuse, + rhino.TextureType.Bump, + rhino.TextureType.Transparency, + rhino.TextureType.Opacity, + rhino.TextureType.Emap + ]; + + const pbrTextureTypes = [ + rhino.TextureType.PBR_BaseColor, + rhino.TextureType.PBR_Subsurface, + rhino.TextureType.PBR_SubsurfaceScattering, + rhino.TextureType.PBR_SubsurfaceScatteringRadius, + rhino.TextureType.PBR_Metallic, + rhino.TextureType.PBR_Specular, + rhino.TextureType.PBR_SpecularTint, + rhino.TextureType.PBR_Roughness, + rhino.TextureType.PBR_Anisotropic, + rhino.TextureType.PBR_Anisotropic_Rotation, + rhino.TextureType.PBR_Sheen, + rhino.TextureType.PBR_SheenTint, + rhino.TextureType.PBR_Clearcoat, + rhino.TextureType.PBR_ClearcoatBump, + rhino.TextureType.PBR_ClearcoatRoughness, + rhino.TextureType.PBR_OpacityIor, + rhino.TextureType.PBR_OpacityRoughness, + rhino.TextureType.PBR_Emission, + rhino.TextureType.PBR_AmbientOcclusion, + rhino.TextureType.PBR_Displacement + ]; + + for ( let i = 0; i < doc.materials().count(); i ++ ) { + + const _material = doc.materials().get( i ); + const _pbrMaterial = _material.physicallyBased(); + + let material = extractProperties( _material ); + + const textures = []; + + for ( let j = 0; j < textureTypes.length; j ++ ) { + + const _texture = _material.getTexture( textureTypes[ j ] ); + if ( _texture ) { + + let textureType = textureTypes[ j ].constructor.name; + textureType = textureType.substring( 12, textureType.length ); + const texture = { type: textureType }; + + const image = doc.getEmbeddedFileAsBase64( _texture.fileName ); + + texture.wrapU = _texture.wrapU; + texture.wrapV = _texture.wrapV; + texture.wrapW = _texture.wrapW; + const uvw = _texture.uvwTransform.toFloatArray( true ); + texture.repeat = [ uvw[ 0 ], uvw[ 5 ] ]; + + if ( image ) { + + texture.image = 'data:image/png;base64,' + image; + + } else { + + self.postMessage( { type: 'warning', id: taskID, data: { + message: `THREE.3DMLoader: Image for ${textureType} texture not embedded in file.`, + type: 'missing resource' + } + + } ); + + texture.image = null; + + } + + textures.push( texture ); + + _texture.delete(); + + } + + } + + material.textures = textures; + + if ( _pbrMaterial.supported ) { + + for ( let j = 0; j < pbrTextureTypes.length; j ++ ) { + + const _texture = _material.getTexture( pbrTextureTypes[ j ] ); + if ( _texture ) { + + const image = doc.getEmbeddedFileAsBase64( _texture.fileName ); + let textureType = pbrTextureTypes[ j ].constructor.name; + textureType = textureType.substring( 12, textureType.length ); + const texture = { type: textureType, image: 'data:image/png;base64,' + image }; + textures.push( texture ); + + _texture.delete(); + + } + + } + + const pbMaterialProperties = extractProperties( _material.physicallyBased() ); + + material = Object.assign( pbMaterialProperties, material ); + + } + + materials.push( material ); + + _material.delete(); + _pbrMaterial.delete(); + + } + + // Handle layers + + for ( let i = 0; i < doc.layers().count(); i ++ ) { + + const _layer = doc.layers().get( i ); + const layer = extractProperties( _layer ); + + layers.push( layer ); + + _layer.delete(); + + } + + // Handle views + + for ( let i = 0; i < doc.views().count(); i ++ ) { + + const _view = doc.views().get( i ); + const view = extractProperties( _view ); + + views.push( view ); + + _view.delete(); + + } + + // Handle named views + + for ( let i = 0; i < doc.namedViews().count(); i ++ ) { + + const _namedView = doc.namedViews().get( i ); + const namedView = extractProperties( _namedView ); + + namedViews.push( namedView ); + + _namedView.delete(); + + } + + // Handle groups + + for ( let i = 0; i < doc.groups().count(); i ++ ) { + + const _group = doc.groups().get( i ); + const group = extractProperties( _group ); + + groups.push( group ); + + _group.delete(); + + } + + // Handle settings + + const settings = extractProperties( doc.settings() ); + + //TODO: Handle other document stuff like dimstyles, instance definitions, bitmaps etc. + + // Handle dimstyles + // console.log( `Dimstyle Count: ${doc.dimstyles().count()}` ); + + // Handle bitmaps + // console.log( `Bitmap Count: ${doc.bitmaps().count()}` ); + + // Handle strings + // console.log( `Document Strings Count: ${doc.strings().count()}` ); + // Note: doc.strings().documentUserTextCount() counts any doc.strings defined in a section + //console.log( `Document User Text Count: ${doc.strings().documentUserTextCount()}` ); + + const strings_count = doc.strings().count(); + + for ( let i = 0; i < strings_count; i ++ ) { + + strings.push( doc.strings().get( i ) ); + + } + + doc.delete(); + + return { objects, materials, layers, views, namedViews, groups, strings, settings }; + + } + + function extractObjectData( object, doc ) { + + const _geometry = object.geometry(); + const _attributes = object.attributes(); + let objectType = _geometry.objectType; + let geometry, attributes, position, data, mesh; + + // skip instance definition objects + //if( _attributes.isInstanceDefinitionObject ) { continue; } + + // TODO: handle other geometry types + switch ( objectType ) { + + case rhino.ObjectType.Curve: + + const pts = curveToPoints( _geometry, 100 ); + + position = {}; + attributes = {}; + data = {}; + + position.itemSize = 3; + position.type = 'Float32Array'; + position.array = []; + + for ( let j = 0; j < pts.length; j ++ ) { + + position.array.push( pts[ j ][ 0 ] ); + position.array.push( pts[ j ][ 1 ] ); + position.array.push( pts[ j ][ 2 ] ); + + } + + attributes.position = position; + data.attributes = attributes; + + geometry = { data }; + + break; + + case rhino.ObjectType.Point: + + const pt = _geometry.location; + + position = {}; + const color = {}; + attributes = {}; + data = {}; + + position.itemSize = 3; + position.type = 'Float32Array'; + position.array = [ pt[ 0 ], pt[ 1 ], pt[ 2 ] ]; + + const _color = _attributes.drawColor( doc ); + + color.itemSize = 3; + color.type = 'Float32Array'; + color.array = [ _color.r / 255.0, _color.g / 255.0, _color.b / 255.0 ]; + + attributes.position = position; + attributes.color = color; + data.attributes = attributes; + + geometry = { data }; + + break; + + case rhino.ObjectType.PointSet: + case rhino.ObjectType.Mesh: + + geometry = _geometry.toThreejsJSON(); + + break; + + case rhino.ObjectType.Brep: + + const faces = _geometry.faces(); + mesh = new rhino.Mesh(); + + for ( let faceIndex = 0; faceIndex < faces.count; faceIndex ++ ) { + + const face = faces.get( faceIndex ); + const _mesh = face.getMesh( rhino.MeshType.Any ); + + if ( _mesh ) { + + mesh.append( _mesh ); + _mesh.delete(); + + } + + face.delete(); + + } + + if ( mesh.faces().count > 0 ) { + + mesh.compact(); + geometry = mesh.toThreejsJSON(); + faces.delete(); + + } + + mesh.delete(); + + break; + + case rhino.ObjectType.Extrusion: + + mesh = _geometry.getMesh( rhino.MeshType.Any ); + + if ( mesh ) { + + geometry = mesh.toThreejsJSON(); + mesh.delete(); + + } + + break; + + case rhino.ObjectType.TextDot: + + geometry = extractProperties( _geometry ); + + break; + + case rhino.ObjectType.Light: + + geometry = extractProperties( _geometry ); + + if ( geometry.lightStyle.name === 'LightStyle_WorldLinear' ) { + + self.postMessage( { type: 'warning', id: taskID, data: { + message: `THREE.3DMLoader: No conversion exists for ${objectType.constructor.name} ${geometry.lightStyle.name}`, + type: 'no conversion', + guid: _attributes.id + } + + } ); + + } + + break; + + case rhino.ObjectType.InstanceReference: + + geometry = extractProperties( _geometry ); + geometry.xform = extractProperties( _geometry.xform ); + geometry.xform.array = _geometry.xform.toFloatArray( true ); + + break; + + case rhino.ObjectType.SubD: + + // TODO: precalculate resulting vertices and faces and warn on excessive results + _geometry.subdivide( 3 ); + mesh = rhino.Mesh.createFromSubDControlNet( _geometry ); + if ( mesh ) { + + geometry = mesh.toThreejsJSON(); + mesh.delete(); + + } + + break; + + /* + case rhino.ObjectType.Annotation: + case rhino.ObjectType.Hatch: + case rhino.ObjectType.ClipPlane: + */ + + default: + + self.postMessage( { type: 'warning', id: taskID, data: { + message: `THREE.3DMLoader: Conversion not implemented for ${objectType.constructor.name}`, + type: 'not implemented', + guid: _attributes.id + } + + } ); + + break; + + } + + if ( geometry ) { + + attributes = extractProperties( _attributes ); + attributes.geometry = extractProperties( _geometry ); + + if ( _attributes.groupCount > 0 ) { + + attributes.groupIds = _attributes.getGroupList(); + + } + + if ( _attributes.userStringCount > 0 ) { + + attributes.userStrings = _attributes.getUserStrings(); + + } + + if ( _geometry.userStringCount > 0 ) { + + attributes.geometry.userStrings = _geometry.getUserStrings(); + + } + + attributes.drawColor = _attributes.drawColor( doc ); + + objectType = objectType.constructor.name; + objectType = objectType.substring( 11, objectType.length ); + + return { geometry, attributes, objectType }; + + } else { + + self.postMessage( { type: 'warning', id: taskID, data: { + message: `THREE.3DMLoader: ${objectType.constructor.name} has no associated mesh geometry.`, + type: 'missing mesh', + guid: _attributes.id + } + + } ); + + } + + } + + function extractProperties( object ) { + + const result = {}; + + for ( const property in object ) { + + const value = object[ property ]; + + if ( typeof value !== 'function' ) { + + if ( typeof value === 'object' && value !== null && value.hasOwnProperty( 'constructor' ) ) { + + result[ property ] = { name: value.constructor.name, value: value.value }; + + } else { + + result[ property ] = value; + + } + + } else { + + // these are functions that could be called to extract more data. + //console.log( `${property}: ${object[ property ].constructor.name}` ); + + } + + } + + return result; + + } + + function curveToPoints( curve, pointLimit ) { + + let pointCount = pointLimit; + let rc = []; + const ts = []; + + if ( curve instanceof rhino.LineCurve ) { + + return [ curve.pointAtStart, curve.pointAtEnd ]; + + } + + if ( curve instanceof rhino.PolylineCurve ) { + + pointCount = curve.pointCount; + for ( let i = 0; i < pointCount; i ++ ) { + + rc.push( curve.point( i ) ); + + } + + return rc; + + } + + if ( curve instanceof rhino.PolyCurve ) { + + const segmentCount = curve.segmentCount; + + for ( let i = 0; i < segmentCount; i ++ ) { + + const segment = curve.segmentCurve( i ); + const segmentArray = curveToPoints( segment, pointCount ); + rc = rc.concat( segmentArray ); + segment.delete(); + + } + + return rc; + + } + + if ( curve instanceof rhino.ArcCurve ) { + + pointCount = Math.floor( curve.angleDegrees / 5 ); + pointCount = pointCount < 2 ? 2 : pointCount; + // alternative to this hardcoded version: https://stackoverflow.com/a/18499923/2179399 + + } + + if ( curve instanceof rhino.NurbsCurve && curve.degree === 1 ) { + + const pLine = curve.tryGetPolyline(); + + for ( let i = 0; i < pLine.count; i ++ ) { + + rc.push( pLine.get( i ) ); + + } + + pLine.delete(); + + return rc; + + } + + const domain = curve.domain; + const divisions = pointCount - 1.0; + + for ( let j = 0; j < pointCount; j ++ ) { + + const t = domain[ 0 ] + ( j / divisions ) * ( domain[ 1 ] - domain[ 0 ] ); + + if ( t === domain[ 0 ] || t === domain[ 1 ] ) { + + ts.push( t ); + continue; + + } + + const tan = curve.tangentAt( t ); + const prevTan = curve.tangentAt( ts.slice( - 1 )[ 0 ] ); + + // Duplicated from THREE.Vector3 + // How to pass imports to worker? + + const tS = tan[ 0 ] * tan[ 0 ] + tan[ 1 ] * tan[ 1 ] + tan[ 2 ] * tan[ 2 ]; + const ptS = prevTan[ 0 ] * prevTan[ 0 ] + prevTan[ 1 ] * prevTan[ 1 ] + prevTan[ 2 ] * prevTan[ 2 ]; + + const denominator = Math.sqrt( tS * ptS ); + + let angle; + + if ( denominator === 0 ) { + + angle = Math.PI / 2; + + } else { + + const theta = ( tan.x * prevTan.x + tan.y * prevTan.y + tan.z * prevTan.z ) / denominator; + angle = Math.acos( Math.max( - 1, Math.min( 1, theta ) ) ); + + } + + if ( angle < 0.1 ) continue; + + ts.push( t ); + + } + + rc = ts.map( t => curve.pointAt( t ) ); + return rc; + + } + +} + +export { Rhino3dmLoader }; diff --git a/WebGl/jsm/loaders/3MFLoader.js b/WebGl/jsm/loaders/3MFLoader.js index af35d19..cb9f32e 100644 --- a/WebGl/jsm/loaders/3MFLoader.js +++ b/WebGl/jsm/loaders/3MFLoader.js @@ -11,6 +11,8 @@ import { Loader, Matrix4, Mesh, + Vector3, + Object3D, MeshPhongMaterial, MeshStandardMaterial, MirroredRepeatWrapping, @@ -264,12 +266,15 @@ class ThreeMFLoader extends Loader { 'LicenseTerms', 'Rating', 'CreationDate', - 'ModificationDate' + 'ModificationDate', + 'customXMLNS0:Orig' ]; if ( 0 <= validNames.indexOf( name ) ) { - - metadataData[ name ] = metadataNode.textContent; + if ( validNames.indexOf( name ) != 8) + metadataData[ name ] = metadataNode.textContent; + else + metadataData['Orig'] = metadataNode.textContent; } @@ -514,6 +519,49 @@ class ThreeMFLoader extends Loader { return components; } + + function parsemetadatagroupNode( componentsNode ) { + + const componentNodes = componentsNode.querySelectorAll( 'metadata' ) ; + var sSliceNumber = '' ; + + if ( componentNodes ) { + + for ( var i = 0 ; i < componentNodes.length ; ++ i) { + + const singleComponentNode = componentNodes[i] ; + + if ( singleComponentNode ) { + + const singleComponentNodeouterHTML = singleComponentNode['outerHTML'] ; + + if ( singleComponentNodeouterHTML) { + + if ( singleComponentNodeouterHTML.includes( 'SliceNbr')) { + + sSliceNumber = singleComponentNode['textContent'] ; + + if ( sSliceNumber ) { + + return sSliceNumber ; + + } + + } + + } + + } + + } + + } + + + + + } + function parseComponentNode( componentNode ) { @@ -615,6 +663,14 @@ class ThreeMFLoader extends Loader { objectData[ 'mesh' ] = parseMeshNode( meshNode ); } + + const metadatagroupNode = objectNode.querySelector( 'metadatagroup' ) ; + + if ( metadatagroupNode ) { + + objectData[ 'SliceNbr' ] = parsemetadatagroupNode( metadatagroupNode ); + + } const componentsNode = objectNode.querySelector( 'components' ); @@ -1056,7 +1112,7 @@ class ThreeMFLoader extends Loader { // mesh const mesh = new Mesh( geometry, material ); - mesh.nLayer = objectData.partnumber ; + mesh.nLayer = objectData.SliceNbr ; return mesh; @@ -1131,8 +1187,7 @@ class ThreeMFLoader extends Loader { for ( let i = 0; i < meshes.length; i ++ ) { meshes[ i ].name = objectData.name; - meshes[ i ].nLayer = objectData.partnumber ; - + meshes[ i ].nLayer = objectData.SliceNbr ; } } @@ -1457,6 +1512,28 @@ class ThreeMFLoader extends Loader { group.add( object3D ); } + + // parsing orig point + try { + const sPoint = Object.entries( data3mf.model)[0][1].metadata.Orig ; + if ( sPoint != "" ) { + let sPoint_arr = sPoint.split(',') ; + if ( sPoint_arr.length == 3) { + var dPoint_x = parseFloat( sPoint_arr[0]) ; + var dPoint_y = parseFloat( sPoint_arr[1]) ; + var dPoint_z = parseFloat( sPoint_arr[2]) ; + var vtORIG = new Vector3( dPoint_x, dPoint_y, dPoint_z) ; + var Orig_group = new Group() ; + Orig_group.name = 'ORIG' ; + Orig_group.type = 'Vector3' ; + Orig_group.children.push( vtORIG) ; + group.add( Orig_group) ; + } + } + } + catch( e) { + console.log( 'Missing origin') ; + } return group;