SVG プロット golang 本 丸写しw


SVG プロットプログラム移植

『プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES) Alan A.A. Donovan and Brian W. Kernighan』をパラパラと開いて見たら、きれいな三次元プロットの絵があって、ライブラリ無しで SVG ファイルを書き出しているようなので、移植してみることにしました。

Goの本を買う気は全くありませんが、多分ネット上にサンプルは落ちているだろうと、探したらありました。ビバ!ネット時代!郷ひろみ!僕たち男の子!

https://github.com/golang/go/wiki/Books
https://github.com/adonovan/gopl.io/blob/master/ch3/surface/main.go

実行結果

SVG ファイルの冒頭部分

<svg xmlns='http://www.w3.org/2000/svg' style='stroke: grey; fill: white; stroke-width: 0.7' width=  600 height=  320>
<polygon points="  302.5981,    6.4081  300.0000,    5.7653  297.4019,    6.4081  300.0000,    7.2564"/>
<polygon points="  300.0000,    7.2564  297.4019,    6.4081  294.8038,    7.2673  297.4019,    8.3568"/>
<polygon points="  297.4019,    8.3568  294.8038,    7.2673  292.2058,    8.3682  294.8038,    9.7242"/>
<polygon points="  294.8038,    9.7242  292.2058,    8.3682  289.6077,    9.7246  292.2058,   11.3613"/>

プログラム

fortran では x,y = func(i, j) 的な左辺の書き方が許されないので、座標の派生型を定義しました。またインデックスは万世一系の我が国にふさわしく1始まりにしました。

go言語は出力のフォーマット指定が C 言語風で分かりにくく、少し戸惑いました。

!   Port from "The Go Programming Language"  chap. 3 
!
!  original : https://github.com/adonovan/gopl.io/blob/master/ch3/surface/main.go
!  // Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
!  // License: https://creativecommons.org/licenses/by-nc-sa/4.0/  
!
    module m_svg
      implicit none
      real, parameter :: pi = 4.0 * atan(1.0) 
      real, parameter :: sin30 = sin(pi / 6.0), cos30 = cos(pi / 6.0)
      integer, parameter :: nwidth = 600, nheight = 320 ! canvas size in pixels
      integer, parameter :: ncells = 100                ! number of grid cells
      real, parameter :: xyrange = 30.0                 ! axis range (-xyrange .. +xyrange) 
      real, parameter :: xyscale = nwidth / 2 / xyrange ! pixels per x or y unit
      real, parameter :: zscale  = nheight * 0.4        ! pixels per z unit
 !
      type :: t_xy
        real :: x, y
      end type  
    contains
      type(t_xy) function corner(i, j) ! Find point (x,y) at corner of cell (i,j).
        integer, intent(in) :: i, j  
        real :: x, y, r, z
        x = xyrange * (real(i) / ncells - 0.5)
        y = xyrange * (real(j) / ncells - 0.5)
        r = hypot(x, y)
        z = sin(r) / r
        corner%x = nwidth  / 2 + (x - y) * cos30 * xyscale
        corner%y = nheight / 2 + (x + y) * sin30 * xyscale - z * zscale
      end function corner
    end module m_svg

    program SVG
      use m_svg
      implicit none
      integer, parameter :: iw = 11
      integer :: i, j
      type(t_xy) :: a, b, c, d
      open(11, file = 'SVG.html')
      write(iw, '(a, i5, a, i5, a)') "<svg xmlns='http://www.w3.org/2000/svg' " // &
                       "style='stroke: grey; fill: white; stroke-width: 0.7' " // &
                       "width=", nwidth, " height=", nheight, ">"
      do i = 1, ncells
        do j = 1, ncells 
          a = corner(i    , j - 1)
          b = corner(i - 1, j - 1)
          c = corner(i - 1, j    )
          d = corner(i    , j    )
          write(iw, '(a, 4(f10.4, ",", f10.4), a)') '<polygon points="', a, b, c, d, '"/>'
        end do
      end do     
      write(iw, '(a)') "</svg>"
    end program SVG