英文:
Coloring for 3D Isometric projection
问题
以下是翻译好的内容:
要求是基于以下程序进行操作:
https://github.com/adonovan/gopl.io/blob/master/ch3/surface/main.go
- 将其转换为一个Web服务器,并将SVG渲染为网页。
- 对SVG进行着色,使峰值为红色,谷底为蓝色。
我确定已经完成了第一部分,而且我认为我也完成了第二部分,但显然不正确,但我不知道错在哪里。请帮忙。
package main
import (
"fmt"
"math"
"net/http"
"strconv"
)
const (
cells = 100 // 网格单元数
xyrange = 30.0 // 坐标轴范围 (-xyrange..+xyrange)
angle = math.Pi / 6 // x、y轴的角度 (=30°)
)
var height, width = 300, 600 // 画布大小(像素)
var xyscale = width / 2 / xyrange // 每个x或y单位的像素数
var zscale = float64(height) * 0.4 // 每个z单位的像素数
var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)
func main() {
addr := ":8000"
fmt.Printf("访问\n http://localhost%s/\n http://localhost%s/?height=600&width=1200\n", addr, addr)
//http服务器
http.HandleFunc("/", handle)
http.ListenAndServe(addr, nil)
}
func handle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/svg+xml")
if err := r.ParseForm(); err != nil {
return
}
for k, v := range r.Form {
if k == "height" {
h, _ := strconv.Atoi(v[0])
if h > 0 {
height = h
}
}
if k == "width" {
w, _ := strconv.Atoi(v[0])
if w > 0 {
width = w
}
}
}
xyscale = width / 2 / xyrange
zscale = float64(height) * 0.4
fmt.Fprintf(w, "<svg xmlns='http://www.w3.org/2000/svg' "+
"style='stroke: grey; stroke-width: 0.7' "+
"width='%d' height='%d'>", 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)
r, g, b := getColor(i, j)
fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g' fill='#%x%x%x'/>\n",
ax, ay, bx, by, cx, cy, dx, dy, r, g, b)
}
}
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)等距地投影到2-D SVG画布上(sx,sy)。
sx := float64(width/2) + (x-y)*cos30*float64(xyscale)
sy := float64(height/2) + (x+y)*sin30*float64(xyscale) - z*zscale
return sx, sy
}
func f(x, y float64) float64 {
r := math.Hypot(x, y) // (0,0)到(x,y)的距离
return math.Sin(r) / r
}
func getColor(i, j int) (int, int, int) {
// 找到单元格(i,j)到单元格(i+1,j+1)中心的中点(x,y)。
x := xyrange * (float64(i)/cells + 0.5/cells - 0.5)
y := xyrange * (float64(j)/cells + 0.5/cells - 0.5)
// 计算表面高度z。
z := math.Hypot(x, y) // (0,0)到(x,y)的距离
v := int(math.Sin(z)*127) + 128
r := v
g := 0
b := 255 - v
return r, g, b
}
这是我得到的结果:
注意,尽管问题似乎是关于Go语言的,但实际上我问的是getColor()
算法。即使你不用Go语言编写,你也可以理解/回答这个问题。
英文:
The ask is, base on the following program
https://github.com/adonovan/gopl.io/blob/master/ch3/surface/main.go
- Turn it to a web server and render the SVG as web page
- Color the SVG so that the peak is red and valley is blue
I've got the 1st part right for sure, and I think I got the 2nd part right but apparently not, yet I have no idea where I'm wrong. Please help.
package main
import (
"fmt"
"math"
"net/http"
"strconv"
)
const (
cells = 100 // number of grid cells
xyrange = 30.0 // axis ranges (-xyrange..+xyrange)
angle = math.Pi / 6 // angle of x, y axes (=30°)
)
var height, width = 300, 600 // canvas size in pixels
var xyscale = width / 2 / xyrange // pixels per x or y unit
var zscale = float64(height) * 0.4 // pixels per z unit
var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)
func main() {
addr := ":8000"
fmt.Printf("Visit\n http://localhost%s/\n http://localhost%[1]s/?height=600&width=1200\n", addr)
//http server
http.HandleFunc("/", handle)
http.ListenAndServe(addr, nil)
}
func handle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/svg+xml")
if err := r.ParseForm(); err != nil {
return
}
for k, v := range r.Form {
if k == "height" {
h, _ := strconv.Atoi(v[0])
if h > 0 {
height = h
}
}
if k == "width" {
w, _ := strconv.Atoi(v[0])
if w > 0 {
width = w
}
}
}
xyscale = width / 2 / xyrange
zscale = float64(height) * 0.4
fmt.Fprintf(w, "<svg xmlns='http://www.w3.org/2000/svg' "+
"style='stroke: grey; stroke-width: 0.7' "+
"width='%d' height='%d'>", 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)
r, g, b := getColor(i, j)
fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g' fill='#%x%x%x'/>\n",
ax, ay, bx, by, cx, cy, dx, dy, r, g, b)
}
}
fmt.Fprintf(w, "</svg>")
}
func corner(i, j int) (float64, float64) {
// 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)
// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).
sx := float64(width/2) + (x-y)*cos30*float64(xyscale)
sy := float64(height/2) + (x+y)*sin30*float64(xyscale) - z*zscale
return sx, sy
}
func f(x, y float64) float64 {
r := math.Hypot(x, y) // distance from (0,0)
return math.Sin(r) / r
}
func getColor(i, j int) (int, int, int) {
// Find point (x,y) at middle of corner of cell (i,j) to cell (i+1,j+1).
x := xyrange * (float64(i)/cells + 0.5/cells - 0.5)
y := xyrange * (float64(j)/cells + 0.5/cells - 0.5)
// Compute surface height z.
z := math.Hypot(x, y) // distance from (0,0)
v := int(math.Sin(z)*127) + 128
r := v
g := 0
b := 255 - v
return r, g, b
}
Here is the result that I got:
NB, although the question seems to be for Go, but it is actually the
getColor()
algorithm that I'm asking about. You can understand/answer even if you don't write in Go.
答案1
得分: 1
你的代码使用格式动词%x
将十六进制值打印到SVG的fill
属性中:
fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g' fill='#%x%x%x'/>\n",
ax, ay, bx, by, cx, cy, dx, dy, r, g, b)
这会导致一些数字(如0和1)以一个十六进制数字的形式进行格式化。例如,RGB(254, 0, 1)将被格式化为fe01
。然后,浏览器会错误地渲染颜色。
将格式动词更改为%02x
,以确保RGB始终以两个十六进制数字打印。
现在RGB(254, 0, 1)被打印为fe0001
,这是正确的十六进制颜色。
输出:
英文:
Your code uses the format verb %x
to print the hex values to the SVG's fill
attribute:
fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g' fill='#%x%x%x'/>\n",
ax, ay, bx, by, cx, cy, dx, dy, r, g, b)
This causes some numbers like 0 and 1 to be formatted with one hex digit. For example RGB (254, 0, 1) would be formatted as fe01
. The browser then render colors incorrectly.
Change the format verbs to %02x
to ensure the RGB is always printed with two hex digits.
Now RGB (254, 0, 1) is printed as fe0001
, which is the correct hex color.
Output:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论