mirror of
https://bitbucket.org/s_l_teichmann/mtsatellite
synced 2024-12-24 01:00:18 +01:00
Introduce struct type Coord to reduce tuples passing around.
This commit is contained in:
parent
066675896d
commit
efe6c6abb8
@ -6,6 +6,7 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,13 +17,25 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
Coord struct {
|
||||||
|
X, Y, Z int16
|
||||||
|
}
|
||||||
|
|
||||||
KeyTransformer func(int64) int64
|
KeyTransformer func(int64) int64
|
||||||
KeyEncoder func(int64) ([]byte, error)
|
KeyEncoder func(int64) ([]byte, error)
|
||||||
KeyDecoder func([]byte) (int64, error)
|
KeyDecoder func([]byte) (int64, error)
|
||||||
KeySplitter func(int64) (int16, int16, int16)
|
KeySplitter func(int64) Coord
|
||||||
KeyJoiner func(int16, int16, int16) int64
|
KeyJoiner func(Coord) int64
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c Coord) String() string {
|
||||||
|
return fmt.Sprintf("(%d, %d, %d)", c.X, c.Y, c.Z)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Coord) Equals(o Coord) bool {
|
||||||
|
return c.X == o.X && c.Y == o.Y && c.Z == o.Z
|
||||||
|
}
|
||||||
|
|
||||||
// Constructs a database key out of byte slice.
|
// Constructs a database key out of byte slice.
|
||||||
func DecodeStringFromBytes(key []byte) (pos int64, err error) {
|
func DecodeStringFromBytes(key []byte) (pos int64, err error) {
|
||||||
return strconv.ParseInt(string(key), 10, 64)
|
return strconv.ParseInt(string(key), 10, 64)
|
||||||
@ -43,19 +56,19 @@ func DecodeFromBigEndian(key []byte) (int64, error) {
|
|||||||
return int64(binary.BigEndian.Uint64(key)), nil
|
return int64(binary.BigEndian.Uint64(key)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func XYZToInterleaved(x, y, z int16) (result int64) {
|
func CoordToInterleaved(c Coord) (result int64) {
|
||||||
const end = 1 << (numBitsPerComponent + 1)
|
const end = 1 << (numBitsPerComponent + 1)
|
||||||
setmask := int64(1)
|
setmask := int64(1)
|
||||||
for mask := int16(1); mask != end; mask <<= 1 {
|
for mask := int16(1); mask != end; mask <<= 1 {
|
||||||
if x&mask != 0 {
|
if c.X&mask != 0 {
|
||||||
result |= setmask
|
result |= setmask
|
||||||
}
|
}
|
||||||
setmask <<= 1
|
setmask <<= 1
|
||||||
if y&mask != 0 {
|
if c.Y&mask != 0 {
|
||||||
result |= setmask
|
result |= setmask
|
||||||
}
|
}
|
||||||
setmask <<= 1
|
setmask <<= 1
|
||||||
if z&mask != 0 {
|
if c.Z&mask != 0 {
|
||||||
result |= setmask
|
result |= setmask
|
||||||
}
|
}
|
||||||
setmask <<= 1
|
setmask <<= 1
|
||||||
@ -63,21 +76,22 @@ func XYZToInterleaved(x, y, z int16) (result int64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func InterleavedToXYZ(c int64) (x, y, z int16) {
|
func InterleavedToCoord(pos int64) Coord {
|
||||||
const end = 1 << (numBitsPerComponent + 1)
|
const end = 1 << (numBitsPerComponent + 1)
|
||||||
|
var x, y, z int16
|
||||||
for mask := int16(1); mask != end; mask <<= 1 {
|
for mask := int16(1); mask != end; mask <<= 1 {
|
||||||
if c&1 == 1 {
|
if pos&1 == 1 {
|
||||||
x |= mask
|
x |= mask
|
||||||
}
|
}
|
||||||
c >>= 1
|
pos >>= 1
|
||||||
if c&1 == 1 {
|
if pos&1 == 1 {
|
||||||
y |= mask
|
y |= mask
|
||||||
}
|
}
|
||||||
c >>= 1
|
pos >>= 1
|
||||||
if c&1 == 1 {
|
if pos&1 == 1 {
|
||||||
z |= mask
|
z |= mask
|
||||||
}
|
}
|
||||||
c >>= 1
|
pos >>= 1
|
||||||
}
|
}
|
||||||
if x >= 1<<numBitsPerComponent {
|
if x >= 1<<numBitsPerComponent {
|
||||||
x -= end
|
x -= end
|
||||||
@ -88,13 +102,13 @@ func InterleavedToXYZ(c int64) (x, y, z int16) {
|
|||||||
if z >= 1<<numBitsPerComponent {
|
if z >= 1<<numBitsPerComponent {
|
||||||
z -= end
|
z -= end
|
||||||
}
|
}
|
||||||
return
|
return Coord{X: x, Y: y, Z: z}
|
||||||
}
|
}
|
||||||
|
|
||||||
func XYZToPlain(x, y, z int16) int64 {
|
func CoordToPlain(c Coord) int64 {
|
||||||
return int64(z)<<(2*numBitsPerComponent) +
|
return int64(c.Z)<<(2*numBitsPerComponent) +
|
||||||
int64(y)<<numBitsPerComponent +
|
int64(c.Y)<<numBitsPerComponent +
|
||||||
int64(x)
|
int64(c.X)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unsignedToSigned(i int16) int16 {
|
func unsignedToSigned(i int16) int16 {
|
||||||
@ -113,22 +127,19 @@ func pythonModulo(i int16) int16 {
|
|||||||
return modulo - -i&mask
|
return modulo - -i&mask
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only to match the C++ code.
|
func PlainToCoord(i int64) (c Coord) {
|
||||||
func PlainToXYZ(i int64) (x, y, z int16) {
|
c.X = unsignedToSigned(pythonModulo(int16(i)))
|
||||||
x = unsignedToSigned(pythonModulo(int16(i)))
|
i = (i - int64(c.X)) >> numBitsPerComponent
|
||||||
i = (i - int64(x)) >> numBitsPerComponent
|
c.Y = unsignedToSigned(pythonModulo(int16(i)))
|
||||||
y = unsignedToSigned(pythonModulo(int16(i)))
|
i = (i - int64(c.Y)) >> numBitsPerComponent
|
||||||
i = (i - int64(y)) >> numBitsPerComponent
|
c.Z = unsignedToSigned(pythonModulo(int16(i)))
|
||||||
z = unsignedToSigned(pythonModulo(int16(i)))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformPlainToInterleaved(pos int64) int64 {
|
func TransformPlainToInterleaved(pos int64) int64 {
|
||||||
x, y, z := PlainToXYZ(pos)
|
return CoordToInterleaved(PlainToCoord(pos))
|
||||||
return XYZToInterleaved(x, y, z)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformInterleavedPlain(pos int64) int64 {
|
func TransformInterleavedPlain(pos int64) int64 {
|
||||||
x, y, z := InterleavedToXYZ(pos)
|
return CoordToPlain(InterleavedToCoord(pos))
|
||||||
return XYZToPlain(x, y, z)
|
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,11 @@ var data = []int16{
|
|||||||
-150, -1, 0, 1, 88, 524, 527, 549,
|
-150, -1, 0, 1, 88, 524, 527, 549,
|
||||||
1783, 1817, 1826, 2028, 2032}
|
1783, 1817, 1826, 2028, 2032}
|
||||||
|
|
||||||
func allData(f func(int16, int16, int16)) {
|
func allData(f func(Coord)) {
|
||||||
for _, z := range data {
|
for _, z := range data {
|
||||||
for _, y := range data {
|
for _, y := range data {
|
||||||
for _, x := range data {
|
for _, x := range data {
|
||||||
f(x, y, z)
|
f(Coord{X: x, Y: y, Z: z})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,84 +22,79 @@ func checkEncodeDecode(
|
|||||||
desc string,
|
desc string,
|
||||||
join KeyJoiner,
|
join KeyJoiner,
|
||||||
encode KeyEncoder, decode KeyDecoder,
|
encode KeyEncoder, decode KeyDecoder,
|
||||||
x, y, z int16, t *testing.T) {
|
c Coord, t *testing.T) {
|
||||||
|
|
||||||
k1 := join(x, y, z)
|
k1 := join(c)
|
||||||
var err error
|
var err error
|
||||||
var b []byte
|
var b []byte
|
||||||
if b, err = encode(k1); err != nil {
|
if b, err = encode(k1); err != nil {
|
||||||
t.Errorf("%s: Failed to encode (%d, %d, %d) %s\n",
|
t.Errorf("%s: Failed to encode %s %s\n", desc, c, err)
|
||||||
desc, x, y, z, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var k2 int64
|
var k2 int64
|
||||||
if k2, err = decode(b); err != nil {
|
if k2, err = decode(b); err != nil {
|
||||||
t.Errorf("%s: Failed to decode (%d, %d, %d) %s\n",
|
t.Errorf("%s: Failed to decode %s %s\n", desc, c, err)
|
||||||
desc, x, y, z, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if k1 != k2 {
|
if k1 != k2 {
|
||||||
t.Errorf("%s: Expected %d got %d for (%d, %d, %d) %b\n",
|
t.Errorf("%s: Expected %d got %d for %s\n", desc, k1, k2, c)
|
||||||
desc, k1, k2, x, y, z)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncodeDecode(t *testing.T) {
|
func TestEncodeDecode(t *testing.T) {
|
||||||
allData(func(x, y, z int16) {
|
allData(func(c Coord) {
|
||||||
checkEncodeDecode(
|
checkEncodeDecode(
|
||||||
"Big endian",
|
"Big endian",
|
||||||
XYZToInterleaved,
|
CoordToInterleaved,
|
||||||
EncodeToBigEndian, DecodeFromBigEndian,
|
EncodeToBigEndian, DecodeFromBigEndian,
|
||||||
x, y, z, t)
|
c, t)
|
||||||
})
|
})
|
||||||
allData(func(x, y, z int16) {
|
allData(func(c Coord) {
|
||||||
checkEncodeDecode(
|
checkEncodeDecode(
|
||||||
"String",
|
"String",
|
||||||
XYZToInterleaved,
|
CoordToInterleaved,
|
||||||
EncodeStringToBytes, DecodeStringFromBytes,
|
EncodeStringToBytes, DecodeStringFromBytes,
|
||||||
x, y, z, t)
|
c, t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkJoinSplit(
|
func checkJoinSplit(
|
||||||
desc string,
|
desc string,
|
||||||
join KeyJoiner, split KeySplitter,
|
join KeyJoiner, split KeySplitter,
|
||||||
x1, y1, z1 int16, t *testing.T) {
|
c Coord, t *testing.T) {
|
||||||
|
|
||||||
k1 := join(x1, y1, z1)
|
k := join(c)
|
||||||
x2, y2, z2 := split(k1)
|
s := split(k)
|
||||||
if x1 != x2 || y1 != y2 || z1 != z2 {
|
if !s.Equals(c) {
|
||||||
t.Errorf("%s: Expected (%d, %d, %d) got (%d, %d, %d) %b\n",
|
t.Errorf("%s: Expected %s got %s %b\n", desc, c, s, k)
|
||||||
desc, x1, y1, z1, x2, y2, z2, k1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJoinSplit(t *testing.T) {
|
func TestJoinSplit(t *testing.T) {
|
||||||
allData(func(x, y, z int16) {
|
allData(func(c Coord) {
|
||||||
checkJoinSplit(
|
checkJoinSplit(
|
||||||
"P2XYZ(XYZ2P(xyz))",
|
"P2C(C2P(xyz))",
|
||||||
XYZToPlain, PlainToXYZ,
|
CoordToPlain, PlainToCoord,
|
||||||
x, y, z, t)
|
c, t)
|
||||||
})
|
})
|
||||||
allData(func(x, y, z int16) {
|
allData(func(c Coord) {
|
||||||
checkJoinSplit(
|
checkJoinSplit(
|
||||||
"I2XYZ(XYZ2I(xyz))",
|
"I2C(C2I(xyz))",
|
||||||
XYZToInterleaved, InterleavedToXYZ,
|
CoordToInterleaved, InterleavedToCoord,
|
||||||
x, y, z, t)
|
c, t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkTransformer(
|
func checkTransformer(
|
||||||
desc string, joiner KeyJoiner,
|
desc string, joiner KeyJoiner,
|
||||||
transform KeyTransformer,
|
transform KeyTransformer,
|
||||||
x, y, z int16, t *testing.T) {
|
c Coord, t *testing.T) {
|
||||||
|
|
||||||
k1 := joiner(x, y, z)
|
k1 := joiner(c)
|
||||||
k2 := transform(k1)
|
k2 := transform(k1)
|
||||||
if k2 != k1 {
|
if k2 != k1 {
|
||||||
t.Errorf("%s: Expected %v got %v for (%d, %d, %d)\n",
|
t.Errorf("%s: Expected %v got %v for %s\n", desc, k1, k2, c)
|
||||||
desc, k1, k2, x, y, z)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,25 +109,25 @@ func compose(transforms ...KeyTransformer) KeyTransformer {
|
|||||||
|
|
||||||
func TestTransforms(t *testing.T) {
|
func TestTransforms(t *testing.T) {
|
||||||
// Mainly to check the test itself.
|
// Mainly to check the test itself.
|
||||||
allData(func(x, y, z int16) {
|
allData(func(c Coord) {
|
||||||
checkTransformer(
|
checkTransformer(
|
||||||
"plain",
|
"plain",
|
||||||
XYZToPlain,
|
CoordToPlain,
|
||||||
compose(),
|
compose(),
|
||||||
x, y, z, t)
|
c, t)
|
||||||
})
|
})
|
||||||
allData(func(x, y, z int16) {
|
allData(func(c Coord) {
|
||||||
checkTransformer(
|
checkTransformer(
|
||||||
"I2P(P2I(plain))",
|
"I2P(P2I(plain))",
|
||||||
XYZToPlain,
|
CoordToPlain,
|
||||||
compose(TransformPlainToInterleaved, TransformInterleavedPlain),
|
compose(TransformPlainToInterleaved, TransformInterleavedPlain),
|
||||||
x, y, z, t)
|
c, t)
|
||||||
})
|
})
|
||||||
allData(func(x, y, z int16) {
|
allData(func(c Coord) {
|
||||||
checkTransformer(
|
checkTransformer(
|
||||||
"P2I(I2P(interleaved))",
|
"P2I(I2P(interleaved))",
|
||||||
XYZToInterleaved,
|
CoordToInterleaved,
|
||||||
compose(TransformInterleavedPlain, TransformPlainToInterleaved),
|
compose(TransformInterleavedPlain, TransformPlainToInterleaved),
|
||||||
x, y, z, t)
|
c, t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user