我們現在使用Go語言來繪製上圖,即函數sin(r)/r所形成的畫面。
代碼如下:
// Surface computes an SVG redenring of a 3-D surface function.
package main
import (
"fmt"
"math"
)
const (
width, height = 600, 320 // 帆布大小,單位是像素
cells = 100 // 方格數量
xyrange = 30.0 // 座標軸範圍,從-xyrange到xyrange
xyscale = width / 2 / xyrange // 像素數每xy座標軸單位長度
zscale = height * 0.4 // 像素數每z軸單位長度
angle = math.Pi / 6 // 視線與水平面夾角
)
var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)
func main() {
// svg文件的風格信息
fmt.Printf("<svg xmlns='http://www.w3.org/2000/svg' "+
"style='stroke: grey; fill: white; stroke-width: 0.7' "+
"width='%d' height='%d'>", width, height)
for i := 0; i < cells; i++ {
for j := 0; j < cells; j++ {
ax, ay, ac := corner(i+1, j)
bx, by, _ := corner(i, j)
cx, cy, _ := corner(i, j+1)
dx, dy, _ := corner(i+1, j+1)
expression := math.IsInf(ax, 0) || math.IsInf(ay, 0)
expression = expression || math.IsInf(bx, 0) || math.IsInf(by, 0)
expression = expression || math.IsInf(cx, 0) || math.IsInf(cy, 0)
expression = expression || math.IsInf(dx, 0) || math.IsInf(dy, 0)
// 如果高度爲無窮,則放棄該格子
if expression {
continue
}
// 繪製其中一個格子,points標誌格子四個角座標,style=fill表示填充顏色
fmt.Printf("<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
"style='fill: #%x'/>\n",
ax, ay, bx, by, cx, cy, dx, dy, ac)
}
}
fmt.Println("</svg>") // svg格式與HTML類似
}
func corner(i, j int) (float64, float64, int) {
// Find point (x,y) at corner of cell (i,j).
x := xyrange * (float64(i) / cells - 0.5)
y := xyrange * (float64(j) / cells - 0.5)
// Compute surface height z
z := f(x, y)
// 最低點的顏色接近純藍色(#0000ff)
// 最高點的顏色接近純紅色(#ff0000)
color := int((0xff0000 - 0x0000ff) * (z + 0.3) / 1.3 + 0x0000ff)
//Project (x, y, z) isometrically onto 2-D SVG canvas (sx, sy)
sx := width/2 + (x-y)*cos30*xyscale
sy := height/2 + (x+y)*sin30*xyscale - z*zscale
return sx, sy, color
}
func f(x, y float64) float64 {
r := math.Hypot(x, y)
return math.Sin(r) / r
}
在命令行輸入:
go run Go文件名.go > svg文件名.svg
在瀏覽器輸入地址
svg文件路徑/svg文件名.svg
即可得到上圖。
除了把svg信息寫到文件中外,我們還可以設置一個服務器,用瀏覽器訪問該服務器就可以觀看此圖。代碼如下。
// Surface computes an SVG redenring of a 3-D surface function.
package main
import (
"fmt"
"math"
"log"
"net/http"
)
const (
width, height = 1200, 640 // 帆布大小,單位是像素
cells = 100 // 方格數量
xyrange = 30.0 // 座標軸範圍,從-xyrange到xyrange
xyscale = width / 2 / xyrange // 像素數每xy座標軸單位長度
zscale = height * 0.4 // 像素數每z軸單位長度
angle = math.Pi / 6 // 視線與水平面夾角
)
var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)
func main() {
http.HandleFunc("/", handler) // 每收到一個請求,就調用handler
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
// 設置響應文件頭信息,這是必須的。否則瀏覽器無法成功解析
w.Header().Set("Content-Type", "image/svg+xml")
// svg文件的風格信息
fmt.Fprintf(w, "<svg xmlns='http://www.w3.org/2000/svg' "+
"style='stroke: grey; fill: white; stroke-width: 0.7' "+
"width='%d' height='%d'>", width, height)
for i := 0; i < cells; i++ {
for j := 0; j < cells; j++ {
ax, ay, ac := corner(i+1, j)
bx, by, _ := corner(i, j)
cx, cy, _ := corner(i, j+1)
dx, dy, _ := corner(i+1, j+1)
expression := math.IsInf(ax, 0) || math.IsInf(ay, 0)
expression = expression || math.IsInf(bx, 0) || math.IsInf(by, 0)
expression = expression || math.IsInf(cx, 0) || math.IsInf(cy, 0)
expression = expression || math.IsInf(dx, 0) || math.IsInf(dy, 0)
// 如果高度爲無窮,則放棄該格子
if expression {
continue
}
// 繪製其中一個格子,points標誌格子四個角座標,style=fill表示填充顏色
fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
"style='fill: #%x'/>\n",
ax, ay, bx, by, cx, cy, dx, dy, ac)
}
}
fmt.Fprintf(w, "</svg>\n") // svg格式與HTML類似
}
func corner(i, j int) (float64, float64, int) {
// Find point (x,y) at corner of cell (i,j).
x := xyrange * (float64(i) / cells - 0.5)
y := xyrange * (float64(j) / cells - 0.5)
// Compute surface height z
z := f(x, y)
// 最低點的顏色接近純藍色(#0000ff)
// 最高點的顏色接近純紅色(#ff0000)
color := int((0xff0000 - 0x0000ff) * (z + 0.3) / 1.3 + 0x0000ff)
//Project (x, y, z) isometrically onto 2-D SVG canvas (sx, sy)
sx := width/2 + (x-y)*cos30*xyscale
sy := height/2 + (x+y)*sin30*xyscale - z*zscale
return sx, sy, color
}
func f(x, y float64) float64 {
r := math.Hypot(x, y)
return math.Sin(r) / r
}
在命令行中運行該文件
go run Go文件名.go
在瀏覽器中訪問地址
localhost:8000
即可😊😋😁
上面代碼實際上是《Go程序設計語言》練習3.1、3.3、3.4的解答。