From ce5fc615a42e211490007328559d6056637a6ddf Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Wed, 11 Jul 2018 01:56:08 +0200 Subject: [PATCH 01/31] Small README update --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ebcaa50..79ba698 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ __2D grid shape generation in Lua__

-This package is intended for the generation and manipulation of shapes on a two -dimensional grid or lattice. It came about as part of experiments in making -roguelike games. **forma** is therefore particularly suited for the generation -of roguelike environments. +**forma** is a utility library for the procedural generation and manipulation of +shapes on a two dimensional grid or lattice. It came about as part of +experiments in making roguelike games. **forma** is therefore particularly +suited for (but not limited to) the generation of roguelike environments. Shapes can be generated in several ways. From simple rasters of primitive shapes like circles, lines and squares, to pattern generation by a [Cellular From c75fda680cfd533d78a2e051d3e5853a2b175d32 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Wed, 11 Jul 2018 02:03:36 +0200 Subject: [PATCH 02/31] README updates for v0.2 --- README.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 79ba698..d089c30 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Build Status](https://travis-ci.org/nhartland/forma.svg?branch=master)](https://travis-ci.org/nhartland/forma) +[![Coverage Status](https://coveralls.io/repos/github/nhartland/forma/badge.svg?branch=master)](https://coveralls.io/github/nhartland/forma?branch=master) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) forma @@ -56,21 +57,18 @@ noise](https://en.wikipedia.org/wiki/Worley_noise): All of the above examples can be generated by code in the `examples` folder. -Warning -------- -The master branch is in active development. API breaking changes may -occasionally occur. +Installation +----------------------------- -Requirements ------------- -Compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1. +**forma** is compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1. The library +is written in pure Lua, no compilation is required. Including the project is +then as simple as including the `forma` directory in your Lua path. -The test suite requires - - [LuaCov](https://keplerproject.github.io/luacov/) - - [luaunit](https://github.com/bluebird75/luaunit) +The easiest way to do this is via LuaRocks: -Generating the documentation requires - - [LDoc](https://github.com/stevedonovan/LDoc) +```Shell + luarocks install forma +``` Running examples ---------------- @@ -86,6 +84,9 @@ Generating documentation Documentation is hosted [here](https://nhartland.github.io/forma/). +Generating the documentation requires + - [LDoc](https://github.com/stevedonovan/LDoc) + Simply running ldoc --output contents --dir docs . @@ -95,7 +96,10 @@ in the root directory should generate all the required pages. Testing ------- -Unit tests are provided for some methods with the luaunit framework, coverage is -tested using LuaCov. To run the tests use +Unit tests and coverage reports are provided. The test suite requires + - [LuaCov](https://keplerproject.github.io/luacov/) + - [luaunit](https://github.com/bluebird75/luaunit) + +To run the tests use ./run_tests.sh From 939c5e336fad751b0427675688e72b9398c3342f Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Wed, 11 Jul 2018 02:05:41 +0200 Subject: [PATCH 03/31] Draft rockspec --- rockspec/forma-0.2-1.rockspec | 41 +++++++++++++++++++++++++++++++++++ rockspec/forma-scm-1.rockspec | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 rockspec/forma-0.2-1.rockspec create mode 100644 rockspec/forma-scm-1.rockspec diff --git a/rockspec/forma-0.2-1.rockspec b/rockspec/forma-0.2-1.rockspec new file mode 100644 index 0000000..815e519 --- /dev/null +++ b/rockspec/forma-0.2-1.rockspec @@ -0,0 +1,41 @@ +package = "forma" +version = "0.2-1" +source = { + url = "git://github.com/nhartland/forma", + tag = "v0.2", +} + +description = { + summary = "Cellular automata and geometry in Lua.", + detailed = [[ +forma is a utility library for the procedural generation and manipulation of +shapes on a two dimensional grid or lattice. + +The library provides a flexible Cellular Automata implementation, along with a +great deal of standard methods from computational geometry. For example 2-D +sampling by Poisson-disc or Lloyd's algorithm, Contiguous segment finding by +flood-filling, Binary space partitioning, Voronoi tessellation, hull finding +and more. +]], + homepage = "https://nhartland.github.io/forma/", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + forma = "forma/init.lua", + ["forma.automata"] = "forma/automata.lua", + ["forma.cell"] = "forma/cell.lua", + ["forma.neighbourhood"] = "forma/neighbourhood.lua", + ["forma.pattern"] = "forma/pattern.lua", + ["forma.primitives"] = "forma/primitives.lua", + ["forma.subpattern"] = "forma/subpattern.lua", + }, + copy_directories = { + "docs", + "examples" + } +} diff --git a/rockspec/forma-scm-1.rockspec b/rockspec/forma-scm-1.rockspec new file mode 100644 index 0000000..b3df058 --- /dev/null +++ b/rockspec/forma-scm-1.rockspec @@ -0,0 +1,41 @@ +package = "forma" +version = "scm-1" +source = { + url = "https://github.com/nhartland/forma/archive/master.zip", + dir = "forma-master", +} + +description = { + summary = "Cellular automata and geometry in Lua.", + detailed = [[ +forma is a utility library for the procedural generation and manipulation of +shapes on a two dimensional grid or lattice. + +The library provides a flexible Cellular Automata implementation, along with a +great deal of standard methods from computational geometry. For example 2-D +sampling by Poisson-disc or Lloyd's algorithm, Contiguous segment finding by +flood-filling, Binary space partitioning, Voronoi tessellation, hull finding +and more. +]], + homepage = "https://nhartland.github.io/forma/", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + forma = "forma/init.lua", + ["forma.automata"] = "forma/automata.lua", + ["forma.cell"] = "forma/cell.lua", + ["forma.neighbourhood"] = "forma/neighbourhood.lua", + ["forma.pattern"] = "forma/pattern.lua", + ["forma.primitives"] = "forma/primitives.lua", + ["forma.subpattern"] = "forma/subpattern.lua", + }, + copy_directories = { + "docs", + "examples" + } +} From 0f57954989095ef55ab3f76e1302724ee3ac3fe0 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Wed, 11 Jul 2018 02:13:08 +0200 Subject: [PATCH 04/31] Isolines example --- CHANGELOG.md | 1 + TODO.md | 2 -- examples/isolines.lua | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100755 examples/isolines.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d316f9..29cc341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,3 +29,4 @@ - Added a Poisson-disc sampling subpattern - Removed some (confusing) functionality from `cell`, namely addition and multiplication with a number value. +- Added isoline drawing example diff --git a/TODO.md b/TODO.md index 482e563..5eb6ddf 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,6 @@ # TODO - Luarocks -- Promote Worley noise example to a more general case in forma.subpattern - Standardise examples a bit more - Consider generalising BSP to even-size partitions of any shape (not just rectangular sub-areas) @@ -9,5 +8,4 @@ #### Computational geometry methods to consider implementing: - Farthest-first traversal -- Isoline drawing (mask-then-surface) - Boundary/contour tracing in place of pattern.edge or pattern.surface diff --git a/examples/isolines.lua b/examples/isolines.lua new file mode 100755 index 0000000..4ebdfe2 --- /dev/null +++ b/examples/isolines.lua @@ -0,0 +1,35 @@ +-- isolines.lua +-- Simmilar to worley.lua but showing isolines +-- of the d2-d1 scalar field. + +local cell = require('forma.cell') +local subpattern = require('forma.subpattern') +local primitives = require('forma.primitives') +math.randomseed( os.time() ) + +-- Distance measure +local measure = cell.chebyshev + +-- Domain and seeds +local sq = primitives.square(80,20) +local rn = subpattern.random(sq, math.floor(sq:size()*0.01)):cell_list() + +-- Worley noise mask +local mask = function(tcell) + local sortfn = function(a,b) + return measure(tcell, a) < measure(tcell, b) + end + table.sort(rn, sortfn) + local d1 = measure(rn[1], tcell) + local d2 = measure(rn[2], tcell) + return d2 - d1 > 1 +end + +-- Compute the d2-d1 thresholded pattern and take its surface +local noise = subpattern.mask(sq, mask) +noise = noise:surface() + +-- Print to screen +noise.offchar = '~' +noise.onchar = '▓' +print(noise) From 16678026972210d6408576b25ca9529343941d9f Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Wed, 11 Jul 2018 19:15:22 +0200 Subject: [PATCH 05/31] Homogenising examples a bit --- examples/async_automata.lua | 38 +++++++++++++++++ examples/binary_space_partition.lua | 17 ++++---- examples/bubbles.lua | 23 +++++++++++ examples/carpet.lua | 41 ------------------- examples/{caves.lua => cellular_automata.lua} | 23 ++++++----- examples/game_of_life.lua | 28 ------------- examples/game_of_life_async.lua | 38 ----------------- examples/isolines.lua | 22 +++++----- examples/maxrectangle.lua | 14 ++++--- examples/primitives.lua | 24 ----------- examples/shapes.lua | 26 ------------ examples/voronoi.lua | 18 +++----- examples/worley.lua | 38 ----------------- forma/subpattern.lua | 1 + 14 files changed, 108 insertions(+), 243 deletions(-) create mode 100755 examples/async_automata.lua create mode 100755 examples/bubbles.lua delete mode 100755 examples/carpet.lua rename examples/{caves.lua => cellular_automata.lua} (53%) delete mode 100755 examples/game_of_life.lua delete mode 100755 examples/game_of_life_async.lua delete mode 100755 examples/primitives.lua delete mode 100755 examples/shapes.lua delete mode 100755 examples/worley.lua diff --git a/examples/async_automata.lua b/examples/async_automata.lua new file mode 100755 index 0000000..08dcfe2 --- /dev/null +++ b/examples/async_automata.lua @@ -0,0 +1,38 @@ +-- async_automata.lua. +-- Here the use of an asynchronous cellular automata is demonstrated, making +-- use also of symmetrisation methods to generate a final, symmetric pattern. + +local pattern = require('forma.pattern') +local primitives = require('forma.primitives') +local automata = require('forma.automata') +local subpattern = require('forma.subpattern') +local neighbourhood = require('forma.neighbourhood') + +math.randomseed( os.time() ) + +-- Domain for CA to operate in +local sq = primitives.square(10,5) + +-- Make a new pattern consisting of a single random cell from the domain +local start_point = sq:rcell() -- Select a random point +local ca_pattern = pattern.new():insert(start_point.x, start_point.y) + +-- Moore neighbourhood rule for CA +local moore = automata.rule(neighbourhood.moore(), "B12/S012345678") + +-- Perform asynchronous CA update until convergence +local converged = false +while converged == false do + ca_pattern, converged = automata.async_iterate(ca_pattern, sq, {moore}) +end + +-- Mirror the basic pattern a couple of times +local symmetrised_pattern = ca_pattern:hreflect() +symmetrised_pattern = symmetrised_pattern:vreflect():vreflect() +symmetrised_pattern = symmetrised_pattern:hreflect():hreflect() + +-- Categorise the pattern according to possible vN neighbours and print to screen +-- This turns the basic pattern into standard 'box-drawing' characters +local vn = neighbourhood.von_neumann() +local segments = subpattern.neighbourhood_categories(symmetrised_pattern, vn) +subpattern.pretty_print(symmetrised_pattern, segments, vn:category_label()) diff --git a/examples/binary_space_partition.lua b/examples/binary_space_partition.lua index 29db88a..b432c81 100755 --- a/examples/binary_space_partition.lua +++ b/examples/binary_space_partition.lua @@ -1,16 +1,13 @@ -- binary_space_partition.lua --- Example and benchmark of binary space partitioning +-- Example of binary space partitioning local subpattern = require('forma.subpattern') local primitives = require('forma.primitives') -math.randomseed(0) --- stress loops for benchmarking -for i=1,100,1 do - -- Generate an 80x20 square and partition it into segments of maximally 50 cells - local square = primitives.square(80,20) - local bsp = subpattern.bsp(square, 50) - -- On the last loop, pretty print the segments - if i==100 then subpattern.pretty_print(square,bsp) end -end +-- Generate an 80x20 square and partition it into segments of maximally 50 cells +local square = primitives.square(80,20) +local bsp = subpattern.bsp(square, 50) + +-- Pretty print resulting pattern segments +subpattern.pretty_print(square,bsp) diff --git a/examples/bubbles.lua b/examples/bubbles.lua new file mode 100755 index 0000000..f363545 --- /dev/null +++ b/examples/bubbles.lua @@ -0,0 +1,23 @@ +-- Example of circle primitives +local cell = require('forma.cell') +local pattern = require('forma.pattern') +local primitives = require('forma.primitives') +local subpattern = require('forma.subpattern') + +math.randomseed( os.time() ) +local max_radius = 4 + +-- Setup domain and some random seeds +local domain = primitives.square(80,20) +local seeds = subpattern.poisson_disc(domain, cell.euclidean, 2*max_radius) +local shapes = pattern.new() + +-- Randomly generate some circles in the domain +for seed in seeds:cells() do + local circle = primitives.circle(math.random(2, max_radius)) + shapes = shapes + circle:shift(seed.x, seed.y) +end + +subpattern.pretty_print(domain, {shapes}, {'o'}) + + diff --git a/examples/carpet.lua b/examples/carpet.lua deleted file mode 100755 index 97cabc4..0000000 --- a/examples/carpet.lua +++ /dev/null @@ -1,41 +0,0 @@ --- carpet.lua. --- Using Async Cellular Automata with symmetrising methods. --- Demonstration of pattern generation by asynchronous cellular automata --- Here a small basic pattern is generated, which is then enlarged by --- reflection into a nicely symmetric larger pattern. - -local pattern = require('forma.pattern') -local primitives = require('forma.primitives') -local automata = require('forma.automata') -local subpattern = require('forma.subpattern') -local neighbourhood = require('forma.neighbourhood') - -math.randomseed( os.time() ) - --- Initial CA domain -local sq = primitives.square(10,5) - --- Make a new pattern consisting of a random (seed) cell from the domain -local rn = pattern.new() -local rp = sq:rcell() -rn:insert(rp.x, rp.y) - --- Moore neighbourhood rule -local moore = automata.rule(neighbourhood.moore(), "B12/S012345678") - -repeat - -- Perform asynchronous CA update - local converged - rn, converged = automata.async_iterate(rn, sq, {moore}) - - if converged == true then - -- Mirror the basic pattern a couple of times - local rflct = rn:hreflect() - rflct = rflct:vreflect():vreflect() - rflct = rflct:hreflect():hreflect() - -- Categorise the pattern according to possible vN neighbours and print to screen - local vn = neighbourhood.von_neumann() - local segments = subpattern.neighbourhood_categories(rflct, vn) - subpattern.pretty_print(rflct, segments, vn:category_label()) - end -until converged == true diff --git a/examples/caves.lua b/examples/cellular_automata.lua similarity index 53% rename from examples/caves.lua rename to examples/cellular_automata.lua index 21cfb14..7195c71 100755 --- a/examples/caves.lua +++ b/examples/cellular_automata.lua @@ -1,23 +1,26 @@ --- caves.lua +-- cellular_automata.lua -- Demonstration of classic cellular-automata cave generation (4-5 rule) local primitives = require('forma.primitives') local subpattern = require('forma.subpattern') local automata = require('forma.automata') local neighbourhood = require('forma.neighbourhood') + math.randomseed( os.time() ) +-- Domain for CA local sq = primitives.square(80,20) -local rn = subpattern.random(sq, math.floor(sq:size()*0.5)) -sq.onchar, sq.offchar = "#", " " --- Moore neighbourhood rule +-- CA initial condition: sample at random from the domain +local ca = subpattern.random(sq, math.floor(sq:size()*0.5)) + +-- Moore neighbourhood 4-5 rule local moore = automata.rule(neighbourhood.moore(), "B5678/S45678") -local ite = 0 -repeat - local converged - rn, converged = automata.iterate(rn, sq, {moore}) +local ite, converged = 0, false +while converged == false and ite < 1000 do + ca, converged = automata.iterate(ca, sq, {moore}) ite = ite+1 -until converged == true or ite > 1000 +end -print(sq-rn) +ca.onchar, ca.offchar = "#", " " +print(ca) diff --git a/examples/game_of_life.lua b/examples/game_of_life.lua deleted file mode 100755 index 607b1a6..0000000 --- a/examples/game_of_life.lua +++ /dev/null @@ -1,28 +0,0 @@ --- life.lua --- Demonstration of a 'Game of Life' rule - -local subpattern = require('forma.subpattern') -local primitives = require('forma.primitives') -local automata = require('forma.automata') -local neighbourhood = require('forma.neighbourhood') -math.randomseed( os.time() ) - --- Domain and seed -local sq = primitives.square(80,20) -local rn = subpattern.random(sq, math.floor(sq:size()*0.5)) - --- vonNeumann neighbourhood for pretty printing -local nbh = neighbourhood.von_neumann() - --- Game of life rule -local life = automata.rule(neighbourhood.moore(), "B3/S23") -local counter, maxcounter = 0, 100 -repeat - counter = counter + 1 - local converged - rn, converged = automata.iterate(rn, sq, {life}) - local segments = subpattern.neighbourhood_categories(rn, nbh) - os.execute("clear") - subpattern.pretty_print(rn, segments, nbh:category_label()) - print(counter .. "/".. maxcounter .. " frames") -until converged == true or counter == maxcounter diff --git a/examples/game_of_life_async.lua b/examples/game_of_life_async.lua deleted file mode 100755 index 27a86fc..0000000 --- a/examples/game_of_life_async.lua +++ /dev/null @@ -1,38 +0,0 @@ --- life.lua --- Demonstration of a 'Game of Life' rule - -local subpattern = require('forma.subpattern') -local primitives = require('forma.primitives') -local automata = require('forma.automata') -local neighbourhood = require('forma.neighbourhood') -math.randomseed( os.time() ) - -local print_every_iteration = false - --- Domain and seed -local sq = primitives.square(40,20) -local rn = subpattern.random(sq, math.floor(sq:size()*0.5)) - --- vonNeumann neighbourhood for pretty printing -local nbh = neighbourhood.von_neumann() - --- Game of life rule --- The async rule converges quite well with an alterative : "B3/S123" -local life = automata.rule(neighbourhood.moore(), "B3/S23") -local counter, maxcounter = 0, 500 -repeat - counter = counter + 1 - local converged - rn, converged = automata.async_iterate(rn, sq, {life}) - - if print_every_iteration then - local reflect = rn:hreflect() - local segments = subpattern.neighbourhood_categories(reflect, nbh) - os.execute("clear") - subpattern.pretty_print(reflect, segments, nbh:category_label()) - end -until converged == true or counter == maxcounter - -local reflect = rn:hreflect() -local segments = subpattern.neighbourhood_categories(reflect, nbh) -subpattern.pretty_print(reflect, segments, nbh:category_label()) diff --git a/examples/isolines.lua b/examples/isolines.lua index 4ebdfe2..724aeb3 100755 --- a/examples/isolines.lua +++ b/examples/isolines.lua @@ -1,6 +1,10 @@ -- isolines.lua --- Simmilar to worley.lua but showing isolines --- of the d2-d1 scalar field. +-- Rasterising isolines of a scalar field. + +-- Here we generate a pattern randomly filled with points, and take as the +-- field N(cell) = F_2(cell) - F_1(cell), where F_n is the chebyshev distance +-- to the nth nearest neighbour. Isolines at N = 0 are drawn by thresholding N +-- at 1 and taking the surface. local cell = require('forma.cell') local subpattern = require('forma.subpattern') @@ -20,16 +24,12 @@ local mask = function(tcell) return measure(tcell, a) < measure(tcell, b) end table.sort(rn, sortfn) - local d1 = measure(rn[1], tcell) - local d2 = measure(rn[2], tcell) - return d2 - d1 > 1 + local F1 = measure(rn[1], tcell) + local F2 = measure(rn[2], tcell) + return F2 - F1 > 1 end --- Compute the d2-d1 thresholded pattern and take its surface +-- Compute the thresholded pattern and print its surface local noise = subpattern.mask(sq, mask) -noise = noise:surface() +subpattern.pretty_print(sq, {noise:surface()}, {'#'}) --- Print to screen -noise.offchar = '~' -noise.onchar = '▓' -print(noise) diff --git a/examples/maxrectangle.lua b/examples/maxrectangle.lua index 6711a4f..dbea305 100755 --- a/examples/maxrectangle.lua +++ b/examples/maxrectangle.lua @@ -1,15 +1,19 @@ -- maxrectangle.lua --- Example and benchmark of maximum rectangle finding +-- Example of maximum rectangle finding in a general domain local pattern = require('forma.pattern') local subpattern = require('forma.subpattern') local primitives = require('forma.primitives') -math.randomseed(0) --- Generate some messy base pattern +math.randomseed( os.time() ) + +-- Generate a messy pattern inside a domain +local domain = primitives.square(80, 20) local total_pattern = pattern.new() -for _=1,100,1 do - local tp = primitives.square(math.random(5)):shift(math.random(20), math.random(20)) +for _=1,200,1 do + -- Generate a randomly sized square at a random point of the domain + local rpoint = domain:rcell() + local tp = primitives.square(math.random(7)):shift(rpoint.x, rpoint.y) total_pattern = total_pattern + tp end diff --git a/examples/primitives.lua b/examples/primitives.lua deleted file mode 100755 index a9e69aa..0000000 --- a/examples/primitives.lua +++ /dev/null @@ -1,24 +0,0 @@ --- primitives.lua --- Examples of geometry primitives - -local cell = require('forma.cell') -local primitives = require('forma.primitives') - -local tp = primitives.circle(1) -local radii = {2,4,5,15} -for _, r in ipairs(radii) do - tp = tp + primitives.circle(r) -end - -tp = tp + primitives.line(cell.new(-15,0), cell.new(15,0)) -tp = tp + primitives.line(cell.new(0,-15), cell.new(0,15)) - -tp = tp + primitives.line(cell.new(0,-15), cell.new(-15,0)) -tp = tp + primitives.line(cell.new(0,15), cell.new(15,0)) - -tp = tp + primitives.line(cell.new(-15,0), cell.new(0,15)) -tp = tp + primitives.line(cell.new(0,-15), cell.new(15,0)) - -tp.onchar='X' -tp.offchar=' ' -print (tp) diff --git a/examples/shapes.lua b/examples/shapes.lua deleted file mode 100755 index 30db6ce..0000000 --- a/examples/shapes.lua +++ /dev/null @@ -1,26 +0,0 @@ --- shapes.lua --- Use of a few different functions to generate shapes - -local pattern = require('forma.pattern') -local primitives = require('forma.primitives') -math.randomseed( os.time() ) - --- Generate some basic shape as a sum of rectangles -local function generate_shape() - local rn = pattern.new() - while rn:size() < 35 do - local sqx, sqy = math.random(3) , math.random(3) - local pqx, pqy = math.random(5) , math.random(5) - rn = rn + primitives.square(sqx,sqy):shift(pqx, pqy) - end - return rn -end - --- Add some symmetry -local rn = generate_shape():hreflect() - --- Print to stdout -rn.onchar, rn.offchar = "X"," " -print(rn) - - diff --git a/examples/voronoi.lua b/examples/voronoi.lua index 11c5513..277d9c2 100755 --- a/examples/voronoi.lua +++ b/examples/voronoi.lua @@ -6,18 +6,12 @@ local primitives = require('forma.primitives') local subpattern = require('forma.subpattern') math.randomseed(os.time()) --- Generate a random pattern and its voronoi tesselation +-- Generate a random pattern in a specified domain local sq = primitives.square(80,20) -local rn = subpattern.random(sq, math.floor(sq:size()*0.01)) +local rn = subpattern.random(sq, 10) --- Compute voronoi tesselation for various measures -local measures = {} -measures.Chebyshev = cell.chebyshev -measures.Euclidean = cell.euclidean -measures.Manhattan = cell.manhattan +-- Compute its voronoi tesselation +local measure = cell.chebyshev +local segments = subpattern.voronoi(rn, sq, measure) -for label, measure in pairs(measures) do - local segments = subpattern.voronoi(rn, sq, measure) - print(label) - subpattern.pretty_print(sq, segments) -end +subpattern.pretty_print(sq, segments) diff --git a/examples/worley.lua b/examples/worley.lua deleted file mode 100755 index dbe1989..0000000 --- a/examples/worley.lua +++ /dev/null @@ -1,38 +0,0 @@ --- worley.lua --- Demonstration of thresholded Worley noise --- https://en.wikipedia.org/wiki/Worley_noise - --- Here we take the noise field N = F_2 - F_1, --- where F_n is the chebyshev distance to the nth --- nearest neighbour, and take the threshold N > 1 - --- Makes a good ice floe generator - -local cell = require('forma.cell') -local subpattern = require('forma.subpattern') -local primitives = require('forma.primitives') -math.randomseed( os.time() ) - --- Distance measure and threshold -local measure = cell.chebyshev -local threshold = 1 - --- Domain and seeds -local sq = primitives.square(80,20) -local rn = subpattern.random(sq, math.floor(sq:size()*0.01)):cell_list() - --- Worley noise mask -local mask = function(tcell) - local sortfn = function(a,b) - return measure(tcell, a) < measure(tcell, b) - end - table.sort(rn, sortfn) - local d1 = measure(rn[1], tcell) - local d2 = measure(rn[2], tcell) - return d2 - d1 > threshold -end - -local noise = subpattern.mask(sq, mask) -noise.offchar = '~' -noise.onchar = '▓' -print(noise) diff --git a/forma/subpattern.lua b/forma/subpattern.lua index c7a92eb..a9561b6 100644 --- a/forma/subpattern.lua +++ b/forma/subpattern.lua @@ -402,6 +402,7 @@ end -- @param chars the characters to be printed for each segment (optional). function subpattern.pretty_print(domain, segments, chars) assert(domain:size() > 0, "subpattern.pretty_print: domain must have at least one cell") + assert(type(segments) == "table", "subpattern.pretty_print: second argument must be a *table* of patterns") -- If no dictionary is supplied generate a new one (starting from '0') if chars == nil then local start_char = 47 From b3f867111d53d6ff2ad6ae5caa75fac47358712a Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Wed, 11 Jul 2018 19:22:14 +0200 Subject: [PATCH 06/31] Homogenising examples --- TODO.md | 10 ++-------- examples/lloyds_algorithm.lua | 26 -------------------------- examples/sampling.lua | 15 ++++++--------- 3 files changed, 8 insertions(+), 43 deletions(-) delete mode 100755 examples/lloyds_algorithm.lua diff --git a/TODO.md b/TODO.md index 5eb6ddf..f2c760c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,11 +1,5 @@ # TODO - Luarocks -- Standardise examples a bit more -- Consider generalising BSP to even-size partitions of any shape (not just - rectangular sub-areas) - -#### Computational geometry methods to consider implementing: - -- Farthest-first traversal -- Boundary/contour tracing in place of pattern.edge or pattern.surface +- Enumerate return values in documentation +- Example gallery diff --git a/examples/lloyds_algorithm.lua b/examples/lloyds_algorithm.lua deleted file mode 100755 index 135c1bc..0000000 --- a/examples/lloyds_algorithm.lua +++ /dev/null @@ -1,26 +0,0 @@ --- voronoi.lua --- Demonstration of voronoi relaxation by lloyds algorithm - -local cell = require('forma.cell') -local primitives = require('forma.primitives') -local subpattern = require('forma.subpattern') -math.randomseed(os.time()) - --- Domain for tesselation -local sq = primitives.square(80,20) -local seeds = subpattern.random(sq, 9) - --- Compute voronoi tesselation for various measures -local measure = cell.manhattan - --- Perform voronoi relaxation at incrementing imax --- Note this isn't very efficient as we are displaying intermediate steps, --- normally you would only call this function once. -local imax = 1 -repeat - print("Step "..imax) - local segments, _, converged = subpattern.voronoi_relax(seeds, sq, measure, imax) - table.sort(segments, function(a,b) return a:centroid().x < b:centroid().x end) - subpattern.pretty_print(sq, segments) - imax = imax + 1 -until converged == true or imax == 100 diff --git a/examples/sampling.lua b/examples/sampling.lua index b11d785..cbcf5e0 100755 --- a/examples/sampling.lua +++ b/examples/sampling.lua @@ -13,13 +13,10 @@ math.randomseed( os.time() ) -- Domain and seed local measure = cell.chebyshev local domain = primitives.square(80,20) -local random = subpattern.random(domain, 40) -local poisson = subpattern.poisson_disc(domain, measure, 5) -local _, lloyd = subpattern.voronoi_relax(random, domain, measure) -print("Random -----------------------------------------------------------------------") -subpattern.pretty_print(domain, {random}) -print("Lloyd's algorithm ------------------------------------------------------------") -subpattern.pretty_print(domain, {lloyd}) -print("Poisson-disc -----------------------------------------------------------------") -subpattern.pretty_print(domain, {poisson}) +-- Random samples, uncomment these turn by turn to see the differences +local random = subpattern.poisson_disc(domain, measure, 5) +--local random = subpattern.random(domain, 40) +--local _, random = subpattern.voronoi_relax(random, domain, measure) + +subpattern.pretty_print(domain, {random}, {'#'}) From ca9f98501ff5035aedcc58cf2faae84f1d718839 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Wed, 11 Jul 2018 19:29:45 +0200 Subject: [PATCH 07/31] Moved generate_img --- examples/generate_img.sh | 19 +++++++++++++++++++ generate_img.sh | 21 --------------------- 2 files changed, 19 insertions(+), 21 deletions(-) create mode 100755 examples/generate_img.sh delete mode 100755 generate_img.sh diff --git a/examples/generate_img.sh b/examples/generate_img.sh new file mode 100755 index 0000000..4652a47 --- /dev/null +++ b/examples/generate_img.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# generate_img.sh +# Generate example images for example gallery +# Requirements: +# - imagemagick +# - Input Mono Light font + +mkdir tmp +mkdir img + +for file in *.lua; do + root="${file%.*}" + echo $root + luajit $file > tmp/$root.txt + convert -size 650x320 xc:black +antialias -font "InputMonoL" -pointsize 12 -fill white \ + -annotate +5+12 "@tmp/$root.txt" ./img/$root.png +done + +rm -rf tmp diff --git a/generate_img.sh b/generate_img.sh deleted file mode 100755 index bfcb3f8..0000000 --- a/generate_img.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# generate_img.sh -# Generate example images for README -# Requirements: -# - imagemagick -# - Input Mono Light font - -IMG_TARGET=./ - -mkdir tmp - -SOURCES=( carpet game_of_life_async caves corridors worley ) - -for i in "${SOURCES[@]}"; do - echo $i - luajit examples/$i.lua > tmp/$i.txt - convert -size 650x320 xc:black +antialias -font "InputMonoL" -pointsize 12 -fill white \ - -annotate +5+12 "@tmp/$i.txt" $IMG_TARGET/$i.png -done - -rm -rf tmp From dbd4df62cc7fc7bec1e156a9aaf75f6878bde7f7 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Thu, 12 Jul 2018 23:44:39 +0200 Subject: [PATCH 08/31] Mitchell's Best-Candidate Algorithm --- examples/sampling.lua | 11 ++++----- forma/subpattern.lua | 52 ++++++++++++++++++++++++++++++++++++++++++- tests/subpattern.lua | 12 ++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/examples/sampling.lua b/examples/sampling.lua index cbcf5e0..ef5f043 100755 --- a/examples/sampling.lua +++ b/examples/sampling.lua @@ -1,9 +1,9 @@ --- sampling.lua -- Demonstrations of various methods for sampling from a pattern. --- `pattern.random` is useful when a regular and uniform sample is not --- required, Lloyd's algorithm when a specific number of uniform samples are --- desired, and Poisson-disc when a minimum separation between samples is the --- only requirement. +-- 1. `pattern.random` generates white noise, it's fast and irreguarly distributed. +-- 2. Lloyd's algorithm when a specific number of uniform samples are desired +-- 3. Mitchell's algorithm is a good (fast) approximation of (2). +-- 3. Poisson-disc when a minimum separation between samples is the only requirement. local cell = require('forma.cell') local subpattern = require('forma.subpattern') @@ -15,7 +15,8 @@ local measure = cell.chebyshev local domain = primitives.square(80,20) -- Random samples, uncomment these turn by turn to see the differences -local random = subpattern.poisson_disc(domain, measure, 5) +local random = subpattern.poisson_disc(domain, measure, 4) +--local random = subpattern.mitchell_sample(domain, measure, 100, 100) --local random = subpattern.random(domain, 40) --local _, random = subpattern.voronoi_relax(random, domain, measure) diff --git a/forma/subpattern.lua b/forma/subpattern.lua index a9561b6..f149d53 100644 --- a/forma/subpattern.lua +++ b/forma/subpattern.lua @@ -67,7 +67,7 @@ end -- together than a specified radius. While much slower than `subpattern.random`, -- it provides a more uniform distribution of points in the domain (simmilar to -- that of `subpattern.voronoi_relax`). --- @param ip domain pattern to sampling from +-- @param ip domain pattern to sample from -- @param distance a measure of distance between two cells d(a,b) e.g cell.euclidean -- @param radius the minimum separation in `distance` between two sample points. -- @param rng (optional) a random number generator, following the signature of math.random. @@ -89,6 +89,56 @@ function subpattern.poisson_disc(ip, distance, radius, rng) return sample end +--- Mitchell's best candidate sampling. +-- Generates an approximate Poisson-disc sampling by Mitchell's algorithm. +-- Picks 'k' sample point attempts at every iteration, and picks the candidate +-- that maximises the distance to existing samples. Halts when `n` samples are +-- picked. +-- @param ip domain pattern to sample from +-- @param distance a measure of distance between two cells d(a,b) e.g cell.euclidean +-- @param n the requested number of samples +-- @param k the number of candidates samples at each iteration +-- @param rng (optional) a random number generator, following the signature of math.random. +-- @return an approximate Poisson-disc sample of `domain` +function subpattern.mitchell_sample(ip, distance, n, k, rng) + -- Bridson's Poisson Disk would be better, but it's hard to implement as it + -- needs a rasterised form of an isosurface for a general distance matric. + assert(getmetatable(ip) == pattern, + "subpattern.mitchell_sample requires a pattern as the first argument") + assert(ip:size() >= n, + "subpattern.mitchell_sample requires a pattern with at least as many points as in the requested sample") + assert(distance(cell.new(5,5), cell.new(5,5)) == 0, + "subpattern.mitchell_sample requires a distance measure as the second argument") + assert(type(n) == "number", "subpattern.mitchell_sample requires a target number of samples") + assert(type(k) == "number", "subpattern.mitchell_sample requires a target number of candidate tries") + if rng == nil then rng = math.random end + local seed = ip:rcell() + local sample = pattern.new():insert(seed.x, seed.y) + for _ = 2, n, 1 do + + local min_distance = 0 + local min_sample = nil + + -- Generate k samples, keeping the furthest + for _=1, k, 1 do + local jcell = ip:rcell(rng) + while sample:has_cell(jcell.x, jcell.y) do + jcell = ip:rcell(rng) end + local jdistance = math.huge + for vcell in sample:cells() do + jdistance = math.min(jdistance, distance(jcell, vcell)) + end + if jdistance > min_distance then + min_sample = jcell + min_distance = jdistance + end + end + -- Push selected sample + sample:insert(min_sample.x, min_sample.y) + end + return sample +end + --- Returns the contiguous sub-pattern of ip that surrounts cell pt -- @param ip pattern upon which the flood fill is to be performed -- @param ipt specifies where the flood fill should begin diff --git a/tests/subpattern.lua b/tests/subpattern.lua index cd889ba..acd17e6 100644 --- a/tests/subpattern.lua +++ b/tests/subpattern.lua @@ -106,6 +106,18 @@ function testSubPatterns:testPoissonDisk() lu.assertTrue(self:check_for_overlap({domain, sample})) end +-- Mitchell's best-candidate sampling ------------------------------------------------- +function testSubPatterns:testMitchellSampling() + -- Approximate Poisson-disc by Mitchell's best-candidate algorithm + local measure = cell.chebyshev + local domain = primitives.square(10) + local sample = subpattern.mitchell_sample(domain, measure, 10, 10) + -- Check that domain is unmodified + lu.assertEquals(domain:size(), 100) + -- Check that the sample doesn't fall out of the domain + lu.assertTrue(self:check_for_overlap({domain, sample})) +end + -- Maximum Rectangle --------------------------------------------------------------- function testSubPatterns:testMaxRectangle() -- Basic test of the 'maximum rectangular area' subpattern finder. From 22a86f0f14098192625c98f4e258306c7713ade1 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Thu, 12 Jul 2018 23:45:10 +0200 Subject: [PATCH 09/31] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29cc341..5b1fece 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,3 +30,4 @@ - Removed some (confusing) functionality from `cell`, namely addition and multiplication with a number value. - Added isoline drawing example +- Added Mitchells Best-Candidate sampling (approximate Poisson-Disc) From 870ee32652e469c4efd8bfff8935b7f1abf951e3 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 00:07:36 +0200 Subject: [PATCH 10/31] Faster shuffled_cells iterator --- forma/pattern.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/forma/pattern.lua b/forma/pattern.lua index 8769a50..43b3895 100644 --- a/forma/pattern.lua +++ b/forma/pattern.lua @@ -256,18 +256,18 @@ function pattern.shuffled_cells(ip, rng) local icell = 0 local ncell = ip:size() - -- Copy cell keys + -- Copy and Fisher-Yates shuffle + local cellkeys = ip.cellkey local skeys = {} - for i=1,ncell,1 do - skeys[#skeys+1] = ip.cellkey[i] - end - - -- Fisher-Yates shuffle - for i=ncell,1,-1 do - local j = rng(ncell) - skeys[i], skeys[j] = skeys[j], skeys[i] + for i = 1, ncell, 1 do + local j = rng(1, i) + if j ~= i then + skeys[i] = skeys[j] + end + skeys[j] = cellkeys[i] end + -- Return iterator return function() icell = icell + 1 if icell <= ncell then From f0cf0a59025d749d3e71e86553473bae276d6af8 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 00:51:51 +0200 Subject: [PATCH 11/31] automata doc improvements --- forma/automata.lua | 97 ++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/forma/automata.lua b/forma/automata.lua index 5beb5b1..531cc63 100644 --- a/forma/automata.lua +++ b/forma/automata.lua @@ -1,58 +1,47 @@ --- Pattern manipulation with Cellular Automata. -- --- This module provides various functions useful for the generation or --- modification of a `pattern` by means of **Cellular Automata**. --- -- Cellular Automata are defined here by two parameters. Firstly a --- `neighbourhood` that the rule acts on, and secondly conditions under which --- cells are *Born* (B) or *Survive* (S). The neighbourhood is specified with --- a `neighbourhood` class and the B/S conditions by a string rule in the --- "Golly" format. i.e a rule which activates `cell`s with one neighbour and --- deactivates cells with two would have the rule string "B1/S2". +-- `neighbourhood` that the rule acts on. Secondly a `rule` specifying the +-- conditions under which cells are *Born* (B) or *Survive* (S). These rules +-- are initialised with a string rule in the "Golly" format. i.e a rule which +-- activates cells with one neighbour and deactivates cells with two would have +-- the rule string "B1/S2". The neighbourhood is specified by an instance of +-- the `neighbourhood` submodule as usual. -- --- Once a rule is specified, there are two implementations of CA used here. +-- Once a rule is specified, there are two provided implementations of a CA. -- Firstly the standard *synchronous* CA is implemented in `automata.iterate` -- whereby all cells are updated simultaneously. Secondly an *asynchronous* --- update is provided in `automata.iterate_async` in which each iteration +-- update is provided in `automata.async_iterate` in which each iteration -- updates only one cell at random. -- -- For both methods, multiple rules can be applied simultaneously through the --- ruleset by supplying a table containting more than one `forma.rule`. Rule +-- ruleset by supplying a table containting more than one `rule`. Rule -- conflicts are resolved in favour of cell deactivation, i.e if there are two -- nested rulesets, with a cell passing one and failing the other either -- survival or birth rules, the cell will be deactivated in the next iteration. -- +-- All CA updates here are only possible on a *finite* domain of cells. That +-- domain must be specified as a `pattern` in the iteration call. +-- -- Both the synchronous and asynchronous iterations return the result of one CA -- iteration and a bool specifying whether or not the iteration has converged -- to a stable pattern. -- --- All CA updates here are only possible on a *finite* domain of cells. That --- domain must be specified in the iteration call. --- --- @usage --- Domain and start seed for the CA --- local domain = primitives.square(80,20) --- local ca_pattern = subpattern.random(sq, 0.5*sq:size()) +--### Relevant examples -- --- -- Game of life rule --- local life = automata.rule(neighbourhood.moore(), "B3/S23") --- --- -- Repeat iteration until convergence is reached --- local converged = false --- repeat --- ca_pattern, converged = automata.iterate(ca_pattern, domain, {life}) --- until converged == true +-- - @{cellular_automata.lua} +-- - @{async_automata.lua} -- -- @module forma.automata local automata= {} local pattern = require('forma.pattern') ---- Cellular automata rule parsing. +-- Cellular automata rule parsing. -- Takes a string signature i.e "X1234" and converts it into a boolean lookup-table -- @param nbh the requested neighbourhood of the rule -- @param rulesub the string signature in question --- @return a boolean look-up table for the rule +-- @return A boolean look-up table for the rule local function parse_rule(nbh, rulesub) local ruletable = {} for i=2,#rulesub,1 do @@ -74,28 +63,29 @@ end -- initialises a rule, and performs a few consistency checks. -- @usage -- -- Initialise a rule corresponding to Conway's Game of Life --- local rule = automata.rule(neighbourhood.moore(), "B3/S23") +-- local gol_rule = automata.rule(neighbourhood.moore(), "B3/S23") -- @param neighbourhood specifying the `neighbourhood` the rule is to be applied in. --- @param rulesig string specifying the ruleset (i.e B23/S1). --- @return a verified rule for CA -function automata.rule(neighbourhood, rulesig) +-- @param rule_string string specifying the ruleset (i.e B23/S1). +-- @return A verified rule for use with the CA methods. +function automata.rule(neighbourhood, rule_string) assert(type(neighbourhood) == 'table', "forma.automata.rule: first argument must be a neighbourhood table") - assert(type(rulesig) == 'string', "forma.automata.rule: parse_rules trying to parse a " .. type(rulesig)) - local Bpos, Spos = string.find(rulesig, 'B'), string.find(rulesig, 'S') - assert(Bpos == 1 and Spos ~= nil, "forma.automata.rule: parse_rules cannot understand rule " .. rulesig) - local Brule, Srule = string.sub(rulesig, 1, Spos-2), string.sub(rulesig, Spos, #rulesig) + assert(type(rule_string) == 'string', "forma.automata.rule: parse_rules trying to parse a " .. type(rule_string)) + local Bpos, Spos = string.find(rule_string, 'B'), string.find(rule_string, 'S') + assert(Bpos == 1 and Spos ~= nil, "forma.automata.rule: parse_rules cannot understand rule " .. rule_string) + local Brule, Srule = string.sub(rule_string, 1, Spos-2), string.sub(rule_string, Spos, #rule_string) local newrule = {neighbourhood = neighbourhood} newrule.B = parse_rule(neighbourhood, Brule) newrule.S = parse_rule(neighbourhood, Srule) return newrule end ---- Pattern neighbour count. +-- Pattern neighbour count. -- Counts how many adjacent cells there are to a cell at (ix, iy) -- @param pa provided pattern for neighbour count -- @param nbh neighbourhood for testing -- @param ix x-coordinate of point check -- @param iy y-coordinate of point check +-- @return Number of active cells in the neighbourhood of cell (ix, iy) local function nCount(pa, nbh, ix, iy) local n = 0 for i=1,#nbh,1 do @@ -105,7 +95,7 @@ local function nCount(pa, nbh, ix, iy) return n end ---- Ruleset pass/fail analysis +-- Ruleset pass/fail analysis -- This function assesses whether or not a cell should be alive local function check_cell(ruleset, ipattern, ix, iy) local alive = ipattern:has_cell(ix, iy) @@ -125,7 +115,7 @@ local function check_cell(ruleset, ipattern, ix, iy) return true end ---- Check that the ruleset has no nil entries +-- Check that the ruleset has no nil entries local function check_ruleset(ruleset) for i=1, #ruleset, 1 do assert(ruleset[i], "forma.automata check_ruleset: nil element found in ruleset") @@ -139,10 +129,20 @@ end --- Synchronous cellular automata iteration. -- Performs one standard synchronous CA update on pattern prevp in the specified domain. +-- @usage +-- -- Domain and initial state (500 seed points) for the CA +-- local domain = primitives.square(100) +-- local ca_pat = subpattern.random(sq, 500) +-- -- Repeat iteration until convergence is reached +-- local converged = false +-- repeat +-- ca_pat, converged = automata.iterate(ca_pat, domain, {gol_rule}) +-- until converged == true -- @param prevp the previous iteration of the pattern -- @param domain the cells in which the CA operates --- @param ruleset a list of forma.rules for performing the CA on --- @return the next iteration, and a bool specifying if convergence has been reached. +-- @param ruleset a table of forma.rules defining the CA +-- @return The result of the CA iteration [pattern]. +-- @return Convergence flag [bool: true if converged, false otherwise]. function automata.iterate(prevp, domain, ruleset) assert(getmetatable(prevp) == pattern, "forma.automata: iterate requires a pattern as a first argument") @@ -160,11 +160,22 @@ end --- Asynchronous cellular automata iteration. -- Performs a CA update on one cell (chosen randomly) in the specified domain. +-- @usage +-- -- Domain and initial state (500 seed points) for the CA +-- local domain = primitives.square(100) +-- local ca_pat = subpattern.random(sq, 500) +-- local rng = math.random +-- -- Repeat iteration until convergence is reached +-- local converged = false +-- repeat +-- ca_pat, converged = automata.async_iterate(ca_pat, domain, {gol_rule}, rng) +-- until converged == true -- @param prevp the previous iteration of the pattern -- @param domain the cells in which the CA operates --- @param ruleset a list of forma.rules for performing the CA on +-- @param ruleset a table of forma.rules defining the CA -- @param rng a (optional) random number generator (syntax as per math.random). --- @return the next iteration, and a bool specifying if convergence has been reached. +-- @return The result of the CA iteration [pattern]. +-- @return Convergence flag [bool: true if converged, false otherwise]. function automata.async_iterate(prevp, domain, ruleset, rng) if rng == nil then rng = math.random end assert(getmetatable(prevp) == pattern, From 06b6f976db8261b4cf3a199a43c4e5526c87d07e Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 00:57:52 +0200 Subject: [PATCH 12/31] cell doc pass --- forma/cell.lua | 57 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/forma/cell.lua b/forma/cell.lua index 2203d80..503db5a 100644 --- a/forma/cell.lua +++ b/forma/cell.lua @@ -9,19 +9,6 @@ -- between cell positions are provided. Specifically, the Manhattan, Chebyshev -- and Euclidean distances. -- --- @usage --- -- Initialisation and cloning of points --- local c1 = cell.new(x,y) -- Constructor --- local c2 = cell.clone(c1) -- Clone ('procedural' style) --- local c3 = c1:clone() -- Clone ('method' stype) --- --- -- Arithmetic --- local c4 = (c1 + c2) - c3 --- --- -- Distance measures --- local d1 = cell.manhattan(c1,c2) -- Manhattan distance ('procedural' stype) --- local d2 = c1:manhattan(c2) -- Manhattan distance ('method' style) --- -- @module forma.cell local cell = {} @@ -35,6 +22,9 @@ local floor = math.floor cell.__index = cell --- Initialise a new forma.cell. +-- @usage +-- local x, y = 1, 5 +-- local new_cell = cell.new(x,y) -- @param x first coordinate -- @param y second coordinate -- @return new forma.cell @@ -46,6 +36,9 @@ function cell.new(x,y) end --- Perform a copy of a cell. +-- @usage +-- local old_cell = cell.new(1,1) +-- local new_cell = old_cell:clone() -- @param icell to be copied -- @return copy of `icell` function cell.clone(icell) @@ -54,6 +47,10 @@ function cell.clone(icell) end --- Add two cell positions +-- @usage +-- local c1, c2 = cell.new(1,1), cell.new(0,0) +-- local c3 = c2 + c1 +-- assert(c3 == c1) -- @within Metamethods -- @param a first cell -- @param b second cell @@ -63,6 +60,10 @@ function cell.__add(a, b) end --- Subtract two cell positions +-- @usage +-- local c1, c2 = cell.new(1,1), cell.new(2,2) +-- local c3 = c2 - c1 +-- assert(c3 == c1) -- @within Metamethods -- @param a first cell -- @param b second cell @@ -72,6 +73,7 @@ function cell.__sub(a, b) end --- Test for equality of two cell vectors. +-- assert(cell.new(0,1) == cell.new(0,1) -- @within Metamethods -- @param a first cell -- @param b second cell @@ -81,6 +83,8 @@ function cell.__eq(a, b) end --- Render a cell as a string. +-- @usage +-- print(cell.new(1,1)) -- @within Metamethods -- @param icell the forma.cell being rendered as a string -- @return string of the form `(icell.x, icell.y)` @@ -89,6 +93,8 @@ function cell.__tostring(icell) end --- Manhattan distance between cells. +-- @usage +-- local distance = cell.manhattan(acell, bcell) -- @within Distance measures -- @param a first cell -- @param b second cell @@ -98,6 +104,8 @@ function cell.manhattan(a,b) end --- Chebyshev distance between cells. +-- @usage +-- local distance = cell.chebyshev(acell, bcell) -- @within Distance measures -- @param a first cell -- @param b second cell @@ -106,7 +114,21 @@ function cell.chebyshev(a,b) return max(abs(a.x-b.x), abs(a.y-b.y)) end +--- Euclidean distance between cells. +-- @usage +-- local distance = cell.euclidean(acell, bcell) +-- @within Distance measures +-- @param a first cell +-- @param b second cell +-- @return L_2(a,b) = sqrt((a-b)^2) +function cell.euclidean(a,b) + return sqrt(cell.euclidean2(a,b)) +end + --- Squared Euclidean distance between cells. +-- A little faster than `cell.euclidean` as it avoids the sqrt. +-- @usage +-- local distance = cell.euclidean2(acell, bcell) -- @within Distance measures -- @param a first cell -- @param b second cell @@ -117,15 +139,6 @@ function cell.euclidean2(a,b) return dx*dx+dy*dy end ---- Euclidean distance between cells. --- @within Distance measures --- @param a first cell --- @param b second cell --- @return L_2(a,b) = sqrt((a-b)^2) -function cell.euclidean(a,b) - return sqrt(cell.euclidean2(a,b)) -end - return cell From d51b5a946de964515b3b864add6553abddeef279 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 01:05:45 +0200 Subject: [PATCH 13/31] More documentation improvements --- forma/neighbourhood.lua | 6 +++--- forma/subpattern.lua | 31 +++++++++++++++++-------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/forma/neighbourhood.lua b/forma/neighbourhood.lua index c69e5b3..206f44c 100644 --- a/forma/neighbourhood.lua +++ b/forma/neighbourhood.lua @@ -1,9 +1,9 @@ --- Cell neighbourhood definitions. --- The **neighbourhood** of a `cell` in a `pattern` defines which other cells are --- considered its neighbours. This is an important definition for many +-- The **neighbourhood** of a `cell` in a `pattern` defines which other cells +-- are considered its neighbours. This is an important definition for many -- functions in forma. For example, when finding all cells that border a -- pattern in `subpattern.edge` a definition of *border* in terms of a --- neighbourhood is required. Cellular `automata` rules are also defined in +-- neighbourhood is required. Cellular `automata` rules are also defined in -- terms of neighbourhoods. -- -- This module provides a class to represent a neighbourhood, along with diff --git a/forma/subpattern.lua b/forma/subpattern.lua index f149d53..9ec53fe 100644 --- a/forma/subpattern.lua +++ b/forma/subpattern.lua @@ -3,12 +3,12 @@ -- `pattern`. The simplest of these is the `random` sampling of a fraction of -- `cell`s from the parent. -- --- Several of these finders return a list of all relevant sub-patterns. For --- example the `segments` method which returns a list of all contiguous +-- Several of these finders return a table of all relevant sub-patterns. For +-- example the `segments` method which returns a table of all contiguous -- (according to some `neighbourhood`) sub-patterns by using a `floodfill`. -- -- In addition to the subpattern finders, a `pretty_print` utility is provided --- to render these lists of sub-patterns into text. +-- to render these tables of sub-patterns into text. -- -- @module forma.subpattern @@ -26,6 +26,7 @@ local neighbourhood = require('forma.neighbourhood') -- Generate a subpattern by applying a boolean mask to an input pattern. -- @param ip the pattern to be masked. -- @param mask a function that takes a `cell` and returns true if the cell passes the mask +-- @return A pattern consisting only of those cells in `domain` which pass the `mask` argument. function subpattern.mask(ip, mask) assert(getmetatable(ip) == pattern, "subpattern.mask requires a pattern as the first argument") assert(type(mask) == 'function', 'subpattern.mask requires a function for the mask') @@ -230,7 +231,7 @@ end --- Find the maximal contiguous rectangular area within a pattern. -- @param ip the input pattern --- @return the subpattern of `ip` consisting of its largest contiguous rectangular area. +-- @return The subpattern of `ip` consisting of its largest contiguous rectangular area. function subpattern.maxrectangle(ip) assert(getmetatable(ip) == pattern, "subpattern.maxrectangle requires a pattern as an argument") local min, max = maxrectangle_coordinates(ip) @@ -242,12 +243,12 @@ end --- Lists of sub-patterns -- @section subpattern_lists ---- Generate a list of contiguous 'segments' or sub-patterns. +--- Generate a table of contiguous 'segments' or sub-patterns. -- This performs a series of flood-fill operations until all -- pattern cells are accounted for in the sub-patterns -- @param ip pattern for which the segments are to be extracted -- @param nbh defines which neighbourhood to scan in while flood-filling (default 8/moore) --- @return a table of forma.patterns consisting of contiguous sub-patterns of ip +-- @return A table of forma.patterns consisting of contiguous sub-patterns of ip. function subpattern.segments(ip, nbh) assert(getmetatable(ip) == pattern, "subpattern.segments requires a pattern as the first argument") nbh = nbh or neighbourhood.moore() @@ -261,12 +262,12 @@ function subpattern.segments(ip, nbh) return segs end ---- Returns a list of 'enclosed' segments of a pattern. +--- Returns a table of 'enclosed' segments of a pattern. -- Enclosed areas are the inactive areas of a pattern which are -- completely surrounded by active areas -- @param ip pattern for which the enclosed areas should be computed -- @param nbh defines which directions to scan in while flood-filling (default 4/vn) --- @return a list of forma.patterns comprising the enclosed areas of ip +-- @return A table of forma.patterns comprising the enclosed areas of ip. function subpattern.enclosed(ip, nbh) assert(getmetatable(ip) == pattern, "subpattern.enclosed requires a pattern as the first argument") assert(ip:size() > 0, "subpattern.enclosed requires a non-empty pattern as the first argument") @@ -346,7 +347,7 @@ end -- into one of the neighbourhood's categories. -- @param ip the pattern in which cells are to be categorised -- @param nbh the forma.neighbourhood used for the categorisation --- @return a table of #nbh patterns, where each cell in ip is categorised +-- @return A table of #nbh patterns, where each cell in ip is categorised. function subpattern.neighbourhood_categories(ip, nbh) assert(getmetatable(ip) == pattern, "subpattern.neighbourhood_categories requires a pattern as a first argument") @@ -367,7 +368,7 @@ end -- @param seeds the set of seed cells for the tesselation -- @param domain the domain of the tesselation -- @param measure the measure used to judge distance between cells --- @return a list of Voronoi segments +-- @return A table of Voronoi segments. function subpattern.voronoi(seeds, domain, measure) assert(getmetatable(seeds) == pattern, "subpattern.voronoi requires a pattern as a first argument") assert(getmetatable(domain) == pattern, "subpattern.voronoi requires a pattern as a second argument") @@ -402,7 +403,9 @@ end -- @param domain the domain to be tesselated -- @param measure the distance measure to be used between cells -- @param max_ite (optional) maximum number of iterations of relaxation (default 30) --- @return (segments, segment centres, convergence bool) +-- @return A table of resuling Voronoi segments. +-- @return A `pattern` consisting of the voronoi segment centres. +-- @return A bool, true if the algorithm converged, false if not. function subpattern.voronoi_relax(seeds, domain, measure, max_ite) if max_ite == nil then max_ite = 30 end assert(getmetatable(seeds) == pattern, "subpattern.voronoi_relax requires a pattern as a first argument") @@ -444,8 +447,8 @@ end --- Utilities -- @section subpattern_utils ---- Pretty print a list of forma.pattern segments. --- Prints a list of pattern segments to `io.output`. If provided, a table of +--- Pretty print a table of forma.pattern segments. +-- Prints a table of pattern segments to `io.output`. If provided, a table of -- segment labels can be used, with one entry per segment. -- @param domain the basic pattern from which the segments were generated. -- @param segments the table of segments to be drawn. @@ -463,7 +466,7 @@ function subpattern.pretty_print(domain, segments, chars) end end assert(#segments == #chars, - "subpattern.pretty_print: there must be as many character list entries as segments") + "subpattern.pretty_print: there must be as many character table entries as segments") -- Print out the segments to a map for i=domain.min.y, domain.max.y,1 do local string = '' From df1caee73e58b2d5fdc8bc92e375eee383a5546d Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 01:07:31 +0200 Subject: [PATCH 14/31] Enumerated multiple returns in docs --- TODO.md | 1 - docs/contents.html | 41 +-- docs/examples/async_automata.lua.html | 116 +++++++ docs/examples/binary_space_partition.lua.html | 32 +- docs/examples/bubbles.lua.html | 99 ++++++ docs/examples/cellular_automata.lua.html | 104 +++++++ docs/examples/corridors.lua.html | 15 +- docs/examples/isolines.lua.html | 112 +++++++ docs/examples/maxrectangle.lua.html | 31 +- docs/examples/platformer.lua.html | 15 +- docs/examples/sampling.lua.html | 101 +++++++ docs/examples/voronoi.lua.html | 33 +- docs/modules/automata.html | 286 ++++++++++++++++++ docs/modules/forma.automata.html | 115 ++++--- docs/modules/forma.cell.html | 184 +++++------ docs/modules/forma.neighbourhood.html | 21 +- docs/modules/forma.pattern.html | 16 +- docs/modules/forma.primitives.html | 15 +- docs/modules/forma.subpattern.html | 105 +++++-- docs/readme/README.md.html | 54 ++-- 20 files changed, 1152 insertions(+), 344 deletions(-) create mode 100644 docs/examples/async_automata.lua.html create mode 100644 docs/examples/bubbles.lua.html create mode 100644 docs/examples/cellular_automata.lua.html create mode 100644 docs/examples/isolines.lua.html create mode 100644 docs/examples/sampling.lua.html create mode 100644 docs/modules/automata.html diff --git a/TODO.md b/TODO.md index f2c760c..e185d97 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,4 @@ # TODO - Luarocks -- Enumerate return values in documentation - Example gallery diff --git a/docs/contents.html b/docs/contents.html index dffdd1b..cdb9574 100644 --- a/docs/contents.html +++ b/docs/contents.html @@ -44,19 +44,16 @@

Readme

Examples

@@ -103,31 +100,27 @@

Readme

Examples

- - - - - + - + - + - + - + - + @@ -139,28 +132,20 @@

Examples

- - - - - + - - - -
binary_space_partition.lua
carpet.luaasync_automata.lua
caves.luabinary_space_partition.lua
corridors.luabubbles.lua
game_of_life.luacellular_automata.lua
game_of_life_async.luacorridors.lua
lloyds_algorithm.luaisolines.lua
primitives.lua
shapes.luasampling.lua
voronoi.lua
worley.lua
generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
diff --git a/docs/examples/async_automata.lua.html b/docs/examples/async_automata.lua.html new file mode 100644 index 0000000..66fdffc --- /dev/null +++ b/docs/examples/async_automata.lua.html @@ -0,0 +1,116 @@ + + + + + forma Reference Manual + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

async_automata.lua

+
+-- async_automata.lua.
+-- Here the use of an asynchronous cellular automata is demonstrated, making
+-- use also of symmetrisation methods to generate a final, symmetric pattern.
+
+local pattern       = require('forma.pattern')
+local primitives    = require('forma.primitives')
+local automata      = require('forma.automata')
+local subpattern    = require('forma.subpattern')
+local neighbourhood = require('forma.neighbourhood')
+
+math.randomseed( os.time() )
+
+-- Domain for CA to operate in
+local sq = primitives.square(10,5)
+
+-- Make a new pattern consisting of a single random cell from the domain
+local start_point = sq:rcell() -- Select a random point
+local ca_pattern  = pattern.new():insert(start_point.x, start_point.y)
+
+-- Moore neighbourhood rule for CA
+local moore = automata.rule(neighbourhood.moore(), "B12/S012345678")
+
+-- Perform asynchronous CA update until convergence
+local converged = false
+while converged == false do
+    ca_pattern, converged = automata.async_iterate(ca_pattern, sq, {moore})
+end
+
+-- Mirror the basic pattern a couple of times
+local symmetrised_pattern = ca_pattern:hreflect()
+symmetrised_pattern = symmetrised_pattern:vreflect():vreflect()
+symmetrised_pattern = symmetrised_pattern:hreflect():hreflect()
+
+-- Categorise the pattern according to possible vN neighbours and print to screen
+-- This turns the basic pattern into standard 'box-drawing' characters
+local vn = neighbourhood.von_neumann()
+local segments = subpattern.neighbourhood_categories(symmetrised_pattern, vn)
+subpattern.pretty_print(symmetrised_pattern, segments, vn:category_label())
+ + +
+
+
+generated by LDoc 1.4.6 +Last updated 2018-07-13 01:06:54 +
+
+ + diff --git a/docs/examples/binary_space_partition.lua.html b/docs/examples/binary_space_partition.lua.html index 178971e..9ddf90c 100644 --- a/docs/examples/binary_space_partition.lua.html +++ b/docs/examples/binary_space_partition.lua.html @@ -34,19 +34,16 @@

forma

Examples

Modules

    @@ -69,27 +66,24 @@

    Readme

    binary_space_partition.lua

     -- binary_space_partition.lua
    --- Example and benchmark of binary space partitioning
    +-- Example of binary space partitioning
     
     local subpattern = require('forma.subpattern')
     local primitives = require('forma.primitives')
    -math.randomseed(0)
     
    --- stress loops for benchmarking
    -for i=1,100,1 do
    -    -- Generate an 80x20 square and partition it into segments of maximally 50 cells
    -    local square = primitives.square(80,20)
    -    local bsp = subpattern.bsp(square, 50)
    -    -- On the last loop, pretty print the segments
    -    if i==100 then subpattern.pretty_print(square,bsp) end
    -end
    +-- Generate an 80x20 square and partition it into segments of maximally 50 cells +local square = primitives.square(80,20) +local bsp = subpattern.bsp(square, 50) + +-- Pretty print resulting pattern segments +subpattern.pretty_print(square,bsp)
    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    diff --git a/docs/examples/bubbles.lua.html b/docs/examples/bubbles.lua.html new file mode 100644 index 0000000..1b1a5c3 --- /dev/null +++ b/docs/examples/bubbles.lua.html @@ -0,0 +1,99 @@ + + + + + forma Reference Manual + + + + +
    + +
    + +
    +
    +
    + + +
    + + + + + + +
    + +

    bubbles.lua

    +
    +-- Example of circle primitives
    +local cell       = require('forma.cell')
    +local pattern    = require('forma.pattern')
    +local primitives = require('forma.primitives')
    +local subpattern = require('forma.subpattern')
    +
    +math.randomseed( os.time() )
    +local max_radius = 4
    +
    +-- Setup domain and some random seeds
    +local domain = primitives.square(80,20)
    +local seeds  = subpattern.poisson_disc(domain, cell.euclidean, 2*max_radius)
    +local shapes = pattern.new()
    +
    +-- Randomly generate some circles in the domain
    +for seed in seeds:cells() do
    +    local circle = primitives.circle(math.random(2, max_radius))
    +    shapes = shapes + circle:shift(seed.x, seed.y)
    +end
    +
    +subpattern.pretty_print(domain, {shapes}, {'o'})
    + + +
    +
    +
    +generated by LDoc 1.4.6 +Last updated 2018-07-13 01:06:54 +
    +
    + + diff --git a/docs/examples/cellular_automata.lua.html b/docs/examples/cellular_automata.lua.html new file mode 100644 index 0000000..5c380df --- /dev/null +++ b/docs/examples/cellular_automata.lua.html @@ -0,0 +1,104 @@ + + + + + forma Reference Manual + + + + +
    + +
    + +
    +
    +
    + + +
    + + + + + + +
    + +

    cellular_automata.lua

    +
    +-- cellular_automata.lua
    +-- Demonstration of classic cellular-automata cave generation (4-5 rule)
    +
    +local primitives    = require('forma.primitives')
    +local subpattern    = require('forma.subpattern')
    +local automata      = require('forma.automata')
    +local neighbourhood = require('forma.neighbourhood')
    +
    +math.randomseed( os.time() )
    +
    +-- Domain for CA
    +local sq = primitives.square(80,20)
    +
    +-- CA initial condition: sample at random from the domain
    +local ca = subpattern.random(sq, math.floor(sq:size()*0.5))
    +
    +-- Moore neighbourhood 4-5 rule
    +local moore = automata.rule(neighbourhood.moore(), "B5678/S45678")
    +local ite, converged = 0, false
    +while converged == false and ite < 1000 do
    +    ca, converged = automata.iterate(ca, sq, {moore})
    +    ite = ite+1
    +end
    +
    +ca.onchar, ca.offchar = "#", " "
    +print(ca)
    + + +
    +
    +
    +generated by LDoc 1.4.6 +Last updated 2018-07-13 01:06:54 +
    +
    + + diff --git a/docs/examples/corridors.lua.html b/docs/examples/corridors.lua.html index a4931f7..0566700 100644 --- a/docs/examples/corridors.lua.html +++ b/docs/examples/corridors.lua.html @@ -34,19 +34,16 @@

    forma

    Examples

    Modules

      @@ -113,7 +110,7 @@

      corridors.lua

      generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
      diff --git a/docs/examples/isolines.lua.html b/docs/examples/isolines.lua.html new file mode 100644 index 0000000..f6c77d1 --- /dev/null +++ b/docs/examples/isolines.lua.html @@ -0,0 +1,112 @@ + + + + + forma Reference Manual + + + + +
      + +
      + +
      +
      +
      + + +
      + + + + + + +
      + +

      isolines.lua

      +
      +-- isolines.lua
      +-- Rasterising isolines of a scalar field.
      +
      +-- Here we generate a pattern randomly filled with points, and take as the
      +-- field N(cell) = F_2(cell) - F_1(cell), where F_n is the chebyshev distance
      +-- to the nth nearest neighbour. Isolines at N = 0 are drawn by thresholding N
      +-- at 1 and taking the surface.
      +
      +local cell          = require('forma.cell')
      +local subpattern    = require('forma.subpattern')
      +local primitives    = require('forma.primitives')
      +math.randomseed( os.time() )
      +
      +-- Distance measure
      +local measure = cell.chebyshev
      +
      +-- Domain and seeds
      +local sq = primitives.square(80,20)
      +local rn = subpattern.random(sq, math.floor(sq:size()*0.01)):cell_list()
      +
      +-- Worley noise mask
      +local mask = function(tcell)
      +    local sortfn = function(a,b)
      +        return measure(tcell, a) < measure(tcell, b)
      +    end
      +    table.sort(rn, sortfn)
      +    local F1 = measure(rn[1], tcell)
      +    local F2 = measure(rn[2], tcell)
      +    return F2 - F1  > 1
      +end
      +
      +-- Compute the thresholded pattern and print its surface
      +local noise = subpattern.mask(sq, mask)
      +subpattern.pretty_print(sq, {noise:surface()}, {'#'})
      + + +
      +
      +
      +generated by LDoc 1.4.6 +Last updated 2018-07-13 01:06:54 +
      +
      + + diff --git a/docs/examples/maxrectangle.lua.html b/docs/examples/maxrectangle.lua.html index 0eb12dd..af5c6e6 100644 --- a/docs/examples/maxrectangle.lua.html +++ b/docs/examples/maxrectangle.lua.html @@ -34,19 +34,16 @@

      forma

      Examples

      Modules

        @@ -69,17 +66,21 @@

        Readme

        maxrectangle.lua

         -- maxrectangle.lua
        --- Example and benchmark of maximum rectangle finding
        +-- Example of maximum rectangle finding in a general domain
         
         local pattern    = require('forma.pattern')
         local subpattern = require('forma.subpattern')
         local primitives = require('forma.primitives')
        -math.randomseed(0)
         
        --- Generate some messy base pattern
        -local total_pattern = pattern.new()
        -for _=1,100,1 do
        -    local tp = primitives.square(math.random(5)):shift(math.random(20), math.random(20))
        +math.randomseed( os.time() )
        +
        +-- Generate a messy pattern inside a domain
        +local domain = primitives.square(80, 20)
        +local total_pattern = pattern.new()
        +for _=1,200,1 do
        +    -- Generate a randomly sized square at a random point of the domain
        +    local rpoint = domain:rcell()
        +    local tp = primitives.square(math.random(7)):shift(rpoint.x, rpoint.y)
             total_pattern = total_pattern + tp
         end
         
        @@ -93,7 +94,7 @@ 

        maxrectangle.lua

        generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
        diff --git a/docs/examples/platformer.lua.html b/docs/examples/platformer.lua.html index fa10226..1c279bb 100644 --- a/docs/examples/platformer.lua.html +++ b/docs/examples/platformer.lua.html @@ -34,19 +34,16 @@

        forma

        Examples

        Modules

          @@ -112,7 +109,7 @@

          platformer.lua

          generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
          diff --git a/docs/examples/sampling.lua.html b/docs/examples/sampling.lua.html new file mode 100644 index 0000000..6a8601d --- /dev/null +++ b/docs/examples/sampling.lua.html @@ -0,0 +1,101 @@ + + + + + forma Reference Manual + + + + +
          + +
          + +
          +
          +
          + + +
          + + + + + + +
          + +

          sampling.lua

          +
          +--- sampling.lua
          +-- Demonstrations of various methods for sampling from a pattern.
          +-- 1. pattern.random generates white noise, it's fast and irreguarly distributed.
          +-- 2. Lloyd's algorithm when a specific number of uniform samples are desired
          +-- 3. Mitchell's algorithm is a good (fast) approximation of (2).
          +-- 3. Poisson-disc when a minimum separation between samples is the only requirement.
          +
          +local cell          = require('forma.cell')
          +local subpattern    = require('forma.subpattern')
          +local primitives    = require('forma.primitives')
          +math.randomseed( os.time() )
          +
          +-- Domain and seed
          +local measure = cell.chebyshev
          +local domain   = primitives.square(80,20)
          +
          +-- Random samples, uncomment these turn by turn to see the differences
          +local random  = subpattern.poisson_disc(domain, measure, 4)
          +--local random  = subpattern.mitchell_sample(domain, measure, 100, 100)
          +--local random   = subpattern.random(domain, 40)
          +--local _, random = subpattern.voronoi_relax(random, domain, measure)
          +
          +subpattern.pretty_print(domain, {random}, {'#'})
          + + +
          +
          +
          +generated by LDoc 1.4.6 +Last updated 2018-07-13 01:06:54 +
          +
          + + diff --git a/docs/examples/voronoi.lua.html b/docs/examples/voronoi.lua.html index 78d2e52..dc8a543 100644 --- a/docs/examples/voronoi.lua.html +++ b/docs/examples/voronoi.lua.html @@ -34,19 +34,16 @@

          forma

          Examples

          Modules

            @@ -76,28 +73,22 @@

            voronoi.lua

            local subpattern = require('forma.subpattern') math.randomseed(os.time()) --- Generate a random pattern and its voronoi tesselation +-- Generate a random pattern in a specified domain local sq = primitives.square(80,20) -local rn = subpattern.random(sq, math.floor(sq:size()*0.01)) +local rn = subpattern.random(sq, 10) --- Compute voronoi tesselation for various measures -local measures = {} -measures.Chebyshev = cell.chebyshev -measures.Euclidean = cell.euclidean -measures.Manhattan = cell.manhattan +-- Compute its voronoi tesselation +local measure = cell.chebyshev +local segments = subpattern.voronoi(rn, sq, measure) -for label, measure in pairs(measures) do - local segments = subpattern.voronoi(rn, sq, measure) - print(label) - subpattern.pretty_print(sq, segments) -end
        +subpattern.pretty_print(sq, segments)
        generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
        diff --git a/docs/modules/automata.html b/docs/modules/automata.html new file mode 100644 index 0000000..6a9f921 --- /dev/null +++ b/docs/modules/automata.html @@ -0,0 +1,286 @@ + + + + + forma Reference Manual + + + + +
        + +
        + +
        +
        +
        + + +
        + + + + + + +
        + +

        Module automata

        +

        Pattern manipulation with Cellular Automata.

        +

        + + +

        This module provides various functions for the generation or modification of + a pattern by means of Cellular Automata.

        + +

        Cellular Automata are defined here by two parameters. Firstly a + neighbourhood that the rule acts on. Secondly a rule specifying the + conditions under which cells are Born (B) or Survive (S). These rules + are initialised with a string rule in the "Golly" format. i.e a rule which + activates cells with one neighbour and deactivates cells with two would have + the rule string "B1/S2". The neighbourhood is specified by an instance of + the neighbourhood submodule as usual.

        + +

        Once a rule is specified, there are two provided implementations of a CA. + Firstly the standard synchronous CA is implemented in automata.iterate + whereby all cells are updated simultaneously. Secondly an asynchronous + update is provided in automata.async_iterate in which each iteration + updates only one cell at random.

        + +

        For both methods, multiple rules can be applied simultaneously through the + ruleset by supplying a table containting more than one rule. Rule + conflicts are resolved in favour of cell deactivation, i.e if there are two + nested rulesets, with a cell passing one and failing the other either + survival or birth rules, the cell will be deactivated in the next iteration.

        + +

        Both the synchronous and asynchronous iterations return the result of one CA + iteration and a bool specifying whether or not the iteration has converged + to a stable pattern.

        + +

        All CA updates here are only possible on a finite domain of cells. That + domain must be specified as a pattern in the iteration call.

        + +

        Relevant examples

        + + +

        + + +

        Ruleset Generation

        + + + + + +
        rule (neighbourhood, rulesig)Define a cellular automata rule.
        +

        CA Iteration

        + + + + + + + + + +
        iterate (prevp, domain, ruleset)Synchronous cellular automata iteration.
        async_iterate (prevp, domain, ruleset, rng)Asynchronous cellular automata iteration.
        + +
        +
        + + +

        Ruleset Generation

        + +
        +
        + + rule (neighbourhood, rulesig) +
        +
        + Define a cellular automata rule. + CA rules in forma are defined by a neighbourhood in the usual CA sense and + a string signature in the 'Golly' format (BXX/SXX). This function + initialises a rule, and performs a few consistency checks. + + +

        Parameters:

        +
          +
        • neighbourhood + specifying the neighbourhood the rule is to be applied in. +
        • +
        • rulesig + string specifying the ruleset (i.e B23/S1). +
        • +
        + +

        Returns:

        +
          + + A verified rule for use with the CA methods. +
        + + + +

        Usage:

        +
          +
          -- Initialise a rule corresponding to Conway's Game of Life
          +local gol_rule = automata.rule(neighbourhood.moore(), "B3/S23")
          +
        + +
        +
        +

        CA Iteration

        + +
        +
        + + iterate (prevp, domain, ruleset) +
        +
        + Synchronous cellular automata iteration. + Performs one standard synchronous CA update on pattern prevp in the specified domain. + + +

        Parameters:

        +
          +
        • prevp + the previous iteration of the pattern +
        • +
        • domain + the cells in which the CA operates +
        • +
        • ruleset + a table of forma.rules defining the CA +
        • +
        + +

        Returns:

        +
          +
        1. + The result of the CA iteration [pattern].
        2. +
        3. + Convergence flag [bool: true if converged, false otherwise].
        4. +
        + + + +

        Usage:

        +
          +
          -- Domain and initial state (500 seed points) for the CA
          +local domain = primitives.square(100)
          +local ca_pat = subpattern.random(sq, 500)
          +-- Repeat iteration until convergence is reached
          +local converged = false
          +repeat
          +	ca_pat, converged = automata.iterate(ca_pat, domain, {gol_rule})
          +until converged == true
          +
        + +
        +
        + + async_iterate (prevp, domain, ruleset, rng) +
        +
        + Asynchronous cellular automata iteration. + Performs a CA update on one cell (chosen randomly) in the specified domain. + + +

        Parameters:

        +
          +
        • prevp + the previous iteration of the pattern +
        • +
        • domain + the cells in which the CA operates +
        • +
        • ruleset + a table of forma.rules defining the CA +
        • +
        • rng + a (optional) random number generator (syntax as per math.random). +
        • +
        + +

        Returns:

        +
          +
        1. + The result of the CA iteration [pattern].
        2. +
        3. + Convergence flag [bool: true if converged, false otherwise].
        4. +
        + + + +

        Usage:

        +
          +
          -- Domain and initial state (500 seed points) for the CA
          +local domain = primitives.square(100)
          +local ca_pat = subpattern.random(sq, 500)
          +local rng    = math.random
          +-- Repeat iteration until convergence is reached
          +local converged = false
          +repeat
          +	ca_pat, converged = automata.async_iterate(ca_pat, domain, {gol_rule}, rng)
          +until converged == true
          +
        + +
        +
        + + +
        +
        +
        +generated by LDoc 1.4.6 +Last updated 2018-07-13 00:47:33 +
        +
        + + diff --git a/docs/modules/forma.automata.html b/docs/modules/forma.automata.html index eb639b0..ea48bae 100644 --- a/docs/modules/forma.automata.html +++ b/docs/modules/forma.automata.html @@ -52,19 +52,16 @@

        Readme

      Examples

      @@ -73,56 +70,49 @@

      Examples

      Module forma.automata

      Pattern manipulation with Cellular Automata.

      -

      This module provides various functions useful for the generation or - modification of a pattern by means of Cellular Automata.

      +

      -

      Cellular Automata are defined here by two parameters. Firstly a - neighbourhood that the rule acts on, and secondly conditions under which - cells are Born (B) or Survive (S). The neighbourhood is specified with - a neighbourhood class and the B/S conditions by a string rule in the - "Golly" format. i.e a rule which activates cells with one neighbour and - deactivates cells with two would have the rule string "B1/S2".

      -

      Once a rule is specified, there are two implementations of CA used here. +

      Cellular Automata are defined here by two parameters. Firstly a + neighbourhood that the rule acts on. Secondly a rule specifying the + conditions under which cells are Born (B) or Survive (S). These rules + are initialised with a string rule in the "Golly" format. i.e a rule which + activates cells with one neighbour and deactivates cells with two would have + the rule string "B1/S2". The neighbourhood is specified by an instance of + the neighbourhood submodule as usual.

      + +

      Once a rule is specified, there are two provided implementations of a CA. Firstly the standard synchronous CA is implemented in automata.iterate whereby all cells are updated simultaneously. Secondly an asynchronous - update is provided in automata.iterate_async in which each iteration + update is provided in automata.async_iterate in which each iteration updates only one cell at random.

      For both methods, multiple rules can be applied simultaneously through the - ruleset by supplying a table containting more than one forma.rule. Rule + ruleset by supplying a table containting more than one rule. Rule conflicts are resolved in favour of cell deactivation, i.e if there are two nested rulesets, with a cell passing one and failing the other either survival or birth rules, the cell will be deactivated in the next iteration.

      +

      All CA updates here are only possible on a finite domain of cells. That + domain must be specified as a pattern in the iteration call.

      +

      Both the synchronous and asynchronous iterations return the result of one CA iteration and a bool specifying whether or not the iteration has converged to a stable pattern.

      -

      All CA updates here are only possible on a finite domain of cells. That - domain must be specified in the iteration call.

      -

      Usage:

      -
        -
        Domain and start seed for the CA
        -local domain     = primitives.square(80,20)
        -local ca_pattern = subpattern.random(sq, 0.5*sq:size())
        -
        --- Game of life rule
        -local life = automata.rule(neighbourhood.moore(), "B3/S23")
        -
        --- Repeat iteration until convergence is reached
        -local converged = false
        -repeat
        -	ca_pattern, converged = automata.iterate(ca_pattern, domain, {life})
        -until converged == true
        -
        -
      +

      Relevant examples

      + + +

      Ruleset Generation

      - +
      rule (neighbourhood, rulesig)rule (neighbourhood, rule_string) Define a cellular automata rule.
      @@ -147,7 +137,7 @@

      Ruleset Generation
      - rule (neighbourhood, rulesig) + rule (neighbourhood, rule_string)
      Define a cellular automata rule. @@ -161,7 +151,7 @@

      Parameters:

    • neighbourhood specifying the neighbourhood the rule is to be applied in.
    • -
    • rulesig +
    • rule_string string specifying the ruleset (i.e B23/S1).
    @@ -169,7 +159,7 @@

    Parameters:

    Returns:

      - a verified rule for CA + A verified rule for use with the CA methods.
    @@ -177,7 +167,7 @@

    Returns:

    Usage:

      -- Initialise a rule corresponding to Conway's Game of Life
      -local rule = automata.rule(neighbourhood.moore(), "B3/S23")
      +local gol_rule = automata.rule(neighbourhood.moore(), "B3/S23")
    @@ -203,18 +193,31 @@

    Parameters:

    the cells in which the CA operates
  • ruleset - a list of forma.rules for performing the CA on + a table of forma.rules defining the CA

Returns:

    - - the next iteration, and a bool specifying if convergence has been reached. +
  1. + The result of the CA iteration [pattern].
  2. +
  3. + Convergence flag [bool: true if converged, false otherwise].
+

Usage:

+
    +
    -- Domain and initial state (500 seed points) for the CA
    +local domain = primitives.square(100)
    +local ca_pat = subpattern.random(sq, 500)
    +-- Repeat iteration until convergence is reached
    +local converged = false
    +repeat
    +	ca_pat, converged = automata.iterate(ca_pat, domain, {gol_rule})
    +until converged == true
    +
@@ -235,7 +238,7 @@

Parameters:

the cells in which the CA operates
  • ruleset - a list of forma.rules for performing the CA on + a table of forma.rules defining the CA
  • rng a (optional) random number generator (syntax as per math.random). @@ -244,12 +247,26 @@

    Parameters:

    Returns:

      - - the next iteration, and a bool specifying if convergence has been reached. +
    1. + The result of the CA iteration [pattern].
    2. +
    3. + Convergence flag [bool: true if converged, false otherwise].
    +

    Usage:

    +
      +
      -- Domain and initial state (500 seed points) for the CA
      +local domain = primitives.square(100)
      +local ca_pat = subpattern.random(sq, 500)
      +local rng    = math.random
      +-- Repeat iteration until convergence is reached
      +local converged = false
      +repeat
      +	ca_pat, converged = automata.async_iterate(ca_pat, domain, {gol_rule}, rng)
      +until converged == true
      +
    @@ -259,7 +276,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    diff --git a/docs/modules/forma.cell.html b/docs/modules/forma.cell.html index 7f4185d..b8d5e72 100644 --- a/docs/modules/forma.cell.html +++ b/docs/modules/forma.cell.html @@ -53,19 +53,16 @@

    Readme

    Examples

    @@ -75,28 +72,13 @@

    Examples

    Module forma.cell

    Integer point/vector class defining the position of a cell.

    The cell class behaves much as a normal 2D vector class, with the - restriction that its components must be integer-valued. Several normal - vector operations are available such as a vector equality check, vector - addition, subtraction, and multiplication by an integer.

    + restriction that its components must be integer-valued. A subset of normal + vector operations are available, namely a vector addition and subtraction, + along with a vector equality check.

    Along with the cell class definition, a number of distance measures between cell positions are provided. Specifically, the Manhattan, Chebyshev and Euclidean distances.

    -

    Usage:

    -
      -
      -- Initialisation and cloning of points
      -local c1 = cell.new(x,y)  -- Constructor
      -local c2 = cell.clone(c1) -- Clone ('procedural' style)
      -local c3 = c1:clone()     -- Clone ('method' stype)
      -
      --- Arithmetic
      -local c4 = (c1 + c2) - c3*5
      -
      --- Distance measures
      -local d1 = cell.manhattan(c1,c2) -- Manhattan distance ('procedural' stype)
      -local d2 = c1:manhattan(c2)      -- Manhattan distance ('method' style)
      -
      -

    Functions

    @@ -114,23 +96,15 @@

    Metamethods

    - + - - - - - - - - - + - + @@ -148,13 +122,13 @@

    Distance measures

    - - - - + + + +
    __add (a, b)Add two cells, or add a number to a cell.Add two cell positions
    __sub (a, b)Subtract two cells, or a number and a cell.
    __mul (a, b)Multiply a cell by an number.
    __div (a, b)Divide a cell position by a number.Subtract two cell positions
    __eq (a, b)Test for equality of two cells.Test for equality of two cell vectors.
    __tostring (icell) Chebyshev distance between cells.
    euclidean2 (a, b)Squared Euclidean distance between cells.
    euclidean (a, b) Euclidean distance between cells.
    euclidean2 (a, b)Squared Euclidean distance between cells.

    @@ -190,6 +164,11 @@

    Returns:

    +

    Usage:

    +
      +
      local x, y = 1, 5
      +local new_cell = cell.new(x,y)
      +
    @@ -215,6 +194,11 @@

    Returns:

    +

    Usage:

    +
      +
      local old_cell = cell.new(1,1)
      +local new_cell = old_cell:clone()
      +
    @@ -226,16 +210,16 @@

    Metamethods

    __add (a, b)
    - Add two cells, or add a number to a cell. + Add two cell positions

    Parameters:

    • a - first cell or number + first cell
    • b - second cell or number + second cell
    @@ -247,6 +231,12 @@

    Returns:

    +

    Usage:

    +
      +
      local c1, c2 = cell.new(1,1), cell.new(0,0)
      +local c3 = c2 + c1
      +assert(c3 == c1)
      +
    @@ -254,16 +244,16 @@

    Returns:

    __sub (a, b)
    - Subtract two cells, or a number and a cell. + Subtract two cell positions

    Parameters:

    • a - first cell or number + first cell
    • b - second cell or number + second cell
    @@ -275,70 +265,21 @@

    Returns:

    - -
    -
    - - __mul (a, b) -
    -
    - Multiply a cell by an number. - - -

    Parameters:

    -
      -
    • a - first cell or number -
    • -
    • b - second cell or number -
    • -
    - -

    Returns:

    -
      - - c = a*b -
    - - - - -
    -
    - - __div (a, b) -
    -
    - Divide a cell position by a number. - - -

    Parameters:

    +

    Usage:

      -
    • a - a forma.cell -
    • -
    • b - a number -
    • +
      local c1, c2 = cell.new(1,1), cell.new(2,2)
      +local c3 = c2 - c1
      +assert(c3 == c1)
    -

    Returns:

    -
      - - c = a/b -
    - - - -
    __eq (a, b)
    - Test for equality of two cells. + Test for equality of two cell vectors. + assert(cell.new(0,1) == cell.new(0,1)

    Parameters:

    @@ -384,6 +325,10 @@

    Returns:

    +

    Usage:

    +
      +
      print(cell.new(1,1))
      +
    @@ -416,6 +361,10 @@

    Returns:

    +

    Usage:

    +
      +
      local distance = cell.manhattan(acell, bcell)
      +
    @@ -444,14 +393,18 @@

    Returns:

    +

    Usage:

    +
      +
      local distance = cell.chebyshev(acell, bcell)
      +
    - - euclidean2 (a, b) + + euclidean (a, b)
    - Squared Euclidean distance between cells. + Euclidean distance between cells.

    Parameters:

    @@ -467,19 +420,24 @@

    Parameters:

    Returns:

      - L_2(a,b)^2 = (a-b)^2 + L_2(a,b) = sqrt((a-b)^2)
    +

    Usage:

    +
      +
      local distance = cell.euclidean(acell, bcell)
      +
    - - euclidean (a, b) + + euclidean2 (a, b)
    - Euclidean distance between cells. + Squared Euclidean distance between cells. + A little faster than cell.euclidean as it avoids the sqrt.

    Parameters:

    @@ -495,11 +453,15 @@

    Parameters:

    Returns:

      - L_2(a,b) = sqrt((a-b)^2) + L_2(a,b)^2 = (a-b)^2
    +

    Usage:

    +
      +
      local distance = cell.euclidean2(acell, bcell)
      +
    @@ -509,7 +471,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    diff --git a/docs/modules/forma.neighbourhood.html b/docs/modules/forma.neighbourhood.html index 123b2bd..d2a4c18 100644 --- a/docs/modules/forma.neighbourhood.html +++ b/docs/modules/forma.neighbourhood.html @@ -52,19 +52,16 @@

    Readme

    Examples

    @@ -73,11 +70,11 @@

    Examples

    Module forma.neighbourhood

    Cell neighbourhood definitions.

    -

    The neighbourhood of a cell in a pattern defines which other cells are - considered its neighbours. This is an important definition for many +

    The neighbourhood of a cell in a pattern defines which other cells + are considered its neighbours. This is an important definition for many functions in forma. For example, when finding all cells that border a pattern in subpattern.edge a definition of border in terms of a - neighbourhood is required. Cellular automata rules are also defined in + neighbourhood is required. Cellular automata rules are also defined in terms of neighbourhoods.

    This module provides a class to represent a neighbourhood, along with @@ -305,7 +302,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    diff --git a/docs/modules/forma.pattern.html b/docs/modules/forma.pattern.html index 88d1225..442f906 100644 --- a/docs/modules/forma.pattern.html +++ b/docs/modules/forma.pattern.html @@ -57,19 +57,16 @@

    Readme

    Examples

    @@ -382,6 +379,7 @@

    Returns:

  • Check if a cell is active in a pattern. + This has fewer checks than usual as it's a common inner-loop call.

    Parameters:

    @@ -1157,7 +1155,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    diff --git a/docs/modules/forma.primitives.html b/docs/modules/forma.primitives.html index bbb3794..2c6ca48 100644 --- a/docs/modules/forma.primitives.html +++ b/docs/modules/forma.primitives.html @@ -51,19 +51,16 @@

    Readme

    Examples

    @@ -203,7 +200,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    diff --git a/docs/modules/forma.subpattern.html b/docs/modules/forma.subpattern.html index f5de22c..a58ef98 100644 --- a/docs/modules/forma.subpattern.html +++ b/docs/modules/forma.subpattern.html @@ -53,19 +53,16 @@

    Readme

    Examples

    @@ -78,12 +75,12 @@

    Module forma.subpattern

    pattern. The simplest of these is the random sampling of a fraction of cells from the parent.

    -

    Several of these finders return a list of all relevant sub-patterns. For - example the segments method which returns a list of all contiguous +

    Several of these finders return a table of all relevant sub-patterns. For + example the segments method which returns a table of all contiguous (according to some neighbourhood) sub-patterns by using a floodfill.

    In addition to the subpattern finders, a pretty_print utility is provided - to render these lists of sub-patterns into text.

    + to render these tables of sub-patterns into text.

    Sub-patterns

    @@ -101,6 +98,10 @@

    Sub-patterns

    Poisson-disc random subpattern. + mitchell_sample (ip, distance, n, k, rng) + Mitchell's best candidate sampling. + + floodfill (ip, ipt, nbh) Returns the contiguous sub-pattern of ip that surrounts cell pt @@ -113,11 +114,11 @@

    Lists of sub-patterns

    - + - + @@ -140,7 +141,7 @@

    Utilities

    segments (ip, nbh)Generate a list of contiguous 'segments' or sub-patterns.Generate a table of contiguous 'segments' or sub-patterns.
    enclosed (ip, nbh)Returns a list of 'enclosed' segments of a pattern.Returns a table of 'enclosed' segments of a pattern.
    bsp (ip, th_volume)
    - +
    pretty_print (domain, segments, chars)Pretty print a list of forma.pattern segments.Pretty print a table of forma.pattern segments.
    @@ -170,6 +171,11 @@

    Parameters:

    +

    Returns:

    +
      + + A pattern consisting only of those cells in domain which pass the mask argument. +
    @@ -224,7 +230,7 @@

    Returns:

    Parameters:

    • ip - domain pattern to sampling from + domain pattern to sample from
    • distance a measure of distance between two cells d(a,b) e.g cell.euclidean @@ -246,6 +252,47 @@

      Returns:

      +
    +
    + + mitchell_sample (ip, distance, n, k, rng) +
    +
    + Mitchell's best candidate sampling. + Generates an approximate Poisson-disc sampling by Mitchell's algorithm. + Picks 'k' sample point attempts at every iteration, and picks the candidate + that maximises the distance to existing samples. Halts when n samples are + picked. + + +

    Parameters:

    +
      +
    • ip + domain pattern to sample from +
    • +
    • distance + a measure of distance between two cells d(a,b) e.g cell.euclidean +
    • +
    • n + the requested number of samples +
    • +
    • k + the number of candidates samples at each iteration +
    • +
    • rng + (optional) a random number generator, following the signature of math.random. +
    • +
    + +

    Returns:

    +
      + + an approximate Poisson-disc sample of domain +
    + + + +
    @@ -296,7 +343,7 @@

    Parameters:

    Returns:

      - the subpattern of ip consisting of its largest contiguous rectangular area. + The subpattern of ip consisting of its largest contiguous rectangular area.
    @@ -312,7 +359,7 @@

    Lists of sub-pat segments (ip, nbh)

    - Generate a list of contiguous 'segments' or sub-patterns. + Generate a table of contiguous 'segments' or sub-patterns. This performs a series of flood-fill operations until all pattern cells are accounted for in the sub-patterns @@ -330,7 +377,7 @@

    Parameters:

    Returns:

      - a table of forma.patterns consisting of contiguous sub-patterns of ip + A table of forma.patterns consisting of contiguous sub-patterns of ip.
    @@ -342,7 +389,7 @@

    Returns:

    enclosed (ip, nbh)
    - Returns a list of 'enclosed' segments of a pattern. + Returns a table of 'enclosed' segments of a pattern. Enclosed areas are the inactive areas of a pattern which are completely surrounded by active areas @@ -360,7 +407,7 @@

    Parameters:

    Returns:

      - a list of forma.patterns comprising the enclosed areas of ip + A table of forma.patterns comprising the enclosed areas of ip.
    @@ -421,7 +468,7 @@

    Parameters:

    Returns:

      - a table of #nbh patterns, where each cell in ip is categorised + A table of #nbh patterns, where each cell in ip is categorised.
    @@ -452,7 +499,7 @@

    Parameters:

    Returns:

      - a list of Voronoi segments + A table of Voronoi segments.
    @@ -488,8 +535,12 @@

    Parameters:

    Returns:

      - - (segments, segment centres, convergence bool) +
    1. + A table of resuling Voronoi segments.
    2. +
    3. + A pattern consisting of the voronoi segment centres.
    4. +
    5. + A bool, true if the algorithm converged, false if not.
    @@ -505,8 +556,8 @@

    Utilities

    pretty_print (domain, segments, chars)
    - Pretty print a list of forma.pattern segments. - Prints a list of pattern segments to io.output. If provided, a table of + Pretty print a table of forma.pattern segments. + Prints a table of pattern segments to io.output. If provided, a table of segment labels can be used, with one entry per segment. @@ -535,7 +586,7 @@

    Parameters:

    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    diff --git a/docs/readme/README.md.html b/docs/readme/README.md.html index 7b96ac9..68802e4 100644 --- a/docs/readme/README.md.html +++ b/docs/readme/README.md.html @@ -47,19 +47,16 @@

    Modules

    Examples

    @@ -68,6 +65,7 @@

    Examples

    Build Status +Coverage Status License

    forma

    @@ -80,10 +78,10 @@

    forma

    -

    This package is intended for the generation and manipulation of shapes on a two -dimensional grid or lattice. It came about as part of experiments in making -roguelike games. forma is therefore particularly suited for the generation -of roguelike environments.

    +

    forma is a utility library for the procedural generation and manipulation of +shapes on a two dimensional grid or lattice. It came about as part of +experiments in making roguelike games. forma is therefore particularly +suited for (but not limited to) the generation of roguelike environments.

    Shapes can be generated in several ways. From simple rasters of primitive shapes like circles, lines and squares, to pattern generation by a Cellular @@ -132,19 +130,19 @@

    forma

    All of the above examples can be generated by code in the examples folder.

    -

    Warning

    -

    The master branch is in active development. API breaking changes may -occasionally occur.

    +

    Installation

    -

    Requirements

    -

    Compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1.

    +

    forma is compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1. The library +is written in pure Lua, no compilation is required. Including the project is +then as simple as including the forma directory in your Lua path.

    -

    The test suite requires - - LuaCov - - luaunit

    +

    The easiest way to do this is via LuaRocks:

    + + +
    +    luarocks install forma
    +
    -

    Generating the documentation requires - - LDoc

    Running examples

    @@ -161,6 +159,9 @@

    Generating documentation

    Documentation is hosted here.

    +

    Generating the documentation requires + - LDoc

    +

    Simply running

    @@ -172,8 +173,11 @@

    Generating documentation

    Testing

    -

    Unit tests are provided for some methods with the luaunit framework, coverage is -tested using LuaCov. To run the tests use

    +

    Unit tests and coverage reports are provided. The test suite requires + - LuaCov + - luaunit

    + +

    To run the tests use

    @@ -186,7 +190,7 @@ 

    Testing

    generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 +Last updated 2018-07-13 01:06:54
    From 7a288029d7f45239c3a8d0a2d0975dd45cba992f Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 01:09:00 +0200 Subject: [PATCH 15/31] Updated ldoc output --- docs/README.md | 1 - docs/contents.html | 2 +- docs/examples/async_automata.lua.html | 2 +- docs/examples/binary_space_partition.lua.html | 2 +- docs/examples/bubbles.lua.html | 2 +- docs/examples/carpet.lua.html | 122 -------- docs/examples/caves.lua.html | 104 ------- docs/examples/cellular_automata.lua.html | 2 +- docs/examples/corridors.lua.html | 2 +- docs/examples/game_of_life.lua.html | 109 ------- docs/examples/game_of_life_async.lua.html | 119 -------- docs/examples/isolines.lua.html | 2 +- docs/examples/lloyds_algorithm.lua.html | 107 ------- docs/examples/maxrectangle.lua.html | 2 +- docs/examples/platformer.lua.html | 2 +- docs/examples/primitives.lua.html | 105 ------- docs/examples/sampling.lua.html | 2 +- docs/examples/shapes.lua.html | 105 ------- docs/examples/town.lua.html | 116 ------- docs/examples/voronoi.lua.html | 2 +- docs/examples/worley.lua.html | 119 -------- docs/modules/automata.html | 286 ------------------ docs/modules/forma.automata.html | 2 +- docs/modules/forma.cell.html | 2 +- docs/modules/forma.neighbourhood.html | 2 +- docs/modules/forma.pattern.html | 2 +- docs/modules/forma.primitives.html | 2 +- docs/modules/forma.subpattern.html | 2 +- docs/readme/README.md.html | 2 +- 29 files changed, 18 insertions(+), 1311 deletions(-) delete mode 100644 docs/README.md delete mode 100644 docs/examples/carpet.lua.html delete mode 100644 docs/examples/caves.lua.html delete mode 100644 docs/examples/game_of_life.lua.html delete mode 100644 docs/examples/game_of_life_async.lua.html delete mode 100644 docs/examples/lloyds_algorithm.lua.html delete mode 100644 docs/examples/primitives.lua.html delete mode 100644 docs/examples/shapes.lua.html delete mode 100644 docs/examples/town.lua.html delete mode 100644 docs/examples/worley.lua.html delete mode 100644 docs/modules/automata.html diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index f9f70c0..0000000 --- a/docs/README.md +++ /dev/null @@ -1 +0,0 @@ -Docs available at https://nhartland.github.io/forma/ diff --git a/docs/contents.html b/docs/contents.html index cdb9574..9ec8ab8 100644 --- a/docs/contents.html +++ b/docs/contents.html @@ -145,7 +145,7 @@

    Examples

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/async_automata.lua.html b/docs/examples/async_automata.lua.html index 66fdffc..6834561 100644 --- a/docs/examples/async_automata.lua.html +++ b/docs/examples/async_automata.lua.html @@ -109,7 +109,7 @@

    async_automata.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/binary_space_partition.lua.html b/docs/examples/binary_space_partition.lua.html index 9ddf90c..f5342e6 100644 --- a/docs/examples/binary_space_partition.lua.html +++ b/docs/examples/binary_space_partition.lua.html @@ -83,7 +83,7 @@

    binary_space_partition.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/bubbles.lua.html b/docs/examples/bubbles.lua.html index 1b1a5c3..c0bb797 100644 --- a/docs/examples/bubbles.lua.html +++ b/docs/examples/bubbles.lua.html @@ -92,7 +92,7 @@

    bubbles.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/carpet.lua.html b/docs/examples/carpet.lua.html deleted file mode 100644 index 4c36ebd..0000000 --- a/docs/examples/carpet.lua.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    carpet.lua

    -
    --- carpet.lua.
    --- Using Async Cellular Automata with symmetrising methods.
    --- Demonstration of pattern generation by asynchronous cellular automata
    --- Here a small basic pattern is generated, which is then enlarged by
    --- reflection into a nicely symmetric larger pattern.
    -
    -local pattern       = require('forma.pattern')
    -local primitives    = require('forma.primitives')
    -local automata      = require('forma.automata')
    -local subpattern    = require('forma.subpattern')
    -local neighbourhood = require('forma.neighbourhood')
    -
    -math.randomseed( os.time() )
    -
    --- Initial CA domain
    -local sq = primitives.square(10,5)
    -
    --- Make a new pattern consisting of a random (seed) cell from the domain
    -local rn = pattern.new()
    -local rp = sq:rcell()
    -rn:insert(rp.x, rp.y)
    -
    --- Moore neighbourhood rule
    -local moore = automata.rule(neighbourhood.moore(), "B12/S012345678")
    -
    -repeat
    -    -- Perform asynchronous CA update
    -    local converged
    -    rn, converged = automata.async_iterate(rn, sq, {moore})
    -
    -    if converged == true then
    -        -- Mirror the basic pattern a couple of times
    -        local rflct = rn:hreflect()
    -        rflct = rflct:vreflect():vreflect()
    -        rflct = rflct:hreflect():hreflect()
    -        -- Categorise the pattern according to possible vN neighbours and print to screen
    -        local vn = neighbourhood.von_neumann()
    -        local segments = subpattern.neighbourhood_categories(rflct, vn)
    -        subpattern.pretty_print(rflct, segments, vn:category_label())
    -    end
    -until converged == true
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/examples/caves.lua.html b/docs/examples/caves.lua.html deleted file mode 100644 index 2b16042..0000000 --- a/docs/examples/caves.lua.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    caves.lua

    -
    --- caves.lua
    --- Demonstration of classic cellular-automata cave generation (4-5 rule)
    -
    -local primitives    = require('forma.primitives')
    -local subpattern    = require('forma.subpattern')
    -local automata      = require('forma.automata')
    -local neighbourhood = require('forma.neighbourhood')
    -math.randomseed( os.time() )
    -
    -local sq = primitives.square(80,20)
    -local rn = subpattern.random(sq, math.floor(sq:size()*0.5))
    -sq.onchar, sq.offchar = "#", " "
    -
    --- Moore neighbourhood rule
    -local moore = automata.rule(neighbourhood.moore(), "B5678/S45678")
    -local ite = 0
    -repeat
    -    local converged
    -    rn, converged = automata.iterate(rn, sq, {moore})
    -    ite = ite+1
    -until converged == true or ite > 1000
    -
    -print(sq-rn)
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/examples/cellular_automata.lua.html b/docs/examples/cellular_automata.lua.html index 5c380df..a2ccddd 100644 --- a/docs/examples/cellular_automata.lua.html +++ b/docs/examples/cellular_automata.lua.html @@ -97,7 +97,7 @@

    cellular_automata.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/corridors.lua.html b/docs/examples/corridors.lua.html index 0566700..db0f42e 100644 --- a/docs/examples/corridors.lua.html +++ b/docs/examples/corridors.lua.html @@ -110,7 +110,7 @@

    corridors.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/game_of_life.lua.html b/docs/examples/game_of_life.lua.html deleted file mode 100644 index b275f2b..0000000 --- a/docs/examples/game_of_life.lua.html +++ /dev/null @@ -1,109 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    game_of_life.lua

    -
    --- life.lua
    --- Demonstration of a 'Game of Life' rule
    -
    -local subpattern    = require('forma.subpattern')
    -local primitives    = require('forma.primitives')
    -local automata      = require('forma.automata')
    -local neighbourhood = require('forma.neighbourhood')
    -math.randomseed( os.time() )
    -
    --- Domain and seed
    -local sq = primitives.square(80,20)
    -local rn = subpattern.random(sq, math.floor(sq:size()*0.5))
    -
    --- vonNeumann neighbourhood for pretty printing
    -local nbh = neighbourhood.von_neumann()
    -
    --- Game of life rule
    -local life = automata.rule(neighbourhood.moore(), "B3/S23")
    -local counter, maxcounter = 0, 100
    -repeat
    -    counter = counter + 1
    -    local converged
    -    rn, converged = automata.iterate(rn, sq, {life})
    -    local segments = subpattern.neighbourhood_categories(rn, nbh)
    -    os.execute("clear")
    -    subpattern.pretty_print(rn, segments, nbh:category_label())
    -    print(counter .. "/".. maxcounter .. " frames")
    -until converged == true or counter == maxcounter
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/examples/game_of_life_async.lua.html b/docs/examples/game_of_life_async.lua.html deleted file mode 100644 index 9604a32..0000000 --- a/docs/examples/game_of_life_async.lua.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    game_of_life_async.lua

    -
    --- life.lua
    --- Demonstration of a 'Game of Life' rule
    -
    -local subpattern    = require('forma.subpattern')
    -local primitives    = require('forma.primitives')
    -local automata      = require('forma.automata')
    -local neighbourhood = require('forma.neighbourhood')
    -math.randomseed( os.time() )
    -
    -local print_every_iteration = false
    -
    --- Domain and seed
    -local sq = primitives.square(40,20)
    -local rn = subpattern.random(sq, math.floor(sq:size()*0.5))
    -
    --- vonNeumann neighbourhood for pretty printing
    -local nbh = neighbourhood.von_neumann()
    -
    --- Game of life rule
    --- The async rule converges quite well with an alterative : "B3/S123"
    -local life = automata.rule(neighbourhood.moore(), "B3/S23")
    -local counter, maxcounter = 0, 500
    -repeat
    -    counter = counter + 1
    -    local converged
    -    rn, converged = automata.async_iterate(rn, sq, {life})
    -
    -    if print_every_iteration then
    -        local reflect = rn:hreflect()
    -        local segments = subpattern.neighbourhood_categories(reflect, nbh)
    -        os.execute("clear")
    -        subpattern.pretty_print(reflect, segments, nbh:category_label())
    -    end
    -until converged == true or counter == maxcounter
    -
    -local reflect = rn:hreflect()
    -local segments = subpattern.neighbourhood_categories(reflect, nbh)
    -subpattern.pretty_print(reflect, segments, nbh:category_label())
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/examples/isolines.lua.html b/docs/examples/isolines.lua.html index f6c77d1..9aa6f97 100644 --- a/docs/examples/isolines.lua.html +++ b/docs/examples/isolines.lua.html @@ -105,7 +105,7 @@

    isolines.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/lloyds_algorithm.lua.html b/docs/examples/lloyds_algorithm.lua.html deleted file mode 100644 index 69bc117..0000000 --- a/docs/examples/lloyds_algorithm.lua.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    lloyds_algorithm.lua

    -
    --- voronoi.lua
    --- Demonstration of voronoi relaxation by lloyds algorithm
    -
    -local cell      = require('forma.cell')
    -local primitives = require('forma.primitives')
    -local subpattern = require('forma.subpattern')
    -math.randomseed(os.time())
    -
    --- Domain for tesselation
    -local sq = primitives.square(80,20)
    -local seeds = subpattern.random(sq, 9)
    -
    --- Compute voronoi tesselation for various measures
    -local measure = cell.manhattan
    -
    --- Perform voronoi relaxation at incrementing imax
    --- Note this isn't very efficient as we are displaying intermediate steps,
    --- normally you would only call this function once.
    -local imax = 1
    -repeat
    -    print("Step "..imax)
    -    local segments, _, converged  = subpattern.voronoi_relax(seeds, sq, measure, imax)
    -    table.sort(segments, function(a,b) return a:centroid().x < b:centroid().x end)
    -    subpattern.pretty_print(sq, segments)
    -    imax = imax + 1
    -until converged == true or imax == 100
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/examples/maxrectangle.lua.html b/docs/examples/maxrectangle.lua.html index af5c6e6..f0e58ae 100644 --- a/docs/examples/maxrectangle.lua.html +++ b/docs/examples/maxrectangle.lua.html @@ -94,7 +94,7 @@

    maxrectangle.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/platformer.lua.html b/docs/examples/platformer.lua.html index 1c279bb..e04c3fc 100644 --- a/docs/examples/platformer.lua.html +++ b/docs/examples/platformer.lua.html @@ -109,7 +109,7 @@

    platformer.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/primitives.lua.html b/docs/examples/primitives.lua.html deleted file mode 100644 index 5d0d569..0000000 --- a/docs/examples/primitives.lua.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    primitives.lua

    -
    --- primitives.lua
    --- Examples of geometry primitives
    -
    -local cell      = require('forma.cell')
    -local primitives = require('forma.primitives')
    -
    -local tp = primitives.circle(1)
    -local radii = {2,4,5,15}
    -for _, r in ipairs(radii) do
    -    tp = tp + primitives.circle(r)
    -end
    -
    -tp = tp + primitives.line(cell.new(-15,0), cell.new(15,0))
    -tp = tp + primitives.line(cell.new(0,-15), cell.new(0,15))
    -
    -tp = tp + primitives.line(cell.new(0,-15), cell.new(-15,0))
    -tp = tp + primitives.line(cell.new(0,15),  cell.new(15,0))
    -
    -tp = tp + primitives.line(cell.new(-15,0), cell.new(0,15))
    -tp = tp + primitives.line(cell.new(0,-15), cell.new(15,0))
    -
    -tp.onchar='X'
    -tp.offchar=' '
    -print (tp)
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/examples/sampling.lua.html b/docs/examples/sampling.lua.html index 6a8601d..1835923 100644 --- a/docs/examples/sampling.lua.html +++ b/docs/examples/sampling.lua.html @@ -94,7 +94,7 @@

    sampling.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/shapes.lua.html b/docs/examples/shapes.lua.html deleted file mode 100644 index dfbc244..0000000 --- a/docs/examples/shapes.lua.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    shapes.lua

    -
    --- shapes.lua
    --- Use of a few different functions to generate shapes
    -
    -local pattern    = require('forma.pattern')
    -local primitives = require('forma.primitives')
    -math.randomseed( os.time() )
    -
    --- Generate some basic shape as a sum of rectangles
    -local function generate_shape()
    -    local rn = pattern.new()
    -    while rn:size() < 35 do
    -        local sqx, sqy = math.random(3) , math.random(3)
    -        local pqx, pqy = math.random(5) , math.random(5)
    -        rn = rn + primitives.square(sqx,sqy):shift(pqx, pqy)
    -    end
    -    return rn
    -end
    -
    --- Add some symmetry
    -local rn = generate_shape():hreflect()
    -
    --- Print to stdout
    -rn.onchar, rn.offchar = "X"," "
    -print(rn)
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/examples/town.lua.html b/docs/examples/town.lua.html deleted file mode 100644 index 36ffdc0..0000000 --- a/docs/examples/town.lua.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    town.lua

    -
    --- town.lua
    --- Generates a plausible small town layout. Following a simmilar setup to the
    --- corridor example but with more post-processing.
    -
    -local pattern       = require('forma.pattern')
    -local automata      = require('forma.automata')
    -local primitives    = require('forma.primitives')
    -local subpattern    = require('forma.subpattern')
    -local neighbourhood = require('forma.neighbourhood')
    -math.randomseed(os.time())
    -
    -local sq = primitives.square(20,10)
    -local tp = pattern.new()
    -local seed = pattern.rcell(sq)
    -pattern.insert(tp, seed.x, seed.y)
    -
    --- Complicated ruleset
    -local moore = automata.rule(neighbourhood.moore(),      "B12/S012345678")
    -local diag  = automata.rule(neighbourhood.diagonal(),   "B0123/S01234")
    -local diag2 = automata.rule(neighbourhood.diagonal_2(), "B01/S01234")
    -local vn    = automata.rule(neighbourhood.von_neumann(),"B12/S01234")
    -local ruleset = {diag2, diag, vn, moore}
    -
    -repeat
    -    local converged
    -    tp, converged = automata.async_iterate(tp, sq, ruleset)
    -until converged == true
    -
    -tp = pattern.edge(tp) -- Comment this out and you get the 'sewerage system'
    -tp = pattern.enlarge(tp,4)
    -tp = pattern.surface(tp)
    -
    --- Pretty print according to neighbourhood
    -local nbh = neighbourhood.von_neumann()
    -local segments = subpattern.neighbourhood_categories(tp, nbh)
    -subpattern.pretty_print(tp, segments, nbh:category_label())
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-06-23 18:02:24 -
    -
    - - diff --git a/docs/examples/voronoi.lua.html b/docs/examples/voronoi.lua.html index dc8a543..0b96e56 100644 --- a/docs/examples/voronoi.lua.html +++ b/docs/examples/voronoi.lua.html @@ -88,7 +88,7 @@

    voronoi.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/examples/worley.lua.html b/docs/examples/worley.lua.html deleted file mode 100644 index 6627105..0000000 --- a/docs/examples/worley.lua.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    worley.lua

    -
    --- worley.lua
    --- Demonstration of thresholded Worley noise
    --- https://en.wikipedia.org/wiki/Worley_noise
    -
    --- Here we take the noise field N = F_2 - F_1,
    --- where F_n is the chebyshev distance to the nth
    --- nearest neighbour, and take the threshold N > 1
    -
    --- Makes a good ice floe generator
    -
    -local cell          = require('forma.cell')
    -local subpattern    = require('forma.subpattern')
    -local primitives    = require('forma.primitives')
    -math.randomseed( os.time() )
    -
    --- Distance measure and threshold
    -local measure = cell.chebyshev
    -local threshold = 1
    -
    --- Domain and seeds
    -local sq = primitives.square(80,20)
    -local rn = subpattern.random(sq, math.floor(sq:size()*0.01)):cell_list()
    -
    --- Worley noise mask
    -local mask = function(tcell)
    -    local sortfn = function(a,b)
    -        return measure(tcell, a) < measure(tcell, b)
    -    end
    -    table.sort(rn, sortfn)
    -    local d1 = measure(rn[1], tcell)
    -    local d2 = measure(rn[2], tcell)
    -    return d2 - d1  > threshold
    -end
    -
    -local noise = subpattern.mask(sq, mask)
    -noise.offchar = '~'
    -noise.onchar  = '▓'
    -print(noise)
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-08 14:23:43 -
    -
    - - diff --git a/docs/modules/automata.html b/docs/modules/automata.html deleted file mode 100644 index 6a9f921..0000000 --- a/docs/modules/automata.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    Module automata

    -

    Pattern manipulation with Cellular Automata.

    -

    - - -

    This module provides various functions for the generation or modification of - a pattern by means of Cellular Automata.

    - -

    Cellular Automata are defined here by two parameters. Firstly a - neighbourhood that the rule acts on. Secondly a rule specifying the - conditions under which cells are Born (B) or Survive (S). These rules - are initialised with a string rule in the "Golly" format. i.e a rule which - activates cells with one neighbour and deactivates cells with two would have - the rule string "B1/S2". The neighbourhood is specified by an instance of - the neighbourhood submodule as usual.

    - -

    Once a rule is specified, there are two provided implementations of a CA. - Firstly the standard synchronous CA is implemented in automata.iterate - whereby all cells are updated simultaneously. Secondly an asynchronous - update is provided in automata.async_iterate in which each iteration - updates only one cell at random.

    - -

    For both methods, multiple rules can be applied simultaneously through the - ruleset by supplying a table containting more than one rule. Rule - conflicts are resolved in favour of cell deactivation, i.e if there are two - nested rulesets, with a cell passing one and failing the other either - survival or birth rules, the cell will be deactivated in the next iteration.

    - -

    Both the synchronous and asynchronous iterations return the result of one CA - iteration and a bool specifying whether or not the iteration has converged - to a stable pattern.

    - -

    All CA updates here are only possible on a finite domain of cells. That - domain must be specified as a pattern in the iteration call.

    - -

    Relevant examples

    - - -

    - - -

    Ruleset Generation

    - - - - - -
    rule (neighbourhood, rulesig)Define a cellular automata rule.
    -

    CA Iteration

    - - - - - - - - - -
    iterate (prevp, domain, ruleset)Synchronous cellular automata iteration.
    async_iterate (prevp, domain, ruleset, rng)Asynchronous cellular automata iteration.
    - -
    -
    - - -

    Ruleset Generation

    - -
    -
    - - rule (neighbourhood, rulesig) -
    -
    - Define a cellular automata rule. - CA rules in forma are defined by a neighbourhood in the usual CA sense and - a string signature in the 'Golly' format (BXX/SXX). This function - initialises a rule, and performs a few consistency checks. - - -

    Parameters:

    -
      -
    • neighbourhood - specifying the neighbourhood the rule is to be applied in. -
    • -
    • rulesig - string specifying the ruleset (i.e B23/S1). -
    • -
    - -

    Returns:

    -
      - - A verified rule for use with the CA methods. -
    - - - -

    Usage:

    -
      -
      -- Initialise a rule corresponding to Conway's Game of Life
      -local gol_rule = automata.rule(neighbourhood.moore(), "B3/S23")
      -
    - -
    -
    -

    CA Iteration

    - -
    -
    - - iterate (prevp, domain, ruleset) -
    -
    - Synchronous cellular automata iteration. - Performs one standard synchronous CA update on pattern prevp in the specified domain. - - -

    Parameters:

    -
      -
    • prevp - the previous iteration of the pattern -
    • -
    • domain - the cells in which the CA operates -
    • -
    • ruleset - a table of forma.rules defining the CA -
    • -
    - -

    Returns:

    -
      -
    1. - The result of the CA iteration [pattern].
    2. -
    3. - Convergence flag [bool: true if converged, false otherwise].
    4. -
    - - - -

    Usage:

    -
      -
      -- Domain and initial state (500 seed points) for the CA
      -local domain = primitives.square(100)
      -local ca_pat = subpattern.random(sq, 500)
      --- Repeat iteration until convergence is reached
      -local converged = false
      -repeat
      -	ca_pat, converged = automata.iterate(ca_pat, domain, {gol_rule})
      -until converged == true
      -
    - -
    -
    - - async_iterate (prevp, domain, ruleset, rng) -
    -
    - Asynchronous cellular automata iteration. - Performs a CA update on one cell (chosen randomly) in the specified domain. - - -

    Parameters:

    -
      -
    • prevp - the previous iteration of the pattern -
    • -
    • domain - the cells in which the CA operates -
    • -
    • ruleset - a table of forma.rules defining the CA -
    • -
    • rng - a (optional) random number generator (syntax as per math.random). -
    • -
    - -

    Returns:

    -
      -
    1. - The result of the CA iteration [pattern].
    2. -
    3. - Convergence flag [bool: true if converged, false otherwise].
    4. -
    - - - -

    Usage:

    -
      -
      -- Domain and initial state (500 seed points) for the CA
      -local domain = primitives.square(100)
      -local ca_pat = subpattern.random(sq, 500)
      -local rng    = math.random
      --- Repeat iteration until convergence is reached
      -local converged = false
      -repeat
      -	ca_pat, converged = automata.async_iterate(ca_pat, domain, {gol_rule}, rng)
      -until converged == true
      -
    - -
    -
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-13 00:47:33 -
    -
    - - diff --git a/docs/modules/forma.automata.html b/docs/modules/forma.automata.html index ea48bae..75d1a8a 100644 --- a/docs/modules/forma.automata.html +++ b/docs/modules/forma.automata.html @@ -276,7 +276,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/modules/forma.cell.html b/docs/modules/forma.cell.html index b8d5e72..e9812cb 100644 --- a/docs/modules/forma.cell.html +++ b/docs/modules/forma.cell.html @@ -471,7 +471,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/modules/forma.neighbourhood.html b/docs/modules/forma.neighbourhood.html index d2a4c18..b6b2be7 100644 --- a/docs/modules/forma.neighbourhood.html +++ b/docs/modules/forma.neighbourhood.html @@ -302,7 +302,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/modules/forma.pattern.html b/docs/modules/forma.pattern.html index 442f906..0d9f1ce 100644 --- a/docs/modules/forma.pattern.html +++ b/docs/modules/forma.pattern.html @@ -1155,7 +1155,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/modules/forma.primitives.html b/docs/modules/forma.primitives.html index 2c6ca48..d0ef49a 100644 --- a/docs/modules/forma.primitives.html +++ b/docs/modules/forma.primitives.html @@ -200,7 +200,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/modules/forma.subpattern.html b/docs/modules/forma.subpattern.html index a58ef98..d702089 100644 --- a/docs/modules/forma.subpattern.html +++ b/docs/modules/forma.subpattern.html @@ -586,7 +586,7 @@

    Parameters:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    diff --git a/docs/readme/README.md.html b/docs/readme/README.md.html index 68802e4..dd60c94 100644 --- a/docs/readme/README.md.html +++ b/docs/readme/README.md.html @@ -190,7 +190,7 @@

    Testing

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:06:54 +Last updated 2018-07-13 01:08:36
    From c51e08077902aba774df967361cf0666fd30c575 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 01:21:49 +0200 Subject: [PATCH 16/31] Tests for square and line primitives --- tests/primitives.lua | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/tests/primitives.lua b/tests/primitives.lua index 14015bd..a70cab4 100644 --- a/tests/primitives.lua +++ b/tests/primitives.lua @@ -1,14 +1,12 @@ --- Tests of basic forma primitives local lu = require('luaunit') local cell = require("forma.cell") +local pattern = require("forma.pattern") local primitives = require("forma.primitives") local subpattern = require("forma.subpattern") testPrimitives = {} -function testPrimitives:setUp() -end - -- Test circle raster ------------------------------------------------ function testPrimitives:testCircle() for i=1,10,1 do @@ -19,6 +17,31 @@ function testPrimitives:testCircle() for pt in inside_circle[1]:cells() do lu.assertTrue(cell.euclidean(pt, cell.new(0,0)) < i ) end + end +end +-- Test square raster ------------------------------------------------ +function testPrimitives:testCircle() + for i=1,10,1 do + -- Check that there are the correct number of points + local square_raster = primitives.square(i) + lu.assertEquals(square_raster:size(), i*i) + end + local test_pattern = pattern.new( {{1,1},{1,1}} ) + lu.assertEquals(test_pattern, primitives.square(2)) +end +-- Test line raster ------------------------------------------------ +function testPrimitives:testLine() + -- Draw a bunch of lines, check their properties + for _=1, 100, 1 do + local start = cell.new(math.random(-100, 100), math.random(-100, 100)) + local finish = cell.new(math.random(-100, 100), math.random(-100, 100)) + local line = primitives.line( start, finish ) + -- Must have start and finish cells + lu.assertTrue(line:has_cell(start.x, start.y)) + lu.assertTrue(line:has_cell(finish.x, finish.y)) + -- Must consist of one contiguous area + local floodfill = subpattern.floodfill(line, start) + lu.assertEquals(floodfill, line) end end From 176529d0d977cfd07c39d27a2de7a4f1d90a42d0 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 01:26:56 +0200 Subject: [PATCH 17/31] Test for cell tostring --- tests/cell.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cell.lua b/tests/cell.lua index ba92fe2..f883768 100644 --- a/tests/cell.lua +++ b/tests/cell.lua @@ -24,6 +24,10 @@ function testCell:testClone() lu.assertEvalToTrue(self.test_cell_1 == self.test_cell_4) end +function testCell:testToString() + lu.assertEquals(tostring(self.test_cell_1), "(1,2)") +end + function testCell:testManhattan() local d1 = cell.manhattan(self.test_cell_1, self.test_cell_2) local d2 = self.test_cell_1:manhattan(self.test_cell_2) From 30624142ce418c637ec70c1b8a22fc900cdd3788 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Fri, 13 Jul 2018 01:29:47 +0200 Subject: [PATCH 18/31] small update to automata docs --- forma/automata.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/forma/automata.lua b/forma/automata.lua index 531cc63..a3811c0 100644 --- a/forma/automata.lua +++ b/forma/automata.lua @@ -160,6 +160,7 @@ end --- Asynchronous cellular automata iteration. -- Performs a CA update on one cell (chosen randomly) in the specified domain. +-- This corresponds to a 'random independent scheme' update. -- @usage -- -- Domain and initial state (500 seed points) for the CA -- local domain = primitives.square(100) From 9867d8f0bc1b1f5e5684e91deb97efa8f6d66b8d Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 13:56:19 +0200 Subject: [PATCH 19/31] Neatened examples --- docs/contents.html | 2 +- docs/examples/async_automata.lua.html | 10 +++---- docs/examples/binary_space_partition.lua.html | 12 ++++----- docs/examples/bubbles.lua.html | 5 ++-- docs/examples/cellular_automata.lua.html | 13 ++++----- docs/examples/corridors.lua.html | 21 +++++---------- docs/examples/isolines.lua.html | 19 ++++++------- docs/examples/maxrectangle.lua.html | 27 +++++++------------ docs/examples/platformer.lua.html | 8 +++--- docs/examples/sampling.lua.html | 7 +++-- docs/examples/voronoi.lua.html | 13 ++++----- docs/modules/forma.automata.html | 3 ++- docs/modules/forma.cell.html | 2 +- docs/modules/forma.neighbourhood.html | 2 +- docs/modules/forma.pattern.html | 2 +- docs/modules/forma.primitives.html | 2 +- docs/modules/forma.subpattern.html | 14 +++++----- docs/readme/README.md.html | 2 +- examples/async_automata.lua | 8 +++--- examples/binary_space_partition.lua | 8 +++--- examples/bubbles.lua | 3 +-- examples/cellular_automata.lua | 9 +++---- examples/corridors.lua | 19 +++++-------- examples/isolines.lua | 17 +++++------- examples/maxrectangle.lua | 25 ++++++----------- examples/platformer.lua | 6 ++--- examples/sampling.lua | 5 ++-- examples/voronoi.lua | 11 +++----- forma/subpattern.lua | 14 +++++----- 29 files changed, 114 insertions(+), 175 deletions(-) diff --git a/docs/contents.html b/docs/contents.html index 9ec8ab8..3e11329 100644 --- a/docs/contents.html +++ b/docs/contents.html @@ -145,7 +145,7 @@

    Examples

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/async_automata.lua.html b/docs/examples/async_automata.lua.html index 6834561..647112b 100644 --- a/docs/examples/async_automata.lua.html +++ b/docs/examples/async_automata.lua.html @@ -65,7 +65,7 @@

    Readme

    async_automata.lua

    --- async_automata.lua.
    +-- Asynchronous Cellular Automata
     -- Here the use of an asynchronous cellular automata is demonstrated, making
     -- use also of symmetrisation methods to generate a final, symmetric pattern.
     
    @@ -75,8 +75,6 @@ 

    async_automata.lua

    local subpattern = require('forma.subpattern') local neighbourhood = require('forma.neighbourhood') -math.randomseed( os.time() ) - -- Domain for CA to operate in local sq = primitives.square(10,5) @@ -93,7 +91,7 @@

    async_automata.lua

    ca_pattern, converged = automata.async_iterate(ca_pattern, sq, {moore}) end --- Mirror the basic pattern a couple of times +-- Add some symmetry by mirroring the basic pattern a couple of times local symmetrised_pattern = ca_pattern:hreflect() symmetrised_pattern = symmetrised_pattern:vreflect():vreflect() symmetrised_pattern = symmetrised_pattern:hreflect():hreflect() @@ -102,14 +100,14 @@

    async_automata.lua

    -- This turns the basic pattern into standard 'box-drawing' characters local vn = neighbourhood.von_neumann() local segments = subpattern.neighbourhood_categories(symmetrised_pattern, vn) -subpattern.pretty_print(symmetrised_pattern, segments, vn:category_label())
    +subpattern.print_patterns(symmetrised_pattern, segments, vn:category_label())
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/binary_space_partition.lua.html b/docs/examples/binary_space_partition.lua.html index f5342e6..879b85c 100644 --- a/docs/examples/binary_space_partition.lua.html +++ b/docs/examples/binary_space_partition.lua.html @@ -65,25 +65,23 @@

    Readme

    binary_space_partition.lua

    --- binary_space_partition.lua
    --- Example of binary space partitioning
    -
    -local subpattern = require('forma.subpattern')
    +-- Binary space partitioning
    +local subpattern = require('forma.subpattern')
     local primitives = require('forma.primitives')
     
     -- Generate an 80x20 square and partition it into segments of maximally 50 cells
     local square = primitives.square(80,20)
     local bsp = subpattern.bsp(square, 50)
     
    --- Pretty print resulting pattern segments
    -subpattern.pretty_print(square,bsp)
    +-- Print resulting pattern segments +subpattern.print_patterns(square,bsp)
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/bubbles.lua.html b/docs/examples/bubbles.lua.html index c0bb797..0d4feef 100644 --- a/docs/examples/bubbles.lua.html +++ b/docs/examples/bubbles.lua.html @@ -71,7 +71,6 @@

    bubbles.lua

    local primitives = require('forma.primitives') local subpattern = require('forma.subpattern') -math.randomseed( os.time() ) local max_radius = 4 -- Setup domain and some random seeds @@ -85,14 +84,14 @@

    bubbles.lua

    shapes = shapes + circle:shift(seed.x, seed.y) end -subpattern.pretty_print(domain, {shapes}, {'o'}) +subpattern.print_patterns(domain, {shapes}, {'o'})
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/cellular_automata.lua.html b/docs/examples/cellular_automata.lua.html index a2ccddd..1f32f71 100644 --- a/docs/examples/cellular_automata.lua.html +++ b/docs/examples/cellular_automata.lua.html @@ -65,21 +65,18 @@

    Readme

    cellular_automata.lua

    --- cellular_automata.lua
    --- Demonstration of classic cellular-automata cave generation (4-5 rule)
    -
    -local primitives    = require('forma.primitives')
    +-- Cellular Automata
    +-- Demonstration of classic cellular-automata cave generation (4-5 rule).
    +local primitives    = require('forma.primitives')
     local subpattern    = require('forma.subpattern')
     local automata      = require('forma.automata')
     local neighbourhood = require('forma.neighbourhood')
     
    -math.randomseed( os.time() )
    -
     -- Domain for CA
     local sq = primitives.square(80,20)
     
     -- CA initial condition: sample at random from the domain
    -local ca = subpattern.random(sq, math.floor(sq:size()*0.5))
    +local ca = subpattern.random(sq, 800)
     
     -- Moore neighbourhood 4-5 rule
     local moore = automata.rule(neighbourhood.moore(), "B5678/S45678")
    @@ -97,7 +94,7 @@ 

    cellular_automata.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/corridors.lua.html b/docs/examples/corridors.lua.html index db0f42e..41ece5f 100644 --- a/docs/examples/corridors.lua.html +++ b/docs/examples/corridors.lua.html @@ -65,13 +65,10 @@

    Readme

    corridors.lua

    --- corridors.lua
    --- Demonstration of forma asynchronous cellular automata
    --- Generates a plausible corridor system in an 80x20 box
    -
    --- 'asynchronous CA' follow the same rules as normal CA, but the rule is
    --- applied at random to only once cell at a time, unlike normal synchronous
    --- rules where the whole pattern is updated.
    +-- Multiple CA rules
    +-- Here the way multiple CA rules can be combined into a single ruleset is
    +-- demonstrated. A asynchronous cellular automata with a complicated ruleset
    +-- generates an interesting 'corridor' like pattern.
     
     local pattern       = require('forma.pattern')
     local primitives    = require('forma.primitives')
    @@ -79,8 +76,6 @@ 

    corridors.lua

    local subpattern = require('forma.subpattern') local neighbourhood = require('forma.neighbourhood') -math.randomseed(os.time()) - local sq = primitives.square(80,20) local seed = sq:rcell() @@ -94,23 +89,21 @@

    corridors.lua

    local vn = automata.rule(neighbourhood.von_neumann(),"B12/S01234") local ruleset = {diag2, diag, vn, moore} -local ite = 0 repeat local converged tp, converged = automata.async_iterate(tp, sq, ruleset) - ite = ite + 1 -until converged == true +until converged local nbh = neighbourhood.von_neumann() local segments = subpattern.neighbourhood_categories(tp, nbh) -subpattern.pretty_print(tp, segments, nbh:category_label())
    +subpattern.print_patterns(tp, segments, nbh:category_label())
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/isolines.lua.html b/docs/examples/isolines.lua.html index 9aa6f97..17afb79 100644 --- a/docs/examples/isolines.lua.html +++ b/docs/examples/isolines.lua.html @@ -65,25 +65,22 @@

    Readme

    isolines.lua

    --- isolines.lua
    --- Rasterising isolines of a scalar field.
    -
    --- Here we generate a pattern randomly filled with points, and take as the
    --- field N(cell) = F_2(cell) - F_1(cell), where F_n is the chebyshev distance
    --- to the nth nearest neighbour. Isolines at N = 0 are drawn by thresholding N
    +-- Rasterising Isolines
    +-- Here we generate a pattern randomly filled with points, and take as a scalar
    +-- field N(cell) = F_2(cell) - F_1(cell), where F_n is the Chebyshev distance
    +-- to the nth nearest neighbour. Isolines at N = 0 are drawn by thresholding N
     -- at 1 and taking the surface.
     
     local cell          = require('forma.cell')
     local subpattern    = require('forma.subpattern')
     local primitives    = require('forma.primitives')
    -math.randomseed( os.time() )
     
     -- Distance measure
     local measure = cell.chebyshev
     
    --- Domain and seeds
    +-- Domain and list of seed cells
     local sq = primitives.square(80,20)
    -local rn = subpattern.random(sq, math.floor(sq:size()*0.01)):cell_list()
    +local rn = subpattern.random(sq, 20):cell_list()
     
     -- Worley noise mask
     local mask = function(tcell)
    @@ -98,14 +95,14 @@ 

    isolines.lua

    -- Compute the thresholded pattern and print its surface local noise = subpattern.mask(sq, mask) -subpattern.pretty_print(sq, {noise:surface()}, {'#'})
    +subpattern.print_patterns(sq, {noise:surface()}, {'#'})
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/maxrectangle.lua.html b/docs/examples/maxrectangle.lua.html index f0e58ae..586f452 100644 --- a/docs/examples/maxrectangle.lua.html +++ b/docs/examples/maxrectangle.lua.html @@ -65,36 +65,27 @@

    Readme

    maxrectangle.lua

    --- maxrectangle.lua
    --- Example of maximum rectangle finding in a general domain
    +-- Maximum rectangle finding
    +-- This generates a messy random pattern, and finds the largest contiguous
    +-- rectangle of active cells within it.
     
    -local pattern    = require('forma.pattern')
     local subpattern = require('forma.subpattern')
     local primitives = require('forma.primitives')
     
    -math.randomseed( os.time() )
    -
    --- Generate a messy pattern inside a domain
    +-- Generate a domain and a messy 'blocking' pattern
     local domain = primitives.square(80, 20)
    -local total_pattern = pattern.new()
    -for _=1,200,1 do
    -    -- Generate a randomly sized square at a random point of the domain
    -    local rpoint = domain:rcell()
    -    local tp = primitives.square(math.random(7)):shift(rpoint.x, rpoint.y)
    -    total_pattern = total_pattern + tp
    -end
    +local blocks = subpattern.random(domain, 80)
     
    --- Find the largest contiguous rectangle in the base pattern
    -local mxrect = subpattern.maxrectangle(total_pattern)
    -local rest_pattern = total_pattern - mxrect
    -subpattern.pretty_print(total_pattern,{rest_pattern, mxrect}, {'.','#'})
    +-- Find the largest contiguous 'unblocked' rectangle in the base pattern +local mxrect = subpattern.maxrectangle(domain - blocks) +subpattern.print_patterns(domain,{blocks, mxrect}, {'o','#'})
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/platformer.lua.html b/docs/examples/platformer.lua.html index e04c3fc..659bbe3 100644 --- a/docs/examples/platformer.lua.html +++ b/docs/examples/platformer.lua.html @@ -95,21 +95,21 @@

    platformer.lua

    tp, converged = automata.async_iterate(tp, sq, ruleset) until converged == true -tp = pattern.edge(tp) -- Comment this out and you get a subsystem +tp = pattern.surface(tp) -- Comment this out and you get a subsystem tp = pattern.enlarge(tp,4) tp = pattern.surface(tp) --- Pretty print according to neighbourhood +-- Print according to neighbourhood local nbh = neighbourhood.von_neumann() local segments = subpattern.neighbourhood_categories(tp, nbh) -subpattern.pretty_print(tp, segments, nbh:category_label()) +subpattern.print_patterns(tp, segments, nbh:category_label())
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/sampling.lua.html b/docs/examples/sampling.lua.html index 1835923..3562afd 100644 --- a/docs/examples/sampling.lua.html +++ b/docs/examples/sampling.lua.html @@ -65,7 +65,7 @@

    Readme

    sampling.lua

    ---- sampling.lua
    +--- Sampling methods
     -- Demonstrations of various methods for sampling from a pattern.
     -- 1. pattern.random generates white noise, it's fast and irreguarly distributed.
     -- 2. Lloyd's algorithm when a specific number of uniform samples are desired
    @@ -75,7 +75,6 @@ 

    sampling.lua

    local cell = require('forma.cell') local subpattern = require('forma.subpattern') local primitives = require('forma.primitives') -math.randomseed( os.time() ) -- Domain and seed local measure = cell.chebyshev @@ -87,14 +86,14 @@

    sampling.lua

    --local random = subpattern.random(domain, 40) --local _, random = subpattern.voronoi_relax(random, domain, measure) -subpattern.pretty_print(domain, {random}, {'#'})
    +subpattern.print_patterns(domain, {random}, {'#'})
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/examples/voronoi.lua.html b/docs/examples/voronoi.lua.html index 0b96e56..d20dbf3 100644 --- a/docs/examples/voronoi.lua.html +++ b/docs/examples/voronoi.lua.html @@ -65,30 +65,27 @@

    Readme

    voronoi.lua

    --- voronoi.lua
    --- Demonstration of voronoi tesselation
    -
    -local cell      = require('forma.cell')
    +-- Voronoi tesselation
    +local cell       = require('forma.cell')
     local primitives = require('forma.primitives')
     local subpattern = require('forma.subpattern')
    -math.randomseed(os.time())
     
     -- Generate a random pattern in a specified domain
     local sq = primitives.square(80,20)
     local rn = subpattern.random(sq, 10)
     
    --- Compute its voronoi tesselation
    +-- Compute the corresponding voronoi tesselation
     local measure  = cell.chebyshev
     local segments = subpattern.voronoi(rn, sq, measure)
     
    -subpattern.pretty_print(sq, segments)
    +subpattern.print_patterns(sq, segments)
    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/modules/forma.automata.html b/docs/modules/forma.automata.html index 75d1a8a..35a2214 100644 --- a/docs/modules/forma.automata.html +++ b/docs/modules/forma.automata.html @@ -227,6 +227,7 @@

    Usage:

    Asynchronous cellular automata iteration. Performs a CA update on one cell (chosen randomly) in the specified domain. + This corresponds to a 'random independent scheme' update.

    Parameters:

    @@ -276,7 +277,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/modules/forma.cell.html b/docs/modules/forma.cell.html index e9812cb..d240358 100644 --- a/docs/modules/forma.cell.html +++ b/docs/modules/forma.cell.html @@ -471,7 +471,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/modules/forma.neighbourhood.html b/docs/modules/forma.neighbourhood.html index b6b2be7..82668ce 100644 --- a/docs/modules/forma.neighbourhood.html +++ b/docs/modules/forma.neighbourhood.html @@ -302,7 +302,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/modules/forma.pattern.html b/docs/modules/forma.pattern.html index 0d9f1ce..fc2fa09 100644 --- a/docs/modules/forma.pattern.html +++ b/docs/modules/forma.pattern.html @@ -1155,7 +1155,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/modules/forma.primitives.html b/docs/modules/forma.primitives.html index d0ef49a..9f6db65 100644 --- a/docs/modules/forma.primitives.html +++ b/docs/modules/forma.primitives.html @@ -200,7 +200,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/modules/forma.subpattern.html b/docs/modules/forma.subpattern.html index d702089..85d0d57 100644 --- a/docs/modules/forma.subpattern.html +++ b/docs/modules/forma.subpattern.html @@ -79,7 +79,7 @@

    Module forma.subpattern

    example the segments method which returns a table of all contiguous (according to some neighbourhood) sub-patterns by using a floodfill.

    -

    In addition to the subpattern finders, a pretty_print utility is provided +

    In addition to the subpattern finders, a print_patterns utility is provided to render these tables of sub-patterns into text.

    @@ -140,8 +140,8 @@

    Lists of sub-patterns

    Utilities

    - - + +
    pretty_print (domain, segments, chars)Pretty print a table of forma.pattern segments.print_patterns (domain, segments, chars)Print a table of forma.patterns.
    @@ -552,11 +552,11 @@

    Utilities

    - - pretty_print (domain, segments, chars) + + print_patterns (domain, segments, chars)
    - Pretty print a table of forma.pattern segments. + Print a table of forma.patterns. Prints a table of pattern segments to io.output. If provided, a table of segment labels can be used, with one entry per segment. @@ -586,7 +586,7 @@

    Parameters:

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/docs/readme/README.md.html b/docs/readme/README.md.html index dd60c94..5b65b33 100644 --- a/docs/readme/README.md.html +++ b/docs/readme/README.md.html @@ -190,7 +190,7 @@

    Testing

    generated by LDoc 1.4.6 -Last updated 2018-07-13 01:08:36 +Last updated 2018-07-14 13:54:03
    diff --git a/examples/async_automata.lua b/examples/async_automata.lua index 08dcfe2..c5b7595 100755 --- a/examples/async_automata.lua +++ b/examples/async_automata.lua @@ -1,4 +1,4 @@ --- async_automata.lua. +-- Asynchronous Cellular Automata -- Here the use of an asynchronous cellular automata is demonstrated, making -- use also of symmetrisation methods to generate a final, symmetric pattern. @@ -8,8 +8,6 @@ local automata = require('forma.automata') local subpattern = require('forma.subpattern') local neighbourhood = require('forma.neighbourhood') -math.randomseed( os.time() ) - -- Domain for CA to operate in local sq = primitives.square(10,5) @@ -26,7 +24,7 @@ while converged == false do ca_pattern, converged = automata.async_iterate(ca_pattern, sq, {moore}) end --- Mirror the basic pattern a couple of times +-- Add some symmetry by mirroring the basic pattern a couple of times local symmetrised_pattern = ca_pattern:hreflect() symmetrised_pattern = symmetrised_pattern:vreflect():vreflect() symmetrised_pattern = symmetrised_pattern:hreflect():hreflect() @@ -35,4 +33,4 @@ symmetrised_pattern = symmetrised_pattern:hreflect():hreflect() -- This turns the basic pattern into standard 'box-drawing' characters local vn = neighbourhood.von_neumann() local segments = subpattern.neighbourhood_categories(symmetrised_pattern, vn) -subpattern.pretty_print(symmetrised_pattern, segments, vn:category_label()) +subpattern.print_patterns(symmetrised_pattern, segments, vn:category_label()) diff --git a/examples/binary_space_partition.lua b/examples/binary_space_partition.lua index b432c81..2675ec3 100755 --- a/examples/binary_space_partition.lua +++ b/examples/binary_space_partition.lua @@ -1,6 +1,4 @@ --- binary_space_partition.lua --- Example of binary space partitioning - +-- Binary space partitioning local subpattern = require('forma.subpattern') local primitives = require('forma.primitives') @@ -8,6 +6,6 @@ local primitives = require('forma.primitives') local square = primitives.square(80,20) local bsp = subpattern.bsp(square, 50) --- Pretty print resulting pattern segments -subpattern.pretty_print(square,bsp) +-- Print resulting pattern segments +subpattern.print_patterns(square,bsp) diff --git a/examples/bubbles.lua b/examples/bubbles.lua index f363545..bcc3826 100755 --- a/examples/bubbles.lua +++ b/examples/bubbles.lua @@ -4,7 +4,6 @@ local pattern = require('forma.pattern') local primitives = require('forma.primitives') local subpattern = require('forma.subpattern') -math.randomseed( os.time() ) local max_radius = 4 -- Setup domain and some random seeds @@ -18,6 +17,6 @@ for seed in seeds:cells() do shapes = shapes + circle:shift(seed.x, seed.y) end -subpattern.pretty_print(domain, {shapes}, {'o'}) +subpattern.print_patterns(domain, {shapes}, {'o'}) diff --git a/examples/cellular_automata.lua b/examples/cellular_automata.lua index 7195c71..73ba408 100755 --- a/examples/cellular_automata.lua +++ b/examples/cellular_automata.lua @@ -1,18 +1,15 @@ --- cellular_automata.lua --- Demonstration of classic cellular-automata cave generation (4-5 rule) - +-- Cellular Automata +-- Demonstration of classic cellular-automata cave generation (4-5 rule). local primitives = require('forma.primitives') local subpattern = require('forma.subpattern') local automata = require('forma.automata') local neighbourhood = require('forma.neighbourhood') -math.randomseed( os.time() ) - -- Domain for CA local sq = primitives.square(80,20) -- CA initial condition: sample at random from the domain -local ca = subpattern.random(sq, math.floor(sq:size()*0.5)) +local ca = subpattern.random(sq, 800) -- Moore neighbourhood 4-5 rule local moore = automata.rule(neighbourhood.moore(), "B5678/S45678") diff --git a/examples/corridors.lua b/examples/corridors.lua index 08e2f6c..26fcd8e 100755 --- a/examples/corridors.lua +++ b/examples/corridors.lua @@ -1,10 +1,7 @@ --- corridors.lua --- Demonstration of forma asynchronous cellular automata --- Generates a plausible corridor system in an 80x20 box - --- 'asynchronous CA' follow the same rules as normal CA, but the rule is --- applied at random to only once cell at a time, unlike normal synchronous --- rules where the whole pattern is updated. +-- Multiple CA rules +-- Here the way multiple CA rules can be combined into a single ruleset is +-- demonstrated. A asynchronous cellular automata with a complicated ruleset +-- generates an interesting 'corridor' like pattern. local pattern = require('forma.pattern') local primitives = require('forma.primitives') @@ -12,8 +9,6 @@ local automata = require('forma.automata') local subpattern = require('forma.subpattern') local neighbourhood = require('forma.neighbourhood') -math.randomseed(os.time()) - local sq = primitives.square(80,20) local seed = sq:rcell() @@ -27,13 +22,11 @@ local diag2 = automata.rule(neighbourhood.diagonal_2(), "B01/S01234") local vn = automata.rule(neighbourhood.von_neumann(),"B12/S01234") local ruleset = {diag2, diag, vn, moore} -local ite = 0 repeat local converged tp, converged = automata.async_iterate(tp, sq, ruleset) - ite = ite + 1 -until converged == true +until converged local nbh = neighbourhood.von_neumann() local segments = subpattern.neighbourhood_categories(tp, nbh) -subpattern.pretty_print(tp, segments, nbh:category_label()) +subpattern.print_patterns(tp, segments, nbh:category_label()) diff --git a/examples/isolines.lua b/examples/isolines.lua index 724aeb3..c407319 100755 --- a/examples/isolines.lua +++ b/examples/isolines.lua @@ -1,22 +1,19 @@ --- isolines.lua --- Rasterising isolines of a scalar field. - --- Here we generate a pattern randomly filled with points, and take as the --- field N(cell) = F_2(cell) - F_1(cell), where F_n is the chebyshev distance --- to the nth nearest neighbour. Isolines at N = 0 are drawn by thresholding N +-- Rasterising Isolines +-- Here we generate a pattern randomly filled with points, and take as a scalar +-- field `N(cell) = F_2(cell) - F_1(cell)`, where `F_n` is the Chebyshev distance +-- to the nth nearest neighbour. Isolines at `N = 0` are drawn by thresholding `N` -- at 1 and taking the surface. local cell = require('forma.cell') local subpattern = require('forma.subpattern') local primitives = require('forma.primitives') -math.randomseed( os.time() ) -- Distance measure local measure = cell.chebyshev --- Domain and seeds +-- Domain and list of seed cells local sq = primitives.square(80,20) -local rn = subpattern.random(sq, math.floor(sq:size()*0.01)):cell_list() +local rn = subpattern.random(sq, 20):cell_list() -- Worley noise mask local mask = function(tcell) @@ -31,5 +28,5 @@ end -- Compute the thresholded pattern and print its surface local noise = subpattern.mask(sq, mask) -subpattern.pretty_print(sq, {noise:surface()}, {'#'}) +subpattern.print_patterns(sq, {noise:surface()}, {'#'}) diff --git a/examples/maxrectangle.lua b/examples/maxrectangle.lua index dbea305..f2cce65 100755 --- a/examples/maxrectangle.lua +++ b/examples/maxrectangle.lua @@ -1,23 +1,14 @@ --- maxrectangle.lua --- Example of maximum rectangle finding in a general domain +-- Maximum rectangle finding +-- This generates a messy random pattern, and finds the largest contiguous +-- rectangle of active cells within it. -local pattern = require('forma.pattern') local subpattern = require('forma.subpattern') local primitives = require('forma.primitives') -math.randomseed( os.time() ) - --- Generate a messy pattern inside a domain +-- Generate a domain and a messy 'blocking' pattern local domain = primitives.square(80, 20) -local total_pattern = pattern.new() -for _=1,200,1 do - -- Generate a randomly sized square at a random point of the domain - local rpoint = domain:rcell() - local tp = primitives.square(math.random(7)):shift(rpoint.x, rpoint.y) - total_pattern = total_pattern + tp -end +local blocks = subpattern.random(domain, 80) --- Find the largest contiguous rectangle in the base pattern -local mxrect = subpattern.maxrectangle(total_pattern) -local rest_pattern = total_pattern - mxrect -subpattern.pretty_print(total_pattern,{rest_pattern, mxrect}, {'.','#'}) +-- Find the largest contiguous 'unblocked' rectangle in the base pattern +local mxrect = subpattern.maxrectangle(domain - blocks) +subpattern.print_patterns(domain,{blocks, mxrect}, {'o','#'}) diff --git a/examples/platformer.lua b/examples/platformer.lua index 0a50e73..b4038e9 100755 --- a/examples/platformer.lua +++ b/examples/platformer.lua @@ -28,12 +28,12 @@ repeat tp, converged = automata.async_iterate(tp, sq, ruleset) until converged == true -tp = pattern.edge(tp) -- Comment this out and you get a subsystem +tp = pattern.surface(tp) -- Comment this out and you get a subsystem tp = pattern.enlarge(tp,4) tp = pattern.surface(tp) --- Pretty print according to neighbourhood +-- Print according to neighbourhood local nbh = neighbourhood.von_neumann() local segments = subpattern.neighbourhood_categories(tp, nbh) -subpattern.pretty_print(tp, segments, nbh:category_label()) +subpattern.print_patterns(tp, segments, nbh:category_label()) diff --git a/examples/sampling.lua b/examples/sampling.lua index ef5f043..c258bcc 100755 --- a/examples/sampling.lua +++ b/examples/sampling.lua @@ -1,4 +1,4 @@ ---- sampling.lua +--- Sampling methods -- Demonstrations of various methods for sampling from a pattern. -- 1. `pattern.random` generates white noise, it's fast and irreguarly distributed. -- 2. Lloyd's algorithm when a specific number of uniform samples are desired @@ -8,7 +8,6 @@ local cell = require('forma.cell') local subpattern = require('forma.subpattern') local primitives = require('forma.primitives') -math.randomseed( os.time() ) -- Domain and seed local measure = cell.chebyshev @@ -20,4 +19,4 @@ local random = subpattern.poisson_disc(domain, measure, 4) --local random = subpattern.random(domain, 40) --local _, random = subpattern.voronoi_relax(random, domain, measure) -subpattern.pretty_print(domain, {random}, {'#'}) +subpattern.print_patterns(domain, {random}, {'#'}) diff --git a/examples/voronoi.lua b/examples/voronoi.lua index 277d9c2..6e5db1c 100755 --- a/examples/voronoi.lua +++ b/examples/voronoi.lua @@ -1,17 +1,14 @@ --- voronoi.lua --- Demonstration of voronoi tesselation - -local cell = require('forma.cell') +-- Voronoi tesselation +local cell = require('forma.cell') local primitives = require('forma.primitives') local subpattern = require('forma.subpattern') -math.randomseed(os.time()) -- Generate a random pattern in a specified domain local sq = primitives.square(80,20) local rn = subpattern.random(sq, 10) --- Compute its voronoi tesselation +-- Compute the corresponding voronoi tesselation local measure = cell.chebyshev local segments = subpattern.voronoi(rn, sq, measure) -subpattern.pretty_print(sq, segments) +subpattern.print_patterns(sq, segments) diff --git a/forma/subpattern.lua b/forma/subpattern.lua index 9ec53fe..4b2e287 100644 --- a/forma/subpattern.lua +++ b/forma/subpattern.lua @@ -7,7 +7,7 @@ -- example the `segments` method which returns a table of all contiguous -- (according to some `neighbourhood`) sub-patterns by using a `floodfill`. -- --- In addition to the subpattern finders, a `pretty_print` utility is provided +-- In addition to the subpattern finders, a `print_patterns` utility is provided -- to render these tables of sub-patterns into text. -- -- @module forma.subpattern @@ -447,26 +447,26 @@ end --- Utilities -- @section subpattern_utils ---- Pretty print a table of forma.pattern segments. +--- Print a table of forma.patterns. -- Prints a table of pattern segments to `io.output`. If provided, a table of -- segment labels can be used, with one entry per segment. -- @param domain the basic pattern from which the segments were generated. -- @param segments the table of segments to be drawn. -- @param chars the characters to be printed for each segment (optional). -function subpattern.pretty_print(domain, segments, chars) - assert(domain:size() > 0, "subpattern.pretty_print: domain must have at least one cell") - assert(type(segments) == "table", "subpattern.pretty_print: second argument must be a *table* of patterns") +function subpattern.print_patterns(domain, segments, chars) + assert(domain:size() > 0, "subpattern.print_patterns: domain must have at least one cell") + assert(type(segments) == "table", "subpattern.print_patterns: second argument must be a *table* of patterns") -- If no dictionary is supplied generate a new one (starting from '0') if chars == nil then local start_char = 47 - assert(#segments < (200 - start_char), "subpattern.pretty_print: too many segments") + assert(#segments < (200 - start_char), "subpattern.print_patterns: too many segments") chars = {} for i=1, #segments, 1 do table.insert(chars, string.char(i+start_char)) end end assert(#segments == #chars, - "subpattern.pretty_print: there must be as many character table entries as segments") + "subpattern.print_patterns: there must be as many character table entries as segments") -- Print out the segments to a map for i=domain.min.y, domain.max.y,1 do local string = '' From 88c8763fba0140ed0b80ca3ffb1715cf3e993d10 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 14:27:18 +0200 Subject: [PATCH 20/31] Example gallery --- examples/README.md | 262 ++++++++++++++++++++++++ examples/img/async_automata.png | Bin 0 -> 576 bytes examples/img/binary_space_partition.png | Bin 0 -> 960 bytes examples/img/bubbles.png | Bin 0 -> 1193 bytes examples/img/cellular_automata.png | Bin 0 -> 1195 bytes examples/img/corridors.png | Bin 0 -> 968 bytes examples/img/gallery.png | Bin 0 -> 509 bytes examples/img/isolines.png | Bin 0 -> 1789 bytes examples/img/maxrectangle.png | Bin 0 -> 1062 bytes examples/img/sampling.png | Bin 0 -> 967 bytes examples/img/voronoi.png | Bin 0 -> 1869 bytes examples/platformer.lua | 39 ---- 12 files changed, 262 insertions(+), 39 deletions(-) create mode 100644 examples/README.md create mode 100644 examples/img/async_automata.png create mode 100644 examples/img/binary_space_partition.png create mode 100644 examples/img/bubbles.png create mode 100644 examples/img/cellular_automata.png create mode 100644 examples/img/corridors.png create mode 100644 examples/img/gallery.png create mode 100644 examples/img/isolines.png create mode 100644 examples/img/maxrectangle.png create mode 100644 examples/img/sampling.png create mode 100644 examples/img/voronoi.png delete mode 100755 examples/platformer.lua diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..7e33dc6 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,262 @@ +# *forma* example gallery +* [Binary space partitioning](#binary-space-partitioning) +* [Voronoi tesselation](#voronoi-tesselation) +* [Maximum rectangle finding](#maximum-rectangle-finding) +* [Circle primitives](#circle-primitives) +* [Cellular automata](#cellular-automata) +* [Sampling methods](#sampling-methods) +* [Rasterising isolines](#rasterising-isolines) +* [Combining cellular automata rules](#combining-cellular-automata-rules) +* [Asynchronous cellular automata](#asynchronous-cellular-automata) + +## Binary space partitioning + +```lua +local subpattern = require('forma.subpattern') +local primitives = require('forma.primitives') + +-- Generate an 80x20 square and partition it into segments of maximally 50 cells +local square = primitives.square(80,20) +local bsp = subpattern.bsp(square, 50) + +-- Print resulting pattern segments +subpattern.print_patterns(square,bsp) + +``` +### Output +![foo](img/binary_space_partition.png ) +## Voronoi tesselation + +```lua +local cell = require('forma.cell') +local primitives = require('forma.primitives') +local subpattern = require('forma.subpattern') + +-- Generate a random pattern in a specified domain +local sq = primitives.square(80,20) +local rn = subpattern.random(sq, 10) + +-- Compute the corresponding voronoi tesselation +local measure = cell.chebyshev +local segments = subpattern.voronoi(rn, sq, measure) + +subpattern.print_patterns(sq, segments) +``` +### Output +![foo](img/voronoi.png ) +## Maximum rectangle finding +This generates a messy random pattern, and finds the largest contiguous +rectangle of active cells within it. + +```lua + +local subpattern = require('forma.subpattern') +local primitives = require('forma.primitives') + +-- Generate a domain and a messy 'blocking' pattern +local domain = primitives.square(80, 20) +local blocks = subpattern.random(domain, 80) + +-- Find the largest contiguous 'unblocked' rectangle in the base pattern +local mxrect = subpattern.maxrectangle(domain - blocks) +subpattern.print_patterns(domain,{blocks, mxrect}, {'o','#'}) +``` +### Output +![foo](img/maxrectangle.png ) +## Circle primitives + +```lua +local cell = require('forma.cell') +local pattern = require('forma.pattern') +local primitives = require('forma.primitives') +local subpattern = require('forma.subpattern') + +local max_radius = 4 + +-- Setup domain and some random seeds +local domain = primitives.square(80,20) +local seeds = subpattern.poisson_disc(domain, cell.euclidean, 2*max_radius) +local shapes = pattern.new() + +-- Randomly generate some circles in the domain +for seed in seeds:cells() do + local circle = primitives.circle(math.random(2, max_radius)) + shapes = shapes + circle:shift(seed.x, seed.y) +end + +subpattern.print_patterns(domain, {shapes}, {'o'}) + + +``` +### Output +![foo](img/bubbles.png ) +## Cellular automata +Demonstration of classic cellular-automata cave generation (4-5 rule). + +```lua +local primitives = require('forma.primitives') +local subpattern = require('forma.subpattern') +local automata = require('forma.automata') +local neighbourhood = require('forma.neighbourhood') + +-- Domain for CA +local sq = primitives.square(80,20) + +-- CA initial condition: sample at random from the domain +local ca = subpattern.random(sq, 800) + +-- Moore neighbourhood 4-5 rule +local moore = automata.rule(neighbourhood.moore(), "B5678/S45678") +local ite, converged = 0, false +while converged == false and ite < 1000 do + ca, converged = automata.iterate(ca, sq, {moore}) + ite = ite+1 +end + +ca.onchar, ca.offchar = "#", " " +print(ca) +``` +### Output +![foo](img/cellular_automata.png ) +## Sampling methods +Demonstrations of various methods for sampling from a pattern. +1. `pattern.random` generates white noise, it's fast and irreguarly distributed. +2. Lloyd's algorithm when a specific number of uniform samples are desired. +3. Mitchell's algorithm is a good (fast) approximation of (2). +3. Poisson-disc when a minimum separation between samples is the only requirement. + +```lua + +local cell = require('forma.cell') +local subpattern = require('forma.subpattern') +local primitives = require('forma.primitives') + +-- Domain and seed +local measure = cell.chebyshev +local domain = primitives.square(80,20) + +-- Random samples, uncomment these turn by turn to see the differences +local random = subpattern.poisson_disc(domain, measure, 4) +--local random = subpattern.mitchell_sample(domain, measure, 100, 100) +--local random = subpattern.random(domain, 40) +--local _, random = subpattern.voronoi_relax(random, domain, measure) + +subpattern.print_patterns(domain, {random}, {'#'}) +``` +### Output +![foo](img/sampling.png ) +## Rasterising isolines +Here we generate a pattern randomly filled with points, and take as a scalar +field `N(cell) = F_2(cell) - F_1(cell)`, where `F_n` is the Chebyshev distance +to the nth nearest neighbour. Isolines at `N = 0` are drawn by thresholding `N` +at 1 and taking the surface. + +```lua + +local cell = require('forma.cell') +local subpattern = require('forma.subpattern') +local primitives = require('forma.primitives') + +-- Distance measure +local measure = cell.chebyshev + +-- Domain and list of seed cells +local sq = primitives.square(80,20) +local rn = subpattern.random(sq, 20):cell_list() + +-- Worley noise mask +local mask = function(tcell) + local sortfn = function(a,b) + return measure(tcell, a) < measure(tcell, b) + end + table.sort(rn, sortfn) + local F1 = measure(rn[1], tcell) + local F2 = measure(rn[2], tcell) + return F2 - F1 > 1 +end + +-- Compute the thresholded pattern and print its surface +local noise = subpattern.mask(sq, mask) +subpattern.print_patterns(sq, {noise:surface()}, {'#'}) + +``` +### Output +![foo](img/isolines.png ) +## Combining cellular automata rules +Here the way multiple CA rules can be combined into a single ruleset is +demonstrated. A asynchronous cellular automata with a complicated ruleset +generates an interesting 'corridor' like pattern. + +```lua + +local pattern = require('forma.pattern') +local primitives = require('forma.primitives') +local automata = require('forma.automata') +local subpattern = require('forma.subpattern') +local neighbourhood = require('forma.neighbourhood') + +local sq = primitives.square(80,20) +local seed = sq:rcell() + +local tp = pattern.new() +tp:insert(seed.x, seed.y) + +-- Complicated ruleset (leaving diag2 out provides a denser pattern) +local moore = automata.rule(neighbourhood.moore(), "B12/S012345678") +local diag = automata.rule(neighbourhood.diagonal(), "B0123/S01234") +local diag2 = automata.rule(neighbourhood.diagonal_2(), "B01/S01234") +local vn = automata.rule(neighbourhood.von_neumann(),"B12/S01234") +local ruleset = {diag2, diag, vn, moore} + +repeat + local converged + tp, converged = automata.async_iterate(tp, sq, ruleset) +until converged + +local nbh = neighbourhood.von_neumann() +local segments = subpattern.neighbourhood_categories(tp, nbh) +subpattern.print_patterns(tp, segments, nbh:category_label()) +``` +### Output +![foo](img/corridors.png ) +## Asynchronous cellular automata +Here the use of an asynchronous cellular automata is demonstrated, making +use also of symmetrisation methods to generate a final, symmetric pattern. + +```lua + +local pattern = require('forma.pattern') +local primitives = require('forma.primitives') +local automata = require('forma.automata') +local subpattern = require('forma.subpattern') +local neighbourhood = require('forma.neighbourhood') + +-- Domain for CA to operate in +local sq = primitives.square(10,5) + +-- Make a new pattern consisting of a single random cell from the domain +local start_point = sq:rcell() -- Select a random point +local ca_pattern = pattern.new():insert(start_point.x, start_point.y) + +-- Moore neighbourhood rule for CA +local moore = automata.rule(neighbourhood.moore(), "B12/S012345678") + +-- Perform asynchronous CA update until convergence +local converged = false +while converged == false do + ca_pattern, converged = automata.async_iterate(ca_pattern, sq, {moore}) +end + +-- Add some symmetry by mirroring the basic pattern a couple of times +local symmetrised_pattern = ca_pattern:hreflect() +symmetrised_pattern = symmetrised_pattern:vreflect():vreflect() +symmetrised_pattern = symmetrised_pattern:hreflect():hreflect() + +-- Categorise the pattern according to possible vN neighbours and print to screen +-- This turns the basic pattern into standard 'box-drawing' characters +local vn = neighbourhood.von_neumann() +local segments = subpattern.neighbourhood_categories(symmetrised_pattern, vn) +subpattern.print_patterns(symmetrised_pattern, segments, vn:category_label()) +``` +### Output +![foo](img/async_automata.png ) diff --git a/examples/img/async_automata.png b/examples/img/async_automata.png new file mode 100644 index 0000000000000000000000000000000000000000..d88ad408fc09bfdc8e7008f1c5d3299e4a4e066e GIT binary patch literal 576 zcmeAS@N?(olHy`uVBq!ia0y~yVCrIEV02&v3NQ#yNyr0IEa{HEjtmSN`?>!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4+$B>F!Z*NCu9X1eP4S0ViDyn?hFHQ3aY~jfV zMb6D=xu_~LQJyvFyou)2jn95%Ol^&cza70ZY$8vmi&F8#>w)3Sk=g5P56cR5x~M5V z-!!lC^S%|0Yi?%me)A<+_Vm7KtB>ARn%1kxUQ?(dG_!wAzTK^vQ$J_<>NqP+Ji+rM zX8YlHKR$oV__g_}PU`(ddrbaH0u5TGz?}X#|M}C9bE{1^f-DN2`1P!N^`@}ne)^&( zCwQnBG4H&;d1u~(lJwtV>7RYJ@9nGBs@|jLr6TRh_u~;zUOrO(rBvj(xu>?Kr?I<0@n zPdT8{J?;>$JuYQW8lGRB%5}|r8}KWAF}0S2>biEBhjN@7W>RdP`(kYX@0FtpG$ zFxNFS2{AOWGPJZZHq|yTvNA9@!|*B!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4zReagLA3%kQ#Wu3gJA+f{#sAA7Y}_^!D7t5*lyO~Rfm z-CR7S{Mgy($FTvYuLd6cD%ell|^RKyKRqf7qIbTIv(sk9e=YCV3 zJe5uVeOCMPim0k5o6<`T?vv5!U2S{r$gRqkmpT7S{Sb1cQfIo)lfCZ9V!QVS9U;fR7mMvQyr$)L zq4%ET%sZPjU5oEX-uxl#Ef3v3W&G>q!tt-S ztY#5TzV**f++FQ*Xms?_Z`GRm$D3t&M@UoG zRX1_}mJ40{JgNPcM6aKV7FX79s@-|9c)<^8hJ<)<>@k#r!;SG3IC`0`G=d!5^7jYl zx(luW)_Ec;fXQ67#5JNMC9x#cD!C{XNHG{07+UBWnClvvgczDw8CqHyn`#>vSs56d iVR)5_q9HdwB{QuOw}!p3K{tUK7(8A5T-G@yGywqQw3%E0 literal 0 HcmV?d00001 diff --git a/examples/img/bubbles.png b/examples/img/bubbles.png new file mode 100644 index 0000000000000000000000000000000000000000..ea9e2a450b1c671d9476a2ce612241bf62597a8e GIT binary patch literal 1193 zcmeAS@N?(olHy`uVBq!ia0y~yVCrIEV02&v3NQ#yNyr0IEa{HEjtmSN`?>!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4i&h)(sMs=I7T)oFzsO$C3`YK@=%-?emgWZ`1Q?(7LE zv(#MgUNYUjL$*oP!K2kzduiUwQxD))uxO<)%-`PnvDtTz^Q9FB*earIKK?DcGb`ZX z^wI!F|C?zi6PZ(aCUWlb*T;azzrmYHp9?<#eK-~0iH>TZ+sqsi(wcKx6 zo;T~p;tUR$+9t1#-1vO6R~!jqx9Y4UEOmOb9% zCOmV&X_ju`BR(0ewdM=n{0uDjUp77Z_rc!4YO(8gCriG*ro#AL==ZE$(&D1*FvThv zpH*j9z4`EX(f$_28GPOPzq}=`zWgz(``p{5uCVYpcXRP)li3%JDtYfMw_LZ`b9Pyq z#djC0=UY#HJOB%025a$mAslfH#>SPe+RNUnC2QR8*(+>T;d|bPPm8nceOWp4?)aU% zMdw`1dRY;I%Ijbop9b>zq&87Ub6o_ka>DdpC$XZ zTQCQ*?4Kj}@#-4Zdv?>x4ip``r*`S;9kB}cs99pCXZ8#JIJIEc`c+$vdQPy!szuCE zNIUpcGG+D&&wp)SPkSq!7FsgrzDoPAr=mBOL=+|JnC;sGRky6=QPB6*)1-Z-&*(Q| zc`p5UcYKnL0dumQ?8AkBF8R-25Hi^+SF0!k7MqMySAUJaf3v~lM{e7LipIXYKc_qy zvmT49*o54>?c3OIKjY!NedUftDnm{r-UW|!RiSm literal 0 HcmV?d00001 diff --git a/examples/img/cellular_automata.png b/examples/img/cellular_automata.png new file mode 100644 index 0000000000000000000000000000000000000000..679d80a8f87dde7c7b74956646c991520006d011 GIT binary patch literal 1195 zcmeAS@N?(olHy`uVBq!ia0y~yVCrIEV02&v3NQ#yNyr0IEa{HEjtmSN`?>!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4`(7Jxn0#`b^E+NINdLpOTSpjY z^DoyA=|1x3<+X##EoE*A+jUh77j9i{e()RP(tRuUefvG-ms-0{asb;()jR2ba)OmM z_FcPo@46pz4$Ch!#tpglUJY+29RB^bby?n|fcW+Dd#_zry!HJy_wHRUyCaV+;0f}s zsFt6@#=-Jynad&mD>Bi>JfFFQB^y0jyV@smd@-20Nyss{)7WX9ZH~C6?4}+^$tBZ{ z$T0F8-gC%H>0u}9ew+UX3b~YTyt1qobSRWc-D+A_<|BIa?ftVxY^f8XZq-%(YkUk; z$(_?XDOS#Sx7Ct(1{D#3BgH-iHS9)-H)d5;gll3*o?eLQxmWirPfJX3%sP4Y#;W)z^JzOTXpo{&x{o_}0TO@C0IcK4I3m)F}zeqB)7H|cuC{v}hNxxU?VRuOEyW^A=~ zUFS7#rH9P-zUu5(neKF0QX}V5#?7vxBGxT`6?mqGu3B1HG|_P0ZOatNW+M;X$m^T` zY~tZf_f(nJdMj?-&!-N3}3l*dUoB+xoM9oee5DS z+Vy@s{lViFYO+XU!&TVBBvcd_MVMvr}6lSJ}$ioFfy? ze`(;DGJUh+r|AkG)i;A9`x|>J&tae4J{AcF^=GEu3G2K5g!@(EG)7ZNlWjVgb0XKR z5S4o7J{_C{pB`e@ehyT#EK*ITLDt`T)t;u`O!?EFtUlaS(YCswOpifd?h|XeH;^$yj~I|vi-Yw z;Nv`S$~wLAybhCUj6O&g!~EoR`59fiovt(Hcu!fd>Ur<2tGj-zeh_+fM=-=eXYXqF zsQxwjXr6fEDLaF+jr;;Bq5sklgSL3b|6$%4r2H$gZP9#Sj#e#kjVMV;EJ?LWE=mPb z3`Pcq7P!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4o=vCY4E{~zzDt7(zB z^niUuvxTG+m*$cQ%N5d>c&9{9kmRm+-qy0Cwc6Dv$33dhn_aP0B<@G&AmyQ^k zxG9zUq;&7N^^wh!smr1zOZ?ok?OH$;9*X_WZZmvR)Z31S%-Hx?)HB-C`K8u})eXH0 zAG6KfPegkF&G{rfL5@p%Q}4T}3%~tiihQxPc=@G&3xIloQpzVvx28>F%i3adnK{{U zoA%3?&!*p_jiq4a%i+mvY7AFI;uz+@esh8Mh}Co2L6+{#?0Cf7<;g%YL7* z^P0YxYugI}kSlD2C2v0J>DxE)g=*2dnfJ94ZM|I`rCL~4woCwq(G$xPwQJeKo<NCdCo(jL?CoBz^a?j7@SbdI%Fi7_wt`u$g2Odv2W=`o%+x%6$`$;#0 z$kcb6R=OB+fcz)dnDf~3Y3YRTq8!EZC(hmzI_>nq6K^JnT{3p}WZD!p3mT7~V?RE> zXylsHnImkuSox0Jy}rfIr+2fMFJb226OicwvC81m{sUr#Mrt>{dqfGgAN6)LEay*O zog3!jA%Co{{-QY8Hyn|1=Ox$v`q<;9-^RWvG^OrMul~WRjVn}^++Eee2@dj}FQqac z=6QABb$;nP`$lH=#iF~5CiN88I6jLA1u5YAS($R*t46h=uH?jGwKW#KpPx5f_*%1h z`p+F*r}m%b-yGy6kTNSDnA#asOI#yLQW8s2t&)pUffR$0fuV)2fw``sNr<6|m7%4T pv8lF!k(GhL8HQJ>C>nC}Q!>*kackHc8*~$7g{P~Z%Q~loCIB5$kh1^) literal 0 HcmV?d00001 diff --git a/examples/img/gallery.png b/examples/img/gallery.png new file mode 100644 index 0000000000000000000000000000000000000000..fe41cbf11f08bacadf6454e0becc6c9298241618 GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0y~yVCrIEV02&v3NQ#yNyr0IEa{HEjtmSN`?>!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4F!Z!ezpJz^l>@Ni}!^R~uDxtm=J#JQTOv*@x;!_3M$o4lN0U!2tF8Ac&GKFp>%r@( z`&*zkJmzHWm)A^_A~L*Y-Dl^1KFey(;_}UJyLPy4SASi9&Q$XC!KbNngI?{Paq7Y* zZ^_;LKKGCB^6q`Dr<(77Eqjj6p3dE6$7i1oDzS>4zEbh$+}gc)_CNeRzk9m^{Y(%% z(BH$XvB7-T!x>xofr?d2Tq8fYRbP~ka16q zR16_f|K)=(am}kGgv*t=Zz&BOpl)?$lYH4x!{39=rop4QKqAp$V-1fYnoj*LCZqzO@m`dO}n@k|Y>L1~#tLk=vmneW%h*uV2tqgOG-8oU2EtO}8YdO$7Dt`Ok zi0gk5Km0m1^JXV)gwzw}6~Tu)w?KAtEdwZ|4GTM|2-%UT01}A8q8t+}NGD(Xv8d9LYBd73> ziYaYR8o33?_AW_BTqxB0uCG~fe(uYRweF0GO9wz!M?5-^T?Zk5-i>ch&L6c=M|Uhc zZ&Hau`tf4qnV&x0yMG9{azTWt=e;dhbdyYgXp-eLT zZhaXYelL`KFzFn2FYw0R`hY$(tvxy18n$C?n9uuT5l z$2M@i^bxYDPra+Hf2_=k)_NrQH?L=PwF?bH;*?xX&_|hhz)rORJ1gC-tykr5?x!{( z^_8~^Wefy92Vc0;A6D9(UR1X^OsUY|thp7X8ZrcJODBTKkc3)N;b4W*!%9h>qsLrg zP# z(&|=OzUx8AP-o8s#8*u&@hzvbs}N|^owk4z5hpvJN}AbNDcHsvNtRpA#YzZ>x1|Pq zbC$HS=uTxP%4Xh%2I}AA{;gRP+v{z>mm`BtS86CJ9JEJ<@nz$!-j;{kr`P^@oT-N- zkfZ$cF&+b^b~qn_1t*CUiQQ0>7BNj$9o+c0uVY4(y=QYII}X`);F88}UT@99^i`Zv z?@+KF(ueG~-UhRntjV}s%+f=zp3LqtF8p0y^g?XmD+}V_YFvp-EJ=3%&8c(`Z~>F0 ztUC3SRG>zVu0UXPC()_1pHgxj+wpV_$6n(Sm4)s&T@+18TA@ep!W7GDRJx|HH*4-p zlSh0J0z%~0XTv|?f$$a3;{FZI42-Mjn^!?$R(_L3-`JVV{<`6n3cH4v1K9uI(xDV=))3CO_eWdHWABUt`+g;K#Z% z-d3fMY(LN!-7rbp1b43^I@a literal 0 HcmV?d00001 diff --git a/examples/img/maxrectangle.png b/examples/img/maxrectangle.png new file mode 100644 index 0000000000000000000000000000000000000000..933e1a49c529d665320b44fcafba4fb21c18aba6 GIT binary patch literal 1062 zcmeAS@N?(olHy`uVBq!ia0y~yVCrIEV02&v3NQ#yNyr0IEa{HEjtmSN`?>!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4_k~GZ z8$%=tojeYx=2|U3r@HeqXWY@HEKg5gkoM9#5|ns^v(jBCv*@%^;WVZA^vSWux{5U? zx}4k@s#18&e8&kdCE? zI)p!c^Y|UMbFy%__wMY7OQ+iAFWbV-(Rr>RykBvpfOo5)dW!Iw|DU?Eo@cG+J!6(L z<^38?^>a^|r!6x%)S2u7ammYuuP+y5^vT((*#E1n(cORcXZ$;_?OLh&k4sY@ew(Eu zxxS9uobk7}TGGk~PhUm+s))@Km)YbrDcvw>@1L@}d*3`vQ}}7QcS(xC>HUBAz7aaj za9z*S!&>>;Y5kvkdq0InKUw;vI``)-qe)ZhLiOSpwLOk)4EeChcG|^1n<|fRW~N`L zn)&_E!nNyNSKmARRM%ibsQ%79f$UpFRKkx09Xy?*^YrTujhT{#PPZf%#7TwEetc8K za(VXB={ILytXnnp%(?p^D%r_1r-pPq-T5W-n)fugx{SOXnEAUYhf-B)(t1e`?&b>yO*x?~0$7 znzVoS`s2TkUz+0=(?2;prJ<_x`h=(b2Olnf(J=if|Lce8e;ZPMDz{!(r_c!u$<%Be z$Gtf+g-&M9iD?fm*Sy~IJ(bmSwpGiu1wxR#WA!sr(YyXh(VeQ-KKjPO^ zRCKfM-QIV!er;dRhY8<6g46%^=s{y!dB)`3b?b7?qaC^9`F5SH(?*pS z_vDwoetv6Sns$a`z;_8)`kW#8PkV>|x|o;GwPstGtu{+Pto3;RxjzO|wRzQ`W+rRA ziF;_fP3?o<12z@Wq?3P7seh9H^GE8l=8={nU}jP+ag8WRNi0dVN-jzTQVd20h8DU8 z=DLO^A%-SahL%>wrrHKZRt5%V7+$5KXvob^$xN%ntzmC$&`qEQ22WQ%mvv4FO#sK9 B+5P|k literal 0 HcmV?d00001 diff --git a/examples/img/sampling.png b/examples/img/sampling.png new file mode 100644 index 0000000000000000000000000000000000000000..96967c2701a483c862190ae474b8ce12722d15b3 GIT binary patch literal 967 zcmeAS@N?(olHy`uVBq!ia0y~yVCrIEV02&v3NQ#yNyr0IEa{HEjtmSN`?>!lvI6-E z$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e46c{DvS0!kH~ zRna^#<>Hq*L7hn*-+ebsQNGs+mMl7T;_AdF%Eo<)&jU2?^cg-6ICu|8wrCitI2K8U zT*-UDd9zdI*emtGsZyK84vAh(2+P^=Zu8D1E9KMmim)UR!^ zx|J@R-8xTRwN1rC@AT44flt>byt3LfC3n@2DDiMs$$r*%zTSJTtg|wgi@OuO`bX0Q z0kG25uTKPRTNx8`vMy!!>m&P=URiDY-MLH6rBjh}(&-IK*Ig&|PdP0Z!I665Rc79? zJDWblt6J`gcH3U@S3It05y&yAJ7pSMC+PD}{H}Ogbo-oytvQzI-u*((LMqd5i*nxV z;)$9Y$@7~by*O}gLaX+Egfa`u;3)oB|2WmyEI&rgE5D?8ia z<3o{uW*rkEUEbF8pIE5B;(XzAMu(lDmrrFIyt7%RVLs)Sl7WPO2RIzFo>w2SI`kxJ z=0Wj|(noiuy1mx|rgqg5*NBpo#FA92Co lWngfI;Z-V%hTQy=%(P0}8urEp-2`f2@O1TaS?83{1OSErn$Q3M literal 0 HcmV?d00001 diff --git a/examples/img/voronoi.png b/examples/img/voronoi.png new file mode 100644 index 0000000000000000000000000000000000000000..38a3b49b38b4170dfdc7b7058b657088285d0e6f GIT binary patch literal 1869 zcmZ{lX;c&E8pnqn1zZA_8*1SyghN4?5cVyivWLa83dU&^0UDGKe6cpm1BDcJSN%a6i50`M>}F?|II7&UxR0gMr>U zn+-Mt0HEXR;}Hx1%7p-+rfNm*^LmaAc`vUd>Ky#7S+EF#4{%5pLZ~y@CO#wh~ z76ASvB*8QQq)`E2h6Mo5A^^}&xpeCrSK>nX7{l8GP#P=Ly-HLXslEZ88WS2@w&@xh zY%&uAfO?p($G*_?XLE}6v6Y+NF*b_s*>aB;Q8Hc zFb%#UWkvw%%PnFy`3V;AuP8Gxqg5McH_=4!au!+F#>p6MOL2OJ{V6*8ai|+V1U`;a z%H#7Y+2n^ZqN4Lid&1HW3OnZ|PSGvZ%y8(_~AFq!$|2d-3e9%l>pNfjT$ zv|d$NV^qkXEC)@U+n8hg#yVen9v^mHTH)e2eoCmeLaSKK@a^*d1^(mo>;gqCfNuc%Th|vq(h0)q)sO2m4VDPJ1roC11$;^ptiro?QV}?UN<@8 zUR6c#CU!~0ernlU_E2=|v?W@vU_>zAEsFnoZp;*}PP66x$5s}f@O&2wD`&G%RN!Qh zo+{o=ZRhf3P@H`Y{rgX|bK|(0JOu2$@7_Fw<2OFG@Z83<8%e5y+6oBjJeyhKmkpNq z`L9~S;RG`Xler5#_spV~el zaT~s?E%hJ#chVq(|E)T|{IGe4qr^2&CPmRRYOI8pRWe-7-)GcVbqPQ-bt@BD6d>fJ zLfA&)N5&(0tb~KSAVWL#Ry1^@iJk^*CnCYehlOY{H!|<*lLeg*3&)q`zuP!2#aq1* zF8cMcb*2h<<)h{u5=ld+El0J<*=oB;oZ*W!bd@F@U>Qo_9~hdkhh<%%+BYdpwh}a* zH%`i_bl9&@_hEY}paQ}|)xH5-tkqxZlU1aAZWoqaJHuK-(?1_9N2C5^Fbf~gV z3EFQ}4oiznND6bR-A3|lvv`U7YJ3f(4#V-}-)dqmpus!G`(impsU_Ifo&QNuZh;fmKB!?d( zoLnkaM31xH>z#k<=}K|(v!QFHk~W^KQyymIP(b*mG3(M2Mm_xF!ss?h8()^{@(*Y; zGfL`FX5#=Cw3FmRvZ_Z6^;k~mh8n{X8f6Wfsaw-Z={ezd`o>Nj;?JR^dLBxRIhx9L zj^?t71E5i@9WAL2me#hR*0#>pPR=%V7F3!ul`02j*#8qqJ`oci%lrQU>5<^4L;&#h L4D`6ZpOyPJz}t30 literal 0 HcmV?d00001 diff --git a/examples/platformer.lua b/examples/platformer.lua deleted file mode 100755 index b4038e9..0000000 --- a/examples/platformer.lua +++ /dev/null @@ -1,39 +0,0 @@ ---- platformer.lua --- Generates a plausible platformer level layout. --- Following a similar setup to the corridor example but with more --- post-processing. - -local pattern = require('forma.pattern') -local automata = require('forma.automata') -local primitives = require('forma.primitives') -local subpattern = require('forma.subpattern') -local neighbourhood = require('forma.neighbourhood') -math.randomseed(os.time()) - --- If you make the prior domain larger, this generator can be useful --- for e.g town layout generation -local sq = primitives.square(19,4) -local seed = pattern.rcell(sq) -local tp = pattern.new():insert(seed.x, seed.y) - --- Complicated ruleset -local moore = automata.rule(neighbourhood.moore(), "B12/S012345678") -local diag = automata.rule(neighbourhood.diagonal(), "B0123/S01234") -local diag2 = automata.rule(neighbourhood.diagonal_2(), "B01/S01234") -local vn = automata.rule(neighbourhood.von_neumann(),"B12/S01234") -local ruleset = {diag2, diag, vn, moore} - -repeat - local converged - tp, converged = automata.async_iterate(tp, sq, ruleset) -until converged == true - -tp = pattern.surface(tp) -- Comment this out and you get a subsystem -tp = pattern.enlarge(tp,4) -tp = pattern.surface(tp) - --- Print according to neighbourhood -local nbh = neighbourhood.von_neumann() -local segments = subpattern.neighbourhood_categories(tp, nbh) -subpattern.print_patterns(tp, segments, nbh:category_label()) - From 7a24c22f5aa66c026545143df5d43e0b55c9b910 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 14:29:23 +0200 Subject: [PATCH 21/31] Example gallery --- CHANGELOG.md | 3 +- README.md | 19 --- TODO.md | 1 - config.ld | 2 +- docs/contents.html | 9 +- docs/examples/async_automata.lua.html | 7 +- docs/examples/binary_space_partition.lua.html | 5 +- docs/examples/bubbles.lua.html | 7 +- docs/examples/cellular_automata.lua.html | 7 +- docs/examples/corridors.lua.html | 7 +- docs/examples/isolines.lua.html | 7 +- docs/examples/maxrectangle.lua.html | 5 +- docs/examples/platformer.lua.html | 116 ------------------ docs/examples/sampling.lua.html | 7 +- docs/examples/voronoi.lua.html | 5 +- docs/modules/forma.automata.html | 5 +- docs/modules/forma.cell.html | 5 +- docs/modules/forma.neighbourhood.html | 5 +- docs/modules/forma.pattern.html | 5 +- docs/modules/forma.primitives.html | 5 +- docs/modules/forma.subpattern.html | 5 +- docs/readme/README.md.html | 17 +-- examples/async_automata.lua | 2 +- examples/bubbles.lua | 2 +- examples/cellular_automata.lua | 2 +- examples/corridors.lua | 2 +- examples/isolines.lua | 2 +- examples/sampling.lua | 2 +- 28 files changed, 49 insertions(+), 217 deletions(-) delete mode 100644 docs/examples/platformer.lua.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1fece..479f8f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,4 +30,5 @@ - Removed some (confusing) functionality from `cell`, namely addition and multiplication with a number value. - Added isoline drawing example -- Added Mitchells Best-Candidate sampling (approximate Poisson-Disc) +- Added Mitchell's Best-Candidate sampling (approximate Poisson-Disc) +- Renamed pretty_print to print_patterns diff --git a/README.md b/README.md index d089c30..c5f0ae3 100644 --- a/README.md +++ b/README.md @@ -47,16 +47,6 @@ finding or Binary Space Partitioning are also available. Once again most of these operations can be performed under custom definitions of the cellular neighbourhood. -Custom pattern operations can be easily implemented making use of a masking -procedure, as shown in an example demonstrating thresholded [Worley -noise](https://en.wikipedia.org/wiki/Worley_noise): - -

    - -

    - -All of the above examples can be generated by code in the `examples` folder. - Installation ----------------------------- @@ -70,15 +60,6 @@ The easiest way to do this is via LuaRocks: luarocks install forma ``` -Running examples ----------------- - -The examples require that the `forma/` directory is in the lua path. The easiest -way to try the examples is to run them from the root directory of this repo. For -example - - lua examples/game_of_life.lua - Generating documentation ------------------------ diff --git a/TODO.md b/TODO.md index e185d97..7bd611c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,3 @@ # TODO - Luarocks -- Example gallery diff --git a/config.ld b/config.ld index fff36bb..6f41f5a 100644 --- a/config.ld +++ b/config.ld @@ -1,5 +1,5 @@ project = 'forma' -title = 'forma Reference Manual' +title = 'forma Reference' description = 'A 2D grid shape generation package' kind_names={topic='Readme'} format = 'markdown' diff --git a/docs/contents.html b/docs/contents.html index 3e11329..cc7d6b9 100644 --- a/docs/contents.html +++ b/docs/contents.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -51,7 +51,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -127,10 +126,6 @@

    Examples

    maxrectangle.lua - - platformer.lua - - sampling.lua @@ -145,7 +140,7 @@

    Examples

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/async_automata.lua.html b/docs/examples/async_automata.lua.html index 647112b..7883c65 100644 --- a/docs/examples/async_automata.lua.html +++ b/docs/examples/async_automata.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -65,7 +64,7 @@

    Readme

    async_automata.lua

    --- Asynchronous Cellular Automata
    +-- Asynchronous cellular automata
     -- Here the use of an asynchronous cellular automata is demonstrated, making
     -- use also of symmetrisation methods to generate a final, symmetric pattern.
     
    @@ -107,7 +106,7 @@ 

    async_automata.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/binary_space_partition.lua.html b/docs/examples/binary_space_partition.lua.html index 879b85c..f082789 100644 --- a/docs/examples/binary_space_partition.lua.html +++ b/docs/examples/binary_space_partition.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -81,7 +80,7 @@

    binary_space_partition.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/bubbles.lua.html b/docs/examples/bubbles.lua.html index 0d4feef..7849792 100644 --- a/docs/examples/bubbles.lua.html +++ b/docs/examples/bubbles.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -65,7 +64,7 @@

    Readme

    bubbles.lua

    --- Example of circle primitives
    +-- Circle primitives
     local cell       = require('forma.cell')
     local pattern    = require('forma.pattern')
     local primitives = require('forma.primitives')
    @@ -91,7 +90,7 @@ 

    bubbles.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/cellular_automata.lua.html b/docs/examples/cellular_automata.lua.html index 1f32f71..82a5d52 100644 --- a/docs/examples/cellular_automata.lua.html +++ b/docs/examples/cellular_automata.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -65,7 +64,7 @@

    Readme

    cellular_automata.lua

    --- Cellular Automata
    +-- Cellular automata
     -- Demonstration of classic cellular-automata cave generation (4-5 rule).
     local primitives    = require('forma.primitives')
     local subpattern    = require('forma.subpattern')
    @@ -94,7 +93,7 @@ 

    cellular_automata.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/corridors.lua.html b/docs/examples/corridors.lua.html index 41ece5f..483622f 100644 --- a/docs/examples/corridors.lua.html +++ b/docs/examples/corridors.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -65,7 +64,7 @@

    Readme

    corridors.lua

    --- Multiple CA rules
    +-- Combining cellular automata rules
     -- Here the way multiple CA rules can be combined into a single ruleset is
     -- demonstrated. A asynchronous cellular automata with a complicated ruleset
     -- generates an interesting 'corridor' like pattern.
    @@ -103,7 +102,7 @@ 

    corridors.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/isolines.lua.html b/docs/examples/isolines.lua.html index 17afb79..b68514f 100644 --- a/docs/examples/isolines.lua.html +++ b/docs/examples/isolines.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -65,7 +64,7 @@

    Readme

    isolines.lua

    --- Rasterising Isolines
    +-- Rasterising isolines
     -- Here we generate a pattern randomly filled with points, and take as a scalar
     -- field N(cell) = F_2(cell) - F_1(cell), where F_n is the Chebyshev distance
     -- to the nth nearest neighbour. Isolines at N = 0 are drawn by thresholding N
    @@ -102,7 +101,7 @@ 

    isolines.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/maxrectangle.lua.html b/docs/examples/maxrectangle.lua.html index 586f452..1f18555 100644 --- a/docs/examples/maxrectangle.lua.html +++ b/docs/examples/maxrectangle.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -85,7 +84,7 @@

    maxrectangle.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/platformer.lua.html b/docs/examples/platformer.lua.html deleted file mode 100644 index 659bbe3..0000000 --- a/docs/examples/platformer.lua.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - forma Reference Manual - - - - -
    - -
    - -
    -
    -
    - - -
    - - - - - - -
    - -

    platformer.lua

    -
    ---- platformer.lua
    --- Generates a plausible platformer level layout.
    --- Following a similar setup to the corridor example but with more
    --- post-processing.
    -
    -local pattern       = require('forma.pattern')
    -local automata      = require('forma.automata')
    -local primitives    = require('forma.primitives')
    -local subpattern    = require('forma.subpattern')
    -local neighbourhood = require('forma.neighbourhood')
    -math.randomseed(os.time())
    -
    --- If you make the prior domain larger, this generator can be useful
    --- for e.g town layout generation
    -local sq = primitives.square(19,4)
    -local seed = pattern.rcell(sq)
    -local tp = pattern.new():insert(seed.x, seed.y)
    -
    --- Complicated ruleset
    -local moore = automata.rule(neighbourhood.moore(),      "B12/S012345678")
    -local diag  = automata.rule(neighbourhood.diagonal(),   "B0123/S01234")
    -local diag2 = automata.rule(neighbourhood.diagonal_2(), "B01/S01234")
    -local vn    = automata.rule(neighbourhood.von_neumann(),"B12/S01234")
    -local ruleset = {diag2, diag, vn, moore}
    -
    -repeat
    -    local converged
    -    tp, converged = automata.async_iterate(tp, sq, ruleset)
    -until converged == true
    -
    -tp = pattern.surface(tp) -- Comment this out and you get a subsystem
    -tp = pattern.enlarge(tp,4)
    -tp = pattern.surface(tp)
    -
    --- Print according to neighbourhood
    -local nbh = neighbourhood.von_neumann()
    -local segments = subpattern.neighbourhood_categories(tp, nbh)
    -subpattern.print_patterns(tp, segments, nbh:category_label())
    - - -
    -
    -
    -generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 -
    -
    - - diff --git a/docs/examples/sampling.lua.html b/docs/examples/sampling.lua.html index 3562afd..0a62620 100644 --- a/docs/examples/sampling.lua.html +++ b/docs/examples/sampling.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -68,7 +67,7 @@

    sampling.lua

    --- Sampling methods -- Demonstrations of various methods for sampling from a pattern. -- 1. pattern.random generates white noise, it's fast and irreguarly distributed. --- 2. Lloyd's algorithm when a specific number of uniform samples are desired +-- 2. Lloyd's algorithm when a specific number of uniform samples are desired. -- 3. Mitchell's algorithm is a good (fast) approximation of (2). -- 3. Poisson-disc when a minimum separation between samples is the only requirement. @@ -93,7 +92,7 @@

    sampling.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/examples/voronoi.lua.html b/docs/examples/voronoi.lua.html index d20dbf3..113fdc5 100644 --- a/docs/examples/voronoi.lua.html +++ b/docs/examples/voronoi.lua.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -41,7 +41,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -85,7 +84,7 @@

    voronoi.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/modules/forma.automata.html b/docs/modules/forma.automata.html index 35a2214..7f66c2d 100644 --- a/docs/modules/forma.automata.html +++ b/docs/modules/forma.automata.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -59,7 +59,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -277,7 +276,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/modules/forma.cell.html b/docs/modules/forma.cell.html index d240358..0a469ed 100644 --- a/docs/modules/forma.cell.html +++ b/docs/modules/forma.cell.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -60,7 +60,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -471,7 +470,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/modules/forma.neighbourhood.html b/docs/modules/forma.neighbourhood.html index 82668ce..16c73fd 100644 --- a/docs/modules/forma.neighbourhood.html +++ b/docs/modules/forma.neighbourhood.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -59,7 +59,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -302,7 +301,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/modules/forma.pattern.html b/docs/modules/forma.pattern.html index fc2fa09..495f7a7 100644 --- a/docs/modules/forma.pattern.html +++ b/docs/modules/forma.pattern.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -64,7 +64,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -1155,7 +1154,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/modules/forma.primitives.html b/docs/modules/forma.primitives.html index 9f6db65..f2060bf 100644 --- a/docs/modules/forma.primitives.html +++ b/docs/modules/forma.primitives.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -58,7 +58,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -200,7 +199,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/modules/forma.subpattern.html b/docs/modules/forma.subpattern.html index 85d0d57..bf439fa 100644 --- a/docs/modules/forma.subpattern.html +++ b/docs/modules/forma.subpattern.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -60,7 +60,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -586,7 +585,7 @@

    Parameters:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/docs/readme/README.md.html b/docs/readme/README.md.html index 5b65b33..329cd0d 100644 --- a/docs/readme/README.md.html +++ b/docs/readme/README.md.html @@ -3,7 +3,7 @@ - forma Reference Manual + forma Reference @@ -54,7 +54,6 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • -
  • platformer.lua
  • sampling.lua
  • voronoi.lua
  • @@ -118,18 +117,6 @@

    forma

    these operations can be performed under custom definitions of the cellular neighbourhood.

    -

    Custom pattern operations can be easily implemented making use of a masking -procedure, as shown in an example demonstrating thresholded Worley -noise:

    - - -

    - -

    - - -

    All of the above examples can be generated by code in the examples folder.

    -

    Installation

    forma is compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1. The library @@ -190,7 +177,7 @@

    Testing

    generated by LDoc 1.4.6 -Last updated 2018-07-14 13:54:03 +Last updated 2018-07-14 14:27:46
    diff --git a/examples/async_automata.lua b/examples/async_automata.lua index c5b7595..562efc9 100755 --- a/examples/async_automata.lua +++ b/examples/async_automata.lua @@ -1,4 +1,4 @@ --- Asynchronous Cellular Automata +-- Asynchronous cellular automata -- Here the use of an asynchronous cellular automata is demonstrated, making -- use also of symmetrisation methods to generate a final, symmetric pattern. diff --git a/examples/bubbles.lua b/examples/bubbles.lua index bcc3826..1a592a9 100755 --- a/examples/bubbles.lua +++ b/examples/bubbles.lua @@ -1,4 +1,4 @@ --- Example of circle primitives +-- Circle primitives local cell = require('forma.cell') local pattern = require('forma.pattern') local primitives = require('forma.primitives') diff --git a/examples/cellular_automata.lua b/examples/cellular_automata.lua index 73ba408..03e5a6c 100755 --- a/examples/cellular_automata.lua +++ b/examples/cellular_automata.lua @@ -1,4 +1,4 @@ --- Cellular Automata +-- Cellular automata -- Demonstration of classic cellular-automata cave generation (4-5 rule). local primitives = require('forma.primitives') local subpattern = require('forma.subpattern') diff --git a/examples/corridors.lua b/examples/corridors.lua index 26fcd8e..5a2ec4b 100755 --- a/examples/corridors.lua +++ b/examples/corridors.lua @@ -1,4 +1,4 @@ --- Multiple CA rules +-- Combining cellular automata rules -- Here the way multiple CA rules can be combined into a single ruleset is -- demonstrated. A asynchronous cellular automata with a complicated ruleset -- generates an interesting 'corridor' like pattern. diff --git a/examples/isolines.lua b/examples/isolines.lua index c407319..79ec810 100755 --- a/examples/isolines.lua +++ b/examples/isolines.lua @@ -1,4 +1,4 @@ --- Rasterising Isolines +-- Rasterising isolines -- Here we generate a pattern randomly filled with points, and take as a scalar -- field `N(cell) = F_2(cell) - F_1(cell)`, where `F_n` is the Chebyshev distance -- to the nth nearest neighbour. Isolines at `N = 0` are drawn by thresholding `N` diff --git a/examples/sampling.lua b/examples/sampling.lua index c258bcc..0cb290d 100755 --- a/examples/sampling.lua +++ b/examples/sampling.lua @@ -1,7 +1,7 @@ --- Sampling methods -- Demonstrations of various methods for sampling from a pattern. -- 1. `pattern.random` generates white noise, it's fast and irreguarly distributed. --- 2. Lloyd's algorithm when a specific number of uniform samples are desired +-- 2. Lloyd's algorithm when a specific number of uniform samples are desired. -- 3. Mitchell's algorithm is a good (fast) approximation of (2). -- 3. Poisson-disc when a minimum separation between samples is the only requirement. From ac235d8e0c15c7035619110082f37453f4452462 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 14:47:43 +0200 Subject: [PATCH 22/31] rockspec modifications --- rockspec/{forma-scm-1.rockspec => forma-0.2b-1.rockspec} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename rockspec/{forma-scm-1.rockspec => forma-0.2b-1.rockspec} (91%) diff --git a/rockspec/forma-scm-1.rockspec b/rockspec/forma-0.2b-1.rockspec similarity index 91% rename from rockspec/forma-scm-1.rockspec rename to rockspec/forma-0.2b-1.rockspec index b3df058..f3e6749 100644 --- a/rockspec/forma-scm-1.rockspec +++ b/rockspec/forma-0.2b-1.rockspec @@ -1,8 +1,8 @@ package = "forma" -version = "scm-1" +version = "0.2b-1" source = { - url = "https://github.com/nhartland/forma/archive/master.zip", - dir = "forma-master", + url = "git://github.com/nhartland/forma", + tag = "v0.2b", } description = { From 51cc3a79e4c27aa5d6d471ff0aad45c6d93087d9 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 15:02:49 +0200 Subject: [PATCH 23/31] README tweaking --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c5f0ae3..82b0db3 100644 --- a/README.md +++ b/README.md @@ -47,12 +47,11 @@ finding or Binary Space Partitioning are also available. Once again most of these operations can be performed under custom definitions of the cellular neighbourhood. -Installation ------------------------------ +## Installation **forma** is compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1. The library -is written in pure Lua, no compilation is required. Including the project is -then as simple as including the `forma` directory in your Lua path. +is written in pure Lua, no compilation is required. Including the project is as +simple as including the `forma` directory in your project or Lua path. The easiest way to do this is via LuaRocks: @@ -60,8 +59,7 @@ The easiest way to do this is via LuaRocks: luarocks install forma ``` -Generating documentation ------------------------- +## Generating documentation Documentation is hosted [here](https://nhartland.github.io/forma/). @@ -74,8 +72,7 @@ Simply running in the root directory should generate all the required pages. -Testing -------- +## Testing Unit tests and coverage reports are provided. The test suite requires - [LuaCov](https://keplerproject.github.io/luacov/) From d848787cde7947ba04fffe862ab4821c6f1078db Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 15:39:21 +0200 Subject: [PATCH 24/31] Fix lazy init --- forma/init.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/forma/init.lua b/forma/init.lua index bd3792e..1bdfee1 100644 --- a/forma/init.lua +++ b/forma/init.lua @@ -7,5 +7,4 @@ require('forma.pattern') require('forma.primitives') require('forma.subpattern') require('forma.automata') -require('forma.categories') require('forma.neighbourhood') From 65c774f355834e0ab00ae2d4fc691346894b763d Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 15:46:42 +0200 Subject: [PATCH 25/31] update example gallery --- examples/README.md | 49 ++++++++++++++++++++++++ examples/generate_img.sh | 2 +- examples/img/async_automata.png | Bin 576 -> 621 bytes examples/img/binary_space_partition.png | Bin 960 -> 960 bytes examples/img/bubbles.png | Bin 1193 -> 1223 bytes examples/img/cellular_automata.png | Bin 1195 -> 1263 bytes examples/img/corridors.png | Bin 968 -> 995 bytes examples/img/gallery.png | Bin 509 -> 508 bytes examples/img/isolines.png | Bin 1789 -> 1856 bytes examples/img/maxrectangle.png | Bin 1062 -> 1038 bytes examples/img/readme.png | Bin 0 -> 1904 bytes examples/img/sampling.png | Bin 967 -> 908 bytes examples/img/voronoi.png | Bin 1869 -> 2134 bytes examples/readme.lua | 43 +++++++++++++++++++++ 14 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 examples/img/readme.png create mode 100755 examples/readme.lua diff --git a/examples/README.md b/examples/README.md index 7e33dc6..8efb4ff 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,7 @@ * [Sampling methods](#sampling-methods) * [Rasterising isolines](#rasterising-isolines) * [Combining cellular automata rules](#combining-cellular-automata-rules) +* [Readme example](#readme-example) * [Asynchronous cellular automata](#asynchronous-cellular-automata) ## Binary space partitioning @@ -219,6 +220,54 @@ subpattern.print_patterns(tp, segments, nbh:category_label()) ``` ### Output ![foo](img/corridors.png ) +## Readme example +This generates the example used in the readme. Runs a 4-5 rule CA for 'cave +generation and then computes the contiguous sub-patterns and prints them. + +```lua + +-- Load forma modules, lazy init is also available, i.e +-- require('forma') +local primitives = require('forma.primitives') +local subpattern = require('forma.subpattern') +local automata = require('forma.automata') +local neighbourhood = require('forma.neighbourhood') + + +-- Generate a square box to run the CA inside +local domain = primitives.square(80,20) + +-- CA initial condition: 800-point random sample of the domain +local ca = subpattern.random(domain, 800) + +-- Moore (8-cell) neighbourhood 4-5 rule +local moore = automata.rule(neighbourhood.moore(), "B5678/S45678") + +-- Run the CA until converged or 1000 iterations +local ite, converged = 0, false +while converged == false and ite < 1000 do + ca, converged = automata.iterate(ca, domain, {moore}) + ite = ite+1 +end + +-- Access a subpattern's cell coordinates for external use +for icell in ca:cells() do + -- local foo = bar(cell) + -- or + -- local foo = bar(cell.x, cell.y) +end + +-- Find all 4-contiguous segments of the CA pattern +-- Uses the von-neumann neighbourhood to determine 'connectedness' +-- but any custom neighbourhood can be used) +local segments = subpattern.segments(ca, neighbourhood.von_neumann()) + +-- Print a representation to io.output +subpattern.print_patterns(domain, segments) + +``` +### Output +![foo](img/readme.png ) ## Asynchronous cellular automata Here the use of an asynchronous cellular automata is demonstrated, making use also of symmetrisation methods to generate a final, symmetric pattern. diff --git a/examples/generate_img.sh b/examples/generate_img.sh index 4652a47..a0b8625 100755 --- a/examples/generate_img.sh +++ b/examples/generate_img.sh @@ -11,7 +11,7 @@ mkdir img for file in *.lua; do root="${file%.*}" echo $root - luajit $file > tmp/$root.txt + lua $file > tmp/$root.txt convert -size 650x320 xc:black +antialias -font "InputMonoL" -pointsize 12 -fill white \ -annotate +5+12 "@tmp/$root.txt" ./img/$root.png done diff --git a/examples/img/async_automata.png b/examples/img/async_automata.png index d88ad408fc09bfdc8e7008f1c5d3299e4a4e066e..42da34f9790844a4a739489d85f7ac929b6e4d6d 100644 GIT binary patch delta 512 zcmX@W@|I;ndA*<>o0a;#5C#UuQcoAhkcwMxZztw88}PIx=JoYIo1Hp=snqI{e z?blw7bx!_I>@&SjZVCuF7UiuO?aYflsVt&nhS?Dt?~u^jT2)x7||hEiEm7 z=Gg34$!oV=*KC~awNLe)&-QTP*QOOly^72r`7<73GpC)bH+*9p`X-0ncz8v$^*^WNCXBXNx1C8`?e0Mr#WA;4TFX`u7Eq=4Js;H$J! z1q&6G6t_vwJ3-R-(-?nOYh+b!*vGImQ2Y(c(o81?1_sp<*NBpo#FA92sYZf5U(^CemK^uB4UkKR_A)~m=~Q>Y>|vwuy#-L0ARQ$J_<>NqP+Ji+rM zX8YlHKR$oV__g_}PU`(ddrbaH0!><`z?}X#|M}C9bE{1^f@}(&`1P!N^`@}ne)^&( zCwQnBG4H&;d1u~(lJwtV>7RYJ@9nGBs@|jLr6TRh_u~;zUOrO(rBvj(xu>?Kr?A6DhQfb8CqHyn`#>vSs56dVR)4~ a*?>tw7DaS#Y|u>xAn;KIlG`9o0a;#kd1X;nEXtwOw6nd%(M-RtPBkF*4_+cU|>)!ag8WRNi0dV p%FR#7OsixtGBC8zH89sTGzl?8(GdS3@hwmTgQu&X%Q~loCIF3$96SI3 delta 97 zcmX@Wet>;KIlF+cvJ|Jrtc`VFnEXtv3@xpUO|=b-tPBj!FuY1-U|>)!ag8WRNi0dV p%FR#7OsixtGBC8zH89sTGzl?8(Xcl*=q6ADgQu&X%Q~loCID3e8&3cL diff --git a/examples/img/bubbles.png b/examples/img/bubbles.png index ea9e2a450b1c671d9476a2ce612241bf62597a8e..993d646f031c10b8ce4f3e2563003859069f6099 100644 GIT binary patch delta 1064 zcmZ3o0a;#5C#V3^PVn_Ar-gY#ze1stiZE0*0Chq;rsrTcjo$VCj9XU zD%Ig_?!Pjn;bZ&Djc;ybdNtO|_V11DbKKpRZ>F19Utg{je{3h5AHUw`>HUhlw?#a+ zN^3S}7XJRcIq+v@h}Dft505Z6x*q8GELpAcy05Ta?a1Gr$Cu1S4Aj5ORG%c5BR7?A zTZzR-hXmf9`}Pa@m6$!QoN&q!ux9h-JSmv!xagRDQu7VN8qPx36B`>`dM_Pe+nCG; z*P|iGw#Wflkrlq^mHrL8cioU9NcG0DS z)9U%uTu3`|=;3tiG38_m+Fki=7?4oyf+*0WmyT!T)NkjaVpcFWjQ61RNj z+uX*cuDWF+|4oBN#n2^x8)w`$Y0+YwQ6tiEmq%sGmTtjn1*sQj7sCDDbbQ^vFaDW@ z6VKRgIwL;W@!rPgCQobfj8^-$bxT(J2|u=k`N1^cWb(gnoVo$a(o~C&`(BfubI>Tt z>F1KEMPecDOLoq_vOJM9b#GXbO}`g=wAGvng$-YD;{mX-&uHb_3|IyfBWSc_Dz>F9{ rwK6fYGBDFNFtRc*&|7;maB>cdf-H(?{D;K13_#%N>gTe~DWM4ffUD|- delta 1034 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 RH-Q=$JYD@<);T3K0RRmJ=#T&a diff --git a/examples/img/corridors.png b/examples/img/corridors.png index 8e0ca9d6304a1eb893e75b83db9b27aa458dc440..ba09853b078f7d5b37c9ece1a226980b4fab6d5f 100644 GIT binary patch delta 835 zcmX@X{+NA2dA*<>yRX8#LktW|uRUEHLn>~)o$FZiRDs83=gwcx{0tPfve=uN&OX1$ z^Js!Y|2H?rmburaOv&^8wjf?9F=Xr1%7baTU*D7-`_7vib39+#GR%$DML8?IW#$AY zF3l&RCmufj)mqiND)Rg6ua635oYq`-u5kLXgUc?lyJvr~`4@1p-f||l=8_3c_gcPW zKAd6st)}u~`>|QYCwV31zEnOqyhB1HRp-9u^VwH|Jrr9-K1n?>PM`8ddAjkMDf{%y z4KAH}utM!k(#hQCE&i-P`JfZk6Q=o0n=E7VdGD!$`Hq`j1@$wTsmJC88U7RC0Nc}K za^B0a;f6iEGKnGaJt~JFY$) zJ%3rhWM<0~SL!GO~}}db+jc z*9x?>x_gV&yK46F=CwybRD`C)Maxexp4Kd;Z)0Y^^Iuia7T>3TR8=^7Gn_o0B?1H3 zLvg)xltS&-z1xf)TkMj)uye8SC4rzxCQG`eor%u0wp{^^cij^=s=sum#nu%+a(-)f zUPo!eNh(*Gvg-#wNca5mh9{0~p>DdaITtvdnxCxS z-n;taYnzQO@BhASSaR9p#?r?2rPcLw7X57Y0>|}wrJJF%_TSynWEnQ?#lO;r`$LsH z7gkTWp^)nViR+dx>*FrjFY?GYKj+W>ebd69aZmqnw5OXMTesxP|Cj7MLXkZzE=w&p xPmW?%5Hz(iF|#r-*ETS+GBD`4b?NEkZe|5p6w#mUS&^{0hExCm delta 830 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 delta 1690 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 diff --git a/examples/img/readme.png b/examples/img/readme.png new file mode 100644 index 0000000000000000000000000000000000000000..6dbd58d389f9e7a5742f935767dbd1cfd6667358 GIT binary patch literal 1904 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 Gv;PUi^W?q& delta 1726 zcmY+EX;c&U8peaHUT_OgZm2>P;-R2S2%Butsvs~?dRPVHG*$w#MU1E<0Vjav8fj}~ z$%I(wtrn0?DvM_7L=r@3m_UUnE(8^1P(eV6!fk=t;J5qn|D50Zd){;2bN+*CdsqK( z3SMjNWWUlyMk1NTgzf$!I{WdIZt28mh>hu+_e5}U1yM|-vpTf(qra?2qCF^#Bf{0R7b>iE8kb7dl;>3% zA{!{$)QZrN%L-N;$!xA!#-TjK_x>lr1rWAa5u7Hv6q(DVSbO?8VXc{dkMX~xXWkEV z5c`1#$wmbNekBK{+{5=qwC#ZAk}1FAr#UXbh6VcOBwnE~Qc z^K;t`#5q8W2i+R8aSNcnB|;TQvGm29+10<}7!)+Zx%z0!HvtTLKKgKmA}!=rBPJT- z+1bX*id9THxCTH@P~SG+hMS{z z!2qdY_lxF2{x8r;b^_X(osu6fjF++o*>epBaip2Hr|J%9tudHS6g-Q(Qi|!wK!C3- zUgBN4_ZA8(yi{IUX`h@fY!;tK=+aDsesd?z9myanvhG|%d}tLP?_mNoy~5I!>1fW9 z`xL0c)0+G6jYCpS+TYi#!$`EY z*M#@YK|JIJcO<0hJhGBg61S69_8R649Bz5J6|2{QajZA9vcI1=u_OyGIhx+D=Vu@C z!)DJ_PUd2m$j>c1OSXyD#uKQaWS<(wHy=B%6q8 zD<%i zJqgRPu1sT7Nm0jil2)=HJ_Rjcr+&$gaPT&3!J?O2Y|IgFDH%DUm0-oZ_=3-miIw-x zjm&BO@PxPNQ`}!kX2W|ptH#Cr@*&rDxx7K?#WiX2cV8!!3B%9^RcZPzwu2n`7PLq@ zpjJg&-Jmvk$+2wy2sy8oPbDI=Pia5aSlb~kO*6*W7%O%i>ZJ&DbZm6tia=75Y|UFb zq26bs$vKON@Tn4XB4&mm%NwFF;a&qhJ>On*{X+O_>NB$FbKQapTH*f6dTdvB)hmwh z&Oug3?~Nj;OXm|MfA^Nm^Rq*pp~3DwZuy^%6)T(~^c$gSE)daeP@e@SIM*f^R})8L z3u@k9Nx|bu0^Uh?QE6sbkT#4IFe`LQEu0+RRQGYS=z-@YrE}-a* zD1Dqiz+aPl!}GwR<HzAa_qk_4{_P*g$5Zsh1+{wt55x!XlbUP6JQ(kc zRV$;-xKi+4gA>@M^4MZ|4n&49YgXC)rWD$$$UuJiKu@bmZdcB9e#X*3OKf>T1V_-w=frHX@*j|^j^u;6{W JukK{${{tklTFC$a diff --git a/examples/readme.lua b/examples/readme.lua new file mode 100755 index 0000000..b4a6ff7 --- /dev/null +++ b/examples/readme.lua @@ -0,0 +1,43 @@ +-- Readme example +-- This generates the example used in the readme. Runs a 4-5 rule CA for 'cave +-- generation and then computes the contiguous sub-patterns and prints them. + +-- Load forma modules, lazy init is also available, i.e +-- require('forma') +local primitives = require('forma.primitives') +local subpattern = require('forma.subpattern') +local automata = require('forma.automata') +local neighbourhood = require('forma.neighbourhood') + + +-- Generate a square box to run the CA inside +local domain = primitives.square(80,20) + +-- CA initial condition: 800-point random sample of the domain +local ca = subpattern.random(domain, 800) + +-- Moore (8-cell) neighbourhood 4-5 rule +local moore = automata.rule(neighbourhood.moore(), "B5678/S45678") + +-- Run the CA until converged or 1000 iterations +local ite, converged = 0, false +while converged == false and ite < 1000 do + ca, converged = automata.iterate(ca, domain, {moore}) + ite = ite+1 +end + +-- Access a subpattern's cell coordinates for external use +for icell in ca:cells() do + -- local foo = bar(cell) + -- or + -- local foo = bar(cell.x, cell.y) +end + +-- Find all 4-contiguous segments of the CA pattern +-- Uses the von-neumann neighbourhood to determine 'connectedness' +-- but any custom neighbourhood can be used) +local segments = subpattern.segments(ca, neighbourhood.von_neumann()) + +-- Print a representation to io.output +subpattern.print_patterns(domain, segments) + From decb9c39a5e0cc04b613b2fa7102b27842c9000d Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 15:53:28 +0200 Subject: [PATCH 26/31] Added examples in the README --- README.md | 88 +++++++++++++++++++++++++++++++-------------- examples/README.md | 1 - examples/readme.lua | 1 - 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 82b0db3..b2906d5 100644 --- a/README.md +++ b/README.md @@ -16,37 +16,73 @@ shapes on a two dimensional grid or lattice. It came about as part of experiments in making roguelike games. **forma** is therefore particularly suited for (but not limited to) the generation of roguelike environments. -Shapes can be generated in several ways. From simple rasters of primitive shapes -like circles, lines and squares, to pattern generation by a [Cellular -Automata](https://en.wikipedia.org/wiki/Cellular_automaton) (CA) implementation, -including both synchronous and asynchronous update rules. Using the CA methods, -patterns such as the classic 4-5 rule 'cave' systems can be generated: - -

    - -

    - -However the real power of the CA implementation is in its flexibility. -Different CA rules with custom cellular *neighbourhoods* (including +[Example Gallery](examples/) + +## Features + +- **A spatial-hashing pattern** class for fast lookup of active cells. +- **Pattern manipulators** such as addition, subtraction and reflection for the + generation of symmetrical patterns. +- **Rasterisation algorithms** for 2D primitives, e.g lines, circles, squares. +- A very flexible **cellular automata** implementation with + - Synchronous and asynchronous updates + - Combination of multiple rule sets +- **Pattern sampling** algorithms including + - Random (white noise) sampling + - Poisson-disc sampling + - Mitchell's best-candidate sampling +- **Algorithms for subpattern finding** including + - Flood-fill contiguous segment finding + - Pattern edge and surface finding + - Binary space partitioning + - Voronoi tessellation / Lloyd's algorithm + +With all of these methods able to use custom definitions of the cellular +**neighbourhood** (e.g [Moore](https://en.wikipedia.org/wiki/Moore_neighborhood), [von -Neumann](https://en.wikipedia.org/wiki/Von_Neumann_neighborhood) and more) may -be combined. Patterns can also be recursively generated by nesting the result of -one pattern in another. Interesting structures can therefore be formed by -combining different CA rule sets with different neighbourhoods and domains. For -example a 'corridor' structure: +Neumann](https://en.wikipedia.org/wiki/Von_Neumann_neighborhood)) and distance +measures. Results can also be nested to produce complex results. + +## Example + +```lua +-- Generate a square box to run the CA inside +local domain = primitives.square(80,20) + +-- CA initial condition: 800-point random sample of the domain +local ca = subpattern.random(domain, 800) + +-- Moore (8-cell) neighbourhood 4-5 rule +local moore = automata.rule(neighbourhood.moore(), "B5678/S45678") + +-- Run the CA until converged or 1000 iterations +local ite, converged = 0, false +while converged == false and ite < 1000 do + ca, converged = automata.iterate(ca, domain, {moore}) + ite = ite+1 +end + +-- Access a subpattern's cell coordinates for external use +for icell in ca:cells() do + -- local foo = bar(cell) + -- or + -- local foo = bar(cell.x, cell.y) +end + +-- Find all 4-contiguous segments of the CA pattern +-- Uses the von-neumann neighbourhood to determine 'connectedness' +-- but any custom neighbourhood can be used) +local segments = subpattern.segments(ca, neighbourhood.von_neumann()) + +-- Print a representation to io.output +subpattern.print_patterns(domain, segments) +``` +### Output

    - +

    -In addition to pattern generation tools, **forma** implements several useful -methods for the manipulation of patterns. Basic operations such as pattern -addition or subtraction, enlargement and reflection are included. On top of -these, more involved methods such as flood-filling, Voronoi tessellation, hull -finding or Binary Space Partitioning are also available. Once again most of -these operations can be performed under custom definitions of the cellular -neighbourhood. - ## Installation **forma** is compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1. The library diff --git a/examples/README.md b/examples/README.md index 8efb4ff..de4c95c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -233,7 +233,6 @@ local subpattern = require('forma.subpattern') local automata = require('forma.automata') local neighbourhood = require('forma.neighbourhood') - -- Generate a square box to run the CA inside local domain = primitives.square(80,20) diff --git a/examples/readme.lua b/examples/readme.lua index b4a6ff7..f18b0ee 100755 --- a/examples/readme.lua +++ b/examples/readme.lua @@ -9,7 +9,6 @@ local subpattern = require('forma.subpattern') local automata = require('forma.automata') local neighbourhood = require('forma.neighbourhood') - -- Generate a square box to run the CA inside local domain = primitives.square(80,20) From 0ac74f1c8797e74afdc9578b8d402f96e60a08d8 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 15:58:25 +0200 Subject: [PATCH 27/31] Readme update --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index b2906d5..92f8965 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ shapes on a two dimensional grid or lattice. It came about as part of experiments in making roguelike games. **forma** is therefore particularly suited for (but not limited to) the generation of roguelike environments. -[Example Gallery](examples/) +
    [Example Gallery](examples/)
    ## Features @@ -77,11 +77,6 @@ local segments = subpattern.segments(ca, neighbourhood.von_neumann()) -- Print a representation to io.output subpattern.print_patterns(domain, segments) ``` -### Output - -

    - -

    ## Installation From b4e4a849ed42998f8a27043e97acf2337d2c1818 Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 16:00:36 +0200 Subject: [PATCH 28/31] Readme update --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 92f8965..40ee2e0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ shapes on a two dimensional grid or lattice. It came about as part of experiments in making roguelike games. **forma** is therefore particularly suited for (but not limited to) the generation of roguelike environments. -
    [Example Gallery](examples/)
    ## Features @@ -43,8 +42,8 @@ With all of these methods able to use custom definitions of the cellular Neumann](https://en.wikipedia.org/wiki/Von_Neumann_neighborhood)) and distance measures. Results can also be nested to produce complex results. -## Example - +## Examples +* [Example Gallery](examples/) ```lua -- Generate a square box to run the CA inside local domain = primitives.square(80,20) From d81d789db3b278512b34df107103696fb6d949fa Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 16:03:26 +0200 Subject: [PATCH 29/31] Readme update --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 40ee2e0..bd3ee93 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ suited for (but not limited to) the generation of roguelike environments. - Binary space partitioning - Voronoi tessellation / Lloyd's algorithm -With all of these methods able to use custom definitions of the cellular +Results can be nested to produce complex patterns, and all of these methods are +able to use custom distance measures and definitions of the cellular **neighbourhood** (e.g [Moore](https://en.wikipedia.org/wiki/Moore_neighborhood), [von -Neumann](https://en.wikipedia.org/wiki/Von_Neumann_neighborhood)) and distance -measures. Results can also be nested to produce complex results. +Neumann](https://en.wikipedia.org/wiki/Von_Neumann_neighborhood)). ## Examples * [Example Gallery](examples/) From 6d5c9c165be8d2b1522386eedc8b296038c130fd Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 16:06:46 +0200 Subject: [PATCH 30/31] Updating docs --- docs/contents.html | 7 +- docs/examples/async_automata.lua.html | 3 +- docs/examples/binary_space_partition.lua.html | 3 +- docs/examples/bubbles.lua.html | 3 +- docs/examples/cellular_automata.lua.html | 3 +- docs/examples/corridors.lua.html | 3 +- docs/examples/isolines.lua.html | 3 +- docs/examples/maxrectangle.lua.html | 3 +- docs/examples/sampling.lua.html | 3 +- docs/examples/voronoi.lua.html | 3 +- docs/modules/forma.automata.html | 3 +- docs/modules/forma.cell.html | 3 +- docs/modules/forma.neighbourhood.html | 3 +- docs/modules/forma.pattern.html | 3 +- docs/modules/forma.primitives.html | 3 +- docs/modules/forma.subpattern.html | 3 +- docs/readme/README.md.html | 124 ++++++++++++------ 17 files changed, 120 insertions(+), 56 deletions(-) diff --git a/docs/contents.html b/docs/contents.html index cc7d6b9..446a756 100644 --- a/docs/contents.html +++ b/docs/contents.html @@ -51,6 +51,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -126,6 +127,10 @@

    Examples

    maxrectangle.lua + + readme.lua + + sampling.lua @@ -140,7 +145,7 @@

    Examples

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/async_automata.lua.html b/docs/examples/async_automata.lua.html index 7883c65..1941730 100644 --- a/docs/examples/async_automata.lua.html +++ b/docs/examples/async_automata.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -106,7 +107,7 @@

    async_automata.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/binary_space_partition.lua.html b/docs/examples/binary_space_partition.lua.html index f082789..fbf165d 100644 --- a/docs/examples/binary_space_partition.lua.html +++ b/docs/examples/binary_space_partition.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -80,7 +81,7 @@

    binary_space_partition.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/bubbles.lua.html b/docs/examples/bubbles.lua.html index 7849792..bb67245 100644 --- a/docs/examples/bubbles.lua.html +++ b/docs/examples/bubbles.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -90,7 +91,7 @@

    bubbles.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/cellular_automata.lua.html b/docs/examples/cellular_automata.lua.html index 82a5d52..e1cf9a8 100644 --- a/docs/examples/cellular_automata.lua.html +++ b/docs/examples/cellular_automata.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -93,7 +94,7 @@

    cellular_automata.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/corridors.lua.html b/docs/examples/corridors.lua.html index 483622f..231dfe7 100644 --- a/docs/examples/corridors.lua.html +++ b/docs/examples/corridors.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -102,7 +103,7 @@

    corridors.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/isolines.lua.html b/docs/examples/isolines.lua.html index b68514f..133c074 100644 --- a/docs/examples/isolines.lua.html +++ b/docs/examples/isolines.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -101,7 +102,7 @@

    isolines.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/maxrectangle.lua.html b/docs/examples/maxrectangle.lua.html index 1f18555..871b4d0 100644 --- a/docs/examples/maxrectangle.lua.html +++ b/docs/examples/maxrectangle.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -84,7 +85,7 @@

    maxrectangle.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/sampling.lua.html b/docs/examples/sampling.lua.html index 0a62620..0296e76 100644 --- a/docs/examples/sampling.lua.html +++ b/docs/examples/sampling.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -92,7 +93,7 @@

    sampling.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/examples/voronoi.lua.html b/docs/examples/voronoi.lua.html index 113fdc5..09dfd19 100644 --- a/docs/examples/voronoi.lua.html +++ b/docs/examples/voronoi.lua.html @@ -41,6 +41,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -84,7 +85,7 @@

    voronoi.lua

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/modules/forma.automata.html b/docs/modules/forma.automata.html index 7f66c2d..fa862b7 100644 --- a/docs/modules/forma.automata.html +++ b/docs/modules/forma.automata.html @@ -59,6 +59,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -276,7 +277,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/modules/forma.cell.html b/docs/modules/forma.cell.html index 0a469ed..2b1c39b 100644 --- a/docs/modules/forma.cell.html +++ b/docs/modules/forma.cell.html @@ -60,6 +60,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -470,7 +471,7 @@

    Usage:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/modules/forma.neighbourhood.html b/docs/modules/forma.neighbourhood.html index 16c73fd..c21d810 100644 --- a/docs/modules/forma.neighbourhood.html +++ b/docs/modules/forma.neighbourhood.html @@ -59,6 +59,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -301,7 +302,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/modules/forma.pattern.html b/docs/modules/forma.pattern.html index 495f7a7..a84b8c0 100644 --- a/docs/modules/forma.pattern.html +++ b/docs/modules/forma.pattern.html @@ -64,6 +64,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -1154,7 +1155,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/modules/forma.primitives.html b/docs/modules/forma.primitives.html index f2060bf..faf2254 100644 --- a/docs/modules/forma.primitives.html +++ b/docs/modules/forma.primitives.html @@ -58,6 +58,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -199,7 +200,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/modules/forma.subpattern.html b/docs/modules/forma.subpattern.html index bf439fa..4916bda 100644 --- a/docs/modules/forma.subpattern.html +++ b/docs/modules/forma.subpattern.html @@ -60,6 +60,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -585,7 +586,7 @@

    Parameters:

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    diff --git a/docs/readme/README.md.html b/docs/readme/README.md.html index 329cd0d..ecb1b39 100644 --- a/docs/readme/README.md.html +++ b/docs/readme/README.md.html @@ -30,6 +30,14 @@

    forma

  • Index
  • +

    Contents

    +

    Readme

    @@ -54,6 +62,7 @@

    Examples

  • corridors.lua
  • isolines.lua
  • maxrectangle.lua
  • +
  • readme.lua
  • sampling.lua
  • voronoi.lua
  • @@ -82,46 +91,90 @@

    forma

    experiments in making roguelike games. forma is therefore particularly suited for (but not limited to) the generation of roguelike environments.

    -

    Shapes can be generated in several ways. From simple rasters of primitive shapes -like circles, lines and squares, to pattern generation by a Cellular -Automata (CA) implementation, -including both synchronous and asynchronous update rules. Using the CA methods, -patterns such as the classic 4-5 rule 'cave' systems can be generated:

    +

    +

    Features

    -

    - -

    +
      +
    • A spatial-hashing pattern class for fast lookup of active cells.
    • +
    • Pattern manipulators such as addition, subtraction and reflection for the + generation of symmetrical patterns.
    • +
    • Rasterisation algorithms for 2D primitives, e.g lines, circles, squares.
    • +
    • A very flexible cellular automata implementation with +
      +- Synchronous and asynchronous updates
      +- Combination of multiple rule sets
      +
      +
    • +
    • Pattern sampling algorithms including -

      However the real power of the CA implementation is in its flexibility. -Different CA rules with custom cellular neighbourhoods (including -Moore, von -Neumann and more) may -be combined. Patterns can also be recursively generated by nesting the result of -one pattern in another. Interesting structures can therefore be formed by -combining different CA rule sets with different neighbourhoods and domains. For -example a 'corridor' structure:

      +
      +- Random (white noise) sampling
      +- Poisson-disc sampling
      +- Mitchell's best-candidate sampling
      +
      +
    • +
    • Algorithms for subpattern finding including +
      +- Flood-fill contiguous segment finding
      +- Pattern edge and surface finding
      +- Binary space partitioning
      +- Voronoi tessellation / Lloyd's algorithm
      +
      -

      - -

      +Results can be nested to produce complex patterns, and all of these methods are +able to use custom distance measures and definitions of the cellular +neighbourhood (e.g +Moore, von +Neumann).
    • +
    +

    +

    Examples

    +

    * Example Gallery

    + +
    +-- Generate a square box to run the CA inside
    +local domain = primitives.square(80,20)
    +
    +-- CA initial condition: 800-point random sample of the domain
    +local ca = subpattern.random(domain, 800)
    +
    +-- Moore (8-cell) neighbourhood 4-5 rule
    +local moore = automata.rule(neighbourhood.moore(), "B5678/S45678")
    +
    +-- Run the CA until converged or 1000 iterations
    +local ite, converged = 0, false
    +while converged == false and ite < 1000 do
    +    ca, converged = automata.iterate(ca, domain, {moore})
    +    ite = ite+1
    +end
    +
    +-- Access a subpattern's cell coordinates for external use
    +for icell in ca:cells() do
    +    -- local foo = bar(cell)
    +    -- or
    +    -- local foo = bar(cell.x, cell.y)
    +end
    +
    +-- Find all 4-contiguous segments of the CA pattern
    +-- Uses the von-neumann neighbourhood to determine 'connectedness'
    +-- but any custom neighbourhood can be used)
    +local segments = subpattern.segments(ca, neighbourhood.von_neumann())
    +
    +-- Print a representation to io.output
    +subpattern.print_patterns(domain, segments)
    +
    -

    In addition to pattern generation tools, forma implements several useful -methods for the manipulation of patterns. Basic operations such as pattern -addition or subtraction, enlargement and reflection are included. On top of -these, more involved methods such as flood-filling, Voronoi tessellation, hull -finding or Binary Space Partitioning are also available. Once again most of -these operations can be performed under custom definitions of the cellular -neighbourhood.

    +

    Installation

    forma is compatible with Lua 5.1, 5.2, 5.3 and LuaJIT 2.0, 2.1. The library -is written in pure Lua, no compilation is required. Including the project is -then as simple as including the forma directory in your Lua path.

    +is written in pure Lua, no compilation is required. Including the project is as +simple as including the forma directory in your project or Lua path.

    The easiest way to do this is via LuaRocks:

    @@ -131,17 +184,7 @@

    Installation

    -

    Running examples

    - -

    The examples require that the forma/ directory is in the lua path. The easiest -way to try the examples is to run them from the root directory of this repo. For -example

    - - -
    -lua examples/game_of_life.lua
    -
    - +

    Generating documentation

    Documentation is hosted here.

    @@ -158,6 +201,7 @@

    Generating documentation

    in the root directory should generate all the required pages.

    +

    Testing

    Unit tests and coverage reports are provided. The test suite requires @@ -177,7 +221,7 @@

    Testing

    generated by LDoc 1.4.6 -Last updated 2018-07-14 14:27:46 +Last updated 2018-07-14 16:06:25
    From c059b544886e5197aed222fd43ab47a3815f939a Mon Sep 17 00:00:00 2001 From: Nathan Hartland Date: Sat, 14 Jul 2018 16:11:59 +0200 Subject: [PATCH 31/31] Updated changelog --- CHANGELOG.md | 28 ++++++++++++++++------------ TODO.md | 3 --- 2 files changed, 16 insertions(+), 15 deletions(-) delete mode 100644 TODO.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 479f8f8..6197a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,30 +5,34 @@ 0.2b --------- -- Improved circle raster (no longer repeats points) +### Features +- Implemented a 'mask' subpattern that masks out cells according to a provided + function +- Added Voronoi relaxation via Lloyd's algorithm +- Added pattern.cells: an iterator over the constituent cells in a pattern +- Added cell_coordinates iterator, returning an (x,y) pair rather than a cell +- Added shuffled_cells iterator, similar to cells but in a randomised order +- Added centroid and medoid (with general distance measure) methods and tests +- Added a Poisson-disc sampling subpattern +- Added Mitchell's Best-Candidate sampling (approximate Poisson-Disc) + +### Bugfix - Fixed bug with subpattern.enclosed which would generate more than one enclosed point for a primitive.circle +- Fixed default initialisation of RNG in automata.async_iterate + +### Misc +- Improved circle raster (no longer repeats points) - Integrated all tests into a single test script, and added luacov coverage -- Implemented a 'mask' subpattern that masks out cells according to a provided - function - Converted subpattern.random to take as an argument a fixed integer number of desired samples rather than a fraction of the domain size. -- Added Voronoi relaxation via Lloyd's algorithm -- Fixed default initialisation of RNG in automata.async_iterate - Removed special handling of '-0' coordinate in cell: No longer required with integer spatial hash in patterns. - Made pattern coordinate limits explicit in MAX_COORDINATE - Changed internal structure of `pattern`, from a list of cells to a list of coordinate hashes -- Added pattern.cells: an iterator over the constituent cells in a pattern -- Added cell_coordinates iterator, returning an (x,y) pair rather than a cell -- Added shuffled_cells iterator, similar to cells but in a randomised order -- Added example of Worley noise - Various optimisations -- Added centroid and medoid (with general distance measure) methods and tests -- Added a Poisson-disc sampling subpattern - Removed some (confusing) functionality from `cell`, namely addition and multiplication with a number value. - Added isoline drawing example -- Added Mitchell's Best-Candidate sampling (approximate Poisson-Disc) - Renamed pretty_print to print_patterns diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 7bd611c..0000000 --- a/TODO.md +++ /dev/null @@ -1,3 +0,0 @@ -# TODO - -- Luarocks