blob: cb6c2fc7c7f08c974f2eee6fb539dc176c07d5e6 [file] [log] [blame]
//#####################################################################
// Copyright 2003-2005, Zhaosheng Bao, Ronald Fedkiw, Geoffrey Irving, Sergey Koltakov, Neil Molino, Joseph Teran.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class EMBEDDED_TETRAHEDRALIZED_VOLUME
//#####################################################################
#ifndef __EMBEDDED_TETRAHEDRALIZED_VOLUME__
#define __EMBEDDED_TETRAHEDRALIZED_VOLUME__
#include "EMBEDDED_OBJECT.h"
#include "TETRAHEDRALIZED_VOLUME.h"
namespace PhysBAM
{
template<class T>
class EMBEDDED_TETRAHEDRALIZED_VOLUME: public EMBEDDED_OBJECT<T, VECTOR_3D<T> >
{
public:
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::embedded_particles;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::parent_particles;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::embedded_sub_elements_in_parent_element;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::embedded_sub_elements_in_parent_element_index;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::interpolation_fraction;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::number_of_embedded_sub_elements_in_parent_element;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::Is_Parent;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::Other_Parent;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::Embedded_Particle_On_Segment;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::particles;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::parents_to_embedded_particles_hash_table;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::embedded_children_index;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::Add_Embedded_Particle_To_Embedded_Chidren;
using EMBEDDED_OBJECT<T, VECTOR_3D<T> >::Fraction_Of_Elements_With_Embedded_Sub_Elements;
TETRAHEDRALIZED_VOLUME<T>& tetrahedralized_volume;
TRIANGLE_MESH embedded_triangle_mesh; // used for the embedded surface
TRIANGULATED_SURFACE<T> embedded_surface;
LIST_ARRAYS<bool> node_in_tetrahedron_is_material;
BOX_3D<T>* bounding_box;
EMBEDDED_TETRAHEDRALIZED_VOLUME (TETRAHEDRALIZED_VOLUME<T>& tetrahedralized_volume_input)
: EMBEDDED_OBJECT<T, VECTOR_3D<T> > (tetrahedralized_volume_input.particles),
tetrahedralized_volume (tetrahedralized_volume_input), embedded_surface (embedded_triangle_mesh, embedded_particles),
node_in_tetrahedron_is_material (4, 0), bounding_box (0)
{}
virtual ~EMBEDDED_TETRAHEDRALIZED_VOLUME()
{
delete bounding_box;
}
static EMBEDDED_TETRAHEDRALIZED_VOLUME* Create()
{
return new EMBEDDED_TETRAHEDRALIZED_VOLUME (*TETRAHEDRALIZED_VOLUME<T>::Create());
}
void Destroy_Data() // this is dangerous
{
tetrahedralized_volume.Destroy_Data();
delete &tetrahedralized_volume;
}
void Clean_Up_Memory()
{
EMBEDDED_OBJECT<T, VECTOR_3D<T> >::Clean_Up_Memory();
embedded_surface.Clean_Up_Memory();
embedded_triangle_mesh.Clean_Up_Memory();
node_in_tetrahedron_is_material.Resize_Array (4, 0);
delete bounding_box;
bounding_box = 0;
}
void Initialize_Node_In_Tetrahedron_Is_Material()
{
if (node_in_tetrahedron_is_material.m == tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m) return; // don't overwrite existing values if they exist
node_in_tetrahedron_is_material.Resize_Array (4, tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m, false, false);
LIST_ARRAYS<bool>::copy (true, node_in_tetrahedron_is_material);
}
bool Node_In_Tetrahedron_Is_Material (const int node, const int tetrahedron) const
{
int i, j, k, l;
tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.Get (tetrahedron, i, j, k, l);
if (node == i) return node_in_tetrahedron_is_material (1, tetrahedron);
else if (node == j) return node_in_tetrahedron_is_material (2, tetrahedron);
else if (node == k) return node_in_tetrahedron_is_material (3, tetrahedron);
else
{
assert (node == l);
return node_in_tetrahedron_is_material (4, tetrahedron);
}
}
int Node_Separated_By_Embedded_Triangle (const int embedded_triangle) const
{
int a, b, c;
embedded_triangle_mesh.triangles.Get (embedded_triangle, a, b, c);
int ppa1, ppa2, ppb1, ppb2, ppc1, ppc2;
parent_particles.Get (a, ppa1, ppa2);
parent_particles.Get (b, ppb1, ppb2);
parent_particles.Get (c, ppc1, ppc2);
if (Is_Parent (ppa1, b) && Is_Parent (ppa1, c)) return ppa1;
else if (Is_Parent (ppa2, b) && Is_Parent (ppa2, c)) return ppa2;
else return 0;
}
bool Nodes_Are_Separated_In_Tetrahedron (const int node1, const int node2, const int tetrahedron)
{
int embedded_node = Embedded_Particle_On_Segment (node1, node2);
if (!embedded_node) return false;
int triangle_1, triangle_2, triangle_3, triangle_4;
Embedded_Triangles_In_Tetrahedron (tetrahedron, triangle_1, triangle_2, triangle_3, triangle_4);
if (!triangle_1) return false;
else if (embedded_triangle_mesh.Node_In_Triangle (embedded_node, triangle_1)) return true;
if (!triangle_2) return false;
else if (embedded_triangle_mesh.Node_In_Triangle (embedded_node, triangle_2)) return true;
if (!triangle_3) return false;
else if (embedded_triangle_mesh.Node_In_Triangle (embedded_node, triangle_3)) return true;
if (!triangle_4) return false;
else if (embedded_triangle_mesh.Node_In_Triangle (embedded_node, triangle_4)) return true;
return false;
}
int Number_Of_Embedded_Cuts (const int tetrahedron) // a quad only counts as one cut
{
int triangle_1, triangle_2, triangle_3, triangle_4, triangle_count = Embedded_Triangles_In_Tetrahedron (tetrahedron, triangle_1, triangle_2, triangle_3, triangle_4);
if (Cut_By_Quad (tetrahedron)) return triangle_count - 1;
else return triangle_count;
}
bool Cut_By_Quad (const int tetrahedron)
{
int triangle_1, triangle_2, triangle_3, triangle_4, triangle_count = Embedded_Triangles_In_Tetrahedron (tetrahedron, triangle_1, triangle_2, triangle_3, triangle_4);
if (triangle_count <= 1) return false;
else if (triangle_count == 2)
{
if (Node_Separated_By_Embedded_Triangle (triangle_1)) return false;
else return true;
}
else if (triangle_count == 3)
{
if (!Node_Separated_By_Embedded_Triangle (triangle_1) || !Node_Separated_By_Embedded_Triangle (triangle_2) || !Node_Separated_By_Embedded_Triangle (triangle_3)) return true;
else return false;
}
else return true;
} // if four embedded triangles, there must be a quad
bool Segment_Is_Broken (const int node1, const int node2)
{
int particle_on_segment = Embedded_Particle_On_Segment (node1, node2);
if (!particle_on_segment) return false;
LIST_ARRAY<int> tetrahedrons_on_edge;
tetrahedralized_volume.tetrahedron_mesh.Tetrahedrons_On_Edge (node1, node2, &tetrahedrons_on_edge);
for (int t = 1; t <= tetrahedrons_on_edge.m; t++) if (!Nodes_Are_Separated_In_Tetrahedron (node1, node2, tetrahedrons_on_edge (t))) return false;
return true;
}
int Number_Of_Edges_With_Embedded_Particles (const int tetrahedron)
{
int i, j, k, l;
tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.Get (tetrahedron, i, j, k, l);
int ij = Embedded_Particle_On_Segment (i, j), ik = Embedded_Particle_On_Segment (i, k), il = Embedded_Particle_On_Segment (i, l),
jk = Embedded_Particle_On_Segment (j, k), jl = Embedded_Particle_On_Segment (j, l), kl = Embedded_Particle_On_Segment (k, l);
return (ij > 0) + (ik > 0) + (il > 0) + (jk > 0) + (jl > 0) + (kl > 0);
}
void Update_Bounding_Box()
{
tetrahedralized_volume.Update_Bounding_Box();
bounding_box->Reset_Bounds (*tetrahedralized_volume.bounding_box);
}
T Fraction_Of_Tetrahedra_With_One_Cut()
{
int count = 0;
for (int t = 1; t <= tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m; t++) if (Number_Of_Embedded_Cuts (t) == 1) count++;
return (T) count / (T) tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m;
}
T Fraction_Of_Tetrahedra_With_Two_Cuts()
{
int count = 0;
for (int t = 1; t <= tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m; t++) if (Number_Of_Embedded_Cuts (t) == 2) count++;
return (T) count / (T) tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m;
}
T Fraction_Of_Tetrahedra_With_Three_Cuts()
{
int count = 0;
for (int t = 1; t <= tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m; t++) if (Number_Of_Embedded_Cuts (t) == 3) count++;
return (T) count / (T) tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m;
}
int Number_Of_Tetrahedra_With_Cuts()
{
int count = 0;
for (int t = 1; t <= tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m; t++) if (Number_Of_Embedded_Cuts (t) > 0) count++;
return count;
}
int Number_Of_Tetrahedra_With_One_Cut()
{
int count = 0;
for (int t = 1; t <= tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m; t++) if (Number_Of_Embedded_Cuts (t) == 1) count++;
return count;
}
int Number_Of_Tetrahedra_With_Two_Cuts()
{
int count = 0;
for (int t = 1; t <= tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m; t++) if (Number_Of_Embedded_Cuts (t) == 2) count++;
return count;
}
int Number_Of_Tetrahedra_With_Three_Cuts()
{
int count = 0;
for (int t = 1; t <= tetrahedralized_volume.tetrahedron_mesh.tetrahedrons.m; t++) if (Number_Of_Embedded_Cuts (t) == 3) count++;
return count;
}
int Add_Embedded_Triangle_If_Not_Already_There (const int embedded_particle1_parent1, const int embedded_particle1_parent2, const int embedded_particle2_parent1,
const int embedded_particle2_parent2, const int embedded_particle3_parent1, const int embedded_particle3_parent2)
{
return Add_Embedded_Triangle_If_Not_Already_There (Embedded_Particle_On_Segment (embedded_particle1_parent1, embedded_particle1_parent2),
Embedded_Particle_On_Segment (embedded_particle2_parent1, embedded_particle2_parent2), Embedded_Particle_On_Segment (embedded_particle3_parent1, embedded_particle3_parent2));
}
template<class RW>
void Read (std::istream& input_stream)
{
Clean_Up_Memory();
EMBEDDED_OBJECT<T, VECTOR_3D<T> >::template Read<RW> (input_stream);
tetrahedralized_volume.template Read<RW> (input_stream);
embedded_surface.template Read<RW> (input_stream);
node_in_tetrahedron_is_material.template Read<RW> (input_stream);
}
template<class RW>
void Write (std::ostream& output_stream) const
{
EMBEDDED_OBJECT<T, VECTOR_3D<T> >::template Write<RW> (output_stream);
tetrahedralized_volume.template Write<RW> (output_stream);
embedded_surface.template Write<RW> (output_stream);
node_in_tetrahedron_is_material.template Write<RW> (output_stream);
}
//#####################################################################
int Tetrahedron_Containing_Triangle (const int embedded_triangle) const;
int Embedded_Triangles_In_Tetrahedron (const int tetrahedron, int& first_embedded_triangle, int& second_embedded_triangle, int& third_embedded_triangle, int& fourth_embedded_triangle);
private:
void Add_Embedded_Triangle_To_Embedded_Triangles_In_Tetrahedron (const int triangle); // incrementally update embedded_sub_elements_in_parent_element
public:
int Add_Embedded_Particle_If_Not_Already_There (const int node1, const int node2, T interpolation_fraction_input);
int Add_Embedded_Triangle_If_Not_Already_There (const int embedded_particle1, const int embedded_particle2, const int embedded_particle3);
void Initialize_Embedded_Sub_Elements_In_Parent_Element();
void Calculate_Triangulated_Surface_From_Levelset_On_Tetrahedron_Nodes (ARRAY<T>& phi, const bool discard_tetrahedra_outside_levelset = true, const bool verbose = true);
void Write_Percentage_Of_Tetrahedra_With_Embedded_Triangles (const std::string& output_directory);
//#####################################################################
};
}
#endif