Simplified area coverage calculation a great deal.

This commit is contained in:
Sascha L. Teichmann 2017-02-26 17:01:15 +01:00
parent 4b92a6c722
commit ca634f28ef
2 changed files with 76 additions and 78 deletions

View File

@ -4,7 +4,9 @@
package common package common
import "math" import (
"math"
)
type Area struct { type Area struct {
X1, Z1 int16 X1, Z1 int16
@ -28,79 +30,73 @@ func areasContain(areas []Area, x, z int16) bool {
return false return false
} }
// UncoveredAreas implements a greedy algorithm to figure out // recalculate implements a greedy algorithm to figure out
// a list of disjunct areas of free regions in the domain // a list of disjunct areas of free regions in the domain
// to the (x, z) block plane. // to the (x, z) block plane.
// oldAreas are searched and found free areas are appended // oldAreas are searched and found free areas are appended
// to newAreas which ist return. // to newAreas which ist return.
// This is useful to spatial query only blocks from db // This is useful to spatial query only blocks from db
// that are not below already rendered blocks. // that are not below already rendered blocks.
func UncoveredAreas(r *Renderer, newAreas, oldAreas []Area) []Area { func (area Area) recalculate(r *Renderer, nareas []Area) []Area {
yM := r.yMin yM := r.yMin
// Scan old areas. const ex = 1
for _, oldArea := range oldAreas { const ez = 2
for z := oldArea.Z1; z <= oldArea.Z2; z++ {
nas := len(nareas)
for z := area.Z1; z <= area.Z2; z++ {
row := z * int16(r.width) row := z * int16(r.width)
for x := oldArea.X1; x <= oldArea.X2; x++ { for x := area.X1; x <= area.X2; x++ {
// Uncovered and not in list of new areas? // Uncovered and not in list of new areas?
if yM[row+x] > math.MinInt32 || areasContain(newAreas, x, z) { if yM[row+x] > math.MinInt32 || areasContain(nareas[nas:], x, z) {
continue continue
} }
area := Area{X1: x, Z1: z, X2: x, Z2: z} a := 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. // Try to extend the area in x and/or z till no further extension is possible.
for extendDirs := 1 | 2; extendDirs != 0; { ext:
var xFirst bool for extend := ex | ez; extend != 0; {
// Try to extend in the direction with most gain // If we extending in both directions a the current area
// of blocks. // is higher than wide we gain more block if extend
if area.higher() { // Higher means to win more blocks in x direction. // in the x direction first.
xFirst = true if (extend == ex|ez && a.higher()) || extend&ex == ex { // check x
} nx := a.X2 + 1
dirs: if nx > area.X2 { // reached border of area
for i := 0; i < 2; i++ { extend &= ^ex
if xFirst {
// Extension in x possible?
if extendDirs&1 == 1 {
nx := area.X2 + 1
if nx > oldArea.X2 {
extendDirs &= ^1
continue continue
} }
// Scan line below current area if its fully free. // Check column right of the current area if its fully free.
for nz := area.Z1; nz <= area.Z2; nz++ { for nz := a.Z1; nz <= a.Z2; nz++ {
if yM[nz*int16(r.width)+nx] > math.MinInt32 || areasContain(newAreas, nx, nz) { if yM[nz*int16(r.width)+nx] > math.MinInt32 ||
extendDirs &= ^1 areasContain(nareas[nas:], nx, nz) {
continue dirs extend &= ^ex
continue ext
} }
} }
// free -> extend // free -> extend
area.X2 = nx a.X2 = nx
} } else if extend&ez == ez { // check z
} else if extendDirs&2 == 2 { nz := a.Z2 + 1
// Symmetric case in z direction if nz > area.Z2 {
nz := area.Z2 + 1 extend &= ^ez
if nz > oldArea.Z2 {
extendDirs &= ^2
continue continue
} }
// Scan line right beside the area if its free. // Check line right below the current area if its free.
row2 := nz * int16(r.width) row2 := nz * int16(r.width)
for nx := area.X1; nx <= area.X2; nx++ { for nx := a.X1; nx <= a.X2; nx++ {
if yM[row2+nx] > math.MinInt32 || areasContain(newAreas, nx, nz) { if yM[row2+nx] > math.MinInt32 ||
extendDirs &= ^2 areasContain(nareas[nas:], nx, nz) {
continue dirs extend &= ^ez
continue ext
} }
} }
area.Z2 = nz // free -> extend
} a.Z2 = nz
// Switch to other search direction (x -> z or z -> x)
xFirst = !xFirst
} }
} }
// At this point the area is extended to max. // At this point the area is extended to max.
newAreas = append(newAreas, area) nareas = append(nareas, a)
} }
} }
} return nareas
return newAreas
} }

View File

@ -103,10 +103,10 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) (bool, error) {
var c1, c2 Coord var c1, c2 Coord
oareas := make([]Area, 0, tileWidth*tileHeight/2) nareas := make([]Area, 0, tileWidth*tileHeight/2)
nareas := make([]Area, 1, tileWidth*tileHeight/2) areas := make([]Area, 1, tileWidth*tileHeight/2)
nareas[0] = Area{ areas[0] = Area{
X1: 0, Z1: 0, X1: 0, Z1: 0,
X2: int16(tileWidth) - 1, Z2: int16(tileHeight) - 1} X2: int16(tileWidth) - 1, Z2: int16(tileHeight) - 1}
@ -118,9 +118,7 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) (bool, error) {
c1.Y = max16(yRange[0], btc.yMin) c1.Y = max16(yRange[0], btc.yMin)
c2.Y = min16(yRange[1], btc.yMax) c2.Y = min16(yRange[1], btc.yMax)
var allCount int for _, area := range areas {
for _, area := range nareas {
c1.X = area.X1 + x c1.X = area.X1 + x
c1.Z = area.Z1 + z c1.Z = area.Z1 + z
c2.X = area.X2 + x c2.X = area.X2 + x
@ -131,18 +129,22 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) (bool, error) {
if count, err = btc.client.QueryCuboid(query, btc.drawBlock); err != nil { if count, err = btc.client.QueryCuboid(query, btc.drawBlock); err != nil {
return false, err return false, err
} }
allCount += count
if err = btc.yOrder.Drain(btc.colors); err != nil { if err = btc.yOrder.Drain(btc.colors); err != nil {
log.Printf("WARN: rendering block failed: %s\n", err) log.Printf("WARN: rendering block failed: %s\n", err)
} }
// If there where loaded blocks in this area recalculate coverage.
if count > 0 {
nareas = area.recalculate(btc.renderer, nareas)
} else {
nareas = append(nareas, area)
} }
if allCount > 0 { }
xareas := UncoveredAreas(btc.renderer, oareas, nareas)
if len(xareas) == 0 { if len(nareas) == 0 {
break break
} }
nareas, oareas = xareas, nareas[:0] areas, nareas = nareas, areas[:0]
}
} }
path := filepath.Join(btc.baseDir, strconv.Itoa(i), strconv.Itoa(j)+".png") path := filepath.Join(btc.baseDir, strconv.Itoa(i), strconv.Itoa(j)+".png")