block.cc
Go to the documentation of this file.
00001 #include "region.hh"
00002 #include "worldfile.hh"
00003 
00004 using namespace Stg;
00005 using std::vector;
00006 
00007 static void canonicalize_winding(vector<point_t>& pts);
00008 
00009 
00013 Block::Block( Model* mod,
00014               const std::vector<point_t>& pts,
00015               meters_t zmin,
00016               meters_t zmax,
00017               Color color,
00018               bool inherit_color,
00019               bool wheel ) :
00020   mod( mod ),
00021   mpts(),
00022   pts(pts),
00023   local_z( zmin, zmax ),
00024   color( color ),
00025   inherit_color( inherit_color ),
00026   wheel(wheel),
00027   rendered_cells() 
00028 {
00029   assert( mod );
00030   canonicalize_winding(this->pts);
00031 }
00032 
00034 Block::Block(  Model* mod,
00035                Worldfile* wf,
00036                int entity)
00037   : mod( mod ),
00038     mpts(),
00039     pts(),
00040     local_z(),
00041     color(),
00042     inherit_color(true),
00043     wheel(),
00044     rendered_cells()
00045 {
00046   assert(mod);
00047   assert(wf);
00048   assert(entity);
00049   
00050   Load( wf, entity );
00051   canonicalize_winding(this->pts);
00052 }
00053 
00054 Block::~Block()
00055 {
00056   if( mapped )
00057     {
00058       UnMap(0);
00059       UnMap(1);
00060     }
00061 }
00062 
00063 void Block::Translate( double x, double y )
00064 {
00065   FOR_EACH( it, pts )
00066     {
00067       it->x += x;
00068       it->y += y;
00069     }
00070   
00071   mod->blockgroup.BuildDisplayList( mod );
00072 }
00073 
00074 double Block::CenterY()
00075 {
00076   double min = billion;
00077   double max = -billion;
00078   
00079   FOR_EACH( it, pts )
00080     {
00081       if( it->y > max ) max = it->y;
00082       if( it->y < min ) min = it->y;
00083     }
00084   
00085   // return the value half way between max and min
00086   return( min + (max - min)/2.0 );
00087 }
00088 
00089 double Block::CenterX()
00090 {
00091   double min = billion;
00092   double max = -billion;
00093   
00094   FOR_EACH( it, pts )
00095     {
00096       if( it->x > max ) max = it->x;
00097       if( it->x < min ) min = it->x;
00098     }
00099 
00100   // return the value half way between maxx and min
00101   return( min + (max - min)/2.0 );
00102 }
00103 
00104 void Block::SetCenter( double x, double y )
00105 {
00106   // move the block by the distance required to bring its center to
00107   // the requested position
00108   Translate( x-CenterX(), y-CenterY() );
00109 }
00110 
00111 void Block::SetCenterY( double y )
00112 {
00113   // move the block by the distance required to bring its center to
00114   // the requested position
00115   Translate( 0, y-CenterY() );
00116 }
00117 
00118 void Block::SetCenterX( double x )
00119 {
00120   // move the block by the distance required to bring its center to
00121   // the requested position
00122   Translate( x-CenterX(), 0 );
00123 }
00124 
00125 void Block::SetZ( double min, double max )
00126 {
00127   local_z.min = min;
00128   local_z.max = max;
00129 
00130   // force redraw
00131   mod->blockgroup.BuildDisplayList( mod );
00132 }
00133 
00134 const Color& Block::GetColor()
00135 {
00136   return( inherit_color ? mod->color : color );
00137 }
00138 
00139 void Block::AppendTouchingModels( std::set<Model*>& touchers )
00140 {
00141   unsigned int layer = mod->world->updates % 2;
00142   
00143   // for every cell we are rendered into
00144   FOR_EACH( cell_it, rendered_cells[layer] )
00145     // for every block rendered into that cell
00146     FOR_EACH( block_it, (*cell_it)->GetBlocks(layer) )
00147     {
00148       if( !mod->IsRelated( (*block_it)->mod ))
00149         touchers.insert( (*block_it)->mod );
00150     }
00151 }
00152 
00153 Model* Block::TestCollision()
00154 {
00155   //printf( "model %s block %p test collision...\n", mod->Token(), this );
00156 
00157   // find the set of cells we would render into given the current global pose
00158   //GenerateCandidateCells();
00159   
00160   if( mod->vis.obstacle_return )
00161     {
00162       if ( global_z.min < 0 )
00163         return mod->world->GetGround();
00164           
00165       unsigned int layer = mod->world->updates % 2;
00166 
00167       // for every cell we may be rendered into
00168       FOR_EACH( cell_it, rendered_cells[layer] )
00169         {
00170           // for every block rendered into that cell
00171           FOR_EACH( block_it, (*cell_it)->GetBlocks(layer) )
00172             {
00173               Block* testblock = *block_it;
00174               Model* testmod = testblock->mod;
00175                                 
00176               //printf( "   testing block %p of model %s\n", testblock, testmod->Token() );
00177                                 
00178               // if the tested model is an obstacle and it's not attached to this model
00179               if( (testmod != this->mod) &&
00180                   testmod->vis.obstacle_return &&
00181                   (!mod->IsRelated( testmod )) && 
00182                   // also must intersect in the Z range
00183                   testblock->global_z.min <= global_z.max && 
00184                   testblock->global_z.max >= global_z.min )
00185                 {
00186                   //puts( "HIT");
00187                   return testmod; // bail immediately with the bad news
00188                 }
00189             }
00190         }
00191     }
00192 
00193   //printf( "model %s block %p collision done. no hits.\n", mod->Token(), this );
00194   return NULL; // no hit
00195 }
00196 
00197 void Block::Map( unsigned int layer )
00198 {
00199   // calculate the local coords of the block vertices
00200   const size_t pt_count(pts.size());
00201         
00202   if( mpts.size() == 0 )
00203     {
00204       // no valid cache of model coord points, so generate them
00205       mpts.resize( pts.size() );
00206                         
00207       for( size_t i=0; i<pt_count; ++i )
00208         mpts[i] = BlockPointToModelMeters( pts[i] );
00209     }
00210   
00211   // now calculate the global pixel coords of the block vertices
00212   const std::vector<point_int_t> gpts = mod->LocalToPixels( mpts );
00213         
00214   // and render this block's polygon into the world
00215   mod->world->MapPoly( gpts, this, layer );
00216         
00217   // update the block's absolute z bounds at this rendering
00218   Pose gpose( mod->GetGlobalPose() );
00219   gpose.z += mod->geom.pose.z;
00220   double scalez( mod->geom.size.z /  mod->blockgroup.GetSize().z );
00221   meters_t z = gpose.z - mod->blockgroup.GetOffset().z;  
00222   global_z.min = (scalez * local_z.min) + z;
00223   global_z.max = (scalez * local_z.max) + z;
00224   
00225   mapped = true;        
00226 }
00227 
00228 #include <algorithm>
00229 #include <functional>
00230 
00231 void Block::UnMap( unsigned int layer )
00232 {
00233   FOR_EACH( it, rendered_cells[layer] )
00234     (*it)->RemoveBlock(this, layer );
00235   
00236   rendered_cells[layer].clear();
00237   mapped = false;
00238 }
00239 
00240 inline point_t Block::BlockPointToModelMeters( const point_t& bpt )
00241 {
00242   Size bgsize = mod->blockgroup.GetSize();
00243   point3_t bgoffset = mod->blockgroup.GetOffset();
00244 
00245   return point_t( (bpt.x - bgoffset.x) * (mod->geom.size.x/bgsize.x),
00246                   (bpt.y - bgoffset.y) * (mod->geom.size.y/bgsize.y));
00247 }
00248 
00249 void Block::InvalidateModelPointCache()
00250 {
00251   // this doesn't happen often, so this simple strategy isn't too wasteful
00252   mpts.clear();
00253 }
00254 
00255 void swap( int& a, int& b )
00256 {
00257   int tmp = a;
00258   a = b;
00259   b = tmp;
00260 }
00261 
00262 void Block::Rasterize( uint8_t* data,
00263                        unsigned int width,
00264                        unsigned int height,
00265                        meters_t cellwidth,
00266                        meters_t cellheight )
00267 {
00268   //printf( "rasterize block %p : w: %u h: %u  scale %.2f %.2f  offset %.2f %.2f\n",
00269   //     this, width, height, scalex, scaley, offsetx, offsety );
00270         
00271   const size_t pt_count = pts.size();
00272   for( size_t i=0; i<pt_count; ++i )
00273     {
00274       // convert points from local to model coords
00275       point_t mpt1 = BlockPointToModelMeters( pts[i] );
00276       point_t mpt2 = BlockPointToModelMeters( pts[(i+1)%pt_count] );
00277           
00278       // record for debug visualization
00279       mod->rastervis.AddPoint( mpt1.x, mpt1.y );
00280           
00281       // shift to the bottom left of the model
00282       mpt1.x += mod->geom.size.x/2.0;
00283       mpt1.y += mod->geom.size.y/2.0;
00284       mpt2.x += mod->geom.size.x/2.0;
00285       mpt2.y += mod->geom.size.y/2.0;
00286           
00287       // convert from meters to cells
00288       point_int_t a( floor( mpt1.x / cellwidth  ),
00289                      floor( mpt1.y / cellheight ));
00290       point_int_t b( floor( mpt2.x / cellwidth  ),
00291                      floor( mpt2.y / cellheight ) );
00292           
00293       bool steep = abs( b.y-a.y ) > abs( b.x-a.x );
00294       if( steep )
00295         {
00296           swap( a.x, a.y );
00297           swap( b.x, b.y );
00298         }
00299           
00300       if( a.x > b.x )
00301         {
00302           swap( a.x, b.x );
00303           swap( a.y, b.y );
00304         }
00305           
00306       double dydx = (double) (b.y - a.y) / (double) (b.x - a.x);
00307       double y = a.y;
00308       for(int x=a.x; x<=b.x; ++x)
00309         {
00310           if( steep )
00311             {
00312               if( ! (floor(y) >= 0) ) continue;
00313               if( ! (floor(y) < (int)width) ) continue;
00314               if( ! (x >= 0) ) continue;
00315               if( ! (x < (int)height) ) continue;
00316             }
00317           else
00318             {
00319               if( ! (x >= 0) ) continue;
00320               if( ! (x < (int)width) ) continue;
00321               if( ! (floor(y) >= 0) ) continue;
00322               if( ! (floor(y) < (int)height) ) continue;
00323             }
00324                   
00325           if( steep )
00326             data[ (int)floor(y) + (x * width)] = 1;
00327           else
00328             data[ x + ((int)floor(y) * width)] = 1;
00329           y += dydx;
00330         }
00331     }
00332 }
00333 
00334 void Block::DrawTop()
00335 {
00336   // draw the top of the block - a polygon at the highest vertical
00337   // extent
00338   glBegin( GL_POLYGON);
00339   FOR_EACH( it, pts )
00340     glVertex3f( it->x, it->y, local_z.max );
00341   glEnd();
00342 }
00343 
00344 void Block::DrawSides()
00345 {
00346   // construct a strip that wraps around the polygon
00347   glBegin(GL_QUAD_STRIP);
00348 
00349   FOR_EACH( it, pts )
00350     {
00351       glVertex3f( it->x, it->y, local_z.max );
00352       glVertex3f( it->x, it->y, local_z.min );
00353     }
00354   // close the strip
00355   glVertex3f( pts[0].x, pts[0].y, local_z.max );
00356   glVertex3f( pts[0].x, pts[0].y, local_z.min );
00357   glEnd();
00358 }
00359 
00360 void Block::DrawFootPrint()
00361 {
00362   glBegin(GL_POLYGON);  
00363   FOR_EACH( it, pts )
00364     glVertex2f( it->x, it->y );
00365   glEnd();
00366 }
00367 
00368 void Block::DrawSolid( bool topview )
00369 {
00370   //    if( wheel )x
00371   //            {
00372   //                    glPushMatrix();
00373 
00374   //                    glRotatef( 90,0,1,0 );
00375   //                    glRotatef( 90,1,0,0 );
00376 
00377   //                    glTranslatef( -local_z.max /2.0, 0, 0 );
00378 
00379 
00380   //                    GLUquadric* quadric = gluNewQuadric();          
00381   //                    gluQuadricDrawStyle( quadric, GLU_FILL );
00382   //                    gluCylinder( quadric, local_z.max, local_z.max, size.x, 16, 16 );
00383   //                    gluDeleteQuadric( quadric );
00384 
00385   //                    glPopMatrix();
00386   //            }
00387   //   else
00388   {
00389     if( ! topview )
00390       DrawSides();
00391          
00392     DrawTop();
00393   }
00394 }
00395 
00396 void Block::Load( Worldfile* wf, int entity )
00397 {
00398   const size_t pt_count = wf->ReadInt( entity, "points", 0);
00399 
00400   char key[128];
00401   for( size_t p=0; p<pt_count; ++p )          
00402     {
00403       snprintf(key, sizeof(key), "point[%d]", (int)p );
00404       
00405       point_t pt( 0, 0 );      
00406       wf->ReadTuple( entity, key, 0, 2, "ll", &pt.x, &pt.y );
00407       pts.push_back( pt );
00408     }
00409   
00410 
00411   wf->ReadTuple( entity, "z", 0, 2, "ll", &local_z.min, &local_z.max );
00412   //local_z.min = wf->ReadTupleLength( entity, "z", 0, 0.0 );
00413   //local_z.max = wf->ReadTupleLength( entity, "z", 1, 1.0 );
00414   
00415   const std::string& colorstr = wf->ReadString( entity, "color", "" );          
00416 
00417   if( colorstr != "" )
00418     {
00419       color = Color( colorstr );
00420       inherit_color = false;
00421     }
00422   else
00423     inherit_color = true;  
00424 
00425   wheel = wf->ReadInt( entity, "wheel", wheel );
00426 }
00427 
00429 // utility functions to ensure block winding is consistent and matches OpenGL's default
00430 
00431 static
00433 void positivize(radians_t& angle)
00434 {
00435   while (angle < 0) angle += 2 * M_PI;
00436 }
00437 
00438 static
00440 void pi_ize(radians_t& angle)
00441 {
00442   while (angle < -M_PI) angle += 2 * M_PI;
00443   while (M_PI < angle)  angle -= 2 * M_PI;
00444 }
00445 
00446 static
00448 radians_t angle_change(point_t v1, point_t v2)
00449 {
00450   radians_t a1 = atan2(v1.y, v1.x);
00451   positivize(a1);
00452 
00453   radians_t a2 = atan2(v2.y, v2.x);
00454   positivize(a2);
00455 
00456   radians_t angle_change = a2 - a1;
00457   pi_ize(angle_change);
00458 
00459   return angle_change;
00460 }
00461 
00462 static
00464 vector<point_t> find_vectors(vector<point_t> const& pts)
00465 {
00466   vector<point_t> vs;
00467   assert(2 <= pts.size());
00468   for (unsigned i = 0, n = pts.size(); i < n; ++i)
00469     {
00470       unsigned j = (i + 1) % n;
00471       vs.push_back(point_t(pts[j].x - pts[i].x, pts[j].y - pts[i].y));
00472     }
00473   assert(vs.size() == pts.size());
00474   return vs;
00475 }
00476 
00477 static
00480 radians_t angles_sum(vector<point_t> const& vs)
00481 {
00482   radians_t angle_sum = 0;
00483   for (unsigned i = 0, n = vs.size(); i < n; ++i)
00484     {
00485       unsigned j = (i + 1) % n;
00486       angle_sum += angle_change(vs[i], vs[j]);
00487     }
00488   return angle_sum;
00489 }
00490 
00491 static
00493 bool is_canonical_winding(vector<point_t> const& ps)
00494 {
00495   // reuse point_t as vector
00496   vector<point_t> vs = find_vectors(ps);
00497   radians_t sum = angles_sum(vs);
00498   bool bCanon = 0 < sum;
00499 
00500   return bCanon;
00501 }
00502 
00503 static
00507 // Note that a simple line that doubles back on itself has an
00508 // angle sum of 0, but that's intrinsic to a line - its winding could
00509 // be either way.
00510 void canonicalize_winding(vector<point_t>& ps)
00511 {
00512   if (not is_canonical_winding(ps))
00513     {
00514       std::reverse(ps.begin(), ps.end());
00515     }
00516 }


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