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