1
0
forked from MTSR/mapserver
mapserver/tilerenderer/renderer.go

249 lines
5.5 KiB
Go
Raw Permalink Normal View History

2019-01-11 18:00:40 +03:00
package tilerenderer
import (
2019-01-18 11:13:37 +03:00
"bytes"
2019-01-17 13:20:03 +03:00
"errors"
2019-01-13 18:37:03 +03:00
"image"
2019-01-17 13:20:03 +03:00
"image/draw"
2019-01-18 11:13:37 +03:00
"image/png"
2019-01-13 18:37:03 +03:00
"mapserver/coords"
2019-01-18 11:13:37 +03:00
"mapserver/db"
2019-01-28 15:31:48 +03:00
"mapserver/eventbus"
2019-01-18 11:13:37 +03:00
"mapserver/mapblockrenderer"
2019-02-09 20:05:40 +03:00
"mapserver/tiledb"
2023-12-29 18:00:11 +03:00
"mapserver/types"
2019-02-15 10:36:48 +03:00
"strconv"
2019-02-15 11:08:22 +03:00
"time"
2023-12-29 18:00:11 +03:00
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
2019-01-11 18:00:40 +03:00
)
type TileRenderer struct {
2019-01-13 18:37:03 +03:00
mapblockrenderer *mapblockrenderer.MapBlockRenderer
2023-12-29 18:00:11 +03:00
layers []*types.Layer
2019-02-09 20:05:40 +03:00
tdb *tiledb.TileDB
2019-01-18 11:13:37 +03:00
dba db.DBAccessor
2019-01-28 15:31:48 +03:00
Eventbus *eventbus.Eventbus
2019-01-11 18:00:40 +03:00
}
func resizeImage(src *image.NRGBA, tgt *image.NRGBA, xoffset int, yoffset int) {
if src == nil {
return
}
w := src.Bounds().Dy() >> 1
h := src.Bounds().Dx() >> 1
sinc := src.Bounds().Dy() * 4
tinc := tgt.Bounds().Dx() * 4
for y := 0; y < h; y++ {
six := y * sinc * 2
2019-10-01 09:14:06 +03:00
tix := 4*xoffset + (yoffset+y)*tinc
for x := 0; x < w; x++ {
r := (uint16(src.Pix[six]) + uint16(src.Pix[six+4]) + uint16(src.Pix[six+sinc]) + uint16(src.Pix[six+sinc+4])) >> 2
g := (uint16(src.Pix[six+1]) + uint16(src.Pix[six+5]) + uint16(src.Pix[six+sinc+1]) + uint16(src.Pix[six+sinc+5])) >> 2
b := (uint16(src.Pix[six+2]) + uint16(src.Pix[six+6]) + uint16(src.Pix[six+sinc+2]) + uint16(src.Pix[six+sinc+6])) >> 2
a := (uint16(src.Pix[six+3]) + uint16(src.Pix[six+7]) + uint16(src.Pix[six+sinc+3]) + uint16(src.Pix[six+sinc+7])) >> 2
tgt.Pix[tix] = uint8(r)
tgt.Pix[tix+1] = uint8(g)
tgt.Pix[tix+2] = uint8(b)
tgt.Pix[tix+3] = uint8(a)
2019-10-01 09:14:06 +03:00
tix += 4
six += 8
}
}
}
2019-01-17 13:20:03 +03:00
func NewTileRenderer(mapblockrenderer *mapblockrenderer.MapBlockRenderer,
2019-02-09 20:05:40 +03:00
tdb *tiledb.TileDB,
2019-01-17 17:14:13 +03:00
dba db.DBAccessor,
2023-12-29 18:00:11 +03:00
layers []*types.Layer) *TileRenderer {
2019-01-17 13:20:03 +03:00
2019-01-13 18:37:03 +03:00
return &TileRenderer{
mapblockrenderer: mapblockrenderer,
2019-01-18 11:13:37 +03:00
layers: layers,
tdb: tdb,
dba: dba,
2019-01-28 15:31:48 +03:00
Eventbus: eventbus.New(),
2019-01-13 18:37:03 +03:00
}
2019-01-11 18:00:40 +03:00
}
2019-01-17 13:20:03 +03:00
const (
2019-10-01 09:14:06 +03:00
IMG_SIZE = 256
SUB_IMG_SIZE = IMG_SIZE >> 1
2019-01-17 13:20:03 +03:00
)
2019-10-01 09:14:06 +03:00
func (tr *TileRenderer) Render(tc *coords.TileCoords) error {
2019-02-07 21:48:05 +03:00
//No tile in db
2019-09-25 11:22:02 +03:00
_, err := tr.renderImage(tc, 2)
2019-01-17 13:20:03 +03:00
if err != nil {
2019-09-25 11:22:02 +03:00
return err
2019-01-17 13:20:03 +03:00
}
2019-09-25 11:22:02 +03:00
return nil
2019-01-17 13:20:03 +03:00
}
2019-09-25 11:22:02 +03:00
func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (*image.NRGBA, error) {
2019-01-17 13:20:03 +03:00
2019-02-07 21:48:05 +03:00
if recursionDepth < 2 {
cachedtile, err := tr.tdb.GetTile(tc)
2019-01-17 13:20:03 +03:00
if err != nil {
2019-09-25 11:22:02 +03:00
return nil, err
2019-01-17 13:20:03 +03:00
}
2019-02-07 21:48:05 +03:00
if cachedtile != nil {
2019-02-09 20:05:40 +03:00
reader := bytes.NewReader(cachedtile)
2019-02-07 21:48:05 +03:00
cachedimg, err := png.Decode(reader)
if err != nil {
2019-09-25 11:22:02 +03:00
return nil, err
2019-02-07 21:48:05 +03:00
}
rect := image.Rectangle{
image.Point{0, 0},
image.Point{IMG_SIZE, IMG_SIZE},
}
2019-01-21 15:27:36 +03:00
2019-02-07 21:48:05 +03:00
img := image.NewNRGBA(rect)
draw.Draw(img, rect, cachedimg, image.ZP, draw.Src)
2019-01-21 15:27:36 +03:00
2019-02-07 21:48:05 +03:00
log.WithFields(logrus.Fields{"x": tc.X, "y": tc.Y, "zoom": tc.Zoom}).Debug("Cached image")
2019-09-25 11:22:02 +03:00
return img, nil
2019-02-07 21:48:05 +03:00
}
2019-01-21 15:27:36 +03:00
}
2019-02-19 11:06:12 +03:00
if recursionDepth <= 1 && tc.Zoom < 13 {
//non-cached layer and not in "origin" zoom, skip tile
2019-01-21 22:13:38 +03:00
log.WithFields(logrus.Fields{"x": tc.X, "y": tc.Y, "zoom": tc.Zoom}).Debug("Skip image")
2019-09-25 11:22:02 +03:00
return nil, nil
2019-01-17 13:20:03 +03:00
}
2019-01-17 13:27:31 +03:00
log.WithFields(logrus.Fields{"x": tc.X, "y": tc.Y, "zoom": tc.Zoom}).Debug("RenderImage")
2019-02-15 11:08:22 +03:00
renderedTiles.With(prometheus.Labels{"zoom": strconv.Itoa(tc.Zoom)}).Inc()
2019-02-15 10:36:48 +03:00
timer := prometheus.NewTimer(renderDuration)
defer timer.ObserveDuration()
2023-12-29 18:00:11 +03:00
currentLayer := types.FindLayerById(tr.layers, tc.LayerId)
2019-01-17 13:20:03 +03:00
if currentLayer == nil {
2023-12-29 18:00:11 +03:00
return nil, errors.New("no layer found")
2019-01-17 13:20:03 +03:00
}
2019-01-17 17:37:33 +03:00
if tc.Zoom > 13 || tc.Zoom < 1 {
2023-12-29 18:00:11 +03:00
return nil, errors.New("invalid zoom")
2019-01-17 17:37:33 +03:00
}
2019-01-17 12:04:09 +03:00
if tc.Zoom == 13 {
//max zoomed in on mapblock level
2019-01-17 13:20:03 +03:00
mbr := coords.GetMapBlockRangeFromTile(tc, 0)
mbr.Pos1.Y = currentLayer.From
mbr.Pos2.Y = currentLayer.To
2019-01-17 13:20:03 +03:00
2019-01-22 14:53:36 +03:00
img, err := tr.mapblockrenderer.Render(mbr.Pos1, mbr.Pos2)
if err != nil {
2019-02-25 09:29:31 +03:00
fields := logrus.Fields{
"pos1": mbr.Pos1,
"pos2": mbr.Pos2,
"err": err,
}
log.WithFields(fields).Debug("mapblock render from tilerender")
2019-09-25 11:22:02 +03:00
return nil, err
2019-01-22 14:53:36 +03:00
}
if img == nil {
2019-09-25 11:22:02 +03:00
return nil, nil
2019-01-22 14:53:36 +03:00
}
buf := new(bytes.Buffer)
png.Encode(buf, img)
2019-09-25 11:22:02 +03:00
return img, nil
2019-01-17 13:20:03 +03:00
}
//zoom 1-12
quads := tc.GetZoomedQuadrantsFromTile()
2019-01-21 22:13:38 +03:00
fields := logrus.Fields{
"UpperLeft": quads.UpperLeft,
"UpperRight": quads.UpperRight,
"LowerLeft": quads.LowerLeft,
"LowerRight": quads.LowerRight,
}
log.WithFields(fields).Debug("Quad image stats")
2019-01-22 15:17:30 +03:00
start := time.Now()
2019-09-25 11:22:02 +03:00
upperLeft, err := tr.renderImage(quads.UpperLeft, recursionDepth-1)
2019-01-17 13:20:03 +03:00
if err != nil {
2019-09-25 11:22:02 +03:00
return nil, err
2019-01-17 13:20:03 +03:00
}
2019-01-17 12:04:09 +03:00
2019-09-25 11:22:02 +03:00
upperRight, err := tr.renderImage(quads.UpperRight, recursionDepth-1)
2019-01-17 13:20:03 +03:00
if err != nil {
2019-09-25 11:22:02 +03:00
return nil, err
2019-01-17 12:04:09 +03:00
}
2019-09-25 11:22:02 +03:00
lowerLeft, err := tr.renderImage(quads.LowerLeft, recursionDepth-1)
2019-01-17 13:20:03 +03:00
if err != nil {
2019-09-25 11:22:02 +03:00
return nil, err
2019-01-17 13:20:03 +03:00
}
2019-09-25 11:22:02 +03:00
lowerRight, err := tr.renderImage(quads.LowerRight, recursionDepth-1)
2019-01-17 13:20:03 +03:00
if err != nil {
2019-09-25 11:22:02 +03:00
return nil, err
2019-01-17 13:20:03 +03:00
}
2019-01-22 15:17:30 +03:00
t := time.Now()
quadrender := t.Sub(start)
start = t
2019-01-17 13:20:03 +03:00
img := image.NewNRGBA(
image.Rectangle{
image.Point{0, 0},
image.Point{IMG_SIZE, IMG_SIZE},
},
)
resizeImage(upperLeft, img, 0, 0)
resizeImage(upperRight, img, SUB_IMG_SIZE, 0)
resizeImage(lowerLeft, img, 0, SUB_IMG_SIZE)
resizeImage(lowerRight, img, SUB_IMG_SIZE, SUB_IMG_SIZE)
2019-01-17 13:20:03 +03:00
2019-01-22 15:17:30 +03:00
t = time.Now()
quadresize := t.Sub(start)
start = t
2019-01-17 13:38:13 +03:00
buf := new(bytes.Buffer)
2019-01-21 22:13:38 +03:00
png.Encode(buf, img)
2019-01-17 13:38:13 +03:00
2019-01-22 15:17:30 +03:00
t = time.Now()
encode := t.Sub(start)
start = t
2019-02-09 20:05:40 +03:00
tile := buf.Bytes()
tr.tdb.SetTile(tc, tile)
2019-01-17 13:20:03 +03:00
2019-01-22 15:17:30 +03:00
t = time.Now()
cache := t.Sub(start)
fields = logrus.Fields{
"X": tc.X,
"Y": tc.Y,
"Zoom": tc.Zoom,
"LayerId": tc.LayerId,
2019-02-09 20:05:40 +03:00
"size": len(tile),
2019-01-22 15:17:30 +03:00
"quadrender": quadrender,
"quadresize": quadresize,
"encode": encode,
"cache": cache,
}
log.WithFields(fields).Debug("Cross stitch")
2019-01-28 15:31:48 +03:00
tr.Eventbus.Emit(eventbus.TILE_RENDERED, tc)
2019-01-22 17:25:33 +03:00
2019-09-25 11:22:02 +03:00
return img, nil
2019-01-11 18:00:40 +03:00
}