From 003ce5035a420ecca2b55d4c11ac971e90ca3dda Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Sun, 26 Feb 2017 13:13:19 +0100 Subject: [PATCH] Moved area coverage stuff out of renderer. It is an optimization to load only needed blocks from db and has nothing to do with rendering. --- common/area.go | 106 ++++++++++++++++++++++++++++++++++++++ common/basetilecreator.go | 2 +- common/renderer.go | 99 ----------------------------------- 3 files changed, 107 insertions(+), 100 deletions(-) create mode 100644 common/area.go diff --git a/common/area.go b/common/area.go new file mode 100644 index 0000000..2d80d35 --- /dev/null +++ b/common/area.go @@ -0,0 +1,106 @@ +// Copyright 2014, 2015, 2017 by Sascha L. Teichmann +// Use of this source code is governed by the MIT license +// that can be found in the LICENSE file. + +package common + +import "math" + +type Area struct { + X1, Z1 int16 + X2, Z2 int16 +} + +func (a Area) contains(x, z int16) bool { + return x >= a.X1 && x <= a.X2 && z >= a.Z1 && z <= a.Z2 +} + +func (a Area) higher() bool { + return a.Z2-a.Z1 > a.X2-a.X1 +} + +func areasContain(areas []Area, x, z int16) bool { + for _, r := range areas { + if r.contains(x, z) { + return true + } + } + return false +} + +// UncoveredAreas implements a greedy algorithm to figure out +// a list of disjunct areas of free regions in the domain +// to the (x, z) block plane. +// oldAreas are searched and found free areas are appended +// to newAreas which ist return. +// This is useful to spatial query only blocks from db +// that are not below already rendered blocks. +func UncoveredAreas(r *Renderer, newAreas, oldAreas []Area) []Area { + yM := r.yMin + + // Scan old areas. + for _, oldArea := range oldAreas { + for z := oldArea.Z1; z <= oldArea.Z2; z++ { + row := z * int16(r.width) + for x := oldArea.X1; x <= oldArea.X2; x++ { + // Uncovered and not in list of new areas? + if yM[row+x] > math.MinInt32 || areasContain(newAreas, x, z) { + continue + } + area := Area{X1: x, Z1: z, X2: x, Z2: z} + // Try to extend the area in x and/or z till no further extension is possible. + for extendDirs := 1 | 2; extendDirs != 0; { + var xFirst bool + // Try to extend in the direction with most gain + // of blocks. + if area.higher() { // Higher means to win more blocks in x direction. + xFirst = true + } + dirs: + for i := 0; i < 2; i++ { + if xFirst { + // Extension in x possible? + if extendDirs&1 == 1 { + nx := area.X2 + 1 + if nx >= int16(r.width) { + extendDirs &= ^1 + continue + } + // Scan line below current area if its fully free. + for nz := area.Z1; nz <= area.Z2; nz++ { + if yM[nz*int16(r.width)+nx] > math.MinInt32 || areasContain(newAreas, nx, nz) { + extendDirs &= ^1 + continue dirs + } + } + // free -> extend + area.X2 = nx + } + } else if extendDirs&2 == 2 { + // Symmetric case in z direction + nz := area.Z2 + 1 + if nz >= int16(r.height) { + extendDirs &= ^2 + continue + } + // Scan line right beside the area if its free. + row2 := nz * int16(r.width) + for nx := area.X1; nx <= area.X2; nx++ { + if yM[row2+nx] > math.MinInt32 || areasContain(newAreas, nx, nz) { + extendDirs &= ^2 + continue dirs + } + } + area.Z2 = nz + } + // Switch to other search direction (x -> z or z -> x) + xFirst = !xFirst + } + } + // At this point the area is extended to max. + newAreas = append(newAreas, area) + } + } + } + return newAreas +} diff --git a/common/basetilecreator.go b/common/basetilecreator.go index 7a8a39b..12b8b2e 100644 --- a/common/basetilecreator.go +++ b/common/basetilecreator.go @@ -137,7 +137,7 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) (bool, error) { } } if allCount > 0 { - xareas := btc.renderer.UncoveredAreas(oareas, nareas) + xareas := UncoveredAreas(btc.renderer, oareas, nareas) if len(xareas) == 0 { break } diff --git a/common/renderer.go b/common/renderer.go index a08865d..fa13e80 100644 --- a/common/renderer.go +++ b/common/renderer.go @@ -12,11 +12,6 @@ import ( "math" ) -type Area struct { - X1, Z1 int16 - X2, Z2 int16 -} - type Renderer struct { width int height int @@ -286,100 +281,6 @@ func (r *Renderer) RenderBlock(block *Block, colors *Colors) (err error) { return } -func (a Area) contains(x, z int16) bool { - return x >= a.X1 && x <= a.X2 && z >= a.Z1 && z <= a.Z2 -} - -func (a Area) higher() bool { - return a.Z2-a.Z1 > a.X2-a.X1 -} - -func areasContain(areas []Area, x, z int16) bool { - for _, r := range areas { - if r.contains(x, z) { - return true - } - } - return false -} - -// UncoveredAreas implements a greedy algorithm to figure out -// a list of disjunct areas of free regions in the domain -// to the (x, z) block plane. -// oldAreas are searched and found free areas are appended -// to newAreas which ist return. -// This is useful to spatial query only blocks from db -// that are not below already rendered blocks. -func (r *Renderer) UncoveredAreas(newAreas, oldAreas []Area) []Area { - yM := r.yMin - - // Scan old areas. - for _, oldArea := range oldAreas { - for z := oldArea.Z1; z <= oldArea.Z2; z++ { - row := z * int16(r.width) - for x := oldArea.X1; x <= oldArea.X2; x++ { - // Uncovered and not in list of new areas? - if yM[row+x] > math.MinInt32 || areasContain(newAreas, x, z) { - continue - } - area := Area{X1: x, Z1: z, X2: x, Z2: z} - // Try to extend the area in x and/or z till no further extension is possible. - for extendDirs := 1 | 2; extendDirs != 0; { - var xFirst bool - // Try to extend in the direction with most gain - // of blocks. - if area.higher() { // Higher means to win more blocks in x direction. - xFirst = true - } - dirs: - for i := 0; i < 2; i++ { - if xFirst { - // Extension in x possible? - if extendDirs&1 == 1 { - nx := area.X2 + 1 - if nx >= int16(r.width) { - extendDirs &= ^1 - continue - } - // Scan line below current area if its fully free. - for nz := area.Z1; nz <= area.Z2; nz++ { - if yM[nz*int16(r.width)+nx] > math.MinInt32 || areasContain(newAreas, nx, nz) { - extendDirs &= ^1 - continue dirs - } - } - // free -> extend - area.X2 = nx - } - } else if extendDirs&2 == 2 { - // Symmetric case in z direction - nz := area.Z2 + 1 - if nz >= int16(r.height) { - extendDirs &= ^2 - continue - } - // Scan line right beside the area if its free. - row2 := nz * int16(r.width) - for nx := area.X1; nx <= area.X2; nx++ { - if yM[row2+nx] > math.MinInt32 || areasContain(newAreas, nx, nz) { - extendDirs &= ^2 - continue dirs - } - } - area.Z2 = nz - } - // Switch to other search direction (x -> z or z -> x) - xFirst = !xFirst - } - } - // At this point the area is extended to max. - newAreas = append(newAreas, area) - } - } - } - return newAreas -} - func (r *Renderer) CreateImage(colors []color.RGBA, background color.RGBA) *image.RGBA { pw, ph := r.width<<4, r.height<<4 image := image.NewRGBA(image.Rect(0, 0, pw, ph))