http://mathling.com/geometric/coordinates  library module

http://mathling.com/geometric/coordinates


Coordinate system mappings

Copyright© Mary Holstege 2021-2023
CC-BY (https://creativecommons.org/licenses/by/4.0/)

December 2022
Status: New

Imports

http://mathling.com/core/utilities
import module namespace util="http://mathling.com/core/utilities"
       at "../core/utilities.xqy"
http://mathling.com/geometric/curve
import module namespace curve="http://mathling.com/geometric/curve"
       at "../geo/curves.xqy"
http://mathling.com/geometric/affine
import module namespace affine="http://mathling.com/geometric/affine"
       at "../geo/affine.xqy"
http://mathling.com/core/config
import module namespace config="http://mathling.com/core/config"
       at "../core/config.xqy"
http://mathling.com/core/errors
import module namespace errors="http://mathling.com/core/errors"
       at "../core/errors.xqy"
http://mathling.com/geometric/point
import module namespace point="http://mathling.com/geometric/point"
       at "../geo/point.xqy"

Functions

Function: bipolar
declare function bipolar($u as xs:double, $v as xs:double) as map(xs:string,item()*)


Bipolar coordinates
x = sinh(v) / (cosh(v) - cos(u))
y = sin(u) / (cosh(v) - cos(u))
for 0 <= u < 2π; -∞ < v < ∞
Make parametric in t; v=f(t) + c

Params
  • u as xs:double
  • v as xs:double
Returns
  • map(xs:string,item()*)
declare function this:bipolar(
  $u as xs:double,
  $v as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($v) - math:cos($u)
  let $x := util:sinh($v) div $divisor
  let $y := math:sin($u) div $divisor
  return (
    point:point($x, $y)
  )
}

Function: bipolar
declare function bipolar($t as xs:double, $f as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)


Bipolar coordinates
x = a sinh(v) / (cosh(v) - cos(u))
y = a sin(u) / (cosh(v) - cos(u))
for 0 <= u < 2π; -∞ < v < ∞
Make parametric in u=t; v=f(t) + c
Which allows a nice sliced rendering via curve:multi-plot()

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:bipolar(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:bipolar($t, $f($t) + $c)
}

Function: circular
declare function circular($u as xs:double, $v as xs:double) as map(xs:string, item()*)


Circular coordinates:
Elliot Tanis and Lee Kuivinen, Circular Coordinates and Computer Drawn
Designs. Mathematics Magazine. Vol 52 No 3. May, 1979:

Coordinates with two perpendicular axes U and V where each point on the
axes is center of circle through origin; (u,v) is intersection of
circle whose center is at u on horizontal axis w/ circle whose center v
is on vertical axis.

(s,t) =>
s = g(u) = 2uv²/(u²+v²)
t = h(u) = 2u²v/(u²+v²)

Params
  • u as xs:double
  • v as xs:double
Returns
  • map(xs:string,item()*)
declare function this:circular(
  $u as xs:double,
  $v as xs:double
) as map(xs:string, item()*)
{
  let $divisor := $u*$u + $v*$v
  let $x := (2*$u*$v*$v) div $divisor
  let $y := (2*$u*$u*$v) div $divisor
  return point:point($x, $y)
}

Function: circular
declare function circular($t as xs:double, $f as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)


Circular coordinates:
Elliot Tanis and Lee Kuivinen, Circular Coordinates and Computer Drawn
Designs. Mathematics Magazine. Vol 52 No 3. May, 1979:

Coordinates with two perpendicular axes U and V where each point on the
axes is center of circle through origin; (u,v) is intersection of
circle whose center is at u on horizontal axis w/ circle whose center v
is on vertical axis.

(s,t) =>
s = g(u) = 2uv²/(u²+v²)
t = h(u) = 2u²v/(u²+v²)
Make parametric in t: u=t, v=f(t) + c
Which allows a nice sliced rendering, e.g.
curve:multi-plot(n-points, n-slices,
function($t, $c) { coord:circular($t, $f, $c) },
$t-extent, $t-symmetric,
$do-spline
)

https://www.johndcook.com/blog/2020/11/09/some-mathematical-art/
Given f(t) compute
x(t) = 2t(f(t))²/(t²+(f(t))²)
y(t) = 2t²f(t)/(t²+(f(t))²)
where f(t) = d(t) + c for x = -10, -9, -8 etc.

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:circular(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:circular($t, $f($t) + $c)
}

Function: parabolic
declare function parabolic($u as xs:double, $v as xs:double) as map(xs:string,item()*)


parabolic()
Parabolic coordinates
x = uv
y = 1/2(v² - u²)

Params
  • u as xs:double
  • v as xs:double
Returns
  • map(xs:string,item()*)
declare function this:parabolic(
  $u as xs:double,
  $v as xs:double
) as map(xs:string,item()*)
{
  point:point(
    $u * $v,
    ($v*$v - $u*$u) div 2
  )
}

Function: parabolic
declare function parabolic($t as xs:double, $f as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:parabolic(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:parabolic($t, $f($t) + $c)
}

Function: elliptic
declare function elliptic($u as xs:double, $v as xs:double) as map(xs:string,item()*)


elliptic()
Elliptic coordinates
x = cosh u cos v
y = sinh u sin v
u >= 0, 0 <= v <= 2π

Params
  • u as xs:double
  • v as xs:double
Returns
  • map(xs:string,item()*)
declare function this:elliptic(
  $u as xs:double,
  $v as xs:double
) as map(xs:string,item()*)
{
  point:point(
    util:cosh($u) * math:cos($v),
    util:sinh($u) * math:sin($v)
  )
}

Function: elliptic
declare function elliptic($t as xs:double, $f as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:elliptic(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:elliptic($t, $f($t) + $c)
}

Function: affine2
declare function affine2($u as xs:double, $v as xs:double, $matrix as xs:double*) as map(xs:string,item()*)


affine2()
Affine coordinates
(x, y) = affine2((u, v))

Params
  • u as xs:double
  • v as xs:double
  • matrix as xs:double*
Returns
  • map(xs:string,item()*)
declare function this:affine2(
  $u as xs:double,
  $v as xs:double,
  $matrix as xs:double* (: 2D affine matrix :)
) as map(xs:string,item()*)
{
  point:vector( affine:affine2(($u, $v), $matrix) )
}

Function: affine2
declare function affine2($t as xs:double, $f as function(xs:double) as xs:double, $c as xs:double, $matrix as xs:double*) as map(xs:string,item()*)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • c as xs:double
  • matrix as xs:double*
Returns
  • map(xs:string,item()*)
declare function this:affine2(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double,
  $matrix as xs:double*
) as map(xs:string,item()*)
{
  this:affine2($t, $f($t) + $c, $matrix)
}

Function: curvilinear2
declare function curvilinear2($u as xs:double, $v as xs:double, $ptmap as function(xs:double*) as xs:double*) as map(xs:string,item()*)


curvilinear2()
Curvilinear coordinates

Params
  • u as xs:double
  • v as xs:double
  • ptmap as function(xs:double*)asxs:double*
Returns
  • map(xs:string,item()*)
declare function this:curvilinear2(
  $u as xs:double,
  $v as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  point:vector( $ptmap(($u, $v)) )
}

Function: curvilinear2
declare function curvilinear2($t as xs:double, $f as function(xs:double) as xs:double, $c as xs:double, $ptmap as function(xs:double*) as xs:double*) as map(xs:string,item()*)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • c as xs:double
  • ptmap as function(xs:double*)asxs:double*
Returns
  • map(xs:string,item()*)
declare function this:curvilinear2(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  this:curvilinear2($t, $f($t) + $c, $ptmap)
}

Function: bipolar-cylindrical
declare function bipolar-cylindrical($u as xs:double, $v as xs:double, $w as xs:double) as map(xs:string,item()*)


bipolar-cylindical()
x = sinh(v)/(cosh(v) - cos(u))
y = sin(u)/(cosh(v) - cos(u))
z = w

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
Returns
  • map(xs:string,item()*)
declare function this:bipolar-cylindrical(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($v) - math:cos($u)
  return (
    point:point(
      util:sinh($v) div $divisor,
      math:sin($u) div $divisor,
      $w
    )
  )
}

Function: bipolar-cylindrical
declare function bipolar-cylindrical($t as xs:double, $f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)


bipolar-cylindical()
Make parametric in t
u = t, v = f(t), w = g(t)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • g as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:bipolar-cylindrical(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:bipolar-cylindrical($t, $f($t) + $c, $g($t))
}

Function: bispherical
declare function bispherical($u as xs:double, $v as xs:double, $w as xs:double) as map(xs:string,item()*)


bispherical()
x = (sin(v)/(cosh(u)-cos(v)))*cos(w)
y = (sin(v)/(cosh(u)-cos(v)))*sin(w)
z = sinh(u)/(cosh(u)-cos(v)))

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
Returns
  • map(xs:string,item()*)
declare function this:bispherical(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($u) - math:cos($v)
  return (
    point:point(
      (math:sin($v) div $divisor)*math:cos($w),
      (math:sin($v) div $divisor)*math:sin($w),
      util:sinh($u) div $divisor
    )
  )
}

Function: bispherical
declare function bispherical($t as xs:double, $f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)


bispherical()
Make parametric in t
u = t, v = f(t), w = g(t)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • g as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:bispherical(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:bispherical($t, $f($t) + $c, $g($t))
}

Function: toroidal
declare function toroidal($u as xs:double, $v as xs:double, $w as xs:double) as map(xs:string,item()*)


toroidal()
x = (sinh(u)/(cosh(u)-cos(v)))*cos(w)
y = (sinh(u)/(cosh(u)-cos(v)))*sin(w)
z = sin(v)/(cosh(u)-cos(v))

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
Returns
  • map(xs:string,item()*)
declare function this:toroidal(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($u) - math:cos($v)
  return (
    point:point(
      (util:sinh($u) div $divisor)*math:cos($w),
      (util:sinh($u) div $divisor)*math:sin($w),
      math:sin($v) div $divisor
    )
  )
}

Function: toroidal
declare function toroidal($t as xs:double, $f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)


toroidal()
Make parametric in t
u = t, v = f(t), w = g(t)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • g as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:toroidal(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:toroidal($t, $f($t) + $c, $g($t))
}

Function: ellipsoidal
declare function ellipsoidal($u as xs:double, $v as xs:double, $w as xs:double, $abc as xs:double*) as map(xs:string,item()*)


ellipsoidal()
x = a u sin(v)cos(w)
y = b u sin(v)sin(w)
z = c u cos(v)
u > 0; 0 <= v <= π; 0 <= w <= 2π

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
  • abc as xs:double*
Returns
  • map(xs:string,item()*)
declare function this:ellipsoidal(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double,
  $abc as xs:double*
) as map(xs:string,item()*)
{
  let $ak := ($abc[1], 1)[1]
  let $bk := ($abc[2], 1)[1]
  let $ck := ($abc[3], 1)[1]
  return (
    point:point(
      $ak * $u * math:sin($v) * math:cos($w),
      $bk * $u * math:sin($v) * math:sin($w),
      $ck * $u * math:cos($v)
    )
  )
}

Function: ellipsoidal
declare function ellipsoidal($u as xs:double, $v as xs:double, $w as xs:double) as map(xs:string,item()*)

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
Returns
  • map(xs:string,item()*)
declare function this:ellipsoidal(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  this:ellipsoidal($u, $v, $w, (1.0, 1.0, 1.0)) (: A unit sphere, actually :)
}

Function: ellipsoidal
declare function ellipsoidal($t as xs:double, $f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double, $c as xs:double, $abc as xs:double*) as map(xs:string,item()*)


ellipsoidal()
Make parametric in t
u = t, v = f(t), w = g(t)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • g as function(xs:double)asxs:double
  • c as xs:double
  • abc as xs:double*
Returns
  • map(xs:string,item()*)
declare function this:ellipsoidal(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double,
  $abc as xs:double*
) as map(xs:string,item()*)
{
  this:ellipsoidal($t, $f($t) + $c, $g($t), $abc)
}

Function: spherical
declare function spherical($u as xs:double, $v as xs:double, $w as xs:double) as map(xs:string,item()*)


spherical()
x = u sin(v)cos(w)
y = u sin(v)sin(w)
z = u cos(v)
u > 0; 0 <= v <= π; 0 <= w <= 2π

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
Returns
  • map(xs:string,item()*)
declare function this:spherical(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  point:point(
    $u * math:sin($v) * math:cos($w),
    $u * math:sin($v) * math:sin($w),
    $u * math:cos($v)
  )
}

Function: spherical
declare function spherical($t as xs:double, $f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double, $c as xs:double) as map(xs:string,item()*)


spherical()
Make parametric in t
u = t, v = f(t), w = g(t)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • g as function(xs:double)asxs:double
  • c as xs:double
Returns
  • map(xs:string,item()*)
declare function this:spherical(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:spherical($t, $f($t) + $c, $g($t))
}

Function: affine3
declare function affine3($u as xs:double, $v as xs:double, $w as xs:double, $matrix as xs:double*) as map(xs:string,item()*)


affine3()
Affine coordinates
(x, y) = affine((u, v))

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
  • matrix as xs:double*
Returns
  • map(xs:string,item()*)
declare function this:affine3(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double,
  $matrix as xs:double* (: 3D affine matrix :)
) as map(xs:string,item()*)
{
  point:vector( affine:affine3(($u, $v, $w), $matrix) )
}

Function: affine3
declare function affine3($t as xs:double, $f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double, $c as xs:double, $matrix as xs:double*) as map(xs:string,item()*)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • g as function(xs:double)asxs:double
  • c as xs:double
  • matrix as xs:double*
Returns
  • map(xs:string,item()*)
declare function this:affine3(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double,
  $matrix as xs:double*
) as map(xs:string,item()*)
{
  this:affine3($t, $f($t) + $c, $g($t), $matrix)
}

Function: curvilinear3
declare function curvilinear3($u as xs:double, $v as xs:double, $w as xs:double, $ptmap as function(xs:double*) as xs:double*) as map(xs:string,item()*)


curvilinear3()
Curvilinear coordinates

Params
  • u as xs:double
  • v as xs:double
  • w as xs:double
  • ptmap as function(xs:double*)asxs:double*
Returns
  • map(xs:string,item()*)
declare function this:curvilinear3(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  point:vector( $ptmap(($u, $v, $w)) )
}

Function: curvilinear3
declare function curvilinear3($t as xs:double, $f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double, $c as xs:double, $ptmap as function(xs:double*) as xs:double*) as map(xs:string,item()*)

Params
  • t as xs:double
  • f as function(xs:double)asxs:double
  • g as function(xs:double)asxs:double
  • c as xs:double
  • ptmap as function(xs:double*)asxs:double*
Returns
  • map(xs:string,item()*)
declare function this:curvilinear3(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  this:curvilinear3($t, $f($t) + $c, $g($t), $ptmap)
}

Function: stereographic
declare function stereographic($pt as map(xs:string,item()*)*) as map(xs:string,item()*)


stereographic()
Stereographic mapping from sphere to plane.
Point is expected to be on unit sphere, so you'll need to do some scaling
and translating. (See geom:stereographic())

Params
  • pt as map(xs:string,item()*)*
Returns
  • map(xs:string,item()*)
declare function this:stereographic(
  $pt as map(xs:string,item()*)*
) as map(xs:string,item()*)
{
  point:point(
    point:px($pt) div (1 - point:pz($pt)),
    point:py($pt) div (1 - point:pz($pt))
  )
}

Function: stereographic3D
declare function stereographic3D($pt as map(xs:string,item()*)*) as map(xs:string,item()*)


stereographic3D()
Inverse stereographic mapping. Returns 3D point on unit sphere, so you'll
need to do some scaling and translating (see geom:stereographic3D())

Params
  • pt as map(xs:string,item()*)*
Returns
  • map(xs:string,item()*)
declare function this:stereographic3D(
  $pt as map(xs:string,item()*)*
) as map(xs:string,item()*)
{
  let $divisor := 1 + point:px($pt)*point:px($pt) + point:py($pt)*point:py($pt)
  return
  point:point(
    2 * point:px($pt) div $divisor,
    2 * point:py($pt) div $divisor,
    (-1 + point:px($pt)*point:px($pt) + point:py($pt)*point:py($pt)) div $divisor
  )
}

Original Source Code

xquery version "3.1";
(:~
 : Coordinate system mappings
 :
 : Copyright© Mary Holstege 2021-2023
 : CC-BY (https://creativecommons.org/licenses/by/4.0/)
 : @since December 2022
 : @custom:Status New
 :)
module namespace this="http://mathling.com/geometric/coordinates"; 

import module namespace config="http://mathling.com/core/config"
       at "../core/config.xqy";
import module namespace errors="http://mathling.com/core/errors"
       at "../core/errors.xqy";
import module namespace util="http://mathling.com/core/utilities"
       at "../core/utilities.xqy";
import module namespace point="http://mathling.com/geometric/point"
       at "../geo/point.xqy";
import module namespace affine="http://mathling.com/geometric/affine"
       at "../geo/affine.xqy";
import module namespace curve="http://mathling.com/geometric/curve"
       at "../geo/curves.xqy";

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

(:~
 : Bipolar coordinates
 : x = sinh(v) / (cosh(v) - cos(u))
 : y = sin(u) / (cosh(v) - cos(u))
 : for 0 <= u < 2π; -∞ < v < ∞
 : Make parametric in t; v=f(t) + c
 :)
declare function this:bipolar(
  $u as xs:double,
  $v as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($v) - math:cos($u)
  let $x := util:sinh($v) div $divisor
  let $y := math:sin($u) div $divisor
  return (
    point:point($x, $y)
  )
};

(:~
 : Bipolar coordinates
 : x = a sinh(v) / (cosh(v) - cos(u))
 : y = a sin(u) / (cosh(v) - cos(u))
 : for 0 <= u < 2π; -∞ < v < ∞
 : Make parametric in u=t; v=f(t) + c
 : Which allows a nice sliced rendering via curve:multi-plot()
 :)
declare function this:bipolar(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:bipolar($t, $f($t) + $c)
};

(:~
 : Circular coordinates:
 : Elliot Tanis and Lee Kuivinen, Circular Coordinates and Computer Drawn
 : Designs. Mathematics Magazine. Vol 52 No 3. May, 1979:
 :
 : Coordinates with two perpendicular axes U and V where each point on the
 : axes is center of circle through origin; (u,v) is intersection of
 : circle whose center is at u on horizontal axis w/ circle whose center v
 : is on vertical axis.
 :
 : (s,t) =>
 : s = g(u) = 2uv²/(u²+v²)
 : t = h(u) = 2u²v/(u²+v²)
 :)
declare function this:circular(
  $u as xs:double,
  $v as xs:double
) as map(xs:string, item()*)
{
  let $divisor := $u*$u + $v*$v
  let $x := (2*$u*$v*$v) div $divisor
  let $y := (2*$u*$u*$v) div $divisor
  return point:point($x, $y)
};

(:~
 : Circular coordinates:
 : Elliot Tanis and Lee Kuivinen, Circular Coordinates and Computer Drawn
 : Designs. Mathematics Magazine. Vol 52 No 3. May, 1979:
 :
 : Coordinates with two perpendicular axes U and V where each point on the
 : axes is center of circle through origin; (u,v) is intersection of
 : circle whose center is at u on horizontal axis w/ circle whose center v
 : is on vertical axis.
 :
 : (s,t) =>
 : s = g(u) = 2uv²/(u²+v²)
 : t = h(u) = 2u²v/(u²+v²)
 : Make parametric in t: u=t, v=f(t) + c
 : Which allows a nice sliced rendering, e.g.
 :   curve:multi-plot(n-points, n-slices, 
 :     function($t, $c) { coord:circular($t, $f, $c) },
 :     $t-extent, $t-symmetric, 
 :     $do-spline
 :   )
 :
 : https://www.johndcook.com/blog/2020/11/09/some-mathematical-art/
 : Given f(t) compute
 : x(t) = 2t(f(t))²/(t²+(f(t))²)
 : y(t) = 2t²f(t)/(t²+(f(t))²)
 : where f(t) = d(t) + c for x = -10, -9, -8 etc.
 :)
declare function this:circular(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:circular($t, $f($t) + $c)
};

(:~
 : parabolic()
 : Parabolic coordinates
 : x = uv
 : y = 1/2(v² - u²)
 :)
declare function this:parabolic(
  $u as xs:double,
  $v as xs:double
) as map(xs:string,item()*)
{
  point:point(
    $u * $v,
    ($v*$v - $u*$u) div 2
  )
};

declare function this:parabolic(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:parabolic($t, $f($t) + $c)
};

(:~
 : elliptic()
 : Elliptic coordinates
 : x = cosh u cos v
 : y = sinh u sin v
 : u >= 0, 0 <= v <= 2π
 :)
declare function this:elliptic(
  $u as xs:double,
  $v as xs:double
) as map(xs:string,item()*)
{
  point:point(
    util:cosh($u) * math:cos($v),
    util:sinh($u) * math:sin($v)
  )
};

declare function this:elliptic(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:elliptic($t, $f($t) + $c)
};

(:~
 : affine2()
 : Affine coordinates
 : (x, y) = affine2((u, v))
 :)
declare function this:affine2(
  $u as xs:double,
  $v as xs:double,
  $matrix as xs:double* (: 2D affine matrix :)
) as map(xs:string,item()*)
{
  point:vector( affine:affine2(($u, $v), $matrix) )
};

declare function this:affine2(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double,
  $matrix as xs:double*
) as map(xs:string,item()*)
{
  this:affine2($t, $f($t) + $c, $matrix)
};

(:~
 : curvilinear2()
 : Curvilinear coordinates
 :)
declare function this:curvilinear2(
  $u as xs:double,
  $v as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  point:vector( $ptmap(($u, $v)) )
};

declare function this:curvilinear2(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $c as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  this:curvilinear2($t, $f($t) + $c, $ptmap)
};

(:=== 3D ===:)

(:~ 
 : bipolar-cylindical()
 : x = sinh(v)/(cosh(v) - cos(u))
 : y = sin(u)/(cosh(v) - cos(u))
 : z = w
 :)
declare function this:bipolar-cylindrical(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($v) - math:cos($u)
  return (
    point:point(
      util:sinh($v) div $divisor,
      math:sin($u) div $divisor,
      $w
    )
  )
};

(:~ 
 : bipolar-cylindical()
 : Make parametric in t
 : u = t, v = f(t), w = g(t)
 :)
declare function this:bipolar-cylindrical(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:bipolar-cylindrical($t, $f($t) + $c, $g($t))
};

(:~ 
 : bispherical()
 : x = (sin(v)/(cosh(u)-cos(v)))*cos(w)
 : y = (sin(v)/(cosh(u)-cos(v)))*sin(w)
 : z = sinh(u)/(cosh(u)-cos(v)))
 :)
declare function this:bispherical(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($u) - math:cos($v)
  return (
    point:point(
      (math:sin($v) div $divisor)*math:cos($w),
      (math:sin($v) div $divisor)*math:sin($w),
      util:sinh($u) div $divisor
    )
  )
};

(:~ 
 : bispherical()
 : Make parametric in t
 : u = t, v = f(t), w = g(t)
 :)
declare function this:bispherical(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:bispherical($t, $f($t) + $c, $g($t))
};

(:~ 
 : toroidal()
 : x = (sinh(u)/(cosh(u)-cos(v)))*cos(w)
 : y = (sinh(u)/(cosh(u)-cos(v)))*sin(w)
 : z = sin(v)/(cosh(u)-cos(v))
 :)
declare function this:toroidal(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  let $divisor := util:cosh($u) - math:cos($v)
  return (
    point:point(
      (util:sinh($u) div $divisor)*math:cos($w),
      (util:sinh($u) div $divisor)*math:sin($w),
      math:sin($v) div $divisor
    )
  )
};

(:~ 
 : toroidal()
 : Make parametric in t
 : u = t, v = f(t), w = g(t)
 :)
declare function this:toroidal(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:toroidal($t, $f($t) + $c, $g($t))
};

(:~ 
 : ellipsoidal()
 : x = a u sin(v)cos(w)
 : y = b u sin(v)sin(w)
 : z = c u cos(v)
 : u > 0; 0 <= v <= π; 0 <= w <= 2π
 :)
declare function this:ellipsoidal(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double,
  $abc as xs:double*
) as map(xs:string,item()*)
{
  let $ak := ($abc[1], 1)[1]
  let $bk := ($abc[2], 1)[1]
  let $ck := ($abc[3], 1)[1]
  return (
    point:point(
      $ak * $u * math:sin($v) * math:cos($w),
      $bk * $u * math:sin($v) * math:sin($w),
      $ck * $u * math:cos($v)
    )
  )
};

declare function this:ellipsoidal(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  this:ellipsoidal($u, $v, $w, (1.0, 1.0, 1.0)) (: A unit sphere, actually :)
};

(:~ 
 : ellipsoidal()
 : Make parametric in t
 : u = t, v = f(t), w = g(t)
 :)
declare function this:ellipsoidal(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double,
  $abc as xs:double*
) as map(xs:string,item()*)
{
  this:ellipsoidal($t, $f($t) + $c, $g($t), $abc)
};

(:~ 
 : spherical()
 : x = u sin(v)cos(w)
 : y = u sin(v)sin(w)
 : z = u cos(v)
 : u > 0; 0 <= v <= π; 0 <= w <= 2π
 :)
declare function this:spherical(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double
) as map(xs:string,item()*)
{
  point:point(
    $u * math:sin($v) * math:cos($w),
    $u * math:sin($v) * math:sin($w),
    $u * math:cos($v)
  )
};

(:~ 
 : spherical()
 : Make parametric in t
 : u = t, v = f(t), w = g(t)
 :)
declare function this:spherical(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double
) as map(xs:string,item()*)
{
  this:spherical($t, $f($t) + $c, $g($t))
};

(:~
 : affine3()
 : Affine coordinates
 : (x, y) = affine((u, v))
 :)
declare function this:affine3(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double,
  $matrix as xs:double* (: 3D affine matrix :)
) as map(xs:string,item()*)
{
  point:vector( affine:affine3(($u, $v, $w), $matrix) )
};

declare function this:affine3(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double,
  $matrix as xs:double*
) as map(xs:string,item()*)
{
  this:affine3($t, $f($t) + $c, $g($t), $matrix)
};

(:~
 : curvilinear3()
 : Curvilinear coordinates
 :)
declare function this:curvilinear3(
  $u as xs:double,
  $v as xs:double,
  $w as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  point:vector( $ptmap(($u, $v, $w)) )
};

declare function this:curvilinear3(
  $t as xs:double,
  $f as function(xs:double) as xs:double,
  $g as function(xs:double) as xs:double,
  $c as xs:double,
  $ptmap as function(xs:double*) as xs:double*
) as map(xs:string,item()*)
{
  this:curvilinear3($t, $f($t) + $c, $g($t), $ptmap)
};

(: 2D <=> 3D :)

(:~
 : stereographic()
 : Stereographic mapping from sphere to plane.
 : Point is expected to be on unit sphere, so you'll need to do some scaling
 : and translating. (See geom:stereographic())
 :)
declare function this:stereographic(
  $pt as map(xs:string,item()*)*
) as map(xs:string,item()*)
{
  point:point(
    point:px($pt) div (1 - point:pz($pt)),
    point:py($pt) div (1 - point:pz($pt))
  )
};

(:~
 : stereographic3D()
 : Inverse stereographic mapping. Returns 3D point on unit sphere, so you'll
 : need to do some scaling and translating (see geom:stereographic3D())
 :)
declare function this:stereographic3D(
  $pt as map(xs:string,item()*)*
) as map(xs:string,item()*)
{
  let $divisor := 1 + point:px($pt)*point:px($pt) + point:py($pt)*point:py($pt)
  return
  point:point(
    2 * point:px($pt) div $divisor,
    2 * point:py($pt) div $divisor,
    (-1 + point:px($pt)*point:px($pt) + point:py($pt)*point:py($pt)) div $divisor
  )
};