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

http://mathling.com/geometric/coordinates

Coordinate system mappings

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: bipolardeclare 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: bipolardeclare 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: circulardeclare 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: circulardeclare 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: parabolicdeclare 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: parabolicdeclare 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: ellipticdeclare 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: ellipticdeclare 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: affine2declare 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: affine2declare 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: curvilinear2declare 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: curvilinear2declare 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-cylindricaldeclare 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-cylindricaldeclare 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: bisphericaldeclare 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: bisphericaldeclare 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: toroidaldeclare 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: toroidaldeclare 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: ellipsoidaldeclare 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)
let \$bk := (\$abc, 1)
let \$ck := (\$abc, 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: ellipsoidaldeclare 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: ellipsoidaldeclare 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: sphericaldeclare 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: sphericaldeclare 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: affine3declare 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: affine3declare 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: curvilinear3declare 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: curvilinear3declare 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: stereographicdeclare 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: stereographic3Ddeclare 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
:
: @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)
let \$bk := (\$abc, 1)
let \$ck := (\$abc, 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
)
};```