2014年1月11日土曜日

64bit版 Debian Jessie でSkypeを使う

インストール

skype - Debian Wiki を参照。

起動オプションの修正

skype が不安定だったり、音声通話ができなかったりする場合の対応。Re: Sound in Debian unstable 64bit broken? で示されているように、環境変数として PULSE_LATENCY_MSEC=30 を設定する。PulseAudio 3.x もしくは 4.x と skype の組み合わせに問題があるらしい。

以下、GNOME3での設定方法。

$ alacarte
もしくは「システムツール → メイン・メニュー」で起動ショートカットを編集する。skype の項目を選択して、「プロパティ → コマンド」を
skype %U
から
env PULSE_LATENCY_MSEC=30 skype %U
へ変更する。

2013年12月20日金曜日

テンキーでサウンド関係の操作を行う (GNOME)

フルキーボードのテンキーはなかなか使う機会がなく、テンキーレスキーボード欲しい症候群を発症しています。が、お値段を見て腰が引けているところでもあります。今回は不遇なテンキーを音量調整と曲の頭出し、再生停止・開始に割り当てるお話です。

GNOMEだと話はとても簡単で、「設定」→「キーボード」→「独自のショートカット」で好きなコマンドを割り当てるだけで完了です。以下割り当てるコマンドについてのメモ。

amixer

まずは音量調整について。システム音量調整にはamixerコマンドが利用できます。詳しくはman amixerで調べるとよいのですが、今回は結果だけ。

# マスター音量を5%上げる
amixer set 'Master' 5%+
# マスター音量を5%下げる
amixer set 'Master' 5%-

rhythmbox-client

音楽再生にはRhythmboxを使っていますので、rhythmbox-clientコマンドが使えます。

# 一時停止・再生の切り替え
rhythmbox-client --play-pause
# 次の曲を再生
rhythmbox-client --next
# 前の曲を再生
rhythmbox-client --previous

2013年11月27日水曜日

位置座標から3次元グリッドのインデックスを検索する (Python & NumPy)

はじめに

定義:

グリッド
3つのインデックス i, j, k で指定できる3次元位置座標の集合。
セル
グリッドに含まれる座標のうち、
(i, j, k), (i+1, j, k), (i+1, j+1, k), (i, j+1, k), (i, j, k+1), (i+1, j, k+1), (i+1, j+1, k+1), (i, j+1, k+1)
の8つで構成される平面に囲まれた空間。グリッドの最大インデックスが (I, J, K) であるとき、セルの最大インデックスは (I-1, J-1, K-1).

目標:

  • 3次元空間内の任意の位置座標 p を含むセルのインデックス (i, j, k) を求める。

方針

  • p からセルの構成面 s へのベクトル
  • セル構成面の外向き法線ベクトル
の内積を計算します。計算結果がすべて0以上であれば、p はセル内もしくはセル構成面上に存在するはずです。

言語は Python3.3, 数値計算用ライブラリ NumPy を利用します。NumPy の練習も兼ねて。

書いてみた

座標からインデックスを求めるよりも、グリッドと法線ベクトル生成に多く時間が取られるスクリプトになってしまいました…。はたしてこれで正しいのかどうか。

import numpy
import time


def get_normals(face_triangles):
    return numpy.cross(face_triangles[:,:,1] - face_triangles[:,:,0],
                        face_triangles[:,:,2] - face_triangles[:,:,0])


def get_cells(points, grid_shape):
    cells_shape = numpy.array(grid_shape[:3]) - 1
    num_of_cells = numpy.multiply.reduce(cells_shape)
    face_triangles = numpy.zeros([num_of_cells, 12, 3, 3], dtype=numpy.float)
    points_on_face = numpy.zeros([num_of_cells, 12, 3], dtype=numpy.float)
    i, j, k = (0, 0, 0)
    dj, dk = (grid_shape[0], grid_shape[0] * grid_shape[1])
    for index in range(num_of_cells):
        if i == cells_shape[0]:
            i = 0
            j += 1
        if j == cells_shape[1]:
            j = 0
            k += 1
        base_i = i
        base_j = dj * j
        base_k = dk * k
        next_i = i + 1
        next_j = dj * (j + 1)
        next_k = dk * (k + 1)
        face_triangles[index] = ((points[i + base_j + base_k],
                                  points[next_i + next_j + base_k],
                                  points[next_i + base_j + base_k]),
                                 (points[i + base_j + base_k],
                                  points[i + next_j + base_k],
                                  points[next_i + next_j + base_k]),
                                 (points[i + base_j + next_k],
                                  points[next_i + base_j + next_k],
                                  points[next_i + next_j + next_k]),
                                 (points[i + base_j + next_k],
                                  points[next_i + next_j + next_k],
                                  points[i + next_j + next_k]),
                                 # y-z
                                 (points[i + base_j + base_k],
                                  points[i + next_j + next_k],
                                  points[i + next_j + base_k]),
                                 (points[i + base_j + base_k],
                                  points[i + base_j + next_k],
                                  points[i + next_j + next_k]),
                                 (points[next_i + base_j + base_k],
                                  points[next_i + next_j + base_k],
                                  points[next_i + next_j + next_k]),
                                 (points[next_i + base_j + base_k],
                                  points[next_i + next_j + next_k],
                                  points[next_i + base_j + next_k]),
                                 # z-x
                                 (points[i + base_j + base_k],
                                  points[next_i + base_j + next_k],
                                  points[i + base_j + next_k]),
                                 (points[i + base_j + base_k],
                                  points[next_i + base_j + base_k],
                                  points[next_i + base_j + next_k]),
                                 (points[i + next_j + base_k],
                                  points[i + next_j + next_k],
                                  points[next_i + next_j + next_k]),
                                 (points[i + next_j + base_k],
                                  points[next_i + next_j + next_k],
                                  points[next_i + next_j + base_k]))
        points_on_face[index, 0::4] = points[i + base_j + base_k]
        points_on_face[index, 1::4] = points[i + base_j + base_k]
        points_on_face[index, 2::4] = points[next_i + next_j + next_k]
        points_on_face[index, 3::4] = points[next_i + next_j + next_k]
        i += 1
    normals = get_normals(face_triangles)
    return (normals, points_on_face)


