import * as d3 from "d3-scale"; import { formatDefaultLocale } from "d3-format"; import "@kitware/vtk.js/Rendering/Profiles/Geometry"; import vtkFullScreenRenderWindow from "@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow"; import vtkActor from "@kitware/vtk.js/Rendering/Core/Actor"; import vtkMapper from "@kitware/vtk.js/Rendering/Core/Mapper"; import vtkScalarBarActor from "@kitware/vtk.js/Rendering/Core/ScalarBarActor"; import vtkColorTransferFunction from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction"; import { Representation } from "@kitware/vtk.js/Rendering/Core/Property/Constants"; import vtkPolyData from "@kitware/vtk.js/Common/DataModel/PolyData"; import { throttle } from '@kitware/vtk.js/macros'; import { FieldDataTypes, FieldAssociations, } from '@kitware/vtk.js/Common/DataModel/DataSet/Constants'; import vtkSphereSource from '@kitware/vtk.js/Filters/Sources/SphereSource'; import vtkLineSource from '@kitware/vtk.js/Filters/Sources/LineSource'; import vtkSphereMapper from '@kitware/vtk.js/Rendering/Core/SphereMapper'; export class VtkModel { constructor() { //当前显示 模版 还是结果 this.isJg = false; /** * 选择点线 */ this.isSelectNode = false; /** * 选择管道 */ this.isSelectPipe = false; //管道节点选择对象 this.selectObj = null; //结果选择的点数据 this.selectJgPointId=0; this.validNodes = [];//节点数据 this.pipes = [];//管道数据 this.renderWindowWith = vtkFullScreenRenderWindow.newInstance(); this.renderer = this.renderWindowWith.getRenderer(); this.renderWindow = this.renderWindowWith.getRenderWindow(); //模板数据 this.polyData = vtkPolyData.newInstance(); this.mapper = vtkMapper.newInstance(); this.actor = vtkActor.newInstance(); this.actor.getProperty().setRepresentation(Representation.SURFACE); //线 this.actor.getProperty().setColor(WHITE); this.mapper.setInputData(this.polyData); this.actor.setMapper(this.mapper); //点数据 this.actor2 = vtkActor.newInstance(); this.actor2.getProperty().setRepresentation(Representation.POINTS); //点 this.actor2.getProperty().setColor(WHITE); this.actor2.getProperty().setPointSize(2); this.actor2.setMapper(this.mapper); //选取 this.lastActor = null; this.nodeActors = []; //节点actor 数据 this.pipeActors = []; //管道actor 数据 this.interactor = this.renderer.getRenderWindow().getInteractor(); this.apiSpecificRenderWindow = this.interactor.getView(); this.hardwareSelector = this.apiSpecificRenderWindow.getSelector(); this.hardwareSelector.setCaptureZValues(true); this.hardwareSelector.setFieldAssociation(FieldAssociations.FIELD_ASSOCIATION_POINTS); document.addEventListener("mousemove", throttleMouseHandler); //结果数据 this.jgActor = vtkActor.newInstance(); this.jgMapper = vtkMapper.newInstance(); this.jgActor.getProperty().setRepresentation(Representation.SURFACE); //面 this.scalarBarActor = vtkScalarBarActor.newInstance(); this.scalarBarActor.setGenerateTicks(this.generateTicks(5)); this.scalarBarActor.setDrawAboveRangeSwatch(true); this.scalarBarActor.setDrawNanAnnotation(false); this.scalarBarActor.setBoxPosition([1, 0]); // 修改设条颜色 const ctf = vtkColorTransferFunction.newInstance(); ctf.addRGBPoint(0.0, 0.0, 0.0, 1.0); ctf.addRGBPoint(1.0, 0.0, 1.0, 0.5); ctf.addRGBPoint(2.0, 0.0, 1.0, 0.0); ctf.addRGBPoint(3.0, 1.0, 0.5, 0.0); ctf.addRGBPoint(4.0, 1.0, 0.0, 0.0); this.jgMapper.setLookupTable(ctf); const lut = this.jgMapper.getLookupTable(); this.scalarBarActor.setScalarsToColors(lut); this.jgActor.setMapper(this.jgMapper); } generateTicks(numberOfTicks) { return (helper) => { const lastTickBounds = helper.getLastTickBounds(); // compute tick marks for axes const scale = d3 .scaleLinear() .domain([0.0, 1.0]) .range([lastTickBounds[0], lastTickBounds[1]]); const samples = scale.ticks(numberOfTicks); const ticks = samples.map((tick) => scale(tick)); // Replace minus "\u2212" with hyphen-minus "\u002D" so that parseFloat() works formatDefaultLocale({ minus: "\u002D" }); const format = scale.tickFormat(ticks[0], ticks[ticks.length - 1], numberOfTicks); const tickStrings = ticks .map(format) .map((tick) => Number(parseFloat(tick).toPrecision(12)).toPrecision()); // d3 sometimes adds unwanted whitespace helper.setTicks(ticks); helper.setTickStrings(tickStrings); }; } modelInit(validNodes, pipes) { this.validNodes = validNodes; this.pipes = pipes; this.modelCreate(); } modelCreate() { console.log("modelInit.."); const points = this.polyData.getPoints(); const lines = this.polyData.getLines(); //无节点actor this.validNodes.forEach((node) => { points.insertNextPoint(parseFloat(node.x), parseFloat(node.y), parseFloat(node.z)); }); //无管道actor this.pipes.forEach((pipe) => { let sid = this.indexIdByPipeNodeId(pipe.snId); let eid = this.indexIdByPipeNodeId(pipe.enId); lines.insertNextCell([sid, eid]); }); //有节点actors const sphereSource = vtkSphereSource.newInstance({ center: [0, 0, 0], radius: 4.0, }); const mapper = vtkMapper.newInstance(); mapper.setInputConnection(sphereSource.getOutputPort()); this.validNodes.forEach((node) => { const actor = vtkActor.newInstance(); actor.setMapper(mapper); actor.setPosition(parseFloat(node.x), parseFloat(node.y), parseFloat(node.z)); actor.getProperty().setColor(WHITE); const nodeActor = {}; nodeActor.node = node; nodeActor.actor = actor; this.nodeActors.push(nodeActor); }); //有管道actors this.pipes.forEach((pipe) => { const lineSource = vtkLineSource.newInstance(); let point1 = this.pointByPipeNodeId(pipe.snId); let point2 = this.pointByPipeNodeId(pipe.enId); lineSource.setPoint1(point1); lineSource.setPoint2(point2); lineSource.setResolution(12); const actor = vtkActor.newInstance(); const mapper = vtkMapper.newInstance(); actor.setMapper(mapper); actor.getProperty().setLineWidth(3);//设置线宽 actor.getProperty().setColor(WHITE); mapper.setInputConnection(lineSource.getOutputPort()); const pipeActor = {}; pipeActor.pipe = pipe; pipeActor.actor = actor; this.pipeActors.push(pipeActor); }); this.modelShow(); this.renderer.resetCamera(); this.renderWindow.render(); } modelClearShow() { this.renderer.removeActor(this.actor); this.renderer.removeActor(this.actor2); this.nodeActors.forEach((nodeActor) => { this.renderer.removeActor(nodeActor.actor); }); this.pipeActors.forEach((pipeActor) => { this.renderer.removeActor(pipeActor.actor); }); } modelShow() { this.modelClearShow(); if (!this.isSelectNode) {//不选择节点 this.renderer.addActor(this.actor2); } if (!this.isSelectPipe) {//不选择管道 this.renderer.addActor(this.actor); } if (this.isSelectNode) {//选择节点 this.nodeActors.forEach((nodeActor) => { this.renderer.addActor(nodeActor.actor); }); } if (this.isSelectPipe) {//选择管道 this.pipeActors.forEach((pipeActor) => { this.renderer.addActor(pipeActor.actor); }); } } selectNodes() { this.isSelectNode = true; this.isSelectPipe = false; this.modelShow(); this.renderWindow.render(); } selectPipes() { this.isSelectNode = false; this.isSelectPipe = true; this.modelShow(); this.renderWindow.render(); } selectNoting(){ this.isSelectNode = false; this.isSelectPipe = false; this.modelShow(); this.renderWindow.render(); } /** * 根据id 获取对应的编号 */ indexIdByPipeNodeId(nid) { for (let index = 0; index < this.validNodes.length; index++) { const node = this.validNodes[index]; if (node.id == nid) { return index; } } return 0; } pointByPipeNodeId(nid) { for (let index = 0; index < this.validNodes.length; index++) { const node = this.validNodes[index]; if (node.id == nid) { return [parseFloat(node.x), parseFloat(node.y), parseFloat(node.z)]; } } return 0; } clearModeAddJg() { this.renderer.addActor(this.jgActor); this.renderer.addActor(this.scalarBarActor); this.modelClearShow(); this.isJg = true; //显示结果 } clearJgAddMode() { this.renderer.removeActor(this.scalarBarActor); this.renderer.removeActor(this.jgActor); this.modelShow(); this.isJg = false; //不显示结果 } } function pickOnMouseEvent(event) { if (vtkmodel.interactor.isAnimating()) { // We should not do picking when interacting with the scene return; } const [x, y] = eventToWindowXY(event); // console.log([x,y]); // vtkmodel.pointerActor.setVisibility(false); vtkmodel.hardwareSelector .getSourceDataAsync(vtkmodel.renderer, x, y, x, y) .then((result) => { if (result) { processSelections(result.generateSelection(x, y, x, y)); // processSelections(result.generateSelection(x, y, x, y)); } else { // processSelections(null); } }); } function eventToWindowXY(event) { // We know we are full screen => window.innerXXX // Otherwise we can use pixel device ratio or else... const { clientX, clientY } = event; const [width, height] = vtkmodel.apiSpecificRenderWindow.getSize(); const x = Math.round((width * clientX) / window.innerWidth); const y = Math.round(height * (1 - clientY / window.innerHeight)); // Need to flip Y return [x, y]; } function processSelections(selections) { if (!selections || selections.length === 0) {//没有选择 if (vtkmodel.lastActor == null) { } else { // vtkmodel.lastActor.getProperty().setColor(WHITE); // vtkmodel.renderWindow.render(); } // vtkmodel.lastActor = null; return; } const { worldPosition: rayHitWorldPosition, compositeID, prop, propID, attributeID, } = selections[0].getProperties(); if (vtkmodel.lastActor != null) { vtkmodel.lastActor.getProperty().setColor(WHITE); vtkmodel.renderWindow.render(); } vtkmodel.nodeActors.forEach((nodeActor) => { if (prop == nodeActor.actor) { vtkmodel.selectObj = nodeActor.node; prop.getProperty().setColor(GREEN); vtkmodel.lastActor = prop; console.log(vtkmodel.selectObj ); } }); vtkmodel.pipeActors.forEach((pipeActor) => { if (prop == pipeActor.actor) { vtkmodel.selectObj = pipeActor.pipe; prop.getProperty().setColor(GREEN); vtkmodel.lastActor = prop; console.log(vtkmodel.selectObj ); } }); if (vtkmodel.isJg) {//结果数据选择cell //选择Cell const input = prop.getMapper().getInputData(); if (!input.getCells()) { input.buildCells(); } const cellPoints = input.getCellPoints(attributeID); if (cellPoints) { const pointIds = cellPoints.cellPointIds; // Find the closest cell point, and use that as cursor position const points = Array.from(pointIds).map((pointId) => input.getPoints().getPoint(pointId) ); // const scalarDataArray=input.getPointData().getScalars().getData(); // pointIds.forEach(pointId=>{ // console.log(input.getPointData().getScalars().getName()); // console.log(scalarDataArray[pointId]);//节点标量数据 // }); vtkmodel.selectJgPointId =pointIds[0]; } } vtkmodel.renderWindow.render(); } const throttleMouseHandler = throttle(pickOnMouseEvent, 20); const WHITE = [0, 0, 1]; const GREEN = [0.1, 0.8, 0.1]; const vtkmodel = new VtkModel(); export { vtkmodel };