Skip to content

Commit

Permalink
Added local mesh modifications:
Browse files Browse the repository at this point in the history
   functions to glue or unglue an edge.
  • Loading branch information
BrunoLevy committed Nov 12, 2022
1 parent 7fc8ce6 commit da642cc
Show file tree
Hide file tree
Showing 3 changed files with 356 additions and 5 deletions.
263 changes: 263 additions & 0 deletions src/lib/geogram/mesh/mesh_local_operations.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/*
* Copyright (c) 2000-2022 Inria
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ALICE Project-Team nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contact: Bruno Levy
*
* https://www.inria.fr/fr/bruno-levy
*
* Inria,
* Domaine de Voluceau,
* 78150 Le Chesnay - Rocquencourt
* FRANCE
*
*/

#include <geogram/mesh/mesh_local_operations.h>
#include <geogram/mesh/mesh_halfedges.h>
#include <geogram/mesh/mesh.h>

namespace {

using namespace GEO;

/**
* \brief Finds the corner of a facet that is adjacent to a given facet.
* \param[in] M a const reference to a Mesh
* \param[in] f a facet index in \p M
* \param[in] f_adj a facet index in \p M
* \return the corner of facet \p f that is adjacent to facet \p f_adj
* or NO_FACET if no such corner exists
*/
index_t find_corner_by_adjacent_facet(
const Mesh& M, index_t f, index_t f_adj
) {
for(index_t c: M.facets.corners(f)) {
if(M.facet_corners.adjacent_facet(c) == f_adj) {
return c;
}
}
return NO_CORNER;
}

/**
* \brief Copies a mesh vertex.
* \details It is not correct to use:
* \code
* M.vertices.create_vertex(M.vertices.point_ptr(v));
* \endcode
* because Mesh::create_vertex() may realloc the points coordinates
* vector, thus invalidating M.vertices.point_ptr(v).
* \param[in] M a reference to the mesh
* \param[in] v the index of the vertex to be copied
* \return the index of the new vertex
*/
index_t copy_vertex(Mesh& M, index_t v) {
index_t result = M.vertices.create_vertex();
double* to = M.vertices.point_ptr(result);
const double* from = M.vertices.point_ptr(v);
for(index_t c=0; c<M.vertices.dimension(); ++c) {
to[c] = from[c];
}
return result;
}
}


/****************************************************************************/

