📄 ivp_rot_inertia_solver.cxx
字号:
// Copyright (C) Ipion Software GmbH 1999-2000. All rights reserved.
/********************************************************************************
* File: ivp_rot_inertia_solver.cxx
* Description: function collection
********************************************************************************/
#include <ivp_physics.hxx>
#include <ivu_float.hxx>
#include <ivu_hash.hxx>
#include <ivp_compact_ledge.hxx>
#include <ivp_rot_inertia_solver.hxx>
#include <ivp_compact_ledge_solver.hxx>
/********************************************************************************
* Names: p_find_center_given_xyz
* Description: integrate the volume of a compact ledge: dz*dy/dx
* In:
* x,y,z: permutation of the original axis: x is index of x-axis ...
* transform: transformation matrix of the original points
* Out:
* center: the center of mass x-axis
* mass: the volume of the object
* inertia: the inertia given that the object is centered
********************************************************************************/
IVP_Compact_Ledge_Mass_Center_Solver::IVP_Compact_Ledge_Mass_Center_Solver(const IVP_U_Matrix *transform_in){
transform = transform_in;
msum = 0.0f;
mzsum = 0.0f;
mzzsum = 0.0f;
}
IVP_Compact_Ledge_Find_Mass_Center::IVP_Compact_Ledge_Find_Mass_Center(){
sum_det = 0.0f;
qsum_surface = 0.0f;
sum_mass.set_to_zero();
}
void IVP_Compact_Ledge_Mass_Center_Solver::integrate_triangle( const IVP_Compact_Ledge *ledge, const IVP_Compact_Triangle *triangle, int x,int y,int z){
IVP_U_Point hesse2;
const IVP_Compact_Edge *edge = triangle->get_first_edge();
IVP_CLS.calc_hesse_vec_object_not_normized( edge, ledge, &hesse2);
hesse2.normize();
IVP_U_Point *hesse = &hesse2;
IVP_DOUBLE fzdy; // Steigung der Flaeche in z nach dy
IVP_DOUBLE fydz;
IVP_BOOL three_edge_area; // flag: integrate triangle or square
if ( IVP_DOUBLE(IVP_Inline_Math::fabsd(hesse->k[z])) < IVP_DOUBLE(IVP_Inline_Math::fabsd(hesse->k[y])) ){
three_edge_area = IVP_FALSE; // intagrate triangle plus square
fydz = 0.5f * hesse->k[z] / hesse->k[y];
fzdy = 0.0f;
}else{
three_edge_area = IVP_TRUE; // Integrate triangle only
if ( IVP_Inline_Math::fabsd(hesse->k[z]) > P_DOUBLE_RES ) {
fzdy = -0.5f * hesse->k[y] / hesse->k[z]; // hesse form is vertical to area !!
} else {
fzdy = 0.0f;
}
fydz = 0.0f;
}
int l;
IVP_DOUBLE area_msum = 0.0f;
IVP_DOUBLE area_mzsum = 0.0f;
IVP_DOUBLE area_mzzsum = 0.0f;
for (l=0;l<3;l++){
IVP_U_Float_Point p0,p1;
{ // get the point coords
const IVP_Compact_Edge *e = triangle->get_edge(l);
const IVP_Compact_Edge *en = e->get_next();
const IVP_U_Float_Point *p0_object = IVP_CLS.give_object_coords(e,ledge);
const IVP_U_Float_Point *p1_object = IVP_CLS.give_object_coords(en,ledge);
transform->vimult4(p0_object, &p0); // start point
transform->vimult4(p1_object,&p1); // start point
}
IVP_U_Point vec; vec.subtract(&p1,&p0);
if (IVP_Inline_Math::fabsd(vec.k[x]) < P_DOUBLE_RES * vec.real_length() ){
continue;
}
IVP_DOUBLE lydx = vec.k[y] / vec.k[x]; // Steigung der Linie in y nach dx
IVP_DOUBLE ly0 = p0.k[y] - lydx * p0.k[x]; // intersection point of line with x-axis
IVP_DOUBLE ka,kb,kc;
if (three_edge_area){
// loese Integrale im Bereich [x0 x1]: (y0 + x lydx)(y0 + x lydx) fzdy [x][x] dx
ka = fzdy * ly0 * ly0;
kb = fzdy * 2.0f * ly0 * lydx;
kc = fzdy * lydx * lydx;
}else{
// loese Integral (x*y)dx = (y0 + x lydx)(lz0 + x lzdx)dx
// + fydz(z0 + x lzdx)(lz0 + x lzdx)
IVP_DOUBLE lzdx = vec.k[z] / vec.k[x];
IVP_DOUBLE lz0 = p0.k[z] - lzdx * p0.k[x];
ka = (ly0 + fydz * lz0) * lz0;
kb = ly0 * lzdx + lydx * lz0 + 2.0f * fydz * lz0 * lzdx;
kc = (lydx + fydz * lzdx)* lzdx;
}
IVP_DOUBLE x0 = p0.k[x];
IVP_DOUBLE x1 = p1.k[x];
IVP_DOUBLE dx = x1 - x0;
IVP_DOUBLE dx2 = (x1*x1 - x0 * x0) *.5f;
IVP_DOUBLE dx3 = (x1*x1*x1 - x0*x0*x0) * (1.0f/ 3.0f);
IVP_DOUBLE dx4 = (x1*x1*x1*x1 - x0*x0*x0*x0) * .25f;
IVP_DOUBLE dx5 = (x1*x1*x1*x1*x1 - x0*x0*x0*x0*x0) *.2f;
IVP_DOUBLE f = dx * ka + dx2 * kb + dx3 * kc; // Flaecheninhalt
IVP_DOUBLE k = dx2 * ka + dx3 * kb + dx4 * kc; // Kippmoment
IVP_DOUBLE m = dx3 * ka + dx4 * kb + dx5 * kc; // Drehmomentum
area_msum += f;
area_mzsum += k;
area_mzzsum += m;
}
msum += area_msum;
mzsum += area_mzsum;
mzzsum += area_mzzsum;
}
void IVP_Compact_Ledge_Find_Mass_Center::integrate_triangle( const IVP_Compact_Ledge *ledge, const IVP_Compact_Triangle *triangle){
const IVP_Compact_Edge *edge = triangle->get_first_edge();
const IVP_U_Float_Point *p0 = IVP_CLS.give_object_coords(edge, ledge);
const IVP_U_Float_Point *p1 = IVP_CLS.give_object_coords(edge->get_next(), ledge);
const IVP_U_Float_Point *p2 = IVP_CLS.give_object_coords(edge->get_prev(), ledge);
IVP_U_Float_Point surface_normal; surface_normal.inline_set_vert_to_area_defined_by_three_points(p0, p2, p1);
IVP_DOUBLE det = surface_normal.dot_product( p0 );
qsum_surface += surface_normal.quad_length();
sum_det += det;
sum_mass.add_multiple( p0, det * 0.25f);
sum_mass.add_multiple( p1, det * 0.25f);
sum_mass.add_multiple( p2, det * 0.25f);
}
void IVP_Compact_Ledge_Find_Mass_Center::integrate_ledge( const IVP_Compact_Ledge *ledge){
const IVP_Compact_Triangle *tri;
int t;
for (t = 0, tri = ledge->get_first_triangle();
t< ledge->get_n_triangles();
t++, tri= tri->get_next_tri() ){
integrate_triangle( ledge,tri);
}
}
void IVP_Compact_Ledge_Find_Mass_Center::integrate_ledges( IVP_U_BigVector<IVP_Compact_Ledge> *v_ledges){
for (int l = v_ledges->len()-1; l>=0;l--){
const IVP_Compact_Ledge *ledge = v_ledges->element_at(l);
integrate_ledge(ledge);
}
}
void IVP_Rot_Inertia_Solver::find_center_given_xyz(IVP_U_BigVector<IVP_Compact_Ledge> *v_ledges,
int x,int y,int z, const IVP_U_Matrix *transform,
IVP_DOUBLE *center, IVP_DOUBLE *mass, IVP_DOUBLE *inertia)
{
/* Search Center value, relativ x-Axis */
IVP_Compact_Ledge_Mass_Center_Solver solver(transform);
for (int l = v_ledges->len()-1; l>=0;l--){
const IVP_Compact_Ledge *ledge = v_ledges->element_at(l);
const IVP_Compact_Triangle *tri;
int t;
for (t = 0, tri = ledge->get_first_triangle();
t< ledge->get_n_triangles();
t++, tri= tri->get_next_tri() ){
solver.integrate_triangle( ledge,tri,x,y,z);
}
}
if(solver.msum < P_DOUBLE_EPS){
*mass = 0.0f;
*center = 0.0f;
*inertia = 1.0f;
}else{
*center = solver.mzsum/solver.msum;
*mass = solver.msum;
*inertia = solver.mzzsum/solver.msum;
}
}
static IVP_RETURN_TYPE localCalcMassCenterAndRotInertia(
IVP_U_BigVector<IVP_Compact_Ledge>* all_ledges,
IVP_U_Point* mass_center_out,
IVP_U_Point* rotation_inertia_out)
{
IVP_U_Matrix transform;
transform.init();
IVP_Compact_Ledge_Find_Mass_Center fmc;
fmc.integrate_ledges( all_ledges );
// do not check the surface if height of object is very smally
IVP_DOUBLE surface = IVP_Inline_Math::sqrtd( fmc.qsum_surface );
if( fmc.sum_det > surface * surface * surface * 1e-9f){
transform.init();
transform.vv = fmc.get_mass_center();
mass_center_out->set(transform.get_position());
IVP_DOUBLE volume;
IVP_U_Point rot_inertia_2d;
IVP_U_Point check_center;
IVP_Rot_Inertia_Solver::find_center_given_xyz(all_ledges,0,1,2,&transform,&check_center.k[0],&volume,&rot_inertia_2d.k[0]);
IVP_Rot_Inertia_Solver::find_center_given_xyz(all_ledges,1,2,0,&transform,&check_center.k[1],&volume,&rot_inertia_2d.k[1]);
IVP_Rot_Inertia_Solver::find_center_given_xyz(all_ledges,2,0,1,&transform,&check_center.k[2],&volume,&rot_inertia_2d.k[2]);
{ // calc 3d rotation inertia based on 2d values
IVP_DOUBLE a = rot_inertia_2d.k[0];
IVP_DOUBLE b = rot_inertia_2d.k[1];
IVP_DOUBLE c = rot_inertia_2d.k[2];
a *=a; b *= b; c *= c;
IVP_DOUBLE sa = IVP_Fast_Math::sqrt(b+c);
IVP_DOUBLE sb = IVP_Fast_Math::sqrt(a+c);
IVP_DOUBLE sc = IVP_Fast_Math::sqrt(a+b);
rotation_inertia_out->set(sa,sb,sc);
}
return IVP_OK;
}else{ // no valid masses found, take geom center
IVP_DOUBLE radius;
IVP_U_Point min_extents, max_extents;
IVP_CLS.calc_bounding_box(all_ledges->element_at(0), &min_extents, &max_extents);
for (int l = all_ledges->len()-1; l>0;l--){
IVP_U_Point mi, ma;
const IVP_Compact_Ledge *ledge = all_ledges->element_at(l);
IVP_CLS.calc_bounding_box(ledge, &mi, &ma);
min_extents.line_min( &mi );
max_extents.line_max( &ma );
}
mass_center_out->set_interpolate( &min_extents, &max_extents, 0.5f);
radius = 0.5f * IVP_Inline_Math::sqrtd( min_extents.quad_distance_to( &max_extents));
IVP_DOUBLE estimate_inertia = radius * radius * 0.5f;
rotation_inertia_out->set(estimate_inertia, estimate_inertia, estimate_inertia);
return IVP_FAULT;
}
}
IVP_RETURN_TYPE IVP_Rot_Inertia_Solver::calc_mass_center_and_rotation_inertia(
const IVP_Compact_Surface *c_surface_in,
IVP_U_Point *mass_center_out,
IVP_U_Point *rotation_inertia_out)
{
IVP_U_BigVector<IVP_Compact_Ledge> all_ledges(128);
IVP_Compact_Ledge_Solver::get_all_ledges(c_surface_in, &all_ledges );
return localCalcMassCenterAndRotInertia(&all_ledges, mass_center_out, rotation_inertia_out);
}
#ifdef HAVOK_MOPP
IVP_RETURN_TYPE IVP_Rot_Inertia_Solver::calc_mass_center_and_rotation_inertia(
const IVP_Compact_Mopp* c_mopp_in,
IVP_U_Point* mass_center_out,
IVP_U_Point* rotation_inertia_out)
{
IVP_U_BigVector<IVP_Compact_Ledge> all_ledges(128);
IVP_Compact_Ledge_Solver::get_all_ledges(c_mopp_in, &all_ledges);
return localCalcMassCenterAndRotInertia(&all_ledges, mass_center_out, rotation_inertia_out);
}
#endif // HAVOK_MOPP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -