如何读取JT文件?

问题描述 投票:0回答:1

我想用C++实现一个JT文件阅读器。 JT 文件格式参考 记录了文件格式。我想出了以下“最小”示例(注意:我只对顶点和面数据(如果可用)感兴趣):

#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>

struct GUID {
    uint32_t a;
    uint16_t b;
    uint16_t c;
    uint64_t d;
};

struct Header {
    char version[80];
    uint8_t byte_order;
    int32_t reserved_field;
    int32_t toc_offset;
    GUID guid;
};

struct TocEntry {
    GUID segment_id;
    int32_t segment_offset;
    int32_t segment_length;
    uint32_t segment_attributes;
};

struct SegmentHeader {
    GUID segment_id;
    int32_t segment_type;
    int32_t segment_length;
    uint32_t segment_attributes;
};

struct ElementHeader {
    GUID object_type_id;
    char8_t object_base_type;
    uint32_t object_id;
};

struct BaseNodeData {
    int16_t version_number;
    uint32_t node_flags;
    int32_t attribute_count;
    std::vector<int32_t> attribute_object_ids;
};

struct CoordF32 {
    float x, y, z;
};

struct BBoxF32 {
    CoordF32 min_corner;
    CoordF32 max_corner;
};

struct BaseShapeData {
    int16_t version_number;
    BBoxF32 reserved_field;
    BBoxF32 untransformed_bbox;
    float area;
};

void read_guid(std::ifstream &file, GUID &guid) {
    unsigned char guid_bytes[16];
    file.read(reinterpret_cast<char *>(guid_bytes), sizeof(guid_bytes));

    guid.a = (guid_bytes[0] << 24) | (guid_bytes[1] << 16) | (guid_bytes[2] << 8) | guid_bytes[3];
    guid.b = (guid_bytes[4] << 8) | guid_bytes[5];
    guid.c = (guid_bytes[6] << 8) | guid_bytes[7];
    guid.d = (static_cast<uint64_t>(guid_bytes[8]) << 56) |
             (static_cast<uint64_t>(guid_bytes[9]) << 48) |
             (static_cast<uint64_t>(guid_bytes[10]) << 40) |
             (static_cast<uint64_t>(guid_bytes[11]) << 32) |
             (static_cast<uint64_t>(guid_bytes[12]) << 24) |
             (static_cast<uint64_t>(guid_bytes[13]) << 16) |
             (static_cast<uint64_t>(guid_bytes[14]) << 8) |
             static_cast<uint64_t>(guid_bytes[15]);
}

void read_header(std::ifstream &file, Header &header) {
    file.read(reinterpret_cast<char *>(&header.version), sizeof(char) * 80);
    file.read(reinterpret_cast<char *>(&header.byte_order), sizeof(uint8_t) * 1);
    file.read(reinterpret_cast<char *>(&header.reserved_field), sizeof(int32_t) * 1);
    file.read(reinterpret_cast<char *>(&header.toc_offset), sizeof(header.toc_offset) * 1);

    read_guid(file, header.guid);
}

