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
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
00101 return( min + (max - min)/2.0 );
00102 }
00103
00104 void Block::SetCenter( double x, double y )
00105 {
00106
00107
00108 Translate( x-CenterX(), y-CenterY() );
00109 }
00110
00111 void Block::SetCenterY( double y )
00112 {
00113
00114
00115 Translate( 0, y-CenterY() );
00116 }
00117
00118 void Block::SetCenterX( double x )
00119 {
00120
00121
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
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
00144 FOR_EACH( cell_it, rendered_cells[layer] )
00145
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
00156
00157
00158
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
00168 FOR_EACH( cell_it, rendered_cells[layer] )
00169 {
00170
00171 FOR_EACH( block_it, (*cell_it)->GetBlocks(layer) )
00172 {
00173 Block* testblock = *block_it;
00174 Model* testmod = testblock->mod;
00175
00176
00177
00178
00179 if( (testmod != this->mod) &&
00180 testmod->vis.obstacle_return &&
00181 (!mod->IsRelated( testmod )) &&
00182
00183 testblock->global_z.min <= global_z.max &&
00184 testblock->global_z.max >= global_z.min )
00185 {
00186
00187 return testmod;
00188 }
00189 }
00190 }
00191 }
00192
00193
00194 return NULL;
00195 }
00196
00197 void Block::Map( unsigned int layer )
00198 {
00199
00200 const size_t pt_count(pts.size());
00201
00202 if( mpts.size() == 0 )
00203 {
00204
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
00212 const std::vector<point_int_t> gpts = mod->LocalToPixels( mpts );
00213
00214
00215 mod->world->MapPoly( gpts, this, layer );
00216
00217
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
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
00269
00270
00271 const size_t pt_count = pts.size();
00272 for( size_t i=0; i<pt_count; ++i )
00273 {
00274
00275 point_t mpt1 = BlockPointToModelMeters( pts[i] );
00276 point_t mpt2 = BlockPointToModelMeters( pts[(i+1)%pt_count] );
00277
00278
00279 mod->rastervis.AddPoint( mpt1.x, mpt1.y );
00280
00281
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
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
00337
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
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
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
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
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
00413
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
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
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
00508
00509
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 }