00001
00080 #ifndef _GNU_SOURCE
00081 #define _GNU_SOURCE
00082 #endif
00083
00084
00085
00086 #include <stdlib.h>
00087 #include <assert.h>
00088 #include <string.h>
00089 #include <locale.h>
00090 #include <limits.h>
00091 #include <libgen.h>
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
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
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
00113 return ( ay == by ? a < b : ay < by );
00114 }
00115
00116
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
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 ),
00135 quit( false ),
00136 show_clock( false ),
00137 show_clock_interval( 100 ),
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
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),
00159 pending_update_callbacks(),
00160 active_energy(),
00161 active_velocity(),
00162 sim_interval( 1e5 ),
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" );
00180 AddModelName( ground, ground->Token() );
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;
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
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
00252
00253 pthread_mutex_lock( &world->sync_mutex );
00254
00255 while( 1 )
00256 {
00257
00258
00259
00260
00261 pthread_cond_wait( &world->threads_start_cond, &world->sync_mutex );
00262 pthread_mutex_unlock( &world->sync_mutex );
00263
00264
00265 world->ConsumeQueue( thread_instance );
00266
00267
00268
00269
00270
00271
00272 pthread_mutex_lock( &world->sync_mutex );
00273 if( --world->threads_working == 0 )
00274 {
00275
00276 pthread_cond_signal( &world->threads_done_cond );
00277 }
00278
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
00298 models_by_name.erase( mod->token );
00299
00300 models.erase( mod );
00301 }
00302
00303 void World::LoadBlock( Worldfile* wf, int entity )
00304 {
00305
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
00317 ModelRanger* rgr( dynamic_cast<ModelRanger*>(models_by_wfentity[ wf->GetEntityParent( entity )]));
00318
00319
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);
00331
00332
00333
00334 creator_t creator = NULL;
00335
00336
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
00350 if( creator )
00351 {
00352
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
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
00382 mod->Load(wf, entity );
00383
00384
00385 models_by_wfentity[entity] = mod;
00386 }
00387
00388 void World::Load( const std::string& worldfile_path )
00389 {
00390
00391
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
00401
00402
00403 const int entity(0);
00404
00405
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
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
00435
00436
00437 for( unsigned int t(0); t<worker_threads; ++t )
00438 {
00439
00440 typedef void* (*func_ptr) (void*);
00441
00442
00443
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
00456 for( int entity(1); entity < wf->GetEntityCount(); ++entity )
00457 {
00458 const char *typestr = (char*)wf->GetEntityType(entity);
00459
00460
00461 if( strcmp( typestr, "window" ) == 0 )
00462 {
00463
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
00474 FOR_EACH( it, models )
00475 {
00476
00477 (*it)->blockgroup.CalcSize();
00478 (*it)->UnMap(updates%2);
00479 (*it)->Map(updates%2);
00480
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
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
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
00561
00562 return cb_list.size();
00563 }
00564
00565 void World::CallUpdateCallbacks()
00566 {
00567
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
00576
00577
00578
00579 cbcount += q.size();
00580
00581 while( ! q.empty() )
00582 {
00583 q.front()->CallUpdateCallbacks();
00584 q.pop();
00585 }
00586 }
00587
00588
00589 assert( update_cb_count >= cbcount );
00590
00591
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
00607
00608
00609 do
00610 {
00611 Event ev( queue.top() );
00612 if( ev.time > sim_time ) break;
00613 queue.pop();
00614
00615
00616
00617
00618
00619 ev.cb( ev.mod, ev.arg);
00620 }
00621 while( !queue.empty() );
00622 }
00623
00624 bool World::Update()
00625 {
00626
00627
00628
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
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
00651
00652
00653
00654 ConsumeQueue( 0 );
00655
00656
00657 pthread_mutex_lock( &sync_mutex );
00658 threads_working = worker_threads;
00659
00660
00661 pthread_cond_broadcast( &threads_start_cond );
00662 pthread_mutex_unlock( &sync_mutex );
00663
00664
00665 FOR_EACH( it, active_velocity )
00666 (*it)->Move();
00667
00668 pthread_mutex_lock( &sync_mutex );
00669
00670
00671 while( threads_working > 0 )
00672 {
00673
00674 pthread_cond_wait( &threads_done_cond, &sync_mutex );
00675 }
00676 pthread_mutex_unlock( &sync_mutex );
00677
00678
00679
00680
00681
00682 dirty = true;
00683
00684
00685
00686
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
00700
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;
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
00735 FOR_EACH( it, ray_list )
00736 delete [] *it;
00737
00738 ray_list.clear();
00739 }
00740
00741
00742 void World::Raytrace( const Pose &gpose,
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,
00749 const uint32_t sample_count,
00750 const bool ztest )
00751 {
00752
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
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
00778
00779
00780
00781 RaytraceResult sample( r.origin, r.range );
00782
00783
00784 double globx( r.origin.x * ppm );
00785 double globy( r.origin.y * ppm );
00786
00787
00788 const double startx( globx );
00789 const double starty( globy );
00790
00791
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);
00796
00797
00798
00799 const double dx( ppm * r.range * cosa);
00800 const double dy( ppm * r.range * sina);
00801
00802
00803
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);
00811 int32_t n(ax+ay);
00812
00813
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
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
00826 double xcrossx(0), xcrossy(0);
00827 double ycrossx(0), ycrossy(0);
00828 double distX(0), distY(0);
00829 bool calculatecrossings( true );
00830
00831
00832
00833
00834
00835
00836
00837 while( n > 0 )
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 )
00843 {
00844
00845
00846
00847
00848 calculatecrossings = true;
00849
00850
00851 int32_t cx( GETCELL(globx) );
00852 int32_t cy( GETCELL(globy) );
00853
00854 Cell* c( ®->cells[ cx + cy * REGIONWIDTH ] );
00855
00856
00857
00858
00859
00860
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
00871 if( r.ztest &&
00872 ( r.origin.z < block->global_z.min ||
00873 r.origin.z > block->global_z.max ) )
00874 continue;
00875
00876
00877 if( (*r.func)( block->mod, (Model*)r.mod, r.arg ))
00878 {
00879
00880 sample.color = block->GetColor();
00881 sample.mod = block->mod;
00882
00883 if( ax > ay )
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
00893 if( exy < 0 )
00894 {
00895 globx += sx;
00896 exy += by;
00897 c += sx;
00898 cx += sx;
00899 }
00900 else
00901 {
00902 globy += sy;
00903 exy -= bx;
00904 c += sy * REGIONWIDTH;
00905 cy += sy;
00906 }
00907 --n;
00908
00909
00910 }
00911
00912 }
00913 else
00914 {
00915
00916
00917
00918 if( calculatecrossings )
00919 {
00920 calculatecrossings = false;
00921
00922
00923
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
00932 const double xdx( sx < 0 ?
00933 regionx - globx - 1.0 :
00934 regionx + REGIONWIDTH - globx );
00935 const double xdy( xdx*tana );
00936
00937 const double ydy( sy < 0 ?
00938 regiony - globy - 1.0 :
00939 regiony + REGIONWIDTH - globy );
00940 const double ydx( ydy/tana );
00941
00942
00943 xcrossx = globx+xdx;
00944 xcrossy = globy+xdy;
00945
00946 ycrossx = globx+ydx;
00947 ycrossy = globy+ydy;
00948
00949
00950
00951 distX = fabs(xdx)+fabs(xdy);
00952 distY = fabs(ydx)+fabs(ydy);
00953 }
00954
00955 if( distX < distY )
00956 {
00957
00958 globx = xcrossx;
00959 globy = xcrossy;
00960
00961 n -= distX;
00962
00963
00964 xcrossx += xjumpx;
00965 xcrossy += xjumpy;
00966
00967 distY -= distX;
00968 distX = xjumpdist;
00969
00970
00971 }
00972 else
00973 {
00974
00975 globx = ycrossx;
00976 globy = ycrossy;
00977
00978 n -= distY;
00979
00980 ycrossx += yjumpx;
00981 ycrossy += yjumpy;
00982
00983 distX -= distY;
00984 distY = yjumpdist;
00985
00986
00987 }
00988 }
00989
00990 }
00991
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
01015 void World::Reload( void )
01016 {
01017 ForEachDescendant( _reload_cb, NULL );
01018 }
01019
01020
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
01031
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
01054
01055
01056
01057 int32_t cx( GETCELL(globx) );
01058 int32_t cy( GETCELL(globy) );
01059
01060
01061
01062
01063 Cell* c( reg->GetCell( cx, cy ) );
01064
01065
01066 while( (cx>=0) && (cx<REGIONWIDTH) &&
01067 (cy>=0) && (cy<REGIONWIDTH) &&
01068 n > 0 )
01069 {
01070 c->AddBlock(block, layer );
01071
01072
01073
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
01100 Extend( point3_t( (sup.x << SRBITS) / ppm,
01101 (sup.y << SRBITS) / ppm,
01102 0 ));
01103
01104
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
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 )
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
01169
01170
01171 }
01172
01173 bool World::Event::operator<( const Event& other ) const
01174 {
01175 return( time > other.time );
01176 }
01177