3D 等角投影着色

发布于 2025-01-16 15:15:02 字数 3541 浏览 5 评论 0原文

要求是,基于以下程序 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
}

这是我得到的结果:

在此处输入图像描述

注意,虽然问题似乎是针对 Go,但实际上是 我正在询问的 getColor() 算法。即使你不是用 Go 写的,你也能理解/回答。

The ask is, base on the following program
https://github.com/adonovan/gopl.io/blob/master/ch3/surface/main.go

  1. Turn it to a web server and render the SVG as web page
  2. 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:

enter image description here

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我最亲爱的 2025-01-23 15:15:02

您的代码使用格式动词 %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:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文