绘制矢量图
<h3>1. <strong>创建渲染器</strong></h3>
<pre><code>const renderer = vtkRenderer.newInstance(); // 将渲染器的背景色设置为透明
renderer.setBackground(0, 0, 0, 0); // RGBA 中的 A 通道设置为 0 表示完全透明</code></pre>
<ul>
<li><strong><code>vtkRenderer.newInstance()</code></strong>:创建一个新的渲染器实例。</li>
<li><strong><code>renderer.setBackground(0, 0, 0, 0)</code></strong>:设置渲染器的背景色为透明。<code>RGBA</code> 中的 <code>A</code> 通道设置为 <code>0</code> 表示完全透明。</li>
</ul>
<h3>2. <strong>创建点数据</strong></h3>
<pre><code>const points = vtkPoints.newInstance();
const { location, vecArr } = data;
points.setData(new Float32Array(location));</code></pre>
<ul>
<li><strong><code>vtkPoints.newInstance()</code></strong>:创建一个新的点集合实例。</li>
<li><strong><code>points.setData(new Float32Array(location))</code></strong>:将点坐标数据(<code>location</code>)转化为 <code>Float32Array</code> 并设置到点集合中。</li>
</ul>
<h3>3. <strong>创建立方体源</strong></h3>
<pre><code>const cubeSource = vtkCubeSource.newInstance(
{
xLength: xLength, // 立方体在 X 轴上的长度
yLength: yLength, // 立方体在 Y 轴上的长度
zLength: zLength // 立方体在 Z 轴上的长度
});</code></pre>
<ul>
<li><strong><code>vtkCubeSource.newInstance({...})</code></strong>:创建一个立方体数据源,立方体的尺寸由 <code>xLength</code>、<code>yLength</code> 和 <code>zLength</code> 指定。</li>
</ul>
<h3>4. <strong>设置立方体的透明度</strong></h3>
<pre><code>const actorHidden = vtkActor.newInstance();
const mapperHidden = vtkMapper.newInstance();
mapperHidden.setInputConnection(cubeSource.getOutputPort());
const propertyHidden = actorHidden.getProperty();
propertyHidden.setOpacity(0); // 设置透明度为 0 actorHidden.setMapper(mapperHidden);
actorHidden.setPosition(gridBounds[0] + xLength / 2, gridBounds[2] + yLength / 2, gridBounds[4] + zLength / 2);</code></pre>
<ul>
<li><strong><code>vtkActor.newInstance()</code></strong>:创建一个新的演员(<code>actor</code>)实例。</li>
<li><strong><code>vtkMapper.newInstance()</code></strong>:创建一个新的映射器(<code>mapper</code>)实例。</li>
<li><strong><code>mapperHidden.setInputConnection(cubeSource.getOutputPort())</code></strong>:将立方体源的输出连接到映射器。</li>
<li><strong><code>propertyHidden.setOpacity(0)</code></strong>:将演员的透明度设置为 <code>0</code>,使其不可见。</li>
<li><strong><code>actorHidden.setMapper(mapperHidden)</code></strong>:将映射器设置到演员。</li>
<li><strong><code>actorHidden.setPosition(...)</code></strong>:将演员的位置设置到立方体中心。</li>
</ul>
<h3>5. <strong>设置向量数据</strong></h3>
<pre><code>const vectors = vtkDataArray.newInstance({
numberOfComponents: 3, // 数据中的组件数量(例如,对于3D点,这将是x, y, z)
values: new Float32Array(transVerPoints(data.vector, vecArr, data, modeView, config, data.median)),
type: 'Float32' // 指定数据类型 });</code></pre>
<ul>
<li><strong><code>vtkDataArray.newInstance({...})</code></strong>:创建一个新的数据数组实例,用于存储向量数据。</li>
<li><strong><code>numberOfComponents: 3</code></strong>:每个向量有三个组件 (x, y, z)。</li>
<li><strong><code>values: new Float32Array(...)</code></strong>:将向量数据转化为 <code>Float32Array</code> 并设置到数据数组中。</li>
</ul>
<h3>6. <strong>设置缩放数据</strong></h3>
<pre><code>const scales = vtkDataArray.newInstance({
numberOfComponents: 1, // size
name: 'scales',
type: 'float32', // 指定数据类型
values: new Float32Array(transVerScale(data.length, data.arrow_length_factor, vecArr, config, data.median))
});</code></pre>
<ul>
<li><strong><code>numberOfComponents: 1</code></strong>:每个缩放因子只有一个组件(即缩放大小)。</li>
<li><strong><code>values: new Float32Array(...)</code></strong>:将缩放因子转化为 <code>Float32Array</code> 并设置到数据数组中。</li>
</ul>
<h3>7. <strong>设置颜色数据</strong></h3>
<pre><code>const colors = vtkDataArray.newInstance({
numberOfComponents: 4, // r, g, b, a
name: 'colorMode',
type: 'uint8',
values: new Uint8Array(arrData)
});</code></pre>
<ul>
<li><strong><code>numberOfComponents: 4</code></strong>:每个颜色值有四个组件(红、绿、蓝、透明度)。</li>
<li><strong><code>values: new Uint8Array(arrData)</code></strong>:将颜色数据转化为 <code>Uint8Array</code> 并设置到数据数组中。</li>
</ul>
<h3>8. <strong>创建 PolyData 并设置属性</strong></h3>
<pre><code>const polyData = vtkPolyData.newInstance();
polyData.setPoints(points);
const pointerD = polyData.getPointData();
pointerD.setVectors(vectors);
pointerD.addArray(scales);
pointerD.setScalars(colors);</code></pre>
<ul>
<li><strong><code>vtkPolyData.newInstance()</code></strong>:创建一个新的 <code>PolyData</code> 实例,用于存储点数据、向量数据、缩放数据和颜色数据。</li>
<li><strong><code>pointerD.setVectors(vectors)</code></strong>:将向量数据设置到 <code>PolyData</code> 中。</li>
<li><strong><code>pointerD.addArray(scales)</code></strong>:将缩放数据添加到 <code>PolyData</code> 中。</li>
<li><strong><code>pointerD.setScalars(colors)</code></strong>:将颜色数据设置到 <code>PolyData</code> 中。</li>
</ul>
<h3>9. <strong>创建箭头源</strong></h3>
<pre><code>const arrowSource = vtkArrowSource.newInstance();
arrowSource.setTipResolution(modeView === '2D' ? 2 : 6);
arrowSource.setTipRadius(0.05 * config.arrowSize / 10);
arrowSource.setTipLength(0.1 * config.arrowSize / 10);
arrowSource.setShaftRadius(0.005 * config.strokeWidth / 10);
arrowSource.setShaftResolution(modeView === '2D' ? 12 : 12);</code></pre>
<ul>
<li><strong><code>vtkArrowSource.newInstance()</code></strong>:创建一个新的箭头源实例。</li>
<li><strong><code>setTipResolution(...)</code></strong>:设置箭头的尖端分辨率。</li>
<li><strong><code>setTipRadius(...)</code></strong>、<strong><code>setTipLength(...)</code></strong>、<strong><code>setShaftRadius(...)</code></strong>:设置箭头的各个部分的尺寸。</li>
<li><strong><code>setShaftResolution(...)</code></strong>:设置箭头杆的分辨率。</li>
</ul>
<h3>10. <strong>应用矩阵变换</strong></h3>
<pre><code>const vtkMatrixBuilder = window.vtk.Common.Core.vtkMatrixBuilder;
const allLength = 0.05 * config.arrowSize / 10 + 0.1 * config.arrowSize / 10 + 0.005 * config.strokeWidth / 10;
vtkMatrixBuilder.buildFromRadian().translate(0 + allLength, 0.0, 0.0).apply(appendPts);</code></pre>
<ul>
<li><strong><code>vtkMatrixBuilder.buildFromRadian()</code></strong>:创建一个矩阵构建器实例。</li>
<li><strong><code>translate(...)</code></strong>:应用平移变换,将箭头中心移动到 [0 + allLength, 0.0, 0.0] 位置。</li>
</ul>
<h3>11. <strong>创建 <code>Glyph3DMapper</code> 并设置属性</strong></h3>
<pre><code>const glyph3DMapper = vtkGlyph3DMapper.newInstance({
scaleArray: 'scales',
colorByArrayName: 'colors'
});
glyph3DMapper.setInputData(polyData);
glyph3DMapper.setSourceConnection(arrowSource.getOutputPort());</code></pre>
<ul>
<li><strong><code>vtkGlyph3DMapper.newInstance({...})</code></strong>:创建一个新的 <code>Glyph3DMapper</code> 实例,并设置其属性。</li>
<li><strong><code>setInputData(polyData)</code></strong>:将 <code>PolyData</code> 设置到映射器中。</li>
<li><strong><code>setSourceConnection(arrowSource.getOutputPort())</code></strong>:将箭头源的输出连接到 <code>Glyph3DMapper</code>。</li>
</ul>
<h3>12. <strong>创建演员并添加到渲染器</strong></h3>
<pre><code>const actor = vtkActor.newInstance(); actor.setMapper(glyph3DMapper);
// 添加演员到渲染器并渲染
renderer.addActor(actor);
renderer.setLayer(4);</code></pre>
<ul>
<li><strong><code>vtkActor.newInstance()</code></strong>:创建一个新的演员实例。</li>
<li><strong><code>actor.setMapper(glyph3DMapper)</code></strong>:将 <code>Glyph3DMapper</code> 设置到演员中。</li>
<li><strong><code>renderer.addActor(actor)</code></strong>:将演员添加到渲染器中。</li>
<li><strong><code>renderer.setLayer(4)</code></strong>:设置渲染器的图层为 4。</li>
</ul>
<h3>总结</h3>
<p>这段代码主要做了以下事情:</p>
<ol>
<li>创建了一个透明背景的渲染器。</li>
<li>生成了点数据并计算了其边界。</li>
<li>创建了一个立方体源和一个不可见的立方体演员用于视觉辅助。</li>
<li>设置了矢量数据、缩放因子和颜色数据。</li>
<li>创建了一个 <code>PolyData</code> 对象,并将点数据、向量、</li>
</ol>
<p>源码</p>
<pre><code class="language-javascript">/**
* 添加矢量图
* @param {*} data
* @param {*} renderer
*/
async addvector(data, renderWindow, modeView, options = {}) {
const renderer = vtkRenderer.newInstance();
// 将渲染器的背景色设置为透明
renderer.setBackground(0, 0, 0, 0); // RGBA 中的 A 通道设置为 0 表示完全透明
// 创建流场数据 点坐标
const points = vtkPoints.newInstance();
const { location, vecArr } = data;
points.setData(new Float32Array(location));
const actorHidden = vtkActor.newInstance();
// 如果返回了图片的世界坐标系
let gridBounds = points.getBounds();
const xLength = gridBounds[1] - gridBounds[0];
const yLength = gridBounds[3] - gridBounds[2];
const zLength = gridBounds[5] - gridBounds[4];
// 创建一个 CubeSource 作为立方体的数据源
const cubeSource = vtkCubeSource.newInstance({
xLength: xLength, // 立方体在 X 轴上的长度
yLength: yLength, // 立方体在 Y 轴上的长度
zLength: zLength // 立方体在 Z 轴上的长度
});
// 创建一个 Mapper
const mapperHidden = vtkMapper.newInstance();
mapperHidden.setInputConnection(cubeSource.getOutputPort());
// 创建一个属性对象并设置透明度
const propertyHidden = actorHidden.getProperty();
propertyHidden.setOpacity(0); // 设置透明度为 0
actorHidden.setMapper(mapperHidden);
actorHidden.setPosition(gridBounds[0] + xLength / 2, gridBounds[2] + yLength / 2, gridBounds[4] + zLength / 2);
console.debug('原始图片网格大小', gridBounds, actorHidden.getBounds());
// 这是向量数据结构
const vectors = vtkDataArray.newInstance({
numberOfComponents: 3, // 数据中的组件数量(例如,对于3D点,这将是x, y, z)
values: new Float32Array(transVerPoints(data.vector, vecArr, data, modeView, config, data.median)),
type: 'Float32' // 指定数据类型
});
// 缩放
const scales = vtkDataArray.newInstance({
numberOfComponents: 1, // size
name: 'scales',
type: 'float32', // 指定数据类型
values: new Float32Array(transVerScale(data.length, data.arrow_length_factor, vecArr, config, data.median))
});
const { arrData, min, max, colorMin, colorMax } = growColorArr(data, vecArr, config, true);
// 颜色
const colors = vtkDataArray.newInstance({
numberOfComponents: 4, // r, g, b a
name: 'colorMode',
type: 'uint8',
values: new Uint8Array(arrData)
});
// 创建vtkPolyData
const polyData = vtkPolyData.newInstance();
polyData.setPoints(points);
const pointerD = polyData.getPointData();
pointerD.setVectors(vectors);
pointerD.addArray(scales);
// 颜色设置必须通过setScalars来设置
pointerD.setScalars(colors);
// 创建箭头源
const arrowSource = vtkArrowSource.newInstance();
arrowSource.setTipResolution(modeView === '2D' ? 2 : 6);
arrowSource.setTipRadius(0.05 * config.arrowSize / 10);
arrowSource.setTipLength(0.1 * config.arrowSize / 10);
arrowSource.setShaftRadius(0.005 * config.strokeWidth / 10);
arrowSource.setShaftResolution(modeView === '2D' ? 12 : 12);
const appendPD = arrowSource.getOutputData();
const appendPts = appendPD.getPoints().getData();
const vtkMatrixBuilder = window.vtk.Common.Core.vtkMatrixBuilder;
// Center the arrow about [0, 0, 0]
const allLength = 0.05 * config.arrowSize / 10 + 0.1 * config.arrowSize / 10 + 0.005 * config.strokeWidth / 10;
vtkMatrixBuilder.buildFromRadian().translate(0 + allLength, 0.0, 0.0).apply(appendPts);
// 创建 Glyph3DMapper
const glyph3DMapper = vtkGlyph3DMapper.newInstance({
scaleArray: 'scales',
colorByArrayName: 'colors'
});
glyph3DMapper.setInputData(polyData);
glyph3DMapper.setSourceConnection(arrowSource.getOutputPort());
const actor = vtkActor.newInstance();
actor.setMapper(glyph3DMapper);
// 添加演员到渲染器并渲染
renderer.addActor(actor);
renderer.setLayer(4);</code></pre>