LoginSignup
0
1

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-03-28
動作環境
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();
    }
}

Jupiter color

qiita.png

Earth color

qiita.png

Microsoft color

qiita.png

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1