diff --git a/common/coords.go b/common/coords.go index 408bc25..881c217 100644 --- a/common/coords.go +++ b/common/coords.go @@ -232,7 +232,7 @@ func NaiveBigMin(minz, maxz, zcode int64) int64 { var ( c1 = InterleavedToCoord(minz) c2 = InterleavedToCoord(maxz) - cand = minz + cand = maxz c Coord ) @@ -248,3 +248,56 @@ func NaiveBigMin(minz, maxz, zcode int64) int64 { return cand } + +const ( + bits = 12 + msb = uint(3*bits - 1) + _000_ = 0 + _001_ = 1 + _010_ = 2 + _011_ = 2 | 1 + _100_ = 4 + _101_ = 4 | 1 + mask = int64(0x924924924924924) + full = int64(0xfffffffffffffff) +) + +func setbits(p uint, v int64) int64 { + m := (mask >> (msb - p)) & (^(full << p) & full) + return (v | m) & ^(1 << p) & full +} + +func unsetbits(p uint, v int64) int64 { + m := ^(mask >> (msb - p)) & full + return (v & m) | (int64(1) << p) +} + +func BigMin(minz, maxz, zcode int64) int64 { + bigmin := maxz + pos := msb + for m := int64(1) << msb; m != 0; m >>= 1 { + var v uint16 + if zcode&m != 0 { + v = _100_ + } + if minz&m != 0 { + v |= _010_ + } + if maxz&m != 0 { + v |= _001_ + } + switch v { + case _001_: + bigmin = unsetbits(pos, minz) + maxz = setbits(pos, maxz) + case _011_: + return minz + case _100_: + return bigmin + case _101_: + minz = unsetbits(pos, minz) + } + pos-- + } + return bigmin +} diff --git a/common/coords_test.go b/common/coords_test.go index 05dd93f..4d3c7d4 100644 --- a/common/coords_test.go +++ b/common/coords_test.go @@ -4,7 +4,11 @@ package common -import "testing" +import ( + "fmt" + "math/rand" + "testing" +) var data = []int16{ -2045, -1850, -1811, -1629, -1104, @@ -138,14 +142,58 @@ func TestTransforms(t *testing.T) { checkTransformer( "I2P(P2I(plain))", CoordToPlain, - compose(TransformPlainToInterleaved, TransformInterleavedPlain), + compose(TransformPlainToInterleaved, TransformInterleavedToPlain), c, t) }) allData(func(c Coord) { checkTransformer( "P2I(I2P(interleaved))", CoordToInterleaved, - compose(TransformInterleavedPlain, TransformPlainToInterleaved), + compose(TransformInterleavedToPlain, TransformPlainToInterleaved), c, t) }) } + +func TestBigMin(t *testing.T) { + const tries = 1 + errors, success := 0, 0 + for i := 0; i < tries; i++ { + x1 := rand.Intn(4000) - 2000 + y1 := rand.Intn(4000) - 2000 + z1 := rand.Intn(4000) - 2000 + w := rand.Intn(20) + 1 + h := rand.Intn(20) + 1 + d := rand.Intn(20) + 1 + x2 := x1 + w + y2 := y1 + h + z2 := z1 + d + + c1 := Coord{X: int16(x1), Y: int16(y1), Z: int16(z1)} + c2 := Coord{X: int16(x2), Y: int16(y2), Z: int16(z2)} + cub := Cuboid{P1: c1, P2: c2} + fmt.Printf("Cuboid: %s\n", cub) + + zmin := CoordToInterleaved(c1) + zmax := CoordToInterleaved(c2) + + for zcode := zmin + 1; zcode < zmax; zcode++ { + c3 := InterleavedToCoord(zcode) + if cub.Contains(c3) { + continue + } + nbm := NaiveBigMin(zmin, zmax, zcode) + cbm := BigMin(zmin, zmax, zcode) + //fmt.Printf("cbm: %d\n", cbm) + //fmt.Printf("nbm: %d\n", nbm) + if nbm != cbm { + errors++ + } else { + success++ + } + } + } + if errors > 0 { + t.Errorf("BigMin: %d errors out of %d (%f)\n", + errors, errors+success, float64(errors)/float64(errors+success)) + } +}