00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "hex.h"
00025
00026 #include <sstream>
00027 #include <cmath>
00028 #include <cerrno>
00029 #include <cassert>
00030
00031 namespace hex {
00032
00033
00034
00035
00036
00037
00038 Point::Point(const std::string s) throw (out_of_range,invalid_argument)
00039 {
00040
00041
00042 const char* buf =s.c_str();
00043 char* endptr =NULL;
00044 errno=0;
00045 this->x = ::strtod(buf,&endptr);
00046 if(endptr==buf || *endptr!=',')
00047 throw hex::invalid_argument(s);
00048 buf =endptr+1;
00049 this->y = ::strtod(buf,&endptr);
00050 if(endptr==buf)
00051 throw hex::invalid_argument(s);
00052 if(ERANGE==errno)
00053 throw hex::out_of_range(s);
00054 }
00055
00056
00057 std::string
00058 Point::str(void) const
00059 {
00060 std::ostringstream ss;
00061 ss<< this->x << "," << this->y;
00062 return ss.str();
00063 }
00064
00065
00066
00067
00068
00069
00070 Hex*
00071 Grid::hex(int i, int j) const throw(hex::out_of_range)
00072 {
00073 int key =Hex::_key(i,j);
00074 std::map<int,Hex*>::const_iterator pos =_hexes.find(key);
00075 if(pos==_hexes.end())
00076 {
00077 if(0>i || i>=_cols)
00078 throw hex::out_of_range("i");
00079 if(0>j || j>=_rows)
00080 throw hex::out_of_range("j");
00081 Hex* newhex = new Hex(*this,i,j);
00082 _hexes.insert( std::make_pair(key,newhex) );
00083 return newhex;
00084 }
00085 return pos->second;
00086 }
00087
00088
00089 Hex*
00090 Grid::hex(Distance x, Distance y) const throw(hex::out_of_range)
00091 {
00092
00093 const static Distance K_2 =K/2.0;
00094
00095 const static Distance BIx = 0.5;
00096 const static Distance BIy = 1.5 * K;
00097
00098 const static Distance CIx = -BIx;
00099 const static Distance CIy = BIy;
00100
00101
00102 y -= K;
00103 int j = lround( y/J );
00104 if(j % 2)
00105 x -= 1.0;
00106 else
00107 x -= 0.5;
00108 int i = lround( x );
00109
00110 Distance dx = x - Distance(i);
00111 Distance dy = y - Distance(j) * J;
00112
00113 if( dy < -K_2 || K_2 < dy )
00114 {
00115 Distance BId = (BIx * dx) + (BIy * dy);
00116 Distance CId = (CIx * dx) + (CIy * dy);
00117
00118 if( BId > 0.5 )
00119 go( i,j, B );
00120 else if( BId < -0.5 )
00121 go( i,j, E );
00122 else if( CId > 0.5 )
00123 go( i,j, C );
00124 else if( CId < -0.5 )
00125 go( i,j, F );
00126 }
00127 return hex(i,j);
00128 }
00129
00130
00131 Hex*
00132 Grid::hex(const Point& p) const throw(hex::out_of_range)
00133 {
00134 return hex(p.x,p.y);
00135 }
00136
00137
00138 Area
00139 Grid::to_area(void) const
00140 {
00141 using namespace std;
00142 set<Hex*> hexes;
00143 for(int i=0; i<_cols; ++i)
00144 for(int j=0; j<_rows; ++j)
00145 hexes.insert( hex(i,j) );
00146 return Area(hexes);
00147 }
00148
00149
00150 Hex*
00151 Grid::hex(const std::string& s) const throw(out_of_range,invalid_argument)
00152 {
00153
00154
00155 const char* buf =s.c_str();
00156 char* endptr =NULL;
00157 errno=0;
00158 int i =::strtol(buf,&endptr,10);
00159 if(endptr==buf || *endptr!='_')
00160 throw hex::invalid_argument(s);
00161 buf =endptr+1;
00162 int j =::strtol(buf,&endptr,10);
00163 if(endptr==buf)
00164 throw hex::invalid_argument(s);
00165 if(ERANGE==errno)
00166 throw hex::out_of_range(s);
00167 return this->hex(i,j);
00168 }
00169
00170
00171 std::set<Hex*>
00172 Grid::hexes(const std::string& s) const throw(out_of_range,invalid_argument)
00173 {
00174
00175
00176 std::istringstream is(s);
00177 std::set<Hex*> result;
00178 while(is.good())
00179 {
00180 std::string tok;
00181 is>>tok;
00182 if(!tok.empty())
00183 result.insert( this->hex(tok) );
00184 }
00185 return result;
00186 }
00187
00188
00189 Area
00190 Grid::area(const std::string& s) const throw(out_of_range,invalid_argument)
00191 {
00192
00193
00194 std::set<Hex*> result;
00195 std::string::size_type pos =s.find_first_of(":>");
00196 if(pos==std::string::npos)
00197 throw hex::invalid_argument(s);
00198 Hex* origin =this->hex( s.substr(0,pos) );
00199 Hex* start =origin;
00200 while(pos!=std::string::npos)
00201 {
00202 std::string::size_type next =s.find_first_of(":>",pos+1);
00203 std::string steps =s.substr( pos+1, (next==s.npos)?(next):(next-pos-1) );
00204 if(s[pos]=='>')
00205 {
00206 start=origin->go(steps);
00207 }
00208 else
00209 {
00210 std::list<Hex*> hexes =Path(start,steps).hexes();
00211 std::copy(hexes.begin(), hexes.end(), inserter(result,result.end()));
00212 start=origin;
00213 }
00214 pos=next;
00215 }
00216 return result;
00217 }
00218
00219
00220 Path
00221 Grid::path(const std::string& s) const throw(out_of_range,invalid_argument)
00222 {
00223 std::string::size_type colon =s.find(':');
00224 if(colon==std::string::npos || (colon+1)>=s.size())
00225 throw hex::invalid_argument(s);
00226 Hex* origin =this->hex( s.substr(0,colon) );
00227 Path result(origin,s.substr(colon+1));
00228 return result;
00229 }
00230
00231
00232 Boundary
00233 Grid::boundary(const std::string& s) const throw(out_of_range,invalid_argument)
00234 {
00235 std::list<Edge*> result;
00236 std::string::size_type plus_minus =s.find_first_of("+-");
00237 if(plus_minus==std::string::npos || (plus_minus+1)>=s.size())
00238 throw hex::invalid_argument(s);
00239 bool clockwise =( '-' == s[plus_minus] );
00240 for(std::string::size_type pos =plus_minus+1; pos<s.size(); ++pos)
00241 {
00242 Direction d =to_direction(s[pos]);
00243 Edge* next;
00244 if(result.empty())
00245 {
00246 next = this->hex(s.substr(0,plus_minus))->edge(d);
00247 }
00248 else
00249 {
00250 next = result.back()->next_in(clockwise);
00251 if(next->direction() != d)
00252 {
00253 next = result.back()->next_out(clockwise);
00254 if(next->direction() != d)
00255 throw hex::invalid_argument(s);
00256 }
00257 }
00258 result.push_back(next);
00259 }
00260 return result;
00261 }
00262
00263
00264 Grid::Grid(int cols, int rows) throw(hex::out_of_range)
00265 : _hexes(), _cols(cols), _rows(rows)
00266 {
00267
00268
00269
00270 if(0>cols || cols>=0x4000)
00271 throw hex::out_of_range("cols");
00272 if(0>rows || rows>=0x4000)
00273 throw hex::out_of_range("rows");
00274 }
00275
00276
00277 Grid::Grid(const Grid& v): _hexes(), _cols(v._cols), _rows(v._rows)
00278 {
00279 using namespace std;
00280 for(map<int,Hex*>::const_iterator h =v._hexes.begin(); h!=v._hexes.end(); ++h)
00281 _hexes.insert( make_pair(h->first,new Hex(*this,*h->second)) );
00282 }
00283
00284
00285 Grid::~Grid()
00286 {
00287 using namespace std;
00288 for(map<int,Hex*>::const_iterator h =_hexes.begin(); h!=_hexes.end(); ++h)
00289 delete h->second;
00290 }
00291
00292
00293 }