tilearea.cpp

Go to the documentation of this file.
00001 /* $Id$ */
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 "tilearea_type.h"
00015 
00021 TileArea::TileArea(TileIndex start, TileIndex end)
00022 {
00023   uint sx = TileX(start);
00024   uint sy = TileY(start);
00025   uint ex = TileX(end);
00026   uint ey = TileY(end);
00027 
00028   if (sx > ex) Swap(sx, ex);
00029   if (sy > ey) Swap(sy, ey);
00030 
00031   this->tile = TileXY(sx, sy);
00032   this->w    = ex - sx + 1;
00033   this->h    = ey - sy + 1;
00034 }
00035 
00040 void TileArea::Add(TileIndex to_add)
00041 {
00042   if (this->tile == INVALID_TILE) {
00043     this->tile = to_add;
00044     this->w = 1;
00045     this->h = 1;
00046     return;
00047   }
00048 
00049   uint sx = TileX(this->tile);
00050   uint sy = TileY(this->tile);
00051   uint ex = sx + this->w - 1;
00052   uint ey = sy + this->h - 1;
00053 
00054   uint ax = TileX(to_add);
00055   uint ay = TileY(to_add);
00056 
00057   sx = min(ax, sx);
00058   sy = min(ay, sy);
00059   ex = max(ax, ex);
00060   ey = max(ay, ey);
00061 
00062   this->tile = TileXY(sx, sy);
00063   this->w    = ex - sx + 1;
00064   this->h    = ey - sy + 1;
00065 }
00066 
00072 bool TileArea::Intersects(const TileArea &ta) const
00073 {
00074   if (ta.w == 0 || this->w == 0) return false;
00075 
00076   assert(ta.w != 0 && ta.h != 0 && this->w != 0 && this->h != 0);
00077 
00078   uint left1   = TileX(this->tile);
00079   uint top1    = TileY(this->tile);
00080   uint right1  = left1 + this->w - 1;
00081   uint bottom1 = top1  + this->h - 1;
00082 
00083   uint left2   = TileX(ta.tile);
00084   uint top2    = TileY(ta.tile);
00085   uint right2  = left2 + ta.w - 1;
00086   uint bottom2 = top2  + ta.h - 1;
00087 
00088   return !(
00089       left2   > right1  ||
00090       right2  < left1   ||
00091       top2    > bottom1 ||
00092       bottom2 < top1
00093     );
00094 }
00095 
00101 bool TileArea::Contains(TileIndex tile) const
00102 {
00103   if (this->w == 0) return false;
00104 
00105   assert(this->w != 0 && this->h != 0);
00106 
00107   uint left   = TileX(this->tile);
00108   uint top    = TileY(this->tile);
00109   uint tile_x = TileX(tile);
00110   uint tile_y = TileY(tile);
00111 
00112   return tile_x >= left && tile_x < left + this->w && tile_y >= top && tile_y < top + this->h;
00113 }
00114 
00118 void TileArea::ClampToMap()
00119 {
00120   assert(this->tile < MapSize());
00121   this->w = min(this->w, MapSizeX() - TileX(this->tile));
00122   this->h = min(this->h, MapSizeY() - TileY(this->tile));
00123 }
00124 
00130 DiagonalTileIterator::DiagonalTileIterator(TileIndex corner1, TileIndex corner2) : TileIterator(corner2), base_x(TileX(corner2)), base_y(TileY(corner2)), a_cur(0), b_cur(0)
00131 {
00132   assert(corner1 < MapSize());
00133   assert(corner2 < MapSize());
00134 
00135   int dist_x = TileX(corner1) - TileX(corner2);
00136   int dist_y = TileY(corner1) - TileY(corner2);
00137   this->a_max = dist_x + dist_y;
00138   this->b_max = dist_y - dist_x;
00139 
00140   /* Unfortunately we can't find a new base and make all a and b positive because
00141    * the new base might be a "flattened" corner where there actually is no single
00142    * tile. If we try anyway the result is either inaccurate ("one off" half of the
00143    * time) or the code gets much more complex;
00144    *
00145    * We also need to increment here to have equality as marker for the end of a row or
00146    * column. Like that it's shorter than having another if/else in operator++
00147    */
00148   if (this->a_max > 0) {
00149     this->a_max++;
00150   } else {
00151     this->a_max--;
00152   }
00153 
00154   if (this->b_max > 0) {
00155     this->b_max++;
00156   } else {
00157     this->b_max--;
00158   }
00159 }
00160 
00164 TileIterator &DiagonalTileIterator::operator++()
00165 {
00166   assert(this->tile != INVALID_TILE);
00167 
00168   /* Determine the next tile, while clipping at map borders */
00169   bool new_line = false;
00170   do {
00171     /* Iterate using the rotated coordinates. */
00172     if (this->a_max == 1 || this->a_max == -1) {
00173       /* Special case: Every second column has zero length, skip them completely */
00174       this->a_cur = 0;
00175       if (this->b_max > 0) {
00176         this->b_cur = min(this->b_cur + 2, this->b_max);
00177       } else {
00178         this->b_cur = max(this->b_cur - 2, this->b_max);
00179       }
00180     } else {
00181       /* Every column has at least one tile to process */
00182       if (this->a_max > 0) {
00183         this->a_cur += 2;
00184         new_line = this->a_cur >= this->a_max;
00185       } else {
00186         this->a_cur -= 2;
00187         new_line = this->a_cur <= this->a_max;
00188       }
00189       if (new_line) {
00190         /* offset of initial a_cur: one tile in the same direction as a_max
00191          * every second line.
00192          */
00193         this->a_cur = abs(this->a_cur) % 2 ? 0 : (this->a_max > 0 ? 1 : -1);
00194 
00195         if (this->b_max > 0) {
00196           ++this->b_cur;
00197         } else {
00198           --this->b_cur;
00199         }
00200       }
00201     }
00202 
00203     /* And convert the coordinates back once we've gone to the next tile. */
00204     uint x = this->base_x + (this->a_cur - this->b_cur) / 2;
00205     uint y = this->base_y + (this->b_cur + this->a_cur) / 2;
00206     /* Prevent wrapping around the map's borders. */
00207     this->tile = x >= MapSizeX() || y >= MapSizeY() ? INVALID_TILE : TileXY(x, y);
00208   } while (this->tile > MapSize() && this->b_max != this->b_cur);
00209 
00210   if (this->b_max == this->b_cur) this->tile = INVALID_TILE;
00211   return *this;
00212 }

Generated on Fri Jun 3 05:19:00 2011 for OpenTTD by  doxygen 1.6.1