LIBEUNOMIA
読み取り中…
検索中…
一致する文字列を見つけられません
hexpainter.h
[詳解]
1/*
2 * Copyright 2016-2021 oZ/acy (名賀月晃嗣)
3 * Redistribution and use in source and binary forms,
4 * with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
37#ifndef INCLUDE_GUARD_EUNOMIA_HEX_PAINTER_H
38#define INCLUDE_GUARD_EUNOMIA_HEX_PAINTER_H
39
40#include <algorithm>
41#include <cmath>
42#include <cstdlib>
43#include "imagebuffer.h"
44
45namespace eunomia
46{
57template<class C_>
59{
60private:
61 int r_;
62 int p0_;
63 int q0_;
64
65 static inline const double SQRT3_ = std::sqrt(3);
66
67public:
74 HexPainter(int r, int p0, int q0) noexcept : r_(r), p0_(p0), q0_(q0) {}
75
81 void resetOrigin(int p0, int q0) noexcept
82 {
83 p0_ = p0;
84 q0_ = q0;
85 }
86
91 void resetRadius(int r) noexcept { r_ = r; }
92
98 void getOrigin(int& p, int& q) const noexcept
99 {
100 p = p0_;
101 q = q0_;
102 }
103
107 int getRadius() const noexcept { return r_; }
108
116 void draw(ImageBuffer<C_>& pict, int x, int y, const C_& color);
117
127 void draw(ImageBuffer<C_>& pict, int x, int y, int w, int h, const C_& color);
128
136 void fill(ImageBuffer<C_>& pict, int x, int y, const C_& color);
137
147 void fill(ImageBuffer<C_>& pict, int x, int y, int w, int h, const C_& color);
148
156 void getHexPosition(int p, int q, int& x, int& y);
157
165 void getPixelPosition(int x, int y, int& p, int& q)
166 {
167 p = SQRT3_ * r_ * (x + 0.5 * (y % 2)) + p0_;
168 q = (3.0 * y * r_) / 2.0 + q0_;
169 }
170
178 void getPixelPosition(int x, int y, double& p, double& q)
179 {
180 p = SQRT3_ * r_ * (x + 0.5 * (y % 2)) + p0_;
181 q = (3.0 * y * r_) / 2.0 + q0_;
182 }
183
187 int distance(int x0, int y0, int x1, int y1)
188 {
189 int y0_2 = y0 / 2;
190 if (y0 < 0)
191 y0_2 -= 1;
192
193 int y1_2 = y1 / 2;
194 if (y1 < 0)
195 y1_2 -= 1;
196
197 int a = std::abs(x1 - x0 - y1_2 + y0_2);
198 int b = std::abs(y1 - y0);
199 int c = std::abs(x1 + y1 - y1_2 - x0 - y0 + y0_2);
200
201 return std::max({a, b, c});
202 }
203
204private:
215 void
216 calcVertex_(
217 int& p1, int& p2, int& q1, int& q2, int& q3, int &q4,
218 double p, double q)
219 {
220 // 頂點の座標: なほ、(p, q)は中心の座標
221 //
222 // (p, q1)
223 // (p1, q2) (p2, q2)
224 // (p, q)
225 // (p1, q3) (p2, q3)
226 // (p, q4)
227 //double p, q;
228 p1 = p - SQRT3_ * r_ / 2.0;
229 p2 = p + SQRT3_ * r_ / 2.0;
230
231 q1 = q - r_;
232 q2 = q - r_ / 2.0;
233 q3 = q + r_ / 2.0;
234 q4 = q + r_;
235 }
236
238 void fillLeftHalf_(ImageBuffer<C_>& pict, int x, int y, const C_& color);
240 void fillRightHalf_(ImageBuffer<C_>& pict, int x, int y, const C_& color);
241};
242
243
244
245
246template<class C_>
247inline
248void
250{
251 double p, q;
252 getPixelPosition(x, y, p, q);
253
254 int p1, p2;
255 int q1, q2, q3, q4;
256 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
257
258 // 座標を求めた後は直線を引く
260 pict.line(p1, q2, p, q1, color);
261 pict.line(p1, q2, p1, q3, color);
262 pict.line(p1, q3, p, q4, color);
264 pict.line(p2, q2, p, q1, color);
265 pict.line(p2, q2, p2, q3, color);
266 pict.line(p2, q3, p, q4, color);
267}
268
269
270template<class C_>
271inline
272void
274 ImageBuffer<C_>& pict, int x, int y, int w, int h, const C_& color)
275{
276 double p, q;
277 int p1, p2, q1, q2, q3, q4;
278
279 for (int j = 0; j < h; j++) {
280
281 // 左端のみ必要な描畫
282 if ((y + j) % 2 == 0) {
283 getPixelPosition(x, y + j, p, q);
284 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
285 pict.line(p1, q3, p, q4, color); // 左下斜め
286 }
287
288 // いつも必要な描畫
289 for (int i = 0; i < w; i++) {
290 getPixelPosition(x + i, y + j, p, q);
291 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
292
293 pict.line(p1, q2, p, q1, color); //左上斜め
294 pict.line(p1, q2, p1, q3, color); //左端
295 pict.line(p2, q2, p, q1, color); //右上斜め
296 }
297
298 // 右端のみ必要な描畫
299 getPixelPosition(x + w - 1, y + j, p, q);
300 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
301 pict.line(p2, q2, p2, q3, color); // 右端
302 if ((y + j) % 2 == 1) {
303 pict.line(p2, q3, p, q4, color); // 右下斜め
304 }
305 }
306
307 // 下端で必要な描畫
308 for (int i = 0; i < w; i++) {
309 getPixelPosition(x + i, y + h - 1, p, q);
310 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
311 pict.line(p1, q3, p, q4, color); // 左下斜め
312 pict.line(p2, q3, p, q4, color); // 右下斜め
313 }
314}
315
316
317template<class C_>
318inline
319void
321{
322 fillLeftHalf_(pict, x, y, color);
323 fillRightHalf_(pict, x, y, color);
324}
325
326template<class C_>
327inline
328void
330 ImageBuffer<C_>& pict, int x, int y, const C_& color)
331{
332 // 頂點の座標の算出
333 double p, q;
334 getPixelPosition(x, y, p, q);
335 int p1, p2;
336 int q1, q2, q3, q4;
337 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
338
339 // 塗り潰し
340 int dp = (int)p - p1;
341 int dq1 = q2 - q1;
342 int dq2 = q4 - q3;
343
344 int pp1 = p1;
345 int pp2 = p;
346 int qq1 = q2;
347 int qq2 = q1;
348 int qq3 = q3;
349 int qq4 = q4;
350
351 int e1 = -dp;
352 int e2 = -dp;
353 int lx = (dp + 1) / 2;
354 for (int i = 0; i < lx; i++) {
355 pict.line(pp1, qq1, pp1, qq3, color);
356 pict.line(pp2, qq2, pp2, qq4, color);
357
358 pp1++;
359 pp2--;
360
361 e1 += 2 * dq1;
362 if (e1 >= 0) {
363 qq1--;
364 qq2++;
365 e1 -= 2 * dp;
366 }
367 e2 += 2 * dq2;
368 if (e2 >= 0) {
369 qq3++;
370 qq4--;
371 e2 -= 2 * dp;
372 }
373 }
374 if (!(dp % 2))
375 pict.line(pp1, qq1, pp1, qq3, color);
376}
377
378template<class C_>
379inline
380void
381HexPainter<C_>::fillRightHalf_(
382 ImageBuffer<C_>& pict, int x, int y, const C_& color)
383{
384 // 頂點の座標の算出
385 double p, q;
386 getPixelPosition(x, y, p, q);
387 int p1, p2;
388 int q1, q2, q3, q4;
389 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
390
391 // 塗り潰し
392 int dp = p2 - (int)p;
393 int dq1 = q2 - q1;
394 int dq2 = q4 - q3;
395 int pp1 = p;
396 int pp2 = p2;
397 int qq1 = q1;
398 int qq2 = q2;
399 int qq3 = q4;
400 int qq4 = q3;
401
402 int e1 = -dp;
403 int e2 = -dp;
404 int lx = (dp + 1) / 2;
405 for (int i = 0; i < lx; i++) {
406 pict.line(pp1, qq1, pp1, qq3, color);
407 pict.line(pp2, qq2, pp2, qq4, color);
408
409 pp1++;
410 pp2--;
411
412 e1 += 2 * dq1;
413 if (e1 >= 0) {
414 qq1++;
415 qq2--;
416 e1 -= 2 * dp;
417 }
418 e2 += 2 * dq2;
419 if (e2 >= 0) {
420 qq3--;
421 qq4++;
422 e2 -= 2 * dp;
423 }
424 }
425 if (!(dp % 2))
426 pict.line(pp1, qq1, pp1, qq3, color);
427}
428
429
430template<class C_>
431inline
432void
434 ImageBuffer<C_>& pict, int x, int y, int w, int h, const C_& color)
435{
436 // 使ひ廻す變數
437 double p, q;
438 int p1, p2;
439 int q1, q2, q3, q4;
440
441 // 中央の「箱」の塗り潰し
442 int pbox0, qbox0, pbox1, qbox1;
443 if (y % 2 == 0) {
444 getPixelPosition(x, y, p, q);
445 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
446 pbox0 = p;
447 qbox0 = q2;
448
449 getPixelPosition(x + w - 1, y, p, q);
450 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
451 pbox1 = p2;
452
453 getPixelPosition(x + w - 1, y + h - 1, p, q);
454 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
455 qbox1 = q3;
456 } else {
457 getPixelPosition(x, y, p, q);
458 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
459 pbox0 = p1;
460 qbox0 = q2;
461
462 getPixelPosition(x + w - 1, y, p, q);
463 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
464 pbox1 = p;
465
466 getPixelPosition(x + w - 1, y + h - 1, p, q);
467 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
468 qbox1 = q3;
469 }
470 pict.box(pbox0, qbox0, pbox1, qbox1, color, true);
471
472 // 左端の塗り潰し
473 for (int j = 0; j < h; j++) {
474 if ((y + j) % 2 == 0) {
475 fillLeftHalf_(pict, x, y + j, color);
476 }
477 }
478
479 // 右端の塗り潰し
480 for (int j = 0; j < h; j++) {
481 if ((y + j) % 2 != 0) {
482 fillRightHalf_(pict, x + w - 1, y + j, color);
483 }
484 }
485
486 for (int i = 0; i < w; i++) {
487 int dp, dq; //dq1, dq2;
488 int pp1, pp2, qq1, qq2; //, qq3, qq4;
489 int e, lx;
490
491 // 上端三角形の塗り潰し
492 getPixelPosition(x + i, y, p, q);
493 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
494
496 dp = (int)p - p1;
497 dq = q2 - q1;
498
499 pp1 = p1;
500 pp2 = p;
501 qq1 = q2;
502 qq2 = q1;
503
504 e = -dp;
505 lx = (dp + 1) / 2;
506 for (int i = 0; i < lx; i++) {
507 pict.line(pp1, qq1, pp1, q2, color);
508 pict.line(pp2, qq2, pp2, q2, color);
509
510 pp1++;
511 pp2--;
512 e += 2 * dq;
513 if (e >= 0) {
514 qq1--;
515 qq2++;
516 e -= 2 * dp;
517 }
518 }
519 if (!(dp % 2))
520 pict.line(pp1, qq1, pp1, q2, color);
521
523 dp = p2 - (int)p;
525 pp1 = p;
526 pp2 = p2;
527 qq1 = q1;
528 qq2 = q2;
529
530 e = -dp;
531 lx = (dp + 1) / 2;
532 for (int i = 0; i < lx; i++) {
533 pict.line(pp1, qq1, pp1, q2, color);
534 pict.line(pp2, qq2, pp2, q2, color);
535
536 pp1++;
537 pp2--;
538
539 e += 2 * dq;
540 if (e >= 0) {
541 qq1++;
542 qq2--;
543 e -= 2 * dp;
544 }
545 }
546 if (!(dp % 2))
547 pict.line(pp1, qq1, pp1, q2, color);
548
549
550 // 下端三角形の塗り潰し
551 getPixelPosition(x + i, y + h - 1, p, q);
552 calcVertex_(p1, p2, q1, q2, q3, q4, p, q);
553
555 dp = (int)p - p1;
556 dq = q4 - q3;
557
558 pp1 = p1;
559 pp2 = p;
560 qq1 = q3;
561 qq2 = q4;
562
563 e = -dp;
564 lx = (dp + 1) / 2;
565 for (int i = 0; i < lx; i++) {
566 pict.line(pp1, q3, pp1, qq1, color);
567 pict.line(pp2, q3, pp2, qq2, color);
568
569 pp1++;
570 pp2--;
571
572 e += 2 * dq;
573 if (e >= 0) {
574 qq1++;
575 qq2--;
576 e -= 2 * dp;
577 }
578 }
579 if (!(dp % 2))
580 pict.line(pp1, q3, pp1, qq1, color);
581
583 dp = p2 - (int)p;
585 pp1 = p;
586 pp2 = p2;
587 qq1 = q4;
588 qq2 = q3;
589
590 e = -dp;
591 lx = (dp + 1) / 2;
592 for (int i = 0; i < lx; i++) {
593 pict.line(pp1, q3, pp1, qq1, color);
594 pict.line(pp2, q3, pp2, qq2, color);
595
596 pp1++;
597 pp2--;
598
599 e += 2 * dq;
600 if (e >= 0) {
601 qq1--;
602 qq2++;
603 e -= 2 * dp;
604 }
605 }
606 if (!(dp % 2))
607 pict.line(pp1, q3, pp1, qq1, color);
608
609 }//end of for
610}
611
612
613
614
615template<class C_>
616inline
617void
618HexPainter<C_>::getHexPosition(int p, int q, int& x, int& y)
619{
620 // []はHEX ()はピクセル
621 // 長方形を五つのHEX(の全部または一部)に分割する。
622 // 長方形左上を(0, 0)とし、差分(dp, dq)を求めて判定する。
623 //
624 // [x0, y0] (√3*R, 0) [x0+1, y0]
625 // (√3*R, R/2)
626 // (0, R) (2*√3*R, R)
627 // [x0, y0+1]
628 // (0, 2*R) (2*√3*R, 2*R)
629 // (√3*R, 5*R/2)
630 // [x0, y0+2] (√3*R, 3*R) [x0+1, y0+2]
631
632 int qq = q - q0_;
633 int y0 = std::floor(qq / 3.0 / r_) * 2;
634 double dq = qq - (y0 / 2) * 3 * r_;
635
636 int pp = p - p0_;
637 int x0 = std::floor(pp * SQRT3_ / 3.0 / r_);
638 double dp = pp - x0 * SQRT3_ * r_;
639
640 double u = -1 * dp * SQRT3_ / 3;
641 double v = dp * SQRT3_ / 3;
642
643 if ((dq < u + r_) || (dq < v)) {
644 if (dp < SQRT3_ * r_ / 2) {
645 x = x0;
646 } else {
647 x = x0 + 1;
648 }
649 y = y0;
650 }
651 else if ((dq >= u + 3 * r_) || (dq >= v + 2 * r_)) {
652 if (dp < SQRT3_ * r_ / 2) {
653 x = x0;
654 } else {
655 x = x0 + 1;
656 }
657 y = y0 + 2;
658 }
659 else {
660 x = x0;
661 y = y0 + 1;
662 }
663}
664
665
666}// end of namespace eunomia
667
668
669
670
671#endif // INCLUDE_GUARD_EUNOMIA_HEX_PAINTER_H
正六角形マス描畫クラス
Definition hexpainter.h:59
void getPixelPosition(int x, int y, int &p, int &q)
ピクセル座標の取得
Definition hexpainter.h:165
void fill(ImageBuffer< C_ > &pict, int x, int y, const C_ &color)
HEXの塗り潰し
Definition hexpainter.h:320
int getRadius() const noexcept
HEXの大きさの取得
Definition hexpainter.h:107
int distance(int x0, int y0, int x1, int y1)
距離の取得
Definition hexpainter.h:187
void getPixelPosition(int x, int y, double &p, double &q)
ピクセル位置の取得
Definition hexpainter.h:178
void getOrigin(int &p, int &q) const noexcept
原點の取得
Definition hexpainter.h:98
void resetOrigin(int p0, int q0) noexcept
原點の再設定
Definition hexpainter.h:81
void resetRadius(int r) noexcept
HEXの大きさの再設定
Definition hexpainter.h:91
void getHexPosition(int p, int q, int &x, int &y)
HEX位置の取得
Definition hexpainter.h:618
void draw(ImageBuffer< C_ > &pict, int x, int y, const C_ &color)
HEX外周の描畫
Definition hexpainter.h:249
HexPainter(int r, int p0, int q0) noexcept
構築子
Definition hexpainter.h:74
畫像バッファ基底クラステンプレート
Definition imagebuffer.h:84
ImageBuffer(int w, int h, int p) noexcept
構築子
Definition imagebuffer.h:101
void line(int x1, int y1, int x2, int y2, const C_ &color)
線分の描畫
Definition ibuf_draw.h:60
void box(int left, int top, int right, int bottom, const C_ &color, bool fill=false)
長方形の描畫
Definition ibuf_draw.h:200
畫像バッファクラステンプレート
Definition colour.h:49