更改 vtk 数据文件版本

Change vtk DataFile version

当我使用 vtkPolyDataWriter 创建 vtk 遗留文件时,我获得了具有连接性和偏移量的新版本数据文件 (5.1)。是否可以更改它并获得 'legacy' 旧格式?

gmsh 似乎无法读取新格式版本的 vtk 文件..

(我使用 python 3.8 和 vtk 包版本 9.0.1)

不,您不能以编程方式选择版本。使用旧格式编写的唯一方法是将 vtk 降级到所需版本。

对于那些感兴趣的人,我 post 用于将新格式转换为旧格式的代码。它适用于多数据和非结构化网格 vtk 网格。

import math
import re


def convert_to_old_format(mesh_fname: str, save_fname: str, copy_lines: bool = False):
    conv = Converter(mesh_fname, save_fname, copy_lines)
    conv.read()
    conv.replace()
    conv.write()


def change_vtk_version(filename: str, v: float = 5.1):
    with open(filename, "r") as f:
        x = f.read()
    x = re.sub(r"(# vtk DataFile Version) (.+)", f"\1 {v}", x)
    with open(filename, "w") as f:
        f.write(x)


class Converter:
    def __init__(self, inp, out=None, copy_lines=False):
        if out is None:
            out = inp
        self.inp = inp
        self.out = out
        self.copy_lines = copy_lines  # if line cells should be copied
        self.original = None
        self.lines = None
        self.polys = None
        self.cells = None

    def read(self):
        with open(self.inp, "r") as f:
            self.original = f.read().split("\n")
        lines_original = list(map(lambda x: x.strip().split(), self.original))

        for i, l in enumerate(self.original):
            if "LINES" in l:
                self.lines = NewContent("LINES", lines_original, i)
            elif "POLYGONS" in l:
                self.polys = NewContent("POLYGONS", lines_original, i)
            elif "CELLS" in l:
                self.cells = NewContent("CELLS", lines_original, i)

    def replace(self):
        if self.polys is not None:
            self.original = self.polys.replace(self.original)
        if self.cells is not None:
            self.original = self.cells.replace(self.original)
        if self.lines is not None:
            self.original = self.lines.replace(self.original, replace=self.copy_lines)

    def write(self):
        with open(self.out, "w") as f:
            f.write("\n".join(self.original))

        change_vtk_version(self.out, 4.2)


class NewContent:
    def __init__(self, kw, content, ln):
        self.kw = kw
        self.ln = ln
        self.name = content[ln][0]
        self.no = int(content[ln][1])
        self.nc = int(content[ln][2])

        flat_list = [item for line in content[ln + 2 :] for item in line]
        flat_list = list(filter("".__ne__, flat_list))

        self.offsets = list(map(int, flat_list[0 : self.no]))
        self.connectivity = list(
            map(int, flat_list[self.no + 2 : self.no + 2 + self.nc])
        )

    @property
    def remove(self):
        return self.ln, self.ln + math.ceil(self.no / 9) + math.ceil(self.nc / 9) + 3

    def replace(self, lines, replace=True):
        nb_cells = self.no - 1
        new_content = []
        if replace:
            new_content = [f"{self.kw} {nb_cells} {nb_cells + self.nc}"]
            for i in range(nb_cells):
                nb_points = self.offsets[i + 1] - self.offsets[i]
                ids = self.connectivity[self.offsets[i] : self.offsets[i + 1]]
                new_content.append(f"{nb_points} {' '.join(map(str, ids))}")

        lines_to_keep = lines
        a, b = self.remove
        del lines_to_keep[a:b]
        lines_to_keep[a:a] = new_content
        lines_to_keep = list(filter("".__ne__, lines_to_keep))
        return lines_to_keep


if __name__ == "__main__":
    convert_to_old_format("mesh.vtk", "mesh_old_format.vtk")

    # change_vtk_version("mesh.vtk", 8.6)