http://mathling.com/art/mutations  library module

http://mathling.com/art/mutations

Mutation functions: point to point in the bi-unit square [-1,1]x[-1,1]
The functions are set up to allow them to be selected generically from
a mapping table (as in the fractal flame code) or applied directly.

Parameters:
Each parameterized function has a parameter with its name which is a map
its parameters. e.g. "mutation.blob" holds parameters for the "blob" function
See Scott Draves & Erik Reckase "The Fractal Flame Algorithm" for specifics.
These can be used to provide default parameter settings for each function.
In addition, the functions are given a weight parameter, which some of
them use. In the fractal flame component this is set to the function weight
in the selection tables. But see this:mutation() for defaulting.

Randomizers:

Imports

http://mathling.com/geometric/mutation
```import module namespace ann="http://mathling.com/geometric/mutation"
at "../geo/mutation.xqy"```
http://mathling.com/core/callable
```import module namespace f="http://mathling.com/core/callable"
at "../core/callable.xqy"```
http://mathling.com/geometric/coordinates
```import module namespace coordinates="http://mathling.com/geometric/coordinates"
at "../geo/coordinates.xqy"```
http://mathling.com/type/distribution
```import module namespace dist="http://mathling.com/type/distribution"
at "../types/distributions.xqy"```
http://mathling.com/geometric/rectangle
```import module namespace box="http://mathling.com/geometric/rectangle"
at "../geo/rectangle.xqy"```
http://mathling.com/type/wrapper
```import module namespace wrapper="http://mathling.com/type/wrapper"
at "../types/wrapper.xqy"```
http://mathling.com/geometric
```import module namespace geom="http://mathling.com/geometric"
at "../geo/euclidean.xqy"```
http://mathling.com/geometric/affine
```import module namespace affine="http://mathling.com/geometric/affine"
at "../geo/affine.xqy"```
http://mathling.com/geometric/point
```import module namespace point="http://mathling.com/geometric/point"
at "../geo/point.xqy"```
http://mathling.com/core/random
```import module namespace rand="http://mathling.com/core/random"
at "../core/random.xqy"```
http://mathling.com/art/core
```import module namespace core="http://mathling.com/art/core"
at "../art/core.xqy"```
http://mathling.com/core/utilities
```import module namespace util="http://mathling.com/core/utilities"
at "../core/utilities.xqy"```
http://mathling.com/core/vector
```import module namespace v="http://mathling.com/core/vector"
at "../core/vector.xqy"```
http://mathling.com/noise/perlin
```import module namespace perlin="http://mathling.com/noise/perlin"
at "../noise/perlin.xqy"```
http://mathling.com/noise/modifiers
```import module namespace noise="http://mathling.com/noise/modifiers"
at "../noise/modifiers.xqy"```
http://mathling.com/core/config
```import module namespace config="http://mathling.com/core/config"
at "../core/config.xqy"```
http://mathling.com/core/errors
```import module namespace errors="http://mathling.com/core/errors"
at "../core/errors.xqy"```

Functions

```Function: rendering-parametersdeclare function rendering-parameters(\$canvas as map(xs:string,item()*), \$algorithm-parameters as map(xs:string,item()*)) as map(xs:string,item()*)```

Params
• canvas as map(xs:string,item()*)
• algorithm-parameters as map(xs:string,item()*)
Returns
• map(xs:string,item()*)
```declare function this:rendering-parameters(
\$canvas as map(xs:string,item()*),
\$algorithm-parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
map {}
}```

```Function: algorithm-parametersdeclare function algorithm-parameters(\$resolution as xs:string, \$canvas as map(xs:string, item()*)) as map(xs:string,item()*)```

Params
• resolution as xs:string
• canvas as map(xs:string,item()*)
Returns
• map(xs:string,item()*)
```declare function this:algorithm-parameters(
\$resolution as xs:string,
\$canvas as map(xs:string, item()*)
) as map(xs:string,item()*)
{
map {
"description": "Mutation functions",
"mutation.weights": map {},
"mutation.blob": map {
"high": 0.75,
"low": 0.25,
"waves": 7
},
"mutation.PDJ": map {
"a": 0.9,
"b": 0.75,
"c": 0.9,
"d": 0.75
},
"mutation.fan2": map {
"x": 0.1,
"y": -0.1
},
"mutation.rings2": map {
"val": 0.5
},
"mutation.perspective": map {
"dist": 0.75
},
"mutation.juliaN": map {
"power": 0.5,
"dist": 0.4
},
"mutation.juliaScope": map {
"power": 0.5,
"dist": 0.4
},
},
"mutation.pie": map {
"slices": 7,
"thickness": 0.2
},
"mutation.ngon": map {
"power": 0.3,
"sides": 7,
"corners": 4,
"circle": 0.3
},
"mutation.curl": map {
"c1": 0.8,
"c2": 0.7
},
"mutation.rectangles": map {
"x": 0.25,
"y": -0.1
},
"mutation.flower": map {
"holes": 0.5,
"petals": 3
},
"mutation.supershape": map {
"holes": 0.5,
"m": 3,
"rnd": 0.5,
"n1": 20.0,
"n2": 10.0,
"n3": 10.0
},
"mutation.conic": map {
"holes": 0.5,
"eccentricity": 0.5
},
"mutation.parabola": map {
"width": 1.0,
"height": 1.0
},
"mutation.bent2": map {
"x": 2.0,
"y": 0.5,
"at": 0.0
},
"mutation.disc2": map {
"twist": 0.0,
"rot": 0.0
},
"mutation.drift": map {
"x.min": 0,
"x.max": 0.03,
"y.min": 0,
"y.max": 0.01
},
"mutation.translate": map {
"tx": 0.01,
"ty": 0.01
},
"mutation.shear": map {
"sx": 0.87,
"sy": 0.87
},
"mutation.shear-x": map {
"sx": 0.87
},
"mutation.shear-y": map {
"sy": 0.87
},
"mutation.rotate": map {
"angle": 90
},
"mutation.sinusoidal": map {
"kx": 1,
"ky": 1
},
"mutation.pillow": map {
"depth": 0.5,
"shrink": 1.0
},
"mutation.flowfield": map {
"noise": perlin:noise2-vector(perlin:context()),
"step-size": 0.05
},
"mutation.bipolar": map {
"extent": 1.0
},
"mutation.elliptic": map {
"scale": 1.0
},
"mutation.circular": map {
"scale": 1.0
},
"mutation.parabolic": map {
"scale": 1.0,
"symmetric": false()
},
"mutation.sphere": map {
}
}
}```

`Function: colophondeclare function colophon(\$parameters as map(xs:string,item()*)) as xs:string?`

colophon()
Standard component colophon

Params
• parameters as map(xs:string,item()*): active parameters for component
Returns
• xs:string?
```declare function this:colophon(\$parameters as map(xs:string,item()*)) as xs:string?
{
()
}```

```Function: metadatadeclare function metadata(\$canvas as map(xs:string,item()*), \$randomizers as map(xs:string,item()*), \$parameters as map(xs:string,item()*))```

Params
• canvas as map(xs:string,item()*): canvas component is operating over
• randomizers as map(xs:string,item()*): active randomizers for component
• parameters as map(xs:string,item()*): active parameters for component
```declare function this:metadata(
\$canvas as map(xs:string,item()*),
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
)
{
()
}```

```Function: randomizersdeclare function randomizers(\$canvas as map(xs:string,item()*), \$parameters as map(xs:string,item()*)) as map(xs:string,item()*)```

Params
• canvas as map(xs:string,item()*)
• parameters as map(xs:string,item()*)
Returns
• map(xs:string,item()*)
```declare function this:randomizers(
\$canvas as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
map {
"mutation.n-composed": dist:zipf(1.7, 3),
"mutation.mutations": dist:uniform-index-of(\$this:FOREGROUND-MUTATIONS),
(: Function parameter randomizers :)
"mutation.blob.high": dist:uniform(0.8, 1.2),
"mutation.blob.low": dist:uniform(0.2, 0.7),
"mutation.blob.waves": dist:uniform(2, 7)=>dist:cast("integer"),
"mutation.PDJ.a": dist:uniform(-3.0, 3.0),
"mutation.PDJ.b": dist:uniform(-3.0, 3.0),
"mutation.PDJ.c": dist:uniform(-3.0, 3.0),
"mutation.PDJ.d": dist:uniform(-3.0, 3.0),
"mutation.fan2.x": dist:uniform(-1.0, 1.0),
"mutation.fan2.y": dist:uniform(-1.0, 1.0),
"mutation.rings2.val": dist:uniform(0.0, 2.0),
"mutation.perspective.angle": dist:uniform(0.0, 1.0), (: radians :)
"mutation.perspective.dist": dist:uniform(1.0, 3.0),
"mutation.juliaN.power": dist:uniform(2, 7)=>dist:cast("integer"),
"mutation.juliaN.dist": dist:constant(1.0),
"mutation.juliaScope": dist:uniform(2, 7)=>dist:cast("integer"),
"mutation.juliaScope.dist": dist:constant(1.0),
"mutation.pie.slices": dist:uniform(0, 10)=>dist:cast("integer"),
"mutation.pie.rotation": dist:uniform(-2.0*math:pi(), 2.0*math:pi()), (: radians :)
"mutation.pie.thickness": dist:uniform(0.0, 1.0),
"mutation.ngon.power": dist:uniform(1.0, 4.0),
"mutation.ngon.sides": dist:uniform(3, 13)=>dist:cast("integer"),
"mutation.ngon.corners": dist:uniform(0.0, 3.0)=>dist:post-multiplier(1.5), (: should be ngon.circle value :)
"mutation.ngon.circle": dist:uniform(0.0, 3.0),
"mutation.curl.c1": dist:uniform(0.0, 1.0),
"mutation.curl.c2": dist:uniform(0.0, 1.0),
"mutation.rectangles.x": dist:uniform(0.0, 1.0),
"mutation.rectangles.y": dist:uniform(0.0, 1.0),
"mutation.supershape.holes": dist:constant(0.0),
"mutation.supershape.m": dist:uniform(0, 6)=>dist:cast("integer"),
"mutation.supershape.rnd": dist:uniform(0.0, 1.0),
"mutation.supershape.n1": dist:uniform(0.0, 40.0),
"mutation.supershape.n2": dist:uniform(0.0, 20.0),
"mutation.supershape.n3": dist:uniform(0.0, 20.0), (: really = n2 :)
"mutation.flower.holes": dist:uniform(0.0, 1.0),
"mutation.flower.petals": dist:uniform(0.0, 4.0),
"mutation.conic.holes": dist:uniform(0.0, 1.0),
"mutation.conic.eccentricity": dist:uniform(0.0, 1.0),
"mutation.parabola.height": dist:uniform(0.5, 1.5),
"mutation.parabola.width": dist:uniform(0.5, 1.5),
"mutation.bent2.at": dist:uniform(-1.0, 1.0),
"mutation.bent2.x": dist:uniform(-1.5, 1.5),
"mutation.bent2.y": dist:uniform(-1.5, 1.5),
"mutation.disc2.twist": dist:uniform(-0.5, 0.5),
"mutation.disc2.rot": dist:uniform(-0.5, 0.5),
"mutation.drift.x.min": dist:constant(0.0),
"mutation.drift.x.max": dist:uniform(0.01, 0.05),
"mutation.drift.y.min": dist:constant(0.0),
"mutation.drift.y.max": dist:uniform(0.01, 0.03),
"mutation.rotate.angle": dist:normal(90, 20)=>dist:cast("integer"), (: degrees :)
"mutation.sinusoidal.kx": dist:poisson(4.5)=>dist:min(0.5),
"mutation.sinusoidal.ky": dist:poisson(4.5)=>dist:min(0.5),
"mutation.translate.tx": dist:normal(0.0, 0.3),
"mutation.translate.ty": dist:normal(0.0, 0.3),
"mutation.shear.sx": dist:uniform(0.0, 1.5),
"mutation.shear.sy": dist:uniform(0.0, 1.5),
"mutation.shear-x.sx": dist:uniform(0.0, 1.5),
"mutation.shear-y.sy": dist:uniform(0.0, 1.5),
"mutation.pillow.depth": dist:uniform(0.25, 1.0),
"mutation.pillow.shrink": dist:uniform(1.0, 3.0),
"mutation.flowfield.step-size": dist:normal(0.05, 0.001)=>dist:min(0)=>dist:max(0.2),
"mutation.bipolar.extent": dist:uniform(1.0, 4.0),
"mutation.elliptic.scale": dist:uniform(0.5, 2.5),
"mutation.circular.scale": dist:uniform(0.5, 3.5),
"mutation.parabolic.scale": dist:uniform(0.5, 2.0),
"mutation.parabolic.symmetric": dist:flip(50),
}
}```

```Function: scaleddeclare function scaled(\$f as item(), \$canvas as map(xs:string,item()*)) as map(*)```

scaled()
Map a point on the canvas to a point in the bi-unit square, apply the
function, and map it back out. (The functions generally only work
properly on bi-unit square.)

