You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从VTK文件中提取六面体网格的外表面?

提取六面体网格中所有六面体的独立外表面

问题描述

我有一个由六面体组成的立方体模型,希望获取所有六面体的外表面(而非整体大立方体的表面),但未能实现。我认为可行方法是遍历所有面,筛选出无相邻面的面,但不确定是否正确。我的代码基于Python,同时欢迎C/C++实现方案。

初始尝试代码

# Read the source file.
reader = vtk.vtkXMLUnstructuredGridReader()
reader.SetFileName(file_name)
reader.Update()

output = reader.GetOutput()
points = output.GetPoints()

# get faces
faces = []
for i in range(output.GetNumberOfCells()):
    cell = output.GetCell(i)
    #print(type(cell)) hexaedron
    cell_points_ids = []
    for face_index in range(cell.GetNumberOfFaces()):
        a=vtk.reference([0,0,0,0])
        cell.GetFaceToAdjacentFaces(face_index,a)

更新尝试1

gf = vtk.vtkGeometryFilter()
gf.SetInputConnection(reader.GetOutputPort())
gf.Update()
polydata_output = gf.GetOutput()

print(polydata_output.GetNumberOfCells()) # 291024
print(output.GetNumberOfCells()) #48504 

更新尝试2

sc = vtk.vtkStaticCleanUnstructuredGrid()
sc.Update()
sc.SetInputData(output)

sc.Update()
gf = vtk.vtkGeometryFilter()
sc_output = sc.GetOutput()
gf.SetInputData(sc_output)
#gf.SetInputConnection(reader.GetOutputPort())
gf.Update()
polydata_output = gf.GetOutput()

print(polydata_output.GetNumberOfCells()) # 19120
print(output.GetNumberOfCells()) #48504 

内部立方体结构


解决方案

你的思路是正确的:遍历每个六面体的所有面,筛选出没有相邻六面体的面,这些就是单个六面体的外表面。vtkGeometryFilter默认提取的是整个网格的外表面(仅暴露在整个模型外部的面),无法满足需求,所以需要手动判断每个面的相邻情况。

Python 实现

import vtk

def extract_hexahedron_surfaces(file_name):
    # 读取网格数据
    reader = vtk.vtkXMLUnstructuredGridReader()
    reader.SetFileName(file_name)
    reader.Update()
    grid = reader.GetOutput()

    # 创建存储结果的PolyData
    result_polydata = vtk.vtkPolyData()
    points = vtk.vtkPoints()
    polygons = vtk.vtkCellArray()

    # 遍历每个六面体单元
    for cell_idx in range(grid.GetNumberOfCells()):
        cell = grid.GetCell(cell_idx)
        if cell.GetCellType() != vtk.VTK_HEXAHEDRON:
            continue  # 只处理六面体

        # 遍历六面体的每个面(共6个)
        for face_idx in range(cell.GetNumberOfFaces()):
            # 获取当前面的相邻单元信息
            adjacent_cells = vtk.reference([-1, -1, -1, -1])
            cell.GetFaceToAdjacentFaces(face_idx, adjacent_cells)
            
            # 判断是否有相邻单元:如果相邻单元ID都是-1,说明该面没有共享
            has_adjacent = False
            for adj_cell in adjacent_cells:
                if adj_cell != -1:
                    has_adjacent = True
                    break
            
            if not has_adjacent:
                # 获取当前面的点ID
                face = cell.GetFace(face_idx)
                point_ids = []
                for pt_idx in range(face.GetNumberOfPoints()):
                    global_pt_id = cell.GetPointId(face.GetPointId(pt_idx))
                    point_ids.append(global_pt_id)
                    # 添加点到结果
                    pt = grid.GetPoint(global_pt_id)
                    points.InsertNextPoint(pt)
                
                # 添加面到结果
                polygons.InsertNextCell(len(point_ids), point_ids)

    # 设置PolyData的点和面
    result_polydata.SetPoints(points)
    result_polydata.SetPolys(polygons)

    # 清理重复的点和面
    cleaner = vtk.vtkCleanPolyData()
    cleaner.SetInputData(result_polydata)
    cleaner.Update()
    cleaned_polydata = cleaner.GetOutput()

    # 保存结果
    writer = vtk.vtkXMLPolyDataWriter()
    writer.SetFileName("hexahedron_surfaces.vtp")
    writer.SetInputData(cleaned_polydata)
    writer.Write()

    return cleaned_polydata

