Region.cpp (7422B)
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include "Region.h" 5 #include "util.h" 6 7 const int kRectAllocSize = 16; 8 9 Region::Region() 10 : fRects(0), 11 fNumRects(0), 12 fOpLevel(0) 13 { 14 } 15 16 Region::Region(const Region ©Region) 17 : fRects(0), 18 fNumRects(0), 19 fOpLevel(0) 20 { 21 SetTo(copyRegion); 22 } 23 24 Region::~Region() 25 { 26 free(fRects); 27 } 28 29 Region& Region::SetTo(const Region ©Region) 30 { 31 AllocSpace(copyRegion.fNumRects); 32 fNumRects = copyRegion.fNumRects; 33 memcpy(fRects, copyRegion.fRects, fNumRects * sizeof(Rect)); 34 return *this; 35 } 36 37 Region& Region::operator=(const Region ©Region) 38 { 39 return SetTo(copyRegion); 40 } 41 42 Rect Region::Bounds() const 43 { 44 Rect bounds(COORD_MAX, COORD_MAX, -COORD_MAX, -COORD_MAX); 45 for (int i = 0; i < fNumRects; i++) { 46 const Rect &rect = RectAt(i); 47 bounds.left = min(bounds.left, rect.left); 48 bounds.right = max(bounds.right, rect.right); 49 bounds.top = min(bounds.top, rect.top); 50 bounds.bottom = max(bounds.bottom, rect.bottom); 51 } 52 53 return bounds; 54 } 55 56 Region& Region::Include(const Rect &rect) 57 { 58 Region temp; 59 60 BeginOperation(); 61 // Make sure that there are no overlaps 62 temp.AddRect(rect); 63 for (int i = 0; i < fNumRects; i++) 64 temp.Exclude(RectAt(i)); 65 66 AddRegionRects(temp); 67 EndOperation(); 68 return *this; 69 } 70 71 Region& Region::Include(const Region ®ion) 72 { 73 BeginOperation(); 74 for (int i = 0; i < region.CountRects(); i++) 75 Include(region.RectAt(i)); 76 EndOperation(); 77 78 return *this; 79 } 80 81 #define SPLIT_TEST(rect1, rect2) \ 82 (max(rect1.left, rect2.left) < min(rect1.right, rect2.right) \ 83 && max(rect1.top, rect2.top) < min(rect1.bottom, rect2.bottom)) 84 85 Region& Region::Exclude(const Rect &excludeRect) 86 { 87 BeginOperation(); 88 int index = 0; 89 int rectsToCheck = fNumRects; 90 while (index < rectsToCheck) { 91 Rect &clipRect = fRects[index]; 92 93 if (!excludeRect.Intersects(clipRect)) { 94 index++; 95 continue; 96 } 97 98 // This clip rect intersects the excluded rect, and could be divided into 99 // as many as eight pieces. Test for each case. Note that none of these 100 // rectangles overlap!!!! 101 Rect quad1(clipRect.left, clipRect.top, excludeRect.left - 1, excludeRect.top - 1); 102 if (SPLIT_TEST(clipRect, quad1)) { 103 quad1.Intersect(clipRect); 104 AddRect(quad1); 105 } 106 107 Rect quad2(excludeRect.left, clipRect.top, excludeRect.right, excludeRect.top - 1); 108 if (SPLIT_TEST(clipRect, quad2)) { 109 quad2.Intersect(clipRect); 110 AddRect(quad2); 111 } 112 113 Rect quad3(excludeRect.right + 1, clipRect.top, clipRect.right, excludeRect.top - 1); 114 if (SPLIT_TEST(clipRect, quad3)) { 115 quad3.Intersect(clipRect); 116 AddRect(quad3); 117 } 118 119 Rect quad4(clipRect.left, excludeRect.top, excludeRect.left - 1, excludeRect.bottom); 120 if (SPLIT_TEST(clipRect, quad4)) { 121 quad4.Intersect(clipRect); 122 AddRect(quad4); 123 } 124 125 Rect quad5(excludeRect.right + 1, excludeRect.top, clipRect.right, excludeRect.bottom); 126 if (SPLIT_TEST(clipRect, quad5)) { 127 quad5.Intersect(clipRect); 128 AddRect(quad5); 129 } 130 131 Rect quad6(clipRect.left, excludeRect.bottom + 1, excludeRect.left - 1, clipRect.bottom); 132 if (SPLIT_TEST(clipRect, quad6)) { 133 quad6.Intersect(clipRect); 134 AddRect(quad6); 135 } 136 137 Rect quad7(excludeRect.left, excludeRect.bottom + 1, excludeRect.right, clipRect.bottom); 138 if (SPLIT_TEST(clipRect, quad7)) { 139 quad7.Intersect(clipRect); 140 AddRect(quad7); 141 } 142 143 Rect quad8(excludeRect.right + 1, excludeRect.bottom + 1, clipRect.right, clipRect.bottom); 144 if (SPLIT_TEST(clipRect, quad8)) { 145 quad8.Intersect(clipRect); 146 AddRect(quad8); 147 } 148 149 // This rect has been split, remove it. Note we don't 150 // change the index 151 RemoveRect(index); 152 rectsToCheck--; 153 } 154 EndOperation(); 155 return *this; 156 } 157 158 Region& Region::Exclude(const Region &ex) 159 { 160 BeginOperation(); 161 Region temp(ex); 162 temp.Invert(); 163 Intersect(temp); 164 EndOperation(); 165 return *this; 166 } 167 168 169 170 Region& Region::Clear() 171 { 172 fNumRects = 0; 173 AllocSpace(0); 174 return *this; 175 } 176 177 Region& Region::ConstrainTo(const Rect &rect) 178 { 179 BeginOperation(); 180 for (int i = fNumRects - 1; i >= 0; i--) { 181 fRects[i].left = max(rect.left, fRects[i].left); 182 fRects[i].right = min(rect.right, fRects[i].right); 183 fRects[i].top = max(rect.top, fRects[i].top); 184 fRects[i].bottom = min(rect.bottom, fRects[i].bottom); 185 if (!fRects[i].Valid()) 186 RemoveRect(i); 187 } 188 189 EndOperation(); 190 return *this; 191 } 192 193 Region& Region::Translate(int x, int y) 194 { 195 for (int i = 0; i < fNumRects; i++) { 196 fRects[i].left += x; 197 fRects[i].right += x; 198 fRects[i].top += y; 199 fRects[i].bottom += y; 200 } 201 202 return *this; 203 } 204 205 Region& Region::Intersect(const Region &intersectRegion) 206 { 207 BeginOperation(); 208 Region newRegion; 209 for (int i = 0; i < fNumRects; i++) { 210 for (int j = 0; j < intersectRegion.fNumRects; j++) { 211 if (RectAt(i).Intersects(intersectRegion.RectAt(j))) { 212 Rect temp(RectAt(i)); 213 temp.Intersect(intersectRegion.RectAt(j)); 214 newRegion.AddRect(temp); 215 } 216 } 217 } 218 219 SetTo(newRegion); 220 EndOperation(); 221 return *this; 222 } 223 224 Region& Region::Invert() 225 { 226 BeginOperation(); 227 Region temp; 228 temp.Include(Rect(-COORD_MAX, -COORD_MAX, COORD_MAX, COORD_MAX)); 229 for (int i = 0; i < fNumRects; i++) 230 temp.Exclude(fRects[i]); 231 232 SetTo(temp); 233 EndOperation(); 234 return *this; 235 } 236 237 const bool Region::FindRect(int x, int y, Rect &outRect) const 238 { 239 for (int i = 0; i < CountRects(); i++) { 240 if (RectAt(i).Contains(x, y)) { 241 outRect = RectAt(i); 242 return true; 243 } 244 } 245 246 return false; 247 } 248 249 void Region::AddRect(const Rect &rect) 250 { 251 AllocSpace(fNumRects + 1); 252 fRects[fNumRects++] = rect; 253 } 254 255 void Region::RemoveRect(int index) 256 { 257 fNumRects--; 258 memcpy(fRects + index, fRects + index + 1, (fNumRects - index) * sizeof(Rect)); 259 AllocSpace(fNumRects); 260 } 261 262 void Region::AddRegionRects(const Region ®ion) 263 { 264 for (int i = 0; i < region.fNumRects; i++) 265 AddRect(region.RectAt(i)); 266 } 267 268 void Region::Consolidate() 269 { 270 // Optimize region by consolidating adjacent rectangles. 271 for (int i = 0; i < fNumRects; i++) { 272 for (int j = fNumRects - 1; j > i; j--) { 273 Rect &rect1 = fRects[i]; 274 Rect &rect2 = fRects[j]; 275 if (rect1.top == rect2.top && rect1.bottom == rect2.bottom) { 276 if (rect1.right + 1 == rect2.left) { 277 rect1.right = rect2.right; 278 RemoveRect(j); 279 } else if (rect2.right + 1 == rect1.left) { 280 rect1.left = rect2.left; 281 RemoveRect(j); 282 } 283 } else if (rect1.left == rect2.left && rect1.right == rect2.right) { 284 if (rect1.top == rect2.bottom + 1) { 285 rect1.top = rect2.top; 286 RemoveRect(j); 287 } else if (rect1.bottom + 1 == rect2.top) { 288 rect1.bottom = rect2.bottom; 289 RemoveRect(j); 290 } 291 } 292 } 293 } 294 } 295 296 void Region::AllocSpace(int numRects) 297 { 298 int currentAlloc = ((fNumRects + kRectAllocSize - 1) / kRectAllocSize) 299 * kRectAllocSize; 300 int sizeWanted = ((numRects + kRectAllocSize - 1) / kRectAllocSize) 301 * kRectAllocSize; 302 303 if (sizeWanted != currentAlloc) { 304 if (fRects == 0 && sizeWanted > 0) 305 fRects = (Rect*) malloc(sizeWanted * sizeof(Rect)); 306 else if (sizeWanted == 0 && fRects != 0) { 307 free(fRects); 308 fRects = 0; 309 } else 310 fRects = (Rect*) realloc(fRects, sizeWanted * sizeof(Rect)); 311 } 312 } 313 314 315 void Region::BeginOperation() 316 { 317 fOpLevel++; 318 } 319 320 void Region::EndOperation() 321 { 322 if (--fOpLevel == 0) 323 Consolidate(); 324 325 ASSERT(fOpLevel >= 0); 326 } 327 328 329 330 void Region::Dump() const 331 { 332 printf("Region: "); 333 for (int i = 0; i < fNumRects; i++) { 334 if ((i % 6) == 5) 335 printf("\n"); 336 printf("(%d %d %d %d) ", fRects[i].left, fRects[i].top, fRects[i].right, 337 fRects[i].bottom); 338 } 339 340 printf("\n"); 341 }