fl-web-component 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +24 -0
  2. package/dist/demo.html +10 -0
  3. package/dist/fl-web-component.common.js +316 -0
  4. package/dist/fl-web-component.common.js.map +1 -0
  5. package/dist/fl-web-component.css +1 -0
  6. package/dist/fl-web-component.umd.js +326 -0
  7. package/dist/fl-web-component.umd.js.map +1 -0
  8. package/dist/fl-web-component.umd.min.js +2 -0
  9. package/dist/fl-web-component.umd.min.js.map +1 -0
  10. package/package.json +47 -0
  11. package/packages/components/button/index.vue +22 -0
  12. package/packages/components/model/api/index.js +429 -0
  13. package/packages/components/model/api/mock/detecttree.js +58 -0
  14. package/packages/components/model/api/mock/getmodel-line.js +79336 -0
  15. package/packages/components/model/api/mock/init.js +1 -0
  16. package/packages/components/model/api/mock/pbstree.js +835 -0
  17. package/packages/components/model/api/mock/topology.json +3238 -0
  18. package/packages/components/model/components/TextOverTooltip/index.vue +84 -0
  19. package/packages/components/model/components/annotation-toolbar.vue +425 -0
  20. package/packages/components/model/components/check-proofing-model.vue +42 -0
  21. package/packages/components/model/components/clipping-type.vue +51 -0
  22. package/packages/components/model/components/com-dialogWrapper/Readme.md +53 -0
  23. package/packages/components/model/components/com-dialogWrapper/index.vue +117 -0
  24. package/packages/components/model/components/detect-panel.vue +327 -0
  25. package/packages/components/model/components/detect-tree.vue +460 -0
  26. package/packages/components/model/components/firstPer-panel.vue +111 -0
  27. package/packages/components/model/components/header-button.vue +546 -0
  28. package/packages/components/model/components/imageViewer/index.vue +127 -0
  29. package/packages/components/model/components/import-model.vue +127 -0
  30. package/packages/components/model/components/location-panel.vue +95 -0
  31. package/packages/components/model/components/measure-type.vue +59 -0
  32. package/packages/components/model/components/pbs-tree.vue +502 -0
  33. package/packages/components/model/components/proof-config.vue +80 -0
  34. package/packages/components/model/components/proof-for-pc.vue +123 -0
  35. package/packages/components/model/components/proof-history.vue +318 -0
  36. package/packages/components/model/components/proof-panel-detail.vue +567 -0
  37. package/packages/components/model/components/proof-panel.vue +770 -0
  38. package/packages/components/model/components/proof-project-user.vue +482 -0
  39. package/packages/components/model/components/proof-publish.vue +130 -0
  40. package/packages/components/model/components/proof-role.vue +535 -0
  41. package/packages/components/model/components/props-panel.vue +249 -0
  42. package/packages/components/model/index.vue +3413 -0
  43. package/packages/components/model/readme.md +31 -0
  44. package/packages/components/model/utils/annotation-tool.js +340 -0
  45. package/packages/components/model/utils/cursor.js +18 -0
  46. package/packages/components/model/utils/detect-v1.js +341 -0
  47. package/packages/components/model/utils/index.js +48 -0
  48. package/packages/components/model/utils/threejs/measure-angle.js +258 -0
  49. package/packages/components/model/utils/threejs/measure-area.js +269 -0
  50. package/packages/components/model/utils/threejs/measure-distance.js +207 -0
  51. package/packages/components/model/utils/threejs/measure-volume.js +94 -0
  52. package/packages/index.js +24 -0
