使用Go語言繪製彩色SVG圖

我們現在使用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的解答。

發佈了238 篇原創文章 · 獲贊 103 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章