NetDEM v1.0
Loading...
Searching...
No Matches
10_gen_dataset_trimesh.cpp

This is an example of how to use the netdem library.

#include "igl_wrapper.hpp"
#include "particle.hpp"
#include "utils_math.hpp"
#include <fstream>
#include <iostream>
#include <random>
#include <sstream>
#include <string>
using namespace netdem;
using namespace std;
void SaveDatasetTrimeshDetection(int num_samples, double (*ds_inputs)[7],
bool *ds_cnt_flags, string filename) {
stringbuf buf;
ostream os(&buf);
int os_width = 24;
os.setf(ios::scientific);
os.precision(15);
for (int i = 0; i < num_samples; i++) {
for (int i_inputs = 0; i_inputs < 7; i_inputs++) {
os.width(os_width);
os << ds_inputs[i][i_inputs] << ", ";
}
os.width(3);
os << (ds_cnt_flags[i] ? 1 : 0) << endl;
}
ofstream outfile;
outfile.open(filename);
if (!outfile) {
cout << "cannot open file: " << filename << endl;
}
outfile << buf.str();
outfile.close();
cout << "data saved to: " << filename << endl;
}
void SaveDatasetTrimeshResolution(int num_samples, double (*ds_inputs)[7],
double (*ds_cnt_feats)[8], string filename) {
stringbuf buf;
ostream os(&buf);
int os_width = 24;
os.setf(ios::scientific);
os.precision(15);
for (int i = 0; i < num_samples; i++) {
// skip the non-contact data
if (ds_cnt_feats[i][0] < 0)
continue;
for (int i_inputs = 0; i_inputs < 7; i_inputs++) {
os.width(os_width);
os << ds_inputs[i][i_inputs] << ", ";
}
for (int i_outputs = 0; i_outputs < 7; i_outputs++) {
os.width(os_width);
os << ds_cnt_feats[i][i_outputs] << ", ";
}
os.width(os_width);
os << ds_cnt_feats[i][7] << endl;
}
ofstream outfile;
outfile.open(filename);
if (!outfile) {
cout << "cannot open file: " << filename << endl;
}
outfile << buf.str();
outfile.close();
cout << "data saved to: " << filename << endl;
}
void GenDatasetTrimesh(int num_samples = 100) {
// load particle
TriMesh tri_mesh_1;
tri_mesh_1.InitFromSTL("data/particle_template.stl");
tri_mesh_1.Decimate(200);
tri_mesh_1.AlignAxes();
tri_mesh_1.SetSize(1.0);
Particle obj_p1 = Particle(&tri_mesh_1);
obj_p1.need_update_stl_model = true;
Particle obj_p2 = Particle(&tri_mesh_1);
obj_p2.need_update_stl_model = true;
cout << "particle created ... " << endl;
// allocate memory
double(*ds_inputs)[7] = new double[num_samples][7];
bool *ds_cnt_flags = new bool[num_samples];
double(*ds_cnt_feats)[8] = new double[num_samples][8];
// use bound sphere to narrow down the random space
double dist_max = obj_p1.shape->GetBoundSphereRadius() * 1.1;
double dist_min{dist_max};
for (auto &vert : tri_mesh_1.vertices) {
dist_min = min(Math::NormL2(vert), dist_min);
}
dist_min *= 0.9;
dist_max = dist_max * 2;
dist_min = dist_min * 2;
double dist_range = dist_max - dist_min;
// random generator
UniformDistribution uniform_dist(0.0, 1.0);
// use spherical centroidal voronoi to sample uniform unit VecXT
VecXT<Vec3d> vertices = SphericalVoronoi::Solve(1000, 10000, 1.0e-4);
VecXT<Vec3i> facets;
IGLWrapper::ConvexHull(vertices, &vertices, &facets);
// the solver and dummy contact model
SolverBooleanPP cnt_solver;
VolumeBased cnt_model;
// random cases
for (int trial = 0, i = 0; trial < num_samples * 100; trial++) {
// random rotation
Vec4d quat;
quat[0] = uniform_dist.Get() * 2.0 - 1.0;
quat[1] = uniform_dist.Get() * 2.0 - 1.0;
quat[2] = uniform_dist.Get() * 2.0 - 1.0;
quat[3] = uniform_dist.Get() * 2.0 - 1.0;
Math::Quaternion::Normalize(&quat);
// random position
int id_facet = floor(uniform_dist.Get() * facets.size());
auto vert_0 = vertices[facets[id_facet][0]];
auto vert_1 = vertices[facets[id_facet][1]];
auto vert_2 = vertices[facets[id_facet][2]];
double u_vert = uniform_dist.Get();
double v_vert = uniform_dist.Get() * (1 - u_vert);
double w_vert = 1 - u_vert - v_vert;
pos[0] = u_vert * vert_0[0] + v_vert * vert_1[0] + w_vert * vert_2[0];
pos[1] = u_vert * vert_0[1] + v_vert * vert_1[1] + w_vert * vert_2[1];
pos[2] = u_vert * vert_0[2] + v_vert * vert_1[2] + w_vert * vert_2[2];
Math::Normalize(&pos);
auto dist_pp = dist_min + uniform_dist.Get() * dist_range;
pos[0] *= dist_pp;
pos[1] *= dist_pp;
pos[2] *= dist_pp;
// apply to particle
obj_p2.SetPosition(pos[0], pos[1], pos[2]);
obj_p2.SetQuaternion(quat[0], quat[1], quat[2], quat[3]);
// contact detection and resolution
cnt_solver.Init(&obj_p1, &obj_p2);
bool cnt_flag = cnt_solver.Detect();
if (!cnt_flag) {
// use distance from particle centroid to plane and plane normal as inputs
ds_inputs[i][0] = obj_p2.pos[0];
ds_inputs[i][1] = obj_p2.pos[1];
ds_inputs[i][2] = obj_p2.pos[2];
ds_inputs[i][3] = obj_p2.quaternion[0];
ds_inputs[i][4] = obj_p2.quaternion[1];
ds_inputs[i][5] = obj_p2.quaternion[2];
ds_inputs[i][6] = obj_p2.quaternion[3];
ds_cnt_flags[i] = cnt_flag;
// volume and directional cross-section area of intersection as outputs
ds_cnt_feats[i][0] = -1;
ds_cnt_feats[i][1] = -1;
ds_cnt_feats[i][2] = -1;
ds_cnt_feats[i][3] = -1;
ds_cnt_feats[i][4] = -1;
ds_cnt_feats[i][5] = -1;
ds_cnt_feats[i][6] = -1;
ds_cnt_feats[i][7] = -1;
i++;
} else {
auto cnt = ContactPP(&obj_p1, &obj_p2);
cnt.SetCollisionModel(&cnt_model);
cnt_solver.ResolveInit(&cnt, 1.0e-4);
auto &cnt_geoms = cnt.collision_entries[0].cnt_geoms;
// skip the contact if overlap is too large
if (cnt_geoms.vol * cnt_geoms.sn > 12.0e-4)
continue;
// use distance from particle centroid to plane and plane normal as inputs
ds_inputs[i][0] = obj_p2.pos[0];
ds_inputs[i][1] = obj_p2.pos[1];
ds_inputs[i][2] = obj_p2.pos[2];
ds_inputs[i][3] = obj_p2.quaternion[0];
ds_inputs[i][4] = obj_p2.quaternion[1];
ds_inputs[i][5] = obj_p2.quaternion[2];
ds_inputs[i][6] = obj_p2.quaternion[3];
ds_cnt_flags[i] = cnt_flag;
// volume and directional cross-section area of intersection as outputs
ds_cnt_feats[i][0] = cnt_geoms.vol;
ds_cnt_feats[i][1] = cnt_geoms.sn;
ds_cnt_feats[i][2] = cnt_geoms.dir_n[0];
ds_cnt_feats[i][3] = cnt_geoms.dir_n[1];
ds_cnt_feats[i][4] = cnt_geoms.dir_n[2];
ds_cnt_feats[i][5] = cnt_geoms.pos[0];
ds_cnt_feats[i][6] = cnt_geoms.pos[1];
ds_cnt_feats[i][7] = cnt_geoms.pos[2];
i++;
}
if (((i + 1) % 100) == 0) {
cout << "number of samples: " << i + 1 << " ..." << endl;
}
if (i >= num_samples) {
break;
}
}
string root_dir = "local/examples/netdem/ann_models/trimesh_trimesh/";
SaveDatasetTrimeshDetection(num_samples, ds_inputs, ds_cnt_flags,
root_dir + "dataset_detection.txt");
SaveDatasetTrimeshResolution(num_samples, ds_inputs, ds_cnt_feats,
root_dir + "dataset_resolution.txt");
delete[] ds_inputs;
delete[] ds_cnt_flags;
delete[] ds_cnt_feats;
}
A class representing a contact between two particles.
Definition contact_pp.hpp:20
Definition particle.hpp:26
virtual void SetQuaternion(double q_0, double q_1, double q_2, double q_3)
Sets the orientation of the particle using a quaternion.
Definition particle.cpp:103
virtual void SetPosition(double pos_x, double pos_y, double pos_z)
Sets the position of the particle.
Definition particle.cpp:83
Vec4d quaternion
The quaternion of the particle.
Definition particle.hpp:108
Vec3d pos
The position of the particle.
Definition particle.hpp:103
Shape * shape
The shape of the particle.
Definition particle.hpp:45
bool need_update_stl_model
Flag indicating whether STl model intersection-based contact detection and resolution is needed.
Definition particle.hpp:207
virtual double GetBoundSphereRadius() const
Return the inertia of the shape.
Definition shape.cpp:126
Solver for triangle mesh contacts between two particles using boolean operations.
Definition solver_boolean_pp.hpp:18
bool Detect() override
Detects collisions between two particles using boolean operations on their triangle meshes.
Definition solver_boolean_pp.cpp:44
void ResolveInit(ContactPP *const cnt, double timestep) override
Initializes the contact point between two particles at time t = 0.
Definition solver_boolean_pp.cpp:74
void Init(Particle *const p1, Particle *const p2) override
Initializes the collision solver with two particles.
Definition solver_boolean_pp.cpp:22
A class representing a triangular mesh in 3D space.
Definition shape_trimesh.hpp:23
void InitFromSTL(std::string const &file)
Initialize the TriMesh object from an STL file.
void Decimate(int num_nodes)
Decimate the TriMesh object.
Definition shape_trimesh.cpp:121
void AlignAxes()
Align the axes of the TriMesh object.
Definition shape_trimesh.cpp:107
void SetSize(double d) override
Set the size of the TriMesh object.
Definition shape_trimesh.cpp:207
VecXT< Vec3d > vertices
The vertices of the triangular mesh.
Definition shape_trimesh.hpp:28
Generates random numbers from a uniform distribution.
Definition distribution_uniform.hpp:15
Contact model that evaluates forces and moments based on volume overlap and relative velocity.
Definition model_volume_based.hpp:13
Definition bond_entry.hpp:7
std::vector< T > VecXT
Definition utils_macros.hpp:31
pos
Definition json_serilization.hpp:19
std::array< double, 3 > Vec3d
Definition utils_macros.hpp:18
std::array< double, 4 > Vec4d
Definition utils_macros.hpp:19