explode3d.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. <template>
  2. <div v-show="isexpdialog" class="dialog_class4 bgcolor tianjia foter_l tianjia">
  3. <div class="expcontent">
  4. <h1 class="headertiele">{{ titleName }}</h1>
  5. <div class="exp">
  6. <div class="expleft" id="expleft1"></div>
  7. <div class="expright">
  8. <!-- 物理量 -->
  9. <div class="heigjie imgneon">
  10. <div class="he_pading1 color1">
  11. <el-form-item label="物理量:">
  12. <el-config-provider :locale="zhCn">
  13. <el-select v-model="formInline.region" @change="regionchange($event)" placeholder="请选择">
  14. <el-option v-for="item in strResultFormatlist" :key="item.id" :label="item.name"
  15. :value="item.value"></el-option>
  16. </el-select>
  17. </el-config-provider>
  18. </el-form-item>
  19. </div>
  20. </div>
  21. <!-- 动画 -->
  22. <el-aside class="L_aside L_aside1 asideg asidegbg leftbgimg1">
  23. <div class="demo-collapse jiance asideg1 jc_header collapseeion jianstyle">
  24. <el-collapse accordion v-model="activeNames1" class="bganimation">
  25. <el-collapse-item name="2" class="imgneon">
  26. <template #title>
  27. <el-icon class="iconimg Frame3" fit="contain"></el-icon>
  28. 动画展示
  29. </template>
  30. <div class="rg_content">
  31. <div class="rg-padding">
  32. <div class="animation_s">
  33. <el-slider :max="endtime" :min="1" v-model="count" @change="sliderchange">
  34. </el-slider>
  35. <div class="tanniu">
  36. <div><el-image :src="t1" fit="contain" @click="Prev"></el-image></div>
  37. <div v-show="suspendshow"><el-image :src="t2" fit="contain" @click="play(500)"></el-image></div>
  38. <div v-show="playshow"><el-image :src="t3" fit="contain" @click="play(500)"></el-image></div>
  39. <div><el-image :src="t4" fit="contain" @click="increment"></el-image></div>
  40. </div>
  41. </div>
  42. </div>
  43. </div>
  44. <!-- <div class="mgsnoe" style="height: 200px"></div> -->
  45. </el-collapse-item>
  46. </el-collapse>
  47. </div>
  48. </el-aside>
  49. </div>
  50. </div>
  51. <div class="dialog-footer footer_div l_btn">
  52. <div class="footerbtn flex1">
  53. <div class="borderimg"><el-button @click="isexpdialog = false">取消</el-button></div>
  54. </div>
  55. <div class="footerbtn flex1">
  56. <div class="borderimg"><el-button @click="quding()">
  57. 确定
  58. </el-button></div>
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. <!-- 瓦斯爆炸弹出列表-->
  64. </template>
  65. <script setup>
  66. import zhCn from "element-plus/es/locale/lang/zh-cn"
  67. import { ref, onMounted, reactive } from "vue"
  68. import { RouterView, RouterLink } from "vue-router"
  69. import { request, uploadFile } from "@/utils/request"
  70. import { ElMessage, ElButton, ElDialog, ElSelect } from "element-plus"
  71. import { createGassControl } from "@/control/gassControl.js"
  72. import emitter from "@/utils/emitter"
  73. import t1 from "@/assets/img/t1.png"
  74. import t2 from "@/assets/img/t2.png"
  75. import t3 from "@/assets/img/t3.png"
  76. import t4 from "@/assets/img/t4.png"
  77. import * as d3 from "d3-scale";
  78. import { formatDefaultLocale } from "d3-format";
  79. import vtkGenericRenderWindow from '@kitware/vtk.js/Rendering/Misc/GenericRenderWindow';
  80. import vtkRenderWindowWithControlBar from "@kitware/vtk.js/Rendering/Misc/RenderWindowWithControlBar";
  81. import vtkActor from "@kitware/vtk.js/Rendering/Core/Actor";
  82. import vtkConeSource from "@kitware/vtk.js/Filters/Sources/ConeSource";
  83. import vtkMapper from "@kitware/vtk.js/Rendering/Core/Mapper";
  84. import { Representation } from "@kitware/vtk.js/Rendering/Core/Property/Constants";
  85. import vtkScalarBarActor from "@kitware/vtk.js/Rendering/Core/ScalarBarActor";
  86. import vtkColorTransferFunction from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction";
  87. import vtkDataArray from "@kitware/vtk.js/Common/Core/DataArray.js";
  88. import vtkLight from "@kitware/vtk.js/Rendering/Core/Light";
  89. const props = defineProps({
  90. aid: Number
  91. })
  92. let isexpdialog = ref(false)
  93. const strResultFormatlist = ref([])
  94. const formInline = ref({
  95. user: "11",
  96. region: "u-velocity",
  97. name: "x方向速度(m/s)",
  98. date: ""
  99. })
  100. const titleName = ref("瓦斯爆炸演化")
  101. const nameMap = {
  102. "u-velocity": 'x方向速度(m/s)',
  103. "v-velocity": 'y方向速度(m/s)',
  104. "w-velocity": 'z方向速度(m/s)',
  105. "static_pressure": '压力(Pa)',
  106. "static_temperature": '温度(℃)',
  107. "O2_mass_fraction": '氧气质量分数(%)',
  108. "CH4_mass_fraction": '甲烷质量分数(%)',
  109. "CO2_mass_fraction": '二氧化碳质量分数(%)',
  110. "H2O_mass_fraction": '水蒸气质量分数(%)',
  111. "N2_mass_fraction": '氮气质量分数(%)'
  112. };
  113. let arr=[];
  114. let currentrow1 = ref(false)
  115. let activeNames1 = ref(["2"])
  116. let starttime = ref(1)
  117. let endtime = ref(60)
  118. let count = ref(1)
  119. let newcount = ref(0)
  120. let timenum = ref(2)
  121. let playshow = ref(true)
  122. const isstop = ref(false)
  123. let suspendshow = ref(false)
  124. let showfalse = ref(false)
  125. let initFlag=false;
  126. let aid = ref()
  127. let vtkObj = {}
  128. let max, min;
  129. watch(
  130. () => [formInline.value.region, count.value, aid.value],
  131. (newVal, oldVal) => {
  132. if(initFlag){
  133. console.log(count.value);
  134. if (newVal[1] != oldVal[1]) {
  135. console.log("步数改变", newVal[1], oldVal[1]);
  136. if (vtkObj.fcon) {
  137. console.log(count.value);
  138. vtkScalarRead(count.value); //步数
  139. }
  140. }
  141. if (newVal[0] != oldVal[0]) {
  142. console.log("标量改变", newVal[0], oldVal[0]);
  143. if (vtkObj.fcon) {
  144. vtkShow();
  145. }
  146. }
  147. }
  148. },
  149. { deep: true }
  150. ); //深度监视
  151. onMounted(() => {
  152. const rootContainer = document.getElementById("expleft1")
  153. // rootContainer.style.position = "relative"
  154. // rootContainer.style.width = "100%"
  155. // rootContainer.style.height = "100%"
  156. vtkObj.fcon = createGassControl();
  157. const fcon = vtkObj.fcon;
  158. vtkObj.renderWindow = vtkGenericRenderWindow.newInstance()
  159. vtkObj.renderWindow.setContainer(rootContainer)
  160. vtkObj.jgMapper = vtkMapper.newInstance()
  161. vtkObj.jgActor = vtkActor.newInstance()
  162. vtkObj.jgActor.getProperty().setRepresentation(Representation.SURFACE) //面
  163. vtkObj.jgActor.setMapper(vtkObj.jgMapper)
  164. // vtkObj.renderWindow.getRenderer().addActor(vtkObj.jgActor);
  165. vtkObj.renderWindow.getRenderer().setBackground(0.0, 0.0, 0.0, 0.0)
  166. vtkObj.scalarBarActor = vtkScalarBarActor.newInstance()
  167. vtkObj.scalarBarActor.setGenerateTicks(generateTicks(5))
  168. vtkObj.scalarBarActor.setDrawAboveRangeSwatch(true)
  169. vtkObj.scalarBarActor.setDrawNanAnnotation(false)
  170. vtkObj.scalarBarActor.setBoxPosition([1, 0])
  171. // 修改设条颜色
  172. const ctf = vtkColorTransferFunction.newInstance()
  173. ctf.addRGBPoint(0.0, 0, 1, 154 / 255.0)
  174. ctf.addRGBPoint(1.0, 1.0, 165.0 / 255.0, 0.0)
  175. ctf.addRGBPoint(2.0, 230 / 255.0, 0.0, 92.0 / 225.0)
  176. vtkObj.jgMapper.setLookupTable(ctf)
  177. const lut = vtkObj.jgMapper.getLookupTable()
  178. vtkObj.scalarBarActor.setScalarsToColors(lut)
  179. vtkObj.renderWindow.resize()
  180. // vtkObj.renderWindow.getRenderer().addActor(vtkObj.scalarBarActor);
  181. // vtkGridRead(props.aid);
  182. // vtkObj.renderWindow.getRenderer().resetCamera();
  183. // vtkObj.renderWindow.getRenderWindow().render();
  184. // 设置环境光和光照
  185. const light = vtkLight.newInstance()
  186. light.setColor(1.0, 1.0, 1.0) // 白色环境光
  187. light.setIntensity(3.0) // 强度为1.0
  188. vtkObj.renderWindow.getRenderer().addLight(light)
  189. emitter.on("pipeName", handleTitleName)
  190. })
  191. onUnmounted(() => {
  192. emitter.off("pipeName", handleTitleName)
  193. })
  194. function handleTitleName(name) {
  195. console.log("接收到的管道名称:", name);
  196. titleName.value = `${name}(灾源点巷道)局部图`;
  197. }
  198. function initVtk() {
  199. }
  200. function generateTicks(numberOfTicks) {
  201. return (helper) => {
  202. const lastTickBounds = helper.getLastTickBounds()
  203. // compute tick marks for axes
  204. const scale = d3
  205. .scaleLinear()
  206. .domain([0.0, 1.0])
  207. .range([lastTickBounds[0], lastTickBounds[1]])
  208. const samples = scale.ticks(numberOfTicks)
  209. const ticks = samples.map((tick) => scale(tick))
  210. // Replace minus "\u2212" with hyphen-minus "\u002D" so that parseFloat() works
  211. formatDefaultLocale({ minus: "\u002D" })
  212. const format = scale.tickFormat(
  213. ticks[0],
  214. ticks[ticks.length - 1],
  215. numberOfTicks
  216. )
  217. const tickStrings = ticks
  218. .map(format)
  219. .map((tick) => Number(parseFloat(tick).toPrecision(12)).toPrecision()) // d3 sometimes adds unwanted whitespace
  220. helper.setTicks(ticks)
  221. helper.setTickStrings(tickStrings)
  222. }
  223. }
  224. let cameraInitialized = false; // 默认还未初始化相机
  225. function vtkShow() {
  226. console.log("执行了 vtkShow");
  227. const scalarBarActor = vtkObj.scalarBarActor
  228. const mapper = vtkObj.jgMapper
  229. const actor = vtkObj.jgActor
  230. const fcon = vtkObj.fcon
  231. const scalarArray = fcon.scalar.get(formInline.value.region)
  232. if (!scalarArray || !fcon.polydata) {
  233. return
  234. }
  235. const dataArray = vtkDataArray.newInstance({
  236. name: formInline.value.region,
  237. size: fcon.polydata.getNumberOfPoints()
  238. })
  239. dataArray.setData(scalarArray)
  240. fcon.polydata.getPointData().setScalars(dataArray)
  241. mapper.setInputData(fcon.polydata)
  242. getMinMax(scalarArray)
  243. mapper.setScalarRange(parseFloat(min.toFixed(3)), parseFloat(max.toFixed(3)))
  244. scalarBarActor.setAxisLabel(formInline.value.name)
  245. mapper.clearColorArrays()
  246. actor.getProperty().setOpacity(count.value)
  247. vtkObj.renderWindow.getRenderer().addActor(scalarBarActor)
  248. vtkObj.renderWindow.getRenderer().addActor(actor)
  249. // 仅第一次调用 resetCamera
  250. if (!cameraInitialized) {
  251. vtkObj.renderWindow.getRenderer().resetCamera()
  252. cameraInitialized = true
  253. }
  254. vtkObj.renderWindow.getRenderWindow().render()
  255. vtkObj.renderWindow.resize()
  256. initFlag = true
  257. }
  258. function getMinMax(scalars) {
  259. // console.log("getMinMax:",scalars);
  260. min = scalars[0]
  261. max = scalars[0]
  262. for (let index = 0; index <= scalars.length; index++) {
  263. let scalar = scalars[index]
  264. if (min > scalar) {
  265. min = scalar
  266. }
  267. if (max < scalar) {
  268. max = scalar
  269. }
  270. }
  271. console.log("max,min:", max, min);
  272. }
  273. onBeforeUnmount(() => {
  274. vtkObj.scalarBarActor.delete()
  275. vtkObj.jgMapper.delete()
  276. vtkObj.jgActor.delete()
  277. vtkObj.renderWindow.delete()
  278. vtkObj = null
  279. })
  280. // 播放暂停
  281. const play = (time) => {
  282. const fcon = vtkObj.fcon;
  283. showfalse.value = !showfalse.value
  284. currentrow1.value = false
  285. if (showfalse.value) {
  286. suspendshow.value = true
  287. playshow.value = false
  288. isstop.value = true //播放
  289. const sleep = (timeout = time) =>
  290. new Promise((resolve, reject) => {
  291. setTimeout(resolve, timeout)
  292. })
  293. let timer = async (timeout) => {
  294. while (count.value < endtime.value && isstop.value) {
  295. if (isstop.value == true) {
  296. await sleep(time)
  297. count.value++
  298. fcon.step = count.value
  299. newcount.value = count.value
  300. // newtime();
  301. }
  302. }
  303. isstop.value = false //暂停
  304. playshow.value = true
  305. suspendshow.value = false
  306. }
  307. timer(time)
  308. } else {
  309. isstop.value = false //暂停
  310. playshow.value = true
  311. suspendshow.value = false
  312. }
  313. }
  314. // 下一页
  315. function increment() {
  316. const fcon = vtkObj.fcon
  317. currentrow1.value = false
  318. isstop.value = false
  319. if (count.value == endtime.value) {
  320. return
  321. }
  322. count.value++
  323. newcount.value = count.value
  324. fcon.step = count.value
  325. //newtime();
  326. }
  327. //回到上一页
  328. function Prev() {
  329. const fcon = vtkObj.fcon
  330. currentrow1.value = false
  331. isstop.value = false
  332. count.value--
  333. fcon.step = count.value
  334. newcount.value = count.value
  335. //newtime();
  336. }
  337. // 时间计算
  338. const newtime = () => {
  339. timeshow.value = true
  340. time.value = null
  341. oldtime.value = sessionStorage.getItem("acctime")
  342. console.log(oldtime.value)
  343. time.value = new Date(oldtime.value).getTime() / 1000
  344. if (count.value == 2) {
  345. let time2 = (count.value - 1) * 60 + time.value
  346. timeline.value = timescount(time2)
  347. } else {
  348. let time2 = count.value * 60 + time.value
  349. timeline.value = timescount(time2)
  350. }
  351. }
  352. function sliderchange(val) {
  353. const fcon = vtkObj.fcon
  354. suspendshow.value = false
  355. playshow.value = true
  356. isstop.value = false
  357. newcount.value = count.value
  358. fcon.step = count.value
  359. }
  360. function vtkGridRead() {
  361. initVtk();
  362. const fcon = vtkObj.fcon
  363. aid.value = props.aid
  364. fcon.step = count.value
  365. fcon.aid = aid.value
  366. const params = {
  367. transCode: "D40003",
  368. aid: aid.value
  369. }
  370. request(params).then((res) => {
  371. endtime.value = res.steps
  372. fcon
  373. .initGemetry(aid.value)
  374. .then((result) => {
  375. vtkScalarRead(count.value) //步数
  376. })
  377. .catch((err) => { })
  378. }).catch((err) => { })
  379. }
  380. function vtkScalarRead(step) {
  381. arr=[];
  382. let i=0;
  383. const fcon = vtkObj.fcon
  384. console.log('fcon:',fcon);
  385. fcon
  386. .getScalrsByStep(step)
  387. .then((result) => {
  388. // console.log(fcon.scalar)
  389. strResultFormatlist.value = [];
  390. fcon.scalar.forEach((value, key) => {
  391. //arr.push(key)
  392. if (nameMap[key]) {
  393. i=i+1
  394. strResultFormatlist.value.push({
  395. id: i,
  396. name:nameMap[key] || key ,
  397. value:key ,
  398. });
  399. }
  400. })
  401. console.log('strResultFormatlist:',strResultFormatlist.value);
  402. vtkShow()
  403. })
  404. .catch((err) => {
  405. console.log(err)
  406. })
  407. }
  408. //深度监视
  409. const regionchange=(val)=>{
  410. formInline.value.region=val;
  411. formInline.value.name=nameMap[val] || val;
  412. }
  413. const quding=()=>{
  414. isexpdialog.value=false;
  415. }
  416. defineExpose({ isexpdialog, vtkGridRead })
  417. </script>
  418. <style lang="scss" scoped>
  419. .exp {
  420. display: flex;
  421. .expleft {
  422. width: 70%;
  423. border-radius: 0px 0px 0px 0px;
  424. border: 1px solid;
  425. border-image: linear-gradient(180deg,
  426. rgba(31, 107, 255, 1),
  427. rgba(31, 107, 255, 0.48)) 1 1;
  428. box-shadow: inset 0px 0px 17px 5px rgba(12, 97, 197, 0.2);
  429. margin-right: 2%;
  430. height: 600px;
  431. }
  432. .expright {
  433. padding: 10px;
  434. width: 340px;
  435. border-radius: 0px 0px 0px 0px;
  436. border: 1px solid;
  437. border-image: linear-gradient(180deg,
  438. rgba(31, 107, 255, 1),
  439. rgba(31, 107, 255, 0.48)) 1 1;
  440. box-shadow: inset 0px 0px 17px 5px rgba(12, 97, 197, 0.2);
  441. }
  442. }
  443. .tanniu {
  444. display: flex;
  445. justify-content: space-between;
  446. align-items: center;
  447. }
  448. .expcontent {
  449. position: absolute;
  450. left: 25%;
  451. top: 100px;
  452. width: 50%;
  453. padding: 10px;
  454. z-index: 11111;
  455. background-color:rgba(13, 22, 57, 0.96);
  456. border: 1px solid;
  457. border-image: linear-gradient(180deg,
  458. rgba(31, 107, 255, 1),
  459. rgba(31, 107, 255, 0.48)) 1 1;
  460. box-shadow: inset 0px 0px 17px 5px rgba(12, 97, 197, 0.2);
  461. }
  462. .headertiele{
  463. color: #fff;
  464. text-align: left;
  465. padding: 0 20px;
  466. font-size: 16px;
  467. font-family: 'YouShe';
  468. }
  469. // #expleft1{
  470. // width:750px;
  471. // height:500px;
  472. // left:25%;
  473. // top: 25%;
  474. // background-color:rgba(12, 97, 197, 1);
  475. // border: 1px solid;
  476. // border-image: linear-gradient(
  477. // 180deg,
  478. // rgba(31, 107, 255, 1),
  479. // rgba(31, 107, 255, 0.48)
  480. // )
  481. // 1 1;
  482. // box-shadow: inset 0px 0px 17px 5px rgba(12, 97, 197, 0.2);
  483. // position: absolute;
  484. // z-index: 11111;
  485. // color: #fff;
  486. // }
  487. </style>