[work 65] Hole

[work 65] Hole

Movie

Source code

about

  • ウィンドウの内側に枠を作る
  • 枠の線上に等間隔で点を配置する
  • 正規分布に従ってランダムな点を枠内に配置する
  • ドロネー図を作成
  • 三角形の塗りはグレースケールで、中心からの距離が近いほど黒になるようにする

file

  • 上部にあるファイル名が表示されているボタンを押すと、表示されるファイルが切り替わります
  • 別ウィンドウ表示したい時や行番号などが無いRawMode表示したい時は、コード内右上のボタンを押してください(ボタンはマウスオーバーすると表示されます)
#include "ofMain.h"
#include "ofApp.h"

//================================
int main( ){

    // 4K:4096x2160
    // 2K:2048x1080
    // FullHD:1920x1080
    // HD:1440x1080
    // HD720p:1280x720
    // DVD:720x480
    // setup the GL context
    ofSetupOpenGL(1280, 720, OF_WINDOW);

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp( new ofApp());

}
#pragma once

#include "ofMain.h"

#include "Hole.hpp"


class ofApp : public ofBaseApp{
public:
    ofApp();
    ~ofApp();
    
    void setup();
    void update();
    void draw();
    
    void keyPressed(int key);
    void keyReleased(int key);
    void mouseMoved(int x, int y);
    void mouseDragged(int x, int y, int button);
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    void mouseEntered(int x, int y);
    void mouseExited(int x, int y);
    void windowResized(int w, int h);
    void dragEvent(ofDragInfo dragInfo);
    void gotMessage(ofMessage msg);
    
private:
    std::shared_ptr<Hole> hole;
};
#include "ofApp.h"


ofApp::ofApp(){
    
}

ofApp::~ofApp(){
    
}

//--------------------------------------------------------------
void ofApp::setup(){
    double fps = 30;
    
    
    ofSetFrameRate(fps);
    ofBackground(255);
    ofSetBackgroundAuto(true);
    ofSetVerticalSync(true);
    
    hole = make_shared<Hole>();
    hole->setup();
}

//--------------------------------------------------------------
void ofApp::update(){
    hole->update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    hole->display();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if (key == 's') {
        ofImage img;
        img.grabScreen(0, 0, ofGetWidth(), ofGetHeight());
        img.save("screenshot.png");
    }
}
#ifndef Hole_hpp
#define Hole_hpp

#include <stdio.h>
#include "ofMain.h"

#include "Delaunay.hpp"
#include <random>


class Hole {
public:
    Hole();
    ~Hole();
    void setup();
    void update();
    void display();
    
private:
    std::shared_ptr<Delaunay2d> d2d;
    
    std::vector<std::array<ofVec2f, 3>> triangle;
    int index;
    
    ofFbo fbo;
};
#endif /* Hole_hpp */
#include "Hole.hpp"


Hole::Hole()
{
    
}


Hole::~Hole()
{
    
}


void Hole::setup()
{
    d2d = make_shared<Delaunay2d>(ofRectangle(0, 0, ofGetWidth(), ofGetHeight()));
    
    index = 0;
    std::vector<ofVec2f> points;
    
    // Frame
    ofRectangle rect(50, 50, ofGetWidth() - 100, ofGetHeight() - 100);
    
    points.push_back(ofVec2f(rect.getLeft(), rect.getTop()));
    points.push_back(ofVec2f(rect.getLeft(), rect.getBottom()));
    points.push_back(ofVec2f(rect.getRight(), rect.getTop()));
    points.push_back(ofVec2f(rect.getRight(), rect.getBottom()));
    
    for (int xoff = 100; xoff < rect.width; xoff += 100) {
        points.push_back(ofVec2f(rect.x + xoff, rect.getTop()));
        points.push_back(ofVec2f(rect.x + xoff, rect.getBottom()));
    }
    
    for (int yoff = 100; yoff < rect.height; yoff += 100) {
        points.push_back(ofVec2f(rect.getLeft(), rect.y + yoff));
        points.push_back(ofVec2f(rect.getRight(), rect.y + yoff));
    }
    
    // set randam point in the frame
    std::random_device seed_gen;
    std::default_random_engine engine(seed_gen());
    
    std::normal_distribution<> dist(0.0, 1.0);
    
    for (int i = 0; i < 200; i++) {
        float x = ofMap((float)dist(engine), -5, 5, rect.getLeft(), rect.getRight(), true);
        float y = ofMap((float)dist(engine), -5, 5, rect.getTop(), rect.getBottom(), true);
        points.push_back(ofVec2f(x, y));
    }
    
    // get delaunay triangle
    d2d->setup(points);
    d2d->getTriangle(triangle);
    
    fbo.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA, 4);
}