Params
• f as item()
• canvas as map(xs:string,item()*)
Returns
• map(*)
```declare function this:scaled(
\$f as item(),
\$canvas as map(xs:string,item()*)
) as map(*)
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$width := box:width(\$canvas)
let \$height := box:height(\$canvas)
let \$fn := ann:function(\$f)
return
if (ann:is-mutation-point(\$f)) then (
ann:f("mut:scaled",
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*)
{
let \$p :=
\$fn(
point:point(
2 * (point:px(\$point) - \$width div 2) div \$width,
2 * (point:py(\$point) - \$height div 2) div \$height
)
)
return (
point:point(
\$width * (point:px(\$p) + 1) div 2,
\$height * (point:py(\$p) + 1) div 2
)=>point:snap()
)
},
\$f
)
) else (
ann:f("mut:scaled",
function(\$point as xs:double*) as xs:double*
{
let \$p :=
\$fn(
(
2 * (v:px(\$point) - \$width div 2) div \$width,
2 * (v:py(\$point) - \$height div 2) div \$height
)
)
return (
(
\$width * (v:px(\$p) + 1) div 2,
\$height * (v:py(\$p) + 1) div 2
)=>v:snap()
)
},
\$f
)
)
}```

`Function: as-pointdeclare function as-point(\$f as item()) as item()`

as-point()
Pass through to make a point-as-point function, converting from vector

• f as item()
Returns
• item()
```declare function this:as-point(
\$f as item()
) as item()
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$fn := ann:function(\$f)
return (
if (ann:is-mutation-vector(\$f)) then (
ann:f(util:function-name(\$f),
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
point:vector(\$fn(point:pcoordinates(\$point)))
}
)
) else (
\$f
)
)
}```

`Function: as-vectordeclare function as-vector(\$f as item()) as item()`

as-vector()
Pass through to make a vector-to-vector function, converting from point-to-point

• f as item()
Returns
• item()
```declare function this:as-vector(
\$f as item()
) as item()
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$fn := ann:function(\$f)
return (
if (ann:is-mutation-point(\$f)) then (
ann:f(util:function-name(\$f),
function(\$point as xs:double*) as xs:double* {
point:pcoordinates(\$fn(point:vector(\$point)))
}
)
) else (
\$f
)
)
}```

```Function: mutationdeclare function mutation(\$name as xs:string, \$parameters as map(xs:string,item()*)) as map(*)```

mutation()
Get the function definition by name, fetch its corresponding parameter
bundle from the parameters, and return the resulting function.
The function will be one of the functions in this namespace.

Params
• name as xs:string
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:mutation(
\$name as xs:string,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$as-point := ends-with(\$name,"+point")
let \$name := if (\$as-point) then substring-before(\$name,"+point") else \$name
let \$f := function-lookup(QName(\$this:URI, "this:"||\$name), 2)
let \$parms := (\$parameters("mutation."||\$name), map {})[1]
let \$weight :=
if (exists(\$parameters("mutation.weights")))
then (\$parameters("mutation.weights")(\$name), 1.0)[1]
else 1.0
return (
if (\$as-point)
then \$f(\$weight, \$parms)=>this:as-point()
else \$f(\$weight, \$parms)
)
}```

```Function: random-mutationdeclare function random-mutation(\$name as xs:string, \$randomizers as map(xs:string,item()*), \$parameters as map(xs:string,item()*)) as map(xs:string,item()*)```

mutation()
Get the function definition by name, and construct the corresponding
parameter bundle by overriding default parameters with randomized values.
Return a wrapper of the resulting function with the dynamic values.
The function will be one of the functions in this namespace.

Params
• name as xs:string
• randomizers as map(xs:string,item()*)
• parameters as map(xs:string,item()*)
Returns
• map(xs:string,item()*)
```declare function this:random-mutation(
\$name as xs:string,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let \$as-point := ends-with(\$name,"+point")
let \$name := if (\$as-point) then substring-before(\$name,"+point") else \$name
let \$f := function-lookup(QName(\$this:URI, "this:"||\$name), 2)
let \$parms :=
util:merge-into((
(\$parameters("mutation."||\$name), map{})[1],
for \$key in map:keys(\$randomizers)[starts-with(., "mutation."||\$name||".")] return (
map {
substring-after(\$key, "mutation."||\$name||"."): core:randomize(\$key, \$randomizers)
}
)
))
let \$weight :=
if (exists(\$parameters("mutation.weights")))
then (\$parameters("mutation.weights")(\$name), 1.0)[1]
else 1.0
return (
if (\$as-point)
then wrapper:wrapper(\$f(\$weight, \$parms)=>this:as-point(), \$parms)
else wrapper:wrapper(\$f(\$weight, \$parms), \$parms)
)
}```

```Function: mutationdeclare function mutation(\$name as xs:string, \$parameters as map(xs:string,item()*), \$weight as xs:double) as map(*)```

mutation()
Get the function definition by name, fetch its corresponding parameter
bundle from the parameters, and return the resulting function.
The function will be one of the functions in this namespace.
Pass in the given weight.

Params
• name as xs:string
• parameters as map(xs:string,item()*)
• weight as xs:double
Returns
• map(*)
```declare function this:mutation(
\$name as xs:string,
\$parameters as map(xs:string,item()*),
\$weight as xs:double
) as map(*)
{
let \$as-point := ends-with(\$name,"+point")
let \$name := if (\$as-point) then substring-before(\$name,"+point") else \$name
let \$f := function-lookup(QName(\$this:URI, "this:"||\$name), 2)
let \$parms := (\$parameters("mutation."||\$name), map {})[1]
return (
if (\$as-point)
then \$f(\$weight, \$parms)=>this:as-point()
else \$f(\$weight, \$parms)
)
}```

```Function: composedeclare function compose(\$f as item(), \$g as item()) as map(*)```

compose()
Apply f then apply g

• f as item()
• g as item()
Returns
• map(*)
```declare function this:compose(
\$f as item(),
\$g as item()
) as map(*)
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
if (not(ann:is-mutation(\$g))) then errors:error("ML-BADARGS", ("g", \$g)) else (),
if (ann:is-mutation-vector(\$f) and ann:is-mutation-vector(\$g)) then (
let \$fn := \$f=>ann:function()
let \$gn := \$g=>ann:function()
return (
ann:f("mut.compose",
function(\$point as xs:double*) as xs:double* {
\$fn(\$point)=>\$gn()
},
(\$f, \$g)
)
)
) else (
let \$f := this:as-point(\$f)
let \$g := this:as-point(\$g)
let \$fn := \$f=>ann:function()
let \$gn := \$g=>ann:function()
return (
ann:f("mut.compose",
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
\$fn(\$point)=>\$gn()
},
(\$f, \$g)
)
)
)
}```

`Function: composedeclare function compose(\$fs as item()*) as map(*)`

compose()
Apply functions in order

Params
• fs as item()*
Returns
• map(*)
```declare function this:compose(
\$fs as item()*
) as map(*)
{
if (some \$f in \$fs satisfies not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("fs", \$fs)) else (),
if (every \$f in \$fs satisfies ann:is-mutation-vector(\$f)) then (
let \$fns := \$fs!ann:function(.)
return (
ann:f("mut:compose",
function(\$point as xs:double*) as xs:double* {
fold-left(\$fns, \$point,
function(\$point as xs:double*, \$fn as function(*)) as xs:double*
{
\$fn(\$point)
}
)
},
\$fs
)
)
) else (
let \$fs := \$fs!this:as-point(.)
let \$fns := \$fs!ann:function(.)
return (
ann:f("mut:compose",
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
fold-left(\$fns, \$point,
function(\$point as map(xs:string,item()*), \$fn as function(*)) as map(xs:string,item()*)
{
\$fn(\$point)
}
)
},
\$fs
)
)
)
}```

```Function: mutationsdeclare function mutations(\$mutations as xs:string, \$canvas as map(xs:string,item()*)?, \$parameters as map(xs:string,item()*)) as map(*)```

mutations()
Return the composite mutation function corresponding to a compound name.
e.g. eyefish·swirl = compose(eyefish(), swirl()) with appropriate parameters
If canvas is present, scale to/from the canvas.

Params
• mutations as xs:string
• canvas as map(xs:string,item()*)?
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:mutations(
\$mutations as xs:string,
\$canvas as map(xs:string,item()*)?,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$mutation-kinds := tokenize(\$mutations, "·")[. ne '']
return (
if (\$mutations="none") then (
this:none(0, map{})
) else if (\$mutations="none+point") then (
this:none(0, map{})=>this:as-point()
) else if (empty(\$canvas)) then (
if (count(\$mutation-kinds)=1) then (
this:mutation(\$mutation-kinds, \$parameters)
) else (
this:compose(
for \$fname in \$mutation-kinds return (
this:mutation(\$fname, \$parameters)
)
)
)
) else (
this:scaled(
if (count(\$mutation-kinds)=1) then (
this:mutation(\$mutation-kinds, \$parameters)
) else (
this:compose(
for \$fname in \$mutation-kinds return (
this:mutation(\$fname, \$parameters)
)
)
)
,
\$canvas
)
)
)
}```

```Function: mutationsdeclare function mutations(\$mutations as xs:string, \$canvas as map(xs:string,item()*)?, \$randomizers as map(xs:string,item()*), \$parameters as map(xs:string,item()*)) as map(xs:string,item()*)```

mutations()
Return the composite mutation function corresponding to a compound name
in a wrapper
e.g. eyefish·swirl = compose(eyefish(), swirl()) with appropriate parameters
If canvas is present, scale to/from the canvas.
If \$mutations="random" pick a random mutation with random parameters
If \$mutations starts with "random", randomize the rest of the mutation names

Params
• mutations as xs:string
• canvas as map(xs:string,item()*)?
• randomizers as map(xs:string,item()*)
• parameters as map(xs:string,item()*)
Returns
• map(xs:string,item()*)
```declare function this:mutations(
\$mutations as xs:string,
\$canvas as map(xs:string,item()*)?,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
if (\$mutations="random") then (
this:random-random-mutations(false(), \$canvas, \$randomizers, \$parameters)
) else if (\$mutations="random+point") then (
this:random-random-mutations(true(), \$canvas, \$randomizers, \$parameters)
) else if (starts-with(\$mutations, "random·")) then (
this:random-mutations(substring-after(\$mutations, "random·"), \$canvas, \$randomizers, \$parameters)
) else (
wrapper:wrapper(
this:mutations(\$mutations, \$canvas, \$parameters),
map {}
)
)
}```

```Function: random-mutationsdeclare function random-mutations(\$mutations as xs:string, \$canvas as map(xs:string,item()*)?, \$randomizers as map(xs:string,item()*), \$parameters as map(xs:string,item()*)) as map(xs:string,item()*)```

random-mutations()
Return the composite mutation function corresponding to a compound name.
e.g. eyefish·swirl = compose(eyefish(), swirl()) with appropriate randomized
parameters
If canvas is present, scale to/from the canvas.
Returns a wrapper of the function with the dynamic values

Params
• mutations as xs:string
• canvas as map(xs:string,item()*)?
• randomizers as map(xs:string,item()*)
• parameters as map(xs:string,item()*)
Returns
• map(xs:string,item()*)
```declare function this:random-mutations(
\$mutations as xs:string,
\$canvas as map(xs:string,item()*)?,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let \$mutation-kinds := tokenize(\$mutations, "·")[. ne '']
return (
if (\$mutations="none") then (
wrapper:wrapper(
this:none(0, map{}),
map {}
)
) else if (\$mutations="none+point") then (
wrapper:wrapper(
this:none(0, map{})=>this:as-point(),
map {}
)
) else if (empty(\$canvas)) then (
if (count(\$mutation-kinds)=1) then (
this:random-mutation(\$mutation-kinds, \$randomizers, \$parameters)
) else (
let \$wrappers :=
for \$fname in \$mutation-kinds return (
this:random-mutation(\$fname, \$randomizers, \$parameters)
)
return (
wrapper:wrapper(
this:compose(for \$wrapper in \$wrappers return wrapper:body(\$wrapper)),
util:merge-into((
for \$fname at \$i in \$mutation-kinds return (
map {
"mutation."||\$fname: wrapper:dynamics(\$wrappers[\$i])
}
)
))
)
)
)
) else (
let \$wrappers :=
for \$fname in \$mutation-kinds return (
this:random-mutation(\$fname, \$randomizers, \$parameters)
)
return (
wrapper:wrapper(
this:scaled(
if (count(\$mutation-kinds)=1) then (
wrapper:body(\$wrappers)
) else (
this:compose(for \$wrapper in \$wrappers return wrapper:body(\$wrapper))
),
\$canvas
),
util:merge-into((
for \$fname at \$i in \$mutation-kinds return (
map {
"mutation."||\$fname: wrapper:dynamics(\$wrappers[\$i])
}
)
))
)
)
)
)
}```

```Function: random-random-mutationsdeclare function random-random-mutations(\$as-point as xs:boolean, \$canvas as map(xs:string,item()*)?, \$randomizers as map(xs:string,item()*), \$parameters as map(xs:string,item()*)) as map(xs:string,item()*)```

Params
• as-point as xs:boolean
• canvas as map(xs:string,item()*)?
• randomizers as map(xs:string,item()*)
• parameters as map(xs:string,item()*)
Returns
• map(xs:string,item()*)
```declare function this:random-random-mutations(
\$as-point as xs:boolean,
\$canvas as map(xs:string,item()*)?,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let \$n-composed as xs:integer := core:randomize("mutation.n-composed", \$randomizers)
let \$name as xs:string :=
(if (\$n-composed = 0) then "none" else (
string-join(
distinct-values(
core:randomize(\$n-composed, (), "mutation.mutations", \$randomizers)
), "·"
)
))||
(if (\$as-point) then "+point" else "")
return (
this:random-mutations(\$name, \$canvas, \$randomizers, \$parameters)
)
}```

`Function: tracedeclare function trace(\$f as item()) as map(*)`

trace()
Tracing pass-through for mutation function

