C++ builder / TCanvas > 4色合成して均等に分割した円のセクターとして描画する実装

```txt:動作環境
C++ Builder XE4
```

関連 [C++ Builder / TCanvas > 円をセクターに分割して、グラデーションを塗る実装](http://qiita.com/7of9/items/8965e19a4e33f9c987b4)
関連 [C++ Builder / 4色の合成 > 組合せリストの取得](http://qiita.com/7of9/items/64cddfd7605e6f2dcdd8)
関連 [color > link > 4色のサンプル](http://qiita.com/7of9/items/1b6a137f4e93ec663a0a)

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();
    }
}
```

### Jupiter color

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/75b51797-6e3c-a753-6e90-85b4ef314ebc.png)


### Earth color

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/7d6fa502-5f2b-e97a-7eb6-2d2174f4e105.png)

### Microsoft color

http://colorhunt.co/blog/google-microsoft-brand-colors/

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/2c784a4d-af19-049d-dab1-fdea300ad4c6.png)