Archive for 4月, 2011

琵琶湖をPostScriptで描く

木曜日, 4月 21st, 2011

先日の日曜日、自転車で琵琶湖をまわってきました。
今年はAndroid端末 HTC DesireでMy Tracksというソフトを動かし、
GPSのログを記録しながら走ってみました。

で、せっかくなの、でそのログを使ってPostScriptで琵琶湖を描いてみました。

PDF
PostScript

なかなかいい感じに出来ました。
滋賀県民以外なら「これが琵琶湖の正確な形です」といっても騙せそうです。
(滋賀県民には「奥琵琶湖の形がおかしい」などとツッコまれそうだ。)

MyTracksは緯度経度のログをCSV形式で、出力することができるので、
それをCommon Lispで読み込み、PostScriptに変換という流れで作りました。
変換につかったプログラムは以下のとおりです。

(defun skip-elms (stream n)
  (when (char= (peek-char nil stream) #\,)
    (read-char stream))
  (dotimes (i n)
    (unless (char= (peek-char nil stream) #\,)
      (read stream))
    (assert (char= (read-char stream) #\,))))

(defun read-latlon (line)
  (let (lat lon)
    (with-input-from-string (s line)
      (skip-elms s 2)
      (setf lat (read-from-string (read s)))
      (skip-elms s 0)
      (setf lon (read-from-string (read s))))
    (values lat lon)))

(defun convert-latlon (lat lon)
  (values (+ 50 (* (- (* lat 111) 3881) 11))
          (+ 50 (* (- (* lon 91) 12363) 11))))

(defun doit ()
  (with-open-file (s "biwa.csv")
    (with-open-file (out "biwa01.ps" :direction :output :if-exists :supersede)
      (write-line "%!" out) (write-line "gsave" out)
      (dotimes (_ 3611)
        (read-line s))
      (do ((i 3612 (1+ i)))
          ((>= i 30334) t)
        (multiple-value-bind (lat lon)
            (multiple-value-call #'convert-latlon
              (read-latlon (read-line s)))
          (if (= i 3612)
              (format out "~A ~A moveto~%" lon lat)
              (format out "~A ~A lineto~%" lon lat))))
      (format out "stroke~%showpage~%grestore"))))

マジックナンバーがたくさん出てますが、
書き捨てのプログラムなので気にしない方針で。
convert-latlonは緯度経度をPostScriptの座標(ポイント)に変換します。
数111は緯度1度あたりのおおよその距離(km)、
数91は経度1度あたりのおおよその距離(km)、
あとの数はA4用紙全体を使うように調整するためのものです。
かなり大雑把ですが、それなりに見栄えがいいのでいいことにしてください。

おまけ:

WiLiKiにアクセス制御機能を付けた

土曜日, 4月 16th, 2011

説明するより実物を見たほうが早いでしょう。

KyotoWiLiKi

以下はdiffです。
(物好きな人は)ご自由にお使いください
(さらに…)

関西Coders 第一回ミーティング

金曜日, 4月 15th, 2011

4月9日に大阪府池田市某所にて、怪しげな集会に行ってきました。

植木のまち池田

池田城

インスタントラーメン発明記念館

池田ァ!!!!!

               __, . : ´  ̄ ̄ ` 、
        、__, . :´: : : : : : : : : : : : : : : : : . ヽ
        \` < . : : : : : : : : : : : : : : : : : : : : : .\
         \  `ヽ、: : : : : : : : : : : : : : : : : : : : : .\
          八_≦=\: : : : : / . : __: : : : : : : . ヽ
        / .: : : : : : : : : : : / . : /   //l : : : : : : . l\
       / .: : : : : : : : : : / \/     l/  |ノ ヽ: : : : :|: . ヽ
      / .: /: : : : : : : : /\_/`\           | : : : :|: : : . \_
    _/ .:// : : : :/⌒V. :/`ヽ ノ ̄ ̄`ヽ、―ニ 二三
    ̄ ̄ / : :/lハ  /: /`ヽ / ´`ヽ _  三,:三ー二二   
         |: :/  l : :/ /   ノヽ–/ ̄ ,    ` ̄ ̄ ̄ ̄
        ∨   | :/ ∧⊂⊃ミ }  …|  /!ヘ;;;;丿
      ___ /Ⅳ//∧   _}`ー‐し’ゝL _
     // ̄\\ |ノ ̄\ヽ    ヘr–‐‐’´}    ;ー——–
    〃 ̄\ \\    \\   ヾ:::-‐’ーr‐'”==-──
   〃    \ \\    ヽ ` / ̄厂`丶、__     レ′
  〃      \ \\    l__/     // ∧
 //        \ >ー 、 |  /    // / l

全体のことはいけがみさんが書いてくれたので、
Prologで書いたML(のサブセット)のインタプリタ(?)の話でも書いておきます。


こんな感じの推論規則を元に、

rule(['|-', Env, I, evalto, I], [], 'E-Int') :- env(Env), i(I).
rule([I1, plus, I2, is, I3], [], 'B-Plus') :-
  i(I1), i(I2), I3 is I1 + I2.
rule(['|-', Env, [if, E1, then, E2, else, E3], evalto, V],
     [['|-', Env, E1, evalto, true],
      ['|-', Env, E2, evalto, V]], 'E-IfT') :-
  e(E1), e(E2), e(E3), env(Env).

こんな感じの述語を定義して、

infer(X, [X, by, Name]) :-
  rule(X, [], Name).
infer(X, [X, by, Name|Z]) :-
  rule(X, Y, Name), infer_list(Y, Z).
infer_list([], []).
infer_list([X|Xs], [Y|Ys]) :- infer(X, Y), infer_list(Xs, Ys).

推論規則を次々つかってやる述語を定義すると、

% 心の目で "if true then 1 + 2 else 0 => X" とお読みください
?- infer(['|-', [], [if, true, then, [1, +, 2], else, 0], evalto, X], Z), output(Z).
|- if true then 1 + 2 else 0 evalto 3 by E-IfT {
  |- true evalto true by E-Bool {};
  |- 1 + 2 evalto 3 by E-Plus {
    |- 1 evalto 1 by E-Int {};
    |- 2 evalto 2 by E-Int {};
    1 plus 2 is 3 by B-Plus {}
  }
}
X = 3,
Z = [...]

式の値を求めた上で証明木を書いてくれるというものです。
(証明木は

 A B
----- RULE
  C

C by RULE {
  A;
  B
}

と記述しています)

一応、型推論やら継続の取り扱いなどもできます。
大学院の講義で「導出を書け」という課題があったため作ったもので、手抜きです。
MLのパーサは書いてないので、人間がパース済みの入力を与えるという、
素晴らしき作りになっています。