00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00057 #ifndef FIRETREE__HEX_H
00058 #define FIRETREE__HEX_H 1
00059
00060
00061 #include <list>
00062 #include <set>
00063 #include <map>
00064 #include <stdexcept>
00065 #include <ostream>
00066 #include <string>
00067
00068
00069 #define HEX_PARANOID_CHECKS
00070
00073 namespace hex {
00074
00075
00076
00077
00078
00080 class exception: public std::exception
00081 {
00082 public:
00083 std::string _what;
00084 exception(const std::string& w) throw(): _what(w) {}
00085 virtual ~exception() throw() {}
00086 virtual const char* what() const throw() { return this->_what.c_str(); }
00087 };
00088
00089 class invalid_argument: public hex::exception
00090 {
00091 public:
00092 invalid_argument(const std::string& w) throw(): hex::exception(w) {}
00093 virtual ~invalid_argument() throw() {}
00094 };
00095
00096 class out_of_range: public hex::exception
00097 {
00098 public:
00099 out_of_range(const std::string& w) throw(): hex::exception(w) {}
00100 virtual ~out_of_range() throw() {}
00101 };
00102
00103
00104
00105
00106
00107 typedef double Distance;
00108
00109 const Distance M_SQRT3 =1.73205080756887729352744634150587236;
00110 const Distance I =1.0;
00111 const Distance J =M_SQRT3/2.0;
00112 const Distance K =1.0/M_SQRT3;
00113
00114
00115
00116
00119 enum Direction { A=0, B=1, C=2, D=3, E=4, F=5 };
00120 const int DIRECTIONS =6;
00121
00122 Direction to_direction(char c) throw(hex::invalid_argument);
00123 char to_char(Direction d);
00124
00125
00126
00127 Direction& operator+= (Direction& d, int i);
00128 Direction operator+ (const Direction& d, int i);
00129 Direction& operator++ (Direction& d);
00130 Direction operator++ (const Direction& d,int);
00131 Direction& operator-= (Direction& d, int i);
00132 Direction operator- (const Direction& d, int i);
00133 Direction& operator-- (Direction& d);
00134 Direction operator-- (const Direction& d,int);
00135
00136 std::ostream& operator<<(std::ostream& os, const Direction& d);
00137
00140 std::string rotate(const std::string& steps, int i);
00141
00142
00143
00144
00145
00146 namespace svg {
00149 class Identity
00150 {
00151 public:
00152 std::string id;
00153 std::string style;
00154 std::string className;
00155 virtual ~Identity(void) {}
00157 std::string attributes(void) const;
00158 };
00159 }
00160
00161
00162
00163
00164
00165 class Grid;
00166 class Edge;
00167 class Hex;
00168 class Area;
00169 class Path;
00170 class Boundary;
00171
00172
00174 struct Point
00175 {
00176 Distance x,y;
00177 Point offset(Distance dx, Distance dy) const { return Point(x+dx,y+dy); }
00178 Point(): x(0.0), y(0.0) {}
00179 Point(Distance x_, Distance y_): x(x_), y(y_) {}
00180 Point(const std::string s) throw (out_of_range,invalid_argument);
00181 Point& operator+=(const Point& p) { x+=p.x; y+=p.y; return *this; }
00182 Point& operator-=(const Point& p) { x-=p.x; y-=p.y; return *this; }
00183 Point operator+(const Point& p) const { return Point(x+p.x,y+p.y); }
00184 Point operator-(const Point& p) const { return Point(x-p.x,y-p.y); }
00185 Point operator*(double v) const { return Point(x*v,y*v); }
00186 Point operator/(double v) const { return Point(x/v,y/v); }
00187 bool operator==(const Point& p) const { return(x==p.x && y==p.y); }
00188 bool operator!=(const Point& p) const { return !operator==(p); }
00189 std::string str(void) const;
00190 };
00191
00194 class Grid
00195 {
00196 mutable std::map<int,Hex*> _hexes;
00197 int _cols;
00198 int _rows;
00199 public:
00200 int cols(void) const { return _cols; }
00201 int rows(void) const { return _rows; }
00202 Distance width(void) const { return I/2.0 + I*cols(); }
00203 Distance height(void) const { return K*2 + J*(rows()-1); }
00204 bool is_in_range(int i, int j) const {return 0<=i&&i<cols()&&0<=j&&j<rows();}
00205 Hex* hex(int i, int j) const throw(hex::out_of_range);
00206 Hex* hex(Distance x, Distance y) const throw(hex::out_of_range);
00207 Hex* hex(const Point& p) const throw(hex::out_of_range);
00208 Area to_area(void) const;
00209 public:
00210 Grid(int cols, int rows) throw(hex::out_of_range);
00211 public:
00212 Grid(const Grid& right);
00213 virtual ~Grid();
00214 private:
00215 Grid& operator=(const Grid&);
00216 public:
00218 Hex* hex(const std::string& s) const
00219 throw(out_of_range,invalid_argument);
00221 std::set<Hex*> hexes(const std::string& s) const
00222 throw(out_of_range,invalid_argument);
00224 Area area(const std::string& s) const
00225 throw(out_of_range,invalid_argument);
00227 Path path(const std::string& s) const
00228 throw(out_of_range,invalid_argument);
00230 Boundary boundary(const std::string& s) const
00231 throw(out_of_range,invalid_argument);
00232 };
00233
00234
00238 class Edge
00239 {
00240 Hex* const _hex;
00241 const Direction _direction;
00242 public:
00243 Hex* hex(void) const { return _hex; }
00244 Direction direction(void) const { return _direction; }
00245 Edge* complement(void) const;
00246 bool is_next(const Edge& v) const;
00247 Edge* next_in(bool clockwise=false) const;
00248 Edge* next_out(bool clockwise=false) const;
00249 Point start_point(float bias =0.0, bool clockwise=false) const;
00250 Point end_point(float bias =0.0, bool clockwise=false) const;
00251 Point join_point(const Edge* next, float bias =0.0) const;
00252 private:
00253 friend class Hex;
00254 Edge(Hex* h, Direction d): _hex(h), _direction(d) {}
00255 ~Edge() {}
00256 };
00257
00258
00260 class Hex
00261 {
00262 Edge _edgeA,_edgeB,_edgeC,_edgeD,_edgeE,_edgeF;
00263 const Grid& _grid;
00264 public:
00265 const int i;
00266 const int j;
00267 const Grid& grid(void) const { return _grid; }
00268 const Edge* edge(const Direction& d) const;
00269 Edge* edge(const Direction& d);
00270 Hex* go(const Direction& d, int distance=1) const;
00271 Hex* go(const std::string& steps) const;
00272 Point centre(void) const;
00273 std::string str(void) const;
00275 static int _key(int i, int j) { return (i<<14) | j; }
00276 public:
00277 Hex(const Grid& grid, int i_, int j_);
00278 private:
00279 friend class Grid;
00280 Hex(const Hex& right);
00281 Hex& operator=(const Hex&);
00282 Hex(const Grid& grid, const Hex& h);
00283 ~Hex() {}
00284 };
00285
00286
00288 class Area: public svg::Identity
00289 {
00290 std::set<Hex*> _hexes;
00291 public:
00292 int size(void) const { return int(_hexes.size()); }
00293 bool contains(Hex* h) const { return _hexes.count(h)>0; }
00294 Boundary boundary(void) const;
00295 const std::set<Hex*>& hexes(void) const { return _hexes; }
00296 std::list<Area> enclosed_areas(void) const;
00299 std::list<Boundary> skeleton(bool include_boundary =true) const;
00301 std::list<hex::Path> fillpaths(Hex* origin =NULL) const;
00302 std::string str(Hex* origin =NULL) const;
00303 public:
00304 Area go(const Direction& d, int distance=1) const throw(hex::out_of_range);
00305 Area go(const std::string& steps) const throw(hex::out_of_range);
00306 public:
00307 Area(void): _hexes() {}
00308 Area(const std::set<Hex*>& hexes);
00309 Area(Hex* h): _hexes() { _hexes.insert(h); }
00310 Area(Hex* h, int distance);
00311 };
00312
00313
00315 class Path: public svg::Identity
00316 {
00317 std::list<Hex*> _hexes;
00318 public:
00319 Area to_area(void) const;
00320 const std::list<Hex*>& hexes(void) const { return _hexes; }
00321 int length(void) const;
00322 std::string steps(void) const;
00323 std::string str(void) const;
00324 public:
00325 Path(void): _hexes() {}
00326 Path(const std::list<Hex*>& hexes): _hexes(hexes) {}
00328 Path(Hex* start, const std::string& steps)
00329 throw(hex::out_of_range,hex::invalid_argument);
00332 Path(Hex* from, const Hex* to) throw();
00333 };
00334
00335
00337 class Boundary: public svg::Identity
00338 {
00339 std::list<Edge*> _edges;
00340 public:
00341 int length(void) const;
00342 bool is_closed(void) const;
00343 bool is_container(void) const;
00344 Boundary complement(void) const throw(hex::out_of_range);
00345 const std::list<Edge*>& edges(void) const { return _edges; }
00346 Path to_path(void) const;
00347 bool clockwise(void) const;
00348 std::string str(void) const;
00350 std::list<Point> stroke(float bias =0.0) const;
00353 Area area(void) const;
00354 public:
00355 Boundary(void): _edges() {}
00356 Boundary(const std::list<Edge*>& edges): _edges(edges) {}
00357 };
00358
00359
00360
00361
00362
00363
00365 void
00366 go(int& i, int& j, Direction d, int distance=1);
00367
00368
00370 void
00371 go(int& i, int& j, const std::string& steps);
00372
00373
00376 std::string
00377 steps(const Hex* from, const Hex* to);
00378
00379
00381 int
00382 distance(const Hex* from, const Hex* to);
00383
00384
00388 std::set<Hex*>
00389 range(Hex* h, int distance);
00390
00391
00393 std::set<Hex*>
00394 set_difference(const std::set<Hex*>& a, const std::set<Hex*>& b);
00395
00396
00398 std::set<Hex*>
00399 set_intersection(const std::set<Hex*>& a, const std::set<Hex*>& b);
00400
00401
00403 std::set<Hex*>
00404 set_union(const std::set<Hex*>& a, const std::set<Hex*>& b);
00405
00406
00408 std::string
00409 set_str(const std::set<Hex*>& a);
00410
00411
00413 bool
00414 bounding_box(const std::set<Hex*>& a, int& i0, int& j0, int& i1, int& j1);
00415
00416
00418 Area
00419 fill(const std::set<Hex*>& beyond, Hex* h);
00420
00421
00423 Area
00424 fill(const std::set<Hex*>& beyond, const Area& a);
00425
00426
00428 std::list<Area>
00429 areas(const std::set<Hex*>& s);
00430
00431
00433 bool
00434 is_connected(const std::set<Hex*>& s);
00435
00436
00438 std::list<Boundary>
00439 skeleton(const std::list<Area>& a, bool include_boundary =true);
00440
00441
00442 }
00443
00444 #endif