Program Listing for File edge_flip.hpp#

Return to documentation for file (pymembrane/cppmodule/src/mesh/edge_flip.hpp)

#ifndef __edge_flip_hpp__
#define __edge_flip_hpp__

#include "../system/systemclass.hpp"
#include "../box/pbc.hpp"

namespace pymemb
{
    inline bool CheckEdgeFlip_lambda(const int flip_edge_index,
                                     HE_FaceProp *faces,
                                     HE_VertexProp *vertices,
                                     HE_EdgeProp *edges,
                                     HE_HalfEdgeProp *halfedges,
                                     const BoxType _box)
    {
        // printf("trying to flip the edge =%i\n", flip_edge_index);
        // by default the edge can flip
        bool can_flip = true;
        // retrieve the vertices around the edge
        int v0 = edges[flip_edge_index].v0;
        int v1 = edges[flip_edge_index].v1;
        int v2 = edges[flip_edge_index].v2;
        int v3 = edges[flip_edge_index].v3;

        int face_k = edges[flip_edge_index].face_k;
        int face_l = edges[flip_edge_index].face_l;

        //(0) Check that the edge is not a boundary edge
        if (edges[flip_edge_index].boundary == true)
        {
            py::print("the edge id ", flip_edge_index, " is a boundary edge");
            // can_flip = false;
            return false;
        }
        //(1) first we need to check if we don't destroy the triangulation by flipping the edge.
        // This can be done by checking that the connectivity of the edges v0, v2 of the involve edge is
        // strictly larger than 3.
        int he, first, he_pair, he_pair_next;
        int n_neighbors_v0 = 0, n_neighbors_v2 = 0;

        // check v0
        he = vertices[v0]._hedge;
        first = he;

        do
        {
            n_neighbors_v0++;
            // MOVE TO THE NEXT FACE
            he_pair = halfedges[he].pair;
            he_pair_next = halfedges[he_pair].next;
            he = he_pair_next;
        } while ((he != first));

        // check v2
        he = vertices[v2]._hedge;
        first = he;

        do
        {
            n_neighbors_v2++;
            // MOVE TO THE NEXT FACE
            he_pair = halfedges[he].pair;
            he_pair_next = halfedges[he_pair].next;
            he = he_pair_next;
        } while ((he != first));

        // if (n_neighbors_v0 <= 4 || n_neighbors_v2 <= 4)
        if (n_neighbors_v0 < 3 || n_neighbors_v2 < 3)
        {
            py::print("the edge id ", flip_edge_index, "vertex the connectivity v0 or v2 is smaller than 3");
            // can_flip = false;
            return false;
        }

        // If that happens then an edge flip might destroy the triangulation.
        // If the sum of angles next to each of the two sides of the edge is >= PI
        // the flip would break triangulation. We disallow such a move.
        // For example, in this case edge cannot be flipped
        //          1:X
        //          * *
        //        *  *
        //      *   *
        //   0:X---X:2 <-- This angle is < PI and the edge cannot be flipped!
        //      *   *
        //       *  *
        //         * *
        //          3:X
        real3 r02, r01, r03;
        r02 = pymemb::minimum_image(vertices[v0].r, vertices[v2].r, _box);
        r03 = pymemb::minimum_image(vertices[v0].r, vertices[v3].r, _box);
        r01 = pymemb::minimum_image(vertices[v0].r, vertices[v1].r, _box);
        real r02_norm_sq = (vdot(r02, r02));
        real r03_norm_sq = (vdot(r03, r03));
        real r01_norm_sq = (vdot(r01, r01));
        real angle_r01_r02 = acos(vdot(r01, r02) / sqrt(r01_norm_sq * r02_norm_sq));
        real angle_r03_r02 = acos(vdot(r03, r02) / sqrt(r03_norm_sq * r02_norm_sq));
        if ((angle_r01_r02 + angle_r03_r02) >= defPI)
        {
            py::print("the edge id ", flip_edge_index, " vertex v0 ", v0, " take part of an obtuse triangles");
            // can_flip = false;
            return false;
        }
        real3 r20, r21, r23;
        r20 = pymemb::minimum_image(vertices[v2].r, vertices[v0].r, _box);
        r23 = pymemb::minimum_image(vertices[v2].r, vertices[v3].r, _box);
        r21 = pymemb::minimum_image(vertices[v2].r, vertices[v1].r, _box);
        real r23_norm_sq = (vdot(r23, r23));
        real r21_norm_sq = (vdot(r21, r21));
        real angle_r21_r20 = acos(vdot(r21, r20) / sqrt(r21_norm_sq * r02_norm_sq));
        real angle_r23_r20 = acos(vdot(r23, r20) / sqrt(r23_norm_sq * r02_norm_sq));
        if ((angle_r21_r20 + angle_r23_r20) >= defPI)
        {
            py::print("the edge id ", flip_edge_index, " vertex v2 ", v2, " take part of an obtuse triangles");
            // can_flip = false;
            return false;
        }
        return true;
    }

