3D 等距投影的着色

Coloring for 3D Isometric projection

问题是,基于以下程序 https://github.com/adonovan/gopl.io/blob/master/ch3/surface/main.go

  1. 将其转为 Web 服务器并将 SVG 呈现为网页
  2. 为 SVG 着色,使峰为红色,谷为蓝色

我肯定第一部分是对的,我想我第二部分是对的,但显然不是,但我不知道我哪里错了。请帮忙。

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
}

这是我得到的结果:

注意,虽然这个问题看起来是围棋的,但实际上是 getColor() 我要问的算法。你可以 understand/answer 即使你不使用 Go 编写。

您的代码使用格式动词 %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,这是正确的十六进制颜色。

输出: