Radial Basis Functions `(rbf)`

! If @David_Tschumperle wants to draw my attention to a singularly obscure G’MIC code passage, he only has to throw in a `rbf`

call. Works like a charm. My obsessions are too well known here.

```
S = [ cos(tilt), sin(tilt) ];
```

An aside: Leonhard Euler said I could do this:

```
foobar : skip ${1}
ang:=$1°
eval " const tilt=$ang;
S = [ cos(tilt), sin(tilt) ];
print(S);
U = cexp([0,tilt]);
print(U)"
```

A nifty way of getting sine/cosine pairs, without explicit calls to the same.

```
gosgood@bertha ~ $ gmic -m /dev/shm/foobar.gmic foobar 57
[gmic]./ Start G'MIC interpreter (v.3.3.3).
[gmic]./ Import commands from file '/dev/shm/foobar.gmic', with debug info (1 new, total: 4711).
[gmic_math_parser] S = (uninitialized) (mem[37]: vector2)
[gmic_math_parser] U = (uninitialized) (mem[43]: vector2)
[gmic_math_parser] S = [ 0.5446390350150272,0.83867056794542394 ] (size: 2)
[gmic_math_parser] U = [ 0.5446390350150272,0.83867056794542394 ] (size: 2)
[gmic]./ End G'MIC interpreter.
gosgood@bertha ~ $ gmic -m /dev/shm/foobar.gmic foobar -134
[gmic]./ Start G'MIC interpreter (v.3.3.3).
[gmic]./ Import commands from file '/dev/shm/foobar.gmic', with debug info (1 new, total: 4711).
[gmic_math_parser] S = (uninitialized) (mem[37]: vector2)
[gmic_math_parser] U = (uninitialized) (mem[43]: vector2)
[gmic_math_parser] S = [ -0.69465837045899703,-0.71933980033865141 ] (size: 2)
[gmic_math_parser] U = [ -0.69465837045899703,-0.71933980033865141 ] (size: 2)
[gmic]./ End G'MIC interpreter.
```

Thanks be to Euler’s Identity.

```
S = [ cos(tilt), sin(tilt) ];
…
pP = J[-1];
P = I;
T = unitnorm(P - pP);
N = lerp([ -T[1],T[0] ],S,tilt_strength)*thickness;
C = round(P - N);
D = round(P + N);
…
```

Now. This is a gem. But — I must confess — I didn’t tumble onto it immediately. Dotless (crossless) calligraphy? Had to draw a little diagram:

In the routine case, your approach offsets points **C** and **D** along courses parallel to vectors **±N**. Depending on the blending parameter `tilt_strength`

, this orients **+N** somewhere in the midsts of the pink arc, being — segment by segment — oriented through a mix between the globally fixed direction **S** and the locally varying perpendicular vectors **±T**. **–N** obediently follows along 180° out of phase.

Points **C** and **D** are offset at most by the distance 2×`thickness`

, when **±N** are perpendicular to the segment **P—Pp** and coincident (parallel) to the perpendiculars **±T**. That particular case arises when *(a.)* the user has set `tilt_strength`

to the blending extreme of zero, so that the vectors **±N** are, in practice, aliases of perpendiculars **±T**, the direction **S** being blended out entirely. By definition, **±T** are always perpendicular to the segment **P—Pp**, their orientations are invariant with respect to the segment, so, segment-by-segment, **C** and **D** are always offset by the same distance from segment **P—Pp**. This is the “non-calligraphic case”. I could be drawing with a felt pen that has a circular cross section.

Then there is case *(b.)*. The user has set `tilt_strength`

to the *other* blending extreme of one, so that the vectors **±N** always coincide with globally invariant **S**. Should a particular segment, **P—Pp**, run perpendicular to **S** then the situation is cut from the same cloth as *(a.)*, in that vectors **±N** parallel **±T** and those circumstances offset points **C** and **D** to the maximum separating distance of 2×`thickness`

. That obtains the maximum calligraphic width. The minimum arises on those occasions when the orientation of **P—Pp** is *exactly* that of **S**. **±N** is locked to **S**, so is coincident with **P—Pp**. Points **C** and **D** extrude along the length of **P—Pp**, so the green quadrilateral becomes, perhaps, a triangle, if the priors **A** and **B** had non-zero perpendicular offsets, or a line otherwise. In any case, we witness the minimum calligraphic width. In the general run of affairs **±N** coincides with a blended direction betwixt the orientations of **S** and **±T** and exhibits the blended behavior of both. It is, all and all, a nice bit of work. Permit me to admire it for a spell.

Now, what sets me to glancing out the window and sighing a bit is this affair of feeding `polygon()`

over-and-over-and-over again, four-point data sets per throw, for hundreds of times. That makes me a bit sad. You are a good deal better acquainted with its internals than I am, so, perhaps my performance worries regarding `polygon()`

are founded on sandy substraits, but in the run-up to the Arabesques article last year, I learned that if I could fashion up some way to feed `polygon()`

an entire curve plotting data set in one `polygon()`

call, it performed roughly 2× to 3× faster over plotting points pairs at a time.

But, of course, perhaps that is the rent to pay for getting around the self-intersection quibble: hundreds of tiny quadrilaterals instead of one big one (that self-intersects). In any case, it is probably cheaper than hundreds of calls to `thicklines`

, which happened to be the first thing I saw on the shelf yesterday afternoon.

Now I see that you have posted a bevy of new things whilst I’ve been working my way through this. Perhaps I should wait a bit before posting this.

Then again, perhaps not.