00001 //---------------------------------------------------------------------------- 00002 /** @file SgPointSet.cpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "SgSystem.h" 00007 #include "SgPointSet.h" 00008 00009 #include <algorithm> 00010 #include <iostream> 00011 #include "SgNbIterator.h" 00012 00013 using namespace std; 00014 00015 //---------------------------------------------------------------------------- 00016 00017 namespace { 00018 00019 int MaxDistance(SgPoint p1, SgPoint p2) 00020 { 00021 return max(abs(SgPointUtil::Row(p1) - SgPointUtil::Row(p2)), 00022 abs(SgPointUtil::Col(p1) - SgPointUtil::Col(p2))); 00023 } 00024 00025 } // namespace 00026 00027 //---------------------------------------------------------------------------- 00028 00029 SgPointSet::PrecompAllPoints::PrecompAllPoints() 00030 { 00031 for (int size = SG_MIN_SIZE; size <= SG_MAX_SIZE; ++size) 00032 { 00033 m_allPoints[size].reset(new SgPointSet()); 00034 for (int col = 1; col <= size; ++col) 00035 for (int row = 1; row <= size; ++row) 00036 m_allPoints[size]->Include(SgPointUtil::Pt(col, row)); 00037 } 00038 } 00039 00040 //---------------------------------------------------------------------------- 00041 00042 SgPointSet::PrecompAllPoints SgPointSet::s_allPoints; 00043 00044 SgPointSet SgPointSet::Border(int boardSize) const 00045 { 00046 return (BorderNoClip() & AllPoints(boardSize)); 00047 } 00048 00049 SgPointSet SgPointSet::BorderNoClip() const 00050 { 00051 SgPointSet bd = (*this >> SG_NS); 00052 bd |= (*this << SG_NS); 00053 bd |= (*this >> SG_WE); 00054 bd |= (*this << SG_WE); 00055 bd -= (*this); 00056 return bd; 00057 } 00058 00059 SgPointSet SgPointSet::Component(SgPoint p) const 00060 { 00061 SgPointSet set1, set2; 00062 set1.Include(p); 00063 SgPointSet* a = &set1, *b = &set2; 00064 do 00065 { 00066 *b = *a | (a->BorderNoClip() & (*this)); 00067 swap(a, b); // swap pointers, not sets. 00068 } while (set1 != set2); 00069 return set1; 00070 } 00071 00072 SgPointSet SgPointSet::ConnComp(SgPoint p) const 00073 { 00074 // alternative connected component algorithm for large diameter sets 00075 SgPointSet out, in = (*this); 00076 SgPoint stack[SG_MAXPOINT]; // AR: use Stack template 00077 out.Include(p); 00078 in.Exclude(p); 00079 int current = 0; 00080 stack[current] = p; 00081 while (current >= 0) 00082 { 00083 SgPoint q = stack[current--]; 00084 for (SgNb4Iterator it(q); it; ++it) 00085 { 00086 SgPoint nb = *it; 00087 if (in.Contains(nb)) 00088 { 00089 out.Include(nb); 00090 in.Exclude(nb); 00091 stack[++current] = nb; 00092 } 00093 } 00094 } 00095 return out; 00096 } 00097 00098 SgPointSet SgPointSet::ConnComp8(SgPoint p) const 00099 { 00100 SG_ASSERT(Contains(p)); 00101 SgPointSet out, in = (*this); 00102 SgPoint stack[SG_MAXPOINT]; // AR: use Stack template 00103 out.Include(p); 00104 in.Exclude(p); 00105 int current = 0; 00106 stack[current] = p; 00107 while (current >= 0) 00108 { 00109 SgPoint q = stack[current--]; 00110 for (SgNb8Iterator it(q); it; ++it) 00111 { 00112 SgPoint nb = *it; 00113 if (in.Contains(nb)) 00114 { 00115 out.Include(nb); 00116 in.Exclude(nb); 00117 stack[++current] = nb; 00118 } 00119 } 00120 } 00121 SG_ASSERT(SupersetOf(out)); 00122 return out; 00123 } 00124 00125 SgPointSet& SgPointSet::Exclude(const SgVector<SgPoint>& vector) 00126 { 00127 for (SgVectorIterator<SgPoint> it(vector); it; ++it) 00128 Exclude(*it); 00129 return (*this); 00130 } 00131 00132 SgPointSet::SgPointSet(const SgVector<SgPoint>& vector) 00133 { 00134 Clear(); 00135 for (SgVectorIterator<SgPoint> it(vector); it; ++it) 00136 Include(*it); 00137 } 00138 00139 void SgPointSet::ToVector(SgVector<SgPoint>* list) const 00140 { 00141 list->Clear(); 00142 for (SgSetIterator si(*this); si; ++si) 00143 list->PushBack(*si); 00144 } 00145 00146 void SgPointSet::Write(ostream& out, int boardSize) const 00147 { 00148 for (int row = boardSize; row >= 1; --row) 00149 { 00150 for (int col = 1; col <= boardSize; ++col) 00151 out << (Contains(SgPointUtil::Pt(col, row)) ? '@' : '-'); 00152 out << '\n'; 00153 } 00154 } 00155 00156 void SgPointSet::Grow(int boardSize) 00157 { 00158 SgPointSet bd = (*this >> SG_NS); 00159 bd |= (*this << SG_NS); 00160 bd |= (*this >> SG_WE); 00161 bd |= (*this << SG_WE); 00162 bd &= AllPoints(boardSize); 00163 *this |= bd; 00164 } 00165 00166 void SgPointSet::Grow(SgPointSet* newArea, int boardSize) 00167 { 00168 *newArea = (*this >> SG_NS); 00169 *newArea |= (*this << SG_NS); 00170 *newArea |= (*this >> SG_WE); 00171 *newArea |= (*this << SG_WE); 00172 *newArea &= AllPoints(boardSize); 00173 *newArea ^= (*this); 00174 *this |= *newArea; 00175 } 00176 00177 void SgPointSet::Grow8(int boardSize) 00178 { 00179 SgPointSet bd = (*this >> SG_NS); 00180 bd |= (*this << SG_NS); 00181 bd |= (*this >> SG_WE); 00182 bd |= (*this << SG_WE); 00183 bd |= (*this >> (SG_NS + SG_WE)); 00184 bd |= (*this << (SG_NS + SG_WE)); 00185 bd |= (*this >> (SG_NS - SG_WE)); 00186 bd |= (*this << (SG_NS - SG_WE)); 00187 bd &= AllPoints(boardSize); 00188 *this |= bd; 00189 } 00190 00191 SgPointSet SgPointSet::Border8(int boardSize) const 00192 { 00193 SgPointSet bd = (*this >> SG_NS); 00194 bd |= (*this << SG_NS); 00195 bd |= (*this >> SG_WE); 00196 bd |= (*this << SG_WE); 00197 bd |= (*this >> (SG_NS + SG_WE)); 00198 bd |= (*this << (SG_NS + SG_WE)); 00199 bd |= (*this >> (SG_NS - SG_WE)); 00200 bd |= (*this << (SG_NS - SG_WE)); 00201 bd -= (*this); 00202 bd &= AllPoints(boardSize); 00203 return bd; 00204 } 00205 00206 bool SgPointSet::IsSize(int size) const 00207 { 00208 SG_ASSERT(size >= 0); 00209 return (Size() == size); 00210 } 00211 00212 bool SgPointSet::MinSetSize(int size) const 00213 { 00214 return Size() >= size; 00215 } 00216 00217 bool SgPointSet::MaxSetSize(int size) const 00218 { 00219 return Size() <= size; 00220 } 00221 00222 bool SgPointSet::Adjacent(const SgPointSet& s) const 00223 { 00224 return BorderNoClip().Overlaps(s); 00225 } 00226 00227 bool SgPointSet::AllAdjacentTo(const SgPointSet& s) const 00228 { 00229 return SubsetOf(s.BorderNoClip()); 00230 } 00231 00232 bool SgPointSet::AdjacentOnlyTo(const SgPointSet& s, int boardSize) const 00233 { 00234 return Border(boardSize).SubsetOf(s); 00235 } 00236 00237 bool SgPointSet::IsCloseTo(SgPoint p) const 00238 { 00239 const int MAX_CLOSE_DISTANCE = 3; 00240 if (Contains(p)) 00241 return true; 00242 00243 for (SgSetIterator it(*this); it; ++it) 00244 { 00245 if (MaxDistance(*it, p) <= MAX_CLOSE_DISTANCE) 00246 return true; 00247 } 00248 return false; 00249 } 00250 00251 SgPointSet SgPointSet::Kernel(int boardSize) const 00252 { 00253 // Kernel is computed by growing the complement, 00254 // and subtracting that from the given set. 00255 // AR: would direct implementation be faster? 00256 SgPointSet k = AllPoints(boardSize) - (*this); 00257 SgPointSet bd = (k >> SG_NS); 00258 bd |= (k << SG_NS); 00259 bd |= (k >> SG_WE); 00260 bd |= (k << SG_WE); 00261 return (*this) - bd; 00262 } 00263 00264 SgPoint SgPointSet::PointOf() const 00265 { 00266 // slight misuse of iterator, only see if can get one point 00267 SgSetIterator it(*this); 00268 if (it) 00269 return *it; 00270 else 00271 return SG_NULLPOINT; 00272 } 00273 00274 SgPoint SgPointSet::Center() const 00275 { 00276 SgRect rect = EnclosingRect(); 00277 if (rect.IsEmpty()) 00278 return SG_NULLPOINT; 00279 00280 SgPoint idealCenter = rect.Center(); 00281 00282 if (Contains(idealCenter)) 00283 return idealCenter; 00284 00285 int minDist = 4 * SG_MAX_SIZE; 00286 SgPoint center = SG_NULLPOINT; 00287 for (SgSetIterator it(*this); it; ++it) 00288 { 00289 int dist = 00290 MaxDistance(*it, idealCenter) 00291 + SgPointUtil::Distance(*it, idealCenter); 00292 if (dist < minDist) 00293 { 00294 center = *it; 00295 minDist = dist; 00296 } 00297 } 00298 return center; 00299 } 00300 00301 SgRect SgPointSet::EnclosingRect() const 00302 { 00303 SgRect r; 00304 for (SgSetIterator it(*this); it; ++it) 00305 r.Include(*it); 00306 return r; 00307 } 00308 00309 bool SgPointSet::IsConnected() const 00310 { 00311 SgPoint p = PointOf(); 00312 if (p == SG_NULLPOINT) 00313 return true; 00314 else 00315 return (Component(p) == (*this)); 00316 } 00317 00318 bool SgPointSet::Is8Connected() const 00319 { // AR: slow. 00320 SgPoint p = PointOf(); 00321 if (p == SG_NULLPOINT) 00322 return true; // Empty set 00323 else 00324 return (ConnComp8(p) == (*this)); 00325 } 00326 00327 //---------------------------------------------------------------------------- 00328