@@ -0,0 +1,3413 @@
1
+ <template>
2
+ <div id="blocker">
3
+ <!-- 顶部按钮-->
4
+ <!-- :currentRoute="currentRoute" -->
5
+ <!-- @layerConfig="layerConfig" -->
6
+ <!-- @setHandleVisiable="setHandleVisiable" -->
7
+ <!-- drawName="" -->
8
+ <!-- 工具栏 -->
9
+ <CheckProofingModel
10
+ ref="checkProofingModel"
11
+ class="check-proofing-container"
12
+ @click="importProofModel"
13
+ :defaultParams="defaultParams"
14
+ />
15
+ <HeaderButton
16
+ v-show="showForScreenshot"
17
+ class="header-button-container"
18
+ ref="headerButton"
19
+ :canvasShow="true"
20
+ :closeRightOperationType="closeRightOperationType"
21
+ :proofingModel="proofingModel"
22
+ @rightOperation="headerRightOperation"
23
+ />
24
+ <ProofConfig
25
+ v-show="showForScreenshot"
26
+ ref="proofConfig"
27
+ class="proof-config-container"
28
+ @viewVersion="viewVersion"
29
+ @publishVersion="publishVersion"
30
+ :defaultParams="defaultParams"
31
+ />
32
+ <!-- <el-card class="tree-container">
33
+ <el-tabs v-model="activeName" :stretch="true">
34
+ <el-tab-pane label="工厂树" name="pbsTree">
35
+ <PbsTree
36
+ class="tree-box-item-card"
37
+ v-show="showForScreenshot"
38
+ ref="pbsTree"
39
+ @pbsNodeClick="pbsNodeClick"
40
+ @checkChange="checkChange"
41
+ />
42
+ </el-tab-pane>
43
+ <el-tab-pane label="碰撞报告" name="detectTree">
44
+ <DetectTree
45
+ class="tree-box-item-card"
46
+ v-show="showForScreenshot"
47
+ ref="detectTree"
48
+ @locate="locateByDetect"
49
+ @highlight="highlightByDetect"
50
+ :treeData="detectTreeData"
51
+ />
52
+ </el-tab-pane>
53
+ </el-tabs>
54
+ </el-card> -->
55
+ <PbsTree
56
+ class="tree-container"
57
+ v-show="showForScreenshot && showPbsTreePanel"
58
+ ref="pbsTree"
59
+ @pbsNodeClick="pbsNodeClick"
60
+ @checkChange="checkChange"
61
+ />
62
+ <!-- 模型 -->
63
+ <div id="instructions"></div>
64
+ <!-- 批注画板 -->
65
+ <div id="konva-drawing-board" v-show="showDrawingBoard"></div>
66
+
67
+ <!-- 工具栏 -->
68
+ <!-- <ToolBtn
69
+ v-if="toolBtnSetting.toolBtn.all"
70
+ :setting="toolBtnSetting.toolBtn"
71
+ ref="toolBtn"
72
+ @handleBtnEvent="handleBtnEvent"
73
+ @home="home"
74
+ @firstPer="firstPer"
75
+ /> -->
76
+ <!-- 测量 -->
77
+ <!-- <MeasureType v-if="ctrlPanel['measure']" @measure="handleMeasure" /> -->
78
+
79
+ <!-- 属性按钮 -->
80
+ <!-- <PropsBtn v-show="showForScreenshot" @lookDetails="lookPropsDetails" /> -->
81
+ <!-- 校审按钮 -->
82
+ <!-- <ProofBtn v-show="showForScreenshot" @lookDetails="lookProofDetails" /> -->
83
+ <!-- 碰撞检测按钮 -->
84
+ <!-- <DetectBtn v-show="showForScreenshot" @lookDetails="lookDetectDetails" /> -->
85
+
86
+ <!-- <el-button
87
+ v-show="showForScreenshot"
88
+ type="primary"
89
+ size="small"
90
+ @click="toggleDrawToolbar"
91
+ class="draw-btn"
92
+ :disabled="disableDrawBtn"
93
+ >批注工具栏</el-button
94
+ > -->
95
+ <div class="right-panel-container">
96
+ <!-- 属性面板 -->
97
+ <PropsPanel
98
+ class="props-panel-container"
99
+ ref="propsPanel"
100
+ v-if="showForScreenshot && showPropsPanel"
101
+ @rightOperation="rightOperation"
102
+ />
103
+ <!-- 校审面板 -->
104
+ <ProofPanel
105
+ class="proof-panel-container"
106
+ ref="proofPanel"
107
+ v-show="showForScreenshot && showProofPanel"
108
+ :defaultParams="defaultParams"
109
+ :proofData="proofData"
110
+ :showProofDetail="showProofDetail"
111
+ :readOnlyMode="readOnlyMode"
112
+ @selectRow="handleClickProofList"
113
+ @deleteRow="handleDeleteProofList"
114
+ @clickEditBtn="handleProofEditBtn"
115
+ @clickAddBtn="handleProofAddBtn"
116
+ @clickCancelBtn="handleProofCancelBtn"
117
+ @clickSaveBtn="handleProofSavelBtn"
118
+ @rightOperation="rightOperation"
119
+ />
120
+ <!-- 碰撞检查 -->
121
+ <DetectPanel
122
+ class="detect-panel-container"
123
+ ref="detectPanel"
124
+ v-if="showForScreenshot && showDetectPanel"
125
+ :defaultParams="defaultParams"
126
+ :treeData="detectTreeData"
127
+ @showReport="focusDetectTree"
128
+ @rightOperation="rightOperation"
129
+ @locate="locateByDetect"
130
+ @highlight="highlightByDetect"
131
+ @getDetectCheckTree="getDetectCheckTree"
132
+ />
133
+ </div>
134
+ <!-- 定位 -->
135
+ <LocationPanel
136
+ v-if="locationPanelShow"
137
+ :position="position"
138
+ ref="locationPanel"
139
+ @sureLocation="postLocation"
140
+ @cancel="cancelLocation"
141
+ />
142
+ <!-- 裁切 -->
143
+ <!-- <ClippingType v-if="ctrlPanel['clipping']" @clippingType="clippingType" /> -->
144
+
145
+ <!-- 点击批注添加时触发, 画板模式 closeDrawing: 退出添加批注功能 -->
146
+ <div v-if="showForScreenshot && showToolbar" class="toolbar_show toolbar-container">
147
+ <!-- 批注工具栏 -->
148
+ <DrawToolbar
149
+ ref="drawToolbar"
150
+ @closeDrawing="closeDrawing"
151
+ @handleDraw="handleDrawAnnotation"
152
+ @handleClear="handleClearAnnotation"
153
+ @colorChange="handleColorChange"
154
+ @save="preHandleProofSavelBtn"
155
+ />
156
+ </div>
157
+ <!-- 第一人称 -->
158
+ <el-dialog v-if="firstPerFlag" width="35%" :visible.sync="firstPerFlag">
159
+ <FirstPerPanel @start="start" />
160
+ </el-dialog>
161
+
162
+ </div>
163
+ </template>
164
+ <script>
165
+ import CameraControls from "camera-controls";
166
+ import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
167
+ import {
168
+ proofInit,
169
+ getModelByGroup,
170
+ getPropertyByGroup,
171
+ upload,
172
+ checkProofingModel,
173
+ getProjectId,
174
+ getDesignIp,
175
+ getOriginalPbsTree,
176
+ getTopology,
177
+ } from "./api/index.js";
178
+ import { loading, loadingClose } from "./utils/index";
179
+ import _ from "lodash";
180
+ import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
181
+ import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
182
+ import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
183
+ import helvetikerFont from "three/examples/fonts/helvetiker_regular.typeface.json";
184
+ import AnnotationDraw from "./utils/annotation-tool";
185
+ import Konva from "konva";
186
+ import cursors from "./utils/cursor";
187
+ import html2canvas from "html2canvas";
188
+ import MeasureDistance from './utils/threejs/measure-distance.js'
189
+ import MeasureArea from './utils/threejs/measure-area.js'
190
+ import MeasureAngle from './utils/threejs/measure-angle.js'
191
+ import MeasureVolume from './utils/threejs/measure-volume.js'
192
+ import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
193
+ import { LDrawUtils } from 'three/examples/jsm/utils/LDrawUtils.js'
194
+ import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js'
195
+ import ProofConfig from './components/proof-config.vue';
196
+ import ProofPanel from './components/proof-panel.vue';
197
+ import CheckProofingModel from './components/check-proofing-model.vue';
198
+ import PbsTree from './components/pbs-tree.vue';
199
+ import DetectTree from './components/detect-tree';
200
+ import PropsPanel from './components/props-panel.vue';
201
+ import CollisionSystem from "./utils/detect-v1";
202
+ import { MeshLineGeometry, MeshLineMaterial, raycast } from 'meshline';
203
+
204
+ // 初始值都为null的变量
205
+ var [animateId, recordAlphaBatch, threeMeasure, gui, cube, ] = (function* (v) {
206
+ while (true) yield v;
207
+ })(null);
208
+
209
+ // 初始值都为false
210
+ var [renderEnabled, roaming, moveForward,
211
+ moveBackward, moveLeft, moveRight, canJump,
212
+ roaming, listenerMouse, isWalking, isWalkingPaused,
213
+ clickKey, addRoamingFlag, markFlag
214
+ ] = (function* (v) {
215
+ while (true) yield v;
216
+ })(false);
217
+
218
+ // 初始值都为数组 []
219
+ var [clippingMesh, bombData, globePlanes,] = (function* (v) {
220
+ while (true) yield v;
221
+ })([]);
222
+
223
+ // 初始值都为数字 0
224
+ var [timeStamp, fpsClock, firstTime, lastTime] = (function* (v) {
225
+ while (true) yield v;
226
+ })(0);
227
+
228
+ // 初始值为空{}
229
+ var [batchTable,] = (function* (v) {
230
+ while (true) yield v;
231
+ })({});
232
+ var spaceUp = true // 处理一直按着空格连续跳的问题
233
+ var singleFrameTime = 1 / 30;
234
+ var renderEnabled = false;
235
+
236
+ var renderer,
237
+ camera,
238
+ scene,
239
+ modelGroup,
240
+ cameraControls,
241
+ instructions,
242
+ timeOut,
243
+ labelRenderer,
244
+ raycaster,
245
+ mouse,
246
+ intersect,
247
+ clock,
248
+ horizontalRaycaster,
249
+ downRaycaster,
250
+ velocity,
251
+ direction,
252
+ rotation,
253
+ pointControls,
254
+ previousModel;
255
+ let oldCheckedNodes = [];
256
+ var removeSpeed = 5000 //控制器移动速度
257
+ var upSpeed = 5000 //控制跳起时的速度
258
+ var modelClickEvent = '', clippingType = '';
259
+ var intersectsObject = [];
260
+
261
+ var targetObj = null,
262
+ konvaStage = null,
263
+ konvaLayer = null,
264
+ annotationTool = null,
265
+ inspectionRect = null;
266
+
267
+ const GEOM_TYPES = {
268
+ geom_3d: 53248,
269
+ geom_3d_text: 53249,
270
+ geom_3d_mtext: 53250,
271
+ geom_3d_obj: 53251,
272
+ geom_2d: 57344,
273
+ geom_2d_text: 57345,
274
+ geom_2d_mtext: 57346,
275
+ geom_2d_circle: 57347,
276
+ geom_2d_arc: 57348,
277
+ geom_2d_ellipse: 57349,
278
+ geom_2d_ellipseArc: 57350,
279
+ geom_2d_others: 57351,
280
+ };
281
+ const INSTANCES_TYPES = {
282
+ TEXTANNO: "TEXTANNO",
283
+ };
284
+ const STAGE_MODEL_TYPE = {
285
+ PID: 1,
286
+ REALITY: 2,
287
+ };
288
+
289
+ var guiParams = {
290
+ 'x轴': 0,
291
+ 'y轴': 0,
292
+ 'z轴': 0,
293
+ }
294
+
295
+ export default {
296
+ name: "GraphicModel",
297
+ // beforeRouteUpdate(to, from, next) {
298
+ // // 离开该组件所对应的特定路由时触发的事件
299
+ // // window.location.reload(); // TODO 临时刷新,待优化
300
+ // // console.log(to)
301
+ // // console.log(from)
302
+ // // this.mounted();
303
+ // next();
304
+ // },
305
+ data() {
306
+ return {
307
+ proofingModel: false,
308
+ showPropsPanel: false,
309
+ showProofPanel: false,
310
+ showDetectPanel: false,
311
+ showPbsTreePanel: true,
312
+ canvasLoading: false, // 批注下画板
313
+ showToolbar: false,
314
+ showDrawingBoard: false,
315
+ checkedToolbarItem: false,
316
+ drawing: false,
317
+ drawingType: "",
318
+ disableDrawBtn: true,
319
+ showForScreenshot: true,
320
+ defaultParams: {
321
+ projectId: null,
322
+ stageId: null,
323
+ version: null,
324
+ },
325
+ dataServerParams: {
326
+ toProjId: null,
327
+ toStagId: null,
328
+ toVersion: null,
329
+ },
330
+ activeName: 'pbsTree',
331
+ maxAltitude: 0,
332
+ firstPerFlag: false, // 第一视角弹框
333
+ isFirstPer: false, // 不再出现弹框
334
+ detectTreeData: [],
335
+ roamPanelName: '漫游',
336
+ roamingPath: [],
337
+ locationPanelShow: false,
338
+ // 操作按钮互斥, 弹出面板也要互斥, 记录控制面板的变量
339
+ ctrlPanel: {
340
+ view: false,
341
+ mark: false,
342
+ roaming: false,
343
+ material: false,
344
+ light: false,
345
+ clipping: false,
346
+ measure: false,
347
+ pid: false,
348
+ spotLight: false,
349
+ bomb: false,
350
+ alpha: false,
351
+ locationUser: false
352
+ },
353
+ toolBtnSetting: {
354
+ property: true,
355
+ rightClick: false,
356
+ leftClick: true,
357
+ leftBtnId: [0, 1],//左侧按钮列表的id,默认为[],为全部显示
358
+ modelBrowser: false,
359
+ treeShow: false,
360
+ scene: false,
361
+ toolBtn: {
362
+ all: true,
363
+ // home: false,
364
+ // view: true,
365
+ // mark: true,
366
+ // roaming: true,
367
+ // material: true,
368
+ // light: true,
369
+ clipping: true,
370
+ measure: true,
371
+ // pid: false,
372
+ // spotLight: true,
373
+ // bomb: true,
374
+ firstPer: true,
375
+ drawing: true,
376
+ // alpha: true,
377
+ // locationUser: true
378
+ }
379
+ },
380
+ modelCenter: {
381
+ x: 0,
382
+ y: 0,
383
+ z: 0
384
+ },
385
+ closeRightOperationType: {
386
+ type: '',
387
+ close: true
388
+ },
389
+ proofData: {
390
+ stageId: '',
391
+ version: null,
392
+ position: '',
393
+ projectId: '',
394
+ relevant: '',
395
+ previewScreenshotData: '',
396
+ problemPrintscreenId: ''
397
+ },
398
+ showProofDetail: false,
399
+ proofConfig: {
400
+ viewVersion: null
401
+ },
402
+ // onceRenderFlag: true, // 首次渲染标识
403
+ };
404
+ },
405
+ computed:{
406
+ activedToolBtn(){
407
+ let actived = false;
408
+ for(const key in this.ctrlPanel){
409
+ if(this.ctrlPanel[key] === true){
410
+ actived = true;
411
+ }
412
+ }
413
+ return actived
414
+ },
415
+ readOnlyMode(){
416
+ return !!this.defaultParams.version
417
+ }
418
+ },
419
+ components: {
420
+ ProofConfig,
421
+ ProofPanel,
422
+ CheckProofingModel,
423
+ PbsTree,
424
+ DetectTree,
425
+ PropsPanel,
426
+ // PbsTree: () => import("./components/pbs-tree"),
427
+ // DetectTree: () => import("./components/detect-tree"),
428
+ // PropsPanel: () => import("./components/props-panel.vue"),
429
+ // ProofPanel: () => import("./components/proof-panel.vue"),
430
+ DetectPanel: () => import("./components/detect-panel.vue"),
431
+ DrawToolbar: () => import("./components/annotation-toolbar.vue"),
432
+ // MeasureType: () => import('./components/measure-type.vue'),
433
+ // ClippingType: () => import('./components/clipping-type.vue'),
434
+ LocationPanel: () => import('./components/location-panel.vue'),
435
+ FirstPerPanel: () => import('./components/firstPer-panel.vue'),
436
+ HeaderButton: () => import("./components/header-button.vue"),
437
+ // CheckProofingModel: () => import("./components/check-proofing-model.vue"),
438
+ },
439
+ beforeRouteEnter(to, from, next) {
440
+ if(!to.query.version){
441
+ localStorage.removeItem('proofHistoryVersion')
442
+ }
443
+ next();
444
+ },
445
+ beforeRouteLeave(to, from, next) {
446
+ try{
447
+ this.$refs.proofPanel.clearUpdateModelInterval();
448
+ this.resetData();
449
+ this.$modal.closeLoading();
450
+ next();
451
+ } catch(err) {
452
+ console.log(err)
453
+ next();
454
+ }
455
+ },
456
+ created() {
457
+ this.defaultParams.projectId = this.$route.query.projectId;
458
+ this.defaultParams.version = this.$route.query.version;
459
+
460
+ console.log('defaultParams', this.defaultParams)
461
+ CameraControls.install({ THREE: this.THREE });
462
+ fpsClock = new this.THREE.Clock();
463
+ raycaster = new this.THREE.Raycaster();
464
+ mouse = new this.THREE.Vector2();
465
+ this.initData();
466
+ },
467
+ mounted() {
468
+ if(this.defaultParams.version){
469
+ this.init();
470
+ this.proofingModel = true;
471
+ }else{
472
+ // 检测模型是否正在校对中
473
+ this.$modal.loading("加载中...");
474
+ checkProofingModel(this.defaultParams).then((proofingModel) => {
475
+ if(proofingModel){
476
+ this.proofingModel = true;
477
+ this.init();
478
+ // this.$refs.proofPanel.IfUpdateModel(this.defaultParams);
479
+ this.$refs.proofConfig.abledProofPublishBtn();
480
+ }else{
481
+ this.$refs.proofConfig.ableImportModelBtn();
482
+ this.$refs.checkProofingModel.showCheckProofingModel();
483
+ this.$modal.closeLoading();
484
+ }
485
+ }).catch(err => {
486
+ console.log(err)
487
+ this.$modal.closeLoading();
488
+ })
489
+ }
490
+ },
491
+ watch: {
492
+ showToolbar(val) {
493
+ if (val === false && konvaStage) {
494
+ this.$nextTick(() => {
495
+ // this.clearPreViewAnn();
496
+ konvaStage.container().style.cursor = "default";
497
+ });
498
+ }
499
+ },
500
+ checkedToolbarItem(val) {
501
+ const div = document.getElementById("konva-drawing-board");
502
+
503
+ if (val) {
504
+ div.style.pointerEvents = "auto";
505
+ } else {
506
+ this.drawingType = "";
507
+ div.style.pointerEvents = "none";
508
+ }
509
+ },
510
+ },
511
+ methods: {
512
+ // 初始化模型服务
513
+ proofInit() {
514
+ loading("加载中...");
515
+
516
+ proofInit(this.defaultParams)
517
+ .then((res) => {
518
+ console.log(this.$refs);
519
+ // this.$refs.pbsTree.getPbsTree(this.defaultParams);
520
+ // this.$refs.detectTree.getPbsTree(this.defaultParams);
521
+
522
+ // 同时请求 ip 和 projectid
523
+ // const requests = [getDesignIp(), getProjectId({
524
+ // projectId: this.defaultParams.projectId
525
+ // })];
526
+
527
+ // console.log(requests)
528
+
529
+ // return Promise.all(requests)
530
+
531
+ return getProjectId({
532
+ projectId: this.defaultParams.projectId,
533
+ version: this.defaultParams.version,
534
+ })
535
+ })
536
+ .catch((err) => {
537
+ console.error(err);
538
+ })
539
+ .finally(() => {
540
+ loadingClose();
541
+ })
542
+ .then((res) => {
543
+ try{
544
+ // const ip = res[0];
545
+ const { data } = res;
546
+ this.dataServerParams.toProjId = data.toProjId; // 此处是校审项目 id 映射的业务项目 id;
547
+ this.dataServerParams.toStagId = data.toStagId;
548
+ this.dataServerParams.toVersion = data.toVersion;
549
+
550
+ this.$refs.pbsTree.getPbsTree({
551
+ // ip,
552
+ toProjId: this.dataServerParams.toProjId,
553
+ toStagId: this.dataServerParams.toStagId,
554
+ toVersion: this.dataServerParams.toVersion,
555
+ })
556
+ }catch(err){
557
+ console.error(err)
558
+ }
559
+ })
560
+ },
561
+ // 初始化操作
562
+ init() {
563
+ instructions = document.getElementById("instructions");
564
+ this.proofInit();
565
+ this.$nextTick(() => {
566
+ this.initAnnotation("konva-drawing-board");
567
+ this.loadDrawData();
568
+ });
569
+ this.draw();
570
+ setTimeout(() => {
571
+ this.timeRender();
572
+ }, 100);
573
+ },
574
+ // 绘制
575
+ draw() {
576
+ modelGroup = new this.THREE.Group();
577
+ this.initLabelRender();
578
+ this.initRender();
579
+ this.initScene();
580
+ this.initCamera({ type: "orthographic" });
581
+ this.initLight();
582
+ const _this = this;
583
+
584
+ window.onresize = this.onWindowResize;
585
+ renderer.domElement.addEventListener("mouseup", this.mouseClick, false);
586
+ renderer.domElement.addEventListener('mousedown', this.setOrbitPoint, false)
587
+
588
+ renderer.domElement.addEventListener("wheel", (e) => {
589
+ // canvas 禁止事件穿透
590
+ if (annotationTool) {
591
+ annotationTool.destroy();
592
+ annotationTool = null;
593
+ }
594
+ this.showDrawingBoard = false;
595
+ });
596
+ cameraControls.addEventListener("wake", (e) => {
597
+ renderEnabled = true;
598
+ listenerMouse = true;
599
+ });
600
+ cameraControls.addEventListener("sleep", (e) => {
601
+ renderEnabled = false;
602
+ });
603
+ cameraControls.addEventListener("controlstart", (res) => {
604
+ // this.resetOrbitPoint();
605
+ // window.controlstart = res;
606
+ // canvas 禁止事件穿透
607
+ this.clearPreViewAnn();
608
+ this.showDrawingBoard = false;
609
+ renderEnabled = true;
610
+ listenerMouse = true;
611
+ });
612
+ this.animate();
613
+ },
614
+ // 初始化无需视图绑定的内部变量
615
+ initData() {
616
+ this.propertyGroup = {};
617
+
618
+ // 缓存模型源数据
619
+ this.groupCache = {};
620
+
621
+ // 缓存属性源数据
622
+ this.groupPropsCache = {};
623
+
624
+ // 首次渲染标识
625
+ this.onceRenderFlag = true;
626
+ this.pickedModel = {
627
+ last: null,
628
+ current: null,
629
+ };
630
+ },
631
+ initHelper() {
632
+ const { stageId, version } = this.defaultParams;
633
+ if (stageId == STAGE_MODEL_TYPE.PID) {
634
+ const gridHelper = this.renderGridHelper();
635
+ scene.add(gridHelper);
636
+ }else{
637
+ const axesHelper = new this.THREE.AxesHelper(10000);
638
+ scene.add(axesHelper);
639
+ }
640
+ },
641
+ renderGridHelper(
642
+ size = 1000,
643
+ divisions = 100,
644
+ color1 = 0x444444,
645
+ color2 = 0x888888,
646
+ orient = "z"
647
+ ) {
648
+ color1 = new this.THREE.Color(color1);
649
+ color2 = new this.THREE.Color(color2);
650
+
651
+ const center = divisions / 2;
652
+ const step = size / divisions;
653
+ const halfSize = size / 2;
654
+
655
+ const vertices = [],
656
+ colors = [];
657
+
658
+ for (let i = 0, j = 0, k = -halfSize; i <= divisions; i++, k += step) {
659
+ if (orient === "x") {
660
+ vertices.push(0, -halfSize, k, 0, halfSize, k);
661
+ vertices.push(0, k, -halfSize, 0, k, halfSize);
662
+ } else if (orient === "y") {
663
+ vertices.push(-halfSize, 0, k, halfSize, 0, k);
664
+ vertices.push(k, 0, -halfSize, k, 0, halfSize);
665
+ } else if (orient === "z") {
666
+ vertices.push(-halfSize, k, 0, halfSize, k, 0);
667
+ vertices.push(k, -halfSize, 0, k, halfSize, 0);
668
+ }
669
+
670
+ const color = i === center ? color1 : color2;
671
+
672
+ color.toArray(colors, j);
673
+ j += 3;
674
+ color.toArray(colors, j);
675
+ j += 3;
676
+ color.toArray(colors, j);
677
+ j += 3;
678
+ color.toArray(colors, j);
679
+ j += 3;
680
+ }
681
+
682
+ const geometry = new this.THREE.BufferGeometry();
683
+ geometry.setAttribute(
684
+ "position",
685
+ new this.THREE.Float32BufferAttribute(vertices, 3)
686
+ );
687
+ geometry.setAttribute(
688
+ "color",
689
+ new this.THREE.Float32BufferAttribute(colors, 3)
690
+ );
691
+
692
+ const material = new this.THREE.LineBasicMaterial({
693
+ vertexColors: true,
694
+ toneMapped: false,
695
+ });
696
+
697
+ return new this.THREE.LineSegments(geometry, material);
698
+ },
699
+ /* 属性区域 */
700
+ // 查看属性
701
+ lookPropsDetails(val) {
702
+ this.$set(this, "showPropsPanel", val);
703
+ if (!val) {
704
+ this.$set(this, "detailsData", {});
705
+ }
706
+ },
707
+ // 查看属性
708
+ lookProofDetails(val) {
709
+ this.$set(this, "showProofPanel", val);
710
+ if (!val) {
711
+ this.$set(this, "proofDetailsData", {});
712
+ }
713
+ },
714
+
715
+ // 点击碰撞检查
716
+ lookDetectDetails(val) {
717
+ this.$refs.detectPanel.init({queryParams: {...this.defaultParams, rebuild: 0}}, { contentType: 'application/x-www-form-urlencoded'})
718
+ },
719
+
720
+ // 初始化渲染器
721
+ initRender() {
722
+ renderer = new this.THREE.WebGLRenderer({
723
+ antialias: true,
724
+ powerPreference: "high-performance",
725
+ alpha: true,
726
+ logarithmicDepthBuffer: true,
727
+ preserveDrawingBuffer: true, //保留图形缓冲区 TODO 临时截图使用
728
+ });
729
+ renderer.setPixelRatio(window.devicePixelRatio * 2);
730
+ renderer.setSize(window.innerWidth, window.innerHeight);
731
+ renderer.sortObjects = false;
732
+ renderer.domElement.id = "three-model";
733
+ //告诉渲染器需要阴影效果
734
+ renderer.shadowMap.enabled = true;
735
+ renderer.toneMapping = this.THREE.ACESFilmicToneMapping;
736
+ renderer.toneMappingExposure = 1.0;
737
+ renderer.outputEncoding = this.THREE.sRGBEncoding;
738
+ instructions.appendChild(renderer.domElement);
739
+ },
740
+ // 初始化文字画布
741
+ initLabelRender() {
742
+ labelRenderer = new CSS2DRenderer()
743
+ labelRenderer.setSize(window.innerWidth, window.innerHeight);
744
+ labelRenderer.domElement.style.position = "absolute";
745
+ labelRenderer.domElement.style.top = "0px";
746
+ labelRenderer.domElement.style.pointerEvents = "none";
747
+ instructions.appendChild(labelRenderer.domElement);
748
+ },
749
+ // 初始化相机
750
+ initCamera(options = {}) {
751
+ const { stageId } = this.defaultParams;
752
+ if (stageId == STAGE_MODEL_TYPE.PID) {
753
+ // 正投影相机
754
+ const width = window.innerWidth; //canvas画布宽度
755
+ const height = window.innerHeight; //canvas画布高度
756
+ const k = width / height; //canvas画布宽高比
757
+ const s = 200; //控制left, right, top, bottom范围大小
758
+ camera = new this.THREE.OrthographicCamera(
759
+ -s * k,
760
+ s * k,
761
+ s,
762
+ -s,
763
+ 1,
764
+ 8000
765
+ );
766
+ // camera.position.set(300, 300, 300);
767
+ // camera.lookAt(new this.THREE.Vector3(300, 300, 0));
768
+ }else{
769
+ camera = new this.THREE.PerspectiveCamera(
770
+ 45,
771
+ window.innerWidth / window.innerHeight,
772
+ 0.1,
773
+ 10000
774
+ );
775
+ }
776
+
777
+ this.initCameraControls();
778
+
779
+ },
780
+
781
+ // 初始化场景
782
+ initScene() {
783
+ scene = new this.THREE.Scene();
784
+
785
+ // const mat4 = new this.THREE.Matrix4();
786
+ // //生成绕x轴旋转90度的矩阵
787
+ // mat4.makeRotationX(-Math.PI/2);
788
+ // scene.applyMatrix4(mat4);
789
+ // window.scene = scene; // TODO delete
790
+ // window.three = this.THREE;
791
+ },
792
+
793
+ // 初始化控件
794
+ initCameraControls() {
795
+ cameraControls = new CameraControls(camera, renderer.domElement);
796
+ cameraControls.dollyToCursor = true;
797
+ cameraControls.smoothTime = 0.1;
798
+ cameraControls.draggingSmoothTime = 0.05;
799
+ cameraControls.truckSpeed = 2.0
800
+ cameraControls.infinityDolly = true
801
+ cameraControls.minDistance = 10
802
+ cameraControls.dollySpeed = 0.15; // 鼠标滚轮每次移动速度倍率
803
+ // window.cameraControls = cameraControls; // TODO delete
804
+ },
805
+ // 初始化光源
806
+ initLight() {
807
+ const pmremGenerator = new this.THREE.PMREMGenerator(renderer);
808
+ scene.environment = pmremGenerator.fromScene(
809
+ new RoomEnvironment(),
810
+ 0.06
811
+ ).texture;
812
+ },
813
+ // resetOrbitPoint() {
814
+ // return; // todo
815
+ // const _v3A = new this.THREE.Vector3();
816
+ // _v3A.set( 0, 0, -1 ).applyQuaternion( cameraControls._camera.quaternion );
817
+ // _v3A.multiplyScalar( cameraControls._spherical.radius );
818
+ // _v3A.add( cameraControls._camera.position );
819
+
820
+ // cameraControls.setFocalOffset( 0, 0, 0, false );
821
+ // cameraControls.moveTo( _v3A.x, _v3A.y, _v3A.z, false );
822
+
823
+ // cameraControls.reset(false);
824
+ // cameraControls.normalizeRotations();
825
+ // cameraControls.truck(0, 0)
826
+ // cameraControls.setFocalOffset(0, 0, 0, false);
827
+ // camera.position.set(0, 0, 0)
828
+ // camera.lookAt(new this.THREE.Vector3(0, 0, 0))
829
+ // camera.updateProjectionMatrix()
830
+
831
+ // cameraControls.setOrbitPoint(0, 0, 0, true)
832
+ // cameraControls.update();
833
+ // },
834
+ // 动画
835
+ animate() {
836
+ const delta = fpsClock.getDelta();
837
+ timeStamp += delta;
838
+ animateId = requestAnimationFrame(this.animate);
839
+ if (timeStamp > singleFrameTime) {
840
+ cameraControls.enabled && cameraControls.update(timeStamp);
841
+ this.firstPerspective()
842
+ renderEnabled = true
843
+ labelRenderer.render(scene, camera);
844
+
845
+ if (renderEnabled) {
846
+ renderer.render(scene, camera);
847
+ }
848
+ timeStamp = timeStamp % singleFrameTime;
849
+ }
850
+ },
851
+ // 延迟渲染
852
+ timeRender() {
853
+ // 设置为可渲染
854
+ renderEnabled = true;
855
+ if (timeOut) {
856
+ clearTimeout(timeOut);
857
+ }
858
+ timeOut = setTimeout(() => {
859
+ renderEnabled = false;
860
+ }, 1500);
861
+ },
862
+ // details面板创建
863
+ detailsMounted() {
864
+ if (this.entityId) {
865
+ this.$refs.propsPanel.getModelProperty(
866
+ this.entityId,
867
+ this.projectId,
868
+ intersect.object.userData.pbsId,
869
+ intersect.object.userData.version
870
+ ); // intersect.object.userData.pbsId
871
+ }
872
+ },
873
+
874
+ // 左击事件
875
+ mouseClick(event) {
876
+ // this.resetOrbitPoint();
877
+ lastTime = new Date().getTime();
878
+ if (event.button === 0) {
879
+ if (lastTime - firstTime < 300) {
880
+ clickKey = true;
881
+ listenerMouse = false;
882
+ }
883
+ if (clickKey) {
884
+ if (roaming || listenerMouse) {
885
+ listenerMouse = false;
886
+ return;
887
+ }
888
+ this.modelClick(event, "left", modelClickEvent);
889
+ clickKey = false;
890
+ }
891
+ } else if (event.button === 2) {
892
+ if (lastTime - firstTime < 300) {
893
+ // this.rightClick(event)
894
+ }
895
+ }
896
+ },
897
+ // 鼠标按下事件
898
+ setOrbitPoint(event) {
899
+ // this.resetOrbitPoint();
900
+ firstTime = new Date().getTime()
901
+ renderer.domElement.onmouseup = () => {
902
+ lastTime = new Date().getTime()
903
+ if( lastTime - firstTime < 300) {
904
+ clickKey = true
905
+ listenerMouse = false
906
+ }
907
+ }
908
+
909
+ if (event.button === 0) {
910
+ const elRect = renderer.domElement.getBoundingClientRect()
911
+ const canvasX = event.clientX - elRect.left
912
+ const canvasY = event.clientY - elRect.top
913
+ const mousePoint = new this.THREE.Vector2()
914
+ mousePoint.set(
915
+ ( canvasX / elRect.width ) * 2.0 - 1.0,
916
+ ( ( elRect.height - canvasY ) / elRect.height ) * 2.0 - 1.0
917
+ )
918
+ // camera.updateMatrixWorld()
919
+ raycaster.setFromCamera(mousePoint, camera)
920
+ const intersects = raycaster.intersectObjects(scene.children, true)
921
+ const obj = intersects && intersects.length > 0 ? intersects[0] : null
922
+ if (obj) {
923
+ cameraControls.setOrbitPoint(
924
+ obj.point.x, obj.point.y, obj.point.z, false
925
+ )
926
+ cameraControls.update()
927
+ }
928
+ }
929
+ },
930
+ highlightModel(model) {
931
+ if (typeof model == "string" && model == "reset") {
932
+ model = null;
933
+ }
934
+ // 非首次
935
+ if (this.pickedModel.last) {
936
+ // 同一模型
937
+ if (model && this.pickedModel.last.name == model.name) {
938
+ return;
939
+ } else {
940
+ // 恢复上个模型颜色
941
+ this.changeModelColor({
942
+ groupModel: this.pickedModel.last,
943
+ type: "reset",
944
+ });
945
+ }
946
+ }
947
+ this.pickedModel.last = model;
948
+
949
+ // 保存颜色
950
+ if (model) {
951
+ this.changeModelColor({
952
+ groupModel: model,
953
+ color: new this.THREE.Color(0x53a8ff),
954
+ });
955
+ }
956
+ },
957
+ changeModelColor({ groupModel, color, type = 'highlight' }) {
958
+ groupModel.children.forEach((item) => {
959
+ if (item.type === "Mesh") {
960
+ if (type == 'toggleHighlight') { // 碰撞报告 - 节点高亮的开关,点击高亮,再次点击取消高亮(此高亮与下面的模型点击高亮是两种高亮,且只显示最后一次处理的高亮)
961
+ if (item.material.userData.toggleColor) { // 恢复颜色:恢复原来的颜色
962
+ if (item.material.userData.highlightColor) { // 如果原色是模型点击高亮
963
+ item.material.color = item.material.userData.highlightColor;
964
+ } else { // 否则恢复原来的颜色
965
+ item.material.color = item.material.userData.originalColor;
966
+ }
967
+ item.material.userData.toggleColor = null;
968
+ } else if (item.material.userData.highlightColor) { // 更新颜色:若存在模型点击高亮,则覆盖
969
+ item.material.userData.toggleColor = color;
970
+ item.material.color = color;
971
+ } else { // 更新颜色:若为原色,则正常高亮
972
+ item.material.userData.originalColor = item.material.color;
973
+ item.material.userData.toggleColor = color;
974
+ item.material.color = color;
975
+ }
976
+ } else if (type == "reset") { // 模型点击 - 恢复颜色:恢复原来的颜色
977
+ if (item.material.userData.toggleColor) {
978
+ item.material.color = item.material.userData.toggleColor;
979
+ } else {
980
+ item.material.color = item.material.userData.originalColor;
981
+ }
982
+ item.material.userData.highlightColor = null;
983
+ } else if (type == "highlight") { // 模型点击 - 更新颜色:高亮当前颜色
984
+ if (!item.material.userData.toggleColor) { // 如果没有碰撞报告高亮,则保存原来的颜色
985
+ item.material.userData.originalColor = item.material.color;
986
+ }
987
+ item.material.userData.highlightColor = color;
988
+ item.material.color = color;
989
+ }
990
+ }
991
+ });
992
+
993
+ this.timeRender();
994
+ },
995
+ // 模型点击事件
996
+ modelClick(event, type, eventType) {
997
+ if (recordAlphaBatch !== null) {
998
+ this.editAlpha(recordAlphaBatch, "alpha", 1.0, true);
999
+ recordAlphaBatch = null;
1000
+ }
1001
+ //通过鼠标点击的位置计算出raycaster所需要的点的位置,以屏幕中心为原点,值的范围为-1到1.
1002
+ mouse.x = (event.clientX / instructions.offsetWidth) * 2 - 1;
1003
+ mouse.y = -(event.clientY / instructions.offsetHeight) * 2 + 1;
1004
+ // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
1005
+ raycaster.setFromCamera(mouse, camera);
1006
+ // 获取raycaster直线和所有模型相交的数组集合
1007
+ const intersects = raycaster.intersectObjects(scene.children, true);
1008
+ console.log("当前点击模型", intersects[0]);
1009
+ if (intersects.length > 0) {
1010
+ // 判断点击的是不是上一次选中的
1011
+ intersect = intersects[0];
1012
+ // 为了兼容之前的模型数据, 更换模型解析后 模型浏览树数据的entityId与batchId相等
1013
+ switch (eventType) {
1014
+ //根据entityId获取相关的属性信息
1015
+ case "showPropsPanel":
1016
+ this.$refs.propsPanel.getPropertiesByEntity(
1017
+ this.entityId,
1018
+ this.projectId,
1019
+ this.pbsId
1020
+ );
1021
+ break;
1022
+ // 点击事件
1023
+ default:
1024
+ const modelId = intersect.object.userData.instanceName;
1025
+ const params = {
1026
+ modelId,
1027
+ propertyGroup: this.propertyGroup
1028
+ };
1029
+
1030
+ this.pickedModel.current = intersect.object.parent;
1031
+
1032
+ if(!this.activedToolBtn){
1033
+ this.highlightModel(this.pickedModel.current);
1034
+ this.$refs.pbsTree.scrollTo(this.pickedModel.current.name);
1035
+ if (type === "left" && this.showPropsPanel) {
1036
+ this.$refs.propsPanel.getModelProperty(params);
1037
+ }
1038
+ }
1039
+
1040
+ // 剖切
1041
+ if (this.ctrlPanel.clipping && clippingType === 'local') {
1042
+ // for(let i = 0; i < this.pickedModel.current.children.length; i++){
1043
+ console.log(this.pickedModel.current )
1044
+ console.log(LDrawUtils.mergeObject( this.pickedModel.current ))
1045
+ this.controlModel(LDrawUtils.mergeObject( this.pickedModel.current ).children[0])
1046
+ // }
1047
+ }
1048
+ // this.getDataByEntityId(event, type, intersect.object)
1049
+ break;
1050
+ }
1051
+ } else {
1052
+ this.highlightModel("reset");
1053
+ this.$refs.propsPanel?.resetProperties();
1054
+ // renderer.autoClear = true
1055
+ //点击区域未获取模型对象
1056
+ this.entityId = "";
1057
+ intersect = undefined;
1058
+ // this.recoverColor()
1059
+ // this.clearCopyMesh()
1060
+ // this.clearEntites()
1061
+ switch (eventType) {
1062
+ default:
1063
+ if (type === "left") {
1064
+ this.leftClickDown && iframe.postMessage("leftClick", {});
1065
+ }
1066
+ break;
1067
+ }
1068
+ }
1069
+ },
1070
+ /**
1071
+ * 根据几何体的类型绘制对应的模型
1072
+ * @param {Object} geom- 几何体对象,包含类型和其他属性
1073
+ * @param {String} instanceName- 实例名称,用于标记模型
1074
+ * @return {Object}- 绘制的模型对象
1075
+ */
1076
+ drawModel(geom, instanceName) {
1077
+ let model;
1078
+
1079
+ if (
1080
+ geom.type == GEOM_TYPES.geom_2d ||
1081
+ geom.type == GEOM_TYPES.geom_2d_others
1082
+ ) {
1083
+ model = this.draw2Dmodel(geom, instanceName);
1084
+ // model = new this.THREE.Object(geom, this.material);
1085
+ } else if (geom.type == GEOM_TYPES.geom_2d_text) {
1086
+ model = this.drawText(geom, instanceName);
1087
+ } else if (
1088
+ geom.type == GEOM_TYPES.geom_2d_circle ||
1089
+ geom.type == GEOM_TYPES.geom_2d_arc ||
1090
+ geom.type == GEOM_TYPES.geom_2d_ellipse ||
1091
+ geom.type == GEOM_TYPES.geom_2d_ellipseArc
1092
+ ) {
1093
+ model = this.drawCurve(geom, instanceName);
1094
+ } else {
1095
+ model = this.draw3Dmodel(geom, instanceName);
1096
+ }
1097
+ return model;
1098
+ },
1099
+ /**
1100
+ * 绘制曲线
1101
+ *
1102
+ * @param {Object} geom- 包含曲线信息的几何体对象
1103
+ * @param {String} instanceName- 曲线实例的名称
1104
+ * @return {Object}- 包含曲线模型和曲线信息的对象
1105
+ */
1106
+ drawCurve(geom, instanceName) {
1107
+ let { points, normals } = geom;
1108
+ let aX = points[0];
1109
+ let aY = points[1];
1110
+ let aZ = points[2];
1111
+ let xrad = points[3];
1112
+ let yrad = points[4];
1113
+ let startAngle = points[5];
1114
+ let endAngle = points[6];
1115
+
1116
+ let curve = new this.THREE.EllipseCurve(
1117
+ 0,
1118
+ 0,
1119
+ xrad,
1120
+ yrad,
1121
+ startAngle,
1122
+ endAngle,
1123
+ false // 曲线方向为逆时针
1124
+ );
1125
+ let curvePoints = curve.getPoints(50);
1126
+ let list = [];
1127
+ for (let i = 0; i < curvePoints.length; i++) {
1128
+ const { x, y } = curvePoints[i];
1129
+ list.push(x);
1130
+ list.push(parseFloat(y));
1131
+
1132
+ // // 根据角度计算动态 Z 值(例如正弦波动)
1133
+ // const angle = Math.atan2(y, x); // 当前点的极角
1134
+ // const z = Math.sin(angle * 2) * 2; // Z轴动态变化
1135
+ // list.push(z); // 将原始的 z 坐标添加到列表中
1136
+ list.push(parseFloat(0)); // 将原始的 z 坐标添加到列表中
1137
+ }
1138
+
1139
+ const model = this.build2Dmodel(geom, { points: list, normals });
1140
+ model.rotation.x = -Math.PI / 2;
1141
+ model.position.set(aX, aY, aZ);
1142
+ model.userData.instanceName = instanceName;
1143
+ return model;
1144
+ },
1145
+ // 绘制 3D 模型
1146
+ draw3Dmodel(geom, instanceName) {
1147
+ const geometry = new this.THREE.BufferGeometry();
1148
+
1149
+ geometry.setIndex(geom.triangles);
1150
+ const position = new Float32Array(geom.points);
1151
+ const normal = new Float32Array(geom.normals);
1152
+ geometry.setAttribute(
1153
+ "position",
1154
+ new this.THREE.BufferAttribute(position, 3)
1155
+ );
1156
+ geometry.setAttribute(
1157
+ "normal",
1158
+ new this.THREE.BufferAttribute(normal, 3)
1159
+ );
1160
+
1161
+ const { color } = geom.prop;
1162
+ const material = new this.THREE.MeshStandardMaterial({
1163
+ color: new this.THREE.Color(
1164
+ `rgb(${color[0]}, ${color[1]}, ${color[2]})`
1165
+ ),
1166
+ side: this.THREE.DoubleSide,
1167
+ transparent: false, // 确保透明属性关闭
1168
+ opacity: 1, // 确保不透明
1169
+ metalness: 0.8,
1170
+ roughness: 0.5,
1171
+ // lightMapIntensity: 0.7,
1172
+ envMapIntensity: 0.5, // 调低环境贴图的强度
1173
+ });
1174
+ const mesh = new this.THREE.Mesh(geometry, material);
1175
+ // mesh.geometry.computeBoundingBox();
1176
+ mesh.userData.instanceName = instanceName;
1177
+
1178
+ return mesh;
1179
+ },
1180
+ // 根据 triangles 分割 points, 生成线
1181
+ getPointsForLine(points, triangles) {
1182
+ let result = [];
1183
+
1184
+ // 数组顶部添加 0 标志位应对索引
1185
+ triangles.unshift(0);
1186
+
1187
+ // 遍历三角形索引数组
1188
+ for (let i = 0; i < triangles.length; i++) {
1189
+ const sliceStartFlag = triangles[i];
1190
+ const sliceEndFlag = triangles[i + 1];
1191
+
1192
+ // 如果有下一个切片索引,则将当前切片的点坐标添加到结果数组中
1193
+ if (sliceEndFlag) {
1194
+ result.push(points.slice(sliceStartFlag * 3, sliceEndFlag * 3));
1195
+ }
1196
+ }
1197
+
1198
+ // 返回提取出的线条点坐标数组
1199
+ return result;
1200
+ },
1201
+ /**
1202
+ * 绘制 2D 模型的方法
1203
+ *
1204
+ * @param {Object} geom - 包含几何体信息的对象
1205
+ * @param {String} instanceName - 模型实例的名称
1206
+ * @returns {Object} - 包含所有 2D 模型的组对象
1207
+ */
1208
+ draw2Dmodel(geom, instanceName) {
1209
+ const points = this.getPointsForLine(geom.points, geom.triangles);
1210
+ const normals = this.getPointsForLine(geom.normals, geom.triangles);
1211
+ const group = new this.THREE.Group();
1212
+
1213
+ for (let i = 0; i < points.length; i++) {
1214
+ const line = this.build2Dmodel(geom, {
1215
+ points: points[i],
1216
+ normals: normals[i],
1217
+ });
1218
+ line.userData.instanceName = instanceName;
1219
+ group.add(line);
1220
+ }
1221
+ return group;
1222
+ },
1223
+ // 绘制 2D 模型
1224
+ build2Dmodel(geom, lineInfo) {
1225
+ const { points, normals } = lineInfo;
1226
+
1227
+ // const geometry = new LineGeometry()
1228
+ const geometry = new this.THREE.BufferGeometry();
1229
+
1230
+ const position = new Float32Array(points);
1231
+ const normal = new Float32Array(normals);
1232
+
1233
+ geometry.setAttribute(
1234
+ "position",
1235
+ new this.THREE.BufferAttribute(position, 3)
1236
+ );
1237
+ geometry.setAttribute(
1238
+ "normal",
1239
+ new this.THREE.BufferAttribute(normal, 3)
1240
+ );
1241
+
1242
+ const { color, linewidth } = geom.prop;
1243
+
1244
+ const material = new MeshLineMaterial({
1245
+ color: new this.THREE.Color(
1246
+ `rgb(${color[0]}, ${color[1]}, ${color[2]})`
1247
+ ),
1248
+ lineWidth: 0.2 * linewidth,
1249
+ });
1250
+ // const line = new Line2( geometry, material );
1251
+ // line.computeLineDistances();
1252
+ const lineGeometry = new MeshLineGeometry();
1253
+ lineGeometry.setPoints(geometry);
1254
+
1255
+ const mesh = new this.THREE.Mesh(lineGeometry, material);
1256
+ mesh.raycast = raycast
1257
+
1258
+ return mesh;
1259
+
1260
+ // // const material = new LineMaterial({
1261
+ // // color: new this.THREE.Color(`rgb(${color[0]}, ${color[1]}, ${color[2]})`),
1262
+ // // linewidth: linewidth,
1263
+ // // // dashed: false,
1264
+ // // })
1265
+ // const material = new this.THREE.LineBasicMaterial({
1266
+ // color: new this.THREE.Color(
1267
+ // `rgb(${color[0]}, ${color[1]}, ${color[2]})`
1268
+ // ),
1269
+ // linewidth: linewidth,
1270
+ // });
1271
+ // // const line = new Line2( geometry, material );
1272
+ // // line.computeLineDistances();
1273
+ // const line = new this.THREE.Line(geometry, material);
1274
+
1275
+ return line;
1276
+ },
1277
+ // drawText 方法,用于渲染 2D 或 3D 文字
1278
+ drawText(geom, instanceName) {
1279
+ const { prop, text, points, normals } = geom;
1280
+ const {
1281
+ color,
1282
+ linewidth,
1283
+ fontsize,
1284
+ fontname,
1285
+ rotate,
1286
+ italic,
1287
+ widthscale,
1288
+ } = prop;
1289
+
1290
+ var loader = new FontLoader();
1291
+ var font = loader.parse(helvetikerFont);
1292
+ var geometry = new TextGeometry(`${text}`, {
1293
+ font: font, // 字体格式
1294
+ size: fontsize, // 字体大小
1295
+ height: 1, // 字体深度
1296
+ curveSegments: 11, // 曲线控制点数
1297
+ bevelEnabled: true, // 斜角
1298
+ bevelThickness: 0.1, // 斜角的深度
1299
+ bevelSize: 1, // 斜角的大小
1300
+ bevelSegments: 1, // 斜角段数
1301
+ });
1302
+ // const { stageId } = this.defaultParams;
1303
+
1304
+ const normal = new Float32Array(normals);
1305
+ // 设置几何体的顶点法线属性.attributes.normal
1306
+ geometry.setAttribute(
1307
+ "normal",
1308
+ new this.THREE.BufferAttribute(normal, 3)
1309
+ );
1310
+
1311
+ const colors = color.split(",");
1312
+ var mat = new this.THREE.MeshBasicMaterial({
1313
+ color: new this.THREE.Color(
1314
+ `rgb(${colors[0]}, ${colors[1]}, ${colors[2]})`
1315
+ ),
1316
+ // opacity: 1,
1317
+ // shininess: 1,
1318
+ });
1319
+
1320
+ const mesh = new this.THREE.Mesh(geometry, mat);
1321
+
1322
+ // if (stageId == STAGE_MODEL_TYPE.PID) {
1323
+ // mesh.translateX(-(fontsize / 2));
1324
+ // mesh.translateY(-(fontsize / 2));
1325
+ // }
1326
+
1327
+ mesh.position.set(points[0], points[1], points[2]);
1328
+ if (rotate) {
1329
+ console.log('rotate', rotate,mesh)
1330
+ mesh.rotateY(rotate);
1331
+ }
1332
+ mesh.rotateX(-Math.PI/2);
1333
+ mesh.translateX(-(fontsize / 2));
1334
+ mesh.translateY(-(fontsize / 2));
1335
+
1336
+ mesh.userData.instanceName = instanceName;
1337
+
1338
+ return mesh;
1339
+ },
1340
+ /**
1341
+ * 根据组 ID 获取模型信息
1342
+ *
1343
+ * @param {string} groupId - 要获取模型信息的组 ID
1344
+ * @returns {Promise}
1345
+ */
1346
+ getModelsByGroup(groupId) {
1347
+ return new Promise((resolve) => {
1348
+ const param = {
1349
+ groupId: groupId,
1350
+ // ...this.defaultParams,
1351
+ ...this.dataServerParams,
1352
+ };
1353
+
1354
+ if(!this.groupCache[groupId]){
1355
+ getModelByGroup(param).then((res) => {
1356
+ const modelsInfo = this.groupCache[groupId] = res;
1357
+ console.log(modelsInfo);
1358
+ resolve(modelsInfo);
1359
+ }).catch((err) => {
1360
+ resolve(err);
1361
+ });
1362
+ }else{
1363
+ resolve(this.groupCache[groupId]);
1364
+ }
1365
+
1366
+ console.log('groupCache', this.groupCache)
1367
+
1368
+ // getModelByGroup(param).then((res) => {
1369
+ // const modelsInfo = res;
1370
+ // console.log(modelsInfo);
1371
+ // resolve(modelsInfo);
1372
+ // }).catch((err) => {
1373
+ // resolve(err);
1374
+ // });
1375
+ });
1376
+ },
1377
+
1378
+ getPropertyByGroup(groupId) {
1379
+ const param = {
1380
+ groupId: groupId,
1381
+ // ...this.defaultParams,
1382
+ ...this.dataServerParams,
1383
+ };
1384
+ if (!this.groupPropsCache[groupId]) {
1385
+ getPropertyByGroup(param).then((res) => {
1386
+ const propInfo = this.groupPropsCache[groupId] = res;
1387
+ console.log(propInfo);
1388
+ Object.assign(this.propertyGroup, propInfo)
1389
+ }).catch((err) => {
1390
+ console.log(err);
1391
+ });
1392
+ } else {
1393
+ Object.assign(this.propertyGroup, this.groupPropsCache[groupId])
1394
+ }
1395
+ },
1396
+ /**
1397
+ * 比较新选中节点与旧选中节点,获取新增和移除的节点
1398
+ * @param {Array} newCheckedNodes - 新选中的节点数组
1399
+ * @returns {Object} - 包含新增和移除节点的对象
1400
+ */
1401
+ diffCheckedNodes(newCheckedNodes) {
1402
+ // 找出新增的元素
1403
+ const addNodes = _.difference(newCheckedNodes, oldCheckedNodes);
1404
+ // 找出删除的元素
1405
+ const removedNodes = _.difference(oldCheckedNodes, newCheckedNodes);
1406
+
1407
+ console.log("oldCheckedNodes", oldCheckedNodes);
1408
+ oldCheckedNodes = newCheckedNodes;
1409
+ console.log("newCheckedNodes", newCheckedNodes);
1410
+ console.log("add:", addNodes); // 输出新增的元素
1411
+ console.log("Removed:", removedNodes); // 输出删除的元素
1412
+ return {
1413
+ addNodes,
1414
+ removedNodes,
1415
+ };
1416
+ },
1417
+ resetData(){
1418
+ oldCheckedNodes = [];
1419
+ },
1420
+ // 勾选 pbs 树渲染对应模型
1421
+ checkChange(nodes) {
1422
+ console.log("nodes", nodes);
1423
+ const { addNodes, removedNodes } = this.diffCheckedNodes(nodes);
1424
+
1425
+ const handleNodes = addNodes.length ? addNodes : removedNodes;
1426
+ const nodeState = addNodes.length ? "add" : "removed";
1427
+ this.getModelByNode(handleNodes, nodeState);
1428
+ },
1429
+ /**
1430
+ * 根据节点获取模型
1431
+ * @param {Array} nodes - 节点数组
1432
+ * @param {String} type - 操作类型,可能是 "add" 或 "remove"
1433
+ */
1434
+ async getModelByNode(nodes, type) {
1435
+ loading("加载中...");
1436
+ // nodes = ['1274011493561532418']
1437
+ for (let i = 0; i < nodes.length; i++) {
1438
+ const models = await this.getModelsByGroup(nodes[i]);
1439
+ models && this.handleModel(models, type);
1440
+
1441
+ type == 'add' && this.getPropertyByGroup(nodes[i]);
1442
+ }
1443
+
1444
+ console.log(this.onceRenderFlag);
1445
+ console.log(this.groupPropsCache);
1446
+ if(this.onceRenderFlag && scene.children.length){
1447
+ // this.initHelper();
1448
+ let box3 = new this.THREE.Box3().setFromObject(scene);
1449
+ this.setModelCenter(box3)
1450
+ this.setCameraConfig();
1451
+
1452
+ this.onceRenderFlag = false;
1453
+ }
1454
+ // 关闭加载提示
1455
+ loadingClose();
1456
+ },
1457
+ // async getModelByNode(nodes, type) {
1458
+ // loading("加载中...");
1459
+ // const promiseGroup = [];
1460
+ // for (let i = 0; i < nodes.length; i++) {
1461
+ // // const models = await this.getModelsByGroup(nodes[i]);
1462
+ // // models && this.handleModel(models, type);
1463
+ // const models = this.getModelsByGroup(nodes[i])
1464
+ // promiseGroup.push(models);
1465
+
1466
+ // models.then((models) => {
1467
+ // this.handleModel(models, type);
1468
+ // });
1469
+ // }
1470
+ // Promise.all(promiseGroup).then(() => {
1471
+ // // 关闭加载提示
1472
+ // loadingClose();
1473
+ // }).catch((error) => {
1474
+ // this.$message({
1475
+ // type: "error",
1476
+ // message: err.msg,
1477
+ // });
1478
+ // // 关闭加载提示
1479
+ // loadingClose();
1480
+ // })
1481
+ // },
1482
+
1483
+ // 点击 pbs 节点定位模型`
1484
+ // 这里应该是有问题的 因为给的是groupId groupName等信息,并没有具体能找到模型实体的id,所以要不就再新增一个接口
1485
+ // 还有一个问题是 定位应该是定位到某一个实体上 所以 tree的信息还得重新获取一下 因为这里写的是模拟的数据 现在接口服务关闭了
1486
+ pbsNodeClick(node) {
1487
+ const obj = scene.getObjectByName(node);
1488
+ console.log(obj);
1489
+
1490
+ if (obj) {
1491
+ this.clearPreViewAnn();
1492
+ this.showDrawingBoard = true;
1493
+ this.disableDrawBtn = true;
1494
+ this.showToolbar = false;
1495
+ if (annotationTool) {
1496
+ annotationTool.destroy();
1497
+ annotationTool = null;
1498
+ }
1499
+
1500
+ if (this.showPropsPanel) {
1501
+ const params = {
1502
+ modelId: obj.name,
1503
+ propertyGroup: this.propertyGroup,
1504
+ // ...this.defaultParams,
1505
+ };
1506
+
1507
+ this.$refs.propsPanel.getModelProperty(params);
1508
+ }
1509
+
1510
+ if(obj.children.length){
1511
+ cameraControls.fitToBox(obj, true);
1512
+ }
1513
+
1514
+ this.highlightModel(obj);
1515
+ }
1516
+ },
1517
+ locateModel(node) {
1518
+ const obj = scene.getObjectByName(node);
1519
+
1520
+ if (obj) {
1521
+ cameraControls.fitToBox(obj, true);
1522
+ }
1523
+ },
1524
+ // 相机定位
1525
+ animateCamera(
1526
+ cameraTargetX,
1527
+ cameraTargetY,
1528
+ cameraTargetZ,
1529
+ controlsTargetX,
1530
+ controlsTargetY,
1531
+ controlsTargetZ,
1532
+ moveSmooth = false,
1533
+ offset
1534
+ ) {
1535
+ // this.resetOrbitPoint(); // 还原轨道中心点
1536
+
1537
+ // offset && cameraControls.setOrbitPoint( 0, 0, 0, false )
1538
+
1539
+ cameraControls.setLookAt(
1540
+ cameraTargetX,
1541
+ cameraTargetY,
1542
+ cameraTargetZ,
1543
+ controlsTargetX,
1544
+ controlsTargetY,
1545
+ controlsTargetZ,
1546
+ moveSmooth
1547
+ );
1548
+
1549
+ offset && cameraControls.setFocalOffset( offset.x, offset.y, offset.z, false )
1550
+ cameraControls.update(0)
1551
+
1552
+ },
1553
+ // 根据 pbs 信息绘制 pbs 模型树
1554
+ handleModel(modelInfo, type) {
1555
+ const instances = modelInfo.instances;
1556
+ const isInstanceChildren =
1557
+ modelInfo.type && modelInfo.type === "instanceChildren";
1558
+
1559
+ const drawObjs = isInstanceChildren
1560
+ ? modelInfo.drawObjs
1561
+ : this.formatDrawObjs(modelInfo.drawObjs);
1562
+
1563
+ for (let i = 0; i < instances.length; i++) {
1564
+ // if(_.isEmpty(instances[i])){
1565
+ // continue;
1566
+ // }
1567
+ const drawId = instances[i].drawObject;
1568
+ const instanceName = instances[i].instanceId;
1569
+ const targetGroup = scene.getObjectByProperty("name", instanceName);
1570
+ // 如果找不到目标组(即首次勾选PBS树节点),则加载模型
1571
+ if (!targetGroup) {
1572
+ const group = new this.THREE.Group();
1573
+ group.name = instances[i].instanceId;
1574
+ group.userData.tags = instances[i].tags?.toUpperCase();
1575
+ group.userData.category = instances[i].category;
1576
+ group.userData.bounding = instances[i].bounding;
1577
+
1578
+ const matrix4 = instances[i].matrix.val;
1579
+
1580
+ if (instances[i].children && instances[i].children.length) {
1581
+ const childrenModelInfo = {
1582
+ instances: instances[i].children,
1583
+ drawObjs,
1584
+ type: "instanceChildren",
1585
+ parentGroup: group,
1586
+ };
1587
+
1588
+ this.handleModel(childrenModelInfo, type);
1589
+ }
1590
+
1591
+ if (drawObjs[drawId]) {
1592
+ drawObjs[drawId]["geoms"].forEach((item) => {
1593
+ const model = this.drawModel(item, instanceName);
1594
+ // intersectsObject.push(model);
1595
+
1596
+ group.add(model);
1597
+ });
1598
+ const m4 = new this.THREE.Matrix4();
1599
+ m4.elements = matrix4;
1600
+ group.applyMatrix4(m4);
1601
+
1602
+ if (isInstanceChildren) {
1603
+ // modelGroup.add(group);
1604
+ modelInfo.parentGroup.add(group);
1605
+ } else {
1606
+ modelGroup.add(group);
1607
+ }
1608
+ }
1609
+
1610
+ // 如果是列表中的最后一个实例,则将模型组添加到场景中
1611
+ // 子实例不需要执行
1612
+ if (i == instances.length - 1 && !isInstanceChildren) {
1613
+ scene.add(modelGroup);
1614
+ }
1615
+ // 如果找到了目标组,并且是新增操作,则显示模型
1616
+ } else if (targetGroup && type == "add") {
1617
+ targetGroup.visible = true;
1618
+ targetGroup.layers.set(0);
1619
+ // 如果找到了目标组,并且是移除操作,则隐藏模型
1620
+ } else if (targetGroup && type == "removed") {
1621
+ targetGroup.visible = false;
1622
+ targetGroup.layers.set(1);
1623
+ }
1624
+ }
1625
+ this.timeRender();
1626
+ },
1627
+ /**
1628
+ * 将数组数据转换为键值对形式的 JSON 对象
1629
+ * @param {Array} data - 包含对象的数组,每个对象都有一个 drawObjId 属性
1630
+ * @returns {Object}
1631
+ */
1632
+ formatDrawObjs(data) {
1633
+ const obj = {};
1634
+ data.forEach((item) => {
1635
+ obj[item.drawObjId] = item;
1636
+ });
1637
+ return obj;
1638
+ },
1639
+ initAnnotation(domId) {
1640
+ // canvas 禁止事件穿透
1641
+ const div = document.getElementById("konva-drawing-board");
1642
+ div.style.pointerEvents = "none";
1643
+
1644
+ const app = document.getElementById("app");
1645
+ konvaStage = new Konva.Stage({
1646
+ className: "stage",
1647
+ container: domId,
1648
+ width: app.clientWidth,
1649
+ height: app.clientHeight,
1650
+ draggable: false,
1651
+ });
1652
+ // window.konvaStage = konvaStage; // TODO delete
1653
+
1654
+ // konvaStage.container().style.background = "rgb(33,40,48)";
1655
+ konvaLayer = new Konva.Layer({
1656
+ name: "konva-layer",
1657
+ });
1658
+ konvaStage.add(konvaLayer);
1659
+ konvaLayer.draw();
1660
+ var scaleBy = 1.5;
1661
+ // konvaStage.on("wheel", (e) => {
1662
+ // e.evt.preventDefault();
1663
+ // var oldScale = konvaStage.scaleX();
1664
+ // var pointer = konvaStage.getPointerPosition();
1665
+ // var mousePointTo = {
1666
+ // x: (pointer.x - konvaStage.x()) / oldScale,
1667
+ // y: (pointer.y - konvaStage.y()) / oldScale,
1668
+ // };
1669
+ // // how to scale? Zoom in? Or zoom out?
1670
+ // let direction = e.evt.deltaY > 0 ? -1 : 1;
1671
+ // if (e.evt.ctrlKey) {
1672
+ // direction = -direction;
1673
+ // }
1674
+ // var newScale = direction > 0 ? oldScale * scaleBy : oldScale / scaleBy;
1675
+ // konvaStage.scale({ x: newScale, y: newScale });
1676
+ // var newPos = {
1677
+ // x: pointer.x - mousePointTo.x * newScale,
1678
+ // y: pointer.y - mousePointTo.y * newScale,
1679
+ // };
1680
+ // konvaStage.position(newPos);
1681
+ // });
1682
+ konvaStage.on("click", (e) => {
1683
+ const position = konvaStage.getPointerPosition();
1684
+ const x = (position.x - konvaStage.getX()) / konvaStage.scaleX();
1685
+ const y = (position.y - konvaStage.getY()) / konvaStage.scaleY();
1686
+ inspectionRect.setX(x);
1687
+ inspectionRect.setY(y);
1688
+ if (
1689
+ e.target.attrs.hasOwnProperty("className") &&
1690
+ e.target.attrs.className === "stage"
1691
+ ) {
1692
+ const obj = this.getIntersects(inspectionRect.getClientRect());
1693
+ targetObj = obj.length > 0 ? obj[obj.length - 1] : null;
1694
+ } else {
1695
+ targetObj = e.target;
1696
+ }
1697
+ // console.log(targetObj)
1698
+ if (targetObj === null || targetObj.attrs.name === "annotation-shape")
1699
+ return;
1700
+ this.entityId = targetObj.attrs.entityId;
1701
+ if (e.evt.button === 0) {
1702
+ this.svgClick(targetObj);
1703
+ } else if (e.evt.button === 2) {
1704
+ // 为2是右击
1705
+ this.rightClick(targetObj);
1706
+ }
1707
+ });
1708
+ konvaStage.on("contextmenu", (e) => {
1709
+ e.evt.preventDefault();
1710
+ });
1711
+ },
1712
+ // 碰撞检测
1713
+ getIntersects(rect) {
1714
+ let l = konvaLayer.children.length;
1715
+ let intersects = [];
1716
+ for (let index = 0; index < l; index++) {
1717
+ const ele = konvaLayer.children[index];
1718
+ if (ele.attrs.name !== "intersect-rect") {
1719
+ const boundingRect = ele.getClientRect();
1720
+ if (
1721
+ !(
1722
+ rect.x + rect.width < boundingRect.x ||
1723
+ boundingRect.x + boundingRect.width < rect.x ||
1724
+ rect.y + rect.height < boundingRect.y ||
1725
+ boundingRect.y + boundingRect.height < rect.y
1726
+ )
1727
+ ) {
1728
+ intersects.push(ele);
1729
+ }
1730
+ }
1731
+ }
1732
+ return intersects;
1733
+ },
1734
+
1735
+ handleDrawAnnotation(parmas = {}) {
1736
+ this.showDrawingBoard = true;
1737
+ this.checkedToolbarItem = true;
1738
+ parmas.type = parmas.type || "";
1739
+ this.drawingType = parmas.type;
1740
+ this.drawingStrokeWidth = parmas.strokeWidth;
1741
+ // 需要开启禁止拖动
1742
+ switch (parmas.type) {
1743
+ case "Rect":
1744
+ konvaStage.container().style.cursor = "crosshair"; // `url('${cursors.eraser}') 15 15, auto`
1745
+ break;
1746
+ case "Line":
1747
+ konvaStage.container().style.cursor = `url('${cursors.pen}') 15 15, auto`;
1748
+ break;
1749
+ case "Circle":
1750
+ konvaStage.container().style.cursor = "crosshair";
1751
+ break;
1752
+ case "Rubber":
1753
+ konvaStage.container().style.cursor = `url('${cursors.eraser}') 10 28, auto`;
1754
+ break;
1755
+ case "Text":
1756
+ konvaStage.container().style.cursor = `url('${cursors.text}') 15 15, auto`;
1757
+ break;
1758
+ }
1759
+ // konvaStage.draggable(false);
1760
+ if (annotationTool) {
1761
+ annotationTool.updateType({
1762
+ type: parmas.type,
1763
+ strokeWidth: parmas.strokeWidth,
1764
+ });
1765
+ } else {
1766
+ annotationTool = new AnnotationDraw.AnnotationTool(
1767
+ konvaStage,
1768
+ konvaLayer,
1769
+ parmas.type,
1770
+ parmas.strokeWidth
1771
+ );
1772
+ annotationTool.start();
1773
+ // window.annotationTool = annotationTool; // TODO delete
1774
+ }
1775
+ },
1776
+ handleClearAnnotation() {
1777
+ this.handleDrawAnnotation();
1778
+ if (annotationTool) {
1779
+ annotationTool.clearLayer();
1780
+ }
1781
+ },
1782
+ handleColorChange(val) {
1783
+ if (annotationTool) {
1784
+ annotationTool.updateColor(val);
1785
+ }
1786
+ },
1787
+
1788
+ locationAnnotation(id) {
1789
+ // this.leftAllDrawings = false
1790
+ // this.leftDrawingStructure = false
1791
+ // this.avatarImage = item.path
1792
+ // this.proxyImageShow = true
1793
+ // 获取标注的列表添加到图纸中并且定位
1794
+ // 清除上一次查看的标注
1795
+ this.clearPreViewAnn();
1796
+ getMarkOne(id)
1797
+ .then((res) => {
1798
+ console.log(res);
1799
+ if (res.code === 200 && res.data) {
1800
+ const x = Number(res.data.x);
1801
+ const y = Number(res.data.y);
1802
+ const z = Number(res.data.z);
1803
+ konvaStage.setX(x);
1804
+ konvaStage.setY(y);
1805
+ konvaStage.scale({
1806
+ x: z,
1807
+ y: z,
1808
+ });
1809
+ // this.drawCallbackData(res.data.relevant);
1810
+ }
1811
+ })
1812
+ .catch();
1813
+ },
1814
+ viewingDraw() {
1815
+ konvaStage.draggable(false); // 不可移动
1816
+ },
1817
+ editingDraw() {
1818
+ konvaStage.draggable(false); // 不可移动
1819
+ },
1820
+ // 保存标记后的图片
1821
+ handleSaveAnnotation() {
1822
+ this.handleDrawAnnotation();
1823
+ if (!annotationTool.layer?.children?.length) {
1824
+ return;
1825
+ }
1826
+ // this.$refs.drawToolbar.showToolbar = false; // 关闭画板工具条
1827
+ this.showToolbar = false; // 关闭画板工具条
1828
+ this.canvasLoading = true;
1829
+ const annotationArr = [];
1830
+ annotationTool.layer.children.forEach((item) => {
1831
+ annotationArr.push(item.attrs);
1832
+ });
1833
+
1834
+ return annotationArr;
1835
+ console.log(JSON.stringify(annotationArr));
1836
+ // this.screenshot(JSON.stringify(annotationArr));
1837
+ },
1838
+ /* 保存批注
1839
+ 将当前可视窗口使用html2canvas插件的照相机功能,保存为图片
1840
+ 将图片及该批注图片相对于svg的位置及大小发给后端
1841
+ 下次点击批注图片时,将SVG位置及大小实时更新 */
1842
+ async screenshot() {
1843
+ this.showForScreenshot = false;
1844
+ let canvasID = document.getElementById("app"); // this.$refs.drawingDisplay
1845
+
1846
+ let canvas;
1847
+ await new Promise((resolve) => {
1848
+ this.$nextTick(async () => {
1849
+ canvas = await html2canvas(canvasID, {
1850
+ allowTaint: true,
1851
+ useCORS: true,
1852
+ });
1853
+ resolve();
1854
+ });
1855
+ });
1856
+
1857
+ let urlData = canvas.toDataURL("image/jpeg", 1.0);
1858
+ this.showForScreenshot = true;
1859
+ return urlData;
1860
+ // this.uploadScreenshot(urlData)
1861
+ // if (res.code === 200) {
1862
+ // await this.uploadByUrl(res.data.link, file);
1863
+ // const obj = {
1864
+ // documentId: this.presentDrawing,
1865
+ // path: res.data.path,
1866
+ // projectId: this.projectId,
1867
+ // name: dataNow,
1868
+ // x: konvaStage.x().toString(),
1869
+ // y: konvaStage.y().toString(),
1870
+ // z: konvaStage.scaleX().toString(),
1871
+ // relevant: annotationArr,
1872
+ // };
1873
+ // const data2 = await addMark(obj);
1874
+ // if (data2.code === 200) {
1875
+ // this.$message.success("保存成功");
1876
+ // this.closeDrawing();
1877
+ // } else {
1878
+ // this.canvasLoading = false;
1879
+ // }
1880
+ // } else {
1881
+ // this.canvasLoading = false;
1882
+ // }
1883
+ },
1884
+ uploadScreenshot(urlData) {
1885
+ // 上传文件
1886
+ const arr = urlData.split(",");
1887
+ const mime = arr[0].match(/:(.*?);/)[1]; // 此处得到的为文件类型
1888
+ const bstr = window.atob(arr[1]); // 此处将base64解码
1889
+ let n = bstr.length;
1890
+ const u8arr = new Uint8Array(n);
1891
+ while (n--) {
1892
+ u8arr[n] = bstr.charCodeAt(n);
1893
+ }
1894
+ const dataNow = Date.now();
1895
+ const file = new File([u8arr], `newCanvas${dataNow}.jpeg`, {
1896
+ type: mime,
1897
+ });
1898
+ const fileData = new FormData();
1899
+ fileData.append("file", file);
1900
+ return upload(fileData);
1901
+ },
1902
+ /* 解决跨域 */
1903
+ uploadByUrl(url, data) {
1904
+ return fetch(url, {
1905
+ mode: "cors",
1906
+ headers: { "Content-Type": "application/octet-stream" },
1907
+ method: "PUT",
1908
+ body: data,
1909
+ });
1910
+ },
1911
+ /* 添加批注触发,打开画板模式 */
1912
+ toggleDrawToolbar(status) {
1913
+ // this.canvasShow = false
1914
+ // 打开工具栏
1915
+ const _setOpenToolbarState = () => {
1916
+ this.leftAllDrawings = false;
1917
+ this.leftDrawingStructure = false;
1918
+ this.showToolbar = true;
1919
+ };
1920
+ // 关闭工具栏
1921
+ const _setCloseToolbarState = () => {
1922
+ this.leftAllDrawings = false;
1923
+ this.leftDrawingStructure = false;
1924
+ this.showToolbar = false;
1925
+ this.checkedToolbarItem = false;
1926
+ };
1927
+
1928
+ if (typeof status == "boolean") {
1929
+ // 明确设置工具栏状态
1930
+ if (status === false) {
1931
+ _setCloseToolbarState();
1932
+ } else {
1933
+ _setOpenToolbarState();
1934
+ }
1935
+ } else {
1936
+ // toggle工具栏
1937
+ if (this.showToolbar) {
1938
+ _setCloseToolbarState();
1939
+ } else {
1940
+ _setOpenToolbarState();
1941
+ }
1942
+ }
1943
+
1944
+ // if (status != undefined ? status === false : this.showToolbar) {
1945
+ // // 关闭工具栏
1946
+ // this.leftAllDrawings = false;
1947
+ // this.leftDrawingStructure = false;
1948
+ // this.showToolbar = false;
1949
+ // this.checkedToolbarItem = false;
1950
+ // // this.checkedToolbarItem = this.clearPreViewAnn();
1951
+ // // this.$set(this, "rightType", "");
1952
+ // } else if (
1953
+ // status != undefined ? status === true : this.showToolbar === false
1954
+ // ) {
1955
+ // // this.checkedToolbarItem = this.clearPreViewAnn();
1956
+ // // this.$set(this, "rightType", "");
1957
+ // }
1958
+ },
1959
+ // 获取图纸数据并加载
1960
+ loadDrawData(id, parmas, callback) {
1961
+ if (this.$route.path.indexOf("DrawingDisplay") > 0) {
1962
+ this.$modal.loading("正在加载,请稍后...");
1963
+ }
1964
+ // recordDocumentId = this.presentDrawing;
1965
+ this.$set(this, "presentDrawing", id);
1966
+ konvaLayer.destroyChildren();
1967
+ konvaStage.scale({
1968
+ x: 1,
1969
+ y: 1,
1970
+ });
1971
+ konvaStage.setX(0);
1972
+ konvaStage.setY(0);
1973
+ inspectionRect = new Konva.Rect({
1974
+ width: 1,
1975
+ height: 1,
1976
+ x: 0,
1977
+ y: 0,
1978
+ stroke: "#000",
1979
+ strokeWidth: 0.2,
1980
+ name: "intersect-rect",
1981
+ visible: false,
1982
+ });
1983
+ konvaLayer.add(inspectionRect);
1984
+ return;
1985
+ getDocPreview(id)
1986
+ .then((res) => {
1987
+ let dxf = null;
1988
+ if (res.type == 0) {
1989
+ const parser = new DxfParser();
1990
+ dxf = parser.parse(res.dxf);
1991
+ let json = JSON.stringify(dxf);
1992
+ let pat = {};
1993
+ pat.json = json;
1994
+ pat.docId = id;
1995
+ addDrawingJson(pat);
1996
+ }
1997
+ if (res.type == 1) {
1998
+ dxf = JSON.parse(res.dxf);
1999
+ }
2000
+ let entities = formatEntity(dxf.entities); // dxf.entities;
2001
+ let layers = dxf.tables.layer.layers;
2002
+ for (let key in layers) {
2003
+ let color = getColors()[layers[key].colorIndex];
2004
+ color = "rgb(" + color + ")";
2005
+ if (entities[key]) {
2006
+ let group = new Konva.Group({
2007
+ x: 0,
2008
+ y: 0,
2009
+ name: key,
2010
+ entityId: key,
2011
+ isGroup: true,
2012
+ visible: true,
2013
+ });
2014
+ let l = entities[key].length;
2015
+ for (let i = 0; i < l; i++) {
2016
+ let type = entities[key][i].type;
2017
+
2018
+ handleFn(
2019
+ type,
2020
+ dxf,
2021
+ entities[key][i],
2022
+ group,
2023
+ key,
2024
+ color,
2025
+ konvaLayer
2026
+ );
2027
+ }
2028
+ konvaLayer.add(group);
2029
+ }
2030
+ }
2031
+ const newScale = 1;
2032
+ konvaStage.scale({
2033
+ x: newScale,
2034
+ y: newScale,
2035
+ });
2036
+ const boundingRect = konvaLayer.getClientRect();
2037
+ const x =
2038
+ this.$refs.svgDraw.clientWidth / 2 -
2039
+ Math.ceil(boundingRect.width) / 2;
2040
+ const y =
2041
+ this.$refs.svgDraw.clientHeight / 2 -
2042
+ (Math.ceil(boundingRect.height) / 2 + boundingRect.y);
2043
+ konvaStage.setX(x);
2044
+ konvaStage.setY(y);
2045
+ activedSvgPan.zoom.x = newScale;
2046
+ activedSvgPan.zoom.y = newScale;
2047
+ activedSvgPan.x = x;
2048
+ activedSvgPan.y = y;
2049
+ setTimeout(() => {
2050
+ if (this.entityId) {
2051
+ this.rightOpenType(this.rightType, this.entityId, true); // 右侧窗口打开时数据更新
2052
+ this.getOnlyId(this.entityId);
2053
+ this.svgCenteredMagnification(this.entityId);
2054
+ }
2055
+ callback && callback(parmas);
2056
+ }, 300);
2057
+ this.$modal.closeLoading();
2058
+ })
2059
+ .catch((err) => {
2060
+ console.log(err);
2061
+ this.$modal.closeLoading();
2062
+ this.$message({
2063
+ type: "error",
2064
+ message: err.msg,
2065
+ });
2066
+ konvaLayer.removeChildren();
2067
+ });
2068
+ },
2069
+ /* 批注退出添加 */
2070
+ closeDrawing() {
2071
+ this.entityId = ""; // 添加批注时,清空entityId
2072
+ // if (this.oldTargetNode.length !== 0) this.resetHightLight([]); // 添加批注时,清空高亮
2073
+ this.showToolbar = false;
2074
+ this.proxyImageShow = false;
2075
+ this.canvasLoading = false;
2076
+ this.showDrawingBoard = false;
2077
+ this.checkedToolbarItem = false;
2078
+
2079
+ if (annotationTool) {
2080
+ annotationTool.destroy();
2081
+ annotationTool = null;
2082
+ }
2083
+ // konvaStage.draggable(true);
2084
+ konvaStage.container().style.cursor = "pointer";
2085
+ this.$set(this, "rightType", "annotation");
2086
+ },
2087
+ clearPreViewAnn() {
2088
+ const lists = konvaStage.find(".annotation-shape");
2089
+ lists.forEach((item) => {
2090
+ item.destroy();
2091
+ });
2092
+ },
2093
+ handleDeleteProofList() {
2094
+ this.clearPreViewAnn();
2095
+ this.closeDrawing();
2096
+ },
2097
+ preHandleProofSavelBtn(){
2098
+ setTimeout(() => {
2099
+ this.handleProofSavelBtn();
2100
+ })
2101
+ },
2102
+ async handleProofSavelBtn() {
2103
+ const cameraViewTag = this.getViewTag();
2104
+ const viewAnnotation = this.handleSaveAnnotation();
2105
+
2106
+ this.proofData.version = this.defaultParams.version;
2107
+ this.proofData.position = JSON.stringify(cameraViewTag);
2108
+
2109
+ // if (_.isEmpty(data.id)) {
2110
+ this.proofData.projectId = this.defaultParams.projectId;
2111
+ // }
2112
+ this.proofData.relevant = viewAnnotation
2113
+ ? JSON.stringify(viewAnnotation)
2114
+ : JSON.stringify("");
2115
+
2116
+ loading("视点截图中...");
2117
+ const previewScreenshotData = await this.screenshot()
2118
+ .catch((err) => {
2119
+ this.$message({
2120
+ type: "error",
2121
+ message: err.msg,
2122
+ });
2123
+ })
2124
+ .finally(() => {
2125
+ loadingClose();
2126
+ });
2127
+
2128
+ this.$refs.proofPanel.openAnnotationDetailDialog();
2129
+
2130
+ this.$set(this.proofData, 'previewScreenshotData', previewScreenshotData)
2131
+ // this.proofData.previewScreenshotData = previewScreenshotData;
2132
+
2133
+ const screenshotMsg = await this.uploadScreenshot(previewScreenshotData)
2134
+
2135
+ if (screenshotMsg.code == 200) {
2136
+ this.proofData.problemPrintscreenId = screenshotMsg.msg;
2137
+ }
2138
+ console.log(this.proofData)
2139
+
2140
+ // console.log(this.proofData.previewScreenshotData)
2141
+
2142
+ // this.$set(this, "proofData", this.proofData);
2143
+
2144
+ // this.$refs.proofPanel.saveForm(
2145
+ // proofData,
2146
+ // () => {
2147
+ // this.toggleDrawToolbar(false);
2148
+ // this.disableDrawBtn = false;
2149
+ // },
2150
+ // () => {
2151
+ // this.disableDrawBtn = true;
2152
+ // }
2153
+ // );
2154
+
2155
+ this.checkedToolbarItem = false;
2156
+ },
2157
+
2158
+ handleClickProofList(data) {
2159
+ const { position, relevant } = data;
2160
+ const { cameraPosition, cameraTarget, offset } = JSON.parse(position);
2161
+
2162
+ console.log('跳转视点', cameraPosition, cameraTarget, offset)
2163
+
2164
+ // 视点
2165
+ this.animateCamera(
2166
+ cameraPosition.x,
2167
+ cameraPosition.y,
2168
+ cameraPosition.z,
2169
+ cameraTarget.x,
2170
+ cameraTarget.y,
2171
+ cameraTarget.z,
2172
+ true,
2173
+ offset
2174
+ );
2175
+ this.clearPreViewAnn();
2176
+ this.highlightModel("reset");
2177
+
2178
+ if (relevant) {
2179
+ // this.showToolbar = true;
2180
+
2181
+ // TODO 暂用 setTimeout
2182
+ setTimeout(() => {
2183
+ this.showDrawingBoard = true;
2184
+ this.disableDrawBtn = true;
2185
+ this.showToolbar = false;
2186
+ if (annotationTool) {
2187
+ annotationTool.destroy();
2188
+ annotationTool = null;
2189
+ }
2190
+
2191
+ const formatRelevant = JSON.parse(relevant);
2192
+ formatRelevant && this.handleLoadAnnotation(formatRelevant);
2193
+ }, 300);
2194
+ }
2195
+ },
2196
+ // 将标注添加到图纸中
2197
+ handleLoadAnnotation(lists) {
2198
+ lists.forEach((item) => {
2199
+ switch (item.type) {
2200
+ case "Rect":
2201
+ const rect = new Konva.Rect({
2202
+ name: item.name,
2203
+ x: item.x,
2204
+ y: item.y,
2205
+ width: item.width,
2206
+ height: item.height,
2207
+ stroke: item.stroke,
2208
+ strokeWidth: item.strokeWidth,
2209
+ visible: true,
2210
+ draggable: true,
2211
+ type: item.type,
2212
+ });
2213
+ rect.on("mousedown", (e) => {
2214
+ e.cancelBubble = true;
2215
+ });
2216
+
2217
+ rect.on("click", (e) => {
2218
+ e.cancelBubble = true;
2219
+ if (this.drawingType === "Rubber") {
2220
+ rect.destroy();
2221
+ }
2222
+ });
2223
+
2224
+ konvaLayer.add(rect);
2225
+ break;
2226
+ case "Circle":
2227
+ const circle = new Konva.Circle({
2228
+ name: item.name,
2229
+ x: item.x,
2230
+ y: item.y,
2231
+ radius: item.radius < 0 ? 0 : item.radius,
2232
+ stroke: item.stroke,
2233
+ strokeWidth: item.strokeWidth,
2234
+ visible: true,
2235
+ draggable: true,
2236
+ type: item.type,
2237
+ });
2238
+ circle.on("mousedown", (e) => {
2239
+ e.cancelBubble = true;
2240
+ });
2241
+
2242
+ circle.on("click", (e) => {
2243
+ e.cancelBubble = true;
2244
+ if (this.drawingType === "Rubber") {
2245
+ circle.destroy();
2246
+ }
2247
+ });
2248
+
2249
+ konvaLayer.add(circle);
2250
+ break;
2251
+ case "Line":
2252
+ const line = new Konva.Line({
2253
+ name: item.name,
2254
+ points: item.points,
2255
+ stroke: item.stroke,
2256
+ strokeWidth: item.strokeWidth,
2257
+ lineCap: item.lineCap,
2258
+ lineJoin: item.lineJoin,
2259
+ visible: true,
2260
+ draggable: true,
2261
+ type: item.type,
2262
+ });
2263
+ line.on("mousedown", (e) => {
2264
+ e.cancelBubble = true;
2265
+ });
2266
+
2267
+ line.on("click", (e) => {
2268
+ e.cancelBubble = true;
2269
+ if (this.drawingType === "Rubber") {
2270
+ line.destroy();
2271
+ }
2272
+ });
2273
+
2274
+ konvaLayer.add(line);
2275
+ break;
2276
+ case "Text":
2277
+ const textNode = new Konva.Text({
2278
+ name: item.name,
2279
+ x: item.x,
2280
+ y: item.y,
2281
+ width: item.width,
2282
+ text: item.text,
2283
+ fontSize: item.fontSize,
2284
+ fill: item.fill,
2285
+ visible: true,
2286
+ draggable: true,
2287
+ type: item.type,
2288
+ });
2289
+ textNode.on("mousedown", (e) => {
2290
+ e.cancelBubble = true;
2291
+ });
2292
+
2293
+ textNode.on("click", (e) => {
2294
+ e.cancelBubble = true;
2295
+ if (this.drawingType === "Rubber") {
2296
+ textNode.destroy();
2297
+ }
2298
+ });
2299
+
2300
+ konvaLayer.add(textNode);
2301
+ break;
2302
+ }
2303
+ });
2304
+ console.log(konvaLayer);
2305
+ },
2306
+ handleProofEditBtn(detailData) {
2307
+ this.toggleDrawToolbar(true);
2308
+ this.disableDrawBtn = false;
2309
+
2310
+ this.proofData = Object.assign(this.proofData, detailData);
2311
+ },
2312
+ handleProofAddBtn() {
2313
+ this.toggleDrawToolbar(true);
2314
+ this.clearPreViewAnn();
2315
+ this.disableDrawBtn = false;
2316
+
2317
+ this.resetProofData();
2318
+ },
2319
+ resetProofData() {
2320
+ this.proofData.stageId = '';
2321
+ this.proofData.version = null;
2322
+ this.proofData.position = '';
2323
+ this.proofData.projectId = '';
2324
+ this.proofData.relevant = '';
2325
+ this.proofData.previewScreenshotData = '';
2326
+ this.proofData.problemPrintscreenId = '';
2327
+ this.proofData.description = '';
2328
+ this.proofData.remark = '';
2329
+ this.proofData.status = '';
2330
+ this.proofData.createTime = '';
2331
+ this.proofData.replyTime = '';
2332
+ this.proofData.postId = '';
2333
+ this.proofData.solveBy = '';
2334
+ delete this.proofData.id;
2335
+ },
2336
+ handleProofCancelBtn() {
2337
+ this.toggleDrawToolbar(false);
2338
+ this.clearPreViewAnn();
2339
+ this.disableDrawBtn = true;
2340
+ },
2341
+ // 添加视点
2342
+ getViewTag() {
2343
+ // todo
2344
+ const delta = fpsClock.getDelta();
2345
+ timeStamp += delta;
2346
+ // cameraControls.update(timeStamp);
2347
+
2348
+ const cameraPosition = cameraControls.getPosition();
2349
+ const cameraTarget = cameraControls.getTarget();
2350
+ const offset = cameraControls.getFocalOffset()
2351
+
2352
+ const element = cameraControls.camera.matrix.elements;
2353
+
2354
+ console.log('获取视点', cameraPosition, cameraTarget)
2355
+
2356
+ const vector = {
2357
+ x: [element[0], element[1], element[2], element[3]],
2358
+ y: [element[4], element[5], element[6], element[7]],
2359
+ z: [element[8], element[9], element[10], element[11]],
2360
+ }
2361
+
2362
+ const up = cameraControls.camera.up;
2363
+ return { cameraPosition, cameraTarget, vector, up, offset};
2364
+ },
2365
+ locateByDetect(data, node){
2366
+ console.log('locateByDetect', data, node)
2367
+ this.pbsNodeClick(node.objectid)
2368
+ },
2369
+ highlightByDetect(data, node){
2370
+ console.log('highlightByDetect', data, node)
2371
+
2372
+ const obj = scene.getObjectByName(node.objectid);
2373
+ this.changeModelColor(
2374
+ {
2375
+ groupModel: obj,
2376
+ color: new this.THREE.Color(0xff0000),
2377
+ type: 'toggleHighlight'
2378
+ });
2379
+ },
2380
+ focusDetectTree(){
2381
+ this.activeName = 'detectTree';
2382
+ },
2383
+ getDetectCheckTree(){
2384
+ const param = this.dataServerParams;
2385
+ getTopology(param)
2386
+ .then((topologyData) => {
2387
+ const collisionSystem = new CollisionSystem({scene, topologyData});
2388
+ this.detectTreeData = collisionSystem.run();
2389
+ })
2390
+ },
2391
+ // 工具按钮互斥操作
2392
+ handleBtnEvent(val) {
2393
+ if (previousModel) { this.recoverColor() }
2394
+ // 新增功能互斥
2395
+ addRoamingFlag = false
2396
+ markFlag = false
2397
+ // 关闭新增标注弹框
2398
+ this.$set(this, 'markPanelShow', false)
2399
+ this.$set(this, 'locationPanelShow', false)
2400
+ // 清除漫游点
2401
+ if (this.roamingPath.length > 0) {
2402
+ this.delTipsLabel()
2403
+ this.roamingPath = []
2404
+ this.removeMesh(points)
2405
+ this.removeMesh(line)
2406
+ }
2407
+ for (let key in this.ctrlPanel) {
2408
+ modelClickEvent = ''
2409
+ if (key !== 'pid' && val.event !== 'pid') {
2410
+ const flag = val.flag === key ? !this.ctrlPanel[key] : false
2411
+ this.$set(this.ctrlPanel, key, flag)
2412
+ } else if (val.event === 'pid') {
2413
+ const flag = val.flag ? true : false
2414
+ this.$set(this.ctrlPanel, 'pid', flag)
2415
+ }
2416
+ }
2417
+ if(val.event === 'drawing' && !this.disableDrawBtn){
2418
+ this.toggleDrawToolbar();
2419
+ }
2420
+ this.btnOperate(val.event, this.ctrlPanel[val.event])
2421
+ },
2422
+ // 不同按钮的操作事项
2423
+ btnOperate(e, flag) {
2424
+ // 打开pid 不参与互斥
2425
+ if (e !== 'pid') {
2426
+ // 清空标注
2427
+ this.clearEntites()
2428
+ // this.cancelLocation()
2429
+ // this.removeMoveMark()
2430
+ // // 清空漫游
2431
+ // this.viewRoaming(false)
2432
+ // 关闭剖切
2433
+ if (clippingType) {
2434
+ clippingType === 'all' ? this.clearAllClipping() : this.clearLocalClipping()
2435
+ clippingType = ''
2436
+ }
2437
+ // 关闭测量
2438
+ if (threeMeasure) this.measure(false)
2439
+ // 关闭聚光灯
2440
+ // if (spotLight) {
2441
+ // this.clearSpotLight()
2442
+ // this.initLight()
2443
+ // }
2444
+ // 恢复爆炸
2445
+ // this.bomb(0, 'all')
2446
+ }
2447
+ modelClickEvent = ''
2448
+ switch (e) {
2449
+ case 'view':
2450
+ modelClickEvent = flag ? 'view' : ''
2451
+ break;
2452
+ case 'mark':
2453
+ if (!flag) {
2454
+ this.handleAddMark(false)
2455
+ this.clearEntites()
2456
+ }
2457
+ modelClickEvent = flag ? 'mark' : ''
2458
+ break;
2459
+ // case 'locationUser':
2460
+ // if (!flag) {
2461
+ // this.cancelLocation()
2462
+ // }
2463
+ // break;
2464
+ case 'roaming':
2465
+ this.viewRoaming(flag)
2466
+ modelClickEvent = flag ? 'roaming' : ''
2467
+ break;
2468
+ case 'material':
2469
+ break;
2470
+ case 'light':
2471
+ flag ? this.clearMeasure() : ''
2472
+ modelClickEvent = flag ? 'light' : ''
2473
+ break;
2474
+ case 'measure':
2475
+ modelClickEvent = !flag ? '' : 'measure'
2476
+ this.measure(flag)
2477
+ break;
2478
+ case 'bomb':
2479
+ modelClickEvent = !flag ? '' : 'bomb'
2480
+ break;
2481
+ case 'spotLight':
2482
+ if (flag) {
2483
+ this.initSpotLight()
2484
+ modelClickEvent = 'spotLight'
2485
+ } else {
2486
+ this.clearSpotLight()
2487
+ modelClickEvent = ''
2488
+ }
2489
+ break;
2490
+ case 'pid':
2491
+ if (flag) {
2492
+ modelClickEvent = 'pid'
2493
+ } else {
2494
+ modelClickEvent = ''
2495
+ }
2496
+ this.$nextTick(() => {
2497
+ this.onContainerResize()
2498
+ })
2499
+ break;
2500
+ case 'clipping':
2501
+ if (!flag) {
2502
+ modelClickEvent = ''
2503
+ clippingType === 'all' ? this.clearAllClipping() : this.clearLocalClipping()
2504
+ clippingType = ''
2505
+ } else {
2506
+ modelClickEvent = 'clipping'
2507
+ }
2508
+ break;
2509
+ case 'alpha':
2510
+ if (flag) {
2511
+ modelClickEvent = 'alphaControl'
2512
+ } else {
2513
+ modelClickEvent = ''
2514
+ this.alphaReset()
2515
+ }
2516
+ }
2517
+ },
2518
+ // 测量类型
2519
+ handleMeasure(type) {
2520
+ if (threeMeasure) {
2521
+ threeMeasure.close()
2522
+ threeMeasure = null
2523
+ }
2524
+ renderEnabled = true
2525
+ switch (type) {
2526
+ case 'distance':
2527
+ threeMeasure = new MeasureDistance.MeasureDistance(renderer, scene, camera, instructions.offsetWidth, instructions.offsetHeight)
2528
+ threeMeasure.start()
2529
+ break;
2530
+ case 'area':
2531
+ threeMeasure = new MeasureArea.MeasureArea(renderer, scene, camera,instructions.offsetWidth, instructions.offsetHeight)
2532
+ threeMeasure.start()
2533
+ break;
2534
+ case 'angle':
2535
+ threeMeasure = new MeasureAngle.MeasureAngle(renderer, scene, camera, instructions.offsetWidth, instructions.offsetHeight)
2536
+ threeMeasure.start()
2537
+ break;
2538
+ case 'volume':
2539
+ threeMeasure = new MeasureVolume.MeasureVolume(renderer, scene, camera, instructions.offsetWidth, instructions.offsetHeight)
2540
+ threeMeasure.start()
2541
+ break;
2542
+ }
2543
+ },
2544
+ // 测量
2545
+ measure(val) {
2546
+ if (!val && threeMeasure) {
2547
+ threeMeasure.close()
2548
+ threeMeasure = null
2549
+ this.timeRender()
2550
+ }
2551
+ },
2552
+ /**
2553
+ * 主视角
2554
+ */
2555
+ home() {
2556
+ if (roaming) {
2557
+ this.disposeRoaming()
2558
+ }
2559
+ const obj = scene.getObjectByName('rootModel')
2560
+ if (obj) {
2561
+ this.setModelCenter(obj.userData.boundingBox, true)
2562
+ }
2563
+ // this.animateCamera(cameraControls._position0.x, cameraControls._position0.y, cameraControls._position0.z, cameraControls._target0.x, cameraControls._target0.y, cameraControls._target0.z)
2564
+ // this.timeRender()
2565
+ },
2566
+ setModelCenter(boundingBox, flag) {
2567
+ // this.resetOrbitPoint();
2568
+ const box3 = new this.THREE.Box3(boundingBox.min, boundingBox.max)
2569
+ const center = new this.THREE.Vector3()
2570
+ box3.getCenter(center)
2571
+ const size = box3.getSize(new this.THREE.Vector3())
2572
+
2573
+ // cameraControls.setOrbitPoint(
2574
+ // center.x, center.y, center.z, false
2575
+ // )
2576
+ // cameraControls.update()
2577
+
2578
+ camera.position.set(center.x, center.y + size.y, center.z + size.z / 2)
2579
+ camera.lookAt(new this.THREE.Vector3(center.x, center.y, center.z))
2580
+ this.animateCamera(center.x, center.y + size.y, center.z + size.z / 2, center.x, center.y, center.z, flag)
2581
+ camera.updateProjectionMatrix()
2582
+ },
2583
+ /* 第一视角区域 */
2584
+ // 出现弹框
2585
+ firstPer() {
2586
+ if (this.ctrlPanel['pid']) {
2587
+ this.$confirm('确定关闭pid?', '提示', {
2588
+ confirmButtonText: '确定',
2589
+ cancelButtonText: '取消',
2590
+ type: 'warning'
2591
+ }).then(() => {
2592
+ // 关闭其余面板
2593
+ for (let key in this.ctrlPanel) {
2594
+ this.$set(this.ctrlPanel, key, false)
2595
+ }
2596
+ this.onWindowResize()
2597
+ this.isFirstPer = sessionStorage.getItem('isFirstPer')
2598
+ // 判断是否出现弹框
2599
+ if (this.isFirstPer === 'true') {
2600
+ this.start(true)
2601
+ } else {
2602
+ this.firstPerFlag = true
2603
+ }
2604
+ }).catch(() => {
2605
+ return false
2606
+ })
2607
+ } else {
2608
+ // 关闭其余面板
2609
+ for (let key in this.ctrlPanel) {
2610
+ this.$set(this.ctrlPanel, key, false)
2611
+ }
2612
+ this.isFirstPer = sessionStorage.getItem('isFirstPer')
2613
+ // 判断是否出现弹框
2614
+ if (this.isFirstPer === 'true') {
2615
+ this.start(true)
2616
+ } else {
2617
+ this.firstPerFlag = true
2618
+ }
2619
+ }
2620
+ },
2621
+ // 开始第一视角
2622
+ start(val) {
2623
+ // this.timeRender()
2624
+ // 记录是否不再出现弹框
2625
+ this.isFirstPer = val
2626
+ sessionStorage.setItem('isFirstPer', val)
2627
+ clock = new this.THREE.Clock()
2628
+ horizontalRaycaster = new this.THREE.Raycaster(new this.THREE.Vector3(), new this.THREE.Vector3(), 0, 10)
2629
+ downRaycaster = new this.THREE.Raycaster(new this.THREE.Vector3(), new this.THREE.Vector3(0, -1, 0), 0, 10)
2630
+ // downRaycaster.params = {
2631
+ // Mesh: { threshold: 5000 },
2632
+ // Line: { threshold: 15000 },
2633
+ // Points: { threshold: 5000 },
2634
+ // LOD: { threshold: 5000 },
2635
+ // Sprite: { threshold: 5000 }
2636
+ // }
2637
+ // downRaycaster.params = {
2638
+ // Mesh: { threshold: 200 },
2639
+ // Line: { threshold: 200 },
2640
+ // Points: { threshold: 200 },
2641
+ // LOD: { threshold: 200 },
2642
+ // Sprite: { threshold: 200 }
2643
+ // }
2644
+
2645
+ velocity = new this.THREE.Vector3() //移动速度变量
2646
+ direction = new this.THREE.Vector3() //移动的方向变量
2647
+ rotation = new this.THREE.Vector3() //当前的相机朝向
2648
+ this.firstPerFlag = false
2649
+ this.initPointerLock()
2650
+ },
2651
+ // 键盘监听事件
2652
+ onKeyDown(event) {
2653
+ if (!event.keyCode) return
2654
+ // this.timeRender()
2655
+ switch (event.keyCode) {
2656
+ // 向左
2657
+ case 37:
2658
+ case 65:
2659
+ moveLeft = true
2660
+ break
2661
+ // 向右
2662
+ case 39:
2663
+ case 68:
2664
+ moveRight = true
2665
+ break
2666
+ // 向前
2667
+ case 38:
2668
+ case 87:
2669
+ moveForward = true
2670
+ break
2671
+ // 向后
2672
+ case 40:
2673
+ case 83:
2674
+ moveBackward = true
2675
+ break
2676
+ // 跳跃
2677
+ case 32:
2678
+ if (canJump && spaceUp) velocity.y += upSpeed
2679
+ canJump = false
2680
+ spaceUp = false
2681
+ break
2682
+ }
2683
+ },
2684
+ onKeyUp(event) {
2685
+ if (!event.keyCode) return
2686
+ // this.timeRender()
2687
+ switch (event.keyCode) {
2688
+ // 前进
2689
+ case 38:
2690
+ case 87:
2691
+ moveForward = false
2692
+ break
2693
+ // 向左
2694
+ case 37:
2695
+ case 65:
2696
+ moveLeft = false
2697
+ break
2698
+ // 后退
2699
+ case 40:
2700
+ case 83:
2701
+ moveBackward = false
2702
+ break
2703
+ // 向右
2704
+ case 39:
2705
+ case 68:
2706
+ moveRight = false
2707
+ break
2708
+ // 跳跃
2709
+ case 32:
2710
+ spaceUp = true
2711
+ break
2712
+ }
2713
+ },
2714
+ // 页面是否锁定
2715
+ initPointerLock() {
2716
+ pointControls = new PointerLockControls(camera, renderer.domElement)
2717
+ // 相机位置
2718
+ // pointControls.getObject().position.set(camera.position.x, camera.position.y, camera.position.z)
2719
+ pointControls.getObject().position.set(0, 3 - this.maxAltitude / 10, 0)
2720
+ // pointControls.getObject().position.set(camera.position.x, 3 - this.maxAltitude / 10, camera.position.y)
2721
+ pointControls.lock()
2722
+ // 锁定
2723
+ pointControls.addEventListener('lock', () => {
2724
+ cameraControls.enabled = false
2725
+ this.toolBtnSetting.toolBtn.all = false
2726
+ window.addEventListener('keydown', this.onKeyDown, false)
2727
+ window.addEventListener('keyup', this.onKeyUp, false)
2728
+ renderer.domElement.removeEventListener('mouseup', this.mouseClick, false)
2729
+ renderer.domElement.removeEventListener('mousedown', this.setOrbitPoint, false)
2730
+ // renderer.domElement.removeEventListener('contextmenu', this.rightClick)
2731
+ })
2732
+ // 解锁
2733
+ pointControls.addEventListener('unlock', () => {
2734
+ cameraControls.enabled = true
2735
+ // 返回初始视角
2736
+ this.home()
2737
+ this.toolBtnSetting.toolBtn.all = true
2738
+ window.removeEventListener('keydown', this.onKeyDown)
2739
+ window.removeEventListener('keyup', this.onKeyUp)
2740
+ renderer.domElement.addEventListener('mouseup', this.mouseClick, false)
2741
+ renderer.domElement.addEventListener('mousedown', this.setOrbitPoint, false)
2742
+ // renderer.domElement.addEventListener('contextmenu', this.rightClick, false)
2743
+ })
2744
+ // 鼠标转动
2745
+ pointControls.addEventListener('change', () => {
2746
+ // this.timeRender()
2747
+ })
2748
+ scene.add(pointControls.getObject())
2749
+ },
2750
+ // 第一视角运动
2751
+ firstPerspective() {
2752
+ if (!cameraControls.enabled && pointControls) {
2753
+ // 获取到控制器对象
2754
+ var control = pointControls.getObject()
2755
+ // 获取刷新时间
2756
+ var delta = clock.getDelta()
2757
+ // velocity每次的速度,为了保证有过渡
2758
+ velocity.x -= velocity.x * 10.0 * delta
2759
+ velocity.z -= velocity.z * 10.0 * delta
2760
+ velocity.y -= 9.8 * 100.0 * delta // 默认下降的速度
2761
+ // 获取当前按键的方向并获取朝哪个方向移动
2762
+ direction.z = Number(moveForward) - Number(moveBackward)
2763
+ direction.x = Number(moveRight) - Number(moveLeft)
2764
+ // 将法向量的值归一化
2765
+ direction.normalize()
2766
+ // 碰撞检测
2767
+ // rotation.copy(control.getWorldDirection(rotation))
2768
+ // var m = new this.THREE.Matrix4()
2769
+ // if (direction.z > 0) {
2770
+ // if (direction.x > 0) {
2771
+ // m.makeRotationY(Math.PI / 4)
2772
+ // } else if (direction.x < 0) {
2773
+ // m.makeRotationY(-Math.PI / 4)
2774
+ // } else {
2775
+ // m.makeRotationY(0)
2776
+ // }
2777
+ // } else if (direction.z < 0) {
2778
+ // if (direction.x > 0) {
2779
+ // m.makeRotationY((Math.PI / 4) * 3)
2780
+ // } else if (direction.x < 0) {
2781
+ // m.makeRotationY((-Math.PI / 4) * 3)
2782
+ // } else {
2783
+ // m.makeRotationY(Math.PI)
2784
+ // }
2785
+ // } else {
2786
+ // if (direction.x > 0) {
2787
+ // m.makeRotationY(Math.PI / 2)
2788
+ // } else if (direction.x < 0) {
2789
+ // m.makeRotationY(-Math.PI / 2)
2790
+ // }
2791
+ // }
2792
+ // rotation.applyMatrix4(m)
2793
+ // horizontalRaycaster.set(control.position, rotation)
2794
+ // var horizontalIntersections = horizontalRaycaster.intersectObjects(
2795
+ // scene.children,
2796
+ // true
2797
+ // )
2798
+ // var horOnObject = horizontalIntersections.length > 0
2799
+ // 判断移动方向修改速度方向
2800
+ // if (!horOnObject) {
2801
+ if (moveForward || moveBackward) velocity.z -= direction.z * removeSpeed * delta
2802
+ if (moveLeft || moveRight) velocity.x -= direction.x * removeSpeed * delta
2803
+ // }
2804
+ // 复制相机的位置
2805
+ downRaycaster.ray.origin.copy(control.position)
2806
+ // 获取相机靠下5的位置
2807
+ downRaycaster.ray.origin.y += 10
2808
+
2809
+ // const foundMeshes = this.findMeshByName(scene.children[0], '2.655.2-MODELELEM-o.160.80.66ee82db-160');
2810
+ // const foundMeshes = this.findMeshByName(scene.children[0], '2.667.2-MODELELEM-o.160.a.1923d213481-160');
2811
+
2812
+ // console.log(foundMeshes[0].children)
2813
+ // 判断是否停留在了立方体上面
2814
+ // var intersections = downRaycaster.intersectObjects(foundMeshes[0].children, true)
2815
+ var intersections = downRaycaster.intersectObjects(scene.children, true)
2816
+
2817
+ // var intersections = downRaycaster.intersectObjects(intersectsObject, false)
2818
+ // const intersected = intersectsObject.find((item) => {
2819
+ // return item.userData.instanceName === '2.655.2-MODELELEM-o.160.80.66ee82db-160'
2820
+ // }
2821
+ // )
2822
+ // console.log(intersected)
2823
+ // console.log('downRaycaster.ray.origin', downRaycaster.ray.origin.x, downRaycaster.ray.origin.y, downRaycaster.ray.origin.z)
2824
+ // console.log('downRaycaster.ray', JSON.stringify(downRaycaster.ray))
2825
+
2826
+ // var intersections = downRaycaster.intersectObjects(scene.children[0], true)
2827
+ var onObject = intersections.length > 0
2828
+ if (onObject === true) {
2829
+ // console.log('onObject', intersections)
2830
+ velocity.y = Math.max(0, velocity.y)
2831
+ canJump = true
2832
+ }
2833
+ // 根据速度值移动控制器
2834
+ pointControls.moveRight(- velocity.x * delta)
2835
+ pointControls.moveForward(- velocity.z * delta)
2836
+ control.position.y += (velocity.y * delta)
2837
+ // 保证控制器的y轴在平面上
2838
+ if (control.position.y < 3 - this.maxAltitude / 10) {
2839
+ velocity.y = -this.maxAltitude / 10
2840
+ control.position.y = 3 - this.maxAltitude / 10
2841
+ canJump = true
2842
+
2843
+ // console.log('control.position.y', control.position.y)
2844
+ }
2845
+ }
2846
+ },
2847
+ findMeshByName(scene, meshName) {
2848
+ const foundMeshes = [];
2849
+ scene.traverse((child) => {
2850
+ if (child.name === meshName) {
2851
+ foundMeshes.push(child);
2852
+ }
2853
+ });
2854
+ return foundMeshes;
2855
+ },
2856
+ // 清除 取消标注的点
2857
+ clearEntites() {
2858
+ if (scene && scene.getObjectByName('mark-label')) {
2859
+ let sprit = scene.getObjectByName('mark-label')
2860
+ scene.remove(sprit)
2861
+ this.clearEntites()
2862
+ }
2863
+ // 清除 取消弹框
2864
+ if (scene && scene.getObjectByName('bullet-box-label')) {
2865
+ let sprit = scene.getObjectByName('bullet-box-label')
2866
+ scene.remove(sprit)
2867
+ this.clearEntites()
2868
+ }
2869
+ return
2870
+ },
2871
+ // 获取mesh的中心点
2872
+ getMeshCenterAndVolume(mesh) {
2873
+ const box = new this.THREE.Box3().setFromObject(mesh)
2874
+ const center = new this.THREE.Vector3();
2875
+ const volume = box.getSize(new this.THREE.Vector3())
2876
+ box.getCenter(center);
2877
+ return {
2878
+ 'center': center,
2879
+ 'box': volume
2880
+ }
2881
+ },
2882
+ createVirtualClippingBox(size, data, clippingPlanes) {
2883
+ const center = [data.center.x, data.center.y, data.center.z,];
2884
+
2885
+ if (cube) {
2886
+ cube.geometry.dispose()
2887
+ cube.material.dispose()
2888
+ scene.remove(cube)
2889
+ cube = null
2890
+ // transformControl.visible = false
2891
+ }
2892
+ const geo = new this.THREE.BoxGeometry(Math.abs(size.x), Math.abs(size.y), Math.abs(size.z))
2893
+ const m = new this.THREE.MeshStandardMaterial({
2894
+ color: 0xffffff,
2895
+ transparent: true,
2896
+ opacity: 0.2,
2897
+ side: this.THREE.DoubleSide,
2898
+ clippingPlanes: clippingPlanes,
2899
+ needsUpdate: true
2900
+ })
2901
+ cube = new this.THREE.Mesh(geo, m)
2902
+ cube.name = 'virtualClippingBox'
2903
+ scene.add(cube)
2904
+ const v3 = new this.THREE.Vector3(center[0] - this.modelCenter.x, center[1] - this.modelCenter.y, center[2] - this.modelCenter.z)
2905
+ cube.position.set(v3.x, v3.y, v3.z)
2906
+ // cube.userData.box = new this.THREE.Vector3(size.x, size.y, size.z)
2907
+ },
2908
+ changeClippingVal(index, type) {
2909
+ clippingMesh.forEach(item => {
2910
+ item.material.clippingPlanes[index].constant += operate[type]
2911
+ })
2912
+ this.timeRender()
2913
+ },
2914
+ clippingType(val) {
2915
+ if (clippingType === val) {
2916
+ // 清除全局剖切效果
2917
+ this.clearAllClipping()
2918
+ clippingType = ''
2919
+ }else if (val === 'all') {
2920
+ clippingType = val;
2921
+ // 先清除局部剖切效果
2922
+ this.clearLocalClipping()
2923
+ // 添加全部剖切效果
2924
+ const box3 = new this.THREE.Box3()
2925
+ box3.expandByObject(scene.children[0])
2926
+ const size = box3.getSize(new this.THREE.Vector3())
2927
+ globePlanes = [
2928
+ Math.ceil(size.x),
2929
+ Math.ceil(size.y),
2930
+ Math.ceil(size.z)
2931
+ ]
2932
+ renderer.clippingPlanes = [
2933
+ new this.THREE.Plane(new this.THREE.Vector3(-1, 0, 0), globePlanes[0]),
2934
+ new this.THREE.Plane(new this.THREE.Vector3(0, -1, 0), globePlanes[1]),
2935
+ new this.THREE.Plane(new this.THREE.Vector3(0, 0, -1), globePlanes[2])
2936
+ ]
2937
+ guiParams = {
2938
+ 'x轴': globePlanes[0],
2939
+ 'y轴': globePlanes[1],
2940
+ 'z轴': globePlanes[2]
2941
+ }
2942
+ this.addClippingGui('全局剖切', renderer.clippingPlanes)
2943
+ } else {
2944
+ // 清除全局剖切效果
2945
+ this.clearAllClipping()
2946
+ }
2947
+ },
2948
+ // 添加剖切轴工具
2949
+ addClippingGui(title, objClipp1, objClipp2) {
2950
+ gui = new GUI({
2951
+ title: title
2952
+ })
2953
+ gui.add(guiParams, 'x轴').min(-(guiParams['x轴'])).max(guiParams['x轴']).onChange(d => {
2954
+ objClipp1[0].constant = d
2955
+ objClipp2 && (objClipp2[0].constant = d)
2956
+ })
2957
+ gui.add(guiParams, 'y轴').min(-(guiParams['y轴'])).max(guiParams['y轴']).onChange(d => {
2958
+ objClipp1[1].constant = d
2959
+ objClipp2 && (objClipp2[1].constant = d)
2960
+ })
2961
+ gui.add(guiParams, 'z轴').min(-(guiParams['z轴'])).max(guiParams['z轴']).onChange(d => {
2962
+ objClipp1[2].constant = d
2963
+ objClipp2 && (objClipp2[2].constant = d)
2964
+ })
2965
+ },
2966
+ // 在全局剖切下恢复原状
2967
+ clearAllClipping() {
2968
+ if(renderer){
2969
+ renderer.clippingPlanes = Object.freeze([])
2970
+ }
2971
+ gui && gui.destroy()
2972
+ },
2973
+ // 清除上一步骤的切片
2974
+ clearClipping() {
2975
+ clippingMesh.forEach(item => {
2976
+ item.material.clippingPlanes = Object.freeze([])
2977
+ item.material.needsUpdate = true
2978
+ })
2979
+ clippingMesh.splice(0)
2980
+ },
2981
+ // 清除局部剖切效果
2982
+ clearLocalClipping() {
2983
+ guiParams = {
2984
+ 'x轴': 0,
2985
+ 'y轴': 0,
2986
+ 'z轴': 0
2987
+ }
2988
+ gui && gui.destroy()
2989
+ this.clearClipping()
2990
+ this.clearClippingTools()
2991
+ },
2992
+ // 清除辅助剖切的工具
2993
+ clearClippingTools() {
2994
+ batchTable = {}
2995
+ bombData.splice(0)
2996
+ if (cube) {
2997
+ cube.material.dispose()
2998
+ cube.geometry.dispose()
2999
+ cube.clear()
3000
+ scene.remove(cube)
3001
+ cube = null
3002
+ }
3003
+ },
3004
+ // 剖切模型
3005
+ controlModel(model) {
3006
+ this.clearClipping()
3007
+ // 创建剖切面
3008
+ const box3 = new this.THREE.Box3()
3009
+ box3.expandByObject(model)
3010
+ const size = box3.getSize(new this.THREE.Vector3())
3011
+ const data = this.getMeshCenterAndVolume(model);
3012
+ const center = [data.center.x, data.center.y, data.center.z,];
3013
+
3014
+ let constant = {
3015
+ x: Math.abs(((center[0] - this.modelCenter.x) + size.x / 2)),
3016
+ y: Math.abs(((center[1] - this.modelCenter.y) + size.y / 2)),
3017
+ z: Math.abs(((center[2] - this.modelCenter.z) + size.z / 2))
3018
+ }
3019
+ const clippingPlanes = [
3020
+ new this.THREE.Plane(new this.THREE.Vector3(-1, 0, 0), constant.x),
3021
+ new this.THREE.Plane(new this.THREE.Vector3(0, -1, 0), constant.y),
3022
+ new this.THREE.Plane(new this.THREE.Vector3(0, 0, -1), constant.z)
3023
+ ]
3024
+
3025
+ // const geometry = new this.THREE.BoxGeometry(Math.abs(size.x), Math.abs(size.y), Math.abs(size.z));
3026
+ // const material = new this.THREE.MeshBasicMaterial( {
3027
+ // color: 0x00ff00,
3028
+ // transparent: true,
3029
+ // opacity: 0.2,
3030
+ // side: this.THREE.DoubleSide,
3031
+ // } );
3032
+ // const mesh = new this.THREE.Mesh( geometry, material );
3033
+ // mesh.position.set(model.position.x, model.position.y, model.position.z)
3034
+ // mesh.material.clippingPlanes = clippingPlanes
3035
+ // mesh.needsUpdate = true;
3036
+
3037
+ // mesh.add(model)
3038
+ // scene.add(mesh)
3039
+ model.material.clippingPlanes = clippingPlanes
3040
+ model.needsUpdate = true
3041
+
3042
+ // 添加虚拟盒子
3043
+ this.createVirtualClippingBox(size, data, clippingPlanes)
3044
+ renderer.localClippingEnabled = true
3045
+ guiParams = {
3046
+ 'x轴': Math.ceil(constant.x),
3047
+ 'y轴': Math.ceil(constant.y),
3048
+ 'z轴': Math.ceil(constant.z)
3049
+ }
3050
+ this.addClippingGui('局部剖切', model.material.clippingPlanes, cube.material.clippingPlanes)
3051
+ },
3052
+ // 动态设置视角滚轮的距离
3053
+ setCameraConfig() {
3054
+ let box3 = new this.THREE.Box3().setFromObject(scene);
3055
+ let size = new this.THREE.Vector3()
3056
+ box3.getSize(size)
3057
+ const maxBorder = Math.max(size.x, size.y, size.z);
3058
+
3059
+ cameraControls.camera.far = maxBorder * 50; // 设置相机的远裁剪面
3060
+
3061
+ cameraControls.minDistance = maxBorder * 0.05; // 动态设置视角滚轮的距离
3062
+
3063
+ camera.updateProjectionMatrix()
3064
+ },
3065
+ /* 右侧显示窗口
3066
+ type: this.rightType所记录的数据 */
3067
+ rightOperation(type) {
3068
+ // this.mutualExclusionPoint();
3069
+ // 控制右侧显示的弹窗
3070
+ // 第一步 判断type 是否与 rightType 相等 如果相等 就是关闭对应的窗口
3071
+ switch(type){
3072
+ case 'proof':
3073
+ if(this.showProofPanel){
3074
+ this.closeRightOperationType = {
3075
+ type: type,
3076
+ close: true,
3077
+ };
3078
+ }else{
3079
+ this.closeRightOperationType = {
3080
+ type: type,
3081
+ close: false,
3082
+ }
3083
+ }
3084
+ this.showProofPanel = !this.showProofPanel;
3085
+ break;
3086
+ case 'detect':
3087
+ if(this.showDetectPanel){
3088
+ this.closeRightOperationType = {
3089
+ type: type,
3090
+ close: true,
3091
+ };
3092
+ }else{
3093
+ this.closeRightOperationType = {
3094
+ type: type,
3095
+ close: false,
3096
+ };
3097
+ }
3098
+ this.showDetectPanel = !this.showDetectPanel;
3099
+ break;
3100
+ case 'property':
3101
+ if(this.showPropsPanel){
3102
+ this.closeRightOperationType = {
3103
+ type: type,
3104
+ close: true,
3105
+ };
3106
+ }else{
3107
+ this.closeRightOperationType = {
3108
+ type: type,
3109
+ close: false,
3110
+ };
3111
+ }
3112
+ this.showPropsPanel = !this.showPropsPanel;
3113
+ break;
3114
+ }
3115
+ // if (this.rightType === type) {
3116
+ // this.$set(this, "rightType", "");
3117
+ // } else {
3118
+ // // 如果不相等 就是切到其他面板 那么就要关闭上一步操作
3119
+ // this.$set(this, "rightType", type);
3120
+ // }
3121
+ },
3122
+ headerRightOperation(type) {
3123
+ this.clearHeaderRightOperation();
3124
+ // 第一步 判断type 是否与 rightType 相等 如果相等 就是关闭对应的窗口
3125
+ switch(type){
3126
+ case 'proof':
3127
+ this.showProofPanel = !this.showProofPanel;
3128
+ break;
3129
+ case 'detect':
3130
+ if(!scene.children.length){
3131
+ this.$message({
3132
+ type: "warning",
3133
+ message: "请先加载模型",
3134
+ });
3135
+ return
3136
+ }
3137
+
3138
+ this.showDetectPanel = !this.showDetectPanel;
3139
+
3140
+ if(this.showDetectPanel && this.showProofPanel){
3141
+ this.showProofPanel = false;
3142
+ this.handleClearAnnotation();
3143
+ this.handleDeleteProofList();
3144
+
3145
+ this.closeRightOperationType = {
3146
+ type: 'proof',
3147
+ close: true,
3148
+ };
3149
+ }
3150
+
3151
+ break;
3152
+ case 'property':
3153
+ this.showPropsPanel = !this.showPropsPanel;
3154
+
3155
+ if(this.showPropsPanel){
3156
+ const modelId = this.pickedModel.current?.name;
3157
+ const params = {
3158
+ modelId,
3159
+ propertyGroup: this.propertyGroup
3160
+ };
3161
+ this.$nextTick(() => {
3162
+ this.$refs.propsPanel.getModelProperty(params);
3163
+ })
3164
+ }
3165
+
3166
+ break;
3167
+ case 'clipping-all': // 剖切
3168
+ this.clippingType('all');
3169
+ break;
3170
+ case 'distance': // 测量
3171
+ case 'area':
3172
+ case 'angle':
3173
+ this.handleMeasure(type);
3174
+ break;
3175
+ case 'first-person':
3176
+ this.firstPer();
3177
+ break;
3178
+ case 'pbsTree':
3179
+ this.showPbsTreePanel = !this.showPbsTreePanel;
3180
+ break;
3181
+ case 'annotate':
3182
+ if(this.defaultParams.version){
3183
+ this.$message({
3184
+ type: "warning",
3185
+ message: "校审历史中无法使用批注功能",
3186
+ });
3187
+ return
3188
+ }
3189
+ if(this.showProofPanel){
3190
+ this.toggleDrawToolbar();
3191
+ }else{
3192
+ this.$message({
3193
+ type: "warning",
3194
+ message: "请在添加或编辑校审意见中使用",
3195
+ });
3196
+ }
3197
+ break;
3198
+ }
3199
+ },
3200
+ clearHeaderRightOperation(){
3201
+ this.measure(false)
3202
+ this.clearAllClipping()
3203
+ },
3204
+ // 清除操作
3205
+ clearRight(type) {
3206
+ // switch (type) {
3207
+ // case "searching":
3208
+ // this.resetRelationSvg2(this.$refs.searching.resetRelationDom); // 在检索状态下 关闭后 需要清除页面高亮的节点
3209
+ // break;
3210
+ // case "inspection":
3211
+ // oldSubsidiaryNode.length > 0 &&
3212
+ // this.resetHightSubsidiaryLight([]);
3213
+ // recordConCharArr.length > 0 && this.resetHighLightConChar();
3214
+ // break;
3215
+ // case "property":
3216
+ // this.getSvgRed();
3217
+ // break;
3218
+ // case "annotation":
3219
+ // this.clearPreViewAnn();
3220
+ // break;
3221
+ // }
3222
+ },
3223
+ viewVersion(item){
3224
+ // this.$set(this.proofConfig, 'viewVersion', item)
3225
+ this.proofConfig.viewVersion = item
3226
+
3227
+ // const params = {}
3228
+ // if(item && item.id){
3229
+ // params.version = item.id
3230
+ // }
3231
+
3232
+ this.redirectPage(item)
3233
+ },
3234
+ redirectPage(params){
3235
+ const queryParams = {
3236
+ projectId: (params && params.projectId) || this.defaultParams.projectId,
3237
+ };
3238
+
3239
+ if(params && params.id){
3240
+ queryParams.version = params.id
3241
+ }
3242
+ this.$router.replace({
3243
+ path: '/proof-model',
3244
+ query: queryParams
3245
+ })
3246
+ window.location.reload()
3247
+ },
3248
+ importProofModel(){
3249
+ this.$refs.proofConfig.openImportModelDialog();
3250
+ },
3251
+ publishVersion(){
3252
+ this.redirectPage()
3253
+ }
3254
+ },
3255
+ };
3256
+ </script>
3257
+ <style lang="scss" scoped>
3258
+ #blocker {
3259
+ // height: 100%;
3260
+ // width: 100%;
3261
+ box-sizing: border-box;
3262
+ position: relative;
3263
+ display: flex;
3264
+ flex-direction: column;
3265
+ // background-color: #2c375d;
3266
+ // background-color: #f0f0f0;
3267
+ // z-index: 2;
3268
+ // display: none;
3269
+ }
3270
+ #instructions {
3271
+ width: 100%;
3272
+ height: calc(100% - 58px);
3273
+ background: linear-gradient( 0deg, rgba(255,255,255,0.9) 0%, #b3d6ff 100%);
3274
+
3275
+ // display: flex;
3276
+ // flex-direction: row;
3277
+ // box-sizing: border-box;
3278
+ // padding: 5px;
3279
+ // height: 100%;
3280
+ }
3281
+ #konva-drawing-board {
3282
+ // z-index: 1;
3283
+ width: 100%;
3284
+ height: 100%;
3285
+ cursor: pointer;
3286
+ overflow: hidden;
3287
+ position: absolute;
3288
+ top: 0;
3289
+ }
3290
+ ::v-deep .measure-label-canvas {
3291
+ // position: absolute;
3292
+ // z-index: 999;
3293
+ pointer-events: none !important;
3294
+ }
3295
+ .toolbar_show {
3296
+ position: absolute;
3297
+ top: 27px;
3298
+ left: 50%;
3299
+ transform: translateX(-50%);
3300
+ z-index: 10;
3301
+ }
3302
+ .draw-btn {
3303
+ position: absolute;
3304
+ bottom: 10px;
3305
+ left: 50%;
3306
+ }
3307
+ .right-panel-container {
3308
+ display: flex;
3309
+ position: fixed;
3310
+ top: 60px;
3311
+ right: 0;
3312
+ z-index: 10;
3313
+ // height: calc(100% - 35px);
3314
+ }
3315
+ ::v-deep .el-tabs__item {
3316
+ color: #fff;
3317
+
3318
+ &.is-active {
3319
+ color: #409EFF;
3320
+ }
3321
+ }
3322
+ // wbs、pbs树样式
3323
+ .tree-container{
3324
+ position: fixed;
3325
+ height: calc(100% - 58px);
3326
+ width: 300px;
3327
+ padding: 20px 20px 10px;
3328
+ left: 0px;
3329
+ top: 58px;
3330
+ background: #DFF0FB;
3331
+ border: none;
3332
+ border-radius: 10px;
3333
+ box-sizing: border-box;
3334
+ z-index: 10;
3335
+ }
3336
+ ::v-deep .el-card__body{
3337
+ padding: 0;
3338
+ }
3339
+
3340
+ ::v-deep .tips-label {
3341
+ width: 65px;
3342
+ color: BLACK;
3343
+ font: 12px Helvetica;
3344
+ padding: 5px;
3345
+ text-align: center;
3346
+ vertical-align: middle;
3347
+ background-color: KHAKI;
3348
+ }
3349
+
3350
+ ::v-deep .measure-label {
3351
+ max-width: 100px;
3352
+ margin-top: -1em;
3353
+ border: 10px;
3354
+ border-radius: 5px;
3355
+ padding: 3px 10px;
3356
+ cursor: pointer;
3357
+ color: rgb(0, 155, 234);
3358
+ background-color: rgb(244, 244, 244);
3359
+ box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.25);
3360
+ }
3361
+ ::v-deep .circle-tag {
3362
+ width: 10px;
3363
+ height: 10px;
3364
+ border-radius: 50%;
3365
+ background-color: #009bea;
3366
+ }
3367
+ ::v-deep .measure-label-font {
3368
+ word-break: break-all;
3369
+ }
3370
+ ::v-deep .props-panel-container,
3371
+ ::v-deep .proof-panel-container,
3372
+ ::v-deep .detect-panel-container{
3373
+ box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.4);
3374
+ border-radius: 10px;
3375
+ margin: 0 5px;
3376
+ z-index: 10;
3377
+ }
3378
+ ::v-deep .proof-config-container{
3379
+ position: fixed;
3380
+ right: 0;
3381
+ z-index: 10;
3382
+ top: 12px;
3383
+ .history-dialog{
3384
+ position: fixed;
3385
+ left: 40%;
3386
+ top: 5px;
3387
+ }
3388
+ }
3389
+ ::v-deep .header-button-container{
3390
+ position: fixed;
3391
+ z-index: 10;
3392
+ top: 0;
3393
+ background: #fff;
3394
+ }
3395
+ ::v-deep .check-proofing-container{
3396
+ width: 100vw;
3397
+ height: 100vh;
3398
+ position: fixed;
3399
+ z-index: 10;
3400
+ display: flex;
3401
+ justify-content: center;
3402
+ align-items: center;
3403
+ }
3404
+ </style>
3405
+ <style>
3406
+ .lil-gui:nth-child(1){
3407
+ top: 200px;
3408
+ }
3409
+ .lil-gui:nth-child(2){
3410
+ top: 400px;
3411
+ }
3412
+
3413
+ </style>