一种平面六边形网格坐标系统的C++实现
一、源代码
1. hexagonal_grid.h
1 #ifndef _HEXAGONAL_GRID_HEADER 2 #define _HEXAGONAL_GRID_HEADER 3 4 class class_hexagonal_grid 5 { 6 public: 7 class_hexagonal_grid() = delete; 8 ~class_hexagonal_grid(); 9 class_hexagonal_grid(const class_hexagonal_grid &) = delete; 10 class_hexagonal_grid & operator=(const class_hexagonal_grid &) = delete; 11 explicit class_hexagonal_grid(unsigned); 12 13 public: 14 unsigned property_number() const; 15 16 // parameter: direction number 17 // return >= 0: target neighbor grid's number 18 // return = -1: neighbor does not exist 19 int property_neighbor_num(unsigned) const; 20 class_hexagonal_grid * property_neighbor_pointer(unsigned) const; 21 unsigned property_position_x() const; 22 unsigned property_position_y() const; 23 24 // parameter 1: direction number 25 // parameter 2: neighbor-grid's pointer 26 void function_set_neighbor(unsigned, class_hexagonal_grid * const); 27 28 // parameter 1: position x 29 // parameter 2: position y 30 void function_set_position(unsigned, unsigned); 31 32 private: 33 unsigned _uint_num; 34 class_hexagonal_grid * _pointer_array_neighbors[6]; 35 unsigned _uint_position_x; 36 unsigned _uint_position_y; 37 }; 38 39 #endif // !_HEXAGONAL_GRID_HEADER
2. hexagonal_grid.cpp
1 #include "hexagonal_grid.h" 2 3 class_hexagonal_grid::~class_hexagonal_grid() 4 { 5 } 6 7 class_hexagonal_grid::class_hexagonal_grid(unsigned uint_num) : 8 _uint_num(uint_num), 9 _pointer_array_neighbors{ nullptr }, 10 _uint_position_x(0), 11 _uint_position_y(0) 12 { 13 } 14 15 unsigned class_hexagonal_grid::property_number() const 16 { 17 return _uint_num; 18 } 19 20 int class_hexagonal_grid::property_neighbor_num(unsigned uint_direc) const 21 { 22 uint_direc %= 6; 23 if (nullptr == _pointer_array_neighbors[uint_direc]) 24 { 25 return -1; 26 } 27 return (signed)(_pointer_array_neighbors[uint_direc]->property_number()); 28 } 29 30 class_hexagonal_grid * class_hexagonal_grid::property_neighbor_pointer(unsigned uint_direc) const 31 { 32 uint_direc %= 6; 33 return _pointer_array_neighbors[uint_direc]; 34 } 35 36 unsigned class_hexagonal_grid::property_position_x() const 37 { 38 return _uint_position_x; 39 } 40 41 unsigned class_hexagonal_grid::property_position_y() const 42 { 43 return _uint_position_y; 44 } 45 46 void class_hexagonal_grid::function_set_neighbor(unsigned uint_direction, class_hexagonal_grid * const pointer_neighbor_grid) 47 { 48 if (nullptr != pointer_neighbor_grid) 49 { 50 pointer_neighbor_grid->_pointer_array_neighbors[(uint_direction + 3) % 6] = this; 51 } 52 _pointer_array_neighbors[uint_direction % 6] = pointer_neighbor_grid; 53 } 54 55 void class_hexagonal_grid::function_set_position(unsigned uint_x, unsigned uint_y) 56 { 57 _uint_position_x = uint_x; 58 _uint_position_y = uint_y; 59 }
3. hexagonal_network.h
1 #ifndef _HEXAGONAL_NETWORK_HEADER 2 #define _HEXAGONAL_NETWORK_HEADER 3 4 #include "hexagonal_grid.h" 5 6 #include <vector> 7 8 class class_hexagonal_network 9 { 10 public: 11 class_hexagonal_network() = delete; 12 ~class_hexagonal_network(); 13 class_hexagonal_network(const class_hexagonal_network &); 14 class_hexagonal_network & operator=(const class_hexagonal_network &); 15 explicit class_hexagonal_network(unsigned); 16 17 public: 18 static unsigned function_calculate_max_grid_count_from_layer(unsigned); 19 20 public: 21 unsigned property_layer() const; 22 unsigned property_size() const; 23 24 public: 25 // parameter 1: source grid number 26 // parameter 2: direction number 27 // return >= 0: target neighbor grid number 28 // return = -1: neighbor does not exist 29 // return = -2: source does not exist 30 int function_get_neighbor_number(unsigned, unsigned) const; 31 // parameter 1: source grid number 32 // parameter 2: horizontal position 33 // parameter 3: vertical position 34 // return = 0: operation succeeded 35 // return = -1: source does not exist 36 int function_get_grid_position(unsigned, unsigned &, unsigned &) const; 37 38 private: 39 unsigned _uint_layer; 40 std::vector<class_hexagonal_grid *> _vector_hexagonal_grids; 41 42 private: 43 void _function_generate_grids(unsigned); 44 void _function_set_grids_position(); 45 }; 46 47 #endif // !_HEXAGONAL_NETWORK_HEADER
4. hexagonal_network.cpp
1 #include "hexagonal_network.h" 2 3 class_hexagonal_network::~class_hexagonal_network() 4 { 5 for (auto it_grid = _vector_hexagonal_grids.begin(); it_grid != _vector_hexagonal_grids.end(); it_grid++) 6 { 7 delete *it_grid; 8 } 9 } 10 11 class_hexagonal_network::class_hexagonal_network(const class_hexagonal_network & another_network): 12 _uint_layer(another_network._uint_layer), 13 _vector_hexagonal_grids(std::vector<class_hexagonal_grid *>(another_network._vector_hexagonal_grids.size())) 14 { 15 _function_generate_grids(_uint_layer); 16 _function_set_grids_position(); 17 } 18 19 class_hexagonal_network & class_hexagonal_network::operator=(const class_hexagonal_network & another_network) 20 { 21 if (this != & another_network) 22 { 23 _function_generate_grids(another_network.property_layer()); 24 _function_set_grids_position(); 25 } 26 return * this; 27 } 28 29 class_hexagonal_network::class_hexagonal_network(unsigned uint_layer): 30 _uint_layer(uint_layer), 31 _vector_hexagonal_grids(std::vector<class_hexagonal_grid *>(function_calculate_max_grid_count_from_layer(uint_layer))) 32 { 33 _function_generate_grids(uint_layer); 34 _function_set_grids_position(); 35 } 36 37 unsigned class_hexagonal_network::function_calculate_max_grid_count_from_layer(unsigned uint_layer) 38 { 39 switch (uint_layer) 40 { 41 case 0: 42 return 0; 43 default: 44 return 3 * uint_layer * (uint_layer - 1) + 1; 45 } 46 } 47 48 unsigned class_hexagonal_network::property_layer() const 49 { 50 return _uint_layer; 51 } 52 53 unsigned class_hexagonal_network::property_size() const 54 { 55 return function_calculate_max_grid_count_from_layer(_uint_layer); 56 } 57 58 int class_hexagonal_network::function_get_neighbor_number(unsigned uint_sou_num, unsigned uint_direc) const 59 { 60 if (uint_sou_num >= _vector_hexagonal_grids.size()) 61 { 62 return -2; 63 } 64 return _vector_hexagonal_grids[uint_sou_num]->property_neighbor_num(uint_direc); 65 } 66 67 int class_hexagonal_network::function_get_grid_position(unsigned uint_sou_num, unsigned & x, unsigned & y) const 68 { 69 if (uint_sou_num >= _vector_hexagonal_grids.size()) 70 { 71 return -1; 72 } 73 x = _vector_hexagonal_grids[uint_sou_num]->property_position_x(); 74 y = _vector_hexagonal_grids[uint_sou_num]->property_position_y(); 75 return 0; 76 } 77 78 void class_hexagonal_network::_function_generate_grids(unsigned uint_layer) 79 { 80 switch (uint_layer) 81 { 82 case 0: 83 return; 84 } 85 86 // 1. allocate memory 87 for (unsigned i_grid = 0; i_grid < _vector_hexagonal_grids.size(); i_grid++) 88 { 89 _vector_hexagonal_grids[i_grid] = new class_hexagonal_grid(i_grid); 90 } 91 switch (uint_layer) 92 { 93 case 1: 94 return; 95 } 96 97 // 2. connect within 2 layer 98 for (unsigned i_direc = 0; i_direc < 6; i_direc++) 99 { 100 (*_vector_hexagonal_grids.begin())->function_set_neighbor(i_direc, _vector_hexagonal_grids[i_direc + 1]); 101 _vector_hexagonal_grids[i_direc + 1]->function_set_neighbor(i_direc + 2, _vector_hexagonal_grids[(i_direc + 1) % 6 + 1]); 102 } 103 switch (uint_layer) 104 { 105 case 2: 106 return; 107 } 108 109 // 3. connect with outer layer grids in counter-clockwise 110 111 // current vertex grid number 112 int cvgn; 113 // outer vertex grid number 114 int ovgn; 115 for (unsigned i_layer = 1; i_layer < uint_layer - 1; i_layer++) 116 { 117 for (unsigned i_direc = 0; i_direc < 6; i_direc++) 118 { 119 // vertex grids add one 120 cvgn = function_calculate_max_grid_count_from_layer(i_layer) + i_direc * i_layer; 121 ovgn = function_calculate_max_grid_count_from_layer(i_layer + 1) + i_direc * (i_layer + 1); 122 _vector_hexagonal_grids[cvgn]->function_set_neighbor(i_direc, _vector_hexagonal_grids[ovgn]); 123 // all grids in counter-clockwise 124 for (unsigned i_subse = 0; i_subse < i_layer; i_subse++) 125 { 126 _vector_hexagonal_grids[cvgn + i_subse]->function_set_neighbor(i_direc + 1, _vector_hexagonal_grids[ovgn + i_subse + 1]); 127 } 128 } 129 } 130 131 // 4. connect with current layer grids && inner layer grids in counter-clockwise 132 133 // inner layer start 134 int ils; 135 // current layer start 136 int cls; 137 // outer layer start 138 int ols; 139 // inner vertex grid number 140 int ivgn; 141 for (unsigned i_layer = 2; i_layer < uint_layer; i_layer++) 142 { 143 for (unsigned i_direc = 0; i_direc < 5; i_direc++) 144 { 145 ivgn = function_calculate_max_grid_count_from_layer(i_layer - 1) + i_direc * (i_layer - 1); 146 cvgn = function_calculate_max_grid_count_from_layer(i_layer) + i_direc * i_layer; 147 _vector_hexagonal_grids[cvgn]->function_set_neighbor(i_direc + 2, _vector_hexagonal_grids[cvgn + 1]); 148 for (unsigned i_subse = 1; i_subse < i_layer; i_subse++) 149 { 150 _vector_hexagonal_grids[cvgn + i_subse]->function_set_neighbor(i_direc + 2, _vector_hexagonal_grids[cvgn + i_subse + 1]); 151 _vector_hexagonal_grids[cvgn + i_subse]->function_set_neighbor(i_direc + 3, _vector_hexagonal_grids[ivgn + i_subse]); 152 } 153 } 154 // sector 6 155 ivgn = function_calculate_max_grid_count_from_layer(i_layer - 1) + 5 * (i_layer - 1); 156 cvgn = function_calculate_max_grid_count_from_layer(i_layer) + 5 * i_layer; 157 _vector_hexagonal_grids[cvgn]->function_set_neighbor(1, _vector_hexagonal_grids[cvgn + 1]); 158 for (unsigned i_subse = 1; i_subse < i_layer - 1; i_subse++) 159 { 160 _vector_hexagonal_grids[cvgn + i_subse]->function_set_neighbor(1, _vector_hexagonal_grids[cvgn + i_subse + 1]); 161 _vector_hexagonal_grids[cvgn + i_subse]->function_set_neighbor(2, _vector_hexagonal_grids[ivgn + i_subse]); 162 } 163 // last one 164 ils = function_calculate_max_grid_count_from_layer(i_layer - 1); 165 cls = function_calculate_max_grid_count_from_layer(i_layer); 166 ols = function_calculate_max_grid_count_from_layer(i_layer + 1); 167 _vector_hexagonal_grids[ols - 1]->function_set_neighbor(1, _vector_hexagonal_grids[cls]); 168 _vector_hexagonal_grids[ols - 1]->function_set_neighbor(2, _vector_hexagonal_grids[ils]); 169 } 170 } 171 172 void class_hexagonal_network::_function_set_grids_position() 173 { 174 switch (_uint_layer) 175 { 176 case 0: 177 return; 178 } 179 180 // move to center left 181 182 class_hexagonal_grid * p_grid = _vector_hexagonal_grids[0]; 183 while (p_grid->property_neighbor_pointer(3) != nullptr) 184 { 185 p_grid = p_grid->property_neighbor_pointer(3); 186 } 187 p_grid->function_set_position(0, _uint_layer - 1); 188 switch (_uint_layer) 189 { 190 case 1: 191 return; 192 } 193 194 // up && down 195 196 unsigned x_start = 0, x = 0, y_up = _uint_layer - 1, y_down = y_up; 197 class_hexagonal_grid * p_grid_up_head = p_grid; 198 class_hexagonal_grid * p_grid_up = nullptr; 199 class_hexagonal_grid * p_grid_down_head = p_grid; 200 class_hexagonal_grid * p_grid_down = nullptr; 201 while (p_grid_up_head->property_neighbor_pointer(1) != nullptr) 202 { 203 p_grid_up_head = p_grid_up_head->property_neighbor_pointer(1); 204 p_grid_down_head = p_grid_down_head->property_neighbor_pointer(5); 205 y_up--; 206 y_down++; 207 x_start++; 208 x = x_start; 209 p_grid_up = p_grid_up_head; 210 p_grid_down = p_grid_down_head; 211 while (p_grid_up != nullptr) 212 { 213 p_grid_up->function_set_position(x, y_up); 214 p_grid_down->function_set_position(x, y_down); 215 p_grid_up = p_grid_up->property_neighbor_pointer(0); 216 p_grid_down = p_grid_down->property_neighbor_pointer(0); 217 x += 2; 218 } 219 } 220 221 // center 222 x = 0; 223 while (p_grid->property_neighbor_pointer(0) != nullptr) 224 { 225 p_grid = p_grid->property_neighbor_pointer(0); 226 x += 2; 227 p_grid->function_set_position(x, _uint_layer - 1); 228 } 229 }
二、使用方法
1. 创建网格类对象
必须使用指定的单参数构造函数 explicit class_hexagonal_network(unsigned) 去创建一个六边形网格类的对象,参数为圈层数,见下图:

