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];
|
}
|
}
|