Skip to content
This repository was archived by the owner on Nov 30, 2023. It is now read-only.

Added 64-bit support #5

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 35 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,41 @@ go get github.com/google/hilbert
Example:

```go
import "github.com/google/hilbert"

// Create a Hilbert curve for mapping to and from a 16 by 16 space.
s, err := hilbert.NewHilbert(16)

// Create a Peano curve for mapping to and from a 27 by 27 space.
//s, err := hilbert.NewPeano(27)

// Now map one dimension numbers in the range [0, N*N-1], to an x,y
// coordinate on the curve where both x and y are in the range [0, N-1].
x, y, err := s.Map(t)

// Also map back from (x,y) to t.
t, err := s.MapInverse(x, y)
package main

import (
"github.com/dsoprea/hilbert"
)

func main() {
// Create a Hilbert curve for mapping to and from a 16 by 16 space.
//s, err := hilbert.NewHilbert64(16)
s, err := hilbert.NewHilbert(16)
if err != nil {
panic(err)
}

// Create a Peano curve for mapping to and from a 27 by 27 space.
//s, err := hilbert.NewPeano64(27)
//s, err := hilbert.NewPeano(27)

t := 112

// Now map one dimension numbers in the range [0, N*N-1], to an x,y
// coordinate on the curve where both x and y are in the range [0, N-1].
x, y, err := s.Map(t)
if err != nil {
panic(err)
}

// (x, y) <= (7, 11)

// Also map back from (x,y) to t.
t, err = s.MapInverse(x, y)
if err != nil {
panic(err)
}
}
```

## Demo
Expand Down
109 changes: 109 additions & 0 deletions hilbert64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package hilbert is for mapping values to and from space-filling curves, such as Hilbert and Peano
// curves.
package hilbert

// Hilbert represents a 2D Hilbert space of order N for mapping to and from.
// Implements SpaceFilling interface.
type Hilbert64 struct {
N uint64
}

// NewHilbert returns a Hilbert space which maps integers to and from the curve.
// n must be a power of two.
func NewHilbert64(n uint64) (*Hilbert64, error) {
if n == 0 {
return nil, ErrNotPositive
}

// Test if power of two
if (n & (n - 1)) != 0 {
return nil, ErrNotPowerOfTwo
}

return &Hilbert64{
N: n,
}, nil
}

// GetDimensions returns the width and height of the 2D space.
func (s *Hilbert64) GetDimensions() (uint64, uint64) {
return s.N, s.N
}

// Map transforms a one dimension value, t, in the range [0, n^2-1] to coordinates on the Hilbert
// curve in the two-dimension space, where x and y are within [0,n-1].
func (s *Hilbert64) Map(t uint64) (x, y uint64, err error) {
if t >= s.N*s.N {
return 0, 0, ErrOutOfRange
}

for i := uint64(1); i < s.N; i = i * 2 {
rx := t&2 == 2
ry := t&1 == 1
if rx {
ry = !ry
}

x, y = s.rotate(i, x, y, rx, ry)

if rx {
x = x + i
}
if ry {
y = y + i
}

t /= 4
}

return
}

// MapInverse transform coordinates on Hilbert curve from (x,y) to t.
func (s *Hilbert64) MapInverse(x, y uint64) (t uint64, err error) {
if x >= s.N || y >= s.N {
return 0, ErrOutOfRange
}

for i := s.N / 2; i > 0; i = i / 2 {
rx := (x & i) > 0
ry := (y & i) > 0

a := uint64(0)
if rx {
a = 3
}
t += i * i * (a ^ uint64(b2i(ry)))

x, y = s.rotate(i, x, y, rx, ry)
}

return
}

// rotate rotates and flips the quadrant appropriately.
func (s *Hilbert64) rotate(n, x, y uint64, rx, ry bool) (uint64, uint64) {
if !ry {
if rx {
x = n - 1 - x
y = n - 1 - y
}

x, y = y, x
}
return x, y
}
Loading