pattern¶
A class containing a set (or pattern) of cells.
The pattern class is the central class of forma, representing a set of
points or cells. It can be initialized empty or using a prototype (an N×M
matrix of 1's and 0's). Helper methods for initialization are provided in the
primitives module. Once created, a pattern is modified only via the insert
method—other manipulations return new patterns.
Pattern manipulators include methods like translate, enlarge, rotate,
hreflect, and vreflect. Other operations, such as computing the exterior_hull
or interior_hull, help determine the boundaries of a pattern.
Coordinates are maintained reliably in the range [-65536, 65536], which can be
adjusted via the MAX_COORDINATE constant.
Functions can be invoked either as functions:
pattern.method(input_pattern, ... )
or as methods:
input_pattern:method(... )
-- Procedural style:
local p1 = pattern.new()
pattern.insert(p1, 1, 1)
-- Method chaining:
local p2 = pattern.new():insert(1, 1)
-- Prototype style:
local p3 = pattern.new({{1,1,1}, {1,0,1}, {1,1,1}})
-- Retrieve a random cell and the medoid cell:
local random_cell = p1:rcell()
local medoid_cell = p1:medoid()
-- Compute the exterior hull using the Moore neighbourhood:
local outer_hull = p1:exterior_hull(neighbourhood.moore())
-- or equivalently:
outer_hull = pattern.exterior_hull(p1, neighbourhood.moore())
Fields¶
| Name | Type | Description |
|---|---|---|
max |
forma.cell |
maximum bounding box corner |
min |
forma.cell |
minimum bounding box corner |
offchar |
string |
character for inactive cells in tostring |
onchar |
string |
character for active cells in tostring |
cellkey |
table |
list of coordinate keys |
cellmap |
table |
spatial hash of coordinate key to index |
Basic¶
pattern.new¶
Pattern constructor. Returns a new pattern. If a prototype is provided (an N×M table of 1's and 0's), the corresponding active cells are inserted.
Parameters:
| Name | Type | Description |
|---|---|---|
prototype |
table? |
an N×M table of ones and zeros |
Returns:
forma.pattern— a new pattern according to the prototype
pattern.clone¶
Creates a copy of an existing pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
input pattern to clone |
Returns:
forma.pattern— a new pattern that is a duplicate of ip
pattern.insert¶
Inserts a new cell into the pattern. Returns the modified pattern to allow for method chaining.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to modify |
x |
integer |
x-coordinate of the new cell |
y |
integer |
y-coordinate of the new cell |
Returns:
forma.pattern— the updated pattern (for cascading calls)
pattern.remove¶
Removes a cell from the pattern. Returns the modified pattern to allow for method chaining.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to modify |
x |
integer |
x-coordinate of the cell to remove |
y |
integer |
y-coordinate of the cell to remove |
Returns:
forma.pattern— the updated pattern (for cascading calls)
pattern.has_cell¶
Checks if a cell at (x, y) is active in the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to check |
x |
integer |
x-coordinate |
y |
integer |
y-coordinate |
Returns:
boolean— true if the cell is active, false otherwise
pattern.filter¶
Filters the pattern using a boolean callback, returning a subpattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
the original pattern |
fn |
fun(cell: forma.cell):boolean |
function that determines if a cell is kept |
Returns:
forma.pattern— a new pattern containing only the cells that pass the filter
pattern.size¶
Returns the number of active cells in the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to measure |
Returns:
integer— count of active cells
Utilities¶
pattern.size_sort¶
Comparator function to sort patterns by their size (descending).
Parameters:
| Name | Type | Description |
|---|---|---|
pa |
forma.pattern |
first pattern |
pb |
forma.pattern |
second pattern |
Returns:
boolean— true if pa's size is greater than pb's
pattern.inverse_size_sort¶
Comparator function to sort patterns by their size (ascending).
Parameters:
| Name | Type | Description |
|---|---|---|
pa |
forma.pattern |
first pattern |
pb |
forma.pattern |
second pattern |
Returns:
boolean— true if pa's size is less than pb's
pattern.bounding_box_density¶
Computes how densely the bounding box is filled. Returns zero for an empty pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
input pattern |
Returns:
number— the fraction of the bounding box that is occupied
pattern.bounding_box_asymmetry¶
Computes the asymmetry of the pattern's bounding box. Returns zero in the case of an empty pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
input pattern |
Returns:
number— the ratio of the bounding box's longest to shortest edge
pattern.count_neighbors¶
Counts active neighbors around a specified cell within the pattern. Can be invoked with either a cell object or with x and y coordinates.
Parameters:
| Name | Type | Description |
|---|---|---|
p |
forma.pattern |
a pattern |
nbh |
forma.neighbourhood |
a neighbourhood (e.g., neighbourhood.moore()) |
arg1 |
integer|forma.cell |
either a cell or the x-coordinate |
arg2 |
integer? |
the y-coordinate if arg1 is not a cell |
Returns:
integer— count of active neighbouring cells
pattern.cell_list¶
Returns a list (table) of active cells in the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to list cells from |
Returns:
forma.cell[]— table of cell objects
pattern.edit_distance¶
Computes the edit distance between two patterns (the total number of differing cells).
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
first pattern |
b |
forma.pattern |
second pattern |
Returns:
integer— the edit distance
Set operations¶
pattern.union¶
Returns the union of a set of patterns.
Parameters:
| Name | Type | Description |
|---|---|---|
| `` | forma.pattern |
a table of patterns or a list of pattern arguments |
Returns:
forma.pattern— a new pattern that is the union of the provided patterns
pattern.intersect¶
Returns the intersection of multiple patterns (cells common to all).
Parameters:
| Name | Type | Description |
|---|---|---|
| `` | forma.pattern |
two or more patterns to intersect |
Returns:
forma.pattern— a new pattern of cells that exist in every input pattern
pattern.xor¶
Returns the symmetric difference (XOR) of two patterns. Cells are included if they exist in either pattern but not in both.
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
first pattern |
b |
forma.pattern |
second pattern |
Returns:
forma.pattern— a new pattern representing the symmetric difference
Iterators¶
pattern.cells¶
Iterator over active cells in the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to iterate over |
Returns:
fun():(forma.cell)?— that returns each active cell as a cell object
pattern.cell_coordinates¶
Iterator over active cell coordinates (x, y) in the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to iterate over |
Returns:
fun():integer?, integer?— that returns the x and y coordinates of each active cell
pattern.shuffled_cells¶
Returns an iterator over active cells in randomized order.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to iterate over |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
fun():(forma.cell)?— that yields each active cell in a random order
pattern.shuffled_coordinates¶
Returns an iterator over active cell coordinates in randomized order.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to iterate over |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
fun():integer?, integer?— that yields x and y coordinates in random order
Metamethods¶
pattern.__tostring¶
Renders the pattern as a string. Active cells are shown with pattern.onchar and inactive cells with pattern.offchar.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to render |
Returns:
string— string representation of the pattern
pattern.__add¶
Adds two patterns using the '+' operator (i.e. returns their union).
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
first pattern |
b |
forma.pattern |
second pattern |
Returns:
forma.pattern— a new pattern representing the union of a and b
pattern.__sub¶
Subtracts one pattern from another using the '-' operator. Returns a new pattern with cells in a that are not in b.
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
base pattern |
b |
forma.pattern |
pattern to subtract from a |
Returns:
forma.pattern— a new pattern with the difference
pattern.__mul¶
Computes the intersection of two patterns using the '*' operator.
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
first pattern |
b |
forma.pattern |
second pattern |
Returns:
forma.pattern— a new pattern containing only the cells common to both
pattern.__pow¶
Computes the symmetric difference (XOR) of two patterns using the '^' operator.
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
first pattern |
b |
forma.pattern |
second pattern |
Returns:
forma.pattern— a new pattern with cells present in either a or b, but not both
pattern.__eq¶
Tests whether two patterns are identical.
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
first pattern |
b |
forma.pattern |
second pattern |
Returns:
boolean— true if the patterns are equal, false otherwise
Cell accessors¶
pattern.centroid¶
Computes the centroid (arithmetic mean) of all cells in the pattern. The result is rounded to the nearest integer coordinate.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
Returns:
forma.cell— a cell representing the centroid (which may not be active)
pattern.medoid¶
Computes the medoid cell of the pattern. The medoid minimizes the total distance to all other cells (using Euclidean distance by default).
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
measure |
(fun(a: forma.cell, b: forma.cell):number)? |
distance function (default: Euclidean) |
Returns:
forma.cell— the medoid cell of the pattern
pattern.rcell¶
Returns a random cell from the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to sample from |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
forma.cell— a random cell from the pattern
Transformations¶
pattern.translate¶
Returns a new pattern translated by a vector (sx, sy).
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to translate |
sx |
integer |
translation along the x-axis |
sy |
integer |
translation along the y-axis |
Returns:
forma.pattern— a new pattern shifted by (sx, sy)
pattern.normalise¶
Normalizes the pattern by translating it so that its minimum coordinate is (0,0).
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to normalize |
Returns:
forma.pattern— a new normalized pattern
pattern.enlarge¶
Returns an enlarged version of the pattern. Each active cell is replaced by an f×f block.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to enlarge |
f |
number |
enlargement factor |
Returns:
forma.pattern— a new enlarged pattern
pattern.rotate¶
Returns a new pattern rotated 90° clockwise about the origin.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to rotate |
Returns:
forma.pattern— a rotated pattern
pattern.vreflect¶
Returns a new pattern that is a vertical reflection of the original.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to reflect vertically |
Returns:
forma.pattern— a vertically reflected pattern
pattern.hreflect¶
Returns a new pattern that is a horizontal reflection of the original.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to reflect horizontally |
Returns:
forma.pattern— a horizontally reflected pattern
Sampling¶
pattern.sample¶
Returns a random subpattern containing a fixed number of cells.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern (domain) to sample from |
ncells |
integer |
number of cells to sample |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
forma.pattern— a new pattern with ncells randomly selected cells
pattern.sample_poisson¶
Returns a Poisson-disc sampled subpattern. Ensures that no two sampled cells are closer than the given radius.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern (domain) to sample from |
distance |
fun(a: forma.cell, b: forma.cell):number |
distance function (e.g., cell.euclidean) |
radius |
number |
minimum separation |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
forma.pattern— a new pattern sampled with Poisson-disc criteria
pattern.sample_mitchell¶
Returns an approximate Poisson-disc sample using Mitchell's best candidate algorithm.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
the input pattern to sample from |
distance |
fun(a: forma.cell, b: forma.cell):number |
distance function (e.g., cell.euclidean) |
n |
integer |
number of samples |
k |
integer |
number of candidate attempts per iteration |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
forma.pattern— a new pattern with n samples chosen via the algorithm
Subpattern finding¶
pattern.floodfill¶
Returns the contiguous subpattern (connected component) starting from a given cell.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern upon which the flood fill is to be performed |
icell |
forma.cell |
a cell specifying the origin of the flood fill |
nbh |
(forma.neighbourhood)? |
neighbourhood to use (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new pattern containing the connected component
pattern.max_rectangle¶
Finds the largest contiguous rectangular subpattern within the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to analyze |
alpha |
number? |
'squareness' parameter. 0 for max rectangle, 1 for max square |
Returns:
forma.pattern— a subpattern representing the maximal rectangle
pattern.convex_hull¶
Computes the convex hull of the pattern. The hull points are connected using line rasterization.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
Returns:
forma.pattern— a new pattern representing the convex hull
pattern.thin¶
Returns a thinned (skeletonized) version of the pattern.
Iteratively removes border cells whose Moore neighbours remain a single
connected component under nbh.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to thin |
nbh |
(forma.neighbourhood)? |
neighbourhood for connectivity (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new, thinned pattern
Morphological operations¶
pattern.erode¶
Returns the erosion of the pattern. A cell is retained only if all of its neighbours (as defined by nbh) are active.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to erode |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new, eroded pattern
pattern.dilate¶
Returns the dilation of the pattern. Each active cell contributes its neighbours (as defined by nbh) to the result.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to dilate |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new, dilated pattern
pattern.gradient¶
Returns the morphological gradient of the pattern. Computes the difference between the dilation and erosion.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
nbh |
(forma.neighbourhood)? |
neighbourhood for dilation/erosion (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new pattern representing the gradient
pattern.opening¶
Returns the morphological opening of the pattern. Performs erosion followed by dilation to remove small artifacts.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new, opened pattern
pattern.closing¶
Returns the morphological closing of the pattern. Performs dilation followed by erosion to fill small holes.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new, closed pattern
pattern.interior_hull¶
Returns a pattern of cells that form the interior hull. These are cells that neighbor inactive cells while still belonging to the pattern.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new pattern representing the interior hull
pattern.exterior_hull¶
Returns a pattern of cells that form the exterior hull. This consists of inactive neighbours of the pattern, useful for enlarging or determining non-overlapping borders.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to process |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.moore()) |
Returns:
forma.pattern— a new pattern representing the exterior hull
Packing¶
pattern.find_packing_position¶
Finds a packing offset where pattern a fits entirely within domain b. Returns a coordinate shift that, when applied to a, makes it tile inside b.
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
pattern to pack |
b |
forma.pattern |
domain pattern in which to pack a |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
(forma.cell)?— a cell (as a coordinate shift) if a valid position is found; nil otherwise
pattern.find_central_packing_position¶
Finds a center-weighted packing offset to place pattern a within pattern
b as close as possible to the cell c. If no c is provided, then the centroid
of pattern b is used.
Parameters:
| Name | Type | Description |
|---|---|---|
a |
forma.pattern |
pattern to pack |
b |
forma.pattern |
domain pattern |
c |
(forma.cell)? |
cell to act as a center for packing |
Returns:
(forma.cell)?— a coordinate shift if a valid position is found; nil otherwise
Decomposition¶
pattern.connected_components¶
Returns a multipattern of the connected components within the pattern. Uses flood-fill to extract contiguous subpatterns.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to analyze |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.moore()) |
Returns:
forma.multipattern— containing each connected component as a subpattern
pattern.interior_holes¶
Returns a multipattern of the interior holes of the pattern. Interior holes are inactive regions completely surrounded by active cells.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to analyze |
nbh |
(forma.neighbourhood)? |
neighbourhood (default: neighbourhood.von_neumann()) |
Returns:
forma.multipattern— of interior hole subpatterns
pattern.bsp¶
Partitions the pattern using binary space partitioning (BSP). Recursively subdivides contiguous rectangular areas until each partition's volume is below th_volume.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to partition |
th_volume |
number |
threshold volume for final partitions |
alpha |
number? |
parameter for squareness of BSP |
Returns:
forma.multipattern— of BSP subpatterns
pattern.neighbourhood_categories¶
Categorizes cells in the pattern based on neighbourhood configurations. Returns a multipattern with one subpattern per neighbourhood category.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern whose cells are to be categorized |
nbh |
forma.neighbourhood |
neighbourhood used for categorization |
Returns:
forma.multipattern— with each category represented as a subpattern
pattern.perlin¶
Applies Perlin noise sampling to the pattern. Generates a multipattern by thresholding Perlin noise values at multiple levels.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern (domain) to sample from |
freq |
number |
frequency for Perlin noise |
depth |
integer |
sampling depth |
thresholds |
number[] |
table of threshold values (each between 0 and 1) |
rng |
(fun(m: integer):integer)? |
random number generator (e.g., math.random) |
Returns:
forma.multipattern— with one component per threshold level
pattern.voronoi¶
Generates Voronoi tessellation segments for a domain based on seed points.
Parameters:
| Name | Type | Description |
|---|---|---|
seeds |
forma.pattern |
pattern containing seed cells |
domain |
forma.pattern |
pattern defining the tessellation domain |
measure |
fun(a: forma.cell, b: forma.cell):number |
distance function (e.g., cell.euclidean) |
Returns:
forma.multipattern— of Voronoi segments
pattern.voronoi_relax¶
Performs centroidal Voronoi tessellation (Lloyd's algorithm) on a set of seeds. Iteratively relaxes seed positions until convergence or a maximum number of iterations.
Parameters:
| Name | Type | Description |
|---|---|---|
seeds |
forma.pattern |
initial seed pattern |
domain |
forma.pattern |
tessellation domain pattern |
measure |
fun(a: forma.cell, b: forma.cell):number |
distance function (e.g., cell.euclidean) |
max_ite |
integer? |
maximum iterations (default: 30) |
Returns:
forma.multipattern— a multipattern of Voronoi segmentsforma.pattern— a pattern of relaxed seed positionsboolean— whether the algorithm converged
Display and utilities¶
pattern.get_max_coordinate¶
Returns the maximum allowed coordinate for spatial hashing.
Returns:
number— maximum coordinate value
pattern.test_coordinate_map¶
Tests the conversion between (x, y) coordinates and the spatial hash key.
Parameters:
| Name | Type | Description |
|---|---|---|
x |
number |
test x-coordinate |
y |
number |
test y-coordinate |
Returns:
boolean— true if the conversion is correct, false otherwise
pattern.print¶
Prints the pattern within an optional domain, line-by-line.
Parameters:
| Name | Type | Description |
|---|---|---|
ip |
forma.pattern |
pattern to render |
char |
string? |
single-character to draw "on" cells |
domain |
(forma.pattern)? |
pattern defining the bounding box |
printer |
fun(line: string)? |
function for printing each line; defaults to io.write(line.."\n") |