• f as item()
Returns
• map(*)
```declare function this:trace(
\$f as item()
) as map(*)
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$fn := ann:function(\$f)
return (
if (ann:is-mutation-point(\$f)) then (
ann:f(util:function-name(\$f),
function (\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
\$fn(\$point)=>trace(util:quote(\$f)||"("||point:quote(\$point)||")")
}
)
) else (
ann:f(util:function-name(\$f),
function (\$point as xs:double*) as xs:double* {
\$fn(\$point)=>trace(util:quote(\$f)||"("||v:quote(\$point)||")")
}
)
)
)
}```

```Function: nonedeclare function none(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:none(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("no-op",
function (\$pt as xs:double*) as xs:double* {
\$pt
}
)
}```

```Function: div2declare function div2(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:div2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:div2",
function(\$pt as xs:double*) as xs:double* {
(\$weight * v:px(\$pt) div 2, \$weight * v:py(\$pt) div 2)
},
(\$weight, \$parameters)
)
}```

```Function: bump_x_div2declare function bump_x_div2(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:bump_x_div2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bump_x_div2",
function(\$pt as xs:double*) as xs:double* {
(\$weight * (v:px(\$pt)+1) div 2, \$weight * v:py(\$pt) div 2)
},
(\$weight, \$parameters)
)
}```

```Function: bump_y_div2declare function bump_y_div2(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:bump_y_div2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bump_y_div2",
function(\$pt as xs:double*) as xs:double* {
(\$weight * v:px(\$pt) div 2, \$weight * (v:py(\$pt)+1) div 2)
},
(\$weight, \$parameters)
)
}```

```Function: translatedeclare function translate(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:translate(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$tx as xs:numeric := \$parameters("tx")
let \$ty as xs:numeric := \$parameters("ty")
return (
ann:f("mut:translate",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:translation2(\$tx, \$ty))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
}```

```Function: sheardeclare function shear(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:shear(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$sx as xs:numeric := \$parameters("sx")
let \$sy as xs:numeric := \$parameters("sy")
return (
ann:f("mut:shear",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:shearing2(\$sx, \$sy))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
}```

```Function: shear-xdeclare function shear-x(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:shear-x(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$sx as xs:numeric := \$parameters("sx")
return (
ann:f("mut:shear-x",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:shearing2(\$sx, 0))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
}```

```Function: shear-ydeclare function shear-y(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:shear-y(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$sy as xs:numeric := \$parameters("sy")
return (
ann:f("mut:shear-y",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:shearing2(0, \$sy))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
}```

```Function: reflectdeclare function reflect(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:reflect(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:reflect",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:reflection2(\$point:ORIGIN))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
}```

```Function: identitydeclare function identity(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:identity(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:identity",
function(\$pt as xs:double*) as xs:double* {
\$pt=>v:times(\$weight)
},
(\$weight, \$parameters)
)
}```

```Function: rotatedeclare function rotate(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:rotate(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$angle as xs:numeric := \$parameters("angle")
return (
ann:f("mut:rotate",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:rotation2(\$angle))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
}```

```Function: sinusoidaldeclare function sinusoidal(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:sinusoidal(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$kx as xs:numeric := \$parameters("kx")
let \$ky as xs:numeric := \$parameters("ky")
return (
ann:f("mut:sinusoidal",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return (\$weight * math:sin(\$kx * \$x), \$weight * math:sin(\$ky * \$y))
},
(\$weight, \$parameters)
)
)
}```

```Function: sphericaldeclare function spherical(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:spherical(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:spherical",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
return
if (\$r2=0)
then (\$weight * \$x div (\$r2+1), \$weight * \$y div (\$r2+1))
else (\$weight * \$x div \$r2, \$weight * \$y div \$r2)
},
(\$weight, \$parameters)
)
}```

```Function: swirldeclare function swirl(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:swirl(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:swirl",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
return
(
\$weight * (\$x*math:sin(\$r2) - \$y*math:cos(\$r2)),
\$weight * (\$x*math:cos(\$r2) + \$y*math:sin(\$r2))
)
},
(\$weight, \$parameters)
)
}```

```Function: horseshoedeclare function horseshoe(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:horseshoe(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:horseshoe",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
if (\$r=0)
then (\$weight*(\$x - \$y)*(\$x + \$y) div (\$r+1), \$weight*2*\$x*\$y div (\$r+1))
else (\$weight*(\$x - \$y)*(\$x + \$y) div \$r, \$weight*2*\$x*\$y div \$r)
},
(\$weight, \$parameters)
)
}```

```Function: polardeclare function polar(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:polar(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:polar",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(\$weight * \$θ div math:pi(), \$weight * (\$r - 1))
},
(\$weight, \$parameters)
)
}```

```Function: hankerchiefdeclare function hankerchief(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:hankerchief(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:hankerchief",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(\$weight * \$r*math:sin(\$θ + \$r), \$weight * \$r*math:cos(\$θ - \$r))
},
(\$weight, \$parameters)
)
}```

```Function: heartdeclare function heart(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:heart(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:heart",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(\$weight * \$r*math:sin(\$θ*\$r), \$weight * \$r*-math:cos(\$θ*\$r))
},
(\$weight, \$parameters)
)
}```

```Function: discdeclare function disc(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:disc(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:disc",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(
\$weight * (\$θ div math:pi()) * math:sin(\$θ*\$r),
\$weight * (\$θ div math:pi()) * math:cos(\$θ*\$r)
)
},
(\$weight, \$parameters)
)
}```

```Function: spiraldeclare function spiral(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:spiral(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:spiral",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
if (\$r = 0)
then
(
\$weight * (math:cos(\$θ) + math:sin(\$r)) div (\$r+1),
\$weight * (math:sin(\$θ) - math:cos(\$r)) div (\$r+1)
)
else
(
(math:cos(\$θ) + math:sin(\$r)) div \$r,
(math:sin(\$θ) - math:cos(\$r)) div \$r
)
},
(\$weight, \$parameters)
)
}```

```Function: hyperbolicdeclare function hyperbolic(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:hyperbolic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:hyperbolic",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
if (\$r = 0)
then (\$weight * math:sin(\$θ) div (\$r + 1), \$weight * \$r * math:cos(\$θ))
else (\$weight * math:sin(\$θ) div \$r, \$weight * \$r * math:cos(\$θ))
},
(\$weight, \$parameters)
)
}```

```Function: diamonddeclare function diamond(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:diamond(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:diamond",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(
\$weight * math:sin(\$θ) * math:cos(\$r),
\$weight * math:cos(\$θ) * math:sin(\$r)
)
},
(\$weight, \$parameters)
)
}```

```Function: exdeclare function ex(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:ex(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:ex",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$p0 := math:sin(\$θ + \$r)
let \$p1 := math:cos(\$θ - \$r)
return
(
\$weight * \$r*(\$p0*\$p0*\$p0 + \$p1*\$p1*\$p1),
\$weight * \$r*(\$p0*\$p0*\$p0 - \$p1*\$p1*\$p1)
)
},
(\$weight, \$parameters)
)
}```

```Function: juliadeclare function julia(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:julia(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:julia",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$root_r := math:sqrt(math:sqrt(\$x*\$x + \$y*\$y))
let \$θ := math:atan2(\$x,\$y)
let \$Ω := if (rand:flip(50)) then 0 else math:pi()
return
(
\$weight * \$root_r * math:cos(\$θ div 2 + \$Ω),
\$weight * \$root_r * math:sin(\$θ div 2 + \$Ω)
)
},
(\$weight, \$parameters)
)
}```

```Function: bentdeclare function bent(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:bent(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bent",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return (
if (\$x ge 0 and \$y ge 0) then \$pt
else if (\$x lt 0 and \$y ge 0) then (\$weight * 2*\$x, \$weight * \$y)
else if (\$x ge 0 and \$y lt 0) then (\$weight * \$x, \$weight * \$y div 2)
else (: x lt 0 and y lt 0 :) (\$weight * 2*\$x, \$weight * \$y div 2)
)
},
(\$weight, \$parameters)
)
}```

```Function: fisheyedeclare function fisheye(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:fisheye(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:fisheye",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
(
\$weight * (2 div (\$r + 1)) * \$y,
\$weight * (2 div (\$r + 1)) * \$x
)
},
(\$weight, \$parameters)
)
}```

```Function: exponentialdeclare function exponential(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:exponential(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:exponential",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * math:exp(\$x - 1)*math:cos(math:pi()*\$y),
\$weight * math:exp(\$x - 1)*math:sin(math:pi()*\$y)
)
},
(\$weight, \$parameters)
)
}```

```Function: powerdeclare function power(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:power(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:power",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$x,\$y)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$rexp := math:pow(\$r, math:sin(\$θ))
return
(\$weight * \$rexp*math:cos(\$θ), \$weight * \$rexp*math:sin(\$θ))
},
(\$weight, \$parameters)
)
}```

```Function: cosinedeclare function cosine(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:cosine(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:cosine",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * math:cos(math:pi()*\$x)*util:cosh(\$y),
\$weight * math:sin(math:pi()*\$x)*util:sinh(\$y)
)
},
(\$weight, \$parameters)
)
}```

```Function: blobdeclare function blob(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:blob(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("high")
let \$p2 as xs:numeric := \$parameters("low")
let \$p3 as xs:numeric := \$parameters("waves")
return (
ann:f("mut:blob",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$factor := \$r*(\$p2 + ((\$p1 - \$p2) div 2)*(math:sin(\$p3*\$θ)+1))
return
(
\$weight * \$factor*math:cos(\$θ),
\$weight * \$factor*math:sin(\$θ)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: PDJdeclare function PDJ(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:PDJ(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("a")
let \$p2 as xs:numeric := \$parameters("b")
let \$p3 as xs:numeric := \$parameters("c")
let \$p4 as xs:numeric := \$parameters("d")
return (
ann:f("mut:PDJ",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * (math:sin(\$p1*\$y) - math:cos(\$p2*\$x)),
\$weight * (math:sin(\$p3*\$x) - math:cos(\$p4*\$y))
)
},
(\$weight, \$parameters)
)
)
}```

```Function: fan2declare function fan2(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:fan2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$fan2_x := \$parameters("x")
let \$p1 as xs:numeric := math:pi()*(\$fan2_x)*(\$fan2_x)
let \$p2 as xs:numeric := \$parameters("y")
return (
ann:f("mut:fan2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$t := \$θ + \$p2 - \$p1*util:trunc(2*\$θ*\$p2 div \$p1)
return
if (\$t gt \$p1 div 2) then (
(
\$weight * \$r * math:sin(\$θ - \$p1 div 2),
\$weight * \$r * math:cos(\$θ - \$p1 div 2)
)
) else (
(
\$weight * \$r * math:sin(\$θ + \$p1 div 2),
\$weight * \$r * math:cos(\$θ + \$p1 div 2)
)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: rings2declare function rings2(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:rings2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$rings2_val := \$parameters("val")
let \$p as xs:numeric := \$rings2_val*\$rings2_val
return (
ann:f("mut:rings2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$t := \$r - 2*util:trunc((\$r + \$p) div (2*\$p)) + \$r*(1-\$p)
return
(\$weight * \$t * math:sin(\$θ), \$weight * \$t * math:cos(\$θ))
},
(\$weight, \$parameters)
)
)
}```

```Function: eyefishdeclare function eyefish(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:eyefish(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:eyefish",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$factor := 2 div (\$r + 1)
return
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
},
(\$weight, \$parameters)
)
}```

```Function: bubbledeclare function bubble(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:bubble(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bubble",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
let \$factor := 4 div (\$r2 + 4)
return
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
},
(\$weight, \$parameters)
)
}```

```Function: cylinderdeclare function cylinder(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:cylinder(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:cylinder",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(\$weight * math:sin(\$x), \$weight * \$y)
},
(\$weight, \$parameters)
)
}```

```Function: perspectivedeclare function perspective(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:perspective(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("angle")
let \$p2 as xs:numeric := \$parameters("dist")
return (
ann:f("mut:perspective",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
let \$factor := \$p2 div (\$p2 - \$y*math:sin(\$p1))
return
(
\$weight * \$factor * \$x,
\$weight * \$factor * \$y * math:cos(\$p1)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: noisedeclare function noise(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:noise(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:noise",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return
(
\$weight * \$Ψ1 * \$x * math:cos(2*math:pi()*\$Ψ2),
\$weight * \$Ψ1 * \$y * math:sin(2*math:pi()*\$Ψ2)
)
},
(\$weight, \$parameters)
)
}```

```Function: juliaNdeclare function juliaN(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:juliaN(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("power")
let \$p2 as xs:numeric := \$parameters("dist")
return (
ann:f("mut:juliaN",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$p3 as xs:numeric := util:trunc(abs(\$p1)*\$Ψ)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$t := (\$φ + 2*math:pi()*\$p3) div \$p1
let \$factor := math:pow(\$r, \$p2 div \$p1)
return
(
\$weight * \$factor * math:cos(\$t),
\$weight * \$factor * math:sin(\$t)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: juliaScopedeclare function juliaScope(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:juliaScope(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("power")
let \$p2 as xs:numeric := \$parameters("dist")
return (
ann:f("mut:juliaScope",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$p3 as xs:numeric := util:trunc(abs(\$p1)*\$Ψ)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$Λ := if (rand:flip(50)) then 0 else 1
let \$t := (\$Λ*\$φ + 2*math:pi()*\$p3) div \$p1
let \$factor := math:pow(\$r, \$p2 div \$p1)
return
(
\$weight * \$factor * math:cos(\$t),
\$weight * \$factor * math:sin(\$t)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: blurdeclare function blur(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:blur(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:blur",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return
(
\$weight * \$Ψ1 * math:cos(2*math:pi()*\$Ψ2),
\$weight * \$Ψ1 * math:sin(2*math:pi()*\$Ψ2)
)
},
(\$weight, \$parameters)
)
}```

