cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

(メモ)ofxMSAInterpolatorのバグ取り

openFrameworksのofxMSAInterpolatorというアドオンは、1次、2次、3次のスプライン補間(置いた点を通る)を提供してくれるライブラリです。0.7時代でメンテナンスが止まってしまっているので、新しいバージョンのopenFrameworksで動かすためには少しだけ手直しが必要です。そのための、メモ。

動かした環境 openframeworks0.8.4 on Microsoft VisualStudio 2012

Addon ofxMSAInterpolator

Bugfix
MSAInterpolator3D.h

/**************************** 3D InterpolatorT (of Vec3) ****************************/

#pragma once

#include "MSAInterpolatorT.h"

namespace msa {
	
	typedef InterpolatorT<Vec3f> Interpolator3D;
	
	
    //--------------------------------------------------------------
	inline float lengthOf(const Vec3f& v) {
		return v.length();
	}
	
	
    //--------------------------------------------------------------
	// OpenGL ES compatibility added by Rob Seward
	// http://www.openframeworks.cc/forum/viewtopic.php?f=25&t=3767&p=19865
	inline void drawInterpolatorRaw(Interpolator3D spline, int dotSize = 20, int lineWidth = 4){
		int numItems = spline.size();
        if(numItems == 0) return;
		
		if(lineWidth) {
			glLineWidth(lineWidth);
			//GLfloat vertex[numItems * 3];
			GLfloat* vertex = new GLfloat[numItems * 3 + 3];
			for(int i=0; i<numItems; i++) {
				vertex[i*3]		= spline.at(i).x;
				vertex[(i*3)+1] = spline.at(i).y;
				vertex[(i*3)+2] = spline.at(i).z;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(3, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_LINE_STRIP, 0, numItems);
			
			delete [] vertex;
		}
		
		if(dotSize) {
			glPointSize(dotSize);
			//GLfloat vertex[numItems * 3];
			GLfloat* vertex=new GLfloat[numItems * 3 + 3];
			for(int i=0; i<numItems; i++) {
				vertex[i*3]		= spline.at(i).x;
				vertex[(i*3)+1] = spline.at(i).y;
				vertex[(i*3)+2] = spline.at(i).z;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(3, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_POINTS, 0, numItems);
			
			delete [] vertex;
		}		
	}
	
	
    //--------------------------------------------------------------
	inline void drawInterpolatorSmooth(Interpolator3D spline, int numSteps, int dotSize = 8, int lineWidth = 2) {
		float spacing = 1.0/numSteps;
        if(spline.size() == 0) return;
        
		if(lineWidth) {
			glLineWidth(lineWidth);
			
			//GLfloat vertex[numSteps * 3];
			GLfloat* vertex = new GLfloat[numSteps * 3 + 3];
			//int i=0;
			//for(float f=0; f<1; f+= spacing) {
			for(int i=0; i<numSteps; i++){
				float f=i*spacing;
				Vec3f v			= spline.sampleAt(f);
				vertex[i*3]		= v.x;
				vertex[(i*3)+1] = v.y;
				vertex[(i*3)+2] = v.z;
				//i++;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(3, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_LINE_STRIP, 0, numSteps);

			if(vertex) delete [] vertex;
		}
		
		if(dotSize) {
			glPointSize(dotSize);
			//GLfloat vertex[numSteps * 3];
			GLfloat* vertex = new GLfloat[numSteps * 3 + 3];
			//int i=0;
			//for(float f=0; f<1; f+= spacing) {
			for(int i=0; i<numSteps; i++){
				float f=i*spacing;
				Vec3f v			= spline.sampleAt(f);
				vertex[i*3]		= v.x;
				vertex[(i*3)+1] = v.y;
				vertex[(i*3)+2] = v.z;
				//i++;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(3, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_POINTS, 0, numSteps);
			
			if(vertex) delete [] vertex;
		}
	}
	
}

Also, MSAInterpolator2D.h

/**************************** 2D InterpolatorT (of Vec2) ****************************/

#pragma once

#include "MSAInterpolatorT.h"

namespace msa {
	
	typedef InterpolatorT<Vec2f> Interpolator2D;

	
    //--------------------------------------------------------------
	inline float lengthOf(const Vec2f& v) {
		return v.length();
	}

	
    //--------------------------------------------------------------
	// OpenGL ES compatibility added by Rob Seward
	// http://www.openframeworks.cc/forum/viewtopic.php?f=25&t=3767&p=19865
	inline void drawInterpolatorRaw(Interpolator2D &spline, int dotSize = 20, int lineWidth = 4){
		int numItems = spline.size();
		
		if(lineWidth) {
			glLineWidth(lineWidth);
			//GLfloat vertex[numItems * 2];
			GLfloat* vertex = new GLfloat[numItems * 2];
			for(int i=0; i<numItems; i++) {
				vertex[i*2]		= spline.at(i).x;
				vertex[(i*2)+1] = spline.at(i).y;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(2, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_LINE_STRIP, 0, numItems);
			
			delete [] vertex;
		}
		
		if(dotSize) {
			glPointSize(dotSize);
			//GLfloat vertex[numItems * 2];
			GLfloat* vertex = new GLfloat[numItems * 2];
			for(int i=0; i<numItems; i++) {
				vertex[i*2]		= spline.at(i).x;
				vertex[(i*2)+1] = spline.at(i).y;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(2, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_POINTS, 0, numItems);
			
			delete [] vertex;
		}		
	}
	
	
    //--------------------------------------------------------------
	inline void drawInterpolatorSmooth(Interpolator2D &spline, int numSteps, int dotSize = 8, int lineWidth = 2) {
		float spacing = 1.0/numSteps;
		if(lineWidth) {
			glLineWidth(lineWidth);
			
			//GLfloat vertex[numSteps * 2];
			GLfloat* vertex = new GLfloat[numSteps * 2];
			//int i=0;
			//for(float f=0; f<1; f+= spacing) {
			for(int i=0; i<numSteps; i++){
				float f=i*spacing;
				Vec2f v			= spline.sampleAt(f);
				vertex[i*2]		= v.x;
				vertex[(i*2)+1] = v.y;
				//i++;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(2, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_LINE_STRIP, 0, numSteps);

			delete [] vertex;
		}
		
		if(dotSize) {
			glPointSize(dotSize);
			//GLfloat vertex[numSteps * 2];
			GLfloat* vertex = new GLfloat[numSteps * 2];
			//int i=0;
			//for(float f=0; f<1; f+= spacing) {
			for(int i=0; i<numSteps; i++){
				float f=i*spacing;
				Vec2f v			= spline.sampleAt(f);
				vertex[i*2]		= v.x;
				vertex[(i*2)+1] = v.y;
				//i++;
			}
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(2, GL_FLOAT, 0, vertex);
			glDrawArrays(GL_POINTS, 0, numSteps);

			delete [] vertex;
		}
	}
}

MSACoreなるライブラリは、Vec2fやVec3fをofVec2fやofVec3fに置き換えて、clamp関数を[2]などを参考に

inline float clamp(float a, float min, float max) {
	if (min < a)
        return a < max ? a : max; 
    else
        return min; 
}

書き換えてしまえば不要になる。
追記20150824: openFrameworksにofClampなる関数があったので、そっちを使えば良いですね。

メモリ確保の+3は、lengthでサンプリングするときの場当たり的なエラーの回避のため。indexの数が正しく合わず場合によっては、最後の結果が表示されない。

多少、無駄を省いた版。
ただし、OpenGL ESの対応は外れてしまっていると思われます。
// OpenGL ES compatibility added by Rob Seward
// http://www.openframeworks.cc/forum/viewtopic.php?f=25&t=3767&p=19865

/**************************** 3D InterpolatorT (of Vec3) ****************************/

#pragma once

#include "MSAInterpolatorT.h"

namespace msa {
	
	typedef InterpolatorT<ofVec3f> Interpolator3D;
	
	
    //--------------------------------------------------------------
	inline float lengthOf(const ofVec3f& v) {
		return v.length();
	}
	
	
    //--------------------------------------------------------------
	inline void drawInterpolatorRaw(Interpolator3D spline, int dotSize = 20, int lineWidth = 4){
		int numItems = spline.size();
        if(numItems == 0) return;
		if(!lineWidth && !dotSize) return;
		
		GLfloat* vertex = new GLfloat[numItems * 3];
		for(int i=0; i<numItems; i++) {
			vertex[i*3]		= spline.at(i).x;
			vertex[(i*3)+1] = spline.at(i).y;
			vertex[(i*3)+2] = spline.at(i).z;
		}

		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertex);
		if(lineWidth){
			glLineWidth(lineWidth);
			glDrawArrays(GL_LINE_STRIP, 0, numItems);
		}
		if(dotSize){
			glPointSize(dotSize);
			glDrawArrays(GL_POINTS, 0, numItems);
		}

		delete [] vertex;
	}
	
	
    //--------------------------------------------------------------
	inline void drawInterpolatorSmooth(Interpolator3D spline, int numSteps, int dotSize = 8, int lineWidth = 2) {
		float spacing = 1.0/numSteps;
        if(spline.size() == 0) return;
        if(!lineWidth && !dotSize) return;
		
		GLfloat* vertex = new GLfloat[(numSteps + 1) * 3];
		for(int i=0; i<numSteps; i++){
			float f=i*spacing;
			ofVec3f v		= spline.sampleAt(f);
			vertex[i*3]		= v.x;
			vertex[(i*3)+1] = v.y;
			vertex[(i*3)+2] = v.z;
		}

		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertex);
		if(lineWidth){
			glLineWidth(lineWidth);
			glDrawArrays(GL_LINE_STRIP, 0, numSteps);
		}
		if(dotSize){
			glPointSize(dotSize);
			glDrawArrays(GL_POINTS, 0, numSteps);
		}

		if(vertex) delete [] vertex;
	}
}
/**************************** 2D InterpolatorT (of Vec2) ****************************/

#pragma once

#include "MSAInterpolatorT.h"

namespace msa {
	
	typedef InterpolatorT<ofVec2f> Interpolator2D;

	
    //--------------------------------------------------------------
	inline float lengthOf(const ofVec2f& v) {
		return v.length();
	}

	
    //--------------------------------------------------------------
	inline void drawInterpolatorRaw(Interpolator2D &spline, int dotSize = 20, int lineWidth = 4){
		int numItems = spline.size();
		if(!lineWidth && !dotSize) return;

		GLfloat* vertex = new GLfloat[numItems * 2];
		for(int i=0; i<numItems; i++) {
			vertex[i*2]		= spline.at(i).x;
			vertex[(i*2)+1] = spline.at(i).y;
		}
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(2, GL_FLOAT, 0, vertex);

		if(lineWidth){
			glLineWidth(lineWidth);
			glDrawArrays(GL_LINE_STRIP, 0, numItems);
		}
		if(dotSize){
			glPointSize(dotSize);
			glDrawArrays(GL_POINTS, 0, numItems);
		}

		delete [] vertex;
	}
	
	
    //--------------------------------------------------------------
	inline void drawInterpolatorSmooth(Interpolator2D &spline, int numSteps, int dotSize = 8, int lineWidth = 2) {
		float spacing = 1.0/numSteps;
		if(!lineWidth && !dotSize) return;

		GLfloat* vertex = new GLfloat[numSteps * 2];
		for(int i=0; i<numSteps; i++){
			float f=i*spacing;
			ofVec2f v		= spline.sampleAt(f);
			vertex[i*2]		= v.x;
			vertex[(i*2)+1] = v.y;
		}
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(2, GL_FLOAT, 0, vertex);

		if(lineWidth){
			glLineWidth(lineWidth);
			glDrawArrays(GL_LINE_STRIP, 0, numSteps);
		}
		if(dotSize){
			glPointSize(dotSize);
			glDrawArrays(GL_POINTS, 0, numSteps);
		}

		delete [] vertex;
	}
}

バグフィックスのために、MSAInterpolatorT.hのなかのgetLength関数で!_dist.empty()ではなかったらサイズを返す、の判断を入れます。

    //--------------------------------------------------------------
	template <typename T>
	const float InterpolatorT<T>::getLength(int i) const {
		if(_useLength&&!_dist.empty()) {
			return i < 0 ? _dist[_dist.size()-1] : _dist.at(i);
		} else {
			return 0;
		}
	}

[1] www.memo.tv
[2] C3(Composite Computer Club) » clamp関数の書き方

スプライン関数入門―情報処理の新しい手法

スプライン関数入門―情報処理の新しい手法

Cによるスプライン関数―データ解析 CG 微分方程式

Cによるスプライン関数―データ解析 CG 微分方程式

スプライン関数とその応用 (シリーズ新しい応用の数学 20)

スプライン関数とその応用 (シリーズ新しい応用の数学 20)

本はあまり役に立たない、、、。