GME  13
ModelGrid.cpp
Go to the documentation of this file.
00001 #include "stdafx.h"
00002 
00003 #include "GMEApp.h"
00004 #include "GMEStd.h"
00005 #include "GuiObject.h"
00006 #include "ModelGrid.h"
00007 
00009 
00010 CModelGrid::CModelGrid()
00011 {
00012 #ifdef GRIDBITS
00013         width = GME_MAX_GRID_DIM / (8 * sizeof(int));
00014 #else
00015         width = GME_MAX_GRID_DIM;
00016 #endif
00017         height = GME_MAX_GRID_DIM;
00018         Clear();
00019         view = 0;
00020 }
00021 
00022 #ifdef GRIDBITS
00023 
00024 #define trafo()         ASSERT(sizeof(int) == 4);                                               \
00025                                         unsigned int xi = (x >> 5);                                             \
00026                                         ASSERT(xi < (unsigned int)width);                               \
00027                                         ASSERT(y < height);                                                     \
00028                                         unsigned int mask = 1 << ((unsigned int)x & 0x1F);
00029 
00030 inline bool CModelGrid::IsAvailable(int x,int y)
00031 {
00032         trafo();
00033         return ((grid[y][xi] & mask) == 0);
00034 }
00035 
00036 inline void CModelGrid::Set(int x,int y)
00037 {
00038         trafo();
00039         grid[y][xi] |= mask;
00040 }
00041 
00042 inline void CModelGrid::Reset(int x,int y)
00043 {
00044         trafo();
00045         mask = ~mask;
00046         grid[y][xi] &= mask;
00047 }
00048 
00049 #else
00050 
00051 inline bool CModelGrid::IsAvailable(int x,int y)
00052 {
00053         return !grid[y][x];
00054 }
00055 
00056 inline void CModelGrid::Set(int x,int y)
00057 {
00058         grid[y][x] = true;
00059 }
00060 
00061 inline void CModelGrid::Reset(int x,int y)
00062 {
00063         grid[y][x] = false;
00064 }
00065 
00066 #endif
00067 
00068 void CModelGrid::Clear()
00069 {
00070         int i;
00071         memset(grid,0,sizeof(grid));
00072         for(i = 0; i < width; i++) {    // frame!
00073 #ifdef GRIDBITS
00074                 grid[0][i] = (unsigned int)~0;
00075                 grid[height - 1][i] = (unsigned int)~0;
00076 #else
00077                 Set(i,0);
00078                 Set(i,GME_MAX_GRID_DIM-1);
00079 #endif
00080         }
00081         for(i = 0; i < height; i++) {
00082                 Set(0,i);
00083                 Set(GME_MAX_GRID_DIM-1,i);
00084         }
00085         view = 0;
00086 }
00087 
00088 bool CModelGrid::IsAvailableG(CPoint &pt,CSize &size)
00089 {
00090         int startx = pt.x;
00091         int starty = pt.y;
00092         int endx = pt.x + size.cx;
00093         int endy = pt.y + size.cy;
00094         // Hack to prevent labels from overlapping
00095         //starty -= 2;
00096         if(startx < 0 || starty < 0 || endx >= GME_MAX_GRID_DIM || endy >= GME_MAX_GRID_DIM)
00097                 return false;
00098         for(int i = starty; i <= endy; i++)
00099                 for(int j = startx; j <= endx; j++)
00100                         if(!IsAvailable(j,i))
00101                                 return false;
00102         return true;
00103 }
00104 
00105 
00106 #define FindStartEnd(rect,chk)                                                                                  \
00107         int startx = (rect.left / GME_GRID_SIZE); \
00108         int starty = (rect.top / GME_GRID_SIZE); \
00109         int endx = ((rect.right + GME_GRID_SIZE - 1) / GME_GRID_SIZE); \
00110         int endy = ((rect.bottom + GME_GRID_SIZE - 1) / GME_GRID_SIZE); \
00111         if(chk) {                                                                                                                               \
00112                 ASSERT(startx >= 0);                                                                                            \
00113                 ASSERT(starty >= 0);                                                                                            \
00114                 ASSERT(endx < GME_MAX_GRID_DIM);                                                                        \
00115                 ASSERT(endy < GME_MAX_GRID_DIM);                                                                        \
00116         }
00117 
00118 
00119 bool CModelGrid::IsAvailable(const CRect& rect)
00120 {
00121         FindStartEnd(rect,0);
00122         if(startx < 0 || starty < 0 || (unsigned int)endx >= GME_MAX_GRID_DIM || (unsigned int)endy >= GME_MAX_GRID_DIM)
00123                 return false;
00124         for(int y = starty; y <= endy; y++)
00125                 for(int x = startx; x <= endx; x++)
00126                         if(!IsAvailable(x,y))
00127                                 return false;
00128         return true;
00129 }
00130 
00131 
00132 #define test_and_return_if_found()                                      \
00133                         if(IsAvailableG(test,size)) {                   \
00134                                 rect.MoveToXY(test.x * GME_GRID_SIZE, test.y * GME_GRID_SIZE);          \
00135                                 return TRUE;                                            \
00136                         }
00137 
00138 bool CModelGrid::GetClosestAvailable(CRect& rect)
00139 {
00140         if(IsAvailable(rect)) {
00141                 rect.MoveToXY((rect.left / GME_GRID_SIZE) * GME_GRID_SIZE,
00142                         (rect.top / GME_GRID_SIZE) * GME_GRID_SIZE);
00143                 return TRUE;
00144         }
00145 
00146         CPoint pt = rect.TopLeft();
00147         pt.x /= GME_GRID_SIZE;
00148         pt.y /= GME_GRID_SIZE;
00149         pt.x = max(0,min(GME_MAX_GRID_DIM - 1,pt.x));
00150         pt.y = max(0,min(GME_MAX_GRID_DIM - 1,pt.y));
00151         CSize size = rect.Size();
00152         size.cx = (size.cx + GME_GRID_SIZE - 1) / GME_GRID_SIZE;
00153         size.cy = (size.cy + GME_GRID_SIZE - 1) / GME_GRID_SIZE;
00154         CPoint test = pt;
00155         for(int rad = 1; rad < GME_MAX_GRID_DIM; rad++) {
00156                 test.x = pt.x - rad;
00157                 if(test.x >= 0)
00158                         for(test.y = max(0,pt.y - rad); test.y < min(GME_MAX_GRID_DIM,pt.y + rad + 1); test.y++)
00159                                 test_and_return_if_found();
00160                 test.x = pt.x + rad;
00161                 if(test.x < GME_MAX_GRID_DIM)
00162                         for(test.y = max(0,pt.y - rad); test.y < min(GME_MAX_GRID_DIM,pt.y + rad + 1); test.y++)
00163                                 test_and_return_if_found();
00164                 test.y = pt.y - rad;
00165                 if(test.y >= 0)
00166                         for(test.x = max(0,pt.x - rad) + 1; test.x < min(GME_MAX_GRID_DIM,pt.x + rad + 1) - 1; test.x++)
00167                                 test_and_return_if_found();
00168                 test.y = pt.y + rad;
00169                 if(test.y < GME_MAX_GRID_DIM)
00170                         for(test.x = max(0,pt.x - rad) + 1; test.x < min(GME_MAX_GRID_DIM,pt.x + rad + 1) - 1; test.x++)
00171                                 test_and_return_if_found();
00172         }
00173         return FALSE;
00174 }
00175 
00176 
00177 void CModelGrid::Set(CRect& rect, bool reset)
00178 {
00179         FindStartEnd(rect,1);
00180         for(int y = starty; y <= endy; y++)
00181                 for(int x = startx; x <= endx; x++)
00182                         reset ? Reset(x,y) : Set(x,y);
00183 }
00184 
00185 
00186 
00188 // Public methods - accepts objects as parameters
00189 
00190 /*
00191 Mod by ZolMol:  If called from CGMEView::SyncOnGrid then
00192                                 the object (*model) might not have the same aspects as its parent so
00193                                 calling GetLocation or GetNameLocation with default parameter might
00194                                 cause null ptr dereferencing
00195 */
00196 void CModelGrid::Set(CGuiObject *model,bool reset, int aspIdx)
00197 {
00198         CRect loc = model->GetLocation( aspIdx);
00199         Set(loc,reset);
00200 
00201         if (theApp.labelAvoidance) {
00202                 loc = model->GetNameLocation( aspIdx);
00203                 Set(loc, reset);
00204         }
00205 }
00206 
00207 void CModelGrid::Reset(CGuiObject *model)
00208 {
00209         Set(model,TRUE);
00210 }
00211 
00212 bool CModelGrid::IsAvailable(CGuiObject *model, int aspIdx) 
00213 {
00214         CRect rect = model->GetLocation(aspIdx);
00215         bool avail = modelGrid.IsAvailable(rect);
00216 
00217         if (theApp.labelAvoidance) {
00218                 rect = model->GetNameLocation(aspIdx);
00219                 avail = avail && modelGrid.IsAvailable(rect);
00220         }
00221 
00222         return avail;
00223 }
00224 
00225 /*
00226 Mod by ZolMol:  If called from CGMEView::SyncOnGrid then
00227                                 the object (*model) might not have the same aspects as its parent so
00228                                 calling GetLocation or GetNameLocation with default parameter might
00229                                 cause null ptr dereferencing
00230 */
00231 bool CModelGrid::GetClosestAvailable(CGuiObject *model, CRect &rect, int aspIdx)
00232 {
00233         bool ret = GetClosestAvailable(rect);
00234 
00235         return ret;
00236 }
00237 
00238 bool CModelGrid::CanNudge(CGuiObject *model,int right,int down)
00239 {
00240         ASSERT(right == 0 || down == 0); // no diagonal nudge!
00241         CRect r = model->GetLocation(); // comment by ZolMol: this is correct since the parent aspect is always valid, and an object is moved (nudged) within the parents aspect only
00242         right *= GME_GRID_SIZE;
00243         down *= GME_GRID_SIZE;
00244         r.right += right;
00245         r.left += right;
00246         r.top += down;
00247         r.bottom += down;
00248         bool can = IsAvailable(r);
00249 
00250         if (theApp.labelAvoidance) {
00251                 r = model->GetNameLocation();
00252                 r.right += right;
00253                 r.left += right;
00254                 r.top += down;
00255                 r.bottom += down;
00256                 can = can && IsAvailable(r);
00257         }
00258 
00259         return can;
00260 }