2016年12月20日火曜日

Pharoからgnuplotでsin(x)

UnifiedFFIを使ってC言語の関数を呼べたので、 Pharoからgnuplotを呼び出してみた。

呼び出す関数は、以前書いたgnuplotへのpipeを開いて コマンドを書き込む以下の関数。

/* gpdo.c */
#include <stdio.h>

FILE *gpstart(void);
void gpstop(FILE *p);
void gpdo(FILE *p, char *s);

FILE *gpstart(void) {
    /* start gnuplot process */
    return popen("gnuplot.exe --persist", "w");
}

void gpstop(FILE *p) {
    /* stop gnuplot process */
    gpdo(p, "quit");
    pclose(p);
}

void gpdo(FILE *p, char *s) {
    /* send command string to gnuplot process */
    fprintf(p, s);
    fprintf(p, "\n");
    fflush(p);
}

Windowsのgcc(MinGW)で共有ライブラリにします。

gcc -shared -o gpdo.so gpdo.c
出力されたgpdo.soをPharo.exeがあるフォルダに配置しました。

と同様に、Pharoを起動してFFILibraryを継承したライブラリファイルを示す クラスGnuplotDoLibを作成しました。そのクラスに、win32ModuleNameメソッド を追加し、共有ライブラリのファイル名を返すようにします。

win32ModuleName
    ^ 'gpdo.so'

次は、関数呼び出し用のクラスを作ります。Objectクラスを継承してGnuplotDoクラスを 作りました。メソッドは関数を呼び出すだけなので、クラス側のメソッドにします。 これで、呼び出すときにわざわざインスタンスを生成する必要がなくなります。 三つの関数についてそれぞれメソッドを追加しました。 FILE構造体へのポインタ(FILE *)については、 今回はPharo側で解釈する必要がない(メンバーにアクセスしたりしない)ため、(void *)とします。

gpOpen
    ^ self ffiCall: #(void * gpstart ()) module: GnuplotDoLib.

gpClose: aHandle
    self ffiCall: #( void gpstop (void * aHandle)) module: GnuplotDoLib

gpHndl: aHandle gpCmd: aString
    self ffiCall: #( void gpdo (void * aHandle, String aString) ) module: GnuplotDoLib

これで準備完了です。Playgroundを開いて動かしてみます。

hndl := GnuplotDo gpOpen.
GnuplotDo gpHndl: hndl gpCmd: 'set xlabel "x"'.
GnuplotDo gpHndl: hndl gpCmd: 'set ylabel "y"'.
GnuplotDo gpHndl: hndl gpCmd: 'plot sin(x)'.
GnuplotDo gpClose: hndl.

とりあえず、これでPharoからgnuplotを起動してラベル設定してsin(x)を プロットする手続きが行えました。 エラーが起こるようなコマンドをgnuplotに渡すとgnuplotがクラッシュ してしまいますが、よしとします。

2016年12月16日金曜日

PharoのUnifiedFFIを使ってみた

Pharo5.0からCの共有ライブラリを呼び出す方法が簡単になったということで、 「Pharo UnifiedFFI」で検索してみたところ、確かにわかりやすいかも。 Windowsでも呼び出せるか、試してみた。システムブラウザで見てみると、UnifiedFFIというパッケージがすでにありました。

呼び出すCの関数は、単純で簡単なdoublenumber.c。

/* doublenumber.c */
#include 
int doublenumber(int n)
{
    return n * 2;
}

WindowsのMinGW gccで共有ライブラリとしてコンパイル/リンクしmylib.soを作成しました。

gcc -shared -o mylib.so doublenumber.c

作成されたmylib.soをPharo.exeと同じフォルダに配置しました。

ここから、Pharoを起動して呼び出すためのクラスを追加します。

まず、FFILibraryを継承したクラスMyTestLibを作成して、3つのメソッドを追加します。

macModuleName
unixModudleName
win32ModuleName

それぞれのメソッドは、各プラットフォームにおけるライブラリのファイル名を返すようにします。 ですからメソッドwin32ModuleNameは、作成した共有ファイル名を返すようにしました。
win32ModuleName
    ^ 'mylib.so'

次に、Objectを継承して関数呼び出しを行うためのクラスMyTestLibCallを作成しました。 このクラスに、doubleNumber:メソッドを追加しました。 このメソッドで外部関数を呼び出します。

doubleNumber: anInteger
    ^ self ffiCall: #( int doublenumber (int anInteger)) module: MyTestLib 

