http://mathling.com/noise/modifiers library module
http://mathling.com/noise/modifiers
Noise function modifications: create new functions from multiple noise
functions with different parameters
Port/refactor/expansion of https://github.com/razaekel/noise-rs
As of 202303 these functions do not return annotated functions, but wrapped
callables. You'll need to use callable:function() to get the actual function
to use.
Copyright© Mary Holstege 2020-2023
CC-BY (https://creativecommons.org/licenses/by/4.0/)
Status: Active
Imports
http://mathling.com/core/randomimport module namespace rand="http://mathling.com/core/random" at "../core/random.xqy"http://mathling.com/noise/annotations
import module namespace ann="http://mathling.com/noise/annotations" at "../noise/annotations.xqy"http://mathling.com/geometric/mutation
import module namespace mutation="http://mathling.com/geometric/mutation" at "../geo/mutation.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/type/distribution
import module namespace dist="http://mathling.com/type/distribution" at "../types/distributions.xqy"http://mathling.com/geometric/affine
import module namespace affine="http://mathling.com/geometric/affine" at "../geo/affine.xqy"http://mathling.com/core/errors
import module namespace errors="http://mathling.com/core/errors" at "../core/errors.xqy"http://mathling.com/geometric/point
import module namespace point="http://mathling.com/geometric/point" at "../geo/point.xqy"
Functions
Function: trace
declare function trace($f as item()) as map(*)
declare function trace($f as item()) as map(*)
trace()
Noise function that just passes through with a trace of the value
Params
- f as item()
Returns
- map(*)
declare %art:noise function this:trace( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( ann:f(util:function-name($f), function ($point as map(xs:string,item()*)) as xs:double { $fn($point)=>trace(util:quote($f)||"("||point:quote($point)||")") } ) ) else ( ann:fv(util:function-name($f), function ($point as xs:double*) as xs:double { $fn($point)=>trace(util:quote($f)||"("||v:quote($point)||")") } ) ) ) }
Function: trace-bounds
declare function trace-bounds($f as item(),
$low as xs:double,
$high as xs:double) as map(*)
declare function trace-bounds($f as item(), $low as xs:double, $high as xs:double) as map(*)
trace-bounds()
Noise function that just passes through with a trace of the value, but
only if it is out of range
Params
- f as item()
- low as xs:double
- high as xs:double
Returns
- map(*)
declare %art:noise function this:trace-bounds( $f as item(), $low as xs:double, $high as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( ann:f(util:function-name($f), function ($point as map(xs:string,item()*)) as xs:double { let $val := $fn($point) return ( if (util:twixt($val, $low, $high)) then $val else $val=>trace(util:quote($f)||"("||point:quote($point)||")") ) } ) ) else ( ann:fv(util:function-name($f), function ($point as xs:double*) as xs:double { let $val := $fn($point) return ( if (util:twixt($val, $low, $high)) then $val else $val=>trace(util:quote($f)||"("||v:quote($point)||")") ) } ) ) ) }
Function: cache
declare function cache($f as item()) as item()
declare function cache($f as item()) as item()
cache()
Wrap noise function in a caching function (depends on saxon:memo-function)
Params
- f as item(): base noise function
Returns
- item()
declare %art:noise function this:cache( $f as item() ) as item() { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( let $cached := this:cache-point($fn, ?) return ( ann:f(util:function-name($f), function ($point as map(xs:string,item()*)) as xs:double { $cached($point) } ) ) ) else ( let $cached := this:cache-vector($fn, ?) return ( ann:fv(util:function-name($f), function ($point as xs:double*) as xs:double { $cached($point) } ) ) ) ) }
Function: cache-vector
declare function cache-vector($fn as function(xs:double*) as xs:double,
$point as xs:double*) as xs:double
declare function cache-vector($fn as function(xs:double*) as xs:double, $point as xs:double*) as xs:double
Params
- fn as function(xs:double*)asxs:double
- point as xs:double*
Returns
- xs:double
declare %saxon:memo-function function this:cache-vector( $fn as function(xs:double*) as xs:double, $point as xs:double* ) as xs:double { $fn($point) }
Function: cache-point
declare function cache-point($fn as function(map(xs:string,item()*)) as xs:double,
$point as map(xs:string,item()*)) as xs:double
declare function cache-point($fn as function(map(xs:string,item()*)) as xs:double, $point as map(xs:string,item()*)) as xs:double
Params
- fn as function(map(xs:string,item()*))asxs:double
- point as map(xs:string,item()*)
Returns
- xs:double
declare %saxon:memo-function function this:cache-point( $fn as function(map(xs:string,item()*)) as xs:double, $point as map(xs:string,item()*) ) as xs:double { $fn($point) }
Function: as-point
declare function as-point($f as item()) as item()
declare function as-point($f as item()) as item()
as-point()
Pass through to make a point-as-point function, converting from vector
Params
- f as item()
Returns
- item()
declare function this:as-point( $f as item() ) as item() { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-vector($f)) then ( ann:f(util:function-name($f), function($point as map(xs:string,item()*)) as xs:double { $fn(point:pcoordinates($point)) } ) ) else ( $f ) ) }
Function: as-vector
declare function as-vector($f as item()) as item()
declare function as-vector($f as item()) as item()
as-vector()
Pass through to make a vector-to-vector function, converting from point-to-point
Params
- f as item()
Returns
- item()
declare function this:as-vector( $f as item() ) as item() { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( ann:fv(util:function-name($f), function($point as xs:double*) as xs:double { $fn(point:vector($point)) } ) ) else ( $f ) ) }
Function: constant
declare function constant($c as xs:double) as map(*)
declare function constant($c as xs:double) as map(*)
constant()
Base noise function that returns a constant value
Params
- c as xs:double
Returns
- map(*)
declare %art:noise function this:constant( $c as xs:double ) as map(*) { ann:f("", (: Just the constant :) function ($point as map(xs:string,item()*)) as xs:double { $c }, $c ) }
Function: constant-vector
declare function constant-vector($c as xs:double) as map(*)
declare function constant-vector($c as xs:double) as map(*)
constant-vector()
Base noise function that returns a constant value (vector form)
Params
- c as xs:double
Returns
- map(*)
declare %art:noise function this:constant-vector( $c as xs:double ) as map(*) { ann:fv("", (: Just the constant :) function ($point as xs:double*) as xs:double { $c }, $c ) }
Function: random
declare function random($distribution as map(xs:string,item()*)) as map(*)
declare function random($distribution as map(xs:string,item()*)) as map(*)
random()
Base noise function that returns a value out of the given distribution,
ignoring the point completely
Params
- distribution as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:random( $distribution as map(xs:string,item()*) ) as map(*) { ann:f("mod:random", function ($point as map(xs:string,item()*)) as xs:double { rand:randomize($distribution) }, $distribution ) }
Function: random-vector
declare function random-vector($distribution as map(xs:string,item()*)) as map(*)
declare function random-vector($distribution as map(xs:string,item()*)) as map(*)
random-vector()
Base noise function that returns a value out of the given distribution,
ignoring the point completely (vector form)
Params
- distribution as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:random-vector( $distribution as map(xs:string,item()*) ) as map(*) { ann:fv("mod:random", function ($point as xs:double*) as xs:double { rand:randomize($distribution) }, $distribution ) }
Function: random-last
declare function random-last($f as item(),
$distribution as map(xs:string,item()*)) as map(*)
declare function random-last($f as item(), $distribution as map(xs:string,item()*)) as map(*)
random-last()
Base noise function that returns a value out of the given distribution,
using $f($point) as the last value for the distribution
Params
- f as item()
- distribution as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:random-last( $f as item(), $distribution as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := $f=>ann:function() return ann:f("mod:random", function ($point as map(xs:string,item()*)) as xs:double { rand:randomize(1, $fn($point), $distribution) }, ($f, $distribution) ) }
Function: random-last-vector
declare function random-last-vector($f as item(),
$distribution as map(xs:string,item()*)) as map(*)
declare function random-last-vector($f as item(), $distribution as map(xs:string,item()*)) as map(*)
random-last-vector()
Base noise function that returns a value out of the given distribution,
using $f($point) as the last value for the distribution. (Vector form.)
Params
- f as item()
- distribution as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:random-last-vector( $f as item(), $distribution as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := $f=>ann:function() return ann:fv("mod:random", function ($point as xs:double*) as xs:double { rand:randomize(1, $fn($point), $distribution) }, ($f, $distribution) ) }
Function: cylinders
declare function cylinders($frequency as xs:double) as map(*)
declare function cylinders($frequency as xs:double) as map(*)
cylinders()
Base noise function that outputs concentric cylinders.
This noise function outputs concentric cylinders centered on the origin. The
cylinders are oriented along the z axis similar to the concentric rings of
a tree. Each cylinder extends infinitely along the z axis.
Params
- frequency as xs:double: Frequency of concentric objects
Returns
- map(*)
declare %art:noise function this:cylinders( $frequency as xs:double ) as map(*) { ann:f("mod:cylinders", function ($point as map(xs:string,item()*)) as xs:double { let $scaled := affine:scale($point=>point:as-dimension(2), $frequency) let $dist-from-center := point:distance($scaled, $point:ORIGIN) let $dist-from-smaller-sphere := $dist-from-center - floor($dist-from-center) let $dist-from-larger-sphere := 1.0 - $dist-from-smaller-sphere let $nearest-dist := min(($dist-from-smaller-sphere, $dist-from-larger-sphere)) (: Shift to [-1,1] range :) return 1.0 - ($nearest-dist * 4.0) }, ($frequency) ) }
Function: cylinders
declare function cylinders() as map(*)
declare function cylinders() as map(*)
Returns
- map(*)
declare %art:noise function this:cylinders( ) as map(*) { this:cylinders(1.0) }
Function: cylinders-vector
declare function cylinders-vector($frequency as xs:double) as map(*)
declare function cylinders-vector($frequency as xs:double) as map(*)
cylinders-vector()
Base noise function that outputs concentric cylinders. (Vector form.)
This noise function outputs concentric cylinders centered on the origin. The
cylinders are oriented along the z axis similar to the concentric rings of
a tree. Each cylinder extends infinitely along the z axis.
Params
- frequency as xs:double: Frequency of concentric objects
Returns
- map(*)
declare %art:noise function this:cylinders-vector( $frequency as xs:double ) as map(*) { ann:fv("mod:cylinders", function ($point as xs:double*) as xs:double { let $scaled := affine:affine2($point, affine:scaling2($frequency, $frequency)) let $dist-from-center := v:distance($scaled, (0,0)) let $dist-from-smaller-sphere := $dist-from-center - floor($dist-from-center) let $dist-from-larger-sphere := 1.0 - $dist-from-smaller-sphere let $nearest-dist := min(($dist-from-smaller-sphere, $dist-from-larger-sphere)) (: Shift to [-1,1] range :) return 1.0 - ($nearest-dist * 4.0) }, ($frequency) ) }
Function: cylinders-vector
declare function cylinders-vector() as map(*)
declare function cylinders-vector() as map(*)
Returns
- map(*)
declare %art:noise function this:cylinders-vector( ) as map(*) { this:cylinders-vector(1.0) }
Function: add
declare function add($f1 as item(),
$f2 as item()) as map(*)
declare function add($f1 as item(), $f2 as item()) as map(*)
add()
Noise function is sum of two noise functions
Params
- f1 as item()
- f2 as item()
Returns
- map(*)
declare %art:noise function this:add( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:add", function ($point as xs:double*) as xs:double { $fn1($point) + $fn2($point) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:add", function ($point as map(xs:string,item()*)) as xs:double { $fn1($point) + $fn2($point) }, ($f1, $f2) ) ) ) }
Function: max
declare function max($f1 as item(),
$f2 as item()) as map(*)
declare function max($f1 as item(), $f2 as item()) as map(*)
max()
Noise function is max of two noise functions
Params
- f1 as item()
- f2 as item()
Returns
- map(*)
declare %art:noise function this:max( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:max", function ($point as xs:double*) as xs:double { max(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:max", function ($point as map(xs:string,item()*)) as xs:double { max(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) ) }
Function: min
declare function min($f1 as item(),
$f2 as item()) as map(*)
declare function min($f1 as item(), $f2 as item()) as map(*)
min()
Noise function is min of two noise functions
Params
- f1 as item()
- f2 as item()
Returns
- map(*)
declare %art:noise function this:min( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:min", function ($point as xs:double*) as xs:double { min(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:min", function ($point as map(xs:string,item()*)) as xs:double { min(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) ) }
Function: multiply
declare function multiply($f1 as item(),
$f2 as item()) as map(*)
declare function multiply($f1 as item(), $f2 as item()) as map(*)
multiply()
Noise function is multiplication of two noise functions
Params
- f1 as item()
- f2 as item()
Returns
- map(*)
declare %art:noise function this:multiply( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:multiply", function ($point as xs:double*) as xs:double { $fn1($point) * $fn2($point) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:multiply", function ($point as map(xs:string,item()*)) as xs:double { $fn1($point) * $fn2($point) }, ($f1, $f2) ) ) ) }
Function: pow
declare function pow($f1 as item(),
$f2 as item()) as map(*)
declare function pow($f1 as item(), $f2 as item()) as map(*)
pow()
Noise function is output of first noise function raised to power of second
Params
- f1 as item()
- f2 as item()
Returns
- map(*)
declare %art:noise function this:pow( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:pow", function ($point as xs:double*) as xs:double { math:pow($fn1($point), $fn2($point)) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:pow", function ($point as map(xs:string,item()*)) as xs:double { math:pow($fn1($point), $fn2($point)) }, ($f1, $f2) ) ) ) }
Function: abs
declare function abs($f as item()) as map(*)
declare function abs($f as item()) as map(*)
abs()
Noise function that is the absolute value of input noise function
Params
- f as item()
Returns
- map(*)
declare %art:noise function this:abs( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:abs", function ($point as xs:double*) as xs:double { abs($fn($point)) }, $f ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:abs", function ($point as map(xs:string,item()*)) as xs:double { abs($fn($point)) }, $f ) ) ) }
Function: clamp
declare function clamp($f as item(),
$min as xs:double,
$max as xs:double) as map(*)
declare function clamp($f as item(), $min as xs:double, $max as xs:double) as map(*)
clamp()
Noise function that clamps the output to a range of value
Params
- f as item()
- min as xs:double
- max as xs:double
Returns
- map(*)
declare %art:noise function this:clamp( $f as item(), $min as xs:double, $max as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:clamp", function ($point as xs:double*) as xs:double { max(($min, min(($max, $fn($point))))) }, $f ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:clamp", function ($point as map(xs:string,item()*)) as xs:double { max(($min, min(($max, $fn($point))))) }, $f ) ) ) }
Function: round
declare function round($f as item()) as map(*)
declare function round($f as item()) as map(*)
round()
Noise function that rounds the output
Params
- f as item()
Returns
- map(*)
declare %art:noise function this:round( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:round", function ($point as xs:double*) as xs:double { round($fn($point)) }, $f ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:round", function ($point as map(xs:string,item()*)) as xs:double { round($fn($point)) }, $f ) ) ) }
Function: curve
declare function curve($f as item(),
$curve as map(xs:string,item()*)*) as map(*)
declare function curve($f as item(), $curve as map(xs:string,item()*)*) as map(*)
curve()
Noise function that maps output onto a curve defined by a series
of control points; mapping is via cubic interpolation
Control points should have distinct x's; they don't have to be 2D, but only
2 dimensions matter
Params
- f as item()
- curve as map(xs:string,item()*)*
Returns
- map(*)
declare %art:noise function this:curve( $f as item(), $curve as map(xs:string,item()*)* ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $curve := for $pt in $curve order by point:px($pt) ascending return $pt (: Check distinct x values :) let $curve := ( for $pt at $i in tail($curve) return util:assert(point:px($pt)!=point:px($curve[$i]), "Control points must have different x values"), $curve ) let $n := count($curve) let $n := (util:assert($n >= 4, "Not enough control points"), $n) return if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:curve", function ($point as xs:double*) as xs:double { let $source-value := $fn($point) (: Find the first control point has an x value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $p at $i in $curve where point:px($p) > $source-value return $i, $n + 1 )[1] (: Ensure that the index is in [3, $n+1] :) let $index-pos := max((3, min(($n + 1, $index-pos)))) (: Find four nearest control points so we can perform cubic interpolation :) let $index0 := max((1, min(($n, $index-pos - 2)))) let $index1 := max((1, min(($n, $index-pos - 1)))) let $index2 := max((1, min(($n, $index-pos)))) let $index3 := max((1, min(($n, $index-pos + 1)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index1=$index2) then ( point:py($curve[$index1]) ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := point:px($curve[$index1]) let $input1 := point:px($curve[$index2]) let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Now perform the cubic interpolation :) return ( this:cubic( point:py($curve[$index0]), point:py($curve[$index1]), point:py($curve[$index2]), point:py($curve[$index3]), $alpha ) ) ) ) }, ($f, $curve) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:curve", function ($point as map(xs:string,item()*)) as xs:double { let $source-value := $fn($point) (: Find the first control point has an x value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $p at $i in $curve where point:px($p) > $source-value return $i, $n + 1 )[1] (: Ensure that the index is in [3, $n+1] :) let $index-pos := max((3, min(($n + 1, $index-pos)))) (: Find four nearest control points so we can perform cubic interpolation :) let $index0 := max((1, min(($n, $index-pos - 2)))) let $index1 := max((1, min(($n, $index-pos - 1)))) let $index2 := max((1, min(($n, $index-pos)))) let $index3 := max((1, min(($n, $index-pos + 1)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index1=$index2) then ( point:py($curve[$index1]) ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := point:px($curve[$index1]) let $input1 := point:px($curve[$index2]) let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Now perform the cubic interpolation :) return ( this:cubic( point:py($curve[$index0]), point:py($curve[$index1]), point:py($curve[$index2]), point:py($curve[$index3]), $alpha ) ) ) ) }, ($f, $curve) ) ) ) }
Function: exponent
declare function exponent($f as item(),
$exponent as xs:double) as map(*)
declare function exponent($f as item(), $exponent as xs:double) as map(*)
exponent()
Noise function that maps output onto an exponential curve.
Because most noise functions will output values that range from -1.0 to 1.0,
this noise function first normalizes the output value (the range becomes 0.0
to 1.0), maps that value onto an exponential curve, then rescales that
value back to the original range.
Params
- f as item()
- exponent as xs:double
Returns
- map(*)
declare %art:noise function this:exponent( $f as item(), $exponent as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:exponent", function ($point as xs:double*) as xs:double { abs(math:pow(abs(($fn($point) + 1.0) div 2.0), $exponent)) * 2.0 - 1.0 }, ($f, $exponent) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:exponent", function ($point as map(xs:string,item()*)) as xs:double { abs(math:pow(abs(($fn($point) + 1.0) div 2.0), $exponent)) * 2.0 - 1.0 }, ($f, $exponent) ) ) ) }
Function: exponent
declare function exponent($f as item()) as map(*)
declare function exponent($f as item()) as map(*)
Params
- f as item()
Returns
- map(*)
declare %art:noise function this:exponent( $f as item() ) as map(*) { this:exponent($f, 1.0) }
Function: negate
declare function negate($f as item()) as map(*)
declare function negate($f as item()) as map(*)
negate()
Noise function that negates the output
Params
- f as item()
Returns
- map(*)
declare %art:noise function this:negate( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:negate", function ($point as xs:double*) as xs:double { -$fn($point) }, ($f) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:negate", function ($point as map(xs:string,item()*)) as xs:double { -$fn($point) }, ($f) ) ) ) }
Function: scale-bias
declare function scale-bias($f as item(),
$scale as xs:double,
$bias as xs:double) as map(*)
declare function scale-bias($f as item(), $scale as xs:double, $bias as xs:double) as map(*)
scale-bias()
Noise function that applies a scaling factor and then a bias to the
source function.
Multiplies by the scaling factor, adds the bias.
Params
- f as item()
- scale as xs:double
- bias as xs:double
Returns
- map(*)
declare %art:noise function this:scale-bias( $f as item(), $scale as xs:double, $bias as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:scale-bias", function ($point as xs:double*) as xs:double { $fn($point) * $scale + $bias }, ($f, $scale, $bias) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:scale-bias", function ($point as map(xs:string,item()*)) as xs:double { $fn($point) * $scale + $bias }, ($f, $scale, $bias) ) ) ) }
Function: scale-bias
declare function scale-bias($f as item(),
$scale as xs:double) as map(*)
declare function scale-bias($f as item(), $scale as xs:double) as map(*)
Params
- f as item()
- scale as xs:double
Returns
- map(*)
declare %art:noise function this:scale-bias( $f as item(), $scale as xs:double ) as map(*) { this:scale-bias($f, $scale, 0.0) }
Function: scale-bias
declare function scale-bias($f as item()) as map(*)
declare function scale-bias($f as item()) as map(*)
Params
- f as item()
Returns
- map(*)
declare %art:noise function this:scale-bias( $f as item() ) as map(*) { this:scale-bias($f, 1.0, 0.0) }
Function: terrace
declare function terrace($f as item(),
$control-points as xs:double*,
$invert as xs:boolean) as map(*)
declare function terrace($f as item(), $control-points as xs:double*, $invert as xs:boolean) as map(*)
terrace()
Noise function that maps the output value from source function
to a terrace-forming curve.
The start of the curve has a slope of zero, smoothly increasing.
It also has control points (x values) that reset the slope to 0 at that
point,producing the terracing effect.
There must be at least 2 control points, which have different values.
The function clamps the output value from the source function if it is
out of range of the control points.
This noise function is often used to generate terrain features such as the
stereotypical desert canyon.
Params
- f as item()
- control-points as xs:double*
- invert as xs:boolean
Returns
- map(*)
declare %art:noise function this:terrace( $f as item(), $control-points as xs:double*, $invert as xs:boolean ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $control-points := for $x in $control-points order by $x ascending return $x (: Check distinct values :) let $control-points := ( for $x at $i in tail($control-points) return util:assert($x!=$control-points[$i], "Control points must have different values"), $control-points ) let $n := count($control-points) let $n := (util:assert($n >= 2, "Not enough control points"), $n) return if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:terrace", function ($point as xs:double*) as xs:double { let $source-value := $fn($point) (: Find the first control point has a value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $x at $i in $control-points where $x > $source-value return $i, $n + 1 )[1] (: Find the two nearest control points so that we can map their values : onto a quadratic curve. :) let $index0 := max((1, min(($n, $index-pos - 1)))) let $index1 := max((1, min(($n, $index-pos)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index0 = $index1) then ( $control-points[$index1] ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := $control-points[$index0] let $input1 := $control-points[$index1] let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Squaring produces terrace effect :) let $alpha := if ($invert) then ( (1.0 - $alpha) * (1.0 - $alpha) ) else ( $alpha * $alpha ) return ( if ($invert) then ( (: Swap input0 and input1 :) this:linear($input1, $input0, $alpha) ) else ( this:linear($input0, $input1, $alpha) ) ) ) ) }, ($f, $control-points, $invert) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:terrace", function ($point as map(xs:string,item()*)) as xs:double { let $source-value := $fn($point) (: Find the first control point has a value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $x at $i in $control-points where $x > $source-value return $i, $n + 1 )[1] (: Find the two nearest control points so that we can map their values : onto a quadratic curve. :) let $index0 := max((1, min(($n, $index-pos - 1)))) let $index1 := max((1, min(($n, $index-pos)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index0 = $index1) then ( $control-points[$index1] ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := $control-points[$index0] let $input1 := $control-points[$index1] let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Squaring produces terrace effect :) let $alpha := if ($invert) then ( (1.0 - $alpha) * (1.0 - $alpha) ) else ( $alpha * $alpha ) return ( if ($invert) then ( (: Swap input0 and input1 :) this:linear($input1, $input0, $alpha) ) else ( this:linear($input0, $input1, $alpha) ) ) ) ) }, ($f, $control-points, $invert) ) ) ) }
Function: terrace
declare function terrace($f as item(),
$control-points as xs:double*) as map(*)
declare function terrace($f as item(), $control-points as xs:double*) as map(*)
Params
- f as item()
- control-points as xs:double*
Returns
- map(*)
declare %art:noise function this:terrace( $f as item(), $control-points as xs:double* ) as map(*) { this:terrace($f, $control-points, false()) }
Function: blend
declare function blend($f1 as item(),
$f2 as item(),
$control as item()) as map(*)
declare function blend($f1 as item(), $f2 as item(), $control as item()) as map(*)
blend()
Noise function that created weighted blend out output values from
source functions, using weighting produced by control function.
Uses linear interpolation: negative values from control functions
weight towards first function, positive towards second.
Params
- f1 as item()
- f2 as item()
- control as item()
Returns
- map(*)
declare %art:noise function this:blend( $f1 as item(), $f2 as item(), $control as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (not(ann:is-noise($control))) then errors:error("ML-BADARGS", ("control", $control)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2) and ann:is-noise-vector($control)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() let $controlfn := $control=>ann:function() return ann:fv("mod:blend", function ($point as xs:double*) as xs:double { let $a := $fn1($point) let $b := $fn2($point) let $alpha := $controlfn($point) return this:linear($a, $b, $alpha) }, ($f1, $f2, $control) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() let $controlfn := $control=>this:as-point()=>ann:function() return ( ann:f("mod:blend", function ($point as map(xs:string,item()*)) as xs:double { let $a := $fn1($point) let $b := $fn2($point) let $alpha := $controlfn($point) return this:linear($a, $b, $alpha) }, ($f1, $f2, $control) ) ) ) }
Function: s-curve3
declare function s-curve3($x as xs:double) as xs:double
declare function s-curve3($x as xs:double) as xs:double
Maps a value onto a cubic S-curve.
Params
- x as xs:double
Returns
- xs:double
declare function this:s-curve3($x as xs:double) as xs:double { $x * $x * (3.0 - ($x * 2.0)) }
Function: s-curve5
declare function s-curve5($x as xs:double) as xs:double
declare function s-curve5($x as xs:double) as xs:double
Params
- x as xs:double
Returns
- xs:double
declare function this:s-curve5($x as xs:double) as xs:double { $x * $x * $x * ($x * ($x * 6 - 15) + 10) }
Function: linear
declare function linear($a as xs:double, $b as xs:double, $alpha as xs:double) as xs:double
declare function linear($a as xs:double, $b as xs:double, $alpha as xs:double) as xs:double
Linear interpolation
Params
- a as xs:double
- b as xs:double
- alpha as xs:double
Returns
- xs:double
declare function this:linear($a as xs:double, $b as xs:double, $alpha as xs:double) as xs:double { $alpha * ($b - $a) + $a }
Function: cubic
declare function cubic($n0 as xs:double, $n1 as xs:double, $n2 as xs:double, $n3 as xs:double, $alpha as xs:double) as xs:double
declare function cubic($n0 as xs:double, $n1 as xs:double, $n2 as xs:double, $n3 as xs:double, $alpha as xs:double) as xs:double
Cubic interpolation
Params
- n0 as xs:double
- n1 as xs:double
- n2 as xs:double
- n3 as xs:double
- alpha as xs:double
Returns
- xs:double
declare function this:cubic($n0 as xs:double, $n1 as xs:double, $n2 as xs:double, $n3 as xs:double, $alpha as xs:double) as xs:double { let $p := ($n3 - $n2) - ($n0 - $n1) let $q := ($n0 - $n1) - $p let $r := $n2 - $n0 let $s := $n1 return $p * $alpha * $alpha * $alpha + $q * $alpha * $alpha + $r * $alpha + $s }
Function: select
declare function select($f1 as item(),
$f2 as item(),
$control as item(),
$lower as xs:double, (: default 0.0 :)
$upper as xs:double, (: default 1.0 :)
$falloff as xs:double) as map(*)
declare function select($f1 as item(), $f2 as item(), $control as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double, (: default 1.0 :) $falloff as xs:double) as map(*)
select()
Noise function that outputs the value selected from one of two source
functions chosen by the output value from a control function.
If output value from control function is in the selection range, then
output value of f2, otherwise value of f1.
If we have positive falloff; do some linear interpolation around the
boundaries.
Params
- f1 as item()
- f2 as item()
- control as item()
- lower as xs:double
- upper as xs:double
- falloff as xs:double
Returns
- map(*)
declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double, (: default 1.0 :) $falloff as xs:double (: default 0.0 :) ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (not(ann:is-noise($control))) then errors:error("ML-BADARGS", ("control", $control)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2) and ann:is-noise-vector($control)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() let $controlfn := $control=>ann:function() return ann:fv("mod:select", function ($point as xs:double*) as xs:double { let $control-value := $controlfn($point) return ( if ($falloff > 0) then ( if ($control-value < $lower - $falloff) then ( $fn1($point) ) else if ($control-value < $lower + $falloff) then ( let $lower-curve := $lower - $falloff let $upper-curve := $lower + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else if ($control-value < $upper - $falloff) then ( $fn2($point) ) else if ($control-value < $upper + $falloff) then ( let $lower-curve := $upper - $falloff let $upper-curve := $upper + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else ( $fn1($point) ) ) else if ($control-value < $lower or $control-value > $upper) then ( $fn1($point) ) else ( $fn2($point) ) ) }, ($f1, $f2, $control, $lower, $upper, $falloff) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() let $controlfn := $control=>this:as-point()=>ann:function() return ( ann:f("mod:select", function ($point as map(xs:string,item()*)) as xs:double { let $control-value := $controlfn($point) return ( if ($falloff > 0) then ( if ($control-value < $lower - $falloff) then ( $fn1($point) ) else if ($control-value < $lower + $falloff) then ( let $lower-curve := $lower - $falloff let $upper-curve := $lower + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else if ($control-value < $upper - $falloff) then ( $fn2($point) ) else if ($control-value < $upper + $falloff) then ( let $lower-curve := $upper - $falloff let $upper-curve := $upper + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else ( $fn1($point) ) ) else if ($control-value < $lower or $control-value > $upper) then ( $fn1($point) ) else ( $fn2($point) ) ) }, ($f1, $f2, $control, $lower, $upper, $falloff) ) ) ) }
Function: select
declare function select($f1 as item(),
$f2 as item(),
$control as item(),
$lower as xs:double, (: default 0.0 :)
$upper as xs:double) as map(*)
declare function select($f1 as item(), $f2 as item(), $control as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double) as map(*)
Params
- f1 as item()
- f2 as item()
- control as item()
- lower as xs:double
- upper as xs:double
Returns
- map(*)
declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double (: default 1.0 :) ) as map(*) { this:select($f1, $f2, $control, $lower, $upper, 0.0) }
Function: select
declare function select($f1 as item(),
$f2 as item(),
$control as item()) as map(*)
declare function select($f1 as item(), $f2 as item(), $control as item()) as map(*)
Params
- f1 as item()
- f2 as item()
- control as item()
Returns
- map(*)
declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item() ) as map(*) { this:select($f1, $f2, $control, 0.0, 1.0, 0.0) }
Function: select
declare function select($f1 as item(),
$f2 as item(),
$control as item(),
$falloff as xs:double) as map(*)
declare function select($f1 as item(), $f2 as item(), $control as item(), $falloff as xs:double) as map(*)
Params
- f1 as item()
- f2 as item()
- control as item()
- falloff as xs:double
Returns
- map(*)
declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item(), $falloff as xs:double ) as map(*) { this:select($f1, $f2, $control, 0.0, 1.0, $falloff) }
Function: range
declare function range($f1 as item(),
$f2 as item(),
$lower as xs:double, (: default 0.0 :)
$upper as xs:double) as map(*)
declare function range($f1 as item(), $f2 as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double) as map(*)
range()
Noise function that outputs the value selected from one noise function
if it is in a particular range, and the value of the other one otherwise.
functions chosen by the output value from a control function.
Params
- f1 as item()
- f2 as item()
- lower as xs:double
- upper as xs:double
Returns
- map(*)
declare %art:noise function this:range( $f1 as item(), $f2 as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double (: default 1.0 :) ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:select", function ($point as xs:double*) as xs:double { let $probe := $fn1($point) return ( if (util:twixt($probe, $lower, $upper)) then ( $probe ) else ( $fn2($point) ) ) }, ($f1, $f2, $lower, $upper) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:range", function ($point as map(xs:string,item()*)) as xs:double { let $probe := $fn1($point) return ( if (util:twixt($probe, $lower, $upper)) then ( $probe ) else ( $fn2($point) ) ) }, ($f1, $f2, $lower, $upper) ) ) ) }
Function: range
declare function range($f1 as item(),
$f2 as item()) as map(*)
declare function range($f1 as item(), $f2 as item()) as map(*)
Params
- f1 as item()
- f2 as item()
Returns
- map(*)
declare %art:noise function this:range( $f1 as item(), $f2 as item() ) as map(*) { this:range($f1, $f2, 0.0, 1.0) }
Function: displace
declare function displace($f as item(),
$displace-x as item(),
$displace-y as item()) as map(*)
declare function displace($f as item(), $displace-x as item(), $displace-y as item()) as map(*)
displace()
Noise function that displaces point based on displacement functions
before applying function.
Params
- f as item()
- displace-x as item()
- displace-y as item()
Returns
- map(*)
declare %art:noise function this:displace( $f as item(), $displace-x as item(), $displace-y as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($displace-x))) then errors:error("ML-BADARGS", ("displace-x", $displace-x)) else (), if (not(ann:is-noise($displace-y))) then errors:error("ML-BADARGS", ("displace-y", $displace-y)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $displace-xfn := $displace-x=>this:as-vector()=>ann:function() let $displace-yfn := $displace-y=>this:as-vector()=>ann:function() return ann:fv("mod:displace", function ($point as xs:double*) as xs:double { $fn(affine:affine2($point, affine:translation2($displace-xfn($point), $displace-yfn($point)))) }, ($f, $displace-x, $displace-y) ) ) else ( let $fn := $f=>ann:function() let $displace-xfn := $displace-x=>this:as-point()=>ann:function() let $displace-yfn := $displace-y=>this:as-point()=>ann:function() return ( ann:f("mod:displace", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $displace-xfn($point), $displace-yfn($point))) }, ($f, $displace-x, $displace-y) ) ) ) }
Function: rotate
declare function rotate($f as item(),
$degrees as item(),
$center as map(xs:string,item()*)) as map(*)
declare function rotate($f as item(), $degrees as item(), $center as map(xs:string,item()*)) as map(*)
rotate()
Noise function that rotates input point around center before
applying function to it.
Params
- f as item()
- degrees as item()
- center as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:rotate( $f as item(), $degrees as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($degrees))) then errors:error("ML-BADARGS", ("degrees", $degrees)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $degreesfn := $degrees=>this:as-vector()=>ann:function() return ann:fv("mod:rotate", function ($point as xs:double*) as xs:double { $fn(affine:affine2($point, affine:rotation2($center, $degreesfn($point)))) }, ($f, $degrees, $center) ) ) else ( let $fn := $f=>ann:function() let $degreesfn := $degrees=>this:as-point()=>ann:function() return ( ann:f("mod:rotate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:rotate($point, $degreesfn($point), $center)) }, ($f, $degrees, $center) ) ) ) }
Function: rotate
declare function rotate($f as item(),
$degrees as item()) as map(*)
declare function rotate($f as item(), $degrees as item()) as map(*)
rotate()
Noise function that rotates input point around origin
applying function to it.
Params
- f as item()
- degrees as item()
Returns
- map(*)
declare %art:noise function this:rotate( $f as item(), $degrees as item() ) as map(*) { this:rotate($f, $degrees, $point:ORIGIN) }
Function: rotate
declare function rotate($f as item(),
$roll-degrees as item(),
$pitch-degrees as item(),
$yaw-degrees as item(),
$center as map(xs:string,item()*)) as map(*)
declare function rotate($f as item(), $roll-degrees as item(), $pitch-degrees as item(), $yaw-degrees as item(), $center as map(xs:string,item()*)) as map(*)
rotate()
Noise function that rotates input point around center
applying function to it.
Params
- f as item()
- roll-degrees as item()
- pitch-degrees as item()
- yaw-degrees as item()
- center as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:rotate( $f as item(), $roll-degrees as item(), $pitch-degrees as item(), $yaw-degrees as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($roll-degrees))) then errors:error("ML-BADARGS", ("roll-degrees", $roll-degrees)) else (), if (not(ann:is-noise($pitch-degrees))) then errors:error("ML-BADARGS", ("pitch-degrees", $pitch-degrees)) else (), if (not(ann:is-noise($yaw-degrees))) then errors:error("ML-BADARGS", ("yaw-degrees", $yaw-degrees)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $rollfn := $roll-degrees=>this:as-vector()=>ann:function() let $pitchfn := $pitch-degrees=>this:as-vector()=>ann:function() let $yawfn := $yaw-degrees=>this:as-vector()=>ann:function() return ann:fv("mod:rotate", function ($point as xs:double*) as xs:double { $fn( affine:affine3( $point, affine:rotation3( $center, $rollfn($point), $pitchfn($point), $yawfn($point) ) ) ) }, ($f, $roll-degrees, $pitch-degrees, $yaw-degrees, $center) ) ) else ( let $fn := $f=>ann:function() let $rollfn := $roll-degrees=>this:as-point()=>ann:function() let $pitchfn := $pitch-degrees=>this:as-point()=>ann:function() let $yawfn := $yaw-degrees=>this:as-point()=>ann:function() return ( ann:f("mod:rotate", function ($point as map(xs:string,item()*)) as xs:double { $fn( affine:rotate( $point, $rollfn($point), $pitchfn($point), $yawfn($point), $center ) ) }, ($f, $roll-degrees, $pitch-degrees, $yaw-degrees, $center) ) ) ) }
Function: rotate
declare function rotate($f as item(),
$roll-degrees as item(),
$pitch-degrees as item(),
$yaw-degrees as item()) as map(*)
declare function rotate($f as item(), $roll-degrees as item(), $pitch-degrees as item(), $yaw-degrees as item()) as map(*)
rotate()
Noise function that rotates input point around origin
applying function to it.
Params
- f as item()
- roll-degrees as item()
- pitch-degrees as item()
- yaw-degrees as item()
Returns
- map(*)
declare %art:noise function this:rotate( $f as item(), $roll-degrees as item(), $pitch-degrees as item(), $yaw-degrees as item() ) as map(*) { this:rotate($f, $roll-degrees, $pitch-degrees, $yaw-degrees, $point:ORIGIN3D) }
Function: scale
declare function scale($f as item(),
$sx as item(),
$sy as item()) as map(*)
declare function scale($f as item(), $sx as item(), $sy as item()) as map(*)
scale()
Noise function that scales the input point before applying function
to it.
Params
- f as item()
- sx as item(): scaling to x coordinate
- sy as item(): scaling to y coordinate
Returns
- map(*)
declare %art:noise function this:scale( $f as item(), $sx as item(), $sy as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:scaling2($sxfn($point), $syfn($point))) ) }, ($f, $sx, $sy) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale($point, $sxfn($point), $syfn($point))) }, ($f, $sx, $sy) ) ) ) }
Function: scale
declare function scale($f as item(),
$scale as item()) as map(*)
declare function scale($f as item(), $scale as item()) as map(*)
scale()
Noise function that scales the input point before applying function
to it.
Params
- f as item()
- scale as item(): scale to apply to each coordinate
Returns
- map(*)
declare %art:noise function this:scale( $f as item(), $scale as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($scale))) then errors:error("ML-BADARGS", ("scale", $scale)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $scalefn := $scale=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn($point=>v:times($scalefn($point))) }, ($f, $scale) ) ) else ( let $fn := $f=>ann:function() let $scalefn := $scale=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn($point=>point:times($scalefn($point))) }, ($f, $scale) ) ) ) }
Function: scale
declare function scale($f as item(),
$sx as item(),
$sy as item(),
$center as map(xs:string,item()*)) as map(*)
declare function scale($f as item(), $sx as item(), $sy as item(), $center as map(xs:string,item()*)) as map(*)
scale()
Noise function that scales the input point before applying function
to it.
Params
- f as item()
- sx as item(): scaling to x coordinate
- sy as item(): scaling to y coordinate
- center as map(xs:string,item()*): center of scaling
Returns
- map(*)
declare %art:noise function this:scale( $f as item(), $sx as item(), $sy as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:scaling2($center, $sxfn($point), $syfn($point))) ) }, ($f, $sx, $sy, $center) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale($point, $sxfn($point), $syfn($point), $center)) }, ($f, $sx, $sy, $center) ) ) ) }
Function: scale3D
declare function scale3D($f as item(),
$sx as item(),
$sy as item(),
$sz as item()) as map(*)
declare function scale3D($f as item(), $sx as item(), $sy as item(), $sz as item()) as map(*)
scale3D()
Noise function that scales the input point before applying function
to it.
Params
- f as item()
- sx as item(): scaling to x coordinate
- sy as item(): scaling to y coordinate
- sz as item(): scaling to y coordinate
Returns
- map(*)
declare %art:noise function this:scale3D( $f as item(), $sx as item(), $sy as item(), $sz as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (not(ann:is-noise($sz))) then errors:error("ML-BADARGS", ("sz", $sz)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() let $szfn := $sz=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:scaling3($sxfn($point), $syfn($point), $szfn($point))) ) }, ($f, $sx, $sy, $sz) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() let $szfn := $sz=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale3D($point, $sxfn($point), $syfn($point), $szfn($point))) }, ($f, $sx, $sy, $sz) ) ) ) }
Function: scale3D
declare function scale3D($f as item(),
$sx as item(),
$sy as item(),
$sz as item(),
$center as map(xs:string,item()*)) as map(*)
declare function scale3D($f as item(), $sx as item(), $sy as item(), $sz as item(), $center as map(xs:string,item()*)) as map(*)
scale3D()
Noise function that scales the input point relative to a center
before applying function to it.
Params
- f as item()
- sx as item(): scaling to x coordinate
- sy as item(): scaling to y coordinate
- sz as item(): scaling to y coordinate
- center as map(xs:string,item()*): center of scaling
Returns
- map(*)
declare %art:noise function this:scale3D( $f as item(), $sx as item(), $sy as item(), $sz as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (not(ann:is-noise($sz))) then errors:error("ML-BADARGS", ("sz", $sz)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() let $szfn := $sz=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:scaling3($center, $sxfn($point), $syfn($point), $szfn($point))) ) }, ($f, $sx, $sy, $sz, $center) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() let $szfn := $sz=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale3D($point, $sxfn($point), $syfn($point), $szfn($point), $center)) }, ($f, $sx, $sy, $sz, $center) ) ) ) }
Function: translate
declare function translate($f as item(),
$tx as item(),
$ty as item()) as map(*)
declare function translate($f as item(), $tx as item(), $ty as item()) as map(*)
translate()
Noise function that translates the input point before applying function
to it.
Params
- f as item()
- tx as item()
- ty as item()
Returns
- map(*)
declare %art:noise function this:translate( $f as item(), $tx as item(), $ty as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($tx))) then errors:error("ML-BADARGS", ("tx", $tx)) else (), if (not(ann:is-noise($ty))) then errors:error("ML-BADARGS", ("ty", $ty)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-vector()=>ann:function() let $tyfn := $ty=>this:as-vector()=>ann:function() return ann:fv("mod:translate", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:translation2($txfn($point), $tyfn($point))) ) }, ($f, $tx, $ty) ) ) else ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-point()=>ann:function() let $tyfn := $ty=>this:as-point()=>ann:function() return ( ann:f("mod:translate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $txfn($point), $tyfn($point))) }, ($f, $tx, $ty) ) ) ) }
Function: translate
declare function translate($f as item(),
$tx as item(),
$ty as item(),
$tz as item()) as map(*)
declare function translate($f as item(), $tx as item(), $ty as item(), $tz as item()) as map(*)
translate()
Noise function that translates the input point before applying function
to it.
Params
- f as item()
- tx as item()
- ty as item()
- tz as item()
Returns
- map(*)
declare %art:noise function this:translate( $f as item(), $tx as item(), $ty as item(), $tz as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($tx))) then errors:error("ML-BADARGS", ("tx", $tx)) else (), if (not(ann:is-noise($ty))) then errors:error("ML-BADARGS", ("ty", $ty)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-vector()=>ann:function() let $tyfn := $ty=>this:as-vector()=>ann:function() let $tzfn := $tz=>this:as-vector()=>ann:function() return ann:fv("mod:translate", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:translation3($txfn($point), $tyfn($point), $tzfn($point))) ) }, ($f, $tx, $ty, $tz) ) ) else ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-point()=>ann:function() let $tyfn := $ty=>this:as-point()=>ann:function() let $tzfn := $tz=>this:as-point()=>ann:function() return ( ann:f("mod:translate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $txfn($point), $tyfn($point), $tzfn($point))) }, ($f, $tx, $ty, $tz) ) ) ) }
Function: shear
declare function shear($f as item(),
$xy as item(),
$yx as item()) as map(*)
declare function shear($f as item(), $xy as item(), $yx as item()) as map(*)
shear()
Noise function that shears the input point before applying function
to it.
Params
- f as item()
- xy as item()
- yx as item()
Returns
- map(*)
declare %art:noise function this:shear( $f as item(), $xy as item(), $yx as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($xy))) then errors:error("ML-BADARGS", ("xy", $xy)) else (), if (not(ann:is-noise($yx))) then errors:error("ML-BADARGS", ("yx", $yx)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-vector()=>ann:function() let $yxfn := $yx=>this:as-vector()=>ann:function() return ann:fv("mod:translate", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:shearing2($xyfn($point), $yxfn($point))) ) }, ($f, $xy, $yx) ) ) else ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-point()=>ann:function() let $yxfn := $yx=>this:as-point()=>ann:function() return ( ann:f("mod:translate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $xyfn($point), $yxfn($point))) }, ($f, $xy, $yx) ) ) ) }
Function: shear
declare function shear($f as item(),
$xy as item(),
$yx as item(),
$xz as item(),
$zx as item(),
$yz as item(),
$zy as item()) as map(*)
declare function shear($f as item(), $xy as item(), $yx as item(), $xz as item(), $zx as item(), $yz as item(), $zy as item()) as map(*)
shear()
Noise function that shears the input point before applying function
to it.
Params
- f as item()
- xy as item()
- yx as item()
- xz as item()
- zx as item()
- yz as item()
- zy as item()
Returns
- map(*)
declare %art:noise function this:shear( $f as item(), $xy as item(), $yx as item(), $xz as item(), $zx as item(), $yz as item(), $zy as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($xy))) then errors:error("ML-BADARGS", ("xy", $xy)) else (), if (not(ann:is-noise($yx))) then errors:error("ML-BADARGS", ("yx", $yx)) else (), if (not(ann:is-noise($xz))) then errors:error("ML-BADARGS", ("xz", $xz)) else (), if (not(ann:is-noise($zx))) then errors:error("ML-BADARGS", ("zx", $zx)) else (), if (not(ann:is-noise($yz))) then errors:error("ML-BADARGS", ("yz", $yz)) else (), if (not(ann:is-noise($zy))) then errors:error("ML-BADARGS", ("zy", $zy)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-vector()=>ann:function() let $yxfn := $yx=>this:as-vector()=>ann:function() let $xzfn := $xz=>this:as-vector()=>ann:function() let $zxfn := $zx=>this:as-vector()=>ann:function() let $yzfn := $yz=>this:as-vector()=>ann:function() let $zyfn := $zy=>this:as-vector()=>ann:function() return ann:fv("mod:shear", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:shearing3( $xyfn($point), $yxfn($point), $xzfn($point), $zxfn($point), $yzfn($point), $zyfn($point) ) ) ) }, ($f, $xy, $yx, $xz, $zx, $yz, $zy) ) ) else ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-point()=>ann:function() let $yxfn := $yx=>this:as-point()=>ann:function() let $xzfn := $xz=>this:as-point()=>ann:function() let $zxfn := $zx=>this:as-point()=>ann:function() let $yzfn := $yz=>this:as-point()=>ann:function() let $zyfn := $zy=>this:as-point()=>ann:function() return ( ann:f("mod:shear", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:shear($point, $xyfn($point), $yxfn($point), $xzfn($point), $zxfn($point), $yzfn($point), $zyfn($point))) }, ($f, $xy, $yx, $xz, $zx, $yz, $zy) ) ) ) }
Function: reflect
declare function reflect($f as item(),
$center as map(xs:string,item()*)) as map(*)
declare function reflect($f as item(), $center as map(xs:string,item()*)) as map(*)
reflect()
Noise function that reflects the input point across a point
before applying function to it.
Params
- f as item()
- center as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:reflect( $f as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:reflect", function ($point as xs:double*) as xs:double { if (count($point)=2) then ( $fn(affine:affine2($point, affine:reflection2($center))) ) else ( $fn(affine:affine3($point, affine:reflection3($center))) ) }, ($f, $center) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:reflect", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:reflect($point, $center)) }, ($f, $center) ) ) ) }
Function: reflect
declare function reflect($f as item()) as map(*)
declare function reflect($f as item()) as map(*)
reflect()
Noise function that reflects the input point across the origin
before applying function to it.
Params
- f as item()
Returns
- map(*)
declare %art:noise function this:reflect( $f as item() ) as map(*) { this:reflect($f, $point:ORIGIN) }
Function: reflect
declare function reflect($f as item(),
$start as map(xs:string,item()*),
$end as map(xs:string,item()*)) as map(*)
declare function reflect($f as item(), $start as map(xs:string,item()*), $end as map(xs:string,item()*)) as map(*)
reflect()
Noise function that reflects the input point across a line
before applying function to it.
Params
- f as item()
- start as map(xs:string,item()*)
- end as map(xs:string,item()*)
Returns
- map(*)
declare %art:noise function this:reflect( $f as item(), $start as map(xs:string,item()*), $end as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:reflect", function ($point as xs:double*) as xs:double { $fn(affine:affine2($point, affine:reflection2($start,$end))) }, ($f, $start, $end) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:reflect", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:reflect($point, $start, $end)) }, ($f, $start, $end) ) ) ) }
Function: destination
declare function destination($f as item(),
$angle as item(),
$length as item()) as map(*)
declare function destination($f as item(), $angle as item(), $length as item()) as map(*)
destination()
Noise function that shifts the point to a new point based on the
length and destination computed from other functions before applying
the base function
Params
- f as item()
- angle as item()
- length as item()
Returns
- map(*)
declare %art:noise function this:destination( $f as item(), $angle as item(), $length as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($angle))) then errors:error("ML-BADARGS", ("angle", $f)) else (), if (not(ann:is-noise($length))) then errors:error("ML-BADARGS", ("length", $length)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $anglefn := $angle=>this:as-vector()=>ann:function() let $lengthfn := $length=>this:as-vector()=>ann:function() return ann:fv("mod:destination", function ($point as xs:double*) as xs:double { $fn(point:pcoordinates(point:destination(point:vector($point), $anglefn($point), $lengthfn($point)))) }, ($f, $angle, $length) ) ) else ( let $fn := $f=>ann:function() let $anglefn := $angle=>this:as-point()=>ann:function() let $lengthfn := $length=>this:as-point()=>ann:function() return ( ann:f("mod:destination", function ($point as map(xs:string,item()*)) as xs:double { $fn(point:destination($point, $anglefn($point), $lengthfn($point))) }, ($f, $angle, $length) ) ) ) }
Function: jitter
declare function jitter($f as item(),
$jitter as item()) as map(*)
declare function jitter($f as item(), $jitter as item()) as map(*)
jitter()
Noise function that jitters the point based on output from a jitter
function (using this:random() would be appropriate here)
Params
- f as item()
- jitter as item()
Returns
- map(*)
declare %art:noise function this:jitter( $f as item(), $jitter as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($jitter))) then errors:error("ML-BADARGS", ("jitter", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $jitterfn := $jitter=>this:as-vector()=>ann:function() return ann:fv("mod:jitter", function ($point as xs:double*) as xs:double { let $dim := count($point) let $coords := for $i in 1 to $dim return $jitterfn($point) let $delta := switch($dim) case 2 return ($coords[1], $coords[2]) case 3 return ($coords[1], $coords[2], $coords[3]) case 4 return ($coords[1], $coords[2], $coords[3], $coords[4]) default return errors:error("ML-BADARGS", ("point", $point)) return $fn(v:add($point, $delta)) }, ($f, $jitter) ) ) else ( let $fn := $f=>ann:function() let $jitterfn := $jitter=>this:as-point()=>ann:function() return ( ann:f("mod:jitter", function ($point as map(xs:string,item()*)) as xs:double { let $dim := point:dimension($point) let $coords := for $i in 1 to $dim return $jitterfn($point) let $delta := switch($dim) case 2 return point:point($coords[1], $coords[2]) case 3 return point:point($coords[1], $coords[2], $coords[3]) case 4 return point:point($coords[1], $coords[2], $coords[3], $coords[4]) default return errors:error("ML-BADARGS", ("point", $point)) return $fn(point:add($point, $delta)) }, ($f, $jitter) ) ) ) }
Function: mutate
declare function mutate($f as item(),
$mutation as item()) as map(*)
declare function mutate($f as item(), $mutation as item()) as map(*)
mutate()
Noise function that applies a mutation function to the input point before
applying function to it
Params
- f as item()
- mutation as item()
Returns
- map(*)
declare %art:noise function this:mutate( $f as item(), $mutation as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(mutation:is-mutation($mutation))) then errors:error("ML-BADARGS", ("mutation", $mutation)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $mutationfn := $mutation=>mutation:function() return ( if (mutation:is-mutation-vector($mutation)) then ( ann:fv("mod:mutate", function ($point as xs:double*) as xs:double { $fn($mutationfn($point)) }, ($f) ) ) else ( ann:fv("mod:mutate", function ($point as xs:double*) as xs:double { $fn(point:pcoordinates($mutationfn(point:vector($point)))) }, ($f) ) ) ) ) else ( let $fn := $f=>ann:function() let $mutationfn := $mutation=>mutation:function() return ( if (mutation:is-mutation-vector($mutation)) then ( ann:f("mod:mutate", function ($point as map(xs:string,item()*)) as xs:double { $fn(point:vector($mutationfn(point:pcoordinates($point)))) }, ($f) ) ) else ( ann:f("mod:mutate", function ($point as map(xs:string,item()*)) as xs:double { $fn($mutationfn($point)) }, ($f) ) ) ) ) }
Original Source Code
xquery version "3.1"; (:~ : Noise function modifications: create new functions from multiple noise : functions with different parameters : Port/refactor/expansion of https://github.com/razaekel/noise-rs : : As of 202303 these functions do not return annotated functions, but wrapped : callables. You'll need to use callable:function() to get the actual function : to use. : : Copyright© Mary Holstege 2020-2023 : CC-BY (https://creativecommons.org/licenses/by/4.0/) : @since April 2021 : @custom:Status Active :) module namespace this="http://mathling.com/noise/modifiers"; declare namespace art="http://mathling.com/art"; declare namespace map="http://www.w3.org/2005/xpath-functions/map"; declare namespace math="http://www.w3.org/2005/xpath-functions/math"; declare namespace saxon="http://saxon.sf.net/"; import module namespace errors="http://mathling.com/core/errors" at "../core/errors.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 util="http://mathling.com/core/utilities" at "../core/utilities.xqy"; import module namespace affine="http://mathling.com/geometric/affine" at "../geo/affine.xqy"; import module namespace point="http://mathling.com/geometric/point" at "../geo/point.xqy"; import module namespace mutation="http://mathling.com/geometric/mutation" at "../geo/mutation.xqy"; import module namespace v="http://mathling.com/core/vector" at "../core/vector.xqy"; import module namespace ann="http://mathling.com/noise/annotations" at "../noise/annotations.xqy"; (:======================================================================: : Basic noise functions: : Useful when we want something simple for one of the controller : functions :======================================================================:) (:~ : trace() : Noise function that just passes through with a trace of the value :) declare %art:noise function this:trace( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( ann:f(util:function-name($f), function ($point as map(xs:string,item()*)) as xs:double { $fn($point)=>trace(util:quote($f)||"("||point:quote($point)||")") } ) ) else ( ann:fv(util:function-name($f), function ($point as xs:double*) as xs:double { $fn($point)=>trace(util:quote($f)||"("||v:quote($point)||")") } ) ) ) }; (:~ : trace-bounds() : Noise function that just passes through with a trace of the value, but : only if it is out of range :) declare %art:noise function this:trace-bounds( $f as item(), $low as xs:double, $high as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( ann:f(util:function-name($f), function ($point as map(xs:string,item()*)) as xs:double { let $val := $fn($point) return ( if (util:twixt($val, $low, $high)) then $val else $val=>trace(util:quote($f)||"("||point:quote($point)||")") ) } ) ) else ( ann:fv(util:function-name($f), function ($point as xs:double*) as xs:double { let $val := $fn($point) return ( if (util:twixt($val, $low, $high)) then $val else $val=>trace(util:quote($f)||"("||v:quote($point)||")") ) } ) ) ) }; (:~ : cache() : Wrap noise function in a caching function (depends on saxon:memo-function) : : @param $f: base noise function :) declare %art:noise function this:cache( $f as item() ) as item() { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( let $cached := this:cache-point($fn, ?) return ( ann:f(util:function-name($f), function ($point as map(xs:string,item()*)) as xs:double { $cached($point) } ) ) ) else ( let $cached := this:cache-vector($fn, ?) return ( ann:fv(util:function-name($f), function ($point as xs:double*) as xs:double { $cached($point) } ) ) ) ) }; declare %saxon:memo-function function this:cache-vector( $fn as function(xs:double*) as xs:double, $point as xs:double* ) as xs:double { $fn($point) }; declare %saxon:memo-function function this:cache-point( $fn as function(map(xs:string,item()*)) as xs:double, $point as map(xs:string,item()*) ) as xs:double { $fn($point) }; (:~ : 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-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-vector($f)) then ( ann:f(util:function-name($f), function($point as map(xs:string,item()*)) as xs:double { $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-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := ann:function($f) return ( if (ann:is-noise-point($f)) then ( ann:fv(util:function-name($f), function($point as xs:double*) as xs:double { $fn(point:vector($point)) } ) ) else ( $f ) ) }; (:~ : constant() : Base noise function that returns a constant value :) declare %art:noise function this:constant( $c as xs:double ) as map(*) { ann:f("", (: Just the constant :) function ($point as map(xs:string,item()*)) as xs:double { $c }, $c ) }; (:~ : constant-vector() : Base noise function that returns a constant value (vector form) :) declare %art:noise function this:constant-vector( $c as xs:double ) as map(*) { ann:fv("", (: Just the constant :) function ($point as xs:double*) as xs:double { $c }, $c ) }; (:~ : random() : Base noise function that returns a value out of the given distribution, : ignoring the point completely :) declare %art:noise function this:random( $distribution as map(xs:string,item()*) ) as map(*) { ann:f("mod:random", function ($point as map(xs:string,item()*)) as xs:double { rand:randomize($distribution) }, $distribution ) }; (:~ : random-vector() : Base noise function that returns a value out of the given distribution, : ignoring the point completely (vector form) :) declare %art:noise function this:random-vector( $distribution as map(xs:string,item()*) ) as map(*) { ann:fv("mod:random", function ($point as xs:double*) as xs:double { rand:randomize($distribution) }, $distribution ) }; (:~ : random-last() : Base noise function that returns a value out of the given distribution, : using $f($point) as the last value for the distribution :) declare %art:noise function this:random-last( $f as item(), $distribution as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := $f=>ann:function() return ann:f("mod:random", function ($point as map(xs:string,item()*)) as xs:double { rand:randomize(1, $fn($point), $distribution) }, ($f, $distribution) ) }; (:~ : random-last-vector() : Base noise function that returns a value out of the given distribution, : using $f($point) as the last value for the distribution. (Vector form.) :) declare %art:noise function this:random-last-vector( $f as item(), $distribution as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $fn := $f=>ann:function() return ann:fv("mod:random", function ($point as xs:double*) as xs:double { rand:randomize(1, $fn($point), $distribution) }, ($f, $distribution) ) }; (:~ : cylinders() : Base noise function that outputs concentric cylinders. : : This noise function outputs concentric cylinders centered on the origin. The : cylinders are oriented along the z axis similar to the concentric rings of : a tree. Each cylinder extends infinitely along the z axis. : : @param $frequency: Frequency of concentric objects :) declare %art:noise function this:cylinders( $frequency as xs:double ) as map(*) { ann:f("mod:cylinders", function ($point as map(xs:string,item()*)) as xs:double { let $scaled := affine:scale($point=>point:as-dimension(2), $frequency) let $dist-from-center := point:distance($scaled, $point:ORIGIN) let $dist-from-smaller-sphere := $dist-from-center - floor($dist-from-center) let $dist-from-larger-sphere := 1.0 - $dist-from-smaller-sphere let $nearest-dist := min(($dist-from-smaller-sphere, $dist-from-larger-sphere)) (: Shift to [-1,1] range :) return 1.0 - ($nearest-dist * 4.0) }, ($frequency) ) }; declare %art:noise function this:cylinders( ) as map(*) { this:cylinders(1.0) }; (:~ : cylinders-vector() : Base noise function that outputs concentric cylinders. (Vector form.) : : This noise function outputs concentric cylinders centered on the origin. The : cylinders are oriented along the z axis similar to the concentric rings of : a tree. Each cylinder extends infinitely along the z axis. : : @param $frequency: Frequency of concentric objects :) declare %art:noise function this:cylinders-vector( $frequency as xs:double ) as map(*) { ann:fv("mod:cylinders", function ($point as xs:double*) as xs:double { let $scaled := affine:affine2($point, affine:scaling2($frequency, $frequency)) let $dist-from-center := v:distance($scaled, (0,0)) let $dist-from-smaller-sphere := $dist-from-center - floor($dist-from-center) let $dist-from-larger-sphere := 1.0 - $dist-from-smaller-sphere let $nearest-dist := min(($dist-from-smaller-sphere, $dist-from-larger-sphere)) (: Shift to [-1,1] range :) return 1.0 - ($nearest-dist * 4.0) }, ($frequency) ) }; declare %art:noise function this:cylinders-vector( ) as map(*) { this:cylinders-vector(1.0) }; (:======================================================================: : Output modifiers: : Adjust the output of the base noise function in some way :======================================================================:) (:~ : add() : Noise function is sum of two noise functions :) declare %art:noise function this:add( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:add", function ($point as xs:double*) as xs:double { $fn1($point) + $fn2($point) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:add", function ($point as map(xs:string,item()*)) as xs:double { $fn1($point) + $fn2($point) }, ($f1, $f2) ) ) ) }; (:~ : max() : Noise function is max of two noise functions :) declare %art:noise function this:max( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:max", function ($point as xs:double*) as xs:double { max(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:max", function ($point as map(xs:string,item()*)) as xs:double { max(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) ) }; (:~ : min() : Noise function is min of two noise functions :) declare %art:noise function this:min( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:min", function ($point as xs:double*) as xs:double { min(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:min", function ($point as map(xs:string,item()*)) as xs:double { min(($fn1($point), $fn2($point))) }, ($f1, $f2) ) ) ) }; (:~ : multiply() : Noise function is multiplication of two noise functions :) declare %art:noise function this:multiply( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:multiply", function ($point as xs:double*) as xs:double { $fn1($point) * $fn2($point) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:multiply", function ($point as map(xs:string,item()*)) as xs:double { $fn1($point) * $fn2($point) }, ($f1, $f2) ) ) ) }; (:~ : pow() : Noise function is output of first noise function raised to power of second :) declare %art:noise function this:pow( $f1 as item(), $f2 as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:pow", function ($point as xs:double*) as xs:double { math:pow($fn1($point), $fn2($point)) }, ($f1, $f2) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:pow", function ($point as map(xs:string,item()*)) as xs:double { math:pow($fn1($point), $fn2($point)) }, ($f1, $f2) ) ) ) }; (:~ : abs() : Noise function that is the absolute value of input noise function :) declare %art:noise function this:abs( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:abs", function ($point as xs:double*) as xs:double { abs($fn($point)) }, $f ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:abs", function ($point as map(xs:string,item()*)) as xs:double { abs($fn($point)) }, $f ) ) ) }; (:~ : clamp() : Noise function that clamps the output to a range of value :) declare %art:noise function this:clamp( $f as item(), $min as xs:double, $max as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:clamp", function ($point as xs:double*) as xs:double { max(($min, min(($max, $fn($point))))) }, $f ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:clamp", function ($point as map(xs:string,item()*)) as xs:double { max(($min, min(($max, $fn($point))))) }, $f ) ) ) }; (:~ : round() : Noise function that rounds the output :) declare %art:noise function this:round( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:round", function ($point as xs:double*) as xs:double { round($fn($point)) }, $f ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:round", function ($point as map(xs:string,item()*)) as xs:double { round($fn($point)) }, $f ) ) ) }; (:~ : curve() : Noise function that maps output onto a curve defined by a series : of control points; mapping is via cubic interpolation : Control points should have distinct x's; they don't have to be 2D, but only : 2 dimensions matter :) declare %art:noise function this:curve( $f as item(), $curve as map(xs:string,item()*)* ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $curve := for $pt in $curve order by point:px($pt) ascending return $pt (: Check distinct x values :) let $curve := ( for $pt at $i in tail($curve) return util:assert(point:px($pt)!=point:px($curve[$i]), "Control points must have different x values"), $curve ) let $n := count($curve) let $n := (util:assert($n >= 4, "Not enough control points"), $n) return if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:curve", function ($point as xs:double*) as xs:double { let $source-value := $fn($point) (: Find the first control point has an x value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $p at $i in $curve where point:px($p) > $source-value return $i, $n + 1 )[1] (: Ensure that the index is in [3, $n+1] :) let $index-pos := max((3, min(($n + 1, $index-pos)))) (: Find four nearest control points so we can perform cubic interpolation :) let $index0 := max((1, min(($n, $index-pos - 2)))) let $index1 := max((1, min(($n, $index-pos - 1)))) let $index2 := max((1, min(($n, $index-pos)))) let $index3 := max((1, min(($n, $index-pos + 1)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index1=$index2) then ( point:py($curve[$index1]) ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := point:px($curve[$index1]) let $input1 := point:px($curve[$index2]) let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Now perform the cubic interpolation :) return ( this:cubic( point:py($curve[$index0]), point:py($curve[$index1]), point:py($curve[$index2]), point:py($curve[$index3]), $alpha ) ) ) ) }, ($f, $curve) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:curve", function ($point as map(xs:string,item()*)) as xs:double { let $source-value := $fn($point) (: Find the first control point has an x value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $p at $i in $curve where point:px($p) > $source-value return $i, $n + 1 )[1] (: Ensure that the index is in [3, $n+1] :) let $index-pos := max((3, min(($n + 1, $index-pos)))) (: Find four nearest control points so we can perform cubic interpolation :) let $index0 := max((1, min(($n, $index-pos - 2)))) let $index1 := max((1, min(($n, $index-pos - 1)))) let $index2 := max((1, min(($n, $index-pos)))) let $index3 := max((1, min(($n, $index-pos + 1)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index1=$index2) then ( point:py($curve[$index1]) ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := point:px($curve[$index1]) let $input1 := point:px($curve[$index2]) let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Now perform the cubic interpolation :) return ( this:cubic( point:py($curve[$index0]), point:py($curve[$index1]), point:py($curve[$index2]), point:py($curve[$index3]), $alpha ) ) ) ) }, ($f, $curve) ) ) ) }; (:~ : exponent() : Noise function that maps output onto an exponential curve. : Because most noise functions will output values that range from -1.0 to 1.0, : this noise function first normalizes the output value (the range becomes 0.0 : to 1.0), maps that value onto an exponential curve, then rescales that : value back to the original range. :) declare %art:noise function this:exponent( $f as item(), $exponent as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:exponent", function ($point as xs:double*) as xs:double { abs(math:pow(abs(($fn($point) + 1.0) div 2.0), $exponent)) * 2.0 - 1.0 }, ($f, $exponent) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:exponent", function ($point as map(xs:string,item()*)) as xs:double { abs(math:pow(abs(($fn($point) + 1.0) div 2.0), $exponent)) * 2.0 - 1.0 }, ($f, $exponent) ) ) ) }; declare %art:noise function this:exponent( $f as item() ) as map(*) { this:exponent($f, 1.0) }; (:~ : negate() : Noise function that negates the output :) declare %art:noise function this:negate( $f as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:negate", function ($point as xs:double*) as xs:double { -$fn($point) }, ($f) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:negate", function ($point as map(xs:string,item()*)) as xs:double { -$fn($point) }, ($f) ) ) ) }; (:~ : scale-bias() : Noise function that applies a scaling factor and then a bias to the : source function. : Multiplies by the scaling factor, adds the bias. :) declare %art:noise function this:scale-bias( $f as item(), $scale as xs:double, $bias as xs:double ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:scale-bias", function ($point as xs:double*) as xs:double { $fn($point) * $scale + $bias }, ($f, $scale, $bias) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:scale-bias", function ($point as map(xs:string,item()*)) as xs:double { $fn($point) * $scale + $bias }, ($f, $scale, $bias) ) ) ) }; declare %art:noise function this:scale-bias( $f as item(), $scale as xs:double ) as map(*) { this:scale-bias($f, $scale, 0.0) }; declare %art:noise function this:scale-bias( $f as item() ) as map(*) { this:scale-bias($f, 1.0, 0.0) }; (:~ : terrace() : Noise function that maps the output value from source function : to a terrace-forming curve. : The start of the curve has a slope of zero, smoothly increasing. : It also has control points (x values) that reset the slope to 0 at that : point,producing the terracing effect. : There must be at least 2 control points, which have different values. : The function clamps the output value from the source function if it is : out of range of the control points. : This noise function is often used to generate terrain features such as the : stereotypical desert canyon. :) declare %art:noise function this:terrace( $f as item(), $control-points as xs:double*, $invert as xs:boolean ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), let $control-points := for $x in $control-points order by $x ascending return $x (: Check distinct values :) let $control-points := ( for $x at $i in tail($control-points) return util:assert($x!=$control-points[$i], "Control points must have different values"), $control-points ) let $n := count($control-points) let $n := (util:assert($n >= 2, "Not enough control points"), $n) return if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:terrace", function ($point as xs:double*) as xs:double { let $source-value := $fn($point) (: Find the first control point has a value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $x at $i in $control-points where $x > $source-value return $i, $n + 1 )[1] (: Find the two nearest control points so that we can map their values : onto a quadratic curve. :) let $index0 := max((1, min(($n, $index-pos - 1)))) let $index1 := max((1, min(($n, $index-pos)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index0 = $index1) then ( $control-points[$index1] ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := $control-points[$index0] let $input1 := $control-points[$index1] let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Squaring produces terrace effect :) let $alpha := if ($invert) then ( (1.0 - $alpha) * (1.0 - $alpha) ) else ( $alpha * $alpha ) return ( if ($invert) then ( (: Swap input0 and input1 :) this:linear($input1, $input0, $alpha) ) else ( this:linear($input0, $input1, $alpha) ) ) ) ) }, ($f, $control-points, $invert) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:terrace", function ($point as map(xs:string,item()*)) as xs:double { let $source-value := $fn($point) (: Find the first control point has a value larger : than the output value from the base function; n+1 if none :) let $index-pos := ( for $x at $i in $control-points where $x > $source-value return $i, $n + 1 )[1] (: Find the two nearest control points so that we can map their values : onto a quadratic curve. :) let $index0 := max((1, min(($n, $index-pos - 1)))) let $index1 := max((1, min(($n, $index-pos)))) (: If some control points are missing (which occurs if the value from : the source function is greater than the largest input value or less : than the smallest input value of the control point array), get the : corresponding output value of the nearest control point and exit. :) return ( if ($index0 = $index1) then ( $control-points[$index1] ) else ( (: Compute the alpha value used for cubic interpolation :) let $input0 := $control-points[$index0] let $input1 := $control-points[$index1] let $alpha := ($source-value - $input0) div ($input1 - $input0) (: Squaring produces terrace effect :) let $alpha := if ($invert) then ( (1.0 - $alpha) * (1.0 - $alpha) ) else ( $alpha * $alpha ) return ( if ($invert) then ( (: Swap input0 and input1 :) this:linear($input1, $input0, $alpha) ) else ( this:linear($input0, $input1, $alpha) ) ) ) ) }, ($f, $control-points, $invert) ) ) ) }; declare %art:noise function this:terrace( $f as item(), $control-points as xs:double* ) as map(*) { this:terrace($f, $control-points, false()) }; (:======================================================================: : Selector functions: : Combine multiple noise functions :======================================================================:) (:~ : blend() : Noise function that created weighted blend out output values from : source functions, using weighting produced by control function. : Uses linear interpolation: negative values from control functions : weight towards first function, positive towards second. :) declare %art:noise function this:blend( $f1 as item(), $f2 as item(), $control as item() ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (not(ann:is-noise($control))) then errors:error("ML-BADARGS", ("control", $control)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2) and ann:is-noise-vector($control)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() let $controlfn := $control=>ann:function() return ann:fv("mod:blend", function ($point as xs:double*) as xs:double { let $a := $fn1($point) let $b := $fn2($point) let $alpha := $controlfn($point) return this:linear($a, $b, $alpha) }, ($f1, $f2, $control) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() let $controlfn := $control=>this:as-point()=>ann:function() return ( ann:f("mod:blend", function ($point as map(xs:string,item()*)) as xs:double { let $a := $fn1($point) let $b := $fn2($point) let $alpha := $controlfn($point) return this:linear($a, $b, $alpha) }, ($f1, $f2, $control) ) ) ) }; (:~ Maps a value onto a cubic S-curve. :) declare function this:s-curve3($x as xs:double) as xs:double { $x * $x * (3.0 - ($x * 2.0)) }; declare function this:s-curve5($x as xs:double) as xs:double { $x * $x * $x * ($x * ($x * 6 - 15) + 10) }; (:~ Linear interpolation :) declare function this:linear($a as xs:double, $b as xs:double, $alpha as xs:double) as xs:double { $alpha * ($b - $a) + $a }; (:~ Cubic interpolation :) (: Alpha is between 0 and 1; 0 gives us first point, 1 gives us last :) declare function this:cubic($n0 as xs:double, $n1 as xs:double, $n2 as xs:double, $n3 as xs:double, $alpha as xs:double) as xs:double { let $p := ($n3 - $n2) - ($n0 - $n1) let $q := ($n0 - $n1) - $p let $r := $n2 - $n0 let $s := $n1 return $p * $alpha * $alpha * $alpha + $q * $alpha * $alpha + $r * $alpha + $s }; (:~ : select() : Noise function that outputs the value selected from one of two source : functions chosen by the output value from a control function. : If output value from control function is in the selection range, then : output value of f2, otherwise value of f1. : If we have positive falloff; do some linear interpolation around the : boundaries. :) declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double, (: default 1.0 :) $falloff as xs:double (: default 0.0 :) ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (not(ann:is-noise($control))) then errors:error("ML-BADARGS", ("control", $control)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2) and ann:is-noise-vector($control)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() let $controlfn := $control=>ann:function() return ann:fv("mod:select", function ($point as xs:double*) as xs:double { let $control-value := $controlfn($point) return ( if ($falloff > 0) then ( if ($control-value < $lower - $falloff) then ( $fn1($point) ) else if ($control-value < $lower + $falloff) then ( let $lower-curve := $lower - $falloff let $upper-curve := $lower + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else if ($control-value < $upper - $falloff) then ( $fn2($point) ) else if ($control-value < $upper + $falloff) then ( let $lower-curve := $upper - $falloff let $upper-curve := $upper + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else ( $fn1($point) ) ) else if ($control-value < $lower or $control-value > $upper) then ( $fn1($point) ) else ( $fn2($point) ) ) }, ($f1, $f2, $control, $lower, $upper, $falloff) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() let $controlfn := $control=>this:as-point()=>ann:function() return ( ann:f("mod:select", function ($point as map(xs:string,item()*)) as xs:double { let $control-value := $controlfn($point) return ( if ($falloff > 0) then ( if ($control-value < $lower - $falloff) then ( $fn1($point) ) else if ($control-value < $lower + $falloff) then ( let $lower-curve := $lower - $falloff let $upper-curve := $lower + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else if ($control-value < $upper - $falloff) then ( $fn2($point) ) else if ($control-value < $upper + $falloff) then ( let $lower-curve := $upper - $falloff let $upper-curve := $upper + $falloff let $alpha := this:s-curve3(($control-value - $lower-curve) div ($upper-curve - $lower-curve)) return this:linear($fn1($point), $fn2($point), $alpha) ) else ( $fn1($point) ) ) else if ($control-value < $lower or $control-value > $upper) then ( $fn1($point) ) else ( $fn2($point) ) ) }, ($f1, $f2, $control, $lower, $upper, $falloff) ) ) ) }; declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double (: default 1.0 :) ) as map(*) { this:select($f1, $f2, $control, $lower, $upper, 0.0) }; declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item() ) as map(*) { this:select($f1, $f2, $control, 0.0, 1.0, 0.0) }; declare %art:noise function this:select( $f1 as item(), $f2 as item(), $control as item(), $falloff as xs:double ) as map(*) { this:select($f1, $f2, $control, 0.0, 1.0, $falloff) }; (:~ : range() : Noise function that outputs the value selected from one noise function : if it is in a particular range, and the value of the other one otherwise. : functions chosen by the output value from a control function. :) declare %art:noise function this:range( $f1 as item(), $f2 as item(), $lower as xs:double, (: default 0.0 :) $upper as xs:double (: default 1.0 :) ) as map(*) { if (not(ann:is-noise($f1))) then errors:error("ML-BADARGS", ("f1", $f1)) else (), if (not(ann:is-noise($f2))) then errors:error("ML-BADARGS", ("f2", $f2)) else (), if (ann:is-noise-vector($f1) and ann:is-noise-vector($f2)) then ( let $fn1 := $f1=>ann:function() let $fn2 := $f2=>ann:function() return ann:fv("mod:select", function ($point as xs:double*) as xs:double { let $probe := $fn1($point) return ( if (util:twixt($probe, $lower, $upper)) then ( $probe ) else ( $fn2($point) ) ) }, ($f1, $f2, $lower, $upper) ) ) else ( let $fn1 := $f1=>this:as-point()=>ann:function() let $fn2 := $f2=>this:as-point()=>ann:function() return ( ann:f("mod:range", function ($point as map(xs:string,item()*)) as xs:double { let $probe := $fn1($point) return ( if (util:twixt($probe, $lower, $upper)) then ( $probe ) else ( $fn2($point) ) ) }, ($f1, $f2, $lower, $upper) ) ) ) }; declare %art:noise function this:range( $f1 as item(), $f2 as item() ) as map(*) { this:range($f1, $f2, 0.0, 1.0) }; (:======================================================================: : Input modifiers: : Modify the input point in some way before applying base noise function :======================================================================:) (:~ : displace() : Noise function that displaces point based on displacement functions : before applying function. :) declare %art:noise function this:displace( $f as item(), $displace-x as item(), $displace-y as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($displace-x))) then errors:error("ML-BADARGS", ("displace-x", $displace-x)) else (), if (not(ann:is-noise($displace-y))) then errors:error("ML-BADARGS", ("displace-y", $displace-y)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $displace-xfn := $displace-x=>this:as-vector()=>ann:function() let $displace-yfn := $displace-y=>this:as-vector()=>ann:function() return ann:fv("mod:displace", function ($point as xs:double*) as xs:double { $fn(affine:affine2($point, affine:translation2($displace-xfn($point), $displace-yfn($point)))) }, ($f, $displace-x, $displace-y) ) ) else ( let $fn := $f=>ann:function() let $displace-xfn := $displace-x=>this:as-point()=>ann:function() let $displace-yfn := $displace-y=>this:as-point()=>ann:function() return ( ann:f("mod:displace", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $displace-xfn($point), $displace-yfn($point))) }, ($f, $displace-x, $displace-y) ) ) ) }; (:~ : rotate() : Noise function that rotates input point around center before : applying function to it. :) declare %art:noise function this:rotate( $f as item(), $degrees as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($degrees))) then errors:error("ML-BADARGS", ("degrees", $degrees)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $degreesfn := $degrees=>this:as-vector()=>ann:function() return ann:fv("mod:rotate", function ($point as xs:double*) as xs:double { $fn(affine:affine2($point, affine:rotation2($center, $degreesfn($point)))) }, ($f, $degrees, $center) ) ) else ( let $fn := $f=>ann:function() let $degreesfn := $degrees=>this:as-point()=>ann:function() return ( ann:f("mod:rotate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:rotate($point, $degreesfn($point), $center)) }, ($f, $degrees, $center) ) ) ) }; (:~ : rotate() : Noise function that rotates input point around origin : applying function to it. :) declare %art:noise function this:rotate( $f as item(), $degrees as item() ) as map(*) { this:rotate($f, $degrees, $point:ORIGIN) }; (:~ : rotate() : Noise function that rotates input point around center : applying function to it. :) declare %art:noise function this:rotate( $f as item(), $roll-degrees as item(), $pitch-degrees as item(), $yaw-degrees as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($roll-degrees))) then errors:error("ML-BADARGS", ("roll-degrees", $roll-degrees)) else (), if (not(ann:is-noise($pitch-degrees))) then errors:error("ML-BADARGS", ("pitch-degrees", $pitch-degrees)) else (), if (not(ann:is-noise($yaw-degrees))) then errors:error("ML-BADARGS", ("yaw-degrees", $yaw-degrees)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $rollfn := $roll-degrees=>this:as-vector()=>ann:function() let $pitchfn := $pitch-degrees=>this:as-vector()=>ann:function() let $yawfn := $yaw-degrees=>this:as-vector()=>ann:function() return ann:fv("mod:rotate", function ($point as xs:double*) as xs:double { $fn( affine:affine3( $point, affine:rotation3( $center, $rollfn($point), $pitchfn($point), $yawfn($point) ) ) ) }, ($f, $roll-degrees, $pitch-degrees, $yaw-degrees, $center) ) ) else ( let $fn := $f=>ann:function() let $rollfn := $roll-degrees=>this:as-point()=>ann:function() let $pitchfn := $pitch-degrees=>this:as-point()=>ann:function() let $yawfn := $yaw-degrees=>this:as-point()=>ann:function() return ( ann:f("mod:rotate", function ($point as map(xs:string,item()*)) as xs:double { $fn( affine:rotate( $point, $rollfn($point), $pitchfn($point), $yawfn($point), $center ) ) }, ($f, $roll-degrees, $pitch-degrees, $yaw-degrees, $center) ) ) ) }; (:~ : rotate() : Noise function that rotates input point around origin : applying function to it. :) declare %art:noise function this:rotate( $f as item(), $roll-degrees as item(), $pitch-degrees as item(), $yaw-degrees as item() ) as map(*) { this:rotate($f, $roll-degrees, $pitch-degrees, $yaw-degrees, $point:ORIGIN3D) }; (:~ : scale() : Noise function that scales the input point before applying function : to it. : : @param $sx: scaling to x coordinate : @param $sy: scaling to y coordinate :) declare %art:noise function this:scale( $f as item(), $sx as item(), $sy as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:scaling2($sxfn($point), $syfn($point))) ) }, ($f, $sx, $sy) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale($point, $sxfn($point), $syfn($point))) }, ($f, $sx, $sy) ) ) ) }; (:~ : scale() : Noise function that scales the input point before applying function : to it. : : @param $scale: scale to apply to each coordinate :) declare %art:noise function this:scale( $f as item(), $scale as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($scale))) then errors:error("ML-BADARGS", ("scale", $scale)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $scalefn := $scale=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn($point=>v:times($scalefn($point))) }, ($f, $scale) ) ) else ( let $fn := $f=>ann:function() let $scalefn := $scale=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn($point=>point:times($scalefn($point))) }, ($f, $scale) ) ) ) }; (:~ : scale() : Noise function that scales the input point before applying function : to it. : : @param $sx: scaling to x coordinate : @param $sy: scaling to y coordinate : @param $center: center of scaling :) declare %art:noise function this:scale( $f as item(), $sx as item(), $sy as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:scaling2($center, $sxfn($point), $syfn($point))) ) }, ($f, $sx, $sy, $center) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale($point, $sxfn($point), $syfn($point), $center)) }, ($f, $sx, $sy, $center) ) ) ) }; (:~ : scale3D() : Noise function that scales the input point before applying function : to it. : : @param $sx: scaling to x coordinate : @param $sy: scaling to y coordinate : @param $sz: scaling to y coordinate :) declare %art:noise function this:scale3D( $f as item(), $sx as item(), $sy as item(), $sz as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (not(ann:is-noise($sz))) then errors:error("ML-BADARGS", ("sz", $sz)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() let $szfn := $sz=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:scaling3($sxfn($point), $syfn($point), $szfn($point))) ) }, ($f, $sx, $sy, $sz) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() let $szfn := $sz=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale3D($point, $sxfn($point), $syfn($point), $szfn($point))) }, ($f, $sx, $sy, $sz) ) ) ) }; (:~ : scale3D() : Noise function that scales the input point relative to a center : before applying function to it. : : @param $sx: scaling to x coordinate : @param $sy: scaling to y coordinate : @param $sz: scaling to y coordinate : @param $center: center of scaling :) declare %art:noise function this:scale3D( $f as item(), $sx as item(), $sy as item(), $sz as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($sx))) then errors:error("ML-BADARGS", ("sx", $sx)) else (), if (not(ann:is-noise($sy))) then errors:error("ML-BADARGS", ("sy", $sy)) else (), if (not(ann:is-noise($sz))) then errors:error("ML-BADARGS", ("sz", $sz)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-vector()=>ann:function() let $syfn := $sy=>this:as-vector()=>ann:function() let $szfn := $sz=>this:as-vector()=>ann:function() return ann:fv("mod:scale", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:scaling3($center, $sxfn($point), $syfn($point), $szfn($point))) ) }, ($f, $sx, $sy, $sz, $center) ) ) else ( let $fn := $f=>ann:function() let $sxfn := $sx=>this:as-point()=>ann:function() let $syfn := $sy=>this:as-point()=>ann:function() let $szfn := $sz=>this:as-point()=>ann:function() return ( ann:f("mod:scale", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:scale3D($point, $sxfn($point), $syfn($point), $szfn($point), $center)) }, ($f, $sx, $sy, $sz, $center) ) ) ) }; (:~ : translate() : Noise function that translates the input point before applying function : to it. :) declare %art:noise function this:translate( $f as item(), $tx as item(), $ty as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($tx))) then errors:error("ML-BADARGS", ("tx", $tx)) else (), if (not(ann:is-noise($ty))) then errors:error("ML-BADARGS", ("ty", $ty)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-vector()=>ann:function() let $tyfn := $ty=>this:as-vector()=>ann:function() return ann:fv("mod:translate", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:translation2($txfn($point), $tyfn($point))) ) }, ($f, $tx, $ty) ) ) else ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-point()=>ann:function() let $tyfn := $ty=>this:as-point()=>ann:function() return ( ann:f("mod:translate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $txfn($point), $tyfn($point))) }, ($f, $tx, $ty) ) ) ) }; (:~ : translate() : Noise function that translates the input point before applying function : to it. :) declare %art:noise function this:translate( $f as item(), $tx as item(), $ty as item(), $tz as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($tx))) then errors:error("ML-BADARGS", ("tx", $tx)) else (), if (not(ann:is-noise($ty))) then errors:error("ML-BADARGS", ("ty", $ty)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-vector()=>ann:function() let $tyfn := $ty=>this:as-vector()=>ann:function() let $tzfn := $tz=>this:as-vector()=>ann:function() return ann:fv("mod:translate", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:translation3($txfn($point), $tyfn($point), $tzfn($point))) ) }, ($f, $tx, $ty, $tz) ) ) else ( let $fn := $f=>ann:function() let $txfn := $tx=>this:as-point()=>ann:function() let $tyfn := $ty=>this:as-point()=>ann:function() let $tzfn := $tz=>this:as-point()=>ann:function() return ( ann:f("mod:translate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $txfn($point), $tyfn($point), $tzfn($point))) }, ($f, $tx, $ty, $tz) ) ) ) }; (:~ : shear() : Noise function that shears the input point before applying function : to it. :) declare %art:noise function this:shear( $f as item(), $xy as item(), $yx as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($xy))) then errors:error("ML-BADARGS", ("xy", $xy)) else (), if (not(ann:is-noise($yx))) then errors:error("ML-BADARGS", ("yx", $yx)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-vector()=>ann:function() let $yxfn := $yx=>this:as-vector()=>ann:function() return ann:fv("mod:translate", function ($point as xs:double*) as xs:double { $fn( affine:affine2($point, affine:shearing2($xyfn($point), $yxfn($point))) ) }, ($f, $xy, $yx) ) ) else ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-point()=>ann:function() let $yxfn := $yx=>this:as-point()=>ann:function() return ( ann:f("mod:translate", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:translate($point, $xyfn($point), $yxfn($point))) }, ($f, $xy, $yx) ) ) ) }; (:~ : shear() : Noise function that shears the input point before applying function : to it. :) declare %art:noise function this:shear( $f as item(), $xy as item(), $yx as item(), $xz as item(), $zx as item(), $yz as item(), $zy as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($xy))) then errors:error("ML-BADARGS", ("xy", $xy)) else (), if (not(ann:is-noise($yx))) then errors:error("ML-BADARGS", ("yx", $yx)) else (), if (not(ann:is-noise($xz))) then errors:error("ML-BADARGS", ("xz", $xz)) else (), if (not(ann:is-noise($zx))) then errors:error("ML-BADARGS", ("zx", $zx)) else (), if (not(ann:is-noise($yz))) then errors:error("ML-BADARGS", ("yz", $yz)) else (), if (not(ann:is-noise($zy))) then errors:error("ML-BADARGS", ("zy", $zy)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-vector()=>ann:function() let $yxfn := $yx=>this:as-vector()=>ann:function() let $xzfn := $xz=>this:as-vector()=>ann:function() let $zxfn := $zx=>this:as-vector()=>ann:function() let $yzfn := $yz=>this:as-vector()=>ann:function() let $zyfn := $zy=>this:as-vector()=>ann:function() return ann:fv("mod:shear", function ($point as xs:double*) as xs:double { $fn( affine:affine3($point, affine:shearing3( $xyfn($point), $yxfn($point), $xzfn($point), $zxfn($point), $yzfn($point), $zyfn($point) ) ) ) }, ($f, $xy, $yx, $xz, $zx, $yz, $zy) ) ) else ( let $fn := $f=>ann:function() let $xyfn := $xy=>this:as-point()=>ann:function() let $yxfn := $yx=>this:as-point()=>ann:function() let $xzfn := $xz=>this:as-point()=>ann:function() let $zxfn := $zx=>this:as-point()=>ann:function() let $yzfn := $yz=>this:as-point()=>ann:function() let $zyfn := $zy=>this:as-point()=>ann:function() return ( ann:f("mod:shear", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:shear($point, $xyfn($point), $yxfn($point), $xzfn($point), $zxfn($point), $yzfn($point), $zyfn($point))) }, ($f, $xy, $yx, $xz, $zx, $yz, $zy) ) ) ) }; (:~ : reflect() : Noise function that reflects the input point across a point : before applying function to it. :) declare %art:noise function this:reflect( $f as item(), $center as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:reflect", function ($point as xs:double*) as xs:double { if (count($point)=2) then ( $fn(affine:affine2($point, affine:reflection2($center))) ) else ( $fn(affine:affine3($point, affine:reflection3($center))) ) }, ($f, $center) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:reflect", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:reflect($point, $center)) }, ($f, $center) ) ) ) }; (:~ : reflect() : Noise function that reflects the input point across the origin : before applying function to it. :) declare %art:noise function this:reflect( $f as item() ) as map(*) { this:reflect($f, $point:ORIGIN) }; (:~ : reflect() : Noise function that reflects the input point across a line : before applying function to it. :) declare %art:noise function this:reflect( $f as item(), $start as map(xs:string,item()*), $end as map(xs:string,item()*) ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() return ann:fv("mod:reflect", function ($point as xs:double*) as xs:double { $fn(affine:affine2($point, affine:reflection2($start,$end))) }, ($f, $start, $end) ) ) else ( let $fn := $f=>ann:function() return ( ann:f("mod:reflect", function ($point as map(xs:string,item()*)) as xs:double { $fn(affine:reflect($point, $start, $end)) }, ($f, $start, $end) ) ) ) }; (:~ : destination() : Noise function that shifts the point to a new point based on the : length and destination computed from other functions before applying : the base function :) declare %art:noise function this:destination( $f as item(), $angle as item(), $length as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($angle))) then errors:error("ML-BADARGS", ("angle", $f)) else (), if (not(ann:is-noise($length))) then errors:error("ML-BADARGS", ("length", $length)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $anglefn := $angle=>this:as-vector()=>ann:function() let $lengthfn := $length=>this:as-vector()=>ann:function() return ann:fv("mod:destination", function ($point as xs:double*) as xs:double { $fn(point:pcoordinates(point:destination(point:vector($point), $anglefn($point), $lengthfn($point)))) }, ($f, $angle, $length) ) ) else ( let $fn := $f=>ann:function() let $anglefn := $angle=>this:as-point()=>ann:function() let $lengthfn := $length=>this:as-point()=>ann:function() return ( ann:f("mod:destination", function ($point as map(xs:string,item()*)) as xs:double { $fn(point:destination($point, $anglefn($point), $lengthfn($point))) }, ($f, $angle, $length) ) ) ) }; (:~ : jitter() : Noise function that jitters the point based on output from a jitter : function (using this:random() would be appropriate here) :) declare %art:noise function this:jitter( $f as item(), $jitter as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(ann:is-noise($jitter))) then errors:error("ML-BADARGS", ("jitter", $f)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $jitterfn := $jitter=>this:as-vector()=>ann:function() return ann:fv("mod:jitter", function ($point as xs:double*) as xs:double { let $dim := count($point) let $coords := for $i in 1 to $dim return $jitterfn($point) let $delta := switch($dim) case 2 return ($coords[1], $coords[2]) case 3 return ($coords[1], $coords[2], $coords[3]) case 4 return ($coords[1], $coords[2], $coords[3], $coords[4]) default return errors:error("ML-BADARGS", ("point", $point)) return $fn(v:add($point, $delta)) }, ($f, $jitter) ) ) else ( let $fn := $f=>ann:function() let $jitterfn := $jitter=>this:as-point()=>ann:function() return ( ann:f("mod:jitter", function ($point as map(xs:string,item()*)) as xs:double { let $dim := point:dimension($point) let $coords := for $i in 1 to $dim return $jitterfn($point) let $delta := switch($dim) case 2 return point:point($coords[1], $coords[2]) case 3 return point:point($coords[1], $coords[2], $coords[3]) case 4 return point:point($coords[1], $coords[2], $coords[3], $coords[4]) default return errors:error("ML-BADARGS", ("point", $point)) return $fn(point:add($point, $delta)) }, ($f, $jitter) ) ) ) }; (:~ : mutate() : Noise function that applies a mutation function to the input point before : applying function to it :) declare %art:noise function this:mutate( $f as item(), $mutation as item() ) as map(*) { if (not(ann:is-noise($f))) then errors:error("ML-BADARGS", ("f", $f)) else (), if (not(mutation:is-mutation($mutation))) then errors:error("ML-BADARGS", ("mutation", $mutation)) else (), if (ann:is-noise-vector($f)) then ( let $fn := $f=>ann:function() let $mutationfn := $mutation=>mutation:function() return ( if (mutation:is-mutation-vector($mutation)) then ( ann:fv("mod:mutate", function ($point as xs:double*) as xs:double { $fn($mutationfn($point)) }, ($f) ) ) else ( ann:fv("mod:mutate", function ($point as xs:double*) as xs:double { $fn(point:pcoordinates($mutationfn(point:vector($point)))) }, ($f) ) ) ) ) else ( let $fn := $f=>ann:function() let $mutationfn := $mutation=>mutation:function() return ( if (mutation:is-mutation-vector($mutation)) then ( ann:f("mod:mutate", function ($point as map(xs:string,item()*)) as xs:double { $fn(point:vector($mutationfn(point:pcoordinates($point)))) }, ($f) ) ) else ( ann:f("mod:mutate", function ($point as map(xs:string,item()*)) as xs:double { $fn($mutationfn($point)) }, ($f) ) ) ) ) };