    inline bool EdgeFlip_lambda(const int flip_edge_index,
                                const bool flip_face_up,
                                HE_FaceProp *faces,
                                HE_VertexProp *vertices,
                                HE_EdgeProp *edges,
                                HE_HalfEdgeProp *halfedges,
                                const BoxType _box)
    {
        // printf("trying to flip the edge =%i\n", flip_edge_index);
        // by default the edge can flip
        bool can_flip = true;
        // retrieve the vertices around the edge
        int v0 = edges[flip_edge_index].v0;
        int v1 = edges[flip_edge_index].v1;
        int v2 = edges[flip_edge_index].v2;
        int v3 = edges[flip_edge_index].v3;

        int face_k = edges[flip_edge_index].face_k;
        int face_l = edges[flip_edge_index].face_l;

        //(0) Check that the edge is not a boundary edge
        if (edges[flip_edge_index].boundary == true)
        {
            // py::print("the edge is a boundary edge\n");
            can_flip = false;
            // break;
        }
        //(1) first we need to check if we don't destroy the triangulation by flipping the edge.
        // This can be done by checking that the connectivity of the edges v0, v2 of the involve edge is
        // strictly larger than 3.
        int he, first, he_pair, he_pair_next;
        int n_neighbors_v0 = 0, n_neighbors_v2 = 0;

        // check v0
        he = vertices[v0]._hedge;
        first = he;

        do
        {
            n_neighbors_v0++;
            // MOVE TO THE NEXT FACE
            he_pair = halfedges[he].pair;
            he_pair_next = halfedges[he_pair].next;
            he = he_pair_next;
        } while ((he != first));

        // check v2
        he = vertices[v2]._hedge;
        first = he;

        do
        {
            n_neighbors_v2++;
            // MOVE TO THE NEXT FACE
            he_pair = halfedges[he].pair;
            he_pair_next = halfedges[he_pair].next;
            he = he_pair_next;
        } while ((he != first));

        // if (n_neighbors_v0 <= 4 || n_neighbors_v2 <= 4)
        if (n_neighbors_v0 < 3 || n_neighbors_v2 < 3)
        {
            // py::print("the connectivity of the edges v0, v2 of the involve edge is smaller than 3\n");
            can_flip = false;
            // break;
        }
        // If that happens then an edge flip might destroy the triangulation.
        // If the sum of angles next to each of the two sides of the edge is >= PI
        // the flip would break triangulation. We disallow such a move.
        // For example, in this case edge cannot be flipped
        //          1:X
        //          * *
        //        *  *
        //      *   *
        //   0:X---X:2 <-- This angle is < PI and the edge cannot be flipped!
        //      *   *
        //       *  *
        //         * *
        //          3:X
        real3 r02, r01, r03;
        r02 = pymemb::minimum_image(vertices[v0].r, vertices[v2].r, _box);
        r03 = pymemb::minimum_image(vertices[v0].r, vertices[v3].r, _box);
        r01 = pymemb::minimum_image(vertices[v0].r, vertices[v1].r, _box);
        real r02_norm_sq = (vdot(r02, r02));
        real r03_norm_sq = (vdot(r03, r03));
        real r01_norm_sq = (vdot(r01, r01));
        real angle_r01_r02 = acos(vdot(r01, r02) / sqrt(r01_norm_sq * r02_norm_sq));
        real angle_r03_r02 = acos(vdot(r03, r02) / sqrt(r03_norm_sq * r02_norm_sq));
        if ((angle_r01_r02 + angle_r03_r02) >= defPI)
        {
            // py::print("v0 and v2 take part of an obtuse triangles\n");
            can_flip = false;
            // break;
        }
        real3 r20, r21, r23;
        r20 = pymemb::minimum_image(vertices[v2].r, vertices[v0].r, _box);
        r23 = pymemb::minimum_image(vertices[v2].r, vertices[v3].r, _box);
        r21 = pymemb::minimum_image(vertices[v2].r, vertices[v1].r, _box);
        real r23_norm_sq = (vdot(r23, r23));
        real r21_norm_sq = (vdot(r21, r21));
        real angle_r21_r20 = acos(vdot(r21, r20) / sqrt(r21_norm_sq * r02_norm_sq));
        real angle_r23_r20 = acos(vdot(r23, r20) / sqrt(r23_norm_sq * r02_norm_sq));
        if ((angle_r21_r20 + angle_r23_r20) >= defPI)
        {
            can_flip = false;
            // break;
        }

        if (can_flip == true)
        {
            // update the halfedges
            int he_vec[6]; // he01, he12, he20, he02, he23, he30;
            int he_edge = edges[flip_edge_index]._hedge;
            if (halfedges[he_edge].vert_from == v0)
            {
                he_vec[3] = he_edge;                   // he02
                he_vec[2] = halfedges[he_vec[3]].pair; // he20
            }
            else
            {
                he_vec[2] = he_edge;                   // he20
                he_vec[3] = halfedges[he_vec[2]].pair; // he02
            }
            he_vec[0] = halfedges[he_vec[2]].next; // he01
            he_vec[1] = halfedges[he_vec[2]].prev; // he12
            he_vec[4] = halfedges[he_vec[3]].next; // he23
            he_vec[5] = halfedges[he_vec[3]].prev; // he30

            // deal with the from, to vertices in the "new" flip edge
            halfedges[he_vec[2]].vert_from = v3;
            halfedges[he_vec[2]].vert_to = v1;
            halfedges[he_vec[3]].vert_from = v1;
            halfedges[he_vec[3]].vert_to = v3;

            // flip face: this stage is crucial if we want to make the faces diffuse
            int new_face_k = face_k;
            int new_face_l = face_l;
            if (flip_face_up == false) // counter-clock wise
            {
                new_face_k = face_l;
                new_face_l = face_k;
            }
            // deal with the references inside of the halfedges
            // he12 > h23 > h20
            halfedges[he_vec[1]].next = he_vec[4];
            halfedges[he_vec[1]].prev = he_vec[2];
            halfedges[he_vec[4]].next = he_vec[2];
            halfedges[he_vec[4]].prev = he_vec[1];
            halfedges[he_vec[2]].next = he_vec[1];
            halfedges[he_vec[2]].prev = he_vec[4];
            // faces
            halfedges[he_vec[1]].face = new_face_k;
            halfedges[he_vec[4]].face = new_face_k;
            halfedges[he_vec[2]].face = new_face_k;

            // he01 > h02 > h30
            halfedges[he_vec[0]].next = he_vec[3];
            halfedges[he_vec[0]].prev = he_vec[5];
            halfedges[he_vec[3]].next = he_vec[5];
            halfedges[he_vec[3]].prev = he_vec[0];
            halfedges[he_vec[5]].next = he_vec[0];
            halfedges[he_vec[5]].prev = he_vec[3];
            // faces
            halfedges[he_vec[5]].face = new_face_l;
            halfedges[he_vec[0]].face = new_face_l;
            halfedges[he_vec[3]].face = new_face_l;

            // deal with the faces and references to the halfedges
            // face_k
            int _v1k = v2;
            int _v2k = v3;
            int _v3k = v1;
            pymemb::arrange_vertices_by_smallest(_v1k, _v2k, _v3k);

            faces[new_face_k].v1 = _v1k; // v1;
            faces[new_face_k].v2 = _v2k; // v2;
            faces[new_face_k].v3 = _v3k; // v3;
            faces[new_face_k]._hedge = he_vec[2];
            // face_l
            int _v1l = v0;
            int _v2l = v1;
            int _v3l = v3;
            pymemb::arrange_vertices_by_smallest(_v1l, _v2l, _v3l);
            faces[new_face_l].v1 = _v1l; // v3;
            faces[new_face_l].v2 = _v2l; // v0;
            faces[new_face_l].v3 = _v3l; // v1;
            faces[new_face_l]._hedge = he_vec[3];

            // deal with the halfedge references to the vertices
            if (vertices[v0]._hedge == he_vec[3] /*he02*/)
                vertices[v0]._hedge = he_vec[0]; /*h01*/
            if (vertices[v2]._hedge == he_vec[2] /*he20*/)
                vertices[v2]._hedge = he_vec[4]; /*h23*/

            // deal with the i,j,v0,v1,v2,v3 in the edge list
            for (auto he_index : he_vec)
            {
                HE_HalfEdgeProp he = halfedges[he_index];
                HE_HalfEdgeProp he_pair = halfedges[halfedges[he_index].pair];
                int edge_index = he.edge;
                edges[edge_index].face_k = he.face;
                edges[edge_index].face_l = he_pair.face;
                edges[edge_index].v0 = he.vert_to;
                edges[edge_index].v2 = he.vert_from;
                edges[edge_index].j = he.vert_to;
                edges[edge_index].i = he.vert_from;
                int he_next = he.next;
                edges[edge_index].v1 = halfedges[he_next].vert_to;
                int he_index_pair_next = he_pair.next;
                edges[edge_index].v3 = halfedges[he_index_pair_next].vert_to;
            }

            // printf("flipped edge =%i\n", flip_edge_index);
        }

        return can_flip;
    }
}
#endif