ffiCall:キーワードには、Cの関数の型、関数名、引数を指示する配列を指定します。
module:キーワードには、先に作成したクラスMyTestLibを指定します。

実際に、MyTestLibCallクラスのインスタンスを生成して、メソッドを呼び出してみます。

MyTestLibCall new doubleNumber: 5

これをPrint Itすると10が表示され、無事に呼び出しされているようです。

2016年11月18日金曜日

一文字飛ばしにした文字列へ変換する

ある文字列を一文字飛ばしにした文字列へ変換する関数をRubyで書くという話を見かけました。 "abcdefg"を入力したら"aceg"が帰ってくる関数です。 Pythonを使っていると、関数を書くまでもなくs[::2]としたら望みの文字列が得られます。せっかくだからRubyで書いてみました。
pythonでは、
def one_skipped(s):
    return s[::2]

print one_skipped('abcdefg') #=> 'aceg'

と関数にするまでもありません。 Juliaでも、
function one_skipped(s)
    s[1:2:length(s)]
end

print(one_skipped("abcdefg"))

のように文字列から文字列を生成できます。

Rubyでも文字列のメソッドに便利なものがあるのかと見てみましたが、 slice()では、範囲のみの指定のようです。 インデックスを指定して一文字取り出すことはできるようですので、 一つとびのインデックスさえ生成できれば、それをもとに文字列を組み立てられそうです。
def one_skipped(s)
    return (0..s.length/2).map {|i| i*2}.collect {|i| s[i]}.join()
end

Rubyはreturnを省略できるということ。i*2として一つ飛びの数に直すより、 i%2==0の判定を使って取り出したいということで、selectメソッドを使ってみます。
def one_skipped(s)
    (0..s.length).select {|i| i%2==0}.collect {|i| s[i]}.join()
end
ずらずらと記述が並びますね。関数に分けてみます。

def range(start, stop, step)
    (start .. stop).select {|i| (i-start)%step==0}
end

def chars_at_indices(s, indices)
    indices.collect {|i| s[i]}
end

def one_skipped(s)
    chars_at_indices(s, range(0, s.length, 2)).join()
end

puts 'abcdefg'
こんな感じでしょうか。関数に分けるほどでもないでしょうか。 せっかく関数に分けたので、SBCLでも書いてみます。
(defun range (start stop step)
  (loop for i from start below stop by step collect i))

(defun chars-at-indices (s indices)
  (loop for i in indices collect (elt s i)))

