Skip to content

Commit

Permalink
Merge pull request #8 from abetusk/master
Browse files Browse the repository at this point in the history
`d2xy[z]`, `xy[z]2d` functions, reference implementations in JS & C, demo JS application
  • Loading branch information
jakubcerveny authored Feb 12, 2024
2 parents 4f9b20e + d00de22 commit 744cf0a
Show file tree
Hide file tree
Showing 18 changed files with 14,460 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

# ignore binary
gilbert
*~
*.swp

.*

62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ by Lutz Tautenhahn in 2003:
> [1] Lutz Tautenhahn: Draw a Space-Filling Curve of Arbitrary Size, http://lutanho.net/pic2html/draw_sfc.html, 2003.
However, this algorithm is complex and would be very difficult to generalize to
3D. Another aproach that focuses on evaluation speed is described in
3D. Another approach that focuses on evaluation speed is described in

> [2] Zhang J., Kamata S., Ueshige Y.: A Pseudo-Hilbert Scan Algorithm for Arbitrarily-Sized Rectangle Region, IWICPAS 2006.
Expand Down Expand Up @@ -99,6 +99,66 @@ obtained with
./gilbert2d.py 100 63 | octave --eval 'waitfor(plotpath(dlmread(stdin())));'
```

### Random Access Functions

The following programs provide a reference implementation to efficiently convert
from an index point along the 1D generalized Hilbert curve to spatial coordinates, `d2xy`/`d2xyz`,
and from spatial coordinates to the position along the generalized Hilbert curve, `xy2d`/`xyz2d`:

| Program | Function | Output |
|---|---|---|
| `gilbert_d2xy.py` | `gilbert_d2xy(index,width,height)` | `(x,y)` |
| `gilbert_xy2d.py` | `gilbert_xy2d(x,y,width,height)` | `index` |
| `gilbert_d2xyz.py` | `gilbert_d2xyz(index,width,height,depth)` | `(x,y,z)` |
| `gilbert_xyz2d.py` | `gilbert_xyz2d(x,y,z,width,height,depth)` | `index` |

Each of the programs run on the command line enumerate through the points or indices for their
respective `d2xy[z]` or `xy[z]2d` functions.

The `gilbert_d2xy.py` and `gilbert_d2xyz.py` programs will print out the `index`, `x`, `y` and `z` point,
where appropriate, in `x`, `y`, `z` order.

For example:

```
./gilbert_xyz2d.py 20 12 2
0 0 0 0
1 0 0 1
7 0 1 0
6 0 1 1
8 0 2 0
...
```

To recover the index order traversal, one can sort on the first element (for example `./gilbert_xyz2d.py 20 12 2 | sort -n | cut -f2- -d' '`).

Each of these functions follows the reference `gilbert2d.py` and `gilbert3d.py` implementations but
"short circuit" the recursion when the index or spatial point wouldn't land in the sub problem.
Each leg of the recursion is restricted to another rectangle or cuboid region, allowing for an easy determination
of a spatial bounds check and to count the length of the path in the sub region.
This provides an $O( \lg(N = W \cdot H \cdot D) )$ algorithm.

### Ports

There are reference implementations for JavaScript and C in the `ports` directory.

| Language | Program | Function | Output |
|----------|---------|----------|--------|
| `C` | `gilbert.c` | `int gilbert_d2xy(int *x, int *y, int idx, int width, int height)` | Values stored in `x`,`y` |
| `C` | `gilbert.c` | `int gilbert_xy2d(int x, int y, int width, int height)` | Returns index |
| `C` | `gilbert.c` | `int gilbert_d2xyz(int *x, int *y int *z, int idx, int width, int height, int depth)` | Values stored in `x`,`y`,`z` |
| `C` | `gilbert.c` | `int gilbert_xyz2d(int x, int y, int z, int width, int height, int depth)` | Returns index |
| `JS` | `gilbert.js` | `gilbert.d2xy(idx,width,height)` | Returns `{"x":x,"y":y}` object |
| `JS` | `gilbert.js` | `gilbert.xy2d(x,y,width,height)` | Returns index |
| `JS` | `gilbert.js` | `gilbert.d2xyz(idx,width,height,depth)` | Returns `{"x":x,"y":y, "z":z}` object |
| `JS` | `gilbert.js` | `gilbert.xyz2d(x,y,z,width,height,depth)` | Returns index |

### [Web Demo](https://jakubcerveny.github.io/gilbert/demo)

There is a web demo program, in the `demo/` sub directory, that can be used to to interactively explore
2D generalized Hilbert curves.

A live version can be found [here](https://jakubcerveny.github.io/gilbert/demo).

---

Expand Down
1 change: 1 addition & 0 deletions demo/gilbert.js
142 changes: 142 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Gilbert Curve</title>

<meta name="viewport" content="width=device-width, initial-scale=1">

<script type='text/javascript' src='gilbert.js'></script>
<script type='text/javascript' src='two.js'></script>



<link rel="stylesheet" href="normalize.css">
<link rel="stylesheet" href="skeleton.css">

</head>

<body>
<div class='container' style='margin-top:1em; text-align:center;'>

<h4>Gilbert Curve
<a class='u-pull-right' href='https://github.com/jakubcerveny/gilbert'>
<svg xmlns="http://www.w3.org/2000/svg" width='15' height='15' opacity='0.5' version="1" viewBox="0 0 99.083 100">
<path d="M49.54 0C22.2-.018.026 22.375 0 49.974.025 77.62 22.198 100.01 49.54 100c27.355.01 49.524-22.38 49.543-50.026C99.063 22.374 76.893-.018 49.54 0zm0 88.48c-21.04 0-38.096-17.23-38.074-38.507C11.443 28.74 28.5 11.513 49.54 11.52c21.05-.008 38.11 17.222 38.132 38.454C87.65 71.25 70.59 88.48 49.542 88.48z"/>
<g transform="translate(23.5,23) scale(6.5)">
<path d="M 2.99 0 h 2.02 v 5.47 H 2.99 z m 0 6.39 h 2.02 V 8 H 2.99 z"/>
</g>
</svg>
</a>
</h4>

</div>

<div class='container' style='margin-top:1em;'>


<div class='row' >
<div class='six columns'>
W <input id='ui_width' type='number' onchange='update_num();' oninput='update_num();' onclick='this.select();' >
</div>

<div class='six columns'>
H <input id='ui_height' type='number' oninput='update_num();' onclick='this.select();' >
</div>
</div>

<div class='row' style='height:6em;'>
<div class='six columns'>

<select id='ui_preset' onchange='update_preset();' >
<option value='custom'>custom</option>
<option value='55x31'>55x31</option>
<option value='100x63'>100x63</option>
<option value='15x12'>15x12</option>
</select>

</div>

<div class='six columns'>
<a id='ui_color' class='button' onclick='update_color();' >rgb/bw</a>
</div>

</div>

<div class='row' >
<div class='twelve columns'>

<a id='ui_svg' class='button' onclick='dl_svg();' >
<svg xmlns="http://www.w3.org/2000/svg" width='15' height='15' opacity='0.8' viewBox="0 0 120 120">
<path d="M48.732 69.783L91.04 27.476l11.74 11.74-42.308 42.31z"/>
<path d="M51 3.424h19.054v60.21H51z"/>
<path d="M60.543 81.572L18.22 39.282l11.72-11.74L72.27 69.85zM9 99.575h103v17H9z"/>
<path d="M5.5 68.576h17v48h-17zm92 0h17v48h-17z"/>
</svg>
SVG</a>

</div>
</div>

</div>

<div class='container'>
<div class='row'>
<div id='gilbert_container'></div>
</div>
</div>



<!--
<div class='row' style='height:6em;'>
<div class='four columns'>
W <input id='ui_width' type='number' style='width:80%;' onchange='update_num();' oninput='update_num();'>
</div>
<div class='four columns'>
<select id='ui_preset' onchange='update_preset();' >
<option value='custom'>custom</option>
<option value='55x31'>55x31</option>
<option value='100x63'>100x63</option>
<option value='15x12'>15x12</option>
</select>
</div>
<div class='four columns'>
<a id='ui_svg' class='button' onclick='dl_svg();' >
<svg xmlns="http://www.w3.org/2000/svg" width='15' height='15' opacity='0.8' viewBox="0 0 120 120">
<path d="M48.732 69.783L91.04 27.476l11.74 11.74-42.308 42.31z"/>
<path d="M51 3.424h19.054v60.21H51z"/>
<path d="M60.543 81.572L18.22 39.282l11.72-11.74L72.27 69.85zM9 99.575h103v17H9z"/>
<path d="M5.5 68.576h17v48h-17zm92 0h17v48h-17z"/>
</svg>
SVG</a>
</div>
</div>
<div class='row'>
<div class='four columns' >
H
<input id='ui_height' type='number' style='width:80%;'onchange='update_num();' oninput='update_num();'>
</div>
<div class='four columns' >
&nbsp;
</div>
<div class='four columns'>
<a id='ui_color' class='button' onclick='update_color();' >rgb/bw</a>
</div>
</div>
-->


<script defer='defer' src='script.js'></script>
</body>
</html>

Loading

0 comments on commit 744cf0a

Please sign in to comment.