動作環境
C++ Builder XE4
関連 C++ Builder / TCanvas > 円をセクターに分割して、グラデーションを塗る実装
関連 C++ Builder / 4色の合成 > 組合せリストの取得
関連 color > link > 4色のサンプル
4色の組合せ15パターン(全て0は除く)に関して、円のセクターとして描画してみる。
Pen->Width=1の時は、fillSector()にて隣のセクターまで塗るバグがあったため、Pen->Width=2にした。
Unit1.h
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TButton *Button1;
TImage *Image1;
void __fastcall Button1Click(TObject *Sender);
private: // ユーザー宣言
// { combination関連
int m_comb_pos;
std::vector<int> m_comb_people;
std::vector<int> m_comb_combination;
void __fastcall comb_setResult(const std::vector<int>& res);
void __fastcall comb_go(int offset, int left);
// } combination関連
//
void __fastcall prepareCombinationList(void);
//
void __fastcall drawRadialLine(double angle_deg);
void __fastcall fillSector(int index, double angle_deg, double width_deg);
void __fastcall drawOnImage(void);
TColor __fastcall getRgbColor(int index);
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <iostream>
#include <vector>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
/*
[get combination list]
original at
http://stackoverflow.com/questions/12991758/creating-all-possible-k-combinations-of-n-items-in-c
then modified
*/
static const int kNumMember = 4;
static const int kMaxList = 50;
static bool s_colorList[kMaxList][kNumMember] = { 0 }; // 4 colors
void __fastcall TForm1::comb_setResult(const std::vector<int>& res)
{
String msg;
for(int idx=0; idx < res.size(); idx++) {
s_colorList[m_comb_pos][res[idx]] = true;
}
m_comb_pos++;
}
void __fastcall TForm1::comb_go(int offset, int left)
{
if (left == 0) {
comb_setResult(m_comb_combination);
return;
}
for (int idx = offset; idx <= m_comb_people.size() - left; idx++) {
m_comb_combination.push_back(m_comb_people[idx]);
comb_go(idx+1, left-1);
m_comb_combination.pop_back();
}
}
void __fastcall TForm1::prepareCombinationList(void)
{
for(int idx=0; idx < kNumMember ; idx++) {
m_comb_people.push_back(idx); // starting from [0]
}
m_comb_pos = 0;
comb_go(0, 1); // k==1
comb_go(0, 2); // k==2
comb_go(0, 3); // k==3
comb_go(0, 4); // k==4
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
prepareCombinationList();
// for debug
for(int lidx=0; lidx < m_comb_pos; lidx++) { // lidx: list index
String msg = IntToStr(lidx) + L":";
for(int midx=0; midx < kNumMember; midx++) { // midx: member index
msg = msg + L" " + IntToStr((int)s_colorList[lidx][midx]);
}
OutputDebugString(msg.c_str());
}
//
drawOnImage();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::drawRadialLine(double angle_deg)
{
TRect R = Image1->ClientRect;
double radius = (R.right - R.left) / 2;
int center_x = (R.left + R.right) / 2;
int center_y = (R.top + R.bottom) / 2;
// for Pen->Width==1, fillSector() may fill adjacent sectors by mistake
Image1->Canvas->Pen->Width = 2;
Image1->Canvas->MoveTo(center_x, center_y);
int to_x = radius * Cos(angle_deg * M_PI / 180.0);
int to_y = radius * Sin(angle_deg * M_PI / 180.0);
to_x += center_x;
to_y += center_y;
Image1->Canvas->LineTo(to_x, to_y);
}
// Jupiter color
// @ http://colorhunt.co/blog/solar-system-stars-color-palettes/
//static const int baseColors[][3] = {
// { 0xE0, 0xCD, 0xAD }, // R, G, B
// { 0xC1, 0xB4, 0x94 }, // R, G, B
// { 0xA8, 0x8B, 0x6D }, // R, G, B
// { 0x67, 0x59, 0x4C }, // R, G, B
//};
// Earth color
// @ http://colorhunt.co/blog/solar-system-stars-color-palettes/
static const int baseColors[][3] = {
{ 0xEA, 0xEA, 0xEA }, // R, G, B
{ 0xCE, 0xAB, 0x4E }, // R, G, B
{ 0x41, 0x7B, 0x38 }, // R, G, B
{ 0x18, 0x2A, 0x61 }, // R, G, B
};
// RGB color
//static const int baseColors[][3] = {
// { 0xFF, 0x00, 0x00 }, // R, G, B
// { 0x00, 0xFF, 0x00 }, // R, G, B
// { 0x00, 0x00, 0xFF }, // R, G, B
// { 0x00, 0x00, 0x00 }, // R, G, B
//};
TColor __fastcall TForm1::getRgbColor(int index)
{
int clrs[kNumMember] = { 0 };
int numColor = 0;
for(int midx = 0; midx < kNumMember; midx++) { // midx: member index
if (s_colorList[index][midx]) {
for (int rgbidx=0; rgbidx < 3; rgbidx++) { // R,G,B
clrs[rgbidx] += baseColors[midx][rgbidx];
}
numColor++;
}
}
if (numColor > 0) {
for(int midx = 0; midx < kNumMember; midx++) {
clrs[midx] = clrs[midx] / numColor;
}
}
int R = clrs[0];
int G = clrs[1];
int B = clrs[2];
return RGB(R, G, B);
}
void __fastcall TForm1::fillSector(int index, double angle_deg, double width_deg)
{
TRect R = Image1->ClientRect;
double radius = (R.right - R.left) / 2;
radius = 0.7 * radius; // to get inside the sector (0.7: arbitrary)
double wrk_ang = angle_deg + width_deg / 2.0; // to get inside the sector
int center_x = (R.left + R.right) / 2;
int center_y = (R.top + R.bottom) / 2;
int pt_x = radius * Cos(wrk_ang * M_PI / 180.0);
int pt_y = radius * Sin(wrk_ang * M_PI / 180.0);
pt_x += center_x;
pt_y += center_y;
Image1->Canvas->Brush->Color = getRgbColor(index);
Image1->Canvas->FloodFill(pt_x, pt_y, clBlack, fsBorder);
// String msg = IntToStr(pt_x) + L"-" + IntToStr(pt_y) + L": " + FloatToStr(angle_deg);
// OutputDebugString(msg.c_str());
}
void __fastcall TForm1::drawOnImage(void)
{
// 1. draw circle
TRect R = Image1->ClientRect;
// X1, Y1 X2 Y2
Image1->Canvas->Ellipse(R.left, R.top, R.right, R.bottom);
// 2. draw line in radial direction
static const int kNumAngles = 20;
for(int idx=0; idx < kNumAngles; idx++) {
double ang_deg = (360.0 / (double)kNumAngles) * idx;
drawRadialLine(ang_deg);
}
// 3.. fill the sectors
for(int idx=0; idx < kNumAngles; idx++) {
double ang_deg = (360.0 / (double)kNumAngles) * idx;
fillSector(idx, ang_deg, /* width_deg=*/(360.0 / kNumAngles));
// debug
//Sleep(1000);
//Application->ProcessMessages();
}
}