Monthly Archives: 4月 2020

2020-04-22

2020年春の新番組

かぐや様2期くらいかなぁ。

印象 開始日時 チャネル タイトル
03/26(木) Netflix 7SEEDS 第2期
03/27(金) 24:00 TOKYO MX GRANBLUE FANTASY The Animation Season2
03/28(土) 11:00 YouTube アイカツオンパレード!
03/30(月) 18:10 NHK Eテレ 忍たま乱太郎 第28シリーズ
04/01(水) 24:30 TOKYO MX 神之塔 -Tower of God-
04/01(水) 07:30 テレビ東京系 みっちりわんこ!あにめ~しょん
04/01(水) 18:00 NHK Eテレ おじゃる丸 第23シリーズ
04/02(木) 17:20 NHK Eテレ のりものまん
04/02(木) 22:30 TOKYO MX 八男って、それはないでしょう!
× 04/02(木) 23:30 TOKYO MX 球詠
04/02(木) 24:00 TOKYO MX かくしごと
04/03(金) 16:00 公式ポータルサイト ベイブレードバースト スパーキング
04/03(金) 17:00 YouTube(爆丸公式Ch) 爆丸アーマードアライアンス
04/03(金) 18:20 NHK Eテレ あはれ!名作くん シーズン5
× 04/03(金) 22:00 TOKYO MX 新サクラ大戦 the Animation
04/03(金) 25:23 テレビ東京 文豪とアルケミスト
04/03(金) 25:55 TBS LISTENERS リスナーズ
04/03(金) 26:25 TBS 波よ聞いてくれ
04/04(土) 07:30 テレビ東京系 遊☆戯☆王 SEVENS
04/04(土) 09:00 NHK Eテレ おしりたんてい 新シリーズ
04/04(土) 17:35 NHK Eテレ MAJOR 2nd 第2シリーズ
04/04(土) 22:00 TOKYO MX アルテ
04/04(土) 25:00 TOKYO MX ギャルと恐竜
04/04(土) 25:30 TOKYO MX 乙女ゲームの破滅フラグしかない悪役令嬢に転生してしまった…
04/04(土) 25:30 テレビ朝日 イエスタデイをうたって
04/05(日) 07:30 テレビ東京系 ディズニー・サンデー ラプンツェル ザ・シリーズ
04/05(日) 09:00 フジテレビ デジモンアドベンチャー:
× 04/05(日) 09:30 テレビ東京系 トミカ絆合体 アースグランナー
04/05(日) 10:30 テレビ東京系 ミュークルドリーミー
04/05(日) 19:00 NHK Eテレ もっと!まじめにふまじめ かいけつゾロリ
04/05(日) 22:00 TOKYO MX 継つぐもも
04/05(日) 22:30 TOKYO MX アイドリッシュセブン Second BEAT!
04/05(日) 23:30 TOKYO MX グレイプニル
04/05(日) 24:15 NHK総合 キングダム 第3シリーズ
04/05(日) 24:30 TOKYO MX 社長、バトルの時間です!
04/05(日) 25:00 TOKYO MX 俺の指で乱れろ。~閉店後二人きりのサロンで…~
04/06(月) 07:05 テレビ東京系 ガル学。~聖ガールズスクエア学院~
× 04/06(月) 17:55 テレビ東京系 ファンファンキティ!
04/06(月) 22:30 TOKYO MX 白猫プロジェクト ZERO CHRONICLE
04/06(月) 22:50 NHK Eテレ 銀河英雄伝説 Die Neue These(NHK版)
04/06(月) 23:29 BS日テレ ぽっこりーず
04/06(月) 24:30 TOKYO MX プリンセスコネクト!Re:Dive
04/06(月) 25:00 チバテレビ あの世のすべては、おばけぐみ
04/06(月) 25:15 TOKYO MX 邪神ちゃんドロップキック'
04/06(月) 25:30 テレビ東京 フルーツバスケット 新作 2nd season
04/07(火) 07:30 テレビ東京系 おりがみにんじゃ コーヤン
04/07(火) 17:55 テレビ東京系 シャドウバース
04/07(火) 24:30 TOKYO MX 放課後ていぼう日誌
04/07(火) 25:35 TOKYO MX 無限の住人-IMMORTAL-
04/08(水) 07:20頃 テレビ東京系 おばけずかん
04/08(水) 22:00 TOKYO MX 本好きの下剋上 司書になるためには手段を選んでいられません 第2部
04/08(水) 23:29 BS日テレ 困ったじいさん
04/08(水) 24:55 フジテレビ BNA
04/09(木) 25:10 フジテレビ 富豪刑事 Balance:UNLIMITED
04/09(木) 25:28 TBS ノー・ガンズ・ライフ 第2期
04/09(木) 25:58 TBS やはり俺の青春ラブコメはまちがっている。完
  04/10(金) 21:00 YouTube 魔神英雄伝ワタル 七魂の龍神丸
