InteractionBox を 使 う ここでは Leap Motion の 座 標 を 変 換 する 方 法 について 解 説 し * Leap Motion V1 では いくつかの 座 標 変 換 の 方 法 がありましたが Leap Motion V2 では InteractionBox の 変 換 のみとなっています より 正 確 には インターセクション ポイント (Intersection Poi nt)および プロジェクション ポイント (Projection Point)V1.2 から 非 推 奨 となりました InteractionBox のイメージは 次 の 図 です 指 がウィンドウのどの 位 置 にいるか ということを 知 ることができま す これを 使 ったプログラムは 4-2 お 絵 かきツールを 作 成 する で 解 説 してい 変 換 された 位 置 の 動 きを 見 る InteractionBox がどのように 動 作 するのか 見 てみましょう プログラム 全 体 のコードは InteractionBox01 にあり InteractionBox を 模 した 枠 の 中 を 指 の 位 置 を 表 わした 球 が 動 き InteractionBox のイメージ このプログラムの 実 行 結 果 Leap Motion の 逆 ピラミッドの 中 に 直 方 体 の 検 出 環 境 を 作 り この 直 方 体 の 左 下 奥 を(0,0,0)として 0 から 1 までの 範 囲 で 値 が 変 化 し たとえば この 値 にウィンドウの 幅 や 高 さ を 掛 けることで 2
update() フレームの 更 新 と 各 座 標 の 取 得 を 行 ない InteractionBox からは 中 心 の 座 標 と 幅 高 さ 奥 行 き がそれぞれ 取 得 ( 単 位 はすべて mm(ミリメートル))できるので 計 算 して 左 右 上 下 前 後 の 位 置 を 求 め void update() // フレームの 更 新 mlastframe = mcurrentframe; mcurrentframe = mleap.frame(); ibox = mcurrentframe.interactionbox(); mleft = ibox.center().x (ibox.width() / 2); mright = ibox.center().x + (ibox.width() / 2); mtop = ibox.center().y + (ibox.height() / 2); mbaottom = ibox.center().y (ibox.height() / 2); mbackside = ibox.center().z (ibox.depth() / 2); mfrontside = ibox.center().z + (ibox.depth() / 2); renderframeparameter(); renderframeparameter() 幅 高 さ 奥 行 き の 値 を 表 示 し void renderframeparameter() ss << "Width :" << ibox.width() << "mm" << " n"; ss << "Height:" << ibox.height() << "mm" << " n"; ss << "Depth :" << ibox.depth() << "mm" << " n"; ss << "Center:" << ibox.center() << " n"; drawleapobject() drawinteractionboxframe() で InteractionBox の 枠 を 描 画 し drawfingerpoint() で InteractionBox 内 の 指 の 位 置 を 描 画 し 3 4
void drawleapobject() // 表 示 処 理 drawinteractionboxframe(); drawfingerpoint(); drawinteractionboxframe() update() で 求 めた 頂 点 の 座 標 から InteractionBox の 枠 を 描 画 し void drawinteractionboxframe() // 中 心 点 //gl::drawsphere( tovec3f( ibox.center() ), 5 ); // 上 面 gl::drawline( Vec3f( mleft, mtop, mbackside ), Vec3f( mright, mtop, mbackside ) ); gl::drawline( Vec3f( mleft, mtop, mfrontside ), Vec3f( mleft, mtop, mbackside ) ); // 下 面 gl::drawline( Vec3f( mleft, mbaottom, mbackside ), Vec3f( mright, mbaottom, mbackside ) ); gl::drawline( Vec3f( mright, mbaottom, mbackside ), Vec3f( mright, mbaottom, mfrontside ) ); gl::drawline( Vec3f( mright, mbaottom, mfrontside ), Vec3f( mleft, mbaottom, mfrontside ) ); gl::drawline( Vec3f( mleft, mbaottom, mfrontside ), Vec3f( mleft, mbaottom, mbackside ) ); // 側 面 gl::drawline( Vec3f( mleft, mtop, mfrontside ), Vec3f( mleft, mbaottom, mfrontside ) ); gl::drawline( Vec3f( mleft, mtop, mbackside ), Vec3f( mleft, mbaottom, mbackside ) ); gl::drawline( Vec3f( mright, mtop, mbackside ), Vec3f( mright, mtop, mfrontside ) ); gl::drawline( Vec3f( mright, mtop, mfrontside ), Vec3f( mright, mbaottom, mfrontside ) ); gl::drawline( Vec3f( mright, mtop, mfrontside ), Vec3f( mleft, mtop, mfrontside ) ); gl::drawline( Vec3f( mright, mtop, mbackside ), Vec3f( mright, mbaottom, mbackside ) ); 5 6
drawfingerpoint() 人 差 し 指 の 座 標 を 描 画 し void drawfingerpoint() // 人 差 し 指 を 取 得 する Leap::Finger finger = mleap.frame().fingers().fingertype( Leap::Finger::Type::TYPE_ INDEX )[0]; if (!finger.isvalid() ) return; 2 次 元 の 位 置 座 標 として 利 用 する InteractionBox で 変 換 された 位 置 割 合 のうち X,Y を 使 うこと で 2 次 元 の 位 置 座 標 として 利 用 することができ Leap::Vector normalizedposition = ibox.normalizepoint( finger.tipposition() ); // 位 置 の 割 合 から 実 際 の 座 標 を 計 算 // 原 点 を 左 下 奥 にする auto x = (normalizedposition.x * ibox.width()) + mleft; auto y = (normalizedposition.y * ibox.height()) + mbaottom; auto z = (normalizedposition.z * ibox.depth()) + mbackside; gl::drawsphere( Vec3f( x, y, z ), 5 ); プログラム それではコードを 見 てみましょう 全 体 のコードは InteractionBox02 にあり 現 在 のフレームで 検 出 された 指 から 人 差 し 指 を 取 得 し その 指 が 有 効 であれば 指 先 の 座 標 を InteractionBox の 位 置 に 変 換 し 変 換 された X,Y,Z の 位 置 に 幅 高 さ 奥 行 き の 値 を 掛 け 原 点 ( 左 下 奥 ) 中 心 にすることとで InteractionBox の 座 標 になり 7 8
draw() でき 変 換 したい 座 標 を Leap::InteractionBox::normalizePoint () に 指 定 し normalizepoint() で 返 される 座 標 系 は InteractionBox の 左 下 奥 が 原 点 となり それぞれ 右 上 手 前 方 向 に 0 から 1 の 範 囲 の InteractionBox の 位 置 の 割 合 で 変 化 し ここでは あらかじめ 取 得 した 人 差 し 指 の 座 標 を 変 換 してい InteractionBox の 座 標 に 変 換 し // 人 差 し 指 を 取 得 する Leap::Finger finger = mleap.frame().fingers().fingertype( Leap::Finger::Type::TYPE_IN DEX )[0]; if (!finger.isvalid() ) return; // InteractionBoxの 座 標 に 変 換 する Leap::InteractionBox ibox = mleap.frame().interactionbox(); Leap::Vector normalizedposition = ibox.normalizepoint( finger.stabilizedtipposition () ); InteractionBox は Leap::Frame::interactionBox() で 取 得 normalizepoint() で 返 される 座 標 系 これを スクリーン(ウィンドウ)の 座 標 に 変 換 し // ウィンドウの 座 標 に 変 換 する float x = normalizedposition.x * WindowWidth; float y = WindowHeight (normalizedposition.y * WindowHeight); X 座 標 はそのままウィンドウサイズを 掛 ければよいのですが Y 座 標 は InteractionBox の 原 点 が 下 ウィンドウの 原 点 が 上 9 10
なので 上 下 を 反 転 してい 位 置 が 緑 色 で 表 わされ ホバー 状 態 タッチと 判 定 されると 指 の 位 置 が 赤 くなり これで 指 の 位 置 をスクリーン(ウィンドウ)の 位 置 に 合 わせることがで きました タッチ 状 態 を 判 定 する ここまでで Leap Motion の 座 標 とスクリーン(ウィンドウ)の 座 標 を 結 び 付 けることができました ここにタッチスクリーンでのタッチ 状 態 を 模 擬 した 判 定 を 加 えること で 非 接 触 のタッチスクリーンを 実 現 でき Leap Motion SDK では タッチの 判 定 を API としてもっており そ れを 利 用 することで 簡 単 に 実 装 でき 先 のプログラムにタッチの 判 定 を 追 加 することで 次 のように 動 作 し ホバー 状 態 ( 指 を 検 出 しているがタッチはしていない 状 態 )では 指 の 11 タッチ 状 態 非 接 触 のインターフェイスでは 操 作 しようとしている 位 置 (ここでは 指 )がわかりづらいことが 難 点 です ホバー 状 態 を 明 確 に 判 定 することで これからタッチしようとしてい る 位 置 をユーザーに 知 らせることができ より 使 いやすい 操 作 体 系 を 提 12
供 でき プログラム それではコードを 見 てみましょう 全 体 のコードは InteractionBox03 にあり ほとんどのコードは InteractionBox02 であり タッチの 判 定 コー ドのみ 追 加 してい void draw() // ウィンドウの 座 標 に 変 換 する float x = normalizedposition.x * WindowWidth; float y = WindowHeight (normalizedposition.y * WindowHeight); // ホバー 状 態 if ( finger.touchzone() == Leap::Pointable::Zone::ZONE_HOVERING ) gl::color(0, 1, 0, 1 finger.touchdistance()); // タッチ 状 態 else if( finger.touchzone() == Leap::Pointable::Zone::ZONE_TOUC HING ) gl::color(1, 0, 0, finger.touchdistance()); // タッチ 対 象 外 else gl::color(0, 0, 1,.05); gl::drawsolidcircle( Vec2f( x, y ), 20 ); 指 の 位 置 を 描 画 する 前 に タッチ 状 態 によって 色 を 変 えてい タッチの 状 態 は Leap::Pointable::Zone 列 挙 体 で 定 義 され Leap::Pointable::touchZone() で 取 得 でき Leap::Pointable::Zone 列 挙 体 には 次 の 値 があり 値 意 味 ZONE_NONE タッチでもホバーでもない ZONE_HOVERING ホバーしている ZONE_TOUCHING タッチしている また タッチ 状 態 の 度 合 い(タッチの 深 さ)を 取 得 することもでき この 値 は Leap::Pointable::touchDistance() で 取 得 でき タッチの 状 態 (touchzone()の 値 )と タッチの 度 合 い (touchdi stance()の 値 )の 関 係 は 次 のようになり Leap Motion でタッチを 判 定 する 13 14