void Hole::update()
{
    if (index < triangle.size()) {
        std::array<ofVec2f, 3> p = triangle.at(index);
        index++;
        
        fbo.begin();
        ofSetColor(0);
        ofNoFill();
        ofDrawTriangle(p.at(0), p.at(1), p.at(2));
        
        ofVec2f c(ofGetWidth() / 2, ofGetHeight() / 2);
        float dist = (p.at(0) - c).length();
        for (int i = 1; i < p.size(); i++) {
            dist = std::max(dist, (p.at(i) - c).length());
        }
        ofSetColor(ofMap(dist, 0, c.length(), 0, 255));
        ofFill();
        ofDrawTriangle(p.at(0), p.at(1), p.at(2));
        fbo.end();
    }
}


void Hole::display()
{
    fbo.draw(0, 0);
}
#ifndef Delaunay_hpp
#define Delaunay_hpp

#include <stdio.h>
#include "ofMain.h"
#include <opencv2/opencv.hpp>



class Delaunay2d {
public:
    Delaunay2d(ofRectangle rect);
    ~Delaunay2d();
    void setup(std::vector<ofVec2f> points);
    void getTriangle(std::vector<std::array<ofVec2f, 3>> &tlist);
    
private:
    Delaunay2d();
    
    cv::Subdiv2D sd;
    std::vector<cv::Vec6f> triangleList;
    cv::Rect area;
};
#endif /* Delaunay_hpp */
#include "Delaunay.hpp"


Delaunay2d::Delaunay2d(ofRectangle rect)
{
    area.x = (int)rect.x;
    area.y = (int)rect.y;
    area.width = (int)rect.width;
    area.height = (int)rect.height;
    
    sd.initDelaunay(area);
}

Delaunay2d::~Delaunay2d()
{
    
}


void Delaunay2d::setup(std::vector<ofVec2f> points)
{
    ofRectangle rect(area.x, area.y, area.width, area.height);
    
    for (ofVec2f ofxp : points) {
        if(rect.inside(ofxp.x, ofxp.y)) {
            cv::Point2f pt;
            pt.x = ofxp.x;
            pt.y = ofxp.y;
            sd.insert(pt);
        } else {
            std::cout << "[Warning] out of area:" << ofxp.x << "," << ofxp.y << std::endl;
        }
    }
    sd.getTriangleList(triangleList);
}


void Delaunay2d::getTriangle(std::vector<std::array<ofVec2f, 3>> &tlist)
{
    std::array<ofVec2f, 3> a;
    ofRectangle r = ofRectangle(area.x, area.y, area.width, area.height);
    
    tlist.clear();
    
    for (cv::Vec6f v6f : triangleList) {
        a[0].x = v6f[0];
        a[0].y = v6f[1];
        a[1].x = v6f[2];
        a[1].y = v6f[3];
        a[2].x = v6f[4];
        a[2].y = v6f[5];
        
        if (r.inside(a[0]) && r.inside(a[1]) && r.inside(a[2])) {
            tlist.push_back(a);
        }
    }
}

Link to the reference page

ソースコードで使用したAPIの中から要点になりそうなものをいくつか選んでリストアップしました。

categoryAPI/Lib
openframeworksofRectangle
c++std::random_device

Development environment

  • openframeworks 0.10.1
  • c++
  • macOS
  • Xcode