函数sin(r)/r的图形输出样例

package main
//根据一个三维曲面函数计算并生成svg
import (
	"fmt"
	"math"
	"net/http"
)

const (
	width, height = 600, 320 //以像素表示的画布大小
	cells         = 100 //网格单元的个数
	xyrange       = 30.0//坐标轴的范围 (-xyrange,xyrange)
	xyscale       = width / 2 / xyrange //x 或 y轴上每个单位长度的像素
	zscale        = height * 0.4 //z轴上每个单位长度的像素
	angle         = math.Pi / 6//x、y轴的角度 (=30°)
)

var sin30, cos30 = math.Sin(angle), math.Cos(angle)

func main() {
	http.HandleFunc("/", drawSVG)
	http.ListenAndServe("localhost:8080", nil)
}

func drawSVG(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "image/svg+xml")
	_, _ = fmt.Fprintf(w, "<svg xmlns='http://www.w3.org/2000/svg' "+
		"style='stroke:grey;fill:white;stroke-width:0.7' width='%d' height='%d'>\n",
		width, height)
	for i := 0; i < cells; i++ {
		for j := 0; j < cells; j++ {
			ax, ay := corner(i+1, j)
			bx, by := corner(i, j)
			cx, cy := corner(i, j+1)
			dx, dy := corner(i+1, j+1)
			_, _ = fmt.Fprintf(w, "<polygon points='%g,%g,%g,%g,%g,%g,%g,%g' />\n", ax, ay, bx, by, cx, cy, dx, dy)
		}
	}
	_, _ = fmt.Fprintf(w, "</svg>")
}

func corner(i, j int) (float64, float64) {
	//求出网格单元 (i,j)的顶点坐标(x,y)
	x := xyrange * (float64(i)/cells - 0.5)
	y := xyrange * (float64(j)/cells - 0.5)
	//计算曲面高度 z
	z := f(x, y)
	//将(x,y,z)等角投射到二维svg绘图平面上,坐标(sx,sy)
	sx := width/2 + (x-y)*cos30*xyscale
	sy := height/2 + (x+y)*sin30*xyscale - z*zscale
	return sx, sy
}

func f(x, y float64) float64 {
	r := math.Hypot(x, y) //到(0,0)的距离
	return math.Sin(r)/r
}

访问浏览器 http://localhost:8080 ,浏览器会展示如下图形

3d表达sin(r)/r

比较特殊的输出格式符

%q 输出被双引号扩起来的字符串,并且会将字符串中的双引号进行转义。

fmt.Printf(“%q”,”abc\””)

输出 “abc\””,而不是abc”

%+v 输出结构体格式,并且带着字段名。

fmt.Printf(“%+v”,Coordinate{Lon:1,Lat:1})

输出{Lon:1,Lat:1}

%#v 这输出go语言的语法表示,如输出Coordinate{Lon:1,Lat:1}

%T 输出变量的类型,如输出Coordinate。

%[1]d 表示输出第一个参数,go语言支持指定输出顺序。

fmt.Printf(“%d , %[1]d”,123)

另外:

\r 是个很酷的格式符,会从当前行头开始显示,比如循环输出计数时可以用到。

判断某点是否在圆形、三角形内

go语言实现的函数

计算两点距离,圆心与某点距离小于等于半径,计算某点和三角形三个点组成的三个小三角形的面积之和是否等于该三角形的面积。

package twod

import (
	"fmt"
	"math"
)

type Coordinate struct {
	Lat float64
	Lon float64
}

//compute the distance between two coordinates
func ComputeDistance(a Coordinate, b Coordinate) float64 {
	return math.Sqrt(math.Pow(b.Lon-a.Lon, 2) + math.Pow(b.Lat-a.Lat, 2))
}

func InsideCircle(center Coordinate, radius float64, p Coordinate) bool {
	return ComputeDistance(center, p) <= radius
}

//compute the angel of ∠BAC
func ComputeAngle(a Coordinate, b Coordinate,c Coordinate) float64{
	lenAC :=ComputeDistance(a,c)
	lenAB :=ComputeDistance(a,b)
	lenBC :=ComputeDistance(b,c)
	molecule :=math.Pow(lenAB,2) + math.Pow(lenAC,2) - math.Pow(lenBC,2)
	denominator := 2*lenAB*lenAC
	return math.Acos(molecule/denominator)*180/math.Pi
}

//compute the area of a triangle
func ComputeArea(a Coordinate, b Coordinate,c Coordinate) float64{
	lenCA :=ComputeDistance(c,a)
	lenCB :=ComputeDistance(c,b)
	lenAB :=ComputeDistance(b,a)

	if lenCA+lenCB > lenAB && lenCB+lenAB > lenCA &&lenAB+lenCA < lenCB {
		panic("not a triangle")
	}

	perimeter :=lenCA+lenCB+lenAB
	return math.Sqrt(perimeter/2*(perimeter/2-lenCA)*(perimeter/2-lenCB)*(perimeter/2-lenAB))
}

func InsideTriangle(a Coordinate, b Coordinate,c Coordinate, p Coordinate) bool {
	areaABP :=ComputeArea(a,b,p)
	areaBCP:=ComputeArea(b,c,p)
	areaCAP :=ComputeArea(c,a,p)

	areaABC :=ComputeArea(a,b,c)
	return fmt.Sprintf("%.3f", areaABP+areaBCP+areaCAP) == fmt.Sprintf("%.3f", areaABC)
}

调用示例:

length := twod.ComputeDistance(
		twod.Coordinate{Lon: 0.3,Lat: 0.3},
		twod.Coordinate{Lon: 1,Lat: 1})
	log.Printf("%.2f", length)

	log.Println(twod.InsideCircle(twod.Coordinate{Lon: 0, Lat: 0}, 5,
		twod.Coordinate{Lon: 0, Lat: 4.8}))

	inside := twod.InsideTriangle(
		twod.Coordinate{Lon: 0, Lat: 0},
		twod.Coordinate{Lon: 50, Lat: 50},
		twod.Coordinate{Lon: 100, Lat: 0},
		twod.Coordinate{Lon: 2, Lat: 2})
	log.Println(inside)

	angel := twod.ComputeAngle(twod.Coordinate{Lon: 0, Lat: 0},
		twod.Coordinate{Lon: 1, Lat: 0},
		twod.Coordinate{Lon: 1, Lat: 3})
	log.Printf("%.2f", angel)