📄 ivp_impact.cxx
字号:
// Copyright (C) Ipion Software GmbH 1999-2000. All rights reserved.
#ifndef WIN32
# pragma implementation "ivp_contact_situation.hxx"
#endif
#include <ivp_physics.hxx>
#include <ivu_memory.hxx>
#include <ivp_compact_ledge.hxx>
#include <ivp_cache_object.hxx>
#include <ivp_physic_private.hxx>
#include <ivp_sim_unit.hxx>
#include <ivp_core_macros.hxx>
#include <ivp_material.hxx>
#include <ivp_impact.hxx>
#include <ivp_mindist_intern.hxx>
#include <ivp_friction.hxx>
#include <ivp_hull_manager.hxx>
#include "ivp_mindist_macros.hxx"
#include <ivp_listener_collision.hxx>
#include <ivp_calc_next_psi_solver.hxx>
#include <ivp_debug_manager.hxx>
#include <ivp_anomaly_manager.hxx>
#define IVP_SAFETY_FACTOR_FOR_DELAY 1.2f
#define IVP_INV_SAFETY_FACTOR_FOR_DELAY 1.0f/IVP_SAFETY_FACTOR_FOR_DELAY
#define IVP_ROT_MAX_UNCERTAINTY 0.5f // max rot degree speed uncertainty for rescue_speed
#define IVP_COLL_DETECT_MIN_INV_TIME 200.0f // inverse time we have to make sure no collision occurs
#define IVP_COLL_DETECT_MIN_TIME 1.0f/IVP_COLL_DETECT_MIN_INV_TIME
#define IVP_SPEED_ADDON_SYSTEM_IMPACT 0.01f
#define IVP_INV_HALF_CONSERVATION_STEPS 0.5f // elasticity is raised with number of impacts in system, at 1.0f/IVP_INV_HALF_CONSERVATION_STEPS the elasticity is at least 0.5
#define MAXIMUM_SYSTEM_PUSH_NUMBER 5000
#define MINIMAL_IMPACT_VELOCITY_FIXPOINT -11.552f
#define IMPACT_EPS 10E-5f
//#define EASEONIMPACT //doesnt work with balls // #+# kill and remove dependent functions
#define SYSTEM_IMPACT_ENABLED
// generates friction mindist from mindist when no friction mindist exists and makes sure that friction mindist (generated or not) is up to date
// sim_unit_not_destroy is the one that has to remain after fusion
IVP_Contact_Point *IVP_Mindist::try_to_generate_managed_friction(IVP_Friction_System **associated_fs,IVP_BOOL *having_new,IVP_Simulation_Unit *sim_unit_not_destroy,IVP_BOOL call_recalc_svals){
IVP_Mindist *my_dist = this;
IVP_Real_Object *obj0 = get_sorted_synapse(0)->l_obj;
IVP_Real_Object *obj1 = get_sorted_synapse(1)->l_obj;
IVP_IF(obj0->get_environment()->debug_information->debug_friction){
printf("new_fri_mindist\n");
}
IVP_Friction_System *fr_sys0,*fr_sys1;
IVP_Friction_Info_For_Core *fr_info0,*fr_info1;
IVP_Core *core0 = obj0->friction_core;
IVP_Core *core1 = obj1->friction_core;
if(core0->physical_unmoveable){
IVP_Core *temp_core;
temp_core=core0;
core0=core1;
core1=temp_core;
}
//core0 is now movable
fr_info0=core0->moveable_core_has_friction_info();
IVP_Environment *my_env = core0->environment;
IVP_Contact_Point *friction_dist;
IVP_BOOL gen_success;
friction_dist = IVP_Friction_Manager::generate_contact_point(my_dist,&gen_success);
{
if(gen_success!=IVP_TRUE) {
*associated_fs=fr_info0->l_friction_system;
*having_new=IVP_FALSE;
if(call_recalc_svals) {
friction_dist->recalc_friction_s_vals();
friction_dist->read_materials_for_contact_situation(friction_dist->tmp_contact_info);
}
return friction_dist;
}
}
if(call_recalc_svals) {
friction_dist->recalc_friction_s_vals(); // this is overhead, because nearly the same function was called for the associated mindist
friction_dist->read_materials_for_contact_situation(friction_dist->tmp_contact_info);
}
{
IVP_Event_Friction event_friction;
IVP_Environment *env = obj0->get_environment();
event_friction.environment = env;
event_friction.contact_situation= friction_dist->tmp_contact_info; //is inherited
event_friction.friction_handle = friction_dist;
env->fire_event_friction_created(&event_friction);
{
if (obj0->flags.collision_listener_exists){
IVP_Cluster_Manager *clus_man = env->get_cluster_manager();
clus_man->fire_event_friction_created(obj0, &event_friction);
}
if (obj1->flags.collision_listener_exists){
IVP_Cluster_Manager *clus_man = env->get_cluster_manager();
clus_man->fire_event_friction_created(obj1, &event_friction);
}
}
}
// IVP_ASSERT(my_env->get_mindist_manager()->debug_test_having_fr_mindist(friction_dist)==IVP_TRUE);
*having_new=IVP_TRUE;
IVP_Friction_System *affected_fs;
if(fr_info0)
{
fr_sys0=fr_info0->l_friction_system;
fr_info1=core1->get_friction_info(fr_sys0);
if(fr_info1)
{
//both objects have same friction_system
fr_sys0->add_dist_to_system(friction_dist);
fr_sys0->dist_added_update_pair_info(friction_dist);
//fr_sys0->fr_solver.calc_calc_solver(fr_sys0);
affected_fs=fr_sys0;
} else {
if(core1->physical_unmoveable)
{
// obj1 may have other friction systems. Doesnt matter systems act independently.
goto add_second_to_first;
} else {
fr_info1=core1->moveable_core_has_friction_info(); //obj1 is movable and so has only one fr_sys
if(fr_info1)
{
//movable object has already a different system, fusion systems
//core0->environment->get_friction_manager()->fusion_friction_systems(fr_sys0,fr_info1->l_friction_system);
fr_sys0->fusion_friction_systems(fr_info1->l_friction_system);
goto add_second_to_first_dist_only;
} else {
add_second_to_first:
// add second core to system of first core
fr_info1=new IVP_Friction_Info_For_Core();
fr_info1->l_friction_system=fr_sys0;
core1->add_friction_info(fr_info1);
fr_sys0->add_core_to_system(core1);
add_second_to_first_dist_only:
fr_sys0->add_dist_to_system(friction_dist);
fr_sys0->dist_added_update_pair_info(friction_dist);
//fr_sys0->fr_solver.calc_calc_solver(fr_sys0);
affected_fs=fr_sys0;
}
}
}
} else {
//first obj has no friction system, first make info-block
fr_info0=new IVP_Friction_Info_For_Core();
//core0->add_friction_info(fr_info0);
if(core1->physical_unmoveable)
{
// obj may have other systems that act independently. Make new system
goto new_system_for_both_objects;
} else {
fr_info1=core1->moveable_core_has_friction_info();
if(fr_info1)
{
// add obj0 to system of obj1
fr_sys1=fr_info1->l_friction_system;
fr_info0->l_friction_system=fr_sys1;
core0->add_friction_info(fr_info0);
fr_sys1->add_core_to_system(core0);
fr_sys1->add_dist_to_system(friction_dist);
fr_sys1->dist_added_update_pair_info(friction_dist);
//fr_sys1->fr_solver.calc_calc_solver(fr_sys1);
affected_fs=fr_sys1;
} else {
// make a new system for both objects
new_system_for_both_objects:
IVP_Friction_System *new_system;
new_system=new IVP_Friction_System(my_env);
fr_info1=new IVP_Friction_Info_For_Core();
fr_info0->l_friction_system=new_system;
fr_info1->l_friction_system=new_system;
core1->add_friction_info(fr_info1);
core0->add_friction_info(fr_info0);
//my_env->get_friction_manager()->add_friction_system(new_system);
new_system->add_dist_to_system(friction_dist);
new_system->dist_added_update_pair_info(friction_dist);
//new_system->fr_solver.calc_calc_solver(new_system);
new_system->add_core_to_system(core0);
new_system->add_core_to_system(core1);
affected_fs=new_system;
}
}
}
//allow to go from object to its distances
fr_info0->friction_info_insert_friction_dist(friction_dist);
fr_info1->friction_info_insert_friction_dist(friction_dist);
#ifdef EASEONIMPACT
fr_info0->set_all_dists_of_obj_neutral();
fr_info1->set_all_dists_of_obj_neutral();
#endif
//printf("add_fri_dist %lx to sys %lx\n",(long)friction_dist,(long)affected_fs); UFTEST
*associated_fs=affected_fs;
//friction_dist->l_friction_system=affected_fs;
#ifdef DEBUG
IVP_IF(0) {
IVP_Friction_System *fs0,*fs1;
fs0=NULL;
fs1=NULL;
if(!core0->physical_unmoveable) {
IVP_Friction_Info_For_Core *info_friction=core0->moveable_core_has_friction_info();
if(info_friction) {
fs0=info_friction->l_friction_system;
}
}
if(!core1->physical_unmoveable) {
IVP_Friction_Info_For_Core *info_for_core=core1->moveable_core_has_friction_info();
if(info_for_core) {
fs1=info_for_core->l_friction_system;
}
}
printf("\nmaking_new_frdist for cores %lx %d %lx %d fss %lx %lx with sim_units: %lx %lx\n",
(long)core0,core0->physical_unmoveable,
(long)core1,core1->physical_unmoveable,
(long)fs0,(long)fs1,(long)core0->sim_unit_of_core,(long)core1->sim_unit_of_core);
core0->sim_unit_of_core->sim_unit_debug_out();
core1->sim_unit_of_core->sim_unit_debug_out();
}
#endif
friction_dist->calc_virtual_mass_of_mindist();
IVP_IF(obj0->get_environment()->get_debug_manager()->check_fs) {
affected_fs->test_hole_fr_system_data();
}
IVP_Simulation_Unit *sim0,*sim1;
sim0=core0->sim_unit_of_core;
sim1=core1->sim_unit_of_core;
if( !(core1->physical_unmoveable | core0->physical_unmoveable) ) {
if(sim0!=sim1) {
if(sim1==sim_unit_not_destroy) {
sim1->fusion_simulation_unities(sim0);
P_DELETE(sim0);
} else {
sim0->fusion_simulation_unities(sim1);
P_DELETE(sim1);
}
}
}
#ifdef DEBUG
IVP_IF(1) {
if(!core0->physical_unmoveable) {
core0->sim_unit_of_core->sim_unit_debug_consistency();
}
if(!core1->physical_unmoveable) {
core1->sim_unit_of_core->sim_unit_debug_consistency();
}
}
#endif
return friction_dist;
}
IVP_DOUBLE IVP_Impact_Solver::get_total_energy(){
// energy of both objects doing impact
IVP_DOUBLE ener;
ener = core[0]->get_energy_on_test(&trans_speed[0],&rot_speed[0])
+ core[1]->get_energy_on_test(&trans_speed[1],&rot_speed[1]);
IVP_IF(core[0]->environment->debug_information->debug_impact) {
IVP_DOUBLE trans_e=trans_speed[1].quad_length() * core[1]->get_mass();
IVP_U_Float_Point hp;
hp.set_pairwise_mult( &rot_speed[1], &rot_speed[1]);
IVP_DOUBLE rot_e = hp.dot_product(core[1]->get_rot_inertia());
printf("total_energies trans %.3f rot %.3f sum %.3f\n",0.5f*trans_e,0.5f*rot_e,ener);
}
return ener;
}
//get relative world speed seen from obj 0
void IVP_Impact_Solver::get_relative_speed_vector()
{
IVP_U_Float_Point world_speed0,world_speed1;
core[0]->get_surface_speed_on_test(obj_point[0],&trans_speed[0],&rot_speed[0],&world_speed0);
core[1]->get_surface_speed_on_test(obj_point[1],&trans_speed[1],&rot_speed[1],&world_speed1);
relative_world_speed.subtract(&world_speed1,&world_speed0);
//relative_world_speed is now relative speed seen from now still object 0
}
// calculates push direction vector. length of vector is 1.0
// if vector isnt steep enough for friction, vector is adjusted (made steepeer).
// function is used by 'do_push' and before 'estimate_push_impulse'
void IVP_Impact_Solver::get_world_push_direction()
{
//given : relative_world_speed;
//wanted : vector world_push_direction giving direction of push (normized)
//world_push_direction differs from relative_world_speed if allowed friction is exceeded. then length is also smaller than 1.0f
IVP_U_Float_Point part_in_direction_surf; //decomposition of velo vec in direction normal and rest (this is the rest)
world_push_direction.set(&relative_world_speed);
world_push_direction.fast_normize();
IVP_DOUBLE angle=world_push_direction.dot_product(surf_normal); // is negativ. the greater (absolut) the steeper is angle
//angle is cos alpha . alpha seen from surface normal
IVP_IF(core[0]->environment->debug_information->debug_impact)
{
printf("wpd %.2f %.2f %.2f ",world_push_direction.k[0],world_push_direction.k[1],world_push_direction.k[2]);
}
if((angle>0.0f))
{
//turnaround_next_time: objects may still be closing, but is only rest speed that can be neglected, as lowest energy point of impact was already traversed
IVP_IF(core[0]->environment->debug_information->debug_impact)
{
printf(" impact_speed_now_reversed ");
}
//world_push_direction.set(surf_normal);
//world_push_direction.mult(-1.0f);
world_push_direction.set(&integral_pushes_world);
world_push_direction.fast_normize();
//angle=-angle;
//world_push_direction.subtract(surf_normal); // impact direction is mirrored relative to surface
return;
} else {
IVP_IF(core[0]->environment->debug_information->debug_impact){
printf(" not_reversed ");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -