📄 ivp_buoyancy_solver.cxx
字号:
environment->add_draw_vector(&middle,&vec4,"",2);
}
#endif
//compute buoyancy values
compute_buoyancy_values_for_one_ball(decision,
distance,
radius,
surface_os,
&geom_center_os);
//compute the volume centers and the volumes under surface_os for the pushing forces
compute_dampening_values_for_one_ball(decision,
distance,
radius,
&geom_center_os,
rel_speed_of_current_os,
&speed_plane_os,
surface_os,
&p1_os,
&p2_os);
}
int IVP_Buoyancy_Solver::compute_disection_points_with_ball(const IVP_U_Float_Hesse *plane1_os,
const IVP_U_Float_Hesse *plane2_os,
const IVP_U_Float_Point *geom_center_os,
const IVP_FLOAT &radius,
IVP_U_Float_Point *p1_os, IVP_U_Float_Point *p2_os) {
/*** convert plane2_ws from hesse form into point-direction form ***/
IVP_U_Hesse tmp_plane2_os;
tmp_plane2_os.set(plane2_os);
tmp_plane2_os.hesse_val = plane2_os->hesse_val;
IVP_U_Plain point_direction_form_of_plane2_os(&tmp_plane2_os); //create point-direction form of speed_plane_ws
IVP_U_Straight straight_os;
IVP_U_Hesse non_float_plane1_os; //IVP_U_Plain cannot handle IVP_U_Float_Points
non_float_plane1_os.set(plane1_os);
non_float_plane1_os.hesse_val = plane1_os->hesse_val;
IVP_RETURN_TYPE is_parallel;
is_parallel = point_direction_form_of_plane2_os.calc_intersect_with(&non_float_plane1_os, &straight_os); //calc intersection of both planes => straight
if (is_parallel == IVP_FAULT) {
return 0; //both planes are parallel, so no intersection exists between them
}
/*** calc intersection of straight with ball ***/
IVP_U_Float_Point straight_start_point;
straight_start_point.set(&(straight_os.start_point)); //start point of straight_os
IVP_U_Float_Point straight_vec;
straight_vec.set(&(straight_os.vec)); //vector of straight_os
IVP_U_Float_Point T;
T.subtract(&straight_start_point, geom_center_os);
IVP_U_Point parameters;
parameters.k[0] = straight_vec.k[0]*straight_vec.k[0] + straight_vec.k[1]*straight_vec.k[1] + straight_vec.k[2]*straight_vec.k[2];
parameters.k[1] = 2*T.k[0]*straight_vec.k[0] + 2*T.k[1]*straight_vec.k[1] + 2*T.k[2]*straight_vec.k[2];
parameters.k[2] = T.k[0]*T.k[0] + T.k[1]*T.k[1] + T.k[2]*T.k[2] - radius*radius;
IVP_U_Point result;
result.solve_quadratic_equation_accurate(¶meters); //solve the quadratic equation and store in result
if (result.k[0] >= 0.0f) { //solutions exist
p1_os->set(&straight_start_point);
p1_os->add_multiple(&straight_vec, result.k[1]);
p2_os->set(&straight_start_point);
p2_os->add_multiple(&straight_vec, result.k[2]);
return 1;
} else { //no solution exists
p1_os->set(0.0f, 0.0f, 0.0f);
p2_os->set(0.0f, 0.0f, 0.0f);
return 0;
}
}
void IVP_Buoyancy_Solver::compute_values_for_one_polygon( IVP_Real_Object *object, const IVP_U_Float_Hesse *surface_os) {
//initialize buoyancy variables with zero values
//volume_under = volume_above = 0;
volume_under = 0;
volume_center_under.set_to_zero();
//volume_center_above.set(0,0,0);
IVP_U_Float_Point s_point; //projected center point
{
IVP_IF(1){
IVP_DOUBLE leng=surface_os->real_length();
IVP_DOUBLE testval=IVP_Inline_Math::fabsd(leng-1.0f);
IVP_ASSERT( testval < 0.001f);
}
s_point.set_multiple(surface_os,-surface_os->hesse_val); //projects center onto surface_os
}
IVP_U_BigVector<IVP_Compact_Ledge> object_ledges(256); //will contain all ledges belonging to "object"
{ //initialize object_ledges with all ledges
IVP_SurfaceManager *surman = controller_buoyancy->attacher_buoyancy->get_buoyancy_surface( object );
surman->get_all_terminal_ledges(&object_ledges);
}
{
int index;
for (index = object_ledges.len()-1; index>=0; index--) {
IVP_Compact_Ledge *tmp_ledge = object_ledges.element_at(index);
compute_values_for_one_ledge(object, tmp_ledge, surface_os, &s_point);
}
}
// finish the volume center computation
if ( volume_under > buoyancy_eps )
volume_center_under.mult( 0.25f / volume_under );
#if 0
if (volume_above > buoyancy_eps )
volume_center_above.mult( 1.0f / volume_above );
#endif
}
/*****************************************************************
* compute the volume between a triangular surface and s_point *
*****************************************************************/
IVP_FLOAT IVP_Buoyancy_Solver::compute_pyramid_volume( const IVP_U_Float_Point *p1,
const IVP_U_Float_Point *p2,
const IVP_U_Float_Point *p3,
const IVP_U_Float_Point *s_point) {
IVP_U_Point hesse;
hesse.inline_set_vert_to_area_defined_by_three_points(p1,p2,p3); //compute orthogonal vector
IVP_U_Float_Point v;
v.subtract( p1, s_point ); //compute difference vector
return (hesse.dot_product(&v)) * ( -1.0f / 6.0f );
}
void IVP_Buoyancy_Solver::compute_values_for_one_triangle(IVP_Real_Object *object,
const IVP_Compact_Triangle *triangle,
const IVP_U_Float_Hesse *surface_os,
const IVP_U_Float_Point *s_point,
const IVP_Compact_Ledge *current_ledge) {
//fetch the points defining the triangle
IVP_U_Float_Point three_points[3];
three_points[0].set(triangle->get_edge(0)->get_start_point(current_ledge));
three_points[1].set(triangle->get_edge(1)->get_start_point(current_ledge));
three_points[2].set(triangle->get_edge(2)->get_start_point(current_ledge));
const IVP_U_Float_Point *triangle_points[5];
triangle_points[0] = &three_points[0]; //p0
triangle_points[1] = &three_points[1];
triangle_points[2] = &three_points[2];
triangle_points[3] = &three_points[0];
triangle_points[4] = &three_points[1];
//check if triangle is under/above surface
IVP_FLOAT distance[6]; //indicates distance of the 3 vertices of the triangle
int sum_distance = 0; //indicates the distance of the whole triangle: completely above/under surface, if 0 or 3
int index_positiv, index_neg;
for (int j=2; j>=0; j--) {
IVP_FLOAT x = surface_os->get_dist(triangle_points[j]);
if (x < 0.0f) {
index_neg = j;
sum_distance++;
//decrease distance to avoid division through zero
distance[j] = x - buoyancy_eps;
distance[j+3] = distance[j];
} else {
index_positiv = j;
//increase distance to avoid division trough zero
distance[j] = x + buoyancy_eps;
distance[j+3] = distance[j];
}
}
compute_volumes_and_centers_for_one_pyramid(object,
triangle_points,
distance,
sum_distance,
index_positiv,
index_neg,
s_point);
compute_rotation_and_translation_values_for_one_triangle(object,
triangle,
triangle_points,
current_ledge,
distance,
sum_distance,
index_positiv,
index_neg);
}
void IVP_Buoyancy_Solver::compute_volumes_and_centers_for_one_pyramid(IVP_Real_Object *object,
const IVP_U_Float_Point *triangle_points[5],
const IVP_FLOAT distance[6],
const int &decision,
const int &index_positiv,
const int &index_neg,
const IVP_U_Float_Point *s_point) {
switch (decision){
case 0: { //triangle is completely under the surface
IVP_DOUBLE volume_pyramid_under = compute_pyramid_volume( triangle_points[0], triangle_points[1], triangle_points[2], s_point );
volume_under += volume_pyramid_under;
//compute the volume center of the pyramid
IVP_U_Float_Point volume_center_pyramid; //volume center of the pyramid
volume_center_pyramid.add(triangle_points[0], triangle_points[1]);
volume_center_pyramid.add(triangle_points[2]);
volume_center_pyramid.add(s_point);
volume_center_pyramid.mult( volume_pyramid_under); //compute the volume center and weigh it with the corresponding volume
//save results to class variables
volume_center_under.add(&volume_center_pyramid);
}
break;
#if 0
case 3: {//triangle is completely above the surface
volume_pyramid_above = compute_pyramid_volume( triangle_points[0], triangle_points[1], triangle_points[2], &s_point );
volume_above += volume_pyramid_above;
//compute the volume center of the pyramid
volume_center_pyramid.set(triangle_points[0]);
volume_center_pyramid.add(triangle_points[1]);
volume_center_pyramid.add(triangle_points[2]);
volume_center_pyramid.add(&s_point);
volume_center_pyramid.mult( 0.25f * volume_pyramid_above); //weight the volume center of this part of the object with its volume
//save results to class variables
volume_center_above.add(&volume_center_pyramid);
}
break;
#endif
case 1: { //the vertex with index "index_neg" is above the surface
//compute the first disection point on the surface
IVP_DOUBLE factor1 = -distance[index_neg] / (distance[index_neg+1] - distance[index_neg]); //division by zero not possible, because distance[index_neg] < 0 and buoyancy_eps is added to each
//compute the second disection point on the surface
IVP_DOUBLE factor2 = -distance[index_neg] / (distance[index_neg+2] - distance[index_neg]); //division by zero not possible, because distance[index_neg] < 0 and buoyancy_eps is added to each
IVP_IF(1){
IVP_U_Float_Point sp1, sp2;
IVP_U_Point sp1_ws, sp2_ws;
sp1.set_interpolate(triangle_points[index_neg], triangle_points[index_neg+1], factor1);
sp2.set_interpolate(triangle_points[index_neg], triangle_points[index_neg+2], factor2);
IVP_Cache_Object *cache_object = object->get_cache_object(); //needed to transform coordinates into other coord. systems
cache_object->transform_position_to_world_coords(&sp1, &sp1_ws);
cache_object->transform_position_to_world_coords(&sp2, &sp2_ws);
cache_object->remove_reference();
IVP_U_Float_Point edge12;
edge12.subtract(&sp1_ws, &sp2_ws);
IVP_U_Point tmp_sp2_ws;
tmp_sp2_ws.set(&sp2_ws);
environment->add_draw_vector(&tmp_sp2_ws, &edge12,"",4);
}
/*** compute the volumes ***/
//compute volume of whole pyramid triangle is part of
IVP_DOUBLE volume_pyramid = compute_pyramid_volume( triangle_points[0], triangle_points[1], triangle_points[2], s_point );
//compute volume of pyramid above the surface
IVP_DOUBLE volume_pyramid_above = volume_pyramid * factor1 * factor2;
//save results to class variables
volume_under += (volume_pyramid - volume_pyramid_above);
/*** compute the volume centers ***/
//compute the area center of the whole triangle (Ce = (A+B+C)/3)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -