自習室

こもります

Unity + Visual Studio で、Native Plugin をデバッグする (Windows)

つづき

前回、 Visual Studio を使って Managed(C#)なPluginを作ってUnityVSを使ってデバッグする方法について書きました。

今回はその続きで、Native(C++) な Plugin をつくってデバッグする方法について書きます。そもそもOpenCVを使いたくてプラグイン化をしているので、今回が本命です。

環境

GitHubにあげました

記事はmanaged/nativeで2回に分けましたが、プロジェクトは一つにまとめてあります。

Native Plugin の場合

UnityVS/MS 公式によれば、 UnityVSとしてはサポートしていないことになっています。

今回 Unity 向けに調べるまでは知らなかったのですが、もともとVisual Studioには、Windows上で実行中のプロセスにアタッチしてデバッグを行う機能があります。

やってみます。

実行中のプロセスにアタッチ

デバッグしたい Native Plugin のプロジェクトを選択した状態で、

DEBUG > Attach to Process...

と選び、開いたウィンドウで、 Unity.exe を選択します

f:id:AMANE:20141215223451j:plain

その状態でブレイクしたい箇所にポイントを張って、 Unity Editor から Play すれば、ブレイクしてくれます。

f:id:AMANE:20141215224559j:plain

コールスタックを見ると、 Unity.exe!MonoBehaviour::Update() からDLLの GetRandom() 関数が呼び出されていることがわかっておもしろいです。

ブレイクされないときがあった

私のリポジトリからCloneしたもので、正しくブレイクに引っかかったくれなかった場合は、一度Unityを閉じてから、Visual Studio の方で Plugin をビルドし直し、Unityの Assets/Plugins のdllを上書きしてから再度実行すると、引っかかるようになります。

最後に

これで Native Plugin もデバッグができるようになりました。前々回の記事OpenCV を Native Plugin 化しましたが、こちらの場合でもちゃんとブレイクできることを確認しています。

Unity + Visual Studio で、Managed Plugin をデバッグする (Windows)

はじめに

前回、OpenCV を 必要な分だけ Native Plugin の DLL としてまとめて利用する方法について書きました。

C++のライブラリを使ってC++のコードを書いて、Native Plugin として利用できるのは良いのですが、Unity Editor での実行中に、C++側のデバッグができるんかい?という疑問がわきました。

今回はそのあたりを調べてみました。ついでにManaged Pluginのデバッグの仕方についても調べたのですが、分量の関係で Managed/Nativeで2回に分けることにしました。

環境

今回もがっつり Windows + Unity Pro 限定な内容になっておりますがご容赦ください。

題材

今回の記事は、Live Training "WRITING PLUGINS" の作例に対してデバッグできるよう改変を加えています。プロジェクトの作り方、コードの書き方、ビルドの仕方はこちらを参考。

GitHubにあげました

記事はmanaged/nativeで2回に分けましたが、プロジェクトは一つにまとめてあります。

まずは Managed Plugin から

UnityVSでできるんじゃないか?と天啓を受けて調べてみたら、確かにありました。

Managed(C#) Plugin は 上記事に書いてあるとおりでできますが、目立ったところだけこちらにメモっておきます。ちなみに、最後のデバッグの開始部分は、上のリンクと少し異なることをしています。上のリンクの仕方でもできますが、本記事のやり方の方が少し楽なので紹介いたします。

Target Framework: .NET Framework 3.5

Unity の Mono が .NET で言うところの 3.5 相当らしいので、そうしておきます。これをやらなくてもDLLのビルドはできるのですが、プロセスにアタッチしようとした際にエラーが出て止まります。

厳密には Unity 3.5 .net SubsetBase Class Libraries を選ぶのが正しい ようです。.NET と Mono は微妙に異なる部分もあるようですし。

PROJECT > PROPERTIES > Application > Target frameworks:

f:id:AMANE:20141215213807j:plain

出力先を Assets/Plugins にする

いつも通りの $(SolutionDir)\(Configuration)\ な場所に出力したdllらをあとから Assets/Plugins にコピーすればいいかと思ったら、VSプロジェクトでのファイル構造などデバッグに必要な情報が、DLLファイルと一緒に書き出される .pdb ファイルに含まれているようで、ビルド→出力 の時点で、利用する場所に書き出される必要があるようです。

PROJECT > PROPERTIES > Build > (下の方)Output > Output path

f:id:AMANE:20141215214510j:plain

ブレイクポイントを使ったデバッグ

あらかじめ Solutionの Properties から、現在選択しているプロジェクトが実行されるようにしておくのがおすすめです。

f:id:AMANE:20141215214829j:plain

Unity Editorも起動した状態で、VSの方で今回デバッグしたいManaged Plugin のプロジェクトを選択し DEBUG > Attach Unity Debugger を実行すると、下のようなウィンドウが開きます。もしここが空欄だった場合は、一度 Unity の方で Play しておくと、出るかもしれません。

f:id:AMANE:20141215215355j:plain

これで該当の Unity の Project 名を選択すると、Unityに対してVSのデバッガがアタッチされ、待機状態になります。この状態でブレイクポイントを張って、Unity Editor に戻って Play します。確かに DLL 化された部分のコードでブレイクできています。

f:id:AMANE:20141215215826j:plain

つづきます

と、Managed な Plugin のデバッグ法について整理してみましたが、実際にManaged Plugin を作るシーンが余り思いつかないので、今回は助走です。

本命の Native Plugin のデバッグは次回の記事で扱います。

UnityでOpenCVを Native Plugin にして利用する (Windows)

はじめに

UnityでOpenCVを使いたい動機と下調べについては前回の記事に書きました

UnityでOpenCVSharpをつかってOpenCVする。マルチスレッドにもしてみる。 (Windows) - 自習室

今回は、OpenCVを native plugin 化して使う方法についてまとめます、というか、 @hecomi 先生のをなぞった時に出た問題点をまとめておきます

環境

参考にした記事

基本(ただしMac)

この記事で、@hecomi 先生が OpenCVを native plugin 化して使う方法についてまとめてくださっています。基本はこれですが、内容がMacでbundleな感じです。

Unity で OpenCV で作成したテクスチャをネイティブプラグイン経由で利用してみた - 凹みTips

公式の基本(ただし英語)

Windowsでのやり方は、公式のLive Trainingで簡潔に説明されていました。前半はC#でManagedなpluginの説明で、23分あたりから、C++で作る Nativeなプラグインの説明になっています。ランダム関数を回して適当に数値を返すだけのプラグインを例にしているので、英語ですがわかりやすいと思います。

Live Training: Introduction to Plugins - YouTube

dllを作ること自体は Visual Studio Expressでもできますが、作った native Pluginを使うことは、Unity Proでないとできません。このあたりはUnityの厳しいところですね。

応用 Windows8.1 で、DllNotFoundException への対処付き

また、 @hecomi 先生が別の記事で、OpenCVのスタティックライブラリをラップしたdllにする方法についてもまとめくださっています。この記事で通常のlibを使ってdllにするとDllNotFoundException が出る、と報告されていますが、私のところでは解消できましたので後ほど紹介します。

Unity と OpenCV を組み合わせて現実・仮想双方を加工した AR な世界を Oculus Rift 越しに覗いてみた - 凹みTips

やること

ここでは試しに、先述の Windows8.1 の環境下で、@hecomi さんの一つ目の記事でやられていた、 OpenCVでカメラキャプチャーしてウィンドウを開いて表示しつつ、Unity内でテクスチャとして利用する、をやってみようと思います。

手順

プロジェクトの作成

このあたりは、Unity - Writing Plugins を参考に。

  • Visual Studio
  • VC++ / Win32 Application を
  • Application type: DLL
  • Additional Options: EmptyProject でつくる

f:id:AMANE:20141212212952j:plain

OpenCV周りのプロジェクト設定をする

PROJECT > Properties からいろいろ下記のような設定します

追加のインクルードディレクトリ

OpenCV関連のヘッダを読めるようにします。適宜OpenCVをインストールした場所に読み替えてください

f:id:AMANE:20141208233647j:plain

OpenCVのスタティックリンクライブラリを利用する

OpenCVをせっかくdllとしてラップするので、別途 OpenCVのdll群を使わなくてもよいようにしたいです。ユーザにOpenCVをインストールさせたり、完成したアプリのフォルダ内にdllをたくさん含んだ状態で配布するのはちょっといけてない感じです。

そこで、OpenCVからリリースされている <OPENCV_ROOT>\build\x86\staticlib.lib ファイルたちを利用するように指定します。これを使って以下ので順でdllを作成すると、すべての .lib ファイルが一つのdllに固められて、そのdllだけをユーザに渡せばいい状態になります。

f:id:AMANE:20141212213158j:plain

ランタイムライブラリをマルチスレッド(/MT)に変更

ここは @hecomi さんの受け売りです。

f:id:AMANE:20141212212939j:plain

DLL化のためのおきまりのコードを書く

#include <iostream>

#define DLLExport __declspec (dllexport)

extern "C"
{
    DLLExport int GetRandom()
    {
        return rand();
    }
}

先ほど動画を貼ったLive Trainingでは、上記のようなコードで ランダムな数値をはき出すだけの機能を dll 化しています。同様の手法で@hecomiさんのこちらの記事では、OpenCVを使ってカメラをたたいたり、別ウィンドウで表示したり、Unityのテクスチャとして使えるようにしています。コードは @hecomiさんの記事を参考にされてください

DLL化のために必要なスタティックライブラリをリンクする

私の環境ですと、 @hecomiさんの記事 の通り だとライブラリが不足しているようで、unresolved external symbol エラーが大量発生します。エラーは下記のようなものたちで、多くはOpenCVのDLL本体に含まれているもののようです。これらもリンクするようにして、最終的には以下のような感じになります。

f:id:AMANE:20141212213644j:plain

このあたりは、こちらの記事様で勉強させていただきました

ビルド→Unityで使う

BUILD -> BUILD <Project Name>

で、ビルドされ、ReleaseなりDebugなりのフォルダに .dll ファイルが生成されます。

これを、Unityで Assets/Plugins/hoge.dll の位置に置きます

dllで定義された関数をUnityで利用する際は、以下のようにDllをインポートし関数を宣言するコードを用意し、オブジェクトにアタッチして使います。これは先述のUnity公式Live Trainingでの例です。

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

public class TestNative : MonoBehaviour
{
    [DllImport("RandomNumberDLL")]
    private static extern int GetRandom();

    // Use this for initialization
    void Start ()
    {
        print("Native Random Number: " + GetRandom());
    }

}

同様に @hecomi さんの記事を参考に、dllに定義したOpenCVを使った関数を呼び出してください

その2:スタティックライブラリを使わない場合

先述の Unity公式 live Trainingと同じやり方になります。

通常のライブラリファイルをリンクする

ProjectのPropertiesで staticlib フォルダを参照するように指定している追加のライブラリディレクトリを、 lib フォルダを参照するように書き換えます。

f:id:AMANE:20141212220007j:plain

ランタイムライブラリを /MD にする

f:id:AMANE:20141212220134j:plain

システム環境変数OpenCVのDLLのありかを通す

Path に以下の二つを記入します (F:\develop\opencv\ の部分は、ご自身の環境に合わせてください)

F:\develop\opencv\build\x64\vc12\bin; 
F:\develop\opencv\build\x86\vc12\bin;

はじめ x64 のものだけを追加していたのですが、 dll を 32bit でビルドしてたため、DllNotFoundException が発生しました。 x86 のbinもPathに通したら、エラーがなくなりました。

ビルドなど以下略

ここから先は、staticlibを使う場合と同じです

最後に

これで、 @hecomi さんの記事のように、カメラ画像がテクスチャに貼れて、同時に別ウィンドウが開きカメラ画像が見られたらOKです。

@hecomi さんありがとうございました。

UnityでOpenCVSharpをつかってOpenCVする。マルチスレッドにもしてみる。 (Windows)

はじめに

顔認識させつつ、ビデオスルーが遅れていないことを示そうとしたら、思いがけずEXILEっぽくなりました。こんばんは。

動機

OVRVISIONをしばらく前に手に入れて放置していたのですが、何か遊ぼうと思い、OpenCVを使ってみたくなりました。カメラ画にエフェクトかけてみたり。

@hecomi 先生のこれがど直球。これこれ。

Ovrvision で色んなエフェクト試してみた - 凹みTips

下調べ

最終的にOculus Riftとつなぎたいので、Unityでやります。 UnityでOpenCVを使う口のすてきな紹介記事様がこちら

UnityでOpenCVまとめ - 株式会社CFlatの明後日スタイルのブログ

  • OpenCVSharpが使いやすそう。こまめにアップデートされてるので安心感もある

  • しかしパフォーマンス落ちそうな気がするのとOpenCVならC++で書きたい、ってのとで、Unityのnative plugin化して使うのも押さえておきたい

というわけで二方向からトライすることにしました。今回はOpenCVSharpを使ってみます。

環境

ソフト
ハード

3年前のミドルエンド、のつもりデスクトップです。

基本をやってみる

まずは @kaorun55 先生

UnityでOpenCVを使う(Windowsアプリ)

これでとりあえずOpenCVSharpでカメラ画像を撮ってきてUnityで表示するとこまでできました

からの @kaorun55 先生!

せっかくだから顔認識とかしたいです。ここも @kaorun55 先生です。

OpenCVで顔検出した場所にUnityのGameObujectを追従させる

ありがとうございます、できました。

しかし、私の環境では 5~6 fps しか出ませんでした。これはつらいです。

顔認識のマルチスレッド化

認識に足を引っ張られて動画がかくかくなのはかっこわるいので、撮ってきた画像を表示しつつUnityのオブジェクトを描画するスレッドと、顔認識をするスレッドを分けましょう。

お勉強

C# のマルチスレッドの書き方を全く知らなかったのでそこの勉強からです

lockステートメントが大変便利ってことがわかった!

やってみる(本記事のメイン)

Post Position 【Unity】 スレッドを使う 記事様のやり方で二つスレッドをたて、 OpenCVで顔検出した場所にUnityのGameObujectを追従させる 記事様でやっているカメラ画像の取得と顔認識の処理をそれぞれのスレッドでやる、という方針です。

詳細はこのあたりのコードをご覧ください

UnityOpenCVSharp/FaceDetectThreaded.cs at master · izmhr/UnityOpenCVSharp · GitHub

一考

結局顔認識が 5~7 fps なのは変わっていません。

ビデオスルーがなめらかになったのは良かったのですが、顔認識が遅れているので、顔とは異なる場所にCubeが表示されてしまいます。「顔を隠す」などアプリ次第では、ビデオスルーを遅くしてでも顔認識と画像が同期している方が適切な場合もあるかもしれません。

逆に、遅い顔認識の結果を補間(予測)して使う、という方向性もあるかと思いますが、難しそうなのでまたいつか。

(おまけ) カメラ画像が崩れているのを修正

@kaorun55 さんの記事では、CVのカメラで撮ってきた画像をUnityのオブジェクトに貼り付ける際に、bmpにしたところで画像が乱れていました。これはOpenCVSharpのバグなのでしょうか…*1

f:id:AMANE:20141206230112j:plain

試行錯誤の結果なので最適とはいえませんが、修正の仕方を見つけたので報告いたします。

Jpegを経由する

実際はばらばらの場所で行っていますが、行った処理だけ抜粋します

// カメラ画像取得
// static Mat capImage;
video.Read (capImage );

// jpegのバイナリに変換
// static byte[] cvtImageJpeg;
cvtImageJpeg = capImage.ImEncode(".jpg");

// テクスチャデータとする
texture.LoadImage(cvtImageJpeg);
texture.Apply();

これでテクスチャ内での画像ずれが無くなりました

さいごに

今回のコードはGitHubにあげてあります。

izmhr/UnityOpenCVSharp · GitHub

OpenCVSharp/OpenCV の dll のたぐいは @kaorun55 さんの記事 UnityでOpenCVを使う(Windowsアプリ) を参考に入れ直してください。

*1: ちょうど最新のリリースで Mat -> Bitmap 変換のバグの修正が入ったようなのですが、これが関係しているのでしょうか…? Release 2.4.10 (11 Nov., 2014) · shimat/opencvsharp · GitHub

JavaScriptでニュートン法を用いて三次方程式を解いて、ついでにグラフも描く

初めに

完成品

ここで動きます

動機

そもそもの目的は、楕円の法線を求めるために四次方程式を解くことだったのですが、まずは手始めに三次方程式を解くことにしました。結果、高校時代に勉強した内容を思い出して、懐かしいような気分に浸れて、変な楽しさがありました(笑)

解の公式を使えば良いのでは?

三次方程式も四次方程式も解の公式が知られていますが、たとえば三次方程式を解く「カルダノの方法」だと、

{ \displaystyle
B = x^{3} - 15x - 4
}

という式を解いて x = 4 を算出することが出来ないなど、汎用性の乏しさが知られています。

三次方程式 - Wikipedia

ニュートン法を使う

この手の計算では一般的に使われているらしいニュートン法を利用する事にしました。

Newton 法による方程式の近似解法

三次方程式は実数解を最低ひとつは持つことが明かですので、まずはニュートン法で実数解をひとつ求めて、残りの解(虚数解も含む)を求めるような関数を作ります。

コード

コードはこちらに上げてあります。

izmhr/newtonCubicEquation · GitHub

場合分け

ポイントだけ解説します

計算をやりやすくするために、特徴的な係数や特徴的な解が得られる場合をあらかじめ場合分けします。やり方にはいろいろあると思いますが、今回のプログラムで採用している場合分けについて紹介します。

{
f(x) = ax^{3} + bx^{2} + cx + d = 0
}

を解きます。

解に0 が含まれる場合

言い換えると、定数項 {d=0}の場合。

{ \displaystyle
f(x) = ax(x^{2} + \frac{b}{a}x + \frac{c}{a}) = 0
}

を解くことになります。 これは一般的な二次方程式の判別式を用いて、残りの2解がどうなるかを場合分けします

{
D = b^{2} - 4ac
}

とすると、

  • { D \gt 0} なら、0に加えて異なる実数解が2つ
  • { D = 0} なら、0に加えて、実数の重解1組
  • { D \lt 0} なら、0に加えて、共役虚数解1組

がそれぞれ存在します。

解に0が含まれない場合は、ニュートン法を用いて、1つ目の実数解を求める

が、そこであたえた近似開始値が解そのものだった場合

ニュートン法の近似開始値 {x_k} に対して

{
ax_k^{3} + bx_k^{2} + cx_k + d = 0
}

この{x_k} をそのまま解の1つ目の実数解として利用する

近似開始値が、極値をとるxであった場合

この場合、ニュートン法が収束しなくなるので、別の近似開始値 {x_k} を使うよううながす。私のプログラムでは0.1加えるようにしているが、万能ではないのでご注意です。

ニュートン法で1つ目の実数解が求まった後

ここでも判別式を利用する。ここで利用する解のパタンを判別する式については、こちらのサイトが詳しいです

http://www2.odn.ne.jp/~aai55890/donnwa2/sanzihannbetu.htm

 {
D_1 = b^{2} - 3ac
}

 {
D_2 = 27a^{2}b^{2} - 18abcd - b^{2}c^{2} + 4b^{3}d + 4ac^{3}
}

  • { D_1} は、{ f^{'}(x)} の判別式。グラフの形状の把握に使う。
  • { D_2} は、{f(x)}極値 {f(\alpha), f(\beta)} に対して、{f(\alpha)f(\beta)} で算出される値で、これも判別式として利用する。x軸との交差回数の判定のために使います

詳細は先ほどのサイトに。

{ D_1 \gt 0} かつ { D_2 \lt 0} のとき

ことなる実数解3つが存在する。1つ目の実数解{x_0}を用いると、解きたい方程式は

{
f(x) = ax^{3} + bx^{2} + cx + d = ax(x - x_0)(x^{2} + Ax + B) = 0
}

と書き直すことが出来、二次方程式を解けば良いことになる。

{ D_1 \gt 0} かつ { D_2 = 0} のとき

このとき、異なる実数解2つで片方は重解になる。 ここで、先のニュートン法で求まった実数解が重解の一部である場合と、独立した解である場合の2通りがあり得る。

ここで、{ x^{2} + Ax + B = 0} が、重解を持てば、{x_0} は単独の解であったということになりますが、{x_0}ニュートン法で求めた解であるため、導き出されるAやBも、誤差を含む値になります。従って、 { x^{2} + Ax + B = 0} が重解を持つかどうかの判別は、

{ A^{2} - 4B = 0}

ではなく

{|A^{2} - 4B| \lt Thresh}

(ここで Threshは、十分に小さい値) という形で行うことになります。 これが満たされれば、{ x^{2} + Ax + B = 0} は重解を持ち、元の{x_0} に加えてもう1解算出すれば良いです。

満たされていない場合は、

{
f(x) = ax^{3} + bx^{2} + cx + d = ax(x - x_0)^{2}(x - x_1) = 0
}
{ x_1 = -\frac{d}{x_0^{2}a}}

が、もう一つの解になります。

それ以外の場合

実数解は初めの1つだけで、残りは共役な虚数解を持つことになります

ウェブアプリとして仕上げる

機能

機能として、以下の様な物を実装しています

  • 主要機能
  • 可視化関連の機能
    • 与えられた三次関数のグラフを描画
    • 実数解をプロット
    • グラフのズームの調整
  • (おまけ) 手っ取り早く試せるよう、サンプルの関数を5つプリセット

CreateJS を利用

グラフの描画は、Canvasに対してCreajteJSを使って行っています。D3などの利用も考えましたが、最近よく使っていて手が慣れてたのでCreateJSを利用しました。

さいごに

  • 算術
  • Canvasの描画
  • ツールとして機能を設計してまとめ上げる
  • htmlのインプットタグなどを使いこなす

など、結構やることが多くて、勉強になりました。インプットタグを使うのが意外としんどかったです。

実際は虚数解が必要になるようなケースはあまりないので、正しい制約下で必要な実数解を最短で算出することが求められるようなことの方が多いでしょう。まだほとんど知らないのですが、次は非線形最適化のツールなど使ってみようと思っています。

 {
Y(n) = a_nX(n) + a_{n-1}X(n-1)
}

改善版 reverse_iterator 使用中のerase()の仕方

2010年5月の記事にコメントいただいた

reverse_iterator使用時のerase()の仕方 - 自習室

この記事に、メモリ衝突が起きるよ、というコメントをいただきました。

自分がこの記事を書く際に使ったコードが見当たらなかったので、改めてそれらしく書いてみました。確かに、イテレータの進め方など結構気を遣わないと、直ぐ見つからないところを叩いたりしてしまうクソコードでした。

不理解だったところ

reverse_iterator が、通常の iterator のアダプター(特定の目的のためにラップして使いやすくする)オブジェクトだ、ということを理解しておりませんでした。

このページの一番上の図と説明が分かりやすい。

std::reverse_iterator - cppreference.com

Reverse iterator stores an iterator to the next element than the one it actually refers to
リバースイテレータは、そのリバースイテレータが指している要素の(正順での)一個先を指している(正順)イテレータを保持している

と書いてある。関係性を式で表すとこうなる

&*r == &*(i-1)

そうすると確かに、erase のために、現在見ている reverse_iterator に対応する iterator を取得しようと思ったら、 base() で対応するイテレータを取得した後、一個戻す、が仕様上正しい操作だ、という気がしてきます。

hogelist.erase(--(hoge_ri.base()));

ここまでの内容を図解したのが下の図。

f:id:AMANE:20141102174443p:plain

標準iteratorとしてerase()したあと、リバースイテレータはどこを指しているのか?

この点は自分もいろいろ混乱したので、図解します。

f:id:AMANE:20141102174454p:plain

上でも書いたように、リバースイテレータは通常のイテレータのアダプタというかラッパなので、本体であるイテレータが指すものから上記関係式で導き出される対象を指しています。erase()した結果、通常イテレータの場所は変化していませんが、それに対応するリバースイテレータが、リスト上では一個前に進んだことになります。

従って、ri++ で(逆向きに)進んでいたとしたら、erase() した時には、ri は自動的に次の要素を指しているので、ri++ は不要、と言うことになります。

サンプルコード

charとint をメンバに持つクラスHogeのlistを作り、その中からユーザのキーボード入力で指定されたintの値を持つhogeを一個ずつ消していく、という内容です。このサンプルでは、特にリバースである必然性はありません。

そもそも2010年の元記事でリバースイテレータを使った理由は、OpenGLで描画をしながら、不要になったオブジェクトを消す、と言う操作を、1回の反復操作で行いたい、というものでした。OpenGLでは後から描いた物が先に描いた物の手前に上書きされるので、リストの作り方次第では、逆順に描画をコールしたいケースが発生します。

全文はこちら

リバースイテレータでリストを回しながら、 時折 erase を行う

大事なとこだけ抜粋します

while(hoge_ri != hogelist.rend())
        {
            if(hoge_ri->check(value)) //当該Hogeインスタンスが value と同値のメンバを持っていたら
            {
                hogelist.erase(--(hoge_ri.base())); // 消す(と同時に進んでいる)
                cout << "###erase### " << value << endl;
            }
            else
            {
                hoge_ri->print(); // 持ってなかったら標準出力して
                hoge_ri++;  //進める
            }
        }

先述の注意点の通り、消したときは、hoge_ri を ++ しておりません。

最後に

そもそもリバースイテレータを必要としない構造で書いた方が、可読性も上がるし良いよなーと思いました。

CreateJSで 2D 線分の交差判定

はじめに

2Dにおける物体どうしの衝突判定アルゴリズム、またはその一部として、線分同士の交差判定が必要になりました。

f:id:AMANE:20141028222308p:plain

アルゴリズム

今回は、こちらの記事を忠実に実装させていただきました

2D衝突編 その10 線分と線分の衝突

線分ですので、

  • 始点 + ベクトル(長さを持つ)
  • 始点 + 終点

のいずれかが分かっていれば良いのでお気楽です。数回の外積計算でフィニッシュです

実装

コードはgithubにあげました

izmhr/lineCrossing · GitHub

使ってるライブラリ

EaselはCanvasを使いやすくラップしてくれているライブラリです。愛しています。

Victorは、2Dのベクトル関連計算のライブラリで、長さを求めたり、内積外積を計算したり、回転指せたりお手の物です。それにベクトルを「定数倍」する関数が無かったので、足した、気がします。

staticな関数もあるvector2dの決まり手的ライブラリってどれなんだろう…教えてエロイひと

ポイントだけ

side.js (辺、の意のつもり) line15 が、公差判定の関数です

Side.prototype.crossing = function(_start, _end)
{
  // http://marupeke296.com/COL_2D_No10_SegmentAndSegment.html

  var v = this.start.clone().subtract(_start);
  var v1 = _end.clone().subtract(_start);
  var v2 = this.end.clone().subtract(this.start);

  if(v1.cross(v2) == 0) return false;

  var t2 = v.cross(v1) / v1.cross(v2);
  var t1 = v.cross(v2) / v1.cross(v2);

  if( 0 <= t2 && t2 <= 1 && 0 <= t1 && t1 <= 1)
  {
    // crossing point
    var cp = _start.clone().add(v1.scalarMultiply(t1));
    this.color = '#f33';
    return {point: cp, distance: t1};
  }
  else
  {
    this.color = '#fff';
    return false;
  }
}

_start _end は、交差する候補の線分の始点終点です。

変数名は、元記事様の変数名と合わせてあります。

線分同士が交差していたら、その {交点と、始点から交点までの距離} を返します。交差していなかったらfalseを返します。

サンプルプログラム

サンプルでは、三つの線分と回転し長さを変えられる線分を用意し、回転する線分の始点から見て、線分との交点の中で最も近い点を検出する、ような物にしてみました。

複数物体や複雑形状への衝突判定に利用するイメージです。

いじょうでふ