# 调用示例
extract_hexahedron_surfaces("your_input_file.vtu")

C++ 实现

#include <vtkXMLUnstructuredGridReader.h>
#include <vtkPolyData.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkHexahedron.h>
#include <vtkCleanPolyData.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkSmartPointer.h>

vtkSmartPointer<vtkPolyData> ExtractHexahedronSurfaces(const std::string& fileName)
{
    // 读取网格数据
    auto reader = vtkSmartPointer<vtkXMLUnstructuredGridReader>::New();
    reader->SetFileName(fileName.c_str());
    reader->Update();
    auto grid = reader->GetOutput();

    // 创建结果PolyData
    auto resultPolydata = vtkSmartPointer<vtkPolyData>::New();
    auto points = vtkSmartPointer<vtkPoints>::New();
    auto polygons = vtkSmartPointer<vtkCellArray>::New();

    // 遍历每个六面体单元
    for (vtkIdType cellIdx = 0; cellIdx < grid->GetNumberOfCells(); ++cellIdx)
    {
        auto cell = vtkHexahedron::SafeDownCast(grid->GetCell(cellIdx));
        if (!cell)
            continue; // 跳过非六面体单元

        // 遍历六面体的每个面
        for (int faceIdx = 0; faceIdx < cell->GetNumberOfFaces(); ++faceIdx)
        {
            // 获取相邻单元ID
            vtkIdType adjacentCells[4];
            cell->GetFaceToAdjacentFaces(faceIdx, adjacentCells);

            // 判断是否有相邻单元
            bool hasAdjacent = false;
            for (int i = 0; i < 4; ++i)
            {
                if (adjacentCells[i] != -1)
                {
                    hasAdjacent = true;
                    break;
                }
            }

            if (!hasAdjacent)
            {
                // 获取当前面的点
                auto face = cell->GetFace(faceIdx);
                vtkIdType pointIds[4];
                face->GetPointIds()->GetIds(pointIds);

                // 转换为全局点ID并添加到点集合
                vtkIdType globalPointIds[4];
                for (int i = 0; i < 4; ++i)
                {
                    globalPointIds[i] = cell->GetPointId(pointIds[i]);
                    double pt[3];
                    grid->GetPoint(globalPointIds[i], pt);
                    points->InsertNextPoint(pt);
                }

                // 添加面到单元集合
                polygons->InsertNextCell(4, globalPointIds);
            }
        }
    }

    // 设置PolyData的数据
    resultPolydata->SetPoints(points);
    resultPolydata->SetPolys(polygons);

    // 清理重复点和面
    auto cleaner = vtkSmartPointer<vtkCleanPolyData>::New();
    cleaner->SetInputData(resultPolydata);
    cleaner->Update();

    // 保存结果
    auto writer = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
    writer->SetFileName("hexahedron_surfaces.vtp");
    writer->SetInputData(cleaner->GetOutput());
    writer->Write();

    return cleaner->GetOutput();
}

// 调用示例
int main()
{
    ExtractHexahedronSurfaces("your_input_file.vtu");
    return 0;
}

关键说明

  1. 相邻面判断:通过GetFaceToAdjacentFaces获取当前面的相邻单元ID,若所有ID都是-1,说明该面未与其他六面体共享,属于单个六面体的外表面。
  2. 数据去重:使用vtkCleanPolyData清理重复的点和面,避免结果中出现冗余数据。
  3. 与vtkGeometryFilter的区别:vtkGeometryFilter仅提取整个网格的外表面,而上述代码提取的是每个六面体自身未被共享的面,包括模型内部六面体的暴露面。

内容的提问来源于stack exchange,提问作者manuersuper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 14:30:59