area.cc

Go to the documentation of this file.
00001 /*                            Package   : libhex
00002  * area.cc                    Created   : 2007/10/11
00003  *                            Author    : Alex Tingle
00004  *
00005  *    Copyright (C) 2007-2008, Alex Tingle.
00006  *
00007  *    This file is part of the libhex application.
00008  *
00009  *    libhex is free software; you can redistribute it and/or
00010  *    modify it under the terms of the GNU Lesser General Public
00011  *    License as published by the Free Software Foundation; either
00012  *    version 2.1 of the License, or (at your option) any later version.
00013  *
00014  *    libhex is distributed in the hope that it will be useful,
00015  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  *    Lesser General Public License for more details.
00018  *
00019  *    You should have received a copy of the GNU Lesser General Public
00020  *    License along with this library; if not, write to the Free Software
00021  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  */
00023 
00024 #include "hex.h"
00025 
00026 #include <cassert>
00027 #include <sstream>
00028 
00029 namespace hex {
00030 
00031 
00032 Boundary
00033 Area::boundary(void) const
00034 {
00035   // Start with a random hex.
00036   Hex* h =*_hexes.begin();
00037   const Grid& grid =h->grid();
00038   const int i0 =h->i;
00039   const int j0 =h->j;
00040   // Find an edge.
00041   int i=0;
00042   while(i<=i0 && !contains(grid.hex(i,j0)))
00043       ++i;
00044   std::list<Edge*> result;
00045   result.push_back( grid.hex(i,j0)->edge(D) );
00046   // Follow the edge round.
00047   while(true)
00048   {
00049     Edge* e =result.back()->next_out();
00050     if( !e || !contains(e->hex()) )
00051         e = result.back()->next_in();
00052     if(e == result.front())
00053         break;
00054     result.push_back(e);
00055   }
00056   return result;
00057 }
00058 
00059 
00060 std::list<Area>
00061 Area::enclosed_areas(void) const
00062 {
00063   Area a =boundary().area();
00064   return areas( set_difference( a._hexes, _hexes ) );
00065 }
00066 
00067 
00068 std::list<Boundary>
00069 Area::skeleton(bool include_boundary) const
00070 {
00071   std::list<Boundary> result;
00072   for(std::set<Hex*>::const_iterator h=_hexes.begin(); h!=_hexes.end(); ++h)
00073   {
00074     std::list<Edge*> edges;
00075     edges.push_back( (**h).edge(A) );
00076     edges.push_back( (**h).edge(B) );
00077     edges.push_back( (**h).edge(C) );
00078     result.push_back(edges);
00079   }
00080   if(include_boundary)
00081       result.push_back(boundary());
00082   return result;
00083 }
00084 
00085 
00086 std::list<hex::Path>
00087 Area::fillpaths(Hex* origin) const
00088 {
00089   // Try to calculate a path that fills area.
00090   std::set<Hex*> queue =_hexes;
00091   std::set<Hex*> seen;
00092   std::list<Path> result;
00093   std::list<Hex*> path;
00094   Hex*      hex = origin? origin: *queue.begin();
00095   Direction dir =F;
00096   while(!queue.empty())
00097   {
00098     path.push_back( hex );
00099     queue.erase( hex );
00100     seen.insert( hex );
00101     Direction d=dir+1;
00102     while(true)
00103     {
00104       if(d==dir)
00105       {
00106         result.push_back( path );
00107         path.clear();
00108         hex = *queue.begin();
00109         break;
00110       }
00111       Hex* hd =hex->go(d);
00112       if(queue.count(hd) && !seen.count(hd))
00113       {
00114         hex = hd;
00115         dir = d+3;
00116         break;
00117       }
00118       ++d;
00119     }
00120   }
00121   return result;
00122 }
00123 
00124 
00125 std::string
00126 Area::str(Hex* origin) const
00127 {
00128   if(!origin)
00129       origin=*_hexes.begin();
00130   std::ostringstream result;
00131   std::list<Path> paths  =this->fillpaths(origin);
00132   result << origin->str();
00133   for(std::list<Path>::const_iterator p =paths.begin(); p!=paths.end(); ++p)
00134   {
00135     if(p->hexes().front()!=origin)
00136         result << ">" << hex::steps(origin,p->hexes().front());
00137     result << ":" << p->steps();
00138   }
00139   return result.str();
00140 }
00141 
00142 
00143 Area
00144 Area::go(const Direction& d, int distance) const throw(hex::out_of_range)
00145 {
00146   Area result;
00147   for(std::set<Hex*>::const_iterator h=_hexes.begin(); h!=_hexes.end(); ++h)
00148   {
00149     Hex* hex =(**h).go(d,distance);
00150     if(!hex)
00151         throw hex::out_of_range("Area::go");
00152     result._hexes.insert(hex);
00153   }
00154   return result;
00155 }
00156 
00157 
00158 Area
00159 Area::go(const std::string& steps) const throw(hex::out_of_range)
00160 {
00161   Area result;
00162   for(std::set<Hex*>::const_iterator h=_hexes.begin(); h!=_hexes.end(); ++h)
00163   {
00164     Hex* hex =(**h).go(steps);
00165     if(!hex)
00166         throw hex::out_of_range("Area::go");
00167     result._hexes.insert(hex);
00168   }
00169   return result;
00170 }
00171 
00172 
00173 Area::Area(const std::set<Hex*>& hexes): _hexes(hexes)
00174 {
00175 #ifdef HEX_PARANOID_CHECKS
00176   assert(is_connected(hexes));
00177 #endif
00178 }
00179 
00180 
00181 Area::Area(Hex* h, int distance): _hexes()
00182 {
00183   for(int i=0; i<=distance; ++i)
00184   {
00185     std::set<Hex*> s =range(h,i);
00186     std::copy(s.begin(),s.end(),inserter(_hexes,_hexes.end()));
00187   }
00188 }
00189 
00190 
00191 } // end namespace hex

Generated on Thu Feb 21 00:00:54 2008 for libhex by  doxygen 1.5.1