规则六边形网格的尺寸可由圈层数决定,其圈层数和网格数目可分别由 unsigned property_layer() const; unsigned property_size() const 两函数得到。
2. 获取临格索引
每个格子都有一个索引(编号),通过 int function_get_neighbor_number(unsigned, unsigned) const 函数可以得到特定索引格子任意方向临格的索引,其排列规则如下图所示:

函数 function_get_neighbor_number 的第一个参数是指定格子的索引,其取值应在网格总数范围内(不包括总数),否则将返回 -2;第二个参数是方向,共六个方向如下图:

如果取到边界的格子,目标方向可能无临格,这时函数返回 -1。正常情况下,函数会返回目标临格的索引。
3. 获取坐标
网格类对象可用 int function_get_grid_position(unsigned, unsigned &, unsigned &) const 函数来获取格点的横纵坐标信息。第一个参数是格点索引,如果不在总数范围内函数将返回 -1;
第二个参数和第三个参数分别为该格点的横纵坐标值。正常执行完毕返回 0。坐标约定见下图:

三、功能测试
1. 测试代码
1 #include <iostream> 2 #include <string> 3 4 #include "hexagonal_network.h" 5 6 int main(int argc, char* argv[]) { 7 class_hexagonal_network nw(4); 8 unsigned x, y; 9 for (unsigned i_grid = 0; i_grid < nw.property_size(); i_grid++) 10 { 11 nw.function_get_grid_position(i_grid, x, y); 12 std::cout << "grid " << i_grid << " at (" << x << ", " << y << "), neighbors: "; 13 for (unsigned i_direc = 0; i_direc < 6; i_direc++) 14 { 15 std::cout << nw.function_get_neighbor_number(i_grid, i_direc) << " "; 16 } 17 std::cout << std::endl; 18 } 19 20 std::string str_pause; 21 std::getline(std::cin, str_pause); 22 return 0; 23 }
2. 输出结果
grid 0 at (6, 3), neighbors: 1 2 3 4 5 6 grid 1 at (8, 3), neighbors: 7 8 2 0 6 18 grid 2 at (7, 2), neighbors: 8 9 10 3 0 1 grid 3 at (5, 2), neighbors: 2 10 11 12 4 0 grid 4 at (4, 3), neighbors: 0 3 12 13 14 5 grid 5 at (5, 4), neighbors: 6 0 4 14 15 16 grid 6 at (7, 4), neighbors: 18 1 0 5 16 17 grid 7 at (10, 3), neighbors: 19 20 8 1 18 36 grid 8 at (9, 2), neighbors: 20 21 9 2 1 7 grid 9 at (8, 1), neighbors: 21 22 23 10 2 8 grid 10 at (6, 1), neighbors: 9 23 24 11 3 2 grid 11 at (4, 1), neighbors: 10 24 25 26 12 3 grid 12 at (3, 2), neighbors: 3 11 26 27 13 4 grid 13 at (2, 3), neighbors: 4 12 27 28 29 14 grid 14 at (3, 4), neighbors: 5 4 13 29 30 15 grid 15 at (4, 5), neighbors: 16 5 14 30 31 32 grid 16 at (6, 5), neighbors: 17 6 5 15 32 33 grid 17 at (8, 5), neighbors: 35 18 6 16 33 34 grid 18 at (9, 4), neighbors: 36 7 1 6 17 35 grid 19 at (12, 3), neighbors: -1 -1 20 7 36 -1 grid 20 at (11, 2), neighbors: -1 -1 21 8 7 19 grid 21 at (10, 1), neighbors: -1 -1 22 9 8 20 grid 22 at (9, 0), neighbors: -1 -1 -1 23 9 21 grid 23 at (7, 0), neighbors: 22 -1 -1 24 10 9 grid 24 at (5, 0), neighbors: 23 -1 -1 25 11 10 grid 25 at (3, 0), neighbors: 24 -1 -1 -1 26 11 grid 26 at (2, 1), neighbors: 11 25 -1 -1 27 12 grid 27 at (1, 2), neighbors: 12 26 -1 -1 28 13 grid 28 at (0, 3), neighbors: 13 27 -1 -1 -1 29 grid 29 at (1, 4), neighbors: 14 13 28 -1 -1 30 grid 30 at (2, 5), neighbors: 15 14 29 -1 -1 31 grid 31 at (3, 6), neighbors: 32 15 30 -1 -1 -1 grid 32 at (5, 6), neighbors: 33 16 15 31 -1 -1 grid 33 at (7, 6), neighbors: 34 17 16 32 -1 -1 grid 34 at (9, 6), neighbors: -1 35 17 33 -1 -1 grid 35 at (10, 5), neighbors: -1 36 18 17 34 -1 grid 36 at (11, 4), neighbors: -1 19 7 18 35 -1

浙公网安备 33010602011771号