mirror of https://github.com/tidwall/tile38.git
105 lines
2.8 KiB
Plaintext
105 lines
2.8 KiB
Plaintext
package rtreebase
|
|
|
|
import (
|
|
"fmt"
|
|
"image/color"
|
|
"io"
|
|
"math"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/tidwall/pinhole"
|
|
)
|
|
|
|
// SavePNG draws and saves an image of the R-tree
|
|
func (tr *RTree) SavePNG(path string, width, height int, scale, rotateY float64, showNodes bool, withGIF bool, printer io.Writer) error {
|
|
return tr.savePNG2D(path, width, height, scale, rotateY, showNodes, withGIF, printer)
|
|
}
|
|
|
|
func (tr *RTree) savePNG2D(path string, width, height int, scale, rotateY float64, showNodes bool, withGIF bool, printer io.Writer) error {
|
|
p := pinhole.New()
|
|
tr.Traverse(func(min, max [D]float64, level int, item interface{}) bool {
|
|
p.Begin()
|
|
if level > 0 && showNodes {
|
|
p.DrawCube(min[0], min[1], 0, max[0], max[1], 0)
|
|
switch level {
|
|
default:
|
|
p.Colorize(color.RGBA{64, 64, 64, 128})
|
|
case 1:
|
|
p.Colorize(color.RGBA{32, 64, 32, 64})
|
|
case 2:
|
|
p.Colorize(color.RGBA{48, 48, 96, 96})
|
|
case 3:
|
|
p.Colorize(color.RGBA{96, 128, 128, 128})
|
|
case 4:
|
|
p.Colorize(color.RGBA{128, 128, 196, 196})
|
|
}
|
|
} else {
|
|
p.DrawDot(min[0], min[1], 0, 0.05)
|
|
p.Colorize(color.White)
|
|
}
|
|
p.End()
|
|
return true
|
|
})
|
|
p.Scale(scale, scale, scale)
|
|
p.Rotate(0, rotateY, 0)
|
|
// render the paths in an image
|
|
opts := *pinhole.DefaultImageOptions
|
|
opts.LineWidth = 0.025
|
|
opts.BGColor = color.Black
|
|
if err := p.SavePNG(path, width, height, &opts); err != nil {
|
|
return err
|
|
}
|
|
if printer != nil {
|
|
fmt.Fprintf(printer, "wrote %s\n", path)
|
|
}
|
|
if withGIF {
|
|
if err := createGIF(p, width, height, path, &opts, printer); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
func createGIF(p *pinhole.Pinhole, width, height int, path string, opts *pinhole.ImageOptions, printer io.Writer) error {
|
|
if err := os.MkdirAll("frames", 0700); err != nil {
|
|
return err
|
|
}
|
|
//var palette = palette.WebSafe
|
|
//outGif := &gif.GIF{}
|
|
for i := 0; i < 120; i++ {
|
|
p.Rotate(0, math.Pi*2/120.0, 0)
|
|
if err := p.SavePNG(fmt.Sprintf("frames/%d.png", i), width, height, opts); err != nil {
|
|
return err
|
|
}
|
|
//inGif := image.NewPaletted(inPng.Bounds(), palette)
|
|
//draw.Draw(inGif, inPng.Bounds(), inPng, image.Point{}, draw.Src)
|
|
//outGif.Image = append(outGif.Image, inGif)
|
|
//outGif.Delay = append(outGif.Delay, 0)
|
|
if printer != nil {
|
|
fmt.Fprintf(printer, "wrote frame %d/%d\n", i, 120)
|
|
}
|
|
}
|
|
if strings.HasSuffix(path, ".png") {
|
|
path = path[:len(path)-4] + ".gif"
|
|
}
|
|
_, err := exec.Command("ffmpeg", "-y", "-i", "frames/%d.png", path).CombinedOutput()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
//ffmpeg -i frames/%d.png test.gif
|
|
//f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600)
|
|
//if err != nil {
|
|
// return err
|
|
//}
|
|
//defer f.Close()
|
|
//if err := gif.EncodeAll(f, outGif); err != nil {
|
|
// return err
|
|
//}
|
|
if printer != nil {
|
|
fmt.Fprintf(printer, "wrote %s\n", path)
|
|
}
|
|
return nil
|
|
}
|