04/10(金) 20:00 ニコニコCh ざしきわらしのタタミちゃん
04/10(金) 22:30 TOKYO MX 天晴爛漫!
04/10(金) 24:30 TOKYO MX 食戟のソーマ 豪の皿
04/10(金) 25:25 TBS系 アルゴナビス from BanG Dream! ANIMATION
04/11(土) 17:30 日本テレビ系 ハクション大魔王2020
04/11(土) 19:00 TOKYO MX ガンダムビルドダイバーズRe:RISE 2nd Season
04/11(土) 23:30 TOKYO MX かぐや様は告らせたい?
04/12(日) 23:00 TOKYO MX ULTRAMAN
04/13(月) 23:00 TOKYO MX 啄木鳥探偵處
04/16(木) 19:53 テレビ東京 テレビ野郎 ナナーナ 怪物クラーケンを追え!
04/20(月) 21:54 TOKYO MX オリンピア・キュクロス
04/23(木) Netflix 攻殻機動隊 SAC_2045
04/25(土) 08:00 テレビ東京系 ヴァンガード 外伝 イフ-if-
04/25(土) 24:00 TOKYO MX ソードアート・オンライン-アリシゼーション- War of Underworld -THE LAST SEASON-
–/–(日) 08:30 テレビ東京系 デュエル・マスターズキング
2020-04-15 ,

org-mode文書をタグなどで検索したときにエントリの中身(本文)を全部表示する(Org 9.3.6)

org-modeで書かれた文書を org-match-sparse-tree を使ってをタグで検索する(Sparse Tree を作る)とマッチしたヘッドラインだけが表示されるのですが、そのとき本文も全て一括で表示して欲しかったのでどうしたらよいのか調べてみました。

例えば DIARY タグで検索して日記を通して読みたいときにいちいち一つ一つのヘッドラインをTABキーで展開してまわるのは面倒です。かといってS-TABだとマッチしていない部分の本文も展開されてしまいます。

マニュアルのSparse Treeの項目を見てもマッチしたエントリを移動する操作くらいしか書いていませんでした。

Sparse Trees (The Org Manual)

しかたがないので org-match-sparse-tree 関数(org.el内)を調べてみることにしました。

org-match-sparse-tree の亜種を作る

org-match-sparse-tree は内部で org-scan-tags を呼んでいます。 org-scan-tags はその名の通りの文書をスキャンしてマッチする部分を巡回する関数です。マッチしたところで何をするかは引数 action で指定することになっていて、 org-match-sparse-tree では 'sparse-tree を渡してマッチした場所をハイライトしたりヘッドラインを表示したりしています。 action には任意の関数も渡せるようになっているので、そこにサブツリーを表示する関数を渡してマッチした部分を子孫も含めて全て表示させることにしました。

org-match-sparse-tree のコードをベースに修正してみます。

