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