fortran66のブログ

fortran について書きます。

【メモ帳】unicode 点字で阿部さん

unicode 表示 

Apple の terminal は unicode 文字を表示してくれるので、unicode点字文字を使ったグラフィックスに挑戦してみることにします。ここで点字文字は 4 行 2 列の点で出来ています。

WindowsDOS 窓や WSL コンソールでは unicode 文字がうまく表示されないのですが、Windows Terminal や Visual Studio Code の Terminal では表示可能のようでしたので、こちらでも挑戦してみました。

unicode 点字

以前 Julia の unicode plots を見て便利そうだなと思っておりました。 docs.juliaplots.org

調べてみると、元々のアイデアpython 用の点字プロットにあるようでした。 github.com

en.wikipedia.org

Fortranunicode

FortranFortran 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 と組み合わせが悪いようでうまくいきませんでした。今後の課題としたいと思います。

f:id:fortran66:20210524204603p:plain

Windows WSL での出力

fpm を使ってみました。ファイル名・ファイル構成などを縛られるのでメンドイです。

f:id:fortran66:20210524210405p:plain

ウホッ!!いい男たち~ヤマジュン・パーフェクト

ウホッ!!いい男たち~ヤマジュン・パーフェクト

  • 作者:山川 純一
  • 発売日: 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

Modern Fortran: Building efficient parallel applications

  • 作者:Curcic, Milan
  • 発売日: 2020/11/24
  • メディア: ペーパーバック