world.cc
Go to the documentation of this file.
00001 
00080 #ifndef _GNU_SOURCE
00081 #define _GNU_SOURCE
00082 #endif
00083 
00084 //#define DEBUG 
00085 
00086 #include <stdlib.h>
00087 #include <assert.h>
00088 #include <string.h> // for strdup(3)
00089 #include <locale.h> 
00090 #include <limits.h>
00091 #include <libgen.h> // for dirname(3)
00092 
00093 #include "stage.hh"
00094 #include "file_manager.hh"
00095 #include "worldfile.hh"
00096 #include "region.hh"
00097 #include "option.hh"
00098 using namespace Stg;
00099 
00100 // // function objects for comparing model positions
00101 bool World::ltx::operator()(const Model* a, const Model* b) const
00102 {
00103   const meters_t ax( a->GetGlobalPose().x );
00104   const meters_t bx( b->GetGlobalPose().x );  
00105   // break ties using the pointer value to give a unique ordering
00106   return ( ax == bx ? a < b : ax < bx ); 
00107 }
00108 bool World::lty::operator()(const Model* a, const Model* b) const
00109 {
00110   const meters_t ay( a->GetGlobalPose().y );
00111   const meters_t by( b->GetGlobalPose().y );  
00112   // break ties using the pointer value ro give a unique ordering
00113   return ( ay == by ? a < b : ay < by ); 
00114 }
00115 
00116 // static data members
00117 unsigned int World::next_id(0);
00118 bool World::quit_all(false);
00119 std::set<World*> World::world_set;
00120 std::string World::ctrlargs;
00121 std::vector<std::string> World::args;
00122 
00123 World::World( const std::string& name, 
00124               double ppm )
00125   : 
00126   // private
00127   destroy( false ),
00128   dirty( true ),
00129   models(),
00130   models_by_name(),
00131   models_with_fiducials(),
00132   models_with_fiducials_byx(),
00133   models_with_fiducials_byy(),
00134   ppm( ppm ), // raytrace resolution
00135   quit( false ),
00136   show_clock( false ),
00137   show_clock_interval( 100 ), // 10 simulated seconds using defaults
00138   sync_mutex(),
00139   threads_working( 0 ),
00140   threads_start_cond(),
00141   threads_done_cond(),
00142   total_subs( 0 ), 
00143   worker_threads( 1 ),
00144 
00145   // protected
00146   cb_list(),
00147   extent(),
00148   graphics( false ), 
00149   option_table(),
00150   powerpack_list(),
00151   quit_time( 0 ),
00152   ray_list(),  
00153   sim_time( 0 ),
00154   superregions(),
00155   updates( 0 ),
00156   wf( NULL ),
00157   paused( false ),
00158   event_queues(1), // use 1 thread by default
00159   pending_update_callbacks(),
00160   active_energy(),
00161   active_velocity(),
00162   sim_interval( 1e5 ), // 100 msec has proved a good default
00163   update_cb_count(0)
00164 {
00165   if( ! Stg::InitDone() )
00166     {
00167       PRINT_WARN( "Stg::Init() must be called before a World is created." );
00168       exit(-1);
00169     }
00170  
00171   pthread_mutex_init( &sync_mutex, NULL );
00172   pthread_cond_init( &threads_start_cond, NULL );
00173   pthread_cond_init( &threads_done_cond, NULL );
00174  
00175   World::world_set.insert( this );
00176   
00177   ground = new Model(this, NULL, "model");
00178   assert(ground);
00179   ground->SetToken( "_ground_model" ); // allow users to identify this unique model
00180   AddModelName( ground, ground->Token() ); // add this name to the world's table
00181   ground->ClearBlocks();
00182   ground->SetGuiMove(false);
00183 }
00184 
00185 World::~World( void )
00186 {
00187   PRINT_DEBUG2( "destroying world %d %s", id, Token() );
00188   if( ground ) delete ground;
00189   if( wf ) delete wf;
00190   World::world_set.erase( this );
00191 }
00192 
00193 SuperRegion* World::CreateSuperRegion( point_int_t origin )
00194 {
00195   SuperRegion* sr( new SuperRegion( this, origin ) );
00196   superregions[origin] = sr;
00197   dirty = true; // force redraw
00198   return sr;
00199 }
00200 
00201 void World::DestroySuperRegion( SuperRegion* sr )
00202 {
00203   superregions.erase( sr->GetOrigin() );
00204   delete sr;
00205 }
00206 
00207 void World::Run()
00208 {
00209     // first check wheter there is a single gui world
00210     bool found_gui = false;
00211     FOR_EACH( world_it, world_set )
00212     {
00213         found_gui |= (*world_it)->IsGUI();
00214     }
00215     if(found_gui && (world_set.size() != 1))
00216     {
00217         PRINT_WARN( "When using the GUI only a single world can be simulated." );
00218         exit(-1);      
00219     }
00220     
00221     if(found_gui)
00222     {
00223         Fl::run();
00224     }
00225     else
00226     {
00227         while(!UpdateAll());
00228     }
00229 }
00230 
00231 bool World::UpdateAll()
00232 {  
00233   bool quit( true );
00234   
00235   FOR_EACH( world_it, World::world_set )
00236     {
00237       if( (*world_it)->Update() == false )
00238         quit = false;
00239     }
00240   
00241   return quit;
00242 }
00243 
00244 
00245 
00246 void* World::update_thread_entry( std::pair<World*,int> *thread_info )
00247 {
00248   World* world( thread_info->first );
00249   const int thread_instance( thread_info->second );
00250   
00251   //printf( "thread ID %d waiting for mutex\n", thread_instance );
00252 
00253   pthread_mutex_lock( &world->sync_mutex );  
00254 
00255   while( 1 )
00256     {
00257       //printf( "thread ID %d waiting for start\n", thread_instance );
00258       // wait until the main thread signals us
00259       //puts( "worker waiting for start signal" );
00260       
00261       pthread_cond_wait( &world->threads_start_cond, &world->sync_mutex );
00262       pthread_mutex_unlock( &world->sync_mutex );
00263                 
00264       //printf( "worker %u thread awakes for task %u\n", thread_instance, task );
00265       world->ConsumeQueue( thread_instance );
00266       //printf( "thread %d done\n", thread_instance );
00267       
00268       // done working, so increment the counter. If this was the last
00269       // thread to finish working, signal the main thread, which is
00270       // blocked waiting for this to happen
00271       
00272       pthread_mutex_lock( &world->sync_mutex );   
00273       if( --world->threads_working == 0 )
00274         {
00275           //puts( "last worker signalling main thread" );
00276           pthread_cond_signal( &world->threads_done_cond );
00277         }
00278       // keep lock going round the loop
00279     }
00280   
00281   return NULL;
00282 }
00283 
00284 void World::AddModel( Model*  mod )
00285 {
00286   models.insert( mod );
00287   models_by_name[mod->token] = mod;
00288 }
00289 
00290 void World::AddModelName( Model* mod, const std::string& name )
00291 {
00292   models_by_name[name] = mod;
00293 }
00294 
00295 void World::RemoveModel( Model* mod )
00296 {
00297   // remove all this model's names to the table
00298   models_by_name.erase( mod->token );
00299 
00300   models.erase( mod );
00301 }
00302 
00303 void World::LoadBlock( Worldfile* wf, int entity )
00304 { 
00305   // lookup the group in which this was defined
00306   Model* mod( models_by_wfentity[ wf->GetEntityParent( entity )]);
00307   
00308   if( ! mod )
00309     PRINT_ERR( "block has no model for a parent" );
00310   
00311   mod->LoadBlock( wf, entity );
00312 }
00313 
00314 void World::LoadSensor( Worldfile* wf, int entity )
00315 { 
00316   // lookup the group in which this was defined
00317   ModelRanger* rgr( dynamic_cast<ModelRanger*>(models_by_wfentity[ wf->GetEntityParent( entity )]));
00318   
00319   //todo verify that the parent is indeed a ranger
00320         
00321   if( ! rgr )
00322     PRINT_ERR( "block has no ranger model for a parent" );
00323   
00324   rgr->LoadSensor( wf, entity );
00325 }
00326 
00327 
00328 Model* World::CreateModel( Model* parent, const std::string& typestr )
00329 {
00330   Model* mod(NULL); // new model to return
00331   
00332   // find the creator function pointer in the map. use the
00333   // vanilla model if the type is NULL.
00334   creator_t creator = NULL;
00335   
00336   // printf( "creating model of type %s\n", typestr );
00337   
00338   std::map< std::string, creator_t>::iterator it = 
00339     Model::name_map.find( typestr );
00340   
00341   if( it == Model::name_map.end() )
00342     {
00343       puts("");
00344       PRINT_ERR1( "Model type %s not found in model typetable", typestr.c_str() );
00345     }
00346   else
00347     creator = it->second;
00348 
00349   // if we found a creator function, call it
00350   if( creator )
00351     {
00352       //printf( "creator fn: %p\n", creator );
00353       mod = (*creator)( this, parent, typestr );
00354     }
00355   else
00356     {
00357       PRINT_ERR1( "Unknown model type %s in world file.", 
00358                   typestr.c_str() );
00359       exit( 1 );
00360     }
00361   
00362   //printf( "created model %s\n", mod->Token() );
00363   
00364   return mod;
00365 }
00366 
00367 void World::LoadModel( Worldfile* wf, int entity )
00368 { 
00369   const int parent_entity( wf->GetEntityParent( entity ));
00370   
00371   PRINT_DEBUG2( "wf entity %d parent entity %d\n", 
00372                 entity, parent_entity );
00373   
00374   Model* parent( models_by_wfentity[ parent_entity ]);
00375     
00376   const char *typestr((char*)wf->GetEntityType(entity));          
00377   assert(typestr);
00378   
00379   Model* mod( CreateModel( parent, typestr ));
00380   
00381   // configure the model with properties from the world file
00382   mod->Load(wf, entity );
00383  
00384   // record the model we created for this worldfile entry
00385   models_by_wfentity[entity] = mod;
00386 }
00387 
00388 void World::Load( const std::string& worldfile_path )
00389 {
00390   // note: must call Unload() before calling Load() if a world already
00391   // exists TODO: unload doesn't clean up enough right now
00392 
00393   printf( " [Loading %s]", worldfile_path.c_str() );
00394   fflush(stdout);
00395 
00396   this->wf = new Worldfile();
00397   wf->Load( worldfile_path );
00398   PRINT_DEBUG1( "wf has %d entitys", wf->GetEntityCount() );
00399 
00400   // end the output line of worldfile components
00401   //puts("");
00402   
00403   const int entity(0);
00404   
00405   // nothing gets added if the string is empty
00406   this->SetToken( wf->ReadString( entity, "name", worldfile_path ));
00407   
00408   this->quit_time = 
00409     (usec_t)( million * wf->ReadFloat( entity, "quit_time", this->quit_time ) );
00410   
00411   this->ppm = 
00412     1.0 / wf->ReadFloat( entity, "resolution", 1.0 / this->ppm );
00413   
00414   this->show_clock = 
00415     wf->ReadInt( entity, "show_clock", this->show_clock );
00416   
00417   this->show_clock_interval = 
00418     wf->ReadInt( entity, "show_clock_interval", this->show_clock_interval );
00419   
00420   // read msec instead of usec: easier for user
00421   this->sim_interval =
00422     1e3 * wf->ReadFloat( entity, "interval_sim", this->sim_interval / 1e3 );
00423   
00424   this->worker_threads = wf->ReadInt( entity, "threads",  this->worker_threads );  
00425   if( this->worker_threads < 1 )
00426     {
00427       PRINT_WARN( "threads set to <1. Forcing to 1" );
00428       this->worker_threads = 1;
00429     }
00430   
00431   pending_update_callbacks.resize( worker_threads + 1 );      
00432   event_queues.resize( worker_threads + 1 );
00433   
00434   //printf( "worker threads %d\n", worker_threads );
00435   
00436   // kick off the threads
00437   for( unsigned int t(0); t<worker_threads; ++t )
00438     {      
00439       //normal posix pthread C function pointer
00440       typedef void* (*func_ptr) (void*);
00441       
00442       // the pair<World*,int> is the configuration for each thread. it can't be a local
00443       // stack var, since it's accssed in the threads
00444 
00445       pthread_t pt;
00446       pthread_create( &pt,
00447                       NULL,
00448                       (func_ptr)World::update_thread_entry, 
00449                       new std::pair<World*,int>( this, t+1 ) );
00450     }
00451   
00452   if( worker_threads > 1 ) 
00453     printf( "[threads %u]", worker_threads );   
00454   
00455   // Iterate through entitys and create objects of the appropriate type
00456   for( int entity(1); entity < wf->GetEntityCount(); ++entity )
00457     {
00458       const char *typestr = (char*)wf->GetEntityType(entity);             
00459       
00460       // don't load window entries here
00461       if( strcmp( typestr, "window" ) == 0 )
00462         {
00463           /* do nothing here */
00464         }
00465       else if( strcmp( typestr, "block" ) == 0 )
00466         LoadBlock( wf, entity );
00467       else if( strcmp( typestr, "sensor" ) == 0 )
00468         LoadSensor( wf, entity );
00469       else
00470         LoadModel( wf, entity );
00471     }
00472   
00473   // call all controller init functions
00474   FOR_EACH( it, models )
00475     {
00476       // all this is a hack and shouldn't be necessary
00477       (*it)->blockgroup.CalcSize();
00478       (*it)->UnMap(updates%2);
00479       (*it)->Map(updates%2);
00480       // to here
00481 
00482       (*it)->InitControllers();
00483     }
00484 
00485   putchar( '\n' );
00486 }
00487 
00488 void World::UnLoad()
00489 {
00490   if( wf ) delete wf;
00491 
00492   FOR_EACH( it, children )
00493     delete (*it);
00494   children.clear();
00495  
00496   models_by_name.clear();
00497   models_by_wfentity.clear();
00498   
00499   ray_list.clear();
00500 
00501   // todo - clean up regions & superregions?
00502         
00503   token = "[unloaded]";
00504 }
00505 
00506 bool World::PastQuitTime() 
00507 { 
00508   return( (quit_time > 0) && (sim_time >= quit_time) ); 
00509 }
00510 
00511 std::string World::ClockString() const
00512 {
00513   const uint32_t usec_per_hour(3600000000U);
00514   const uint32_t usec_per_minute(60000000U);
00515   const uint32_t usec_per_second(1000000U);
00516   const uint32_t usec_per_msec(1000U);
00517   
00518   const uint32_t hours(sim_time / usec_per_hour);
00519   const uint32_t minutes((sim_time % usec_per_hour) / usec_per_minute);
00520   const uint32_t seconds((sim_time % usec_per_minute) / usec_per_second);
00521   const uint32_t msec((sim_time % usec_per_second) / usec_per_msec);
00522         
00523   std::string str;  
00524   char buf[256];
00525 
00526   if( hours > 0 )
00527     {
00528       snprintf( buf, 255, "%uh", hours );
00529       str += buf;
00530     }
00531 
00532   snprintf( buf, 255, " %um %02us %03umsec", minutes, seconds, msec);
00533   str += buf;
00534   
00535   return str;
00536 }
00537 
00538 void World::AddUpdateCallback( world_callback_t cb, 
00539                                void* user )
00540 {
00541   // add the callback & argument to the list
00542   cb_list.push_back( std::pair<world_callback_t,void*>(cb, user) );
00543 
00544 }
00545 
00546 int World::RemoveUpdateCallback( world_callback_t cb, 
00547                                  void* user )
00548 {
00549   std::pair<world_callback_t,void*> p( cb, user );
00550   
00551   FOR_EACH( it, cb_list )
00552     {
00553       if( (*it) == p )
00554         {
00555           cb_list.erase( it );          
00556           break;
00557         }
00558     }
00559   
00560   // return the number of callbacks now in the list. Useful for
00561   // detecting when the list is empty.
00562   return cb_list.size();
00563 }
00564 
00565 void World::CallUpdateCallbacks()
00566 {
00567   // call model CB_UPDATE callbacks queued up by worker threads
00568   size_t threads( pending_update_callbacks.size() );
00569   int cbcount( 0 );
00570         
00571   for( size_t t(0); t<threads; ++t )
00572     {
00573       std::queue<Model*>& q( pending_update_callbacks[t] );
00574                         
00575       //                        printf( "pending callbacks for thread %u: %u\n", 
00576       //                                                        (unsigned int)t, 
00577       //                                                        (unsigned int)q.size() );
00578                         
00579       cbcount += q.size();
00580 
00581       while( ! q.empty() )
00582         {
00583           q.front()->CallUpdateCallbacks();
00584           q.pop();
00585         }
00586     }
00587   //    printf( "cb total %u (global %d)\n\n", (unsigned int)cbcount,update_cb_count );
00588         
00589   assert( update_cb_count >= cbcount );
00590 
00591   // world callbacks
00592   FOR_EACH( it, cb_list )
00593     {  
00594       if( ((*it).first )( this, (*it).second ) )
00595         it = cb_list.erase( it );
00596     }      
00597 }
00598 
00599 void World::ConsumeQueue( unsigned int queue_num )
00600 {  
00601   std::priority_queue<Event>& queue( event_queues[queue_num] );
00602   
00603   if( queue.empty() )
00604     return;
00605   
00606   //printf( "event queue len %d\n", (int)queue.size() );
00607   
00608   // update everything on the event queue that happens at this time or earlier
00609   do
00610     {
00611       Event ev( queue.top() );
00612       if( ev.time > sim_time ) break;
00613       queue.pop();
00614                         
00615       //printf( "Q%d @ %llu next event ptr %p cb %p\n", queue_num, sim_time, ev.mod, ev.cb );
00616       //std::string modelType = ev.mod->GetModelType();
00617       //printf( "@ %llu next event <%s %llu %s>\n",  sim_time, modelType.c_str(), ev.time, ev.mod->Token() ); 
00618       
00619       ev.cb( ev.mod, ev.arg); // call the event's callback on the model                 
00620     }
00621   while( !queue.empty() );
00622 }
00623 
00624 bool World::Update()
00625 {
00626   //puts( "World::Update()" );
00627         
00628   // if we've run long enough, exit
00629   if( PastQuitTime() ) 
00630     return true;                
00631         
00632   if( show_clock && ((this->updates % show_clock_interval) == 0) )
00633     {
00634       printf( "\r[Stage: %s]", ClockString().c_str() );
00635       fflush( stdout );
00636     }
00637         
00638   sim_time += sim_interval; 
00639         
00640   // rebuild the sets sorted by position on x,y axis
00641   models_with_fiducials_byx.clear(); 
00642   models_with_fiducials_byy.clear(); 
00643         
00644   FOR_EACH( it, models_with_fiducials )
00645     {
00646       models_with_fiducials_byx.insert( *it ); 
00647       models_with_fiducials_byy.insert( *it ); 
00648     }
00649 
00650   //printf( "x %lu y %lu\n", models_with_fiducials_byy.size(),
00651   //                    models_with_fiducials_byx.size() );
00652 
00653   // handle the zeroth queue synchronously in the main thread
00654   ConsumeQueue( 0 );
00655   
00656   // handle all the remaining queues asynchronously in worker threads
00657   pthread_mutex_lock( &sync_mutex );
00658   threads_working = worker_threads; 
00659   // unblock the workers - they are waiting on this condition var
00660   //puts( "main thread signalling workers" );
00661   pthread_cond_broadcast( &threads_start_cond );
00662   pthread_mutex_unlock( &sync_mutex );           
00663   
00664   // update the position of all position models based on their velocity
00665   FOR_EACH( it, active_velocity )
00666     (*it)->Move();
00667   
00668   pthread_mutex_lock( &sync_mutex );
00669   // wait for all the last update job to complete - it will
00670   // signal the worker_threads_done condition var
00671   while( threads_working > 0  )
00672     {
00673       //puts( "main thread waiting for workers to finish" );
00674       pthread_cond_wait( &threads_done_cond, &sync_mutex );
00675     }
00676   pthread_mutex_unlock( &sync_mutex );           
00677   //puts( "main thread awakes" );
00678   
00679   // TODO: allow threadsafe callbacks to be called in worker
00680   // threads            
00681   
00682   dirty = true; // need redraw 
00683   
00684   // this stuff must be done in series here
00685   
00686   // world callbacks
00687   CallUpdateCallbacks();
00688   
00689   FOR_EACH( it, active_energy )
00690     (*it)->UpdateCharge();
00691   
00692   ++updates;  
00693     
00694   return false;
00695 }
00696 
00697 unsigned int World::GetEventQueue( Model* mod ) const
00698 {
00699   // todo: there should be a policy that works faster than random, but
00700   // random should do a good core load balancing.
00701 
00702   if( worker_threads < 1 )
00703     return 0;
00704   return( (random() % worker_threads) + 1);
00705 }
00706 
00707 Model* World::GetModel( const std::string& name ) const
00708 {
00709   PRINT_DEBUG1( "looking up model name %s in models_by_name", name.c_str() );
00710         
00711   std::map<std::string,Model*>::const_iterator it( models_by_name.find( name ) );
00712         
00713   if( it == models_by_name.end() )
00714     {
00715       PRINT_WARN1( "lookup of model name %s: no matching name", name.c_str() );
00716       return NULL;
00717     }
00718   else
00719     return it->second; // the Model*
00720 }
00721 
00722 void World::RecordRay( double x1, double y1, double x2, double y2 )
00723 {  
00724   float* drawpts( new float[4] );
00725   drawpts[0] = x1;
00726   drawpts[1] = y1;
00727   drawpts[2] = x2;
00728   drawpts[3] = y2;
00729   ray_list.push_back( drawpts );
00730 }
00731 
00732 void World::ClearRays()
00733 {
00734   // destroy the C arrays first
00735   FOR_EACH( it, ray_list )
00736     delete [] *it;
00737   
00738   ray_list.clear();
00739 }
00740 
00741 // Perform multiple raytraces evenly spaced over an angular field of view
00742 void World::Raytrace( const Pose &gpose, // global pose
00743                       const meters_t range,
00744                       const radians_t fov,
00745                       const ray_test_func_t func,
00746                       const Model* model,                        
00747                       const void* arg,
00748                       RaytraceResult* samples, // preallocated storage for samples
00749                       const uint32_t sample_count, // number of samples
00750                       const bool ztest ) 
00751 {
00752   // find the direction of the first ray
00753   Pose raypose( gpose );
00754   const double starta( fov/2.0 - raypose.a );
00755   
00756   for( uint32_t s(0); s < sample_count; ++s )
00757     {
00758       raypose.a = (s * fov / (double)(sample_count-1)) - starta;
00759       samples[s] = Raytrace( raypose, range, func, model, arg, ztest );
00760     }
00761 }
00762 
00763 // Stage spends 50-99% of its time in this method.
00764 RaytraceResult World::Raytrace( const Pose &gpose, 
00765                                 const meters_t range,
00766                                 const ray_test_func_t func,
00767                                 const Model* mod,               
00768                                 const void* arg,
00769                                 const bool ztest ) 
00770 {
00771   return Raytrace( Ray( mod, gpose, range, func, arg, ztest ));
00772 }
00773 
00774 
00775 RaytraceResult World::Raytrace( const Ray& r )
00776 {
00777   //rt_cells.clear();
00778   //rt_candidate_cells.clear();
00779   
00780   // initialize the sample
00781   RaytraceResult sample( r.origin, r.range );
00782   
00783   // our global position in (floating point) cell coordinates
00784   double globx( r.origin.x * ppm );
00785   double globy( r.origin.y * ppm );
00786         
00787   // record our starting position
00788   const double startx( globx );
00789   const double starty( globy );
00790   
00791   // eliminate a potential divide by zero
00792   const double angle( r.origin.a == 0.0 ? 1e-12 : r.origin.a );
00793   const double sina(sin(angle));
00794   const double cosa(cos(angle));
00795   const double tana(sina/cosa); // approximately tan(angle) but faster
00796 
00797   // the x and y components of the ray (these need to be doubles, or a
00798   // very weird and rare bug is produced)
00799   const double dx( ppm * r.range * cosa);
00800   const double dy( ppm * r.range * sina);
00801   
00802   // fast integer line 3d algorithm adapted from Cohen's code from
00803   // Graphics Gems IV  
00804   const int32_t sx(sgn(dx));  
00805   const int32_t sy(sgn(dy));  
00806   const int32_t ax(abs(dx)); 
00807   const int32_t ay(abs(dy));  
00808   const int32_t bx(2*ax);       
00809   const int32_t by(2*ay);       
00810   int32_t exy(ay-ax); // difference between x and y distances
00811   int32_t n(ax+ay); // the manhattan distance to the goal cell
00812     
00813   // the distances between region crossings in X and Y
00814   const double xjumpx( sx * REGIONWIDTH );
00815   const double xjumpy( sx * REGIONWIDTH * tana );
00816   const double yjumpx( sy * REGIONWIDTH / tana );
00817   const double yjumpy( sy * REGIONWIDTH );
00818 
00819   // manhattan distance between region crossings in X and Y
00820   const double xjumpdist( fabs(xjumpx)+fabs(xjumpy) );
00821   const double yjumpdist( fabs(yjumpx)+fabs(yjumpy) );
00822 
00823   const unsigned int layer( (updates+1) % 2 );
00824   
00825   // these are updated as we go along the ray
00826   double xcrossx(0), xcrossy(0);
00827   double ycrossx(0), ycrossy(0);
00828   double distX(0), distY(0);
00829   bool calculatecrossings( true );
00830 
00831   // Stage spends up to 95% of its time in this loop! It would be
00832   // neater with more function calls encapsulating things, but even
00833   // inline calls have a noticeable (2-3%) effect on performance.
00834 
00835   // several useful asserts are commented out so that Stage is not too
00836   // slow in debug builds. Add them in if chasing a suspected raytrace bug
00837   while( n > 0  ) // while we are still not at the ray end
00838     { 
00839       SuperRegion* sr( GetSuperRegion(point_int_t(GETSREG(globx),GETSREG(globy))));
00840       Region* reg( sr ? sr->GetRegion(GETREG(globx),GETREG(globy)) : NULL );
00841                         
00842       if( reg && reg->count ) // if the region contains any objects
00843         {
00844           //assert( reg->cells.size() );
00845                                         
00846           // invalidate the region crossing points used to jump over
00847           // empty regions
00848           calculatecrossings = true;
00849                                         
00850           // convert from global cell to local cell coords
00851           int32_t cx( GETCELL(globx) ); 
00852           int32_t cy( GETCELL(globy) );
00853 
00854           Cell* c( &reg->cells[ cx + cy * REGIONWIDTH ] );
00855 
00856           // this assert makes Stage slow when compiled for debug
00857           //  assert(c); // should be good: we know the region contains objects
00858 
00859           // while within the bounds of this region and while some ray remains
00860           // we'll tweak the cell pointer directly to move around quickly
00861           while( (cx>=0) && (cx<REGIONWIDTH) && 
00862                  (cy>=0) && (cy<REGIONWIDTH) && 
00863                  n > 0 )
00864             {                    
00865               FOR_EACH( it, c->blocks[layer] )
00866                 {
00867                   Block* block( *it );
00868                   assert( block );
00869                   
00870                   // skip if not in the right z range
00871                   if( r.ztest && 
00872                       ( r.origin.z < block->global_z.min || 
00873                         r.origin.z > block->global_z.max ) )
00874                     continue; 
00875                                                                         
00876                   // test the predicate we were passed
00877                   if( (*r.func)( block->mod, (Model*)r.mod, r.arg )) 
00878                     {
00879                       // a hit!
00880                       sample.color = block->GetColor();
00881                       sample.mod = block->mod;
00882                                                                                         
00883                       if( ax > ay ) // faster than the equivalent hypot() call
00884                         sample.range = fabs((globx-startx) / cosa) / ppm;
00885                       else
00886                         sample.range = fabs((globy-starty) / sina) / ppm;
00887                                                                                         
00888                       return sample;
00889                     }                             
00890                 }
00891 
00892               // increment our cell in the correct direction
00893               if( exy < 0 ) // we're iterating along X
00894                 {
00895                   globx += sx; // global coordinate
00896                   exy += by;                                            
00897                   c += sx; // move the cell left or right
00898                   cx += sx; // cell coordinate for bounds checking
00899                 }
00900               else  // we're iterating along Y
00901                 {
00902                   globy += sy; // global coordinate
00903                   exy -= bx;                                            
00904                   c += sy * REGIONWIDTH; // move the cell up or down
00905                   cy += sy; // cell coordinate for bounds checking
00906                 }                        
00907               --n; // decrement the manhattan distance remaining
00908                                                                                                                                                                 
00909               //rt_cells.push_back( point_int_t( globx, globy ));
00910             }                                   
00911           //printf( "leaving populated region\n" );
00912         }                                                        
00913       else // jump over the empty region
00914         {                                                 
00915           // on the first run, and when we've been iterating over
00916           // cells, we need to calculate the next crossing of a region
00917           // boundary along each axis
00918           if( calculatecrossings )
00919             {
00920               calculatecrossings = false;
00921                                                         
00922               // find the coordinate in cells of the bottom left corner of
00923               // the current region
00924               const int32_t ix( globx );
00925               const int32_t iy( globy );                                  
00926               double regionx( ix/REGIONWIDTH*REGIONWIDTH );
00927               double regiony( iy/REGIONWIDTH*REGIONWIDTH );
00928               if( (globx < 0) && (ix % REGIONWIDTH) ) regionx -= REGIONWIDTH;
00929               if( (globy < 0) && (iy % REGIONWIDTH) ) regiony -= REGIONWIDTH;
00930                                                         
00931               // calculate the distance to the edge of the current region
00932               const double xdx( sx < 0 ? 
00933                                 regionx - globx - 1.0 : // going left
00934                                 regionx + REGIONWIDTH - globx ); // going right                  
00935               const double xdy( xdx*tana );
00936                                         
00937               const double ydy( sy < 0 ? 
00938                                 regiony - globy - 1.0 :  // going down
00939                                 regiony + REGIONWIDTH - globy ); // going up             
00940               const double ydx( ydy/tana );
00941                                         
00942               // these stored hit points are updated as we go along
00943               xcrossx = globx+xdx;
00944               xcrossy = globy+xdy;
00945                                                         
00946               ycrossx = globx+ydx;
00947               ycrossy = globy+ydy;
00948                                                         
00949               // find the distances to the region crossing points
00950               // manhattan distance is faster than using hypot()
00951               distX = fabs(xdx)+fabs(xdy);
00952               distY = fabs(ydx)+fabs(ydy);                
00953             }
00954                                         
00955           if( distX < distY ) // crossing a region boundary left or right
00956             {
00957               // move to the X crossing
00958               globx = xcrossx; 
00959               globy = xcrossy; 
00960                                                         
00961               n -= distX; // decrement remaining manhattan distance
00962                                                         
00963               // calculate the next region crossing
00964               xcrossx += xjumpx; 
00965               xcrossy += xjumpy;
00966                                                         
00967               distY -= distX;
00968               distX = xjumpdist;
00969                                                         
00970               //rt_candidate_cells.push_back( point_int_t( xcrossx, xcrossy ));
00971             }                    
00972           else // crossing a region boundary up or down
00973             {             
00974               // move to the X crossing
00975               globx = ycrossx;
00976               globy = ycrossy;
00977                                                         
00978               n -= distY; // decrement remaining manhattan distance                                                     
00979               // calculate the next region crossing
00980               ycrossx += yjumpx;
00981               ycrossy += yjumpy;
00982                                                         
00983               distX -= distY;
00984               distY = yjumpdist;
00985 
00986               //rt_candidate_cells.push_back( point_int_t( ycrossx, ycrossy ));
00987             }   
00988         }                               
00989       //rt_cells.push_back( point_int_t( globx, globy ));
00990     } 
00991   // hit nothing
00992   sample.mod = NULL;
00993   return sample;
00994 }
00995 
00996 static int _save_cb( Model* mod, void* dummy )
00997 {
00998   mod->Save();
00999   return 0;
01000 }
01001 
01002 bool World::Save( const char *filename )
01003 {
01004   ForEachDescendant( _save_cb, NULL );
01005   return this->wf->Save( filename ? filename : wf->filename );
01006 }
01007 
01008 static int _reload_cb(  Model* mod, void* dummy )
01009 {
01010   mod->Load();
01011   return 0;
01012 }
01013 
01014 // reload the current worldfile
01015 void World::Reload( void )
01016 {
01017   ForEachDescendant( _reload_cb, NULL );
01018 }
01019 
01020 // add a block to each cell described by a polygon in world coordinates
01021 void World::MapPoly( const std::vector<point_int_t>& pts, Block* block, unsigned int layer )
01022 {
01023   const size_t pt_count( pts.size() );
01024   
01025   for( size_t i(0); i<pt_count; ++i )
01026     {
01027       const point_int_t& start(pts[i] );
01028       const point_int_t& end(pts[(i+1)%pt_count]);
01029                         
01030       // line rasterization adapted from Cohen's 3D version in
01031       // Graphics Gems II. Should be very fast.  
01032       const int32_t dx( end.x - start.x );
01033       const int32_t dy( end.y - start.y );
01034       const int32_t sx(sgn(dx));  
01035       const int32_t sy(sgn(dy));  
01036       const int32_t ax(abs(dx));  
01037       const int32_t ay(abs(dy));  
01038       const int32_t bx(2*ax);   
01039       const int32_t by(2*ay);    
01040 
01041       int32_t exy(ay-ax); 
01042       int32_t n(ax+ay);
01043                         
01044       int32_t globx(start.x);
01045       int32_t globy(start.y);
01046                         
01047       while( n ) 
01048         {                               
01049           Region* reg( GetSuperRegionCreate( point_int_t(GETSREG(globx), 
01050                                                          GETSREG(globy)))
01051                        ->GetRegion( GETREG(globx), 
01052                                     GETREG(globy)));                                                                            
01053           // assert(reg);
01054                                         
01055           // add all the required cells in this region before looking up
01056           // another region                     
01057           int32_t cx( GETCELL(globx) ); 
01058           int32_t cy( GETCELL(globy) );
01059                                         
01060           // need to call Region::GetCell() before using a Cell pointer
01061           // directly, because the region allocates cells lazily, waiting
01062           // for a call of this method
01063           Cell* c( reg->GetCell( cx, cy ) );
01064                                         
01065           // while inside the region, manipulate the Cell pointer directly
01066           while( (cx>=0) && (cx<REGIONWIDTH) && 
01067                  (cy>=0) && (cy<REGIONWIDTH) && 
01068                  n > 0 )
01069             {                                   
01070               c->AddBlock(block, layer ); 
01071                                                         
01072               // cleverly skip to the next cell (now it's safe to
01073               // manipulate the cell pointer)
01074               if( exy < 0 ) 
01075                 {
01076                   globx += sx;
01077                   exy += by;
01078                   c += sx;
01079                   cx += sx;
01080                 }
01081               else 
01082                 {
01083                   globy += sy;
01084                   exy -= bx; 
01085                   c += sy * REGIONWIDTH;
01086                   cy += sy;
01087                 }
01088               --n;
01089             }
01090         }                       
01091     }
01092 }
01093 
01094 
01095 SuperRegion* World::AddSuperRegion( const point_int_t& sup )
01096 {
01097   SuperRegion* sr( CreateSuperRegion( sup ) );
01098 
01099   // set the lower left corner of the new superregion
01100   Extend( point3_t( (sup.x << SRBITS) / ppm,
01101                     (sup.y << SRBITS) / ppm,
01102                     0 ));
01103   
01104   // top right corner of the new superregion
01105   Extend( point3_t( ((sup.x+1) << SRBITS) / ppm,
01106                     ((sup.y+1) << SRBITS) / ppm,
01107                     0 ));  
01108   return sr;
01109 }
01110 
01111 
01112 inline SuperRegion* World::GetSuperRegion( const point_int_t& org )
01113 {
01114   SuperRegion* sr(NULL);
01115   
01116   // I despise some STL syntax sometimes...
01117   std::map<point_int_t,SuperRegion*>::iterator it( superregions.find(org) );
01118   
01119   if( it != superregions.end() )
01120     sr = it->second;
01121   
01122   return sr;
01123 }
01124 
01125 inline SuperRegion* World::GetSuperRegionCreate( const point_int_t& org )
01126 {
01127   SuperRegion* sr( GetSuperRegion(org) );
01128   
01129   if( sr == NULL ) // no superregion exists! make a new one
01130     {
01131       sr = AddSuperRegion( org );  
01132       assert( sr ); 
01133     }
01134   return sr;
01135 }
01136 
01137 
01138 void World::Extend( point3_t pt )
01139 {
01140   extent.x.min = std::min( extent.x.min, pt.x );
01141   extent.x.max = std::max( extent.x.max, pt.x );
01142   extent.y.min = std::min( extent.y.min, pt.y );
01143   extent.y.max = std::max( extent.y.max, pt.y );
01144   extent.z.min = std::min( extent.z.min, pt.z );
01145   extent.z.max = std::max( extent.z.max, pt.z );
01146 }
01147 
01148 
01149 void World::AddPowerPack( PowerPack* pp )
01150 {
01151   powerpack_list.push_back( pp ); 
01152 }
01153 
01154 void World::RemovePowerPack( PowerPack* pp )
01155 {
01156   EraseAll( pp, powerpack_list );
01157 }
01158 
01160 void World:: RegisterOption( Option* opt )
01161 {
01162   assert(opt);
01163   option_table.insert( opt );
01164 }
01165 
01166 void World::Log( Model* mod )
01167 {
01168   //LogEntry( sim_time, mod);
01169   //printf( "log entry count %u\n", (unsigned int)LogEntry::Count() );
01170   //LogEntry::Print();
01171 }
01172 
01173 bool World::Event::operator<( const Event& other ) const 
01174 {
01175   return( time > other.time );
01176 }
01177 


stage
Author(s): Richard Vaughan , Brian Gerkey , Reed Hedges , Andrew Howard , Toby Collett , Pooya Karimian , Jeremy Asher , Alex Couture-Beil , Geoff Biggs , Rich Mattes , Abbas Sadat
autogenerated on Thu Aug 27 2015 15:20:57