/******************************************************************************** * * * This file is part of IfcOpenShell. * * * * IfcOpenShell is free software: you can redistribute it and/or modify * * it under the terms of the Lesser GNU General Public License as published by * * the Free Software Foundation, either version 3.0 of the License, or * * (at your option) any later version. * * * * IfcOpenShell is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * Lesser GNU General Public License for more details. * * * * You should have received a copy of the Lesser GNU General Public License * * along with this program. If not, see . * * * ********************************************************************************/ // v13 layout (all multi-byte fields native-endian; endianness marker in header). // // SidecarHeader (12 bytes) // // uint32_t num_vertex_bytes // uint8_t[] vertex data (12 B/vertex: pos u16x3 + oct-normal i8x2 + rgba8) // uint32_t num_indices // uint32_t[] index data (mesh-local indices; base_vertex applied at draw time) // // uint32_t num_meshes // MeshInfo[num_meshes] // // uint32_t num_instances // InstanceCpu[num_instances] (already sorted by mesh_id; v13 layout) // // uint32_t has_coordinate_operation (v11+) // double[16] coordinate_operation_meters (v11+; column-major) // double project_length_to_meters (v11+) // double map_unit_to_meters (v11+) // // uint32_t num_elements // PackedElementInfo[num_elements] // uint32_t string_table_bytes // char[string_table_bytes] #include "SidecarCache.h" #include #include struct SidecarHeader { uint32_t magic; uint32_t version; uint32_t endian; }; // foo.ifc -> foo.ifcview // foo.ifcdb/ -> foo.ifcview // foo.ifcdb -> foo.ifcview // foo (no ext) -> foo.ifcview static std::string sidecarPath(const std::string& ifc_path) { std::string p = ifc_path; while (!p.empty() && (p.back() == '/' || p.back() == '\\')) p.pop_back(); auto slash = p.find_last_of("/\\"); auto dot = p.find_last_of('.'); std::string stem = (dot != std::string::npos && (slash == std::string::npos || dot > slash)) ? p.substr(0, dot) : p; return stem + ".ifcview"; } template static bool writeVec(FILE* f, const std::vector& v) { uint32_t n = static_cast(v.size()); if (fwrite(&n, 4, 1, f) != 1) return false; if (n > 0 && fwrite(v.data(), sizeof(T), n, f) != n) return false; return true; } template static bool readVec(FILE* f, std::vector& v) { uint32_t n; if (fread(&n, 4, 1, f) != 1) return false; v.resize(n); if (n > 0 && fread(v.data(), sizeof(T), n, f) != n) return false; return true; } bool writeSidecar(const std::string& ifc_path, const SidecarData& data) { std::string path = sidecarPath(ifc_path); FILE* f = fopen(path.c_str(), "wb"); if (!f) return false; SidecarHeader hdr = { SIDECAR_MAGIC, SIDECAR_VERSION, SIDECAR_ENDIAN }; if (fwrite(&hdr, sizeof(hdr), 1, f) != 1) { fclose(f); return false; } if (!writeVec(f, data.vertices)) { fclose(f); return false; } if (!writeVec(f, data.indices)) { fclose(f); return false; } if (!writeVec(f, data.meshes)) { fclose(f); return false; } if (!writeVec(f, data.instances)) { fclose(f); return false; } // v11 georef block (148 B). if (fwrite(&data.has_coordinate_operation, 4, 1, f) != 1) { fclose(f); return false; } if (fwrite(data.coordinate_operation_meters, sizeof(double), 16, f) != 16) { fclose(f); return false; } if (fwrite(&data.project_length_to_meters, sizeof(double), 1, f) != 1) { fclose(f); return false; } if (fwrite(&data.map_unit_to_meters, sizeof(double), 1, f) != 1) { fclose(f); return false; } if (!writeVec(f, data.elements)) { fclose(f); return false; } uint32_t stbl_len = static_cast(data.string_table.size()); if (fwrite(&stbl_len, 4, 1, f) != 1) { fclose(f); return false; } if (stbl_len > 0 && fwrite(data.string_table.data(), 1, stbl_len, f) != stbl_len) { fclose(f); return false; } fclose(f); return true; } std::optional readSidecar(const std::string& ifc_path) { std::string path = sidecarPath(ifc_path); FILE* f = fopen(path.c_str(), "rb"); if (!f) return std::nullopt; auto fail = [&]() -> std::optional { fclose(f); return std::nullopt; }; SidecarHeader hdr; if (fread(&hdr, sizeof(hdr), 1, f) != 1) return fail(); if (hdr.magic != SIDECAR_MAGIC || hdr.version != SIDECAR_VERSION || hdr.endian != SIDECAR_ENDIAN) return fail(); SidecarData data; if (!readVec(f, data.vertices)) return fail(); if (!readVec(f, data.indices)) return fail(); if (!readVec(f, data.meshes)) return fail(); if (!readVec(f, data.instances)) return fail(); // v11 georef block. if (fread(&data.has_coordinate_operation, 4, 1, f) != 1) return fail(); if (fread(data.coordinate_operation_meters, sizeof(double), 16, f) != 16) return fail(); if (fread(&data.project_length_to_meters, sizeof(double), 1, f) != 1) return fail(); if (fread(&data.map_unit_to_meters, sizeof(double), 1, f) != 1) return fail(); if (!readVec(f, data.elements)) return fail(); uint32_t stbl_len; if (fread(&stbl_len, 4, 1, f) != 1) return fail(); data.string_table.resize(stbl_len); if (stbl_len > 0 && fread(data.string_table.data(), 1, stbl_len, f) != stbl_len) return fail(); fclose(f); return data; }