API documentation is in the various subdirectories, e.g. `string/api.html`

as well as in the `documentation`

directory.

The code here is generally licensed as CC-BY (https://creativecommons.org/licenses/by/4.0/).

Attribution should be to Mary Holstege and include a link to the code base at http://mathling.com/code/

Some of the same data is based on WordNet 3.0® and is made available under that license (see `data`

directory).

The noise code is a port of noise-rs which is used under an MIT License (see `noise`

directory).

Much of the colour space conversion code is a port of hsluv-c which is used under an MIT License (see `colourspace`

directory).

Much of the SDF code is based in part on code from Inigo Quilez which is used under an MIT License with some operators from Karsten Schmidt which is used under an Apache license, and a few details from Electric Square Ltd., also under and MIT License (see `sdf`

directory).

The gradients are based on gradient definitions from a variety of sources used under MIT, BSD, and CC Licenses (see `COLOURS`

directory).

The Wave Function Collapse algorithm is a port of the WFC code, which is used under an MIT license. See `wfc`

directory.

Major incompatibility: SDF functions

- Since XSL doesn't support function annotations, to support annotations in function libraries like SDF, a new callable wrapper has been introduced. It is necessary to use
`callable:function()`

to get at the actual function now. Other functions-that-produce-annotated functions (noise, modifiers) will get this treatment going forward. However,`callable:function()`

will work on bare functions too, so it is advisable to just use it with these modules to future-proof code.

- Since XSL doesn't support function annotations, to support annotations in function libraries like SDF, a new callable wrapper has been introduced. It is necessary to use
Other incompatibilities

- Namespace changed from http://mathling.com/art/colour-space to http://mathling.com/colour/space
- Moved
`components/paths.xqy`

to`shapes/paths.xqy`

; namespace changed from http://mathling.com/art/paths to http://mathling.com/shape/paths - Split grid functions out of
`components/paths.xqy`

into`shapes/grids.xqy`

with namespace http://mathling.com/grid - Renamed SDF smooth operators to round (e.g. sdf:opSmoothUnion => sdf:opRoundUnion)
- Remove $geom:ORIGIN* (use $point:ORIGIN* instead)
- Remove deprecated function rand:uniform-distribution-of (use dist)
- dist:markov() with 1 argument now uses 1 as start (not a random index, which creates circular imports)
- util:clamp() now requires both arguments; use util:clamp-some() for open ranges

Documentation

- XQDocs for all modules, to varying degrees of detail

XSL APIs

- Ports to XSL of some of the core libraries (more to come!)

Examples

- Rendering examples in XQuery and XSLT
- Randomization and loops

Complete reworking of drawing functions

- Drawing operations for various objects not in that object's module

Major new objects and capabilities

- Blocks: axis aligned 3D blocks (see
`geo/box.xqy`

) - Coordinate mappings such as bipolar (see
`geo/coordinates.xqy`

) - Patterns: patterns:fir(), patterns:nested-arc(), patterns:diamonds(), patterns:voronoi() (see
`shapes/patterns.xqy`

) - Clipping regions (see
`types/reach.xqy`

) - Navigable hex grids (see
`shapes/grids.xqy`

) - New colour palettes from https://nrennie.github.io/PrettyCols/

- Blocks: axis aligned 3D blocks (see
Sequences (see

`core/sequences.xqy`

)- New sequences: seq:primes(), seq:prime-factors(), seq:factors(), seq:recaman(), seq:gerrymander2(), seq:inventory()
- Sequence operators: seq:μ(), seq:mobius(), seq:lodumo(), seq:binomial(), seq:ordinal()
- More error checking on sequence arguments

SDF changes (see

`sdf/`

)- Reorganization as described in incompatibilities
- Make SDFs easier to use when you don't need scaling (i.e. not raymarching)
- Add sdf:make-point-render() and sdf:make-vector-render() which return functions to do the ray-casting (avoids repeated camera angle calculations etc.)
- Additional SDF operators (chamfered, smooth, and stepped)

New art components and capabilities

- Backgrounds: background:terrain() shadowed height field
- Shadowy people (see
`components/people.xqy`

) - Squishy blob fills (see
`components/squishy.xqy`

) - Barnsley ferns (see
`components/barnsley.xqy`

)

Miscellaneous new functions

- util:annotations() (see
`core/utilities.xqy`

) - dist:weighted-distribution-of() (see
`types/distributions.xqy`

) - curve:plot() curve:multi-plot() (see
`geo/curves.xqy`

) - splittree:find(), splittree:parent(), splittree:split-tree3() (see
`geo/splitree.xqy`

) - effect:displace() (see
`svg/effects.xqy`

) - gradient:luminance-range() (see
`svg/gradients.xqy`

) - english:word-syllable() and mode 'syllables' (see
`components/english.xqy`

) - path:simplify(), path:chaikin() (see
`geo/path.xqy`

) - edge:closest-point() (see
`geo/edge.xqy`

)

- util:annotations() (see
Bug fixes

- Off-by-one sequence length fix: jacobsthal(), katydid(), grasshopper()
- Arc bounding box raised assertion failure on degenerate arc
- Handle edge cases for ellipse:circle-center-of(), ellipse:circle-from()

Tests

- More sequence, SDF, utilities, geo tests
- XSLT tests

Major new components and capabilities

- Quaternions (
`core/quaternion.xqy`

,`core/vquaternion.xqy`

) - MusicXML basic parsing (
`music/music.xqy`

) - Text wrapper and text layout within rectangles (
`types/text.xqy`

,`string/string.xqy`

) - Pseudospirals (
`components/paths.xqy`

) - Randomized components
- Polynomial spirals (
`components/polyspiral.xqy`

) - Arrangements: initial gathering of basic point arrangements by name (
`components/arrangements.xqy`

) - Modifiers: gathering of modifier functions (double to double) by name (
`components/modifiers.xqy`

) - Refraction: Snell's law refraction calculations; various material parameters (
`components/refraction.xqy`

) - Pixel sorting: pixel sorting (
`components/pixelsort.xqy`

) - Crosshatch: crosshatching of various kinds (
`components/crosshatch.xqy`

) - English: gibberish with English letter distributions (
`components/english.xqy`

) - Old key: old-fashioned block keys (
`components/oldkey.xqy`

)

- Polynomial spirals (

- Quaternions (
Effects and filters

- New builtin effects: sandstone and sandpaper
- New effect composition modifiers: overlay, blend-multiply, blend-screen, blend-darken, blend-lighten, compose-over, compose-in, compose-out, compose-atop, compose-xor
- Make effect building API more compositional; add effect:blur(), effect:perturb()
- Bug: effect prefixes using wrong regex; not working properly

Colours and gradients

- Fix name confusion cube_1_0 vs cube1_0
- New palette: plant-dyes plus associated colour names
- Add variables capturing key palette/gradient aspects: $gradient:SMALL-GRADIENTS, $gradient:SPLIT-GRADIENTS, $gradient:CYCLIC-GRADIENTS, $gradient:LINEAR-GRADIENTS
- Bug: werner_reds, werner_blues, werner_browns misnamed in gradient:starts-darker() so not properly accounted for
- Make gradient building API more compositional; make modifiers in names fully compositional
- gradient:random-colour() selecting random colour from gradient with optional reluminance bounds
- gradient:colours() to reluminate colours from gradient within luminance bounds
- gradient:circularize() to extend set of colours to make circular gradient
- Escape rgb() colour names in URL references
- Clamp values in CMYK-to-RGB conversion to avoid errors
- New: cs:greyscale-value-to-rgb(), cs:greyscale-value-to-xyz(), cs:rgb-to-greyscale-value(), cs:rgb-to-greyscale(), tone:cmyk-snap()
- Bug: Wrong accessor used for ambient light; diffuse lighting could be off
- Bug: error in RGB-to-CMYK conversion

Images

- New: Image wrapper with data URL escaping and embedding (
`image/image.xqy`

) - New: image matrix convolutions, plus edge-detection, sharpen, and blur (
`image/convolution.xqy`

) - New: pixel sorting (
`image/pixelsort.xqy`

)

- New: Image wrapper with data URL escaping and embedding (
Randomizers

- core:randomize() will return keys corresponding to random index if available
- Add selector distribution to multimodal distributions (not just uniform)
- New: dist:zipf-index-of(), dist:weighted-index-of()

Geometry

- More refactoring (see specifics below)
- Add solid geometry objects to more generic geometric operations (e.g. geom:points())
- Add more pass-throughs to generic geometric operations for wrappers, slots, and masks
- Extend and improve region intersection; add tolerance
- New: geom:apply-transforms(), geom:circle-intersection(), transform:matrix()
- geom:points(), geom:vertices() take sequence of regions, not singleton
- Add option to conrec functions to return polygons
- Improved error reporting
- Bug: fix off-by-one point check in spline:spline()
- Bug: signed distance was 0 limited for edges, paths, and polygons
- Bug: polygon-contains(circle) wrong sense of comparison
- Bug: polygon-intersects(circle) incomplete
- Points:
- New: point:midpoint(), point:angle(), point:inclination(), point:pcoordinate(), point:centroid()
- Handle INF and NaN better in points

- Solids:
- New: solid:n-faces(), solid:points()

- Edges:
- geom:edge-angle() => edge:angle()
- geom:edge-inclination() => edge:inclination()
- geom:edge-length() => edge:length()
- geom:edge-intersects() => edge:linear-intersects()
- geom:quad-intersects() => edge:quad-intersects()
- geom:cubic-intersects() => edge:cubic-intersects()
- geom:arc-intersects() => edge:arc-intersects()
- geom:arc-midpoint() => edge:arc-midpoint()
- geom:interpolate-edge() => edge:interpolate-edge()
- geom:interpolate-edge-using() => edge:interpolate-edge-using()
- geom:interpolate-quadratic() => quadratic:interpolate-quadratic()
- geom:interpolate-quadratic-using() => quadratic:interpolate-quadratic-using()
- geom:interpolate-cubic() => cubic:interpolate-cubic()
- geom:interpolate-cubic-using() => cubic:interpolate-cubic-using()
- geom:interpolate-arc() => arc:interpolate-arc()
- geom:interpolate-arc-using() => arc:interpolate-arc-using()
- New: edge:edge-intersects(), edge:tangent(), edge:to-edges(), edge:slice(), edge:chop(), edge:point-distance(), edge:linear-t(), edge:quad-t(), edge:cubic-t(), edge:arc-t(), edge:edge-t(), edge:arc-intersection()

- Ellipses and circles
- geom:ellipse-point() => ellipse:ellipse-point()
- geom:interpolate-circle() => ellipse:interpolate-circle()
- geom:interpolate-circle-using() => ellipse:interpolate-circle-using()
- geom:interpolate-ellipse() => ellipse:interpolate-ellipse()
- geom:interpolate-ellipse-using() => ellipse:interpolate-ellipse-using()
- geom:circle-center-of() => ellipse:circle-center-of()
- geom:circle-from() => ellipse:circle-from()
- New: ellipse:bounding-box(), ellipse:circle-circle-intersection(), ellipse:ellipse-intersects-ellipse(), ellipse:bounding-box(), ellipse:tangent-angle(), ellipse:interpolate(), ellipse:interpolate-using()
- Bug: incorrectly using degrees instead of radians for ellipse rotation in ellipse:contains-point()

- Boxes and rectangles:
- geom:box-intersects() => box:box-intersects(), rect:box-intersects()
- New: box:intersects-box()

- Paths and polygons:
- geom:path-point() => path:path-point()
- geom:polygon-contains-point() => path:polygon-contains-point()
- geom:slice-path() => path:slice()
- Subsume geom:polygon-intersects-polygon() into geom:region-intersects()
- New: path:polygon-center(), path:tangent(), path:bounding-box(), path:edge-intersections(), path:path-t()

Complex numbers

- New: vector form API
- New: z:abs(), z:sinh(), z:cosh(), z:ppow(), z:exp()
- Incompatibility: z:complex-rφ() now takes radians; z:complex-rφd() takes degrees

Tweaks

- Canvas: change resolution to naming system (e.g. medium+reverse+45+border); new core:inner-canvas()
- Utilities: new util:intmix(), util:hypermix(), util:expmix(), util:factorial(), util:binomial()
- trace() function in mutations, modifiers, and SDF functions
- Wrappers: wrapper:shapes() to extract geometric drawable shapes (exclude def, ref, element metadata, etc.)
- Drawing: use function lookup to find drawing functions; don't draw empty paths; supper stroked paths
- Voronoi: allow non-rectangular bounds; use shorter "infinite" edges
- Backgrounds: border frames, circle crosshatching
- Mountains: add smoothing
- Speckles: speckles:tangents(); more controls; better ray calculation for singleton point
- Mutations: typo in name of perspective parameter; add new randomized parameters for various mutations; new mutation:trace(), mutation:translate()
- Paths: new paths:hex-grid(), better handling of border edges in grids
- Sequences: new seq:padovan(), seq:fractal(), seq:golomb(), seq:lazy-caterer(), seq:jacobsthal(), seq:jacobsthal-lucas(), seq:pascal-row(), seq:pascal(), seq:katydid(), seq:grasshopper(), seq:k-combinations(), seq:foreach-k-combination()

Misc

- Various minor bug fixes and additional tests, examples, and documentation

Major new algorithm: Wave Function Collapse (

`wfc/`

)Mutations:

- Additional mutation functions (pillow, crumble, rotate, flowfield, supershape, flower, conic, parabola, bent2, dist2)
- Fixes to some mutations (arch, gaussian, blur, ring/ring2)
- Parameter drift extents
- Add randomization framework to mutation naming system

Other new:

- Mask type for drawing masks ('types/mask.xqy`)
- Extended helix functions
- $config:POINT-IS-PIXEL to control how points get rendered by default
- Shift wave component to use wrapper
- More examples and docs

Refactoring of geometry code

- Partition basic affine support operations to
`geo/affine.xqy`

- Consolidation and clean-up of affine code in general
- Shifting edge intersection point operations to
`geo/edge.xqy`

; some renaming, e.g.`geom:slice-edge()`

=>`edge:slice()`

- Shift box code to
`geo/box.xqy`

to avoid twisted imports; external interface unchanged

- Partition basic affine support operations to
Geometry additional:

- Better handling of precision issues with edge operations
- New: edge:quad-t(), edge:cubic-t()
- More passthroughs for wrappers and slots in geometry operations
- New: transform:parse-matrix()
- Slightly better arc handling; new:
`edge:as-point-arc()`

- Bug: box:mutate() and some arc transforms lose properties

Colours

- Make Werner colour names more consistent with other colour names
- Support gradient merges and interleaves in naming system

Other bugs:

- Missing abs() in complex:is-real()
- For consistency path angle should return 270 not -90
- Missing cast in one branch or util:unsignedLong
- rgb:to-int() inverted the coordinates, causing colour changes
- rand:n-partition() used wrong subroutine, incorrect results

Major new components and features

- STL 3D model files[1] (
`3d/`

) - PNG read/write [2] (
`images/png.xqy`

) - CONREC (contouring algorithm) implementation[3] (
`geo/conrec.xqy`

) - Exponential random distribution (
`types/distibutions.xqy`

) - Parametric, polar, and dependent curve plotting (
`geo/curves.xqy`

) - Polynomials (values, definite integrals, derivatives, anti-derivatives) (
`types/polynomial.xqy`

) - Filter manipulation functions (
`svg/effects.xqy`

) Randomized components:

- Backgrounds: neutral backgrounds with crosshatching, stippling, etc. (se
`components/backgrounds.xqy`

) - Cellular: Cellular automatons[4] (
`components/cellular.xqy`

) - Contours: random contours (
`components/contours.xqy`

) - Egg: egg shapes based on universal egg equation[45 (
`components/egg.xqy`

) - Divisions: rectangular subdivisions (
`components/divisions.xqy`

) - Fractal flame: fractal flame implementation[6] (
`components/fflame.xqy`

) - Waves: symmetrically damped waves (
`components/waves.xqy`

) - Glyphs (
`components/xtrs.xqy`

) - Harmonographs (
`components/harmonograph.xqy`

)

- Backgrounds: neutral backgrounds with crosshatching, stippling, etc. (se
Various spirals and curves (

`components/paths.xqy`

)- harmonographs and damped pendulums, damped sine waves, torus-knot-driven wiggles, modulated Lissajous, Rose curve, trefoil, Maurer rose, granny knot, harmonograph, Euler's spiral, polynomial spiral, Cotes' spiral, Poinsot spiral, reciprocal spiral, equiangular spiral, epispiral, cochleoid spiral, atom spiral, circle involute, lituus, Gielis curve (super ellipse), super rose, super spiral, logarithmic spiral, Fermat's spiral, tractrix, Doppler curve, conchospiral, Lamé curve

- STL 3D model files[1] (
Colours and gradients:

- Upgrade to version 7 of Scientific Colour Maps
- Add palettes and colours from Werner's Nomenclature of Colours
- Other new palettes (
`svg/gradients.xqy`

) - Add RGBA constructor that takes string values
- Add RGB to integer and integer to RGB functions
`gradient:average-luminance()`

to compute relative brightness of a set of colours- Clean up and extend the gradient manipulation code
- Fix cardinality errors in gradient expansion functions

Random distributions:

`dist:post-shift()`

to add a value to the output of the core algorithm`dist:simple-sums()`

method for constructing a cumulative weight table from an ordered set of raw weights- Add
`keys`

hook for automating getting values from random indexes (`art/core.xqy`

) - Add explicit
`double`

cast to override the implicit`integer`

cast of some of the distributions (e.g. Zipf)

Types:

- Wrappers: Generic bundling of objects with dynamic parameters; refactor components to use wrappers, support wrapper passthroughs in various contexts
- Noise-based colouring, for applying a colour shift against a gradient based on a noise field

Isohedral tiling:

- Add parameter to
`tiling:create-tiles`

to control the extent of the bounds and override the default - Add boundary settor to tiles, so that we can apply affines, for example

- Add parameter to
Geometry:

- ARF inprovements: use radius not diameter for default scaling and add explicit radius parameter, lower Δt and iterations to improve performance, more controls over graph layout, edge case checks
- Add support for various solids to geometric operations (correct ellipsoid support is WIP)
- Change affine operations to take sequences of regions, for easier use
- Generic
`geom:area()`

,`geom:length()`

,`geom:n-faces()`

,`geom:region-point()`

functions `geom:tangent()`

and`geom:normal()`

for 2D linear, quad, or cubic edge, plus associated`geom:tangent-angle()`

and`geom:normal-angle()`

(angle of the tangent or normal vector)`point:valid()`

to check for point coordinates that are infinite or NaN- More solid geometry operations on faces:
`solid:normal()`

,`solid:face-area()`

,`solid:face-centroid()`

- Method for conversion of one of the Platonic solids to the generic polyhedron

Framework

- Improved support for merging information from components; refactoring of components to make use of this
- Support selecting keys based on random index in
`core:randomize()`

- High level generation of dynamic random values:
`core:random-parameter-map()`

,`core:random-parameters()`

- Hooks for colour buckets drawing
- Limited SVG path parsing support
- Fix metadata passthrough in SVG drawing functions

Signed distance functions

- Improvements to
`sdf:toSDF()`

- Sequence operations to reduce function stacking:
`sdf:opUnion()`

,`sdf:opIntersect()`

- Improvements to
Components

- Mutation functions: add weight into calculations
`mut:drift()`

, handle missing parameters - Systems: add quadratic Gosper curve
- Array arrangements: ability to return boxes, allow use of boxes or slots for sizing

- Mutation functions: add weight into calculations
Incompatibilities

- Adjustments and additions to standard resolutions (pic, page, poster, rev-pic, rev-poster)
- SDF octohedron renamed octahedron
- Flip argument order on
`util:min-key()`

and`util:max-key()`

`geom:region-center()`

honours a`center`

property- Change
`solid:edges()`

to return distinct edges; add`solid:ordered-edges()`

to get the full set of edges (including shared), in face order - Change order of output arguments in
`transform:describe()`

to better match SVG transform property

Various fixes:

- Fixes to dodecahedron: add missing face, fix ordering of some faces, fix scaling
- Better handling of some edge cases in
`geom:region-center()`

, fix bug in center of 4-sided polygon - Check some edge cases in quad length calculations
- Better area calculations for triangles
- Fix mishandling of rotated ellipses in
`geom:ellipse-point()`

- Fix cardinality errors within
`core:dump-randomizer()`

and`$core:EVAL11`

- Fix
`systems:pentaplexity()`

to use parameters for scaling and generations - Raise error if light direction is origin (gives NaN values)
- Handle degenerate edges in SDF; avoid NaNs
- More tests and examples

Possible future mayhem:

- Refactoring of spirals and related curves from
`components/paths.xqy`

- Refactoring of more geometric operations to push more to the individual geometric types

- Refactoring of spirals and related curves from

[1] Requires functions from the `http://expath.org/ns/file`

and `http://expath.org/ns/binary`

namespaces.

[2] Depends on Saxon Java API extensions; metadata saved in a secondary file due to lacunae in Java PNG implementation.

[3] See Paul Bourke "CONREC: A Contouring Subroutine" (`http://paulbourke.net/papers/conrec/`

) for more information.

[4] See `https://en.wikipedia.org/wiki/Elementary_cellular_automaton`

for more information.

[5] See Valeriy G. Narushin, Michael N. Romanov, and Darren K. Griffin " A universal formula for avian egg shape" (`https://www.biorxiv.org/content/10.1101/2020.08.15.252148v1`

) for more information.

[6] See Scott Draves & Erik Reckase "The Fractal Flame Algorithm" (https://flam3.com/flame_draves.pdf) for more information.

Geometry:

- More refactoring of edge/point/circle code (shifting to specific type module)
- Some support for Platonic solids and generic polyhedra
- Signed distance function for region types
- ARF graph layout
- Point maps (hash map for points)
- Additional circle/polygon intersection support (needs more tests)
- Isometric projection
- Pass-through slot bodies in various geometric operations
- Fix bug in
`box:max-y`

for spaces - Fix bug in
`geom:project`

return type - Fix cardinality bug in some instances of
`mutate()`

Sequences:

- Consolidate some sequence/set operations in sequences.xqy (Fibonacci, combinations and permutations)
- Additional sequences: deBruijn, Thue-Morse, Feibenbaum, ruler

Utilities:

- Add Poisson and binomial Poisson distributions
- Matrix operations
- Stack data structure
- Base conversions
`util:logK()`

and`util:log2()`

(log base K and log base 2)`rand:mutual-prime-pair()`

(pair of mutually prime integers)`util:modix`

handle negative numbers to preserve sequentiality- Include canvas edge in
`paths:array()`

calculations - Fix mishandling of pre-multiplier in resampling
- Bugs in skewed normal distribution
- Cardinality errors in some random functions
- Fix function annotation mechanism

Drawing/Colour/Effects:

- Add configuration for SVG vs DSL drawing so components can be agnostic
- Integrate projection into drawing functions for solids
- Diffuse lighting model
- Effect manipulations: merging, renaming, changing lighting colour or point light source, changing extent, changing turbulence
`gradient:random-gradient()`

select a random well-known gradient or its reverse- Doc fix: tonemapping should take place over linear RGB (XYZ space)

Components:

- Functions to array points on circular arc, helix, spirals of various types
- Mutation function library
- L-systems
- Trees
- Smooth curls
- Flowfields
- Mutated torus knots
- Frustrated N-gons
- Mountain ranges

Additions, extensions, and bug fixes to geometry code:

`geo:region-intersects`

between most region types`geo:region-contains`

between some region types`geo:shortest-distance`

from point to region`geo:intersection`

between edges`geo:bounding-circle`

of region (Weltz' algorithm)`geo:bounding-box`

of region`geo:region-center`

`geo:regions`

edge following to construct polygons from edge graph- Graph object (
`graph.xqy`

) - Squarified tree construction (
`treemap.xqy`

) - Delaunay triangulation (
`delaunay.xqy`

)

Drawing code

- Simple geometric object to SVG rendering (
`draw.xqy`

) - SVG filter construction/manipulation (
`effect.xqy`

)

- Simple geometric object to SVG rendering (
Miscellaneous

- Read PPM image data into non-sparse matrix, much faster
- ACES, Hablic, Reinhard tonemapping (
`tonemap.xqy`

) - Add missing prefixes to
`$EDGE-START`

and`$EDGE-END`

in tiling code - Enpsulate entity/string dictionary saving methods
- Linear, quadratric, and cubic root calculations (
`roots.xqy`

) - Complex numbers (
`complex.xqy`

)

Major refactoring of geospatial code, with some additional operations for splinning and reversing edges, among others. As a consequence of this a number of edge and path functions have shifted from

`euclidean.xqy`

to`edge.xqy`

or`path.xqy`

in some cases with a slight renaming. Example:`geom:linear-edge-point`

is not`edge:linear-point`

. In addition a few functions have moved to`utilities.xqy`

(`remap-degrees`

,`remap-radians`

).Handle error cases in

`edge:quad-length`

better.Change

`geom:inclination`

to define it as 90° not 0° when the points are the same.Change

`geom:destination`

to avoid small round-off errors in Z values from inclination imprecision.Add split tree and well-separated pair decomposition and spanning edges on WSPDs. (Depends on bug-fix in Saxon 10.6 to work.)

Add support for dithering of raw images.

Add support for complex numbers.

Add modules for signed distance function calculation, with various rendering and lighting calculations, with tests.

Add SVG gradient collection and module for manipulating SVG gradients.

Add permutation and combination calculations to

`utilities.xqy`

.Slight refactoring of random distributions code to avoid tangled imports.

ε is now defined globally in

`config.xqy`

`util:twixt`

will reorder out-of-order arguments.

Bug fix to

`rand:skewed()`

: incorrect calculation of standard deviation.Bug fix to

`rand:flip()`

: scaling error.Reimplementation and API change to

`rand:random-selection()`

to give more precise probability mapping.Additional/cleaned-up randomizer tests: advice on optimizer flags for Saxon EE

`util:rangeindex()`

+ tests