int main() {
    std::string filename = "jt/data/145275T010_001_MODEL_SOLIDS.jt";
    std::ifstream file(filename.c_str());
    if (!file.is_open()) {
        throw std::runtime_error("could not load file");
    }

    // Read header
    Header header{};
    read_header(file, header);
    // print version
    std::cout << "version: ";
    for (int i = 0; i < 75; i++) {
        std::cout << header.version[i];
    }
    std::cout << std::endl;

    // Read TOC entries
    int32_t toc_entry_count = -1;
    file.read(reinterpret_cast<char *>(&toc_entry_count), sizeof(int32_t) * 1);

    std::vector<TocEntry> toc_entries;
    toc_entries.resize(toc_entry_count);

    for (int i = 0; i < toc_entry_count; ++i) {
        TocEntry &entry = toc_entries[i];
        read_guid(file, entry.segment_id);
        file.read(reinterpret_cast<char *>(&entry.segment_offset), sizeof(int32_t) * 1);
        file.read(reinterpret_cast<char *>(&entry.segment_length), sizeof(int32_t) * 1);
        file.read(reinterpret_cast<char *>(&entry.segment_attributes), sizeof(uint32_t) * 1);
    }

    // no visit every segment
    for (const TocEntry &entry: toc_entries) {
        file.seekg(entry.segment_offset);
        SegmentHeader segment_header{};
        read_guid(file, segment_header.segment_id);
        file.read(reinterpret_cast<char *>(&segment_header.segment_type), sizeof(int32_t) * 1);
        file.read(reinterpret_cast<char *>(&segment_header.segment_length), sizeof(int32_t) * 1);
        if (segment_header.segment_type == 6) std::cout << "Shape" << std::endl;

        // it it is of type "Shape"
        if (segment_header.segment_type == 6) {
            //std::cout << "Found shape!" << std::endl;
            uint32_t element_length;
            file.read(reinterpret_cast<char *>(&element_length), sizeof(int32_t) * 1);

            ElementHeader element_type{};
            read_guid(file, element_type.object_type_id);
            file.read(reinterpret_cast<char *>(&element_type.object_base_type), sizeof(char8_t) * 1);
            file.read(reinterpret_cast<char *>(&element_type.object_id), sizeof(int32_t) * 1);

            std::cout << "Base type: " << static_cast<int>(element_type.object_base_type) << std::endl;

            if (static_cast<int>(element_type.object_base_type) == 4) {
                std::cout << "Shape LOD found" << std::endl;
                // read 7.2.1.1.1.1.1 Base Node Data

                BaseNodeData base_node_data{};
                file.read(reinterpret_cast<char *>(&base_node_data.version_number), sizeof(int16_t) * 1);
                assert(base_node_data.version_number == 0x0001);

                file.read(reinterpret_cast<char *>(&base_node_data.node_flags), sizeof(uint32_t) * 1);

                file.read(reinterpret_cast<char *>(&base_node_data.attribute_count), sizeof(int32_t) * 1);

                for(int i = 0; i < base_node_data.attribute_count; ++i) {
                    int attribute_object_id = -1;
                    file.read(reinterpret_cast<char *>(&attribute_object_id), sizeof(int32_t) * 1);
                    base_node_data.attribute_object_ids.push_back(attribute_object_id);
                }

                // see 7.2.1.1.1.10.1.1 Base Shape Data
                BaseShapeData base_shape_data{};
                file.read(reinterpret_cast<char *>(&base_shape_data.version_number), sizeof(int16_t) * 1);
                assert(base_shape_data.version_number == 0x0001);  // <--- fails
            }
        }
    }
}

可以从这里下载用于测试该程序的演示文件。我下载了存档 http://media.ugs.com/teamcenter/jtfiles/NX_TurboCharger.zip 并绑定到加载“145275T010_001_MODEL_SOLIDS.jt”文件。

从文档中,我了解到文件格式如下所示:

.
├── Segment Header
|   └── [...]
└── Data
    ├── Logical Element Header
    |   ├── ElementLength : I32
    |   └── ElementHeader
    |       ├── ObjectType Id : I32
    |       ├── ObjectBase Type : UChar
    |       └── ObjectID : I32
    └── Object Data
        ├── Base Node Type
        |   ├── VersionNumber : I16
        |   ├── NodeFlags : U32
        |   ├── AttributeCount
        |   └── Attributes   
        ├── VersionNumber : I16

问题:

  1. 在文档中,逻辑元素标头表示为元素长度+对象数据。这让我很困惑——这是一个递归定义吗?我认为这是一个错误,应该是元素长度+元素标题

  2. 似乎基本节点类型以及对象数据部分都有一个

    VersionNumber
    属性。它是否正确?由于某种原因,我的断言失败了 - 文档说 ObjectData 的版本属性应该始终是
    1

  3. 如果我尝试继续读取数据,例如

// see 7.2.1.1.1.10.1.1 Base Shape Data
BaseShapeData base_shape_data{};
file.read(reinterpret_cast<char *>(&base_shape_data.version_number), sizeof(int16_t) * 1);
//assert(base_shape_data.version_number == 0x0001);


file.read(reinterpret_cast<char *>(&base_shape_data.reserved_field.min_corner.x), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.reserved_field.min_corner.y), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.reserved_field.min_corner.z), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.reserved_field.max_corner.x), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.reserved_field.max_corner.y), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.reserved_field.max_corner.z), sizeof(float) * 1);

file.read(reinterpret_cast<char *>(&base_shape_data.untransformed_bbox.min_corner.x), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.untransformed_bbox.min_corner.y), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.untransformed_bbox.min_corner.z), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.untransformed_bbox.max_corner.x), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.untransformed_bbox.max_corner.y), sizeof(float) * 1);
file.read(reinterpret_cast<char *>(&base_shape_data.untransformed_bbox.max_corner.z), sizeof(float) * 1);

file.read(reinterpret_cast<char *>(&base_shape_data.area), sizeof(float) * 1);

std::cout << "Area: " << base_shape_data.area << std::endl;

我只得到边界框和面积值的无意义数据。也许我跳过了一些东西 - 但什么?

很高兴能澄清这些问题。

graphics 3d file-format siemens jupiter-tessellation
1个回答
0
投票

我对你的问题没有具体的答案,但我建议你看一下 JTAssistant 源代码,特别是 TKJT 部分。它可能对你有帮助。

我最近分叉了它以允许在我的环境中进行编译: https://github.com/pgibertini/oce-jt

© www.soinside.com 2019 - 2024. All rights reserved.