tilearea.cpp

Go to the documentation of this file.
00001 /* $Id: tilearea.cpp 21747 2011-01-09 14:55:22Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 
00014 #include "map_func.h"
00015 #include "tilearea_type.h"
00016 
00022 TileArea::TileArea(TileIndex start, TileIndex end)
00023 {
00024   uint sx = TileX(start);
00025   uint sy = TileY(start);
00026   uint ex = TileX(end);
00027   uint ey = TileY(end);
00028 
00029   if (sx > ex) Swap(sx, ex);
00030   if (sy > ey) Swap(sy, ey);
00031 
00032   this->tile = TileXY(sx, sy);
00033   this->w    = ex - sx + 1;
00034   this->h    = ey - sy + 1;
00035 }
00036 
00041 void TileArea::Add(TileIndex to_add)
00042 {
00043   if (this->tile == INVALID_TILE) {
00044     this->tile = to_add;
00045     this->w = 1;
00046     this->h = 1;
00047     return;
00048   }
00049 
00050   uint sx = TileX(this->tile);
00051   uint sy = TileY(this->tile);
00052   uint ex = sx + this->w - 1;
00053   uint ey = sy + this->h - 1;
00054 
00055   uint ax = TileX(to_add);
00056   uint ay = TileY(to_add);
00057 
00058   sx = min(ax, sx);
00059   sy = min(ay, sy);
00060   ex = max(ax, ex);
00061   ey = max(ay, ey);
00062 
00063   this->tile = TileXY(sx, sy);
00064   this->w    = ex - sx + 1;
00065   this->h    = ey - sy + 1;
00066 }
00067 
00073 bool TileArea::Intersects(const TileArea &ta) const
00074 {
00075   if (ta.w == 0 || this->w == 0) return false;
00076 
00077   assert(ta.w != 0 && ta.h != 0 && this->w != 0 && this->h != 0);
00078 
00079   uint left1   = TileX(this->tile);
00080   uint top1    = TileY(this->tile);
00081   uint right1  = left1 + this->w - 1;
00082   uint bottom1 = top1  + this->h - 1;
00083 
00084   uint left2   = TileX(ta.tile);
00085   uint top2    = TileY(ta.tile);
00086   uint right2  = left2 + ta.w - 1;
00087   uint bottom2 = top2  + ta.h - 1;
00088 
00089   return !(
00090       left2   > right1  ||
00091       right2  < left1   ||
00092       top2    > bottom1 ||
00093       bottom2 < top1
00094     );
00095 }
00096 
00100 void TileArea::ClampToMap()
00101 {
00102   assert(this->tile < MapSize());
00103   this->w = min(this->w, MapSizeX() - TileX(this->tile));
00104   this->h = min(this->h, MapSizeY() - TileY(this->tile));
00105 }
00106 
00107 DiagonalTileIterator::DiagonalTileIterator(TileIndex corner1, TileIndex corner2) : TileIterator(corner2), base_x(TileX(corner2)), base_y(TileY(corner2)), a_cur(0), b_cur(0)
00108 {
00109   assert(corner1 < MapSize());
00110   assert(corner2 < MapSize());
00111 
00112   int dist_x = TileX(corner1) - TileX(corner2);
00113   int dist_y = TileY(corner1) - TileY(corner2);
00114   this->a_max = dist_x + dist_y;
00115   this->b_max = dist_y - dist_x;
00116 
00117   /* Unfortunately we can't find a new base and make all a and b positive because
00118    * the new base might be a "flattened" corner where there actually is no single
00119    * tile. If we try anyway the result is either inaccurate ("one off" half of the
00120    * time) or the code gets much more complex;
00121    *
00122    * We also need to increment here to have equality as marker for the end of a row or
00123    * column. Like that it's shorter than having another if/else in operator++
00124    */
00125   if (this->a_max > 0) {
00126     this->a_max++;
00127   } else {
00128     this->a_max--;
00129   }
00130 
00131   if (this->b_max > 0) {
00132     this->b_max++;
00133   } else {
00134     this->b_max--;
00135   }
00136 }
00137 
00138 TileIterator &DiagonalTileIterator::operator++()
00139 {
00140   assert(this->tile != INVALID_TILE);
00141 
00142   bool new_line = false;
00143   do {
00144     /* Iterate using the rotated coordinates. */
00145     if (this->a_max > 0) {
00146       this->a_cur += 2;
00147       new_line = this->a_cur >= this->a_max;
00148     } else {
00149       this->a_cur -= 2;
00150       new_line = this->a_cur <= this->a_max;
00151     }
00152     if (new_line) {
00153       /* offset of initial a_cur: one tile in the same direction as a_max
00154        * every second line.
00155        */
00156       this->a_cur = abs(this->a_cur) % 2 ? 0 : (this->a_max > 0 ? 1 : -1);
00157 
00158       if (this->b_max > 0) {
00159         ++this->b_cur;
00160       } else {
00161         --this->b_cur;
00162       }
00163     }
00164 
00165     /* And convert the coordinates back once we've gone to the next tile. */
00166     uint x = this->base_x + (this->a_cur - this->b_cur) / 2;
00167     uint y = this->base_y + (this->b_cur + this->a_cur) / 2;
00168     /* Prevent wrapping around the map's borders. */
00169     this->tile = x >= MapSizeX() || y >= MapSizeY() ? INVALID_TILE : TileXY(x, y);
00170   } while (this->tile > MapSize() && this->b_max != this->b_cur);
00171 
00172   if (this->b_max == this->b_cur) this->tile = INVALID_TILE;
00173   return *this;
00174 }

Generated on Sun Jan 9 16:02:03 2011 for OpenTTD by  doxygen 1.6.1