1

How do I obtain the space filling function (continuous surjection $[0, 1] \to [0, 1]^2$) from a space filling curve?

  • Is this a math question or a Mathematica question? – J. M.'s missing motivation May 28 '20 at 17:15
  • This is a Mathematica question. I'd like a function that takes a number $l$, and outputs the coordinates $(x, y)$ on the curve at a distance of $l$ from the start of the curve. –  May 28 '20 at 17:16
  • Are you actually looking for the infinitely-recursed space-filling curve? Because for any finite level $n$, the Hilbert curve $H_n$ doesn't actually fill space (it's not a surjection); but your answer below seems to imply that you're just looking for the points along $H_n$. – Michael Seifert May 28 '20 at 18:05
  • Yes, an infinitely-recursed curve would be best, but an approximation is ok. –  May 28 '20 at 18:06

2 Answers2

3

Implementing the algorithm found on Brian Hayes's webpage, which takes advantage of the base-4 expansion of a number between 0 and 1:

hilbertMap[quadits_List] := hilbertMap[quadits] =
  If[Length[quadits] == 0, {1/2, 1/2},
   Switch[First[quadits],
    0, {{0, 1/2}, {1/2, 0}}.hilbertMap[Drop[quadits, 1]],
    1, {{1/2, 0}, {0, 1/2}}.hilbertMap[Drop[quadits, 1]] + {0, 1/2},
    2, {{1/2, 0}, {0, 1/2}}.hilbertMap[Drop[quadits, 1]] + {1/2, 1/2},
    3, -{{0, 1/2}, {1/2, 0}}.hilbertMap[Drop[quadits, 1]] + {1, 1/2}]
   ]
hilbertCoords[x_, prec_] := 
  hilbertMap[IntegerDigits[Floor[x 4^prec], 4]]

Briefly: IntegerDigits[Floor[x 4^prec], 4] obtains the first prec digits of the base-4 expansion of a number between 0 and 1, after the decimal (quartal?) point. The hilbertMap function takes this list of digits and uses the algorithm described by Brian Hayes. (EDIT: as pointed out by @MarkMcClure in the comments, this algorithm appeared previously in Space-Filling Curves by Hans Sagan.)

The result is accurate to within $\pm 2^{-(\text{prec} + 1)}$; if a numerical result to within machine precision is needed, prec can be set to $MachinePrecision/Log[10, 2]. This algorithm is also significantly faster than the use of the built-in HilbertCurve, which calculates all of the points in the curve; this algorithm effectively only calculates the points that are needed.

Michael Seifert
  • 15,208
  • 31
  • 68
  • 2
    Looks like a direct implementation of the algorithm on page 18 of Space-Filling Curves by Hans Sagan; odd that Hayes' page doesn't mention that. It's also worth mentioning that the result can be computed exactly for any rational input. An example is shown in this response on math.stackexchange. – Mark McClure May 28 '20 at 19:17
1

A linear interpolation seems to work:

toFunction[line_]:=With[{l=Length[line[[1]]],m=Max[line[[1]]]},Interpolation[Table[{(i-1)/(l-1),line[[1]][[i]]/m},{i,1,l}],InterpolationOrder->1]]
f=toFunction[HilbertCurve[6]];

ParametricPlot[f[l],{l,0,1},PerformanceGoal->"Quality",PlotPoints->5000]
  • 1
    Pretty sure you want InterpolationOrder -> 1 rather than InterpolationOrder -> 0. Look at Plot[f[l], {l, 0, 0.01}] in each case and see which one seems more reasonable. – Michael Seifert May 28 '20 at 17:45
  • Yeah, that looks better, thanks! –  May 28 '20 at 17:49