mirror of
https://bitbucket.org/s_l_teichmann/mtsatellite
synced 2024-11-17 23:58:17 +01:00
Added more functions for treating coordinates.
This commit is contained in:
parent
da5c70b55b
commit
a210207f8e
112
common/coords.go
112
common/coords.go
@ -5,9 +5,18 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
KeyTransformer func(int64) int64
|
||||||
|
KeyEncoder func(int64) []byte
|
||||||
|
KeyDecoder func([]byte) int64
|
||||||
|
KeySplitter func(int64) (int16, int16, int16)
|
||||||
|
KeyJoiner func(int16, int16, int16) int64
|
||||||
|
)
|
||||||
|
|
||||||
// Constructs a database key out of byte slice.
|
// Constructs a database key out of byte slice.
|
||||||
func DecodePosFromBytes(key []byte) (pos int64, err error) {
|
func DecodePosFromBytes(key []byte) (pos int64, err error) {
|
||||||
return strconv.ParseInt(string(key), 10, 64)
|
return strconv.ParseInt(string(key), 10, 64)
|
||||||
@ -17,3 +26,106 @@ func DecodePosFromBytes(key []byte) (pos int64, err error) {
|
|||||||
func EncodePosToBytes(key int64) []byte {
|
func EncodePosToBytes(key int64) []byte {
|
||||||
return []byte(strconv.FormatInt(key, 10))
|
return []byte(strconv.FormatInt(key, 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EncodeAsBigEndian(key int64) (enc []byte) {
|
||||||
|
enc = make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(enc, uint64(key))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeFromBigEndian(key []byte) int64 {
|
||||||
|
return int64(binary.BigEndian.Uint64(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
numBitsPerComponent = 12
|
||||||
|
maxPositive = 2048
|
||||||
|
modulo = 4096
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
95
common/coords_test.go
Normal file
95
common/coords_test.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
//var data = []int16{-2}
|
||||||
|
var data = []int16{
|
||||||
|
-2045, -1850, -1811, -1629, -1104,
|
||||||
|
-967, -725, -646, -329, -212,
|
||||||
|
-150, 88, 524, 527, 549,
|
||||||
|
1783, 1817, 1826, 2028, 2032}
|
||||||
|
|
||||||
|
func allData(f func(int16, int16, int16)) {
|
||||||
|
for _, z := range data {
|
||||||
|
for _, y := range data {
|
||||||
|
for _, x := range data {
|
||||||
|
f(x, y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkJoinSplit(
|
||||||
|
desc string,
|
||||||
|
join KeyJoiner, split KeySplitter,
|
||||||
|
x1, y1, z1 int16, t *testing.T) {
|
||||||
|
|
||||||
|
k1 := join(x1, y1, z1)
|
||||||
|
x2, y2, z2 := split(k1)
|
||||||
|
if x1 != x2 || y1 != y2 || z1 != z2 {
|
||||||
|
t.Errorf("%s: Expected (%d, %d, %d) got (%d, %d, %d) %b\n",
|
||||||
|
desc, x1, y1, z1, x2, y2, z2, k1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJoinSplit(t *testing.T) {
|
||||||
|
allData(func(x, y, z int16) {
|
||||||
|
checkJoinSplit(
|
||||||
|
"P2XYZ(XYZ2P(xyz))",
|
||||||
|
XYZToPlain, PlainToXYZ,
|
||||||
|
x, y, z, t)
|
||||||
|
})
|
||||||
|
allData(func(x, y, z int16) {
|
||||||
|
checkJoinSplit(
|
||||||
|
"I2XYZ(XYZ2I(xyz))",
|
||||||
|
XYZToInterleaved, InterleavedToXYZ,
|
||||||
|
x, y, z, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkTransformer(
|
||||||
|
desc string, joiner KeyJoiner,
|
||||||
|
transform KeyTransformer,
|
||||||
|
x, y, z int16, t *testing.T) {
|
||||||
|
|
||||||
|
k1 := joiner(x, y, z)
|
||||||
|
k2 := transform(k1)
|
||||||
|
if k2 != k1 {
|
||||||
|
t.Errorf("%s: Expected %v got %v for (%d, %d, %d)\n",
|
||||||
|
desc, k1, k2, x, y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compose(transforms ...KeyTransformer) KeyTransformer {
|
||||||
|
return func(x int64) int64 {
|
||||||
|
for _, transform := range transforms {
|
||||||
|
x = transform(x)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTransforms(t *testing.T) {
|
||||||
|
// Mainly to check the test itself.
|
||||||
|
allData(func(x, y, z int16) {
|
||||||
|
checkTransformer(
|
||||||
|
"plain",
|
||||||
|
XYZToPlain,
|
||||||
|
compose(),
|
||||||
|
x, y, z, t)
|
||||||
|
})
|
||||||
|
allData(func(x, y, z int16) {
|
||||||
|
checkTransformer(
|
||||||
|
"I2P(P2I(plain))",
|
||||||
|
XYZToPlain,
|
||||||
|
compose(TransformPlainToInterleaved, TransformInterleavedPlain),
|
||||||
|
x, y, z, t)
|
||||||
|
})
|
||||||
|
allData(func(x, y, z int16) {
|
||||||
|
checkTransformer(
|
||||||
|
"P2I(I2P(interleaved))",
|
||||||
|
XYZToInterleaved,
|
||||||
|
compose(TransformInterleavedPlain, TransformPlainToInterleaved),
|
||||||
|
x, y, z, t)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user