gotutiyan’s blog

競技プログラミングをやったりopenframeworksでお絵かきをしたりしています。

2種リング

今まで円の描画はofDrawCircleを使って行っていましたが、この方法では「1つの円の中で複数の色を使う」ことができないので、ほかの方法で円を書いてみることにしました。
色の変わる方向を交互にしたのでこの題名に。


円は、点を打つことでも描くことができます。三角関数で学んだ「単位円」がその代表で、sin^2*cos*2=1を利用して円を描くことができています。この単位円上に点を打っていくことによって、円が完成します。openframeworksは「点を打つ」ことができないので、今回はごく小さな円を描くことで対応しました。クリックすることで色がランダムに変化します。

円1つをクラスで作成し、このインスタンスを2次元に並べています。以下はそのクラスの処理の説明です。

今回は1つの円につき色を2色使っていますが、色の境目がよくわかるように補色にしています。補色は、ある色情報のRGBが(x,y,z)の時、(255-x,255-y,255-z)で表せます。全て255から引くだけです。

また、円をたくさん並べていることから、大きな円を構成するための小さな円があり、もちろんx,y座標の情報を持っています。この小さな円それぞれが持つy座標の値と、大きな円それぞれが持つ色の境目のy座標を示す変数posを比べて、その大小で色を塗り分けます。
三角関数の中身に書いているDEG_TO_RADは、「度数法(degree)からラジアン(radian)に変換する」という意味があるので、for文のループ変数0~359が、0~359度の1周分になっていて、それがラジアンに変換されることで三角関数がうまく働きます。

#include "ofApp.h"
#define rep(i,j,k) for(int i=j;i<k;i++)
float radius=50;

class PIC{
    int r,g,b;
    int x,y;
    int pos,speed;
    
    public :
//初期化関数
    void init(int i,int j){
        x=radius/2+radius*i*2;
        y=radius/2+radius*j*2;
        
        r=ofRandom(255);
        g=ofRandom(255);
        b=ofRandom(255);
        
        if((i+j)%2){  //色の変化の方向を互い違いにするため、iとjの和の偶奇で分ける
            pos=radius;
            speed=-1;
        }else {
            pos=-radius;
            speed=1;
        }
    }
    
    void move(){
        pos+=speed;
        if(pos<-radius || pos>radius) speed*=-1;
        
         rep(i,0,360){
             ofPushMatrix();
             ofTranslate(x+radius/2,y+radius/2);
    //DEG_TO_RADで度数法からラジアンへ
             float x=cos((i)*DEG_TO_RAD)*radius;   
             float y=sin((i)*DEG_TO_RAD)*radius;
         
             if(y<pos)ofSetColor(r,g,b);
             else ofSetColor(255-r,255-g,255-b); //補色を作る
             ofDrawCircle(x,y,2,2);
             ofPopMatrix();
         }
    }
};

vector<vector<PIC>> v;

void ofApp::setup(){
    ofSetFrameRate(60);
    ofSetBackgroundColor(0);
    ofSetColor(255);
    ofSetCircleResolution(32);
    ofFill();
    
    int num=ofGetWidth()/(radius*2);  //numは円を書く個数
    // vectorをリサイズして使うことで、画面幅や半径が変わっても対応できる(はず)
    v.resize(num,vector<PIC>(num));  
    
    rep(i,0,num) rep(j,0,num) v[i][j].init(i,j);  //初期化をします
    
    
    
}

void ofApp::update(){
    
}

void ofApp::draw(){
    int num=ofGetWidth()/(radius*2);
    rep(i,0,num){
        rep(j,0,num){
            v[i][j].move();
        }
    }
}

 //クリックしたらinit()を発動させることで色をランダムに変化させる
void ofApp::mousePressed(int x, int y, int button){ 
    int num=ofGetWidth()/(radius*2);
    rep(i,0,num)rep(j,0,num)v[i][j].init(i,j);
}