2014-08-04 17:10:19 +02:00
|
|
|
// Copyright 2014 by Sascha L. Teichmann
|
|
|
|
// Use of this source code is governed by the MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
2014-08-16 16:06:42 +02:00
|
|
|
package common
|
2014-08-04 17:10:19 +02:00
|
|
|
|
2014-08-16 17:41:54 +02:00
|
|
|
import (
|
2014-08-18 16:29:17 +02:00
|
|
|
"encoding/binary"
|
2014-08-16 17:41:54 +02:00
|
|
|
"strconv"
|
|
|
|
)
|
2014-08-04 17:10:19 +02:00
|
|
|
|
2014-08-18 18:01:34 +02:00
|
|
|
const (
|
|
|
|
numBitsPerComponent = 12
|
|
|
|
maxPositive = 2048
|
|
|
|
modulo = 4096
|
|
|
|
)
|
|
|
|
|
2014-08-18 16:29:17 +02:00
|
|
|
type (
|
|
|
|
KeyTransformer func(int64) int64
|
2014-08-18 18:01:34 +02:00
|
|
|
KeyEncoder func(int64) ([]byte, error)
|
|
|
|
KeyDecoder func([]byte) (int64, error)
|
2014-08-18 16:29:17 +02:00
|
|
|
KeySplitter func(int64) (int16, int16, int16)
|
|
|
|
KeyJoiner func(int16, int16, int16) int64
|
|
|
|
)
|
|
|
|
|
2014-08-04 17:10:19 +02:00
|
|
|
// Constructs a database key out of byte slice.
|
2014-08-18 18:01:34 +02:00
|
|
|
func DecodeStringFromBytes(key []byte) (pos int64, err error) {
|
2014-08-04 17:10:19 +02:00
|
|
|
return strconv.ParseInt(string(key), 10, 64)
|
|
|
|
}
|
2014-08-16 17:41:54 +02:00
|
|
|
|
|
|
|
// Encode a block pos to byte slice.
|
2014-08-18 18:01:34 +02:00
|
|
|
func EncodeStringToBytes(key int64) ([]byte, error) {
|
|
|
|
return []byte(strconv.FormatInt(key, 10)), nil
|
2014-08-16 17:41:54 +02:00
|
|
|
}
|
2014-08-18 16:29:17 +02:00
|
|
|
|
2014-08-18 18:01:34 +02:00
|
|
|
func EncodeToBigEndian(key int64) (enc []byte, err error) {
|
2014-08-18 16:29:17 +02:00
|
|
|
enc = make([]byte, 8)
|
|
|
|
binary.BigEndian.PutUint64(enc, uint64(key))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:01:34 +02:00
|
|
|
func DecodeFromBigEndian(key []byte) (int64, error) {
|
|
|
|
return int64(binary.BigEndian.Uint64(key)), nil
|
2014-08-18 16:29:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func XYZToInterleaved(x, y, z int16) (result int64) {
|
|
|
|
const end = 1 << (numBitsPerComponent + 1)
|
|
|
|
setmask := int64(1)
|
|
|
|
for mask := int16(1); mask != end; mask <<= 1 {
|
|
|
|
if x&mask != 0 {
|
|
|
|
result |= setmask
|
|
|
|
}
|
|
|
|
setmask <<= 1
|
|
|
|
if y&mask != 0 {
|
|
|
|
result |= setmask
|
|
|
|
}
|
|
|
|
setmask <<= 1
|
|
|
|
if z&mask != 0 {
|
|
|
|
result |= setmask
|
|
|
|
}
|
|
|
|
setmask <<= 1
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func InterleavedToXYZ(c int64) (x, y, z int16) {
|
|
|
|
const end = 1 << (numBitsPerComponent + 1)
|
|
|
|
for mask := int16(1); mask != end; mask <<= 1 {
|
|
|
|
if c&1 == 1 {
|
|
|
|
x |= mask
|
|
|
|
}
|
|
|
|
c >>= 1
|
|
|
|
if c&1 == 1 {
|
|
|
|
y |= mask
|
|
|
|
}
|
|
|
|
c >>= 1
|
|
|
|
if c&1 == 1 {
|
|
|
|
z |= mask
|
|
|
|
}
|
|
|
|
c >>= 1
|
|
|
|
}
|
|
|
|
if x >= 1<<numBitsPerComponent {
|
|
|
|
x -= end
|
|
|
|
}
|
|
|
|
if y >= 1<<numBitsPerComponent {
|
|
|
|
y -= end
|
|
|
|
}
|
|
|
|
if z >= 1<<numBitsPerComponent {
|
|
|
|
z -= end
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func XYZToPlain(x, y, z int16) int64 {
|
|
|
|
return int64(z)<<24 + int64(y)<<12 + int64(x)
|
|
|
|
}
|
|
|
|
|
|
|
|
func unsignedToSigned(i int16) int16 {
|
|
|
|
if i < maxPositive {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
return i - maxPositive*2
|
|
|
|
}
|
|
|
|
|
|
|
|
// To match C++ code.
|
|
|
|
func pythonModulo(i int16) int16 {
|
|
|
|
if i >= 0 {
|
|
|
|
return i % modulo
|
|
|
|
}
|
|
|
|
return modulo - (-i)%modulo
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only to match the C++ code.
|
|
|
|
func PlainToXYZ(i int64) (x, y, z int16) {
|
|
|
|
x = unsignedToSigned(pythonModulo(int16(i)))
|
|
|
|
i = (i - int64(x)) / modulo
|
|
|
|
y = unsignedToSigned(pythonModulo(int16(i)))
|
|
|
|
i = (i - int64(y)) / modulo
|
|
|
|
z = unsignedToSigned(pythonModulo(int16(i)))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func TransformPlainToInterleaved(pos int64) int64 {
|
|
|
|
x, y, z := PlainToXYZ(pos)
|
|
|
|
return XYZToInterleaved(x, y, z)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TransformInterleavedPlain(pos int64) int64 {
|
|
|
|
x, y, z := InterleavedToXYZ(pos)
|
|
|
|
return XYZToPlain(x, y, z)
|
|
|
|
}
|