Title: | 2x2, 3x3 and Nxn Space-Filling Curves |
---|---|
Description: | Implementation of all possible forms of 2x2 and 3x3 space-filling curves, i.e., the generalized forms of the Hilbert curve <https://en.wikipedia.org/wiki/Hilbert_curve>, the Peano curve <https://en.wikipedia.org/wiki/Peano_curve> and the Peano curve in the meander type (Figure 5 in <https://eudml.org/doc/141086>). It can generates nxn curves expanded from any specific level-1 units. It also implements the H-curve and the three-dimensional Hilbert curve. |
Authors: | Zuguang Gu [aut, cre] |
Maintainer: | Zuguang Gu <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.0.1 |
Built: | 2024-11-16 05:51:36 UTC |
Source: | https://github.com/jokergoo/sfcurve |
Subunit in the curve
## S3 method for class 'sfc_nxn' x[i, j, ..., drop = TRUE] ## S4 method for signature 'sfc_nxn' sfc_index(p, index = "") test_sfc_index(p, index)
## S3 method for class 'sfc_nxn' x[i, j, ..., drop = TRUE] ## S4 method for signature 'sfc_nxn' sfc_index(p, index = "") test_sfc_index(p, index)
x |
An |
i , index
|
A string of digits representing the path on the hierarchy of the curve. The left side
corresponds to the top level and the right side corresponds to the bottom level on the curve. For the
2x2 curve, the digits can only be 1-4, and for the Peano and Meander curves, the digites can be 1-9.
The hierarchical index should be specified in a format of |
j |
A value of |
... |
Ignore. |
drop |
A value of |
p |
An |
sfc_index()
only works on square curves (i.e. a curve with a single base letter as seed.)
test_sfc_index()
is a helper function for demonstrating sfc_index()
.
sfc_index()
returns an integer vector.
p = sfc_2x2("I", "11111") p["3:2:1"] # for 2x2 and 3x3 curves, ":" can be omitted p["321"] p["3:2:1", TRUE] # or p["3:2:1", drop = FALSE] # only for testing p = sfc_2x2("I", "11111") om = par(no.readonly = TRUE) par(mfrow = c(2, 2)) test_sfc_index(p, "3") test_sfc_index(p, "3:2") test_sfc_index(p, "3:2:1") test_sfc_index(p, "3:2:1:1") par(om) p = sfc_3x3_meander("I", "11111") om = par(no.readonly = TRUE) par(mfrow = c(2, 2)) test_sfc_index(p, "7") test_sfc_index(p, "7:5") test_sfc_index(p, "7:5:9") test_sfc_index(p, "7:5:9:2") par(om)
p = sfc_2x2("I", "11111") p["3:2:1"] # for 2x2 and 3x3 curves, ":" can be omitted p["321"] p["3:2:1", TRUE] # or p["3:2:1", drop = FALSE] # only for testing p = sfc_2x2("I", "11111") om = par(no.readonly = TRUE) par(mfrow = c(2, 2)) test_sfc_index(p, "3") test_sfc_index(p, "3:2") test_sfc_index(p, "3:2:1") test_sfc_index(p, "3:2:1:1") par(om) p = sfc_3x3_meander("I", "11111") om = par(no.readonly = TRUE) par(mfrow = c(2, 2)) test_sfc_index(p, "7") test_sfc_index(p, "7:5") test_sfc_index(p, "7:5:9") test_sfc_index(p, "7:5:9:2") par(om)
Utility functions
## S3 method for class 'sfc_sequence' x[i] ## S3 replacement method for class 'sfc_sequence' x[i] <- value ## S3 method for class 'sfc_sequence' length(x) ## S3 method for class 'sfc_sequence' c(...)
## S3 method for class 'sfc_sequence' x[i] ## S3 replacement method for class 'sfc_sequence' x[i] <- value ## S3 method for class 'sfc_sequence' length(x) ## S3 method for class 'sfc_sequence' c(...)
x |
An |
i |
Numeric index. |
value |
An |
... |
A list of |
For efficiency, c.sfc_sequence()
does not check whether the input sfc_sequence
objects are compatible.
length.sfc_sequence()
returns an integer scalar.
c.sfc_sequence()
returns an sfc_sequence
object.
p = sfc_sequence("ABCDEFGH") p p[1:4] p[1:4] = p[8:5] p length(p) c(p, p)
p = sfc_sequence("ABCDEFGH") p p[1:4] p[1:4] = p[8:5] p length(p) c(p, p)
All traverse paths of a sequence
all_traverse_paths(rules, p) get_one_traverse_path(rules, p) plot_traverse_paths(rules, p, type = c("all", "11|22", "12|21"))
all_traverse_paths(rules, p) get_one_traverse_path(rules, p) plot_traverse_paths(rules, p, type = c("all", "11|22", "12|21"))
rules |
An |
p |
An |
type |
If the value is |
Given an input sequence with rotations, all_traverse_paths()
lists all combinations of expansion
codes from the first letter to the last letter in p
(i.e. all possible traverse paths).
get_one_traverse_path()
returns one random traverse path.
all_traverse_paths()
returns a list of integer vectors.
get_one_traverse_path()
returns an integer vector.
# expansion rules for the general 3x3 curves p = SFC_RULES_3x3_COMBINED@rules$I[[3]] get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) # p = SFC_RULES_3x3_COMBINED@rules$I[[3]] plot_traverse_paths(SFC_RULES_3x3_COMBINED, p) plot_traverse_paths(SFC_RULES_3x3_COMBINED, p, type = "11|22") plot_traverse_paths(SFC_RULES_3x3_COMBINED, p, type = "12|21") # 2x2 curve p = sfc_2x2("I", 11) plot_traverse_paths(SFC_RULES_2x2, p) # Peano curve p = sfc_3x3_peano("I", 1) plot_traverse_paths(SFC_RULES_3x3_PEANO, p) # Meander curve p = sfc_3x3_meander("I", 1) plot_traverse_paths(SFC_RULES_3x3_MEANDER, p)
# expansion rules for the general 3x3 curves p = SFC_RULES_3x3_COMBINED@rules$I[[3]] get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) get_one_traverse_path(SFC_RULES_3x3_COMBINED, p) # p = SFC_RULES_3x3_COMBINED@rules$I[[3]] plot_traverse_paths(SFC_RULES_3x3_COMBINED, p) plot_traverse_paths(SFC_RULES_3x3_COMBINED, p, type = "11|22") plot_traverse_paths(SFC_RULES_3x3_COMBINED, p, type = "12|21") # 2x2 curve p = sfc_2x2("I", 11) plot_traverse_paths(SFC_RULES_2x2, p) # Peano curve p = sfc_3x3_peano("I", 1) plot_traverse_paths(SFC_RULES_3x3_PEANO, p) # Meander curve p = sfc_3x3_meander("I", 1) plot_traverse_paths(SFC_RULES_3x3_MEANDER, p)
A list of pre-defined base patterns. See the Examples section.
BASE_I BASE_J BASE_R BASE_L BASE_U BASE_B BASE_D BASE_P BASE_Q BASE_C BASE_LIST
BASE_I BASE_J BASE_R BASE_L BASE_U BASE_B BASE_D BASE_P BASE_Q BASE_C BASE_LIST
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class sfc_base
of length 1.
An object of class list
of length 10.
BASE_I
and BASE_J
are identical. They are only used to distinguish the two
"going forward" patterns for the level-1 units with 11/22 corner values, i.e. bottom-left to top-right, and bottom-right
to top-left.
sfc_base
objects.
BASE_I BASE_J BASE_R BASE_L BASE_U BASE_B BASE_D BASE_P BASE_Q BASE_C draw_multiple_curves( BASE_I, BASE_J, BASE_R, BASE_L, BASE_U, BASE_B, BASE_D, BASE_P, BASE_Q, BASE_C, nrow = 2 )
BASE_I BASE_J BASE_R BASE_L BASE_U BASE_B BASE_D BASE_P BASE_Q BASE_C draw_multiple_curves( BASE_I, BASE_J, BASE_R, BASE_L, BASE_U, BASE_B, BASE_D, BASE_P, BASE_Q, BASE_C, nrow = 2 )
Draw multiple curves
draw_multiple_curves( ..., list = NULL, nrow = NULL, ncol = NULL, extend = TRUE, title = FALSE, closed = FALSE, padding = unit(0, "pt"), lwd = 4, col = NULL )
draw_multiple_curves( ..., list = NULL, nrow = NULL, ncol = NULL, extend = TRUE, title = FALSE, closed = FALSE, padding = unit(0, "pt"), lwd = 4, col = NULL )
... |
A list of |
list |
The list of curve object can also be directly specified as a "list" object. |
nrow |
Number of rows in the layout. |
ncol |
Number of columns in the layout. |
extend |
Whether to draw the entry and exit segments? It is only used when input is a list of |
title |
Whether to add titles on each panel? The title is constructed in the form of |
closed |
Whether the curves are closed? The value should be a logical vector. If it is |
padding |
Space around each curve. The value should be a |
lwd |
Line width with length 1. |
col |
Color for the segments with length 1. If the value is |
This function is used for quick comparison on curves.
No value is returned.
# for all forms of curves initialized by base pattern 'R', with rotation 0, and on level 3 draw_multiple_curves( sfc_2x2("R", "111"), sfc_2x2("R", "112"), sfc_2x2("R", "121"), sfc_2x2("R", "122"), sfc_2x2("R", "211"), sfc_2x2("R", "212"), sfc_2x2("R", "221"), sfc_2x2("R", "222"), nrow = 2, title = TRUE) # simply a list of sequences # note they only contain I/R/L, so the base patterns I/R/L are internally used draw_multiple_curves( sfc_sequence("IIII"), sfc_sequence("RRRR"), sfc_sequence("RRLL"), nrow = 1 )
# for all forms of curves initialized by base pattern 'R', with rotation 0, and on level 3 draw_multiple_curves( sfc_2x2("R", "111"), sfc_2x2("R", "112"), sfc_2x2("R", "121"), sfc_2x2("R", "122"), sfc_2x2("R", "211"), sfc_2x2("R", "212"), sfc_2x2("R", "221"), sfc_2x2("R", "222"), nrow = 2, title = TRUE) # simply a list of sequences # note they only contain I/R/L, so the base patterns I/R/L are internally used draw_multiple_curves( sfc_sequence("IIII"), sfc_sequence("RRRR"), sfc_sequence("RRLL"), nrow = 1 )
Draw the expansion rules
draw_rules_2x2() draw_rules_3x3_peano(flip = FALSE) draw_rules_3x3_meander(flip = FALSE)
draw_rules_2x2() draw_rules_3x3_peano(flip = FALSE) draw_rules_3x3_meander(flip = FALSE)
flip |
Whether to use the "flipped" rules? For the Peano curve and the Meander curve, there is also a "fliiped" version of the curve expansion rules. See the vignettes for details. |
The expansion rules define how the curve is expanded from level-0 to level-1.
No value is returned.
draw_rules_2x2() # the units in the main rules of the Peano curve are vertical draw_rules_3x3_peano() # the units in the flipped rules of the Peano curve are horizontal draw_rules_3x3_peano(flip = TRUE) # the units in the main rules of the Meander curve are "forward" # i.e. the direction of the "wave" is the same as the direction of the curve draw_rules_3x3_meander() # the units in the flipped rules of the Meander curve are "backward" draw_rules_3x3_meander(flip = TRUE)
draw_rules_2x2() # the units in the main rules of the Peano curve are vertical draw_rules_3x3_peano() # the units in the flipped rules of the Peano curve are horizontal draw_rules_3x3_peano(flip = TRUE) # the units in the main rules of the Meander curve are "forward" # i.e. the direction of the "wave" is the same as the direction of the curve draw_rules_3x3_meander() # the units in the flipped rules of the Meander curve are "backward" draw_rules_3x3_meander(flip = TRUE)
Seed sequences of the H-curve
H0 H1 H2
H0 H1 H2
An object of class matrix
(inherits from array
) with 4 rows and 2 columns.
An object of class matrix
(inherits from array
) with 16 rows and 2 columns.
An object of class matrix
(inherits from array
) with 16 rows and 2 columns.
The three objects simply contain coordinates of points on the three base H-curves.
Two-column matrices.
H0 draw_multiple_curves(H0, H1, H2, nrow = 1, closed = TRUE)
H0 draw_multiple_curves(H0, H1, H2, nrow = 1, closed = TRUE)
Three dimensional Hilbert curve
hilbert_3d(level = 2L)
hilbert_3d(level = 2L)
level |
The level of the curve. |
There are many forms of 3D Hilbert curve. Here we only implement one specific form.
A three-column matrix of coordinates of points on the 3D Hilbert curve.
Michael Bader. Space-Filling Curves: An Introduction with Applications in Scientific Computing, Springer Science & Business Media, 2012. doi:10.1007/978-3-642-31046-1.
pos = hilbert_3d(2) if(require(rgl) && interactive()) { plot3d(pos, type = "l", lwd = 4, col = 2) }
pos = hilbert_3d(2) if(require(rgl) && interactive()) { plot3d(pos, type = "l", lwd = 4, col = 2) }
Various curves in their standard forms
hilbert_curve(level = 2L, by = "Cpp") moore_curve(level = 2L) beta_omega_curve(level = 2L) peano_curve(level = 2L, pattern = "vvvvvvvvv", by = "Cpp") meander_curve(level = 2L, pattern = "fffffffff", code = rep(1, level)) h_curve(iteration = 2L)
hilbert_curve(level = 2L, by = "Cpp") moore_curve(level = 2L) beta_omega_curve(level = 2L) peano_curve(level = 2L, pattern = "vvvvvvvvv", by = "Cpp") meander_curve(level = 2L, pattern = "fffffffff", code = rep(1, level)) h_curve(iteration = 2L)
level |
Level of the curve. |
by |
Which implementation? Only for the testing purpose. |
pattern |
The orientation of units on level-2, i.e. the orientation of the 9 3x3 units. The value should be a string with 9 letters of "v"/"h" (vertical or horizontal) for the Peano curve, and "f"/"b" (forward or backward) for the Meander curve. The length of the string should be maximal 9. If the length is smaller than 9, the stringis automatically recycled. |
code |
Internally used. |
iteration |
Number of iterations. |
These are just special forms of sfc_2x2()
, sfc_3x3_peano()
, sfc_3x3_meander()
and sfc_h()
.
A two-column matrix of coordinates of points on the curve.
hilbert_curve(2) draw_multiple_curves( hilbert_curve(3), hilbert_curve(4), nrow = 1 ) draw_multiple_curves( moore_curve(3), moore_curve(4), nrow = 1 ) draw_multiple_curves( beta_omega_curve(3), beta_omega_curve(4), nrow = 1 ) draw_multiple_curves( peano_curve(2), peano_curve(3), nrow = 1 ) draw_multiple_curves( peano_curve(3, pattern = "vh"), peano_curve(3, pattern = "vvvhhhvvv"), nrow = 1 ) draw_multiple_curves( meander_curve(2), meander_curve(3), nrow = 1 ) draw_multiple_curves( meander_curve(3, pattern = "fbfbfbfbf"), meander_curve(3, pattern = "bbbbbffff"), nrow = 1 ) draw_multiple_curves( h_curve(1), h_curve(2), nrow = 1, closed = TRUE )
hilbert_curve(2) draw_multiple_curves( hilbert_curve(3), hilbert_curve(4), nrow = 1 ) draw_multiple_curves( moore_curve(3), moore_curve(4), nrow = 1 ) draw_multiple_curves( beta_omega_curve(3), beta_omega_curve(4), nrow = 1 ) draw_multiple_curves( peano_curve(2), peano_curve(3), nrow = 1 ) draw_multiple_curves( peano_curve(3, pattern = "vh"), peano_curve(3, pattern = "vvvhhhvvv"), nrow = 1 ) draw_multiple_curves( meander_curve(2), meander_curve(3), nrow = 1 ) draw_multiple_curves( meander_curve(3, pattern = "fbfbfbfbf"), meander_curve(3, pattern = "bbbbbffff"), nrow = 1 ) draw_multiple_curves( h_curve(1), h_curve(2), nrow = 1, closed = TRUE )
Level-1 unit in the Peano curve and Meander curve
## S4 method for signature 'sfc_3x3_peano' level1_unit_orientation(p) ## S4 method for signature 'sfc_3x3_peano' change_level1_unit_orientation(p, to = c("horizontal", "vertical")) ## S4 method for signature 'sfc_3x3_meander' level1_unit_orientation(p) ## S4 method for signature 'sfc_3x3_meander' change_level1_unit_orientation(p, to = c("forward", "backward"))
## S4 method for signature 'sfc_3x3_peano' level1_unit_orientation(p) ## S4 method for signature 'sfc_3x3_peano' change_level1_unit_orientation(p, to = c("horizontal", "vertical")) ## S4 method for signature 'sfc_3x3_meander' level1_unit_orientation(p) ## S4 method for signature 'sfc_3x3_meander' change_level1_unit_orientation(p, to = c("forward", "backward"))
p |
For |
to |
A string of "vertical/horizontal" (on the |
"vertical" and "horizontal" correspond to the direction of the "long segments" in a Peano curve (see Examples).
level1_unit_orientation()
is normally used inside sfc_apply()
. change_level1_unit_orientation()
changes all level-1 units of a Peano curve or a Meander curve simultaneously.
level1_unit_orientation()
returns "verticalhorizontal" (on the sfc_3x3_peano
object) or "forward/backward" (on the sfc_3x3_meander
object).
change_level1_unit_orientation()
returns an sfc_3x3_peano
or sfc_3x3_meander
object.
p = sfc_3x3_peano("I", 111) # the first level-1 unit level1_unit_orientation(p[1:9, TRUE]) # the fourth level-1 unit level1_unit_orientation(p[1:9 + 27, TRUE]) p2 = change_level1_unit_orientation(p, "horizontal") p3 = change_level1_unit_orientation(p, "vertical") draw_multiple_curves(p, p2, p3, title = c("original", "all horizontal", "all vertical"), nrow = 1) # by default, orientations of all level-1 units in Meander curve are forward p = sfc_3x3_meander("I", 111) level1_unit_orientation(p[1:9, TRUE]) p2 = change_level1_unit_orientation(p, "backward") draw_multiple_curves(p, p2, title = c("all forward", "all backward"), nrow = 1)
p = sfc_3x3_peano("I", 111) # the first level-1 unit level1_unit_orientation(p[1:9, TRUE]) # the fourth level-1 unit level1_unit_orientation(p[1:9 + 27, TRUE]) p2 = change_level1_unit_orientation(p, "horizontal") p3 = change_level1_unit_orientation(p, "vertical") draw_multiple_curves(p, p2, p3, title = c("original", "all horizontal", "all vertical"), nrow = 1) # by default, orientations of all level-1 units in Meander curve are forward p = sfc_3x3_meander("I", 111) level1_unit_orientation(p[1:9, TRUE]) p2 = change_level1_unit_orientation(p, "backward") draw_multiple_curves(p, p2, title = c("all forward", "all backward"), nrow = 1)
Plot segments
plot_segments(x, grid = FALSE, title = FALSE, closed = FALSE, ...)
plot_segments(x, grid = FALSE, title = FALSE, closed = FALSE, ...)
x |
A two-column matrix of coordinates of points. |
grid |
Whether to add grid lines on the plot? |
title |
The value should be |
closed |
Whether the curve is closed? |
... |
Other arguments passed to |
This function is only for a quick demonstration of curves represented as two-column coordinate matrices.
No value is returned.
pos = cbind(c(0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 1, 1), c(1, 2, 2, 3, 3, 2, 2, 1, 1, 0, 0, 1)) plot_segments(pos)
pos = cbind(c(0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 1, 1), c(1, 2, 2, 3, 3, 2, 2, 1, 1, 0, 0, 1)) plot_segments(pos)
Create space-filling curves
sfc_2x2(seed, code = integer(0), rot = 0L) sfc_3x3_peano(seed, code = integer(0), rot = 0L, level = NULL, flip = FALSE) sfc_3x3_meander(seed, code = integer(0), rot = 0L, flip = FALSE)
sfc_2x2(seed, code = integer(0), rot = 0L) sfc_3x3_peano(seed, code = integer(0), rot = 0L, level = NULL, flip = FALSE) sfc_3x3_meander(seed, code = integer(0), rot = 0L, flip = FALSE)
seed |
The seed sequence. In most cases, the seed sequence is a single base pattern, which can be specified as a single letter, then |
code |
A vector of the expansion code. The left side corresponds to the top levels of the curve and the right side corresponds to the bottom level of the curve.
The value can be set as a vector e.g. |
rot |
Rotation of the seed sequence, measured in the polar coordinate system, in degrees. |
level |
Specifically for |
flip |
Whether to use the "flipped" rules? For the Peano curve and the Meander curve, there is also a "fliiped" version
of curve expansion rules. On each level expansion in the Peano curve and the Meander curve, a point expands to nine points in
3x3 grids. Thus the value of |
sfc_2x2()
generates the Hilbert curve from the seed sequence.
sfc_3x3_peano()
generates the Peano curve from the seed sequence.
sfc_3x3_meander()
generates the Meander curve from the seed sequence.
sfc_hilbert()
returns an sfc_2x2
object.
sfc_peano()
returns an sfc_3x3_peano
object.
sfc_meander()
returns an sfc_3x3_meander
object.
These three classes are child classes of sfc_nxn
.
sfc_2x2("I", "111") |> plot() sfc_2x2("I", "111", rot = 90) |> plot() sfc_2x2("IR", "111", rot = 90) |> plot() sfc_3x3_peano("I", "111") |> plot() sfc_3x3_peano("I", "111", flip = c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE)) |> plot() sfc_3x3_peano("IJ", "111") |> plot() sfc_3x3_peano("I", level = 4, flip = function(p) { p@rot %in% c(90, 270) }) |> plot(lwd = 1) level = 4 sfc_3x3_peano("I", level = level, flip = function(p) { if(length(p) == 9^(level-1)) { l = rep(FALSE, length(p)) ind = 1:9^2 + 9^2*rep(c(0, 2, 4, 6, 8), each = 9^2) l[ind] = p@rot[ind] %in% c(90, 270) ind = 1:9^2 + 9^2*rep(c(1, 3, 5, 7), each = 9^2) l[ind] = p@rot[ind] %in% c(0, 180) l } else { rep(FALSE, length(p)) } }) |> plot(lwd = 1) sfc_3x3_meander("I", "111") |> plot() sfc_3x3_meander("I", "111", flip = c(TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE)) |> plot() sfc_3x3_meander("IR", "111") |> plot()
sfc_2x2("I", "111") |> plot() sfc_2x2("I", "111", rot = 90) |> plot() sfc_2x2("IR", "111", rot = 90) |> plot() sfc_3x3_peano("I", "111") |> plot() sfc_3x3_peano("I", "111", flip = c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE)) |> plot() sfc_3x3_peano("IJ", "111") |> plot() sfc_3x3_peano("I", level = 4, flip = function(p) { p@rot %in% c(90, 270) }) |> plot(lwd = 1) level = 4 sfc_3x3_peano("I", level = level, flip = function(p) { if(length(p) == 9^(level-1)) { l = rep(FALSE, length(p)) ind = 1:9^2 + 9^2*rep(c(0, 2, 4, 6, 8), each = 9^2) l[ind] = p@rot[ind] %in% c(90, 270) ind = 1:9^2 + 9^2*rep(c(1, 3, 5, 7), each = 9^2) l[ind] = p@rot[ind] %in% c(0, 180) l } else { rep(FALSE, length(p)) } }) |> plot(lwd = 1) sfc_3x3_meander("I", "111") |> plot() sfc_3x3_meander("I", "111", flip = c(TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE)) |> plot() sfc_3x3_meander("IR", "111") |> plot()
General 3x3 space-filling curves
sfc_3x3_combined(seed, level = 0, rot = 0L, flip = FALSE) ## S4 method for signature 'sfc_3x3_combined' sfc_expand(p, code = NULL, flip = FALSE) draw_rules_3x3_combined(flip = FALSE)
sfc_3x3_combined(seed, level = 0, rot = 0L, flip = FALSE) ## S4 method for signature 'sfc_3x3_combined' sfc_expand(p, code = NULL, flip = FALSE) draw_rules_3x3_combined(flip = FALSE)
seed |
The seed sequence. In most cases, the seed sequence is a single base pattern, which can be specified as a single letter, then |
level |
Level of the curve. Currently it is restricted to an integer no bigger than 5. |
rot |
Rotation of the seed sequence, measured in the polar coordinate system, in degrees. |
flip |
The same setting as in |
p |
An |
code |
Ignore. The traverse codes are selected randomly. |
This type of 3x3 curve uses the combintation of base patterns from both the Peano curve and the Meander curve. On each level, the traverse path is randomly selected.
sfc_3x3_combined()
returns an sfc_3x3_combined
object.
draw_multiple_curves( sfc_3x3_combined("I", level = 3), sfc_3x3_combined("I", level = 3), sfc_3x3_combined("I", level = 3), nrow = 1 ) draw_rules_3x3_combined() draw_rules_3x3_combined(flip = TRUE)
draw_multiple_curves( sfc_3x3_combined("I", level = 3), sfc_3x3_combined("I", level = 3), sfc_3x3_combined("I", level = 3), nrow = 1 ) draw_rules_3x3_combined() draw_rules_3x3_combined(flip = TRUE)
4x4 space-filling curves in meander type
sfc_4x4_meander(seed, code = integer(0), rot = 0L, flip = FALSE, type = 1L) ## S4 method for signature 'sfc_4x4_meander' sfc_expand(p, code, flip = FALSE) draw_rules_4x4_meander(type = 1, flip = FALSE)
sfc_4x4_meander(seed, code = integer(0), rot = 0L, flip = FALSE, type = 1L) ## S4 method for signature 'sfc_4x4_meander' sfc_expand(p, code, flip = FALSE) draw_rules_4x4_meander(type = 1, flip = FALSE)
seed |
The seed sequence. In most cases, the seed sequence is a single base pattern, which can be specified as a single letter, then |
code |
A vector of the expansion code. The left side corresponds to the higher levels (more to the top-level) of the curve and the right side corresponds to the lower level (more to the bottom-level) of the curve.
The value can be set as a vector e.g. |
rot |
Rotation of the seed sequence, measured in the polar coordinate system, in degrees. |
flip |
The same setting as in |
type |
Which type of rules to use? 1 for |
p |
An |
It is an extension of the 3x3 Meander curves to mode 4. For simplicity, it only supports I/R/L
base patterns.
sfc_4x4_meander()
returns an sfc_4x4_meander
object.
draw_multiple_curves( sfc_4x4_meander("I", "11", type = 1), sfc_4x4_meander("I", "12", type = 1), sfc_4x4_meander("I", "11", type = 2), sfc_4x4_meander("I", "12", type = 2), nrow = 2 ) seed = paste(rep(paste0("R", sapply(0:10, function(i) strrep("I", i))), each = 2), collapse="") sfc_4x4_meander(seed, 1) |> plot() draw_rules_4x4_meander(type = 1) draw_rules_4x4_meander(type = 2)
draw_multiple_curves( sfc_4x4_meander("I", "11", type = 1), sfc_4x4_meander("I", "12", type = 1), sfc_4x4_meander("I", "11", type = 2), sfc_4x4_meander("I", "12", type = 2), nrow = 2 ) seed = paste(rep(paste0("R", sapply(0:10, function(i) strrep("I", i))), each = 2), collapse="") sfc_4x4_meander(seed, 1) |> plot() draw_rules_4x4_meander(type = 1) draw_rules_4x4_meander(type = 2)
Apply to every unit in the sfc_nxn curve
## S4 method for signature 'sfc_nxn' sfc_apply(p, depth = 1, fun = function(x) x)
## S4 method for signature 'sfc_nxn' sfc_apply(p, depth = 1, fun = function(x) x)
p |
An |
depth |
An integer between 0 and |
fun |
A function of which the argument |
This function is mainly used to flip subunits on various levels on the curve, thus mainly on the Peano curve and the Meander curve. A depth of 0 corresponds to the complete curve. A depth of 1 corresponds to the nine first-level units, et al.
Currently, sfc_apply()
only works on curves with a single base pattern as the seed.
An sfc_nxn
object.
p = sfc_3x3_peano("I", level = 3) # flip the global curve draw_multiple_curves( p, sfc_apply(p, 0, sfc_flip_unit), nrow = 1 ) # flip all the subunits on depth = 1 draw_multiple_curves( p, sfc_apply(p, 1, sfc_flip_unit), nrow = 1 ) # flip all the subunits on depth = 2 draw_multiple_curves( p, sfc_apply(p, 2, sfc_flip_unit), nrow = 1 ) # flip all level-1 patterns on the Peano curve to horizontal # only works on the lowest subunit, p2 = sfc_apply(p, 2, function(x) { if(level1_unit_orientation(x) == "vertical") { sfc_flip_unit(x) } else { x } }) # then on depth=1, only flip the unit with odd index p3 = sfc_apply(p2, 1, function(x, i) { if(i %% 2 == 1) { sfc_flip_unit(x) } else { x } }) draw_multiple_curves(p2, p3, nrow = 1) # flip all level-1 patterns to vertical p3 = sfc_apply(p, 2, function(x) { if(level1_unit_orientation(x) == "horizontal") { sfc_flip_unit(x) } else { x } }) draw_multiple_curves(p, p3, nrow = 1)
p = sfc_3x3_peano("I", level = 3) # flip the global curve draw_multiple_curves( p, sfc_apply(p, 0, sfc_flip_unit), nrow = 1 ) # flip all the subunits on depth = 1 draw_multiple_curves( p, sfc_apply(p, 1, sfc_flip_unit), nrow = 1 ) # flip all the subunits on depth = 2 draw_multiple_curves( p, sfc_apply(p, 2, sfc_flip_unit), nrow = 1 ) # flip all level-1 patterns on the Peano curve to horizontal # only works on the lowest subunit, p2 = sfc_apply(p, 2, function(x) { if(level1_unit_orientation(x) == "vertical") { sfc_flip_unit(x) } else { x } }) # then on depth=1, only flip the unit with odd index p3 = sfc_apply(p2, 1, function(x, i) { if(i %% 2 == 1) { sfc_flip_unit(x) } else { x } }) draw_multiple_curves(p2, p3, nrow = 1) # flip all level-1 patterns to vertical p3 = sfc_apply(p, 2, function(x) { if(level1_unit_orientation(x) == "horizontal") { sfc_flip_unit(x) } else { x } }) draw_multiple_curves(p, p3, nrow = 1)
Constructor of the sfc_base class
sfc_base( letter, in_direction, out_direction, grob = NULL, primary = TRUE, open = TRUE )
sfc_base( letter, in_direction, out_direction, grob = NULL, primary = TRUE, open = TRUE )
letter |
A single letter to represent the base pattern. |
in_direction |
The direction of the segment that enters the point, measured in the polar coordinate system, in degrees. |
out_direction |
The direction of the segment that leaves the point, measured in the polar coordinate system, in degrees. |
grob |
A |
primary |
Currently, going forward, turning left and turning right can be set as primary base patterns because other high-level patterns can be built from them. |
open |
Can the base pattern be connected to other base patterns? |
The "base pattern" is designed not only for single point but also for combination of points that form a "base curve". However, currently, it is fixed to the single point base pattern.
Currently, this package supports 2x2 and 3x3 space-filling curves that fills grids in 2D space constructed by the Gaussian integers. And when the curve expands, we only allow the segments to go forward, backward, left and right. Thus there are the following base patterns pre-defined in this package:
BASE_R
: turn right.
BASE_L
: turn left.
BASE_U
: go backward.
BASE_B
: leave the start point where the start point is closed.
BASE_D
: leave the start point where the start point is closed.
BASE_P
: return to the end point where the end point is closed.
BASE_Q
: return to the end point where the end point is closed.
BASE_C
: self-closed.
The base pattern determines the final form of the curve.
An sfc_base
object.
BASE_I
BASE_I
Expand a sequence
## S4 method for signature 'sfc_rules,sfc_nxn' sfc_expand_by_rules(p, seq, code = 1L, flip = FALSE, by = "Cpp") ## S4 method for signature 'sfc_rules,factor' sfc_expand_by_rules(p, seq, code = 1L, flip = FALSE, by = "Cpp") ## S4 method for signature 'sfc_rules,character' sfc_expand_by_rules(p, seq, code = 1L, flip = FALSE, by = "Cpp")
## S4 method for signature 'sfc_rules,sfc_nxn' sfc_expand_by_rules(p, seq, code = 1L, flip = FALSE, by = "Cpp") ## S4 method for signature 'sfc_rules,factor' sfc_expand_by_rules(p, seq, code = 1L, flip = FALSE, by = "Cpp") ## S4 method for signature 'sfc_rules,character' sfc_expand_by_rules(p, seq, code = 1L, flip = FALSE, by = "Cpp")
p |
An |
seq |
An |
code |
The expansion code. |
flip |
For the Peano curve and the Meander curves, each unit can be flipped without affecting other parts in the curve. This argument
controls whether to flip the unit. Since currently it only works on the Peano curve and the Meander curve, |
by |
Which implementation? Only for the testing purpose. |
If seq
is an sfc_nxn
object, the function also returns an "expanded" sfc_nxn
object. Or else it returns an sfc_sequence
object.
sfc_expand_by_rules(SFC_RULES_2x2, sfc_2x2("I"))
sfc_expand_by_rules(SFC_RULES_2x2, sfc_2x2("I"))
Expand the curve to the next level
## S4 method for signature 'sfc_2x2' sfc_expand(p, code, flip = FALSE) ## S4 method for signature 'sfc_3x3_peano' sfc_expand(p, code = 1, flip = FALSE) ## S4 method for signature 'sfc_3x3_meander' sfc_expand(p, code, flip = FALSE) ## S3 method for class 'sfc_nxn' e1 | e2
## S4 method for signature 'sfc_2x2' sfc_expand(p, code, flip = FALSE) ## S4 method for signature 'sfc_3x3_peano' sfc_expand(p, code = 1, flip = FALSE) ## S4 method for signature 'sfc_3x3_meander' sfc_expand(p, code, flip = FALSE) ## S3 method for class 'sfc_nxn' e1 | e2
p |
An |
code |
Expansion code, a single integer. |
flip |
Whethe to flip level-1 units? The value should be a logical vector of length one or the same as the length of |
e1 |
An |
e2 |
Expansion codes. |
For the Hilbert curve and Meander curve, as long as the expansion code of the first base pattern in the sequence is determinted,
the expansion codes for other base patterns in the sequence are all determined. For the Peano curve, since
there is only one traverse path on any level, code
is ignored.
These functions are mainly used internally.
An object in the same class as the input.
p = sfc_2x2("I", 11) sfc_expand(p, 2) # I|211 p = sfc_3x3_peano("I", 11) sfc_expand(p, 2) # I|211 p = sfc_3x3_meander("I", 11) sfc_expand(p, 2) # I|211 p = sfc_2x2("I") p|1 p|121 p|"121" p|1|1|1
p = sfc_2x2("I", 11) sfc_expand(p, 2) # I|211 p = sfc_3x3_peano("I", 11) sfc_expand(p, 2) # I|211 p = sfc_3x3_meander("I", 11) sfc_expand(p, 2) # I|211 p = sfc_2x2("I") p|1 p|121 p|"121" p|1|1|1
Generate a nxn curve based on expansion rules
sfc_generator( rules, name, envir = topenv(parent.frame()), flippable = FALSE, verbose = TRUE )
sfc_generator( rules, name, envir = topenv(parent.frame()), flippable = FALSE, verbose = TRUE )
rules |
An |
name |
Name of the curve. The name will be used for the functions that will be generated. |
envir |
Environment where the functions are exported. |
flippable |
Whether |
verbose |
Whether to print messages? |
Two functions will be exported:
sfc_{name}()
draw_rules_{name}()
For the simplicity, flipping is not supported yet.
No value is returned.
UNIVERSE_4x4_PEANO = c("I", "R", "L") RULES_4x4_PEANO = list() RULES_4x4_PEANO[["I"]][[1]] = sfc_unit("RIILLIIRRIILLIIR", rot = 0, universe = UNIVERSE_4x4_PEANO) RULES_4x4_PEANO[["I"]][[2]] = sfc_hflip(RULES_4x4_PEANO[["I"]][[1]]) RULES_4x4_PEANO[["R"]][[1]] = sfc_unit("IIIRRIILLIIRRIIL", rot = 0, universe = UNIVERSE_4x4_PEANO) RULES_4x4_PEANO[["R"]][[2]] = sfc_rotate(sfc_unit("LIIRRIILLIIRRIII", rot = 270, universe = UNIVERSE_4x4_PEANO), 90) RULES_4x4_PEANO[["L"]][[1]] = sfc_hflip(RULES_4x4_PEANO[["R"]][[2]]) RULES_4x4_PEANO[["L"]][[2]] = sfc_hflip(RULES_4x4_PEANO[["R"]][[1]]) SFC_RULES_4x4_PEANO = sfc_rules(rules = RULES_4x4_PEANO, name = "Peano 4x4", bases = BASE_LIST[UNIVERSE_4x4_PEANO]) sfc_generator(SFC_RULES_4x4_PEANO, "4x4_peano") draw_rules_4x4_peano() sfc_4x4_peano("I", 111) |> plot()
UNIVERSE_4x4_PEANO = c("I", "R", "L") RULES_4x4_PEANO = list() RULES_4x4_PEANO[["I"]][[1]] = sfc_unit("RIILLIIRRIILLIIR", rot = 0, universe = UNIVERSE_4x4_PEANO) RULES_4x4_PEANO[["I"]][[2]] = sfc_hflip(RULES_4x4_PEANO[["I"]][[1]]) RULES_4x4_PEANO[["R"]][[1]] = sfc_unit("IIIRRIILLIIRRIIL", rot = 0, universe = UNIVERSE_4x4_PEANO) RULES_4x4_PEANO[["R"]][[2]] = sfc_rotate(sfc_unit("LIIRRIILLIIRRIII", rot = 270, universe = UNIVERSE_4x4_PEANO), 90) RULES_4x4_PEANO[["L"]][[1]] = sfc_hflip(RULES_4x4_PEANO[["R"]][[2]]) RULES_4x4_PEANO[["L"]][[2]] = sfc_hflip(RULES_4x4_PEANO[["R"]][[1]]) SFC_RULES_4x4_PEANO = sfc_rules(rules = RULES_4x4_PEANO, name = "Peano 4x4", bases = BASE_LIST[UNIVERSE_4x4_PEANO]) sfc_generator(SFC_RULES_4x4_PEANO, "4x4_peano") draw_rules_4x4_peano() sfc_4x4_peano("I", 111) |> plot()
The graphics object
## S4 method for signature 'sfc_base' sfc_grob(p) ## S4 method for signature 'sfc_sequence' sfc_grob( p, bases = NULL, extend = FALSE, title = FALSE, closed = FALSE, lwd = 4, col = NULL, ... ) ## S3 method for class 'sfc_sequence' plot( x, bases = NULL, grid = FALSE, extend = FALSE, title = FALSE, closed = FALSE, ... ) ## S3 method for class 'grob_sfc_sequence' plot(x, grid = FALSE, ...) ## S4 method for signature 'sfc_nxn' sfc_grob( p, bases = p@rules@bases, extend = FALSE, title = FALSE, closed = FALSE, ... ) ## S3 method for class 'sfc_nxn' plot(x, grid = FALSE, extend = FALSE, title = FALSE, closed = FALSE, ...) ## S4 method for signature 'matrix' sfc_grob(p, title = NULL, closed = FALSE, lwd = 4, col = NULL, ...)
## S4 method for signature 'sfc_base' sfc_grob(p) ## S4 method for signature 'sfc_sequence' sfc_grob( p, bases = NULL, extend = FALSE, title = FALSE, closed = FALSE, lwd = 4, col = NULL, ... ) ## S3 method for class 'sfc_sequence' plot( x, bases = NULL, grid = FALSE, extend = FALSE, title = FALSE, closed = FALSE, ... ) ## S3 method for class 'grob_sfc_sequence' plot(x, grid = FALSE, ...) ## S4 method for signature 'sfc_nxn' sfc_grob( p, bases = p@rules@bases, extend = FALSE, title = FALSE, closed = FALSE, ... ) ## S3 method for class 'sfc_nxn' plot(x, grid = FALSE, extend = FALSE, title = FALSE, closed = FALSE, ...) ## S4 method for signature 'matrix' sfc_grob(p, title = NULL, closed = FALSE, lwd = 4, col = NULL, ...)
p |
The corresponding object. |
bases |
A list of base patterns, normally |
extend |
Whether to add the entry and exit segments? |
title |
Whether to add title on the top of the plot? The title is constructed in the form of |
closed |
Whether the curve is closed? |
lwd |
Line width. |
col |
Color for segments. If the value is |
... |
Other arguments passed to |
x |
The corresponding object. |
grid |
Whether to add grid lines on the plot? |
If p
is an sfc_sequence
and p
contains base patterns defined in "I/J/R/L/U/B/D/P/Q/C"
,
the default BASE_LIST
is automatically used for bases
. If p
is an sfc_nxn
object, bases
is already stored in p
and it is passed to this function automatically.
A grid::grob()
object.
sfc_grob(BASE_I) plot(sfc_2x2("I", "11")) plot(sfc_2x2("I", "11"), extend = TRUE, title = TRUE, grid = TRUE) plot(sfc_sequence("IIIRRR"))
sfc_grob(BASE_I) plot(sfc_2x2("I", "11")) plot(sfc_2x2("I", "11"), extend = TRUE, title = TRUE, grid = TRUE) plot(sfc_sequence("IIIRRR"))
H-curve
sfc_h(h, iteration = 1, connect = c("h", "v"), random = FALSE) expand_h(h1, h2 = h1, h3 = h1, h4 = h1, connect = "hhhh")
sfc_h(h, iteration = 1, connect = c("h", "v"), random = FALSE) expand_h(h1, h2 = h1, h3 = h1, h4 = h1, connect = "hhhh")
h |
The seed of the H-curve. The value should be one of |
iteration |
Number of iterations. |
connect |
How the four subunits are connected to form the H-curve on the next level. See Details. |
random |
Whether to generate subunits randomly on each iteration. |
h1 |
The first subunit on the bottom left. |
h2 |
The second subunit on the top left. |
h3 |
The third subunit on the top right. |
h4 |
The fourth subunit on the bottom right. |
An H-curve on level k is composed with four subunits on level k-1. If we number the four subunits in the following order:
2 3 1 4
where subunit 1 connects to subunit 2, subunit 2 connects to subunit 3, et al., and e.g. subunit 1 connects to subunit 2 via its toprigth corner. Since H-curve can be thought of as a closed curve, to, e.g. let subunit 1 to connect to subunit 2, its topright corner needs to be opened. There are two segments on subunit 1 that can be removed/opened: the horizontal segment and the vertical segment on the topright corner in subunit 1.
In this way, in sfc_h()
, the argument connect
only accepts a single value of "h"
or "v"
where the types of segments for
all the four subunits are the same, i.e. whether all the horizontal corner segments are opened or whether all the vertical corner
segments are opened. In expand_h()
, the argument connect
can be set to a string with four letters or a vector of length four where the type of segments of the
four subunits can be set separately.
In the random mode, each subunit is generated randomly, the type of the open segment is choosen randomly, also each subunit has a probability of 0.5 to rotate by 90 degrees.
A two-column matrix of coordinates of points on the curve.
draw_multiple_curves( sfc_h(H0, iteration = 2), sfc_h(H2, iteration = 2), closed = TRUE, nrow =1 ) draw_multiple_curves( sfc_h(H1, iteration = 3, random = TRUE), sfc_h(H1, iteration = 3, random = TRUE), closed = TRUE, nrow = 1 ) draw_multiple_curves( expand_h(H0, connect = "hvvh"), expand_h(H1, connect = "vvhh"), closed = TRUE, nrow = 1 ) # set the four subunits separately h1 = expand_h(H0, connect = "hhhh") h2 = expand_h(H0, connect = "vvvv") h3 = expand_h(H0, connect = "hvhv") h4 = expand_h(H0, connect = "hvvh") expand_h(h1, h2, h3, h4, connect = "vhvh") |> plot_segments(closed = TRUE) fun = function(h, iteration) { for(i in 1:iteration) h = expand_h(h, connect = "vhvh") h } fun(H0, 4) |> plot_segments(closed = TRUE)
draw_multiple_curves( sfc_h(H0, iteration = 2), sfc_h(H2, iteration = 2), closed = TRUE, nrow =1 ) draw_multiple_curves( sfc_h(H1, iteration = 3, random = TRUE), sfc_h(H1, iteration = 3, random = TRUE), closed = TRUE, nrow = 1 ) draw_multiple_curves( expand_h(H0, connect = "hvvh"), expand_h(H1, connect = "vvhh"), closed = TRUE, nrow = 1 ) # set the four subunits separately h1 = expand_h(H0, connect = "hhhh") h2 = expand_h(H0, connect = "vvvv") h3 = expand_h(H0, connect = "hvhv") h4 = expand_h(H0, connect = "hvvh") expand_h(h1, h2, h3, h4, connect = "vhvh") |> plot_segments(closed = TRUE) fun = function(h, iteration) { for(i in 1:iteration) h = expand_h(h, connect = "vhvh") h } fun(H0, 4) |> plot_segments(closed = TRUE)
Whether two sfc_sequence objects are compatible
## S4 method for signature 'sfc_sequence,sfc_sequence' sfc_is_compatible(p1, p2, strict = TRUE) ## S4 method for signature 'sfc_sequence,sfc_rules' sfc_is_compatible(p1, p2) ## S4 method for signature 'sfc_rules,sfc_sequence' sfc_is_compatible(p1, p2)
## S4 method for signature 'sfc_sequence,sfc_sequence' sfc_is_compatible(p1, p2, strict = TRUE) ## S4 method for signature 'sfc_sequence,sfc_rules' sfc_is_compatible(p1, p2) ## S4 method for signature 'sfc_rules,sfc_sequence' sfc_is_compatible(p1, p2)
p1 |
An |
p2 |
An |
strict |
|
The function compares whether the two universe base pattern sets are identical.
If strict
is TRUE
, the order of the two universe sets should also be the same.
If strict
is FALSE
, the universe set of p2
can be a subset of the universe set of p1
.
A logical scalar.
p1 = sfc_2x2("I") p2 = sfc_2x2("R") sfc_is_compatible(p1, p2) p1 = sfc_2x2("I") p2 = sfc_sequence("R") sfc_is_compatible(p1, p2) sfc_is_compatible(p1, p2, strict = FALSE) p1 = sfc_sequence("ABC") p2 = sfc_sequence("DEF") sfc_is_compatible(p1, p2)
p1 = sfc_2x2("I") p2 = sfc_2x2("R") sfc_is_compatible(p1, p2) p1 = sfc_2x2("I") p2 = sfc_sequence("R") sfc_is_compatible(p1, p2) sfc_is_compatible(p1, p2, strict = FALSE) p1 = sfc_sequence("ABC") p2 = sfc_sequence("DEF") sfc_is_compatible(p1, p2)
The level of the curve
## S4 method for signature 'sfc_nxn' sfc_level(p)
## S4 method for signature 'sfc_nxn' sfc_level(p)
p |
An |
An integer.
p = sfc_2x2("I", "11") sfc_level(p) p = sfc_2x2("I", "1111") sfc_level(p)
p = sfc_2x2("I", "11") sfc_level(p) p = sfc_2x2("I", "1111") sfc_level(p)
The mode of the curve
## S4 method for signature 'sfc_nxn' sfc_mode(p) ## S4 method for signature 'sfc_rules' sfc_mode(p)
## S4 method for signature 'sfc_nxn' sfc_mode(p) ## S4 method for signature 'sfc_rules' sfc_mode(p)
p |
The corresponding object. |
An integer.
p = sfc_2x2("I", "1") sfc_mode(p) p = sfc_3x3_peano("I", "1") sfc_mode(p) sfc_mode(SFC_RULES_2x2) sfc_mode(SFC_RULES_3x3_PEANO)
p = sfc_2x2("I", "1") sfc_mode(p) p = sfc_3x3_peano("I", "1") sfc_mode(p) sfc_mode(SFC_RULES_2x2) sfc_mode(SFC_RULES_3x3_PEANO)
The previous and the next point
## S4 method for signature 'sfc_base' sfc_previous_point(p, x, rot, length = 1) ## S4 method for signature 'sfc_base' sfc_next_point(p, x, rot, length = 1)
## S4 method for signature 'sfc_base' sfc_previous_point(p, x, rot, length = 1) ## S4 method for signature 'sfc_base' sfc_next_point(p, x, rot, length = 1)
p |
An |
x |
The coordinate of the current point. |
rot |
Rotation of the current point. |
length |
Length of the segment between the previous/next point and the current point. |
A vector of length two.
sfc_previous_point(BASE_R, c(0, 0), 0) sfc_previous_point(BASE_R, c(0, 0), 90) sfc_previous_point(BASE_R, c(0, 0), 180) sfc_previous_point(BASE_R, c(1, 0), 0) sfc_previous_point(BASE_R, c(1, 0), 90) sfc_previous_point(BASE_R, c(1, 0), 180) sfc_next_point(BASE_R, c(0, 0), 0) sfc_next_point(BASE_R, c(0, 0), 90) sfc_next_point(BASE_R, c(0, 0), 180) sfc_next_point(BASE_R, c(1, 0), 0) sfc_next_point(BASE_R, c(1, 0), 90) sfc_next_point(BASE_R, c(1, 0), 180)
sfc_previous_point(BASE_R, c(0, 0), 0) sfc_previous_point(BASE_R, c(0, 0), 90) sfc_previous_point(BASE_R, c(0, 0), 180) sfc_previous_point(BASE_R, c(1, 0), 0) sfc_previous_point(BASE_R, c(1, 0), 90) sfc_previous_point(BASE_R, c(1, 0), 180) sfc_next_point(BASE_R, c(0, 0), 0) sfc_next_point(BASE_R, c(0, 0), 90) sfc_next_point(BASE_R, c(0, 0), 180) sfc_next_point(BASE_R, c(1, 0), 0) sfc_next_point(BASE_R, c(1, 0), 90) sfc_next_point(BASE_R, c(1, 0), 180)
Reduce a curve
## S4 method for signature 'sfc_nxn' sfc_reduce(p, to = sfc_level(p) - 1) ## S4 method for signature 'matrix' sfc_reduce(p, to = level - 1, mode = NULL) add_base_structure(gb, level = 1) mark_local_units(gb, level = 1, k = 5)
## S4 method for signature 'sfc_nxn' sfc_reduce(p, to = sfc_level(p) - 1) ## S4 method for signature 'matrix' sfc_reduce(p, to = level - 1, mode = NULL) add_base_structure(gb, level = 1) mark_local_units(gb, level = 1, k = 5)
p |
An |
to |
Which level to reduce to? Value should be between 1 and |
mode |
Mode of the curve. |
gb |
A |
level |
The level of the unit. |
k |
Number of subunits |
The reduction is applied on the coordinates of points.
add_base_structure()
adds a base structure on a certain level to the curve.
mark_local_units()
highlights k
subunits on level level
. k
subunits are picked
randomly.
A two-column matrix of coordinates of the reduced curve.
p = sfc_3x3_peano("I", level = 3) draw_multiple_curves( p, sfc_reduce(p, 2), sfc_reduce(p, 1), nrow = 1) p = hilbert_curve(level = 4) draw_multiple_curves( p, sfc_reduce(p, 3), sfc_reduce(p, 2), nrow = 1) p = hilbert_curve(3) draw_multiple_curves( add_base_structure(p, level = 1), add_base_structure(p, level = 2), nrow = 1 ) p = hilbert_curve(4) draw_multiple_curves( mark_local_units(p, level = 1), mark_local_units(p, level = 2), nrow = 1 )
p = sfc_3x3_peano("I", level = 3) draw_multiple_curves( p, sfc_reduce(p, 2), sfc_reduce(p, 1), nrow = 1) p = hilbert_curve(level = 4) draw_multiple_curves( p, sfc_reduce(p, 3), sfc_reduce(p, 2), nrow = 1) p = hilbert_curve(3) draw_multiple_curves( add_base_structure(p, level = 1), add_base_structure(p, level = 2), nrow = 1 ) p = hilbert_curve(4) draw_multiple_curves( mark_local_units(p, level = 1), mark_local_units(p, level = 2), nrow = 1 )
Transformations of a sequence
## S4 method for signature 'sfc_sequence' sfc_rotate(p, rot) ## S3 method for class 'sfc_sequence' e1 ^ e2 ## S4 method for signature 'sfc_sequence' sfc_hflip(p, fix_ends = FALSE, bases = NULL) ## S4 method for signature 'sfc_sequence' sfc_vflip(p, fix_ends = FALSE, bases = NULL) ## S4 method for signature 'sfc_sequence' sfc_dflip(p, slop = 1L, fix_ends = FALSE, bases = NULL) ## S4 method for signature 'sfc_sequence' sfc_reverse(p) ## S3 method for class 'sfc_sequence' rev(x)
## S4 method for signature 'sfc_sequence' sfc_rotate(p, rot) ## S3 method for class 'sfc_sequence' e1 ^ e2 ## S4 method for signature 'sfc_sequence' sfc_hflip(p, fix_ends = FALSE, bases = NULL) ## S4 method for signature 'sfc_sequence' sfc_vflip(p, fix_ends = FALSE, bases = NULL) ## S4 method for signature 'sfc_sequence' sfc_dflip(p, slop = 1L, fix_ends = FALSE, bases = NULL) ## S4 method for signature 'sfc_sequence' sfc_reverse(p) ## S3 method for class 'sfc_sequence' rev(x)
p , e1
|
An |
rot , e2
|
Rotation measured in the polar coordinate system, in degrees. |
fix_ends |
By default, the curve is flipped as a complete whole, which means, the associated entry and exit directions of the curve
is also adjusted accordingly. When flipping subunits in a curve, e.g. level-1 subunits in a Peano curve, we want the
entry and exit direction of the subunit not changed so that the subunits are still connected in the curve after the flipping. In this
case, |
bases |
A list of base patterns, consider to use |
slop |
Slop of the diagonal. Value can only be 1 or -1. |
x |
An |
sfc_rotate()
and ^()
rotate each base pattern.
sfc_hflip()
flips a sequence horizontally.
sfc_vflip()
flips a sequence vertically.
sfc_dflip()
flips a sequence against a diagonal line (with slop 1 or -1).
An sfc_sequence
object.
p = sfc_3x3_meander("R", 2, rot = -90) draw_multiple_curves( p, sfc_hflip(p), sfc_hflip(p, fix_ends = TRUE), nrow = 1) p = sfc_3x3_meander("L", 2, rot = -90) draw_multiple_curves( p, sfc_vflip(p), sfc_vflip(p, fix_ends = TRUE), nrow = 1) p = sfc_3x3_peano("I", 2) draw_multiple_curves( p, sfc_dflip(p, 1), sfc_dflip(p, 1, fix_ends = TRUE), nrow = 1)
p = sfc_3x3_meander("R", 2, rot = -90) draw_multiple_curves( p, sfc_hflip(p), sfc_hflip(p, fix_ends = TRUE), nrow = 1) p = sfc_3x3_meander("L", 2, rot = -90) draw_multiple_curves( p, sfc_vflip(p), sfc_vflip(p, fix_ends = TRUE), nrow = 1) p = sfc_3x3_peano("I", 2) draw_multiple_curves( p, sfc_dflip(p, 1), sfc_dflip(p, 1, fix_ends = TRUE), nrow = 1)
Constructor of the sfc_rules class
sfc_rules(rules, bases, flip = list(), name = "sfc_rules")
sfc_rules(rules, bases, flip = list(), name = "sfc_rules")
rules |
A list of rules. |
bases |
A list of base patterns. |
flip |
A list of rules. They are "flipped" version of |
name |
A self-defined string. |
It is mainly used internally.
rules
is a two-level list. It is in a format of rules[[ base ]][[ expansion_code ]] = sfc_unit()
.
In the following example where we define the expansion rules for the 2x2 curve:
UNIVERSE_2x2 = c("I", "R", "L", "U", "B", "D", "P", "Q", "C") RULES_2x2 = list() RULES_2x2[["I"]][[1]] = sfc_unit(c("R", "L", "L", "R"), rot = 0, universe = UNIVERSE_2x2)
I
is the level-0 base pattern, [[1]]
corresponds to the first form of expansion to level-1, and the value
assigned is a sfc_unit()
object which is basically a list of base patterns.
Then we also need to provide the base patterns which define how to extend the curve. The list of base patterns
is assigned to the bases
argument. In the same example, we set bases
as:
list("I" = BASE_I, "R" = BASE_R, "L" = BASE_L, "U" = BASE_U, ...)
where e.g. BASE_I
is a pre-defined base pattern in the sfc_base
class.
There are the following pre-defined rules:
Check https://github.com/jokergoo/sfcurve/blob/master/R/zz_global.R to see how these pre-defined rules are constructed.
An sfc_rules
object.
A list of pre-defined expansion rules for different curves.
SFC_RULES_2x2 SFC_RULES_3x3_PEANO SFC_RULES_3x3_MEANDER SFC_RULES_3x3_COMBINED SFC_RULES_4x4_MEANDER_1 SFC_RULES_4x4_MEANDER_2
SFC_RULES_2x2 SFC_RULES_3x3_PEANO SFC_RULES_3x3_MEANDER SFC_RULES_3x3_COMBINED SFC_RULES_4x4_MEANDER_1 SFC_RULES_4x4_MEANDER_2
An object of class sfc_rules
of length 1.
An object of class sfc_rules
of length 1.
An object of class sfc_rules
of length 1.
An object of class sfc_rules
of length 1.
An object of class sfc_rules
of length 1.
An object of class sfc_rules
of length 1.
SFC_RULES_3x3_PEANO
, SFC_RULES_3x3_MEANDER
and SFC_RULES_3x3_COMBINED
, SFC_RULES_MEANDER_4x4_1
, SFC_RULES_MEANDER_4x4_2
also contain the "flipped" expansion rules.
SFC_RULES_3x3_COMBINED
is a combination of SFC_RULES_3x3_PEANO
and SFC_RULES_3x3_MEANDER
where
in SFC_RULES_3x3_PEANO
, J
is replaced by its original pattern I
.
SFC_RULES_4x4_MEANDER_1
and SFC_RULES_4x4_MEANDER_2
are extension rules of Meander curves (3x3)
on the 4x4 mode It is only for the demonstration purpose, thus only I/R/L
are supported.
sfc_rules
objects.
SFC_RULES_2x2 SFC_RULES_3x3_PEANO SFC_RULES_3x3_MEANDER SFC_RULES_3x3_COMBINED SFC_RULES_4x4_MEANDER_1 SFC_RULES_4x4_MEANDER_2
SFC_RULES_2x2 SFC_RULES_3x3_PEANO SFC_RULES_3x3_MEANDER SFC_RULES_3x3_COMBINED SFC_RULES_4x4_MEANDER_1 SFC_RULES_4x4_MEANDER_2
Coordinates of the points on the curve
## S4 method for signature 'sfc_nxn' sfc_segments(p, bases = p@rules@bases, start = c(0, 0), ...) ## S4 method for signature 'sfc_sequence' sfc_segments(p, bases = NULL, start = c(0, 0), by = "Cpp")
## S4 method for signature 'sfc_nxn' sfc_segments(p, bases = p@rules@bases, start = c(0, 0), ...) ## S4 method for signature 'sfc_sequence' sfc_segments(p, bases = NULL, start = c(0, 0), by = "Cpp")
p |
An |
bases |
A list of base patterns, consider to use |
start |
Coordinate of the start point. |
... |
Other argument. |
by |
Which implementation? Only for the testing purpose. |
For the sfc_segments()
on the sfc_sequence
object, if bases
is not set,
it uses BASE_LIST
internally. Make sure the sequence only contains the pre-defined base patterns.
A two-column matrix of coordinates of points on the curve.
p = sfc_2x2("I", "11") loc = sfc_segments(p) plot(loc, type = "l", asp = 1)
p = sfc_2x2("I", "11") loc = sfc_segments(p) plot(loc, type = "l", asp = 1)
Constructor of the sfc_sequence class
sfc_sequence(seq, rot = 0L, universe = NULL) sfc_seed(seq, rot = 0L, universe = NULL) sfc_unit(seq, rot = 0L, universe = NULL)
sfc_sequence(seq, rot = 0L, universe = NULL) sfc_seed(seq, rot = 0L, universe = NULL) sfc_unit(seq, rot = 0L, universe = NULL)
seq |
A sequence of base patterns. The value can be a vector of letters or a single string. |
rot |
The corresponding rotations of base patterns. If it has length one and the sequence contains R/L/I (right/left/forward),
|
universe |
The universe of base patterns. A vector of letters. |
This funtion is very low-level. Normally, users do not need to directly use this constructor.
sfc_seed
class is the same as the sfc_sequence
class. It is used specifically as the "seed sequence"
when generating the curves.
sfc_unit
class also inherits the sfc_sequence
class but has one additionally slot: corner
.
It is used specifically when defining the expansion rules.
An sfc_sequence
object.
sfc_sequence("ABCD", rot = c(0, 90, 180, 270), universe = c("A", "B", "C", "D"))
sfc_sequence("ABCD", rot = c(0, 90, 180, 270), universe = c("A", "B", "C", "D"))
Shape of the curve
## S4 method for signature 'sfc_2x2' sfc_shape(p) all_2x2_shapes(level = 2) ## S4 method for signature 'sfc_3x3_peano' sfc_shape(p) all_3x3_peano_shapes(level = 2) ## S4 method for signature 'sfc_3x3_meander' sfc_shape(p) all_3x3_meander_shapes(level = 2)
## S4 method for signature 'sfc_2x2' sfc_shape(p) all_2x2_shapes(level = 2) ## S4 method for signature 'sfc_3x3_peano' sfc_shape(p) all_3x3_peano_shapes(level = 2) ## S4 method for signature 'sfc_3x3_meander' sfc_shape(p) all_3x3_meander_shapes(level = 2)
p |
An |
level |
Level of the 2x2 curve. |
The shape of the curve is defined as a form of the curve without considering entry/exit directions, rotation, flipping (reflection) nor reversing.
The process of selecting the shape segment of the curve denoted as P
is:
The entry-point should locate in the bottom left subunit and the exit-point should
locate in the bottom right subunit. We try the four rotations (0, 90, 180, 270), and
the four rotations on the horizontally flipped curve. Once we find the transformed curve
that satisfies this criterion, we name it as P2
.
We also generate P3
which is a horizontally flipped version of rev(P2)
.
We compare the first point p
of P2
and P3
, and select the one whose p
has the smaller
x-coordinate (i.e. more to the left of the curve). If the x-coordinates of p
are the same in
P2
and P3
, we select the one whose p
has the smaller y-coordinate.
The process of selecting the shape segment of the curve denoted as P
is:
The entry-point should locate in the bottom left subunit and the exit-point should
locate in the top right subunit. We try the four rotations (0, 90, 180, 270). Once we find the transformed curve
that satisfies this criterion, we name it as P2
.
We also generate P3
which is a 180 degrees rotation on the reversed P2
, P4
which is a diagonal flip with slop of 1 on P2
and P5
which is a diagonal flip with slop of 1 on P3
.
We calculate the "UID" of P(2-5)
and pick the one with the smallest UID as the final curve.
The UID of a 3x3 Peano curve is based on the hierarchical indices of the units on it. The hierarchy of the Peano curve is traversed in a depth-first manner. On each node, the orientation of the corresponding unit is calculated where vertical is 1 and horizontal is 2. The digits are concatenated into a long string.
all_3x3_peano_shapes()
only calculates all shapes for Peano curve on level 2.
all_3x3_meander_shapes()
only considers the Meander curve with all subunits on all levels in forward orientation.
sfc_shape()
returns a two-column data frame of the xy-coordinates of the shape curve.
all_2x2_shapes()
returns a list of n
two-column data frames where each data frame corresponds to
the xy-coordnates of the corresponding shape curve.
p1 = sfc_2x2("I", 11) p2 = sfc_2x2("R", 22) draw_multiple_curves( p1, p2, sfc_shape(p1), sfc_shape(p2), col = "black") sl = all_2x2_shapes(2) draw_multiple_curves(list = sl, lwd = 2, col = "black") sl = all_2x2_shapes(3) draw_multiple_curves(list = sl, lwd = 2, col = "black") p = sfc_3x3_peano("I", 11) draw_multiple_curves( p, sfc_dflip(p), sfc_shape(p), sfc_shape(sfc_dflip(p)), col = "black") sl = all_3x3_peano_shapes() length(sl) # the first 8 shapes draw_multiple_curves(sl[1:8], col = "black") sl = all_3x3_meander_shapes(2) draw_multiple_curves(list = sl, lwd = 2, col = "black")
p1 = sfc_2x2("I", 11) p2 = sfc_2x2("R", 22) draw_multiple_curves( p1, p2, sfc_shape(p1), sfc_shape(p2), col = "black") sl = all_2x2_shapes(2) draw_multiple_curves(list = sl, lwd = 2, col = "black") sl = all_2x2_shapes(3) draw_multiple_curves(list = sl, lwd = 2, col = "black") p = sfc_3x3_peano("I", 11) draw_multiple_curves( p, sfc_dflip(p), sfc_shape(p), sfc_shape(sfc_dflip(p)), col = "black") sl = all_3x3_peano_shapes() length(sl) # the first 8 shapes draw_multiple_curves(sl[1:8], col = "black") sl = all_3x3_meander_shapes(2) draw_multiple_curves(list = sl, lwd = 2, col = "black")
The universe base pattern set
## S4 method for signature 'sfc_rules' sfc_universe(p) ## S4 method for signature 'sfc_sequence' sfc_universe(p)
## S4 method for signature 'sfc_rules' sfc_universe(p) ## S4 method for signature 'sfc_sequence' sfc_universe(p)
p |
The corresponding object. |
A vector of base patterns.
sfc_universe(SFC_RULES_2x2) sfc_universe(SFC_RULES_3x3_PEANO)
sfc_universe(SFC_RULES_2x2) sfc_universe(SFC_RULES_3x3_PEANO)
Validate the sequence
## S4 method for signature 'sfc_sequence' sfc_validate(p, by = "sfc_2x2") ## S4 method for signature 'character' sfc_validate(p, by = "sfc_2x2")
## S4 method for signature 'sfc_sequence' sfc_validate(p, by = "sfc_2x2") ## S4 method for signature 'character' sfc_validate(p, by = "sfc_2x2")
p |
An |
by |
One of |
It is mainly used to validate a seed sequence whether they follow the forward-left-right rule.
A logical scalar.
try(sfc_validate("LLLLL")) try(sfc_validate(sfc_sequence("IIIII", rot = c(0, 90, 180, 270, 0), universe = sfc_universe(SFC_RULES_2x2))))
try(sfc_validate("LLLLL")) try(sfc_validate(sfc_sequence("IIIII", rot = c(0, 90, 180, 270, 0), universe = sfc_universe(SFC_RULES_2x2))))
Print the object
## S4 method for signature 'sfc_base' show(object) ## S4 method for signature 'sfc_nxn' show(object) ## S4 method for signature 'sfc_rules' show(object) ## S4 method for signature 'sfc_sequence' show(object)
## S4 method for signature 'sfc_base' show(object) ## S4 method for signature 'sfc_nxn' show(object) ## S4 method for signature 'sfc_rules' show(object) ## S4 method for signature 'sfc_sequence' show(object)
object |
The corresponding object. |
No value is returned.
Flip units
unit_orientation(p, index = "") ## S4 method for signature 'sfc_nxn' sfc_flip_unit(p, index = "", to = NULL) ## S4 method for signature 'sfc_unit' sfc_flip_unit(p, bases)
unit_orientation(p, index = "") ## S4 method for signature 'sfc_nxn' sfc_flip_unit(p, index = "", to = NULL) ## S4 method for signature 'sfc_unit' sfc_flip_unit(p, bases)
p |
The corresponding object. |
index |
A string of digits representing the path on the hierarchy of the curve. The left
side corresponds to the top level and the right side corresponds to the bottom level
on the curve. For the 2x2 curve, the digits can only be 1-4, and for the Peano and
Meander curves, the digits can be 1-9. The hierarchical index should be specified in a format of |
to |
The orientation to flip to. If the specified unit already has such orientation, the function returns the original curve. |
bases |
Normally use |
The orientation of a unit is the orientation of the line connected by the entry-corner and exit-corner of that unit.
A unit in the curve is represented as a square block (e.g. 2^k x 2^k
for the 2x2 curve and 3^k x 3^k
for the Peano and Meander curves, k
between 1 and the level of the curve).
In the 2x2 curve, if an unit can be flipped, it is symmetric, thus flipping in the 2x2 curve does not change its form.
The flipping is mainly applied on the Peano curve and the Meander curves. Peano curve only allows flippings by the diagonals and the Meander
curve only allows flipping horizontally or vertically. The type of flipping is choosen automatically in the function.
Currently, sfc_flip_unit()
only works on curves with a single base pattern as the seed.
unit_orientation()
returns a string one of "vertical", "horizontal", "diagonal_1" and "diagonal_-1".
sfc_flip_unit
returns an sfc_nxn
object.
p = sfc_3x3_meander("I", 11) draw_multiple_curves( p, sfc_flip_unit(p, "1"), # bottom left sfc_flip_unit(p, "2"), # bottom middle sfc_flip_unit(p, "3"), # bottom right nrow = 2) p = sfc_3x3_peano("I", level = 3) draw_multiple_curves( p, sfc_flip_unit(p, ""), sfc_flip_unit(p, "2"), sfc_flip_unit(p, "2:1"), nrow = 2) p = sfc_3x3_peano("I", level = 2) draw_multiple_curves(p, sfc_flip_unit(p, c("4", "7")), sfc_flip_unit(p, c("1", "2", "3", "5", "6", "8", "9")), nrow = 1)
p = sfc_3x3_meander("I", 11) draw_multiple_curves( p, sfc_flip_unit(p, "1"), # bottom left sfc_flip_unit(p, "2"), # bottom middle sfc_flip_unit(p, "3"), # bottom right nrow = 2) p = sfc_3x3_peano("I", level = 3) draw_multiple_curves( p, sfc_flip_unit(p, ""), sfc_flip_unit(p, "2"), sfc_flip_unit(p, "2:1"), nrow = 2) p = sfc_3x3_peano("I", level = 2) draw_multiple_curves(p, sfc_flip_unit(p, c("4", "7")), sfc_flip_unit(p, c("1", "2", "3", "5", "6", "8", "9")), nrow = 1)