Program Listing for File meshoperations.cpp#
↰ Return to documentation for file (pymembrane/cppmodule/src/mesh/meshoperations.cpp)
#include "meshoperations.hpp"
#include "edge_flip.hpp"
#include "computegeometry.hpp"
#include "../system/systemclass.hpp"
#include "../box/pbc.hpp"
#include <set>
real MeshOperations::compute_average_edge_length()
{
real avg_edge_length = 0.0;
for (int edge_id=0; edge_id<_system.Numedges; edge_id++)
{
int v0 = _system.edges[edge_id].i;
int v1 = _system.edges[edge_id].j;
avg_edge_length += pymemb::vector_length(pymemb::vector_subtract(_system.vertices[v0].r, _system.vertices[v1].r));
}
return avg_edge_length/_system.Numedges;
}
bool MeshOperations::check_if_edge_can_flip(const int& flip_edge_index)
{
auto can_flip = pymemb::CheckEdgeFlip_lambda(flip_edge_index,
(&_system.faces[0]),
(&_system.vertices[0]),
(&_system.edges[0]),
(&_system.halfedges[0]),
_system.get_box());
return can_flip;
}
bool MeshOperations::edge_need_flip(int flip_edge_index)
{
int v0 = _system.edges[flip_edge_index].v0;
int v1 = _system.edges[flip_edge_index].v1;
int v2 = _system.edges[flip_edge_index].v2;
int v3 = _system.edges[flip_edge_index].v3;
real3 r0 = _system.vertices[v0].r;
real3 r1 = _system.vertices[v1].r;
real3 r2 = _system.vertices[v2].r;
real3 r3 = _system.vertices[v3].r;
// first check if edge can flip
real angle_0102 = pymemb::compute_angle_vertex(r0, r1, r2);
real angle_0203 = pymemb::compute_angle_vertex(r0, r2, r3);
if (angle_0102 + angle_0203 >= M_PI)
return false;
real angle_2120 = pymemb::compute_angle_vertex(r2, r1, r0);
real angle_2023 = pymemb::compute_angle_vertex(r2, r0, r3);
if (angle_2120 + angle_2023 >= M_PI)
return false;
int f0 = _system.edges[flip_edge_index].face_k;
int f1 = _system.edges[flip_edge_index].face_l;
real3 ra = _system.vertices[_system.faces[f0].v1].r;
real3 rb = _system.vertices[_system.faces[f0].v2].r;
real3 rc = _system.vertices[_system.faces[f0].v3].r;
real3 n_f0 = pymemb::compute_normal_triangle_unit(ra, rb, rc);
ra = _system.vertices[_system.faces[f1].v1].r;
rb = _system.vertices[_system.faces[f1].v2].r;
rc = _system.vertices[_system.faces[f1].v3].r;
real3 n_f1 = pymemb::compute_normal_triangle_unit(ra, rb, rc);
if (pymemb::vector_dot(n_f0, n_f1) < 0)
return false;
// this condition is relevant when using surface tension and substrate
// to avoid flip on triple line
// comment or delete for other use
int t0 = _system.vertices[v0].type;
int t1 = _system.vertices[v1].type;
int t2 = _system.vertices[v2].type;
int t3 = _system.vertices[v3].type;
if (t0 == t2 && (t0 > t1 || t0 > t3))
return false;
// then check if angles can be improved by flip
real angle012 = pymemb::compute_angle_vertex(r1, r0, r2);
real angle210 = pymemb::compute_angle_vertex(r3, r0, r2);
return angle012 + angle210 > M_PI;
}
/*
v0 v0
/ | \ / \
/ | \ / \
v3 | v1 --> v3------v1
\ | / \ /
\ | / \ /
v2 v2
*/
void MeshOperations::edge_flip(int edge_index)
{
int he02 = _system.edges[edge_index]._hedge;
int he20 = _system.halfedges[he02].pair;
int he21 = _system.halfedges[he02].next;
int he10 = _system.halfedges[he21].next;
int he03 = _system.halfedges[he20].next;
int he32 = _system.halfedges[he03].next;
int v0 = _system.halfedges[he02].vert_from;
int v1 = _system.halfedges[he21].vert_to;
int v2 = _system.halfedges[he02].vert_to;
int v3 = _system.halfedges[he03].vert_to;
int f021 = _system.halfedges[he02].face;
int f203 = _system.halfedges[he20].face;
//repurposed halfedges
int he13 = he02;
_system.halfedges[he13].vert_from = v1;
_system.halfedges[he13].vert_to = v3;
int he31 = he20;
_system.halfedges[he31].vert_from = v3;
_system.halfedges[he31].vert_to = v1;
//repurposed faces
int f132 = f021;
_system.faces[f132]._hedge = he13;
_system.faces[f132].v1 = v1;
_system.faces[f132].v2 = v3;
_system.faces[f132].v3 = v2;
int f310 = f203;
_system.faces[f310]._hedge = he31;
_system.faces[f310].v1 = v3;
_system.faces[f310].v2 = v1;
_system.faces[f310].v3 = v0;
//repurposed edge
_system.edges[edge_index].i = v1;
_system.edges[edge_index].j = v3;
_system.edges[edge_index].v0 = v1;
_system.edges[edge_index].v1 = v2;
_system.edges[edge_index].v2 = v3;
_system.edges[edge_index].v3 = v0;
//updating halfedges
_system.halfedges[he13].next = he32;
_system.halfedges[he32].prev = he13;
_system.halfedges[he32].next = he21;
_system.halfedges[he21].prev = he32;
_system.halfedges[he21].next = he13;
_system.halfedges[he13].prev = he21;
_system.halfedges[he31].next = he10;
_system.halfedges[he10].prev = he31;
_system.halfedges[he10].next = he03;
_system.halfedges[he03].prev = he10;
_system.halfedges[he03].next = he31;
_system.halfedges[he31].prev = he03;
_system.halfedges[he32].face = f132;
_system.halfedges[he10].face = f310;
//updating vertices
_system.vertices[v0]._hedge = he03;
_system.vertices[v2]._hedge = he21;
//updating edge
int edge = _system.halfedges[he10].edge;
if (_system.edges[edge].v1 == v2)
_system.edges[edge].v1 = v3;
if (_system.edges[edge].v3 == v2)
_system.edges[edge].v3 = v3;
edge = _system.halfedges[he03].edge;
if (_system.edges[edge].v1 == v2)
_system.edges[edge].v1 = v1;
if (_system.edges[edge].v3 == v2)
_system.edges[edge].v3 = v1;
edge = _system.halfedges[he32].edge;
if (_system.edges[edge].v1 == v0)
_system.edges[edge].v1 = v1;
if (_system.edges[edge].v3 == v0)
_system.edges[edge].v3 = v1;
edge = _system.halfedges[he21].edge;
if (_system.edges[edge].v1 == v0)
_system.edges[edge].v1 = v3;
if (_system.edges[edge].v3 == v0)
_system.edges[edge].v3 = v3;
}
void MeshOperations::refine_mesh_edge_flip()
{
for(int edge_index=0; edge_index<_system.Numedges; edge_index++)
{
if (edge_need_flip(edge_index))
edge_flip(edge_index);
}
}
/*
void MeshOperations::equiangulation(void)
{
Equiangulation_kernel(_system.Numedges,
(&_system.faces[0]),
(&_system.vertices[0]),
(&_system.edges[0]),
(&_system.halfedges[0]),
true
);
for (int flip_edge_index = 0;
flip_edge_index < _system.Numedges;
flip_edge_index += 1)
{
// retrieve the vertices around the edge
int v0 = _system.edges[flip_edge_index].v0;
int v1 = _system.edges[flip_edge_index].v1;
int v2 = _system.edges[flip_edge_index].v2;
int v3 = _system.edges[flip_edge_index].v3;
auto need_flip = pymemb::is_equiangular(_system.vertices[v0].r,
_system.vertices[v1].r,
_system.vertices[v2].r,
_system.vertices[v3].r,
_system.get_box());
if (!need_flip)
{
pymemb::EdgeFlip_lambda(flip_edge_index,
true,
&_system.faces[0],
&_system.vertices[0],
&_system.edges[0],
&_system.halfedges[0],
_system.get_box());
py::print("flipped edge =%i\n", flip_edge_index);
}
}
}*/
void MeshOperations::compute_vertex_connexity(int vertex_index)
{
_system.vertices[vertex_index].coordination = 0;
int he = _system.vertices[vertex_index]._hedge;
int first = he;
do
{
_system.vertices[vertex_index].coordination++;
int he_pair = _system.halfedges[he].pair;
he = _system.halfedges[he_pair].next;
} while (he != first);
}
void MeshOperations::compute_vertices_connexities()
{
for (int i=0; i<_system.Numvertices; i++)
{
compute_vertex_connexity(i);
}
}
int MeshOperations::create_vertex(real mass)
{
HE_Vertex<PropertyVertices> vertex;
vertex.id = _system.Numvertices;
vertex.mass = mass;
vertex.type = 1;
_system.vertices.push_back(vertex);
_system.Numvertices++;
return vertex.id;
}
int MeshOperations::create_edge()
{
HE_Edge<PropertyEdges> e;
HE_HalfEdge<PropertyEdges> he0;
HE_HalfEdge<PropertyEdges> he1;
he0.index = _system.Numhalfedges;
he1.index = _system.Numhalfedges+1;
e.id = _system.Numedges;
he0.pair = he1.index;
he0.edge = e.id;
he1.pair = he0.index;
he1.edge = e.id;
e._hedge = he0.index;
_system.edges.push_back(e);
_system.halfedges.push_back(he0);
_system.halfedges.push_back(he1);
_system.Numedges++;
_system.Numhalfedges += 2;
return e.id;
}
int MeshOperations::create_face()
{
HE_Face<PropertyFaces> f;
f.id = _system.Numfaces;
_system.faces.push_back(f);
_system.Numfaces++;
return f.id;
}
void MeshOperations::delete_vertex(int vertex_index)
{
// shift all vertices in the array > vertex_index
for (int vid=vertex_index; vid<_system.Numvertices-1; vid++)
{
_system.vertices[vid] = _system.vertices[vid+1];
_system.vertices[vid].id--;
}
// udpating vertices id in edge structure
for (int edge_id=0; edge_id<_system.Numedges; edge_id++)
{
if (_system.edges[edge_id].i > vertex_index)
_system.edges[edge_id].i--;
if (_system.edges[edge_id].j > vertex_index)
_system.edges[edge_id].j--;
if (_system.edges[edge_id].v0 > vertex_index)
_system.edges[edge_id].v0--;
if (_system.edges[edge_id].v1 > vertex_index)
_system.edges[edge_id].v1--;
if (_system.edges[edge_id].v2 > vertex_index)
_system.edges[edge_id].v2--;
if (_system.edges[edge_id].v3 > vertex_index)
_system.edges[edge_id].v3--;
}
// udpating vertices id in halfedge structure
for (int hedge_id=0; hedge_id<_system.Numhalfedges; hedge_id++)
{
if (_system.halfedges[hedge_id].vert_from > vertex_index)
_system.halfedges[hedge_id].vert_from--;
if (_system.halfedges[hedge_id].vert_to > vertex_index)
_system.halfedges[hedge_id].vert_to--;
}
// updating vertices id in face structure
for (int face_id=0; face_id<_system.Numfaces; face_id++)
{
if (_system.faces[face_id].v1 > vertex_index)
_system.faces[face_id].v1--;
if (_system.faces[face_id].v2 > vertex_index)
_system.faces[face_id].v2--;
if (_system.faces[face_id].v3 > vertex_index)
_system.faces[face_id].v3--;
}
_system.Numvertices--;
}
void MeshOperations::delete_edge(int edge_index)
{
int he = _system.edges[edge_index]._hedge;
int he_pair = _system.halfedges[he].pair;
if (he < he_pair)
he_pair--;
delete_hedge(he);
delete_hedge(he_pair);
// shift all edges in the array > edge_index
for (int edge_id=edge_index; edge_id<_system.Numedges-1; edge_id++)
{
_system.edges[edge_id] = _system.edges[edge_id+1];
_system.edges[edge_id].id--;
}
// udpating edges id in halfedge structure
for (int hedge_id=0; hedge_id<_system.Numhalfedges; hedge_id++)
{
if(_system.halfedges[hedge_id].edge > edge_index)
_system.halfedges[hedge_id].edge--;
}
_system.Numedges--;
}
void MeshOperations::delete_face(int face_index)
{
// shift all faces in the array > face_index
for (int face_id=face_index; face_id<_system.Numfaces-1; face_id++)
{
_system.faces[face_id] = _system.faces[face_id+1];
_system.faces[face_id].id--;
}
// udpating faces id in edge structure
for (int edge_id=0; edge_id<_system.Numedges; edge_id++)
{
if (_system.edges[edge_id].face_k > face_index)
_system.edges[edge_id].face_k--;
if (_system.edges[edge_id].face_l > face_index)
_system.edges[edge_id].face_l--;
}
// udpating faces id in halfedge structure
for (int hedge_id=0; hedge_id<_system.Numhalfedges; hedge_id++)
{
if (_system.halfedges[hedge_id].face > face_index)
_system.halfedges[hedge_id].face--;
}
_system.Numfaces--;
}
void MeshOperations::delete_hedge(int hedge_index)
{
// shift all halfedges in the array > hedge_index
for (int hedge_id=hedge_index; hedge_id<_system.Numhalfedges-1; hedge_id++)
{
_system.halfedges[hedge_id] = _system.halfedges[hedge_id+1];
_system.halfedges[hedge_id].index--;
}
// udpating halfedges id in vertex structure
for (int vertex_id=0; vertex_id<_system.Numvertices; vertex_id++)
{
if (_system.vertices[vertex_id]._hedge > hedge_index)
_system.vertices[vertex_id]._hedge--;
}
// updating halfedges id in edge structure
for (int edge_id=0; edge_id<_system.Numedges; edge_id++)
{
if (_system.edges[edge_id]._hedge > hedge_index)
_system.edges[edge_id]._hedge--;
}
// updating halfedges id in face structure
for (int face_id=0; face_id<_system.Numfaces; face_id++)
{
if (_system.faces[face_id]._hedge > hedge_index)
_system.faces[face_id]._hedge--;
}
_system.Numhalfedges--;
for (int hedge_id=0; hedge_id<_system.Numhalfedges; hedge_id++)
{
if (_system.halfedges[hedge_id].next > hedge_index)
_system.halfedges[hedge_id].next--;
if (_system.halfedges[hedge_id].pair > hedge_index)
_system.halfedges[hedge_id].pair--;
if (_system.halfedges[hedge_id].prev > hedge_index)
_system.halfedges[hedge_id].prev--;
}
}
bool MeshOperations::edge_can_collapse(int edge_index)
{
int he01 = _system.edges[edge_index]._hedge;
int v0 = _system.halfedges[he01].vert_from;
int v1 = _system.halfedges[he01].vert_to;
// First we check which of the two points will be kept
// if one of them is higher type, we keep this one
if (_system.vertices[v0].type < _system.vertices[v1].type)
{
he01 = _system.halfedges[he01].pair;
v0 = _system.halfedges[he01].vert_from;
v1 = _system.halfedges[he01].vert_to;
}
real3 r0 = _system.vertices[v0].r;
real3 r1 = _system.vertices[v1].r;
int he = _system.vertices[v0]._hedge;
int first = he;
std::set<int> v0_neighbours;
do
{
v0_neighbours.insert(_system.halfedges[he].vert_to);
he = _system.halfedges[he].pair;
he = _system.halfedges[he].next;
} while (he != first);
int count = 0;
he = _system.vertices[v1]._hedge;
first = he;
do
{
if( v0_neighbours.find(_system.halfedges[he].vert_to) != v0_neighbours.end())
count++;
he = _system.halfedges[he].pair;
he = _system.halfedges[he].next;
} while (he != first);
if (count != 2)
return false;
int stop = _system.halfedges[he01].pair;
he = _system.halfedges[he01].next;
he = _system.halfedges[he].pair;
he = _system.halfedges[he].next;
do
{
int v2 = _system.halfedges[he].vert_to;
int he_next = _system.halfedges[he].next;
int v3 = _system.halfedges[he_next].vert_to;
real3 r2 = _system.vertices[v2].r;
real3 r3 = _system.vertices[v3].r;
real3 n123 = pymemb::compute_normal_triangle_unit(r1, r2, r3);
real3 n023 = pymemb::compute_normal_triangle_unit(r0, r2, r3);
// a triangle will flip, can't perform edge collapse
if (pymemb::vector_dot(n123, n023) <= 0)
return false;
he = _system.halfedges[he].pair;
he = _system.halfedges[he].next;
} while (he != stop);
return true;
}
/* Collapsing edge v0v1
*/
void MeshOperations::edge_case_collapse(int he01, int &del_e1, int &del_e2, int &del_f0, int &del_f1)
{
int he12 = _system.halfedges[he01].next;
int he20 = _system.halfedges[he12].next;
int he10 = _system.halfedges[he01].pair;
int he03 = _system.halfedges[he10].next;
int he31 = _system.halfedges[he03].next;
int he = _system.halfedges[he31].pair;
int he32 = _system.halfedges[he].next;
int v0 = _system.halfedges[he01].vert_from;
int v1 = _system.halfedges[he01].vert_to;
int v2 = _system.halfedges[he20].vert_from;
int v3 = _system.halfedges[he03].vert_to;
del_e1 = _system.halfedges[he12].edge;
del_e2 = _system.halfedges[he31].edge;
del_f0 = _system.halfedges[he01].face;
del_f1 = _system.halfedges[he10].face;
int f132 = _system.halfedges[he32].face;
//updating halfedges
_system.halfedges[he20].next = he03;
_system.halfedges[he03].prev = he20;
_system.halfedges[he03].next = he32;
_system.halfedges[he32].prev = he03;
_system.halfedges[he32].next = he20;
_system.halfedges[he20].prev = he32;
_system.halfedges[he20].face = f132;
_system.halfedges[he03].face = f132;
//updating vertices
_system.vertices[v0]._hedge = he03;
_system.vertices[v2]._hedge = he20;
_system.vertices[v3]._hedge = he32;
//updating face
_system.faces[f132].v1 = v0;
_system.faces[f132].v2 = v3;
_system.faces[f132].v3 = v2;
_system.faces[f132]._hedge = he32;
//updating edges
int e02 = _system.halfedges[he20].edge;
if (_system.edges[e02].v1 == v1)
_system.edges[e02].v1 = v3;
if (_system.edges[e02].v3 == v1)
_system.edges[e02].v3 = v3;
int he_pair = _system.halfedges[he20].pair;
_system.edges[e02].face_k = f132;
_system.edges[e02].face_l = _system.halfedges[he_pair].face;
int e03 = _system.halfedges[he03].edge;
if (_system.edges[e03].v1 == v1)
_system.edges[e03].v1 = v2;
if (_system.edges[e03].v3 == v1)
_system.edges[e03].v3 = v2;
he_pair = _system.halfedges[he03].pair;
_system.edges[e03].face_k = f132;
_system.edges[e03].face_l = _system.halfedges[he_pair].face;
int e23 = _system.halfedges[he32].edge;
if (_system.edges[e23].v1 == v1)
_system.edges[e23].v1 = v0;
if (_system.edges[e23].v3 == v1)
_system.edges[e23].v3 = v0;
}
void MeshOperations::edge_collapse(int edge_index, int &del_vertex, int &del_e1,
int &del_e2, int &del_f0, int &del_f1)
{
int he01 = _system.edges[edge_index]._hedge;
int v0 = _system.halfedges[he01].vert_from;
int v1 = _system.halfedges[he01].vert_to;
// First we check which of the two points will be kept
// if one of them is higher type, we keep this one
if (_system.vertices[v0].type < _system.vertices[v1].type)
{
he01 = _system.halfedges[he01].pair;
v0 = _system.halfedges[he01].vert_from;
v1 = _system.halfedges[he01].vert_to;
}
del_vertex = v1;
compute_vertex_connexity(v1);
// dealing with edge case
if (_system.vertices[v1].coordination == 3)
{
edge_case_collapse(he01, del_e1, del_e2, del_f0, del_f1);
return;
}
// Get all ids needed
del_f0 = _system.halfedges[he01].face;
int he10 = _system.halfedges[he01].pair;
del_f1 = _system.halfedges[he10].face;
int he03 = _system.halfedges[he10].next;
int he31 = _system.halfedges[he03].next;
int he12 = _system.halfedges[he01].next;
int he20 = _system.halfedges[he12].next;
int he = _system.halfedges[he31].pair;
int he35 = _system.halfedges[he].next;
int he51 = _system.halfedges[he35].next;
he = _system.halfedges[he12].pair;
int he14 = _system.halfedges[he].next;
int he42 = _system.halfedges[he14].next;
del_e1 = _system.halfedges[he31].edge;
del_e2 = _system.halfedges[he12].edge;
int v2 =_system.halfedges[he12].vert_to;
int v3 = _system.halfedges[he03].vert_to;
int v4 = _system.halfedges[he14].vert_to;
int v5 = _system.halfedges[he51].vert_from;
he = he14;
do
{
_system.halfedges[he].vert_from = v0;
int edge = _system.halfedges[he].edge;
_system.edges[edge].i = v0;
_system.edges[edge].j = _system.halfedges[he].vert_to;
_system.edges[edge].v0 = v0;
_system.edges[edge].v2 = _system.halfedges[he].vert_to;
int he_pair = _system.halfedges[he].pair;
int he_next = _system.halfedges[he].next;
_system.halfedges[he_pair].vert_to = v0;
//Updating face
int face = _system.halfedges[he].face;
_system.faces[face]._hedge = he_next;
_system.faces[face].v1 = v0;
_system.faces[face].v2 = _system.halfedges[he].vert_to;
_system.faces[face].v3 = _system.halfedges[he_next].vert_to;
int outer_edge = _system.halfedges[he_next].edge;
if (_system.edges[outer_edge].v1 == v1)
_system.edges[outer_edge].v1 = v0;
if (_system.edges[outer_edge].v3 == v1)
_system.edges[outer_edge].v3 = v0;
he = _system.halfedges[he_pair].next;
} while(he != he10);
// Updating vertices
_system.vertices[v2]._hedge = he20;
_system.vertices[v3]._hedge = he35;
_system.vertices[v0]._hedge = he03;
// Updating halfedges
_system.halfedges[he03].next = he35;
_system.halfedges[he35].prev = he03;
_system.halfedges[he51].next = he03;
_system.halfedges[he03].prev = he51;
_system.halfedges[he20].next = he14;
_system.halfedges[he14].prev = he20;
_system.halfedges[he03].face = _system.halfedges[he35].face;
_system.halfedges[he42].next = he20;
_system.halfedges[he20].prev = he42;
_system.halfedges[he20].face = _system.halfedges[he42].face;
// Updating outer edges
int outer_edge = _system.halfedges[he20].edge;
if (_system.edges[outer_edge].v1 == v1)
_system.edges[outer_edge].v1 = v4;
if (_system.edges[outer_edge].v3 == v1)
_system.edges[outer_edge].v3 = v4;
he = _system.halfedges[he20].pair;
_system.edges[outer_edge].face_k = _system.halfedges[he].face;
_system.edges[outer_edge].face_l = _system.halfedges[he14].face;
outer_edge = _system.halfedges[he03].edge;
if (_system.edges[outer_edge].v1 == v1)
_system.edges[outer_edge].v1 = v5;
if (_system.edges[outer_edge].v3 == v1)
_system.edges[outer_edge].v3 = v5;
he = _system.halfedges[he03].pair;
_system.edges[outer_edge].face_k = _system.halfedges[he].face;
_system.edges[outer_edge].face_l = _system.halfedges[he35].face;
}
/* Splitting edge v0v2
v0 v0
/ | \ / | \
/ | \ / | \
v3 | v1 --> v3--v4--v1
\ | / \ | /
\ | / \ | /
v2 v2
Repurpose face : f034 = f032 // f041 = f021
Repurpose edge : e04 = e02
Repurpose halfedge : he04 = he02 // he40 = he20
*/
void MeshOperations::edge_split(int edge_index, int v4, int e34, int e14, int e24,
int f243, int f142)
{
// First get all ids needed
int he02 = _system.edges[edge_index]._hedge;
int v0 = _system.halfedges[he02].vert_from;
int v2 = _system.halfedges[he02].vert_to;
int he21 = _system.halfedges[he02].next;
int v1 = _system.halfedges[he21].vert_to;
int he_pair = _system.halfedges[he02].pair;
int he03 = _system.halfedges[he_pair].next;
int v3 = _system.halfedges[he03].vert_to;
int he23 = _system.halfedges[he03].next;
he23 = _system.halfedges[he23].pair;
int he01 = _system.halfedges[he21].next;
he01 = _system.halfedges[he01].pair;
int he34 = _system.edges[e34]._hedge;
int he43 = _system.halfedges[he34].pair;
int he14 = _system.edges[e14]._hedge;
int he41 = _system.halfedges[he14].pair;
int he24 = _system.edges[e24]._hedge;
int he42 = _system.halfedges[he24].pair;
int f021 = _system.halfedges[he02].face;
int f032 = _system.halfedges[he03].face;
_system.vertices[v4].r = pymemb::vector_sum(_system.vertices[v0].r, _system.vertices[v2].r);
aXvec(0.5, _system.vertices[v4].r);
_system.vertices[v4]._hedge = he43;
_system.vertices[v4].type = std::min(_system.vertices[v0].type, _system.vertices[v2].type);
// Setting up topology on new halfedges
_system.halfedges[he34].vert_from = v3;
_system.halfedges[he34].vert_to = v4;
_system.halfedges[he34].next = _system.halfedges[he02].pair;
_system.halfedges[he34].prev = he03;
_system.halfedges[he34].face = f032;
_system.halfedges[he43].vert_from = v4;
_system.halfedges[he43].vert_to = v3;
_system.halfedges[he43].next = _system.halfedges[he23].pair;
_system.halfedges[he43].prev = he24;
_system.halfedges[he43].face = f243;
_system.halfedges[he14].vert_from = v1;
_system.halfedges[he14].vert_to = v4;
_system.halfedges[he14].next = he42;
_system.halfedges[he14].prev = he21;
_system.halfedges[he14].face = f142;
_system.halfedges[he41].vert_from = v4;
_system.halfedges[he41].vert_to = v1;
_system.halfedges[he41].next = _system.halfedges[he01].pair;
_system.halfedges[he41].prev = he02;
_system.halfedges[he41].face = f021;
_system.halfedges[he24].vert_from = v2;
_system.halfedges[he24].vert_to = v4;
_system.halfedges[he24].next = he43;
_system.halfedges[he24].prev = _system.halfedges[he23].pair;
_system.halfedges[he24].face = f243;
_system.halfedges[he42].vert_from = v4;
_system.halfedges[he42].vert_to = v2;
_system.halfedges[he42].next = he21;
_system.halfedges[he42].prev = he14;
_system.halfedges[he42].face = f142;
// Setting up new edges
_system.edges[e34].i = v3;
_system.edges[e34].j = v4;
_system.edges[e34]._hedge = he34;
_system.edges[e34].face_k = _system.halfedges[he34].face;
_system.edges[e34].face_l = _system.halfedges[he43].face;
_system.edges[e34].v0 = v3;
_system.edges[e34].v1 = v0;
_system.edges[e34].v2 = v4;
_system.edges[e34].v3 = v2;
_system.edges[e14].i = v1;
_system.edges[e14].j = v4;
_system.edges[e14]._hedge = he14;
_system.edges[e14].face_k = _system.halfedges[he14].face;
_system.edges[e14].face_l = _system.halfedges[he41].face;
_system.edges[e14].v0 = v1;
_system.edges[e14].v1 = v2;
_system.edges[e14].v2 = v4;
_system.edges[e14].v3 = v0;
_system.edges[e24].i = v2;
_system.edges[e24].j = v4;
_system.edges[e24]._hedge = he24;
_system.edges[e24].face_k = _system.halfedges[he24].face;
_system.edges[e24].face_l = _system.halfedges[he42].face;
_system.edges[e24].v0 = v2;
_system.edges[e24].v1 = v3;
_system.edges[e24].v2 = v4;
_system.edges[e24].v3 = v1;
// Setting up new face
_system.faces[f243].v1 = v2;
_system.faces[f243].v2 = v4;
_system.faces[f243].v3 = v3;
_system.faces[f243]._hedge = he24;
_system.faces[f142].v1 = v1;
_system.faces[f142].v2 = v4;
_system.faces[f142].v3 = v2;
_system.faces[f142]._hedge = he14;
// Updating vertices
_system.vertices[v2]._hedge = he21;
// Updating repurposed halfedges
_system.halfedges[he02].vert_to = v4;
_system.halfedges[he02].next = he41;
int he = _system.halfedges[he02].pair;
_system.halfedges[he].vert_from = v4;
_system.halfedges[he].prev = he34;
// Updating repurposed edge
_system.edges[edge_index].i = v0;
_system.edges[edge_index].j = v4;
_system.edges[edge_index].v0 = v0;
_system.edges[edge_index].v1 = v1;
_system.edges[edge_index].v2 = v4;
_system.edges[edge_index].v3 = v3;
// Updating repurposed faces
_system.faces[f021].v1 = v0;
_system.faces[f021].v2 = v4;
_system.faces[f021].v3 = v1;
_system.faces[f021]._hedge = he02;
_system.faces[f032].v1 = v0;
_system.faces[f032].v2 = v3;
_system.faces[f032].v3 = v4;
_system.faces[f032]._hedge = he03;
// Updating exterior halfedges
he = _system.halfedges[he23].pair;
_system.halfedges[he].face = f243;
_system.halfedges[he].next = he24;
_system.halfedges[he].prev = he43;
_system.halfedges[he21].face = f142;
_system.halfedges[he21].next = he14;
_system.halfedges[he21].prev = he42;
he = _system.halfedges[he01].pair;
_system.halfedges[he].prev = he41;
_system.halfedges[he03].next = he34;
// Updating exterior edges
int e = _system.halfedges[he23].edge;
_system.edges[e].face_k = _system.halfedges[he23].face;
_system.edges[e].face_l = _system.halfedges[he24].face;
_system.edges[e].v0 = v2;
he = _system.halfedges[he23].next;
_system.edges[e].v1 = _system.halfedges[he].vert_to;
_system.edges[e].v2 = v3;
_system.edges[e].v3 = v4;
e = _system.halfedges[he21].edge;
_system.edges[e].face_k = _system.halfedges[he21].face;
he = _system.halfedges[he21].pair;
_system.edges[e].face_l = _system.halfedges[he].face;
_system.edges[e].v0 = v2;
he = _system.halfedges[he].next;
_system.edges[e].v1 = _system.halfedges[he].vert_to;
_system.edges[e].v2 = v1;
_system.edges[e].v3 = v4;
e = _system.halfedges[he01].edge;
_system.edges[e].face_k = _system.halfedges[he01].face;
_system.edges[e].face_l = _system.halfedges[he02].face;
_system.edges[e].v0 = v0;
_system.edges[e].v1 = v4;
_system.edges[e].v2 = v1;
he = _system.halfedges[he01].next;
_system.edges[e].v3 = _system.halfedges[he].vert_to;
e = _system.halfedges[he03].edge;
_system.edges[e].face_k = _system.halfedges[he03].face;
he = _system.halfedges[he03].pair;
_system.edges[e].face_l = _system.halfedges[he].face;
_system.edges[e].v0 = v0;
_system.edges[e].v1 = v4;
_system.edges[e].v2 = v3;
he = _system.halfedges[he].next;
_system.edges[e].v3 = _system.halfedges[he].vert_to;
}
void MeshOperations::refine_mesh_edge_split(real threshold)
{
real avg_edge_length = compute_average_edge_length();
for (int edge_id=0; edge_id<_system.Numedges; edge_id++)
{
int v0 = _system.edges[edge_id].i;
int v1 = _system.edges[edge_id].j;
real edge_length = pymemb::vector_length(pymemb::vector_subtract(_system.vertices[v0].r, _system.vertices[v1].r));
if (edge_length/avg_edge_length > threshold)
{
int v = create_vertex();
int e0 = create_edge();
int e1 = create_edge();
int e2 = create_edge();
int f0 = create_face();
int f1 = create_face();
edge_split(edge_id, v, e0, e1, e2, f0, f1);
}
}
}
void MeshOperations::simplify_mesh(real threshold)
{
real avg_edge_length = compute_average_edge_length();
for (int edge_id=0; edge_id<_system.Numedges; edge_id++)
{
int v0 = _system.edges[edge_id].i;
int v1 = _system.edges[edge_id].j;
real edge_length = pymemb::vector_length(pymemb::vector_subtract(_system.vertices[v0].r, _system.vertices[v1].r));
if (edge_length/avg_edge_length < threshold)
{
int del_v, del_e1, del_e2, del_f0, del_f1;
edge_collapse(edge_id, del_v, del_e1, del_e2, del_f0, del_f1);
delete_vertex(del_v);
_system.vertices.resize(_system.Numvertices);
delete_edge(del_e1);
if (del_e1 < del_e2)
del_e2--;
if (del_e1 < edge_id)
edge_id--;
delete_edge(del_e2);
if (del_e2 < edge_id)
edge_id--;
delete_edge(edge_id);
_system.halfedges.resize(_system.Numhalfedges);
_system.edges.resize(_system.Numedges);
delete_face(del_f0);
if (del_f0 < del_f1)
del_f1--;
delete_face(del_f1);
_system.faces.resize(_system.Numfaces);
}
}
}
void MeshOperations::adapt_mesh(real threshold)
{
real avg_edge_length = compute_average_edge_length();
std::vector<std::pair<real, int>> sorted_edges;
for (int edge_id=0; edge_id<_system.Numedges; edge_id++)
{
real3 a = _system.vertices[_system.edges[edge_id].i].r;
real3 b = _system.vertices[_system.edges[edge_id].j].r;
std::pair<real, int> len_edge(pymemb::vector_length(pymemb::vector_subtract(a, b)), edge_id);
sorted_edges.push_back(len_edge);
}
std::sort(sorted_edges.begin(), sorted_edges.end());
int i=0;
int j=sorted_edges.size()-1;
while (i < j)
{
real min_ratio = sorted_edges[i].first/avg_edge_length;
real max_ratio = sorted_edges[j].first/avg_edge_length;
if (min_ratio < threshold || max_ratio > (1/threshold))
{
if (edge_can_collapse(sorted_edges[i].second))
{
int del_e1, del_e2, del_v, del_f0, del_f1;
edge_collapse(sorted_edges[i].second, del_v, del_e1, del_e2, del_f0, del_f1);
while (del_e1 == sorted_edges[j].second || del_e2 == sorted_edges[j].second)
j--;
edge_split(sorted_edges[j].second, del_v, sorted_edges[i].second, del_e1, del_e2, del_f0, del_f1);
}
else
j++;
}
else
break;
i++;
j--;
}
}