├── .gitignore ├── Fast Hilbert Curves in C, without Recursion.html ├── README.md ├── hilbert.c └── hilbert.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | data/*.jpg 30 | config.php 31 | -------------------------------------------------------------------------------- /Fast Hilbert Curves in C, without Recursion.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Fast Hilbert Curves in C, without Recursion 10 | 11 |
Fast Hilbert Curve Generation, Sorting, and Range 12 | Queries
13 | 14 |


15 |

Hilbert curves are one of a class of space filling curves - continuous, 16 | nonsmooth curves that pass arbitrarily close to every point in space of 17 | arbitrary dimension - and much information about planar Hilbert curves 18 | is on the web - see here 19 | for example - but little information on efficient generation of Hilbert 20 | curves and related activities like Hilbert sorting, Hilbert range queries, 21 | and so on, is available.  The common recursive generation of planar 22 | Hilbert curves does not easily lead to fast nonrecursive algorithms for 23 | related problems, nor to higher-dimensional generalizations. A rather opaque 24 | description of a nonrecursive algorithm by Butz ("Alternative Algorithm 25 | for Hilbert's Space-Filling Curve", IEEE Trans. Comp., April, 1971, pp 26 | 424-426) led to an implementation by Spencer Thomas that appeared in Graphics 27 | Gems and has been widely circulated on the net. 28 |

I began with his implementation, and began rearranging it to eliminate 29 | the need for various precomputed tables.  In the process, I found 30 | that the basic index-to-point and point-to-index calculations could be 31 | made quite terse, without any supplementary tables.  I extended those 32 | algorithms to allow the comparison of two points to see which falls first 33 | on a Hilbert curve.  Although this comparison can be achieved by converting 34 | each point to its integer index and comparing integers, there can be a 35 | problem with regard to the size of the resulting integers overflowing conventional 36 | integer types.  My implementation of the comparison is less sensitive 37 | to this problem.  Further extensions led to algorithms for finding 38 | the first vertex of a box to appear on the Hilbert curve, finding the first 39 | point (not necessarily a vertex) of a box to lie on the curve, and for 40 | finding the first point after a given point to lie in the box. 41 |

The purpose of this work is to enable efficient multidimensional searches 42 | and to associate spatial locality in searches with spatial locality in 43 | the ordering of items in a B-tree based database.  With the ability 44 | to find the first point in a box after a given point, it is possible to 45 | enumerate all the points in the database within a box without examining 46 | every point in the database.   Likewise, it would be possible 47 | to compute efficiently "spatial joins" - that is, all pairs of points that 48 | both lie in some small box. 49 |

At this point, I can explain the algorithms best by offering the source 50 | code, so here is the C source 51 | and here is the corresponding header 52 | file. 53 |

Please let me know if you find this implemenation of nonrecursive multidimensional 54 | Hilbert curve methods useful or entertaining. 55 |

Doug Moore 56 |
(dougm@caam.rice.edu) 57 |

-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fast Hilbert Curve Generation, Sorting, and Range Queries 2 | `hibert.c` and `hilbert.h` 3 | 4 | A hilbert mapping implementation in C, without recursion. 5 | -------------------------------------------------------------------------------- /hilbert.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE below for information on rights to use, modify and distribute 2 | this code. */ 3 | 4 | /* 5 | * hilbert.c - Computes Hilbert space-filling curve coordinates, without 6 | * recursion, from integer index, and vice versa, and other Hilbert-related 7 | * calculations. Also known as Pi-order or Peano scan. 8 | * 9 | * Author: Doug Moore 10 | * Dept. of Computational and Applied Math 11 | * Rice University 12 | * http://www.caam.rice.edu/~dougm 13 | * Date: Sun Feb 20 2000 14 | * Copyright (c) 1998-2000, Rice University 15 | * 16 | * Acknowledgement: 17 | * This implementation is based on the work of A. R. Butz ("Alternative 18 | * Algorithm for Hilbert's Space-Filling Curve", IEEE Trans. Comp., April, 19 | * 1971, pp 424-426) and its interpretation by Spencer W. Thomas, University 20 | * of Michigan (http://www-personal.umich.edu/~spencer/Home.html) in his widely 21 | * available C software. While the implementation here differs considerably 22 | * from his, the first two interfaces and the style of some comments are very 23 | * much derived from his work. */ 24 | 25 | 26 | #include "hilbert.h" 27 | 28 | /* implementation of the hilbert functions */ 29 | 30 | #define adjust_rotation(rotation,nDims,bits) \ 31 | do { \ 32 | /* rotation = (rotation + 1 + ffs(bits)) % nDims; */ \ 33 | bits &= -bits & nd1Ones; \ 34 | while (bits) \ 35 | bits >>= 1, ++rotation; \ 36 | if ( ++rotation >= nDims ) \ 37 | rotation -= nDims; \ 38 | } while (0) 39 | 40 | #define ones(T,k) ((((T)2) << (k-1)) - 1) 41 | 42 | #define rdbit(w,k) (((w) >> (k)) & 1) 43 | 44 | #define rotateRight(arg, nRots, nDims) \ 45 | ((((arg) >> (nRots)) | ((arg) << ((nDims)-(nRots)))) & ones(bitmask_t,nDims)) 46 | 47 | #define rotateLeft(arg, nRots, nDims) \ 48 | ((((arg) << (nRots)) | ((arg) >> ((nDims)-(nRots)))) & ones(bitmask_t,nDims)) 49 | 50 | #define DLOGB_BIT_TRANSPOSE 51 | static bitmask_t 52 | bitTranspose(unsigned nDims, unsigned nBits, bitmask_t inCoords) 53 | #if defined(DLOGB_BIT_TRANSPOSE) 54 | { 55 | unsigned const nDims1 = nDims-1; 56 | unsigned inB = nBits; 57 | unsigned utB; 58 | bitmask_t inFieldEnds = 1; 59 | bitmask_t inMask = ones(bitmask_t,inB); 60 | bitmask_t coords = 0; 61 | 62 | while ((utB = inB / 2)) 63 | { 64 | unsigned const shiftAmt = nDims1 * utB; 65 | bitmask_t const utFieldEnds = 66 | inFieldEnds | (inFieldEnds << (shiftAmt+utB)); 67 | bitmask_t const utMask = 68 | (utFieldEnds << utB) - utFieldEnds; 69 | bitmask_t utCoords = 0; 70 | unsigned d; 71 | if (inB & 1) 72 | { 73 | bitmask_t const inFieldStarts = inFieldEnds << (inB-1); 74 | unsigned oddShift = 2*shiftAmt; 75 | for (d = 0; d < nDims; ++d) 76 | { 77 | bitmask_t in = inCoords & inMask; 78 | inCoords >>= inB; 79 | coords |= (in & inFieldStarts) << oddShift++; 80 | in &= ~inFieldStarts; 81 | in = (in | (in << shiftAmt)) & utMask; 82 | utCoords |= in << (d*utB); 83 | } 84 | } 85 | else 86 | { 87 | for (d = 0; d < nDims; ++d) 88 | { 89 | bitmask_t in = inCoords & inMask; 90 | inCoords >>= inB; 91 | in = (in | (in << shiftAmt)) & utMask; 92 | utCoords |= in << (d*utB); 93 | } 94 | } 95 | inCoords = utCoords; 96 | inB = utB; 97 | inFieldEnds = utFieldEnds; 98 | inMask = utMask; 99 | } 100 | coords |= inCoords; 101 | return coords; 102 | } 103 | #else 104 | { 105 | bitmask_t coords = 0; 106 | unsigned d; 107 | for (d = 0; d < nDims; ++d) 108 | { 109 | unsigned b; 110 | bitmask_t in = inCoords & ones(bitmask_t,nBits); 111 | bitmask_t out = 0; 112 | inCoords >>= nBits; 113 | for (b = nBits; b--;) 114 | { 115 | out <<= nDims; 116 | out |= rdbit(in, b); 117 | } 118 | coords |= out << d; 119 | } 120 | return coords; 121 | } 122 | #endif 123 | 124 | /***************************************************************** 125 | * hilbert_i2c 126 | * 127 | * Convert an index into a Hilbert curve to a set of coordinates. 128 | * Inputs: 129 | * nDims: Number of coordinate axes. 130 | * nBits: Number of bits per axis. 131 | * index: The index, contains nDims*nBits bits 132 | * (so nDims*nBits must be <= 8*sizeof(bitmask_t)). 133 | * Outputs: 134 | * coord: The list of nDims coordinates, each with nBits bits. 135 | * Assumptions: 136 | * nDims*nBits <= (sizeof index) * (bits_per_byte) 137 | */ 138 | void 139 | hilbert_i2c(unsigned nDims, unsigned nBits, bitmask_t index, bitmask_t coord[]) 140 | { 141 | if (nDims > 1) 142 | { 143 | bitmask_t coords; 144 | halfmask_t const nbOnes = ones(halfmask_t,nBits); 145 | unsigned d; 146 | 147 | if (nBits > 1) 148 | { 149 | unsigned const nDimsBits = nDims*nBits; 150 | halfmask_t const ndOnes = ones(halfmask_t,nDims); 151 | halfmask_t const nd1Ones= ndOnes >> 1; /* for adjust_rotation */ 152 | unsigned b = nDimsBits; 153 | unsigned rotation = 0; 154 | halfmask_t flipBit = 0; 155 | bitmask_t const nthbits = ones(bitmask_t,nDimsBits) / ndOnes; 156 | index ^= (index ^ nthbits) >> 1; 157 | coords = 0; 158 | do 159 | { 160 | halfmask_t bits = (index >> (b-=nDims)) & ndOnes; 161 | coords <<= nDims; 162 | coords |= rotateLeft(bits, rotation, nDims) ^ flipBit; 163 | flipBit = (halfmask_t)1 << rotation; 164 | adjust_rotation(rotation,nDims,bits); 165 | } while (b); 166 | for (b = nDims; b < nDimsBits; b *= 2) 167 | coords ^= coords >> b; 168 | coords = bitTranspose(nBits, nDims, coords); 169 | } 170 | else 171 | coords = index ^ (index >> 1); 172 | 173 | for (d = 0; d < nDims; ++d) 174 | { 175 | coord[d] = coords & nbOnes; 176 | coords >>= nBits; 177 | } 178 | } 179 | else 180 | coord[0] = index; 181 | } 182 | 183 | /***************************************************************** 184 | * hilbert_c2i 185 | * 186 | * Convert coordinates of a point on a Hilbert curve to its index. 187 | * Inputs: 188 | * nDims: Number of coordinates. 189 | * nBits: Number of bits/coordinate. 190 | * coord: Array of n nBits-bit coordinates. 191 | * Outputs: 192 | * index: Output index value. nDims*nBits bits. 193 | * Assumptions: 194 | * nDims*nBits <= (sizeof bitmask_t) * (bits_per_byte) 195 | */ 196 | bitmask_t 197 | hilbert_c2i(unsigned nDims, unsigned nBits, bitmask_t const coord[]) 198 | { 199 | if (nDims > 1) 200 | { 201 | unsigned const nDimsBits = nDims*nBits; 202 | bitmask_t index; 203 | unsigned d; 204 | bitmask_t coords = 0; 205 | for (d = nDims; d--; ) 206 | { 207 | coords <<= nBits; 208 | coords |= coord[d]; 209 | } 210 | 211 | if (nBits > 1) 212 | { 213 | halfmask_t const ndOnes = ones(halfmask_t,nDims); 214 | halfmask_t const nd1Ones= ndOnes >> 1; /* for adjust_rotation */ 215 | unsigned b = nDimsBits; 216 | unsigned rotation = 0; 217 | halfmask_t flipBit = 0; 218 | bitmask_t const nthbits = ones(bitmask_t,nDimsBits) / ndOnes; 219 | coords = bitTranspose(nDims, nBits, coords); 220 | coords ^= coords >> nDims; 221 | index = 0; 222 | do 223 | { 224 | halfmask_t bits = (coords >> (b-=nDims)) & ndOnes; 225 | bits = rotateRight(flipBit ^ bits, rotation, nDims); 226 | index <<= nDims; 227 | index |= bits; 228 | flipBit = (halfmask_t)1 << rotation; 229 | adjust_rotation(rotation,nDims,bits); 230 | } while (b); 231 | index ^= nthbits >> 1; 232 | } 233 | else 234 | index = coords; 235 | for (d = 1; d < nDimsBits; d *= 2) 236 | index ^= index >> d; 237 | return index; 238 | } 239 | else 240 | return coord[0]; 241 | } 242 | 243 | /***************************************************************** 244 | * Readers and writers of bits 245 | */ 246 | 247 | typedef bitmask_t (*BitReader) (unsigned nDims, unsigned nBytes, 248 | char const* c, unsigned y); 249 | typedef void (*BitWriter) (unsigned d, unsigned nBytes, 250 | char* c, unsigned y, int fold); 251 | 252 | 253 | #if defined(sparc) 254 | #define __BIG_ENDIAN__ 255 | #endif 256 | 257 | #if defined(__BIG_ENDIAN__) 258 | #define whichByte(nBytes,y) (nBytes-1-y/8) 259 | #define setBytes(dst,pos,nBytes,val) \ 260 | memset(&dst[pos+1],val,nBytes-pos-1) 261 | #else 262 | #define whichByte(nBytes,y) (y/8) 263 | #define setBytes(dst,pos,nBytes,val) \ 264 | memset(&dst[0],val,pos) 265 | #endif 266 | 267 | static bitmask_t 268 | getIntBits(unsigned nDims, unsigned nBytes, char const* c, unsigned y) 269 | { 270 | unsigned const bit = y%8; 271 | unsigned const offs = whichByte(nBytes,y); 272 | unsigned d; 273 | bitmask_t bits = 0; 274 | c += offs; 275 | for (d = 0; d < nDims; ++d) 276 | { 277 | bits |= rdbit(*c, bit) << d; 278 | c += nBytes; 279 | } 280 | return bits; 281 | } 282 | 283 | #include 284 | static void 285 | propogateIntBits(unsigned d, unsigned nBytes, 286 | char* c, unsigned y, int fold) 287 | { 288 | unsigned const byteId = whichByte(nBytes,y); 289 | unsigned const b = y%8; 290 | char const bthbit = 1 << b; 291 | char* const target = &c[d*nBytes]; 292 | target[byteId] ^= bthbit; 293 | if (!fold) 294 | { 295 | char notbit = ((target[byteId] >> b) & 1) - 1; 296 | if (notbit) 297 | target[byteId] |= bthbit-1; 298 | else 299 | target[byteId] &= -bthbit; 300 | setBytes(target,byteId,nBytes,notbit); 301 | } 302 | } 303 | 304 | /* An IEEE double is treated as a 2100 bit number. In particular, 0 is treated 305 | as a 1 followed by 2099 zeroes, and negative 0 as a 0 followed by 2099 ones. 306 | Only 53 bits differ between a number and a zero of the same sign, with the 307 | position of the 53 determined by the exponent, and the values of the 53 by 308 | the significand (with implicit leading 1 bit). Although IEEE 754 uses the 309 | maximum exponent for NaN's and infinities, this implementation ignores that 310 | decision, so that infinities and NaN's are treated as very large numbers. 311 | Note that we do not explicitly construct a 2100 bit bitmask in the IEEE 312 | routines below. */ 313 | 314 | enum { IEEEexpBits = 11 }; 315 | enum { IEEEsigBits = 52 }; 316 | enum { IEEErepBits = (1 << IEEEexpBits) + IEEEsigBits }; 317 | 318 | typedef union ieee754_double 319 | { 320 | double d; 321 | 322 | /* This is the IEEE 754 double-precision format. */ 323 | struct 324 | { 325 | #if defined(__BIG_ENDIAN__) 326 | unsigned int negative:1; 327 | unsigned int exponent:11; 328 | /* Together these comprise the mantissa. */ 329 | unsigned int mantissa0:20; 330 | unsigned int mantissa1:32; 331 | #else /* Big endian. */ 332 | /* Together these comprise the mantissa. */ 333 | unsigned int mantissa1:32; 334 | unsigned int mantissa0:20; 335 | unsigned int exponent:11; 336 | unsigned int negative:1; 337 | #endif /* Little endian. */ 338 | } ieee; 339 | } ieee754_double; 340 | 341 | static bitmask_t 342 | getIEEESignBits(unsigned nDims, double const* c) 343 | { 344 | unsigned d; 345 | ieee754_double x; 346 | bitmask_t bits = 0; 347 | for (d = 0; d < nDims; ++d) 348 | { 349 | x.d = c[d]; 350 | bits |= x.ieee.negative << d; 351 | } 352 | return bits; 353 | } 354 | 355 | static bitmask_t 356 | getIEEEBits(unsigned nDims, 357 | unsigned ignoreMe, /* ignored */ 358 | char const* cP, 359 | unsigned y) 360 | /* retrieve bits y of elements of double array c, where an expanded IEEE 361 | double has 2100 bits. */ 362 | { 363 | unsigned d; 364 | double const* c = (double const*) cP; 365 | ieee754_double x; 366 | bitmask_t bits = 0; 367 | for (x.d = c[d=0]; d < nDims; x.d = c[++d]) 368 | { 369 | bitmask_t bit = x.ieee.negative; 370 | unsigned normalized = (x.ieee.exponent != 0); 371 | unsigned diff = y - (x.ieee.exponent - normalized); 372 | if (diff <= 52) 373 | bit ^= 1 & ((diff < 32)? x.ieee.mantissa1 >> diff: 374 | (diff < 52)? x.ieee.mantissa0 >> (diff - 32): 375 | /* else */ normalized); 376 | else 377 | bit ^= (y == IEEErepBits-1); 378 | 379 | bits |= bit << d; 380 | } 381 | return bits; 382 | } 383 | 384 | static void 385 | propogateIEEEBits(unsigned d, unsigned nBytes, 386 | char* cP, unsigned y, int fold) 387 | { 388 | ieee754_double* x = d + (ieee754_double*) cP; 389 | unsigned normalized = (x->ieee.exponent != 0); 390 | unsigned diff = y - (x->ieee.exponent - normalized); 391 | if (diff < 32) 392 | { 393 | unsigned b = 1 << diff; 394 | unsigned bit = x->ieee.mantissa1 & b; 395 | x->ieee.mantissa1 &= ~(b-1); 396 | x->ieee.mantissa1 |= b; 397 | if (bit) 398 | --x->ieee.mantissa1; 399 | } 400 | else if (diff < 52) 401 | { 402 | unsigned b = 1 << (diff - 32); 403 | unsigned bit = x->ieee.mantissa0 & b; 404 | x->ieee.mantissa0 &= ~(b-1); 405 | x->ieee.mantissa0 |= b; 406 | if (bit) 407 | --x->ieee.mantissa0; 408 | x->ieee.mantissa1 = bit?-1: 0; 409 | } 410 | else if (diff == 52) /* "flip" the implicit 1 bit */ 411 | { 412 | if (normalized) 413 | --x->ieee.exponent; 414 | else 415 | x->ieee.exponent = 1; 416 | x->ieee.mantissa0 = -normalized; 417 | x->ieee.mantissa1 = -normalized; 418 | } 419 | else if (diff < IEEErepBits) 420 | { 421 | if (y == IEEErepBits-1) 422 | { 423 | x->ieee.negative ^= 1; 424 | x->ieee.exponent = 0; 425 | } 426 | else 427 | x->ieee.exponent = y - 51; 428 | x->ieee.mantissa0 = 0; 429 | x->ieee.mantissa1 = 0; 430 | } 431 | } 432 | 433 | static unsigned 434 | getIEEEexptMax(unsigned nDims, double const* c) 435 | { 436 | unsigned max = 0; 437 | unsigned d; 438 | for (d = 0; d < nDims; ++d) 439 | { 440 | ieee754_double x; 441 | x.d = c[d]; 442 | if (max < x.ieee.exponent) 443 | max = x.ieee.exponent; 444 | } 445 | if (max) --max; 446 | return max; 447 | } 448 | 449 | static void 450 | getIEEEinitValues(double const* c1, 451 | unsigned y, 452 | unsigned nDims, 453 | unsigned* rotation, 454 | bitmask_t* bits, 455 | bitmask_t* index) 456 | { 457 | bitmask_t const one = 1; 458 | unsigned d; 459 | bitmask_t signBits = getIEEESignBits(nDims, c1); 460 | unsigned signParity, leastZeroBit, strayBit; 461 | 462 | /* compute the odd/evenness of the number of sign bits */ 463 | { 464 | bitmask_t signPar = signBits; 465 | for (d = 1; d < nDims; d *= 2) 466 | signPar ^= signPar >> d; 467 | signParity = signPar & 1; 468 | } 469 | 470 | /* find the position of the least-order 0 bit in among signBits and adjust it 471 | if necessary */ 472 | for (leastZeroBit = 0; leastZeroBit < nDims; ++leastZeroBit) 473 | if (rdbit(signBits, leastZeroBit) == 0) 474 | break; 475 | strayBit = 0; 476 | if (leastZeroBit == nDims-2) 477 | strayBit = 1; 478 | else if (leastZeroBit == nDims) 479 | leastZeroBit = nDims-1; 480 | 481 | if (y % 2 == 1) 482 | { 483 | *rotation = (IEEErepBits - y + 1 + leastZeroBit) % nDims; 484 | if (y < IEEErepBits-1) 485 | { 486 | *bits = signBits ^ (one << ((*rotation + strayBit) % nDims)); 487 | *index = signParity; 488 | } 489 | else /* y == IEEErepBits-1 */ 490 | { 491 | *bits = signBits ^ (ones(bitmask_t,nDims) &~ 1); 492 | *index = signParity ^ (nDims&1); 493 | } 494 | } 495 | else /* y % 2 == 0 */ 496 | if (y < IEEErepBits) 497 | { 498 | unsigned shift_amt = (IEEErepBits - y + leastZeroBit) % nDims; 499 | *rotation = (shift_amt + 2 + strayBit) % nDims; 500 | *bits = signBits ^ (one << shift_amt); 501 | *index = signParity ^ 1; 502 | } 503 | else /* y == IEEErepBits */ 504 | { 505 | *rotation = 0; 506 | *bits = one << (nDims-1); 507 | *index = 1; 508 | } 509 | } 510 | 511 | /***************************************************************** 512 | * hilbert_cmp, hilbert_ieee_cmp 513 | * 514 | * Determine which of two points lies further along the Hilbert curve 515 | * Inputs: 516 | * nDims: Number of coordinates. 517 | * nBytes: Number of bytes of storage/coordinate (hilbert_cmp only) 518 | * nBits: Number of bits/coordinate. (hilbert_cmp only) 519 | * coord1: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 520 | * coord2: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 521 | * Return value: 522 | * -1, 0, or 1 according to whether 523 | coord1coord2 524 | * Assumptions: 525 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 526 | */ 527 | 528 | static int 529 | hilbert_cmp_work(unsigned nDims, unsigned nBytes, unsigned nBits, 530 | unsigned max, unsigned y, 531 | char const* c1, char const* c2, 532 | unsigned rotation, 533 | bitmask_t bits, 534 | bitmask_t index, 535 | BitReader getBits) 536 | { 537 | bitmask_t const one = 1; 538 | bitmask_t const nd1Ones = ones(bitmask_t,nDims) >> 1; /* used in adjust_rotation macro */ 539 | while (y-- > max) 540 | { 541 | bitmask_t reflection = getBits(nDims, nBytes, c1, y); 542 | bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y); 543 | bits ^= reflection; 544 | bits = rotateRight(bits, rotation, nDims); 545 | if (diff) 546 | { 547 | unsigned d; 548 | diff = rotateRight(diff, rotation, nDims); 549 | for (d = 1; d < nDims; d *= 2) 550 | { 551 | index ^= index >> d; 552 | bits ^= bits >> d; 553 | diff ^= diff >> d; 554 | } 555 | return (((index ^ y ^ nBits) & 1) == (bits < (bits^diff)))? -1: 1; 556 | } 557 | index ^= bits; 558 | reflection ^= one << rotation; 559 | adjust_rotation(rotation,nDims,bits); 560 | bits = reflection; 561 | } 562 | return 0; 563 | } 564 | 565 | int 566 | hilbert_cmp(unsigned nDims, unsigned nBytes, unsigned nBits, 567 | void const* c1, void const* c2) 568 | { 569 | bitmask_t const one = 1; 570 | bitmask_t bits = one << (nDims-1); 571 | return hilbert_cmp_work(nDims, nBytes, nBits, 0, nBits, 572 | (char const*)c1, (char const*)c2, 573 | 0, bits, bits, getIntBits); 574 | } 575 | 576 | int 577 | hilbert_ieee_cmp(unsigned nDims, double const* c1, double const* c2) 578 | { 579 | unsigned rotation, max; 580 | bitmask_t bits, index; 581 | if (getIEEESignBits(nDims, c1) != getIEEESignBits(nDims, c2)) 582 | max = 2047; 583 | else 584 | { 585 | unsigned max1 = getIEEEexptMax(nDims, c1); 586 | unsigned max2 = getIEEEexptMax(nDims, c2); 587 | max = (max1 > max2)? max1: max2; 588 | } 589 | 590 | getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index); 591 | return hilbert_cmp_work(nDims, 8, 64, max, max+53, 592 | (char const*)c1, (char const*)c2, 593 | rotation, bits, index, getIEEEBits); 594 | } 595 | 596 | /***************************************************************** 597 | * hilbert_box_vtx 598 | * 599 | * Determine the first or last vertex of a box to lie on a Hilbert curve 600 | * Inputs: 601 | * nDims: Number of coordinates. 602 | * nBytes: Number of bytes/coordinate. 603 | * nBits: Number of bits/coordinate. 604 | * findMin: Is it the least vertex sought? 605 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 606 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 607 | * Output: 608 | * c1 and c2 modified to refer to selected corner 609 | * value returned is log2 of size of largest power-of-two-aligned box that 610 | * contains the selected corner and no other corners 611 | * Assumptions: 612 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 613 | */ 614 | 615 | 616 | static unsigned 617 | hilbert_box_vtx_work(unsigned nDims, unsigned nBytes, unsigned nBits, 618 | int findMin, 619 | unsigned max, unsigned y, 620 | char* c1, char* c2, 621 | unsigned rotation, 622 | bitmask_t bits, 623 | bitmask_t index, 624 | BitReader getBits) 625 | { 626 | bitmask_t const one = 1; 627 | bitmask_t const ndOnes = ones(bitmask_t,nDims); 628 | bitmask_t const nd1Ones= ndOnes >> 1; 629 | bitmask_t bitsFolded = 0; 630 | 631 | while (y--) 632 | { 633 | bitmask_t reflection = getBits(nDims, nBytes, c1, y); 634 | bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y); 635 | if (diff) 636 | { 637 | unsigned d; 638 | bitmask_t smear = rotateRight(diff, rotation, nDims) >> 1; 639 | bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims); 640 | for (d = 1; d < nDims; d *= 2) 641 | { 642 | index ^= index >> d; 643 | digit ^= (digit >> d) &~ smear; 644 | smear |= smear >> d; 645 | } 646 | index &= 1; 647 | if ((index ^ y ^ findMin) & 1) 648 | digit ^= smear+1; 649 | digit = rotateLeft(digit, rotation, nDims) & diff; 650 | reflection ^= digit; 651 | 652 | for (d = 0; d < nDims; ++d) 653 | if (rdbit(diff, d)) 654 | { 655 | int way = rdbit(digit, d); 656 | char* target = d*nBytes + (way? c1: c2); 657 | char* const source = 2*d*nBytes + c1 - target + c2; 658 | memcpy(target, source, nBytes); 659 | } 660 | 661 | bitsFolded |= diff; 662 | if (bitsFolded == ndOnes) 663 | return y; 664 | } 665 | 666 | bits ^= reflection; 667 | bits = rotateRight(bits, rotation, nDims); 668 | index ^= bits; 669 | reflection ^= one << rotation; 670 | adjust_rotation(rotation,nDims,bits); 671 | bits = reflection; 672 | } 673 | return y; 674 | } 675 | 676 | unsigned 677 | hilbert_box_vtx(unsigned nDims, unsigned nBytes, unsigned nBits, 678 | int findMin, void* c1, void* c2) 679 | { 680 | bitmask_t const one = 1; 681 | bitmask_t bits = one << (nDims-1); 682 | return hilbert_box_vtx_work(nDims, nBytes, nBits, findMin, 683 | 0, nBits, (char*)c1, (char*)c2, 684 | 0, bits, bits, getIntBits); 685 | } 686 | 687 | unsigned 688 | hilbert_ieee_box_vtx(unsigned nDims, 689 | int findMin, double* c1, double* c2) 690 | { 691 | unsigned rotation, max; 692 | bitmask_t bits, index; 693 | if (getIEEESignBits(nDims, c1) != getIEEESignBits(nDims, c2)) 694 | max = 2047; 695 | else 696 | { 697 | unsigned max1 = getIEEEexptMax(nDims, c1); 698 | unsigned max2 = getIEEEexptMax(nDims, c2); 699 | max = (max1 > max2)? max1: max2; 700 | } 701 | 702 | getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index); 703 | 704 | return hilbert_box_vtx_work(nDims, 8, 64, findMin, 705 | max, max+53, (char *)c1, (char *)c2, 706 | rotation, bits, index, getIEEEBits); 707 | } 708 | 709 | /***************************************************************** 710 | * hilbert_box_pt 711 | * 712 | * Determine the first or last point of a box to lie on a Hilbert curve 713 | * Inputs: 714 | * nDims: Number of coordinates. 715 | * nBytes: Number of bytes/coordinate. 716 | * nBits: Number of bits/coordinate. 717 | * findMin: Is it the least vertex sought? 718 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 719 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 720 | * Output: 721 | * c1 and c2 modified to refer to least point 722 | * Assumptions: 723 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 724 | */ 725 | unsigned 726 | hilbert_box_pt_work(unsigned nDims, unsigned nBytes, unsigned nBits, 727 | int findMin, 728 | unsigned max, unsigned y, 729 | char* c1, char* c2, 730 | unsigned rotation, 731 | bitmask_t bits, 732 | bitmask_t index, 733 | BitReader getBits, 734 | BitWriter propogateBits) 735 | { 736 | bitmask_t const one = 1; 737 | bitmask_t const nd1Ones = ones(bitmask_t,nDims) >> 1; 738 | bitmask_t fold1 = 0, fold2 = 0; 739 | unsigned smearSum = 0; 740 | 741 | while (y-- > max) 742 | { 743 | bitmask_t reflection = getBits(nDims, nBytes, c1, y); 744 | bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y); 745 | if (diff) 746 | { 747 | bitmask_t smear = rotateRight(diff, rotation, nDims) >> 1; 748 | bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims); 749 | unsigned d; 750 | for (d = 1; d < nDims; d *= 2) 751 | { 752 | index ^= index >> d; 753 | digit ^= (digit >> d) &~ smear; 754 | smear |= smear >> d; 755 | } 756 | smearSum += smear; 757 | index &= 1; 758 | if ((index ^ y ^ findMin) & 1) 759 | digit ^= smear+1; 760 | digit = rotateLeft(digit, rotation, nDims) & diff; 761 | reflection ^= digit; 762 | 763 | for (d = 0; d < nDims; ++d) 764 | if (rdbit(diff, d)) 765 | { 766 | int way = rdbit(digit, d); 767 | char* c = way? c1: c2; 768 | bitmask_t fold = way? fold1: fold2; 769 | propogateBits(d, nBytes, c, y, rdbit(fold, d)); 770 | } 771 | diff ^= digit; 772 | fold1 |= digit; 773 | fold2 |= diff; 774 | } 775 | 776 | bits ^= reflection; 777 | bits = rotateRight(bits, rotation, nDims); 778 | index ^= bits; 779 | reflection ^= one << rotation; 780 | adjust_rotation(rotation,nDims,bits); 781 | bits = reflection; 782 | } 783 | return smearSum; 784 | } 785 | 786 | unsigned 787 | hilbert_box_pt(unsigned nDims, unsigned nBytes, unsigned nBits, 788 | int findMin, void* c1, void* c2) 789 | { 790 | bitmask_t const one = 1; 791 | bitmask_t bits = one << (nDims-1); 792 | return hilbert_box_pt_work(nDims, nBytes, nBits, findMin, 793 | 0, nBits, (char*)c1, (char*)c2, 794 | 0, bits, bits, 795 | getIntBits, propogateIntBits); 796 | } 797 | 798 | unsigned 799 | hilbert_ieee_box_pt(unsigned nDims, 800 | int findMin, double* c1, double* c2) 801 | { 802 | unsigned rotation, max; 803 | bitmask_t bits, index; 804 | bitmask_t c1Signs = getIEEESignBits(nDims, c1); 805 | bitmask_t c2Signs = getIEEESignBits(nDims, c2); 806 | if (c1Signs != c2Signs) 807 | { 808 | rotation = 0; 809 | bits = (bitmask_t)1 << (nDims-1); 810 | index = 1; 811 | hilbert_box_pt_work(nDims, 8, 64, findMin, 812 | IEEErepBits-1, IEEErepBits, (char *)c1, (char *)c2, 813 | rotation, bits, index, 814 | getIEEEBits, propogateIEEEBits); 815 | } 816 | 817 | /* having put everything in the same orthant, start */ 818 | { 819 | unsigned max1 = getIEEEexptMax(nDims, c1); 820 | unsigned max2 = getIEEEexptMax(nDims, c2); 821 | max = (max1 > max2)? max1: max2; 822 | } 823 | 824 | getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index); 825 | 826 | return hilbert_box_pt_work(nDims, 8, 64, findMin, 827 | max, max+53, (char *)c1, (char *)c2, 828 | rotation, bits, index, 829 | getIEEEBits, propogateIEEEBits); 830 | } 831 | 832 | /***************************************************************** 833 | * hilbert_nextinbox 834 | * 835 | * Determine the first point of a box after or before a given point to lie on 836 | * a Hilbert curve 837 | * Inputs: 838 | * nDims: Number of coordinates. 839 | * nBytes: Number of bytes/coordinate. 840 | * nBits: Number of bits/coordinate. 841 | * findPrev: Is it a previous point that you want? 842 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 843 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 844 | * point: Array of nDims nBytes-byte coordinates - lower bound on point returned 845 | * 846 | * Output: 847 | if returns 1: 848 | * c1 and c2 modified to refer to least point after "point" in box 849 | else returns 0: 850 | arguments unchanged; "point" is beyond the last point of the box 851 | * Assumptions: 852 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 853 | */ 854 | int 855 | hilbert_nextinbox(unsigned nDims, unsigned nBytes, unsigned nBits, 856 | int findPrev, void* c1V, void* c2V, void const* ptV) 857 | { 858 | bitmask_t const one = 1; 859 | unsigned y = nBits; 860 | bitmask_t const ndOnes = ones(bitmask_t,nDims); 861 | bitmask_t const nd1Ones = ndOnes >> 1; 862 | unsigned rotation = 0; 863 | bitmask_t bits = 0; 864 | bitmask_t index = 0; 865 | bitmask_t fold1 = 0, fold2 = 0; 866 | bitmask_t valu1 = 0, valu2 = 0; 867 | unsigned p_y; 868 | bitmask_t p_separator = 0, p_firstSeparator; 869 | bitmask_t p_cornerdiff, p_reflection; 870 | bitmask_t p_fold1, p_fold2, p_valu1, p_valu2; 871 | 872 | char* c1 = (char*)c1V; 873 | char* c2 = (char*)c2V; 874 | char const* pt = (const char*)ptV; 875 | 876 | while (y-- > 0) 877 | { 878 | bitmask_t reflection = getIntBits(nDims, nBytes, pt, y); 879 | bitmask_t diff = reflection ^ /* planes that separate box and point */ 880 | ((getIntBits(nDims, nBytes, c1, y) &~ fold1) | valu1); 881 | 882 | if (diff) 883 | /* some coordinate planes separate point from box or 884 | dividing box or both; smear the bits of diff to reflect that 885 | after the first diff dimension, they might as well all be 886 | diffing; adjust the diff to reflect the fact that diffed 887 | dimensions don't matter. */ 888 | { 889 | /* compute (the complement of) a "digit" in the integer index of this 890 | point */ 891 | bitmask_t cornerdiff = (diff ^ reflection) ^ /* separate box crnrs */ 892 | ((getIntBits(nDims, nBytes, c2, y) &~ fold2) | valu2); 893 | bitmask_t separator = diff & ~cornerdiff; 894 | /* eventually, the most significant separating cutting plane */ 895 | bitmask_t firstSeparator; 896 | /* bits less significant than the msb of separator are irrelevant; 897 | for convenience, call them all separators too */ 898 | bitmask_t rotSep = rotateRight(separator, rotation, nDims); 899 | /* compute the (complement of the) digit of the hilbert code 900 | assoc with point */ 901 | bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims); 902 | unsigned d; 903 | for (d = 1; d < nDims; d *= 2) 904 | { 905 | index ^= index >> d; 906 | digit ^= digit >> d; 907 | rotSep |= rotSep >> d; 908 | } 909 | index &= 1; 910 | digit &= rotSep; 911 | if ((index ^ y ^ findPrev) & 1) 912 | digit ^= rotSep; 913 | 914 | separator = rotateLeft(rotSep, rotation, nDims); 915 | rotSep -= rotSep >> 1; 916 | firstSeparator = rotateLeft(rotSep, rotation, nDims); 917 | /* forget about all the planes that split the box, except those that 918 | are more significant than the most significant separator. */ 919 | cornerdiff &= ~separator; 920 | 921 | if (cornerdiff && digit) 922 | /* some coordinate planes divide the box. Call the part of the 923 | box in the same orthant as the point "here" and the part of 924 | the box in the next (or previous) orthant "there". Remember 925 | what the "there" orthant of the box looks like in case it 926 | turns out that the curve doesn't reenter the box "here" after 927 | (before) passing thru point. Continue working with the 928 | "here" part. If there is no "there" there, skip it */ 929 | { 930 | p_firstSeparator = digit & -digit; 931 | p_separator = 2*p_firstSeparator-1; 932 | p_separator = rotateLeft(p_separator, rotation, nDims); 933 | p_firstSeparator = rotateLeft(p_firstSeparator, rotation, nDims); 934 | p_cornerdiff = cornerdiff &~ (p_separator ^ p_firstSeparator); 935 | p_y = y; 936 | p_reflection = reflection ^ p_firstSeparator; 937 | p_fold1 = fold1; 938 | p_fold2 = fold2; 939 | p_valu1 = valu1; 940 | p_valu2 = valu2; 941 | } 942 | 943 | if (digit < rotSep) 944 | 945 | /* use next box */ 946 | { 947 | if (!p_separator) return 0; /* no next point */ 948 | separator = p_separator; 949 | firstSeparator = p_firstSeparator; 950 | y = p_y; 951 | cornerdiff = p_cornerdiff; 952 | reflection = p_reflection; 953 | fold1 = p_fold1; 954 | fold2 = p_fold2; 955 | valu1 = p_valu1; 956 | valu2 = p_valu2; 957 | } 958 | 959 | if (cornerdiff) 960 | { 961 | /* reduce currbox */ 962 | bitmask_t corner = diff & cornerdiff; 963 | cornerdiff ^= corner; 964 | fold1 |= corner; 965 | fold2 |= cornerdiff; 966 | valu1 |= ~reflection & corner; 967 | valu2 |= ~reflection & cornerdiff; 968 | } 969 | 970 | separator ^= firstSeparator; 971 | if (firstSeparator) 972 | /* we have completely separated the point from a part of the box 973 | ahead of it on the curve; almost done */ 974 | { 975 | unsigned byteId = whichByte(nBytes,y); 976 | bitmask_t bthbit = one << y%8; 977 | for (d = 0; d < nDims; ++d) 978 | { 979 | char lo1, lo2; 980 | char* cc1 = &c1[d*nBytes]; 981 | char* cc2 = &c2[d*nBytes]; 982 | char const* pnt = &pt[d*nBytes]; 983 | char hibits = -bthbit; 984 | char hipart = pnt[byteId] & hibits; 985 | memcpy(cc1, pnt, byteId); 986 | memcpy(cc2, pnt, byteId); 987 | 988 | if (rdbit(separator, d)) 989 | hibits ^= bthbit; 990 | if (rdbit(firstSeparator, d)) 991 | hipart ^= bthbit; 992 | 993 | if (rdbit(fold1, d)) 994 | { 995 | lo1 = -rdbit(valu1, d); 996 | setBytes(cc1,byteId,nBytes,lo1); 997 | } 998 | else lo1 = cc1[byteId]; 999 | cc1[byteId] = hipart | (lo1 &~ hibits); 1000 | 1001 | if (rdbit(fold2, d)) 1002 | { 1003 | lo2 = -rdbit(valu2, d); 1004 | setBytes(cc2,byteId,nBytes,lo2); 1005 | } 1006 | else lo2 = cc2[byteId]; 1007 | cc2[byteId] = hipart | (lo2 &~ hibits); 1008 | } 1009 | 1010 | hilbert_box_pt(nDims, nBytes, nBits, !findPrev, c1V, c2V); 1011 | return 1; 1012 | } 1013 | } 1014 | 1015 | bits ^= reflection; 1016 | bits = rotateRight(bits, rotation, nDims); 1017 | index ^= bits; 1018 | reflection ^= one << rotation; 1019 | adjust_rotation(rotation,nDims,bits); 1020 | bits = reflection; 1021 | } 1022 | 1023 | /* point is in box */ 1024 | { 1025 | unsigned d; 1026 | for (d = 0; d < nDims; ++d) 1027 | ((char*)c1)[d] = ((char*)c2)[d] = ((char*)pt)[d]; 1028 | } 1029 | return 1; 1030 | } 1031 | 1032 | 1033 | 1034 | /***************************************************************** 1035 | * hilbert_incr 1036 | * 1037 | * Advance from one point to its successor on a Hilbert curve 1038 | * Inputs: 1039 | * nDims: Number of coordinates. 1040 | * nBits: Number of bits/coordinate. 1041 | * coord: Array of nDims nBits-bit coordinates. 1042 | * Output: 1043 | * coord: Next point on Hilbert curve 1044 | * Assumptions: 1045 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 1046 | */ 1047 | 1048 | void 1049 | hilbert_incr(unsigned nDims, unsigned nBits, bitmask_t coord[]) 1050 | { 1051 | bitmask_t const one = 1; 1052 | bitmask_t const ndOnes = ones(bitmask_t,nDims); 1053 | bitmask_t const nd1Ones= ndOnes >> 1; 1054 | unsigned b, d; 1055 | unsigned rotation = 0; 1056 | bitmask_t reflection = 0; 1057 | bitmask_t index = 0; 1058 | unsigned rb = nBits-1; 1059 | bitmask_t rd = ndOnes; 1060 | 1061 | for (b = nBits; b--;) 1062 | { 1063 | bitmask_t bits = reflection; 1064 | reflection = 0; 1065 | for (d = 0; d < nDims; ++d) 1066 | reflection |= rdbit(coord[d], b) << d; 1067 | bits ^= reflection; 1068 | bits = rotateRight(bits, rotation, nDims); 1069 | index ^= bits; 1070 | for (d = 1; d < nDims; d *= 2) 1071 | index ^= index >> d; 1072 | if (index++ != ndOnes) 1073 | { 1074 | rb = b; 1075 | rd = index & -index; 1076 | rd = rotateLeft(rd, rotation, nDims); 1077 | 1078 | } 1079 | index &= 1; 1080 | index <<= nDims-1; 1081 | 1082 | reflection ^= one << rotation; 1083 | adjust_rotation(rotation,nDims,bits); 1084 | } 1085 | for (d = 0; !rdbit(rd, d); ++d) {} 1086 | coord[d] ^= (2 << rb) - 1; 1087 | } 1088 | 1089 | 1090 | /* LICENSE 1091 | * 1092 | * This software is copyrighted by Rice University. It may be freely copied, 1093 | * modified, and redistributed, provided that the copyright notice is 1094 | * preserved on all copies. 1095 | * 1096 | * There is no warranty or other guarantee of fitness for this software, 1097 | * it is provided solely "as is". Bug reports or fixes may be sent 1098 | * to the author, who may or may not act on them as he desires. 1099 | * 1100 | * You may include this software in a program or other software product, 1101 | * but must display the notice: 1102 | * 1103 | * Hilbert Curve implementation copyright 1998, Rice University 1104 | * 1105 | * in any place where the end-user would see your own copyright. 1106 | * 1107 | * If you modify this software, you should include a notice giving the 1108 | * name of the person performing the modification, the date of modification, 1109 | * and the reason for such modification. 1110 | */ 1111 | 1112 | 1113 | 1114 | /* Revision history: 1115 | 1116 | July 1998: Initial release 1117 | 1118 | Sept 1998: Second release 1119 | 1120 | Dec 1998: Fixed bug in hilbert_c2i that allowed a shift by number of bits in 1121 | bitmask to vaporize index, in last bit of the function. Implemented 1122 | hilbert_incr. 1123 | 1124 | August 1999: Added argument to hilbert_nextinbox so that you can, optionally, 1125 | find the previous point along the curve to intersect the box, rather than the 1126 | next point. 1127 | 1128 | Nov 1999: Defined fast bit-transpose function (fast, at least, if the number 1129 | of bits is large), and reimplemented i2c and c2i in terms of it. Collapsed 1130 | loops in hilbert_cmp, with the intention of reusing the cmp code to compare 1131 | more general bitstreams. 1132 | 1133 | Feb 2000: Implemented almost all the floating point versions of cmp, etc, so 1134 | that coordinates expressed in terms of double-precision IEEE floating point 1135 | can be ordered. Still have to do next-in-box, though. 1136 | 1137 | Oct 2001: Learned that some arbitrary coding choices caused some routines 1138 | to fail in one dimension, and changed those choices. 1139 | 1140 | version 2001-10-20-05:34 1141 | 1142 | */ 1143 | 1144 | /* What remains is test code that won't be compiled unless you define the 1145 | TEST_HILBERT preprocessor symbol */ 1146 | 1147 | #ifdef TEST_HILBERT 1148 | #include 1149 | #define abs(x) (((x)>=0)?(x):(-(x))) 1150 | 1151 | int main() 1152 | { 1153 | #define maxDim (8*sizeof(bitmask_t)) 1154 | bitmask_t coord[maxDim], coordPrev[maxDim]; 1155 | unsigned nDims, nBits, nPrints, orderCheck, i; 1156 | bitmask_t r, r1; 1157 | 1158 | for (;;) 1159 | { 1160 | printf( "Enter nDims, nBits, nPrints, orderCheck: " ); 1161 | scanf( "%d", &nDims); 1162 | if ( nDims == 0 ) 1163 | break; 1164 | scanf( "%d%d%d", &nBits, &nPrints, &orderCheck); 1165 | while ( (i = getchar()) != '\n' && i != EOF ) 1166 | ; 1167 | if ( i == EOF ) 1168 | break; 1169 | 1170 | if (nDims*nBits > 8*sizeof(r)) 1171 | { 1172 | printf("Product of nDims and nBits not exceed %d.\n", 8*sizeof(r)); 1173 | break; 1174 | } 1175 | 1176 | if (nBits == 0) 1177 | { 1178 | printf("nBits must be positive.\n"); 1179 | break; 1180 | } 1181 | 1182 | if (nPrints > (1ULL << (nDims*nBits))) 1183 | nPrints = 1ULL << (nDims*nBits); 1184 | 1185 | for (r = 0; r < nPrints; ++r) 1186 | { 1187 | bitmask_t coord1[maxDim]; 1188 | int miscount = 0; 1189 | hilbert_i2c( nDims, nBits, r, coord ); 1190 | printf("%d: ", (unsigned)r); 1191 | for (i = 0; i < nDims; ++i) 1192 | { 1193 | int diff = (int)(coord[i] - coordPrev[i]); 1194 | miscount += abs(diff); 1195 | coordPrev[i] = coord[i]; 1196 | printf(" %d", (unsigned)coord[i]); 1197 | } 1198 | if (r > 0 && miscount != 1) 1199 | printf(".....error"); 1200 | printf("\n"); 1201 | r1 = hilbert_c2i( nDims, nBits, coord ); 1202 | if ( r != r1 ) 1203 | printf( "r = 0x%x; r1 = 0x%x\n", (unsigned)r, (unsigned)r1); 1204 | for (i = 0; i < nDims; ++i) 1205 | coord[i] = coordPrev[i]; 1206 | 1207 | if (! orderCheck) 1208 | continue; 1209 | 1210 | for (r1 = 0; r1 < r; ++r1 ) 1211 | { 1212 | unsigned ans; 1213 | hilbert_i2c( nDims, nBits, r1, coord1 ); 1214 | ans = hilbert_cmp( nDims, sizeof(coord[0]), nBits, coord, coord1); 1215 | if (ans != 1) 1216 | { 1217 | int width = (nDims*nBits + 3) / 4; 1218 | printf( "cmp r = 0x%0*x; r1 = 0x%0*x, ans = %2d\n", 1219 | width, (unsigned)r, 1220 | width, (unsigned)r1, ans ); 1221 | } 1222 | } 1223 | hilbert_i2c( nDims, nBits, r1, coord1 ); 1224 | if (hilbert_cmp( nDims, sizeof(coord[0]), nBits, coord, coord1) != 0) 1225 | printf( "cmp r = 0x%0*x; r1 = 0x%0*x\n", (nDims*nBits+3)/4, (unsigned)r, 1226 | (nDims*nBits+3)/4, (unsigned)r1 ); 1227 | 1228 | } 1229 | } 1230 | return 0; 1231 | } 1232 | 1233 | #endif 1234 | 1235 | #ifdef TEST_IEEE 1236 | #include 1237 | #include 1238 | #include 1239 | 1240 | int cmp(const void* xv, const void* yv) 1241 | { 1242 | double const* x = xv; 1243 | double const* y = yv; 1244 | /* return hilbert_cmp(2, 8, 64, x, y); */ 1245 | return hilbert_ieee_cmp(2, x, y); 1246 | } 1247 | 1248 | int main() 1249 | { 1250 | double *a; 1251 | unsigned i; 1252 | unsigned n; 1253 | printf("How many points? "); 1254 | scanf("%d", &n); 1255 | a = (double*) malloc(2*n*sizeof(double)); 1256 | for (i = 0; i < n; ++i) 1257 | a[2*i] = drand48()-0.5, a[2*i+1] = drand48()-0.5; 1258 | 1259 | qsort(a, n, 2*sizeof(double), cmp); 1260 | 1261 | for (i = 0; i < n; ++i) 1262 | printf("%8g %8g\n", a[2*i], a[2*i+1]); 1263 | free(a); 1264 | return 0; 1265 | } 1266 | 1267 | #endif 1268 | 1269 | #ifdef TEST_CMP 1270 | #include 1271 | 1272 | #define maxDim (8*sizeof(bitmask_t)) 1273 | int main() 1274 | { 1275 | double coord[maxDim]; 1276 | unsigned nDims, i, k; 1277 | 1278 | printf( "Enter nDims: " ); 1279 | scanf( "%d", &nDims); 1280 | if ( nDims == 0 ) 1281 | return 0; 1282 | while ( (i = getchar()) != '\n' && i != EOF ) 1283 | ; 1284 | if ( i == EOF ) 1285 | return 0; 1286 | 1287 | for (k = 0; k < (1<>i)&1)? -1.: 1.; 1292 | 1293 | 1294 | hilbert_ieee_cmp( nDims, coord, coord); 1295 | } 1296 | return 0; 1297 | } 1298 | 1299 | #endif 1300 | 1301 | #ifdef TEST_VTX 1302 | #include 1303 | #include 1304 | 1305 | #define maxDim (8*sizeof(bitmask_t)) 1306 | 1307 | unsigned g_nDims; 1308 | 1309 | int cmp(void const* c1p, void const* c2p) 1310 | { 1311 | return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p); 1312 | } 1313 | 1314 | int main() 1315 | { 1316 | unsigned corner0[maxDim], corner1[maxDim]; 1317 | unsigned cornerlo[maxDim], cornerhi[maxDim], work[maxDim]; 1318 | typedef unsigned array_t[maxDim]; 1319 | array_t* array; 1320 | 1321 | unsigned nDims, i, k; 1322 | 1323 | printf( "Enter nDims: " ); 1324 | scanf( "%d", &nDims); 1325 | if ( nDims == 0 ) 1326 | return 0; 1327 | while ( (i = getchar()) != '\n' && i != EOF ) 1328 | ; 1329 | if ( i == EOF ) 1330 | return 0; 1331 | 1332 | printf("Enter one corner (%d coordinates): ", nDims); 1333 | for (k = 0; k < nDims; ++k) 1334 | scanf("%d", &corner0[k]); 1335 | 1336 | printf("Enter other corner (%d coordinates): ", nDims); 1337 | for (k = 0; k < nDims; ++k) 1338 | scanf("%d", &corner1[k]); 1339 | 1340 | 1341 | /* find first corner */ 1342 | for (k = 0; k < nDims; ++k) 1343 | { 1344 | cornerlo[k] = corner0[k]; 1345 | work[k] = corner1[k]; 1346 | } 1347 | 1348 | hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1349 | 1, cornerlo, work); 1350 | printf("Predicted lo corner: "); 1351 | for (k = 0; k < nDims; ++k) 1352 | printf("%4u", cornerlo[k]); 1353 | printf("\n"); 1354 | 1355 | 1356 | /* find last corner */ 1357 | for (k = 0; k < nDims; ++k) 1358 | { 1359 | work[k] = corner0[k]; 1360 | cornerhi[k] = corner1[k]; 1361 | } 1362 | 1363 | hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1364 | 0, work, cornerhi); 1365 | printf("Predicted hi corner: "); 1366 | for (k = 0; k < nDims; ++k) 1367 | printf("%4u", cornerhi[k]); 1368 | printf("\n"); 1369 | 1370 | array = (array_t*) malloc(maxDim*sizeof(unsigned) << nDims); 1371 | for (k = 0; k < (1<>j)&1)? corner1: corner0; 1378 | eltk[j] = src[j]; 1379 | } 1380 | } 1381 | 1382 | g_nDims = nDims; 1383 | qsort(array, (1< 1402 | #include 1403 | #include 1404 | 1405 | #define maxDim (8*sizeof(bitmask_t)) 1406 | typedef double key_t; 1407 | 1408 | unsigned g_nDims; 1409 | 1410 | int cmp(void const* c1p, void const* c2p) 1411 | { 1412 | return hilbert_ieee_cmp(g_nDims, c1p, c2p); 1413 | } 1414 | 1415 | int main() 1416 | { 1417 | key_t corner0[maxDim], corner1[maxDim]; 1418 | key_t cornerlo[maxDim], cornerhi[maxDim], work[maxDim]; 1419 | typedef key_t array_t[maxDim]; 1420 | array_t* array; 1421 | 1422 | unsigned nDims, i, k; 1423 | 1424 | printf( "Enter nDims: " ); 1425 | scanf( "%d", &nDims); 1426 | if ( nDims == 0 ) 1427 | return 0; 1428 | 1429 | for (i = 0; i < 10000; ++i) 1430 | { 1431 | for (k = 0; k < nDims; ++k) 1432 | { 1433 | corner0[k] = 2.*drand48() - 1.; 1434 | corner1[k] = 2.*drand48() - 1.; 1435 | } 1436 | 1437 | /* find first corner */ 1438 | for (k = 0; k < nDims; ++k) 1439 | { 1440 | cornerlo[k] = corner0[k]; 1441 | work[k] = corner1[k]; 1442 | } 1443 | 1444 | hilbert_ieee_box_vtx(nDims, 1, cornerlo, work); 1445 | 1446 | /* find last corner */ 1447 | for (k = 0; k < nDims; ++k) 1448 | { 1449 | work[k] = corner0[k]; 1450 | cornerhi[k] = corner1[k]; 1451 | } 1452 | 1453 | hilbert_ieee_box_vtx(nDims, 0, work, cornerhi); 1454 | 1455 | array = (array_t*) malloc(maxDim*sizeof(key_t) << nDims); 1456 | for (k = 0; k < (1<>j)&1)? corner1: corner0; 1463 | eltk[j] = src[j]; 1464 | } 1465 | } 1466 | 1467 | g_nDims = nDims; 1468 | qsort(array, (1< 1490 | #include 1491 | 1492 | #define maxDim (8*sizeof(bitmask_t)) 1493 | 1494 | unsigned g_nDims; 1495 | 1496 | int cmp(void const* c1p, void const* c2p) 1497 | { 1498 | return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p); 1499 | } 1500 | 1501 | int main() 1502 | { 1503 | unsigned point0[maxDim], point1[maxDim]; 1504 | unsigned pointlo[maxDim], pointhi[maxDim], work[maxDim]; 1505 | typedef unsigned array_t[maxDim]; 1506 | array_t* array; 1507 | 1508 | unsigned nDims, i, k, outvolume = 1, involume = 1; 1509 | unsigned nextItem; 1510 | 1511 | printf( "Enter nDims: " ); 1512 | scanf( "%d", &nDims); 1513 | if ( nDims == 0 ) 1514 | return 0; 1515 | while ( (i = getchar()) != '\n' && i != EOF ) 1516 | ; 1517 | if ( i == EOF ) 1518 | return 0; 1519 | 1520 | printf("Enter one point (%d coordinates): ", nDims); 1521 | for (k = 0; k < nDims; ++k) 1522 | scanf("%d", &point0[k]); 1523 | 1524 | printf("Enter other point (%d coordinates, strictly greater): ", nDims); 1525 | for (k = 0; k < nDims; ++k) 1526 | { 1527 | unsigned diff; 1528 | scanf("%d", &point1[k]); 1529 | diff = point1[k] - point0[k]; 1530 | outvolume *= diff + 1; 1531 | involume *= diff - 1; 1532 | } 1533 | 1534 | 1535 | /* find first point */ 1536 | for (k = 0; k < nDims; ++k) 1537 | { 1538 | pointlo[k] = point0[k]; 1539 | work[k] = point1[k]; 1540 | } 1541 | 1542 | hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1543 | 1, pointlo, work); 1544 | printf("Predicted lo point: "); 1545 | for (k = 0; k < nDims; ++k) 1546 | printf("%4u", pointlo[k]); 1547 | printf("\n"); 1548 | 1549 | 1550 | /* find last point */ 1551 | for (k = 0; k < nDims; ++k) 1552 | { 1553 | work[k] = point0[k]; 1554 | pointhi[k] = point1[k]; 1555 | } 1556 | 1557 | hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1558 | 0, work, pointhi); 1559 | printf("Predicted hi point: "); 1560 | for (k = 0; k < nDims; ++k) 1561 | printf("%4u", pointhi[k]); 1562 | printf("\n"); 1563 | 1564 | 1565 | 1566 | array = (array_t*) malloc(maxDim*sizeof(unsigned) * (outvolume-involume)); 1567 | if (array == 0) 1568 | { 1569 | fprintf(stderr, "Out of memory.\n"); 1570 | exit(-1); 1571 | } 1572 | nextItem = 0; 1573 | for (k = 0; k < outvolume; ++k) 1574 | { 1575 | unsigned kk = k; 1576 | unsigned j; 1577 | unsigned* eltk = &array[nextItem][0]; 1578 | int boundary = 0; 1579 | 1580 | for (j = 0; j < nDims; ++j) 1581 | { 1582 | unsigned diff1 = point1[j] - point0[j] + 1; 1583 | unsigned pos = point0[j] + (kk % diff1); 1584 | boundary |= (point0[j] == pos || pos == point1[j]); 1585 | eltk[j] = pos; 1586 | kk /= diff1; 1587 | } 1588 | if (boundary) 1589 | ++nextItem; 1590 | } 1591 | 1592 | g_nDims = nDims; 1593 | qsort(array, outvolume-involume, maxDim*sizeof(unsigned), cmp); 1594 | 1595 | printf("Result of sort\n"); 1596 | for (k = 0; k < outvolume-involume; k += outvolume-involume-1) 1597 | { 1598 | unsigned j; 1599 | unsigned* eltk = &array[k][0]; 1600 | for (j = 0; j < nDims; ++j) 1601 | printf("%4u", eltk[j]); 1602 | printf("\n"); 1603 | } 1604 | free((char*)array); 1605 | return 0; 1606 | } 1607 | 1608 | #endif 1609 | 1610 | #ifdef TEST_IEEE_PT 1611 | #include 1612 | #include 1613 | 1614 | #define maxDim (8*sizeof(bitmask_t)) 1615 | 1616 | int main() 1617 | { 1618 | double point0[maxDim], point1[maxDim]; 1619 | double pointlo[maxDim], pointhi[maxDim], work[maxDim]; 1620 | 1621 | unsigned nDims, k, i; 1622 | 1623 | printf( "Enter nDims: " ); 1624 | scanf( "%d", &nDims); 1625 | if ( nDims == 0 ) 1626 | return 0; 1627 | while ( (i = getchar()) != '\n' && i != EOF ) 1628 | ; 1629 | if ( i == EOF ) 1630 | return 0; 1631 | 1632 | printf("Enter one point (%d coordinates): ", nDims); 1633 | for (k = 0; k < nDims; ++k) 1634 | scanf("%lf", &point0[k]); 1635 | 1636 | printf("Enter other point (%d coordinates, strictly greater): ", nDims); 1637 | for (k = 0; k < nDims; ++k) 1638 | scanf("%lf", &point1[k]); 1639 | 1640 | /* find last point */ 1641 | for (k = 0; k < nDims; ++k) 1642 | { 1643 | work[k] = point0[k]; 1644 | pointhi[k] = point1[k]; 1645 | } 1646 | 1647 | hilbert_ieee_box_pt(nDims, 0, work, pointhi); 1648 | printf("Predicted hi point: "); 1649 | for (k = 0; k < nDims; ++k) 1650 | printf("%10lg", pointhi[k]); 1651 | printf("\n"); 1652 | 1653 | /* find first point */ 1654 | for (k = 0; k < nDims; ++k) 1655 | { 1656 | pointlo[k] = point0[k]; 1657 | work[k] = point1[k]; 1658 | } 1659 | 1660 | hilbert_ieee_box_pt(nDims, 1, pointlo, work); 1661 | printf("Predicted lo point: "); 1662 | for (k = 0; k < nDims; ++k) 1663 | printf("%10lg", pointlo[k]); 1664 | printf("\n"); 1665 | 1666 | /* validate by sorting random boundary points */ 1667 | #define nPts 1000000 1668 | assert(hilbert_ieee_cmp(nDims, pointlo, pointhi) < 0); 1669 | for (i = 0; i < nPts; ++i) 1670 | { 1671 | double pt1[maxDim], pt2[maxDim]; 1672 | for (k = 0; k < nDims; ++k) 1673 | { 1674 | if (i % nDims == k) 1675 | pt1[k] = point0[k]; 1676 | else 1677 | pt1[k] = point0[k] + drand48()*(point1[k]-point0[k]); 1678 | } 1679 | for (k = 0; k < nDims; ++k) 1680 | { 1681 | if (i % nDims == k) 1682 | pt2[k] = point1[k]; 1683 | else 1684 | pt2[k] = point0[k] + drand48()*(point1[k]-point0[k]); 1685 | } 1686 | if (hilbert_ieee_cmp(nDims, pt1, pt2) < 0) 1687 | { 1688 | if (hilbert_ieee_cmp(nDims, pt1, pointlo) < 0) 1689 | memcpy(pointlo, pt1, maxDim*sizeof(double)); 1690 | if (hilbert_ieee_cmp(nDims, pointhi, pt2) < 0) 1691 | memcpy(pointhi, pt2, maxDim*sizeof(double)); 1692 | } 1693 | else 1694 | { 1695 | if (hilbert_ieee_cmp(nDims, pt2, pointlo) < 0) 1696 | memcpy(pointlo, pt2, maxDim*sizeof(double)); 1697 | if (hilbert_ieee_cmp(nDims, pointhi, pt1) < 0) 1698 | memcpy(pointhi, pt1, maxDim*sizeof(double)); 1699 | } 1700 | } 1701 | 1702 | printf("Sorted hi and lo:\n"); 1703 | for (k = 0; k < nDims; ++k) 1704 | printf("%10lg", pointhi[k]); 1705 | printf("\n"); 1706 | for (k = 0; k < nDims; ++k) 1707 | printf("%10lg", pointlo[k]); 1708 | printf("\n"); 1709 | 1710 | return 0; 1711 | } 1712 | 1713 | #endif 1714 | 1715 | #ifdef TEST_NEXT 1716 | #include 1717 | 1718 | int main() 1719 | { 1720 | unsigned i; 1721 | unsigned c1[100], c2[100], pt[100]; 1722 | unsigned nDims, nBytes = 4; 1723 | int stat, findPrev; 1724 | printf("Enter nDims: " ); 1725 | scanf("%u", &nDims); 1726 | 1727 | printf("Enter 1st box corner: "); 1728 | for (i = 0; i < nDims; ++i) 1729 | scanf("%u", &c1[i]); 1730 | printf("Enter 2nd box corner: "); 1731 | for (i = 0; i < nDims; ++i) 1732 | scanf("%u", &c2[i]); 1733 | printf("Enter point: "); 1734 | for (i = 0; i < nDims; ++i) 1735 | scanf("%u", &pt[i]); 1736 | printf("Find prev?: "); 1737 | scanf("%d", &findPrev); 1738 | 1739 | stat = hilbert_nextinbox(nDims, nBytes, 8*nBytes, findPrev, c1, c2, pt); 1740 | 1741 | if (stat) 1742 | for (i = 0; i < nDims; ++i) 1743 | printf("%u ", c1[i]); 1744 | else 1745 | printf("No such point"); 1746 | 1747 | printf("\n"); 1748 | return 0; 1749 | } 1750 | #endif 1751 | -------------------------------------------------------------------------------- /hilbert.h: -------------------------------------------------------------------------------- 1 | /* C header file for Hilbert curve functions */ 2 | #if !defined(_hilbert_h_) 3 | #define _hilbert_h_ 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /* define the bitmask_t type as an integer of sufficient size */ 10 | typedef unsigned long long bitmask_t; 11 | /* define the halfmask_t type as an integer of 1/2 the size of bitmask_t */ 12 | typedef unsigned long halfmask_t; 13 | 14 | /***************************************************************** 15 | * hilbert_i2c 16 | * 17 | * Convert an index into a Hilbert curve to a set of coordinates. 18 | * Inputs: 19 | * nDims: Number of coordinate axes. 20 | * nBits: Number of bits per axis. 21 | * index: The index, contains nDims*nBits bits (so nDims*nBits must be <= 8*sizeof(bitmask_t)). 22 | * Outputs: 23 | * coord: The list of nDims coordinates, each with nBits bits. 24 | * Assumptions: 25 | * nDims*nBits <= (sizeof index) * (bits_per_byte) 26 | */ 27 | 28 | void hilbert_i2c(unsigned nDims, unsigned nBits, bitmask_t index, bitmask_t coord[]); 29 | 30 | /***************************************************************** 31 | * hilbert_c2i 32 | * 33 | * Convert coordinates of a point on a Hilbert curve to its index. 34 | * Inputs: 35 | * nDims: Number of coordinates. 36 | * nBits: Number of bits/coordinate. 37 | * coord: Array of n nBits-bit coordinates. 38 | * Outputs: 39 | * index: Output index value. nDims*nBits bits. 40 | * Assumptions: 41 | * nDims*nBits <= (sizeof bitmask_t) * (bits_per_byte) 42 | */ 43 | 44 | bitmask_t hilbert_c2i(unsigned nDims, unsigned nBits, bitmask_t const coord[]); 45 | 46 | /***************************************************************** 47 | * hilbert_cmp, hilbert_ieee_cmp 48 | * 49 | * Determine which of two points lies further along the Hilbert curve 50 | * Inputs: 51 | * nDims: Number of coordinates. 52 | * nBytes: Number of bytes of storage/coordinate (hilbert_cmp only) 53 | * nBits: Number of bits/coordinate. (hilbert_cmp only) 54 | * coord1: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 55 | * coord2: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 56 | * Return value: 57 | * -1, 0, or 1 according to whether 58 | coord1coord2 59 | * Assumptions: 60 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 61 | */ 62 | 63 | int hilbert_cmp(unsigned nDims, unsigned nBytes, unsigned nBits, void const* coord1, void const* coord2); 64 | int hilbert_ieee_cmp(unsigned nDims, double const* coord1, double const* coord2); 65 | 66 | /***************************************************************** 67 | * hilbert_box_vtx 68 | * 69 | * Determine the first or last vertex of a box to lie on a Hilbert curve 70 | * Inputs: 71 | * nDims: Number of coordinates. 72 | * nBytes: Number of bytes/coordinate. 73 | * nBits: Number of bits/coordinate. (hilbert_cmp only) 74 | * findMin: Is it the least vertex sought? 75 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 76 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 77 | * Output: 78 | * c1 and c2 modified to refer to selected corner 79 | * value returned is log2 of size of largest power-of-two-aligned box that 80 | * contains the selected corner and no other corners 81 | * Assumptions: 82 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 83 | */ 84 | unsigned 85 | hilbert_box_vtx(unsigned nDims, unsigned nBytes, unsigned nBits, 86 | int findMin, void* c1, void* c2); 87 | unsigned 88 | hilbert_ieee_box_vtx(unsigned nDims, 89 | int findMin, double* c1, double* c2); 90 | 91 | /***************************************************************** 92 | * hilbert_box_pt 93 | * 94 | * Determine the first or last point of a box to lie on a Hilbert curve 95 | * Inputs: 96 | * nDims: Number of coordinates. 97 | * nBytes: Number of bytes/coordinate. 98 | * nBits: Number of bits/coordinate. 99 | * findMin: Is it the least vertex sought? 100 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 101 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 102 | * Output: 103 | * c1 and c2 modified to refer to least point 104 | * Assumptions: 105 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 106 | */ 107 | unsigned 108 | hilbert_box_pt(unsigned nDims, unsigned nBytes, unsigned nBits, 109 | int findMin, void* coord1, void* coord2); 110 | unsigned 111 | hilbert_ieee_box_pt(unsigned nDims, 112 | int findMin, double* c1, double* c2); 113 | 114 | /***************************************************************** 115 | * hilbert_nextinbox 116 | * 117 | * Determine the first point of a box after a given point to lie on a Hilbert curve 118 | * Inputs: 119 | * nDims: Number of coordinates. 120 | * nBytes: Number of bytes/coordinate. 121 | * nBits: Number of bits/coordinate. 122 | * findPrev: Is the previous point sought? 123 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 124 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 125 | * point: Array of nDims nBytes-byte coordinates - lower bound on point returned 126 | * 127 | * Output: 128 | if returns 1: 129 | * c1 and c2 modified to refer to least point after "point" in box 130 | else returns 0: 131 | arguments unchanged; "point" is beyond the last point of the box 132 | * Assumptions: 133 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 134 | */ 135 | int 136 | hilbert_nextinbox(unsigned nDims, unsigned nBytes, unsigned nBits, 137 | int findPrev, void* coord1, void* coord2, 138 | void const* point); 139 | 140 | /***************************************************************** 141 | * hilbert_incr 142 | * 143 | * Advance from one point to its successor on a Hilbert curve 144 | * Inputs: 145 | * nDims: Number of coordinates. 146 | * nBits: Number of bits/coordinate. 147 | * coord: Array of nDims nBits-bit coordinates. 148 | * Output: 149 | * coord: Next point on Hilbert curve 150 | * Assumptions: 151 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 152 | */ 153 | 154 | void 155 | hilbert_incr(unsigned nDims, unsigned nBits, bitmask_t coord[]); 156 | 157 | #ifdef __cplusplus 158 | } 159 | #endif 160 | 161 | #endif /* _hilbert_h_ */ 162 | --------------------------------------------------------------------------------