Skip to content

Commit

Permalink
fixed bug in extrusions when surface has a non-manifold vertex on bor…
Browse files Browse the repository at this point in the history
…der; made radial sort more robust when using expansion_nt, by trying to find a good reference bundle along the whole polyline (instead of just trying the first one)
  • Loading branch information
BrunoLevy committed Dec 7, 2023
1 parent e9dd934 commit 96b91e0
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 30 deletions.
10 changes: 10 additions & 0 deletions src/lib/geogram/mesh/mesh_CSG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,11 @@ namespace GEO {
for(index_t le=0; le<3; ++le) {
if(M->facets.adjacent(f,le) == index_t(-1)) {
index_t v = M->facets.vertex(f,le);
// There may be non-manifold borders incident to
// the same border vertex several times.
if(reorder_vertices[v] != index_t(-1)) {
continue;
}
reorder_vertices[v] = nv_border;
++nv_border;
}
Expand Down Expand Up @@ -1281,6 +1286,11 @@ namespace GEO {
for(index_t le=0; le<3; ++le) {
if(M->facets.adjacent(f,le) == index_t(-1)) {
index_t v = M->facets.vertex(f,le);
// There may be non-manifold borders incident to
// the same border vertex several times.
if(reorder_vertices[v] != index_t(-1)) {
continue;
}
reorder_vertices[v] = nv_border;
++nv_border;
}
Expand Down
72 changes: 44 additions & 28 deletions src/lib/geogram/mesh/mesh_surface_intersection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ namespace GEO {
}
}

void MeshSurfaceIntersection::RadialBundles::get_sorted_charts(
void MeshSurfaceIntersection::RadialBundles::get_sorted_incident_charts(
index_t bndl, vector<ChartPos>& chart_pos
) {
chart_pos.resize(0);
Expand Down Expand Up @@ -1370,30 +1370,32 @@ namespace GEO {
vector<index_t> bndl_h;

for(index_t P = b; P < e; ++P) {
// Sort first bundle in polyline
index_t bndl_ref = bundle(P,0);
index_t N = I_.radial_bundles_.nb_halfedges(bndl_ref);
if(!I_.radial_bundles_.radial_sort(bndl_ref, RS)) {
// May return false with expansions, when it
// cannot sort (coplanar facets)
std::cerr << "Radial sort fail in polyline of size "
<< N << std::endl;
geo_assert_not_reached;
}
I_.radial_bundles_.get_sorted_charts(
bndl_ref, ref_chart_to_radial_id
);

// reference bundle is OK if it is not incident to the
// same chart twice (which may occur in very weird configs)
bool bndl_ref_OK = true;
for(index_t i=0; i+1<ref_chart_to_radial_id.size(); ++i) {
bndl_ref_OK = bndl_ref_OK && (
ref_chart_to_radial_id[i].first ==
ref_chart_to_radial_id[i+1].first
);
index_t bndl_ref = NO_INDEX;
index_t N = NO_INDEX;

for(index_t bndl: bundles(P)) {
bool OK = I_.radial_bundles_.radial_sort(bndl, RS);
if(OK) {
I_.radial_bundles_.get_sorted_incident_charts(
bndl, ref_chart_to_radial_id
);
for(
index_t i=0; i+1<ref_chart_to_radial_id.size(); ++i
) {
OK = OK && (
ref_chart_to_radial_id[i].first !=
ref_chart_to_radial_id[i+1].first
);
}
}
if(OK) {
bndl_ref = bndl;
N = I_.radial_bundles_.nb_halfedges(bndl);
break;
}
}

// Copy order to all other bundles in polyline
for(index_t bndl: bundles(P)) {
if(bndl == bndl_ref) {
Expand All @@ -1402,15 +1404,15 @@ namespace GEO {

// Necessary condition: reference bndl should be OK
// and current bndl should have same nbr of halfedges
bool OK = bndl_ref_OK && (
bool OK = (bndl_ref != NO_INDEX) && (
I_.radial_bundles_.nb_halfedges(bndl)==N
);

// Now check that charts around current bndl are the
// same as charts around reference bndl. It can happen
// that they differ even if N matches (example21.csg)
if(OK) {
I_.radial_bundles_.get_sorted_charts(
I_.radial_bundles_.get_sorted_incident_charts(
bndl, cur_chart_to_radial_id
);
for(index_t i=0; i<N; ++i) {
Expand All @@ -1421,6 +1423,9 @@ namespace GEO {
}
}
if(OK) {
// Here ref_bnfl has a valid order, and bndl has
// the same surrounding charts as ref_bndl,
// so we can reuse the radial order computed in ref_bndl
bndl_h.assign(N, NO_INDEX);
for(index_t i=0; i<N; ++i) {
// This halfedge ...
Expand All @@ -1436,9 +1441,20 @@ namespace GEO {
} else {
// Else compute the radial sort geometrically
bool OK = I_.radial_bundles_.radial_sort(bndl, RS);
// May return !OK with expansions when it
// cannot sort (coplanar facets)
geo_assert(OK);
// May return !OK (if not using geogram_plus) when it
// cannot sort (example_022.csg and example_024.csg)
if(!OK) {
std::cerr << std::endl
<< "FATAL ERROR: "
<< "Did not manage to sort a bundle"
<< " in Polyline of length "
<< nb_bundles(P)
<< std::endl;
std::cerr << "(if you reached this point, you may"
<< " need geogramplus, contact TESSAEL)"
<< std::endl;
geo_assert_not_reached;
}
}
if(I_.verbose_ && nb() > 500) {
Process::acquire_spinlock(log_lock);
Expand Down
14 changes: 12 additions & 2 deletions src/lib/geogram/mesh/mesh_surface_intersection.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,8 @@ namespace GEO {
/**
* \brief Gets a halfedge in a bundle from local index
* \param[in] bndl the bundle
* \param[in] li the local index, in [0 .. nb_halfedges(bndl)-1]
* \param[in] li the local index of the halfedge in the bundle,
* in [0 .. nb_halfedges(bndl)-1]
* \return the halfedge
*/
index_t halfedge(index_t bndl, index_t li) {
Expand All @@ -791,6 +792,13 @@ namespace GEO {
return H_[bndl_start_[bndl] + li];
}

/**
* \brief Sets a halfedge in a bundle
* \param[in] bndl the bundle
* \param[in] li the local index of the halfedge in the bunble,
* in [0 .. nb_halfedges(bndl)-1]
* \param[in] h the new halfedge
*/
void set_halfedge(index_t bndl, index_t li, index_t h) {
geo_debug_assert(bndl < nb());
geo_debug_assert(li < nb_halfedges(bndl));
Expand Down Expand Up @@ -962,7 +970,9 @@ namespace GEO {
* sorted by chart id, and where the halfedge index is the original
* index in the bundle before sorting
*/
void get_sorted_charts(index_t bndl, vector<ChartPos>& chart_pos);
void get_sorted_incident_charts(
index_t bndl, vector<ChartPos>& chart_pos
);

private:
MeshSurfaceIntersection& I_;
Expand Down

0 comments on commit 96b91e0

Please sign in to comment.