forked from MTSR/mapserver
working tile stitching
This commit is contained in:
parent
abbf16b4bd
commit
acd2e0c8d0
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user