琵琶湖をPostScriptで描く

先日の日曜日、自転車で琵琶湖をまわってきました。
今年は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用紙全体を使うように調整するためのものです。
かなり大雑把ですが、それなりに見栄えがいいのでいいことにしてください。

おまけ:

Leave a Reply