リサージュ曲線

リサージュ曲線を描いてみました。
リサージュ曲線はx,yを媒介変数表示することで表現できます。
以下のサイトのリサージュ曲線の項を参考に、プログラムで表現してみます。係数のsizeは、リサージュ曲線の完成形の、縦横の大きさを表します。

x=size*sin(3*θ)
y=size*sin(4*θ)

mathtrain.jp
以下のプログラムでは、θの部分をaddx[ ],addy[ ]としています。

数学の授業で書くようなグラフは、この媒介変数表示において、θを変えることにより計算できる点を無限に打つことで実線として書けています。
プログラムでは無数に点は打てず、processingではまだしもopenframeworksでは点を打つ関数が無いので、200個程度の円を描いて動かすことにします。

これらは結局周期運動になるので、あるタイミングで複数の点が1点に重なることがあり、見ていて楽しいですね。
コードは以下の通りです。

#include "ofApp.h"
#include <vector>
#include <utility>
#include <algorithm>
#define rep(i,j,k) for(int i=j;i<k;i++)
#define pb push_back

int n=200,size=200;
vector<double> x(n),y(n),addx(n,0),addy(n,0);

void ofApp::setup(){
    ofSetRectMode(OF_RECTMODE_CENTER);
    ofSetFrameRate(60);
    ofSetBackgroundColor(0);
    ofSetColor(255);
    ofSetCircleResolution(64);
    //ofNoFill();
    
    rep(i,0,n){
        x[i]=size*sin(3*addx[i]);
        y[i]=size*sin(4*addy[i]);
    }
}

void ofApp::update(){
    
}

void ofApp::draw(){
    ofTranslate(250,250);
    rep(i,0,n){
        ofDrawEllipse(x[i], y[i], 10, 10);
        addx[i]+=PI/512*(i+1)/n;
        addy[i]+=PI/512*(i+1)/n;
        x[i]=size*sin(3*addx[i]);
        y[i]=size*sin(4*addy[i]);
    }
}