使用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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章