(defun one-skipped (s)
  (concatenate 'string (chars-at-indices s (range 0 (length s) 2))))

普段使わない言語を、ちょっと調べつつ書いてみる題材としてちょうどよいですね。

Rubyは、Windows上で、
ruby 2.1.2p95 (2014-05-08 revision 45877)
irb 0.9.6(09/06/30)
を用いました。

2016年11月11日金曜日

Gmailの下書きメモと同期するスクリプトを作ってみた

ポメラのdm200いいですね。 Gmailの下書きを利用して同期する機能があるということ。

Windowsでもそんなことやってみようと、pythonで作ってどんな感じかと試し中。 IMAPでgmailに接続して、下書きフォルダにメッセージを送るとともに、「メモ」ラベルをつけてみました。 こうすると、たんに「メモ」にメッセージを送るのとは違い、ブラウザで開いたGmailからも編集可能です。


IMAPでメッセージを削除するときは、「メモ」ラベルを消した後でないと、\Deleteフラグをstoreしても削除されませんでした。 直接「メモ」に送ったメッセージは、\Deleteフラグをstoreするだけで削除されました。 ただ、直接「メモ」に送ると、ブラウザで開いたGmailからは編集不可能でした。 「[Gmail]/下書き」にいれないと再編集できないようですね。

Windowsならファイルの同期には、Dropboxを使うので、あえてGmailに同期する必要はなさそうです。
dm200を手に入れたときには、ターゲットを変更して、便利に使えるのかもしれません。

2016年10月29日土曜日

pythonでSTL形式のデータを作ってみた

gnuplotでは、以下のようなスクリプトで球面を描画したりします。
set parametric # 媒介変数モード
set urange[0:2*pi] # uの範囲を設定
set vrange[0:2*pi] # vの範囲を設定
set ticslevel 0
set hidden3d
set isosample 50
set view equal xyz
splot cos(u/2.0)*cos(v),sin(u/2.0)*cos(v),sin(v) w l
このようなものを3Dモデルとして出力したいということで、 pythonで(u, v)の関数をSTL形式にして出力するスクリプトを書いてみました。 ほかの言語で書き換えて遊ぶのにも、ちょうどよい内容と長さかと思います。
import math

def Sphere(u, v):
    x = math.cos(u/2.0)*math.cos(v)
    y = math.sin(u/2.0)*math.cos(v)
    z = math.sin(v)
    return x, y, z

def VectorSub(v1, v2):
    return [e1-e2 for e1, e2 in zip(v1, v2)] 

def VectorDiv(v, a):
    return [e/a for e in v] 

def VectorCross(v1, v2):
    x1, y1, z1 = v1
    x2, y2, z2 = v2
    return [y1*z2-z1*y2, z1*x2-x1*z2, x1*y2-y1*x2]

def VectorAbs(v):
    return math.sqrt(sum([e**2 for e in v]))

def NormalVector(p1, p2, p3):
    v1 = VectorSub(p2, p1)
    v2 = VectorSub(p3, p2)
    vc = VectorCross(v1, v2)
    a = VectorAbs(vc)
    v = VectorDiv(vc, a) if a!=0.0 else False
    return v

def STLfacet(apolygon, inverse=False):
    if inverse:
        points = apolygon[::-1]
    else:
        points = apolygon[:]

    nv = NormalVector(*points)

    if not nv:
        return ""

    l = "facet normal %g %g %g\n" % tuple(nv)
    l = l + "outer loop\n"
    for p in points:
        l = l + "vertex %g %g %g\n" % tuple(p)
    l = l + "endloop\n"
    l = l + "endfacet\n"
    return l

def PolygonsToSTL(name, polygons, inverse=False):
    l = "solid %s\n" % name
    for p in polygons:
        l = l + STLfacet(p, inverse)
    l = l+"endsolid\n"
    return l

def Polygons_of_Function_UV(func):
    nu = 90 
    nv = 90 
    du = 2.0 * math.pi / nu
    dv = 2.0 * math.pi / nv

    u = [du * i for i in range(nu+1)]
    v = [dv * i for i in range(nv+1)]

    polygons = []
    for i in range(nu):
        for j in range(nv):
            p1 = func(u[i], v[j])
            p2 = func(u[i+1], v[j])
            p3 = func(u[i+1], v[j+1])
            p4 = func(u[i], v[j+1])
            polygons.append((p1, p2, p4))
            polygons.append((p4, p2, p3))
    return polygons

def OutputSTL(name, polygons):
    with open('%s.stl' % name, "w") as fp:
        fp.write(PolygonsToSTL(name, polygons, False))

if __name__ == '__main__':
    OutputSTL("Sphere", Polygons_of_Function_UV(Sphere))


出力されたSTLデータを見るには、GLC Playerが便利ですね。また、Windows10には、3D Builderがついているので、そのままでSTLデータを見ることができます。GLC Playerでスナップショットを取ったものが下の図です。

関数を次のものにしてみます。

def Dounut(u, v):
    x = math.cos(u)*(1+0.5*math.cos(v))
    y = math.sin(u)*(1+0.5*math.cos(v))
    z = 0.5*math.sin(v)
    return x, y, z

ドーナツの形になりました。

def Helical(u, v):
    n = 10.0
    a = 0.6
    b = 0.3
    rm = (lambda v: a*b/math.sqrt(b*b*math.cos(v)**2 + a*a*math.sin(v)**2))
    r = (lambda u, v: 1 + rm(v)*math.cos(v+n*u/2.0))
    x = r(u, v) * math.cos(u)
    y = r(u, v) * math.sin(u)
    z = rm(v) * math.sin(v + n*u/2.0)
    return x, y, z

楕円をぐるぐる回転させていくと、ねじれた形状になりました。

2016年10月20日木曜日

Windowsでファイルをドロップしてpythonスクリプトを起動する

ファイルをドラッグ&ドロップでpythonスクリプトを起動し、処理たいこともあるようで、Googleで検索してみると、二つ方法があるようですね。

一つは、レジストリを編集してPythonスクリプトにドロップハンドルを設定する方法があるようです。

もう一つは、バッチファイルを使う方法です。レジストリをいじったりしないので、こちらの方が好みですし、おすすめです。

testDragAndDrop.py (pythonスクリプトファイル)
import sys
for arg in sys.argv:
    print arg
raw_input()

testDragAndDrop.bat (バッチファイル)
python testDragAndDrop.py %*

の二つのファイルを用意して、testDragAndDrop.batにファイルをドロップするとtestDragAndDrop.pyに引数としてドロップされたファイルのパスが渡されます。非常に簡単ですね。バッチファイルのショートカットを作成して、そちらにドロップすることも可能です。

2016年10月11日火曜日

DELL Latitude10とWindows10 1607 anniversary update

DELLのLatitude10は、いつの間にかWindows10 Anniversary Updateが来たようです。1607用のセキュリティアップデートもきましたが、いまのところ順調にに動作しています。



ただしBluetoothドライバは、標準のものに戻っています。キングジムのポメラDM100をBluetoothキーボードとして利用するには問題ない(キーアサインの問題はソフトウェアで解決済み)のですが、Bluetoothを使ったファイル転送機能は、1607でも問題があるようです。

Windows10へアップグレードした時と同様に、DELLのサポートページからBluetoothドライバ(Network_Driver_4Y0Y8_WIN_12.0.6300_A06.EXE)をダウンロードしてきてインストールしたところ、ファイルのやりとりができるようになりました。

さて、新しくポメラDM200が発表されましたが、このBluetoothのファイル転送機能はなくなるということ。環境によってファイル転送できたりできなかったりとあるようなので、削除されたのでしょうか。QRコードやケーブル接続してPCリンクによるファイル転送、さらにWifiを使ってファイル転送まであるので問題なさそうです。画面が広くなったり、キーボードが新しくなったり、漢字変換も賢くなったりと楽しみな箇所がいっぱいです。

2016年7月31日日曜日

プチコン3号でたらい回し関数

プチコン3号SmileBasicを試してみたく、new3DSLLを手に入れた。たらい回し関数(竹内関数)を入力して実行してみた。

 DEF TARAI(X,Y,Z)
  IF X<=Y THEN
    RETURN Y
  ELSE
    RETURN TARAI(TARAI(X-1, Y, Z), TARAI(Y-1, Z, X), TARAI(Z-1, X, Y))
  ENDIF
END

PRINT TIME$
PRINT TARAI(12,6,0)
PRINT TIME$

BASICとはいっても、行番号いらないし、ローカル変数あるし、再帰呼び出しも可能なんですね。
引数(12, 6, 0)の場合、28秒で返ってきました。

さて、比較するものがないと困るので、メインで使っているToshiba dynabook SS RX1(Windows Vista 32bit)のpython 2.7.6でたらい回し関数を実行してみました。6秒ほどで返ってきました。

#import time
def tarai(x, y, z):
    if (x <= y):
        return y
    else:
        return tarai(
                    tarai(x-1, y, z),
                    tarai(y-1, z, x),
                    tarai(z-1, x, y))
start = time.time()
print tarai(12, 6, 0)
stop = time.time()
print stop - start

これを、zenfone2(ZE551ML)のqpythonで試すと12秒でした。

2016年3月23日水曜日

Kivy LauncherでAnimated Gif Viewer

Kivy Launcherのアップデートがあったので、せっかくなのでAnimated Gif Viewerを作ってみた。Kivyで作成して、QPythonでの動作を確認したけど、Kivy Launcherでは起動しない。GIFイメージの読み込みにPILを使っているけど、出力されたlogを見るとどうやら、GIFイメージを読むときに AttributeError: tobytes が起こっている。Pillowではtostring()が廃止予定になってtobytes()が使われるらしいとのこと。どうやらKivy Launcherが呼び出しているPILのバージョンが古いためにtobytes()メソッドがないらしい。そういうわけで、以下のようにスクリプトのあたまでtostring()を呼び出すようにtobytes()メソッドを追加してみた。

from PIL import Image as PILImage

def tobytes(pilimg, encoder_name="raw", *args):
    return pilimg.tostring(encoder_name=encoder_name)

PILImage.Image.tobytes = tobytes

無事に起動することができた。こういうところ、Pythonは便利ですね。


Next, Back, Pause, Rotate, Resume, Open, Quitとボタンをつけてみました。
GUIをwxPythonで作り直して、Windows用にもしてみた。



2016年1月15日金曜日

Kivy LauncherでImageViewerの起動に失敗

Zenfone2でKivy Launcherから自作のImageViewerを起動していたけど、新年になって起動しなくなった。どうやらバージョンアップして、動作が怪しくなったみたい。スクリプトを実行してもログも出力せずに、終了してしまった。Google Groupの方でも話題になっている。しかたがないので、プロジェクトのフォルダーをそのままQPythonに移動した。以前試したときは動かなかったけど、今回は問題なく起動した。こちらもバージョンが上がって、Kivyのバージョンが1.9.0になったようだ。

2016/3/21追記
Kivy Launcherのアップデートがあり、自作のImageViewerもKivy Launcherから無事に起動するようになった。