球表面・球内に一様分布する点をいっぱい生成する
球表面・球内に一様分布する点の生成方法を調べたのでメモ。
下記のページを参考にしました。
球面上にランダムで置いたプロットをなるべく分散させたい - Qiita
http://apollon.issp.u-tokyo.ac.jp/~watanabe/pdf/prob.pdf
球表面に一様分布する点
単位球表面に一様に分布する点の座標 は、2つの一様乱数
を用いて、
で求められます。
任意の半径の球を考える場合は、各座標に半径をかければ求められます。
球内に一様分布する点
単位球内に一様に分布する点の座標 は、3つの一様乱数
を用いて、
で求められます。
球表面と同様に任意の半径の球を考える場合は、各座標に半径をかければ求められます。
実際に生成してみる
openFrameworksで実際に生成してみるとこんな感じになります。
緑の点が球表面、赤の点が球内に一様分布する点になります。
ちゃんと一様に分布してるっぽい。
ofApp.h
#pragma once #include "ofMain.h" class ofApp : public ofBaseApp{ public: void setup(); void draw(); ofEasyCam cam; ofMesh mesh; int num; // 頂点数 float radius; // 半径 };
ofApp.cpp
#include "ofApp.h" //-------------------------------------------------------------- void ofApp::setup(){ ofBackground(0x32); ofEnableDepthTest(); cam.setDistance(480); num = 2000; radius = 200; // 球表面に一様な分布する点を生成 for (int i = 0; i < num; i++) { float z = ofRandom(-1.0, 1.0); float phi = ofDegToRad(ofRandom(360)); float x = sqrt(1 - z * z) * cos(phi); float y = sqrt(1 - z * z) * sin(phi); mesh.addVertex(radius * ofVec3f(x, y, z)); mesh.addColor(ofColor::fromHsb(100, 200, 250)); } // 球内に一様に分布する点を生成 for (int i = 0; i < num; i++) { float r = ofRandom(1.0); float z = ofRandom(-1.0, 1.0); float phi = ofDegToRad(ofRandom(360)); float x = cbrt(r) * sqrt(1 - z * z) * cos(phi); float y = cbrt(r) * sqrt(1 - z * z) * sin(phi); z = cbrt(r) * z; mesh.addVertex(radius * ofVec3f(x, y, z)); mesh.addColor(ofColor::fromHsb(240, 200, 250)); } } //-------------------------------------------------------------- void ofApp::draw(){ cam.begin(); ofRotate(ofGetElapsedTimef()*10, 1, 1, 0); glPointSize(4.0); mesh.drawVertices(); cam.end(); }