Program Listing for File potentialSurfaceTension.cpp#

Return to documentation for file (pymembrane/cppmodule/src/potentials/potentialSurfaceTension.cpp)

#include "potentialSurfaceTension.hpp"

bool is_triple_line_vertex(const int vid,
                            HE_VertexProp *vertices,
                            HE_HalfEdgeProp *halfedges)
{
    if (vertices[vid].type != 2)
        return false;

    int he = vertices[vid]._hedge;
    int first = he;

    do
    {
        int v = halfedges[he].vert_to;
        if (vertices[v].type == 1)
            return true;
        he = halfedges[he].pair;
        he = halfedges[he].next;
    } while (he != first);

    return false;
}

void ComputeVertexSurfaceTensionForce_fn(const int vid,
                                        HE_VertexProp *vertices,
                                        HE_HalfEdgeProp *halfedges,
                                        real *m_gamma,
                                        real *curvature)
{
    int he = vertices[vid]._hedge;
    int first = he;
    int type_0 = vertices[vid].type;
    real3 a = vertices[vid].r;
    real3 tension_force;
    tension_force.x = 0;
    tension_force.y = 0;
    tension_force.z = 0;

    real gamma_type = m_gamma[type_0];
    if (type_0 == 1)
    {
        do
        {
            int v1 = halfedges[he].vert_to;
            int he_next = halfedges[he].next;
            int v2 = halfedges[he_next].vert_to;
            real3 b = vertices[v1].r;
            real3 c = vertices[v2].r;

            real3 normal = pymemb::compute_normal_triangle_unit(a, b, c);
            real area = pymemb::compute_area_triangle_from_vertex(a, b, c);
            real angle = pymemb::compute_angle_vertex(a, b, c);
            angle = angle/M_PI;
            Xvec1(normal, angle*area, normal);

            tension_force = pymemb::vector_sum(tension_force, normal);

            he = halfedges[he].pair;
            he = halfedges[he].next;
        } while (he != first);

        vertices[vid].forceC.x += tension_force.x*(-curvature[vid])*gamma_type;
        vertices[vid].forceC.y += tension_force.y*(-curvature[vid])*gamma_type;
        vertices[vid].forceC.z += tension_force.z*(-curvature[vid])*gamma_type;
    }

    else if (is_triple_line_vertex(vid, vertices, halfedges))
    {
        real3 triple_line_force;
        triple_line_force.x = 0;
        triple_line_force.y = 0;
        triple_line_force.z = 0;
        real triple_line_length = 0.0;
        real3 line_normal, plane_normal;
        line_normal.x = 0;
        line_normal.y = 0;
        line_normal.z = 0;
        plane_normal.x = 0;
        plane_normal.y = 0;
        plane_normal.z = 0;
        real3 tangent;
        tangent.x = 0;
        tangent.y = 0;
        tangent.z = 0;
        do
        {
            int v1 = halfedges[he].vert_to;
            int he_next = halfedges[he].next;
            int v2 = halfedges[he_next].vert_to;
            real3 b = vertices[v1].r;
            real3 c = vertices[v2].r;

            if (is_triple_line_vertex(v1, vertices, halfedges))
            {
                real length = pymemb::vector_length(pymemb::vector_subtract(a, b))/2;
                triple_line_length += length;
                real3 p;
                p.x = (a.x + b.x)/2;
                p.y = (a.y + b.y)/2;
                p.z = (a.z + b.z)/2;
                real3 normal;
                if (vertices[v2].type == 2)
                    normal = pymemb::unit_vector(pymemb::vector_subtract(p, c));
                else
                {
                    int he_pair = halfedges[he].pair;
                    he_pair = halfedges[he_pair].next;
                    real3 d = vertices[halfedges[he_pair].vert_to].r;
                    normal = pymemb::unit_vector(pymemb::vector_subtract(p, d));
                }
                Xvec1(normal, length, normal);
                line_normal = pymemb::vector_sum(line_normal, normal);
            }

            if (vertices[v1].type == 1 || vertices[v2].type == 1)
            {
                real area = pymemb::compute_area_triangle_from_vertex(a, b, c);
                real3 p = pymemb::vector_sum(b, c);
                Xvec1(p, 0.5, p);
                real3 ap = pymemb::vector_subtract(p, a);
                Xvec1(ap, area, ap);    //mesh_op.refine_mesh_edge_flip();
                //mesh_op.adapt_mesh();
                tangent = pymemb::vector_sum(tangent, ap);
            }
            else
            {
                real3 ab = pymemb::vector_subtract(b, a);
                real3 ac = pymemb::vector_subtract(c, a);
                real3 triangle_normal = pymemb::vector_cross(ab, ac);
                plane_normal = pymemb::vector_sum(plane_normal, triangle_normal);
            }

            he = halfedges[he].pair;
            he = halfedges[he].next;
        } while (he != first);

        tangent = pymemb::unit_vector(tangent);
        Xvec1(tangent, triple_line_length, tangent);
        plane_normal = pymemb::unit_vector(plane_normal);
        real tproj = pymemb::vector_dot(tangent, plane_normal);
        real3 tminus;
        Xvec1(tminus, tproj, plane_normal);
        tangent = pymemb::vector_subtract(tangent, tminus);

        line_normal = pymemb::unit_vector(line_normal);
        Xvec1(line_normal, triple_line_length, line_normal);

        vertices[vid].forceC.x += tangent.x*m_gamma[1] + line_normal.x*m_gamma[2];
        vertices[vid].forceC.y += tangent.y*m_gamma[1] + line_normal.y*m_gamma[2];
        vertices[vid].forceC.z += tangent.z*m_gamma[1] + line_normal.z*m_gamma[2];
    }
}

real ComputeVertexSurfaceTension::compute_face_energy(int face_id)
{
    int v1 = _system.faces[face_id].v1;
    int v2 = _system.faces[face_id].v2;
    int v3 = _system.faces[face_id].v3;

    real area = pymemb::compute_area_triangle_from_vertex(_system.vertices[v1].r, _system.vertices[v2].r, _system.vertices[v3].r);

    if (_system.vertices[v1].type == 1 || _system.vertices[v2].type == 1 || _system.vertices[v3].type == 1 )
    {
        return area * m_gamma[1];
    }

    return -m_gamma[2] * area;
}

void ComputeVertexSurfaceTension::compute_energy(void)
{
    for (int face_id=0; face_id <_system.Numfaces; face_id++)
    {
        _system.faces[face_id].energy = compute_face_energy(face_id);
    }
}

void ComputeVertexSurfaceTension::compute(void)
{
    pymemb::vector<real> curvature = _system.compute_mesh.meancurvature();
    //pymemb::vector<real> curvature = _system.compute_mesh.gaussiancurvature();

    for(int i=0; i<_system.Numvertices; i++) {
        ComputeVertexSurfaceTensionForce_fn(i, &_system.vertices[0],
                                            &_system.halfedges[0],
                                            &m_gamma[0],
                                        &curvature[0]);
    }
}