mtsatellite/common/coords.go

135 lines
2.7 KiB
Go

// 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.
package common
import (
"encoding/binary"
"strconv"
)
const (
numBitsPerComponent = 12
modulo = 1 << numBitsPerComponent
maxPositive = modulo / 2
)
type (
KeyTransformer func(int64) int64
KeyEncoder func(int64) ([]byte, error)
KeyDecoder func([]byte) (int64, error)
KeySplitter func(int64) (int16, int16, int16)
KeyJoiner func(int16, int16, int16) int64
)
// Constructs a database key out of byte slice.
func DecodeStringFromBytes(key []byte) (pos int64, err error) {
return strconv.ParseInt(string(key), 10, 64)
}
// Encode a block pos to byte slice.
func EncodeStringToBytes(key int64) ([]byte, error) {
return []byte(strconv.FormatInt(key, 10)), nil
}
func EncodeToBigEndian(key int64) (enc []byte, err error) {
enc = make([]byte, 8)
binary.BigEndian.PutUint64(enc, uint64(key))
return
}
func DecodeFromBigEndian(key []byte) (int64, error) {
return int64(binary.BigEndian.Uint64(key)), nil
}
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)<<(2*numBitsPerComponent) +
int64(y)<<numBitsPerComponent +
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 {
const mask = modulo - 1
if i >= 0 {
return i & mask
}
return modulo - -i&mask
}
// Only to match the C++ code.
func PlainToXYZ(i int64) (x, y, z int16) {
x = unsignedToSigned(pythonModulo(int16(i)))
i = (i - int64(x)) >> numBitsPerComponent
y = unsignedToSigned(pythonModulo(int16(i)))
i = (i - int64(y)) >> numBitsPerComponent
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)
}