第 9 阶段练习与参考答案
先按教程目录阅读第 28–30 章并完成三个页面的观察。以下练习与章节正文分开;参考答案给出判断路径,截图颜色可能因设备和浏览器略有差异。
练习 1:画出两个管线
请分别画出第 28 章表面页与第 29 章体页的对象连接。指出哪一步产生 vtkPolyData,哪两条显示管线共享 vtkImageData。
参考答案
表面页为 VTP → vtkXMLPolyDataReader → vtkPolyData → vtkMapper(+LookupTable) → vtkActor → Renderer。体页为 index.json + Density → vtkHttpDataSetReader → vtkImageData,之后分成 vtkImageMapper → vtkImageSlice 与 vtkVolumeMapper → vtkVolume,分别加入两个 Renderer。第 29 章没有先把体转成 PolyData;第 30 章的 vtkImageMarchingCubes 才把 ImageData 的等值面提取为 PolyData。
练习 2:数据范围与颜色范围
在表面页选 Heat,记录原始范围;关闭自动范围,把映射最小值设为 10。哪些值应变化,哪些不应变化?如果关闭标量着色,Actor 用哪个颜色来源?
参考答案
Heat.getRange() 的原始范围约 [20.00,95.61] 不变;Mapper 与 LookupTable 的显示范围改为 [10,95.61],色带所对应的数值也变化。关闭 scalar visibility 后不再由 Point Data 标量给表面着色,显示主要受 Actor Property 的单色设置及光照影响。
练习 3:数组关联方式
导入一个只含 Cell Data 标量、没有单分量 Point Data 的 VTP,本查看器为什么不会列出那个字段?如果业务要求对它着色,应改哪些地方?
参考答案
示例只从 getPointData().getArrays() 筛选候选,并把 Mapper 设为 setScalarModeToUsePointFieldData(),因此不会把 Cell Data 当点属性使用。需要从 getCellData() 建列表,选择对应的 Cell Field Data 模式,并核对元组数与单元数。点标量和单元标量的颜色插值语义不同,图例应说明关联方式。
练习 4:同一体数据的两种参数
第 29 章中把 K 从 16 改成 22,再把不透明度起始值从 45 改成 80。分别是哪一个对象被修改?Density 的值和数组长度会变化吗?
参考答案
前者调用 vtkImageMapper.setSlice(22),只改变左侧选取的平面;以本例单位 spacing 和原点计算,z 从 0 到 6。后者重建 vtkPiecewiseFunction 的控制点,影响右侧 vtkVolumeProperty 使用的透明度映射。二者都不修改 Density 的 Float32 数值或 32768 个元组,也不重新下载文件。
练习 5:采样与内存
第 29 章把体渲染的沿射线采样间距从 1 增到 2,会不会让 ImageData 的 32³ 个值变成 16³?如果要真正降低源数据分辨率,需要做什么?
参考答案
不会。setSampleDistance(2) 改 Mapper 沿视线的采样步距,源数据仍是 32³、131072 字节。真正降分辨率需要生成或读取新的较低分辨率 ImageData,并正确更新 extent、spacing、origin、方向与属性数组;这样可能丢失小结构。绘制采样减少与数据降采样是不同层面的性能策略。
练习 6:用 Network 验证按需加载
刷新第 30 章页面,依次点击两个加载按钮,最后在下拉框来回切换。写出数据文件请求的预期顺序,并解释为何初始列表里出现 Contrast 不等于已下载。
参考答案
预期请求依次是 index.json、data/Density、data/Contrast。下拉框只选已下载字段,不再请求数组。清单记载数组名称、类型、范围与外部引用;reader.getArrays() 因而能列出名字,但 image.getPointData().getArrayByName('Contrast') 在下载前为空。缓存可能影响传输量显示,是否发起请求仍以 Network 面板为准。
练习 7:等值面没有更新
第 30 章中两个数组都已下载,切换下拉框后状态文字变化但几何没变。列出至少四个应检查的点,按从数据到画面的顺序排列。
参考答案
先检查目标数组是否真的在 image.getPointData() 且有 32768 个值;再检查 getScalars().getName() 是否已被 setActiveScalars(name) 改变;检查阈值是否位于该数组有效范围并是否调用 iso.getOutputData() 触发过滤;最后检查 Mapper 是否连接 iso.getOutputPort()、Actor 是否可见、Renderer 是否重新绘制及相机裁剪范围。若两个字段本身在该阈值下恰好形状相近,应比较输出点数、单元数或取不同阈值,不能只凭肉眼断言未更新。
练习 8:把教学数据换成真实数据
计划导入一份医学影像或仿真体场。为了让第 29 章的图像可解释,除了“能读入”外,应先确认哪几项元数据与显示规则?
参考答案
确认标量代表的量、单位与有效范围;origin、spacing、extent 和方向矩阵;Point Data 与 Cell Data 关联;缺失或背景值;所需窗宽窗位、颜色和不透明度函数的业务依据。还要核对隐私与使用许可等项目要求。示例中的 0–220 控制点、单位 spacing 与固定相机只为教学设置,不能直接赋予真实数据的诊断或物理意义。