JT文件阅读器C++开发疑问:格式解析与数据读取问题
JT文件阅读器开发疑问与代码求助
我想用C++实现一个JT文件阅读器,仅读取其中的顶点与面数据。参考《JT File Format Reference》文档,编写了如下极简示例代码:
#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); } // 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; // if it is of type "Shape" if (segment_header.segment_type == 6) { 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 } } } }
测试使用的是NX_TurboCharger归档中的145275T010_001_MODEL_SOLIDS.jt文件。
根据文档,我理解的JT文件格式结构如下:
. ├── Segment Header | └── [...] └── Data ├── Logical Element Header | ├── ElementLength : I32 | └── ElementHeader | ├── ObjectType Id : GUID | ├── ObjectBase Type : UChar | └── ObjectID : I32 └── Object Data ├── Base Node Type | ├── VersionNumber : I16 | ├── NodeFlags : U32 | ├── AttributeCount | └── Attributes ├── Base Shape Data | ├── VersionNumber : I16 | └── [...]
现存在以下技术疑问:
- 文档中Logical Element Header被描述为Element Length + Object Data,这看起来像是递归定义,我认为应为Element Length + Element Header,是否正确?
- Base Node Type与Base Shape Data段均包含VersionNumber属性,这是否符合规范?我的断言(Base Shape Data的VersionNumber应为1)执行失败,原因是什么?
- 当我尝试继续读取Base Shape Data的边界框与面积数据时,得到的都是无意义值,是否遗漏了某些读取步骤?
内容的提问来源于stack exchange,提问作者Vertexwahn
相关产品推荐
相关产品推荐