def get_indices_from_coordinate(coordinate, normals, points_on_face):
    vectors = points_on_face - coordinate
    dotprods = numpy.einsum('ijk, ijk->ij', vectors, normals)
    is_coord_back_of_face = numpy.greater_equal(dotprods, [0])
    return numpy.where(numpy.all(is_coord_back_of_face, 1))[0]


if __name__ == "__main__":
    grid_shape = [37, 25, 54]
    num_of_points = numpy.multiply.reduce(grid_shape)
    delta = [1.0, 1.0, 1.0]
    points = numpy.zeros([num_of_points, 3])
    i, j, k = (0, 0, 0)
    start = time.clock()
    for index in range(num_of_points):
        if i == grid_shape[0]:
            i = 0
            j += 1
        if j == grid_shape[1]:
            j = 0
            k += 1
        points[index] = (delta[0] * i, delta[1] * j, delta[2] * k)
        i += 1
    lap1 = time.clock()
    normals, points_on_face = get_cells(points, grid_shape)
    testpoint = numpy.random.rand(3) * 100
    lap2 = time.clock()
    indices = get_indices_from_coordinate(testpoint, normals, points_on_face)
    lap3 = time.clock()
    if len(indices) is 0:
        print(" ".join(["({0[0]}, {0[1]}, {0[2]})".format(testpoint),
                         "is not included in the cells."]))
    for index in indices:
        print(" ".join(["({0[0]}, {0[1]}, {0[2]})".format(testpoint),
                         "is included in cell {}".format(index)]))
    print("lap1: {}\nlap2: {}\nlap3: {}".format(lap1 - start,
                                                 lap2 - lap1,
                                                 lap3 - lap2))

次回、壁面衝突判定の予定

2013年10月14日月曜日

Multiple Dygraph in Twitter Bootstrap based Tab

This post is a response to "Multiple Dygraph is not working in Twitter bootstrap based Tab !"

Bootstrap の tab に dygraph.js でグラフを描画している時に、「タブを切り替えるとグラフが正しく描画されない」という問題があります。より正確に言えば、「初期状態で非表示の領域にグラフを描画すると問題がおきる」でしょうか。

参考:Issue 238 - dygraphs - Canvas & container div have zero height and width when parent is invisible.

対策としてはリンク先でも述べられている通り、グラフが格納された div 要素が表示されたら、 Dygraph インスタンスの .resize() メソッドを実行すれば表示はされます。ただし、高さと幅が初期値に固定されてしまいます。これを防ぐために、描画領域の要素から style プロパティを削除しています。

Nginx 最新版を Raspberry Pi にインストールする

WebSocket をリバースプロキシに通す必要がありまして、Nginx を使うことにしました。ただ Raspbian 公式リポジトリではバージョン 1.2 が提供されています。WebSocket のリバースプロキシには Nginx 1.3 以降で対応しているそうなので、以下の方法で最新版をインストールしました。以下の記事が参考になりました。(ほぼそのまま)

/etc/apt/sources.list に以下の2行を追記。

deb http://nginx.org/packages/debian/ wheezy nginx
deb-src http://nginx.org/packages/debian/ wheezy nginx
以下のコマンドを実行。
$ sudo apt-get update
$ sudo apt-get build-dep nginx
$ sudo apt-get source nginx
$ cd nginx-1.4.3
$ sudo dpkg-buildpackage -uc -b
$ sudo dpkg -i nginx_1.4.3-1~wheezy_armhf.deb

2013年10月5日土曜日

ファイルをブラウザにダウンロードさせる (Python, Tornado Web Server)

たとえばCSVファイルをダウンロードさせる場合。

class FileHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Content-Type', "text/csv")
        self.set_header('Content-Disposition',
                        "attachment; filename=\"{}\"".format(filename))
        self.set_header('Content-Length', os.path.getsize(filename))
        with open(filename, 'rb') as fp:
            self.write(fp.read())

2013年9月13日金曜日

Pythonで無線LANのSSIDをスキャン

Raspberry Pi で、無線LANアダプタが認識しているSSIDを調べる必要が出てきたので。

まずはシステムコマンドの確認から。wlan0 について調べる場合は、

$ sudo iwlist wlan0 scan | grep 'ESSID:".\+"'
で一覧が取れます。grep のあとについてる正規表現でESSIDが空になっている行を弾いています。このコマンドで取れる応答は、
    ESSID:"ssid1"
    ESSID:"ssid2"
    ...
のようになっています。これをpythonで受け取り、SSIDだけ抜き出してリストにします。
#!/usr/bin/python3
import subprocess

stdout = subprocess.check_output("iwlist wlan0 scan | grep 'ESSID:\".\+\"',
                                 shell=True)
ssid_list = [line.lstrip('ESSID:').strip('"') for line in stdout.split()]
以上。