ツタンラーメンの忘備録

プログラミングや精神疾患、ラーメンについて書いていきます。たぶん。

WindowsのopenFrameworksでLeap Motionを使えるようにする

手軽にまとまった記事がないのでここでまとめて記載する。

1. Visual C++で必要な処理
2. oFで必要な処理
の二点にわかれる。

1. VC++に関して
下記記事を参考
www.naturalsoftware.jp

2. oFに関して
下記記事を参照
gndo.blogspot.jp
Macの記事だけど基本的にoFと名前が被っているところをどうにかするだけ。
サンプルコードも

testApp::drawSphere(Vector vector, float radius) {
//を
ofApp::drawSphere(Vector vector, float radius) {
//に変える

だけです。簡単!

ただWindowsにまとまったサイトがなかったのでここを参照してくださいということで。
下記サンプルは実験するには冗長なので、軽く遊びたいだけなら上記サイトを見てください。


でサンプルコードと合わせて球を表示させつつなんかコンソールにむっちゃ表示させるようにした。

//ofApp.h
#pragma once

#include "ofMain.h"
#include "Leap.h"
using namespace Leap;
class ofApp : public ofBaseApp, public Listener{

	public:
		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);

		// Leap Motionのコントローラー
		Controller leap;
		// カメラ
		ofCamera camera;
		// 球体の描画処理
		void drawSphere(Vector vector, float radius);


		//----- 一過性のイベントだけListnerから取得 ----------------------------//
		//----- フレームの処理はdraw()で行う -----------------------------------//
		void onConnect(const Controller&) {
			cout << __FUNCTION__ << endl;
		}

		void onDisconnect(const Controller&) {
			cout << __FUNCTION__ << endl;
		}

		void onFocusGained(const Controller&) {
			cout << __FUNCTION__ << endl;
		}

		void onFocusLost(const Controller&) {
			cout << __FUNCTION__ << endl;
		}

		void onServiceConnect(const Controller&) {
			cout << __FUNCTION__ << endl;
		}

		void onServiceDisconnect(const Controller&) {
			cout << __FUNCTION__ << endl;
		}
		//------------------------------------------------------------//
};
//ofApp.cpp
#include "ofApp.h"

const std::string fingerNames[] = { "Thumb", "Index", "Middle", "Ring", "Pinky" };
const std::string boneNames[] = { "Metacarpal", "Proximal", "Middle", "Distal" };
const std::string stateNames[] = { "STATE_INVALID", "STATE_START", "STATE_UPDATE", "STATE_END" };

//--------------------------------------------------------------
void ofApp::setup(){
	// カメラの初期位置と方向を指定
	camera.setFov(60);
	camera.setPosition(0, 200, ofGetWidth() / 3);
	camera.lookAt(ofVec3f(0, 200, 0));
	//ofSetFrameRate(1);
}

//--------------------------------------------------------------
void ofApp::update(){
	const Frame frame = leap.frame();
	std::cout << "Frame id: " << frame.id()
		<< ", timestamp: " << frame.timestamp()
		<< ", hands: " << frame.hands().count()
		<< ", extended fingers: " << frame.fingers().extended().count()
		<< ", tools: " << frame.tools().count()
		<< ", gestures: " << frame.gestures().count() << std::endl;

	HandList hands = frame.hands();
	for (HandList::const_iterator hl = hands.begin(); hl != hands.end(); ++hl) {
		// Get the first hand
		const Hand hand = *hl;
		std::string handType = hand.isLeft() ? "Left hand" : "Right hand";
		std::cout << std::string(2, ' ') << handType << ", id: " << hand.id()
			<< ", palm position: " << hand.palmPosition() << std::endl;
		// Get the hand's normal vector and direction
		const Vector normal = hand.palmNormal();
		const Vector direction = hand.direction();

		// Calculate the hand's pitch, roll, and yaw angles
		std::cout << std::string(2, ' ') << "pitch: " << direction.pitch() * RAD_TO_DEG << " degrees, "
			<< "roll: " << normal.roll() * RAD_TO_DEG << " degrees, "
			<< "yaw: " << direction.yaw() * RAD_TO_DEG << " degrees" << std::endl;

		// Get the Arm bone
		Arm arm = hand.arm();
		std::cout << std::string(2, ' ') << "Arm direction: " << arm.direction()
			<< " wrist position: " << arm.wristPosition()
			<< " elbow position: " << arm.elbowPosition() << std::endl;

		// Get fingers
		const FingerList fingers = hand.fingers();
		for (FingerList::const_iterator fl = fingers.begin(); fl != fingers.end(); ++fl) {
			const Finger finger = *fl;
			std::cout << std::string(4, ' ') << fingerNames[finger.type()]
				<< " finger, id: " << finger.id()
				<< ", length: " << finger.length()
				<< "mm, width: " << finger.width() << std::endl;

			// Get finger bones
			for (int b = 0; b < 4; ++b) {
				Bone::Type boneType = static_cast<Bone::Type>(b);
				Bone bone = finger.bone(boneType);
				std::cout << std::string(6, ' ') << boneNames[boneType]
					<< " bone, start: " << bone.prevJoint()
					<< ", end: " << bone.nextJoint()
					<< ", direction: " << bone.direction() << std::endl;
			}
		}
	}

	// Get tools
	const ToolList tools = frame.tools();
	for (ToolList::const_iterator tl = tools.begin(); tl != tools.end(); ++tl) {
		const Tool tool = *tl;
		std::cout << std::string(2, ' ') << "Tool, id: " << tool.id()
			<< ", position: " << tool.tipPosition()
			<< ", direction: " << tool.direction() << std::endl;
	}

	// Get gestures
	const GestureList gestures = frame.gestures();
	for (int g = 0; g < gestures.count(); ++g) {
		Gesture gesture = gestures[g];

		switch (gesture.type()) {
		case Gesture::TYPE_CIRCLE:
		{
			CircleGesture circle = gesture;
			std::string clockwiseness;

			if (circle.pointable().direction().angleTo(circle.normal()) <= PI / 2) {
				clockwiseness = "clockwise";
			}
			else {
				clockwiseness = "counterclockwise";
			}

			// Calculate angle swept since last frame
			float sweptAngle = 0;
			if (circle.state() != Gesture::STATE_START) {
				CircleGesture previousUpdate = CircleGesture(leap.frame(1).gesture(circle.id()));
				sweptAngle = (circle.progress() - previousUpdate.progress()) * 2 * PI;
			}
			std::cout << std::string(2, ' ')
				<< "Circle id: " << gesture.id()
				<< ", state: " << stateNames[gesture.state()]
				<< ", progress: " << circle.progress()
				<< ", radius: " << circle.radius()
				<< ", angle " << sweptAngle * RAD_TO_DEG
				<< ", " << clockwiseness << std::endl;
			break;
		}
		case Gesture::TYPE_SWIPE:
		{
			SwipeGesture swipe = gesture;
			std::cout << std::string(2, ' ')
				<< "Swipe id: " << gesture.id()
				<< ", state: " << stateNames[gesture.state()]
				<< ", direction: " << swipe.direction()
				<< ", speed: " << swipe.speed() << std::endl;
			break;
		}
		case Gesture::TYPE_KEY_TAP:
		{
			KeyTapGesture tap = gesture;
			std::cout << std::string(2, ' ')
				<< "Key Tap id: " << gesture.id()
				<< ", state: " << stateNames[gesture.state()]
				<< ", position: " << tap.position()
				<< ", direction: " << tap.direction() << std::endl;
			break;
		}
		case Gesture::TYPE_SCREEN_TAP:
		{
			ScreenTapGesture screentap = gesture;
			std::cout << std::string(2, ' ')
				<< "Screen Tap id: " << gesture.id()
				<< ", state: " << stateNames[gesture.state()]
				<< ", position: " << screentap.position()
				<< ", direction: " << screentap.direction() << std::endl;
			break;
		}
		default:
			std::cout << std::string(2, ' ') << "Unknown gesture type." << std::endl;
			break;
		}
	}

	if (!frame.hands().isEmpty() || !gestures.isEmpty()) {
		std::cout << std::endl;
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	camera.begin();
	// 背景を黒に塗りつぶし
	ofBackground(0, 0, 0);
	// フレームを取得
	Frame frame = leap.frame();
	// Handをあるだけ列挙
	for (int i = 0; i<frame.hands().count(); i++) {
		Hand hand = frame.hands()[i];
		// てのひらの位置に球体を描画
		drawSphere(hand.palmPosition(), 20);
		// Hand内のFingerをあるだけ描画
		for (int j = 0; j<hand.fingers().count(); j++) {
			Finger finger = frame.fingers()[j];
			drawSphere(finger.tipPosition(), 8);
			//drawSphere(finger.jointPosition(), 2);
		}
	}
	camera.end();
}

void ofApp::drawSphere(Vector vector, float radius) {
	// 球体の描画処理    
	ofNoFill();
	ofPushMatrix();
	ofPoint point = ofPoint(vector.x, vector.y, vector.z);
	ofTranslate(point);
	ofRotateX(point.x);
	ofRotateY(point.y);
	ofRotateZ(point.z);
	ofSetColor(0xCC, 0, 0, 255);
	ofSphere(radius);
	ofPopMatrix();
}

コメントもそのまま残っていて草はえますね。
これを描くとコンソールにむっちゃ言葉が出てきて追いきれません。位置とかを送ってそうですね(雑な理解)

btn.addEventListenerが使えなかった(nullが返ってきた)

初心者にありがち?なミスなんだけど、

//a.js
const btn = document.getElementById('btn');
btn.addEventListener( 'click' , function() {
    socket.emit('btn', true);
} );

//もしくは

document.querySelector('#btn').onclick = function () {
  socket.emit('btn', true);
}

とするとnullが返ってくる。

htmlはざっくり

<script type="text/javascript" src="a.js"></script>
<body>
    <input type="button" id="btn" value="ループ開始" class="select" />
</body>

こんなん

理由は下記がわかりやすい

teratail.com
簡単に言うと呼び出しが早すぎて順番が逆転する状態らしい。

私流に描くと

window.onload = function(){
  const btn = document.getElementById('btn');
  btn.addEventListener( 'click' , function() {
      socket.emit('btn', true);
  } );
};

やらかしてしまった…。こんなんに時間を取られたのか…。

ちなみに

<script type="text/javascript" src="a.js"></script>

<script type="text/javascript" scr="a.js"></script>

と描くミスをたまにやる。初心者はやることが違いますね(笑)
scr

openLayers 3 で地図の移動

opeLayers2系で開発していたのだけれど、3に移行したほうがいいかなということで開発を3に割り振った。
で、いろいろなサンプルを見て回ったのだけれど見たのは全部マップを一回表示されるだけで終わっている。地図アプリケーションって検索したら別のところ行きたいじゃないですか、で苦労したんだけど灯台下暗しでした。

function setMapCenter(center){ //イベントで呼ばれる関数
  view.setCenter(ol.proj.transform([center.lon, center.lat], "EPSG:4326", "EPSG:3857"));
};

center:画面の中央位置のオブジェクト。別になんでもいい。
これだけ書けばいい(当たり前っちゃ当たり前なんですが…)

これやるためにはviewをグローバル変数として持っていないといけないんだけど、そこはおいおい考えるとして、これでできます。
ちなみにviewがどう定義されているかというと(だいたいどこかをコピペしているだけですが)

view = new ol.View({
        projection: "EPSG:3857",
        maxZoom: 17,
        minZoom: 6
    });

さらにちなみに円を描画したいときには下記のような関数を持っておくと便利です(おそらく円でなくてもこの関数は便利)

function drawCircle(center){
  var circle_layer = new ol.layer.Vector({
    source: new ol.source.Vector({
      features: [
        new ol.Feature(
          new ol.geom.Point(
            ol.proj.transform(
              [center.lon, center.lat],
              "EPSG:4326",
              "EPSG:3857"
            )
          )
        )
      ]
    }),
    style: new ol.style.Style({
      image: new ol.style.Circle({
        fill: new ol.style.Fill({
          color: 'rgba(255,0,0,0.8)'
        }),
        /*stroke: new ol.style.Stroke({
          color: 'rgb(255,0,0)',
          width: 15
        }),*/
        radius: 120
      })
    })
  });
  return circle_layer;
}

これを発展させて円をいっぱい描画したいので、それもできたら記事にします。

ちなみにlayerを消す機能を実装していないので永遠にlayerが増え続けます。ちゃんとここも修正します。

デスクトップ版LINEの通知がうるさかったので切りたかった

のだけど、
ameblo.jp
面白そうだから、これを試してみました。

適当にアニメキャラクターボイスを使ってみるとほら簡単
LINE通知の度に推しの声を聞いていると、軽く死にたくなるので止めましょう。
というわけでピカチュウにしました。

快適なオタクライフを!(私はオタクではありません)

raspberry pi 3で固定IPを割り当てる

調べれば出てくるのでとりあえずやってみた

Raspberry Pi 3 (Raspbian Jessie)の無線LANに固定IPアドレスを設定する - Qiita

無線LAN設定はしてあるので、「固定IP設定」の章から読む。


で、むっちゃ初心者なので固定IPアドレスってなんでもいいと思っていたんだけど、そんなことはなかった。いろいろ迷ったあげく、現状割り当てられているIPアドレスを書いておいたら動いたので、よしとしている。変わらないといいんだけど…。
知らなかったんだけど適当なIPアドレス割り振っても

ip addr

のコマンド打てばちゃんと表示される。しかし、インターネットにすらつながらなくなるのね

パソコンのIPアドレス・デフォルトゲートウェイ・DNSサーバーアドレスの確認方法
固定IP以外の二つはwin端末から上記方法で解決した。情報が古いがそのまま使える。


暖房の使い過ぎでブレーカーが落ちて停電してからIPアドレス変わったので固定したほうがいいかなーとか思ったけど、意味あるのだろうか。

VBAの特殊性

VBAは意外と便利なんだけど、文法が特殊。しばらくVBAをやらなそうだからいくつか備忘録的に書いておこう。

Dim hensuu As Integer '変数名も大文字から始めることが多いイメージ


'コメント


If A = B Then

ElseIf

End If


Dim i As Integer
For i = 0 To 10 Step 1
  '10も含む
Next i


Dim A(9) As String '配列、10個用意される、0~9まで


'参照渡し?ができる
Function Plus(A, B, C)
  C = A + B + 1
  Plus = A + B
End Function
'とすると
Result = Plus(1, 2, Kai)
'とできて
'Result = 3
'Kai = 4
'となる

ごめんなさい。記憶で書いているので間違っているかも。とにかく特殊性があるということが言いたい。他の言語やってればやっているほど、不思議な感覚がする。

ちなみに予測変換は

Ctrl+space

で出ます。
あといちいちエラーのところに戻されるので、設定で切っておくべきだと思います。