```Function: gaussiandeclare function gaussian(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:gaussian(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:gaussian",
function(\$pt as xs:double*) as xs:double* {
(: Q&D approximation for Gaussian distribution :)
let \$Ψ := for \$i in 1 to 5 return rand:uniform(0.0, 1.0)
let \$factor := sum(\$Ψ[position()<=4]) - 2
return
(
\$weight * \$factor * math:cos(2*math:pi()*\$Ψ[5]),
\$weight * \$factor * math:sin(2*math:pi()*\$Ψ[5])
)
},
(\$weight, \$parameters)
)
}```

```Function: radialBlurdeclare function radialBlur(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:radialBlur(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("angle") * (math:pi() div 2)
let \$ν36 as xs:numeric := \$weight
return (
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$Ψ := for \$i in 1 to 4 return rand:uniform(0.0, 1.0)
let \$t1 := \$ν36 * (sum(\$Ψ) - 2)
let \$t2 := \$φ + \$t1*math:sin(\$p1)
let \$t3 := \$t1 * math:cos(\$p1) - 1
return
(
\$weight * (\$r*math:cos(\$t2) + \$t3*\$x) div \$ν36,
\$weight * (\$r*math:sin(\$t2) + \$t3*\$y) div \$ν36
)
},
(\$weight, \$parameters)
)
)
}```

```Function: piedeclare function pie(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:pie(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("slices")
let \$p2 as xs:numeric := \$parameters("rotation")
let \$p3 as xs:numeric := \$parameters("thickness")
return (
ann:f("mut:pie",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
let \$Ψ3 := rand:uniform(0.0, 1.0)
let \$t1 := util:trunc(\$Ψ1*\$p1 + 0.5)
let \$t2 := \$p2 + (2*math:pi() div \$p1)*(\$t1 + \$Ψ2*\$p3)
return
(\$weight * \$Ψ3*math:cos(\$t2), \$weight * \$Ψ3*math:sin(\$t2))
},
(\$weight, \$parameters)
)
)
}```

```Function: ngondeclare function ngon(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:ngon(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("power")
let \$p2 as xs:numeric := \$parameters("sides")
let \$p3 as xs:numeric := \$parameters("corners")
let \$p4 as xs:numeric := \$parameters("circle")
return (
ann:f("mut:ngon",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$t3 := \$φ - \$p2*floor(\$φ div \$p2)
let \$t4 :=
if (\$t3 gt \$p2 div 2) then \$t3
else \$t3 - \$p2
let \$k := (\$p3 * ((1 div math:cos(\$t4)) - 1) + \$p4) div math:pow(\$r, \$p1)
return
(\$weight * \$k*\$x, \$weight * \$k*\$y)
},
(\$weight, \$parameters)
)
)
}```

```Function: curldeclare function curl(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:curl(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("c1")
let \$p2 as xs:numeric := \$parameters("c2")
return (
ann:f("mut:curl",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$t1 := 1 + \$p1*\$x + \$p2*(\$x*\$x - \$y*\$y)
let \$t2 := \$p1*\$y + 2*\$p2*\$x*\$y
let \$inv-factor := \$t1*\$t1 + \$t2*\$t2
let \$factor :=
if (\$inv-factor = 0)
then 1 div (\$inv-factor + 1)
else 1 div \$inv-factor
return
(
\$weight * \$factor*(\$x*\$t1 + \$y*\$t2),
\$weight * \$factor*(\$y*\$t1 - \$x*\$t2)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: rectanglesdeclare function rectangles(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:rectangles(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("x")
let \$p2 as xs:numeric := \$parameters("y")
return (
ann:f("mut:rectangles",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * ((2*floor(\$x div \$p1) + 1)*\$p1 - \$x),
\$weight * ((2*floor(\$y div \$p2) + 1)*\$p2 - \$y)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: supershapedeclare function supershape(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:supershape(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$holes as xs:numeric := \$parameters("holes")
let \$m as xs:numeric := \$parameters("m")
let \$n1 as xs:numeric := \$parameters("n1")
let \$n2 as xs:numeric := \$parameters("n1")
let \$n3 as xs:numeric := \$parameters("n1")
let \$rnd as xs:numeric := \$parameters("rnd")
let \$m_over_4 := \$m div 4.0
let \$neg1_over_n1 := -1.0 div \$n1
return (
ann:f("mut:supershape",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$y,\$x)
let \$α := \$m_over_4 * \$θ + math:pi() div 4.0
let \$t1 := math:pow(abs(math:sin(\$α)), \$n2)
let \$t2 := math:pow(abs(math:cos(\$α)), \$n3)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$factor := ( (\$rnd*\$Ψ1 + (1.0 - \$rnd)*\$r - \$holes) * math:pow(\$t1 + \$t2, \$neg1_over_n1) ) div \$r
return (
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: flowerdeclare function flower(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:flower(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$holes as xs:numeric := \$parameters("holes")
let \$petals as xs:numeric := \$parameters("petals")
return (
ann:f("mut:flower",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$y,\$x)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$r := \$weight * (\$Ψ1 - \$holes) * math:cos(\$petals * \$θ)
return (
(\$r * math:cos(\$θ), \$r * math:sin(\$θ))
)
},
(\$weight, \$parameters)
)
)
}```

```Function: conicdeclare function conic(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:conic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$holes as xs:numeric := \$parameters("holes")
let \$eccentricity as xs:numeric := \$parameters("eccentricity")
return (
ann:f("mut:conic",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$y,\$x)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$r := \$weight * (\$Ψ1 - \$holes) * \$eccentricity div (1 + \$eccentricity * math:cos(\$θ))
return (
(\$r * math:cos(\$θ), \$r * math:sin(\$θ))
)
},
(\$weight, \$parameters)
)
)
}```

```Function: paraboladeclare function parabola(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:parabola(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$width as xs:numeric := \$parameters("width")
let \$height as xs:numeric := \$parameters("height")
return (
ann:f("mut:parabola",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$y,\$x)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return (
(
\$weight * \$height * math:sin(\$r) * math:sin(\$r) * \$Ψ1,
\$weight * \$width * math:cos(\$r) * \$Ψ2
)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: bent2declare function bent2(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:bent2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$at as xs:numeric := \$parameters("at")
let \$bendx as xs:numeric := \$parameters("x")
let \$bendy as xs:numeric := \$parameters("y")
return (
ann:f("mut:bent2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$x := if (\$x < \$at) then \$x * \$bendx else \$x
let \$y := if (\$y < \$at) then \$y * \$bendy else \$y
return (
(\$weight * \$x, \$weight * \$y)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: archdeclare function arch(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:arch(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν41 as xs:numeric := \$weight
return (
ann:f("mut:arch",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$sin := math:sin(\$Ψ*math:pi()*\$ν41)
return
(
\$weight * \$sin,
\$weight * \$sin*\$sin div math:cos(\$Ψ*math:pi()*\$ν41)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: tangentdeclare function tangent(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:tangent(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:tangent",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
if (math:cos(\$y) = 0)
then (\$weight, \$weight * math:tan(\$y))
else (\$weight * math:sin(\$x) div math:cos(\$y), \$weight * math:tan(\$y))
},
(\$weight, \$parameters)
)
}```

```Function: squaredeclare function square(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:square(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:square",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return
(\$weight * (\$Ψ1 - 0.5), \$weight * (\$Ψ2 - 0.5))
},
(\$weight, \$parameters)
)
}```

```Function: raysdeclare function rays(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:rays(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν44 as xs:numeric := \$weight
return (
ann:f("mut:rays",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y + 1.0E-7
let \$factor := math:tan(\$Ψ*math:pi()*\$ν44) div \$r2
return
(
\$weight * \$factor*math:cos(\$x),
\$weight * \$factor*math:sin(\$y)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: bladedeclare function blade(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:blade(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν45 as xs:numeric := \$weight
return (
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
(
\$weight * (\$x*(math:cos(\$Ψ*\$r*\$ν45) + math:sin(\$Ψ*\$r*\$ν45))),
\$weight * (\$x*(math:cos(\$Ψ*\$r*\$ν45) - math:sin(\$Ψ*\$r*\$ν45)))
)
},
(\$weight, \$parameters)
)
)
}```

```Function: secantdeclare function secant(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:secant(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν46 as xs:numeric := \$weight
return (
ann:f("mut:secant",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
if (math:cos(\$r*\$ν46)=0)
then
(
\$weight * \$x,
\$weight * (1 + 1.0 div math:cos(\$r*\$ν46))
)
else
(
\$weight * \$x,
\$weight * (-1 + 1.0 div math:cos(\$r*\$ν46))
)
},
(\$weight, \$parameters)
)
)
}```

```Function: twintriandeclare function twintrian(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:twintrian(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν47 as xs:numeric := \$weight
return (
ann:f("mut:twintrian",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$t :=
math:log10(math:sin(\$Ψ*\$r*\$ν47)*math:sin(\$Ψ*\$r*\$ν47)) +
math:cos(\$Ψ*\$r*\$ν47)
return
(
\$weight * \$x * \$t,
\$weight * \$x * (\$t - math:pi()*math:sin(\$Ψ*\$r*\$ν47))
)
},
(\$weight, \$parameters)
)
)
}```

```Function: crossdeclare function cross(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:cross(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:cross",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$d := \$x*\$x - \$y*\$y
let \$factor := math:sqrt(1.0 div (\$d*\$d + 1.0E-7))
return
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
},
(\$weight, \$parameters)
)
}```

```Function: disc2declare function disc2(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:disc2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$twist as xs:numeric := \$parameters("twist")
let \$rot as xs:numeric := \$parameters("rot")
let \$pirot := \$rot * math:pi()
let \$sintwist := math:sin(\$twist)
let \$costwist := math:cos(\$twist)
let \$high := \$twist > 2*math:pi()
let \$low := \$twist < -2*math:pi()
if (\$high) then \$sintwist * (1 + \$twist - 2*math:pi())
else if (\$low) then \$sintwist * (1 + \$twist + 2*math:pi())
else \$sintwist
if (\$high) then \$costwist * (1 + \$twist - 2*math:pi())
else if (\$low) then \$costwist * (1 + \$twist + 2*math:pi())
else \$costwist
return (
ann:f("mut:disc2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$y,\$x)
let \$t := \$rot * math:pi() * (\$x + \$y)
let \$r := \$weight * \$θ div math:pi()
return
},
(\$weight, \$parameters)
)
)
}```

```Function: driftdeclare function drift(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:drift(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$dx1 as xs:numeric := \$parameters("x.min")
let \$dy1 as xs:numeric := \$parameters("y.min")
let \$dx2 as xs:numeric? := \$parameters("x.max")
let \$dy2 as xs:numeric? := \$parameters("y.max")
let \$x-range as map(xs:string,item()*) :=
if (empty(\$dx2) or \$dx1=\$dx2)
then dist:constant(\$dx1)
else dist:uniform(\$dx1, \$dx2)
let \$y-range as map(xs:string,item()*) :=
if (empty(\$dy2) or \$dy1=\$dy2)
then dist:constant(\$dy1)
else dist:uniform(\$dy1, \$dy2)
return (
ann:f("mut:drift",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt) + rand:randomize(\$x-range)
let \$y := v:py(\$pt) + rand:randomize(\$y-range)
return
(\$weight * \$x, \$weight * \$y)
},
(\$weight, \$parameters)
)
)
}```

```Function: crumpledeclare function crumple(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:crumple(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:crumple",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$rfold := abs(0.5 - \$r)
let \$θ := math:atan2(\$x,\$y)
return (
(\$weight * \$rfold * math:cos(\$θ), \$weight * \$rfold * math:sin(\$θ))
)
},
(\$weight, \$parameters)
)
}```

```Function: pillowdeclare function pillow(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:pillow(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$depth as xs:numeric := \$parameters("depth")
let \$shrink as xs:numeric := \$parameters("shrink")
let \$d2 as xs:numeric := \$depth * \$depth
return (
ann:f("mut:pillow",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := abs(\$d2 - \$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$factor := \$shrink div (\$r2 + 1)
return (
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
)
},
(\$weight, \$parameters)
)
)
}```

```Function: flowfielddeclare function flowfield(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:flowfield(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{

let \$noise as function(*) := \$parameters("noise")=>noise:as-vector()=>f:function()
let \$step as xs:numeric := \$parameters("step-size")
return (
ann:f("mut:flowfield",
function(\$pt as xs:double*) as xs:double* {
let \$θ := \$noise(\$pt) * 180 + 180
return v:destination(\$pt, \$θ, \$step)
},
(\$weight, \$parameters)
)
)
}```

```Function: bipolardeclare function bipolar(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:bipolar(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$extent := \$parameters("extent")
return
ann:f("mut:bipolar",
function(\$pt as xs:double*) as xs:double* {
let \$u := (v:px(\$pt) + 1) * math:pi() (: [-1,1]=>[0,2π) :)
let \$v := v:py(\$pt) * \$extent (: [-1,1] => [-extent,extent] :)
return coordinates:bipolar(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
}```

```Function: ellipticdeclare function elliptic(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:elliptic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$scale := \$parameters("scale")
return
ann:f("mut:elliptic",
function(\$pt as xs:double*) as xs:double* {
let \$u := (v:px(\$pt) + 1) * \$scale (: [-1,1]=>[0,\$scale] :)
let \$v := (v:py(\$pt) + 1) * math:pi() (: [-1,1]=>[0,2π] :)
return coordinates:elliptic(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
}```

