载入中...
搜索中...
未找到
GridProjection.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <utility>
6
7namespace eve::grid {
8namespace {
9
10bool staggerDoShift(const GridConfig &cfg, int cx, int cy) {
11 const int major = (cfg.staggerAxis == StaggerAxis::Y) ? cy : cx;
12 const bool odd = (major & 1) != 0;
13 return cfg.staggerIndex == StaggerIndex::Odd ? odd : !odd;
14}
15
16// odd-r offset(staggerAxis=Y, odd)pointy-top hex <-> cube。
17void offsetToCube(int col, int row, int &x, int &y, int &z) {
18 x = col - (row - (row & 1)) / 2;
19 y = row;
20 z = -x - y;
21}
22
23void cubeToOffset(int x, int y, int &col, int &row) {
24 row = y;
25 col = x + (row - (row & 1)) / 2;
26}
27
28} // namespace
29
30void cellToWorld(const GridConfig &cfg, int cx, int cy, float &px, float &py) {
31 const float tw = cellPitchX(cfg);
32 const float th = cellPitchY(cfg);
33 switch (cfg.layout) {
35 px = cfg.originX + float(cx) * tw;
36 py = cfg.originY + float(cy) * th;
37 break;
40 // 菱形投影(IsometricZAsY 在 v1 与 Isometric 同构,Z-as-Y 由平面轴承担)。
41 px = cfg.originX + float(cx - cy) * tw * 0.5f;
42 py = cfg.originY + float(cx + cy) * th * 0.5f;
43 break;
46 const bool hex = cfg.layout == GridLayout::Hexagon && cfg.hexSideLength > 0.f;
47 if (cfg.staggerAxis == StaggerAxis::Y) {
48 const float pitchY = hex ? (th + cfg.hexSideLength) * 0.5f : th * 0.5f;
49 px = cfg.originX + float(cx) * tw +
50 (staggerDoShift(cfg, cx, cy) ? tw * 0.5f : 0.f);
51 py = cfg.originY + float(cy) * pitchY;
52 } else {
53 const float pitchX = hex ? (tw + cfg.hexSideLength) * 0.5f : tw * 0.5f;
54 px = cfg.originX + float(cx) * pitchX;
55 py = cfg.originY + float(cy) * th +
56 (staggerDoShift(cfg, cx, cy) ? th * 0.5f : 0.f);
57 }
58 break;
59 }
60 }
61}
62
63float cellToDepthY(const GridConfig &cfg, int cx, int cy) {
64 float px = 0.f, py = 0.f;
65 cellToWorld(cfg, cx, cy, px, py);
66 return py + cfg.cellH;
67}
68
69void worldToCell(const GridConfig &cfg, float px, float py, int &cx, int &cy, int mapW,
70 int mapH) {
71 switch (cfg.layout) {
73 const float lx = px - cfg.originX;
74 const float ly = py - cfg.originY;
75 const float tw = cfg.cellW > 0.f ? cellPitchX(cfg) : 1.f;
76 const float th = cfg.cellH > 0.f ? cellPitchY(cfg) : 1.f;
77 cx = int(std::floor(lx / tw));
78 cy = int(std::floor(ly / th));
79 break;
80 }
83 const float lx = px - cfg.originX;
84 const float ly = py - cfg.originY;
85 const float tw = cfg.cellW > 0.f ? cfg.cellW * 0.5f : 1.f;
86 const float th = cfg.cellH > 0.f ? cfg.cellH * 0.5f : 1.f;
87 const float a = lx / tw;
88 const float b = ly / th;
89 cx = int(std::floor((b + a) * 0.5f));
90 cy = int(std::floor((b - a) * 0.5f));
91 break;
92 }
93 default: {
94 // 最近格中心(staggered / hex)。
95 cx = 0;
96 cy = 0;
97 float best = 1e30f;
98 const int w = std::max(1, mapW);
99 const int h = std::max(1, mapH);
100 for (int y = 0; y < h; ++y) {
101 for (int x = 0; x < w; ++x) {
102 float wx = 0.f, wy = 0.f;
103 cellToWorld(cfg, x, y, wx, wy);
104 wx += cfg.cellW * 0.5f;
105 wy += cfg.cellH * 0.5f;
106 const float dx = wx - px;
107 const float dy = wy - py;
108 const float d = dx * dx + dy * dy;
109 if (d < best) {
110 best = d;
111 cx = x;
112 cy = y;
113 }
114 }
115 }
116 break;
117 }
118 }
119}
120
121void foreachRotatedFootprint(int w, int h, const std::vector<uint8_t> &mask, int steps,
122 bool hexMode, const std::function<void(int lx, int ly)> &fn) {
123 if (!fn) return;
124 if (w <= 0) w = 1;
125 if (h <= 0) h = 1;
126
127 // 1. 收集实心局部格。
128 std::vector<std::pair<int, int>> solid;
129 for (int ly = 0; ly < h; ++ly) {
130 for (int lx = 0; lx < w; ++lx) {
131 bool solidCell = true;
132 if (!mask.empty()) {
133 const size_t idx = size_t(ly) * size_t(w) + size_t(lx);
134 solidCell = idx < mask.size() && mask[idx] != 0;
135 }
136 if (solidCell) solid.emplace_back(lx, ly);
137 }
138 }
139 if (solid.empty()) return;
140
141 // 2. 旋转到归一化局部坐标。
142 std::vector<std::pair<int, int>> rotated;
143 rotated.reserve(solid.size());
144 int minX = 1 << 30, minY = 1 << 30;
145 for (const auto &c : solid) {
146 int rx = c.first;
147 int ry = c.second;
148 if (hexMode) {
149 int x = 0, y = 0, z = 0;
150 offsetToCube(c.first, c.second, x, y, z);
151 const int s = ((steps % 6) + 6) % 6;
152 for (int i = 0; i < s; ++i) {
153 const int nx = -z;
154 const int ny = -x;
155 const int nz = -y;
156 x = nx;
157 y = ny;
158 z = nz;
159 }
160 cubeToOffset(x, y, rx, ry);
161 } else {
162 const int q = ((steps % 4) + 4) % 4;
163 switch (q) {
164 case 1: // 90° CCW
165 rx = c.second;
166 ry = w - 1 - c.first;
167 break;
168 case 2: // 180°
169 rx = w - 1 - c.first;
170 ry = h - 1 - c.second;
171 break;
172 case 3: // 270° CCW / 90° CW
173 rx = h - 1 - c.second;
174 ry = c.first;
175 break;
176 default:
177 break;
178 }
179 }
180 rotated.emplace_back(rx, ry);
181 minX = std::min(minX, rx);
182 minY = std::min(minY, ry);
183 }
184 for (const auto &c : rotated) fn(c.first - minX, c.second - minY);
185}
186
187void rotatedFootprintSize(int w, int h, const std::vector<uint8_t> &mask, int steps,
188 bool hexMode, int &outW, int &outH) {
189 int maxX = -1;
190 int maxY = -1;
191 foreachRotatedFootprint(w, h, mask, steps, hexMode, [&](int lx, int ly) {
192 maxX = std::max(maxX, lx);
193 maxY = std::max(maxY, ly);
194 });
195 outW = maxX + 1;
196 outH = maxY + 1;
197}
198
199} // namespace eve::grid
float cx
Definition CardTypes.cpp:31
float cy
Definition CardTypes.cpp:32
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
int h
int w
std::vector< Colorf > px
uint32_t a
uint32_t b
uint32_t c
int idx
SettlementPipeline::Stage fn
int d
uint32_t s
Definition Weather.cpp:28
void cellToWorld(const GridConfig &cfg, int cx, int cy, float &px, float &py)
void worldToCell(const GridConfig &cfg, float px, float py, int &cx, int &cy, int mapW, int mapH)
void foreachRotatedFootprint(int w, int h, const std::vector< uint8_t > &mask, int steps, bool hexMode, const std::function< void(int lx, int ly)> &fn)
float cellToDepthY(const GridConfig &cfg, int cx, int cy)
void rotatedFootprintSize(int w, int h, const std::vector< uint8_t > &mask, int steps, bool hexMode, int &outW, int &outH)
float cellPitchY(const GridConfig &cfg)
Definition GridConfig.h:44
float cellPitchX(const GridConfig &cfg)
Definition GridConfig.h:43
WidgetDesc row(std::vector< WidgetDesc > children, std::string id)
Horizontal elastic layout row.
Definition Widget.cpp:431
StaggerAxis staggerAxis
Definition GridConfig.h:32