#include #include #include #include #include #include #include "lut.hpp" #include "common_structure.hpp" #include "implicit_arrangement.h" /* POD data of ia_data */ std::vector ia_vertices{}; std::vector> ia_face_vertices{}; std::vector ia_faces_ptr{}; std::vector ia_face_vertices_count{}; std::vector ia_supporting_planes{}; std::vector ia_positive_cells{}; std::vector ia_negative_cells{}; std::vector> ia_cell_faces{}; std::vector ia_cells_ptr{}; std::vector ia_cell_faces_count{}; std::vector ia_num_vertices{}; std::vector ia_num_faces{}; std::vector ia_num_cells{}; /* global variables */ std::vector ia_data{}; std::vector ia_indices{}; inline void from_json(const nlohmann::json& j, Point3D& p) { p.i0 = j[0].get(); p.i1 = j[1].get(); p.i2 = j[2].get(); } inline void parse_ia_into_pods(const nlohmann::json& j) { const auto& vertices = j[0].get>(); ia_num_vertices.emplace_back(vertices.size()); ia_vertices.insert(ia_vertices.end(), vertices.begin(), vertices.end()); assert(ia_num_vertices.back() > 0); ia_num_faces.emplace_back(j[1].size()); for (const auto& face_entry : j[1]) { ia_face_vertices_count.emplace_back(face_entry[0].size()); ia_face_vertices.emplace_back(face_entry[0].get>()); ia_faces_ptr.emplace_back(ia_face_vertices.back().data()); ia_supporting_planes.emplace_back(face_entry[1].get()); ia_positive_cells.emplace_back(face_entry[2].get()); ia_negative_cells.emplace_back(face_entry[3].get()); } assert(ia_num_faces.back() > 0); ia_num_cells.emplace_back(j[2].size()); for (const auto& cell_entry : j[2]) { ia_cell_faces_count.emplace_back(cell_entry.size()); ia_cell_faces.emplace_back(cell_entry.get>()); ia_cells_ptr.emplace_back(ia_cell_faces.back().data()); } assert(ia_num_cells.back() > 0); } EXTERN_C API bool load_lut() { if (!ia_data.empty() && !ia_indices.empty()) return true; auto deserialize_ia = [](const nlohmann::json& json) { auto& ia = ia_data.emplace_back(Arrangement3D{}); const auto& vertices = json[0].get>(); }; auto t0 = tbb::tick_count::now(); std::ifstream file("ia_lut.msgpack", std::ios::in | std::ios::binary); if (!file.is_open()) { std::cerr << "Error: IA LUT file does not exist!" << std::endl; return false; } std::vector msgpack(std::istreambuf_iterator(file), {}); nlohmann::json json = nlohmann::json::from_msgpack(msgpack); file.close(); ia_indices = json["start_index"].get>(); /* a tet has at least 4 vertices and 4 faces, and we'll use this assumption to reverse space for POD data */ ia_vertices.reserve(json["data"].size() * 4); ia_face_vertices.reserve(json["data"].size() * 4 * 3); // 3 vertices per triangle face ia_faces_ptr.reserve(json["data"].size() * 4); ia_face_vertices_count.reserve(json["data"].size() * 4); ia_supporting_planes.reserve(json["data"].size() * 4); ia_positive_cells.reserve(json["data"].size() * 4); ia_negative_cells.reserve(json["data"].size() * 4); ia_cell_faces.reserve(json["data"].size() * 4); ia_cells_ptr.reserve(json["data"].size()); ia_cell_faces_count.reserve(json["data"].size()); ia_num_vertices.reserve(json["data"].size()); ia_num_faces.reserve(json["data"].size()); ia_num_cells.reserve(json["data"].size()); // HINT: change of capcity may happen here. for (const auto& entry : json["data"]) parse_ia_into_pods(entry); ia_data.resize(json["data"].size()); uint32_t vertices_offset{}, faces_offset{}, cells_offset{}; for (size_t i = 0; i < json["data"].size(); i++) { auto& ia = ia_data[i]; ia.num_vertices = ia_num_vertices[i]; ia.points = ia_vertices.data() + vertices_offset; ia.num_faces = ia_num_faces[i]; ia.vertices = ia_faces_ptr.data() + faces_offset; ia.face_vertices_count = ia_face_vertices_count.data() + faces_offset; ia.supporting_planes = ia_supporting_planes.data() + faces_offset; ia.positive_cells = ia_positive_cells.data() + faces_offset; ia.negative_cells = ia_negative_cells.data() + faces_offset; ia.num_cells = ia_num_cells[i]; ia.faces = ia_cells_ptr.data() + cells_offset; ia.cell_faces_count = ia_cell_faces_count.data() + cells_offset; ia.num_unique_planes = 0; } auto t1 = tbb::tick_count::now(); std::cout << "Loading LUT took " << std::fixed << std::setprecision(10) << (t1 - t0).seconds() << " seconds." << std::endl; return true; } uint32_t ia_compute_outer_index(const Plane3D& p0) { // Plane must not intersect tet at vertices. if (p0.f0 == 0 || p0.f1 == 0 || p0.f2 == 0 || p0.f3 == 0) return INVALID_INDEX; // To reuse the 2 plane lookup table, we assume the second plane is negative // on all tet vertices. size_t index = 0; if (p0.f0 > 0) index |= 1; if (p0.f1 > 0) index |= 4; if (p0.f2 > 0) index |= 16; if (p0.f3 > 0) index |= 64; return index; } uint32_t ia_compute_outer_index(const Plane3D& p0, const Plane3D& p1) { // Plane must not intersect tet at vertices. if (p0.f0 == 0 || p0.f1 == 0 || p0.f2 == 0 || p0.f3 == 0) return INVALID_INDEX; if (p1.f0 == 0 || p1.f1 == 0 || p1.f2 == 0 || p1.f3 == 0) return INVALID_INDEX; size_t index = 0; if (p0.f0 > 0) index |= 1; if (p1.f0 > 0) index |= 2; if (p0.f1 > 0) index |= 4; if (p1.f1 > 0) index |= 8; if (p0.f2 > 0) index |= 16; if (p1.f2 > 0) index |= 32; if (p0.f3 > 0) index |= 64; if (p1.f3 > 0) index |= 128; return index; } uint32_t ia_compute_inner_index(uint32_t outer_index, const Plane3D& p0, const Plane3D& p1) { std::bitset<2> v0 = outer_index & 3; std::bitset<2> v1 = (outer_index >> 2) & 3; std::bitset<2> v2 = (outer_index >> 4) & 3; std::bitset<2> v3 = (outer_index >> 6) & 3; size_t index = 0; size_t edge_count = 0; std::array pp0, pp1; auto add_edge = [&](size_t i, size_t j) -> bool { pp0 = {(&p0.f0)[i], (&p0.f0)[j]}; pp1 = {(&p1.f0)[i], (&p1.f0)[j]}; const auto s = orient1d(pp0.data(), pp1.data()); if (s == ORIENTATION_ZERO || s == ORIENTATION_INVALID) return false; if (s > 0) index |= (1 << edge_count); edge_count++; return true; }; if ((v0 ^ v1).all()) if (!add_edge(0, 1)) return INVALID_INDEX; if ((v0 ^ v2).all()) if (!add_edge(0, 2)) return INVALID_INDEX; if ((v0 ^ v3).all()) if (!add_edge(0, 3)) return INVALID_INDEX; if ((v1 ^ v2).all()) if (!add_edge(1, 2)) return INVALID_INDEX; if ((v1 ^ v3).all()) if (!add_edge(1, 3)) return INVALID_INDEX; if ((v2 ^ v3).all()) if (!add_edge(2, 3)) return INVALID_INDEX; if (edge_count == 4) { assert(index != 6 && index != 9); // Impossible cases. if (index < 6) { } else if (index < 9) { index -= 1; // Skipping INVALID_INDEX case with index 6. } else { index -= 2; // Skipping INVALID_INDEX case with index 6 and 9. } } return index; }