namespace GEO {

void glue_edges(
Mesh& M,
index_t f1, index_t c1,
index_t f2, index_t c2
) {
geo_assert(M.facet_corners.adjacent_facet(c1) == NO_FACET);
geo_assert(M.facet_corners.adjacent_facet(c2) == NO_FACET);
geo_debug_assert(c1 >= M.facets.corners_begin(f1));
geo_debug_assert(c1 < M.facets.corners_end(f1));
geo_debug_assert(c2 >= M.facets.corners_begin(f2));
geo_debug_assert(c2 < M.facets.corners_end(f2));


// Glue geometry
{
index_t v1 = M.facet_corners.vertex(c1);
index_t v2 = M.facet_corners.vertex(
M.facets.next_corner_around_facet(f1,c1)
);

double* p1 = M.vertices.point_ptr(v1);
double* p2 = M.vertices.point_ptr(v2);

index_t w1 = M.facet_corners.vertex(c2);
index_t w2 = M.facet_corners.vertex(
M.facets.next_corner_around_facet(f2,c2)
);

double* q1 = M.vertices.point_ptr(w1);
double* q2 = M.vertices.point_ptr(w2);

for(index_t c=0; c<M.vertices.dimension(); ++c) {
p1[c] = 0.5*(p1[c] + q2[c]);
q1[c] = 0.5*(q1[c] + p2[c]);
}
}


index_t f[2];
f[0] = f1;
f[1] = f2;
index_t c[2];
c[0] = c1;
c[1] = c2;

vector<index_t> delete_vertex(M.vertices.nb(),0);

// We need to keep the corners to update in a temporary
// vector, since updating them during the traversal would
// break the traversal (don't saw the branch you are sitting
// on !!)

for(index_t k=0; k<2; ++k) {
index_t v = M.facet_corners.vertex(c[k]);
vector<index_t> corners_to_update;
MeshHalfedges MH(M);
{
MeshHalfedges::Halfedge H(f[k],c[k]);
do {
index_t w = M.facet_corners.vertex(H.corner);
if(w != v) {
delete_vertex[w] = 1;
corners_to_update.push_back(H.corner);
}
} while(MH.move_to_prev_around_vertex(H));
}
{
MeshHalfedges::Halfedge H(f[1-k], c[1-k]);
MH.move_to_next_around_border(H);
do {
index_t w = M.facet_corners.vertex(H.corner);
if(w != v) {
delete_vertex[w] = 1;
corners_to_update.push_back(H.corner);
}
} while(MH.move_to_prev_around_vertex(H));

}
for(index_t i=0; i<corners_to_update.size(); ++i) {
M.facet_corners.set_vertex(
corners_to_update[i],v
);
}
}

M.facet_corners.set_adjacent_facet(c[0],f[1]);
M.facet_corners.set_adjacent_facet(c[1],f[0]);



M.vertices.delete_elements(delete_vertex);
}

void unglue_edges(
Mesh& M,
index_t f1, index_t c1
) {
geo_debug_assert(c1 >= M.facets.corners_begin(f1));
geo_debug_assert(c1 < M.facets.corners_end(f1));
index_t f2 = M.facet_corners.adjacent_facet(c1);
geo_assert(f2 != NO_FACET);
index_t c2 = find_corner_by_adjacent_facet(M,f2,f1);
geo_assert(c2 != NO_CORNER);

M.facet_corners.set_adjacent_facet(c1,NO_FACET);
M.facet_corners.set_adjacent_facet(c2,NO_FACET);

// Now, we need to determine whether edge extremities were dissociated.

MeshHalfedges MH(M);

MeshHalfedges::Halfedge H1(f1,c1);
MeshHalfedges::Halfedge H2(f2,c2);

MeshHalfedges::Halfedge H1_prev(H1);
MH.move_to_prev_around_border(H1_prev);
MeshHalfedges::Halfedge H1_next(H1);
MH.move_to_next_around_border(H1_next);

// If the predecessor of H1 around the border is not H2, then
// H1's origin was splitted into two vertices. Thus we
// create the new vertex and assign it to H1's origin (c1).
if(H1_prev != H2) {
vector<index_t> corners_to_update;
index_t v = M.facet_corners.vertex(c1);
index_t new_v = copy_vertex(M,v);

// Note: we cannot set the corner vertices while we
// are traversing, since traversal relies on corner-vertex
// relations (do not saw the branch you are sitting on...),
// thus we store the corners to be updated in a temporary
// vector (a bit ugly, but not a big drama).
MeshHalfedges::Halfedge H(H1);
do {
corners_to_update.push_back(H.corner);
} while(MH.move_to_prev_around_vertex(H));
for(index_t i=0; i<corners_to_update.size(); ++i) {
M.facet_corners.set_vertex(
corners_to_update[i],new_v
);
}
}

// If the successor of H1 around the border is not H2, then
// H2's origin was splitted into two vertices. Thus we
// create the new vertex and assign it to H2's origin (c2).
if(H1_next != H2) {
vector<index_t> corners_to_update;
index_t v = M.facet_corners.vertex(c2);
index_t new_v = copy_vertex(M,v);
// Note: we cannot set the corner vertices while we
// are traversing, since traversal relies on corner-vertex
// relations (do not saw the branch you are sitting on...),
// thus we store the corners to be updated in a temporary
// vector (a bit ugly, but not a big drama).
MeshHalfedges::Halfedge H(H2);
do {
corners_to_update.push_back(H.corner);
} while(MH.move_to_prev_around_vertex(H));
for(index_t i=0; i<corners_to_update.size(); ++i) {
M.facet_corners.set_vertex(
corners_to_update[i],new_v
);
}
}
}
}


81 changes: 81 additions & 0 deletions src/lib/geogram/mesh/mesh_local_operations.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2000-2022 Inria
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ALICE Project-Team nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contact: Bruno Levy
*
* https://www.inria.fr/fr/bruno-levy
*
* Inria,
* Domaine de Voluceau,
* 78150 Le Chesnay - Rocquencourt
* FRANCE
*
*/

#ifndef GEOGRAM_MESH_LOCAL_OPERATIONS
#define GEOGRAM_MESH_LOCAL_OPERATIONS

#include <geogram/basic/common.h>
#include <geogram/basic/numeric.h>

/**
* \file geogram/mesh/mesh_local_operations.h
* \brief Functions to modify a mesh locally
*/

namespace GEO {

class Mesh;

/**
* \brief Glues two edges on the border of a surface mesh.
* \param[in] M a reference to the mesh
* \param[in] f1 , c1 the first edge, as a corner seen from a facet
* \param[in] f2 , c2 the second edge, as a corner seen from a facet
* \pre Both edges are on the border
*/
void GEOGRAM_API glue_edges(
Mesh& M,
index_t f1, index_t c1,
index_t f2, index_t c2
);

/**
* \brief Unglues an edge from its opposite edge.
* \param[in] M a reference to the mesh
* \param[in] f1 , c1 the edge, as a corner seen from a facet
* \pre The edge (f,c) is not on the border
*/
void GEOGRAM_API unglue_edges(
Mesh& M,
index_t f1, index_t c1
);
}

#endif

Loading

0 comments on commit da642cc

Please sign in to comment.