00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <cassert>
00024
00025
00026
00027
00028
00029
00030
00031 #include "util/math/fife_math.h"
00032 #include "util/log/logger.h"
00033
00034 #include "hexgrid.h"
00035
00036 namespace FIFE {
00037 static Logger _log(LM_HEXGRID);
00038
00039 static const double HEX_WIDTH = 1;
00040 static const double HEX_TO_EDGE = HEX_WIDTH / 2;
00041 static const double HEX_TO_CORNER = 0.5 / Mathd::Cos(Mathd::pi() / 6);
00042 static const double HEX_EDGE_HALF = HEX_TO_CORNER * Mathd::Sin(Mathd::pi() / 6);
00043 static const double VERTICAL_MULTIP = Mathd::Sqrt(HEX_WIDTH*HEX_WIDTH - HEX_TO_EDGE*HEX_TO_EDGE);
00044 static const double VERTICAL_MULTIP_INV = 1 / VERTICAL_MULTIP;
00045
00046 HexGrid::HexGrid(bool allow_diagonals): CellGrid(allow_diagonals) {
00047 FL_DBG(_log, "Constructing new HexGrid");
00048 FL_DBG(_log, LMsg("HEX_WIDTH ") << HEX_WIDTH);
00049 FL_DBG(_log, LMsg("HEX_TO_EDGE ") << HEX_TO_EDGE);
00050 FL_DBG(_log, LMsg("HEX_TO_CORNER ") << HEX_TO_CORNER);
00051 FL_DBG(_log, LMsg("HEX_EDGE_HALF ") << HEX_EDGE_HALF);
00052 FL_DBG(_log, LMsg("VERTICAL_MULTIP ") << VERTICAL_MULTIP);
00053 }
00054
00055 CellGrid* HexGrid::clone() {
00056 HexGrid* nGrid = new HexGrid(m_allow_diagonals);
00057 nGrid->setRotation(m_rotation);
00058 nGrid->setXScale(m_xscale);
00059 nGrid->setYScale(m_yscale);
00060 nGrid->setXShift(m_xshift);
00061 nGrid->setYShift(m_yshift);
00062 nGrid->setZShift(m_zshift);
00063
00064 return nGrid;
00065 }
00066
00067 HexGrid::~HexGrid() {
00068 }
00069
00070 bool HexGrid::isAccessible(const ModelCoordinate& curpos, const ModelCoordinate& target) {
00071 if (curpos == target) {
00072 return true;
00073 }
00074
00075 if(curpos.y % 2) {
00076
00077 if((curpos.x == target.x) && (curpos.y - 1 == target.y)) {
00078 return true;
00079 }
00080
00081 if((curpos.x + 1 == target.x) && (curpos.y - 1 == target.y)) {
00082 return true;
00083 }
00084
00085 if((curpos.x + 1 == target.x) && (curpos.y == target.y)) {
00086 return true;
00087 }
00088
00089 if((curpos.x + 1 == target.x) && (curpos.y + 1 == target.y)) {
00090 return true;
00091 }
00092
00093 if((curpos.x == target.x) && (curpos.y + 1 == target.y)) {
00094 return true;
00095 }
00096
00097 if((curpos.x - 1 == target.x) && (curpos.y == target.y)) {
00098 return true;
00099 }
00100
00101 } else {
00102
00103 if((curpos.x - 1 == target.x) && (curpos.y - 1 == target.y)) {
00104 return true;
00105 }
00106
00107 if((curpos.x == target.x) && (curpos.y - 1 == target.y)) {
00108 return true;
00109 }
00110
00111 if((curpos.x + 1 == target.x) && (curpos.y == target.y)) {
00112 return true;
00113 }
00114
00115 if((curpos.x == target.x) && (curpos.y + 1 == target.y)) {
00116 return true;
00117 }
00118
00119 if((curpos.x - 1 == target.x) && (curpos.y + 1 == target.y)) {
00120 return true;
00121 }
00122
00123 if((curpos.x - 1 == target.x) && (curpos.y == target.y)) {
00124 return true;
00125 }
00126 }
00127
00128 return false;
00129
00130 }
00131
00132 double HexGrid::getAdjacentCost(const ModelCoordinate& curpos, const ModelCoordinate& target) {
00133 assert(isAccessible(curpos, target));
00134 if (curpos == target) {
00135 return 0;
00136 } else if (curpos.y == target.y) {
00137 return m_xscale;
00138 } else {
00139 double a = VERTICAL_MULTIP * m_yscale;
00140 double b = HEX_TO_EDGE * m_xscale;
00141 return Mathd::Sqrt((a * a) + (b * b));
00142 }
00143 }
00144
00145 const std::string& HexGrid::getType() const {
00146 static std::string type("hexagonal");
00147 return type;
00148 }
00149
00150 const std::string& HexGrid::getName() const {
00151 static std::string hexGrid("Hex Grid");
00152 return hexGrid;
00153 }
00154
00155 double HexGrid::getXZigzagOffset(double y) {
00156
00157
00158 double ay = ABS(y);
00159 int32_t i_layer_y = static_cast<int32_t>(ay);
00160 double offset = ay - static_cast<double>(i_layer_y);
00161 if ((i_layer_y % 2) == 1) {
00162 offset = 1 - offset;
00163 }
00164 return HEX_TO_EDGE * offset;
00165 }
00166
00167 ExactModelCoordinate HexGrid::toMapCoordinates(const ExactModelCoordinate& layer_coords) {
00168 ExactModelCoordinate tranformed_coords(layer_coords);
00169 tranformed_coords.x += getXZigzagOffset(layer_coords.y);
00170 tranformed_coords.y *= VERTICAL_MULTIP;
00171 ExactModelCoordinate result = m_matrix * tranformed_coords;
00172 FL_DBG(_log, LMsg("layercoords ") << layer_coords << " converted to map: " << result);
00173 return result;
00174 }
00175
00176 ExactModelCoordinate HexGrid::toExactLayerCoordinates(const ExactModelCoordinate& map_coord) {
00177 ExactModelCoordinate layer_coords = m_inverse_matrix * map_coord;
00178 layer_coords.y /= VERTICAL_MULTIP;
00179 layer_coords.x -= getXZigzagOffset(layer_coords.y);
00180 FL_DBG(_log, LMsg("mapcoords ") << map_coord << " converted to layer: " << layer_coords);
00181 return layer_coords;
00182 }
00183
00184 ModelCoordinate HexGrid::toLayerCoordinates(const ExactModelCoordinate& map_coord) {
00185 FL_DBG(_log, LMsg("==============\nConverting map coords ") << map_coord << " to int32_t layer coords...");
00186 ExactModelCoordinate elc = m_inverse_matrix * map_coord;
00187 elc.y *= VERTICAL_MULTIP_INV;
00188 ExactModelCoordinate lc = ExactModelCoordinate(floor(elc.x), floor(elc.y), floor(elc.z));
00189 double dx = elc.x - lc.x;
00190 double dy = elc.y - lc.y;
00191 double dz = elc.z - lc.z;
00192 int32_t x = static_cast<int32_t>(lc.x);
00193 int32_t y = static_cast<int32_t>(lc.y);
00194 int32_t z = static_cast<int32_t>(lc.z);
00195
00196
00197 ModelCoordinate result;
00198
00199 if ((y % 2) == 0) {
00200
00201 if ((1 - dy) < HEX_EDGE_HALF) {
00202 FL_DBG(_log, "In lower rect area");
00203 result = ModelCoordinate(x, y+1, z);
00204 }
00205 else if (dy < HEX_EDGE_HALF) {
00206
00207 if (dx > 0.5) {
00208
00209 result = ModelCoordinate(x+1, y, z);
00210 }
00211 else {
00212
00213 result = ModelCoordinate(x, y, z);
00214 }
00215 }
00216
00217 else {
00218
00219 if (dx < 0.5) {
00220
00221 if (ptInTriangle(ExactModelCoordinate(dx, dy),
00222 ExactModelCoordinate(0, VERTICAL_MULTIP * HEX_EDGE_HALF),
00223 ExactModelCoordinate(0, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)),
00224 ExactModelCoordinate(0.5, VERTICAL_MULTIP * HEX_EDGE_HALF)
00225 )) {
00226
00227 result = ModelCoordinate(x, y, z);
00228 } else {
00229
00230 result = ModelCoordinate(x, y+1, z);
00231 }
00232 } else {
00233
00234 if (ptInTriangle(ExactModelCoordinate(dx, dy),
00235 ExactModelCoordinate(1, VERTICAL_MULTIP * HEX_EDGE_HALF),
00236 ExactModelCoordinate(1, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)),
00237 ExactModelCoordinate(0.5, VERTICAL_MULTIP * HEX_EDGE_HALF)
00238 )) {
00239
00240 result = ModelCoordinate(x+1, y, z);
00241 } else {
00242
00243 result = ModelCoordinate(x, y+1, z);
00244 }
00245 }
00246 }
00247 }
00248 else {
00249
00250 if (dy < HEX_EDGE_HALF) {
00251
00252 result = ModelCoordinate(x, y, z);
00253 }
00254 else if ((1 - dy) < HEX_EDGE_HALF) {
00255
00256 if (dx > 0.5) {
00257
00258 result = ModelCoordinate(x+1, y+1, z);
00259 }
00260 else {
00261
00262 result = ModelCoordinate(x, y+1, z);
00263 }
00264 }
00265 else {
00266
00267 if (dx < 0.5) {
00268
00269 if (ptInTriangle(ExactModelCoordinate(dx, dy),
00270 ExactModelCoordinate(0, VERTICAL_MULTIP * HEX_EDGE_HALF),
00271 ExactModelCoordinate(0, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)),
00272 ExactModelCoordinate(0.5, VERTICAL_MULTIP * (1-HEX_EDGE_HALF))
00273 )) {
00274
00275 result = ModelCoordinate(x, y+1, z);
00276 } else {
00277
00278 result = ModelCoordinate(x, y, z);
00279 }
00280 } else {
00281
00282 if (ptInTriangle(ExactModelCoordinate(dx, dy),
00283 ExactModelCoordinate(1, VERTICAL_MULTIP * HEX_EDGE_HALF),
00284 ExactModelCoordinate(1, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)),
00285 ExactModelCoordinate(0.5, VERTICAL_MULTIP * (1-HEX_EDGE_HALF))
00286 )) {
00287
00288 result = ModelCoordinate(x+1, y+1, z);
00289 } else {
00290
00291 result = ModelCoordinate(x, y, z);
00292 }
00293 }
00294 }
00295 }
00296
00297 return result;
00298 }
00299
00300 void HexGrid::getVertices(std::vector<ExactModelCoordinate>& vtx, const ModelCoordinate& cell) {
00301 FL_DBG(_log, LMsg("===============\ngetting vertices for ") << cell);
00302 vtx.clear();
00303 double x = static_cast<double>(cell.x);
00304 double y = static_cast<double>(cell.y);
00305 double horiz_shift = 0;
00306 if (cell.y % 2 != 0) {
00307 horiz_shift = HEX_TO_EDGE;
00308 FL_DBG(_log, "on uneven row");
00309 }
00310 double tx, ty;
00311
00312 #define ADD_PT(_x, _y) vtx.push_back(ExactModelCoordinate(_x, _y));
00313
00314 ty = y - VERTICAL_MULTIP_INV * HEX_EDGE_HALF;
00315 tx = x - HEX_TO_EDGE - getXZigzagOffset(ty) + horiz_shift;
00316 ADD_PT(tx, ty);
00317
00318 ty = y - VERTICAL_MULTIP_INV * HEX_TO_CORNER;
00319 tx = x - getXZigzagOffset(ty) + horiz_shift;
00320 ADD_PT(tx, ty);
00321
00322 ty = y - VERTICAL_MULTIP_INV * HEX_EDGE_HALF;
00323 tx = x + HEX_TO_EDGE - getXZigzagOffset(ty) + horiz_shift;
00324 ADD_PT(tx, ty);
00325
00326 ty = y + VERTICAL_MULTIP_INV * HEX_EDGE_HALF;
00327 tx = x + HEX_TO_EDGE - getXZigzagOffset(ty) + horiz_shift;
00328 ADD_PT(tx, ty);
00329
00330 ty = y + VERTICAL_MULTIP_INV * HEX_TO_CORNER;
00331 tx = x - getXZigzagOffset(ty) + horiz_shift;
00332 ADD_PT(tx, ty);
00333
00334 ty = y + VERTICAL_MULTIP_INV * HEX_EDGE_HALF;
00335 tx = x - HEX_TO_EDGE - getXZigzagOffset(ty) + horiz_shift;
00336 ADD_PT(tx, ty);
00337 }
00338 }