1
0
forked from MTSR/mapserver

working tile stitching

This commit is contained in:
NatureFreshMilk 2019-01-17 11:20:03 +01:00
parent abbf16b4bd
commit acd2e0c8d0
4 changed files with 150 additions and 7 deletions

View File

@ -14,4 +14,5 @@ type DBAccessor interface {
Migrate() error Migrate() error
GetTile(pos coords.TileCoords) (*Tile, error) GetTile(pos coords.TileCoords) (*Tile, error)
SetTile(tile *Tile) error SetTile(tile *Tile) error
RemoveTile(pos coords.TileCoords) error
} }

View File

@ -90,6 +90,17 @@ func (db *Sqlite3Accessor) SetTile(tile *Tile) error {
return err return err
} }
const removeTileQuery = `
delete from tiles
where x = ? and y = ? and zoom = ? and layerid = ?
`
func (db *Sqlite3Accessor) RemoveTile(pos coords.TileCoords) error {
_, err := db.db.Exec(removeTileQuery, pos.X, pos.Y, pos.Zoom, pos.LayerId)
return err
}
func NewSqliteAccessor(filename string) (*Sqlite3Accessor, error) { func NewSqliteAccessor(filename string) (*Sqlite3Accessor, error) {
db, err := sql.Open("sqlite3", filename) db, err := sql.Open("sqlite3", filename)
if err != nil { if err != nil {

View File

@ -1,29 +1,147 @@
package tilerenderer package tilerenderer
import ( import (
"errors"
"image" "image"
"bytes"
"image/png"
"image/draw"
"mapserver/coords" "mapserver/coords"
"mapserver/mapblockrenderer" "mapserver/mapblockrenderer"
"mapserver/layerconfig"
"mapserver/tiledb"
) )
type TileRenderer struct { type TileRenderer struct {
mapblockrenderer *mapblockrenderer.MapBlockRenderer mapblockrenderer *mapblockrenderer.MapBlockRenderer
layers []layerconfig.Layer
tdb tiledb.DBAccessor
} }
func NewTileRenderer(mapblockrenderer *mapblockrenderer.MapBlockRenderer) *TileRenderer { func NewTileRenderer(mapblockrenderer *mapblockrenderer.MapBlockRenderer,
tdb tiledb.DBAccessor,
layers []layerconfig.Layer) *TileRenderer {
return &TileRenderer{ return &TileRenderer{
mapblockrenderer: mapblockrenderer, mapblockrenderer: mapblockrenderer,
layers: layers,
tdb: tdb,
} }
} }
//TODO layerConfig const (
func (tr *TileRenderer) Render(tc coords.TileCoords) (*image.NRGBA, error) { IMG_SIZE = 256
)
func (tr *TileRenderer) Render(tc coords.TileCoords) ([]byte, error) {
//Check cache
tile, err := tr.tdb.GetTile(tc)
if err != nil {
return nil, err
}
if tile == nil {
//No tile in db
img, err := tr.RenderImage(tc)
if err != nil {
return nil, err
}
buf := new(bytes.Buffer)
png.Encode(buf, img)
return buf.Bytes(), nil
}
return tile.Data, nil
}
func (tr *TileRenderer) RenderImage(tc coords.TileCoords) (*image.NRGBA, error) {
cachedtile, err := tr.tdb.GetTile(tc)
if err != nil {
return nil, err
}
if cachedtile != nil {
reader := bytes.NewReader(cachedtile.Data)
cachedimg, err := png.Decode(reader)
if err != nil {
return nil, err
}
return cachedimg.(*image.NRGBA), nil
}
var layer *layerconfig.Layer
for _, l := range(tr.layers) {
if l.Id == tc.LayerId {
layer = &l
}
}
if layer == nil {
return nil, errors.New("No layer found")
}
if tc.Zoom == 13 { if tc.Zoom == 13 {
//max zoomed in on mapblock level //max zoomed in on mapblock level
//mbr := coords.GetMapBlockRangeFromTile(tc, 0) mbr := coords.GetMapBlockRangeFromTile(tc, 0)
//return tr.mapblockrenderer.Render() mbr.Pos1.Y = layer.From
mbr.Pos2.Y = layer.To
return tr.mapblockrenderer.Render(mbr.Pos1, mbr.Pos2)
} }
return nil, nil if tc.Zoom > 13 || tc.Zoom < 1 {
return nil, errors.New("Invalid zoom")
}
//zoom 1-12
quads := tc.GetZoomedQuadrantsFromTile()
upperLeft, err := tr.RenderImage(quads.UpperLeft)
if err != nil {
return nil, err
}
upperRight, err := tr.RenderImage(quads.UpperRight)
if err != nil {
return nil, err
}
lowerLeft, err := tr.RenderImage(quads.LowerLeft)
if err != nil {
return nil, err
}
lowerRight, err := tr.RenderImage(quads.LowerRight)
if err != nil {
return nil, err
}
img := image.NewNRGBA(
image.Rectangle{
image.Point{0, 0},
image.Point{IMG_SIZE, IMG_SIZE},
},
)
rect := image.Rect(0, 0, 128, 128)
draw.Draw(img, rect, upperLeft, image.ZP, draw.Src)
rect = image.Rect(128, 0, 256, 128)
draw.Draw(img, rect, upperRight, image.ZP, draw.Src)
rect = image.Rect(0, 128, 128, 256)
draw.Draw(img, rect, lowerLeft, image.ZP, draw.Src)
rect = image.Rect(128, 128, 256, 256)
draw.Draw(img, rect, lowerRight, image.ZP, draw.Src)
return img, nil
} }

View File

@ -9,8 +9,11 @@ import (
"mapserver/testutils" "mapserver/testutils"
"mapserver/mapblockrenderer" "mapserver/mapblockrenderer"
"mapserver/coords" "mapserver/coords"
"mapserver/layerconfig"
"mapserver/tiledb"
"os" "os"
"testing" "testing"
"bytes"
) )
func TestTileRender(t *testing.T) { func TestTileRender(t *testing.T) {
@ -20,6 +23,7 @@ func TestTileRender(t *testing.T) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer os.Remove(tmpfile.Name()) defer os.Remove(tmpfile.Name())
testutils.CreateTestDatabase(tmpfile.Name()) testutils.CreateTestDatabase(tmpfile.Name())
@ -42,7 +46,13 @@ func TestTileRender(t *testing.T) {
r := mapblockrenderer.NewMapBlockRenderer(cache, c) r := mapblockrenderer.NewMapBlockRenderer(cache, c)
tr := NewTileRenderer(r) tiletmpfile, err := ioutil.TempFile("", "TestTileRenderTiles.*.sqlite")
defer os.Remove(tiletmpfile.Name())
tdb, _ := tiledb.NewSqliteAccessor(tiletmpfile.Name())
tdb.Migrate()
tr := NewTileRenderer(r, tdb, layerconfig.DefaultLayers)
if tr == nil { if tr == nil {
panic("no renderer") panic("no renderer")
@ -59,4 +69,7 @@ func TestTileRender(t *testing.T) {
if data == nil { if data == nil {
panic("no data") panic("no data")
} }
f, _ := os.Create("../output/0_0_12.png")
bytes.NewReader(data).WriteTo(f)
} }