```Function: circulardeclare function circular(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:circular(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$scale := \$parameters("scale")
return
ann:f("mut:circular",
function(\$pt as xs:double*) as xs:double* {
let \$u := v:px(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
let \$v := v:py(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
return coordinates:circular(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
}```

```Function: parabolicdeclare function parabolic(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:parabolic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$scale := \$parameters("scale")
let \$symmetric := \$parameters("symmetric")
return
if (\$symmetric) then (
ann:f("mut:parabolic",
function(\$pt as xs:double*) as xs:double* {
let \$u := v:px(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
let \$v := v:py(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
return coordinates:parabolic(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
) else (
ann:f("mut:parabolic",
function(\$pt as xs:double*) as xs:double* {
let \$u := (v:px(\$pt) + 1) * \$scale (: [-1,1]=>[0,\$scale] :)
let \$v := (v:py(\$pt) + 1) * \$scale (: [-1,1]=>[0,\$scale] :)
return coordinates:parabolic(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
)
}```

```Function: spheredeclare function sphere(\$weight as xs:double, \$parameters as map(xs:string,item()*)) as map(*)```

Params
• weight as xs:double
• parameters as map(xs:string,item()*)
Returns
• map(*)
```declare function this:sphere(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
return
ann:f("mut:sphere",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$latitude := math:asin(\$y div \$radius)
let \$sin-longitude := \$x div \$circle-radius
let \$longitude := math:asin(\$sin-longitude) + math:pi() div 2
return (
\$weight * \$longitude * \$radius div math:pi(), \$weight * \$y
)
},
(\$weight, \$parameters)
)
}```

Original Source Code

