blob: 62175fdf54cb133732b86832caea799e2e3659d0 [file] [log] [blame]
//#####################################################################
// Copyright 2002-2004, Chris Allocco, Robert Bridson, Ron Fedkiw, Geoffrey Irving, Eran Guendelman, Sergey Koltakov, Neil Molino, Igor Neverov, Andrew Selle, Joseph Teran.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class TRIANGULATED_SURFACE
//#####################################################################
#ifndef __TRIANGULATED_SURFACE__
#define __TRIANGULATED_SURFACE__
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include "TRIANGULATED_OBJECT.h"
#include "TRIANGLE_3D.h"
#include "../Collisions_And_Interactions/PARTICLE_PARTITION.h"
#include "../Grids/TRIANGLE_MESH.h"
#include "../Particles/SOLIDS_PARTICLE.h"
#include "../Matrices_And_Vectors/VECTOR_3D.h"
#include "../Arrays/ARRAY.h"
#include "../Arrays/ARRAYS.h"
#include "../Arrays/ARRAYS_3D.h"
namespace PhysBAM
{
template<class T> class GRID_3D;
template<class T> class OCTREE_GRID;
template<class T> class IMPLICIT_SURFACE;
template<class T>
class TRIANGULATED_SURFACE: public TRIANGULATED_OBJECT<T, VECTOR_3D<T> >
{
public:
using TRIANGULATED_OBJECT<T, VECTOR_3D<T> >::triangle_mesh;
using TRIANGULATED_OBJECT<T, VECTOR_3D<T> >::particles;
using TRIANGULATED_OBJECT<T, VECTOR_3D<T> >::Discard_Valence_Zero_Particles_And_Renumber;
LIST_ARRAY<TRIANGLE_3D<T> >* triangle_list;
BOX_3D<T>* bounding_box;
ARRAY<T>* segment_lengths;
PARTICLE_PARTITION<T>* particle_partition;
int desired_particle_partition_size_m, desired_particle_partition_size_n, desired_particle_partition_size_mn;
bool use_vertex_normals, avoid_normal_interpolation_across_sharp_edges;
T normal_variance_threshold;
ARRAYS<VECTOR_3D<T> >* vertex_normals;
T density;
TRIANGULATED_SURFACE (TRIANGLE_MESH& triangle_mesh_input, SOLIDS_PARTICLE<T, VECTOR_3D<T> >& particles_input)
: TRIANGULATED_OBJECT<T, VECTOR_3D<T> > (triangle_mesh_input, particles_input),
triangle_list (0), bounding_box (0), segment_lengths (0), particle_partition (0),
desired_particle_partition_size_m (0), desired_particle_partition_size_n (0), desired_particle_partition_size_mn (0),
avoid_normal_interpolation_across_sharp_edges (false), normal_variance_threshold ( (T).1),
vertex_normals (0)
{
Use_Face_Normals();
Set_Density();
}
virtual ~TRIANGULATED_SURFACE()
{
delete triangle_list;
delete bounding_box;
delete segment_lengths;
delete particle_partition;
delete vertex_normals;
}
static TRIANGULATED_SURFACE* Create()
{
return new TRIANGULATED_SURFACE (* (new TRIANGLE_MESH), * (new SOLIDS_PARTICLE<T, VECTOR_3D<T> >));
}
void Destroy_Data() // this is dangerous
{
delete &triangle_mesh;
delete &particles;
}
void Clean_Up_Memory()
{
delete triangle_list;
triangle_list = 0;
delete bounding_box;
bounding_box = 0;
delete segment_lengths;
segment_lengths = 0;
delete particle_partition;
particle_partition = 0;
delete vertex_normals;
vertex_normals = 0;
Use_Face_Normals();
}
void Refresh_Auxiliary_Structures()
{
TRIANGULATED_OBJECT<T, VECTOR_3D<T> >::Refresh_Auxiliary_Structures();
if (triangle_list) Update_Triangle_List();
if (vertex_normals) Update_Vertex_Normals();
if (bounding_box) Update_Bounding_Box();
if (segment_lengths) Initialize_Segment_Lengths();
}
void Initialize_Triangle_Hierarchy (const bool update_boxes = true) // creates and updates the boxes as well
{}
void Initialize_Particle_Partition (const int m = 0, const int n = 0, const int mn = 0)
{
assert (bounding_box);
int m_new = m, n_new = n, mn_new = mn;
if (desired_particle_partition_size_m) m_new = desired_particle_partition_size_m;
if (desired_particle_partition_size_n) n_new = desired_particle_partition_size_n;
if (desired_particle_partition_size_mn) mn_new = desired_particle_partition_size_mn;
assert (m_new && n_new && mn_new);
delete particle_partition;
particle_partition = new PARTICLE_PARTITION<T> (*bounding_box, m_new, n_new, mn_new, particles);
}
void Initialize_Particle_Hierarchy (const bool update_boxes = true);
void Set_Desired_Particle_Partition_Size (const int m, const int n, const int mn)
{
desired_particle_partition_size_m = m;
desired_particle_partition_size_n = n;
desired_particle_partition_size_mn = mn;
}
void Use_Vertex_Normals() // averaged on the faces
{
use_vertex_normals = true;
}
void Use_Face_Normals() // i.e. flat normals
{
use_vertex_normals = false;
}
void Set_Density (const T density_input = 100) // default is water
{
density = density_input;
}
TRIANGLE_3D<T> Get_Triangle (const int aggregate_id) const
{
return TRIANGLE_3D<T> (particles.X (triangle_mesh.triangles (1, aggregate_id)), particles.X (triangle_mesh.triangles (2, aggregate_id)), particles.X (triangle_mesh.triangles (3, aggregate_id)));
}
VECTOR_3D<T> Face_Normal (const int index) const
{
if (triangle_list) return (*triangle_list) (index).normal;
int i, j, k;
triangle_mesh.triangles.Get (index, i, j, k);
return TRIANGLE_3D<T>::Clockwise_Normal (particles.X (i), particles.X (j), particles.X (k));
}
VECTOR_3D<T> Centroid (const int triangle) const
{
int i, j, k;
triangle_mesh.triangles.Get (triangle, i, j, k);
return (T) one_third * (particles.X (i) + particles.X (j) + particles.X (k));
}
T Area (const int triangle) const
{
int i, j, k;
triangle_mesh.triangles.Get (triangle, i, j, k);
return TRIANGLE_3D<T>::Area (particles.X (i), particles.X (j), particles.X (k));
}
void Rescale (const T scaling_factor)
{
Rescale (scaling_factor, scaling_factor, scaling_factor);
}
void Rescale (const T scaling_x, const T scaling_y, const T scaling_z)
{
for (int k = 1; k <= particles.number; k++) particles.X (k) *= VECTOR_3D<T> (scaling_x, scaling_y, scaling_z);
if (triangle_list) Update_Triangle_List();
if (bounding_box) Update_Bounding_Box();
}
void Print_Mesh_Diagnostics()
{
std::cout << "MESH DIAGNOSTICS" << std::endl;
if (Check_For_Self_Intersection ( (T) 1e-8)) std::cout << "found self intersections!" << std::endl;
else std::cout << "no self intersections" << std::endl;
std::cout << "total Triangles = " << triangle_mesh.triangles.m << std::endl;
std::cout << "total Mass = " << particles.mass.Total_Mass (particles) << std::endl;
std::cout << "min Mass Particle = " << particles.mass.Minimum_Mass (particles) << std::endl;
std::cout << "max Mass Particle = " << particles.mass.Maximum_Mass (particles) << std::endl;
std::cout << "total Area = " << Total_Area() << std::endl;
std::cout << "min Area = " << Minimum_Area() << std::endl;
std::cout << "Density = " << density << std::endl;
std::cout << "min Altitude = " << Minimum_Altitude() << std::endl;
std::cout << "min Edge Length = " << Minimum_Edge_Length() << std::endl;
std::cout << "max Edge Length = " << Maximum_Edge_Length() << std::endl;
std::cout << "min Angle = " << Minimum_Angle() << std::endl;
std::cout << "max Angle = " << Maximum_Angle() << std::endl;
std::cout << "ave min Angle = " << Average_Minimum_Angle() << std::endl;
std::cout << "ave max Angle = " << Average_Maximum_Angle() << std::endl;
std::cout << "max Aspect Ratio = " << Maximum_Aspect_Ratio() << std::endl;
std::cout << "ave Aspect Ratio = " << Average_Aspect_Ratio() << std::endl;
}
//#####################################################################
void Update_Triangle_List(); // updates the triangles assuming the particle particles.Xs are already updated
void Update_Triangle_List (const ARRAY<VECTOR_3D<T> >& X);
void Update_Triangle_List (const ARRAY<VECTOR_3D<T> >& X, const VECTOR_2D<int>& triangle_range);
void Update_Bounding_Box();
void Initialize_Torus_Mesh_And_Particles (const int m, const int n, const T major_radius, const T minor_radius);
void Initialize_Segment_Lengths();
void Update_Vertex_Normals();
bool Intersection (RAY_3D<T>& ray, const T thickness_over_two = 0) const;
bool Closest_Non_Intersecting_Point (RAY_3D<T>& ray, const T thickness_over_two = 0) const;
VECTOR_3D<T> Normal (const VECTOR_3D<T>& location, const int aggregate = 0) const;
bool Inside (const VECTOR_3D<T>& location, const T thickness_over_two = 0) const;
bool Inside_Relative_To_Triangle (const VECTOR_3D<T>& location, const int triangle_index_for_ray_test, const T thickness_over_two = 0) const;
bool Inside_Using_Ray_Test (RAY_3D<T>& ray, const T thickness_over_two = 0) const;
bool Outside (const VECTOR_3D<T>& location, const T thickness_over_two = 0) const;
bool Boundary (const VECTOR_3D<T>& location, const T thickness_over_two = 0) const;
bool Inside_Any_Triangle (const VECTOR_3D<T>& location, int& triangle_id, const T thickness_over_two = 0) const;
VECTOR_3D<T> Surface (const VECTOR_3D<T>& location, const T max_depth = 0, const T thickness = 0, int* closest_triangle = 0, T* distance = 0) const; // without max_depth, this is slow
T Signed_Solid_Angle_Of_Triangle_Web (const VECTOR_3D<T>& location, int web_root_node) const;
bool Check_For_Self_Intersection (const T thickness = 0, const bool update_bounding_boxes = true, LIST_ARRAYS<int>* intersecting_segment_triangle_pairs = 0);
bool Find_First_Segment_Triangle_Intersection (const SEGMENT_MESH& test_segment_mesh, const ARRAY<VECTOR_3D<T> >& X, const T thickness, const int max_coarsening_attempts = 5,
const bool update_bounding_boxes = true);
bool Segment_Triangle_Intersection (const SEGMENT_MESH& test_segment_mesh, const ARRAY<VECTOR_3D<T> >& X, const T thickness = 0, const bool update_bounding_boxes = true,
LIST_ARRAYS<int>* intersecting_segment_triangle_pairs = 0);
void Get_Triangles_Near_Edges (ARRAY<LIST_ARRAY<int> >& triangles_near_edges, const SEGMENT_MESH& test_segment_mesh, const ARRAY<VECTOR_3D<T> >& X, const T thickness = 0,
const bool update_bounding_boxes = true);
VECTOR_3D<T> Centroid_Of_Neighbors (const int node) const;
T Calculate_Signed_Distance (const VECTOR_3D<T>& location, T thickness = 0) const;
void Calculate_Signed_Distance_Function (const GRID_3D<T>& grid, ARRAYS_3D<T>& phi, bool print_progress = false);
void Calculate_Heaviside_Function (const GRID_3D<T>& grid, ARRAYS_3D<T>& phi, bool print_progress = false);
void Calculate_Signed_Distance_Function (const GRID_3D<T>& uniform_grid, OCTREE_GRID<T>& grid, ARRAY<T>& phi, const int maximum_depth, const T half_band_width = 0, const bool verbose = false);
void Linearly_Subdivide();
void Loop_Subdivide();
void Root_Three_Subdivide();
T Total_Area() const;
T Thin_Shell_Mass() const;
T Minimum_Angle (int* index = 0) const;
T Maximum_Angle (int* index = 0) const;
T Average_Minimum_Angle() const;
T Average_Maximum_Angle() const;
T Minimum_Edge_Length (int* index = 0) const;
T Maximum_Edge_Length (int* index = 0) const;
T Average_Edge_Length() const;
T Maximum_Aspect_Ratio (int* index = 0) const;
T Average_Aspect_Ratio() const;
T Minimum_Area (int* index = 0) const;
T Minimum_Altitude (int* index = 0) const;
void Set_Mass_Of_Particles (const bool use_constant_mass = false, const bool verbose = true);
T Maximum_Magnitude_Phi (const IMPLICIT_SURFACE<T>& implicit_surface, int* index = 0);
void Make_Orientations_Consistent_With_Implicit_Surface (const IMPLICIT_SURFACE<T>& implicit_surface);
void Close_Surface (const bool merge_coincident_vertices, const T merge_coincident_vertices_threshold, const bool fill_holes, const bool verbose = false);
void Remove_Degenerate_Triangles (const T area_threshold = (T) 1e-8);
//#####################################################################
};
}
#endif