world.cc
Go to the documentation of this file.
1 
80 #ifndef _GNU_SOURCE
81 #define _GNU_SOURCE
82 #endif
83 
84 //#define DEBUG
85 
86 #include <stdlib.h>
87 #include <assert.h>
88 #include <string.h> // for strdup(3)
89 #include <locale.h>
90 #include <limits.h>
91 #include <libgen.h> // for dirname(3)
92 
93 #include "stage.hh"
94 #include "file_manager.hh"
95 #include "worldfile.hh"
96 #include "region.hh"
97 #include "option.hh"
98 using namespace Stg;
99 
100 // // function objects for comparing model positions
101 bool World::ltx::operator()(const Model* a, const Model* b) const
102 {
103  const meters_t ax( a->GetGlobalPose().x );
104  const meters_t bx( b->GetGlobalPose().x );
105  // break ties using the pointer value to give a unique ordering
106  return ( ax == bx ? a < b : ax < bx );
107 }
108 bool World::lty::operator()(const Model* a, const Model* b) const
109 {
110  const meters_t ay( a->GetGlobalPose().y );
111  const meters_t by( b->GetGlobalPose().y );
112  // break ties using the pointer value ro give a unique ordering
113  return ( ay == by ? a < b : ay < by );
114 }
115 
116 // static data members
117 unsigned int World::next_id(0);
118 bool World::quit_all(false);
119 std::set<World*> World::world_set;
120 std::string World::ctrlargs;
121 std::vector<std::string> World::args;
122 
123 World::World( const std::string& name,
124  double ppm )
125  :
126  // private
127  destroy( false ),
128  dirty( true ),
129  models(),
130  models_by_name(),
134  ppm( ppm ), // raytrace resolution
135  quit( false ),
136  show_clock( false ),
137  show_clock_interval( 100 ), // 10 simulated seconds using defaults
138  sync_mutex(),
139  threads_working( 0 ),
142  total_subs( 0 ),
143  worker_threads( 1 ),
144 
145  // protected
146  cb_list(),
147  extent(),
148  graphics( false ),
149  option_table(),
150  powerpack_list(),
151  quit_time( 0 ),
152  ray_list(),
153  sim_time( 0 ),
154  superregions(),
155  updates( 0 ),
156  wf( NULL ),
157  paused( false ),
158  event_queues(1), // use 1 thread by default
160  active_energy(),
161  active_velocity(),
162  sim_interval( 1e5 ), // 100 msec has proved a good default
163  update_cb_count(0)
164 {
165  if( ! Stg::InitDone() )
166  {
167  PRINT_WARN( "Stg::Init() must be called before a World is created." );
168  exit(-1);
169  }
170 
171  pthread_mutex_init( &sync_mutex, NULL );
172  pthread_cond_init( &threads_start_cond, NULL );
173  pthread_cond_init( &threads_done_cond, NULL );
174 
175  World::world_set.insert( this );
176 
177  ground = new Model(this, NULL, "model");
178  assert(ground);
179  ground->SetToken( "_ground_model" ); // allow users to identify this unique model
180  AddModelName( ground, ground->Token() ); // add this name to the world's table
181  ground->ClearBlocks();
182  ground->SetGuiMove(false);
183 }
184 
186 {
187  PRINT_DEBUG2( "destroying world %d %s", id, Token() );
188  if( ground ) delete ground;
189  if( wf ) delete wf;
190  World::world_set.erase( this );
191 }
192 
194 {
195  SuperRegion* sr( new SuperRegion( this, origin ) );
196  superregions[origin] = sr;
197  dirty = true; // force redraw
198  return sr;
199 }
200 
202 {
203  superregions.erase( sr->GetOrigin() );
204  delete sr;
205 }
206 
208 {
209  // first check wheter there is a single gui world
210  bool found_gui = false;
211  FOR_EACH( world_it, world_set )
212  {
213  found_gui |= (*world_it)->IsGUI();
214  }
215  if(found_gui && (world_set.size() != 1))
216  {
217  PRINT_WARN( "When using the GUI only a single world can be simulated." );
218  exit(-1);
219  }
220 
221  if(found_gui)
222  {
223  Fl::run();
224  }
225  else
226  {
227  while(!UpdateAll());
228  }
229 }
230 
232 {
233  bool quit( true );
234 
235  FOR_EACH( world_it, World::world_set )
236  {
237  if( (*world_it)->Update() == false )
238  quit = false;
239  }
240 
241  return quit;
242 }
243 
244 
245 
246 void* World::update_thread_entry( std::pair<World*,int> *thread_info )
247 {
248  World* world( thread_info->first );
249  const int thread_instance( thread_info->second );
250 
251  //printf( "thread ID %d waiting for mutex\n", thread_instance );
252 
253  pthread_mutex_lock( &world->sync_mutex );
254 
255  while( 1 )
256  {
257  //printf( "thread ID %d waiting for start\n", thread_instance );
258  // wait until the main thread signals us
259  //puts( "worker waiting for start signal" );
260 
261  pthread_cond_wait( &world->threads_start_cond, &world->sync_mutex );
262  pthread_mutex_unlock( &world->sync_mutex );
263 
264  //printf( "worker %u thread awakes for task %u\n", thread_instance, task );
265  world->ConsumeQueue( thread_instance );
266  //printf( "thread %d done\n", thread_instance );
267 
268  // done working, so increment the counter. If this was the last
269  // thread to finish working, signal the main thread, which is
270  // blocked waiting for this to happen
271 
272  pthread_mutex_lock( &world->sync_mutex );
273  if( --world->threads_working == 0 )
274  {
275  //puts( "last worker signalling main thread" );
276  pthread_cond_signal( &world->threads_done_cond );
277  }
278  // keep lock going round the loop
279  }
280 
281  return NULL;
282 }
283 
284 void World::AddModel( Model* mod )
285 {
286  models.insert( mod );
287  models_by_name[mod->token] = mod;
288 }
289 
290 void World::AddModelName( Model* mod, const std::string& name )
291 {
292  models_by_name[name] = mod;
293 }
294 
296 {
297  // remove all this model's names to the table
298  models_by_name.erase( mod->token );
299 
300  models.erase( mod );
301 }
302 
303 void World::LoadBlock( Worldfile* wf, int entity )
304 {
305  // lookup the group in which this was defined
306  Model* mod( models_by_wfentity[ wf->GetEntityParent( entity )]);
307 
308  if( ! mod )
309  PRINT_ERR( "block has no model for a parent" );
310 
311  mod->LoadBlock( wf, entity );
312 }
313 
314 void World::LoadSensor( Worldfile* wf, int entity )
315 {
316  // lookup the group in which this was defined
317  ModelRanger* rgr( dynamic_cast<ModelRanger*>(models_by_wfentity[ wf->GetEntityParent( entity )]));
318 
319  //todo verify that the parent is indeed a ranger
320 
321  if( ! rgr )
322  PRINT_ERR( "block has no ranger model for a parent" );
323 
324  rgr->LoadSensor( wf, entity );
325 }
326 
327 
328 Model* World::CreateModel( Model* parent, const std::string& typestr )
329 {
330  Model* mod(NULL); // new model to return
331 
332  // find the creator function pointer in the map. use the
333  // vanilla model if the type is NULL.
334  creator_t creator = NULL;
335 
336  // printf( "creating model of type %s\n", typestr );
337 
338  std::map< std::string, creator_t>::iterator it =
339  Model::name_map.find( typestr );
340 
341  if( it == Model::name_map.end() )
342  {
343  puts("");
344  PRINT_ERR1( "Model type %s not found in model typetable", typestr.c_str() );
345  }
346  else
347  creator = it->second;
348 
349  // if we found a creator function, call it
350  if( creator )
351  {
352  //printf( "creator fn: %p\n", creator );
353  mod = (*creator)( this, parent, typestr );
354  }
355  else
356  {
357  PRINT_ERR1( "Unknown model type %s in world file.",
358  typestr.c_str() );
359  exit( 1 );
360  }
361 
362  //printf( "created model %s\n", mod->Token() );
363 
364  return mod;
365 }
366 
367 void World::LoadModel( Worldfile* wf, int entity )
368 {
369  const int parent_entity( wf->GetEntityParent( entity ));
370 
371  PRINT_DEBUG2( "wf entity %d parent entity %d\n",
372  entity, parent_entity );
373 
374  Model* parent( models_by_wfentity[ parent_entity ]);
375 
376  const char *typestr((char*)wf->GetEntityType(entity));
377  assert(typestr);
378 
379  Model* mod( CreateModel( parent, typestr ));
380 
381  // configure the model with properties from the world file
382  mod->Load(wf, entity );
383 
384  // record the model we created for this worldfile entry
385  models_by_wfentity[entity] = mod;
386 }
387 
388 void World::Load( const std::string& worldfile_path )
389 {
390  // note: must call Unload() before calling Load() if a world already
391  // exists TODO: unload doesn't clean up enough right now
392 
393  printf( " [Loading %s]", worldfile_path.c_str() );
394  fflush(stdout);
395 
396  this->wf = new Worldfile();
397  wf->Load( worldfile_path );
398  PRINT_DEBUG1( "wf has %d entitys", wf->GetEntityCount() );
399 
400  // end the output line of worldfile components
401  //puts("");
402 
403  const int entity(0);
404 
405  // nothing gets added if the string is empty
406  this->SetToken( wf->ReadString( entity, "name", worldfile_path ));
407 
408  this->quit_time =
409  (usec_t)( million * wf->ReadFloat( entity, "quit_time", this->quit_time ) );
410 
411  this->ppm =
412  1.0 / wf->ReadFloat( entity, "resolution", 1.0 / this->ppm );
413 
414  this->show_clock =
415  wf->ReadInt( entity, "show_clock", this->show_clock );
416 
417  this->show_clock_interval =
418  wf->ReadInt( entity, "show_clock_interval", this->show_clock_interval );
419 
420  // read msec instead of usec: easier for user
421  this->sim_interval =
422  1e3 * wf->ReadFloat( entity, "interval_sim", this->sim_interval / 1e3 );
423 
424  this->worker_threads = wf->ReadInt( entity, "threads", this->worker_threads );
425  if( this->worker_threads < 1 )
426  {
427  PRINT_WARN( "threads set to <1. Forcing to 1" );
428  this->worker_threads = 1;
429  }
430 
432  event_queues.resize( worker_threads + 1 );
433 
434  //printf( "worker threads %d\n", worker_threads );
435 
436  // kick off the threads
437  for( unsigned int t(0); t<worker_threads; ++t )
438  {
439  //normal posix pthread C function pointer
440  typedef void* (*func_ptr) (void*);
441 
442  // the pair<World*,int> is the configuration for each thread. it can't be a local
443  // stack var, since it's accssed in the threads
444 
445  pthread_t pt;
446  pthread_create( &pt,
447  NULL,
448  (func_ptr)World::update_thread_entry,
449  new std::pair<World*,int>( this, t+1 ) );
450  }
451 
452  if( worker_threads > 1 )
453  printf( "[threads %u]", worker_threads );
454 
455  // Iterate through entitys and create objects of the appropriate type
456  for( int entity(1); entity < wf->GetEntityCount(); ++entity )
457  {
458  const char *typestr = (char*)wf->GetEntityType(entity);
459 
460  // don't load window entries here
461  if( strcmp( typestr, "window" ) == 0 )
462  {
463  /* do nothing here */
464  }
465  else if( strcmp( typestr, "block" ) == 0 )
466  LoadBlock( wf, entity );
467  else if( strcmp( typestr, "sensor" ) == 0 )
468  LoadSensor( wf, entity );
469  else
470  LoadModel( wf, entity );
471  }
472 
473  // call all controller init functions
474  FOR_EACH( it, models )
475  {
476  // all this is a hack and shouldn't be necessary
477  (*it)->blockgroup.CalcSize();
478  (*it)->UnMap(updates%2);
479  (*it)->Map(updates%2);
480  // to here
481 
482  (*it)->InitControllers();
483  }
484 
485  putchar( '\n' );
486 }
487 
489 {
490  if( wf ) delete wf;
491 
492  FOR_EACH( it, children )
493  delete (*it);
494  children.clear();
495 
496  models_by_name.clear();
497  models_by_wfentity.clear();
498 
499  ray_list.clear();
500 
501  // todo - clean up regions & superregions?
502 
503  token = "[unloaded]";
504 }
505 
507 {
508  return( (quit_time > 0) && (sim_time >= quit_time) );
509 }
510 
511 std::string World::ClockString() const
512 {
513  const uint32_t usec_per_hour(3600000000U);
514  const uint32_t usec_per_minute(60000000U);
515  const uint32_t usec_per_second(1000000U);
516  const uint32_t usec_per_msec(1000U);
517 
518  const uint32_t hours(sim_time / usec_per_hour);
519  const uint32_t minutes((sim_time % usec_per_hour) / usec_per_minute);
520  const uint32_t seconds((sim_time % usec_per_minute) / usec_per_second);
521  const uint32_t msec((sim_time % usec_per_second) / usec_per_msec);
522 
523  std::string str;
524  char buf[256];
525 
526  if( hours > 0 )
527  {
528  snprintf( buf, 255, "%uh", hours );
529  str += buf;
530  }
531 
532  snprintf( buf, 255, " %um %02us %03umsec", minutes, seconds, msec);
533  str += buf;
534 
535  return str;
536 }
537 
539  void* user )
540 {
541  // add the callback & argument to the list
542  cb_list.push_back( std::pair<world_callback_t,void*>(cb, user) );
543 
544 }
545 
547  void* user )
548 {
549  std::pair<world_callback_t,void*> p( cb, user );
550 
551  FOR_EACH( it, cb_list )
552  {
553  if( (*it) == p )
554  {
555  cb_list.erase( it );
556  break;
557  }
558  }
559 
560  // return the number of callbacks now in the list. Useful for
561  // detecting when the list is empty.
562  return cb_list.size();
563 }
564 
566 {
567  // call model CB_UPDATE callbacks queued up by worker threads
568  size_t threads( pending_update_callbacks.size() );
569  int cbcount( 0 );
570 
571  for( size_t t(0); t<threads; ++t )
572  {
573  std::queue<Model*>& q( pending_update_callbacks[t] );
574 
575  // printf( "pending callbacks for thread %u: %u\n",
576  // (unsigned int)t,
577  // (unsigned int)q.size() );
578 
579  cbcount += q.size();
580 
581  while( ! q.empty() )
582  {
583  q.front()->CallUpdateCallbacks();
584  q.pop();
585  }
586  }
587  // printf( "cb total %u (global %d)\n\n", (unsigned int)cbcount,update_cb_count );
588 
589  assert( update_cb_count >= cbcount );
590 
591  // world callbacks
592  FOR_EACH( it, cb_list )
593  {
594  if( ((*it).first )( this, (*it).second ) )
595  it = cb_list.erase( it );
596  }
597 }
598 
599 void World::ConsumeQueue( unsigned int queue_num )
600 {
601  std::priority_queue<Event>& queue( event_queues[queue_num] );
602 
603  if( queue.empty() )
604  return;
605 
606  //printf( "event queue len %d\n", (int)queue.size() );
607 
608  // update everything on the event queue that happens at this time or earlier
609  do
610  {
611  Event ev( queue.top() );
612  if( ev.time > sim_time ) break;
613  queue.pop();
614 
615  //printf( "Q%d @ %llu next event ptr %p cb %p\n", queue_num, sim_time, ev.mod, ev.cb );
616  //std::string modelType = ev.mod->GetModelType();
617  //printf( "@ %llu next event <%s %llu %s>\n", sim_time, modelType.c_str(), ev.time, ev.mod->Token() );
618 
619  ev.cb( ev.mod, ev.arg); // call the event's callback on the model
620  }
621  while( !queue.empty() );
622 }
623 
625 {
626  //puts( "World::Update()" );
627 
628  // if we've run long enough, exit
629  if( PastQuitTime() )
630  return true;
631 
632  if( show_clock && ((this->updates % show_clock_interval) == 0) )
633  {
634  printf( "\r[Stage: %s]", ClockString().c_str() );
635  fflush( stdout );
636  }
637 
639 
640  // rebuild the sets sorted by position on x,y axis
641  models_with_fiducials_byx.clear();
642  models_with_fiducials_byy.clear();
643 
645  {
646  models_with_fiducials_byx.insert( *it );
647  models_with_fiducials_byy.insert( *it );
648  }
649 
650  //printf( "x %lu y %lu\n", models_with_fiducials_byy.size(),
651  // models_with_fiducials_byx.size() );
652 
653  // handle the zeroth queue synchronously in the main thread
654  ConsumeQueue( 0 );
655 
656  // handle all the remaining queues asynchronously in worker threads
657  pthread_mutex_lock( &sync_mutex );
659  // unblock the workers - they are waiting on this condition var
660  //puts( "main thread signalling workers" );
661  pthread_cond_broadcast( &threads_start_cond );
662  pthread_mutex_unlock( &sync_mutex );
663 
664  // update the position of all position models based on their velocity
666  (*it)->Move();
667 
668  pthread_mutex_lock( &sync_mutex );
669  // wait for all the last update job to complete - it will
670  // signal the worker_threads_done condition var
671  while( threads_working > 0 )
672  {
673  //puts( "main thread waiting for workers to finish" );
674  pthread_cond_wait( &threads_done_cond, &sync_mutex );
675  }
676  pthread_mutex_unlock( &sync_mutex );
677  //puts( "main thread awakes" );
678 
679  // TODO: allow threadsafe callbacks to be called in worker
680  // threads
681 
682  dirty = true; // need redraw
683 
684  // this stuff must be done in series here
685 
686  // world callbacks
688 
689  FOR_EACH( it, active_energy )
690  (*it)->UpdateCharge();
691 
692  ++updates;
693 
694  return false;
695 }
696 
697 unsigned int World::GetEventQueue( Model* mod ) const
698 {
699  // todo: there should be a policy that works faster than random, but
700  // random should do a good core load balancing.
701 
702  if( worker_threads < 1 )
703  return 0;
704  return( (random() % worker_threads) + 1);
705 }
706 
707 Model* World::GetModel( const std::string& name ) const
708 {
709  PRINT_DEBUG1( "looking up model name %s in models_by_name", name.c_str() );
710 
711  std::map<std::string,Model*>::const_iterator it( models_by_name.find( name ) );
712 
713  if( it == models_by_name.end() )
714  {
715  PRINT_WARN1( "lookup of model name %s: no matching name", name.c_str() );
716  return NULL;
717  }
718  else
719  return it->second; // the Model*
720 }
721 
722 void World::RecordRay( double x1, double y1, double x2, double y2 )
723 {
724  float* drawpts( new float[4] );
725  drawpts[0] = x1;
726  drawpts[1] = y1;
727  drawpts[2] = x2;
728  drawpts[3] = y2;
729  ray_list.push_back( drawpts );
730 }
731 
733 {
734  // destroy the C arrays first
735  FOR_EACH( it, ray_list )
736  delete [] *it;
737 
738  ray_list.clear();
739 }
740 
741 // Perform multiple raytraces evenly spaced over an angular field of view
742 void World::Raytrace( const Pose &gpose, // global pose
743  const meters_t range,
744  const radians_t fov,
745  const ray_test_func_t func,
746  const Model* model,
747  const void* arg,
748  RaytraceResult* samples, // preallocated storage for samples
749  const uint32_t sample_count, // number of samples
750  const bool ztest )
751 {
752  // find the direction of the first ray
753  Pose raypose( gpose );
754  const double starta( fov/2.0 - raypose.a );
755 
756  for( uint32_t s(0); s < sample_count; ++s )
757  {
758  raypose.a = (s * fov / (double)(sample_count-1)) - starta;
759  samples[s] = Raytrace( raypose, range, func, model, arg, ztest );
760  }
761 }
762 
763 // Stage spends 50-99% of its time in this method.
765  const meters_t range,
766  const ray_test_func_t func,
767  const Model* mod,
768  const void* arg,
769  const bool ztest )
770 {
771  return Raytrace( Ray( mod, gpose, range, func, arg, ztest ));
772 }
773 
774 
776 {
777  //rt_cells.clear();
778  //rt_candidate_cells.clear();
779 
780  // initialize the sample
781  RaytraceResult sample( r.origin, r.range );
782 
783  // our global position in (floating point) cell coordinates
784  double globx( r.origin.x * ppm );
785  double globy( r.origin.y * ppm );
786 
787  // record our starting position
788  const double startx( globx );
789  const double starty( globy );
790 
791  // eliminate a potential divide by zero
792  const double angle( r.origin.a == 0.0 ? 1e-12 : r.origin.a );
793  const double sina(sin(angle));
794  const double cosa(cos(angle));
795  const double tana(sina/cosa); // approximately tan(angle) but faster
796 
797  // the x and y components of the ray (these need to be doubles, or a
798  // very weird and rare bug is produced)
799  const double dx( ppm * r.range * cosa);
800  const double dy( ppm * r.range * sina);
801 
802  // fast integer line 3d algorithm adapted from Cohen's code from
803  // Graphics Gems IV
804  const int32_t sx(sgn(dx));
805  const int32_t sy(sgn(dy));
806  const int32_t ax(abs(dx));
807  const int32_t ay(abs(dy));
808  const int32_t bx(2*ax);
809  const int32_t by(2*ay);
810  int32_t exy(ay-ax); // difference between x and y distances
811  int32_t n(ax+ay); // the manhattan distance to the goal cell
812 
813  // the distances between region crossings in X and Y
814  const double xjumpx( sx * REGIONWIDTH );
815  const double xjumpy( sx * REGIONWIDTH * tana );
816  const double yjumpx( sy * REGIONWIDTH / tana );
817  const double yjumpy( sy * REGIONWIDTH );
818 
819  // manhattan distance between region crossings in X and Y
820  const double xjumpdist( fabs(xjumpx)+fabs(xjumpy) );
821  const double yjumpdist( fabs(yjumpx)+fabs(yjumpy) );
822 
823  const unsigned int layer( (updates+1) % 2 );
824 
825  // these are updated as we go along the ray
826  double xcrossx(0), xcrossy(0);
827  double ycrossx(0), ycrossy(0);
828  double distX(0), distY(0);
829  bool calculatecrossings( true );
830 
831  // Stage spends up to 95% of its time in this loop! It would be
832  // neater with more function calls encapsulating things, but even
833  // inline calls have a noticeable (2-3%) effect on performance.
834 
835  // several useful asserts are commented out so that Stage is not too
836  // slow in debug builds. Add them in if chasing a suspected raytrace bug
837  while( n > 0 ) // while we are still not at the ray end
838  {
839  SuperRegion* sr( GetSuperRegion(point_int_t(GETSREG(globx),GETSREG(globy))));
840  Region* reg( sr ? sr->GetRegion(GETREG(globx),GETREG(globy)) : NULL );
841 
842  if( reg && reg->count ) // if the region contains any objects
843  {
844  //assert( reg->cells.size() );
845 
846  // invalidate the region crossing points used to jump over
847  // empty regions
848  calculatecrossings = true;
849 
850  // convert from global cell to local cell coords
851  int32_t cx( GETCELL(globx) );
852  int32_t cy( GETCELL(globy) );
853 
854  Cell* c( &reg->cells[ cx + cy * REGIONWIDTH ] );
855 
856  // this assert makes Stage slow when compiled for debug
857  // assert(c); // should be good: we know the region contains objects
858 
859  // while within the bounds of this region and while some ray remains
860  // we'll tweak the cell pointer directly to move around quickly
861  while( (cx>=0) && (cx<REGIONWIDTH) &&
862  (cy>=0) && (cy<REGIONWIDTH) &&
863  n > 0 )
864  {
865  FOR_EACH( it, c->blocks[layer] )
866  {
867  Block* block( *it );
868  assert( block );
869 
870  // skip if not in the right z range
871  if( r.ztest &&
872  ( r.origin.z < block->global_z.min ||
873  r.origin.z > block->global_z.max ) )
874  continue;
875 
876  // test the predicate we were passed
877  if( (*r.func)( block->mod, (Model*)r.mod, r.arg ))
878  {
879  // a hit!
880  sample.color = block->GetColor();
881  sample.mod = block->mod;
882 
883  if( ax > ay ) // faster than the equivalent hypot() call
884  sample.range = fabs((globx-startx) / cosa) / ppm;
885  else
886  sample.range = fabs((globy-starty) / sina) / ppm;
887 
888  return sample;
889  }
890  }
891 
892  // increment our cell in the correct direction
893  if( exy < 0 ) // we're iterating along X
894  {
895  globx += sx; // global coordinate
896  exy += by;
897  c += sx; // move the cell left or right
898  cx += sx; // cell coordinate for bounds checking
899  }
900  else // we're iterating along Y
901  {
902  globy += sy; // global coordinate
903  exy -= bx;
904  c += sy * REGIONWIDTH; // move the cell up or down
905  cy += sy; // cell coordinate for bounds checking
906  }
907  --n; // decrement the manhattan distance remaining
908 
909  //rt_cells.push_back( point_int_t( globx, globy ));
910  }
911  //printf( "leaving populated region\n" );
912  }
913  else // jump over the empty region
914  {
915  // on the first run, and when we've been iterating over
916  // cells, we need to calculate the next crossing of a region
917  // boundary along each axis
918  if( calculatecrossings )
919  {
920  calculatecrossings = false;
921 
922  // find the coordinate in cells of the bottom left corner of
923  // the current region
924  const int32_t ix( globx );
925  const int32_t iy( globy );
926  double regionx( ix/REGIONWIDTH*REGIONWIDTH );
927  double regiony( iy/REGIONWIDTH*REGIONWIDTH );
928  if( (globx < 0) && (ix % REGIONWIDTH) ) regionx -= REGIONWIDTH;
929  if( (globy < 0) && (iy % REGIONWIDTH) ) regiony -= REGIONWIDTH;
930 
931  // calculate the distance to the edge of the current region
932  const double xdx( sx < 0 ?
933  regionx - globx - 1.0 : // going left
934  regionx + REGIONWIDTH - globx ); // going right
935  const double xdy( xdx*tana );
936 
937  const double ydy( sy < 0 ?
938  regiony - globy - 1.0 : // going down
939  regiony + REGIONWIDTH - globy ); // going up
940  const double ydx( ydy/tana );
941 
942  // these stored hit points are updated as we go along
943  xcrossx = globx+xdx;
944  xcrossy = globy+xdy;
945 
946  ycrossx = globx+ydx;
947  ycrossy = globy+ydy;
948 
949  // find the distances to the region crossing points
950  // manhattan distance is faster than using hypot()
951  distX = fabs(xdx)+fabs(xdy);
952  distY = fabs(ydx)+fabs(ydy);
953  }
954 
955  if( distX < distY ) // crossing a region boundary left or right
956  {
957  // move to the X crossing
958  globx = xcrossx;
959  globy = xcrossy;
960 
961  n -= distX; // decrement remaining manhattan distance
962 
963  // calculate the next region crossing
964  xcrossx += xjumpx;
965  xcrossy += xjumpy;
966 
967  distY -= distX;
968  distX = xjumpdist;
969 
970  //rt_candidate_cells.push_back( point_int_t( xcrossx, xcrossy ));
971  }
972  else // crossing a region boundary up or down
973  {
974  // move to the X crossing
975  globx = ycrossx;
976  globy = ycrossy;
977 
978  n -= distY; // decrement remaining manhattan distance
979  // calculate the next region crossing
980  ycrossx += yjumpx;
981  ycrossy += yjumpy;
982 
983  distX -= distY;
984  distY = yjumpdist;
985 
986  //rt_candidate_cells.push_back( point_int_t( ycrossx, ycrossy ));
987  }
988  }
989  //rt_cells.push_back( point_int_t( globx, globy ));
990  }
991  // hit nothing
992  sample.mod = NULL;
993  return sample;
994 }
995 
996 static int _save_cb( Model* mod, void* dummy )
997 {
998  mod->Save();
999  return 0;
1000 }
1001 
1002 bool World::Save( const char *filename )
1003 {
1004  ForEachDescendant( _save_cb, NULL );
1005  return this->wf->Save( filename ? filename : wf->filename );
1006 }
1007 
1008 static int _reload_cb( Model* mod, void* dummy )
1009 {
1010  mod->Load();
1011  return 0;
1012 }
1013 
1014 // reload the current worldfile
1015 void World::Reload( void )
1016 {
1017  ForEachDescendant( _reload_cb, NULL );
1018 }
1019 
1020 // add a block to each cell described by a polygon in world coordinates
1021 void World::MapPoly( const std::vector<point_int_t>& pts, Block* block, unsigned int layer )
1022 {
1023  const size_t pt_count( pts.size() );
1024 
1025  for( size_t i(0); i<pt_count; ++i )
1026  {
1027  const point_int_t& start(pts[i] );
1028  const point_int_t& end(pts[(i+1)%pt_count]);
1029 
1030  // line rasterization adapted from Cohen's 3D version in
1031  // Graphics Gems II. Should be very fast.
1032  const int32_t dx( end.x - start.x );
1033  const int32_t dy( end.y - start.y );
1034  const int32_t sx(sgn(dx));
1035  const int32_t sy(sgn(dy));
1036  const int32_t ax(abs(dx));
1037  const int32_t ay(abs(dy));
1038  const int32_t bx(2*ax);
1039  const int32_t by(2*ay);
1040 
1041  int32_t exy(ay-ax);
1042  int32_t n(ax+ay);
1043 
1044  int32_t globx(start.x);
1045  int32_t globy(start.y);
1046 
1047  while( n )
1048  {
1050  GETSREG(globy)))
1051  ->GetRegion( GETREG(globx),
1052  GETREG(globy)));
1053  // assert(reg);
1054 
1055  // add all the required cells in this region before looking up
1056  // another region
1057  int32_t cx( GETCELL(globx) );
1058  int32_t cy( GETCELL(globy) );
1059 
1060  // need to call Region::GetCell() before using a Cell pointer
1061  // directly, because the region allocates cells lazily, waiting
1062  // for a call of this method
1063  Cell* c( reg->GetCell( cx, cy ) );
1064 
1065  // while inside the region, manipulate the Cell pointer directly
1066  while( (cx>=0) && (cx<REGIONWIDTH) &&
1067  (cy>=0) && (cy<REGIONWIDTH) &&
1068  n > 0 )
1069  {
1070  c->AddBlock(block, layer );
1071 
1072  // cleverly skip to the next cell (now it's safe to
1073  // manipulate the cell pointer)
1074  if( exy < 0 )
1075  {
1076  globx += sx;
1077  exy += by;
1078  c += sx;
1079  cx += sx;
1080  }
1081  else
1082  {
1083  globy += sy;
1084  exy -= bx;
1085  c += sy * REGIONWIDTH;
1086  cy += sy;
1087  }
1088  --n;
1089  }
1090  }
1091  }
1092 }
1093 
1094 
1096 {
1097  SuperRegion* sr( CreateSuperRegion( sup ) );
1098 
1099  // set the lower left corner of the new superregion
1100  Extend( point3_t( (sup.x << SRBITS) / ppm,
1101  (sup.y << SRBITS) / ppm,
1102  0 ));
1103 
1104  // top right corner of the new superregion
1105  Extend( point3_t( ((sup.x+1) << SRBITS) / ppm,
1106  ((sup.y+1) << SRBITS) / ppm,
1107  0 ));
1108  return sr;
1109 }
1110 
1111 
1113 {
1114  SuperRegion* sr(NULL);
1115 
1116  // I despise some STL syntax sometimes...
1117  std::map<point_int_t,SuperRegion*>::iterator it( superregions.find(org) );
1118 
1119  if( it != superregions.end() )
1120  sr = it->second;
1121 
1122  return sr;
1123 }
1124 
1126 {
1127  SuperRegion* sr( GetSuperRegion(org) );
1128 
1129  if( sr == NULL ) // no superregion exists! make a new one
1130  {
1131  sr = AddSuperRegion( org );
1132  assert( sr );
1133  }
1134  return sr;
1135 }
1136 
1137 
1139 {
1140  extent.x.min = std::min( extent.x.min, pt.x );
1141  extent.x.max = std::max( extent.x.max, pt.x );
1142  extent.y.min = std::min( extent.y.min, pt.y );
1143  extent.y.max = std::max( extent.y.max, pt.y );
1144  extent.z.min = std::min( extent.z.min, pt.z );
1145  extent.z.max = std::max( extent.z.max, pt.z );
1146 }
1147 
1148 
1150 {
1151  powerpack_list.push_back( pp );
1152 }
1153 
1155 {
1156  EraseAll( pp, powerpack_list );
1157 }
1158 
1161 {
1162  assert(opt);
1163  option_table.insert( opt );
1164 }
1165 
1166 void World::Log( Model* mod )
1167 {
1168  //LogEntry( sim_time, mod);
1169  //printf( "log entry count %u\n", (unsigned int)LogEntry::Count() );
1170  //LogEntry::Print();
1171 }
1172 
1173 bool World::Event::operator<( const Event& other ) const
1174 {
1175  return( time > other.time );
1176 }
1177 
static bool quit_all
quit all worlds ASAP
Definition: stage.hh:832
std::set< Model * > models
Definition: stage.hh:840
Model class
Definition: stage.hh:1742
meters_t y
Definition: stage.hh:485
SuperRegion * CreateSuperRegion(point_int_t origin)
Definition: world.cc:193
meters_t x
Definition: stage.hh:485
bool ztest
Definition: stage.hh:770
pthread_cond_t threads_done_cond
signalled by last worker thread to unblock main thread
Definition: stage.hh:892
Bounds y
volume extent along y axis, initially zero
Definition: stage.hh:453
static bool UpdateAll()
Definition: world.cc:231
int32_t GETSREG(const int32_t x)
Definition: region.hh:29
virtual void UnLoad()
Definition: world.cc:488
const Model * mod
Definition: stage.hh:765
int GetEntityParent(int entity)
Definition: worldfile.cc:1204
uint64_t updates
the number of simulated time steps executed so far
Definition: stage.hh:912
std::map< int, Model * > models_by_wfentity
Definition: stage.hh:846
bool graphics
true iff we have a GUI
Definition: stage.hh:900
double max
largest value in range, initially zero
Definition: stage.hh:435
void LoadBlock(Worldfile *wf, int entity)
Definition: world.cc:303
World class
Definition: stage.hh:814
The Stage library uses its own namespace.
Definition: canvas.hh:8
const char * GetEntityType(int entity)
Definition: worldfile.cc:1214
std::list< std::pair< world_callback_t, void * > > cb_list
List of callback functions and arguments.
Definition: stage.hh:898
static std::vector< std::string > args
Definition: stage.hh:826
bool InitDone()
Definition: stage.cc:41
void Extend(point3_t pt)
Definition: world.cc:1138
virtual void Reload()
Definition: world.cc:1015
unsigned int show_clock_interval
updates between clock outputs
Definition: stage.hh:887
const int32_t SRBITS(RBITS+SBITS)
std::list< float * > ray_list
List of rays traced for debug visualization.
Definition: stage.hh:906
bool operator()(const Model *a, const Model *b) const
Definition: world.cc:108
void RegisterOption(Option *opt)
Register an Option for pickup by the GUI.
Definition: world.cc:1160
int32_t GETREG(const int32_t x)
Definition: region.hh:28
void LoadModel(Worldfile *wf, int entity)
Definition: world.cc:367
void RemovePowerPack(PowerPack *pp)
Definition: world.cc:1154
std::set< Option * > option_table
GUI options (toggles) registered by models.
Definition: stage.hh:902
const Color & GetColor()
Definition: block.cc:134
const std::string ReadString(int entity, const char *name, const std::string &value)
Definition: worldfile.cc:1376
SuperRegion * AddSuperRegion(const point_int_t &coord)
Definition: world.cc:1095
std::string token
Definition: stage.hh:696
pthread_cond_t threads_start_cond
signalled to unblock worker threads
Definition: stage.hh:891
meters_t z
Definition: stage.hh:485
static std::set< World * > world_set
all the worlds that exist
Definition: stage.hh:831
usec_t sim_interval
Definition: stage.hh:1087
std::set< Model *, ltx > models_with_fiducials_byx
Definition: stage.hh:864
void LoadSensor(Worldfile *wf, int entity)
Definition: world.cc:314
void EraseAll(T thing, C &cont)
Definition: stage.hh:621
double min
smallest value in range, initially zero
Definition: stage.hh:433
std::map< std::string, Model * > models_by_name
Definition: stage.hh:843
bool operator<(const Event &other) const
Definition: world.cc:1173
#define PRINT_DEBUG2(m, a, b)
Definition: stage.hh:668
double ppm
the resolution of the world model in pixels per meter
Definition: stage.hh:883
void AddBlock(Block *b, unsigned int index)
Definition: region.cc:267
int update_cb_count
Definition: stage.hh:1092
SuperRegion * GetSuperRegionCreate(const point_int_t &org)
Definition: world.cc:1125
ray_test_func_t func
Definition: stage.hh:768
const double million
Definition: stage.hh:142
void DestroySuperRegion(SuperRegion *sr)
Definition: world.cc:201
usec_t time
time that event occurs
Definition: stage.hh:1048
void Load(Worldfile *wf, int wf_entity)
Definition: stage.hh:2234
model_callback_t cb
Definition: stage.hh:1050
unsigned int worker_threads
the number of worker threads to use
Definition: stage.hh:894
const point_int_t & GetOrigin() const
Definition: region.hh:115
void ForEachDescendant(model_callback_t func, void *arg)
Definition: ancestor.cc:46
float s
Definition: glutgraphics.cc:58
void AddUpdateCallback(world_callback_t cb, void *user)
Definition: world.cc:538
meters_t z
location in 3 axes
Definition: stage.hh:251
meters_t y
Definition: stage.hh:251
Model *(* creator_t)(World *, Model *, const std::string &type)
Definition: stage.hh:87
static void * update_thread_entry(std::pair< World *, int > *info)
Definition: world.cc:246
Bounds global_z
Definition: stage.hh:1283
int total_subs
the total number of subscriptions to all models
Definition: stage.hh:893
Pose origin
Definition: stage.hh:766
void RecordRay(double x1, double y1, double x2, double y2)
Definition: world.cc:722
bool Save(const std::string &filename)
Definition: worldfile.cc:193
usec_t sim_time
the current sim time in this world in microseconds
Definition: stage.hh:907
virtual void AddModel(Model *mod)
Definition: world.cc:284
virtual bool Update(void)
Definition: world.cc:624
static int _reload_cb(Model *mod, void *dummy)
Definition: world.cc:1008
Pose GetGlobalPose() const
Definition: model.cc:1379
void ClearRays()
Definition: world.cc:732
unsigned int threads_working
the number of worker threads not yet finished
Definition: stage.hh:890
meters_t range
Definition: stage.hh:767
std::string filename
Definition: worldfile.hh:350
void LoadSensor(Worldfile *wf, int entity)
static unsigned int next_id
initially zero, used to allocate unique sequential world ids
Definition: stage.hh:834
std::map< point_int_t, SuperRegion * > superregions
Definition: stage.hh:908
pthread_mutex_t sync_mutex
protect the worker thread management stuff
Definition: stage.hh:889
meters_t range
range to beam hit in meters
Definition: stage.hh:745
#define PRINT_ERR(m)
Definition: stage.hh:625
bool dirty
iff true, a gui redraw would be required
Definition: stage.hh:837
uint64_t usec_t
Definition: stage.hh:186
bounds3d_t extent
Describes the 3D volume of the world.
Definition: stage.hh:899
double meters_t
Definition: stage.hh:174
RaytraceResult Raytrace(const Ray &ray)
Definition: world.cc:775
Model * ground
Definition: stage.hh:951
virtual void Save()
Definition: model.cc:1633
Color color
the color struck by this beam
Definition: stage.hh:747
friend class Model
Definition: stage.hh:818
static int _save_cb(Model *mod, void *dummy)
Definition: world.cc:996
Region * GetRegion(int32_t x, int32_t y)
Definition: region.hh:104
virtual void SetToken(const std::string &str)
Definition: stage.hh:2022
Worldfile * wf
If set, points to the worldfile used to create this world.
Definition: stage.hh:913
virtual ~World()
Definition: world.cc:185
bool(* ray_test_func_t)(Model *candidate, Model *finder, const void *arg)
Definition: stage.hh:603
#define PRINT_WARN(m)
Definition: stage.hh:633
Bounds x
volume extent along x axis, intially zero
Definition: stage.hh:451
int GetEntityCount()
Definition: worldfile.cc:1196
bool operator()(const Model *a, const Model *b) const
Definition: world.cc:101
std::vector< Model * > children
Definition: stage.hh:689
bool paused
if true, the simulation is stopped
Definition: stage.hh:921
std::vector< std::priority_queue< Event > > event_queues
Definition: stage.hh:1059
virtual void SetToken(const std::string &str)
Definition: stage.hh:718
virtual void RemoveModel(Model *mod)
Definition: world.cc:295
ModelRanger class
Definition: stage.hh:2747
bool show_clock
iff true, print the sim time on stdout
Definition: stage.hh:886
#define PRINT_DEBUG1(m, a)
Definition: stage.hh:667
Bounds z
volume extent along z axis, initially zero
Definition: stage.hh:455
const int32_t REGIONWIDTH(1<< RBITS)
Cell * GetCell(int32_t x, int32_t y)
Definition: region.hh:70
double ReadFloat(int entity, const char *name, double value)
Definition: worldfile.cc:1434
static void Run()
Definition: world.cc:207
static std::map< std::string, creator_t > name_map
Definition: stage.hh:2466
bool PastQuitTime()
Definition: world.cc:506
bool destroy
Definition: stage.hh:836
void SetGuiMove(bool val)
Definition: model.cc:1323
bool quit
quit this world ASAP
Definition: stage.hh:884
Model * GetModel(const std::string &name) const
Definition: world.cc:707
std::set< Model * > active_energy
Definition: stage.hh:1079
std::set< Model *, lty > models_with_fiducials_byy
Definition: stage.hh:868
std::list< PowerPack * > powerpack_list
List of all the powerpacks attached to models in the world.
Definition: stage.hh:903
#define PRINT_ERR1(m, a)
Definition: stage.hh:626
void ConsumeQueue(unsigned int queue_num)
Definition: world.cc:599
std::vector< std::queue< Model * > > pending_update_callbacks
Definition: stage.hh:1062
const void * arg
Definition: stage.hh:769
void Log(Model *mod)
Definition: world.cc:1166
std::vector< Block * > blocks[2]
Definition: region.hh:40
std::vector< Model * > models_with_fiducials
Definition: stage.hh:850
int ReadInt(int entity, const char *name, int value)
Definition: worldfile.cc:1398
std::set< ModelPosition * > active_velocity
Definition: stage.hh:1081
#define FOR_EACH(I, C)
Definition: stage.hh:616
SuperRegion * GetSuperRegion(const point_int_t &org)
Definition: world.cc:1112
radians_t a
rotation about the z axis.
Definition: stage.hh:252
int32_t GETCELL(const int32_t x)
Definition: region.hh:27
int(* world_callback_t)(World *world, void *user)
Definition: stage.hh:570
Model * CreateModel(Model *parent, const std::string &typestr)
Definition: world.cc:328
void CallUpdateCallbacks()
Call all calbacks in cb_list, removing any that return true;.
Definition: world.cc:565
virtual bool Save(const char *filename)
Definition: world.cc:1002
void AddModelName(Model *mod, const std::string &name)
Definition: world.cc:290
bool Load(const std::string &filename)
Definition: worldfile.cc:125
unsigned int GetEventQueue(Model *mod) const
Definition: world.cc:697
static std::string ctrlargs
Definition: stage.hh:827
World(const std::string &name="MyWorld", double ppm=DEFAULT_PPM)
Definition: world.cc:123
Model * mod
the model struck by this beam
Definition: stage.hh:746
#define PRINT_WARN1(m, a)
Definition: stage.hh:634
Model * mod
model to which this block belongs
Definition: stage.hh:1269
virtual std::string ClockString(void) const
Definition: world.cc:511
double radians_t
Definition: stage.hh:177
int RemoveUpdateCallback(world_callback_t cb, void *user)
Definition: world.cc:546
meters_t x
Definition: stage.hh:251
void MapPoly(const std::vector< point_int_t > &poly, Block *block, unsigned int layer)
Definition: world.cc:1021
const char * Token() const
Definition: stage.hh:715
int sgn(int a)
Definition: stage.hh:162
virtual void Load(const std::string &worldfile_path)
Definition: world.cc:388
void ClearBlocks()
Definition: model.cc:421
void AddPowerPack(PowerPack *pp)
Definition: world.cc:1149
usec_t quit_time
Definition: stage.hh:905


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 Mon Jun 10 2019 15:06:10