LIBPOLYMNIA
hex.h
[詳解]
1 /**********************************************************************/
9 #ifndef INC_POLYMNIA_HEX_H__
10 #define INC_POLYMNIA_HEX_H__
11 
12 #include <algorithm>
13 #include <cmath>
14 #include "ibuf.h"
15 
16 namespace polymnia
17 {
18  template<class C_> class HexPainter;
19 }
20 
21 
22 /*------------------------------------------------*/
31 template<class C_>
33 {
34 private:
35  int r_;
36  int p0_;
37  int q0_;
38 
39  static inline const double SQRT3_ = std::sqrt(3);
40 
41 public:
46  HexPainter(int r, int p0, int q0) : r_(r), p0_(p0), q0_(q0) {}
47 
53  void resetOrigin(int p0, int q0)
54  {
55  p0_ = p0;
56  q0_ = q0;
57  }
58 
63  void resetRadius(int r) { r_ = r; }
64 
70  void getOrigin(int& p, int& q) const
71  {
72  p = p0_;
73  q = q0_;
74  }
75 
79  int getRadius() const { return r_; }
80 
88  void draw(polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col);
89 
99  void
100  draw(
101  polymnia::ImageBuffer<C_>* pict, int x, int y, int w, int h, const C_& col);
102 
110  void fill(polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col);
111 
121  void
122  fill(
123  polymnia::ImageBuffer<C_>* pict, int x, int y, int w, int h, const C_& col);
124 
132  void getHexPosition(int& x, int& y, int p, int q);
133 
141  void getPixelPosition(int& p, int& q, int x, int y)
142  {
143  p = SQRT3_ * r_ * (x + 0.5 * (y % 2)) + p0_;
144  q = (3.0 * y * r_) / 2.0 + q0_;
145  }
146 
154  void getPixelPosition(double& p, double& q, int x, int y)
155  {
156  p = SQRT3_ * r_ * (x + 0.5 * (y % 2)) + p0_;
157  q = (3.0 * y * r_) / 2.0 + q0_;
158  }
159 
163  int distance(int x0, int y0, int x1, int y1)
164  {
165  int y0_2 = y0 / 2;
166  if (y0 < 0)
167  y0_2 -= 1;
168 
169  int y1_2 = y1 / 2;
170  if (y1 < 0)
171  y1_2 -= 1;
172 
173  int a = std::abs(x1 - x0 - y1_2 + y0_2);
174  int b = std::abs(y1 - y0);
175  int c = std::abs(x1 + y1 - y1_2 - x0 - y0 + y0_2);
176 
177  return std::max({a, b, c});
178  }
179 
180 private:
191  void
192  calcVertex_(
193  int& p1, int& p2, int& q1, int& q2, int& q3, int &q4,
194  double p, double q)
195  {
196  // 頂點の座標: なほ、(p, q)は中心の座標
197  //
198  // (p, q1)
199  // (p1, q2) (p2, q2)
200  // (p, q)
201  // (p1, q3) (p2, q3)
202  // (p, q4)
203  //double p, q;
204  p1 = p - SQRT3_ * r_ / 2.0;
205  p2 = p + SQRT3_ * r_ / 2.0;
206 
207  q1 = q - r_;
208  q2 = q - r_ / 2.0;
209  q3 = q + r_ / 2.0;
210  q4 = q + r_;
211  }
212 
214  void fillLeftHalf_(
215  polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col);
217  void fillRightHalf_(
218  polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col);
219 };
220 
221 
222 
223 
224 //============================
225 template<class C_>
226 inline
227 void
229  polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col)
230 {
231  double p, q;
232  getPixelPosition(p, q, x, y);
233 
234  int p1, p2;
235  int q1, q2, q3, q4;
236  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
237 
238  // 座標を求めた後は直線を引く
240  pict->line(p1, q2, p, q1, col);
241  pict->line(p1, q2, p1, q3, col);
242  pict->line(p1, q3, p, q4, col);
244  pict->line(p2, q2, p, q1, col);
245  pict->line(p2, q2, p2, q3, col);
246  pict->line(p2, q3, p, q4, col);
247 }
248 
249 
250 //============================
251 template<class C_>
252 inline
253 void
255  polymnia::ImageBuffer<C_>* pict, int x, int y, int w, int h, const C_& col)
256 {
257  double p, q;
258  int p1, p2, q1, q2, q3, q4;
259 
260  for (int j = 0; j < h; j++) {
261 
262  // 左端のみ必要な描畫
263  if ((y + j) % 2 == 0) {
264  getPixelPosition(p, q, x, y + j);
265  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
266  pict->line(p1, q3, p, q4, col); // 左下斜め
267  }
268 
269  // いつも必要な描畫
270  for (int i = 0; i < w; i++) {
271  getPixelPosition(p, q, x + i, y + j);
272  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
273 
274  pict->line(p1, q2, p, q1, col); //左上斜め
275  pict->line(p1, q2, p1, q3, col); //左端
276  pict->line(p2, q2, p, q1, col); //右上斜め
277  }
278 
279  // 右端のみ必要な描畫
280  getPixelPosition(p, q, x + w - 1, y + j);
281  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
282  pict->line(p2, q2, p2, q3, col); // 右端
283  if ((y + j) % 2 == 1) {
284  pict->line(p2, q3, p, q4, col); // 右下斜め
285  }
286  }
287 
288  // 下端で必要な描畫
289  for (int i = 0; i < w; i++) {
290  getPixelPosition(p, q, x + i, y + h - 1);
291  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
292  pict->line(p1, q3, p, q4, col); // 左下斜め
293  pict->line(p2, q3, p, q4, col); // 右下斜め
294  }
295 }
296 
297 
298 //============================
299 template<class C_>
300 inline
301 void
303  polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col)
304 {
305  fillLeftHalf_(pict, x, y, col);
306  fillRightHalf_(pict, x, y, col);
307 }
308 
309 template<class C_>
310 inline
311 void
313  polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col)
314 {
315  // 頂點の座標の算出
316  double p, q;
317  getPixelPosition(p, q, x, y);
318  int p1, p2;
319  int q1, q2, q3, q4;
320  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
321 
322  // 塗り潰し
323  int dp = (int)p - p1;
324  int dq1 = q2 - q1;
325  int dq2 = q4 - q3;
326 
327  int pp1 = p1;
328  int pp2 = p;
329  int qq1 = q2;
330  int qq2 = q1;
331  int qq3 = q3;
332  int qq4 = q4;
333 
334  int e1 = -dp;
335  int e2 = -dp;
336  int lx = (dp + 1) / 2;
337  for (int i = 0; i < lx; i++) {
338  pict->line(pp1, qq1, pp1, qq3, col);
339  pict->line(pp2, qq2, pp2, qq4, col);
340 
341  pp1++;
342  pp2--;
343 
344  e1 += 2 * dq1;
345  if (e1 >= 0) {
346  qq1--;
347  qq2++;
348  e1 -= 2 * dp;
349  }
350  e2 += 2 * dq2;
351  if (e2 >= 0) {
352  qq3++;
353  qq4--;
354  e2 -= 2 * dp;
355  }
356  }
357  if (!(dp % 2))
358  pict->line(pp1, qq1, pp1, qq3, col);
359 }
360 
361 template<class C_>
362 inline
363 void
365  polymnia::ImageBuffer<C_>* pict, int x, int y, const C_& col)
366 {
367  // 頂點の座標の算出
368  double p, q;
369  getPixelPosition(p, q, x, y);
370  int p1, p2;
371  int q1, q2, q3, q4;
372  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
373 
374  // 塗り潰し
375  int dp = p2 - (int)p;
376  int dq1 = q2 - q1;
377  int dq2 = q4 - q3;
378  int pp1 = p;
379  int pp2 = p2;
380  int qq1 = q1;
381  int qq2 = q2;
382  int qq3 = q4;
383  int qq4 = q3;
384 
385  int e1 = -dp;
386  int e2 = -dp;
387  int lx = (dp + 1) / 2;
388  for (int i = 0; i < lx; i++) {
389  pict->line(pp1, qq1, pp1, qq3, col);
390  pict->line(pp2, qq2, pp2, qq4, col);
391 
392  pp1++;
393  pp2--;
394 
395  e1 += 2 * dq1;
396  if (e1 >= 0) {
397  qq1++;
398  qq2--;
399  e1 -= 2 * dp;
400  }
401  e2 += 2 * dq2;
402  if (e2 >= 0) {
403  qq3--;
404  qq4++;
405  e2 -= 2 * dp;
406  }
407  }
408  if (!(dp % 2))
409  pict->line(pp1, qq1, pp1, qq3, col);
410 }
411 
412 
413 //============================
414 template<class C_>
415 inline
416 void
418  polymnia::ImageBuffer<C_>* pict, int x, int y, int w, int h, const C_& col)
419 {
420  // 使ひ廻す變數
421  double p, q;
422  int p1, p2;
423  int q1, q2, q3, q4;
424 
425 
426  // 中央の「箱」の塗り潰し
427  int pbox0, qbox0, pbox1, qbox1;
428  if (y % 2 == 0) {
429  getPixelPosition(p, q, x, y);
430  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
431  pbox0 = p;
432  qbox0 = q2;
433 
434  getPixelPosition(p, q, x + w - 1, y);
435  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
436  pbox1 = p2;
437 
438  getPixelPosition(p, q, x + w - 1, y + h - 1);
439  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
440  qbox1 = q3;
441  } else {
442  getPixelPosition(p, q, x, y);
443  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
444  pbox0 = p1;
445  qbox0 = q2;
446 
447  getPixelPosition(p, q, x + w - 1, y);
448  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
449  pbox1 = p;
450 
451  getPixelPosition(p, q, x + w - 1, y + h - 1);
452  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
453  qbox1 = q3;
454  }
455  pict->box(pbox0, qbox0, pbox1, qbox1, col, true);
456 
457  // 左端の塗り潰し
458  for (int j = 0; j < h; j++) {
459  if ((y + j) % 2 == 0) {
460  fillLeftHalf_(pict, x, y + j, col);
461  }
462  }
463 
464  // 右端の塗り潰し
465  for (int j = 0; j < h; j++) {
466  if ((y + j) % 2 != 0) {
467  fillRightHalf_(pict, x + w - 1, y + j, col);
468  }
469  }
470 
471  for (int i = 0; i < w; i++) {
472  int dp, dq; //dq1, dq2;
473  int pp1, pp2, qq1, qq2; //, qq3, qq4;
474  int e, lx;
475 
476  // 上端三角形の塗り潰し
477  getPixelPosition(p, q, x + i, y);
478  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
479 
481  dp = (int)p - p1;
482  dq = q2 - q1;
483 
484  pp1 = p1;
485  pp2 = p;
486  qq1 = q2;
487  qq2 = q1;
488 
489  e = -dp;
490  lx = (dp + 1) / 2;
491  for (int i = 0; i < lx; i++) {
492  pict->line(pp1, qq1, pp1, q2, col);
493  pict->line(pp2, qq2, pp2, q2, col);
494 
495  pp1++;
496  pp2--;
497  e += 2 * dq;
498  if (e >= 0) {
499  qq1--;
500  qq2++;
501  e -= 2 * dp;
502  }
503  }
504  if (!(dp % 2))
505  pict->line(pp1, qq1, pp1, q2, col);
506 
508  dp = p2 - (int)p;
510  pp1 = p;
511  pp2 = p2;
512  qq1 = q1;
513  qq2 = q2;
514 
515  e = -dp;
516  lx = (dp + 1) / 2;
517  for (int i = 0; i < lx; i++) {
518  pict->line(pp1, qq1, pp1, q2, col);
519  pict->line(pp2, qq2, pp2, q2, col);
520 
521  pp1++;
522  pp2--;
523 
524  e += 2 * dq;
525  if (e >= 0) {
526  qq1++;
527  qq2--;
528  e -= 2 * dp;
529  }
530  }
531  if (!(dp % 2))
532  pict->line(pp1, qq1, pp1, q2, col);
533 
534 
535  // 下端三角形の塗り潰し
536  getPixelPosition(p, q, x + i, y + h - 1);
537  calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
538 
540  dp = (int)p - p1;
541  dq = q4 - q3;
542 
543  pp1 = p1;
544  pp2 = p;
545  qq1 = q3;
546  qq2 = q4;
547 
548  e = -dp;
549  lx = (dp + 1) / 2;
550  for (int i = 0; i < lx; i++) {
551  pict->line(pp1, q3, pp1, qq1, col);
552  pict->line(pp2, q3, pp2, qq2, col);
553 
554  pp1++;
555  pp2--;
556 
557  e += 2 * dq;
558  if (e >= 0) {
559  qq1++;
560  qq2--;
561  e -= 2 * dp;
562  }
563  }
564  if (!(dp % 2))
565  pict->line(pp1, q3, pp1, qq1, col);
566 
568  dp = p2 - (int)p;
570  pp1 = p;
571  pp2 = p2;
572  qq1 = q4;
573  qq2 = q3;
574 
575  e = -dp;
576  lx = (dp + 1) / 2;
577  for (int i = 0; i < lx; i++) {
578  pict->line(pp1, q3, pp1, qq1, col);
579  pict->line(pp2, q3, pp2, qq2, col);
580 
581  pp1++;
582  pp2--;
583 
584  e += 2 * dq;
585  if (e >= 0) {
586  qq1--;
587  qq2++;
588  e -= 2 * dp;
589  }
590  }
591  if (!(dp % 2))
592  pict->line(pp1, q3, pp1, qq1, col);
593 
594  }//end of for
595 }
596 
597 
598 
599 
600 //============================
601 template<class C_>
602 inline
603 void
604 polymnia::HexPainter<C_>::getHexPosition(int& x, int& y, int p, int q)
605 {
606  // []はHEX ()はピクセル
607  // 長方形を五つのHEX(の全部または一部)に分割する。
608  // 長方形左上を(0, 0)とし、差分(dp, dq)を求めて判定する。
609  //
610  // [x0, y0] (√3*R, 0) [x0+1, y0]
611  // (√3*R, R/2)
612  // (0, R) (2*√3*R, R)
613  // [x0, y0+1]
614  // (0, 2*R) (2*√3*R, 2*R)
615  // (√3*R, 5*R/2)
616  // [x0, y0+2] (√3*R, 3*R) [x0+1, y0+2]
617 
618  int qq = q - q0_;
619  int y0 = std::floor(qq / 3.0 / r_) * 2;
620  double dq = qq - (y0 / 2) * 3 * r_;
621 
622  int pp = p - p0_;
623  int x0 = std::floor(pp * SQRT3_ / 3.0 / r_);
624  double dp = pp - x0 * SQRT3_ * r_;
625 
626  double u = -1 * dp * SQRT3_ / 3;
627  double v = dp * SQRT3_ / 3;
628 
629  if ((dq < u + r_) || (dq < v)) {
630  if (dp < SQRT3_ * r_ / 2) {
631  x = x0;
632  } else {
633  x = x0 + 1;
634  }
635  y = y0;
636  }
637  else if ((dq >= u + 3 * r_) || (dq >= v + 2 * r_)) {
638  if (dp < SQRT3_ * r_ / 2) {
639  x = x0;
640  } else {
641  x = x0 + 1;
642  }
643  y = y0 + 2;
644  }
645  else {
646  x = x0;
647  y = y0 + 1;
648  }
649 }
650 
651 
652 
653 
654 #endif // INC_POLYMNIA_HEX_H__
HexPainter(int r, int p0, int q0)
構築子
Definition: hex.h:46
Definition: dibio.h:20
畫像バッファのクラステンプレート
void getOrigin(int &p, int &q) const
原點の取得
Definition: hex.h:70
void fill(polymnia::ImageBuffer< C_ > *pict, int x, int y, const C_ &col)
HEXの塗り潰し
Definition: hex.h:302
void draw(polymnia::ImageBuffer< C_ > *pict, int x, int y, const C_ &col)
HEX外周の描畫
Definition: hex.h:228
int distance(int x0, int y0, int x1, int y1)
距離の取得
Definition: hex.h:163
void resetRadius(int r)
HEXの大きさの再設定
Definition: hex.h:63
void getPixelPosition(double &p, double &q, int x, int y)
ピクセル位置の取得
Definition: hex.h:154
void line(int x1, int y1, int x2, int y2, const C_ &col)
直線を描畫
Definition: ibuf-imp_.h:222
正六角形マス描畫クラス
Definition: hex.h:18
void getHexPosition(int &x, int &y, int p, int q)
HEX位置の取得
Definition: hex.h:604
void box(int x1, int y1, int x2, int y2, const C_ &col, bool fl=false)
長方形を描畫
Definition: ibuf-imp_.h:353
int getRadius() const
HEXの大きさの取得
Definition: hex.h:79
void getPixelPosition(int &p, int &q, int x, int y)
ピクセル座標の取得
Definition: hex.h:141
畫像バッファ基底クラステンプレート
Definition: ibuf.h:23
void resetOrigin(int p0, int q0)
原點の再設定
Definition: hex.h:53