```xquery version "3.1";
(:~
: Mutation functions: point to point in the bi-unit square [-1,1]x[-1,1]
: The functions are set up to allow them to be selected generically from
: a mapping table (as in the fractal flame code) or applied directly.
:
: Parameters:
: Each parameterized function has a parameter with its name which is a map
: its parameters. e.g. "mutation.blob" holds parameters for the "blob" function
: See Scott Draves & Erik Reckase "The Fractal Flame Algorithm" for specifics.
: These can be used to provide default parameter settings for each function.
: In addition, the functions are given a weight parameter, which some of
: them use. In the fractal flame component this is set to the function weight
: in the selection tables. But see this:mutation() for defaulting.
:
: Randomizers:
:
: @custom:Status Stable, subject to additions
:)
module namespace this="http://mathling.com/art/mutations";

import module namespace core="http://mathling.com/art/core"
at "../art/core.xqy";
import module namespace config="http://mathling.com/core/config"
at "../core/config.xqy";
import module namespace util="http://mathling.com/core/utilities"
at "../core/utilities.xqy";
import module namespace f="http://mathling.com/core/callable"
at "../core/callable.xqy";
import module namespace rand="http://mathling.com/core/random"
at "../core/random.xqy";
import module namespace dist="http://mathling.com/type/distribution"
at "../types/distributions.xqy";
import module namespace errors="http://mathling.com/core/errors"
at "../core/errors.xqy";
import module namespace v="http://mathling.com/core/vector"
at "../core/vector.xqy";
import module namespace box="http://mathling.com/geometric/rectangle"
at "../geo/rectangle.xqy";
import module namespace wrapper="http://mathling.com/type/wrapper"
at "../types/wrapper.xqy";
import module namespace geom="http://mathling.com/geometric"
at "../geo/euclidean.xqy";
import module namespace ann="http://mathling.com/geometric/mutation"
at "../geo/mutation.xqy";
import module namespace point="http://mathling.com/geometric/point"
at "../geo/point.xqy";
import module namespace affine="http://mathling.com/geometric/affine"
at "../geo/affine.xqy";
import module namespace coordinates="http://mathling.com/geometric/coordinates"
at "../geo/coordinates.xqy";
import module namespace noise="http://mathling.com/noise/modifiers"
at "../noise/modifiers.xqy";
import module namespace perlin="http://mathling.com/noise/perlin"
at "../noise/perlin.xqy";

declare namespace art="http://mathling.com/art";

declare namespace map="http://www.w3.org/2005/xpath-functions/map";
declare namespace array="http://www.w3.org/2005/xpath-functions/array";
declare namespace math="http://www.w3.org/2005/xpath-functions/math";

declare variable \$this:URI as xs:string := "http://mathling.com/art/mutations";

declare function this:rendering-parameters(
\$canvas as map(xs:string,item()*),
\$algorithm-parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
map {}
};

declare function this:algorithm-parameters(
\$resolution as xs:string,
\$canvas as map(xs:string, item()*)
) as map(xs:string,item()*)
{
map {
"description": "Mutation functions",
"mutation.weights": map {},
"mutation.blob": map {
"high": 0.75,
"low": 0.25,
"waves": 7
},
"mutation.PDJ": map {
"a": 0.9,
"b": 0.75,
"c": 0.9,
"d": 0.75
},
"mutation.fan2": map {
"x": 0.1,
"y": -0.1
},
"mutation.rings2": map {
"val": 0.5
},
"mutation.perspective": map {
"dist": 0.75
},
"mutation.juliaN": map {
"power": 0.5,
"dist": 0.4
},
"mutation.juliaScope": map {
"power": 0.5,
"dist": 0.4
},
},
"mutation.pie": map {
"slices": 7,
"thickness": 0.2
},
"mutation.ngon": map {
"power": 0.3,
"sides": 7,
"corners": 4,
"circle": 0.3
},
"mutation.curl": map {
"c1": 0.8,
"c2": 0.7
},
"mutation.rectangles": map {
"x": 0.25,
"y": -0.1
},
"mutation.flower": map {
"holes": 0.5,
"petals": 3
},
"mutation.supershape": map {
"holes": 0.5,
"m": 3,
"rnd": 0.5,
"n1": 20.0,
"n2": 10.0,
"n3": 10.0
},
"mutation.conic": map {
"holes": 0.5,
"eccentricity": 0.5
},
"mutation.parabola": map {
"width": 1.0,
"height": 1.0
},
"mutation.bent2": map {
"x": 2.0,
"y": 0.5,
"at": 0.0
},
"mutation.disc2": map {
"twist": 0.0,
"rot": 0.0
},
"mutation.drift": map {
"x.min": 0,
"x.max": 0.03,
"y.min": 0,
"y.max": 0.01
},
"mutation.translate": map {
"tx": 0.01,
"ty": 0.01
},
"mutation.shear": map {
"sx": 0.87,
"sy": 0.87
},
"mutation.shear-x": map {
"sx": 0.87
},
"mutation.shear-y": map {
"sy": 0.87
},
"mutation.rotate": map {
"angle": 90
},
"mutation.sinusoidal": map {
"kx": 1,
"ky": 1
},
"mutation.pillow": map {
"depth": 0.5,
"shrink": 1.0
},
"mutation.flowfield": map {
"noise": perlin:noise2-vector(perlin:context()),
"step-size": 0.05
},
"mutation.bipolar": map {
"extent": 1.0
},
"mutation.elliptic": map {
"scale": 1.0
},
"mutation.circular": map {
"scale": 1.0
},
"mutation.parabolic": map {
"scale": 1.0,
"symmetric": false()
},
"mutation.sphere": map {
}
}
};

(:~
: colophon()
: Standard component colophon
:
: @param \$parameters: active parameters for component
:)
declare function this:colophon(\$parameters as map(xs:string,item()*)) as xs:string?
{
()
};

(:~
:
: @param \$canvas: canvas component is operating over
: @param \$randomizers: active randomizers for component
: @param \$parameters: active parameters for component
:)
\$canvas as map(xs:string,item()*),
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
)
{
()
};

declare variable \$this:MUTATIONS as xs:string* := (
"div2", "bump_x_div2", "bump_y_div2", "translate",
"shear", "shear-x", "shear-y", "reflect", "identity", "rotate",
"sinusoidal", "spherical", "swirl", "horseshoe", "polar", "hankerchief",
"heart", "disc", "spiral", "hyperbolic", "diamond", "ex", "julia", "bent",
"fisheye", "exponential", "power", "cosine", "blob", "PDJ", "fan2",
"rings2", "eyefish", "bubble", "cylinder", "perspective", "noise", "juliaN",
"juliaScope", "blur", "gaussian", "radialBlur", "pie", "ngon", "curl",
"rectangles", "supershape", "flower", "conic", "parabola", "bent2", "arch",
"tangent", "square", "rays", "blade", "secant", "twintrian", "cross",
"disc2", "drift", "crumple", "pillow", "flowfield",
"bipolar", "elliptic", "circular", "parabolic", "sphere"
);

declare variable \$this:FOREGROUND-MUTATIONS as xs:string* := (
"div2", "bump_x_div2", "bump_y_div2",
"shear", "shear-x", "shear-y", "reflect", "identity", "rotate",
"sinusoidal", "spherical", "swirl", "horseshoe", "polar", "hankerchief",
"heart", "disc", "spiral", "hyperbolic", "diamond", "ex", "bent",
"fisheye", "exponential", "power", "cosine", "blob", "PDJ", "fan2",
"rings2", "eyefish", "bubble", "cylinder", "perspective", "ngon", "curl",
"rectangles", "bent2",
"tangent", "secant", "cross",
"drift", "crumple", "pillow", "flowfield",
"bipolar", "elliptic", "circular", "sphere"
);

declare variable \$this:BACKGROUND-MUTATIONS as xs:string* := (
"julia", "juliaN", "flower", "conic", "parabola", "noise",
"juliaScope", "blur", "gaussian", "radialBlur", "pie", "supershape", "arch",
"square", "blade",  "rays", "twintrian", "disc2", "translate", "parabolic"
);

declare function this:randomizers(
\$canvas as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
map {
"mutation.n-composed": dist:zipf(1.7, 3),
"mutation.mutations": dist:uniform-index-of(\$this:FOREGROUND-MUTATIONS),
(: Function parameter randomizers :)
"mutation.blob.high": dist:uniform(0.8, 1.2),
"mutation.blob.low": dist:uniform(0.2, 0.7),
"mutation.blob.waves": dist:uniform(2, 7)=>dist:cast("integer"),
"mutation.PDJ.a": dist:uniform(-3.0, 3.0),
"mutation.PDJ.b": dist:uniform(-3.0, 3.0),
"mutation.PDJ.c": dist:uniform(-3.0, 3.0),
"mutation.PDJ.d": dist:uniform(-3.0, 3.0),
"mutation.fan2.x": dist:uniform(-1.0, 1.0),
"mutation.fan2.y": dist:uniform(-1.0, 1.0),
"mutation.rings2.val": dist:uniform(0.0, 2.0),
"mutation.perspective.angle": dist:uniform(0.0, 1.0), (: radians :)
"mutation.perspective.dist": dist:uniform(1.0, 3.0),
"mutation.juliaN.power": dist:uniform(2, 7)=>dist:cast("integer"),
"mutation.juliaN.dist": dist:constant(1.0),
"mutation.juliaScope": dist:uniform(2, 7)=>dist:cast("integer"),
"mutation.juliaScope.dist": dist:constant(1.0),
"mutation.pie.slices": dist:uniform(0, 10)=>dist:cast("integer"),
"mutation.pie.rotation": dist:uniform(-2.0*math:pi(), 2.0*math:pi()), (: radians :)
"mutation.pie.thickness": dist:uniform(0.0, 1.0),
"mutation.ngon.power": dist:uniform(1.0, 4.0),
"mutation.ngon.sides": dist:uniform(3, 13)=>dist:cast("integer"),
"mutation.ngon.corners": dist:uniform(0.0, 3.0)=>dist:post-multiplier(1.5), (: should be ngon.circle value :)
"mutation.ngon.circle": dist:uniform(0.0, 3.0),
"mutation.curl.c1": dist:uniform(0.0, 1.0),
"mutation.curl.c2": dist:uniform(0.0, 1.0),
"mutation.rectangles.x": dist:uniform(0.0, 1.0),
"mutation.rectangles.y": dist:uniform(0.0, 1.0),
"mutation.supershape.holes": dist:constant(0.0),
"mutation.supershape.m": dist:uniform(0, 6)=>dist:cast("integer"),
"mutation.supershape.rnd": dist:uniform(0.0, 1.0),
"mutation.supershape.n1": dist:uniform(0.0, 40.0),
"mutation.supershape.n2": dist:uniform(0.0, 20.0),
"mutation.supershape.n3": dist:uniform(0.0, 20.0), (: really = n2 :)
"mutation.flower.holes": dist:uniform(0.0, 1.0),
"mutation.flower.petals": dist:uniform(0.0, 4.0),
"mutation.conic.holes": dist:uniform(0.0, 1.0),
"mutation.conic.eccentricity": dist:uniform(0.0, 1.0),
"mutation.parabola.height": dist:uniform(0.5, 1.5),
"mutation.parabola.width": dist:uniform(0.5, 1.5),
"mutation.bent2.at": dist:uniform(-1.0, 1.0),
"mutation.bent2.x": dist:uniform(-1.5, 1.5),
"mutation.bent2.y": dist:uniform(-1.5, 1.5),
"mutation.disc2.twist": dist:uniform(-0.5, 0.5),
"mutation.disc2.rot": dist:uniform(-0.5, 0.5),
"mutation.drift.x.min": dist:constant(0.0),
"mutation.drift.x.max": dist:uniform(0.01, 0.05),
"mutation.drift.y.min": dist:constant(0.0),
"mutation.drift.y.max": dist:uniform(0.01, 0.03),
"mutation.rotate.angle": dist:normal(90, 20)=>dist:cast("integer"), (: degrees :)
"mutation.sinusoidal.kx": dist:poisson(4.5)=>dist:min(0.5),
"mutation.sinusoidal.ky": dist:poisson(4.5)=>dist:min(0.5),
"mutation.translate.tx": dist:normal(0.0, 0.3),
"mutation.translate.ty": dist:normal(0.0, 0.3),
"mutation.shear.sx": dist:uniform(0.0, 1.5),
"mutation.shear.sy": dist:uniform(0.0, 1.5),
"mutation.shear-x.sx": dist:uniform(0.0, 1.5),
"mutation.shear-y.sy": dist:uniform(0.0, 1.5),
"mutation.pillow.depth": dist:uniform(0.25, 1.0),
"mutation.pillow.shrink": dist:uniform(1.0, 3.0),
"mutation.flowfield.step-size": dist:normal(0.05, 0.001)=>dist:min(0)=>dist:max(0.2),
"mutation.bipolar.extent": dist:uniform(1.0, 4.0),
"mutation.elliptic.scale": dist:uniform(0.5, 2.5),
"mutation.circular.scale": dist:uniform(0.5, 3.5),
"mutation.parabolic.scale": dist:uniform(0.5, 2.0),
"mutation.parabolic.symmetric": dist:flip(50),
}
};

(:~
: scaled()
: Map a point on the canvas to a point in the bi-unit square, apply the
: function, and map it back out. (The functions generally only work
: properly on bi-unit square.)
:)
declare function this:scaled(
\$f as item(),
\$canvas as map(xs:string,item()*)
) as map(*)
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$width := box:width(\$canvas)
let \$height := box:height(\$canvas)
let \$fn := ann:function(\$f)
return
if (ann:is-mutation-point(\$f)) then (
ann:f("mut:scaled",
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*)
{
let \$p :=
\$fn(
point:point(
2 * (point:px(\$point) - \$width div 2) div \$width,
2 * (point:py(\$point) - \$height div 2) div \$height
)
)
return (
point:point(
\$width * (point:px(\$p) + 1) div 2,
\$height * (point:py(\$p) + 1) div 2
)=>point:snap()
)
},
\$f
)
) else (
ann:f("mut:scaled",
function(\$point as xs:double*) as xs:double*
{
let \$p :=
\$fn(
(
2 * (v:px(\$point) - \$width div 2) div \$width,
2 * (v:py(\$point) - \$height div 2) div \$height
)
)
return (
(
\$width * (v:px(\$p) + 1) div 2,
\$height * (v:py(\$p) + 1) div 2
)=>v:snap()
)
},
\$f
)
)
};

(:~
: as-point()
: Pass through to make a point-as-point function, converting from vector
:)
declare function this:as-point(
\$f as item()
) as item()
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$fn := ann:function(\$f)
return (
if (ann:is-mutation-vector(\$f)) then (
ann:f(util:function-name(\$f),
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
point:vector(\$fn(point:pcoordinates(\$point)))
}
)
) else (
\$f
)
)
};

(:~
: as-vector()
: Pass through to make a vector-to-vector function, converting from point-to-point
:)
declare function this:as-vector(
\$f as item()
) as item()
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$fn := ann:function(\$f)
return (
if (ann:is-mutation-point(\$f)) then (
ann:f(util:function-name(\$f),
function(\$point as xs:double*) as xs:double* {
point:pcoordinates(\$fn(point:vector(\$point)))
}
)
) else (
\$f
)
)
};

(:~
: mutation()
: Get the function definition by name, fetch its corresponding parameter
: bundle from the parameters, and return the resulting function.
: The function will be one of the functions in this namespace.
:)
declare function this:mutation(
\$name as xs:string,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$as-point := ends-with(\$name,"+point")
let \$name := if (\$as-point) then substring-before(\$name,"+point") else \$name
let \$f := function-lookup(QName(\$this:URI, "this:"||\$name), 2)
let \$parms := (\$parameters("mutation."||\$name), map {})[1]
let \$weight :=
if (exists(\$parameters("mutation.weights")))
then (\$parameters("mutation.weights")(\$name), 1.0)[1]
else 1.0
return (
if (\$as-point)
then \$f(\$weight, \$parms)=>this:as-point()
else \$f(\$weight, \$parms)
)
};

(:~
: mutation()
: Get the function definition by name, and construct the corresponding
: parameter bundle by overriding default parameters with randomized values.
: Return a wrapper of the resulting function with the dynamic values.
: The function will be one of the functions in this namespace.
:)
declare function this:random-mutation(
\$name as xs:string,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let \$as-point := ends-with(\$name,"+point")
let \$name := if (\$as-point) then substring-before(\$name,"+point") else \$name
let \$f := function-lookup(QName(\$this:URI, "this:"||\$name), 2)
let \$parms :=
util:merge-into((
(\$parameters("mutation."||\$name), map{})[1],
for \$key in map:keys(\$randomizers)[starts-with(., "mutation."||\$name||".")] return (
map {
substring-after(\$key, "mutation."||\$name||"."): core:randomize(\$key, \$randomizers)
}
)
))
let \$weight :=
if (exists(\$parameters("mutation.weights")))
then (\$parameters("mutation.weights")(\$name), 1.0)[1]
else 1.0
return (
if (\$as-point)
then wrapper:wrapper(\$f(\$weight, \$parms)=>this:as-point(), \$parms)
else wrapper:wrapper(\$f(\$weight, \$parms), \$parms)
)
};

(:~
: mutation()
: Get the function definition by name, fetch its corresponding parameter
: bundle from the parameters, and return the resulting function.
: The function will be one of the functions in this namespace.
: Pass in the given weight.
:)
declare function this:mutation(
\$name as xs:string,
\$parameters as map(xs:string,item()*),
\$weight as xs:double
) as map(*)
{
let \$as-point := ends-with(\$name,"+point")
let \$name := if (\$as-point) then substring-before(\$name,"+point") else \$name
let \$f := function-lookup(QName(\$this:URI, "this:"||\$name), 2)
let \$parms := (\$parameters("mutation."||\$name), map {})[1]
return (
if (\$as-point)
then \$f(\$weight, \$parms)=>this:as-point()
else \$f(\$weight, \$parms)
)
};

(:~
: compose()
: Apply f then apply g
:)
declare function this:compose(
\$f as item(),
\$g as item()
) as map(*)
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
if (not(ann:is-mutation(\$g))) then errors:error("ML-BADARGS", ("g", \$g)) else (),
if (ann:is-mutation-vector(\$f) and ann:is-mutation-vector(\$g)) then (
let \$fn := \$f=>ann:function()
let \$gn := \$g=>ann:function()
return (
ann:f("mut.compose",
function(\$point as xs:double*) as xs:double* {
\$fn(\$point)=>\$gn()
},
(\$f, \$g)
)
)
) else (
let \$f := this:as-point(\$f)
let \$g := this:as-point(\$g)
let \$fn := \$f=>ann:function()
let \$gn := \$g=>ann:function()
return (
ann:f("mut.compose",
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
\$fn(\$point)=>\$gn()
},
(\$f, \$g)
)
)
)
};

(:~
: compose()
: Apply functions in order
:)
declare function this:compose(
\$fs as item()*
) as map(*)
{
if (some \$f in \$fs satisfies not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("fs", \$fs)) else (),
if (every \$f in \$fs satisfies ann:is-mutation-vector(\$f)) then (
let \$fns := \$fs!ann:function(.)
return (
ann:f("mut:compose",
function(\$point as xs:double*) as xs:double* {
fold-left(\$fns, \$point,
function(\$point as xs:double*, \$fn as function(*)) as xs:double*
{
\$fn(\$point)
}
)
},
\$fs
)
)
) else (
let \$fs := \$fs!this:as-point(.)
let \$fns := \$fs!ann:function(.)
return (
ann:f("mut:compose",
function(\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
fold-left(\$fns, \$point,
function(\$point as map(xs:string,item()*), \$fn as function(*)) as map(xs:string,item()*)
{
\$fn(\$point)
}
)
},
\$fs
)
)
)
};

(:~
: mutations()
: Return the composite mutation function corresponding to a compound name.
: e.g. eyefish·swirl = compose(eyefish(), swirl()) with appropriate parameters
: If canvas is present, scale to/from the canvas.
:)
declare function this:mutations(
\$mutations as xs:string,
\$canvas as map(xs:string,item()*)?,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$mutation-kinds := tokenize(\$mutations, "·")[. ne '']
return (
if (\$mutations="none") then (
this:none(0, map{})
) else if (\$mutations="none+point") then (
this:none(0, map{})=>this:as-point()
) else if (empty(\$canvas)) then (
if (count(\$mutation-kinds)=1) then (
this:mutation(\$mutation-kinds, \$parameters)
) else (
this:compose(
for \$fname in \$mutation-kinds return (
this:mutation(\$fname, \$parameters)
)
)
)
) else (
this:scaled(
if (count(\$mutation-kinds)=1) then (
this:mutation(\$mutation-kinds, \$parameters)
) else (
this:compose(
for \$fname in \$mutation-kinds return (
this:mutation(\$fname, \$parameters)
)
)
)
,
\$canvas
)
)
)
};

(:~
: mutations()
: Return the composite mutation function corresponding to a compound name
: in a wrapper
: e.g. eyefish·swirl = compose(eyefish(), swirl()) with appropriate parameters
: If canvas is present, scale to/from the canvas.
: If \$mutations="random" pick a random mutation with random parameters
: If \$mutations starts with "random", randomize the rest of the mutation names
:)
declare function this:mutations(
\$mutations as xs:string,
\$canvas as map(xs:string,item()*)?,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
if (\$mutations="random") then (
this:random-random-mutations(false(), \$canvas, \$randomizers, \$parameters)
) else if (\$mutations="random+point") then (
this:random-random-mutations(true(), \$canvas, \$randomizers, \$parameters)
) else if (starts-with(\$mutations, "random·")) then (
this:random-mutations(substring-after(\$mutations, "random·"), \$canvas, \$randomizers, \$parameters)
) else (
wrapper:wrapper(
this:mutations(\$mutations, \$canvas, \$parameters),
map {}
)
)
};

(:~
: random-mutations()
: Return the composite mutation function corresponding to a compound name.
: e.g. eyefish·swirl = compose(eyefish(), swirl()) with appropriate randomized
: parameters
: If canvas is present, scale to/from the canvas.
: Returns a wrapper of the function with the dynamic values
:)
declare function this:random-mutations(
\$mutations as xs:string,
\$canvas as map(xs:string,item()*)?,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let \$mutation-kinds := tokenize(\$mutations, "·")[. ne '']
return (
if (\$mutations="none") then (
wrapper:wrapper(
this:none(0, map{}),
map {}
)
) else if (\$mutations="none+point") then (
wrapper:wrapper(
this:none(0, map{})=>this:as-point(),
map {}
)
) else if (empty(\$canvas)) then (
if (count(\$mutation-kinds)=1) then (
this:random-mutation(\$mutation-kinds, \$randomizers, \$parameters)
) else (
let \$wrappers :=
for \$fname in \$mutation-kinds return (
this:random-mutation(\$fname, \$randomizers, \$parameters)
)
return (
wrapper:wrapper(
this:compose(for \$wrapper in \$wrappers return wrapper:body(\$wrapper)),
util:merge-into((
for \$fname at \$i in \$mutation-kinds return (
map {
"mutation."||\$fname: wrapper:dynamics(\$wrappers[\$i])
}
)
))
)
)
)
) else (
let \$wrappers :=
for \$fname in \$mutation-kinds return (
this:random-mutation(\$fname, \$randomizers, \$parameters)
)
return (
wrapper:wrapper(
this:scaled(
if (count(\$mutation-kinds)=1) then (
wrapper:body(\$wrappers)
) else (
this:compose(for \$wrapper in \$wrappers return wrapper:body(\$wrapper))
),
\$canvas
),
util:merge-into((
for \$fname at \$i in \$mutation-kinds return (
map {
"mutation."||\$fname: wrapper:dynamics(\$wrappers[\$i])
}
)
))
)
)
)
)
};

declare function this:random-random-mutations(
\$as-point as xs:boolean,
\$canvas as map(xs:string,item()*)?,
\$randomizers as map(xs:string,item()*),
\$parameters as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let \$n-composed as xs:integer := core:randomize("mutation.n-composed", \$randomizers)
let \$name as xs:string :=
(if (\$n-composed = 0) then "none" else (
string-join(
distinct-values(
core:randomize(\$n-composed, (), "mutation.mutations", \$randomizers)
), "·"
)
))||
(if (\$as-point) then "+point" else "")
return (
this:random-mutations(\$name, \$canvas, \$randomizers, \$parameters)
)
};

(:~
: trace()
: Tracing pass-through for mutation function
:)
declare function this:trace(
\$f as item()
) as map(*)
{
if (not(ann:is-mutation(\$f))) then errors:error("ML-BADARGS", ("f", \$f)) else (),
let \$fn := ann:function(\$f)
return (
if (ann:is-mutation-point(\$f)) then (
ann:f(util:function-name(\$f),
function (\$point as map(xs:string,item()*)) as map(xs:string,item()*) {
\$fn(\$point)=>trace(util:quote(\$f)||"("||point:quote(\$point)||")")
}
)
) else (
ann:f(util:function-name(\$f),
function (\$point as xs:double*) as xs:double* {
\$fn(\$point)=>trace(util:quote(\$f)||"("||v:quote(\$point)||")")
}
)
)
)
};

(:======================================================================:
: Specific mutation functions
:======================================================================:)

declare function this:none(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("no-op",
function (\$pt as xs:double*) as xs:double* {
\$pt
}
)
};

(:
: Notation conventions:
: r = √x²+y²
: θ = arctan(x/y)
: φ = arctan(y/x)
: Ψ = rand(uniform(0,1))
: Ω = rand(0|π)
: Λ = rand(0|1)
: Not handling dependent/parametric variations right now
:)

declare function this:div2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:div2",
function(\$pt as xs:double*) as xs:double* {
(\$weight * v:px(\$pt) div 2, \$weight * v:py(\$pt) div 2)
},
(\$weight, \$parameters)
)
};

declare function this:bump_x_div2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bump_x_div2",
function(\$pt as xs:double*) as xs:double* {
(\$weight * (v:px(\$pt)+1) div 2, \$weight * v:py(\$pt) div 2)
},
(\$weight, \$parameters)
)
};

declare function this:bump_y_div2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bump_y_div2",
function(\$pt as xs:double*) as xs:double* {
(\$weight * v:px(\$pt) div 2, \$weight * (v:py(\$pt)+1) div 2)
},
(\$weight, \$parameters)
)
};

declare function this:translate(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$tx as xs:numeric := \$parameters("tx")
let \$ty as xs:numeric := \$parameters("ty")
return (
ann:f("mut:translate",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:translation2(\$tx, \$ty))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
};

declare function this:shear(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$sx as xs:numeric := \$parameters("sx")
let \$sy as xs:numeric := \$parameters("sy")
return (
ann:f("mut:shear",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:shearing2(\$sx, \$sy))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
};

declare function this:shear-x(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$sx as xs:numeric := \$parameters("sx")
return (
ann:f("mut:shear-x",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:shearing2(\$sx, 0))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
};

declare function this:shear-y(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$sy as xs:numeric := \$parameters("sy")
return (
ann:f("mut:shear-y",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:shearing2(0, \$sy))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
};

declare function this:reflect(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:reflect",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:reflection2(\$point:ORIGIN))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
};

declare function this:identity(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:identity",
function(\$pt as xs:double*) as xs:double* {
\$pt=>v:times(\$weight)
},
(\$weight, \$parameters)
)
};

declare function this:rotate(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$angle as xs:numeric := \$parameters("angle")
return (
ann:f("mut:rotate",
function(\$pt as xs:double*) as xs:double* {
\$pt=>affine:affine2(affine:rotation2(\$angle))=>v:times(\$weight)
},
(\$weight, \$parameters)
)
)
};

declare function this:sinusoidal(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$kx as xs:numeric := \$parameters("kx")
let \$ky as xs:numeric := \$parameters("ky")
return (
ann:f("mut:sinusoidal",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return (\$weight * math:sin(\$kx * \$x), \$weight * math:sin(\$ky * \$y))
},
(\$weight, \$parameters)
)
)
};

declare function this:spherical(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:spherical",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
return
if (\$r2=0)
then (\$weight * \$x div (\$r2+1), \$weight * \$y div (\$r2+1))
else (\$weight * \$x div \$r2, \$weight * \$y div \$r2)
},
(\$weight, \$parameters)
)
};

declare function this:swirl(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:swirl",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
return
(
\$weight * (\$x*math:sin(\$r2) - \$y*math:cos(\$r2)),
\$weight * (\$x*math:cos(\$r2) + \$y*math:sin(\$r2))
)
},
(\$weight, \$parameters)
)
};

declare function this:horseshoe(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:horseshoe",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
if (\$r=0)
then (\$weight*(\$x - \$y)*(\$x + \$y) div (\$r+1), \$weight*2*\$x*\$y div (\$r+1))
else (\$weight*(\$x - \$y)*(\$x + \$y) div \$r, \$weight*2*\$x*\$y div \$r)
},
(\$weight, \$parameters)
)
};

declare function this:polar(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:polar",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(\$weight * \$θ div math:pi(), \$weight * (\$r - 1))
},
(\$weight, \$parameters)
)
};

declare function this:hankerchief(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:hankerchief",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(\$weight * \$r*math:sin(\$θ + \$r), \$weight * \$r*math:cos(\$θ - \$r))
},
(\$weight, \$parameters)
)
};

declare function this:heart(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:heart",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(\$weight * \$r*math:sin(\$θ*\$r), \$weight * \$r*-math:cos(\$θ*\$r))
},
(\$weight, \$parameters)
)
};

declare function this:disc(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:disc",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(
\$weight * (\$θ div math:pi()) * math:sin(\$θ*\$r),
\$weight * (\$θ div math:pi()) * math:cos(\$θ*\$r)
)
},
(\$weight, \$parameters)
)
};

declare function this:spiral(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:spiral",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
if (\$r = 0)
then
(
\$weight * (math:cos(\$θ) + math:sin(\$r)) div (\$r+1),
\$weight * (math:sin(\$θ) - math:cos(\$r)) div (\$r+1)
)
else
(
(math:cos(\$θ) + math:sin(\$r)) div \$r,
(math:sin(\$θ) - math:cos(\$r)) div \$r
)
},
(\$weight, \$parameters)
)
};

declare function this:hyperbolic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:hyperbolic",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
if (\$r = 0)
then (\$weight * math:sin(\$θ) div (\$r + 1), \$weight * \$r * math:cos(\$θ))
else (\$weight * math:sin(\$θ) div \$r, \$weight * \$r * math:cos(\$θ))
},
(\$weight, \$parameters)
)
};

declare function this:diamond(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:diamond",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
return
(
\$weight * math:sin(\$θ) * math:cos(\$r),
\$weight * math:cos(\$θ) * math:sin(\$r)
)
},
(\$weight, \$parameters)
)
};

declare function this:ex(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:ex",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$p0 := math:sin(\$θ + \$r)
let \$p1 := math:cos(\$θ - \$r)
return
(
\$weight * \$r*(\$p0*\$p0*\$p0 + \$p1*\$p1*\$p1),
\$weight * \$r*(\$p0*\$p0*\$p0 - \$p1*\$p1*\$p1)
)
},
(\$weight, \$parameters)
)
};

declare function this:julia(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:julia",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$root_r := math:sqrt(math:sqrt(\$x*\$x + \$y*\$y))
let \$θ := math:atan2(\$x,\$y)
let \$Ω := if (rand:flip(50)) then 0 else math:pi()
return
(
\$weight * \$root_r * math:cos(\$θ div 2 + \$Ω),
\$weight * \$root_r * math:sin(\$θ div 2 + \$Ω)
)
},
(\$weight, \$parameters)
)
};

declare function this:bent(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bent",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return (
if (\$x ge 0 and \$y ge 0) then \$pt
else if (\$x lt 0 and \$y ge 0) then (\$weight * 2*\$x, \$weight * \$y)
else if (\$x ge 0 and \$y lt 0) then (\$weight * \$x, \$weight * \$y div 2)
else (: x lt 0 and y lt 0 :) (\$weight * 2*\$x, \$weight * \$y div 2)
)
},
(\$weight, \$parameters)
)
};

declare function this:fisheye(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:fisheye",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
(
\$weight * (2 div (\$r + 1)) * \$y,
\$weight * (2 div (\$r + 1)) * \$x
)
},
(\$weight, \$parameters)
)
};

declare function this:exponential(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:exponential",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * math:exp(\$x - 1)*math:cos(math:pi()*\$y),
\$weight * math:exp(\$x - 1)*math:sin(math:pi()*\$y)
)
},
(\$weight, \$parameters)
)
};

declare function this:power(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:power",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$x,\$y)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$rexp := math:pow(\$r, math:sin(\$θ))
return
(\$weight * \$rexp*math:cos(\$θ), \$weight * \$rexp*math:sin(\$θ))
},
(\$weight, \$parameters)
)
};

declare function this:cosine(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:cosine",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * math:cos(math:pi()*\$x)*util:cosh(\$y),
\$weight * math:sin(math:pi()*\$x)*util:sinh(\$y)
)
},
(\$weight, \$parameters)
)
};

declare function this:blob(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("high")
let \$p2 as xs:numeric := \$parameters("low")
let \$p3 as xs:numeric := \$parameters("waves")
return (
ann:f("mut:blob",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$factor := \$r*(\$p2 + ((\$p1 - \$p2) div 2)*(math:sin(\$p3*\$θ)+1))
return
(
\$weight * \$factor*math:cos(\$θ),
\$weight * \$factor*math:sin(\$θ)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:PDJ(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("a")
let \$p2 as xs:numeric := \$parameters("b")
let \$p3 as xs:numeric := \$parameters("c")
let \$p4 as xs:numeric := \$parameters("d")
return (
ann:f("mut:PDJ",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * (math:sin(\$p1*\$y) - math:cos(\$p2*\$x)),
\$weight * (math:sin(\$p3*\$x) - math:cos(\$p4*\$y))
)
},
(\$weight, \$parameters)
)
)
};

declare function this:fan2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$fan2_x := \$parameters("x")
let \$p1 as xs:numeric := math:pi()*(\$fan2_x)*(\$fan2_x)
let \$p2 as xs:numeric := \$parameters("y")
return (
ann:f("mut:fan2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$t := \$θ + \$p2 - \$p1*util:trunc(2*\$θ*\$p2 div \$p1)
return
if (\$t gt \$p1 div 2) then (
(
\$weight * \$r * math:sin(\$θ - \$p1 div 2),
\$weight * \$r * math:cos(\$θ - \$p1 div 2)
)
) else (
(
\$weight * \$r * math:sin(\$θ + \$p1 div 2),
\$weight * \$r * math:cos(\$θ + \$p1 div 2)
)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:rings2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$rings2_val := \$parameters("val")
let \$p as xs:numeric := \$rings2_val*\$rings2_val
return (
ann:f("mut:rings2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$t := \$r - 2*util:trunc((\$r + \$p) div (2*\$p)) + \$r*(1-\$p)
return
(\$weight * \$t * math:sin(\$θ), \$weight * \$t * math:cos(\$θ))
},
(\$weight, \$parameters)
)
)
};

declare function this:eyefish(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:eyefish",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$factor := 2 div (\$r + 1)
return
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
},
(\$weight, \$parameters)
)
};

declare function this:bubble(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:bubble",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
let \$factor := 4 div (\$r2 + 4)
return
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
},
(\$weight, \$parameters)
)
};

declare function this:cylinder(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:cylinder",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(\$weight * math:sin(\$x), \$weight * \$y)
},
(\$weight, \$parameters)
)
};

declare function this:perspective(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("angle")
let \$p2 as xs:numeric := \$parameters("dist")
return (
ann:f("mut:perspective",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y
let \$factor := \$p2 div (\$p2 - \$y*math:sin(\$p1))
return
(
\$weight * \$factor * \$x,
\$weight * \$factor * \$y * math:cos(\$p1)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:noise(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:noise",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return
(
\$weight * \$Ψ1 * \$x * math:cos(2*math:pi()*\$Ψ2),
\$weight * \$Ψ1 * \$y * math:sin(2*math:pi()*\$Ψ2)
)
},
(\$weight, \$parameters)
)
};

declare function this:juliaN(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("power")
let \$p2 as xs:numeric := \$parameters("dist")
return (
ann:f("mut:juliaN",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$p3 as xs:numeric := util:trunc(abs(\$p1)*\$Ψ)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$t := (\$φ + 2*math:pi()*\$p3) div \$p1
let \$factor := math:pow(\$r, \$p2 div \$p1)
return
(
\$weight * \$factor * math:cos(\$t),
\$weight * \$factor * math:sin(\$t)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:juliaScope(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("power")
let \$p2 as xs:numeric := \$parameters("dist")
return (
ann:f("mut:juliaScope",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$p3 as xs:numeric := util:trunc(abs(\$p1)*\$Ψ)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$Λ := if (rand:flip(50)) then 0 else 1
let \$t := (\$Λ*\$φ + 2*math:pi()*\$p3) div \$p1
let \$factor := math:pow(\$r, \$p2 div \$p1)
return
(
\$weight * \$factor * math:cos(\$t),
\$weight * \$factor * math:sin(\$t)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:blur(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:blur",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return
(
\$weight * \$Ψ1 * math:cos(2*math:pi()*\$Ψ2),
\$weight * \$Ψ1 * math:sin(2*math:pi()*\$Ψ2)
)
},
(\$weight, \$parameters)
)
};

declare function this:gaussian(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:gaussian",
function(\$pt as xs:double*) as xs:double* {
(: Q&D approximation for Gaussian distribution :)
let \$Ψ := for \$i in 1 to 5 return rand:uniform(0.0, 1.0)
let \$factor := sum(\$Ψ[position()<=4]) - 2
return
(
\$weight * \$factor * math:cos(2*math:pi()*\$Ψ[5]),
\$weight * \$factor * math:sin(2*math:pi()*\$Ψ[5])
)
},
(\$weight, \$parameters)
)
};

\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("angle") * (math:pi() div 2)
let \$ν36 as xs:numeric := \$weight
return (
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$Ψ := for \$i in 1 to 4 return rand:uniform(0.0, 1.0)
let \$t1 := \$ν36 * (sum(\$Ψ) - 2)
let \$t2 := \$φ + \$t1*math:sin(\$p1)
let \$t3 := \$t1 * math:cos(\$p1) - 1
return
(
\$weight * (\$r*math:cos(\$t2) + \$t3*\$x) div \$ν36,
\$weight * (\$r*math:sin(\$t2) + \$t3*\$y) div \$ν36
)
},
(\$weight, \$parameters)
)
)
};

declare function this:pie(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("slices")
let \$p2 as xs:numeric := \$parameters("rotation")
let \$p3 as xs:numeric := \$parameters("thickness")
return (
ann:f("mut:pie",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
let \$Ψ3 := rand:uniform(0.0, 1.0)
let \$t1 := util:trunc(\$Ψ1*\$p1 + 0.5)
let \$t2 := \$p2 + (2*math:pi() div \$p1)*(\$t1 + \$Ψ2*\$p3)
return
(\$weight * \$Ψ3*math:cos(\$t2), \$weight * \$Ψ3*math:sin(\$t2))
},
(\$weight, \$parameters)
)
)
};

declare function this:ngon(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("power")
let \$p2 as xs:numeric := \$parameters("sides")
let \$p3 as xs:numeric := \$parameters("corners")
let \$p4 as xs:numeric := \$parameters("circle")
return (
ann:f("mut:ngon",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$φ := math:atan2(\$y,\$x)
let \$t3 := \$φ - \$p2*floor(\$φ div \$p2)
let \$t4 :=
if (\$t3 gt \$p2 div 2) then \$t3
else \$t3 - \$p2
let \$k := (\$p3 * ((1 div math:cos(\$t4)) - 1) + \$p4) div math:pow(\$r, \$p1)
return
(\$weight * \$k*\$x, \$weight * \$k*\$y)
},
(\$weight, \$parameters)
)
)
};

declare function this:curl(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("c1")
let \$p2 as xs:numeric := \$parameters("c2")
return (
ann:f("mut:curl",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$t1 := 1 + \$p1*\$x + \$p2*(\$x*\$x - \$y*\$y)
let \$t2 := \$p1*\$y + 2*\$p2*\$x*\$y
let \$inv-factor := \$t1*\$t1 + \$t2*\$t2
let \$factor :=
if (\$inv-factor = 0)
then 1 div (\$inv-factor + 1)
else 1 div \$inv-factor
return
(
\$weight * \$factor*(\$x*\$t1 + \$y*\$t2),
\$weight * \$factor*(\$y*\$t1 - \$x*\$t2)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:rectangles(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$p1 as xs:numeric := \$parameters("x")
let \$p2 as xs:numeric := \$parameters("y")
return (
ann:f("mut:rectangles",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
(
\$weight * ((2*floor(\$x div \$p1) + 1)*\$p1 - \$x),
\$weight * ((2*floor(\$y div \$p2) + 1)*\$p2 - \$y)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:supershape(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$holes as xs:numeric := \$parameters("holes")
let \$m as xs:numeric := \$parameters("m")
let \$n1 as xs:numeric := \$parameters("n1")
let \$n2 as xs:numeric := \$parameters("n1")
let \$n3 as xs:numeric := \$parameters("n1")
let \$rnd as xs:numeric := \$parameters("rnd")
let \$m_over_4 := \$m div 4.0
let \$neg1_over_n1 := -1.0 div \$n1
return (
ann:f("mut:supershape",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$y,\$x)
let \$α := \$m_over_4 * \$θ + math:pi() div 4.0
let \$t1 := math:pow(abs(math:sin(\$α)), \$n2)
let \$t2 := math:pow(abs(math:cos(\$α)), \$n3)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$factor := ( (\$rnd*\$Ψ1 + (1.0 - \$rnd)*\$r - \$holes) * math:pow(\$t1 + \$t2, \$neg1_over_n1) ) div \$r
return (
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:flower(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$holes as xs:numeric := \$parameters("holes")
let \$petals as xs:numeric := \$parameters("petals")
return (
ann:f("mut:flower",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$y,\$x)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$r := \$weight * (\$Ψ1 - \$holes) * math:cos(\$petals * \$θ)
return (
(\$r * math:cos(\$θ), \$r * math:sin(\$θ))
)
},
(\$weight, \$parameters)
)
)
};

declare function this:conic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$holes as xs:numeric := \$parameters("holes")
let \$eccentricity as xs:numeric := \$parameters("eccentricity")
return (
ann:f("mut:conic",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$y,\$x)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$r := \$weight * (\$Ψ1 - \$holes) * \$eccentricity div (1 + \$eccentricity * math:cos(\$θ))
return (
(\$r * math:cos(\$θ), \$r * math:sin(\$θ))
)
},
(\$weight, \$parameters)
)
)
};

declare function this:parabola(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$width as xs:numeric := \$parameters("width")
let \$height as xs:numeric := \$parameters("height")
return (
ann:f("mut:parabola",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$y,\$x)
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return (
(
\$weight * \$height * math:sin(\$r) * math:sin(\$r) * \$Ψ1,
\$weight * \$width * math:cos(\$r) * \$Ψ2
)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:bent2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$at as xs:numeric := \$parameters("at")
let \$bendx as xs:numeric := \$parameters("x")
let \$bendy as xs:numeric := \$parameters("y")
return (
ann:f("mut:bent2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$x := if (\$x < \$at) then \$x * \$bendx else \$x
let \$y := if (\$y < \$at) then \$y * \$bendy else \$y
return (
(\$weight * \$x, \$weight * \$y)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:arch(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν41 as xs:numeric := \$weight
return (
ann:f("mut:arch",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$sin := math:sin(\$Ψ*math:pi()*\$ν41)
return
(
\$weight * \$sin,
\$weight * \$sin*\$sin div math:cos(\$Ψ*math:pi()*\$ν41)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:tangent(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:tangent",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
return
if (math:cos(\$y) = 0)
then (\$weight, \$weight * math:tan(\$y))
else (\$weight * math:sin(\$x) div math:cos(\$y), \$weight * math:tan(\$y))
},
(\$weight, \$parameters)
)
};

declare function this:square(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:square",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ1 := rand:uniform(0.0, 1.0)
let \$Ψ2 := rand:uniform(0.0, 1.0)
return
(\$weight * (\$Ψ1 - 0.5), \$weight * (\$Ψ2 - 0.5))
},
(\$weight, \$parameters)
)
};

declare function this:rays(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν44 as xs:numeric := \$weight
return (
ann:f("mut:rays",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := \$x*\$x + \$y*\$y + 1.0E-7
let \$factor := math:tan(\$Ψ*math:pi()*\$ν44) div \$r2
return
(
\$weight * \$factor*math:cos(\$x),
\$weight * \$factor*math:sin(\$y)
)
},
(\$weight, \$parameters)
)
)
};

\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν45 as xs:numeric := \$weight
return (
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
(
\$weight * (\$x*(math:cos(\$Ψ*\$r*\$ν45) + math:sin(\$Ψ*\$r*\$ν45))),
\$weight * (\$x*(math:cos(\$Ψ*\$r*\$ν45) - math:sin(\$Ψ*\$r*\$ν45)))
)
},
(\$weight, \$parameters)
)
)
};

declare function this:secant(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν46 as xs:numeric := \$weight
return (
ann:f("mut:secant",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
return
if (math:cos(\$r*\$ν46)=0)
then
(
\$weight * \$x,
\$weight * (1 + 1.0 div math:cos(\$r*\$ν46))
)
else
(
\$weight * \$x,
\$weight * (-1 + 1.0 div math:cos(\$r*\$ν46))
)
},
(\$weight, \$parameters)
)
)
};

declare function this:twintrian(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$ν47 as xs:numeric := \$weight
return (
ann:f("mut:twintrian",
function(\$pt as xs:double*) as xs:double* {
let \$Ψ := rand:uniform(0.0, 1.0)
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$t :=
math:log10(math:sin(\$Ψ*\$r*\$ν47)*math:sin(\$Ψ*\$r*\$ν47)) +
math:cos(\$Ψ*\$r*\$ν47)
return
(
\$weight * \$x * \$t,
\$weight * \$x * (\$t - math:pi()*math:sin(\$Ψ*\$r*\$ν47))
)
},
(\$weight, \$parameters)
)
)
};

declare function this:cross(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:cross",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$d := \$x*\$x - \$y*\$y
let \$factor := math:sqrt(1.0 div (\$d*\$d + 1.0E-7))
return
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
},
(\$weight, \$parameters)
)
};

declare function this:disc2(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$twist as xs:numeric := \$parameters("twist")
let \$rot as xs:numeric := \$parameters("rot")
let \$pirot := \$rot * math:pi()
let \$sintwist := math:sin(\$twist)
let \$costwist := math:cos(\$twist)
let \$high := \$twist > 2*math:pi()
let \$low := \$twist < -2*math:pi()
if (\$high) then \$sintwist * (1 + \$twist - 2*math:pi())
else if (\$low) then \$sintwist * (1 + \$twist + 2*math:pi())
else \$sintwist
if (\$high) then \$costwist * (1 + \$twist - 2*math:pi())
else if (\$low) then \$costwist * (1 + \$twist + 2*math:pi())
else \$costwist
return (
ann:f("mut:disc2",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$θ := math:atan2(\$y,\$x)
let \$t := \$rot * math:pi() * (\$x + \$y)
let \$r := \$weight * \$θ div math:pi()
return
},
(\$weight, \$parameters)
)
)
};

declare function this:drift(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$dx1 as xs:numeric := \$parameters("x.min")
let \$dy1 as xs:numeric := \$parameters("y.min")
let \$dx2 as xs:numeric? := \$parameters("x.max")
let \$dy2 as xs:numeric? := \$parameters("y.max")
let \$x-range as map(xs:string,item()*) :=
if (empty(\$dx2) or \$dx1=\$dx2)
then dist:constant(\$dx1)
else dist:uniform(\$dx1, \$dx2)
let \$y-range as map(xs:string,item()*) :=
if (empty(\$dy2) or \$dy1=\$dy2)
then dist:constant(\$dy1)
else dist:uniform(\$dy1, \$dy2)
return (
ann:f("mut:drift",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt) + rand:randomize(\$x-range)
let \$y := v:py(\$pt) + rand:randomize(\$y-range)
return
(\$weight * \$x, \$weight * \$y)
},
(\$weight, \$parameters)
)
)
};

declare function this:crumple(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
ann:f("mut:crumple",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r := math:sqrt(\$x*\$x + \$y*\$y)
let \$rfold := abs(0.5 - \$r)
let \$θ := math:atan2(\$x,\$y)
return (
(\$weight * \$rfold * math:cos(\$θ), \$weight * \$rfold * math:sin(\$θ))
)
},
(\$weight, \$parameters)
)
};

(: Default depth=0.5, shrink=1; invert that to get a flange :)
declare function this:pillow(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$depth as xs:numeric := \$parameters("depth")
let \$shrink as xs:numeric := \$parameters("shrink")
let \$d2 as xs:numeric := \$depth * \$depth
return (
ann:f("mut:pillow",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$r2 := abs(\$d2 - \$x*\$x + \$y*\$y)
let \$θ := math:atan2(\$x,\$y)
let \$factor := \$shrink div (\$r2 + 1)
return (
(\$weight * \$factor * \$x, \$weight * \$factor * \$y)
)
},
(\$weight, \$parameters)
)
)
};

declare function this:flowfield(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{

let \$noise as function(*) := \$parameters("noise")=>noise:as-vector()=>f:function()
let \$step as xs:numeric := \$parameters("step-size")
return (
ann:f("mut:flowfield",
function(\$pt as xs:double*) as xs:double* {
let \$θ := \$noise(\$pt) * 180 + 180
return v:destination(\$pt, \$θ, \$step)
},
(\$weight, \$parameters)
)
)
};

declare function this:bipolar(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$extent := \$parameters("extent")
return
ann:f("mut:bipolar",
function(\$pt as xs:double*) as xs:double* {
let \$u := (v:px(\$pt) + 1) * math:pi() (: [-1,1]=>[0,2π) :)
let \$v := v:py(\$pt) * \$extent (: [-1,1] => [-extent,extent] :)
return coordinates:bipolar(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
};

declare function this:elliptic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$scale := \$parameters("scale")
return
ann:f("mut:elliptic",
function(\$pt as xs:double*) as xs:double* {
let \$u := (v:px(\$pt) + 1) * \$scale (: [-1,1]=>[0,\$scale] :)
let \$v := (v:py(\$pt) + 1) * math:pi() (: [-1,1]=>[0,2π] :)
return coordinates:elliptic(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
};

declare function this:circular(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$scale := \$parameters("scale")
return
ann:f("mut:circular",
function(\$pt as xs:double*) as xs:double* {
let \$u := v:px(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
let \$v := v:py(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
return coordinates:circular(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
};

declare function this:parabolic(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
let \$scale := \$parameters("scale")
let \$symmetric := \$parameters("symmetric")
return
if (\$symmetric) then (
ann:f("mut:parabolic",
function(\$pt as xs:double*) as xs:double* {
let \$u := v:px(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
let \$v := v:py(\$pt) * \$scale (: [-1,1]=>[-\$scale,\$scale] :)
return coordinates:parabolic(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
) else (
ann:f("mut:parabolic",
function(\$pt as xs:double*) as xs:double* {
let \$u := (v:px(\$pt) + 1) * \$scale (: [-1,1]=>[0,\$scale] :)
let \$v := (v:py(\$pt) + 1) * \$scale (: [-1,1]=>[0,\$scale] :)
return coordinates:parabolic(\$u, \$v)=>point:pcoordinates()
},
(\$weight, \$parameters)
)
)
};

(: Surface of a sphere :)
declare function this:sphere(
\$weight as xs:double,
\$parameters as map(xs:string,item()*)
) as map(*)
{
return
ann:f("mut:sphere",
function(\$pt as xs:double*) as xs:double* {
let \$x := v:px(\$pt)
let \$y := v:py(\$pt)
let \$latitude := math:asin(\$y div \$radius)