unicode 表示
Apple の terminal は unicode 文字を表示してくれるので、unicode の点字文字を使ったグラフィックスに挑戦してみることにします。ここで点字文字は 4 行 2 列の点で出来ています。
Windows の DOS 窓や WSL コンソールでは unicode 文字がうまく表示されないのですが、Windows Terminal や Visual Studio Code の Terminal では表示可能のようでしたので、こちらでも挑戦してみました。
unicode 点字
以前 Julia の unicode plots を見て便利そうだなと思っておりました。 docs.juliaplots.org
調べてみると、元々のアイデアは python 用の点字プロットにあるようでした。 github.com
Fortran と unicode
Fortran は Fortran 90 の時点で、日本語の JIS 漢字を念頭に多バイト文字種を ISO 規格に取り入れるという先進性を持っていたのですが、先進的過ぎて unicode 登場より前に決めた規格なのでその後停滞して未だに unicode は手際よく扱えません。
ここでは、2,3文字ばかり点字フォントを Fortran のソースファイルにコピペしてきて文字コードを読み取り、力ずくで経験的に点字フォント出力を実現しました。文字コードを Little endian 整数としてみると、64文字毎の固まりが 256 だけ間隔を空けて並んでおりました。
これは本来の文字コード表とやや違っているので、何か endian の変換がうまくいっていないようです。もしかしたら 4 バイトを反転させるのではなく 2 バイト2組で反転させるのかもしれません。文字コードについては興味も関心も知識も無いので、今後の課題とします。
unicode に紙テープやパンチカードの穴の表示を入れることを、ここに提案したいと思います。
このフォント出力の問題があり、プログラムの移植はだるかったので、ゼロから作りました。 点を打てるようにすれば、以降はこれまで作ってきたルーチンをそのまま使えるので楽です。
とりま阿部さんを描きます。 fortran66.hatenablog.com
Apple M1 Mac での出力
fpm (fortran package manager ) を使ってみたかったのですが x86_64 用しかなく、arm 用の gfortran と組み合わせが悪いようでうまくいきませんでした。今後の課題としたいと思います。
Windows WSL での出力
fpm を使ってみました。ファイル名・ファイル構成などを縛られるのでメンドイです。
- 作者:山川 純一
- 発売日: 2003/11/01
- メディア: コミック
ソース・コード
gfortran, intel fortran どちらでも行けます。
描画領域からのはみ出しチェックをしていないので、はみ出すと配列はみだしで死にます。
いちおう、type-bound procedure を使って OOP 風にしてあります。複数 figure を描いてゆけます。
module uniplot implicit none private public :: fig_t type :: fig_t private integer :: nx, ny integer, allocatable :: array(:, :) contains procedure :: init procedure :: point procedure :: show procedure :: line0 procedure :: line end type fig_t contains subroutine init(fig, nx, ny) class(fig_t), intent(out) :: fig integer, intent(in) :: nx, ny fig%nx = nx fig%ny = ny allocate(fig%array(0:(nx+1)/2, 0:(ny+3)/4) ) end subroutine init subroutine point(fig, ix, iy) class(fig_t), intent(in out) :: fig integer, intent(in) :: ix, iy integer :: iax, iay iax = ix / 2 iay = iy / 4 fig%array(iax, iay) = ior(fig%array(iax, iay), icode(mod(ix, 2), mod(iy, 4))) end subroutine point pure elemental integer function icode(kx, ky) integer, intent(in) :: kx, ky if (ky == 3) then icode = 64 + 64 * kx else ! 0, 1, 2 icode = 2**(ky + 3*kx) end if end function icode subroutine line0(fig, ix0, iy0, ix1, iy1) class(fig_t), intent(in out) :: fig integer, intent(in) :: ix0, iy0, ix1, iy1 integer :: i, ix, iy, nx, ny real :: d nx = ix1 - ix0 ny = iy1 - iy0 if (abs(nx) < abs(ny)) then d = nx / real(ny) do i = 0, abs(ny) ix = nint(ix0 + d * sign(i, ny)) iy = iy0 + sign(i, ny) call fig%point(ix, iy) end do else d = ny / real(nx) do i = 0, abs(nx) iy = nint(iy0 + d * sign(i, nx)) ix = ix0 + sign(i, nx) call fig%point(ix, iy) end do end if end subroutine line0 subroutine show(fig) class(fig_t), intent(in) :: fig integer :: iy do iy = 0, ubound(fig%array, 2) print '(*(a))', reverse_endian(shift_code(fig%array(:, iy))) end do end subroutine show pure elemental integer function shift_code(k) integer, intent(in) :: k integer, parameter :: n0 = Z'E2A080' !14852224 shift_code = n0 + 256 * (k /64) + mod(k, 64) !E2A180, E2A280, E2A380 end function shift_code pure elemental character(len = 4) function reverse_endian(i) integer, intent(in) :: i character:: tmp(4) tmp = transfer(i, ' ', size = 4) reverse_endian = transfer(tmp(4:1:-1), ' ') !array 4 to len 4 end function reverse_endian subroutine line(fig, x, y, ipen) class(fig_t), intent(in out) :: fig real, intent(in) :: x, y integer, intent(in) :: ipen integer, save :: ix0 = 0, iy0 = 0 integer :: ix, iy real, parameter :: xn = 80.0, yn = 100.0, fx = 1.0, fy = 0.85 ix = nint( fx * x + xn) iy = nint(-fy * y + yn) if (ipen == 1) call fig%line0(ix0, iy0, ix, iy) ix0 = ix iy0 = iy end subroutine line end module uniplot
program uniplot_main use :: uniplot implicit none type(fig_t) :: fig1 call fig1%init(140, 140) ! chin chin call fig1%line( 0.0, 11.0, 0) call fig1%line( 0.0, 8.0, 1) call fig1%line( -8.0, -26.5, 0) call fig1%line(-11.0, -24.0, 1) call fig1%line( 8.0, -26.5, 0) call fig1%line( 11.0, -24.0, 1) call fig1%line( 5.5, -26.0, 0) call fig1%line( 2.0, -36.0, 1) call fig1%line( -5.5, -26.0, 0) call fig1%line( -2.0, -36.0, 1) call fig1%line( 20.0, -18.0, 0) call fig1%line( 8.5, -19.0, 1) call fig1%line( 4.0, -21.5, 1) call fig1%line( 0.0, -23.0, 1) call fig1%line( -4.0, -21.5, 1) call fig1%line( -8.5, -19.0, 1) call fig1%line(-20.0, -18.0, 1) call fig1%line( 12.0, -16.0, 0) call fig1%line( 22.0, 14.0, 1) call fig1%line(-12.0, -16.0, 0) call fig1%line(-22.0, 14.0, 1) call fig1%line( 53.0, -9.0, 0) call fig1%line( 28.5, 1.0, 1) call fig1%line( 28.5, -14.0, 0) call fig1%line( 28.5, 25.0, 1) call fig1%line( 28.5, 33.0, 0) call fig1%line( 28.5, 76.0, 1) call fig1%line( -2.5, 76.0, 1) call fig1%line( -2.5, 72.0, 1) call fig1%line( -0.5, 68.0, 1) call fig1%line( 1.0, 66.0, 1) call fig1%line( -1.5, 67.0, 1) call fig1%line( -4.0, 72.0, 1) call fig1%line( -4.0, 76.0, 1) call fig1%line(-28.5, 76.0, 1) call fig1%line(-28.5, 33.0, 1) call fig1%line(-28.5, 25.0, 0) call fig1%line(-28.5, -14.0, 1) call fig1%line(-53.0, -9.0, 0) call fig1%line(-28.5, 1.0, 1) call fig1%line( 0.0, 0.0, 0) call fig1%line( 6.5, 0.0, 1) call fig1%line( 10.0, 3.0, 1) call fig1%line( 15.0, 7.0, 1) call fig1%line( 22.0, 14.0, 1) call fig1%line( 28.5, 25.0, 1) call fig1%line( 31.0, 26.0, 1) call fig1%line( 35.0, 34.0, 1) call fig1%line( 38.0, 44.0, 1) call fig1%line( 38.0, 53.0, 1) call fig1%line( 36.0, 55.0, 1) call fig1%line( 32.0, 55.0, 1) call fig1%line( 28.5, 51.0, 1) call fig1%line( 0.0, 0.0, 0) call fig1%line( -6.5, 0.0, 1) call fig1%line(-10.0, 3.0, 1) call fig1%line(-15.0, 7.0, 1) call fig1%line(-22.0, 14.0, 1) call fig1%line(-28.5, 25.0, 1) call fig1%line(-31.0, 26.0, 1) call fig1%line(-35.0, 34.0, 1) call fig1%line(-38.0, 44.0, 1) call fig1%line(-38.0, 53.0, 1) call fig1%line(-36.0, 55.0, 1) call fig1%line(-32.0, 55.0, 1) call fig1%line(-28.5, 51.0, 1) call fig1%line( 34.0, 55.0, 0) call fig1%line( 34.0, 76.0, 1) call fig1%line( 31.0, 82.0, 1) call fig1%line( 26.0, 87.0, 1) call fig1%line( 21.0, 91.0, 1) call fig1%line( 15.0, 95.0, 1) call fig1%line( 0.0, 95.0, 1) call fig1%line(-34.0, 55.0, 0) call fig1%line(-34.0, 76.0, 1) call fig1%line(-31.0, 82.0, 1) call fig1%line(-26.0, 87.0, 1) call fig1%line(-21.0, 91.0, 1) call fig1%line(-15.0, 95.0, 1) call fig1%line( 0.0, 95.0, 1) ! nose call fig1%line( -5.0, 41.0, 0) call fig1%line( -4.0, 40.0, 1) call fig1%line( 0.0, 40.0, 1) call fig1%line( 2.0, 42.0, 1) call fig1%line( 3.0, 42.0, 1) call fig1%line( 5.5, 37.0, 1) call fig1%line( 5.0, 37.0, 1) call fig1%line( 4.0, 38.5, 1) call fig1%line( 0.5, 38.5, 1) call fig1%line( 0.0, 37.0, 1) call fig1%line( -2.0, 37.0, 1) call fig1%line( -3.0, 38.5, 1) call fig1%line( -7.0, 38.5, 1) call fig1%line( -8.0, 37.0, 1) call fig1%line( -8.5, 40.0, 1) call fig1%line( -4.0, 45.0, 1) call fig1%line( -4.0, 54.0, 1) call fig1%line( -5.0, 55.0, 1) call fig1%line( -6.0, 53.0, 0) call fig1%line( -5.0, 53.0, 1) call fig1%line( -5.0, 47.0, 1) call fig1%line( -7.5, 46.0, 1) call fig1%line( -6.0, 53.0, 1) ! left eye call fig1%line(-24.0, 55.0, 0) call fig1%line(-22.0, 53.0, 1) call fig1%line(-17.0, 54.5, 1) call fig1%line( -8.0, 55.0, 1) call fig1%line( -7.0, 55.5, 1) call fig1%line( -8.5, 56.5, 1) call fig1%line(-24.0, 55.0, 1) call fig1%line( -8.0, 54.5, 0) call fig1%line(-12.0, 52.5, 1) call fig1%line(-23.0, 56.0, 0) call fig1%line(-21.5, 57.0, 1) call fig1%line(-10.0, 58.0, 1) call fig1%line( -9.0, 57.0, 1) ! left eyebrow call fig1%line(-27.5, 56.5, 0) call fig1%line(-24.0, 59.0, 1) call fig1%line(-11.0, 59.5, 1) call fig1%line( -7.0, 61.0, 1) call fig1%line( -4.0, 65.0, 1) call fig1%line( -9.0, 63.0, 1) call fig1%line(-25.0, 62.0, 1) call fig1%line(-27.5, 56.5, 1) ! right eyebrow call fig1%line( 27.5, 56.5, 0) call fig1%line( 24.0, 59.0, 1) call fig1%line( 11.0, 59.5, 1) call fig1%line( 7.0, 61.0, 1) call fig1%line( 4.0, 65.0, 1) call fig1%line( 9.0, 63.0, 1) call fig1%line( 25.0, 62.0, 1) call fig1%line( 27.5, 56.5, 1) ! right eye call fig1%line( 19.0, 53.0, 0) call fig1%line( 23.0, 55.0, 1) call fig1%line( 16.0, 55.0, 1) call fig1%line( 9.0, 56.0, 1) call fig1%line( 9.5, 55.0, 1) call fig1%line( 19.0, 53.0, 1) call fig1%line( 9.0, 58.0, 0) call fig1%line( 12.0, 58.0, 1) call fig1%line( 19.0, 56.0, 1) call fig1%line( 21.5, 56.0, 1) call fig1%line( 0.0, 29.0, 0) call fig1%line( 5.0, 29.0, 1) call fig1%line( 11.0, 27.0, 1) call fig1%line( 6.0, 32.0, 1) call fig1%line( 0.0, 30.0, 1) call fig1%line( -6.0, 32.0, 1) call fig1%line(-11.0, 27.0, 1) call fig1%line( -5.0, 29.0, 1) call fig1%line( 0.0, 29.0, 1) call fig1%line(-6.5, 21.5, 0) call fig1%line(-3.5, 20.0, 1) call fig1%line( 3.5, 20.0, 1) call fig1%line( 6.5, 21.5, 1) call fig1%line(-5.0, 21.0, 0) call fig1%line( 5.0, 21.0, 1) call fig1%show() end program uniplot_main
Modern Fortran: Building efficient parallel applications
- 作者:Curcic, Milan
- 発売日: 2020/11/24
- メディア: ペーパーバック