;; org-match-sparse-treeをベースに修正
(defun org-match-sparse-tree-show-subtree (&optional todo-only match)
  "Create a sparse tree according to tags string MATCH.

MATCH is a string with match syntax.  It can contain a selection
of tags (\"+work+urgent-boss\"), properties (\"LEVEL>3\"), and
TODO keywords (\"TODO=\\\"WAITING\\\"\") or a combination of
those.  See the manual for details.

If optional argument TODO-ONLY is non-nil, only select lines that
are also TODO tasks."
  (interactive "P")
  (org-agenda-prepare-buffers (list (current-buffer)))
  (let ((org--matcher-tags-todo-only todo-only))

    ;; 修正点ここから
    ;; まずはトップレベル以外は全て非表示にする。ハイライトももしあれば解除する。
    (org-overview)
    (org-remove-occur-highlights)
    ;; 修正点ここまで

    (org-scan-tags
     ;; 修正点ここから
     ;; マッチしたところをハイライトしてからサブツリーを表示する
     (lambda ()
       (and org-highlight-sparse-tree-matches
            (org-get-heading) (match-end 0)
            (org-highlight-new-match
             (match-beginning 1) (match-end 1)))

       (org-show-subtree) )
     ;; 修正点ここまで
     (cdr (org-make-tags-matcher match))
     org--matcher-tags-todo-only)))

元々の (org-scan-tags 'sparse-tree ....) では、マッチした場所で (org-show-context 'tags-tree) を呼び出しており、 (org-show-context)(org-show-set-visibility) を呼び出してその場所を表示状態にします。どのような表示を行うかは org-show-context-detail 変数でカスタマイズできるのですがサブツリー全体を表示するというオプションはありません。 'local が一番近いのですが、なぜか次のエントリーのヘッドラインまで表示してしまいます(ドキュメントにもそう書いてあるので意図した動作のようです)。他のオプションには if point is not on headline, also show entry and all children 等と書いてあり、ヘッドライン外にポイントがないと内容は表示してくれません。しかたがないので (org-show-context) の代わりに直接 (org-show-subtree) を呼ぶようにしてあります。

一時的に org-show-context をオーバーライド

org-match-sparse-tree の実行中、 (org-show-context) を一時的にオーバーライドしても結果は同じです。こちらの方がシンプルでしょうか?

(require 'cl)
(defun org-match-sparse-tree-show-subtree (&optional todo-only match)
  (interactive "P")
  (flet ((org-show-context (&optional key) (org-show-subtree)))
    (org-match-sparse-tree todo-only match)))

fletで一時的にorg-show-contextをオーバーライドしてみました。

マッチしたところだけ後から展開する

これでマッチした全エントリーの中身(サブツリー)を表示出来たのですが通常の動作との使い分けが面倒なことに気がつきました。最初から本文を全部読みたいと思って検索するなら上で定義した (org-match-sparse-tree-show-subtree) を使えば良いのですが「とりあえずタグで検索 → 一覧が出る → 一覧を全部展開」という手順の方が自然な気がします。

本当に欲しかったのはS-TABでマッチした(ハイライトした)エントリだけをvisibility cyclingすることなのではないでしょうか。

マッチした部分は (org-occur-next-match) という関数で巡回出来ます(M-g n や M-g p で移動するときに使われます)。マッチした部分のハイライトは (org-highlight-new-match beg end) で行われています。これは org-occur のためにある関数のようですが指定された範囲にオーバーレイを適用して、オーバーレイを org-occur-highlights リストに追加します。検索後にC-c C-cでハイライトが消えるのは (org-ctrl-c-ctrl-c) 内で org-occur-highlights リストに何か入っているときは (org-remove-occur-highlights) を呼んでいるからだったりします。 (org-occur-next-match) で次のマッチ、前のマッチに移動出来るのはオーバーレイの 'org-type プロパティに値 'org-occur が設定されているからで、その値を検索して移動しているようです。

なので (org-occur-next-match) でハイライト部分を巡回して (org-show-subtree) しまくればマッチしたエントリーの内容をサブツリーを含めて表示出来ます。

(defun org-show-occur-highlights-subtree ()
  (interactive)
  (save-excursion
    (goto-char (point-min))

    (while (ignore-errors (org-occur-next-match 1))
      (org-show-subtree))))

本当は S-TAB をオーバーライドしてハイライトがあるときはハイライトされている部分だけを展開したり折りたたんだりできればいいのですが現在の展開状態を調べる必要があるので面倒そうなので今日はここまでにしておきます。

(2020-04-16追記)S-TABでマッチしたエントリのみを展開したり閉じたりする

ここまでで一応検索結果(Sparse Tree)の本文を一括で表示(展開)できるようになったのですが、やっぱり S-TAB に割り当てて検索結果を開いたり閉じたりしたい! ということで引き続き調べてみました。

まず、既存の S-TAB がどのようになっているのか調べる必要があります。

調べてみた結果、次のようなフローになっていることが分かりました。複雑ですね。

S-TAB => org-shifttab => org-global-cycle => (org-cycle '(4)) => org-cycle-internal-global

C-u 引数によって多少流れが変わることもあるかもしれませんが最終的には org-cycle-internal-global が呼ばれるようです。

org-cycle-internal-global関数は切り替えの処理を行いますが最初はOVERVIEWで表示し、同じコマンドが連続して呼ばれたときに => CONTENTS => ALL => OVERVIEW … の順で表示を切り替える実装になっています。私はこれまで気がついていなかったのですが現在の状態から次の状態へ変わるわけではないんですね。例えば他の作業をした後にS-TABを3回押せばどんな状態からでも必ずALLになるわけです。

実際の表示状態の変更は次の関数が行います。

org-overview
トップレベルのヘッドラインだけ表示
org-content
全てのヘッドラインだけを表示
org-show-all
内容も含めて全て表示(ドロワーなど一部を除く)

ハイライトがあるとき(Sparse Tree表示時)の動作はこれらの関数を修正すべきでしょう。S-TABだけでなくこれらの関数を直接呼び出すこともあるでしょうし。

……と思ったのですが、これらの関数がハイライトがあるときにどのような動作をすべきか考えたのですがなかなか一貫性のある挙動を決めることができませんでした。

org-overview
このまま? ハイライトされている部分だけを表示?(デフォルトの表示って事?)
org-content
ハイライトされているエントリ以下の全てのヘッドラインを表示? org-occurでマッチしたヘッドライン以外の部分はどうする?
org-show-all
ハイライトされているエントリ以下の全てを表示?

org-occurがあるのでハイライトされるのはヘッドラインだけとは限らないところが問題を難しくします。Sparse Treeを表示した直後に1回S-TABを押したときに同じ表示になる(何も変わらない)のも避けたいところです。

仕方が無いので既存の動作との一貫性は脇に置いてSparse Tree表示時の特殊な挙動として仕様を決めることにしました。

org-sparse-tree-show-matched
マッチしたところを表示(デフォルト)
org-sparse-tree-show-all
サブツリーを含めて全て表示

ハイライトがあるときは、この二つと既存の三つをS-TABで切り替えることにします。

OVERVIEW => SPARSE-TREE-SHOW-MATCHED => SPARSE-TREE-SHOW-ALL => CONTENTS => ALL

つまり2回S-TABすればマッチした箇所(タグ検索の場合はヘッドラインのみ)が、3回S-TABすれば本文まで展開してくれるわけです。既存の操作感覚に割と近くなっていると思います。マッチした部分に限定されたくない場合に備えて、4回S-TABすればCONTENTS、5回S-TABすればALLとなるようにしました。

;; org-sparse-tree-cycle.el
;; https://misohena.jp/blog/2020-04-15-show-contents-of-entry-when-sparse-tree-in-org-mode.html
;;

(defun org-sparse-tree-show-all ()
  "マッチした部分をサブツリーを含めて表示します。"
  (interactive)
  (save-excursion
    (org-overview)

    (goto-char (point-min))
    (while (ignore-errors (org-occur-next-match 1))
      (org-show-context 'tags-tree)
      (org-show-subtree))))

(defun org-sparse-tree-show-matched ()
  "マッチした部分を表示します。"
  (interactive)
  (save-excursion
    (org-overview)

    (goto-char (point-min))
    (while (ignore-errors (org-occur-next-match 1))
      (org-show-context 'tags-tree))))

;; この関数は org-cycle-internal-global を元に修正しています。
(defun org-sparse-tree-cycle-internal ()
  "Do the sparse tree cycling action."
  ;; Rotate overview => sparse-tree-show-matched => sparse-tree-show-all => contents => show all

  ;; Hack to avoid display of messages for .org  attachments in Gnus
  (let ((ga (string-match "\\*fontification" (buffer-name))))
    (cond
     ((and (eq last-command this-command)
           (eq org-cycle-global-status 'sparse-tree-show-all))
      ;; We just created the overview - now do table of contents
      ;; This can be slow in very large buffers, so indicate action
      (run-hook-with-args 'org-pre-cycle-hook 'contents)
      (unless ga (org-unlogged-message "CONTENTS..."))
      (org-content)
      (unless ga (org-unlogged-message "CONTENTS...done"))
      (setq org-cycle-global-status 'contents)
      (run-hook-with-args 'org-cycle-hook 'contents))

     ((and (eq last-command this-command)
           (eq org-cycle-global-status 'contents))
      ;; We just showed the table of contents - now show everything
      (run-hook-with-args 'org-pre-cycle-hook 'all)
      (org-show-all '(headings blocks))
      (unless ga (org-unlogged-message "SHOW ALL"))
      (setq org-cycle-global-status 'all)
      (run-hook-with-args 'org-cycle-hook 'all))

     ((and (eq last-command this-command)
      ;; sparse tree show matched
           (eq org-cycle-global-status 'overview))
      (org-sparse-tree-show-matched)
      (setq org-cycle-global-status 'sparse-tree-show-matched))

     ((and (eq last-command this-command)
           (eq org-cycle-global-status 'sparse-tree-show-matched))
      ;; sparse tree show all
      (org-sparse-tree-show-all)
      (setq org-cycle-global-status 'sparse-tree-show-all))

     (t
      ;; overview
      (run-hook-with-args 'org-pre-cycle-hook 'overview)
      (org-overview)
      (unless ga (org-unlogged-message "OVERVIEW"))
      (setq org-cycle-global-status 'overview)
      (run-hook-with-args 'org-cycle-hook 'overview)))))

(defun org-sparse-tree-shifttab-advice (oldfun arg)
  (if org-occur-highlights
      ;; ハイライトがある
      (org-sparse-tree-cycle-internal)
    ;; 元の関数を呼ぶ
    (funcall oldfun arg)))

;; org-shifttabをオーバーライドする
(advice-add 'org-shifttab :around #'org-sparse-tree-shifttab-advice)

うん、これでSparse Treeが大分使いやすくなりました。

2020-04-06

星表を使って星空を描く

ESAのHipparcosGaiaのデータを使用して星空を描いてみました。

  • js_hoshizora:

    JavaScript+WebGLで10万個くらいの星空を描いてみたもの。実行はこちら

  • drawstars:

    Gaiaのデータを使って精巧な天の川まで描いてみたもの。あまりに天体の数が多いのでリアルタイムは不可能。C++でコマンドラインツールに仕立てました。去年の夏に撮影した天の川と比較してみたところほとんど一致しました。

昔から一度星空を描いてみたかったのです。小学生の頃図書館にBASICで書かれたグラフィックスの本があってその中に星空・星座を描くものがあったのですが当時の私にはさっぱり理解出来ませんでした。

天体の位置計算 増補版やWebの情報で勉強してみると精度を求めないのであればそれほど難しくないようでした。基本的に赤経・赤偉で星の位置が与えられているので、それを地球のある地点から見た座標系に変換すればOKです。言葉の定義などをしっかり学んで考えてみれば3Dグラフィックスでおなじみの行列での座標変換でした。

一番困ったのは色の計算。一般に星の観測は複数の異なる帯域(赤とか青とか)に反応するセンサーを用い、色はその差分で表されるのですが、そこから画面のRGB値にするのに苦労しました。今でも適当です。

恒星時の計算もひっかかりました。年々式が変わっているようなのですが原理をあまり理解していないのでよく分かりません。精度を求めないのであれば適当でもなんとか。

歳差やら章動やら天体の固有運動、視差、光行差等はまだろくに学んでいないので考慮していません。色についても赤方偏移や減光など色々な要因で変わるみたいですが後々の課題と言うことで。

正距円筒図法で描かれた天の川
図1: 正距円筒図法で描かれた天の川
テクスチャにして投影した天の川
図2: テクスチャにして投影した天の川
現実の天の川
図3: 現実の天の川
描画された天の川
図4: 描画された天の川