You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
8.8 KiB
207 lines
8.8 KiB
9 months ago
|
#include <container/hashmap.hpp>
|
||
|
#include <algorithm/glue_algorithm.hpp>
|
||
|
|
||
|
#include "ia_cut_face.hpp"
|
||
|
#include "robust_assert.hpp"
|
||
|
|
||
|
template <size_t N>
|
||
|
static inline std::array<uint32_t, 3> ia_cut_2_face_impl(IAComplex<N>& ia_complex,
|
||
|
uint32_t fid,
|
||
|
uint32_t plane_index,
|
||
|
const int8_t* orientations,
|
||
|
const std::array<uint32_t, 3>* subedges)
|
||
|
{
|
||
|
auto& edges = ia_complex.edges;
|
||
|
auto& faces = ia_complex.faces;
|
||
|
edges.reserve(edges.size() + 1);
|
||
|
faces.reserve(faces.size() + 2);
|
||
|
|
||
|
auto& f = faces[fid];
|
||
|
const size_t num_boundary_edges = f.edges.size();
|
||
|
|
||
|
small_vector_mp<uint32_t> positive_subedges{}, negative_subedges{};
|
||
|
positive_subedges.reserve(num_boundary_edges);
|
||
|
negative_subedges.reserve(num_boundary_edges);
|
||
|
|
||
|
IAEdge<N> cut_edge;
|
||
|
uint32_t cut_edge_index = INVALID_INDEX;
|
||
|
bool face_is_coplanar = true;
|
||
|
uint32_t cut_edge_positive_location = INVALID_INDEX;
|
||
|
uint32_t cut_edge_negative_location = INVALID_INDEX;
|
||
|
|
||
|
auto get_end_vertex = [&](uint32_t local_eid) {
|
||
|
auto curr_eid = f.edges[local_eid];
|
||
|
auto next_eid = f.edges[(local_eid + 1) % num_boundary_edges];
|
||
|
const auto& e0 = edges[curr_eid];
|
||
|
const auto& e1 = edges[next_eid];
|
||
|
if (e0.vertices[0] == e1.vertices[0] || e0.vertices[0] == e1.vertices[1]) {
|
||
|
return e0.vertices[0];
|
||
|
} else {
|
||
|
ROBUST_ASSERT(e0.vertices[1] == e1.vertices[0] || e0.vertices[1] == e1.vertices[1]);
|
||
|
return e0.vertices[1];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
for (size_t j = 0; j < num_boundary_edges; j++) {
|
||
|
const auto eid = f.edges[j];
|
||
|
|
||
|
bool last_positive = false;
|
||
|
bool last_negative = false;
|
||
|
auto intersection_point = subedges[eid][2];
|
||
|
auto positive_subedge = subedges[eid][0];
|
||
|
auto negative_subedge = subedges[eid][1];
|
||
|
|
||
|
if (positive_subedge == INVALID_INDEX && negative_subedge == INVALID_INDEX) {
|
||
|
// Edge is coplanar with the plane.
|
||
|
cut_edge_index = eid;
|
||
|
} else {
|
||
|
if (positive_subedge != INVALID_INDEX) {
|
||
|
positive_subedges.emplace_back(positive_subedge);
|
||
|
auto end_vid = get_end_vertex(static_cast<uint32_t>(j));
|
||
|
if (orientations[end_vid] <= 0) {
|
||
|
// This edge is the last edge with positive subedge.
|
||
|
cut_edge_positive_location = positive_subedges.size();
|
||
|
last_positive = true;
|
||
|
}
|
||
|
}
|
||
|
if (negative_subedge != INVALID_INDEX) {
|
||
|
negative_subedges.emplace_back(negative_subedge);
|
||
|
auto end_vid = get_end_vertex(static_cast<uint32_t>(j));
|
||
|
if (orientations[end_vid] >= 0) {
|
||
|
// This edge is the last edge with negative subedge.
|
||
|
cut_edge_negative_location = negative_subedges.size();
|
||
|
last_negative = true;
|
||
|
}
|
||
|
}
|
||
|
face_is_coplanar = false;
|
||
|
}
|
||
|
if (intersection_point != INVALID_INDEX) {
|
||
|
if (last_positive) {
|
||
|
cut_edge.vertices[0] = intersection_point;
|
||
|
} else if (last_negative) {
|
||
|
cut_edge.vertices[1] = intersection_point;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (face_is_coplanar) { return {INVALID_INDEX, INVALID_INDEX, INVALID_INDEX}; }
|
||
|
|
||
|
if (positive_subedges.empty() || negative_subedges.empty()) {
|
||
|
// No cut.
|
||
|
if (positive_subedges.empty()) {
|
||
|
ROBUST_ASSERT(!negative_subedges.empty());
|
||
|
if constexpr (N == 2) f.signs[plane_index] = false;
|
||
|
return {INVALID_INDEX, fid, cut_edge_index};
|
||
|
} else {
|
||
|
ROBUST_ASSERT(!positive_subedges.empty());
|
||
|
ROBUST_ASSERT(negative_subedges.empty());
|
||
|
if constexpr (N == 2) f.signs[plane_index] = true;
|
||
|
return {fid, INVALID_INDEX, cut_edge_index};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ROBUST_ASSERT(cut_edge_index == INVALID_INDEX);
|
||
|
{
|
||
|
// Insert cut edge.
|
||
|
if constexpr (N == 2) {
|
||
|
cut_edge.supporting_plane = plane_index;
|
||
|
} else {
|
||
|
cut_edge.supporting_planes = {f.supporting_plane, plane_index};
|
||
|
}
|
||
|
cut_edge_index = edges.size();
|
||
|
edges.emplace_back(std::move(cut_edge));
|
||
|
}
|
||
|
|
||
|
// Create subfaces.
|
||
|
IAFace<N> positive_subface, negative_subface;
|
||
|
if constexpr (N == 2) {
|
||
|
positive_subface.signs = f.signs;
|
||
|
negative_subface.signs = f.signs;
|
||
|
positive_subface.signs[plane_index] = true;
|
||
|
negative_subface.signs[plane_index] = false;
|
||
|
} else {
|
||
|
positive_subface.supporting_plane = f.supporting_plane;
|
||
|
negative_subface.supporting_plane = f.supporting_plane;
|
||
|
positive_subface.positive_cell = f.positive_cell;
|
||
|
positive_subface.negative_cell = f.negative_cell;
|
||
|
negative_subface.positive_cell = f.positive_cell;
|
||
|
negative_subface.negative_cell = f.negative_cell;
|
||
|
}
|
||
|
|
||
|
ROBUST_ASSERT(cut_edge_index != INVALID_INDEX);
|
||
|
if (cut_edge_positive_location != positive_subedges.size()) {
|
||
|
algorithm::rotate<algorithm::ExecutionPolicySelector::simd_only>(positive_subedges.begin(),
|
||
|
positive_subedges.begin() + cut_edge_positive_location,
|
||
|
positive_subedges.end());
|
||
|
}
|
||
|
if (cut_edge_negative_location != negative_subedges.size()) {
|
||
|
algorithm::rotate<algorithm::ExecutionPolicySelector::simd_only>(negative_subedges.begin(),
|
||
|
negative_subedges.begin() + cut_edge_negative_location,
|
||
|
negative_subedges.end());
|
||
|
}
|
||
|
positive_subedges.emplace_back(cut_edge_index);
|
||
|
positive_subface.edges = std::move(positive_subedges);
|
||
|
ROBUST_ASSERT(positive_subface.edges.size() > 2);
|
||
|
negative_subedges.emplace_back(cut_edge_index);
|
||
|
negative_subface.edges = std::move(negative_subedges);
|
||
|
ROBUST_ASSERT(negative_subface.edges.size() > 2);
|
||
|
|
||
|
faces.emplace_back(std::move(positive_subface));
|
||
|
faces.emplace_back(std::move(negative_subface));
|
||
|
uint32_t positive_fid = static_cast<uint32_t>(faces.size() - 2);
|
||
|
uint32_t negative_fid = static_cast<uint32_t>(faces.size() - 1);
|
||
|
|
||
|
// Update face id on each side of involved edge.
|
||
|
if constexpr (N == 2) {
|
||
|
// Cut edge.
|
||
|
{
|
||
|
auto& e = edges[cut_edge_index];
|
||
|
e.positive_face = positive_fid;
|
||
|
e.negative_face = negative_fid;
|
||
|
}
|
||
|
|
||
|
auto& positive_f = faces[positive_fid];
|
||
|
auto& negative_f = faces[negative_fid];
|
||
|
|
||
|
for (auto eid : positive_f.edges) {
|
||
|
if (eid == cut_edge_index) continue;
|
||
|
auto& e = edges[eid];
|
||
|
ROBUST_ASSERT(e.positive_face == fid || e.negative_face == fid);
|
||
|
if (e.positive_face == fid) {
|
||
|
e.positive_face = positive_fid;
|
||
|
} else {
|
||
|
e.negative_face = positive_fid;
|
||
|
}
|
||
|
}
|
||
|
for (auto eid : negative_f.edges) {
|
||
|
if (eid == cut_edge_index) continue;
|
||
|
auto& e = edges[eid];
|
||
|
ROBUST_ASSERT(e.positive_face == fid || e.negative_face == fid);
|
||
|
if (e.positive_face == fid) {
|
||
|
e.positive_face = negative_fid;
|
||
|
} else {
|
||
|
e.negative_face = negative_fid;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {positive_fid, negative_fid, cut_edge_index};
|
||
|
}
|
||
|
|
||
|
std::array<uint32_t, 3> ia_cut_2_face(IAComplex<2>& ia_complex,
|
||
|
uint32_t fid,
|
||
|
uint32_t plane_index,
|
||
|
const int8_t* orientations,
|
||
|
const std::array<uint32_t, 3>* subedges)
|
||
|
{
|
||
|
return ia_cut_2_face_impl(ia_complex, fid, plane_index, orientations, subedges);
|
||
|
}
|
||
|
|
||
|
std::array<uint32_t, 3> ia_cut_2_face(IAComplex<3>& ia_complex,
|
||
|
uint32_t fid,
|
||
|
uint32_t plane_index,
|
||
|
const int8_t* orientations,
|
||
|
const std::array<uint32_t, 3>* subedges)
|
||
|
{
|
||
|
return ia_cut_2_face_impl(ia_complex, fid, plane_index, orientations, subedges);
|
||
|
}
|