import * as Three from 'three' const THREE = Three; // const STLLoader = require('three-stl-loader')(THREE); import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js'; import { EditorControls } from '../editor/js/EditorControls.js'; import { ViewHelper } from '../editor/js/Viewport.ViewHelper.js'; import { LoaderUtils } from '../editor/js/LoaderUtils.js'; import * as dat from "dat.gui"; var loader = new THREE.FontLoader(); var labels = new THREE.Object3D(); var modelSize = 600; var modelFont = ''; let cloneModel; let objectMaterial = null;//模型材质对象 var cameraPosition = {}; loader.load('static/fonts/helvetiker_regular.typeface.json', function (font) { modelFont = font; }) //模型渲染基本配置 const getBasicModelLoaderConfig = () => ({ cameraPosition: { //照相机位置 x: 600, y: 200, z: 0 }, defaultCameraOption: { //照相机默认配置 fov: 45, near: 0.1, far: 5000 }, axesSize: 800, //坐标轴尺寸 gridOption: { //网格 size: 300, division: 50, color1: 0xFFFFFF, color2: 0xFFFFFF }, sceneTranslateY: -120, //场景y轴平移距离 ambientLightColor: 0xffffff, //环境光颜色 rendererClearColor: 0xCCCCCC, //渲染器刷新色 meshBaseSize: 300, //物体尺寸边界 objectJson: [],//文件读取 defaultMaterial: new THREE.MeshPhysicalMaterial({ color: '#333333', //物体颜色 '#0087FF' '#333333' '#ff0000' metalness: 1.0, roughness: 0.4, reflectivity: 0.5, side: THREE.DoubleSide, }) }); let config = getBasicModelLoaderConfig(); const AXES = { X: 'axes_x', Y: 'axes_y', Z: 'axes_z' }; function getFrame(elId) { //获取容器元素 return document.getElementById(elId); } /*--模型渲染器--*/ export default class MobileLoader { constructor({ elId, //容器id control = true, //是否添加控制器 axes = false, //是否添加坐标轴 boundingBox = false, //是否添加包围盒 machineBox = false, //是否显示机器包围盒 machineSize = null, //机器框尺寸 grid = false, //是否添加网格 width, //画布宽度 height, //画布高度 }) { config = getBasicModelLoaderConfig(); //初始化参数 this.frameId = elId; this.clock = new THREE.Clock(); // only used for animations this.control = control; this.needAxes = axes; this.needBoundingBox = boundingBox; this.needMachineBox = machineBox; this.needGrid = grid; this.machineSize = machineSize; //若按机器边框渲染,重置参数 if (this.needMachineBox) { this.control = false; this.needGrid = false; config.sceneTranslateY = 0; config.cameraPosition = { x: 0, y: -700, z: 0 }; config.defaultMaterial = new THREE.MeshPhysicalMaterial({ color: 0x6d0c74, metalness: 0.7, roughness: 0.7, reflectivity: 1, side: THREE.DoubleSide, }); } this.loader = new STLLoader(); this.models = []; this.container = document.getElementById(elId); this.size = this.initSize(width, height); this.camera = this.createCamera(); this.viewHelper = new ViewHelper(this.camera, this.container); this.controls = new EditorControls(this.camera, this.container); var scope = this; this.controls.addEventListener('change', function () { scope.refresh(); }); this.viewHelper.controls = this.controls; //初始化场景 this.scene = new THREE.Scene(); this.renderer = this.createRenderer(); const { x, y, z } = config.cameraPosition; this.camera.position.set(x, y, z); this.initLights(); this.createRenderScene(); this.showDialog(); } createGUI() { var scope = this; var params = new function () { this.X轴 = 1; this.Y轴 = 0; this.Z轴 = 0; this.距离 = 0; }; scope.gui = new dat.GUI(); scope.gui.add(params, 'X轴', -1, 1).onChange(() => setParams()); scope.gui.add(params, 'Y轴', -1, 1).onChange(() => setParams()); scope.gui.add(params, 'Z轴', -1, 1).onChange(() => setParams()); scope.gui.add(params, '距离', -modelSize, modelSize).onChange(() => setParams()); function setParams() { scope.globalPlanes.set(new THREE.Vector3(params.X轴, params.Y轴, params.Z轴), params.距离); scope.refresh(); } setTimeout(function () { document.getElementsByClassName('dg main a')[0].style.width = '120px' document.getElementsByClassName('dg main a')[0].style.marginTop = (window.innerHeight - 120) + 'px' document.getElementsByClassName('close-button close-bottom')[0].style.width = '120px' document.getElementsByClassName('close-button close-bottom')[0].style.opacity = 0 }, 100) } showDialog() { // var form = document.createElement( 'form' ); // form.style.display = 'none'; // document.body.appendChild( form ); var fileInput = document.createElement('input'); fileInput.multiple = true; fileInput.type = 'file'; var scope = this; fileInput.addEventListener('change', function () { scope.loadFiles(fileInput.files); //form.reset(); }); //form.appendChild( fileInput ); if (document.getElementsByClassName('iconfolder-opened')[0]) { document.getElementsByClassName('iconfolder-opened')[0].addEventListener('click', function () { fileInput.click(); }) } if (document.getElementsByClassName('iconel-icon-camera')[0]) { document.getElementsByClassName('iconel-icon-camera')[0].addEventListener('click', function () { let imgData = scope.renderer.domElement.toDataURL("image/png"); let a = document.createElement("a"); // 生成一个a元素 let event = new MouseEvent("click"); // 创建一个单击事件 a.download = "photo"; // 设置图片名称 a.href = imgData; // 将生成的URL设置为a.href属性 a.dispatchEvent(event); // 触发a的单击事件 }) } if (document.getElementsByClassName('iconel-icon-magic-stick')[0]) { document.getElementsByClassName('iconel-icon-magic-stick')[0].addEventListener('click', function () { var css = document.getElementsByClassName('iconel-icon-magic-stick')[0].getAttribute('class'); var dom = document.getElementsByClassName('iconel-icon-magic-stick')[0]; var models = scope.models; if (scope.models[0].type == 'Object3D') { models = scope.models[0].children; } if (css.indexOf('active') > 0) { dom.classList.remove("active"); models.forEach((model, index) => { model.material.transparent = false; //model.material.opacity = 0.3; }); } else { dom.classList.add("active"); models.forEach((model, index) => { model.material.transparent = true; model.material.opacity = 0.3; }); } scope.refresh(); }) } if (document.getElementsByClassName('iconel-icon-box')[0]) { document.getElementsByClassName('iconel-icon-box')[0].addEventListener('click', function () { var css = document.getElementsByClassName('iconel-icon-box')[0].getAttribute('class'); var dom = document.getElementsByClassName('iconel-icon-box')[0]; var models = scope.models; if (scope.models[0].type == 'Object3D') { models = scope.models[0].children; } if (css.indexOf('active') > 0) { dom.classList.remove("active"); models.forEach((model, index) => { model.material.transparent = false; //model.material.opacity = 0.3; model.children = []; }); } else { dom.classList.add("active"); models.forEach((model, index) => { let edgesMtl = new THREE.LineBasicMaterial({ color: 0xff0000 }); let modelEdges = new THREE.EdgesGeometry(model.geometry, 1); let modelLine = new THREE.LineSegments(modelEdges, edgesMtl); model.add(modelLine); model.material.transparent = true; model.material.opacity = 0.3; }); } scope.refresh(); }) } if (document.getElementsByClassName('iconel-icon-scissors')[0]) { document.getElementsByClassName('iconel-icon-scissors')[0].addEventListener('click', function () { var css = document.getElementsByClassName('iconel-icon-scissors')[0].getAttribute('class'); var dom = document.getElementsByClassName('iconel-icon-scissors')[0]; for (var i = 0; i < scope.scene.children.length; i++) { if (scope.scene.children[i].type == 'PlaneHelper') { scope.scene.children[i].geometry.dispose(); scope.scene.children[i].material.dispose(); scope.scene.remove(scope.scene.children[i]); } } if (css.indexOf('active') > 0) { dom.classList.remove("active"); scope.renderer.clippingPlanes = []; scope.renderer.localClippingEnabled = false; scope.refresh(); if (scope.gui) { scope.gui.destroy(); scope.gui = ''; } } else { dom.classList.add("active"); scope.globalPlanes = new THREE.Plane(new THREE.Vector3(1, 0, 0), 0); var planeHelper = new THREE.PlaneHelper(scope.globalPlanes, modelSize, 0xff0000) planeHelper.visible = true; planeHelper.rotation.z = Math.PI / 2; planeHelper.position.set(0, 0, 0); scope.scene.add(planeHelper); scope.renderer.clippingPlanes = [scope.globalPlanes]; scope.renderer.localClippingEnabled = true; scope.globalPlanes.constant = 0; scope.refresh(); scope.createGUI(); } }) } if (document.getElementsByClassName('iconrefresh-right')[0]) { document.getElementsByClassName('iconrefresh-right')[0].addEventListener('click', function () { var css = document.getElementsByClassName('iconrefresh-right')[0].getAttribute('class'); var dom = document.getElementsByClassName('iconrefresh-right')[0]; document.getElementsByClassName('iconrefresh-right')[0].classList.remove("active"); scope.animationId && cancelAnimationFrame(scope.animationId); const animation = time => { scope.rotateObjY(1); scope.animationId = requestAnimationFrame(animation); }; if (css.indexOf('active') > 0) { dom.classList.remove("active"); scope.animationId && cancelAnimationFrame(scope.animationId); } else { dom.classList.add("active"); animation(); } }) } if (document.getElementsByClassName('iconrefresh-left')[0]) { document.getElementsByClassName('iconrefresh-left')[0].addEventListener('click', function () { var css = document.getElementsByClassName('iconrefresh-left')[0].getAttribute('class'); var dom = document.getElementsByClassName('iconrefresh-left')[0]; document.getElementsByClassName('iconrefresh-left')[0].classList.remove("active"); scope.animationId && cancelAnimationFrame(scope.animationId); const animation = time => { scope.rotateObjY(-1); scope.animationId = requestAnimationFrame(animation); }; if (css.indexOf('active') > 0) { dom.classList.remove("active"); scope.animationId && cancelAnimationFrame(scope.animationId); } else { dom.classList.add("active"); animation(); } }) } if (document.getElementsByClassName('iconel-icon-bottom')[0]) { document.getElementsByClassName('iconel-icon-bottom')[0].addEventListener('click', function () { scope.viewHelper.prepareAnimationData({ userData: { type: 'posY' } }, scope.viewHelper.controls.center) scope.viewHelper.animating = true }) } if (document.getElementsByClassName('iconel-icon-top')[0]) { document.getElementsByClassName('iconel-icon-top')[0].addEventListener('click', function () { scope.viewHelper.prepareAnimationData({ userData: { type: 'negY' } }, scope.viewHelper.controls.center) scope.viewHelper.animating = true }) } if (document.getElementsByClassName('iconel-icon-right')[0]) { document.getElementsByClassName('iconel-icon-right')[0].addEventListener('click', function () { scope.viewHelper.prepareAnimationData({ userData: { type: 'posX' } }, scope.viewHelper.controls.center) scope.viewHelper.animating = true }) } if (document.getElementsByClassName('iconel-icon-monitor')[0]) { document.getElementsByClassName('iconel-icon-monitor')[0].addEventListener('click', function () { if (document.fullscreenElement === null) { document.documentElement.requestFullscreen(); // scope.enlargeMax(); // scope.refresh(); } else if (document.exitFullscreen) { document.exitFullscreen(); // scope.initSize(); // scope.recoverSize(); } setTimeout(function () { document.getElementsByClassName('dg main a')[0].style.width = '120px' document.getElementsByClassName('dg main a')[0].style.marginTop = (window.innerHeight - 120) + 'px' document.getElementsByClassName('close-button close-bottom')[0].style.width = '120px' document.getElementsByClassName('close-button close-bottom')[0].style.opacity = 0 }, 100) }) } if (document.getElementsByClassName('iconel-icon-info')[0]) { document.getElementsByClassName('iconel-icon-info')[0].addEventListener('click', function () { var css = document.getElementsByClassName('iconel-icon-info')[0].getAttribute('class'); var dom = document.getElementsByClassName('iconel-icon-info')[0]; if (css.indexOf('active') > 0) { dom.classList.remove("active"); if (labels) { labels.visible = false; } } else { dom.classList.add("active"); labels.visible = true; } scope.refresh(); }) } if (document.getElementsByClassName('icons-home')[0]) { document.getElementsByClassName('icons-home')[0].addEventListener('click', function () { if (scope.models.length > 0) { scope.rebuildObject(scope.models[0]); scope.refresh(); } }) } if (document.getElementsByClassName('iconel-icon-copy-document')[0]) { document.getElementsByClassName('iconel-icon-copy-document')[0].addEventListener('click', function () { var css = document.getElementsByClassName('iconel-icon-copy-document')[0].getAttribute('class'); var dom = document.getElementsByClassName('iconel-icon-copy-document')[0]; var mtool2 = document.getElementsByClassName('mtool2')[0]; if (css.indexOf('active') > 0) { dom.classList.remove("active"); mtool2.style.display = 'none'; } else { dom.classList.add("active"); mtool2.style.display = 'block'; } }) } if (document.getElementsByClassName('iconfolder-opened')[0]) { } } loadFiles(files, filesMap) { if (files.length > 0) { var filesMap = filesMap || LoaderUtils.createFilesMap(files); var manager = new THREE.LoadingManager(); manager.setURLModifier(function (url) { url = url.replace(/^(\.?\/)/, ''); // remove './' var file = filesMap[url]; if (file) { // console.log('Loading', url); return URL.createObjectURL(file); } return url; }); //manager.addHandler( /\.tga$/i, new TGALoader() ); for (var i = 0; i < files.length; i++) { this.loadFile(files[i], manager); //this.renderFromFile(files[i]); } } } loadFile(file, manager) { var filename = file.name; var extension = filename.split('.').pop().toLowerCase(); var that = this; var reader = new FileReader(); var scope = this; switch (extension) { case 'fbx': reader.addEventListener('load', async function (event) { var contents = event.target.result; var { FBXLoader } = await import('three/examples/jsm/loaders/FBXLoader.js'); var loader = new FBXLoader(manager); var object = loader.parse(contents); for (var i = object.children.length - 1; i >= 0; i--) { if (object.children[i].type !== "Mesh") { object.remove(object.children[i]); } else { //object.children[i].material=config.defaultMaterial; //object.children[i].geometry.computeBoundingBox(); var material = config.defaultMaterial; for (var j = 0; j < config.objectJson.length; j++) { if (object.children[i].name == config.objectJson[j].name) { material = new THREE.MeshPhysicalMaterial({ color: config.objectJson[j].color, //物体颜色 metalness: 1.0, roughness: 0.4, reflectivity: 0.5, side: THREE.DoubleSide, }) } } object.children[i].material = material; var mesh = object.children[i]; gro.add(mesh); } } scope.scene.add(scope.rebuildObject(gro)); scope.refresh(); }, false); reader.readAsArrayBuffer(file); break; // case 'ifc': // reader.addEventListener( 'load', async function ( event ) { // var { IFCLoader } = await import( 'three/examples/jsm/loaders/IFCLoader.js' ); // var loader = new IFCLoader(); // var scene = await loader.parse( event.target.result ); // }, false ); // reader.readAsArrayBuffer( file ); // break; case 'obj': reader.addEventListener('load', async function (event) { var contents = event.target.result; var { OBJLoader } = await import('three/examples/jsm/loaders/OBJLoader.js'); var object = new OBJLoader().parse(contents); var gro = new THREE.Object3D(); for (var i = object.children.length - 1; i >= 0; i--) { if (object.children[i].type !== "Mesh") { object.remove(object.children[i]); } else { //object.children[i].material=config.defaultMaterial; //object.children[i].geometry.computeBoundingBox(); var material = config.defaultMaterial; for (var j = 0; j < config.objectJson.length; j++) { if (object.children[i].name == config.objectJson[j].name) { material = new THREE.MeshPhysicalMaterial({ color: config.objectJson[j].color, //物体颜色 metalness: 1.0, roughness: 0.4, reflectivity: 0.5, side: THREE.DoubleSide, }) } } object.children[i].material = material; var mesh = object.children[i]; gro.add(mesh); } } //scope.scene.add(scope.rebuildObject(object)); scope.scene.add(scope.rebuildObject(gro)); scope.refresh(); }, false); reader.readAsText(file); break; case 'stl': reader.addEventListener('load', async function (event) { var contents = event.target.result; var { STLLoader } = await import('three/examples/jsm/loaders/STLLoader.js'); var geometry = new STLLoader().parse(contents); scope.renderMesh(geometry); }, false); if (reader.readAsBinaryString !== undefined) { reader.readAsBinaryString(file); } else { reader.readAsArrayBuffer(file); } break; case 'js': case 'json': reader.addEventListener('load', function (event) { var contents = event.target.result; var data; try { labels = new THREE.Object3D(); data = JSON.parse(contents); config.objectJson = data.objects; for (var i = 0; i < data.dimentions.length; i++) { var a = data.dimentions[i].indicatorpoint1.split(','); a = [parseInt(a[0]), parseInt(a[1]), parseInt(a[2])] var b = data.dimentions[i].indicatorpoint2.split(','); b = [parseInt(b[0]), parseInt(b[1]), parseInt(b[2])] var c = data.dimentions[i].textpoint.split(','); c = [parseInt(c[0]), parseInt(c[1]), parseInt(c[2])] var ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2] var abc = [c[0] - ab[0], c[1] - ab[1], c[2] - ab[2]] var a1 = [a[0] + abc[0], a[1] + abc[1], a[2] + abc[2]] var b1 = [b[0] + abc[0], b[1] + abc[1], b[2] + abc[2]] var a2 = [a[0] + abc[0] * 1.1, a[1] + abc[1] * 1.1, a[2] + abc[2] * 1.1] var b2 = [b[0] + abc[0] * 1.1, b[1] + abc[1] * 1.1, b[2] + abc[2] * 1.1] var material = new THREE.LineBasicMaterial({ color: data.dimentions[i].color }) var geometry = new THREE.Geometry(); // geometry.vertices.push(new THREE.Vector3(a[0], a[1], a[2])); // geometry.vertices.push(new THREE.Vector3(a1[0], a1[1], a1[2])); geometry.vertices.push(new THREE.Vector3(a[0], a[1], a[2])); geometry.vertices.push(new THREE.Vector3(a2[0], a2[1], a2[2])); var line = new THREE.Line(geometry, material); labels.add(line); //that.scene.add(line); geometry = new THREE.Geometry(); // geometry.vertices.push(new THREE.Vector3(b[0], b[1], b[2])); // geometry.vertices.push(new THREE.Vector3(b1[0], b1[1], b1[2])); geometry.vertices.push(new THREE.Vector3(b[0], b[1], b[2])); geometry.vertices.push(new THREE.Vector3(b2[0], b2[1], b2[2])); line = new THREE.Line(geometry, material); //that.scene.add(line); labels.add(line); // geometry = new THREE.Geometry(); // geometry.vertices.push(new THREE.Vector3(a1[0], a1[1], a1[2])); // geometry.vertices.push(new THREE.Vector3(b1[0], b1[1], b1[2])); // line = new THREE.Line( geometry, material ); // that.scene.add(line); var hex = data.dimentions[i].color; var c1 = [(a1[0] + b1[0]) / 2, (a1[1] + b1[1]) / 2, (a1[2] + b1[2]) / 2] var origin = new THREE.Vector3(c1[0], c1[1], c1[2]); var c1a1 = [a1[0] - c1[0], a1[1] - c1[1], a1[2] - c1[2]] var dir = new THREE.Vector3(c1a1[0], c1a1[1], c1a1[2]); var length = origin.distanceTo(new THREE.Vector3(a1[0], a1[1], a1[2])); var arrowHelper = new THREE.ArrowHelper(dir, origin, length, hex); //var axis=new THREE.Vector3(-abc[0],-abc[1],-abc[2]) //arrowHelper.translateOnAxis(axis.normalize(),10); //that.scene.add(arrowHelper); labels.add(arrowHelper); var c1b1 = [b1[0] - c1[0], b1[1] - c1[1], b1[2] - c1[2]] dir = new THREE.Vector3(c1b1[0], c1b1[1], c1b1[2]); length = origin.distanceTo(new THREE.Vector3(b1[0], b1[1], b1[2])); arrowHelper = new THREE.ArrowHelper(dir, origin, length, hex); //that.scene.add(arrowHelper); labels.add(arrowHelper); ///////////////////////////文字///////////////////////////////////// //var loader = new THREE.FontLoader(); //loader.load('three/examples/fonts/helvetiker_regular.typeface.json',function(font){ //loader.load('static/fonts/helvetiker_regular.typeface.json',function(font){ var text = data.dimentions[i].textcontent; var g = new THREE.TextGeometry(text, { // 设定文字字体, font: modelFont, //尺寸 size: 5, //厚度 height: 0, }); //计算边界,暂时不用管 g.computeBoundingBox(); //3D文字材质 var m = new THREE.MeshBasicMaterial({ color: hex }); var mesh = new THREE.Mesh(g, m); mesh.position.set(c[0], c[1], c[2]); var axis = new THREE.Vector3(a1[0] - b1[0], a1[1] - b1[1], a1[2] - b1[2]) var a = parseInt(data.dimentions[i].textangle) / 180 mesh.rotateOnAxis(axis.normalize(), Math.PI * a); //that.scene.add(mesh); labels.add(mesh); scope.scene.add(labels); //}); } } catch (error) { alert(error); return; } //handleJSON( data ); }, false); reader.readAsText(file); break; default: console.error('Unsupported file format (' + extension + ').'); break; } } refresh() { const { width, height } = this.size; if (this.renderer) { this.renderer.setSize(width, height); this.renderer.render(this.scene, this.camera); this.renderer.autoClear = false; this.viewHelper.render(this.renderer); this.renderer.autoClear = true; } } createRenderScene() { if (this.needMachineBox) { this.camera.lookAt(0, 0, 0); } else { this.camera.lookAt(this.scene.position); } this.scene.add(this.camera); if (this.needGrid) { //网格 const { size, division, color1, color2 } = config.gridOption; this.scene.add(new THREE.GridHelper(size, division, color1, color2)); } //坐标轴:X轴红色, Y轴绿色, Z轴蓝色 // this.needAxes && this.scene.add(new THREE.AxesHelper(config.axesSize)); // this.scene.position.y = config.sceneTranslateY; this.handleResize = () => { const { width, height } = this.initSize(); this.resize(width, height); }; window.addEventListener('resize', this.handleResize, false); var scope = this; const animate = () => { var delta = this.clock.getDelta(); var needsUpdate = false; if (scope.viewHelper.animating === true) { scope.viewHelper.update(delta); needsUpdate = true; } if (needsUpdate === true) { scope.refresh(); } }; this.renderer.setAnimationLoop(animate); scope.refresh(); } cleanAll() { //释放所有资源 //window.removeEventListener('resize', this.handleResize); //cancelAnimationFrame(this.cycleId); if (this.gui) { this.gui.destroy(); this.gui = ''; } if (this.mesh) { this.mesh.geometry.dispose(); this.mesh.material.dispose(); } if (this.machineBox) { this.machineBox.geometry.dispose(); this.machineBox.material.dispose(); } // this.scene && this.scene.dispose(); this.controls && this.controls.dispose(); this.renderer.dispose(); this.renderer.forceContextLoss(); // this.renderer.context && (this.renderer.context = null); this.renderer.domElement = null; this.renderer = null; } renderFromFile(file, onFinish) { //从模型文件创建 this.reader = new FileReader(); this.onFileLoaded(geometry => { geometry.sourceFile = file.ETag; this.renderMesh(geometry, onFinish); }); if (this.reader.readAsBinaryString !== undefined) { this.reader.readAsBinaryString(file) } else { this.reader.readAsArrayBuffer(file) } } async renderFromUrl(url, onFinish, onerror) { //从http请求url创建 var scope = this; var extension = url.split('.').pop().toLowerCase(); var lastLength = extension.length //var jsonFile = url.substr(0, url.length - lastLength) + 'json'; // var jsonFile='../../../static/stl/name2.json'; // var jsonFile = '../../../static/stl/SLG/SLG-FL/SLG-FL.json'; switch (extension) { case 'stl': var { STLLoader } = await import('three/examples/jsm/loaders/STLLoader.js'); new STLLoader().load(url, function (geometry) { scope.renderMesh(geometry, onFinish); }, // called when loading is in progresses function (xhr) { // console.log((xhr.loaded / xhr.total * 100) + '% loaded'); }, // called when loading has errors function (error) { // console.log('An error happened'); }) break; case 'obj': var { OBJLoader } = await import('three/examples/jsm/loaders/OBJLoader.js'); new OBJLoader().load( // resource URL url, // called when resource is loaded function (object) { var gro = new THREE.Object3D(); for (var i = object.children.length - 1; i >= 0; i--) { if (object.children[i].type !== "Mesh") { object.remove(object.children[i]); continue; } var obj_name = object.children[i].name; var sss = obj_name.split("_"); var feat_id = sss[sss.length - 1]; var material = config.defaultMaterial; for (var j = 0; j < config.objectJson.length; j++) { if (obj_name == config.objectJson[j].name || feat_id == config.objectJson[j].name) { material = new THREE.MeshPhysicalMaterial({ color: config.objectJson[j].color, //物体颜色 metalness: 1.0, roughness: 0.4, reflectivity: 0.5, side: THREE.DoubleSide, }) } } object.children[i].material = material; var mesh = object.children[i]; gro.add(mesh); } scope.scene.add(scope.rebuildObject(gro)); scope.refresh(); if (onFinish && onFinish instanceof Function) onFinish(); }, // called when loading is in progresses function (xhr) { // console.log((xhr.loaded / xhr.total * 100) + '% loaded'); }, // called when loading has errors function (error) { // console.log('An error happened'); } ); break; case 'fbx': var { FBXLoader } = await import('three/examples/jsm/loaders/FBXLoader.js'); new FBXLoader().load( // resource URL url, // called when resource is loaded function (object) { var gro = new THREE.Object3D(); for (var i = object.children.length - 1; i >= 0; i--) { if (object.children[i].type !== "Mesh") { object.remove(object.children[i]); continue; } var obj_name = object.children[i].name; var sss = obj_name.split("_"); var feat_id = sss[sss.length - 1]; var material = config.defaultMaterial; for (var j = 0; j < config.objectJson.length; j++) { for (var k = 0; k < config.objectJson[j].names.length; k++) { if (obj_name == config.objectJson[j].names[k] || feat_id == config.objectJson[j].names[k]) { material = new THREE.MeshPhysicalMaterial({ color: config.objectJson[j].color, //物体颜色 metalness: 1.0, roughness: 0.4, reflectivity: 0.5, side: THREE.DoubleSide, }) } } } object.children[i].material = material; var mesh = object.children[i]; gro.add(mesh); } scope.scene.add(scope.rebuildObject(gro)); scope.refresh(); if (onFinish && onFinish instanceof Function) onFinish(); }, // called when loading is in progresses function (xhr) { // console.log((xhr.loaded / xhr.total * 100) + '% loaded'); }, // called when loading has errors function (error) { // console.log('An error happened'); } ); break; default: console.error('Unsupported file format (' + extension + ').'); break; } } //初始化模型配置 initialSetting(json_file_url, finish_callback) { var scope = this; let request = new XMLHttpRequest(); request.open('get', json_file_url); request.send(null); request.onload = function () { if (request.status == 200) { //var obj=JSON.parse(request.responseText); let setting_data = JSON.parse(request.responseText); //console.log(setting_data); if (setting_data.graphic) { config.objectJson = setting_data.graphic.elements; if (setting_data.graphic.config && setting_data.graphic.config.color) { config.defaultMaterial = new THREE.MeshPhysicalMaterial({ color: setting_data.graphic.config.color, //物体颜色 metalness: 1.0, roughness: 0.4, reflectivity: 0.5, side: THREE.DoubleSide, }) } scope.initSizeByJson(setting_data) } if (typeof finish_callback == "function") { finish_callback(true, setting_data); } } else { if (typeof finish_callback == "function") { finish_callback(false, null); } } } } //渲染模型的尺寸 initSizeByJson(data) { var scope = this try { config.objectJson = data.graphic.elements; config.dataJson = data; let arrowSizeT = data.dimention.config.arrow ? data.dimention.config.arrow.size ? parseFloat(data.dimention.config.arrow.size) : 0.1 : 0.1;//箭头尺寸 //0.1 let arrowColorT = data.dimention.config.arrow ? data.dimention.config.arrow.color ? data.dimention.config.arrow.color : "#000000" : "#000000";//箭头颜色 let textSizeT = data.dimention.config.text ? data.dimention.config.text.size ? parseFloat(data.dimention.config.text.size) : 0.08 : 0.08;//0.08 let textColorT = data.dimention.config.text ? data.dimention.config.text.color ? data.dimention.config.text.color : "#000000" : "#000000";//文字颜色 let offsetFromDimLineT = data.dimention.config.text ? data.dimention.config.text.offsetFromDimLine ? parseFloat(data.dimention.config.text.offsetFromDimLine) : 0.02 : 0.02;//文字离箭头引线的距离 let dimLineColorT = data.dimention.config.extensionLine ? data.dimention.config.extensionLine.color ? data.dimention.config.extensionLine.color : "#000000" : "#000000";//尺寸界限颜色 let extendBeyondDimLinesT = data.dimention.config.extensionLine ? data.dimention.config.extensionLine.extendBeyondDimLines ? parseFloat(data.dimention.config.extensionLine.extendBeyondDimLines) : 0.02 : 0.02;//箭头离尺寸界限的距离 let offsetFromOrigin = data.dimention.config.extensionLine ? data.dimention.config.extensionLine.offsetFromOrigin ? parseFloat(data.dimention.config.extensionLine.offsetFromOrigin) : 0.02 : 0.02;//尺寸界限离物体的距离 labels.children = [] for (var i = 0; i < data.dimention.elements.length; i++) { let item = data.dimention.elements[i]; let offsetFromDimLine = item.text.offsetFromDimLine ? item.text.offsetFromDimLine : offsetFromDimLineT; let extendBeyondDimLines = item.indicatorLine.extendBeyondDimLines ? item.indicatorLine.extendBeyondDimLines : extendBeyondDimLinesT; let dimLineColor = item.indicatorLine.color ? item.indicatorLine.color : dimLineColorT; let textColor = item.text.color ? item.text.color : textColorT; let textSize = item.text.size ? item.text.size : textSizeT; let arrowSize = item.arrow ? item.arrow.size ? item.arrow.size : arrowSizeT : arrowSizeT; let arrowColor = item.arrow ? item.arrow.color ? item.arrow.color : arrowColorT : arrowColorT; if (item.type == "leader") { let pointData = item.indicatorLine; let a = pointData.line1.point1; a = [parseFloat(a.x), parseFloat(a.y), parseFloat(a.z)] let a1 = pointData.line1.point2; a1 = [parseFloat(a1.x), parseFloat(a1.y), parseFloat(a1.z)] let b = pointData.line1.point3; b = [parseFloat(b.x), parseFloat(b.y), parseFloat(b.z)] let axisF = this.planeNormal(a, a1, b); var c = item.text.location; c = [parseFloat(c.x), parseFloat(c.y), parseFloat(c.z)] var line = this.drawLine(a, a1, dimLineColor); labels.add(line); let arrowHelper = this.drawArrowHelper(a, a1, arrowColor, arrowSize); labels.add(arrowHelper); ///////////////////////////文字///////////////////////////////////// var points = this.drawPoint(a1); labels.add(points); var text = item.text.content; var mesh = this.drawText(text, textSize, textColor); mesh.position.set(a1[0] + textWidthX * 0.1, a1[1], a1[2]); let textWidthX = (mesh.geometry.boundingBox.max.x - mesh.geometry.boundingBox.min.x) * 1.2; var axis = new THREE.Vector3(a1[0] - a[0], a1[1] - a[1], a1[2] - a[2]).normalize();//尺寸引线坐标轴方向 var axis2 = new THREE.Vector3(a1[0] + textWidthX - a1[0], a1[1] - a1[1], a1[2] - a1[2]).normalize().normalize();//箭头坐标轴方向 // console.log(axisF,axis, axis2,text, 1283) if (axisF.x != 0 && axisF.y == 0 && axisF.z == 0) { if (a[0] < 0) { if (axis.y < 0) { var line = this.drawLine(a1, [a1[0], a1[1] - textWidthX, a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0], a1[1] - textWidthX * 0.1, a1[2]); } else { var line = this.drawLine(a1, [a1[0], a1[1] + textWidthX, a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0], a1[1] + textWidthX * 0.9, a1[2]); } var o1 = 90 * 3.14 / 180 mesh.rotateY(-o1) mesh.rotateZ(-o1) } else { if (axis.y < 0) { var line = this.drawLine(a1, [a1[0], a1[1] - textWidthX, a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0], a1[1] - textWidthX * 0.9, a1[2]); } else { var line = this.drawLine(a1, [a1[0], a1[1] + textWidthX, a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0], a1[1] + textWidthX * 0.1, a1[2]); } var o1 = 90 * 3.14 / 180 mesh.rotateY(o1) mesh.rotateZ(o1) } var axis2 = new THREE.Vector3(0, 1, 0).normalize() mesh.translateOnAxis(axis2, offsetFromDimLine) } else if (axisF.x == 0 && axisF.y != 0 && axisF.z == 0) { if (a[1] > 0) { if (axis.x < 0) { var line = this.drawLine(a1, [a1[0] - textWidthX, a1[1], a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0] - textWidthX * 0.1, a1[1], a1[2]); } else { var line = this.drawLine(a1, [a1[0] + textWidthX, a1[1], a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0] + textWidthX * 0.9, a1[1], a1[2]); } var o1 = 90 * Math.PI / 180 var o2 = 180 * Math.PI / 180 mesh.rotateX(o1) mesh.rotateY(o2) } else { if (axis.x < 0) { var line = this.drawLine(a1, [a1[0] - textWidthX, a1[1], a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0] - textWidthX * 0.9, a1[1], a1[2]); } else { var line = this.drawLine(a1, [a1[0] + textWidthX, a1[1], a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0] + textWidthX * 0.1, a1[1], a1[2]); } var o1 = 90 * 3.14 / 180 mesh.rotateX(o1) } var axis2 = new THREE.Vector3(0, 1, 0).normalize() mesh.translateOnAxis(axis2, offsetFromDimLine) } else if (axisF.x == 0 && axisF.y == 0 && axisF.z != 0) { if (axis.x < 0) { var line = this.drawLine(a1, [a1[0] - textWidthX, a1[1], a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0] - textWidthX * 0.9, a1[1], a1[2]); } else { var line = this.drawLine(a1, [a1[0] + textWidthX, a1[1], a1[2]], dimLineColor); labels.add(line); mesh.position.set(a1[0] + textWidthX * 0.1, a1[1], a1[2]); } var axis2 = new THREE.Vector3(0, 1, 0).normalize() mesh.translateOnAxis(axis2, offsetFromDimLine) } labels.add(mesh); scope.scene.add(labels); } else if (item.type == "diameter") { let pointData = item.indicatorLine; let a = pointData.line1.point1; a = [parseFloat(a.x), parseFloat(a.y), parseFloat(a.z)] let a1 = pointData.line1.point2; a1 = [parseFloat(a1.x), parseFloat(a1.y), parseFloat(a1.z)] let b = pointData.line1.point3; b = [parseFloat(b.x), parseFloat(b.y), parseFloat(b.z)] let axisF = this.planeNormal(a, a1, b); if (axisF.x != 0 && axisF.y == 0 && axisF.z == 0) { //调换第一第二坐标位置 if ((a1[1] - a[1]) < 0) { var temp = a; a = a1; a1 = temp } } else if (axisF.x == 0 && axisF.y != 0 && axisF.z == 0) { //调换第一第二坐标位置 if ((a1[0] - a[0]) < 0) { var temp = a; a = a1; a1 = temp } } else if (axisF.x == 0 && axisF.y == 0 && axisF.z != 0) { //调换第一第二坐标位置 if ((a1[0] - a[0]) < 0) { var temp = a; a = a1; a1 = temp } } let Line3 = new THREE.Line3(new THREE.Vector3(a[0], a[1], a[2]), new THREE.Vector3(a1[0], a1[1], a1[2])) let c = Line3.getCenter() c = [c.x, c.y, c.z];//圆心坐标点 let r = Line3.distance() / 2;//半径 // console.log(r, 1110) ///////////////////////////文字///////////////////////////////////// var points = this.drawPoint(c); labels.add(points); //将模型添加到场景 var text = item.text.content; var mesh = this.drawText(text, textSize, textColor); mesh.position.set(c[0], c[1], c[2]); let textOffsetX = - 0.5 * (mesh.geometry.boundingBox.max.x - mesh.geometry.boundingBox.min.x); let textWidthX = (mesh.geometry.boundingBox.max.x - mesh.geometry.boundingBox.min.x) * 1.2; if (2 * r >= textWidthX) { //箭头一 let arrowHelper1 = this.drawArrowHelper(a, c, arrowColor, arrowSize); labels.add(arrowHelper1); //箭头二 let arrowHelper2 = this.drawArrowHelper(a1, c, arrowColor, arrowSize); labels.add(arrowHelper2); var axis = new THREE.Vector3(a1[0] - a[0], a1[1] - a[1], a1[2] - a[2]).normalize();//箭头坐标轴方向 if (axisF.x != 0 && axisF.y == 0 && axisF.z == 0) { let jiaodu = Math.atan2(a1[2] - c[2], a1[1] - c[1]) * 180 / Math.PI let x1 = Math.sin(Math.atan2(a1[2] - c[2], a1[1] - c[1])) let y1 = Math.cos(Math.atan2(a1[2] - c[2], a1[1] - c[1])) var axis2 = new THREE.Vector3(0, x1, -y1).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine) if (a[0] < 0) { if (axis.x < 0) { mesh.translateOnAxis(axis, textOffsetX) } else { mesh.translateOnAxis(axis, -textOffsetX) } let o1 = 90 * Math.PI / 180 let o2 = (90 + jiaodu) * Math.PI / 180 mesh.rotateX(o2) mesh.rotateY(-o1) } else { if (axis.x < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } let o1 = 90 * Math.PI / 180 let o2 = (90 + jiaodu) * Math.PI / 180 mesh.rotateX(o2) mesh.rotateY(o1) } line = this.drawArc(r, a[0], c[1], c[2], dimLineColor, "yz") labels.add(line); } else if (axisF.x == 0 && axisF.y != 0 && axisF.z == 0) { let jiaodu = Math.atan2(a1[2] - c[2], a1[0] - c[0]) * 180 / Math.PI; let x1 = Math.sin(Math.atan2(a1[2] - c[2], a1[0] - c[0])); let y1 = Math.cos(Math.atan2(a1[2] - c[2], a1[0] - c[0])); var axis2 = new THREE.Vector3(x1, 0, -y1).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine); if (a[1] > 0) { if (axis.x < 0) { mesh.translateOnAxis(axis, textOffsetX); } else { mesh.translateOnAxis(axis, -textOffsetX); } let o1 = 90 * Math.PI / 180; let o2 = (180 - jiaodu) * Math.PI / 180; mesh.rotateX(-o1); mesh.rotateZ(o2); } else { if (axis.x < 0) { mesh.translateOnAxis(axis, -textOffsetX); } else { mesh.translateOnAxis(axis, textOffsetX); } let o1 = 90 * Math.PI / 180; let o2 = (jiaodu) * Math.PI / 180; mesh.rotateX(o1); mesh.rotateZ(o2); } line = this.drawArc(r, a[1], c[0], c[2], dimLineColor, "xz"); labels.add(line); } else if (axisF.x == 0 && axisF.y == 0 && axisF.z != 0) { let jiaodu = Math.atan2(a1[1] - c[1], a1[0] - c[0]) * 180 / Math.PI let x1 = Math.sin(Math.atan2(a1[1] - c[1], a1[0] - c[0])); let y1 = Math.cos(Math.atan2(a1[1] - c[1], a1[0] - c[0])); if (axis.x < 0) { mesh.translateOnAxis(axis, -textOffsetX); } else { mesh.translateOnAxis(axis, textOffsetX); } let o2 = (jiaodu) * Math.PI / 180; var axis2 = new THREE.Vector3(x1, -y1, 0,).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine); mesh.rotateZ(o2); line = this.drawArc(r, a[2], c[0], c[1], dimLineColor, "xy"); labels.add(line); } } else { var axis = new THREE.Vector3(a1[0] - a[0], a1[1] - a[1], a1[2] - a[2]).normalize();//箭头坐标轴方向 var line = this.drawLine(a, a1, dimLineColor); labels.add(line); let aT = []; let a1T = []; if (axisF.x != 0 && axisF.y == 0 && axisF.z == 0) { let jiaodu = Math.atan2(a1[2] - c[2], a1[1] - c[1]) * 180 / Math.PI let x1 = Math.cos((180 + jiaodu) * Math.PI / 180) * (r + arrowSize * 1.5) let y1 = Math.sin((180 + jiaodu) * Math.PI / 180) * (r + arrowSize * 1.5) let x2 = Math.cos(jiaodu * Math.PI / 180) * (r + arrowSize * 1.5) let y2 = Math.sin(jiaodu * Math.PI / 180) * (r + arrowSize * 1.5) aT = [a[0], x1, y1]; a1T = [a[0], x2, y2]; if (a[0] < 0) { var a2T = [aT[0], aT[1] - textWidthX, aT[2]] var line = this.drawLine(aT, a2T, dimLineColor); labels.add(line); mesh.position.set(aT[0], aT[1] - textWidthX * 0.1, aT[2]); var axis2 = new THREE.Vector3(0, 0, -1).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine); let o1 = 90 * Math.PI / 180 mesh.rotateX(o1) mesh.rotateY(-o1) } else { var a2T = [a1T[0], a1T[1] + textWidthX, a1T[2]] var line = this.drawLine(a1T, a2T, dimLineColor); labels.add(line); mesh.position.set(a1T[0], a1T[1] + textWidthX * 0.1, a1T[2]); var axis2 = new THREE.Vector3(0, 0, -1).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine); let o1 = 90 * Math.PI / 180 mesh.rotateY(o1) mesh.rotateZ(o1) } line = this.drawArc(r, a[0], c[1], c[2], dimLineColor, "yz") labels.add(line); } else if (axisF.x == 0 && axisF.y != 0 && axisF.z == 0) { let jiaodu = Math.atan2(a1[2] - c[2], a1[0] - c[0]) * 180 / Math.PI; let x1 = Math.cos((180 + jiaodu) * Math.PI / 180) * (r + arrowSize * 1.5) let y1 = Math.sin((180 + jiaodu) * Math.PI / 180) * (r + arrowSize * 1.5) let x2 = Math.cos(jiaodu * Math.PI / 180) * (r + arrowSize * 1.5) let y2 = Math.sin(jiaodu * Math.PI / 180) * (r + arrowSize * 1.5) aT = [x1, a[1], y1]; a1T = [x2, a[1], y2]; if (a[1] > 0) { var a2T = [aT[0] - textWidthX, aT[1], aT[2]] var line = this.drawLine(aT, a2T, dimLineColor); labels.add(line); mesh.position.set(aT[0] - textWidthX * 0.1, aT[1], aT[2]); var axis2 = new THREE.Vector3(0, 0, -1).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine); let o1 = 90 * Math.PI / 180; let o2 = 180 * Math.PI / 180; mesh.rotateX(-o1); mesh.rotateZ(o2); } else { var a2T = [a1T[0] + textWidthX, a1T[1], a1T[2]] var line = this.drawLine(a1T, a2T, dimLineColor); labels.add(line); mesh.position.set(a1T[0] + textWidthX * 0.1, a1T[1], a1T[2]); var axis2 = new THREE.Vector3(0, 0, -1).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine); let o1 = 90 * Math.PI / 180; mesh.rotateX(o1); } line = this.drawArc(r, a[1], c[0], c[2], dimLineColor, "xz"); labels.add(line); } else if (axisF.x == 0 && axisF.y == 0 && axisF.z != 0) { let jiaodu = Math.atan2(a1[1] - c[1], a1[0] - c[0]) * 180 / Math.PI let x1 = Math.cos((180 + jiaodu) * Math.PI / 180) * (r + arrowSize * 1.5) let y1 = Math.sin((180 + jiaodu) * Math.PI / 180) * (r + arrowSize * 1.5) let x2 = Math.cos(jiaodu * Math.PI / 180) * (r + arrowSize * 1.5) let y2 = Math.sin(jiaodu * Math.PI / 180) * (r + arrowSize * 1.5) aT = [x1, y1, a[2],]; a1T = [x2, y2, a[2],]; var a2T = [a1T[0] + textWidthX, a1T[1], a1T[2]] var line = this.drawLine(a1T, a2T, dimLineColor); labels.add(line); mesh.position.set(a1T[0] + textWidthX * 0.1, a1T[1], a1T[2]); var axis2 = new THREE.Vector3(0, -1, 0).normalize(); mesh.translateOnAxis(axis2, -offsetFromDimLine); line = this.drawArc(r, a[2], c[0], c[1], dimLineColor, "xy"); labels.add(line); } //箭头一 let arrowHelper1 = this.drawArrowHelper(a, aT, arrowColor, arrowSize); labels.add(arrowHelper1); //箭头二 let arrowHelper2 = this.drawArrowHelper(a1, a1T, arrowColor, arrowSize); labels.add(arrowHelper2); } labels.add(mesh); scope.scene.add(labels); } else if (item.type == "line") { let pointData = item.indicatorLine; let a = pointData.line1.point1; a = [parseFloat(a.x), parseFloat(a.y), parseFloat(a.z)] let b = pointData.line2.point1; b = [parseFloat(b.x), parseFloat(b.y), parseFloat(b.z)] let a1 = pointData.line1.point2; a1 = [parseFloat(a1.x), parseFloat(a1.y), parseFloat(a1.z)] let b1 = pointData.line2.point2; b1 = [parseFloat(b1.x), parseFloat(b1.y), parseFloat(b1.z)] let axisF = this.planeNormal(a, a1, b1); let temp1 = []; let temp2 = []; temp1[0] = a1[0] - a[0] < 0 ? a1[0] + extendBeyondDimLines : a1[0] - extendBeyondDimLines temp1[1] = a1[1] - a[1] < 0 ? a1[1] + extendBeyondDimLines : a1[1] - extendBeyondDimLines temp1[2] = a1[2] - a[2] < 0 ? a1[2] + extendBeyondDimLines : a1[2] - extendBeyondDimLines temp2[0] = b1[0] - b[0] < 0 ? b1[0] + extendBeyondDimLines : b1[0] - extendBeyondDimLines temp2[1] = b1[1] - b[1] < 0 ? b1[1] + extendBeyondDimLines : b1[1] - extendBeyondDimLines temp2[2] = b1[2] - b[2] < 0 ? b1[2] + extendBeyondDimLines : b1[2] - extendBeyondDimLines let a2 = scope.crossPoint(temp1[0], temp1[1], temp1[2], a[0], a[1], a[2], a1[0], a1[1], a1[2]); let b2 = scope.crossPoint(temp2[0], temp2[1], temp2[2], b[0], b[1], b[2], b1[0], b1[1], b1[2]); var line = this.drawLine(a, a1, dimLineColor); labels.add(line); line = this.drawLine(b, b1, dimLineColor); labels.add(line); let c = [(a2[0] + b2[0]) / 2, (a2[1] + b2[1]) / 2, (a2[2] + b2[2]) / 2] let arrowHelper = this.drawArrowHelper(a2, c, arrowColor, arrowSize); labels.add(arrowHelper); arrowHelper = this.drawArrowHelper(b2, c, arrowColor, arrowSize); labels.add(arrowHelper); ///////////////////////////文字///////////////////////////////////// var points = this.drawPoint(c); labels.add(points); //将模型添加到场景 var text = item.text.content; var mesh = this.drawText(text, textSize, textColor); mesh.position.set(c[0], c[1], c[2]); let textOffsetX = - 0.5 * (mesh.geometry.boundingBox.max.x - mesh.geometry.boundingBox.min.x); let axis = new THREE.Vector3(a2[0] - b2[0], a2[1] - b2[1], a2[2] - b2[2]).normalize().round();//箭头坐标轴方向 if (axisF.x != 0 && axisF.y == 0 && axisF.z == 0) { if (a[0] >= 0) { if (axis.y != 0) { if (axis.y < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(0, 0, 1), offsetFromDimLine) let o = 90 * 3.14 / 180 mesh.rotateY(o) mesh.rotateZ(o) } else if (axis.z != 0) { if (axis.z < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(0, -1, 0), offsetFromDimLine) let o1 = 90 * 3.14 / 180 let o2 = 180 * 3.14 / 180 mesh.rotateY(o1) mesh.rotateZ(o2) } } else { if (axis.y != 0) { if (axis.y < 0) { mesh.translateOnAxis(axis, textOffsetX) } else { mesh.translateOnAxis(axis, -textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(0, 0, 1), offsetFromDimLine) let o = 90 * 3.14 / 180 mesh.rotateY(-o) mesh.rotateZ(-o) } else if (axis.z != 0) { if (axis.z < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(0, 1, 0), offsetFromDimLine) let o1 = 90 * 3.14 / 180 mesh.rotateY(-o1) } } } else if (axisF.x == 0 && axisF.y != 0 && axisF.z == 0) { if (a[1] > 0) { if (axis.x != 0) { if (axis.x < 0) { mesh.translateOnAxis(axis, textOffsetX) } else { mesh.translateOnAxis(axis, -textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(0, 0, 1), offsetFromDimLine) let o1 = 90 * 3.14 / 180 let o2 = 180 * 3.14 / 180 mesh.rotateX(-o1) mesh.rotateZ(o2) } else if (axis.z != 0) { if (axis.z < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(1, 0, 0), offsetFromDimLine) let o1 = 90 * 3.14 / 180 mesh.rotateX(-o1) mesh.rotateZ(-o1) } } else { if (axis.x != 0) { if (axis.x < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(0, 0, 1), offsetFromDimLine) let o = 90 * 3.14 / 180 mesh.rotateX(o) } else if (axis.z != 0) { if (axis.z < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(-1, 0, 0), offsetFromDimLine) let o1 = 90 * 3.14 / 180 mesh.rotateX(o1) mesh.rotateZ(o1) } } } else if (axisF.x == 0 && axisF.y == 0 && axisF.z != 0) { if (axis.x != 0) { if (axis.x < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(0, 1, 0), offsetFromDimLine) } else if (axis.y != 0) { if (axis.y < 0) { mesh.translateOnAxis(axis, -textOffsetX) } else { mesh.translateOnAxis(axis, textOffsetX) } mesh.translateOnAxis(new THREE.Vector3(-1, 0, 0), offsetFromDimLine) let o1 = 90 * 3.14 / 180 mesh.rotateZ(o1) } } labels.add(mesh); scope.scene.add(labels); } } if (document.getElementsByClassName('el-icon-info')[0]) { var css = document.getElementsByClassName('el-icon-info')[0].getAttribute('class'); if (css.indexOf('active') > 0) { if (labels) { labels.visible = true; } } else { labels.visible = false; } } scope.refresh(); } catch (error) { alert(error); return; } } setDimDisplay(isDisp) { labels.visible = isDisp; this.refresh(); } //绘制圆 drawArc(r, x, c1, c2, color, plane) { /** * r 半径 x 二维坐标变成三维坐标需要的第三个数值 * c1 c2 二维坐标系中圆中心坐标 * plane 平面标识:xy xz yz三种平面 * color 圆线的颜色 */ const vertices = []; const divisions = 50; for (let i = 0; i <= divisions; i++) { const v = (i / divisions) * (Math.PI * 2); const a = Math.sin(v) * r + c1; const b = Math.cos(v) * r + c2; if (plane == "yz") { vertices.push(x, a, b,); } else if (plane == "xz") { vertices.push(a, x, b,); } else if (plane == "xy") { vertices.push(a, b, x,); } } const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); const material = new THREE.LineBasicMaterial({ color: color, linewidth: 1 //由于OpenGL Core Profile与 大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。 }); const line = new THREE.Line(geometry, material); return line } //绘制箭头 drawArrowHelper(a, c, arrowColor, size) { /** * a 箭头的第一个点 * c 箭头的第二个点 * arrowColor 箭头颜色 * size 箭头大小 */ let headLength = size; let headWidth = size / 5; let origin = new THREE.Vector3(c[0], c[1], c[2]); let ca1 = [a[0] - c[0], a[1] - c[1], a[2] - c[2]] let dir = new THREE.Vector3(ca1[0], ca1[1], ca1[2]); let length = origin.distanceTo(new THREE.Vector3(a[0], a[1], a[2])); let arrowHelper = new THREE.ArrowHelper(dir.normalize(), origin, length, arrowColor, headLength, headWidth); return arrowHelper } //绘制线 drawLine(a, b, color) { /** * a 直线的第一个点 * b 直线的第二个点 * color 直线的颜色 */ let material = new THREE.LineBasicMaterial({ color: color }) let geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(a[0], a[1], a[2])); geometry.vertices.push(new THREE.Vector3(b[0], b[1], b[2])); let line = new THREE.Line(geometry, material); return line } //绘制点 drawPoint(a, color, size) { /** * a 绘制点的坐标 * color 点的颜色 * size 点的大小 */ var p = new THREE.Vector3(a[0], a[1], a[2]); var geometry = new THREE.Geometry(); geometry.vertices.push(p); var pointMaterial = new THREE.PointsMaterial({ color: color ? color : 0xFFFFFF, //设置颜色,默认 0xFFFFFF vertexColors: false, //定义材料是否使用顶点颜色,默认false ---如果该选项设置为true,则color属性失效 size: size ? size : 0.01 //定义粒子的大小。默认为1.0 }); //生成点模型 var points = new THREE.Points(geometry, pointMaterial); return points } //绘制文字 drawText(text, size, color) { /** * text 文字内容 * size 文字尺寸 * color 文字颜色 */ let g = new THREE.TextGeometry(text, { // 设定文字字体, font: modelFont, //尺寸 size: size, //厚度 height: 0, }); //计算边界,暂时不用管 g.computeBoundingBox(); //3D文字材质 let m = new THREE.MeshBasicMaterial({ color: color }); let mesh = new THREE.Mesh(g, m); return mesh; } //平面法向量 planeNormal(a, b, c) { /** * 根据不在一条直线上的三个点 计算平面的法向量 */ let plane = new THREE.Plane(); let p11 = new THREE.Vector3(a[0], a[1], a[2]); let p12 = new THREE.Vector3(b[0], b[1], b[2]); let p13 = new THREE.Vector3(c[0], c[1], c[2]); plane.setFromCoplanarPoints(p11, p12, p13) let axisF = plane.normal.normalize().round(); return axisF } //更新材质设置 updataMaterial() { var scope = this let object = scope.models[0] var gro = new THREE.Object3D(); for (var i = object.children.length - 1; i >= 0; i--) { if (object.children[i].type !== "Mesh") { object.remove(object.children[i]); } else { var material = config.defaultMaterial; for (var j = 0; j < config.objectJson.length; j++) { for (var k = 0; k < config.objectJson[j].names.length; k++) { if (object.children[i].name == config.objectJson[j].names[k]) { material = new THREE.MeshPhysicalMaterial({ color: config.objectJson[j].color, //物体颜色 metalness: 1.0, roughness: 0.4, reflectivity: 0.5, side: THREE.DoubleSide, }) } } } object.children[i].material = material; var mesh = object.children[i]; gro.add(mesh); } } scope.scene.add(scope.rebuildObject(gro)); scope.refresh(); } //更新尺寸标注的值 updateSizeValue(data, idstr) { var scope = this; let dataJson = config.dataJson; let elements = dataJson.dimention.elements; data.forEach((item) => { for (var i = 0; i < elements.length; i++) { let node = elements[i]; if (item.ID == node.id) { node.text.content = item.Value; break; } } }); labels.children = [] setTimeout(() => { scope.initSizeByJson(dataJson) }, 10); } //解析模型文件 onFileLoaded(callback) { this.reader.addEventListener('load', event => { const contents = event.target.result; const geometry = this.loader.parse(contents); geometry.sourceType = 'stl'; callback(geometry); }, false); } //渲染网格模型 renderMesh(geometry, onFinish, material = config.defaultMaterial) { geometry.computeVertexNormals(); //模型顶点平滑化 geometry.computeBoundingBox(); //计算模型包围盒 geometry.center(); //模型居中 this.mesh = new THREE.Mesh(geometry, material); //是否添加包围盒 this.needBoundingBox && this.initBboxHelper(this.mesh); if (this.needMachineBox) { const { x, y, z } = this.machineSize; this.createMachineBox(x, y, z); this.scene.add(this.mesh); } else { this.scene.add(this.rebuildObject(this.mesh)); } this.refresh(); if (onFinish && onFinish instanceof Function) onFinish(); } setMaterial(material) { //设置材质 this.mesh.material.dispose(); this.mesh.material = material; } //模型变换 rebuildObject(mesh, onFinish) { //旋转 mesh.rotation.x = -Math.PI / 2; mesh.rotation.z = Math.PI / 2; mesh.position.set(0, 0, 0); labels.rotation.x = -Math.PI / 2; labels.rotation.z = Math.PI / 2; labels.position.set(0, 0, 0); //缩放 const box = new THREE.Box3().setFromObject(mesh); const dx = Math.abs(box.max.x - box.min.x); const dy = Math.abs(box.max.y - box.min.y); const dz = Math.abs(box.max.z - box.min.z); //const rate = config.meshBaseSize / Math.max(dx, dy, dz); modelSize = Math.max(dx, dy, dz); // mesh.scale.set(rate, rate, rate); cameraPosition = { x: Math.max(dx, dy, dz) * 2, y: Math.max(dx, dy, dz) * 1.2, z: 0 } this.camera.position.set(Math.max(dx, dy, dz) * 2, Math.max(dx, dy, dz) * 1.2, 0); this.camera.updateProjectionMatrix(); var delta = new THREE.Vector3(-1.6, -0, 0); this.controls.rotate(delta) //this.refresh(); //平移 const box2 = new THREE.Box3().setFromObject(mesh); //mesh.position.y -= box2.min.y; const ax = (box2.max.x + box2.min.x) / 2; const az = (box2.max.z + box2.min.z) / 2; const ay = (box2.max.y + box2.min.y) / 2; mesh.position.x -= ax; mesh.position.z -= az; mesh.position.y -= ay; labels.position.x -= ax; labels.position.z -= az; labels.position.y -= ay; if (this.models.length < 1) this.models.push(mesh); return mesh; } //全屏 enlargeMax() { //const {innerWidth, innerHeight} = window; this.size.width = window.innerWidth; this.size.height = window.innerHeight; this.resize(innerWidth, innerHeight); this.renderer.setPixelRatio(window.devicePixelRatio) } //恢复初始尺寸 recoverSize() { const { width, height } = this.size; this.resize(width, height); } //更新大小 resize(width, height) { this.camera.aspect = width / height; this.camera.updateProjectionMatrix(); this.renderer.setSize(width, height); } //周围边框 initBboxHelper(mesh) { const bboxHelper = new THREE.BoxHelper(mesh); bboxHelper.visible = true; bboxHelper.geometry.computeBoundingBox(); this.scene.add(bboxHelper); } /* 灯光 */ initLights() { //方向光 this.initDirectionalLight(0, -400, 0); this.initDirectionalLight(0, 400, 0); this.initDirectionalLight(400, 0, 0); this.initDirectionalLight(-400, 0, 0); this.initDirectionalLight(0, 0, 400); this.initDirectionalLight(0, 0, -400); const light = new THREE.SpotLight(0xffff00, 1, 100, Math.PI / 6, 25); light.position.set(0, 400, 0); this.scene.add(light); //环境光 const light2 = new THREE.AmbientLight(config.ambientLightColor); this.scene.add(light2); //点光源 this.initPointLight(600, 600, 600); this.initPointLight(-600, 600, 600); this.initPointLight(600, 600, -600); this.initPointLight(-600, 600, -600); } //方向光 initDirectionalLight(x, y, z) { const light = new THREE.DirectionalLight(0xFFFFFF); light.position.set(x, y, z).normalize(); this.scene.add(light); } //点光源 initPointLight(x, y, z) { const light = new THREE.PointLight(0xFFFFFF, 1); light.position.set(x, y, z); this.scene.add(light); } //设置画布尺寸 initSize(w, h) { let width, height; if (w && h) { width = w; height = h; } else { const frame = getFrame(this.frameId); width = frame.offsetWidth; height = frame.offsetHeight; } this.size = { width, height }; return this.size; } /* 创建相机 */ createCamera({ fov, near, far } = config.defaultCameraOption) { const { width, height } = this.size; return new THREE.PerspectiveCamera(fov, width / height, near, far); } /* 创建渲染器 */ createRenderer() { const { width, height } = this.size; const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true }); renderer.setSize(width, height); renderer.setClearColor(new THREE.Color(config.rendererClearColor)); renderer.gammaInput = true; renderer.gammaOutput = true; this.container.appendChild(renderer.domElement); return renderer; } /**********************************************************************************************/ //设置背景色 setBackgroundColor(color) { this.renderer.setClearColor(new THREE.Color(color)); this.refresh(); } //创建机器边框 createMachineBox(x, y, z) { this.machineSize = { x, y, z }; this.originGeometry = this.mesh.geometry.clone(); const machineGeometry = new THREE.BoxGeometry(x, y, z); if (this.machineBox) { this.machineBox.geometry.dispose(); this.machineBox.geometry = machineGeometry; this.resetObject(); } else { this.machineBox = new THREE.Mesh(machineGeometry, new THREE.MeshNormalMaterial({ transparent: true, opacity: 0.2, side: THREE.DoubleSide })); this.machineBox.position.set(0, 0, 0); this.scene.add(this.machineBox); } this.setModelSize(); this.setAxesScaleLimits(); this.resetMachineBoxView(); } setAxesScaleLimits() { //计算单轴缩放倍数范围 if (!this.machineSize || !this.mesh) { return null; } const { x, y, z } = this.machineSize; const box = new THREE.Box3().setFromObject(this.mesh); const xSize = box.max.x - box.min.x, ySize = box.max.y - box.min.y, zSize = box.max.z - box.min.z; const getFloor = (l, s) => (Math.floor((l / s) * 100) / 100); const getCeil = (l, s) => (Math.ceil((l / s) * 100) / 100); this.axesScaleLimits = { x: { max: getFloor(x, xSize), min: getCeil(1, xSize) }, y: { max: getFloor(y, ySize), min: getCeil(1, ySize) }, z: { max: getFloor(z, zSize), min: getCeil(1, zSize) } } } getAxesScaleLimits() { //获取单轴缩放倍数范围 return this.axesScaleLimits || null; } setModelSize() { //计算模型尺寸 const box = new THREE.Box3().setFromObject(this.mesh); const xSize = (box.max.x - box.min.x).toFixed(2), ySize = (box.max.y - box.min.y).toFixed(2), zSize = (box.max.z - box.min.z).toFixed(2); this.modelSize = { xSize, ySize, zSize }; } getModelSize() { //获取模型尺寸 return this.modelSize || null; } resetObject() { //重置模型 this.mesh.geometry.dispose(); this.mesh.geometry = this.originGeometry.clone(); this.resetMachineBoxView(); this.setModelSize(); this.setAxesScaleLimits(); } handleTransitionByMatrix(matrix) { //执行变换 //this.mesh.geometry.applyMatrix(matrix); this.models[0].applyMatrix4(matrix); labels.applyMatrix4(matrix); this.refresh(); //this.resetMachineBoxView(); //this.setModelSize(); } resetMachineBoxView() { //刷新机器边框位置及照相机位置 const mBox = new THREE.Box3().setFromObject(this.machineBox); const box = new THREE.Box3().setFromObject(this.mesh); const boxCenterZ = (box.max.z + box.min.z) / 2; const boxH = box.max.z - box.min.z; const dz = boxCenterZ - mBox.min.z - boxH / 2; this.machineBox.position.z += dz; const mBox2 = new THREE.Box3().setFromObject(this.machineBox); const yLen = mBox2.max.y - mBox2.min.y; const asp = 2.3333; this.camera.position.set(0, -yLen * asp, (mBox2.max.z + mBox2.min.z) / 2); } rotateByMatrix(axis, radians) { //应用旋转矩阵 let rotateMatrix = new THREE.Matrix4(); rotateMatrix.makeRotationAxis(axis.normalize(), radians); this.handleTransitionByMatrix(rotateMatrix); } rotateObject(axes, angle) { //绕坐标轴旋转物体 const radian = THREE.Math.degToRad(angle); switch (axes) { case AXES.X: this.rotateByMatrix(new THREE.Vector3(1, 0, 0), radian); break; case AXES.Y: this.rotateByMatrix(new THREE.Vector3(0, 1, 0), radian); break; case AXES.Z: this.rotateByMatrix(new THREE.Vector3(0, 0, 1), radian); break; default: break; } this.setAxesScaleLimits(); } rotateObjX(angle) { //绕X轴旋转 this.rotateObject(AXES.X, angle); } rotateObjY(angle) { //绕Y轴旋转 this.rotateObject(AXES.Y, angle); } rotateObjZ(angle) { //绕Z轴旋转 this.rotateObject(AXES.Z, angle); } scaleByMatrix(x, y, z) { //应用缩放矩阵 let scaleMatrix = new THREE.Matrix4(); scaleMatrix.makeScale(x, y, z); this.handleTransitionByMatrix(scaleMatrix); } scaleObject(scale) { //缩放模型 this.scaleByMatrix(scale, scale, scale); } scaleCloneModel(scale) { cloneModel = this.models[0].clone(); if (this.models[0].material) { cloneModel.material = this.models[0].material.clone(); cloneModel.material.transparent = true; cloneModel.material.opacity = 0.4; } cloneModel.scale.set(scale, scale, scale); this.scene.add(cloneModel); this.refresh(); } setModelVisible(val) { this.models[0].visible = val; this.refresh(); } scaleAroundAxes(axes, scale) { // 单轴缩放 switch (axes) { case AXES.X: this.scaleByMatrix(scale, 1, 1); break; case AXES.Y: this.scaleByMatrix(1, scale, 1); break; case AXES.Z: this.scaleByMatrix(1, 1, scale); break; default: break; } } scaleObjX(scale) { // x轴方向缩放 this.scaleAroundAxes(AXES.X, scale); } scaleObjY(scale) { // y轴方向缩放 this.scaleAroundAxes(AXES.Y, scale); } scaleObjZ(scale) { // z轴方向缩放 this.scaleAroundAxes(AXES.Z, scale); } crossPoint(x, y, z, startx, starty, startz, endx, endy, endz) { var se = (startx - endx) * (startx - endx) + (starty - endy) * (starty - endy) + (startz - endz) * (startz - endz);//线段两点距离平方 var p = ((x - startx) * (endx - startx) + (y - starty) * (endy - starty) + (z - startz) * (endz - startz)); //向量点乘=|a|*|b|*cosA var r = p / se; //r即点到线段的投影长度与线段长度比 var outx = startx + r * (endx - startx); var outy = starty + r * (endy - starty); var outz = startz + r * (endz - startz); return [outx, outy, outz]; } }