Comment{
jlb.ulb
241013 re-ordered
Group 1: utility classes & etc.
Group 2: Recommended classes & etc.
Group 2: Not recommended classes & etc.
}
comment{
Group 1: utility classes and etc.
}
class Geometry {
; Perhaps the start of a general Geometry class.
; Original version 03 November 2012
; Latest change 230416
static bool func PointInTriangle(complex z, complex v0, complex v1, complex v2)
; Is point z strictly inside the triangle specified by three vertices?
; (For allowing points on the triangle itself, change the > to >= and < to <=.)
; Usually with roundoff there is no difference.
;
; Method and notation from mathworld.wolfram.com/TriangleInterior.html
complex v = z
v1 = v1 - v0
v2 = v2 - v0
float v1v2 = real(v1)*imag(v2)-imag(v1)*real(v2)
float vv1 = real(v )*imag(v1)-imag(v )*real(v1)
float vv2 = real(v )*imag(v2)-imag(v )*real(v2)
float v0v1 = real(v0)*imag(v1)-imag(v0)*real(v1)
float v0v2 = real(v0)*imag(v2)-imag(v0)*real(v2)
float a = (vv2-v0v2)/v1v2
float b = -(vv1-v0v1)/v1v2
return (a >= 0 && b >= 0 && a+b <= 1)
endfunc
static float func DistanceToCircumCenter(float s1, float s2, float s3)
; Distance to meeting point of the three angle bisectors,
; given the side lengths. Equal to radius of circumcircle.
float k = (s1 + s2 + s3)/2
return sqrt((k-s1)*(k-s2)*(k-s3)/k)
endfunc
; next add 240303
; formula derived from using |v1-c| = |v2-c| = |v3-c|
; and solving for c and conj(c)
; static complex func CircumCenter(complex v1, complex v2, complex v30
; return ( |v1|*(v3-v2) + |v2|*(v1-v3) + |v3|*(v2-v1) ) \
; / (conj(v1)*(v3-v2) + conj(v2)*(v1-v3) + conj(v3)*(v2-v1) )
; endfunc
; next three functions added October 2020
static float func Det(complex v1, complex v2)
; det is actually the cross product of the two points considered as vectors
return real(v1)*imag(v2)-imag(v1)*real(v2)
endfunc
static float func DistancePointToLine(complex p, complex v1, complex v2)
; distance from point p to the infinite line determined by two end points
; formula from mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
if v1 == v2
return cabs(p - v1)
endif
return abs(Det(v2-v1, v1-p))/cabs(v2-v1)
endfunc
; this one added 230416
static float func DistancePointToLine2(complex pt, complex pv, float angle)
; distance from point p to the infinite line determined by point pv and angle
; formula from https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
return abs(cos(angle)*imag(pv-pt) - sin(angle)*real(pv-pt))
endfunc
static float func TriangleArea(complex v0, complex v1, complex v2)
; formula from mathworld.wolfram.com/TriangleArea.html
return 0.5*abs(Det(v1-v0,v2-v0))
endfunc
; longest side of a triangle
static int func LongestSide(complex v0, complex v1, complex v2)
float d1 = |v0-v1|
float d2 = |v1-v2|
float d3 = |v2-v0|
if d1 >= d2 && d1 >= d3
return 1
elseif d2 >= d3 && d2 >= d1
return 2
else
return 3
endif
endfunc
; next two added 17 October 2021
; formula for t from http://paulbourke.net/geometry/pointlineplane/
static float func DistancePointToLIneSegment(complex p, complex v1, complex v2)
if v1 == v2
return cabs(p - v1)
endif
; the perpendicular from p to the segment is at v1 + t * (v2-v1)
float t = ( (real(p)-real(v1))*(real(v2)-real(v1)) + (imag(p)-imag(v1))*(imag(v2)-imag(v1)) ) \
/ | v2 - v1 |
if t >= 0 && t <= 1 ; the perpendicular hits the segment
return cabs(p-(v1+t*(v2-v1)) )
; or as above in DistancePointToLine
;return abs(Det(v2-v1, v1-p))/cabs(v2-v1)
else ; it's one of the endpoints
float d1 = cabs(p-v1)
float d2 = cabs(p-v2)
if d1 <= d2
return d1
else
return d2
endif
endif
endfunc
; find distance from a point to a triangle or quadrilateral
static float func DistancePointToFigure(complex pt, int n, complex v1, complex v2, complex v3, complex v4)
if n < 3 || n > 4
return -1
endif
float d1, float d2, float d3, float d4
d1 = Geometry.DistancePointToLIneSegment(pt, v1, v2)
d2 = Geometry.DistancePointToLIneSegment(pt, v2, v3)
if n == 3
d3 = Geometry.DistancePointToLIneSegment(pt, v3, v1)
d4 = d3
else
d3 = Geometry.DistancePointToLIneSegment(pt, v3, v4)
d4 = Geometry.DistancePointToLIneSegment(pt, v4, v1)
endif
if d2 < d1, d1 = d2, endif
if d3 < d1, d1 = d3, endif
if d4 < d1, d1 = d4, endif
return d1
endfunc
; formula for t from http://paulbourke.net/geometry/pointlineplane/
; 220620 return vector from closest point on a line segment to p
static complex func ClosestPointToLineSegment(complex p, complex v1, complex v2)
if v1 == v2
return p-v1
endif
; the perpendicular from p to the segment is at v1 + t * (v2-v1)
float t = ( (real(p)-real(v1))*(real(v2)-real(v1)) + (imag(p)-imag(v1))*(imag(v2)-imag(v1)) ) \
/ | v2 - v1 |
if t >= 0 && t <= 1 ; the perpendicular hits the segment
return p-(v1+t*(v2-v1))
else ; it's one of the endpoints
float d1 = |p-v1|
float d2 = |p-v2|
if d1 <= d2
return p-v1
else
return p-v2
endif
endif
endfunc
; 220620 return vector from from closest point on a triangle or quadrilateral to pt
; if quadrilateral, the vertices are assumed to be in clockwise or counterclockwise order.
static complex func ClosestPointToFigure(complex pt, int n, \
complex v1, complex v2, complex v3, complex v4)
complex pv = (0,0)
if n < 3 || n > 4
return pv
endif
complex pv1, complex pv2, complex pv3, complex pv4
pv1 = Geometry.ClosestPointToLIneSegment(pt, v1, v2)
pv2 = Geometry.ClosestPointToLIneSegment(pt, v2, v3)
if n == 3
pv3 = Geometry.ClosestPointToLIneSegment(pt, v3, v1)
pv4 = pv3
else
pv3 = Geometry.ClosestPointToLIneSegment(pt, v3, v4)
pv4 = Geometry.ClosestPointToLIneSegment(pt, v4, v1)
endif
float d1 = |pv1|, float d2 = |pv2|, float d3 = |pv3|, float d4 = |pv4|
float d = d1, pv = pv1
if d2 < d, d = d2, pv = pv2, endif
if d3 < d, d = d3, pv = pv3, endif
if d4 < d, pv = pv4, endif
return pv
endfunc
; 220923 return vector from from closest vertex on a triangle or quadrilateral to pt
static complex func ClosestPointToVertex(complex pt, int n, \
complex v1, complex v2, complex v3, complex v4)
complex pv = (0,0)
if n < 3 || n > 4
return pv
endif
complex pv1, complex pv2, complex pv3, complex pv4
pv1 = pt - v1, pv2 = pt - v2, pv3 = pt - v3, pv4 = pt - v4
float d1 = |pv1|, float d2 = |pv2|, float d3 = |pv3|, float d4 = |pv4|
float d = d1, pv = pv1
if d2 < d, d = d2, pv = pv2, endif
if d3 < d, d = d3, pv = pv3, endif
if n == 4 && d4 < d, pv = pv4, endif
return pv
endfunc
; 230314 calculate Barycentric Coordinates of a point in a triangle
; Does not check to see if the point actually is inside the triangle
; Formulas as in https://en.wikipedia.org/wiki/Barycentric_coordinate_system
static func BarycentricCoordinates(complex pt, complex v1, complex v2, complex v3, \
float &b1, float &b2, float &b3)
float x1 = real(v1), float y1 = imag(v1)
float x2 = real(v2), float y2 = imag(v2)
float x3 = real(v3), float y3 = imag(v3)
float xp = real(pt), float yp = imag(pt)
float det = (y2-y3)*(x1-x3) + (x3-x2)*(y1-y3)
b1 = ( (y2-y3)*(xp-x3) + (x3-x2)*(yp-y3) )/det
b2 = ( (y3-y1)*(xp-x3) + (x1-x3)*(yp-y3) )/det
b3 = 1 - b1 - b2
endfunc
}
class JLB_Random(common.ulb:Generic) {
; This class provides a robust pseudo-random number generator for UF.
; The basic generator produces a random sequence of integers in the range
; from 0 to 2147483647, inclusive. Note that 2147483647 is the largest
; positive integer in UF.
;
; To use, first call Init(seed) with seed an odd positive integer. This
; initializes the sequence. If the call to init is omitted, the default seed
; (1245) is used.
; Then i = RandomInt(0) provides successive numbers in the sequence.
; Also, i = RandomInt(j) with j non-zero will first reset the sequence
; using j as the new seed.
; To produce a random integer in [1, N], inclusive, use RandomIntInRange,
; which uses RandomInt(). First set N with SetRange(). If the call to
; SetRange is omitted, the default N (16) is used.
;
; To produce a random float in [0, 1), use RandomFloat(), which uses
; RandomInt(). It works by dividing the integer returned by RandomInt()
; by 2147483648.0 (which is a float equal to 2^31). The value
; 0 can be obtained, but not the value 1. This is sometimes useful. <>
;
; The random number generator is robust, probably the simplest robust
; generator. It uses the same algorithm as a routine in the NIST math
; library.
;
; Original version: br>
; Blue, James L., Applied and Computational Mathematics Division, NIST
; Kahaner, David K., Applied and Computational Mathematics Division, NIST
; Marsaglia, George, Florida State University
;
; Reference: Marsaglia G., "a Current View of Random Number Generators,"
; Proceedings Computer Science and Statistics: 16th
; Symposium on the Interface, Elsevier, Amsterdam, 1985.
;
public:
import "common.ulb"
; Constructor
func JLB_Random(Generic pparent)
Generic.Generic(pparent)
;
; Init with default seed.
;
Init(@p_seed)
;
; Set default range maximum
;
m_Nmax = 16
endfunc
; Call to this to initialize the random number generator.
; @param seed an odd positive integer
func Init(int seed)
; Fix up seed if Init is improperly called
if (seed < 0)
seed = seed + 2147483647
endif
if (seed % 2 == 0)
seed = 2147483647 - seed
endif
count = 0
; Initialize the history array with a simple linear congruential generator.
float x = seed
int i = 0
; Note: floats in UF have enough range so that 9069*2147483647
; is exactly representable.
repeat
x = (9069.0 * x) % 2147483648.0
m_hist[i] = round(x) ; x is exactly an integer
i = i + 1
until (i == 17)
m_i = 4
m_j = 16
endfunc
; Init and run off some random ints. Sometimes this helps, historically.
func Init2(int seed, int n)
Init(seed)
while n > 0
RandomInt(0)
n = n - 1
endwhile
endfunc
; @param pn If non-zero, initialize with seed = pn. If zero, just get next value
; @return the next value in the integer sequence. Values are from 0 to 2147483647, inclusive
int func RandomInt(const int pn)
if (pn != 0) ;reset seed
Init(pn)
endif
count = count + 1
int k = m_hist[m_i] - m_hist[m_j]
if (k < 0)
k = k + 2147483647
endif
m_hist[m_j] = k
m_i = m_i - 1
if (m_i < 0)
m_i = 16
endif
m_j = m_j - 1
if (m_j < 0)
m_j = 16
endif
return k
endfunc
int func HowMany( )
return count
endfunc
; Set the maximum integer for the range version.
; @param Nmax maximum integer (set to 16 if Nmax <= 0)
; @return true if Nmax > 0, false if Nmax <= 0
; not needed if use RandomIntInRange2 instead of RandomIntInRange
bool func SetNmax(const int Nmax)
if (Nmax <= 0) ; bad, so use default value
m_Nmax = 16
return false
endif
m_Nmax = Nmax
return true
endfunc
; Produce the next value in the sequence - range version
;
; @param pn If non-zero, initialize with seed = pn. If zero, just get next value
; @return the next value in the sequence. Values are from 1 to Nmax, inclusive.
; The second version is preferred; the first is retained for not breaking old ones.
int func RandomIntInRange(const int pn)
; In general the high-order bits have better random properties than
; the low-order bits, so do it this way instead of RandomInt(pn)%m_Nmax.
;
float x = RandomInt(pn) / 2147483648.0
return (1 + trunc( x * m_Nmax))
endfunc
; returns values in [1..nmax]
int func RandomIntInRange2(const int pn, const int nmax)
float x = RandomInt(pn) / 2147483648.0
int n = nmax
if n <= 0
n = 1
endif
return (1 + trunc( x * n))
endfunc
; Produce the next value in the sequence - float version
;
; @param pn If non-zero, initialize with seed = pn. If zero, just get next value
; @return the next value in the sequence. Value range is [0,1).
float func RandomFloat(const int pn)
return (RandomInt(pn) / 2147483648.0)
endfunc
; this one is random in [-1,1)
float func RandomFloat2(const int pn)
return 2*RandomFloat(pn)-1
endfunc
; 230401 random unit vector
complex func RandomVector(const int pn)
float ang = #pi * RandomFloat2(pn)
return exp(flip(ang))
endfunc
protected:
int m_hist[17] ; history array
int m_i ; index 1 into array
int m_j ; index 2 into array
int m_Nmax ; maximum integer for range version
int count ; how many randoms so far
default:
title = "Random"
int param p_seed
caption = "Seed"
default = 12345
hint = "Sets the seed for the random number generator. \
Each different seed produces a different sequence of random values."
endparam
}
class MyMath{
; fmax, fmin = max, min of floats
; imax, imin = max, min of ints
; quadrant = quadrant number 0..3 of complex
; fround = round float to n digits
; crouond = round complex to n digits
; atan2a = atan with values 0 to 2*#pi
; atan2s = atan with values 0 to 1
; fsort2 = sort 2 floats
; fsort3 = sort 3 floats
; fsort4 = sort 4 floats
static float func fmax(float a, float b)
if a >= b, return a, endif, return b
endfunc
static float func fmin(float a, float b)
if a <= b, return a, endif, return b
endfunc
static int func imax(int a, int b)
if a >= b, return a, endif, return b
endfunc
static int func imin(int a, int b)
if a <= b, return a, endif, return b
endfunc
static int func quadrant(complex z)
; 1 0
; 2 3
if real(z) >= 0 && imag(z) >= 0, return 0, endif
if real(z) <= 0 && imag(z) >= 0, return 1, endif
if real(z) <= 0 && imag(z) <= 0, return 2, endif
return 3
endfunc
static float func fround(float x, int n)
;n = imax(n, 0)
float scale = 10.0 ^ n
return round(scale*x)/scale
endfunc
static complex func cround(complex z, int n)
return fround(real(z), n) + flip(fround(imag(z), n))
endfunc
; the common atan with values 0 to 2*#pi
static float func atan2a(complex z)
float a = atan2(z)
if a < 0, a = a + 2*#pi, endif
return a
endfunc
; the common atan with values scaled to 0 to 1
static float func atan2s(complex z)
float a = atan2(z) / (2*#pi)
if a < 0, a = a + 1, endif
return a
endfunc
static func fsort2(float &a, float &b)
float t
if b < a, t = b, b = a, a = t, endif
endfunc
static func fsort3(float &a, float &b, float &c)
fsort2(a, b)
fsort2(a, c)
fsort2(a, b)
endfunc
static func fsort4(float &a, float &b, float &c, float &d)
fsort2(a, b)
fsort2(c, d)
fsort2(a, c)
fsort2(b, d)
fsort2(b, c)
endfunc
}
; combine two complex values in various ways
class CombineXY {
public:
func CombineXY()
endfunc
static complex func go(complex zx, complex zy, int i)
float x, float y
if i == 0, x = +real(zx), y = +real(zy),
elseif i == 1, x = +real(zx), y = -real(zy),
elseif i == 2, x = +real(zx), y = +imag(zy),
elseif i == 3, x = +real(zx), y = -imag(zy),
elseif i == 4, x = -real(zx), y = +real(zy),
elseif i == 5, x = -real(zx), y = -real(zy),
elseif i == 6, x = -real(zx), y = +imag(zy),
elseif i == 7, x = -real(zx), y = -imag(zy),
elseif i == 0, x = +real(zx), y = +real(zy),
elseif i == 9, x = +imag(zx), y = -real(zy),
elseif i == 10, x = +imag(zx), y = +imag(zy),
elseif i == 11, x = +imag(zx), y = -imag(zy),
elseif i == 12, x = -imag(zx), y = +real(zy),
elseif i == 13, x = -imag(zx), y = -real(zy),
elseif i == 14, x = -imag(zx), y = +imag(zy),
else, x = -imag(zx), y = -imag(zy),
endif
return x + flip(y)
endfunc
}
class GammaBlend{
public:
func GammaBlend( )
gamma = 2.2 ; default value
endfunc
func SetGamma(float gam)
gamma = gam
endfunc
func Zero()
rr = 0, gg = 0, bb = 0, aa = 0, ff = 0
;gamma = 2
endfunc
func AddOne(color c, float f)
rr = rr + f * red(c)^gamma
gg = gg + f * green(c)^gamma
bb = bb + f * blue(c)^gamma
aa = aa + f * alpha(c)
ff = ff + f
endfunc
color func Final( )
rr = (rr / ff)^(1/gamma)
gg = (gg / ff)^(1/gamma)
bb = (bb / ff)^(1/gamma)
aa = (aa / ff)
return rgba(rr, gg, bb, aa)
endfunc
color func Blend2(color c1, float f1, color c2, float f2)
float rr = ((f1* red(c1)^gamma + f2* red(c2)^gamma)/(f1+f2))^(1/gamma)
float gg = ((f1*green(c1)^gamma + f2*green(c2)^gamma)/(f1+f2))^(1/gamma)
float bb = ((f1* blue(c1)^gamma + f2* blue(c2)^gamma)/(f1+f2))^(1/gamma)
float aa = (f1*alpha(c1) + f2*alpha(c2) ) /(f1+f2)
return rgba(rr, gg, bb, aa)
endfunc
protected:
float rr, float gg, float bb, float aa, float ff
float gamma
}
class ComplexToFloat{
public:
func ComplexToFloat()
endfunc
static float func go(const complex zz, int mode, bool abs_value)
float ans
float r = real(zz)
float i = imag(zz)
float rabs = abs(r)
float iabs = abs(i)
if mode == 0 ; "Mod"
ans = sqrt(r^2 + i^2)
elseif mode == 1 ; "Real"
ans = r
elseif mode == 2 ; "Imag"
ans = i
elseif mode == 3 ; "Real+Imag"
ans = r+i
elseif mode == 4 ; "Real-Imag"
ans = r-i
elseif mode == 5 ; "Real*Imag"
ans = abs(r*i)
elseif mode == 6 ; "Real/Imag"
ans = r/i
elseif mode == 7 ; "Real^Imag"
ans = r^i
elseif mode == 8 ; "Imag/Real"
ans = i/r
elseif mode == 9 ; "Imag^Real"
ans = i^r
elseif mode == 10 ; "|Real|+|Imag|"
ans = rabs+iabs
elseif mode == 11 ; "|Real|-|Imag|"
ans = rabs-iabs
elseif mode == 12 ; "Max(Real,Imag)"
ans = MyMath.fmax(i, r)
elseif mode == 13 ;"Min(Real,Imag)"
ans = MyMath.fmin(i, r)
elseif mode == 14 ; "Max(|Real|,|Imag|)"
ans = MyMath.fmax(iabs, rabs)
elseif mode == 15 ; "Min(|Real|,|Imag|)"
ans = MyMath.fmin(iabs, rabs)
else;if mode == 16 ; "Angle"
ans = atan2(zz)/ (2 * #pi)
if ans < 0
ans = ans + 1
endif
endif
if abs_value
ans = abs(ans)
endif
return ans
endfunc
}
; an auxiliary function
; 211003 corrected #12 to #15, added cc argument and more cases
class ComplexToFloat2{
public:
func ComplexToFloat2()
endfunc
static float func go(const complex zz, const complex cc, int mode, bool abs_value)
float ans
float r = real(zz) , float i = imag(zz)
float rabs = abs(r), float iabs = abs(i)
float rc = real(cc), float ic = imag(cc)
if mode == 0 ; "Cabs"
ans = sqrt(r^2 + i^2)
elseif mode == 1 ; "Real"
ans = r
elseif mode == 2 ; "Imag"
ans = i
elseif mode == 3 ; "Real+Imag"
ans = r+i
elseif mode == 4 ; "Real-Imag"
ans = r-i
elseif mode == 5 ; "Real*Imag"
ans = r*i
;ans = abs(r*i) (old version used abs for no good reason)
elseif mode == 6 ; "Real/Imag"
ans = r/i
elseif mode == 7 ; "Real^Imag"
ans = r^i
elseif mode == 8 ; "Imag/Real"
ans = i/r
elseif mode == 9 ; "Imag^Real"
ans = i^r
elseif mode == 10 ; "|Real|+|Imag|"
ans = rabs+iabs
elseif mode == 11 ; "|Real|-|Imag|"
ans = rabs-iabs
elseif mode == 12 ; "Max(|Real|,|Imag|)"
ans = rabs
if iabs > rabs, ans = iabs, endif
elseif mode == 13 ; "Max(Real,Imag)"
ans = r
if i > r, ans = i, endif
elseif mode == 14 ; "Min(|Real|,|Imag|)"
ans = rabs
if iabs < rabs, ans = iabs, endif
elseif mode == 15 ;"Min(Real,Imag)"
ans = rabs
if i < r, ans = i, endif
elseif mode == 16 ; "Angle"
ans = atan2(zz)/ (2 * #pi)
if ans < 0
ans = ans + 1
endif
elseif mode == 17 ; "z cross+ c"
ans = r*ic + i*rc
elseif mode == 18 ; "z cross- c"
ans = r*ic - i*rc
elseif mode == 19 ;"z dot+ c"
ans = r*rc + i*ic
elseif mode == 20 ; "z dot- c"
ans = r*rc - i*ic
else;if mode == 21 ; cabs(z*c)
ans = cabs(zz*cc)
endif
if abs_value
ans = abs(ans)
endif
return ans
endfunc
}
; make a smooth transition avoiding tanh overflow
class TSmooth {
public:
func TSmooth()
endfunc
; return 0.5*(1+tanh(x)) while avoiding overflow
static float func go(const float x)
float xx = 2*x
float t ;t = tanh(x)
if xx >= 0
t= (1 - exp(-xx))/(1 + exp(-xx))
else
t = (exp(xx)-1)/(exp(xx)+1)
endif
return 0.5 * (1 + t)
endfunc
}
; tanh(z) avoiding tanh overflow
class TanhZ {
public:
func TanhZ()
endfunc
static complex func go(complex z)
z = z*2
if real(z) >= 0
return (1 - exp(-z))/(1 + exp(-z))
else
return (exp(z)-1)/(exp(z)+1)
endif
endfunc
}
; Calculate function f(z)^n and its first two derivatives.
; Derivatives courtesy of https://www.derivative-calculator.net/
class Deriv {
public:
; constructor initializes the state
func Deriv(int k)
kind = k ; don't break old version
endfunc
func Set_k(int k)
kind = k
endfunc
func pow_calc(complex z, complex n)
complex c = 0
complex s = 0
complex q = 0
complex t = 0
if kind == 0 ; z
f = z^n
fp = n*z^(n-1)
fpp = n*(n-1)*z^(n-2)
elseif kind == 1 ; sin(z)
s = sin(z)
c = cos(z)
f = s^n
fp = n*c*s^(n-1)
fpp = n*(n-1)*c*c*s^(n-2) - n*f
elseif kind == 2 ; sinh(z)
s = sinh(z)
c = cosh(z)
f = s^n
fp = n*c*s^(n-1)
fpp = n*(n-1)*c*c*s^(n-2) + n*f
elseif kind == 3 ; asin(z)
s = asin(z)
q = sqrt(1-z*z)
f = s^n
fp = n*s^(n-1)/q
fpp = n*(n-1)*s^(n-2)/q^2 + n*z*s^(n-1)/q^3
elseif kind == 4 ; asinh(z)
s = asinh(z)
q = sqrt(1+z*z)
f = s^n
fp = n*s^(n-1)/q
fpp = n*(n-1)*s^(n-2)/q^2 - n*z*s^(n-1)/q^3
elseif kind == 5 ; cos(z)
s = sin(z)
c = cos(z)
f = c^n
fp = -n*s*c^(n-1)
fpp = n*(n-1)*s*s*c^(n-2) - n*f
elseif kind == 6 ; cosh(z)
s = sinh(z)
c = cosh(z)
f = c^n
fp = n*s*c^(n-1)
fpp = n*(n-1)*s*s*c^(n-2) + n*f
elseif kind == 7 ; acos(z)
c = acos(z)
q = sqrt(1-z*z)
f = c^n
fp = -n*c^(n-1)/q
fpp = n*(n-1)*c^(n-2)/q^2 - n*z*c^(n-1)/q^3
elseif kind == 8 ; acosh(z)
c = acosh(z)
q = sqrt(z*z-1)
f = c^n
fp = n*c^(n-1)/q
fpp = n*(n-1)*c^(n-2)/q^2 - n*z*c^(n-1)/q^3
elseif kind == 9 ; tan(z)
t = tan(z)
s = 1/cos(z) ;sec(z)
f = t^n
fp = n*s*s*t^(n-1)
fpp = n*(n-1)*s*s*s*s*t^(n-2) + 2*n*s*s*f
elseif kind == 10 ; tanh(z)
t = tanh(z)
s = 1/cosh(z) ;sech(z)
f = t^n
fp = n*s*s*t^(n-1)
fpp = n*(n-1)*s*s*s*s*t^(n-2) - 2*n*s*s*f
elseif kind == 11 ; atan(z)
t = atan(z)
q = 1 + z*z
f = t^n
fp = n*t^(n-1)/q
fpp = n*(n-1)*t^(n-2)/q^2 - 2*n*z*t^(n-1)/q^2
elseif kind == 12 ; atanh(z)
t = atanh(z)
q = 1 - z*z
f = t^n
fp = n*t^(n-1)/q
fpp = n*(n-1)*t^(n-2)/q^2 + 2*n*z*t^(n-1)/q^2
elseif kind == 13 ;cotan(z)
c = cotan(z)
s = 1/sin(z) ;csq(z)
f = c^n
fp = -n*s*s*c^(n-1)
fpp = n*(n-1)*s*s*s*s*c^(n-2) + 2*n*s*s*f
elseif kind == 14 ;cotanh(z)
c = cotanh(z)
s = 1/sinh(z) ;csch (z)
f = c^n
fp = -n*s*s*c^(n-1)
fpp = n*(n-1)*s*s*s*s*c^(n-2) + 2*n*s*s*f
elseif kind == 15 ; log(z)
q = log(z)
f = q^n
fp = n*q^(n-1)/z
fpp = ( n*(n-1)*q^(n-2) - n*q^(n-1) ) / z^2
elseif kind == 16 ; exp(z)
f = exp(n*z)
fp = n*f
fpp = n*n*f
endif
endfunc
int kind
complex f
complex fp
complex fpp
}
; combine two complex values in various ways
class Combine {
public:
func Combine()
endfunc
static complex func go(const complex t1, int op, const complex t2)
if (op == 0 )
return t1 + t2
elseif (op == 1)
return t1 - t2
elseif (op == 2)
return t1 * t2
elseif (op == 3)
return t1 / t2
else;if (op == 4)
return t1 ^ t2
endif
endfunc
}
class Reduction(common.ulb:Generic) {
; Reduction base class. No title, so only used for a base class.
; Iterate takes a complex argument, returns a bool.
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func Reduction(Generic pparent)
Generic.Generic(pparent)
endfunc
func Init(complex pz)
endfunc
; @param pz
; @param pc
bool func Iterate(complex pz)
return true
endfunc
default:
int param v_Reduction
caption = "Version (Reduction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_Reduction < 100
endparam
}
class JLB_SimpleBailout(Reduction) {
public:
import "common.ulb"
func JLB_SimpleBailout(Generic pparent)
Reduction.Reduction(pparent)
endfunc
func Init(complex pz)
m_BailoutValue = real(pz) ;@p_default
endfunc
; @param pz
; @return true if bailed out
bool func Iterate(complex pz)
float tmp = |pz|
return (tmp > m_BailoutValue || isNan(tmp))
endfunc
; func SetBailoutValue(float value)
; m_BailoutValue = value
; endfunc
protected:
float m_BailoutValue
default:
title = "Simple Bailout"
int param v_SimpleBailout
caption = "Version (SimpleBailout)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_SimpleBailout < 100
endparam
; float param p_default
; default = 1
; visible = false
; endparam
}
class Contraction(common.ulb:Generic) {
; Contraction base class.
; Exact copy from mmf.ulb in case of future changes
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func Contraction(Generic pparent)
Generic.Generic(pparent)
endfunc
; @param pz
; @param pc
func Init(complex pz, complex pc)
endfunc
; @param pz
; @param pc
; @return the contracted value
complex func Iterate(complex pz, complex pc)
return pz
endfunc
default:
int param v_contraction
caption = "Version (Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_contraction < 100
endparam
}
class JLB_AdvancedBailout(Reduction) {
; The Iterate code is a direct copy from Ron Barnett's code, which appears in
; several places.
public:
import "common.ulb"
func JLB_AdvancedBailout(Generic pparent)
Reduction.Reduction(pparent)
endfunc
func Init(complex pz)
m_BailoutValue = real(pz)
endfunc
; @param pz
; @return true if bailed out.
bool func Iterate(complex pz)
float tmp = |pz|
if (isNan(tmp) || isInf(tmp))
return true
elseif @bailout_type == "mod"
return (tmp > m_BailoutValue)
elseif @bailout_type == "real"
return (sqr(real(pz)) > m_BailoutValue)
elseif @bailout_type == "imag"
return (sqr(imag(pz)) > m_BailoutValue)
elseif @bailout_type == "or"
return (sqr(real(pz)) > m_BailoutValue || sqr(imag(pz)) > m_BailoutValue)
elseif @bailout_type == "and"
return (sqr(real(pz)) > m_BailoutValue && sqr(imag(pz)) > m_BailoutValue)
elseif @bailout_type == "manh"
return (sqr(abs(real(pz)) + abs(imag(pz))) > m_BailoutValue)
else ;if @bailout_type == "manr"
return (sqr(real(pz) + imag(pz)) > m_BailoutValue)
; else;if @bailout_type == "function"
; return (sqr(real(@bailout_func(pz))) > m_BailoutValue)
endif
endfunc
protected:
float m_BailoutValue
default:
title = "Advanced Bailout"
int param v_AdvancedBailout
caption = "Version (AdvancedBailout)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_AdvancedBailout < 100
endparam
param bailout_type
caption = "Bailout test type"
default = 0
enum = "mod" "real" "imag" "or" "and" "manh" "manr" ; "function"
hint = "mod gives the usual behavior"
endparam
}
class CalcValue {
public:
func CalcValue()
endfunc
static float func go(const int mode, const complex pz, const complex pc)
if mode == 0 ; "cabs" or mod
return cabs(pz)
elseif mode == 1 ; "real"
return real(pz)
elseif mode == 2 ; "imag"
return imag(pz)
elseif mode == 3 ; "real+imag"
return real(pz) + imag(pz)
elseif mode == 4 ; "real-imag"
return real(pz) - imag(pz)
elseif mode == 4 ; "real*imag"
return real(pz) * imag(pz)
elseif mode == 5 ; "z angle"
return atan2(pz)
elseif mode == 6 ; "z cross+ c"
return real(pz)*imag(pc) + imag(pz)*real(pc)
elseif mode == 7 ; "z cross- c"
return real(pz)*imag(pc) - imag(pz)*real(pc)
elseif mode == 8 ;"z dot+ c"
return real(pz)*real(pc) + imag(pz)*imag(pc)
else ; "z dot- c"
return real(pz)*real(pc) - imag(pz)*imag(pc)
endif
endfunc
}
comment{
Group 2: Recommended classes & etc.
}
class JLB_ShapesDirect2(common.ulb:DirectColoring) {
; version 100 of 03 November 2012
; This is a direct coloring formula.
;
; Superpose up to 500 annulus shapes with optional texture. The coloring
; can be blended into a background color. Overlapping shapes get averaged.
;
; Best with Linear Transfer Function. With Linear and Color Density = 1, the
; gradient is used exactly once around the annulus.
public:
import "common.ulb"
import "dmj5.ulb" ; texture class
; constructor
func JLB_ShapesDirect2(Generic pparent)
DirectColoring.DirectColoring(pparent)
m_distortion = new @fdistortion(this)
do_distort = (@fdistortion != DMJ_TrapShapeFlat) && (@pDistSize != 0.0)
m_texture = new @ftexture(this)
do_texture = (@ftexture != DMJ_TrapShapeFlat) && (@pTexSize != 0.0)
m_gb = new GammaBlend( )
r = new JLB_Random(0)
r.Init(@seed)
if (@two_D)
nshapes = @n2_1*@n2_2
if (nshapes > 500)
nshapes = 500
endif
else
nshapes = @num
endif
bool keep_aspect = @aspect || (@shape_type == "Circle") || (@shape_type == "Square")
float x_size
float y_size
float x_spread
float y_spread
if (@shape_type == "Circle")
x_size = y_size = @radius
x_spread = y_spread = @radius_spread
elseif (@shape_type == "Triangle")
x_size = @t_w
y_size = 1.0
x_spread = @tx_spread0
y_spread = @ty_spread0
else
x_size = @x_size0/2 ; @x_size0 is side length, x_size is half-length
x_spread = @x_spread0
if (@shape_type == "Square")
y_size = @x_size0/2
y_spread = x_spread
else
y_size = @y_size0/2
y_spread = @y_spread0
endif
endif
if (keep_aspect)
y_spread = x_spread * y_size / x_size
endif
back_out = rgb(1,1,1) ; for quieting the compiler
back_ins = rgb(1,1,1)
if (@blend_type == "Blend outside edge")
back_out = @bkg_out
elseif (@blend_type == "Blend inside edge")
back_ins = @bkg_ins
elseif (@blend_type == "Blend both edges")
back_ins = @bkg_ins
back_out = @bkg_out
endif
; generate the shapes
float ctr_rad = cabs(@center)
float ctr_ang = atan2(@center)
int i = 0
int i2_1 = 0
int i2_2 = 0
while (i < nshapes)
if (@two_D)
ctr[i] = @center + i2_1*@off2_1 + i2_2*@off2_2
if (@ctr_chg_type == "Random")
ctr[i] = ctr[i] + @center_spread*((r.RandomFloat(0)-0.5) + flip(r.RandomFloat(0)-0.5))
endif
i2_1 = i2_1 + 1
if (i2_1 == @n2_1)
i2_1 = 0
i2_2 = i2_2 + 1
endif
else ; not 2D
; centers and angles w.r.t. the center of each shape
if (@ctr_chg_type == "Random")
ctr[i] = @center + @center_spread*((r.RandomFloat(0)-0.5) + flip(r.RandomFloat(0)-0.5))
else ;if (@ctr_chg_type == "Incremental")
float p = ctr_rad*(@ctr_rad_mult^i)
float a = ctr_ang - i*@ctr_ang_add*#pi/180
ctr[i] = p*exp(flip(a))
endif
endif
; x and y sizes of each shape
if (@rad_chg_type == "Random")
x_rad[i] = x_size + x_spread * (r.RandomFloat(0)-0.5)
if keep_aspect
y_rad[i] = x_rad[i] * y_size/x_size
else
y_rad[i] = y_size + y_spread * (r.RandomFloat(0)-0.5)
endif
else ;if (@rad_chg_type == "Incremental")
if (@rad_chg_type2 == "Add")
x_rad[i] = x_size + (x_spread * i)
y_rad[i] = y_size + (y_spread * i)
else ;if (@rad_chg_type2 == "Multiply")
x_rad[i] = x_size * (x_spread ^ i)
y_rad[i] = y_size * (y_spread ^ i)
endif
if keep_aspect
y_rad[i] = x_rad[i] * y_size/x_size
endif
endif
; thickness of each shape
float thk
if (@thick_chg_type == "Random")
thk = @thick + @thick_spread * (r.RandomFloat(0)-0.5)
else ;if (@thick_chg_type == "Incremental")
if (@thick_chg_type2 == "Add")
thk = @thick + (@thick_spread * i)
else ;if (@thick_chg_type2 == "Multiply")
thk = @thick * (@thick_spread ^ i)
endif
endif
if (thk < 0.0)
thk = 0.0
endif
if (@shape_type == "Ellipse")
delta1[i] = thk/(0.5*(x_rad[i]+y_rad[i]))
delta2[i] = delta1[i]
elseif (@shape_type == "Triangle")
delta1[i] = thk/2
; max delta = radius of circumscribed circle
float dmax = Geometry.DistanceToCircumCenter(abs(x_rad[i]), \
cabs(@t_voff*y_rad[i]), cabs(@t_voff*y_rad[i] - x_rad[i]))
if (delta1[i] > dmax) ; radius of inscribed circle
delta1[i] = dmax
endif
delta2[i] = 1.0 ; vertices ccw
if (x_rad[i]*imag(@t_voff)*y_rad[i] < 0) ; vertices cw
delta2[i] = -1.0
endif
else
delta1[i] = thk/x_rad[i]
delta2[i] = thk/y_rad[i]
endif
if (@shape_type != "Triangle")
;Avoid some weird behavior
if (delta1[i] > 1.0)
delta1[i] = 1.0
endif
if (delta2[i] > 1.0)
delta2[i] = 1.0
endif
endif
; orientation angle for each ahape
if (@ang_chg_type == "Random")
angle[i] = @ang + @ang_spread * (r.RandomFloat(0)-0.5)
else ;if @ang_chg_type == "Incremental"
angle[i] = @ang - @ang_spread * i
endif
angle[i] = angle[i] * #pi/180
; gradient offset for each shape
if (@grad_chg_type == "Random")
grad_off[i] = @grad_offset + @grad_offset_spread* (r.RandomFloat(0)-0.5)
else ;if (@grad_chg_type == "Icremental")
grad_off[i] = @grad_offset + @grad_offset_spread * i
endif
while (grad_off[i] > 1.0)
grad_off[i] = grad_off[i] - 1.0
endwhile
while (grad_off[i] < 0.0)
grad_off[i] = grad_off[i] + 1.0
endwhile
i = i + 1
endwhile
endfunc
; initialize the objects
func Init(complex pz, complex ppixel)
DirectColoring.Init(pz, ppixel)
m_distortion.Init(pz)
m_texture.Init(pz)
m_gb.SetGamma(@gamma) ; default is 2.2
endfunc
; call for each iterated point
func Iterate(complex pz)
DirectColoring.Iterate(pz)
endfunc
; override the parent and call in the final section of the coloring formula.
color func Result(complex pz)
float idx
int count = 0
int i = 0
color color_list[500]
complex z = #pixel
if (do_distort)
z = z + m_distortion.Iterate(z) * @pDistSize
z = z + flip(m_distortion.Iterate(z) * @pDistSize)
endif
while (i < nshapes)
bool hit = false
; get rotated relative coordinates
complex rot_ctr = ctr[i]
if (@shape_type == "Triangle") ; rotate about triangle "center"
rot_ctr = rot_ctr + (x_rad[i] + @t_voff*y_rad[i])/3
endif
float x = real(z)-real(rot_ctr)
float y = imag(z)-imag(rot_ctr)
float c = cos(angle[i])
float s = sin(angle[i])
float xr = x*c-y*s
float yr = x*s+y*c
complex zr = rot_ctr + xr + flip(yr) ;; 9/28/12 !!
; Scale to size
float dx = xr / x_rad[i]
float dy = yr / y_rad[i]
float d1
float d2
float d3
float dist = 1 ; Make dist = 0 at the center of the annulus, +1 or -1 at the edges.
if (@shape_type == "Circle" || @shape_type == "Ellipse")
dist= (abs(dx))^@p + (abs(dy))^@p
dist = (dist - 1.0)/delta1[i]
;dist = abs(dist)/delta1[i]
hit = abs(dist) <= 1.0
elseif (@shape_type == "Square" || @shape_type == "Rectangle")
; Have to look at all sides. Opposites are identical, though.
d1 = (abs(dx) - 1.0) / delta1[i]
d2 = (abs(dy) - 1.0) / delta2[i]
if (abs(d1) <= 1.0 && abs(dy) <= 1.0+delta2[i])
hit = true
dist = d1
endif
if (abs(d2) <= 1.0 && abs(dx) <= 1.0+delta1[i])
if (hit) ; corners are tricky
if (d2 > d1)
dist = d2
endif
else
hit = true
dist = d2
endif
endif
else ;if (@shape_type == "Triangle")
complex v0 = ctr[i] ; lower left corner
complex v1 = v0 + x_rad[i]
complex v2 = v0 + @t_voff*y_rad[i]
float del2 = cabs(v2-v0) ; variables in derivation
float del3 = cabs(v2-v1)
float a = real(@t_voff)*y_rad[i]
float b = imag(@t_voff)*y_rad[i]
float w = x_rad[i]
float del = delta1[i]
; It's a hit if zr is within the outer annulus and outside the inner annulus
complex dv0
complex dv1
complex dv2
if (imag(@t_voff) > 0.0)
dv0 = del*((delta2[i]*del2+a)/b+(0,1))
dv1 = del*(-(delta2[i]*del3+w-a)/b+(0,1))
dv2 = del*(delta2[i]*((w-a)*del2-a*del3)/(b*w)-flip(delta2[i]*(del2+del3)/w))
else
dv0 = del*((delta2[i]*del2-a)/b-(0,1))
dv1 = del*((-delta2[i]*del3+w-a)/b-(0,1))
dv2 = del*(delta2[i]*((w-a)*del2-a*del3)/(b*w)-flip(delta2[i]*(del2+del3)/w))
endif
bool outer = Geometry.PointInTriangle(zr, v0-dv0, v1-dv1, v2-dv2)
bool inner = Geometry.PointInTriangle(zr, v0+dv0, v1+dv1, v2+dv2)
hit = outer && !inner
if (hit)
xr = real(zr-ctr[i])
yr = imag(zr-ctr[i])
if (imag(@t_voff) > 0.0)
d1 = -yr/del
d2 = -delta2[i]*(b*xr-a*yr)/del2/del
d3 = delta2[i]*(b*xr+(w-a)*yr-b*w)/del3/del
else
d1 = yr/del
d2 = -delta2[i]*(b*xr-a*yr)/del2/del
d3 = delta2[i]*(b*xr+(w-a)*yr-b*w)/del3/del
endif
bool inside = Geometry.PointInTriangle(zr, v0, v1, v2)
if (inside) ; dist should be negative
dist = -1
if (d1 <= 0 && d1 >= -1)
dist = d1
endif
if (d2 <= 0 && d2 >= -1 && d2 > dist)
dist = d2
endif
if (d3 <= 0 && d3 >= -1 && d3 > dist)
dist = d3
endif
else ; outside, dist should be positive
dist = -1
if (d1 >= 0 && d1 <= 1)
dist = d1
endif
if (d2 >= 0 && d2 <= 1 && d2 > dist)
dist = d2
endif
if (d3 >= 0 && d3 <= 1 && d3 > dist)
dist = d3
endif
endif
endif
endif ; @shape_type
if (hit)
if (@uniform_grad)
idx = grad_off[i]
else
complex gctr = ctr[i]
if (@shape_type == "Triangle")
gctr = gctr + (x_rad[i] + @t_voff*y_rad[i])/3
endif
float theta = atan2(z-gctr)/(2*#pi) ; gradient scale is 0 to 1.
if (theta < 0.0)
theta = theta + 1.0
endif
idx = grad_off[i] + theta
endif
float dt = 0.0
if (do_texture)
dt = m_Texture.Iterate(z) * @pTexSize
endif
idx = idx + dt
color new_color = gradient(idx - trunc(idx))
float t = dist ; -1<=t<=1
color cb
if (t >= 0)
if (@blend_type == "Blend outside edge" || @blend_type == "Blend both edges")
cb = back_out
if (@keep_hue_out)
cb = hsla(hue(new_color), sat(cb), lum(cb), alpha(cb))
endif
; if @v_ShapesDirect2 < 220806
new_color = blend(new_color, cb, t^@pb_out)
; else
; new_color = m_gb.Blend2(new_color, 1-t^@pb_out, cb, t^@pb_out)
; endif
endif
else ;if (t < 0)
if (@blend_type == "Blend inside edge" || @blend_type == "Blend both edges")
cb = back_ins
if (@keep_hue_ins)
cb = hsla(hue(new_color), sat(cb), lum(cb), alpha(cb))
endif
t = -t
; if @v_ShapesDirect2 < 220806
new_color = blend(new_color, cb, t^@pb_ins)
; else
; new_color = m_gb.Blend2(new_color, 1-t^@pb_ins, cb, t^@pb_ins)
; endif
endif
endif
color_list[count] = new_color
count = count + 1
endif
i = i + 1
endwhile
m_solid = (count == 0) ; parameter in Coloring class
color return_color = rgb(0,0,0)
if (count > 0)
int ntot = count
if ((@overlap == "First N" || @overlap == "Last N") && @N_over < count)
ntot = @N_over
endif
int n1, int n2
if (@overlap == "First N" || @overlap == "Average All")
n1 = 0
n2 = ntot - 1
else ;if if (@overlap == "Last N")
n1 = count - ntot
n2 = count - 1
endif
if @v_ShapesDirect2 < 220806
while (n1 <= n2)
return_color = blend(return_color, color_list[n1], 1.0/ntot)
n1 = n1 + 1
endwhile
else
m_gb.Zero()
; if n1 == n2
; m_gb.SetGamma(1)
; endif
while (n1 <= n2)
m_gb.AddOne(color_list[n1], 1.0/ntot)
n1 = n1 + 1
endwhile
return_color = m_gb.final()
endif
endif
return return_color
endfunc
protected:
TrapShape m_distortion
TrapShape m_texture
JLB_Random r
GammaBlend m_gb
; For each shape
complex ctr[500] ; center
float x_rad[500] ; sizes
float y_rad[500]
float delta1[500] ; Scaled thickness
float delta2[500]
float grad_off[500] ; Offset of the gradient
float angle[500] ; Orientation angle
int nshapes
color back_out
color back_ins
bool do_distort
bool do_texture
default:
title = "Shapes Direct2"
int param v_ShapesDirect2
caption = "Version (ShapesDirect2)"
default = 220806
hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used."
visible = @v_ShapesDirect2 < 220806
endparam
; general parameters
;
heading
text="This coloring ignores the formula, so use a Pixel formula."
endheading
param shape_type
caption = "Shape"
enum = "Circle" "Ellipse" "Square" "Rectangle" "Triangle"
default = 0
endparam
bool param two_D
caption = "Two-D array?"
default = false
endparam
float param p
caption = "Power"
default = 2.0
min = 0.0
hint = "Use 2 for standard circles or ellipses"
visible = (@shape_type < 2)
endparam
int param num
caption = "Number of shapes"
min = 1
max = 500
default = 10
visible = !@two_D
endparam
complex param off2_1
caption = "First offset"
default = (1,0)
visible = @two_D
endparam
complex param off2_2
caption = "Second offset"
default = (0,1)
visible = @two_D
endparam
int param n2_1
caption = "# along offset 1"
default = 4
min = 1
visible = @two_D
endparam
int param n2_2
caption = "# along offset 2"
default = 4
min = 1
visible = @two_D
endparam
heading
caption = "Initial Point and its movement"
endheading
complex param center
caption = "Initial point"
default = (0,0)
hint = "Center of first shape, except ower left corner for triangles"
endparam
param ctr_chg_type
caption = "Point change"
enum = "Random" "Incremental"
default = 0
hint = "How to move the centers of subsequent shapes"
visible = !@two_D
endparam
float param center_spread
caption = "Random movement"
min = 0.0
default = 0.1
visible = (@ctr_chg_type == 0)
hint = "Maximum movement of X and Y components of the shape center"
endparam
; param ctr_incr_type
; caption = "Center change type?"
; ebum = "Add" "Multipl
; default = 0
; visible = (@ctr_chg_type == 1)
; endparam
float param ctr_rad_mult
caption = "Ctr. radius multiply"
min = 0.0
default = 1.1
visible = (@ctr_chg_type == 1)
endparam
float param ctr_ang_add
caption = "Ctr. angle add (degrees)"
default = 15
visible = (@ctr_chg_type == 1)
endparam
heading
caption = "Shape parameters"
endheading
float param radius
caption = "Initial radius"
min = 0.0
default = 1.0
hint = "Radius of first circle"
visible = (@shape_type==0)
endparam
float param x_size0
caption = "Initial x_size"
min = 0.0
default = 1.0
visible = (@shape_type > 0 && @shape_type < 4)
hint = "X semi-axis for ellipses, X side length for squares and rectangles"
endparam
float param y_size0
caption = "Initial y_size"
min = 0.0
default = 0.75
visible = (@shape_type == 1 || @shape_type == 3)
hint = "Y semi-axis for ellipses, Y side length for rectangles"
endparam
float param t_w
caption = "Triangle horiz. leg"
; min = 0.0
default = 1.0
visible = (@shape_type == 4)
endparam
complex param t_voff
caption = "Triangle 3rd vertex"
hint = "Offset from lower left corner"
default = (0.0, 1.0)
visible = (@shape_type == 4)
endparam
param rad_chg_type
caption = "Size change"
enum = "Random" "Incremental"
default = 0
hint = "How to change the size of subsequent shapes"
endparam
param rad_chg_type2
caption = "Size change type"
enum = "Add" "Multipy"
default = 0
visible = (@rad_chg_type == 1)
endparam
float param radius_spread
caption = "Variation of radius"
min = 0.0
default = 0.1
visible = (@shape_type == 0)
hint = "Maximum change of x_size and y_size for subsequent shapes"
endparam
float param x_spread0
caption = "Change of x_size"
min = 0.0
default = 0.5
visible = (@shape_type > 0 && @shape_type < 4)
; hint = "X semi-axis for ellipses, X side length for squares and rectangles"
endparam
float param y_spread0
caption = "Change of y_size"
min = 0.0
default = 0.1
visible = (@shape_type == 1 || @shape_type == 3) && !@aspect
; hint = "Y semi-axis for ellipses, Y side length for rectangles"
endparam
float param tx_spread0
caption = "Change of bottom"
; min = 0.0
default = 0.5
visible = (@shape_type == 4)
endparam
float param ty_spread0
caption = "Change of top"
; min = 0.0
default = 0.1
visible = (@shape_type == 4) && !@aspect
endparam
bool param aspect
caption = "Keep aspect ratio?"
default = true
visible = (@shape_type !=0 && @shape_type !=2)
hint = "Keep the ratio of x_size to y_size constant? "
endparam
heading
caption = "Rotation angle and its changing"
endheading
float param ang
caption = "Initial rotation angle"
default = 0.0
hint = "Rotation angle if first shape"
visible = (@shape_type > 0) || (@p != 2.0)
endparam
param ang_chg_type
caption = "Angle change"
enum = "Random" "Incremental"
default = 0
hint = "How to change the rotation angle of subsequent shapes"
visible = (@shape_type > 0) || (@p != 2.0)
endparam
float param ang_spread
caption = "Variation of angle"
;min = 0.0
default = 45
hint = "Maximum degrees to add for each subsequent shape"
;visible = (@shape_type > 0)
endparam
heading
caption = "Thickness of annulus and its changing"
endheading
float param thick
caption="Initial thickness"
default=0.1
hint = "Thickness of initial shape's annulus"
min = 0
endparam
param thick_chg_type
caption = "Thickness change"
enum = "Random" "Incremental"
hint = "How to change the thickness of subsequent shapes"
default = 0
endparam
param thick_chg_type2
caption = "Thickness change type"
enum = "Add" "Multipy"
default = 0
visible = (@thick_chg_type == 1)
endparam
float param thick_spread
caption = "Thickness change"
hint = "Amount to add or factor to multiply by"
default = 0.1
endparam
; float param tp
; caption = "Thickness power"
; visible = (@shape_type <= 1)
; min = 0
; default = 1.0
; endparam
heading
caption = "Gradient offset and its changing"
endheading
bool param uniform_grad
caption = "Uniform shape coloring?"
default = false
hint = "Shape coloring uniform around the shape?"
endparam
float param grad_offset
caption="Initial gradient offset"
min = 0.0
max = 1.0
default=0
hint = "Offset of the gradient of the first shape. \
With Color Density = 1 and Transfer Function = Linear, the gradient goes \
around the annulus exactly once, for total offset = 1."
endparam
param grad_chg_type
caption = "Offset change"
enum = "Random" "Incremental"
hint = "How to change the gradient offset"
default = 0
endparam
float param grad_offset_spread
caption = "Variation of offset"
hint = "Amount of offset change"
default = 0.1
endparam
heading
Caption = "Edge blending"
endheading
param blend_type
caption = "Blend type"
enum = "Flat" "Blend outside edge" "Blend inside edge" "Blend both edges"
hint = "Make the edges of the annulas blend into a background color?"
default = 3
endparam
float param pb_out
caption = "Outside blend power"
default = 2.0
min = 0.0
visible = (@blend_type == 1 || @blend_type == 3)
; hint = "Large numbers give flatter blending"
endparam
bool param keep_hue_out
caption = "Keep hue?"
default = false
hint = "Use hue of annulus with saturation, luminosity, and opacity of \
outside blend color"
visible = (@blend_type == 1 || @blend_type == 3)
endparam
color param bkg_out
caption = "Outside blend color"
default = rgb(1,1,1) ; white
visible = (@blend_type == 1 || @blend_type == 3)
hint = "Color to blend the outside edge into"
endparam
float param pb_ins
caption = "Inside blend power"
default = 2.0
min = 0.0
visible = (@blend_type == 2 || @blend_type == 3)
; hint = "Large numbers give flatter blending"
endparam
bool param keep_hue_ins
caption = "Keep hue?"
default = false
hint = "Use hue of annulus with saturation, luminosity, and opacity of \
inside blend color"
visible = (@blend_type == 2 || @blend_type == 3)
endparam
color param bkg_ins
caption = "Inside blend color"
default = rgb(1,1,1) ; white
visible = (@blend_type == 2 || @blend_type == 3)
hint = "Color to blend the inside edge into"
endparam
heading
caption = "Overlap coloring"
endheading
param overlap
caption = "Overlap coloring"
enum = "First N" "Average All" "Last N"
default = 1
hint = "How to color pixels if shapes overlap"
endparam
int param N_over
caption = "N"
default = 1
min = 1
visible = (@overlap == 0 || @overlap == 2)
hint = "How many shapes contribute to coloring"
endparam
float param gamma
caption = "gamma for blending"
default = 2.2
endparam
heading
caption = "Texture"
endheading
TrapShape param ftexture
caption = "Texture"
default = DMJ_TrapShapeFlat
hint = "TrapShape plugins can be used to add texture"
endparam
float param pTexSize
caption = "Texture Strength"
default = 0.1
visible = @ftexture != DMJ_TrapShapeFlat
endparam
heading
caption = "Shape distortion"
endheading
TrapShape param fdistortion
caption = "Distortion"
default = DMJ_TrapShapeFlat
hint = "TrapShape plugins can be used to distort the shapes."
endparam
float param pDistSize
caption = "Distortion Strength"
default = 0.1
visible = @fdistortion != DMJ_TrapShapeFlat
endparam
heading
caption = "Random number seed"
visible = (@ctr_chg_type==0 || @rad_chg_type==0 || @ang_chg_type==0)
endheading
int param seed
caption = "Seed"
default = 12345
visible = (@ctr_chg_type==0 || @rad_chg_type==0 || @ang_chg_type==0 || \
@grad_chg_type==0)
endparam
}
class JLB_QuadMirror2(common.ulb:UserTransform) {
; Pick a block from the image, then repeat it mirroring both
; horizontally and vertically.
; 240803 show selected block in its original position
; 240803 move stuff from Init( ) to constructor
public:
import "common.ulb"
func JLB_QuadMirror2(Generic pparent)
UserTransform.UserTransform(pparent)
m_PixelCoordinate = new PixelCoordinate(pparent)
m_FractalCoordinate = new FractalCoordinate(pparent)
; the rest of this func used to be in Init( ), but that was bad
int ix = 1, if (@bpos > 1 ), ix = 2, endif
int iy = 1, if (@bpos == 1 || @bpos == 3), iy = 2, endif
; block size in pixels1
m_bx = real(#screenmax) / @nx
m_by = imag(#screenmax) / @ny
; pixel of center of block to be mirrored
m_pix_c = m_PixelCoordinate.Iterate(@z_c)
if (@show == "Selected block") ; pixel location of original block
; m_x1 = real(#screenmax)/2 - m_bx/2
; m_y1 = imag(#screenmax)/2 - m_by/2
m_x1 = real(m_pix_c) - m_bx/2
m_y1 = imag(m_pix_c) - m_by/2
elseif (@show == 2) ; pixel location of original block
m_x1 = (ix - 1) * m_bx ; in mirrored image
m_y1 = (iy - 1) * m_by
endif
m_x2 = m_x1 + m_bx
m_y2 = m_y1 + m_by
mm_pix_c = (m_x1 + m_x2)/2 + flip((m_y1 + m_y2)/2)
endfunc
; now the default Inits are fine
; func Init(complex pz)
; UserTransform.Init(pz)
; m_PixelCoordinate.Init(pz)
; m_FractalCoordinate.Init(pz)
; endfunc
complex func Iterate(complex pz)
UserTransform.Iterate(pz)
complex tz = #screenpixel
;if (@show == 1), tz = tz - m_pix_c, endif
float tx = real(tz)
float ty = imag(tz)
if (@show == 0)
return pz
elseif (@show == "Selected block")
if (tx >= m_x1 && tx <= m_x2 && ty >= m_y1 && ty <= m_y2)
;if tx >= -m_bx/2 && tx <= m_bx/2 && ty >= -m_by/2 && ty <= m_by/2
return m_FractalCoordinate.Iterate(tz); + m_pix_c - #screenmax/2)
else
return m_FractalCoordinate.Iterate(#screenmax/2) ;@z_c
endif
else
; calculate pixel within source block for mirrored pixel to use
int n
float dx
if (tx > m_x2)
dx = tx - m_x2
n = floor(dx/m_bx)
dx = dx - n*m_bx
if (n % 2 == 0)
tx = m_x1 + m_bx - dx
else
tx = m_x1 + dx
endif
elseif (tx < m_x1)
dx = m_x1 - tx
n = floor(dx/m_bx)
dx = dx - n * m_bx
if (n % 2 == 0)
tx = m_x1 + dx
else
tx = m_x1 + m_bx - dx
endif
endif ; now m_x1 <= tx <= m_x2
float dy
if (ty > m_y2)
dy = ty - m_y2
n = floor(dy/m_by)
dy = dy - n*m_by
if (n % 2 == 0)
ty = m_y1 + m_by - dy
else
ty = m_y1 + dy
endif
elseif (ty < m_y1)
dy = m_y1 - ty
n = floor(dy/m_by)
dy = dy - n * m_by
if (n % 2 == 0)
ty = m_y1 + dy
else
ty = m_y1 + m_by - dy
endif
endif ; now m_y1 <= ty <= m_y2
tz = tx + flip(ty) ; pixel offset in original block
return m_FractalCoordinate.Iterate(tz + m_pix_c - mm_pix_c)
endif
endfunc
protected:
PixelCoordinate m_PixelCoordinate
FractalCoordinate m_FractalCoordinate
complex m_pix_c ; center of mirrored block in pixels
complex mm_pix_c ; center of mirrored block in new location
float m_bx, float m_by ; block dimensions in pixels
float m_x1, float m_x2 ; block edges in pixels
float m_y1, float m_y2
default:
title = "QuadMirror2 new"
rating = Recommended
heading
caption = "How many repeated blocks?"
endheading
int param nx
caption = "Horizontal"
default = 4
min = 1
endparam
int param ny
caption = "Vertical"
default = 2
min = 1
endparam
heading
caption = "Where to put the original block"
endheading
param bpos
caption = "Block position"
enum = "1, 1" "1, 2" "2, 1" "2, 2"
default = 2
endparam
heading
endheading
complex param z_c
caption = "Center point"
default = #center
hint = "Center of block to be mirrored"
endparam
heading
endheading
param show
caption = "Show"
enum = "Unmirrored original" "Selected block" "Mirrored image"
default = 2
; hint = "?"
endparam
}
class JLB_Vignette(common.ulb:DirectColoring) {
; This is a direct coloring formula.
; put a vignette shape on a layer; use it as the top layer to modify the image
; type 1 : center is white, use it to multiply the lower layer
; type 2 : center is transparent
; Use with a pixel formula
public:
import "common.ulb"
; constructor
func JLB_Vignette(Generic pparent)
DirectColoring.DirectColoring(pparent)
endfunc
; initialize the objects
func Init(complex pz, complex ppixel)
DirectColoring.Init(pz, ppixel)
if @v_Vignette == 102
type = 0
else
type = @vtype
rr = red(gradient(0))
gg = green(gradient(0))
bb = blue(gradient(0))
endif
endfunc
; call for each iterated point
func Iterate(complex pz)
DirectColoring.Iterate(pz)
endfunc
; override the parent and call in the final section of the coloring formula.
color func Result(complex pz)
; screen relative coordinates go from 0 to +1, symmetric in x and y
; zero at screen center, 1 at screen edges
float x = abs( (real(#screenpixel) / (0.5*#width )) - 1)
float y = abs( (imag(#screenpixel) / (0.5*#height)) - 1)
float r = x^@shape + y^@shape
float r0 = @radius^@shape
if r <= r0
if type == 0
return hsl(0, 1, 1) ; white
else
return hsla(0,0,0,0) ; transparent
endif
endif
; t = 0 at inner radius, 1 at outer radius (at 2 in earliest version)
float t
float r1 = @r_outer
if @v_Vignette > 102
r1 = r1^@shape ; it was wrong before
endif
if @v_Vignette < 102
t = (r - r0) / (2 - r0)
else
t = (r - r0) / (r1 - r0)
endif
t = MyMath.fmin(t, 1)
;t= MyMath.fmax(0, t) ; not needed
float luminance
if @v_Vignette < 102
luminance = 1 - (1-@dark) * t^@power
return hsl(0, 0, luminance) ; gray
elseif type == 0
luminance = 1 - (1-@dark2) * t^@power
return hsl(0, 0, luminance) ; gray
else
float opacity = t^@power
return rgba(rr, gg, bb, opacity) ; partly transparent
endif
endfunc
protected:
int type
float rr, float gg, float bb
default:
title = "Vignette"
int param v_Vignette
caption = "Version (Vignette)"
default = 230105
visible = @v_Vignette < 102 ; 230105 change is backwards compatible
endparam
heading
text="This coloring ignores the formula. Use a Pixel formula. \
Distances are screen-relative."
endheading
heading
text = "White center: useful as a multiplying layer for darkening corners."
visible = @vtype == 0
endheading
heading
text = "Transparent center: useful as a normal layer for making a border."
visible = @vtype == 1
endheading
param vtype
caption = "Center color"
enum = "White" "Transparent"
default = 0
endparam
float param radius
caption = "Inner radius"
min = 0
max = 2
default = 0.5
endparam
float param r_outer
caption = "Outer radius"
min = 0
max = 2
default = 2
visible = @v_Vignette > 101
endparam
float param shape
caption = "Shape of vignette"
min = 0.25
default = 2
hint = "Use 2 for circle/ellipse shape, >2 for squarer, 1 for diamond, 0.5 for astroid"
endparam
float param power
caption = "Smoothness of vignette"
min = 0
default = 2
hint = "small values make abrupt inner edge, large values smoother"
endparam
float param dark
caption = "Brightness of vignette at corners"
default = 0.25
hint = "0 for solid black, 1 for no effect"
min = 0
max = 1
visible = @v_Vignette < 102
endparam
float param dark2
caption = "Brightness at outer radius"
default = 0.25
hint = "0 for solid black, 1 for no effect"
min = 0
max = 1
visible = @v_Vignette == 102 || @vtype == 0
endparam
}
class JLB_Cells(common.ulb:GradientColoring) {
;
; November 2020
; Divide into rectangular or triangularcells
;
public:
func JLB_Cells(Generic pparent)
GradientColoring.GradientColoring(pparent)
g = new Geometry ; only used for triangles
StartRandom(100)
MinArea = 0.01 * @pMinArea * #width * #height ; convert from percent
MinSide = @pMinSide * #width
MinSideSq = sqr(MinSide)
xb = @pXBorder * #width
yb = @pYBorder * #width
lw = @B * #width
NumSmall = 0
if @pWhich == 0
FirstTriangles()
else
NumCells = 1
V1[0] = xb + flip(yb)
V2[0] = #width-xb + flip(#height-yb)
Check(0)
endif
int tries = 0 ; just in case of disaster
while NumSmall < NumCells && NumCells < @pMaxCells && tries < @pMaxCells
if @pWhich == 0
Divide3()
else
Divide4()
endif
tries = tries + 1
endwhile
Shuffle()
endfunc
func FirstTriangles()
int num = 2
if @pFirstDiv == "3" && @pMaxCells >= 3
num = 3
endif
if @pFirstDiv == "4" && @pMaxCells >= 4
num = 4
endif
complex vul = xb + flip(yb)
complex vur = #width-xb + flip(yb)
complex vll = xb + flip(#height-yb)
complex vlr = #width-xb + flip(#height-yb)
if num == 2 ; two triangles
if r.RandomFloat(0) < 0.5
V1[0] = vul, V2[0] = vur, V3[0] = vll
V1[1] = vlr, V2[1] = vur, V3[1] = vll
else
V1[0] = vll, V2[0] = vul, V3[0] = vlr
V1[1] = vur, V2[1] = vul, V3[1] = vlr
endif
elseif num == 3
; first choose which side to divide
float w = #width - 2*xb
float h = #height - 2*yb
int k
if @pChoose == "Random"
k = r.RandomIntInRange2(0, 4)
elseif @pChoose == "Larger"
float x = 2*(w+h)*r.RandomFloat(0)
if x <= w
k = 1
elseif x <= w + h
k = 2
elseif x <= 2*w + h
k = 3
else
k = 4
endif
else ; "Largest"
if w == h
k = r.RandomIntInRange2(0, 4)
else
k = 1
if w < h
k = 2
endif
if r.RandomFloat(0) > 0.5
k = k + 2
endif
endif
endif
float frac = 0.5
if @pSlop > 0
frac = 0.5 + @pSlop*r.RandomFloat2(0)
endif
complex vvv
if k == 1 ; top
vvv = vul + frac*(vur-vul)
V1[0] = vul, V2[0] = vvv, V3[0] = vll
V1[1] = vlr, V2[1] = vvv, V3[1] = vll
V1[2] = vur, V2[2] = vvv, V3[2] = vlr
elseif k == 2 ; right
vvv = vur + frac*(vlr-vur)
V1[0] = vul, V2[0] = vvv, V3[0] = vll
V1[1] = vul, V2[1] = vvv, V3[1] = vur
V1[2] = vll, V2[2] = vvv, V3[2] = vlr
elseif k == 3 ; bottom
vvv = vll + frac*(vlr-vll)
V1[0] = vul, V2[0] = vvv, V3[0] = vll
V1[1] = vul, V2[1] = vvv, V3[1] = vur
V1[2] = vur, V2[2] = vvv, V3[2] = vlr
else ; left
vvv = vul + frac*(vll-vul)
V1[0] = vul, V2[0] = vvv, V3[0] = vur
V1[1] = vlr, V2[1] = vvv, V3[1] = vur
V1[2] = vll, V2[2] = vvv, V3[2] = vlr
endif
else ; four triangles
float frac = 0.5
if @pSlop > 0
frac = 0.5 + @pSlop*r.RandomFloat2(0)
endif
float xc = xb + frac*(#width-2*xb)
if @pSlop > 0
frac = 0.5 + @pSlop*r.RandomFloat2(0)
endif
float yc = yb + frac*(#height-2*yb)
complex vc = xc + flip(yc) ; the center vertex
V1[0] = vul, V2[0] = vur, V3[0] = vc
V1[1] = vll, V2[1] = vul, V3[1] = vc
V1[2] = vll, V2[2] = vlr, V3[2] = vc
V1[3] = vlr, V2[3] = vur, V3[3] = vc
endif
NumCells = num
int i = 0
while i < NumCells
Check(i)
i = i + 1
endwhile
endfunc
func Init(complex pz, complex ppixel)
GradientColoring.Init(pz, ppixel)
endfunc
func Divide3()
int n = Choose()
float frac
if NumCells+3 > @pMaxCells || r.RandomFloat(0) > @pDivide4
; divide into 2 triangles
frac = 0.5
if @pSlop > 0
frac = 0.5 + @pSlop*r.RandomFloat2(0)
endif
; divide longest side. later maybe other possibilities
int k = g.LongestSide(V1[n], V2[n], V3[n])
complex w1, complex w2, complex w3
if k == 1 ; side v1v2 is longest; divide it
w1 = V3[n], w2 = V1[n], w3 = V2[n]
elseif k == 2 ; side v2v3 is longest
w1 = V1[n], w2 = V3[n], w3 = V2[n]
else ; side v3v1 is longest
w1 = V2[n], w2 = V1[n], w3 = V3[n]
endif
complex w4 = w2 + frac*(w3-w2)
V1[n] = w1, V2[n] = w2, V3[n] = w4
int m = NumCells
V1[m] = w1, V2[m] = w3, V3[m] = w4
; are the new cells divisible?
Check(n)
Check(m)
NumCells = NumCells + 1
else
; divide into 4 triangles
complex p1 = V1[n]
complex p2 = V2[n]
complex p3 = V3[n]
frac = 0.5 + @pSlop*r.RandomFloat2(0)
complex p4 = p1 + frac*(p2-p1)
frac = 0.5 + @pSlop*r.RandomFloat2(0)
complex p5 = p2 + frac*(p3-p2)
frac = 0.5 + @pSlop*r.RandomFloat2(0)
complex p6 = p3 + frac*(p1-p3)
V1[n] = p1, V2[n] = p4, V3[n] = p6, Check(n)
m = NumCells
V1[m] = p3, V2[m] = p5, V3[m] = p6, Check(m)
m = m + 1
V1[m] = p2, V2[m] = p4, V3[m] = p5, Check(m)
m = m + 1
V1[m] = p4, V2[m] = p5, V3[m] = p6, Check(m)
NumCells = NumCells + 3
endif
endfunc
func Divide4()
int n = Choose()
float frac
if NumCells+4 > @pMaxCells || r.RandomFloat(0) >= @pDivide5
; divide into 2 cells
frac = 0.5 + @pSlop*r.RandomFloat2(0)
bool divideX
if Small[n] == 2
divideX = true
elseif Small[n] == 1
divideX = false
else
float xx = real(V2[n]-V1[n])
float yy = imag(V2[n]-V1[n])
if xx != yy && r.RandomFloat(0) < @pPreferLong
divideX = (xx >= yy)
else
divideX = r.RandomFloat(0) <= @pXFrac
endif
endif
if divideX
; n is left part, new is right part
V1[NumCells] = real(V1[n]+frac*(V2[n]-V1[n])) + flip(imag(V1[n]))
V2[NumCells] = V2[n]
;V1[n] unchanged
V2[n] = real(V1[NumCells]) + flip(imag(V2[n]))
else
; n is top part, new is bottom part
V1[NumCells] = real(V1[n]) + flip(imag(V1[n]+frac*(V2[n]-V1[n])))
V2[NumCells] = V2[n]
;V1[n] unchanged
V2[n] = real(V2[n]) + flip(imag(V1[NumCells]))
endif
Check(n)
Check(NumCells)
NumCells = NumCells + 1
else
; divide into 5 cells
float x1 = real(V1[n]), float y1 = imag(V1[n])
float x2 = real(V2[n]), float y2 = imag(V2[n])
; if all the fracs are the same, the inner rectangle is centered.
frac = (1+@pSlop*r.RandomFloat2(0))/3
float x3 = x1 + frac*(x2-x1)
;frac = (1+@pSlop*r.RandomFloat2(0))/3
float x4 = x2 - frac*(x2-x1)
;frac = (1+@pSlop*r.RandomFloat2(0))/3
float y3 = y1 + frac*(y2-y1)
;frac = (1+@pSlop*r.RandomFloat2(0))/3
float y4 = y2 - frac*(y2-y1)
; clockwise or counter-clockwise
int m
if r.RandomFloat2(0) > @pCW
V1[n] = x1+flip(y1), V2[n] = x4+flip(y3), Check(n), m = NumCells
V1[m] = x4+flip(y1), V2[m] = x2+flip(y4), Check(m), m = m + 1
V1[m] = x3+flip(y4), V2[m] = x2+flip(y2), Check(m), m = m + 1
V1[m] = x1+flip(y3), V2[m] = x3+flip(y2), Check(m), m = m + 1
V1[m] = x3+flip(y3), V2[m] = x4+flip(y4), Check(m)
else
V1[n] = x1+flip(y1), V2[n] = x3+flip(y4), Check(n), m = NumCells
V1[m] = x3+flip(y1), V2[m] = x2+flip(y3), Check(m), m = m + 1
V1[m] = x4+flip(y3), V2[m] = x2+flip(y2), Check(m), m = m + 1
V1[m] = x1+flip(y4), V2[m] = x4+flip(y2), Check(m), m = m + 1
V1[m] = x3+flip(y3), V2[m] = x4+flip(y4), Check(m)
endif
NumCells = NumCells + 4
endif
endfunc
; select cell to divide
int func Choose()
int n
int nLarge = MakeLargeList()
if LargestArea > @pRatio*SmallestArea
int m = r.RandomIntInRange2(0, nLarge) - 1
return Large[m]
endif
if @pChoose == 0 ; any available cell is okay; uniform probability per cell
;r.SetNMax(NumCells)
repeat
n = r.RandomIntInRange2(0, NumCells) - 1
until Small[n] < 3
elseif @pChoose == 1 ; prefer to divide larger cells; probability proportional to area
repeat
repeat
float x = r.RandomFloat(0)*#width
float y = r.RandomFloat(0)*#height
n = CellNum(x, y)
until n >= 0 ; rounding can make the point be not in any triangle.
until Small[n] < 3
else ; only do one of the largest ones. (Guaranteed to be dividable.)
int m = r.RandomIntInRange2(0, nLarge) - 1
n = Large[m]
endif
return n
endfunc
int func MakeLargeList()
SmallestArea = LargestArea = Area(0)
Large[0] = 0
int count = 1
int i = 1
while i < NumCells
float tmp = Area(i)
if tmp < SmallestArea
SmallestArea = tmp
endif
float ratio = tmp/LargestArea
if ratio > 1+@eps
count = 1
Large[0] = i
LargestArea = tmp
elseif ratio > 1-@eps ; essentially the same area
Large[count] = i
count = count + 1
endif
i = i + 1
endwhile
return count
endfunc
float func Area(int n)
if @pWhich == 0
return g.TriangleArea(V1[n], V2[n], V3[n])
else
return real(V2[n]-V1[n])*imag(V2[n]-V1[n])
endif
endfunc
; is cell n too small to divide?
func Check(int n)
int i = 0
if Area(n) < 2*MinArea
i = 4
elseif @pWhich == 0
if |V1[n]-V2[n]| < 2*MinSideSq
i = 3
elseif |V2[n]-V3[n]| < 2*MinSideSq
i = 3
elseif |V3[n]-V1[n]| < 2*MinSideSq
i = 3
endif
else
if real(V2[n]-V1[n]) < 2*MinSide || @pXFrac == 0.0
i = 1
endif
if imag(V2[n]-V1[n]) < 2*MinSide || @pXFrac == 1.0
i = i + 2
endif
endif
if i >= 3
NumSmall = NumSmall + 1
endif
Small[n] = i
endfunc
func Iterate(complex pz)
GradientColoring.Iterate(pz)
endfunc
float func ResultIndex(complex pz)
float x = real(#screenpixel)
float y = imag(#screenpixel)
int n = CellNum(x, y)
if @pLines ; just show cell border lines
if n < 0 ; the point is in the outside border, maybe close enough to be in the line
if (x<=xb && x>=xb-lw && y>=yb-lw && y<=#height-yb+lw) ; left outer line
return 0
elseif (y<=yb && y>=yb-lw && x>=xb-lw && x<=#width-xb+lw) ; top outer line
return 0
elseif (y>=#height-yb && y<=#height-yb+lw && x>=xb-lw && x<=#width-xb+lw) ; bottom outer line
return 0
elseif (x>=#width-xb && x<=#width-xb+lw && y>=yb-lw && y<=#height-yb+lw) ; right outer line
return 0
else
return 0.667 ; usually this will be transparent
endif
else ; the point is inside a cell, is it near an edge?
if @pWhich == 0
if g.DistancePointToLine(#screenpixel, V1[n], V2[n]) <= lw + @eps
return 0
elseif g.DistancePointToLine(#screenpixel, V2[n], V3[n]) <= lw + @eps
return 0
elseif g.DistancePointToLine(#screenpixel, V3[n], V1[n]) <= lw + @eps
return 0
endif
elseif x<=real(V1[n])+lw || x>=real(V2[n])-lw || y<=imag(V1[n])+lw || y>=imag(V2[n])-lw
return 0
endif
return 0.333 ; usually this will be transparent
endif
else ; not doing cell lines
if n < 0
m_Solid = true ; m_Solid inherited through GradientColoring class
; from Coloring class
return -1 ; m_Solid dominates #index in Coloring
else
return Perm[n]/NumCells
endif
endif
endfunc
int func CellNum(float x, float y)
if x#width-xb || y#height-yb ; in the outer border
return -1
endif
int i = 0
while i < NumCells
bool yes
if @pWhich == 0
yes = g.PointInTriangle(x+flip(y), V1[i], V2[i], V3[i])
else
yes = x >= real(V1[i]) && x <= real(V2[i]) && y >= imag(V1[i]) && y <= imag(V2[i])
endif
if yes
return i
endif
i = i + 1 ;
endwhile
return -1 ; should never get here
endfunc
func StartRandom(int n)
; this seems to improve the random sequence
r = new JLB_Random(0)
r.Init(@seed)
int i = 0
while i < n
r.RandomInt(0)
i = i + 1
endwhile
endfunc
func Shuffle( )
int n = 0
while n < NumCells
Perm[n] = n
n = n + 1
endwhile
int times = 0
while times < @pRandomColor
int n = 0
while n < NumCells
int m = r.RandomIntInRange2(0, NumCells) - 1
int tmp = Perm[n]
Perm[n] = Perm[m]
Perm[m] = tmp
n = n + 1
endwhile
times = times + 1
endwhile
endfunc
private:
JLB_Random r
int NumCells
int NumSmall
; if triangles, V1, V2, V3 = the 3 vertices
; if rectangles, V1 = upper left corner of cell, V2 = lower right corner of cell, V3 not used
complex V1[@pMaxCells]
complex V2[@pMaxCells]
complex V3[@pMaxCells]
int Small[@pMaxCells] ; 0 = okay, 1 = small in X, 2 = in Y, 3 = both, 4 in area
int Large[@pMaxCells] ; list of largest cell. Doesn't need to be this big, but ...
float SmallestArea
float LargestArea
int Perm[@pMaxCells] ; permutation used for randomizing colors
; float MinXSize ; used only for rectangles
; float MinYSize
float MinArea
float MinSide
float MinSideSq ; square of minimum side length for triangles only
float xb, float yb ; border widths
float lw ; line width
Geometry g
default:
title = "Cells"
;rating = Recommended
; heading
; caption = "Use a pixel formula"
; endheading
; heading
; caption = "Distances are from 0 to 1."
; endheading
int param v_cells
caption = "Version (Cells)"
default = 100
hint = "This version parameter is used to detect when a change has been made \
to the formula that is incompatible with the previous version. When that \
happens, this field will reflect the old version number to alert you to the fact \
that an alternate rendering is being used."
visible = @v_cells < 100
endparam
param pWhich
caption = "Cell type"
enum = "Triangles" "Rectangles"
default = 1
endparam
int param pMaxCells
caption = "Maximum # of cells"
default = 25
min = 1
endparam
int param seed
caption = "Seed"
hint = "Seed for the random number generator"
default = 12345
endparam
float param pXBorder
caption = "Left and right borders"
hint = "as fraction of width"
default = 0
min = 0
max = 0.3
endparam
float param pYBorder
caption = "Top and bottom borders"
hint = "as fraction of width (not height!)"
default = 0
min = 0
max = 0.3
endparam
param pFirstDiv
caption = "First divide"
hint = "Divide initial rectangle in 2, 3, or 4 parts"
default = 1
enum = "2" "3" "4"
visible = @pWhich == 0 && @pMaxCells >= 3
endparam
param pChoose
caption = "How to choose a cell"
enum = "Random" "Larger" "Largest"
hint = "Larger: larger cells are more likely to be divided. \
Largest: only the largest cells will be divided."
default = 1
endparam
float param pRatio
caption = "Max ratio of areas"
default = 4
min = 1
visible = @pChoose != 2
endparam
float param pDivide5
caption = "Divide 5 fraction"
default = 0.125
min = 0
max = 1
hint = "Fraction of the time to divide cells into 5 cells instead of 2."
visible = @pWhich == 1
endparam
float param pCW
caption = "Preference for clockwise"
hint = "Fraction of the time for 5 cell divisions to go clockwise instead of \
counter-clockwise."
min = 0
max = 1
default = 0.5
visible = @pWhich == 1 && @pDivide5 > 0
endparam
float param pDivide4
caption = "Divide 4 fraction"
default = 0.125
min = 0
max = 1
hint = "Fraction of the time to divide triangles into 4 triangles\
instead of 2."
visible = @pWhich == 0
endparam
float param pPreferLong
caption = "Longer side preference"
hint = "Fraction of time to divide the longer side"
default = 0.75
min = 0
max = 1
visible = @pWhich == 1
endparam
float param pXFrac
caption = "Horizontal divide fraction"
hint = "Fraction of cells divided left to right; the rest divided top to bottom"
default = 0.5
min = 0
max = 1
visible = @pWhich == 1
endparam
float param pSlop
caption = "Divide tolerance"
default = 0.05
hint = "How much off the nominal value a cell division can be."
min = 0
max = 0.49
endparam
float param pMinSide
caption = "Minimum side length"
hint = "Cells with a side less than twice this cannot be divided"
default = 0.05
;min = 0.001
;visible = @pWhich == 0
endparam
float param pMinArea
caption = "Minimum cell area (%)"
hint = "Cells less than twice this area cannot be divided."
default = 0.1
max = 25
endparam
int param pRandomColor
caption = "Shuffle colors"
hint = "See which you prefer."
min = 0
default = 1
visible = !@pLines
endparam
bool param pLines
caption = "Show lines?"
default = false
hint = "If true, cell lines are colored as #index 0, \
cell interiors as 0.333, and outer border as 0.667."
endparam
float param B
caption = "Half-width of edge lines"
hint = "Width as a fraction of horizontal dimension"
default = 0.004
min = 0
max = 0.25
visible = @pLines
endparam
float param eps ; slop for Large calculation
default = 1.e-6
visible = false
endparam
}
class JLB_MoveCenter(common.ulb:UserTransform) {
; Move the fractal to a new center
public:
import "common.ulb"
func JLB_MoveCenter(Generic pparent)
UserTransform.UserTransform(pparent)
m_FractalCoordinate = new FractalCoordinate(pparent)
endfunc
func Init(complex pz)
UserTransform.Init(pz)
m_FractalCoordinate.Init(pz)
complex new_center = @horiz*#width + flip(@vert*#height)
offset = #center - m_FractalCoordinate.Iterate(new_center)
if @clip
float xctr = @horiz * real(#screenmax)
float yctr = @vert * imag(#screenmax)
xmin = xctr - 0.5 * @xclip * real(#screenmax)
xmax = xctr + 0.5 * @xclip * real(#screenmax)
ymin = yctr - 0.5 * @yclip * imag(#screenmax)
ymax = yctr + 0.5 * @yclip * imag(#screenmax)
endif
endfunc
complex func Iterate(complex pz)
UserTransform.Iterate(pz)
if @clip
if real(#screenpixel) < xmin || real(#screenpixel) > xmax \
|| imag(#screenpixel) < ymin || imag(#screenpixel) > ymax
m_solid = true
endif
endif
return pz + offset
endfunc
protected:
FractalCoordinate m_FractalCoordinate
complex offset
float xmin, float xmax
float ymin, float ymax
default:
title = "MoveCenter"
rating = Recommended
int param vMoveCenter
caption = "Version"
default = 220716
visible = @vMoveCenter < 220716 ; backwards compatible
endparam
heading
caption = "Move the fractal to a new center."
endheading
heading
caption = "Optionally clip a rectangle around it."
endheading
heading
caption = "Screen coordinates are used."
endheading
heading
caption = "Upper left is (0,0), lower right is (1,1)."
endheading
float param horiz
caption = "Horizontal"
default = 0.25
min = 0
max = 1
endparam
float param vert
caption = "Vertical"
default = 0.25
min = 0
max = 1
endparam
bool param clip
caption = "Clip outside?"
default = false
endparam
float param xclip
caption = "Horizontal width"
default = 0.25
min = 0
max = 1
visible = @clip
endparam
float param yclip
caption = "Vertical width"
default = 0.25
min = 0
max = 1
visible = @clip
endparam
}
class Distance(common.ulb:Generic) {
;
; Distance base class. No title, so only used for a base class.
; Given a complex value, return a float.
public:
import "common.ulb"
func Distance(Generic pparent)
Generic.Generic(pparent)
endfunc
func Init(complex zz)
m_mode = 0
m_abs_value = false
endfunc
func SetParams(int m, bool a)
m_mode = m
m_abs_value = a
endfunc
func SetIter(int k)
m_iter = k
endfunc
int func GetIter( )
return m_iter
endfunc
float func Iterate(complex zz)
return cabs(zz)
endfunc
protected:
int m_mode
bool m_abs_value
int m_iter
default:
int param v_Distance
caption = "Version (Distance)"
default = 211019
visible = false
endparam
}
class DistancePlus(common.ulb:Generic) {
; Same as Distance except for the integer argument.
; Given a complex value, return a float and an integer.
; 240707 added Set* and Get*, for * = Center, Rotation, and Scale
; Backwards compatible
public:
func DistancePlus(Generic pparent)
Generic.Generic(pparent)
endfunc
func Init(complex zz)
m_mode = 0
m_abs_value = false
endfunc
func SetParams(int m, bool a)
m_mode = m
m_abs_value = a
m_ctr = (0,0)
m_rot = (1,0)
m_scale = 1
endfunc
int func GetWhich( )
return 0
endfunc
func SetIter(int k)
m_iter = k
endfunc
int func GetIter( )
return m_iter
endfunc
func ScaleShape(float f)
endfunc
func unScaleShape( )
endfunc
func SetCenter(complex ctr)
m_ctr = ctr
endfunc
complex func GetCenter( )
return m_ctr
endfunc
func SetRotation(complex rot)
m_rot = rot
endfunc
complex func GetRotation( )
return m_rot
endfunc
func SetScale(float scale)
m_scale = scale
endfunc
float func GetScale( )
return m_scale
endfunc
float func Iterate(complex zz, int &i)
i = 1
return cabs(zz)
endfunc
protected:
int m_mode
bool m_abs_value
int m_iter
complex m_ctr
complex m_rot
float m_scale
default:
int param v_Distance
caption = "Version"
default = 240304
visible = false
endparam
}
class DistancePlus2(common.ulb:Generic) {
;
; Exactly the same as DistancePlus. Needed to keep
; NestedShapes from using itself as a plug-in.
public:
func DistancePlus2(Generic pparent)
Generic.Generic(pparent)
endfunc
func Init(complex zz)
m_mode = 0
m_abs_value = false
endfunc
func SetParams(int m, bool a)
m_mode = m
m_abs_value = a
endfunc
int func GetWhich( )
return 0
endfunc
func SetIter(int k)
m_iter = k
endfunc
int func GetIter( )
return m_iter
endfunc
func ScaleShape(float f)
endfunc
func unScaleShape( )
endfunc
float func Iterate(complex zz, int &i)
i = 1
return cabs(zz)
endfunc
protected:
int m_mode
bool m_abs_value
int m_iter
default:
int param v_Distance
caption = "Version"
default = 240304
visible = false
endparam
}
class JLB_DGaussianInteger(Distance) {
; The essential part of Kerry Mitchell's code in Standard.ucl
; 220921 allowed real and imag parts to use different types.
; backward compatible.
; 240209 disallowed this, unnecessary complication
public:
func JLB_DGaussianInteger(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
endfunc
float func Iterate(complex zz)
complex temp
zz = @a * zz
if @p_std
if @how == 0
temp = aux(real(zz), @type) + flip(aux(imag(zz), @type))
zz = zz - temp ; x and y are in (-1,+1)
return m_dist.Iterate(zz-temp)
else;if @how == 1
float r0 = cabs(zz)
float r = r0 - aux(r0, @type) ; r is in (-1,+1)
zz = zz * r / r0
return m_dist.Iterate(zz)
endif
else
temp = aux(real(zz), @xtype) + flip(aux(imag(zz), @ytype))
return m_dist.Iterate(zz-temp)
endif
endfunc
float func aux(float v, int t)
if t == 0
return round(v)
elseif t == 1
return trunc(v)
elseif t == 2
return floor(v)
elseif t == 3
return ceil(v)
else
if v >= 0, return ceil(v), else, return floor(v), endif
endif
endfunc
private:
Distance m_dist
default:
title = "Gaussian Integer"
rating = Recommended
int param version
caption = "Version"
default = 240301
visible = @version < 240301
endparam
heading
text = "(current is 240301.}"
visible = @version < 240301
endheading
complex param a ; added 240310. backward compatible.
caption = "Z multiplier"
default = 1
endparam
param how
caption = "Method"
enum = "X and Y" "Radius" ; maybe something like "angle"
default = 0
endparam
bool param p_std ; this was an unnecessary complication
caption = "Standard?"
default = true
visible = @version < 240209
endparam
param xtype
caption="Real Type"
default=0
enum="round" "trunc" "floor" "ceil" "trunc*"
visible = !@p_std
endparam
param ytype
caption="Imag Type"
default=0
enum="round" "trunc" "floor" "ceil" "trunc*"
visible = !@p_std
endparam
param type
caption="Integer Type"
default=0
enum="round" "trunc" "floor" "ceil" "trunc*"
visible = @p_std
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DGrid2(Distance) {
; ??? backwards compatible ???
public:
func JLB_DGrid2(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
if @screen_center
ctr = #center
else
ctr = @dcenter
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
xgrid = abs(real(@grid))
ygrid = abs(imag(@grid))
if @type == "Hexagonal"
a3 = 1.5 * xgrid
v = 0.5 * sqrt(3.0) * ygrid
endif
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
if @type == "Rectangular" || @type == "Triangular"
Get_Rect(zz, old_even, old_up)
endif
endfunc
float func Iterate(complex zz)
if @version < 220910
zz = ctr + rot * (zz - ctr) ; wrong!
else
zz = rot * (zz - ctr)
endif
; Note that floor(v) doesn't work if v > 2147483647, the largest positive integer.
complex grid_ctr
float d1, float d2
complex tmp
if @type == "Rectangular" || @type == "Triangular"
complex za = abs(zz)
if real(za/xgrid) > 2e9 || imag(za/ygrid) > 2e9 ; not enough precision
return -1
endif
; zz is in the rectangle whose lower left is (i,j)
; find coordinates of the rectangle
bool new_even, bool new_up
Get_Rect(zz, new_even, new_up)
if @type == "Rectangular"
if @parity == "Odd" && new_even
return -1
endif
if @parity == "Even" && !new_even
return -1
endif
if @parity == "Change" && new_even == old_even
return -1
endif
if @parity == "Same" && new_even != old_even
return -1
endif
old_even = new_even
if @type2 == "Center"
grid_ctr = 0.5*(x1+x2) + flip(0.5*(y1+y2))
tmp = zz - grid_ctr
elseif @type2 == "Edge"
tmp = Geometry.ClosestPointToFigure(zz, 4, v1, v2, v3, v4)
else;if @type2 == "Corner"
tmp = Geometry.ClosestPointToVertex(zz, 4, v1, v2, v3, v4)
endif
else
if @tri == "Up" && !new_up
return -1
endif
if @tri == "Down" && new_up
return -1
endif
if @tri == "Change" && new_up == old_up
return -1
endif
if @tri == "Same" && new_up != old_up
return -1
endif
old_up = new_up
; the point is in the triangle (v1, v2, v3)
if @type2 == "Center"
tmp = zz - (v1 + v2 + v3) / 3
elseif @type2 == "Edge"
tmp = Geometry.ClosestPointToFigure(zz, 3, v1, v2, v3, v3) ; last arg not used
else;if @type2 == "Corner"
tmp = Geometry.ClosestPointToVertex(zz, 3, v1, v2, v3, v3)
endif
endif
if @do_scale
tmp = real(tmp)/xgrid + flip(imag(tmp)/ygrid)
endif
if @version < 220619
return MyMath.fmin(real(tmp), imag(tmp))
else
float t = m_dist.Iterate(tmp/rot) ;^@pow
return t
endif
elseif @type == "Hexagonal"
int j = floor(abs(imag(zz))/v )
int i = floor(abs(real(zz))/a3)
complex ctr1
complex ctr2
if j % 2 == 1 ; odd band
if i % 2 == 1
ctr1 = (i )*a3 + flip((j )*v)
ctr2 = (i+1)*a3 + flip((j+1)*v)
else
ctr1 = (i )*a3 + flip((j+1)*v)
ctr2 = (i+1)*a3 + flip((j )*v)
endif
else ; even band
if i % 2 == 1
ctr1 = (i )*a3 + flip((j+1)*v)
ctr2 = (i+1)*a3 + flip((j )*v)
else
ctr1 = (i )*a3 + flip((j )*v)
ctr2 = (i+1)*a3 + flip((j+1)*v)
endif
endif
zz = abs(zz)
tmp = ctr2-zz
if |ctr1-zz| <= |ctr2-zz|
tmp = ctr1-zz
endif
return m_dist.Iterate(tmp/rot) ; ^@pow
; end heaxagonal
else;if @type == "Polar"
float r = cabs(zz)
if r/@rgrid > 2e9
return -1
endif
int i = floor(r/@rgrid)
float r1 = i*@rgrid, float r2 = r1+@rgrid
; angular spacing chosen to make the grid more or less square, except inmost one,
; with each grid about the same area.
int n = 6*i+3
float agrid = 2*#pi / n
float offset = (@angle + i * @delta) * #pi/180
float theta = atan2(zz) + offset
if theta < 0, theta = theta + 2*#pi, endif
;if theta >= 2*#pi, theta = theta - 2*#pi, endif
int j = floor(theta / agrid) ; j >= 0
float theta1 = j*agrid - offset
float theta2 = theta1+agrid ; okay if >2*#pi
if @type2 == "Center"
grid_ctr = (r1+0.5*@rgrid) * exp(flip((theta1+0.5*agrid)))
tmp = zz - grid_ctr
else
v1 = r1 * exp(flip(theta1)) ; v1-v2 is straight
v2 = r2 * exp(flip(theta1)) ; v2-v3 is outer arc
v3 = r2 * exp(flip(theta2)) ; v3-v4 is straight
v4 = r1 * exp(flip(theta2)) ; v4-v1 is inner arc
if @type2 == "Corner"
tmp = Geometry.ClosestPointToVertex(zz, 4, v1, v2, v3, v4)
else;if @type == "Edge"
tmp = Geometry.ClosestPointToLIneSegment(zz, v1, v2)
d1 = |tmp|
vv = zz - r2 * exp(flip((theta))) ; outer arc
d2 = |vv|
if d2 < d1
d1 = d2, tmp = vv
endif
complex vv = Geometry.ClosestPointToLIneSegment(zz, v3, v4)
d2 = |vv|
if d2 < d1
d1 = d2, tmp = vv
endif
vv = zz - r1 * exp(flip((theta))) ; inner arc
d2 = |vv|
if d2 < d1
tmp = vv
endif
endif ; polar
endif
d1 = m_dist.Iterate(tmp)
if @do_pscale
d1 = d1 / @rgrid
endif
return d1 ;^@pow
endif ; @type
endfunc
func Get_Rect(complex zz, bool &even, bool &up)
float xx = real(zz)
float i = floor(xx/xgrid)
x1 = i * xgrid
x2 = x1 + xgrid
float yy = imag(zz)
float j = floor(yy/ygrid)
y1 = j * ygrid
y2 = y1 + ygrid
even = (i + j) % 2 == 0
v1 = x1 + flip(y1) ; lower left corner
v2 = x2 + flip(y1) ; lower right corne
v3 = x2 + flip(y2) ; upper right corner
v4 = x1 + flip(y2) ; upper left corner
if @type == "Triangular"
; which of the triangles contains the point? Assign v1, v2, v3 to its vertices
up = false
if @ttype == "Left"
if Geometry.PointInTriangle(zz, v1, v2, v4)
v3 = v4 ; 4-3
else ; |\|
v1 = v4 ; 1-2
up = true
endif
else;if @ttype == "Right"
if Geometry.PointInTriangle(zz, v1, v4, v3)
v2 = v4 ; 4-3
up = true; |/|
; 1-2
;else it's in the original 1, 2, 3
endif
endif
endif
endfunc
private:
complex ctr
complex rot
float xgrid, float ygrid
complex v1, complex v2, complex v3, complex v4
bool old_even, bool old_up
float x1, float x2
float y1, float y2
Distance m_dist
float a3, float v
default:
title = "Grid2"
;rating = Recommended
heading
text = "Divide the plane into a grid. Calculate the distance to the \
nearest grid edge or grid center."
endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
bool param screen_center
caption = "Use screen center?"
default = true
endparam
complex param dcenter
caption = "Center"
default = (0,0)
visible = !@screen_center
endparam
param type
enum = "Rectangular" "Polar" "Hexagonal" "Triangular"
caption = "Grid type"
default = 0
endparam
param parity
enum = "Even" "Odd" "Either" "Change" "Same"
caption = "Which rectangles?"
default = 2
visible = @type == 0
endparam
param ttype
enum = "Left" "Right"
caption = "Split the rectangle"
default = 0
visible = @type == "Triangular"
endparam
param tri
enum = "Up" "Down" "Either" "Change" "Same"
caption = "Which half"
default = 2
visible = @type == "Triangular"
endparam
param type2
enum = "Edge" "Center" "Corner"
caption = "Distance to"
default = 0
visible = @type !=2
endparam
complex param grid
caption = "Grid spacing"
default = (1,1)
visible = @type == 0 || @type >= 2
endparam
float param rgrid
caption = "Radial spacing"
default = 1
min = 0
visible = @type == 1
endparam
float param angle
caption = "Rotation angle"
default = 0
endparam
float param delta
caption = "Delta angle"
default = 0
visible = @type == 1
endparam
bool param do_scale
caption = "Scale to grid?"
default = false
visible = @type == 0 || @type == 3
endparam
bool param do_pscale
caption = "Scale to radial spacing?"
default = false
visible = @type == 1
endparam
; float param pow
; caption = "Power"
; default = 1
; endparam
heading
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DLines2(Distance) {
; line is a*x + b*y + c = 0
; a*real(zz) + b*imag(zz) + c = d
public:
func JLB_DLines2(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
float t = @angle1*(#pi/180)
a1 = sin(t)
b1 = -cos(t)
c1 = -real(@point1)*sin(t) + imag(@point1)*cos(t)
if @num == " 2"
t = @angle2*(#pi/180)
a2 = sin(t)
b2 = -cos(t)
c2 = -real(@point2)*sin(t) + imag(@point2)*cos(t)
endif
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
float tmp
old_side = Get_Side(zz, a1, b1, c1, tmp)
if @num == " 2"
old_side = old_side + 10 * Get_Side(zz, a2, b2, c2, tmp)
endif
endfunc
float func Iterate(complex zz)
float d = -MyMath.fmax( 1, |zz| )
float d1, float d2
bool okay = false
new_side = Get_Side(zz, a1, b1, c1, d1) ; calculates d1
if @num == " 1"
if @side == "Either"
okay = true
elseif @side == " +"
okay = d1 >= 0
elseif @side == " -"
okay = d1 < 0
elseif @side == "Change"
okay = old_side != new_side
else;if @side == "Same"
okay = old_side == new_side
endif
if okay
d1 = abs(d1)
if @version < 240224
zz = (a1+flip(b1)) * d1 ;WRONG! all thes perpendiculars are parallel
else
zz = d1 * zz
endif
endif
else
new_side = new_side + 10 * Get_Side(zz, a2, b2, c2, d2) ; calculates d2
if @sides == "Any"
okay = true
elseif @sides == 0
okay = d1 > 0 && d2 > 0
elseif @sides == 1
okay = d1 > 0 && d2 < 0
elseif @sides == 2
okay = d1 < 0 && d2 > 0
elseif @sides == 3
okay = d1 < 0 && d2 < 0
elseif @sides == "Change"
okay = old_side != new_side
else;if @sides == "Same"
okay = old_side == new_side
endif
if okay
d1 = MyMath.fmin(abs(d1),abs(d2))
if @version < 240224
zz = d1 * (a1+flip(b1)) ; again WRONG
else
zz = d1 * zz
endif
endif
endif
old_side = new_side
if okay
d = m_dist.Iterate(zz)
if @version < 240224
d = d / @scale
bool neg = ( d < 0 )
d = abs(d)^@pow
if neg, d = -d, endif
else
d = abs(d)
endif
endif
return d
endfunc
int func Get_Side(complex zz, float a, float b, float c, float &d)
float x = real(zz)
float y = imag(zz)
d = a * x + b * y + c
if d >= 0
return 1
else
return 0
endif
endfunc
private:
float a1,float b1, float c1
float a2,float b2, float c2
Distance m_dist
int old_side
int new_side
default:
title = "Lines2"
rating = Recommended
; heading
; text = "Lines are defined by a point and an angle. "
; endheading
int param version
caption = "Version"
default = 240224
visible = @version < 240224
endparam
heading
text = "(current is 240224.}"
visible = @version < 240224
endheading
param num
caption = "1 or 2 lines?"
enum = " 1" " 2"
default = 0
endparam
complex param point1
caption = "Point on line 1"
default = (2,0)
endparam
float param angle1
caption = "Angle of line 1"
default = 90
endparam
param side
caption = "Pos./neg. side/etc."
enum = " +" " -" "Either" "Change" "Same"
default = 2
visible = @num == " 1"
endparam
complex param point2
caption = "Point on line 2"
default = (0,0)
visible = @num == " 2"
endparam
float param angle2
caption = "Angle of line 2"
default =45
visible = @num == " 2"
endparam
param sides
caption = "Pos. or neg. sides"
enum = " + +" " + -" " - +" " - -" "Any" "Change" "Same"
default = 4
visible = @num == " 2"
endparam
float param scale
caption = "Scale (> 0)"
default = 1
min = 1e-30
visible = @version < 240224
endparam
float param pow
caption = "Distance power"
default = 1
hint = "Positive values emphasize iterations with z farther from the line(s); \
negative values emphasize iterations with z nearer to the line(s)."
visible = @version < 240224
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD2
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DSpiral(Distance) {
; log spiral: r = a * exp(b * angle)
; Power spiral: r = a * angle^p
public:
func JLB_DSpiral(Generic pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
if @screen_center
sctr = #center
else
sctr = @ctr
endif
aa = abs(@a);
scale = 1
if @do_scale
scale = aa
endif
twopi = 2*#pi
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
endfunc
float func Iterate(complex zz)
zz = zz - sctr
float theta = atan2(zz)
if @a > 0
if theta < 0, theta = theta + twopi, endif
; theta in [0, twopi)
else
if theta > 0, theta = theta - twopi, endif
; theta in (-twopi, 0]
theta = abs(theta)
endif
float r = cabs(zz)
float tmp
if @type == 0
tmp = ((r/aa)^(1/@p) - theta) / twopi
else
tmp = (log(r/aa)/@b - theta) / twopi
endif
int k = floor(tmp)
if k < 0, k = 0, endif ; inside first arm or lack of precision
float r1, float r2
if @type == 0
r1 = aa * (theta + k*twopi )^@p
r2 = aa * (theta + k*twopi + twopi)^@p
else
r1 = aa * exp(@b*(theta + k*twopi ))
r2 = aa * exp(@b*(theta + k*twopi + twopi) )
endif
float d
if k == 0 ; inside first arm
d = 1 - r/r2
if d < 0 || d > 1 ; failure because of lack of precision
return -1
endif
else
d = (r - r1) / (r2 - r1)
if d < 0 || d > 1 ; failure because of lack of precision
return -1
endif
if d > 0.5, d = 1 - d, endif ; distance to closer arm
endif
; d is between 0 and 1
d = d * scale
zz = d * zz / cabs(zz)
;d = ComplexToFloat2.go(zz, (0,0), m_mode, true)
d = m_dist.Iterate(zz)
return d
endfunc
private:
float scale
float twopi
complex sctr
float aa
Distance m_dist
default:
title = "Spiral"
rating = Recommended
heading
text = "Color by distance to closest arm of the spiral."
endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
param type
caption = "Spiral type"
default = 0
enum = "power" "log"
endparam
bool param screen_center
caption = "Use screen center?"
default = true
endparam
param ctr
caption = "Spiral center"
default = (0,0)
visible = !@screen_center
endparam
float param a
caption = "Spiral multiplier"
default = 1
hint = "If negative, spiral goes in the opposite direction."
endparam
float param p
caption = "Spiral power"
min = 1e-4
default = 1
hint = "Useful values mostly between 0.5 and 2."
visible = @type == 0
endparam
float param b
caption = "Coefficient"
default = 0.1
min = 1e-6
visible = @type == 1
endparam
bool param do_scale
caption = "Scale by multiplier?"
default = true
visible = @a != 1
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DTriangle(Distance) {
public:
func JLB_DTriangle(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
first = true
endfunc
; The insides of Triangle Inequality Average
float func Iterate(complex zz)
if first
first = false ; to agree with the original
return -1
endif
float ac = m_dist.Iterate(#pixel)
float bc = m_dist.Iterate(zz-#pixel)
float cc = m_dist.Iterate(zz)
float least = abs(bc - ac)
float most = bc + ac
if most <= least
return -1
endif
return (cc - least) / (most - least)
endfunc
private:
bool first
Distance m_dist
default:
title = "TIA Distance"
rating = Recommended
; heading
; text = "Standard Triangle Inequality Average coloring. Using TIA type as the Final smooth \
; may be useful."
; endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DTrap(Distance) {
; Use a trap shape to calculate a distance
public:
import "common.ulb"
import "Standard.ulb"
func JLB_DTrap(Generic pparent)
fShape = new @shape(this)
endfunc
func Init(complex zz)
fShape.init(zz)
endfunc
float func Iterate(complex zz)
float ans = fshape.iterate(zz)
return abs(ans)
endfunc
private:
TrapShape fShape
default:
title = "Trap"
rating = Recommended
heading
text = "Use a trap shape for calculating distance."
endheading
TrapShape param shape
caption = "Trap Shape"
default = Standard_TrapShapeCross
hint = "Selects the shape of the orbit trap."
endparam
}
class JLB_TwoDistances(common.ulb:UserTransform) {
; Make a UserTransform out of two Distance formulas
public:
;import "common.ulb"
func JLB_TwoDistances(Generic pparent)
UserTransform.UserTransform(pparent)
mx = new @fx(this)
my = new @fy(this)
if @version < 221224
xyswitch = @switch
else
xyswitch = @switch2 == 1 || @switch2 == 3
endif
endfunc
func Init(complex pz)
UserTransform.Init(pz)
mx.Init(pz)
my.Init(pz)
mx.SetParams(0, false)
my.SetParams(0, false)
endfunc
complex func Iterate(complex pz)
float x = mx.Iterate(pz)
float y = my.Iterate(pz)
if xyswitch
pz = y + flip(x)
else
pz = x + flip(y)
endif
if @version >= 221224 && @switch2 > 1
xyswitch = !xyswitch
endif
return pz
endfunc
protected:
Distance mx
Distance my
bool xyswitch
default:
rating = Recommended
title = "Two Distances"
int param version
caption = "Version"
default = 221224
visible = @version < 221224
endparam
heading
text = "(Current is 221224.)"
visible = @version < 221224
endheading
; heading
; caption = "Make a transform from two Distances."
; endheading
bool param switch
caption = "Switch X and Y distances?"
default = false
visible = @version < 221224
endparam
param switch2
caption = "X/Y switch?"
enum = "No" "Yes" "No/Yes/No . . ." "Yes/No/Yes . . ."
default = 0
visible = @version >= 221224
endparam
Distance param fx
caption = "X Distance"
default = JLB_DSimple2
endparam
Distance param fy
caption = "Y Distance"
default = JLB_DCircle
endparam
}
class JLB_FTransform(common.ulb:UserTransform) {
; Inspired by Bona Spallona in OM.ulb
; A Transform replacement of UF's built-in functions
; First trig and hyperbolic, completing UF's built-in set,
; then then the rest of UF's standard set,
; then a few extras from OM.ulb
;
; Many interesting complications are possible using Combo Transform.
public:
complex func Iterate(complex pz)
if @F == "sin", pz = sin(pz)
elseif @F == "sinh", pz = sinh(pz)
elseif @F == "asin", pz = asin(pz)
elseif @F == "asinh", pz = asinh(pz)
elseif @F == "cos", pz = cos(pz)
elseif @F == "cosh", pz = cosh(pz)
elseif @F == "acos", pz = acos(pz)
elseif @F == "acosh", pz = acosh(pz)
elseif @F == "tan", pz = tan(pz)
elseif @F == "tanh", pz = tanh(pz)
elseif @F == "atan", pz = atan(pz)
elseif @F == "atanh", pz = atanh(pz)
elseif @F == "cotan", pz = cotan(pz)
elseif @F == "cotanh", pz = cotanh(pz)
elseif @F == "acotan", pz = atan(1/pz)
elseif @F == "acotanh", pz = atanh(1/pz)
elseif @F == "sec", pz = 1/cos(pz)
elseif @F == "sech", pz = 1/cosh(pz)
elseif @F == "asec", pz = acos(1/pz)
elseif @F == "asech", pz = acosh(1/pz)
elseif @F == "cosec", pz = 1/sin(pz)
elseif @F == "cosech", pz = 1/sinh(pz)
elseif @F == "acosec", pz = asin(1/pz)
elseif @F == "acosech", pz = asinh(1/pz)
elseif @F == "sqr", pz = sqr(pz)
elseif @F == "cube", pz = pz^3
elseif @F == "sqrt", pz = sqrt(pz)
elseif @F == "log", pz = log(pz)
elseif @F == "exp", pz = exp(pz)
elseif @F == "abs", pz = abs(pz)
elseif @F == "cabs" , pz = cabs(pz)
elseif @F == "conj",pz = conj(pz)
elseif @F == "flip", pz = flip(pz)
elseif @F == "ident", pz = pz
elseif @F == "capident"
float size = cabs(pz)
if size > @cap, pz = pz * @cap / size, endif
elseif @F == "zero", pz = 0
elseif @F == "recip", pz = recip(pz)
elseif @F == "ceil", pz = ceil(pz) ; up
elseif @F == "floor", pz = floor(pz) ; down
elseif @F == "trunc", pz = trunc(pz) ; towards 0
elseif @F == "trunc*" ; away from 0
float x = real(pz)
if x >= 0, x = ceil(x), else, x = floor(x), endif
float y = imag(pz)
if y >= 0, y = ceil(y), else, y = floor(y), endif
pz = x + flip(y)
elseif @F == "round", pz = round(pz)
elseif @F == "power", pz = pz^@p
elseif @F == "gd", pz = asin(tanh(pz)) ; Gudermannian (Wikipedia)
elseif @F == "agd", pz = atanh(sin(pz)) ; inverse Gudermannian
elseif @F == "logit", pz = log(pz/(1-pz))
elseif @F == "expit", pz = 1/(1+exp(-pz))
elseif @F == "gauss", pz = exp(-sqr(pz))
elseif @F == "agauss", pz = sqrt(-log(pz))
elseif @F == "softplus", pz = log(1+exp(pz))
elseif @F == "asoftplus", pz = log(exp(pz)-1)
elseif @F == "softminus", pz = pz-log(1+exp(pz))
elseif @F == "asoftminus", pz = pz-log(1-exp(pz))
elseif @F == "sinc"
if pz == 0, pz = 1, else, pz = sin(pz)/pz, endif
else;if @F == "decay"
pz = pz/(1+pz^@q)
endif
return pz
endfunc
default:
rating = Recommended
title = "Function - Menu"
; heading
; caption = "'Function Transform' is better"
; endheading
int param version
caption = "Version"
default = 220730
visible = @version < 220730
endparam
heading
text = "(Current is 220730.)"
visible = @version < 220730
endheading
param F
caption="Function"
enum = "sin" "sinh" "asin" "asinh" "cos" "cosh" "acos" "acosh" \
"tan" "tanh" "atan" "atanh" "cotan" "cotanh" "acotan" "acotanh" \
"sec" "sech" "asec" "asech" "cosec" "cosech" "acosec" "acosech" \
"sqr" "cube" "sqrt" "log" "exp" "abs" "cabs" "conj"\
"flip" "ident" "capident" "zero" "recip" "ceil" "floor" "trunc" "trunc*" "round" \
"power" "gd" "agd" "logit" "expit" "gauss" "agauss" \
"softplus" "softminus" "asoftplus" "asoftminus" "sinc" "decay"
default=0
endparam
complex param p
caption = "Power"
default = 2
visible = @F == "Power"
endparam
float param q
caption = "Decay power"
default = 2
visible = @F == "decay"
endparam
float param cap
caption = "Cap"
default = 1
min = 0
visible = @F == "capident"
endparam
}
class JLB_BubbleTransform(common.ulb:UserTransform) {
;
public:
func JLB_BubbleTransform(Generic pparent)
UserTransform.UserTransform(pparent)
if @use_ctr
ctr = #center
else
ctr = @center
endif
if @xfer == 0
ctr2 = ctr
else
ctr2 = @ectr
endif
r0 = @rad0
r1 = r0
if @mode == "Linear"
r1 = r0 * @rfac
endif
rot = exp(flip(@angle*#pi/180))
b_rot = 1
if @b != 2
b_rot = exp(flip(@b_angle*#pi/180))
endif
endfunc
complex func Iterate(complex pz)
complex tmp = b_rot * (pz-ctr)
float x = abs(real(tmp))
float y = abs(imag(tmp))
float r = (x^@b + y^@b)^(1/@b)
float term = @s * (r/r0)^@p
if r <= r0
complex pznew = ctr2 + term * (pz-ctr) * rot
return pznew
endif
if @mode == "None"
return pz
endif
float keep
if @mode == "Linear"
if r >= r1
return pz
endif
keep = 1 - (r-r0)/(r1-r0)
elseif @mode == "Exponential"
keep = exp(-@a*(r/r0-1))
else;if @mode == "Gaussian"
keep = exp(-@a*(r/r0-1)^2)
endif
float ang = keep * @angle
complex pznew = (1-keep) * pz + \
keep * (ctr2 + term * (pz-ctr) * exp(flip(ang*#pi/180)))
return pznew
endfunc
private:
complex ctr
complex ctr2
float r0
float r1
complex b_rot
complex rot
default:
title = "Bubble"
rating = Recommended
param use_ctr
caption = "Use Screen Center"
default = true
endparam
complex param center
caption = "Bubble center"
default = (0, 0)
visible = !@use_ctr
endparam
float param rad0
caption = "Bubble size"
default = 0.25/#magn
;min = 0
endparam
float param b
caption = "Bubble shape"
default = 2
min = 0.25 ; best value?
endparam
float param b_angle
caption = "Bubble rotation"
default = 0
visible = @b != 2
endparam
heading
endheading
param xfer
caption = "Transfer from"
enum = "Bubble" "Elsewhere"
default = 0
endparam
complex param ectr
caption = "Elsewhere center"
default = #center
visible = @xfer == 1
endparam
float param s
caption = "Strength"
default = 2
;min = 0
endparam
float param p
caption = "Power"; from center"
default = 2
;min = 0
endparam
float param angle
caption = "Rotation angle"
default = 0
endparam
param mode
caption = "Fade mode"
enum = "None" "Linear" "Exponential" "Gaussian"
default = 0
endparam
float param rfac
caption = "Fade distance factor"
default = 1.5
min = 1
visible = @mode == 1
endparam
float param a
caption = "Fade strength"
default = 5
min = 0
visible = @mode > 1
endparam
}
class JLB_DTransform(Distance) {
public:
import "common.ulb"
func JLB_DTransform(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
zzTransform = new @T(this)
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, m_abs_value)
endfunc
float func Iterate(complex zz)
zz = zzTransform.Iterate(@a*zz)
float d = m_dist.Iterate(zz)
return d
endfunc
private:
Distance m_dist
UserTransform zzTransform
default:
title = "Transform"
rating = Recommended
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
heading
caption = "z_new = T(a*z)"
endheading
complex param a
caption = "a"
default = 1
endparam
UserTransform param T
caption = "Transform T"
default = JLB_UT_Function
endparam
heading
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_MaskShape(common.ulb:DirectColoring) {
; some code copied from Bubble transform and Circle2
;
public:
func JLB_MaskShape(Generic pparent)
DirectColoring(pparent)
if @use_ctr, ctr = #center, else, ctr = @center, endif
if @type == "Circle", h = v = @rad, else, h = @horiz, v = @vert, endif
rot = exp(flip(-@angle*#pi/180))
rr = red(gradient(0))
gg = green(gradient(0))
bb = blue(gradient(0))
endfunc
func Init(complex pz, complex ppixel)
DirectColoring.Init(pz, ppixel)
endfunc
func Iterate(complex pz)
endfunc
color func Result(complex pz)
m_solid = false
complex tmp = rot * (pz-ctr)
float x = abs(real(tmp))
float y = abs(imag(tmp))
float r= ( (x/h)^@p + (y/v)^@p ) ^ (1/@p)
float opacity = 0
if r <= 1
opacity = 1
else
if @mode == "Linear"
if r > @rfade
opacity = 0
else
opacity = 1 - (r-1)/(@rfade-1)
endif
elseif @mode == "Exponential"
opacity = exp(-@a*(r-1))
elseif @mode == "Gaussian"
opacity = exp(-@a*(r-1)^2)
endif
endif
if @invert
opacity = 1 - opacity
endif
return rgba(rr, gg, bb, opacity)
endfunc
private:
complex ctr
complex rot
float h, float v
float rr, float gg, float bb
default:
title = "Mask from shape"
rating = Recommended
bool param invert
caption = "Invert mask shape?"
default = false
endparam
param use_ctr
caption = "Use Screen Center"
default = true
endparam
complex param center
caption = "Shape center"
default = (0, 0)
visible = !@use_ctr
endparam
param type
caption = "Shape type"
enum = "Circle" "Ellipse"
default = 0
endparam
float param p
caption = "Shape power"
default = 2
min = 0
hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square."
endparam
float param rad
caption = "Circle radius"
default = 2.0
min = 0
visible = @type == 0
endparam
float param horiz
caption = "Ellipse x value"
default = 2.0
min = 0
visible = @type == 1
endparam
float param vert
caption = "Ellipse y value"
default = 2.0
min = 0
visible = @type == 1
endparam
float param angle
caption = "Rotation angle"
default = 0
visible = @p != 2.0 || (@type == 1 && @horiz != @vert)
endparam
param mode
caption = "Fade mode"
enum = "None" "Linear" "Exponential" "Gaussian"
default = 0
endparam
float param rfade
caption = "Fade distance factor"
default = 1.5
min = 1
visible = @mode == 1
endparam
float param a
caption = "Fade strength"
default = 5
min = 0
visible = @mode > 1
endparam
}
class JLB_Waves(common.ulb:UserTransform) {
public:
func JLB_Waves(Generic pparent)
Generic.Generic(pparent)
hfreq = real(@freq)
vfreq = imag(@freq)
phase = @p*#pi/180
rot = exp(flip(@dir*#pi/180))
ctr = #center
if !@center
ctr = @ctr
endif
endfunc
complex func Iterate(complex pz) ; if mapping, called with pz = #pixel
float factor = 1
if @fade > 0
factor = 0
float dist = cabs(pz - ctr)
if @fade == "Power"
if dist < @distance
factor = (1 - dist/@distance)^@power
endif
elseif @fade == "Exponential"
float t = dist/@distance
factor = exp(-t)
else;if @fade == "Gaussian"
float t = sqr(dist/@distance)
factor = exp(-t)
endif
endif
if factor > 0
float x = real(pz-ctr), float y = imag(pz-ctr)
float arg = phase
if @type == 1 || @type == 3
arg = arg + @hfac * real(@FH(hfreq*x))
else
arg = arg + hfreq*x
endif
if @type == 2 || @type == 3
arg = arg + @vfac * real(@FV(vfreq*y))
else
arg = arg + vfreq*y
endif
float delta = @a * real(@F(arg))
pz = pz + delta * rot * factor
endif
return pz
endfunc
private:
float hfreq, float vfreq
float phase
complex rot
complex ctr
default:
title = "Waves"
rating = Recommended
int param version
caption = "Version-Waves"
default = 230601
visible = @version < 230601
endparam
heading
text = "(current is 230601.}"
visible = @version < 230601
endheading
bool param center
caption = "Use screen center?"
default = true
endparam
complex param ctr
caption = "Center"
default = (0,0)
visible = !@center
endparam
float param a
caption = "Amplitude"
default = 0.5
endparam
float param dir
caption = "Direction (degrees)"
hint = "90 means vertical"
default = 90
endparam
func F
caption = "Function"
default = sin()
endfunc
complex param freq
caption = "H && V frequencies"
default = (1,1)
endparam
float param p
caption = "Phase (degrees)"
default = 0
endparam
param type
caption = "Modification"
enum = "none" "H" "V" "both"
default = 0
endparam
func FH
caption = "H modification"
default = ident()
visible = @type == 1 || @type == 3
endfunc
float param hfac
caption = "H factor"
default = 1
visible = @type == 1 || @type == 3
endparam
func FV
caption = "V modification"
default = ident()
visible = @type == 2 || @type == 3
endfunc
float param vfac
caption = "V factor"
default = 1
visible = @type == 2 || @type == 3
endparam
heading
visible = @fade > 0
endheading
param fade
caption = "Decay?"
enum = "None" "Power" "Exponential" "Gaussian"
default = 0
endparam
float param distance
caption = "Distance"
default = 1
min = 0
visible = @fade > 0
endparam
float param power
caption = "Decay power"
default = 2
min = 0
visible = @fade == 1
endparam
}
class JLB_DFuncs(Distance) {
public:
import "common.ulb"
func JLB_DFuncs(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
m_fx = new @f1(this)
m_fy = new @f2(this)
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
endfunc
float func Iterate(complex zz)
int n = 0
while n < @nmax
complex xa = @b*ComplexToFloat.go(zz, @xarg, true)
complex ya = @b*ComplexToFloat.go(zz, @yarg, true)
float xx = real(@a*m_fx.Iterate(xa))
float yy = real(@a*m_fy.Iterate(ya))
if @kind == "Add"
zz = zz + xx + flip(yy)
else
zz = xx + flip(yy)
endif
n = n + 1
endwhile
return m_dist.Iterate(zz)
endfunc
private:
Distance m_dist
UserTransform m_fx
UserTransform m_fy
default:
title = "XY Funcs"
rating = Recommended
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
heading
caption = "xnew = a*F(b*arg)"
endheading
UserTransform param f1
caption = "X function"
default = JLB_UT_Function
;selectable = false
endparam
param xarg
caption = "X arg"
enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \
"Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle"
endparam
heading
caption = "ynew = a*F(b*arg)"
endheading
UserTransform param f2
caption = "Y function"
default = JLB_UT_Function
;selectable = false
endparam
param yarg
caption = "Y arg"
enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \
"Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle"
endparam
heading
endheading
complex param a
caption = "a"
default = 1
endparam
complex param b
caption = "b"
default = 1
endparam
int param @nmax
caption = "Iterations"
default = 1
min = 1
endparam
param kind
caption = "Add or Replace"
enum = "Add" "Replace"
default = 0
endparam
heading
endheading
heading
;text = "Use for distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DAboveBelow(Distance) {
public:
func JLB_DAboveBelow(Generic pparent)
Distance(pparent)
if @sw
m_1 = new @dist_below(this)
m_2 = new @dist_above(this)
else
m_1 = new @dist_above(this)
m_2 = new @dist_below(this)
endif
m_SD = new @f_SD(this)
endfunc
func Init(complex zz)
m_SD.SetScale(false)
m_1.Init(zz)
m_2.Init(zz)
count = 0
endfunc
float func Iterate(complex zz)
float test = count
count = count + 1
if @mode == 0
test = m_SD.Iterate(zz)
endif
if @trans == 0 ; abrupt transition
if test >= @crit
return m_1.Iterate(zz)
else
return m_2.Iterate(zz)
endif
endif
; smooth transition using tanh
float frac = TSmooth.go((test-@crit)/@trans)
float d1 = m_1.Iterate(zz)
float d2 = m_2.Iterate(zz)
return frac * d1 + (1-frac) * d2
endfunc
private:
Distance m_1
Distance m_2
int count
SD m_SD
default:
title = "AboveBelow"
rating = Recommended
heading
text = "Use a distance method depending on a critical value."
; hint = "Use real and imaginary parts of z to \
; calculate value to compare with critical value."
endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "Current version is 240101"
visible = @version < 240101
endheading
float param crit
caption = "Critical value"
default = 1
endparam
bool param sw
caption = "Switch above and below methods"
default = false
endparam
param mode
caption = "Use for critical value"
enum = "Z distance" "Iteration number"
default = 0
endparam
SD param f_SD
caption = "Method"
default = JLB_D01
visible = @mode == 0
endparam
float param trans
caption = "Transition parameter"
default = 0.5
min = 0
endparam
Distance param dist_above
caption = "Above method"
default = JLB_DSimpleShapes
endparam
Distance param dist_below
caption = "Below method"
default = JLB_DSimpleShapes
endparam
}
class JLB_PolynomialUserTransform(common.ulb:UserTransform) {
public:
func JLB_PolynomialUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
if (@p_poly_type == "Poly")
m_a[0] = @p_a0, m_a[1] = @p_a1, m_a[2] = @p_a2, m_a[3] = @p_a3
m_a[4] = @p_a4, m_a[5] = @p_a5, m_a[6] = @p_a6
endif
endfunc
; @param pz
; @return the new pz
complex func Iterate(complex pz)
complex f
int i
if (@p_poly_type == "Poly")
i = @p_degree
f = m_a[i]
while (i > 0)
i = i - 1
f = m_a[i] + pz * f
endwhile
else;if (@p_poly_type == "Power")
f = pz^@p_power
endif
return f
endfunc
protected:
complex m_a[7] ; coefficients of polynomial
default:
rating = Recommended
title = "Polynomial Transform"
int param version
caption = "Version (Polynomial_UserTransform)"
default = 231111
visible = @version < 231111
endparam
heading
text = "Current version is 231111"
visible = @version < 231111
endheading
param p_poly_type
caption = "Polynomial type"
enum = "Poly" "Power"
default = 0
hint = "Poly: polynomial has real powers, degree 6 or less. \
Power: polynomial is a single power, real or complex."
endparam
int param p_degree
caption = "Highest power"
default = 3
min = 0
max = 6
visible = (@p_poly_type == 0)
endparam
complex param p_a0
caption = "Constant coefficient"
default = (1,0)
visible = (@p_poly_type == 0)
endparam
complex param p_a1
caption = "Degree 1 coefficient"
default = (1,0)
visible = (@p_degree >= 1) && (@p_poly_type == 0)
endparam
complex param p_a2
caption = "Degree 2 coefficient"
default = (1,0)
visible = (@p_degree >= 2) && (@p_poly_type == 0)
endparam
complex param p_a3
caption = "Degree 3 coefficient"
default = (1,0)
visible = (@p_degree >= 3) && (@p_poly_type == 0)
endparam
complex param p_a4
caption = "Degree 4 coefficient"
default = (1,0)
visible = (@p_degree >= 4) && (@p_poly_type == 0)
endparam
complex param p_a5
caption = "Degree 5 coefficient"
default = (1,0)
visible = (@p_degree >= 5) && (@p_poly_type == 0)
endparam
complex param p_a6
caption = "Degree 6 coefficient"
default = (1,0)
visible = (@p_degree >= 6) && (@p_poly_type == 0)
endparam
complex param p_power
caption = "Power"
default = (3,0)
visible = (@p_poly_type == 1)
endparam
}
class JLB_UT_Function(common.ulb:UserTransform) {
; 240331 added parameter "a" and version number
public:
func JLB_UT_Function(Generic pparent)
UserTransform(pparent)
m = new @T(this)
endfunc
complex func Iterate(complex pz)
return m.Iterate(@a*pz)
endfunc
private:
FT m
default:
rating = Recommended
title = "Function - Plug-in"
int param version
caption = "Version"
default = 240331
visible = @version < 240331
endparam
heading
text = "(Current is 240331.)"
visible = @version < 240331
endheading
heading
caption = "v_new = F(a*v)"
endheading
FT param T
caption = "Function"
default = JLB_05cos
endparam
complex param a
caption = "a"
default = (1,0)
endparam
}
class FT(common.ulb:Generic) {
;
; FT base class. No title, so only used for a base class.
; Given a complex value, return a complex.
;
; Useful for replacing function calls, so the effect is visible as thumbnails.
public:
import "common.ulb"
func FT(Generic pparent)
Generic.Generic(pparent)
endfunc
complex func Iterate(complex pz)
return pz
endfunc
}
class JLB_00ident(FT) { ; yes, this is a duplicate of "33 ident"
public: ; but people are used to having it there
complex func Iterate(complex pz)
return pz
endfunc
default:
title = "00 ident"
}
class JLB_01sin(FT) {
public:
complex func Iterate(complex pz)
return sin(pz)
endfunc
default:
title = "01 sin"
}
class JLB_02sinh(FT) {
public:
complex func Iterate(complex pz)
return sinh(pz)
endfunc
default:
title = "02 sinh"
}
class JLB_03asin(FT) {
public:
complex func Iterate(complex pz)
return asin(pz)
endfunc
default:
title = "03 asin"
}
class JLB_04asinh(FT) {
public:
complex func Iterate(complex pz)
return asinh(pz)
endfunc
default:
title = "04 asinh"
}
class JLB_05cos(FT) {
public:
complex func Iterate(complex pz)
return cos(pz)
endfunc
default:
title = "05 cos"
}
class JLB_06cosh(FT) {
public:
complex func Iterate(complex pz)
return cosh(pz)
endfunc
default:
title = "06 cosh"
}
class JLB_07acos(FT) {
public:
complex func Iterate(complex pz)
return acos(pz)
endfunc
default:
title = "07 acos"
}
class JLB_08acosh(FT) {
public:
complex func Iterate(complex pz)
return acosh(pz)
endfunc
default:
title = "08 acosh"
}
class JLB_09tan(FT) {
public:
complex func Iterate(complex pz)
return tan(pz)
endfunc
default:
title = "09 tan"
}
class JLB_10tanh(FT) {
public:
complex func Iterate(complex pz)
return tanh(pz)
endfunc
default:
title = "10 tanh"
}
class JLB_11atan(FT) {
public:
complex func Iterate(complex pz)
return atan(pz)
endfunc
default:
title = "11 atan"
}
class JLB_12atanh(FT) {
public:
complex func Iterate(complex pz)
return atanh(pz)
endfunc
default:
title = "12 atanh"
}
class JLB_13cotan(FT) {
public:
complex func Iterate(complex pz)
return cotan(pz)
endfunc
default:
title = "13 cotan"
}
class JLB_14cotanh(FT) {
public:
complex func Iterate(complex pz)
return cotanh(pz)
endfunc
default:
title = "14 cotanh"
}
class JLB_15acotan(FT) {
public:
complex func Iterate(complex pz)
return atan(1/pz)
endfunc
default:
title = "15 acotan"
}
class JLB_16acotanh(FT) {
public:
complex func Iterate(complex pz)
return atanh(1/pz)
endfunc
default:
title = "16 acotanh"
}
class JLB_17sec(FT) {
public:
complex func Iterate(complex pz)
return 1/cos(pz)
endfunc
default:
title = "17 sec"
}
class JLB_18sech(FT) {
public:
complex func Iterate(complex pz)
return 1/cosh(pz)
endfunc
default:
title = "18 sech"
}
class JLB_19asec(FT) {
public:
complex func Iterate(complex pz)
return acos(1/pz)
endfunc
default:
title = "19 asec"
}
class JLB_20asech(FT) {
public:
complex func Iterate(complex pz)
return acosh(1/pz)
endfunc
default:
title = "20 asech"
}
class JLB_21cosec(FT) {
public:
complex func Iterate(complex pz)
return 1/sin(pz)
endfunc
default:
title = "21 cosec"
}
class JLB_22cosech(FT) {
public:
complex func Iterate(complex pz)
return 1/sinh(pz)
endfunc
default:
title = "22 cosech"
}
class JLB_23acosec(FT) {
public:
complex func Iterate(complex pz)
return asin(1/pz)
endfunc
default:
title = "23 acosec"
}
class JLB_24acosech(FT) {
public:
complex func Iterate(complex pz)
return asinh(1/pz)
endfunc
default:
title = "24 acosech"
}
class JLB_25sqr(FT) {
public:
complex func Iterate(complex pz)
return sqr(pz)
endfunc
default:
title = "25 sqr"
}
class JLB_25a_cubesqr(FT) {
public:
complex func Iterate(complex pz)
return pz^3
endfunc
default:
title = "25a cube"
}
class JLB_26sqrt(FT) {
public:
complex func Iterate(complex pz)
return sqrt(pz)
endfunc
default:
title = "26 sqrt"
}
class JLB_27log(FT) {
public:
complex func Iterate(complex pz)
return log(pz)
endfunc
default:
title = "27 log"
}
class JLB_28exp(FT) {
public:
complex func Iterate(complex pz)
return exp(pz)
endfunc
default:
title = "28 exp"
}
class JLB_29abs(FT) {
public:
complex func Iterate(complex pz)
return abs(pz)
endfunc
default:
title = "29 abs"
}
class JLB_30cabs(FT) {
public:
complex func Iterate(complex pz)
return cabs(pz)
endfunc
default:
title = "30 cabs"
}
class JLB_31conj(FT) {
public:
complex func Iterate(complex pz)
return conj(pz)
endfunc
default:
title = "31 conj"
}
class JLB_32flip(FT) {
public:
complex func Iterate(complex pz)
return flip(pz)
endfunc
default:
title = "32 flip"
}
class JLB_33capident(FT) {
public:
complex func Iterate(complex pz)
float size = cabs(pz)
if size > @cap
return pz * @cap / size
else
return pz
endif
endfunc
default:
title = "33 capped ident"
float param cap
caption = "Cap"
default = 1
min = 0
endparam
}
class JLB_34zero(FT) {
public:
complex func Iterate(complex pz)
return zero(pz)
endfunc
default:
title = "34 zero"
}
class JLB_35recip(FT) {
public:
complex func Iterate(complex pz)
return recip(pz)
endfunc
default:
title = "35 recip"
}
class JLB_36ceil(FT) {
public:
complex func Iterate(complex pz)
return ceil(pz)
endfunc
default:
title = "36 ceil"
}
class JLB_37floor(FT) {
public:
complex func Iterate(complex pz)
return floor(pz)
endfunc
default:
title = "37 floor"
}
class JLB_38trunc(FT) {
public:
complex func Iterate(complex pz)
return trunc(pz)
endfunc
default:
title = "38 trunc"
}
class JLB_39trunc*(FT) {
public:
complex func Iterate(complex pz)
float x = real(pz)
if x >= 0, x = ceil(x), else, x = floor(x), endif
float y = imag(pz)
if y >= 0, y = ceil(y), else, y = floor(y), endif
return x + flip(y)
endfunc
default:
title = "39 trunc*"
}
class JLB_40round(FT) {
public:
complex func Iterate(complex pz)
return round(pz)
endfunc
default:
title = "40 round"
}
class JLB_41power(FT) {
public:
complex func Iterate(complex pz)
return pz^@p
endfunc
default:
title = "41 power"
complex param p
caption = "Power"
default = 2
endparam
}
class JLB_42gd(FT) {
public:
complex func Iterate(complex pz)
return asin(tanh(pz))
endfunc
default:
title = "42 gd"
}
class JLB_43agd(FT) {
public:
complex func Iterate(complex pz)
return atanh(sin(pz))
endfunc
default:
title = "43 agd"
}
class JLB_44logit(FT) {
public:
complex func Iterate(complex pz)
return log(pz/(1-pz))
endfunc
default:
title = "44 logit"
}
class JLB_45expit(FT) {
public:
complex func Iterate(complex pz)
return 1/(1+exp(-pz))
endfunc
default:
title = "45 expit"
}
class JLB_46gauss(FT) {
public:
complex func Iterate(complex pz)
return exp(-sqr(pz))
endfunc
default:
title = "46 gauss"
}
class JLB_46agauss(FT) {
public:
complex func Iterate(complex pz)
return sqrt(-log(pz))
endfunc
default:
title = "46a agauss"
}
class JLB_47softplus(FT) {
public:
complex func Iterate(complex pz)
return log(1+exp(pz))
endfunc
default:
title = "47 softplus"
}
class JLB_48asoftplus(FT) {
public:
complex func Iterate(complex pz)
return log(exp(pz)-1)
endfunc
default:
title = "48 asoftplus"
}
class JLB_49softminus(FT) {
public:
complex func Iterate(complex pz)
return pz-log(1+exp(pz))
endfunc
default:
title = "49 softminus"
}
class JLB_50asoftminus(FT) {
public:
complex func Iterate(complex pz)
return pz-log(1-exp(pz))
endfunc
default:
title = "50 asoftminus"
}
class JLB_51sinc(FT) {
public:
complex func Iterate(complex pz)
if pz == 0
return 1
else
return sin(pz)/pz
endif
endfunc
default:
title = "51 sinc"
}
class JLB_52decay(FT) {
public:
complex func Iterate(complex pz)
return pz/(1+pz^@p)
endfunc
default:
title = "52 decay"
float param p
caption = "Decay power"
default = 4
endparam
}
; class JLB_99twofunc(FT) {
; public:
; func JLB_99twofunc(Generic pparent)
; FT(pparent)
; if @swap
; m_f = new @g(this)
; m_g = new @f(this)
; else
; m_f = new @f(this)
; m_g = new @g(this)
; endif
; endfunc
;
; complex func Iterate(complex pz)
; if @how == "f+g"
; return m_f.Iterate(pz) + m_g.Iterate(pz)
; elseif @how == "f-g"
; return m_f.Iterate(pz) - m_g.Iterate(pz)
; elseif @how == "f*g"
; return m_f.Iterate(pz) * m_g.Iterate(pz)
; elseif @how == "f/g"
; return m_f.Iterate(pz) / m_g.Iterate(pz)
; elseif @how == "f^g"
; return m_f.Iterate(pz) ^ m_g.Iterate(pz)
; else;if @how == "f(g)"
; return m_f.Iterate(m_g.Iterate(pz))
; endif
; endfunc
;
; protected:
; FT m_f
; FT m_g
; default:
; title = "99 two functions"
; heading
; text = " zz = g(z), znew = f(zz)"
; visible = @how == "f(g)"
; endheading
; FT param f
; caption = "f"
; default = JLB_27log
; endparam
; FT param g
; caption = "g"
; default = JLB_01sin
; endparam
; bool param swap
; caption = "Swap f and g?"
; default = false
; endparam
; param how
; enum = "f+g" "f-g" "f*g" "f/g" "f^g" "f(g)"
; default = 5
; endparam
; }
class JLB_D_SD(Distance){
; A distance class similar to ComplexToFloat2
; using plug-ins from class SD
; used for critical value in JLB_FX_AboveBelow
; and as default in many Distance classes
public:
func JLB_D_SD(Generic pparent)
Distance(pparent)
m_SD = new @d_SD(this)
endfunc
func Init(complex zz)
if (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale
m_SD.SetFactor(@factor)
endif
; if @d_SD == JLB_D19
m_SD.SD_Set(0, 0) ; initial path length = 0 - no path yet
;endif
m_SD.SetScale(@scale)
m_z0 = zz
endfunc
float func Iterate(complex zz)
float d = m_SD.Iterate(zz)
;$define debug
if |#pixel-1| < 1e-6
print(zz, " ", d)
endif
; m_abs_value is from Distance base class, default is False
; Color by Distance sets m_abs_value to True
if m_abs_value
d = abs(d)
endif
if @version < 240209 && @invert && d != 0
d = 1/d
endif
return d
endfunc
protected:
SD m_SD
complex m_z0 ; used by D019
default:
title = "Simple distance"
rating = Recommended
int param version
caption = "Version"
default = 240209
visible = @version < 240209
endparam
heading
text = "(current is 240209.}"
visible = @version < 240209
endheading
SD param d_SD
caption = "Use for distance"
default = JLB_D01
endparam
bool param scale
caption = "Scale?"
default = true
visible = @d_SD != JLB_D19 && @d_SD != JLB_D20 && @d_SD != JLB_D20a
endparam
float param factor
caption = "Scale divisor"
default = 1
min = 1e-6
visible = (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale
endparam
bool param invert ; eliminate, now part of Color by Distance
caption = "Use reciprocal?"
default = false
visible = @version < 240209
endparam
}
class SD(common.ulb:Generic) {
;
; SD base class. No title, so only used for a base class.
; A variation of sorts on the Distance class
; Given a complex value, return a float.
; Optionally scale the float to 0..1
; Designed for use in Color by Distance
;
; Useful for seeing the effect visible as thumbnails in Browse mode.
; Note that in the titles of class members, |Real| means abs(real(pz)), not its square.
public:
import "common.ulb"
func SD(Generic pparent)
Generic.Generic(pparent)
m_scale = false
endfunc
func SD_Set(int m, float f)
m_iter = m, m_pathlength = f
endfunc
func SetScale(bool scale)
m_scale = scale
endfunc
func SetFactor(float factor)
m_factor = factor
endfunc
float func Iterate(complex pz)
return 1
endfunc
protected:
int m_iter
float m_pathlength ; used by D19
bool m_scale
float m_factor ; used by D00 and D01
complex m_z0
}
class JLB_D00(SD) {
public:
float func Iterate(complex pz)
float d = |pz|
if m_scale
d = real(TanhZ.Go(d / m_factor)) ; range 0 to 1
endif
return d
endfunc
default:
title = "D00 |z|"
}
class JLB_D01(SD) {
public:
float func Iterate(complex pz)
float d = cabs(pz)
if m_scale
d = real(TanhZ.Go(d / m_factor)) ; range 0 to 1
endif
return d
endfunc
default:
title = "D01 cabs"
}
class JLB_D02(SD) {
public:
float func Iterate(complex pz)
float d = real(pz)
if m_scale
d = d/cabs(pz) ; range -1 to +1
d = (d + 1)/2
endif
return d
endfunc
default:
title = "D02 Real"
}
class JLB_D03(SD) {
public:
float func Iterate(complex pz)
float d = imag(pz)
if m_scale
d = d/cabs(pz) ; range -1 to +1
d = (d+1)/2
endif
return d
endfunc
default:
title = "D03 Imag"
}
class JLB_D04(SD) {
public:
float func Iterate(complex pz)
float d = abs(real(pz))+abs(imag(pz))
if m_scale
d = d/cabs(pz) ; range 1 to sqrt(2)
d = (d-1)/(sqrt(2)-1)
endif
return d
endfunc
default:
title = "D04 |Real|+|Imag|"
}
class JLB_D05(SD) {
public:
float func Iterate(complex pz)
float d = real(pz)+imag(pz)
if m_scale
d = d/cabs(pz) ; range -sqrt(2) to sqrt(2)
d = (d+sqrt(2))/(2*sqrt(2))
endif
return d
endfunc
default:
title = "D05 Real+Imag"
}
class JLB_D06(SD) {
public:
float func Iterate(complex pz)
float d = abs(real(pz))-abs(imag(pz))
if m_scale
d = d/cabs(pz) ; range -1 to 1
d = (d+1)/2
endif
return d
endfunc
default:
title = "D06 |Real|-|Imag|"
}
class JLB_D07(SD) {
public:
float func Iterate(complex pz)
float d = abs(imag(pz))-abs(real(pz))
if m_scale
d = d/cabs(pz) ; range -1 to 1
d = (d+1)/2
endif
return d
endfunc
default:
title = "D07 |Imag|-|Real|"
}
class JLB_D08(SD) {
public:
float func Iterate(complex pz)
float d = real(pz)-imag(pz)
if m_scale
d = d/cabs(pz) ; range -sqrt(2) to sqrt(2)
d = (d+sqrt(2))/(2*sqrt(2))
endif
return d
endfunc
default:
title = "D08 Real-Imag"
}
class JLB_D09(SD) {
public:
float func Iterate(complex pz)
float d = imag(pz)-real(pz)
if m_scale
d = d/cabs(pz) ; range -sqrt(2) to sqrt(2)
d = (d+sqrt(2))/(2*sqrt(2))
endif
return d
endfunc
default:
title = "D09 Imag-Real"
}
class JLB_D10(SD) {
public:
float func Iterate(complex pz)
float d = real(pz)*imag(pz)
if m_scale
d = d/|pz| ; range -0.5 to 0.5
d = (d+0.5)
endif
return d
endfunc
default:
title = "D10 Real*Imag"
}
class JLB_D11(SD) {
public:
float func Iterate(complex pz)
float d
if !m_scale
d = real(pz)/imag(pz)
else
d = real(pz)/cabs(pz) ; range -1 to +1
d = (d + 1)/2 ; range 0 to 1
float a = 1+abs(imag(pz)) ; range 1 to infinity
d = d/a ; range 0 to 1
endif
return d
endfunc
default:
title = "D11 Real/Imag"
}
class JLB_D12(SD) {
public:
float func Iterate(complex pz)
float d
if !m_scale
d = imag(pz)/real(pz)
else
d = imag(pz)/cabs(pz) ; range -1 to +1
d = (d + 1)/2 ; range 0 to 1
float a = 1+abs(real(pz)) ; range 1 to infinity
d = d/a ; range 0 to 1
endif
return d
endfunc
default:
title = "D12 Imag/Real"
}
;
; Note: for real x and y, for x^y UF does abs(x)^y
;
class JLB_D13(SD) {
public:
float func Iterate(complex pz)
float d
if !m_scale
d = real(pz)^imag(pz)
else
d = real(pz)/cabs(pz) ; range -1 to +1
d = (d + 1)/2 ; range 0 to 1
d = d^abs(imag(pz))
endif
return d
endfunc
default:
title = "D13 Real^Imag"
}
class JLB_D14(SD) {
public:
float func Iterate(complex pz)
float d
if !m_scale
d = imag(pz)^real(pz)
else
d = imag(pz)/cabs(pz) ; range -1 to +1
d = (d + 1)/2 ; range 0 to 1
d = d^abs(real(pz))
endif
return d
endfunc
default:
title = "D14 Imag^Real"
}
class JLB_D15(SD) {
public:
float func Iterate(complex pz)
float d = MyMath.fmax(abs(real(pz)),abs(imag(pz)))
if m_scale
d = d/cabs(pz) ; range sqrt(0.5) to 1
d = (d-sqrt(0.5))/(1-sqrt(0.5))
endif
return d
endfunc
default:
title = "D15 Max(|Real|,|Imag|)"
}
class JLB_D16(SD) {
public:
float func Iterate(complex pz)
float d = MyMath.fmax(real(pz),imag(pz))
if m_scale
d = d/cabs(pz) ; range 0 to 1
endif
return d
endfunc
default:
title = "D16 Max(Real,Imag)"
}
class JLB_D17(SD) {
public:
float func Iterate(complex pz)
float d = MyMath.fmin(abs(real(pz)),abs(imag(pz)))
if m_scale
d = d/cabs(pz) ; range 0 to sqrt(0.5)
d = d/sqrt(0.5)
endif
return d
endfunc
default:
title = "D17 Min(|Real|,|Imag|)"
}
class JLB_D18(SD) {
public:
float func Iterate(complex pz)
float d = MyMath.fmin(real(pz),imag(pz))
if m_scale
d = d/cabs(pz) ; range -1 to sqrt(0.5)
d = (d+1)/(sqrt(0.5)+1)
endif
return d
endfunc
default:
title = "D18 Min(Real,Imag)"
}
class JLB_D19(SD) {
; only mathematically correct if all iterations used for coloring
public:
float func Iterate(complex pz)
if m_pathlength == 0 ; first time
pz_old = m_z0 ; set in Init of SD
endif
float a = cabs(pz-pz_old) ; incremental path length
pz_old = pz
m_pathlength = m_pathlength + a
float d = cabs(pz-m_z0)/m_pathlength ; range 0 to 1, 1 on first entry
return d
endfunc
private:
complex pz_old
default:
title = "D19 Path ratio"
; heading
; text = " (Already scaled to 0..1)"
; endheading
}
class JLB_D20(SD) {
public:
float func Iterate(complex pz)
float d = atan2(pz)/(2*#pi) ; range -0.5 to +0.5
if @type == 0
if d < 0, d = d + 1, endif ; range 0 to 1
else
d = d + 0.5 ; range 0 to 1
endif
return d
endfunc
default:
title = "D20 Angle"
param type
caption = "Type"
enum = "1" "2"
default = 0
endparam
}
class JLB_D20a(SD) {
public:
float func Iterate(complex pz)
;$define debug
complex p = (0,1)
float d = atan2(pz)*180/#pi ; range -180 to +180
if d < 0, d = d + 360, endif ; range 0 to 360
float b = d - @ctr
float spacing = 360/@mult
b = b - spacing * round(b/spacing)
b = abs(b)
b = MyMath.fmin(b, spacing-b)
if |#pixel-p| < 1e-6
print(" z ", pz, " ctr ", @ctr, " d ", d, " b ", b)
endif
if b > 0.5 * @width
d = 2
else
d = b / (0.5 *@width)
endif
if |#pixel-p| < 1e-6
print(" d ", d)
endif
return d
endfunc
default:
title = "D20a Angle+"
heading
text = "(All in degrees)"
endheading
float param ctr
caption = "Reference angle"
min = 0
max = 360
default = 0
endparam
int param mult
caption = "Multiplicity"
min = 1
default = 3
endparam
float param width
caption = "Width"
min = 0
max = 360
default = 45
endparam
}
class JLB_UT_Tweak(common.ulb:UserTransform) {
; 240405 added @nsteps and added "Transform" to the name
public:
;Simport "common.ulb"
func JLB_UT_Tweak(Generic pparent)
UserTransform(pparent)
if @type > 0
m_zT = new @uT(pparent)
endif
endfunc
complex func Iterate(complex pz)
int n = 0
while n < @nsteps
complex tmp
if @type == "Linear"
tmp = @e1 + @e2*pz
else
tmp = @e1 + @e2*m_zT.Iterate(@a*pz)
endif
if @kind == "Add"
pz = pz + tmp
else
pz = tmp
endif
n = n + 1
endwhile
return pz
endfunc
private:
UserTransform m_zT
default:
title = "Tweak Transform"
rating = Recommended
param kind
caption = "Add or Replace"
enum = "Add" "Replace"
default = 0
endparam
int param nsteps
caption = "Number of steps"
default = 1
min = 0
endparam
; heading
; text = " (v can be z or c or ...)"
; endheading
heading
caption = "v_new = v + e1 + e2*v"
visible = @type == 0 && @kind == 0
endheading
heading
caption = "v_new = e1 + e2*v"
visible = @type == 0 && @kind == 1
endheading
heading
caption = "v_new = v + e1 + e2*T(a*v)"
visible = @type > 0 && @kind == 0
endheading
heading
caption = "v_new = e1 + e2*T(a*v)"
visible = @type > 0 && @kind == 1
endheading
param type
caption = "Tweak type"
enum = "Linear" "Transform"
default = 0
endparam
complex param e1
caption = "e1"
default = (0,0)
endparam
complex param e2
caption = "e2"
default = (0.1,0)
endparam
complex param a
caption = "a"
default = 1
visible = @type > 0
endparam
UserTransform param uT
caption = "Transform"
default = JLB_UT_Function
visible = @type > 0
endparam
}
class ZZ(common.ulb:Generic) {
;
; ZZ base class. No title, so only used for a base class.
; Used at the beginning of Color by Distance and Distance Coloring 2
; Useful for seeing the effect visible as thumbnails in Browse mode.
public:
func ZZ(Generic pparent)
Generic.Generic(pparent)
endfunc
complex func Go(complex zz, complex zzprev, complex pixel)
return zz
endfunc
}
class JLB_Z01(ZZ) {
public:
complex func Go(complex zz, complex zzprev, complex pixel)
return zz
endfunc
default:
rating = Recommended
title = "Z01 z"
}
class JLB_Z02(ZZ) {
public:
complex func Go(complex zz, complex zzprev, complex pixel)
return zz-zzprev
endfunc
default:
rating = Recommended
title = "Z02 z - zprev"
}
class JLB_Z03(ZZ) {
public:
complex func Go(complex zz, complex zzprev, complex pixel)
return zz/zzprev
endfunc
default:
rating = Recommended
title = "Z03 z / zprev"
}
class JLB_Z04(ZZ) {
public:
complex func Go(complex zz, complex zzprev, complex pixel)
return zz-pixel
endfunc
default:
rating = Recommended
title = "Z04 z - pixel"
}
class JLB_Z05(ZZ) {
public:
complex func Go(complex zz, complex zzprev, complex pixel)
return zz/pixel
endfunc
default:
rating = Recommended
title = "Z05 z / pixel"
}
class JLB_Z06(ZZ) {
public:
func ZZ(Generic pparent)
Generic.Generic(pparent)
f = new @ff(this)
if @how > 0
g = new @gg(this)
endif
endfunc
complex func Go(complex zz, complex zzprev, complex pixel)
if @how == 0
return f.Iterate(zz)
elseif @how == 1
return f.Iterate(zz)-g.Iterate(zzprev)
elseif @how == 2
return f.Iterate(zz)/g.Iterate(zzprev)
elseif @how == 3
return f.Iterate(zz)-g.Iterate(pixel)
else;if @how == 4
return f.Iterate(zz)/g.Iterate(pixel)
endif
endfunc
private:
FT f
FT g
default:
rating = Recommended
title = "Z06 f(z) & etc."
param how
caption = "How"
enum = "f(z)" "f(z)-g(zprev)" "f(z)/g(zprev)" \
"f(z)-g(pixel)" "f(z)/g(pixel)"
default = 1
endparam
FT param ff
caption = "f"
default = JLB_05cos
endparam
FT param gg
caption = "g"
default = JLB_01sin
visible = @how > 0
endparam
}
class CT(common.ulb:Generic) {
;
; CT base class. No title, so only used for a base class.
; Used in Color by Distance for Coloring Type
; Useful for seeing the effect visible as thumbnails in Browse mode.
public:
func CT(Generic pparent)
Generic.Generic(pparent)
endfunc
func Accumulate(float d, float &dsum, float &dsumsq, int count)
endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
endfunc
}
class JLB_C01(CT) {
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
if count == 1, dsum = d, endif
endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
count = 1
endfunc
; func FinalAverage(float &dsum, float dsumsq, int &count)
; endfunc
default:
rating = Recommended
title = "C01 First distance"
}
class JLB_C02(CT) {
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = d
endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
count = 1
endfunc
; func FinalAverage(float &dsum, float dsumsq, int &count)
; endfunc
default:
rating = Recommended
title = "C02 Last distance"
}
class JLB_C03(CT) {
public:
; func Accumulate(float d, float &dsum, float &dsumsq, int count)
; endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
dsum = dmin
count = 1
endfunc
; func FinalAverage(float &dsum, float dsumsq, int &count)
; endfunc
default:
rating = Recommended
title = "C03 Smallest distance"
}
class JLB_C04(CT) {
public:
; func Accumulate(float d, float &dsum, float &dsumsq, int count)
; endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
dsum = dmax
count = 1
endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
count = 1
endfunc
default:
rating = Recommended
title = "C04 Largest distance"
}
class JLB_C05(CT) {
public:
; func Accumulate(float d, float &dsum, float &dsumsq, int count)
; endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
dsum = dmax - dmin
count = 1
endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
count = 1
endfunc
default:
rating = Recommended
title = "C05 Distance range"
}
class JLB_C06(CT) {
public:
; func Accumulate(float d, float &dsum, float &dsumsq, int count)
; endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
dsum = dmax / dmin ; dmin guaranteed > 0
count = 1
endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
count = 1
endfunc
default:
rating = Recommended
title = "C06 Distance ratio"
}
class JLB_C07(CT) {
public:
; func Accumulate(float d, float &dsum, float &dsumsq, int count)
; endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
dsum = count / @scale
count = 1
endfunc
default:
rating = Recommended
title = "C07 Iteration count"
heading
text = "(Ignores any distance method plug-in)"
endheading
float param scale
caption = "Scale"
default = 100
min = 1
endparam
}
class JLB_C07a(CT) {
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = dsum + d
endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
count = 1 ; avoid averaging
endfunc
; func FinalAverage(float &dsum, float dsumsq, int &count)
; endfunc
default:
rating = Recommended
title = "C07a Sum"
}
class JLB_C08(CT) {
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = dsum + d
endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; endfunc
; func FinalAverage(float &dsum, float dsumsq, int &count)
; endfunc
default:
rating = Recommended
title = "C08 Arithmetic average"
}
class JLB_C09(CT) {
; instead doing nth root of the product, average the logs and then exponentiate
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = dsum + log(d) ; d guaranteed > 0
endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
dsum = exp(dsum)
endfunc
default:
rating = Recommended
title = "C09 Geometric average"
}
class JLB_C10(CT) {
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = dsum + 1 / d ; d guaranteed > 0
endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
dsum = 1 / dsum
endfunc
default:
rating = Recommended
title = "C10 Harmonic average"
}
class JLB_C10a(CT) {
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
if @p == 0
dsum = dsum + log(d) ; d guaranteed > 0
else
dsum = dsum + d^@p
endif
endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
if @p == 0
dsum = exp(dsum)
else
dsum = dsum ^ (1/@p)
endif
endfunc
default:
rating = Recommended
title = "C10a Power average"
float param p
caption = "Power"
default = 2
hint = "p=+1, same as Arithmetic average; \
p=-1, same as Harmonic average; \
p near 0, similar to Geometric average"
endparam
heading
text = "p=0, doing geometric average"
visible = @p==0
endheading
}
class JLB_C11(CT) {
; "Std. Deviation" ignoring -1
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = dsum + d
dsumsq = dsumsq + d * d
endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
dsum = sqrt(dsumsq - sqr(dsum))
endfunc
default:
rating = Recommended
title = "C11 Variation 1"
}
class JLB_C12(CT) {
; "Coefficient of Variation"
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = dsum + d
dsumsq = dsumsq + d * d
endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
dsum = sqrt(dsumsq - sqr(dsum)) / dsum
endfunc
default:
rating = Recommended
title = "C12 Variation 2"
}
class JLB_C13(CT) {
; "Fractal Dimension" -- more or less
public:
func Accumulate(float d, float &dsum, float &dsumsq, int count)
dsum = dsum + d
dsumsq = dsumsq + d * d
endfunc
func Aux(float &dsum, float dmin, float dmax, int &count)
ddmin = dmin, ddmax = dmax
endfunc
func FinalAverage(float &dsum, float dsumsq, int &count)
if ddmax == ddmin
dsum = 0
else
dsum = sqrt(dsumsq - sqr(dsum)) / (ddmax - ddmin)
endif
endfunc
private:
float ddmin
float ddmax
default:
rating = Recommended
title = "C13 Variation 3"
}
; class JLB_C16(CT) {
; public:
; func Accumulate(float d, float &dsum, float &dsumsq, int count)
; dsum = d
; endfunc
; func Aux(float &dsum, float dmin, float dmax, int &count)
; count = 1
; endfunc
; ; func FinalAverage(float &dsum, float dsumsq, int &count)
; ; endfunc
; default:
; rating = Recommended
; title = "C16 Shape"
; }
class JLB_DColoring(common.ulb:GradientColoring) { ; 240917
; Accumulate a sum at each step, or at selected steps, of the orbit.
; Use the result to calculate a color index.
; 231203 added pathlength
; 240826 added partial smoothing; backwards compatible REMOVED
; 240917 correction: changed za from float to complex; backwards compatible
public:
import "common.ulb"
func JLB_DColoring(Generic pparent)
GradientColoring(pparent)
m_dist = new @fdist(this) ; distance plug-in
m_ct = new @fct(this) ; coloring plug-in
if @d_zd > 0
m_zdist = new @fzdist(this)
endif
rotation = 1
min_d_use = 0, max_d_use = 1e38
z_off = (0,0)
if !@Basic
m_BP1 = new @fBP1(this) ; distance adjustment plug-in
m_BP2 = new @fBP2(this) ; final adjustment plug-in
m_ZZ = new @fZZ(this) ; initial z plug-in
if @fz > 0
m_zT = new @fUT(this) ; initial z transform plug-in
endif
rotation = cos(@angle * #pi/180.0) - flip(sin(@angle * #pi/180.0))
if (@version < 240224 && @UseMinMax ) || \
(@version >= 240224 && @someDist == "Some")
min_d_use = @ddmin, max_d_use = @ddmax
endif
z_off = @offset
endif
endfunc
func Init(complex pz, complex ppixel)
GradientColoring.Init(pz, ppixel)
m_dist.init(pz)
m_dist.SetParams(0, true) ; iteration 0, absolute value distance
if @d_zd > 9
m_zdist.init(pz)
m_zdist.SetParams(0, true)
endif
dsum = dsum_prev = dsumsq = dmin = dmax = 0
z_prev = pz
iter = 0 ; iter updated each call to Iterate()
iter1 = 1
iter2 = 2000000000 ; largest int is 2147483647
if !@Basic && @some_all > 0
iter1 = @start
iter2 = @start + @howmany - 1
endif
count = 0 ; count updates only for succesful distance calculation
endfunc
func Iterate(complex pz)
GradientColoring.Iterate(pz)
; doing only certain iterations?
iter = iter + 1
bool okay = (iter >= iter1 && iter <= iter2)
if !okay
return
endif
; initial changes to z
complex zz = pz
if !@Basic
zz = m_ZZ.Go(pz, z_prev, #pixel) ; z, z-zprev, etc.
endif
z_prev = pz
dsum_prev = dsum
zz = zz * rotation
if !@Basic && @fz > 0
zz = m_zT.Iterate(@a*zz)
endif
; the iteration itself!
m_dist.SetIter(iter)
zz = zz - z_off
float d = m_dist.Iterate(zz) ; here it is!
; doing only certain distance ranges?
if d < min_d_use || d > max_d_use
return
endif
if @d_zd > 0
d = m_zdist.Iterate(@za * d * zz)
endif
; NOTE: get rid of this??
; per-iteration distance adjustment?
if !@Basic && d != 0
float t = @b1
if @fBP1 == JLB_BP99, t = @n1, endif
d = m_BP1.Go(d, t, @p1)
endif
; bookkeeping
count = count + 1
if count == 1
dmin = dmax = d
else
if d < dmin, dmin = d, endif
if d > dmax, dmax = d, endif
dsum_prev = dsum
endif
; accumulate based on coloring plug-in
m_ct.Accumulate(d, dsum, dsumsq, count)
endfunc ; Iterate
float func ResultIndex(complex pz)
; use the final iteration by default (UF doesn't call Iterate after bailout)
if @Basic || (!@Basic && @dofinal)
Iterate(pz)
endif
if @solid && count == 0
m_solid = true ; from base class
return 0
endif
; any cleaning up?
m_ct.Aux(dsum, dmin, dmax, count)
if count > 0
dsum = dsum / count ; average "d"
dsumsq = dsumsq / count ; average sqr(d)
endif
if count > 1
dsum_prev = dsum_prev / (count-1) ; only needed for TIA smoothing
endif
; finish some types
m_ct.FinalAverage(dsum, dsumsq, count)
; do Mandelbrot or TIA smoothing?
if @final > 0 && count > 0 ; && !@Basic is possible
FinalSmooth( )
endif
float d = dsum
; two old versions have been superceded.
if @version < 240108 && !@Basic && @recip && d != 0
d = 1/d
endif
if @version >= 240108 && !@Basic && @version < 240224 && d != 0
if @lastgasp == "Reciprocal"
d = 1/d
elseif @lastgasp == "Power"
d = d^@p_lastgasp
endif
endif
if @version >= 240224 && !@Basic && d != 0
float t = @b2
if @fBP2 == JLB_BP99, t = @n2, endif
d = m_BP2.Go(d, t, @p2)
endif
; all done! d is the index value
return d
endfunc ; ResultIndex
func FinalSmooth( )
if @final == 1
float il = 1/log(@power)
float lp = log(log(@bailout))
; 0.05 to agree with original Smooth (Mandelbrot)
; dsum = 0.05 * (count - 1 + il*lp - il*log(log(abs(dsum))))
float d = 0.05 * (iter + il*lp - il*log(log(dsum)))
;dsum = d*@full + dsum*(1-@full)
dsum = d
elseif @final == 2
float il = 1/log(@power) ; as in Triangle in Standard.ulb
float lp = log(log(@bailout)/2.0)
float fac = il * lp - il*log(log(cabs(#z)))
;dsum = dsum * count / (count+1) ; to agree with original
;dsum_prev = dsum_prev * (count-1) / count
float d = cabs(dsum_prev + (dsum - dsum_prev) * (fac + 1))
;dsum = d*@full + dsum*(1-@full)
dsum = d
endif
endfunc
private:
complex rotation
Distance m_dist
Distance m_zdist
CT m_ct
ZZ m_ZZ
BP m_BP1
BP m_BP2
UserTransform m_zT
float dsum
float dsum_prev ; used by TIA smoothing
float dsumsq ; used by Variations 1, 2, 3
float dmin, float dmax
float min_d_use, float max_d_use
complex z_off
complex z_prev
int count
int iter, int iter1, int iter2
default:
title = "Color by Distance"
rating = Recommended
int param version
caption = "Version"
default = 240420
visible = @version < 240420
endparam
heading
text = "(current is 240420.}"
visible = @version < 240420
endheading
bool param solid
caption = "Use solid background?"
default = true
endparam
bool param Basic
caption = "Basic version?"
default = true
endparam
heading
caption = "Accumulation phase"
endheading
Distance param fzdist
caption = "d * z conversion"
default = JLB_D_SD
selectable = false
visible = @d_zd > 0
endparam
bool param dofinal
caption = "Use final distance?"
default = true
visible =!@Basic
endparam
ZZ param fZZ
caption = "Use for zz "
visible = !@Basic
endparam
float param angle
caption = "Rotate zz by "
default = 0
visible = !@Basic
endparam
heading
caption = "Use zz or T(a*zz)"
; caption = "Use zz or T(zz)"
visible = !@Basic
endheading
param fz
caption = "Which?"
enum = "zz" "T(a*zz)"
; enum = "zz" "T(zz)"
default = 0
visible = !@Basic
endparam
complex param a
caption = "a"
default = 1
visible = !@Basic && @fz > 0
endparam
UserTransform param fUT
caption = "Transform"
default = JLB_UT_OneFunction
visible = !@Basic && @fz > 0
endparam
heading
visible = !@Basic && @fz == "T(a*zz)"
endheading
complex param offset
caption = "ZZ Offset"
default = (0,0)
visible = !@Basic
endparam
heading
visible = !@Basic
endheading
heading
caption = "Distance plug-in"
endheading
Distance param fdist
caption = "Plug-in"
default = JLB_D_SD
visible = @fct != JLB_C07
endparam
heading
caption = "End of distance plug-in"
endheading
param d_zd
caption = "Color using"
enum = "d = Distance" "a * d * z"
default = 0
visible = @version >= 240420
endparam
complex param za
caption = "a"
default = 1
visible = @version >= 240420 && @d_zd > 0
endparam
BP param fBP1
caption = "Distance adjustment"
visible = !@Basic
default = JLB_BP00
endparam
float param b1
caption = "Factor b"
default = 1
min = 0
visible = !@Basic && @fBP1 != JLB_BP00 && @fBP1 != JLB_BP99
endparam
float param p1
caption = "Power p"
default = 1
visible = !@Basic && @fBP1 != JLB_BP00 && @fBP1 != JLB_BP99
endparam
int param n1
caption = "Number of values"
default = 4
min = 2
visible = !@Basic && @fBP1 == JLB_BP99
endparam
heading
visible = !@Basic
endheading
param someDist
caption = "Use all / some distances?"
enum = "All" "Some"
default = 0
visible = !@Basic && @version >= 240224
endparam
bool param UseMinMax
caption = "Min/max distances?"
default = false
visible = !@Basic && @version < 240224
endparam
float param ddmin
caption = "Minimum distance"
default = 0
min = 0
visible = !@Basic && ( (@version < 240224 && @UseMinMax) || \
(@version >= 240224 && @someDist == "Some") )
endparam
float param ddmax
caption = "Maximum distance"
default = 1
min = 0
visible = !@Basic && ( (@version < 240224 && @UseMinMax) || \
(@version >= 240224 && @someDist == "Some") )
endparam
heading
visible = !@Basic
endheading
param some_all
enum = " All" " Some" ;" Some + More"
default = 0
caption = "Use all / some iterations?"
visible = !@Basic
endparam
int param start
caption = "Starting with iteration?"
default = 4
min = 1
visible = !@Basic && @some_all > 0
endparam
int param howmany
caption = "How many to use?"
default = 100
min = 1
visible = !@Basic && @some_all > 0
endparam
heading
caption = "Final phase of coloring"
endheading
CT param fct
caption = "How to color"
default = JLB_C05
endparam
heading
endheading
param final
caption = "Final smooth"
enum = "None" "Mandelbrot type" "TIA type"
default = 0
; visible = !@Basic ; possible
endparam
float param power
caption = "Smoothing exponent"
default = 2.0
visible = @final > 0 ; && !@Basic is possible
endparam
float param bailout
caption = "Smoothing bailout"
default = 100
min = 1
visible = @final > 0 ; && !@Basic is possible
endparam
; float param full
; caption = "Smoothing fullness"
; default = 1
; min = 0
; max = 1
; endparam
heading
visible = !@Basic
endheading
bool param recip
caption = "Use reciprocal?"
default = false
;hint = "Color based on, for example, 1/Mod(z) instead of Mod(z)."
visible = @version < 240108 && !@Basic
endparam
param lastgasp
caption = "Last gasp change"
enum = "None" "Reciprocal" "Power"
default = 0
visible = @version >= 240108 && !@Basic && @version < 240224
endparam
float param p_lastgasp
caption = "Power"
default = 1
visible = @version >= 240108 && !@Basic && @lastgasp == 2
endparam
BP param fBP2
caption = "Final adjustment"
visible = !@Basic && @version >= 240224
default = JLB_BP00
endparam
float param b2
caption = "Factor b"
default = 1
min = 0
visible = !@Basic && @fBP2 != JLB_BP00 && @fBP2 != JLB_BP99
endparam
float param p2
caption = "Power p"
default = 2
visible = !@Basic && @version >= 240224 && @fBP2 != JLB_BP00 && @fBP2 != JLB_BP99
endparam
int param n2
caption = "Number of values"
default = 4
min = 2
visible = !@Basic && @version >= 240224 && @fBP2 == JLB_BP99
endparam
}
class JLB_UT_Basic(common.ulb:UserTransform) {
public:
func JLB_UT_Basic(Generic pparent)
UserTransform.UserTransform(pparent)
m_T = new @f_T(this)
endfunc
func Init(complex pz)
m_T.Init(pz)
endfunc
complex func Iterate(complex pz)
return @a1 + @a2*m_T.Iterate(@a3*pz)
endfunc
private:
UserTransform m_T
default:
rating = Recommended
title = "Basic Transform"
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
heading
caption = "znew = a1+a2*f(a3*z)"
endheading
complex param a1
caption = "a1"
default = (0,0)
endparam
complex param a2
caption = "a2"
default = (1,0)
endparam
complex param a3
caption = "a3"
default = (1,0)
endparam
UserTransform param f_T
default = JLB_UT_Function
selectable = false
endparam
}
class JLB_UT_Moebius(common.ulb:UserTransform) {
public:
func JLB_UT_Moebius(Generic pparent)
UserTransform.UserTransform(pparent)
if @fz > 0
m_t = new @fT(this)
endif
endfunc
complex func Iterate(complex pz)
complex zz = pz
if @fz > 0
zz = m_t.Iterate(@ab*zz)
endif
return (@a0 + @a1*zz) / (@b0 + @b1*zz)
endfunc
private:
UserTransform m_t
default:
rating = Recommended
title = "Moebius Transform"
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
caption = "z_new = (a0+a1*zz)/(b0+b1*zz)"
endheading
; heading
; text = "zz = z or T(ab*z)"
; endheading
param fz
caption = "zz?"
enum = "zz = z" "zz = T(ab*z)"
default = 0
endparam
UserTransform param fT
caption = "Transform"
default = JLB_UT_Function
visible = @fz > 0
endparam
complex param a0
caption = "a0"
default = (1,0)
endparam
complex param a1
caption = "a1"
default = (1,0)
endparam
complex param b0
caption = "b0"
default = (1,0)
endparam
complex param b1
caption = "b1"
default = (-1,0)
endparam
complex param ab
caption = "ab"
default = (1,0)
visible = @fz > 0
endparam
}
class JLB_UT_Linear(common.ulb:UserTransform) {
; simplified version of Moebius
; 240301 T(z) instead of T(b*z)
public:
func JLB_UT_Linear(Generic pparent)
UserTransform.UserTransform(pparent)
if @fz > 0
m_t = new @fT(this)
endif
endfunc
complex func Iterate(complex pz)
complex zz = pz
if @fz > 0
if @version < 240301
zz = m_t.Iterate(@b*zz)
else
zz = m_t.Iterate(zz)
endif
endif
return @a + @b * zz
endfunc
private:
UserTransform m_t
default:
rating = Recommended
title = "Linear Transform"
int param version
caption = "Version"
default = 240301
visible = @version < 240301
endparam
heading
text = "(Current is 240301.}"
visible = @version < 240301
endheading
heading
caption = "z_new = a+b*zz"
endheading
param fz
caption = "zz?"
enum = "zz = z" "zz = T(z)"
default = 0
endparam
UserTransform param fT
caption = "Transform"
default = JLB_UT_Function
visible = @fz > 0
endparam
complex param a
caption = "a"
default = (1,0)
endparam
complex param b
caption = "b"
default = (1,0)
endparam
}
class JLB_UT_XY(common.ulb:UserTransform) {
; combine an X transform and a Y transform
public:
func JLB_UT_XY(Generic pparent)
UserTransform(pparent)
m_fx = new @f_Tx(this)
m_fy = new @f_Ty(this)
m_PM = new @f_PM(this)
endfunc
complex func Iterate(complex pz)
complex zx = m_fx.Iterate(pz)
complex zy = m_fy.Iterate(pz)
complex znew = m_PM.go(zx, zy)
if @how == "Add"
znew = pz + @step * znew
endif
return znew
endfunc
private:
UserTransform m_fx
UserTransform m_fy
PM m_PM
default:
rating = Recommended
title = "X and Y Transforms"
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
heading
caption = "znew: +-r/i(Tx), +-r/i(Ty)"
endheading
UserTransform param f_Tx
caption = "Tx"
default = JLB_UT_Function
endparam
UserTransform param f_Ty
caption = "Ty"
default = JLB_UT_Function
endparam
heading
caption = "Combining"
endheading
PM param f_PM
caption = "dx dy"
default = JLB_PRPI
endparam
param how
caption = "How?"
enum = "Add" "Replace"
default = 0
endparam
param step
caption = "Step_size"
default = 0.1
visible = @how == 0
endparam
}
class JLB_Switch(common.ulb:Formula) {
; 240718 and 240723 Added All/Some to post-iteration tweaking, both z and c
; 240818 added bailout because of iterations
; 240903 added isInf and isNAN to iteration bailout
; Backward compatible
public:
import "Standard.ulb" ; for the default plug-in, Standard Mandelbrot
;$define debug
func JLB_Switch(Generic pparent)
Formula(pparent)
if @hasbail == "Yes"
mF = new @f_Formula (this)
FX = false
else
mFX = new @f_FormulaX(this)
m_BB = new @f_BB(this)
FX = true
len = mFX.GetLen( )
multi = mFX.GetMulti( )
endif
if !@Basic
if @pre , m_pre = new @preUT(this) , endif
if @post , m_post = new @postUT (this), endif
if @post2, m_post2 = new @post2UT(this), endif
endif
endfunc
complex func Init(complex pz) ; over-rides the func in Formula
Formula.Init(pz)
; if |#pixel-(0,1)|<1e-6
; print("Switch Init FX ", FX, " multi ", multi)
; endif
if FX
mFX.Init(pz)
iseed = 0
if @version >= 241020 ; otherwise m_c is set in mFX
if multi
iseed = 0 ; index into ic array
int i = 0
while i < len
cseed[i] = mFX.GetC2(i)
i = i + 1
endwhile
; if |#pixel-(0,1)|<1e-6
; print("Switch Init")
; i = 0, while i < len, print("cseed ", i, " ", cseed[i]), i=i+1, endwhile
; endif
; m_c set at each iteration
else
; m_c set in mFX
endif
endif
else
pz = mF.Init(pz)
endif
pzold = pz
iter = 0 ; iter updated each call to Iterate()
iter1z = 1, iter2z = 2000000000 ; largest int is 2147483647
if !@Basic && @post && @some_all > 0
iter1z = @start, iter2z = @start + @howmany - 1
endif
iter1c = 1, iter2c = 2000000000 ; largest int is 2147483647
if FX && multi && @version >= 241020
; no post-tweaking of c
elseif !@Basic && @post2 && @some_all > 0
iter1c = @start2, iter2c = @start2 + @howmany2 - 1
endif
return pz
endfunc
complex func Iterate(complex pz) ; over-rides the func in Formula
pzold = pz
iter = iter + 1
if FX && @version >= 241020 && multi
complex cnew = cseed[iseed]
mFX.SetC(cnew)
; if |#pixel-(0,1)| < 1e-6
; print(" iter ", iter, " iseed ", iseed, " c ", cnew)
; endif
endif
if !@Basic && @pre && iter == 1
pz = m_pre.Iterate(pz)
endif
if FX
pz = mFX.Iterate(pz)
else
pz = mF.Iterate(pz)
endif
if !@Basic
if @post && iter >= iter1z && iter <= iter2z
pz = m_post.Iterate(pz)
endif
if @post2 && iter >= iter1c && iter <= iter2c
complex c=1, complex cc=1
if FX && @version >= 241020 && multi
c = cseed[iseed]
cc = m_post2.Iterate(c)
mFX.SetC(cc)
cseed[iseed] = cc
elseif FX
c = mFX.GetC( )
cc = m_post2.Iterate(c)
mFX.SetC(cc)
endif
; if |#pixel-(0.,0)| < 1e-6 && FX
; print("C ",#pixel, " z ", pz, " c ", c, " cc ", cc)
; endif
; if |#pixel-(0.5,0)| < 1e-6
; mFX.printseeds( )
; endif
endif
endif
if FX, iseed = (iseed+1) % len, endif
return pz
endfunc
bool func IsBailedOut(complex pz) ; over-rides the func in Formula
if @hasbail == "Yes"
return mF.IsBailedOut(pz)
endif
; handle bailout here
if (@how == "Divergent" || @how == "Either") && m_BB.Go(pz, @Dbailout)
; if @Diverging && m_BB.Go(pz, @Dbailout)
return true
endif
if (@how == "Convergent" || @how == "Either") && cabs(pz - pzold) < @Cbailout
; if @Converging && cabs(pz - pzold) < @Cbailout
return true
endif
if @how == "Iterations"
float a = cabs(pz)
return iter >= #maxiter || isInf(a) || isNAN(a)
endif
return false
endfunc
protected:
Formula mF
FormulaX mFX
bool FX
UserTransform m_pre
UserTransform m_post
UserTransform m_post2
BB m_BB
complex pzold
int iter, int iter1z, int iter2z, int iter1c, int iter2c
; multi-seed stuff
bool multi
complex cseed[10] ; the cycle of seeds
int len ; the number of seeds in the cycle
int iseed ; index into cseed[]
default:
title = "Switch Formula"
rating = Recommended
int param version
caption = "Version"
default = 241020
visible = @version < 241020
endparam
heading
text = "(Current is 241020.}"
visible = @version < 241020
endheading
heading
caption = "Does Formula do its own bailout test?"
endheading
param hasbail
caption = " "
enum = "Yes" "No"
default = 1
endparam
param how
caption = "Bailout type"
enum = "Divergent" "Convergent" "Either" "Iterations"
default = 0
visible = @hasbail == 1
endparam
BB param f_BB
caption = "Divergent bailout method"
default = JLB_B00
visible = @hasbail > 0 && (@how == 0 || @how == 2)
endparam
float param Dbailout
caption = "Divergent bailout value"
default = 100
min = 1
visible = @hasbail > 0 && (@how == 0 || @how == 2)
endparam
float param Cbailout
caption = "Convergent bailout value"
default = 1e-4
visible = @hasbail > 0 && (@how == 1 || @how == 2)
endparam
bool param Basic
caption = "Basic version of Switch Formula?"
default = true
endparam
heading
visible = @pre
endheading
bool param pre
caption = "Tweak z before first iteration?"
default = false
visible = !@Basic
endparam
UserTransform param preUT
caption = "Tweak transform"
default = JLB_UT_Tweak
visible = @pre && !@Basic
selectable = false
endparam
heading
caption = "End of pre-tweaking"
visible = !@Basic && @pre
endheading
Formula param f_Formula
caption = "Formula"
default = Standard_Mandelbrot
visible = @hasbail == 0
endparam
FormulaX param f_FormulaX
caption = "FormulaX"
default = JLB_FX_Mandelbrot
visible = @hasbail == 1
endparam
heading
visible = !@Basic
endheading
bool param post
caption = "Tweak z after iterations?"
default = false
visible = !@Basic
endparam
param some_all
enum = " All" " Some"
default = 0
caption = "After all / some?"
visible = !@Basic && @post
endparam
int param start
caption = "Starting with iteration?"
default = 1
min = 1
visible = !@Basic && @post && @some_all > 0
endparam
int param howmany
caption = "How many?"
default = 1
min = 1
visible = !@Basic && @post && @some_all > 0
endparam
UserTransform param postUT
caption = "Tweak transform"
default = JLB_UT_Tweak
visible = @post && !@Basic
selectable = false
endparam
heading
caption = "End of z post-tweaking"
visible = !@Basic && @post
endheading
heading
visible = !@Basic ;&& !@post && !@post2
endheading
bool param post2
caption = "Tweak c after iterations?"
default = false
visible = !@Basic && @hasbail == "No"
endparam
param some_all2
enum = " All" " Some"
default = 0
caption = "After all / some?"
visible = !@Basic && @post2 && @hasbail == "No"
endparam
int param start2
caption = "Starting with iteration?"
default = 1
min = 1
visible = !@Basic && @post2 && @some_all2 > 0 && @hasbail == "No"
endparam
int param howmany2
caption = "How many?"
default = 1
min = 1
visible = !@Basic && @post && @some_all2 > 0 && @hasbail == "No"
endparam
UserTransform param post2UT
caption = "Tweak transform"
default = JLB_UT_Tweak
visible = @post2 && !@Basic && @hasbail == "No"
selectable = false
endparam
heading
visible = @hasbail == "No"
endheading
complex param p_power ; not used; over-rides Formula
visible = false
endparam
}
class BB(common.ulb:Generic) {
; BB base class. No title, so only used for a base class.
; Given a complex and a float, return a bool.
; Return true if some functin of the complex is larger than the float.
; Designed to be used for bailout calculation, so the effect is visible as thumbnails.
public:
import "common.ulb"
func BB(Generic pparent)
Generic.Generic(pparent)
endfunc
bool func Go(complex pz, float v)
return false
endfunc
}
class JLB_B00(BB) {
public:
bool func Go(complex pz, float v)
return |pz| > v
endfunc
default:
title = "B00 |z|"
}
class JLB_B01(BB) {
public:
bool func Go(complex pz, float v)
return cabs(pz) > v
endfunc
default:
title = "B01 cabs"
}
class JLB_B02(BB) {
public:
bool func Go(complex pz, float v)
return abs(real(pz)) > v
endfunc
default:
title = "B02 |Real|"
}
class JLB_B03(BB) {
public:
bool func Go(complex pz, float v)
return abs(imag(pz)) > v
endfunc
default:
title = "B03 |Imag|"
}
class JLB_B04(BB) {
public:
bool func Go(complex pz, float v)
return (abs(real(pz)) > v) && (abs(imag(pz)) > v)
endfunc
default:
title = "B04 |Real| and |Imag|"
}
class JLB_B05(BB) {
public:
bool func Go(complex pz, float v)
return (abs(real(pz)) > v) || (abs(imag(pz)) > v)
endfunc
default:
title = "B05 |Real| or |Imag|"
}
class JLB_B06(BB) {
public:
bool func Go(complex pz, float v)
return abs(real(pz)) + abs(imag(pz)) > v
endfunc
default:
title = "B06 |Real|+|Imag|"
}
class JLB_B07(BB) {
public:
bool func Go(complex pz, float v)
return abs(real(pz) * imag(pz)) > v*v
endfunc
default:
title = "B07 |Real*Imag|"
}
class JLB_B08(BB) {
public:
bool func Go(complex pz, float v)
return MyMath.fmax(abs(real(pz)), abs(imag(pz))) > v
endfunc
default:
title = "B08 max(|Real|,|Imag|)"
}
class JLB_B09(BB) {
public:
bool func Go(complex pz, float v)
return MyMath.fmin(abs(real(pz)), abs(imag(pz))) > v
endfunc
default:
title = "B09 min(|Real|,|Imag|)"
}
class FormulaX(common.ulb:Formula) {
; A variation on Formula. Has the "c" value, hides p_power
; 241020 allow multi-seeds used in a cycle
public:
;$define debug
func FormulaX(Generic pparent)
Formula(pparent)
int i = 0, while i < 10, ic[i] = 9, i=i+1, endwhile
if @multi
docycle( )
else
len = 1
ic[0] = 0
endif
print("FormulaX ", @cycle)
print(ic[0]," ",ic[1]," ",ic[2]," ",ic[3]," ",ic[4]," ",\
ic[5]," ",ic[6]," ",ic[7]," ",ic[8]," ",ic[9], " X")
seed[0] = 0, seed[1] = @seed1, seed[2] = @seed2
seed[3] = @seed3, seed[4] = @seed4, seed[5] = @seed5
endfunc
func docycle( )
int tmp = @cycle
len = 0
int i
while tmp > 0
i = tmp % 10 ; final digit
if i > @N, i = 0, endif ; out of range means pixel
ic[len] = i
len = len + 1
tmp = floor(tmp/10)
endwhile
; now ic has the seed indices in reverse order, so reverse
i = 0, int j = len-1
while (i < j)
int t = ic[j], ic[j] = ic[i], ic[i] = t
i = i + 1, j = j - 1
endwhile
endfunc
func printseeds( ) ; debugging
int i = 0
while i <= @N
print("seed[", i, "] = ", seed[i])
i=i+1
endwhile
endfunc
func printcseeds( ) ; debugging
int i = 0
while i < len
print("FX cseed[", i, "] = ", cseed[i])
i=i+1
endwhile
endfunc
complex func Init(complex pz)
Formula.Init(pz)
if !@multi
m_c = #pixel, if !@p_Mtype, m_c = @p_seed, endif
cseed[0] = m_c
return pz
endif
; multi
int i = 0
while i < len
if ic[i] == 0
cseed[i] = #pixel
else
cseed[i] = seed[ic[i]]
endif
i = i + 1
endwhile
if |#pixel-(0,1)| < 1e-6
print("Formula X Init ",#pixel)
printcseeds( )
endif
return pz
endfunc
; these for non-multi-seed
complex func GetC( )
return m_c
endfunc
func SetC(complex c)
m_c = c
endfunc
; these for multi-seed
complex func GetC2(int i) ; 0<=i<=len-1
m_c = cseed[i]
; if |#pixel-(0.5,0)|<1e-6
; print("Getc2 ", i, " len ", len, " ", 1+i%len, " c ", m_c)
; printseeds( )
; endif
return m_c
endfunc
func SetC2(complex c, int i) ; 0<=i<=len-1
; if |#pixel-(0,1)|<1e-6
; print("Setc2 ", i, " old c ", cseed[i], " new c ", c)
; printcseeds( )
; endif
m_c = cseed[i] = c
; if |#pixel-(0,1)|<1e-6
; print("m_c ", m_c)
; printcseeds( )
; endif
endfunc
;
int func GetLen( )
return len
endfunc
bool func GetMulti( )
return @multi
endfunc
protected:
complex m_c
complex seed[6]
int len ; length of cycle
int ic[10] ; max integer is 2,147,483,647 = 10 digits
complex cseed[10]
default:
; int param version
; caption = "FormulaX Version"
; default = 241020
; visible = @version < 2421020
; endparam
; heading
; text = "(Current is 241020.}"
; visible = @version < 241020
; endheading
bool param multi
caption = "Multiple seeds?"
default = false
endparam
int param cycle
caption = "Cycle pattern"
default = 123456789
min = 0
visible = @multi
endparam
int param N
caption = "Number of seeds"
min = 1
max = 5
default = 1
visible = @multi
endparam
complex param seed1
caption = "seed 1"
default = (1,0)
visible = @multi ;&& @N >= 1
endparam
complex param seed2
caption = "seed 2"
default = (0,1)
visible = @multi && @N >= 2
endparam
complex param seed3
caption = "seed 3"
default = (-1,0)
visible = @multi && @N >= 3
endparam
complex param seed4
caption = "seed 4"
default = (0,-1)
visible = @multi && @N >= 4
endparam
complex param seed5
caption = "seed 5"
default = (0,0)
visible = @multi && @N >= 5
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = !@multi
endparam
complex param p_seed
caption = "Seed for J-type"
default = (1.0,-0.5)
visible = !@multi &&!@p_Mtype
endparam
complex param p_power
visible = false ; hide it!
endparam
}
class JLB_FX_Mandelbrot(FormulaX) {
public:
import "common.ulb"
func JLB_FX_Mandelbrot(Generic pparent)
FormulaX(pparent)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex znew
if (@Basic)
znew = pz^2 + m_c
elseif @type == "Standard"
znew = pz^@p + m_c
else
float t = |pz| ^ (@p/2)
float angle = @p * atan2(pz)
znew = t * exp(flip(angle)) + m_c
endif
m_iterations = m_iterations + 1
;$define debug
if |#pixel-(1,0)| < 1e-6
print("M ", #pixel, " c ", m_c, " z ", pz, " zz ", znew)
endif
return znew
endfunc
default:
title = "Mandelbrot"
rating = Recommended
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
bool param Basic
caption = "Basic Mandelbrot?"
default = true
endparam
heading
caption = "z_new = z^2 + c"
visible = @Basic
endheading
heading
caption = "z_new = z^p + c" ; F(z) or T(z) ?
; caption = "z_new = z^p op c" ; F(z) or T(z) ?
visible = !@Basic
endheading
float param p
caption = "p"
default = 2
visible = !@Basic
endparam
param type
enum = "Standard" "Fatou?"
caption = "type"
default = 0
visible = !@Basic
endparam
}
class JLB_FX_Lambda(FormulaX) {
public:
import "common.ulb"
func JLB_FX_Lambda(Generic pparent)
FormulaX(pparent)
if !@Basic && @version >= 240205
m_T = new @T(this)
endif
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex znew
if (@Basic)
znew = m_c * pz * (1 - pz)
else
complex zz = pz
if @version >= 240205
zz = m_T.Iterate(pz)
endif
znew = m_c * zz^@p * (@a - zz)^@q
endif
return znew
endfunc
protected:
UserTransform m_T
default:
title = "Lambda"
;rating = Recommended
int param version
caption = "Version"
default = 240205
visible = @version < 240205
endparam
heading
text = "(Current is 240205.}"
visible = @version < 240205
endheading
bool param Basic
caption = "Basic Lambda?"
default = true
endparam
heading
caption = "z_new = c * z * (1 - z)"
visible = @Basic
endheading
heading
caption = "z_new = c * z^p * (a - z)^q"
visible = !@Basic && @version < 240205
endheading
heading
caption = "z_new = c * T(z)^p * (a - T(z))^q"
visible = !@Basic && @version >= 240205
endheading
UserTransform param T
caption = "T"
default = JLB_UT_Function
visible = !@Basic
endparam
complex param p
caption = "p"
default = 1
visible = !@Basic
endparam
complex param a
caption = "a"
default = 1
visible = !@Basic
endparam
complex param q
caption = "q"
default = 1
visible = !@Basic
endparam
}
class JLB_FX_Nova(FormulaX) {
public:
func JLB_FX_Nova(Generic pparent)
FormulaX(pparent)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex znew
;if (@Basic)
znew = pz - @step * (pz^3-1) / (3 * pz^2) + m_c
;endif
return znew
endfunc
protected:
default:
title = "Nova"
;rating = Recommended
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
; bool param Basic
; caption = "Basic Nova?"
; default = true
; endparam
heading
caption = "z_new = z - step * (z^3-1) / (3*z*2) + c"
;visible = @Basic
endheading
complex param step
caption = "Step size"
default = (1,0)
; hint = "This can be used to slow down the convergence of \
; the formula."
endparam
; heading
; caption = "z_new = c * z^p * (a - z)^q"
; visible = !@Basic
; endheading
; complex param p
; caption = "p"
; default = 1
; visible = !@Basic
; endparam
; complex param a
; caption = "a"
; default = 1
; visible = !@Basic
; endparam
; complex param q
; caption = "q"
; default = 1
; visible = !@Basic
; endparam
}
class JLB_FX_AboveBelow(FormulaX) {
public:
import "common.ulb"
func JLB_FX_AboveBelow(Generic pparent)
FormulaX(pparent)
if @sw
m_1 = new @f_FXbelow(this)
m_2 = new @f_FXabove(this)
else
m_1 = new @f_FXabove(this)
m_2 = new @f_FXbelow(this)
endif
type = 0 ; SD
if @version < 240207 && @mode == "Iteration"
type = 2
endif
if @version >= 240207
if @mode2 == "Distance"
type = 1
elseif @mode2 == "Iteration"
type = 2
endif
endif
if type == 0
m_SD = new @f_SD(this)
elseif type == 1
m_D = new @f_D(this)
endif
endfunc
complex func Init(complex pz)
if type == 0
m_SD.SetScale(false)
elseif type == 1
m_D.Init(pz) ;m_abs_value set to False
endif
m_1.Init(pz)
m_2.Init(pz)
count = 0
return pz
endfunc
complex func Iterate(complex pz)
float test = count
count = count + 1
if type == 0
test = m_SD.Iterate(pz)
elseif type == 1
test = m_D.Iterate(pz)
endif
if @trans == 0 ; abrupt transition
if test >= @crit
return m_1.Iterate(pz)
else
return m_2.Iterate(pz)
endif
endif
; smooth transition using tanh
float frac = TSmooth.go((test-@crit)/@trans)
complex zabove = m_1.Iterate(pz)
complex zbelow = m_2.Iterate(pz)
complex znew = frac * zabove + (1-frac) * zbelow
return znew
endfunc
private:
FormulaX m_1
FormulaX m_2
SD m_SD
Distance m_D
int count
int type ; 0 for SD, 1 for D, 2 for iteration
default:
title = "AboveBelow"
;rating = Recommended
int param version
caption = "Version"
default = 240207
visible = @version < 240207
endparam
heading
text = "(Current is 240207.}"
visible = @version < 240207
endheading
; heading
; endheading
float param crit
caption = "Critical value"
default = 1
endparam
bool param sw
caption = "Switch Above and Below formulas"
default = false
endparam
param mode
caption = "Use for test value"
enum = "Method" "Iteration"
default = 0
visible = @version < 240207
endparam
param mode2
caption = "Use for test value"
enum = "Simple" "Distance" "Iteration"
default = 0
visible = @version >= 240207
endparam
SD param f_SD
caption = "Method"
default = JLB_D02
visible = (@version < 240207 && @mode == 0) || \
(@version >= 240207 && @mode2 == 0)
endparam
Distance param f_D
caption = "Distance Method"
default = JLB_DCircle2
visible = @version >= 240207 && @mode2 == 1
endparam
float param trans
caption = "Transition parameter"
default = 0
;min = 0
endparam
heading
caption = "End of test value section"
endheading
FormulaX param f_FXabove
caption = "Above formula"
default = JLB_FX_Mandelbrot
endparam
FormulaX param f_FXbelow
caption = "Below formula"
default = JLB_FX_Poly
endparam
bool param p_Mtype
visible = false ; hide, as the two FXs have their own
endparam
complex param p_seed
visible = false ; hide, as the two FXs have their own
endparam
}
class JLB_FX_Gnarly(FormulaX) {
; use one FX for the new x, another for the new y
; 2402 -- needs work
public:
import "common.ulb"
func JLB_FX_Gnarly(Generic pparent)
FormulaX(pparent)
m_FXx = new @f_FXx(this)
m_FXy = new @f_FXy(this)
m_PM = new @f_PM(this)
endfunc
complex func Init(complex pz)
m_FXx.Init(pz)
m_FXy.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex zx = m_FXx.Iterate(pz)
complex zy = m_FXy.Iterate(pz)
;znew = CombineXY.go(zx, zy, @xytype)
complex znew = m_PM.go(zx, zy)
if @how == "Add"
znew = pz + @step * znew
endif
return znew
endfunc
private:
FormulaX m_FXx
FormulaX m_FXy
PM m_PM
default:
title = "Gnarly"
;rating = Recommended
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
; heading
; endheading
FormulaX param f_FXx
caption = "x formula"
default = JLB_FX_Mandelbrot
endparam
FormulaX param f_FXy
caption = "y formula"
default = JLB_FX_Lambda
endparam
heading
caption = "Combining"
endheading
PM param f_PM
caption = "dx dy"
default = JLB_PRPI
endparam
param how
caption = "How?"
enum = "Add" "Replace"
default = 0
endparam
param step
caption = "Step_size"
default = 0.1
visible = @how == 0
endparam
bool param p_Mtype
visible = false ; hide, as the two FXs have their own
endparam
complex param p_seed
visible = false ; hide, as the two FXs have their own
endparam
}
class JLB_FX_Combo(FormulaX) {
; This does two or three FormulaXs and combines them
; with one of the operators +, -, *, /, ^, ( ).
; The latter means use as argument to the previous function.
; This allows formulas such as z = (f1 + f2)/f3 + c
; or z = f1(f2(f3())) + c
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_FX_Combo(Generic pparent)
FormulaX(pparent)
m_FX1 = new @f_FX1(this)
m_FX2 = new @f_FX2(this)
if @how ==1 || @how == 2 || @how == 5
m_FX3 = new @f_FX3(this)
endif
endfunc
complex func Init(complex pz)
m_FX1.Init(pz)
m_FX2.Init(pz)
if @how ==1 || @how == 2 || @how == 5
m_FX3.Init(pz)
endif
return pz
endfunc
; @param pz
; @param pc
; @return new pz
complex func Iterate(complex pz)
complex z1
complex z2
complex z3
if @how == 3 ;"f1 only"
z1 = m_FX1.Iterate(pz)
elseif @how == 4 ;"f2 only"
z1 = m_FX2.Iterate(pz)
elseif @how == 5 ;"f3 only"
z1 = m_FX3.Iterate(pz)
elseif @how == 0 ;"f1 op f2"
z2 = m_FX2.Iterate(pz)
if @op1a == "( )" ; f1(f2(pz))
z1 = m_FX1.Iterate(z2)
else ; f1(pz) op1 f2(pz)
z1 = m_FX1.Iterate(pz)
z1 = Combine.go(z1, @op1a, z2)
endif
elseif @how == 1 ;"f1 op1 (f2 op2 f3)"
if @op2a == "( )" ; f1(pz) op1 f2(f3(pz))
z3 = m_FX3.Iterate(pz)
z2 = m_FX2.Iterate(z3)
if @op1 == "( )" ; f1(f2(f3(pz)))
z1 = m_FX1.Iterate(z2)
else ; f1(pz) op1 f2(f3(pz))
z1 = m_FX1.Iterate(pz)
z1 = Combine.go(z1, @op1, z2)
endif
else ; op2 != ()
z3 = m_FX3.Iterate(pz)
z2 = m_FX2.Iterate(pz)
z2 = Combine.go(z2, @op2a, z3)
if @op1 == "( )" ; f1(f2(pz) op2a f3(pz))
z1 = m_FX1.Iterate(z2)
else
z1 = m_FX1.Iterate(pz)
z1 = Combine.go(z1, @op1, z2)
endif
endif
else;if @how == 2 ;"(f1 op1 f2) op2 f3"
; op2 of "()" not allowed with this ordering
z2 = m_FX2.Iterate(pz)
if @op1 == "( )" ; (f1(f2(pz))) op2b f3(pz)
z1 = m_FX1.Iterate(z2)
else
z1 = m_FX1.Iterate(pz)
z1 = Combine.go(z1, @op1, z2)
endif
z3 = m_FX3.Iterate(pz)
z1 = Combine.go(z1, @op2b, z3)
endif
complex znew = z1
return znew
endfunc
protected:
FormulaX m_FX1
FormulaX m_FX2
FormulaX m_FX3
default:
rating = Recommended
title = "Combo FormulaX"
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
param how
caption = "Combos"
default = 0
enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3" \
"f1 only" "f2 only" "f3 only"
endparam
param op1
caption = "Op1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
visible = @how ==1 || @how == 2
endparam
param op1a
caption = "Op"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
visible = @how == 0
endparam
param op2a
caption = "Op2"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
visible = (@how == 1)
endparam
param op2b
caption = "Op2"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default = 2
visible = (@how == 2)
endparam
heading
caption = "f1"
visible = @how < 4
endheading
FormulaX param f_FX1
caption = "Formula 1"
default = JLB_FX_Mandelbrot
visible = @how < 4
endparam
heading
endheading
; heading
; endheading
heading
caption = "f2"
visible = @how < 3 || @how == 4
endheading
FormulaX param f_FX2
default = JLB_FX_Poly
caption = "Formula 2"
visible = @how < 3 || @how == 4
endparam
heading
caption = "f3"
visible = @how ==1 || @how == 2 || @how == 5
endheading
FormulaX param f_FX3
default = JLB_FX_Mandelbrot
caption = "Formula 3"
visible = @how ==1 || @how == 2 || @how == 5
endparam
; hide these
bool param p_Mtype
visible = false
endparam
complex param p_seed
visible = false
endparam
}
class JLB_FX_Transform(FormulaX) {
; 240703 added final power. Backward compatible.
public:
import "common.ulb"
func JLB_FX_Transform(Generic pparent)
FormulaX(pparent)
m_UT = new @f_UT(this)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
m_UT.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
if @version < 240821
return ((m_UT.Iterate(pz))^@p + m_c)^@q
else
return (m_UT.Iterate(pz))^@p + m_c
endif
endfunc
protected:
UserTransform m_UT
default:
title = "Transform"
rating = Recommended
int param version
caption = "Version"
default = 240821
visible = @version < 240821
endparam
heading
text = "(Current is 240821.}"
visible = @version < 240821
endheading
heading
caption = "z_new = (T(z)^p + c)^q"
visible = @version < 240821
endheading
heading
caption = "z_new = T(z)^p + c"
visible = @version >= 240821
endheading
float param p
caption = "p"
default = 2
endparam
float param q
caption = "q"
default = 1
visible = @version < 240821
endparam
UserTransform param f_UT
caption = "Transform T"
default = JLB_PolynomialUserTransform
endparam
}
class JLB_FX_ComboUT(FormulaX) {
; This does two or three UTs and combines them
; with one of the operators +, -, *, /, ^, ( ).
; The latter means use as argument to the previous function.
; This allows formulas such as z = (T1 + T2)/T3 + c
; or z = T1(T2(T3())) + c
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_FX_ComboUT(Generic pparent)
FormulaX(pparent)
m_UT1 = new @f_UT1(this)
m_UT2 = new @f_UT2(this)
if @how ==1 || @how == 2 || @how == 5
m_UT3 = new @f_UT3(this)
endif
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
m_UT1.Init(pz)
m_UT2.Init(pz)
if @how ==1 || @how == 2 || @how == 5
m_UT3.Init(pz)
endif
return pz
endfunc
; @param pz
; @param pc
; @return new pz
complex func Iterate(complex pz)
complex z1
complex z2
complex z3
if @how == 3 ;"T1 only"
z1 = m_UT1.Iterate(pz)
elseif @how == 4 ;"T2 only"
z1 = m_UT2.Iterate(pz)
elseif @how == 5 ;"T3 only"
z1 = m_UT3.Iterate(pz)
elseif @how == 0 ;"T1 op T2"
z2 = m_UT2.Iterate(pz)
if @op1a == "( )" ; T1(T2(pz))
z1 = m_UT1.Iterate(z2)
else ; T1(pz) op1 T2(pz)
z1 = m_UT1.Iterate(pz)
z1 = Combine.go(z1, @op1a, z2)
endif
elseif @how == 1 ;"T1 op1 (T2 op2 T3)"
if @op2a == "( )" ; T1(pz) op1 T2(T3(pz))
z3 = m_UT3.Iterate(pz)
z2 = m_UT2.Iterate(z3)
if @op1 == "( )" ; T1(T2(T3(pz)))
z1 = m_UT1.Iterate(z2)
else ; T1(pz) op1 T2(T3(pz))
z1 = m_UT1.Iterate(pz)
z1 = Combine.go(z1, @op1, z2)
endif
else ; op2 != ()
z3 = m_UT3.Iterate(pz)
z2 = m_UT2.Iterate(pz)
z2 = Combine.go(z2, @op2a, z3)
if @op1 == "( )" ; T1(T2(pz) op2a T3(pz))
z1 = m_UT1.Iterate(z2)
else
z1 = m_UT1.Iterate(pz)
z1 = Combine.go(z1, @op1, z2)
endif
endif
else;if @how == 2 ;"(T1 op1 T2) op2 T3"
; op2 of "()" not allowed with this ordering
z2 = m_UT2.Iterate(pz)
if @op1 == "( )" ; (T1(T2(pz))) op2b T3(pz)
z1 = m_UT1.Iterate(z2)
else
z1 = m_UT1.Iterate(pz)
z1 = Combine.go(z1, @op1, z2)
endif
z3 = m_UT3.Iterate(pz)
z1 = Combine.go(z1, @op2b, z3)
endif
if @version >= 240130
z1 = z1 + m_c
endif
return z1
endfunc
protected:
UserTransform m_UT1
UserTransform m_UT2
UserTransform m_UT3
default:
rating = Recommended
title = "Combo UT Formula"
int param version
caption = "Version"
default = 240130
visible = @version < 240130
endparam
heading
text = "(Current is 240130.}"
visible = @version < 240130
endheading
param how
caption = "Combos"
default = 0
enum = "T1 op T2 + c" "T1 op1 (T2 op2 T3) + c" "(T1 op1 T2) op2 T3 + c" \
"T1 + c only" "T2 + c only" "T3 + c only"
endparam
param op1
caption = "Op1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
visible = @how ==1 || @how == 2
endparam
param op1a
caption = "Op"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
visible = @how == 0
endparam
param op2a
caption = "Op2"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
visible = (@how == 1)
endparam
param op2b
caption = "Op2"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default = 2
visible = (@how == 2)
endparam
heading
caption = "T1"
visible = @how < 4
endheading
UserTransform param f_UT1
caption = "Transform 1"
default = JLB_UT_Basic
visible = @how < 4
endparam
heading
endheading
; heading
; endheading
heading
caption = "T2"
visible = @how < 3 || @how == 4
endheading
UserTransform param f_UT2
default = JLB_PolynomialUserTransform
caption = "Transform 2"
visible = @how < 3 || @how == 4
endparam
heading
caption = "T3"
visible = @how ==1 || @how == 2 || @how == 5
endheading
UserTransform param f_UT3
default = JLB_PolynomialUserTransform
caption = "Transform 3"
visible = @how ==1 || @how == 2 || @how == 5
endparam
}
class JLB_FX_Magnet(FormulaX) {
; combines Magnet 1 and Magnet 2 from Standard.ulb
public:
func JLB_FX_Magnet(Generic pparent)
FormulaX(pparent)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex znew
if @type == "1"
znew = sqr( (pz^2+m_c-1) / (2*pz+m_c-2) )
else
znew = sqr( (pz^3 + 3 * (m_c-1) * pz + (m_c-1) * (m_c-2)) \
/ (3 * pz^2 + 3 * (m_c-2) * pz + (m_c-1) * (m_c-2) + 1) )
endif
return znew
endfunc
protected:
default:
title = "Magnet"
;rating = Recommended
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
; heading
; caption = "Convergent formula"
; endheading
param type
caption = "Magnet type?"
enum = "1" "2"
default = 0
endparam
heading
caption = "z_new = sqr((z^2+c-1)/(2*z+c-2))"
visible = @type == 0
endheading
heading
caption = "z_new = (like type 1, but cubic)"
; caption = "z_new = sqr((z^3+3*(c-1)*z+(c-1)*(c-2))/ \
; (3*z^2+3*(c-2)*z+(c-1)*(c-2)+1))"
visible = @type == 1
endheading
}
class JLB_FX_Newton(FormulaX) {
; Iteration of polynomial(z) - c = 0 by relaxed Newton's method or other
; iterative method.
public:
func JLB_FX_Newton(Generic pparent)
FormulaX(pparent)
if (@poly_type == "Polynomial")
a[0] = @a0, a[1] = @a1, a[2] = @a2, a[3] = @a3
a[4] = @a4, a[5] = @a5, a[6] = @a6
a[@degree+1] = a[@degree+2] = 0
int i = 0
while (i <= @degree)
ap[i] = (i+1)*a[i+1] ; f' - coefficient of z^i
app[i] = (i+2)*(i+1)*a[i+2] ; f" - coefficient of z^i
i = i + 1
endwhile
endif
D = new Deriv(0)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
iter = 0
if @iter_type == "Secant"
z0 = pz + @z_off
eval(z0)
f0 = f
endif
return pz
endfunc
complex func Iterate(complex pz)
; calculate f, fp, fpp
eval(pz)
complex znew
if (@iter_type == "Newton" || @iter_type == "Secant")
znew = pz - @step * f / fp
elseif (@iter_type == "Type 1") ; Halley's method approx.
znew = pz - @step * (f/fp)*(1 + f*fpp/(2*fp*fp))
elseif (@iter_type == "Type 2") ; Halley's method
znew = pz - @step * (f/fp) / ( 1 - f*fpp/(2*fp*fp))
else;if (@iter_type == "Type 3") ; Laguerre
; see https://mathworld.wolfram.com/LaguerresMethod.html
; G = fp/f, H = G^2-fpp/f
; znew = z - n/max{G+-sqrt[(n-1)(nH-G^2)]}
; Halley's "irrational method" sets n=2
; Laguerre sets n=polynomial degree, but no good for Two Powers version
; where p and q and be complex and not the same
; complex root = sqrt(1-2*f*fpp/(fp*fp))
int n = 2
if @poly_type == 0, n = @degree, endif
complex root = sqrt((n-1)*(n-1-n*f*fpp/(fp*fp)))
complex d1 = 1 + root
complex d2 = 1 - root
if (|d1| < |d2|), d1 = d2, endif
znew = pz - @step * 2*(f/fp) / d1
endif
if @iter_type == "Secant"
z0 = pz, f0 = f
endif
iter = iter + 1
return znew
endfunc
func eval(complex pz)
if (@poly_type == "Polynomial")
; Solving F(z) = 0
D.Set_k(@kind)
D.pow_calc(pz, 1)
complex fz = D.f
complex fzp = D.fp
complex fzpp = D.fpp
int i = @degree
f = a[i]
while (i > 0)
i = i - 1
f = a[i] + fz * f
endwhile
f = f + m_c
; df/dz
if @iter_type == "Secant"
fp = (f - f0) / (pz - z0)
fpp = 0
return
endif
i = @degree - 1
complex sum1 = ap[i]
while (i > 0)
i = i - 1
sum1 = ap[i] + fz * sum1
endwhile
fp = fzp * sum1
fpp = 0 ; avoid compiler warning
if (@iter_type > 1)
; d2f/dz2
i = @degree - 2
complex sum2 = app[i]
while (i > 0)
i = i - 1
sum2 = app[i] + fz * sum2
endwhile
fpp = fzpp * sum1 + fzp * fzp * sum2
endif
else;if (@poly_type == "Two Powers")
D.Set_k(@kind)
D.pow_calc(pz, @power)
f = D.f
fp = D.fp
fpp = D.fpp
D.Set_k(@kind2)
D.pow_calc(pz, @power2)
f = f + @a*D.f + m_c
fp = fp + @a*D.fp
fpp = fpp + @a*D.fpp
if @iter_type == "Secant"
fp = (f - f0) / (pz - z0)
fpp = 0
endif
endif
endfunc
protected:
complex z0, complex f0
complex f, complex fp, complex fpp
complex a[9] ; coefficients of polynomial
complex ap[9] ; coefficients of first derivative of polynomial
complex app[9] ; coefficients of second derivative of polynomial
Deriv D
complex n ; real for polynomial type; complex for powers of functions
int iter
default:
title = "Poly Newton"
rating = Recommended
int param version
caption = "Version"
default = 240615
visible = @version < 240615
endparam
heading
text = "(Current is 240615.}"
visible = @version < 240615
endheading
param poly_type
caption = "Function type"
enum = "Polynomial" "Two Powers"
default = 0
endparam
heading
caption = "Solve a0 + a1*f(z) + a2*f(z)^2 + ... + c = 0"
visible = @poly_type == 0
endheading
heading
caption = "Solve f(z)^p + a*g(z)^q + c = 0"
visible = @poly_type == 1
endheading
; Polynomial params
int param degree
caption = "Degree (<=6)"
default = 3
min = 2
max = 6
visible = (@poly_type == 0)
endparam
param kind
caption = "f"
; These are the ones with calculated derivatives in the Deriv class
enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \
"cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \
"tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \
"log(z)" "exp(z)"
default = 0
;visible = @poly_type == 0
endparam
heading
caption = "Coeffients"
visible = (@poly_type == 0)
endheading
complex param a0
caption = "a0 = constant coef"
default = (0,0)
visible = (@poly_type == 0)
endparam
complex param a1
caption = "a1 = degree 1 coef"
default = (1,0)
visible = (@poly_type == 0)
endparam
complex param a2
caption = "a2 = degree 2 coef"
default = (1,0)
visible = (@poly_type == 0)
endparam
complex param a3
caption = "a3 = degree 3 coef"
default = (1,0)
visible = (@degree >= 3) && (@poly_type == 0)
endparam
complex param a4
caption = "a4 = degree 4 coef"
default = (1,0)
visible = (@degree >= 4) && (@poly_type == 0)
endparam
complex param a5
caption = "a5 = degree 5 coef"
default = (1,0)
visible = (@degree >= 5) && (@poly_type == 0)
endparam
complex param a6
caption = "a6 = degree 6 coef"
default = (1,0)
visible = (@degree >= 6) && (@poly_type == 0)
endparam
complex param power
caption = "p"
default = (3,0)
visible = (@poly_type == 1)
endparam
; second function
complex param a
caption = "a"
default = 1
visible = (@poly_type == 1)
endparam
param kind2
caption = "f2"
enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \
"cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \
"tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \
"log(z)" "exp(z)"
default = 0
visible = @poly_type == 1
endparam
complex param power2
caption = "q"
default = (2,0)
visible = (@poly_type == 1)
endparam
heading
endheading
param iter_type
caption = "Iteration type"
enum = "Newton" "Secant" "Type 1" "Type 2" "Type 3" ;"Type 4"
default = 0
hint = "Newton is the usual, using only the first derivative. \
Secant approximates the derivative by a first difference \
The other types also use the second derivative. \
Type 1 is Householder iteration; type 2 is Halley's iteration; \
type 3 is Halley's irrational iteration; \
type 4 is Laguerre's method for polynomials."
endparam
complex param z_off
caption = "Offset for starting"
default = (0.1,0.1)
visible = @iter_type == 1
endparam
param step
caption = "Step size"
default = (1,0)
; hint = "Nonstandard values may not allow \
; convergence, but can give interesting shapes."
endparam
}
class JLB_FX_Poly(FormulaX) {
public:
import "common.ulb"
func JLB_FX_Poly(Generic pparent)
FormulaX(pparent)
if @poly_type == "Two Powers"
m1 = new @T1(this)
m2 = new @T2(this)
else
a[0] = @a0, a[1] = @a1, a[2] = @a2, a[3] = @a3
a[4] = @a4, a[5] = @a5, a[6] = @a6
if @poly_type == "Polynomial in T(z)"
m0 = new @T0(this)
endif
endif
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex znew
if @poly_type == "Two Powers"
znew = m1.Iterate(pz)^@p + m2.Iterate(pz)^@q + m_c
else
complex zz = pz
if @poly_type == "Polynomial in T(z)"
zz = m0.Iterate(pz)
endif
int i = @degree
complex sum = a[i]
while (i > 0)
i = i - 1
sum = a[i] + zz * sum
endwhile
znew = sum + m_c
endif
m_iterations = m_iterations + 1
return znew
endfunc
protected:
complex a[7] ; coefficients of polynomial
UserTransform m0
UserTransform m1
UserTransform m2
default:
title = "Polynomial"
rating = Recommended
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
heading
caption = "z_new = a0 + a1*z + a2*z^2 + ... + c"
visible = @poly_type == 0
endheading
heading
caption = "z_new = a0 + a1*T(z) + a2*T(z)^2 + ... + c"
visible = @poly_type == 1
endheading
heading
caption = "z_new = T1(z)^p + T2(z)^q + c"
visible = @poly_type == 2
endheading
param poly_type
caption = "Function type"
enum = "Polynomial in z" "Polynomial in T(z)" "Two Powers"
default = 0
endparam
UserTransform param T0
caption = "T"
default = JLB_UT_Function
visible = @poly_type == 1
endparam
; Polynomial params
int param degree
caption = "Degree (<=6)"
default = 3
min = 1
max = 6
visible = (@poly_type < 2)
endparam
heading
caption = "Coeffients"
visible = (@poly_type < 2)
endheading
complex param a0
caption = "a0 = constant coef"
default = (2,0)
visible = (@poly_type < 2)
endparam
complex param a1
caption = "a1 = degree 1 coef"
default = (1,0)
visible = (@poly_type < 2)
endparam
complex param a2
caption = "a2 = degree 2 coef"
default = (1,0)
visible = (@degree >= 2) && (@poly_type < 2)
endparam
complex param a3
caption = "a3 = degree 3 coef"
default = (1,0)
visible = (@degree >= 3) && (@poly_type < 2)
endparam
complex param a4
caption = "a4 = degree 4 coef"
default = (1,0)
visible = (@degree >= 4) && (@poly_type < 2)
endparam
complex param a5
caption = "a5 = degree 5 coef"
default = (1,0)
visible = (@degree >= 5) && (@poly_type < 2)
endparam
complex param a6
caption = "a6 = degree 6 coef"
default = (1,0)
visible = (@degree >= 6) && (@poly_type < 2)
endparam
; Two powers params
UserTransform param T1
caption = "T1"
default = JLB_UT_Function
visible = @poly_type == 2
endparam
complex param p
caption = "p"
default = (3,0)
visible = (@poly_type == 2)
endparam
UserTransform param T2
caption = "T2"
default = JLB_UT_Function
visible = @poly_type == 2
endparam
complex param q
caption = "q"
default = (2,0)
visible = (@poly_type == 2)
endparam
}
class JLB_FX_Gnarl(FormulaX) {
; Based on the Gnarl formula from mt.ufm, as a FormulaX.
; Calculate dx and dy based on the real or imaginary parts
; of z and c, then combine.
public:
import "common.ulb"
func JLB_FX_Gnarl(Generic pparent)
FormulaX(pparent)
; m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180))
m_T = new @T(this)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex znew
float xc = real(m_c)
float yc = imag(m_c)
complex zrot = pz ;* m_rot
float x = real(zrot)
float y = imag(zrot)
complex px, complex py
px = y, py = x
complex dz = m_T.Iterate(px+flip(py))
float dx = real(dz)
float dy = imag(dz)
float qx, float qy
qx = yc, qy = xc
dx = dx + qx
dy = dy + qy
znew = pz + @step * (dx + flip(dy)) + @cstep * m_c
return znew
endfunc
protected:
complex m_rot
UserTransform m_T
default:
rating = Recommended
title = "Gnarl"
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
heading
caption = "Combo in action"
endheading
UserTransform param T
;caption = "Gnarl T"
default = JLB_UT_Combo
selectable = false ; don't want this changed
endparam
heading
caption = "Z step size"
endheading
param step
caption = "Step size"
default = 0.1
hint = "How much of this to use. z_new = z + Step_size * z_calc"
endparam
heading
caption = "C step size"
endheading
float param cstep
caption = "Step size"
default = 0.1
endparam
}
class JLB_UT_Combo(common.ulb:UserTransform) {
func JLB_UT_Combo(Generic pparent)
UserTransform(pparent)
m_T1 = new @T1(this)
m_T2 = new @T2(this)
if @mode > 0
m_T3 = new @T3(this)
endif
endfunc
complex func Iterate(complex pz)
float px = real(pz)
float py = imag(pz)
complex dx, complex dy
complex tx1, complex tx2, complex tx3
complex ty1, complex ty2, complex ty3
if @mode == 0 ;"T1 op1 T2"
;tx2 = @a2*@T2(@b2*px)
;ty2 = @a2*@T2(@b2*py)
tx2 = iter(2, @b2*px)
ty2 = iter(2, @b2*py)
if @op1a == "( )" ; T1(T2(.))
; dx = @a1*@T1(@b1*tx2)
; dy = @a1*@T1(@b1*ty2)
dx = iter(1, @b1*tx2 + @mult*px)
dy = iter(1, @b1*ty2 + @mult*py)
else ; T1(.) op1 T2(.)
; tx1 = @a1*@T1(@b1*px)
; ty1 = @a1*@T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
dx = Combine.go(tx1, @op1a, tx2)
dy = Combine.go(ty1, @op1a, ty2)
endif
elseif @mode == 1 ;"T1 op1 (T2 op2 T3)"
if @op2a == "( )" ; T1 op T2(T3(.))
; tx3 = @a3*T3(@b3*px)
; ty3 = @a3*T3(@b3*py)
tx3 = iter(3, @b3*px)
ty3 = iter(3, @b3*py)
; tx2 = @a2*T2(@b2*tx3)
; ty2 = @a2*T2(@b2*ty3)
tx2 = iter(2, @b2*tx3 + @mult*px)
ty2 = iter(2, @b2*ty3 + @mult*py)
if @op1 == "( )" ; T1(T2(T3(.)))
; dx = @a1*T1(@b1*tx2)
; dy = @a1*T1(@b1*ty2)
dx = iter(1, @b1*tx2 + @mult*px)
dy = iter(1, @b1*ty2 + @mult*py)
else ; T1(.) op1 T2(T3(.))
; tx1 = @a1*T1(@b1*px)
; ty1 = @a1*T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
dx = Combine.go(tx1, @op1, tx2)
dy = Combine.go(ty1, @op1, ty2)
endif
else;
; tx3 = @a3*T3(@b3*px)
; ty3 = @a3*T3(@b3*py)
tx3 = iter(3, @b3*px)
ty3 = iter(3, @b3*py)
; tx2 = @a2*T2(@b2*px)
; ty2 = @a2*T2(@b2*py)
tx2 = iter(2, @b2*px)
ty2 = iter(2, @b2*py)
tx2 = Combine.go(tx2, @op2a, tx3)
ty2 = Combine.go(ty2, @op2a, ty3)
if @op1 == "( )" ; T1(T2(.) op2a T3(.))
; dx = @a1*T1(@b1*tx2)
; dy = @a1*T1(@b1*ty2)
dx = iter(1, @b1*tx2 + @mult*px)
dy = iter(1, @b1*ty2 + @mult*px)
else
; tx1 = @a1*T1(@b1*px)
; ty1 = @a1*T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
dx = Combine.go(tx1, @op1, tx2)
dy = Combine.go(ty1, @op1, ty2)
endif
endif
else ;@mode == "(T1 op1 T2) op2 T3"
; @op3a == "( )" not allowed with this ordering
; tx2 = @a2*T2(@b2*px)
; ty2 = @a2*T2(@b2*py)
tx2 = @a2*m_T2.Iterate(@b2*px)
;tx2 = iter(2, @b2*px)
ty2 = iter(2, @b2*py)
if @op1 == "( )" ; (T1(T2(.))) op2b T3(.)
; tx1 = @a1*T1(@b1*tx2)
; ty1 = @a1*T1(@b1*ty2)
tx1 = iter(1, @b1*tx2)
ty1 = iter(1, @b1*ty2)
else
; tx1 = @a1*T1(@b1*px)
; ty1 = @a1*T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
tx1 = Combine.go(tx1, @op1, tx2)
ty1 = Combine.go(ty1, @op1, ty2)
endif
; tx3 = @a3*T3(@b3*px)
; ty3 = @a3*T3(@b3*py)
tx3 = iter(3, @b3*px)
ty3 = iter(3, @b3*py)
dx = Combine.go(tx1, @op2b, tx3)
dy = Combine.go(ty1, @op2b, ty3)
endif
return dx + flip(dy)
endfunc
complex func iter(int n, complex v)
if n == 1
return real( @a1*m_T1.Iterate(v) )
elseif n == 2
return real( @a2*m_T2.Iterate(v) )
else
return real( @a3*m_T3.Iterate(v) )
endif
endfunc
protected:
UserTransform m_T1
UserTransform m_T2
UserTransform m_T3
default:
rating = Recommended
title = "Transform Combo"
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
param mode
caption = "Combining"
default = 0
enum = "T1 op T2" "T1 op1 (T2 op2 T3)" "(T1 op1 T2) op2 T3"
endparam
param op1
caption = "Operator 1"
enum = "+" "-" "*" "/" "^" "( )"
default = 5
hint = "How to combine Transform values."
visible = @mode > 0
endparam
param op1a
caption = "Operator"
enum = "+" "-" "*" "/" "^" "( )"
default = 5
hint = "How to combine Transform values."
visible = @mode == 0
endparam
param op2a
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" "( )"
default = 5
hint = "How to combine Transform values."
visible = (@mode == 1)
endparam
param op2b
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default =0
hint = "How to combine Transform values."
visible = (@mode == 2)
endparam
heading
caption = "a1*T1(b1*v)"
endheading
complex param a1
caption = "a1"
default = 1
hint = "multiplies T1"
endparam
complex param b1
caption = "b1"
default = 2
hint = "multiplies T1's arg"
endparam
UserTransform param T1
caption = "T1"
default = JLB_UT_Function ;JLB_FTransform
endparam
heading
caption = "a2*T2(b2*v)"
endheading
complex param a2
caption = "a2"
default = 2.7
hint = "multiplies T2"
endparam
complex param b2
caption = "b2"
default = 2.7
hint = "multiplies T2's arg"
endparam
UserTransform param T2
caption = "T2"
default = JLB_UT_Function ;JLB_FTransform
endparam
heading
caption = "a3*T3(b3*v)"
visible = @mode > 0
endheading
complex param a3
caption = "a3"
default = 0
hint = "multiplies T3"
visible = @mode > 0
endparam
complex param b3
caption = "b3"
default = 1
hint = "multiplies T3's arg"
visible = @mode > 0
endparam
UserTransform param T3
caption = "T3"
default = JLB_UT_Function ;JLB_FTransform
visible = @mode > 0
endparam
heading
endheading
float param mult ; maybe use this someday. doesn't seem useful.
caption = "( ) parameter"
default = 0
; visible = ( @mode == 0 && @op1a == "( )" ) || \
; ( @mode == 1 && ( @op2a == "( )" || @op1 == "( )" ) ) || \
; ( @mode == 2 && @op1 == "( )" )
visible = false
endparam
}
class JLB_FX_Dual(FormulaX) {
public:
import "common.ulb"
func JLB_FX_Dual(Generic pparent)
FormulaX(pparent)
if @sw
m_FX1 = new @f_FX2(this)
m_FX2 = new @f_FX1(this)
else
m_FX1 = new @f_FX1(this)
m_FX2 = new @f_FX2(this)
endif
endfunc
complex func Init(complex pz)
m_FX1.Init(pz)
m_FX2.Init(pz)
count = 0
return pz
endfunc
complex func Iterate(complex pz)
if @n1 + @n2 == 0
return m_FX1.Iterate(pz)
endif
complex znew
if count < @n1
znew = m_FX1.Iterate(pz)
else
znew = m_FX2.Iterate(pz)
endif
count = count + 1
if count == @n1 + @n2
count = 0
endif
return znew
endfunc
private:
FormulaX m_FX1
FormulaX m_FX2
int count
default:
title = "Two Formulas"
rating = Recommended
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
bool param sw
caption = "Switch formulas 1 and 2?"
default = false
endparam
heading
endheading
int param n1
caption = "Formula 1 iterations"
default = 1
min = 0
endparam
FormulaX param f_FX1
caption = "Formula 1"
default = JLB_FX_Mandelbrot
endparam
heading
endheading
int param n2
caption = "Formula 2 iterations"
default = 1
min = 0
endparam
FormulaX param f_FX2
caption = "Formula 2"
default = JLB_FX_Mandelbrot
endparam
bool param p_Mtype
visible = false ; hide, as the two FXs have their own
endparam
complex param p_seed
visible = false ; hide, as the two FXs have their own
endparam
}
class CD(common.ulb:Generic) {
;
; CD base class. No title, so only used for a base class.
; A variation of sorts on the Distance class
; Given a complex value, return a float.
; Optionally scale the float by the largest power of the argument
; Designed for use in Color by Distance
;
; Useful for seeing the effect visible as thumbnails in Browse mode.
public:
import "common.ulb"
func CD(Generic pparent)
Generic.Generic(pparent)
endfunc
func SetScale(bool scale)
m_scale = scale
endfunc
func SetAB(float aa, float bb)
a = aa, b = bb
endfunc
func Setp(float pp)
p = pp
endfunc
func SetAll(complex zz, bool exch)
; not all of these are needed for all plug-ins, but simplify, simplify, simplify
c1 = cabs(zz), c2 = c1*c1, c3 = c2*c1, c4 = c2*c2
x = real(zz), y = imag(zz)
if exch, float t=x, x=y, y=t, endif
x2 = x^2, y2 = y^2, d2 = x2-y2
endfunc
float func Iterate(complex zz)
return 1
endfunc
protected:
;int m_iter
bool m_scale
float c1, float c2, float c3, float c4
float x, float y, float x2, float y2, float d2
float a, float b, float p
}
; these two are the same as the parent, but can be treated differently
; CD1 has one parameter, CD2 has two parameters
class CD1(CD) {
public:
func CD1(Generic pparent)
CD.CD(pparent)
endfunc
}
class CD2(CD) {
public:
func CD2(Generic pparent)
CD.CD(pparent)
endfunc
}
class JLB_D_CD(Distance){
; A distance class using Curve plug-ins from class CD
; 240229 added Basic. Backward compatible, I think.
public:
func JLB_D_CD(Generic pparent)
Distance(pparent)
if @numpar == "1"
m_CD1 = new @d_CD1(this)
else
m_CD2 = new @d_CD2(this)
endif
endfunc
func Init(complex zz)
if @numpar == "1"
m_CD1.SetAB(@a, 1)
m_CD1.SetScale(@scale)
else
m_CD2.SetAB(@a, @b)
m_CD2.SetScale(@scale)
endif
endfunc
float func Iterate(complex zz)
float d
if @version < 240224 ; this now in Color by Distance
d = abs(Go(zz))
if @invert && d != 0
d = 1/d
endif
return d
endif
bool okay = false
if @Basic
d = Go(zz)
okay = true
elseif @in_out == "Show inside shape" || @in_out == "Show outside shape"
d = Go(#pixel)
if IsInside(d)
okay = (@in_out == "Show inside shape")
else
okay = (@in_out == "Show outside shape")
endif
else
d = Go(zz)
bool inside = IsInside(d)
if @in_out == "Either"
okay = true
elseif @in_out == "Inside"
okay = inside
elseif @in_out == "Outside"
okay = !inside
endif
endif
if !okay
return -1
endif
d = abs(d)
return d
endfunc
float func Go(complex zz)
float d
if @numpar == "1"
m_CD1.SetAll(zz, @exch)
d = m_CD1.Iterate(zz)
else
m_CD2.SetAll(zz, @exch)
d = m_CD2.Iterate(zz)
endif
return d
endfunc
bool func IsInside(float d)
return d <= 0
endfunc
protected:
CD1 m_CD1
CD2 m_CD2
default:
title = "Curve Distance"
;rating = Recommended
heading
text = " Try Shape Distance with the Curve plug-in."
endheading
int param version
caption = "Version"
default = 240224
visible = @version < 240224
endparam
heading
text = "(Current is 240224.)"
visible = @version < 240224
endheading
; heading
; text = "Scaling is often useful, as is Mandelbrot smoothing."
; endheading
bool param basic
caption = "Basic"
default = true
endparam
param numpar
caption = "# parameters"
enum = "1" "2"
default = 0
endparam
CD1 param d_CD1
caption = "Curve"
default = JLB_CD101
visible = @numpar == "1"
endparam
CD2 param d_CD2
caption = "Curve"
default = JLB_CD201
visible = @numpar == "2"
endparam
; float param p
; caption = "Power"
; default = 0.5
; visible = @d_CD1 == JLB_CD103 ; Astroid
; endparam
bool param exch
caption = "Exchange x and y?"
default = false
visible = (@numpar == "1" \
&& @d_CD1 != JLB_CD118 \
&& @d_CD1 != JLB_CD133 \
&& @d_CD1 != JLB_CD141 ) || \
(@numpar == "2" \
&& @d_CD2 != JLB_CD203a \
&& @d_CD2 != JLB_CD205 \
&& @d_CD2 != JLB_CD232)
; Folium of Descartes, Quadrifolium, Trott
; Astroid, Beetle, Windmill
endparam
bool param scale
caption = "Scale?"
default = true
endparam
float param a
caption = "Parameter a"
default = 1.0
endparam
float param b
caption = "Parameter b"
default = 1.0
visible = @numpar == "2"
endparam
param in_out
caption = "Inside/outside/etc."
enum = "Inside" "Outside" "Either" "Show inside shape" "Show outside shape"
; enum = "Inside" "Outside" "Either" "Change" "Same" \
; "In->In" "In->Out" "Out->In" "Out->Out" "Show shape"
default = 2
visible = !@Basic
endparam
bool param invert ; moved to Color by Distance
caption = "Use reciprocal?"
default = false
visible = @version < 240224
endparam
}
class JLB_CD101(CD1) {
public:
float func Iterate(complex zz)
float d = (c2-a*x)^2 - a^2*c2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD101 Arachnea"
}
class JLB_CD102(CD1) {
public:
float func Iterate(complex zz)
float d = x2*(a*x2-y2)^2 - y2*c2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD102 Arcs of Samothrace"
}
class JLB_CD103(CD1) {
public:
float func Iterate(complex zz)
float d = (a*x2+y)^2 + x2*(x2-1)
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD103 Besace"
}
class JLB_CD104(CD1) {
public:
float func Iterate(complex zz)
float d = y2*(a-x2) - (x2+2*a*y-a^2)^2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD104 Bicorn"
}
class JLB_CD105(CD1) {
public:
float func Iterate(complex zz)
float d = (x2-a^2)*(x-a)^2 + (y2-a)^2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD105 Bicuspid"
}
class JLB_CD106(CD1) {
public:
float func Iterate(complex zz)
float d = x2*x2 + y2*y2 - a*x*y2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD106 Bifoliate"
}
class JLB_CD107(CD1) {
public:
float func Iterate(complex zz)
float d = (x2-a^2)*(x-a)^2 + (y2-a)^2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD107 Bow"
}
class JLB_CD108(CD1) {
public:
float func Iterate(complex zz)
float t = x2*x2*c2 - a*d2 ; fixed error - d2 was d
float d = t
if m_scale, d = d/c4/c2, endif
;$define debug
if |#pixel-1| < 1e-6
print(zz, " ", m_scale, " ", t, " ", d)
endif
return d
endfunc
default:
title = "CD108 Bow Tie"
}
class JLB_CD109(CD1) {
public:
float func Iterate(complex zz)
float d = x2^3 + y2^3 - a*x2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD109 Butterfly"
}
class JLB_CD110(CD1) {
public:
float func Iterate(complex zz)
float d = (c2-a*x)^2 - a^2*c2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD110 Cardioid"
}
class JLB_CD111(CD1) {
public:
float func Iterate(complex zz)
float d = 4*(c2-a*x)^3 - 27*a^2*c2^2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD111 Cayley's Sextic"
}
class JLB_CD112(CD1) {
public:
float func Iterate(complex zz)
float d = x*c2 - a*y2
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD112 Cissoid of Diocles"
}
class JLB_CD113(CD1) {
public:
float func Iterate(complex zz)
float d = c2^3 + a*(3*x^4 - 6*x2*y2 - 5*y^4) + 8*a^2*y2 - 4*a^3
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD113 Cornoid"
}
class JLB_CD114(CD1) {
public:
float func Iterate(complex zz)
float d = c2^2 + 8*a*x*(x2-3*y2) + 18*a^2*c2 - 27*a^4
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD114 Deltoid"
}
class JLB_CD115(CD1) {
public:
float func Iterate(complex zz)
float d = c2^3 - a*x2
if m_scale, d = d/c4/c2, endif ; curve 2 had d/c3/c3, wrong
return d
endfunc
default:
title = "CD115 Dipole"
}
class JLB_CD116(CD1) {
public:
float func Iterate(complex zz)
float d = c2^2 - a*x^3
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD116 Egg of Kepler"
}
class JLB_CD117(CD1) {
public:
float func Iterate(complex zz)
float d = x^4 - a*d2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD117 Eight"
}
class JLB_CD117a(CD1) {
public: ; added 240308
float func Iterate(complex zz)
float d = y2 - a*(x^3 + x)
if m_scale, d = d/c1/c2, endif
return d
endfunc
default:
title = "CD117a Elliptic 1a"
}
class JLB_CD117b(CD1) {
public: ; added 240308
float func Iterate(complex zz)
float d = y2 - (x^3 + a*x)
if m_scale, d = d/c1/c2, endif
return d
endfunc
default:
title = "CD117b Elliptic 1b"
}
class JLB_CD117c(CD1) {
public: ; added 240308
float func Iterate(complex zz)
float d = y2 - (a*x^3 + x)
if m_scale, d = d/c1/c2, endif
return d
endfunc
default:
title = "CD117b Elliptic 1c"
}
class JLB_CD118(CD1) {
public:
float func Iterate(complex zz)
float d = x^3 + y^3 - 3*a*x*y
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD118 Folium of Descartes"
}
class JLB_CD119(CD1) {
public:
float func Iterate(complex zz)
float d = c2*(2*c2-a)^2 - a^2*x2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD119 Folium of Durer"
}
class JLB_CD120(CD1) {
public:
float func Iterate(complex zz)
float d = (x2+y2-a)^3 - x2*y2*y
if m_scale, d = d/c3/c3, endif
return d
endfunc
default:
title = "CD120 Heart"
}
class JLB_CD121(CD1) {
public:
float func Iterate(complex zz)
float d = x2*(x-y) + a
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD121 Heat Capacity"
}
class JLB_CD122(CD1) {
public:
float func Iterate(complex zz)
float d = x^3 - 3*x*y2 - a
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD122 Humbert's Cubic"
}
class JLB_CD123(CD1) {
public:
float func Iterate(complex zz)
float d = x2 - a*y2
if m_scale, d = d/c2, endif
return d
endfunc
default:
title = "CD123 Hyperbola"
}
class JLB_CD124(CD1) {
public:
float func Iterate(complex zz)
float d = x^4 - a*c2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD124 Kampyle of Eudoxus"
}
class JLB_CD125(CD1) {
public:
float func Iterate(complex zz)
float d = x2*c2 - a*y2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD125 Kappa"
}
class JLB_CD126(CD1) {
public:
float func Iterate(complex zz)
float d = c2^3 - a*x*(x2-3*y2)
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD126 Kiepert"
}
class JLB_CD127(CD1) {
public:
float func Iterate(complex zz)
float d = a^2*y2 - (a-x2)^3
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD127 Kiss"
}
class JLB_CD128(CD1) {
public:
float func Iterate(complex zz)
float d = (x2-a)^2 - y2*(3*a+2*y)
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD128 Knot"
}
class JLB_CD129(CD1) {
public:
float func Iterate(complex zz)
float d = x2*y2 - a*(a-y2)
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD129 Lemniscate of Bernoulli"
}
class JLB_CD130(CD1) {
public:
float func Iterate(complex zz)
float d = x*y*d2 - a*c2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD130 Maltese Cross"
}
class JLB_CD131(CD1) {
public:
float func Iterate(complex zz)
float d = c2*(x*2+y2-a)^2 - 4*a*(c2-a*x)^2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD131 Nephroid of Freeth"
}
class JLB_CD132(CD1) {
public:
float func Iterate(complex zz)
float d = y - a*x2
if m_scale, d = d/c2, endif
return d
endfunc
default:
title = "CD132 Parabola"
}
class JLB_CD133(CD1) {
public:
float func Iterate(complex zz)
float d = c2^3 - a*x2*y2
if m_scale, d = d/c2/c4, endif
return d
endfunc
default:
title = "CD133 Quadrifolium"
}
class JLB_CD134(CD1) {
public:
float func Iterate(complex zz)
float d = x*c2 - a*d2
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD134 Right Strophoid"
}
class JLB_CD135(CD1) {
public:
float func Iterate(complex zz)
float d = y2 - a*x*x2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD135 Semicubical Parabola"
}
class JLB_CD136(CD1) {
public:
float func Iterate(complex zz)
float d = c2*(c2-a*y)^2 - x2*d2^2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD136 Sextic"
}
class JLB_CD137(CD1) {
public:
float func Iterate(complex zz)
float d = c2^2 - a*x*d2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD137 Torpedo"
}
class JLB_CD138(CD1) {
public:
float func Iterate(complex zz)
float d = (c2-a)^2 - x2*c2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD138 Trisectrix of Delange"
}
class JLB_CD139(CD1) {
public:
float func Iterate(complex zz)
float d = x*(x2-3*y2) - a*c2
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD139 Trisectrix of Longchamps"
}
class JLB_CD140(CD1) {
public:
float func Iterate(complex zz)
float d = x*c2 - a*(3*x2-y2)
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD140 Trisectrix of Maclaurin"
}
class JLB_CD141(CD1) {
public:
float func Iterate(complex zz)
float d = 144*(x^4+y^4) - 225*c2 + 350*x2*y2 + 81*a
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD141 Trott"
}
class JLB_CD142(CD1) {
public:
float func Iterate(complex zz)
float d = x*c2 - a*(x2+2*y2)
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD142 Visiera"
}
class JLB_CD143(CD1) {
public:
float func Iterate(complex zz)
float d = y^4 + a*d2 ;mathworld version
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD143 Viviani's"
}
class JLB_CD144(CD1) {
public:
float func Iterate(complex zz)
float d = x2*x2-y2*y2 + a*x*y
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD144 Wavy Cross"
}
class JLB_CD145(CD1) {
public:
float func Iterate(complex zz)
float d = x2*y + a^2*(y-a)
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD145 Witch of Agnesi"
}
class JLB_CD201(CD2) {
public:
float func Iterate(complex zz)
float d = d2^2 - a*x2 + b*y2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD201 Alain"
}
class JLB_CD202(CD2) {
public:
float func Iterate(complex zz)
float d = (y2-x2)*(x-a)*(2*x-3*a) - b*(c2-2*x)^2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD202 Ampersand"
}
class JLB_CD203(CD2) {
public:
float func Iterate(complex zz)
float d = y*(x2+a^2) - a*b*x
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD203 Anguinea"
}
class JLB_CD203a(CD2) {
public:
float func Iterate(complex zz)
float d = x^b + y^b - a^b
if m_scale, d = d/c1^b, endif
return d
endfunc
default:
title = "CD203a Astroid"
}
class JLB_CD204(CD2) {
public:
float func Iterate(complex zz)
float d = x^4*c2 - (a*x2-b)^2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD204 Atripthaloid"
}
class JLB_CD205(CD2) {
public:
float func Iterate(complex zz)
float d = c2*(c2-a*x-a*y) - b*x2*y2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD205 Beetle"
}
class JLB_CD206(CD2) {
public:
float func Iterate(complex zz)
float d = (x2-b*y)^2 - a*d2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD206 Besace"
}
class JLB_CD207(CD2) {
public:
float func Iterate(complex zz)
float d = c2^2 - (a*x+b*y)*x2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD207 Bifolium"
}
class JLB_CD208(CD2) {
public:
float func Iterate(complex zz)
float d = a^2*y2 - b^2*x*2 - x2*y2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD208 Bullet-Nose"
}
class JLB_CD209(CD2) {
public:
float func Iterate(complex zz)
float d = c2^2 - a*d2 + b^4
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD209 Cassinian Ovals"
}
class JLB_CD210(CD2) {
public:
float func Iterate(complex zz)
float d = (x-a)^2*c2 - b^2*x2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD210 Conchoid of Nicomedes"
}
class JLB_CD211(CD2) {
public:
float func Iterate(complex zz)
float d = x2*y2 - a*x2 - b*y
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD211 Cross"
}
class JLB_CD212(CD2) {
public:
float func Iterate(complex zz)
float d = a^2*y - x^3 + b*x
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD212 Cubical Parabola"
}
class JLB_CD213(CD2) {
public:
float func Iterate(complex zz)
float d = a*(x-a)*c2 - b*x2
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD213 Cubic of de Sluze"
}
class JLB_CD214(CD2) {
public:
float func Iterate(complex zz)
float d = x*c2 + (a+b)*x2 - (a-b)*y2
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD214 Curve of Cramer"
}
class JLB_CD215(CD2) {
public:
float func Iterate(complex zz)
float d = x2*c2 - (a+b)*x2*y + (a-b)^2*y/4
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD215 Double Heart"
}
class JLB_CD216(CD2) {
public:
float func Iterate(complex zz)
float d = b*y2 - x2*x2*(a-x2)
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD216 Dumbbell"
}
class JLB_CD217(CD2) {
public:
float func Iterate(complex zz)
float d = x2*y2 - (x-a)*(b-x)
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD217 Egg of Granville"
}
class JLB_CD218(CD2) {
public:
float func Iterate(complex zz)
float d = b*x2 + a*y2 - a*b ; original was a/b
; properly for an ellipse, a*2 and b*2
if m_scale, d = d/c2, endif
return d
endfunc
default:
title = "CD218 Ellipse"
}
class JLB_CD218a(CD2) {
public: ; added 240308
float func Iterate(complex zz)
float d = y2 - x^3 - a*x - b
if m_scale, d = d/c1/c2, endif
return d
endfunc
default:
title = "CD218a Elliptic 2a"
}
class JLB_CD218b(CD2) {
public: ; added 240308
float func Iterate(complex zz)
float d = y2 - b*x^3 - a*x
if m_scale, d = d/c1/c2, endif
return d
endfunc
default:
title = "CD218b Elliptic 2b"
}
class JLB_CD219(CD2) {
public:
float func Iterate(complex zz)
float d = y*(y2-a) - b*x*(x2-a)
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD219 Euler's Cubic"
}
class JLB_CD220(CD2) {
public:
float func Iterate(complex zz)
float d = c2*(x*(x-a)+y2) - b*x*y2
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD220 Folium of Kepler"
}
class JLB_CD221(CD2) {
public:
float func Iterate(complex zz)
float d = y - a*real(sin(b*x)) ; sin = @F
if m_scale, d = d/c1, endif
return d
endfunc
default:
title = "CD221 Function"
;stuff goes here
}
class JLB_CD222(CD2) {
public:
float func Iterate(complex zz)
float d = c2^2 - a*x2 - b*y2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD222 Hippopede"
}
class JLB_CD223(CD2) {
public:
float func Iterate(complex zz)
float d = (c2-a*x)^2 - b*c2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD223 Limacon of Pascal"
}
class JLB_CD224(CD2) {
public:
float func Iterate(complex zz)
float d = (c2-a)^3 - b*y2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD224 Nephroid"
}
class JLB_CD225(CD2) {
public:
float func Iterate(complex zz)
float d = x*c2 - b*x*y - a*y2
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD225 Ophiuride"
}
class JLB_CD226(CD2) {
public:
float func Iterate(complex zz)
float d = x*x2*(a-x) - b*y2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD226 Pear"
}
class JLB_CD227(CD2) {
public:
float func Iterate(complex zz)
float d = b^2*y2 + (x-a)*x^3
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD227 Piriform Quartic"
}
class JLB_CD228(CD2) {
public:
float func Iterate(complex zz)
float d = y*(x+b*y)^2 - a*x
if m_scale, d = d/c3, endif
return d
endfunc
default:
title = "CD228 Serpentine"
}
class JLB_CD229(CD2) {
public:
float func Iterate(complex zz)
float d = y2*(a^2*b-x2) - x2*(a-x)^2
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD229 Tighrope"
}
class JLB_CD230(CD2) { ; fixed - was 220, a duplicate
public:
float func Iterate(complex zz)
float d = c2^2 - a*x*(x2-b*y2)
if m_scale, d = d/c4, endif
return d
endfunc
default:
title = "CD230 Trifolium"
}
class JLB_CD231(CD2) {
public:
float func Iterate(complex zz)
float d = c2^3 - a*(b*x2-y2)^2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD231 Trisectrix of Ceva"
}
class JLB_CD232(CD2) {
public:
float func Iterate(complex zz)
float d = 4*x2*y2*c2 - a*(x2-b*y2)^2
if m_scale, d = d/c4/c2, endif
return d
endfunc
default:
title = "CD232 Windmill"
}
class JLB_UT_CD(common.ulb:UserTransform) {
public:
func JLB_UT_CD(Generic pparent)
UserTransform(pparent)
m_Dx = new @f_Dx(this)
m_Dy = new @f_Dy(this)
endfunc
func Init(complex pz)
m_Dx.Init(pz)
m_Dy.Init(pz)
endfunc
complex func Iterate(complex pz)
float x = m_Dx.Iterate(pz)
float y = m_Dy.Iterate(pz)
if @xytype == "- +" || @xytype == "- -", x = -x, endif
if @xytype == "+ -" || @xytype == "- -", y = -y, endif
pz= x+flip(y)
return pz
endfunc
private:
Distance m_Dx
Distance m_Dy
default:
rating = Recommended
title = "X and Y Distances"
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(Current is 240115.}"
visible = @version < 240115
endheading
heading
caption = "znew = +-Dx, +-flip(Dy)"
endheading
; heading
; caption = "X and Y combining"
; endheading
param xytype
caption = "Dx Dy signs"
enum = "+ +" "+ -" "- +" "- -"
default = 0
endparam
heading
endheading
Distance param f_Dx
caption = "Dx"
default = JLB_D_CD
endparam
heading
endheading
Distance param f_Dy
caption = "Dy"
default = JLB_D_CD
endparam
heading
endheading
}
class PM(common.ulb:Generic) {
; PM base class. No title, so only used for a base class.
; CombineXY as a class. Make a complex from one part of zx and one part of zy.
public:
complex func go(complex zx, complex zy)
return 1
endfunc
}
; 16 possibilities
class JLB_PRPR(PM) {
public:
complex func go(complex zx, complex zy)
return +real(zx) + flip(real(zy))
endfunc
default:
title = "+r+r"
}
class JLB_PRMR(PM) {
public:
complex func go(complex zx, complex zy)
return +real(zx) - flip(real(zy))
endfunc
default:
title = "+r-r"
}
class JLB_PRPI(PM) {
public:
complex func go(complex zx, complex zy)
return +real(zx) + flip(imag(zy))
endfunc
default:
title = "+r+i"
}
class JLB_PRMI(PM) {
public:
complex func go(complex zx, complex zy)
return +real(zx) - flip(imag(zy))
endfunc
default:
title = "+r-i"
}
class JLB_MRPR(PM) {
public:
complex func go(complex zx, complex zy)
return -real(zx) + flip(real(zy))
endfunc
default:
title = "-r+r"
}
class JLB_MRMR(PM) {
public:
complex func go(complex zx, complex zy)
return -real(zx) - flip(real(zy))
endfunc
default:
title = "-r-r"
}
class JLB_MRPI(PM) {
public:
complex func go(complex zx, complex zy)
return -real(zx) + flip(imag(zy))
endfunc
default:
title = "-r+i"
}
class JLB_MRMI(PM) {
public:
complex func go(complex zx, complex zy)
return -real(zx) - flip(imag(zy))
endfunc
default:
title = "-r-i"
}
class JLB_PIPR(PM) {
public:
complex func go(complex zx, complex zy)
return +imag(zx) + flip(real(zy))
endfunc
default:
title = "+i+r"
}
class JLB_PIMR(PM) {
public:
complex func go(complex zx, complex zy)
return +imag(zx) - flip(real(zy))
endfunc
default:
title = "+i-r"
}
class JLB_PIPI(PM) {
public:
complex func go(complex zx, complex zy)
return +imag(zx) + flip(imag(zy))
endfunc
default:
title = "+i+i"
}
class JLB_PIMI(PM) {
public:
complex func go(complex zx, complex zy)
return +imag(zx) - flip(imag(zy))
endfunc
default:
title = "+i-i"
}
class JLB_MIPR(PM) {
public:
complex func go(complex zx, complex zy)
return -imag(zx) + flip(real(zy))
endfunc
default:
title = "-i+r"
}
class JLB_MIMR(PM) {
public:
complex func go(complex zx, complex zy)
return -imag(zx) - flip(real(zy))
endfunc
default:
title = "-i-r"
}
class JLB_MIPI(PM) {
public:
complex func go(complex zx, complex zy)
return -imag(zx) + flip(imag(zy))
endfunc
default:
title = "-i+i"
}
class JLB_MIMI(PM) {
public:
complex func go(complex zx, complex zy)
return -imag(zx) - flip(imag(zy))
endfunc
default:
title = "-i-i"
}
class BP(common.ulb:Generic) {
; BP base class. No title, so only used for a base class.
; Given a positive float and two parameters, return a positive float.
; many possibilities!
public:
import "common.ulb"
func BP(Generic pparent)
Generic.Generic(pparent)
endfunc
float func Go(float d, float b, float p)
return d
endfunc
}
class JLB_BP00(BP) {
public:
float func Go(float d, float b, float p)
return d
endfunc
default:
title = "BP00 no change"
}
class JLB_BP01(BP) {
public:
float func Go(float d, float b, float p)
return b * d^p
endfunc
default:
title = "BP01 power"
}
class JLB_BP02(BP) {
public:
float func Go(float d, float b, float p)
return (0.5*(1-cos(b*d*#pi)))^p
endfunc
default:
title = "BP02 haversine"
}
class JLB_BP03(BP) {
public:
float func Go(float d, float b, float p)
return (tanh(b*d))^p
endfunc
default:
title = "BP03 tanh"
}
class JLB_BP99(BP) {
public:
float func Go(float d, float b, float p)
int n = round(b)
return round(n*d)/n
endfunc
default:
title = "BP99 discontinuous"
}
class JLB_UT_Formula(common.ulb:UserTransform) {
public:
import "Standard.ulb"
func JLB_UT_Formula(Generic pparent)
UserTransform(pparent)
if @hasC == "Yes"
m_Formula = new @f_Formula (this)
else
m_FormulaX = new @f_FormulaX(this)
endif
endfunc
complex func Iterate(complex pz)
; int n = 0
; while n < @nsteps
if @hasC == "Yes"
pz = m_Formula.Iterate(pz)
else
pz = m_FormulaX.Iterate(pz)
endif
; n = n + 1
; endwhile
return pz
endfunc
protected:
Formula m_Formula
FormulaX m_FormulaX
default:
title = "Formula Transform"
rating = Recommended
int param version
caption = "Version"
default = 240301
visible = @version < 240301
endparam
heading
text = "(Current is 240301.}"
visible = @version < 240301
endheading
heading
caption = "Does Formula define its own C?"
endheading
param hasC
caption = " "
enum = "Yes" "No"
default = 1
endparam
; int param nsteps
; caption = "Number of steps"
; default = 1
; min = 0
; endparam
Formula param f_Formula
caption = "Formula"
default = Standard_Mandelbrot
visible = @hasC == 0
endparam
FormulaX param f_FormulaX
caption = "FormulaX"
default = JLB_FX_Mandelbrot
visible = @hasC == 1
endparam
}
class JLB_DShapeDistance(Distance) {
; 241110 added optional final step to Two Shapes option; backward compatible
public:
func JLB_DShapeDistance(Generic pparent)
Distance(pparent)
if @version < 240607
m_dist = new @dist(this)
endif
s1 = s2 = 1
ww = @which
if ww == 1 && @how == 1
ww = 3
endif
if ww == 0 ; one shape
m_shap = new @dp_1s(this)
elseif ww == 1 ; nesting
m_shapns = new @dp_ns(this)
elseif ww == 2 ; two shapes
m_shap2a = new @dp_2a(this)
m_shap2b = new @dp_2b(this)
else;if ww == 3 ; one shape scaled
m_shap2a = new @dp_1s(this)
m_shap2b = m_shap2a
s1 = @scale1, s2 = @scale2
endif
endfunc
func Init(complex zz)
if @version < 240607
m_dist.Init(zz)
m_dist.SetParams(0, m_abs_value)
endif
int i=0, int ia=0, int ib=0 ; make compiler happy
; ignore return values, just check in/out/etc.
if ww == 0 ; one shape
m_shap.Iterate(zz, i)
elseif ww == 1 ; nesting
m_shapns.Iterate(zz, i)
elseif ww == 2 ; two shapes
m_shap2a.Iterate(zz, ia)
m_shap2b.Iterate(zz, ib)
else;if ww == 3 ; one shape scaled
m_shap2a.Iterate(s1*zz, ia)
m_shap2b.Iterate(s2*zz, ib)
endif
if ww < 2
oldval = i
else
oldval = ia + 10 * ib
endif
endfunc
float func Iterate(complex zz)
int newval
int i=0, int ia=0, int ib=0 ; make compiler happy
float r=0, float r2a=0, float r2b=0 ; make compiler happy
bool okay = false, bool okaya = false, bool okayb = false
; just showing shapes
if @show2
if ww == 0
r = m_shap.Iterate(#pixel, i)
okay = i==1
elseif ww == 1
r = m_shapns.Iterate(#pixel, i)
okay = i==1
r = 1 ; only the shape 240804
else
r2a = m_shap2a.Iterate(#pixel, ia)
r2b = m_shap2b.Iterate(#pixel, ib)
if @show_type != "#2 shape"
okaya = ia == 1
if okaya, r = r2a, endif
endif
if @show_type != "#1 shape"
okayb = ib == 1
if okayb, r = r2b, endif
endif
if @show_type == "Both" && okaya && okayb
r = Mymath.fmin(r2a, r2b)
endif
okay = okaya || okayb
endif
if okay, return r, else, return -1, endif
endif
; regular iteration
if ww == 0
r = m_shap.Iterate(zz, i)
elseif ww == 1
r = m_shapns.Iterate(zz, i)
else
r2a = abs(m_shap2a.Iterate(s1*zz, ia))
r2b = abs(m_shap2b.Iterate(s2*zz, ib))
endif
if ww < 2
newval = i
else
newval = ia + 10 * ib
endif
if @which == 0
okay = test_1s(oldval, newval, @in_out, r)
elseif @which == 1 && @how == 0
okay = test_ns(oldval, newval, @in_out1, r)
else
; in_out2 values are the same as the first 5 of in_out
int oldv = oldval % 10
int newv = newval % 10
okaya = test_1s(oldv, newv, @in_out2a, r2a)
oldv = floor(oldval / 10)
newv = floor(newval / 10)
okayb = test_1s(oldv, newv, @in_out2b, r2b)
if @how2 == "Min"
r = Mymath.fmin(r2a, r2b)
elseif @how2 == "Middle"
r = (r2a + r2b)/2
elseif @how2 == "Max"
r = Mymath.fmax(r2a, r2b)
else;if @how2 == "Difference"
r = abs(r2a - r2b)
endif
okay = okaya && okayb
endif
oldval = newval
if !okay
return -1
endif
if @version < 240607 ; this option now in Color by Distance
return m_dist.Iterate(r * zz)
endif
return r
endfunc
; testing for one whape
bool func test_1s(int oldval, int newval, int v, float &r)
bool okay = false
if v == 0 ; "Inside"
okay = newval == 1
elseif v == 1 ; "Outside"
okay = newval != 1
elseif v == 2 ; "Either"
okay = true
elseif v == 3 ; "Change"
okay = oldval != newval
elseif v == 4 ; "Same"
okay = oldval == newval
elseif v == 5 ; "In->In"
okay = (oldval==1) && (newval==1)
elseif v == 6 ; "In->Out"
okay = (oldval==1) && (newval!=1)
elseif v == 7 ; "Out->In"
okay = (oldval!=1) && (newval==1)
else;if v == 8 ; "Out->Out"
okay = (oldval!=1) && (newval!=1)
; else;if v == 9 "Show shape"
; int i
; r = m_shap.Iterate(#pixel, i)
; okay = i==1
endif
return okay
endfunc
; testing for nested whapes
bool func test_ns(int oldval, int newval, int v, float &r)
bool okay = false
if v == 0 ; "Inner"
okay = newval == 0
elseif v == 1 ; "Middle"
okay = newval == 1
elseif v == 2 ; "Outer"
okay = newval == 2
elseif v == 3 ; "Any"
okay = true
elseif v == 4 ; "Change"
okay = oldval != newval
elseif v == 5 ; "Same"
okay = oldval == newval
elseif v == 6 ; "Inwards"
okay = oldval > newval
else;if v == 7 ; "Outwards"
okay = oldval < newval
; else;if v == 8 "Show shape"
; int i
; r = m_shapns.Iterate(#pixel, i)
; okay = i==1
endif
return okay
endfunc
protected:
Distance m_dist
DistancePlus m_shap
DistancePlus2 m_shapns
DistancePlus m_shap2a
DistancePlus m_shap2b
DistancePlus m_ns
int oldval
int ww
float s1, float s2
default:
title = "Shape Distance"
rating = Recommended
int param version
caption = "Version"
default = 240805
visible = @version < 240805
endparam
heading
text = "(current is 240805.}"
visible = @version < 240805
endheading
param which
caption = "Which"
enum = "One shape" "Two - same" "Two - different"
default = 0
endparam
param how
caption = " How"
enum = "Nesting" "Z-scale"
default = 0
visible = @which == 1
endparam
float param scale1
caption = "Scale factor #1"
default = 1
visible = @which == 1 && @how == 1
endparam
float param scale2
caption = "Scale factor #2"
default = 2
visible = @which == 1 && @how == 1
endparam
bool param show2
caption = "Show shape(s)?"
default = false
endparam
param in_out
caption = "In/Out/etc."
enum = "Inside" "Outside" "Either" "Change" "Same" \
"In->In" "In->Out" "Out->In" "Out->Out"; "Show shape"
default = 2
visible = @which == 0 && !@show2
endparam
param in_out1
caption = "Inner/Outer/etc."
enum = "Inner" "Middle" "Outer" "Any" "Change" "Same" \
"Inwards" "Outwards" ;"Show shape"
default = 3
visible = (@which == 1 && @how == 0) && !@show2
endparam
param show_type
caption = "Show"
enum = "#1 shape" "#2 shape" "Both"
default = 2
visible = @which == 2 && @show2
endparam
param in_out2a
caption = "#1 In/Out/etc."
enum = "Inside" "Outside" "Either" "Change" "Same"
default = 2
visible = (@which == 2 || (@which==1 && @how==1)) && !@show2
endparam
param in_out2b
caption = "#2 In/Out/etc."
enum = "Inside" "Outside" "Either" "Change" "Same"
default = 2
visible = (@which == 2 || (@which==1 && @how==1)) && !@show2
endparam
param how2
caption = "Which distance?"
enum = "Min" "Middle" "Max" "Difference"
default = 0
visible = (@which == 2 || (@which==1 && @how==1)) && !@show2
endparam
DistancePlus param dp_1s
caption = "Shape"
default = JLB_DP_CE
visible = @which == 0 || (@which == 1 && @how == 1)
endparam
DistancePlus2 param dp_ns
caption = "Shape for nesting"
default = JLB_DP2_NS
selectable = false
visible = @which == 1 && @how == 0
endparam
DistancePlus param dp_2a
caption = "Shape #1"
default = JLB_DP_CE
visible = @which == 2
endparam
DistancePlus param dp_2b
caption = "Shape #2"
default = JLB_DP_SR
visible = @which == 2
endparam
heading
endheading
Distance param dist
default = JLB_D_SD
selectable = false
visible = !@show2 && @version < 240607
endparam
}
; Circle/Ellipse DP
class JLB_DP_CE(DistancePlus) {
public:
func JLB_DP_CE(Generic pparent)
Generic.Generic(pparent)
if @screen_center, ctr = #center, else, ctr = @center, endif
float ang = @angle*#pi/180
rot = cos(ang) + flip(sin(ang))
if @type == "Circle" || @standard
px = py = pxy = @p
else
px = @qx, py = @qy, pxy = (px+py)/2 ; sqrt(px*py) ?
endif
if @type == "Circle"
h = v = scale = @r
else;if @type == "Ellipse"
h = abs(real(@hvE)), v = abs(imag(@hvE))
; h = @hE, v = @vE
scale = (h + v)/2 ; maybe max(h,v)
endif
SetCenter(ctr)
SetRotation(rot)
SetScale(scale)
endfunc
float func Iterate(complex zz, int &i)
float r
bool inside = IsInsideCE(rot*(zz-ctr), r)
i = 0
if inside, i = 1, endif
return r
endfunc
bool func IsInsideCE(complex zz, float &r)
; calling function rotates and shifts zz
float x = abs(real(zz))
float y = abs(imag(zz))
r= ( (x/h)^px + (y/v)^py ) ^ (1/pxy)
bool v = r <= 1
r = abs(1-r) * scale ; Simple Shapes didn't do this.
return v
endfunc
func ScaleShape(float f)
hsave = h, vsave = v
h = h*f, v = v*f
endfunc
func unScaleShape( )
h = hsave, v = vsave
endfunc
protected:
complex ctr
complex rot
float h, float v
float hsave, float vsave
float px, float py, float pxy
float scale
default:
title = "Circle/Ellipse"
rating = Recommended
int param version
caption = "Version"
default = 240303
visible = @version < 240303
endparam
heading
text = "(Current is 240303.}"
visible = @version < 240303
endheading
param type
caption = "Shape type"
enum = "Circle" "Ellipse"
default = 0
endparam
bool param screen_center
caption = "Use screen center for shape center?"
default = true
;visible = !(@type == 2 && !@equi)
endparam
param center
caption = "Shape center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Shape rotation angle"
default = 0
endparam
bool param standard
caption = "Standard?"
default = true
visible = @type == 1
endparam
float param p
caption = "Shape power"
default = 2
min = 0
visible = @type == 0 || (@type == 1 && @standard)
endparam
float param qx
caption = "X shape power"
default = 2
min = 0.2
visible = @type == 1 && !@standard
endparam
float param qy
caption = "Y shape power"
default = 2
min = 0.2
visible = @type == 1 && !@standard
endparam
float param r
caption = "Radius"
default = 1
min = 0
visible = @type == 0
endparam
complex param hvE
caption = "Shape"
default = (2,1)
;min = 0
visible = @type == 1
endparam
}
; Triangle DP
class JLB_DP_T(DistancePlus) {
public:
func JLB_DP_T(Generic pparent)
Generic.Generic(pparent)
if @screen_center, ctr = #center, else, ctr = @center, endif
float ang = @angle*#pi/180
rot = cos(ang) + flip(sin(ang))
complex v1, complex v2, complex v3
if @equi
v1 = flip(2*@Tside/3)
complex rrot = cos(#pi*2/3) + flip(sin(#pi*2/3))
v2 = v1 * rrot
v3 = v2 * rrot
v1 = v1 + ctr, v2 = v2 + ctr, v3 = v3 + ctr
else
v1 = @vt1, v2 = @vt2, v3 = @vt3
endif
; scale = DistanceToCircumCenter(cabs(v1-v2), cabs(v2-v3), cabs(v3-v1))
;scale = ( cabs(v1-v2) + cabs(v2-v3) + cabs(v3-v1) ) / 3
ctr = ( v1 + v2 + v3 ) / 3 + @center
v1r = ctr + conj(rot)*(v1-ctr)
v2r = ctr + conj(rot)*(v2-ctr)
v3r = ctr + conj(rot)*(v3-ctr)
SetCenter(ctr)
SetRotation(rot)
SetScale(Geometry.DistanceToCircumCenter(cabs(v1-v2), cabs(v2-v3), cabs(v3-v1)))
endfunc
float func Iterate(complex zz, int &i)
float r
bool inside = IsInsideT(zz, r)
i = 0
if inside, i = 1, endif
return r
endfunc
bool func IsInsideT(complex zz, float &r)
; zz is not rotated and shifted
complex v = Geometry.ClosestPointToFigure(zz, 3, v1r, v2r, v3r, v3r)
r = cabs(v)
return Geometry.PointInTriangle(zz, v1r, v2r, v3r)
endfunc
func ScaleShape(float f)
v1rsave = v1r, v2rsave = v2r, v3rsave = v3r
v1r = ctr + f*(v1r-ctr), v2r = ctr + f*(v2r-ctr)
v3r = ctr + f*(v3r-ctr)
endfunc
func unScaleShape( )
v1r = v1rsave, v2r = v2rsave, v3r = v3rsave
endfunc
protected:
complex ctr
complex rot
complex v1r, complex v2r, complex v3r
complex v1rsave, complex v2rsave, complex v3rsave
default:
title = "Triangle"
rating = Recommended
int param version
caption = "Version"
default = 240303
visible = @version < 240303
endparam
heading
text = "(current is 240303.}"
visible = @version < 240303
endheading
bool param screen_center
caption = "Use screen center for shape center?"
default = true
;visible = !(@type == 2 && !@equi)
endparam
param center
caption = "Shape center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Shape rotation angle"
default = 0
endparam
bool param equi
caption = "Equilateral triangle?"
default = true
endparam
float param Tside
caption = "Side length"
default = 2.0
min = 0
visible = @equi
endparam
; non-equilateral stuff
complex param vt1
caption = "Vertex 1"
default = (0,0)
visible = !@equi
endparam
complex param vt2
caption = "Vertex 2"
default = (1,0)
visible = !@equi
endparam
complex param vt3
caption = "Vertex 3"
default = (0,1)
visible = !@equi
endparam
}
; Square/Rectangle DP
class JLB_DP_SR(DistancePlus) {
public:
func JLB_DP_SR(Generic pparent)
Generic.Generic(pparent)
if @screen_center, ctr = #center, else, ctr = @center, endif
float ang = @angle*#pi/180
rot = cos(ang) + flip(sin(ang))
complex v1, complex v2, complex v3, complex v4
if @type == "Square"
h = v = 0.5 * @Sside
else
h = 0.5 * @hR, v = 0.5 * @vR
endif
complex v1 = ctr + h + flip(v) ; upper right corner
complex v2 = ctr + h - flip(v) ; lower right corner
complex v3 = ctr - h - flip(v) ; lower left corner
complex v4 = ctr - h + flip(v) ; upper left corner
v1r = ctr + conj(rot)*(v1-ctr)
v2r = ctr + conj(rot)*(v2-ctr)
v3r = ctr + conj(rot)*(v3-ctr)
v4r = ctr + conj(rot)*(v4-ctr)
SetCenter(ctr)
SetRotation(rot)
SetScale(sqrt(h*h+v*v)/2) ; half the diagonal
endfunc
float func Iterate(complex zz, int &i)
float r
bool inside = IsInsideSR(zz, r)
i = 0
if inside, i = 1, endif
return r
endfunc
bool func IsInsideSR(complex zz, float &r)
; check both triangles
complex p = Geometry.ClosestPointToFigure(zz, 4, v1r, v2r, v3r, v4r)
r = cabs(p)
return Geometry.PointInTriangle(zz, v1r, v2r, v3r) || \
Geometry.PointInTriangle(zz, v3r, v4r, v1r)
endfunc
func ScaleShape(float f)
v1rsave = v1r, v2rsave = v2r, v3rsave = v3r, v4rsave = v4r
v1r = ctr + f*(v1r-ctr), v2r = ctr + f*(v2r-ctr)
v3r = ctr + f*(v3r-ctr), v4r = ctr + f*(v4r-ctr)
endfunc
func unScaleShape( )
v1r = v1rsave, v2r = v2rsave, v3r = v3rsave, v4r = v4rsave
endfunc
protected:
complex ctr
complex rot
float h, float v
complex v1r, complex v2r, complex v3r, complex v4r
complex v1rsave, complex v2rsave, complex v3rsave, complex v4rsave
default:
title = "Square/Rectangle"
rating = Recommended
int param version
caption = "Version"
default = 240303
visible = @version < 240303
endparam
heading
text = "(current is 240303.}"
visible = @version < 240303
endheading
param type
caption = "Shape type"
enum = "Square" "Rectangle"
default = 0
endparam
bool param screen_center
caption = "Use screen center for shape center?"
default = true
endparam
param center
caption = "Shape center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Shape rotation angle"
default = 0
endparam
float param Sside
caption = "Side length"
default = 2.0
min = 0
visible = @type == 0
endparam
float param hR
caption = "Rectangle X length"
default = 2
min = 0
visible = @type == 1
endparam
float param vR
caption = "Rectangle Y length"
default = 1
min = 0
visible = @type == 1
endparam
}
; Angle DP
class JLB_DP_A(DistancePlus) {
public:
func JLB_DP_A(Generic pparent)
Generic.Generic(pparent)
if @screen_center, ctr = #center, else, ctr = @center, endif
w = @width
endfunc
float func Iterate(complex zz, int &i)
float r
bool inside = IsInsideA(zz, r)
i = 0
if inside, i = 1, endif
return r
endfunc
bool func IsInsideA(complex zz, float &r)
float d = atan2(zz-ctr)*180/#pi ; range -180 to +180
if d < 0, d = d + 360, endif ; range 0 to 360
float spacing = 360/@mult
float b = d - @ref_angle
b = b - spacing * round(b/spacing)
b = abs(b)
b = MyMath.fmin(b, spacing-b)
r = b / (0.5 * w)
return r <= 1
endfunc
func ScaleShape(float f)
wsave = w
w = w*f
endfunc
func unScaleShape( )
w = wsave
endfunc
protected:
complex ctr
float w
float wsave
default:
title = "Angle"
rating = Recommended
int param version
caption = "Version"
default = 240607
visible = @version < 240607
endparam
heading
text = "(current is 240607.}"
visible = @version < 240607
endheading
bool param screen_center
caption = "Use screen center for shape center?"
default = true
;visible = !(@type == 2 && !@equi)
endparam
param center
caption = "Shape center"
default = (0,0)
visible = !@screen_center
endparam
heading
text = "(All in degrees)"
endheading
float param ref_angle
caption = "Reference angle"
min = 0
max = 360
default = 0
endparam
int param mult
caption = "Multiplicity"
min = 1
default = 3
endparam
float param width
caption = "Width"
min = 0
max = 360
default = 45
endparam
}
; nested shapes
class JLB_DP2_NS(DistancePlus2) {
public:
func JLB_DP2_NS(Generic pparent)
Generic.Generic(pparent)
if @version < 240810 ; allow any shape
m_shap = new @dp(this)
else ; only the ones that can nest
if @shape == 0
m_shap = new JLB_DP_CE(this)
elseif @shape == 1
m_shap = new JLB_DP_SR(this)
else
m_shap = new JLB_DP_T(this)
endif
endif
s1 = MyMath.fmin(@scale1, @scale2)
s2 = MyMath.fmax(@scale1, @scale2)
endfunc
float func Iterate(complex zz, int &i)
float r1 = 1e30, float r2
int i1 = 0, int i2
; inner shape
bool inside1 = false
if s1 > 0
m_shap.ScaleShape(s1)
r1 = m_shap.Iterate(zz, i1)
inside1 = (i1 == 1)
m_shap.unScaleShape( )
endif
; outer shape
m_shap.ScaleShape(s2)
r2 = m_shap.Iterate(zz, i2)
bool inside2 = (i2 == 1)
m_shap.unScaleShape( )
i = 0
if inside1 ; inner
i = 0
elseif !inside1 && inside2 ; middle
i = 1
else;if !inside1 && !inside2 ; outer
i = 2
endif
return MyMath.fmin(r1, r2)
endfunc
protected:
DistancePlus m_shap
float s1, float s2
default:
title = "Nested shapes"
rating = Recommended
int param version
caption = "Version"
default = 240810
visible = @version < 240810
endparam
heading
text = "(current is 240810.}"
visible = @version < 240810
endheading
DistancePlus param dp
caption = "Plug-in"
default = JLB_DP_CE
visible = @version < 240810
endparam
param shape
enum = "Circle/Ellipse" "Square/Rectangle" "Triangle"
default = 0
visible = @version >= 240810
endparam
float param scale1
caption = "Inner scaling"
default = 1
min = 0
endparam
float param scale2
caption = "Outer scaling"
default = 2
min = 0
endparam
heading
text = "reversing scales"
visible = @scale1 > @scale2
endheading
}
class JLB_DP_CD(DistancePlus){
; Color by Distance plug-in using Curves--CD10x, etc.
public:
func JLB_DP_CD(Generic pparent)
DistancePlus(pparent)
if @numpar == "1"
m_CD1 = new @d_CD1(this)
m_CD1.SetAB(@a, 1)
m_CD1.SetScale(@scale)
else
m_CD2 = new @d_CD2(this)
m_CD2.SetAB(@a, @b) ;
m_CD2.SetScale(@scale)
endif
if @screen_center, ctr = #center, else, ctr = @center, endif
float ang = @angle*#pi/180
rot = cos(ang) + flip(sin(ang))
scale = 1
SetCenter(ctr)
SetRotation(rot)
SetScale(scale)
endfunc
float func Iterate(complex zz, int &i)
zz = scale * zz
float r
bool inside = IsInsideC(rot*(zz-ctr), r)
i = 0
if inside, i = 1, endif
return r
endfunc
bool func IsInsideC(complex zz, float &r)
; calling function rotates and shifts zz
if @numpar == "1"
m_CD1.SetAll(zz, @exch)
r = m_CD1.Iterate(zz)
else
m_CD2.SetAll(zz, @exch)
r = m_CD2.Iterate(zz)
endif
bool v = r < @bdry
r = abs(r)
return v
endfunc
func ScaleShape(float f)
scale = f
endfunc
func unScaleShape( )
scale = 1
endfunc
protected:
CD1 m_CD1
CD2 m_CD2
complex ctr
complex rot
float scale ; for Nested Shapes
default:
title = "Curve"
rating = Recommended
int param version
caption = "Version"
default = 240314
visible = @version < 240314
endparam
heading
text = "(Current is 240314.)"
visible = @version < 240314
endheading
; heading
; text = "Scaling is often useful, as is Mandelbrot smoothing."
; endheading
bool param screen_center
caption = "Use screen center for shape center?"
default = true
;visible = !(@type == 2 && !@equi)
endparam
param center
caption = "Shape center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Shape rotation angle"
default = 0
endparam
float param bdry
caption = "In/Out boundary"
default = 0
endparam
param numpar
caption = "# parameters"
enum = "1" "2"
default = 0
endparam
CD1 param d_CD1
caption = "Curve"
default = JLB_CD101
visible = @numpar == "1"
endparam
CD2 param d_CD2
caption = "Curve"
default = JLB_CD201
visible = @numpar == "2"
endparam
bool param exch
caption = "Exchange x and y?"
default = false
visible = (@numpar == "1" \
&& @d_CD1 != JLB_CD118 \
&& @d_CD1 != JLB_CD133 \
&& @d_CD1 != JLB_CD141 ) || \
(@numpar == "2" \
&& @d_CD2 != JLB_CD203a \
&& @d_CD2 != JLB_CD205 \
&& @d_CD2 != JLB_CD232)
; Folium of Descartes, Quadrifolium, Trott
; Astroid, Beetle, Windmill
endparam
bool param scale
caption = "Scale?"
default = true
endparam
float param a
caption = "Parameter a"
default = 1.0
endparam
float param b
caption = "Parameter b"
default = 1.0
visible = @numpar == "2"
endparam
}
class JLB_DP_Trap(DistancePlus){
; a plug-in for Color by Distance using Trap plug-ins
public:
import "common.ulb"
import "standard.ulb"
func JLB_DP_Trap(Generic pparent)
DistancePlus(pparent)
m_T = new @shape(this)
if @screen_center, ctr = #center, else, ctr = @center, endif
float ang = @angle*#pi/180
rot = cos(ang) + flip(sin(ang))
scale = 1
SetCenter(ctr)
SetRotation(rot)
;SetScale(scale)
endfunc
float func Iterate(complex zz, int &i)
;scale = GetScale( )
zz = scale * zz
float r
bool inside = IsInsideC(rot*(zz-ctr), r)
i = 0
if inside, i = 1, endif
return r
endfunc
bool func IsInsideC(complex zz, float &r)
; calling function rotates and shifts zz
if @exch, zz = flip(zz), endif
r = m_T.Iterate(zz)
bool v = r < @bdry
r = abs(r)
return v
endfunc
func ScaleShape(float f)
scale = f
endfunc
func unScaleShape( )
scale = 1
endfunc
protected:
TrapShape m_T
complex ctr
complex rot
float scale ; for Nested Shapes
default:
title = "Trap"
rating = Recommended
int param version
caption = "Version"
default = 240804
visible = @version < 240804
endparam
heading
text = "(Current is 240804.)"
visible = @version < 240804
endheading
bool param screen_center
caption = "Use screen center for shape center?"
default = true
endparam
param center
caption = "Shape center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Shape rotation angle"
default = 0
endparam
float param bdry
caption = "Boundary"
default = 0
endparam
TrapShape param shape
caption = "Trap Shape"
default = Standard_TrapShapeHeart
endparam
bool param exch
caption = "Exchange x and y?"
default = false
endparam
}
class JLB_DCiliaPlus(Distance){
; A generalized version of dmj-cilia in dmj.ucl
public:
func JLB_DCiliaPlus(Generic pparent)
Distance(pparent)
if @t1 == "Distance"
m_SD1 = new @d_SD1(this)
endif
if @t2 == "Distance"
m_SD2 = new @d_SD2(this)
endif
endfunc
func Init(complex zz)
if @t1 == "Distance"
if (@d_SD1 == JLB_D00 || @d_SD1 == JLB_D01)
m_SD1.SetFactor(@divisor1)
endif
m_SD1.SD_Set(0, 0) ; initial path length = 0 - no path yet
m_SD1.SetScale(true)
endif
if @t2 == "Distance"
if (@d_SD2 == JLB_D00 || @d_SD2 == JLB_D01)
m_SD2.SetFactor(@divisor2)
endif
m_SD2.SD_Set(0, 0) ; initial path length = 0 - no path yet
m_SD2.SetScale(true)
endif
if @t1 == 0 || @t2 == 0
il = real(1/log(@pow))
lp = log(log(@Top))
endif
endfunc
float func Iterate(complex zz)
complex z0 = zz
float d = Go(zz, z0, @t1, 1) ; names d and f are left over from dmj-cilia
float f = Go(zz, z0, @t2, 2)
if d < 0 ; negative only if log used and cabs(z) > @Top
d = fixup(d)
endif
if f < 0
f = fixup(f)
endif
if d < 0 || f < 0
return -1
endif
; apply skew
d = d + @skew*f ; dmj suggests half-integers
d = d - floor(d)
; All these take two numbers, d and f, each in 0..1, and procudes
; an index also in 0..1
; At end, with d in 0..1, can use d, 1-d, abs(1-2*d), or 1-abs(1-2*d)
float d1, float d2
if (@ciliatype == 0) ; sawtooth
if (d < 0.5)
d = d * (f+1) ; 0..1
else
d = (d-0.5) * (f+1) - f/2 + 0.5
;d = d * (f+1) - f ; 0..1
endif
d = Xform(d, @V)
elseif (@ciliatype == 1) ; interpolated
d1 = Xform(d, @V1)
d = @fac*d
d = d - floor(d)
d2 = Xform(d, @V2)
d = d1 + f*(d2-d1) ; = d1*(1-f) + d2*f
d = Xform(d, @V)
elseif (@ciliatype == 2) ; sine waves
float a1 = 2 * #pi * d
float a2 = 2 * #pi * d * @fac
if @type == "cos cos" || @type == "cos sin"
d1 = (1 + cos(a1)) / 2
else
d1 = (1 + sin(a1)) / 2
endif
if @type == "cos cos" || @type == "sin cos"
d2 = (1 + cos(a2)) / 2
else
d2 = (1 + sin(a2)) / 2
endif
d = d1 + f*(d2-d1) ; = d1*(1-f) + d2*f
d = Xform(d, @V)
elseif (@ciliatype == 3) ; cells
d = ((0.25-sqr(d-0.5)) * (0.25-sqr(f-0.5))) * 16
d = Xform(d, @V)
elseif (@ciliatype == 4) ; bricks
d1 = Xform(d, @V)
d2 = Xform(f, @V)
if @Use == 0
d = MyMath.Fmin(d1, d2)
else
d = MyMath.Fmax(d1, d2)
endif
elseif (@ciliatype == 5) ; diamonds
d = 0.5 - abs(d - 0.5) ; 0..0.5 hat shape
float v = @vv ; original v = 2/3
if (f < v)
d = d + f/(2*v) ; 0..1
;d = abs(1-2*d) ; optional, but smoother for one case
else
if (d < f/(2*v)-0.5)
d = f*(2/v)-2-4*d
else
d = 1-(0.5-d)/(1-f/(2*v))
endif
endif
d = Xform(d, @V)
elseif (@ciliatype == 6) ; Simple
if @s_type == "d#1"
;
elseif @s_type == "d#2"
d = f
elseif @s_type == "Arithmetic Average"
d = (d + f) / 2
elseif @s_type == "Geometric Average"
d = sqrt(d * f)
elseif @s_type == "Harmonic Average"
d = 2 * d * f / (d + f)
d = MyMath.fmax(d, f)
elseif @s_type == "Min"
d = MyMath.fmin(d, f)
elseif @s_type == "Difference"
d = abs(d - f)
elseif @s_type == "Product"
d = d * f
endif
d = Xform(d, @V)
endif
return d
endfunc
float func fixup(float d) ; guaranteed d > 0
if @bigZ == "No"
return -1
elseif @bigZ == "Floor"
return d - floor(d)
else
return abs(d) - floor(abs(d))
endif
endfunc
float func Xform(float d, int v)
if v == 1
d = 1 - d
elseif v == 2
d = abs(1-2*d)
elseif v == 3
d = 1 - abs(1-2*d)
endif
return d
endfunc
; Go returns a value in 0..1
float func Go(complex zz, complex z0, int t, int i)
; zz is the latest, z0 may be a previous one
float v = -1
if t == 0 ; "LogLog"
v = real(il*(lp - log(log(cabs(zz))))) ; fractional iteration
elseif t == 1 ; "Log"
v = log(@Top/cabs(zz))
elseif t == 2 ; "Angle"
v = atan2(z0)/(2*#pi)
if (v <= 0)
v = v + 1
endif ; v in 0..1
else; ; "Distance"
if i == 1
v = m_SD1.Iterate(z0)
else
v = m_SD2.Iterate(z0)
endif
endif
if v == 0, v = 1, endif ; 0 not allowed
return v
endfunc
protected:
float il
float lp
; complex z1, complex z2, complex z3
SD m_SD1
SD m_SD2
default:
title = "Cilia Plus"
rating = Recommended
int param version
caption = "Version"
default = 240420
visible = @version < 240420
endparam
heading
text = "(current is 240420.}"
visible = @version < 240420
endheading
float param pow
caption = "Exponent"
default = 2
;min = 1.01
visible = @t1 == 0 || @t2 == 0
endparam
float param Top
caption = "Top"
default = 100
min = 1
visible = @t1 <= 1 || @t2 <= 1
endparam
param bigz
caption = "Use cabs(z)>Top?"
enum = "No" "Floor" "Ceiling"
default = 0
visible = @t1 <= 1 || @t2 <= 1
endparam
param t1
caption = "First d"
enum = "LogLog" "Log" "Angle" "Distance"
default = 2
endparam
SD param d_SD1
caption = "Distance 1"
default = JLB_D02
visible = @t1 == 3
endparam
param t2
caption = "Second d"
enum = "LogLog" "Log" "Angle" "Distance"
default = 0
endparam
SD param d_SD2
caption = "Distance 2"
default = JLB_D03
visible = @t2 == 3
endparam
float param divisor1
caption = "Divisor 1"
default = 1
min = 1e-6
visible = @t1 == 3 && (@d_SD1 == JLB_D00 || @d_SD1 == JLB_D01)
endparam
float param divisor2
caption = "Divisor 2"
default = 1
min = 1e-6
visible = @t1 == 3 && (@d_SD2 == JLB_D00 || @d_SD2 == JLB_D01)
endparam
param ciliatype
caption = "Cilia Type"
default = 4
enum = "Sawtooth" "Interpolated" "Sine waves" "Cells" \
"Bricks" "Diamonds" "Simple"
hint = "This is the function used to generate the \
cilia pieces. Each has a different 'flavor'."
endparam
; Interpolated
param V1
caption = "First"
enum = "V 0" "V 1" "V 2" "V 3"
default = 2
visible = @ciliatype == 1
endparam
param V2
caption = "Second"
enum = "V 0" "V 1" "V 2" "V 3"
default = 2
visible = @ciliatype == 1
endparam
; Interpolated or Sine waves
float param fac ; fac = 2 is sometimes smoother
caption = "Multiplier"
default = 2
;min = 1
visible = @ciliatype == 1 || @ciliatype == 2
endparam
; Sine waves
param type
caption = "Cos or Sin"
enum = "cos cos" "cos sin" "sin cos" "sin sin"
default = 0
visible = @ciliatype == 2
endparam
; Bricks
param Use
caption = "Use"
default = 0
enum = "Smaller d" "Larger d"
visible = @ciliatype == 4
endparam
; Diamonds
float param vv
caption = "Parameter"
default = 1
min = 0
max = 1
visible = @ciliatype == 5
endparam
; Simple
param s_type
caption = "Simple type"
enum = "d#1" "d#2" "Arithmetic Average" "Geometric Average" \
"Harmonic Average" "Max" "Min" \
"Difference" "Product"
default = 2
visible = @ciliatype == 6
endparam
param skew
caption = "Cilia Skew"
default = 0.0
endparam
param V
caption = "Final"
enum = "V 0" "V 1" "V 2" "V 3"
default = 0
endparam
}
class JLB_DfBM(Distance) { ; 240915
; this is a re-writing of, and a combination of,
; the versions in dmj.ucl and in mt.ucl
; New 240715; 240915 changed FT plug-in to UserTransform plug-in
public:
import "common.ulb"
func JLB_DfBM(Generic pparent)
Distance(pparent)
rot = (0,1) ^ (@angle / 90.0)
drot = (0,1) ^ (@astep / 90.0)
; half ranges from 4 (2^2) to 8192 (2^13)
half = round(2.0 ^ (2 + 0.11 * @spread))
whole = 2 * half
if @version < 240915
m = new @T(this)
elseif @useT
m_t = new @f_UT(this)
endif
if @screen_center, ctr = #center, else, ctr = @center, endif
endfunc
func Init(complex zz)
sum = 0
endfunc
float func Iterate(complex zz)
float decay = exp(-|zz|/sqr(@fade))
complex v = zz - ctr
if @version < 240915
v = m.Iterate(v)
elseif @useT
v = m_t.Iterate(v)
endif
v = v * @scale * rot
float freq = 1.0
int i = @octaves
while (i > 0)
float d = fbm(v)
sum = sum + d * freq * decay
freq = freq * @step
v = v * drot / @step
i = i - 1
endwhile
return abs(sum) ; abs not in dmj, but needed
endfunc
float func fbm(complex v)
; determine integer coordinate for corners of square
; surrounding v
float bx0 = floor(real(v)) % half
float by0 = floor(imag(v)) % half
if (bx0 < 0), bx0 = bx0 + half, endif
if (by0 < 0), by0 = by0 + half, endif
float bx1 = (bx0 + 1) % half
float by1 = (by0 + 1) % half
float rx0 = real(v) - floor(real(v))
float ry0 = imag(v) - floor(imag(v))
float rx1 = rx0 - 1
float ry1 = ry0 - 1
; create a "random" index for each corner
; Notes from dmj
; (this is where Intel's version differs from Perlin's;
; I used Intel's version because it doesn't require a
; pre-computed random table, which is difficult to manage
; in UF.)
if @type == "dmj"
float b00 = (bx0^@p % 65536 + by0)^@p % 65536
float b10 = (bx1^@p % 65536 + by0)^@p % 65536
float b01 = (bx0^@p % 65536 + by1)^@p % 65536
float b11 = (bx1^@p % 65536 + by1)^@p % 65536
; produce a "random" vector for each corner
float g_b00_0 = (b00 )^@p*0.25 % whole - half
float g_b10_0 = (b10 )^@p*0.25 % whole - half
float g_b01_0 = (b01 )^@p*0.25 % whole - half
float g_b11_0 = (b11 )^@p*0.25 % whole - half
float g_b00_1 = (b00+1)^@p*0.25 % whole - half
float g_b10_1 = (b10+1)^@p*0.25 % whole - half
float g_b01_1 = (b01+1)^@p*0.25 % whole - half
float g_b11_1 = (b11+1)^@p*0.25 % whole - half
else ; mt's version
float b00 = (bx0^@p * 2473 % 65536 + by0)^@p % 65536
float b01 = (bx0^@p * 2473 % 65536 + by1)^@p % 65536
float b10 = (bx1^@p * 2473 % 65536 + by0)^@p % 65536
float b11 = (bx1^@p * 2473 % 65536 + by1)^@p % 65536
float g_b00_0 = b00^@p * 5381 % 65536 / 4 % whole - half
float g_b01_0 = b01^@p * 5381 % 65536 / 4 % whole - half
float g_b10_0 = b10^@p * 5381 % 65536 / 4 % whole - half
float g_b11_0 = b11^@p * 5381 % 65536 / 4 % whole - half
float g_b00_1 = (b00 + 1)^@p * 79997 % 65536 / 4 % whole - half
float g_b01_1 = (b01 + 1)^@p * 79997 % 65536 / 4 % whole - half
float g_b10_1 = (b10 + 1)^@p * 79997 % 65536 / 4 % whole - half
float g_b11_1 = (b11 + 1)^@p * 79997 % 65536 / 4 % whole - half
endif
; normalize each vector
float d
d = 1 / sqrt(sqr(g_b00_0) + sqr(g_b00_1))
g_b00_0 = g_b00_0 * d
g_b00_1 = g_b00_1 * d
d = 1 / sqrt(sqr(g_b10_0) + sqr(g_b10_1))
g_b10_0 = g_b10_0 * d
g_b10_1 = g_b10_1 * d
d = 1 / sqrt(sqr(g_b01_0) + sqr(g_b01_1))
g_b01_0 = g_b01_0 * d
g_b01_1 = g_b01_1 * d
d = 1 / sqrt(sqr(g_b11_0) + sqr(g_b11_1))
g_b11_0 = g_b11_0 * d
g_b11_1 = g_b11_1 * d
; produce colors for each corner
float u1 = rx0 * g_b00_0 + ry0 * g_b00_1
float v1 = rx1 * g_b10_0 + ry0 * g_b10_1
float u2 = rx0 * g_b01_0 + ry1 * g_b01_1
float v2 = rx1 * g_b11_0 + ry1 * g_b11_1
; interpolate between corners using bilinear filtering
float sx = sqr(rx0) * (3 - rx0*2)
float sy = sqr(ry0) * (3 - ry0*2)
float a = u1 + sx*(v1-u1)
float b = u2 + sx*(v2-u2)
return a + sy*(b-a)
endfunc
private:
complex rot
complex drot
float sum
int half
int whole
FT m
UserTransform m_t
complex ctr
default:
title = "Fractional Brownian Motion"
rating = Recommended
int param version
caption = "Version"
default = 240915
visible = @version < 240915
endparam
heading
text = "(current is 240915.}"
visible = @version < 240915
endheading
FT param T
caption = "Function"
default = JLB_00ident
visible = @version < 240915
endparam
bool param useT
caption = "Use transform?"
default = false
visible = @version >= 240915
endparam
UserTransform param f_UT
caption = "Transform f"
default = JLB_UT_OneFunction
visible = @version >= 240915 && @useT
endparam
bool param screen_center
caption = "Use screen center?"
default = true
endparam
complex param center
caption = "Center"
default = (0,0)
visible = !@screen_center
endparam
float param scale
caption = "Scale"
default = 1.0
endparam
float param angle
caption = "Rotation"
default = 0.0
endparam
heading
endheading
param type
caption = "Noise type"
enum = "dmj" "mt"
default = 0
endparam
float param spread
caption = "Spread (0..100)"
min = 0
max = 100
default = 50
endparam
float param p
caption = "Noise power"
default = 2.0
endparam
float param fade
caption = "Fade radius"
default = 16.0
endparam
; heading
; endheading
int param octaves
caption = "# of steps"
default = 1
min = 1
endparam
float param step
caption = "Step factor"
default = 2
;min = 1
visible = @octaves > 1
endparam
float param astep
caption = "Rotation change"
default = 45
visible = @octaves > 1
endparam
}
class JLB_FX_DucksPlus(FormulaX) {
; Based on "Ducks (Julia)" by Samuel Monnier, in sam.ufm.
; Note that his reference, http://www.algorithmic-worlds.net,
; does log(z+c) and his formula does log(z)+c, which seems better.
; This formula mostly does not diverge or converge, so bailout is
; determined by the number of iterations allowed.
; Use Iterations bailout or Inside coloring.
; 240909 moved m_c outside Final power
public:
import "common.ulb"
func JLB_FX_DucksPlus(Generic pparent)
FormulaX(pparent)
f = new @Tfunc(this)
t = new @UT(this)
rot = exp(flip(@angle * #pi / 180))
delta = 2 * #pi / @order
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
complex z = rot * pz
if @order > 1
float arg = round(atan2(z)/delta) * delta
z = z * exp(flip(-arg))
endif
z = t.Iterate(z) ; maybe mess x and y
if @version < 240909
z = f.Iterate(z^@p) + m_c ; apply a function and a power
z = z ^ @q ; and an over-all power
else
z = f.Iterate(z^@p) ; apply a function and a power
z = z ^ @q +m_c ; and a final power
endif
return z
endfunc
private:
FT f
UserTransform t
complex rot
float delta
default:
title = "DucksPlus"
rating = Recommended
int param version
caption = "Version"
default = 240909
visible = @version < 240909
endparam
heading
text = "(Current is 240909.}"
visible = @version < 240909
endheading
heading
endheading
float param Angle
caption = "Angle"
default = 0
;visible = !@Basic
endparam
int param order
caption = "Symmetry order"
default = 4
min = 1
endparam
UserTransform param UT
caption = "How?"
default = JLB_UT_XY_Signs
selectable = false
endparam
FT param Tfunc
caption = "Z function"
default = JLB_01sin
endparam
float param p
caption = "Z power"
default = 1
endparam
float param q
caption = "Final power"
default = 1
endparam
}
class JLB_UT_XY_Signs(common.ulb:UserTransform) {
; experiment with signs of X and Y
public:
func JLB_UT_XY_Signs(Generic pparent)
UserTransform(pparent)
endfunc
complex func Iterate(complex pz)
float x = real(pz), float ax
float y = imag(pz), float ay
if @version < 240918 ; forgot about |x|
ax = |x|, ay = |y|
else
ax = abs(x), ay = abs(y)
endif
if @how == 1, x = x, y = -y
elseif @how == 2, x = x, y = ay
elseif @how == 3, x = x, y = -ay
elseif @how == 4, x = -x
elseif @how == 5, x = -x, y = -y
elseif @how == 6, x = -x, y = ay
elseif @how == 7, x = -x, y = -ay
elseif @how == 8, x = ax
elseif @how == 9, x = ax, y = -y
elseif @how ==10, x = ax, y = ay
elseif @how ==11, x = ax, y = -ay
elseif @how ==12, x = -ax
elseif @how ==13, x = -ax, y = -y
elseif @how ==14, x = -ax, y = ay
elseif @how ==15, x = -ax, y = -ay
endif
if @exch
return y + flip(x)
else
return x + flip(y)
endif
endfunc
default:
rating = Recommended
title = "X+Y Signs"
int param version
caption = "Version"
default = 240918
visible = @version < 240918
endparam
heading
text = "(Current is 240918.}"
visible = @version < 240918
endheading
heading
text = " Note: |x| means abs(x), |y| means abs(y)"
endheading
param how
caption = "New x,y?"
enum = "x, y" "x, -y" "x, |y|" "x, -|y|" \
"-x, y" "-x, -y" "-x, |y|" "-x, -|y|" \
"|x|, y" "|x|, -y" "|x|, |y|" "|x|, -|y|" \
"-|x|, y" "-|x|, -y" "-|x|, |y|" "-|x|, -|y|"
default = 0
endparam
bool param exch
caption = "Exchange x and y?"
default = false
endparam
}
class JLB_UT_DucksPlus(common.ulb:UserTransform) {
; Based on "Ducks (Julia)" by Samuel Monnier, in sam.ufm.
; If used in a formula, it mostly does not diverge or converge,
; so bailout is determined by the number of iterations allowed.
public:
import "common.ulb"
func JLB_UT_DucksPlus(Generic pparent)
UserTransform.UserTransform(pparent)
f = new @Tfunc(this)
t = new @UT(this)
rot = exp(flip(@angle * #pi / 180))
delta = 2 * #pi / @order
endfunc
; complex func Init(complex pz)
; FormulaX.Init(pz)
; return pz
; endfunc
complex func Iterate(complex pz)
complex z = rot * pz
if @order > 1
float arg = round(atan2(z)/delta) * delta
z = z * exp(flip(-arg))
endif
z = t.Iterate(z) ; maybe mess x and y
z = f.Iterate(z^@p) ; apply a function and a power
;z = z ^ @q ; and an over-all power
return z
endfunc
private:
FT f
UserTransform t
complex rot
float delta
default:
title = "DucksPlus Transform"
rating = Recommended
int param version
caption = "Version"
default = 240624
visible = @version < 240624
endparam
heading
text = "(Current is 240624.}"
visible = @version < 240624
endheading
float param Angle
caption = "Angle"
default = 0
;visible = !@Basic
endparam
int param order
caption = "Symmetry order"
default = 4
min = 1
endparam
UserTransform param UT
caption = "How?"
default = JLB_UT_XY_Signs
selectable = false
endparam
FT param Tfunc
caption = "Z function"
default = JLB_27log
endparam
float param p
caption = "Z power"
default = 1
endparam
; float param q
; caption = "Final power"
; default = 1
; endparam
}
class JLB_UT_Shape(common.ulb:UserTransform) {
; use the distance from the shape, and whether inside or outside,
; to get a multiplier for z
public:
func JLB_UT_Shape(Generic pparent)
UserTransform.UserTransform(pparent)
m_shap = new @dp(this)
;scale = m_shap.GetScale( )
ctr = m_shap.GetCenter( )
endfunc
complex func Iterate(complex pz)
int i
float d = m_shap.Iterate(pz, i)
; in the simplest case, the circle shape, scale = radius, and
; d = distance to the circle, includes a factor of scale
; d/scale = 1 for z at the center, 0 for z at the circle, > 0 outside
bool inside = (i==1)
if inside
if @ihow == "Decay"
d = d / (1 + d^@p)
elseif @ihow == "Do nothing"
d = 0
endif
if @neg, d = -d, endif
else
if @ohow == "Decay"
d = d / (1 + d^@p)
elseif @ohow == "Do nothing"
d = 0
endif
endif
return pz + @mult * d * (pz - ctr)
endfunc
private:
DistancePlus m_shap
;float scale
complex ctr
default:
rating = Recommended
title = "Shape Transform"
int param version
caption = "Version"
default = 240707
visible = @version < 240707
endparam
DistancePlus param dp
caption = "Shape"
default = JLB_DP_CE
;visible = @which == 0
endparam
param ihow
caption = "Inside how?"
enum = "Normal" "Decay" "Do nothing"
default = 0
endparam
bool param neg
caption = "Negate inside?"
default = false
endparam
param ohow
caption = "Outside how?"
enum = "Normal" "Decay" "Do nothing"
default = 0
endparam
complex param mult
caption = "Distance multiplier"
default = 1
endparam
float param p
caption = "Decay power"
default = 2
min = 1
visible = @ihow==1 || @ohow == 1
endparam
}
class JLB_UT_Rotate(common.ulb:UserTransform) {
; second option copied from "Self Rotation" in mmf.ulb
public:
func JLB_UT_Rotate(Generic pparent)
UserTransform.UserTransform(pparent)
if @Type == 0
rot = exp(flip(@angle * #pi / 180))
endif
endfunc
complex func Iterate(complex pz)
if @Type == 0
return pz * rot
else
return pz * (pz/cabs(pz))^@times
endif
endfunc
private:
complex rot
default:
rating = Recommended
title = "Rotation Transform"
int param version
caption = "Version"
default = 240718
visible = @version < 240718
endparam
heading
text = "(Current is 240718.}"
visible = @version < 240718
endheading
heading
caption = "z_new = z*rotation"
endheading
param Type
enum = "Fixed Angle" "Self Fraction"
default = 0
endparam
float param angle
caption = "Rotation (degrees)"
default = 15
visible = @Type == 0
endparam
float param times
caption = "Fraction"
default = 1
visible = @Type > 0
endparam
}
class JLB_UT_GnarlZ(common.ulb:UserTransform) { ; 240818
; New 240818
; A UserTransform that "gnarls" both x,y and z
public:
import "common.ulb"
func JLB_UT_GnarlZ(Generic pparent)
UserTransform.UserTransform(pparent)
m1 = new @f1(this)
if @which != "1"
m2 = new @f2(this)
if @which == "3"
m3 = new @f3(this)
endif
endif
var = @variant
if @h == 0 || @hz == 0 || @version < 240827
var = 0
endif
endfunc
complex func Iterate(complex pz)
int n = 0
while n < @nsteps
complex z1, complex z2
if var == 0
z1 = xy_iter(pz)
z2 = z_iter(pz)
pz = pz + @h*z1 + @hz*z2*z_scale(z2)
elseif var == 1
z1 = xy_iter(pz)
pz = pz + @h*z1
z2 = z_iter(pz)
pz = pz + @hz*z2*z_scale(z2)
else
z2 = z_iter(pz)
pz = pz + @hz*z2*z_scale(z2)
z1 = xy_iter(pz)
pz = pz + @h*z1
endif
n = n + 1
endwhile
return pz
endfunc
float func z_scale(complex z)
float s = 1
if @zshow != "None"
float d = cabs(z)
if @zshow == "Type 1" ; this allows z > @zmax, okay
s = (1+d*@zmax)/(1+d*d)
elseif d > @zmax
;d = exp(-(d-@zmax)^2) ; this gave bad results
s = 1 / (1 + (d-@zmax)^2) ; this seems better
endif
endif
return s
endfunc
complex func xy_iter(complex pz)
float x = real(pz)
float y = imag(pz)
complex argx = 0, complex argy = 0
; final term
if @which == "3"
argx = m3.Iterate(@b*y)
argy = m3.Iterate(@b*x)
endif
; middle term
if @which == "2" || @which == "3"
argx = m2.Iterate(@a*(y^@q+argx))
argy = m2.Iterate(@a*(x^@q+argy))
endif
; initial term
float dx = real(m1.Iterate(y^@p+argx))
float dy = real(m1.Iterate(x^@p+argy))
if @signs == "-+" || @signs == "--", dx = -dx, endif
if @signs == "+-" || @signs == "--", dy = -dy, endif
pz = dx+flip(dy)
return pz
endfunc
complex func z_iter(complex pz)
complex argz = 0
; final term
if @which == "3"
argz = m3.Iterate(@b*pz)
endif
; middle term
if @which == "2" || @which == "3"
argz = m2.Iterate(@a*(pz^@q+argz))
endif
; initial term
pz = m1.Iterate(pz^@p+argz)
return pz
endfunc
private:
UserTransform m1
UserTransform m2
UserTransform m3
int var
default:
title = "Gnarl Z"
rating = Recommended
int param version
caption = "Version"
default = 240818
visible = @version < 240818
endparam
heading
text = "(Current is 240818.}"
visible = @version < 240818
endheading
param variant
caption = "Variant"
enum = "0" "1" "2"
default = 0
visible = @h != 0 && @hz != 0 && @version >= 240818
endparam
param which
caption = "Number of funcs"
enum = "1" "2" "3"
default = 1
endparam
heading
text = " f1"
endheading
UserTransform param f1 ; caption doesn't show
default = JLB_FTransform
selectable = false
endparam
int param p
caption = " f1 power"
default = 1
endparam
heading
endheading
heading
text = " f2"
visible = @which != "1"
endheading
UserTransform param f2 ; caption doesn't show
default = JLB_FTransform
selectable = false
visible = @which != "1"
endparam
int param q
caption = " f2 power"
default = 1
visible = @which != "1"
endparam
float param a
caption = "a"
default = 2.7
visible = @which != "1"
endparam
heading
visible = @which != "1"
endheading
heading
text = " f3"
visible = @which == "3"
endheading
UserTransform param f3 ; caption doesn't show
default = JLB_FTransform
selectable = false
visible = @which == "3"
endparam
float param b
caption = "b"
default = 2.7
visible = @which == "3"
endparam
heading
visible = @which == "3"
endheading
int param nsteps
caption = "number of steps"
default = 1
min = 1
endparam
float param h
caption = "Step size"
default = 0.1
endparam
param signs
enum = "++" "-+" "+-" "--"
default = 1
visible = @h != 0
endparam
heading
endheading
float param hz
caption = "Z step size"
default = 0.01
endparam
param zshow
caption = "Scaling type"
enum = "None" "Type 1" "Type 2"
default = 1
visible = @hz != 0
endparam
float param zmax
caption = "max Z"
default = 1
min = 0
visible = @hz != 0 && @zshow > 0
endparam
}
class JLB_FX_GnarlZ(FormulaX) { ; 240818
; New 240818
; Use the Gnarl Z transform as a FormulaX
public:
import "common.ulb"
func JLB_FX_GnarlZ(Generic pparent)
Formula(pparent)
m_UT = new @f_UT(this)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
m_UT.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
return m_UT.Iterate(pz)
endfunc
protected:
UserTransform m_UT
default:
title = "Gnarl+Z"
rating = Recommended
int param version
caption = "Version"
default = 240818
visible = @version < 240818
endparam
heading
text = "(Current is 240818.}"
visible = @version < 240818
endheading
UserTransform param f_UT
caption = "Gnarl"
default = JLB_UT_GnarlZ
selectable = false
endparam
; Hide these from FormulaX, as Gnarl Z doesn't use m_c
bool param p_Mtype
visible = false ; hide it!
endparam
complex param p_seed
visible = false ; hide it!
endparam
}
class JLB_UT_OneOrTwoFunc(common.ulb:UserTransform) { ; 240903
; New 240903
; Make a UserTransform out of two functions
public:
func JLB_UT_OneOrTwoFunc(Generic pparent)
UserTransform(pparent)
if @which == "Menu"
if @exch && @howmany == "2"
m_fm = new @gm(this)
m_gm = new @fm(this)
else
m_fm = new @fm(this)
if @howmany == "2"
m_gm = new @gm(this)
endif
endif
else;if @which == "Plug-in"
if @exch && @howmany == "2"
m_fp = new @gp(this)
m_gp = new @fp(this)
else
m_fp = new @fp(this)
if @howmany == "2"
m_gp = new @gp(this)
endif
endif
endif
endfunc
complex func Iterate(complex pz)
complex t
int n = 0
while n < @nsteps
if @howmany == "1"
t = ffunc(pz)
elseif @how == "f+g"
t = ffunc(pz) + gfunc(pz)
elseif @how == "f-g"
t = ffunc(pz) - gfunc(pz)
elseif @how == "f*g"
t = ffunc(pz) * gfunc(pz)
elseif @how == "f/g"
t = ffunc(pz) / gfunc(pz)
elseif @how == "f^g"
t = ffunc(pz) ^ gfunc(pz)
else;if @how == "f(g)"
t = ffunc(gfunc(pz))
endif
t = @h*t
if @addrep == "Add", pz = pz + t, else, pz = t, endif
n = n + 1
endwhile
return pz
endfunc
complex func ffunc(complex z)
if @which == "Menu"
return m_fm.Iterate(@a*z)
else
return m_fp.Iterate(@a*z)
endif
endfunc
complex func gfunc(complex z)
if @which == "Menu"
return m_gm.Iterate(@b*z)
else
return m_gp.Iterate(@b*z)
endif
endfunc
private:
UserTransform m_fm
UserTransform m_gm
FT m_fp
FT m_gp
default:
rating = Recommended
title = "1 or 2 Functions"
int param version
caption = "Version"
default = 240903
visible = @version < 240903
endparam
heading
text = "(Current is 240903.)"
visible = @version < 240903
endheading
param which
caption = "Choose from"
enum = "Menu" "Plug-in"
default = 0
endparam
heading
endheading
param addrep
caption = "Add or Replace?"
enum = "Add" "Replace"
default = 1
endparam
; heading
; caption = "each step z = z + h*f(a*z)"
; visible = @addrep == "Add"
; endheading
; heading
; caption = "each step z = h*f(a*z)"
; visible = @addrep == "Replace"
; endheading
int param nsteps
caption = " # of steps"
default = 1
min = 1
endparam
float param h
caption = " Step size"
default = 1
endparam
heading
endheading
param howmany
caption = "1 or 2 functions?"
enum = "1" "2"
default = 1
endparam
param how
caption = "Combine"
enum = "f+g" "f-g" "f*g" "f/g" "f^g" "f(g)"
default = 5
visible = @howmany == "2"
endparam
bool param exch
caption = "Switch f and g?"
default = false
visible = @howmany == "2"
endparam
; heading
; endheading
heading
text = " f(a*z)"
visible = @which == "Menu"
endheading
UserTransform param fm ; caption doesn't show
default = JLB_FTransform
selectable = false
visible = @which == "Menu"
endparam
FT param fp
caption = " f(a*z)"
default = JLB_01sin
visible = @which == "Plug-in"
endparam
complex param a
caption = "a"
default = (1,0)
endparam
heading
text = " g(b*z)"
visible = @which == "Menu" && @howmany == "2"
endheading
UserTransform param gm ; caption doesn't show
default = JLB_FTransform
selectable = false
visible = @which == "Menu" && @howmany == "2"
endparam
FT param gp
caption = " g(b*z)"
default = JLB_05cos
visible = @which == "Plug-in" && @howmany == "2"
endparam
complex param b
caption = "b"
default = (1,0)
visible = @howmany == "2"
endparam
}
class JLB_FX_OneOrTwoFunc(FormulaX) { ; 240904
; New 240904
; Use the OneOrTwoFunc transform as a FormulaX
public:
import "common.ulb"
func JLB_FX_OneOrTwoFunc(Generic pparent)
FormulaX(pparent)
m_UT = new @f_UT(this)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
m_UT.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
return m_UT.Iterate(pz) + m_c
endfunc
protected:
UserTransform m_UT
default:
title = "1 or 2 Functions"
rating = Recommended
int param version
caption = "Version"
default = 240904
visible = @version < 240904
endparam
heading
text = "(Current is 240904.}"
visible = @version < 240904
endheading
heading
endheading
heading
caption = "Function(s)"
endheading
UserTransform param f_UT
caption = "invisible"
default = JLB_UT_OneOrTwoFunc
selectable = false
endparam
}
class JLB_UT_OneOrTwoUT(common.ulb:UserTransform) { ; 240904
; New 240904
; Make a UserTransform our of two UserTransforms
; It's the same as JLB_UT_OneOrTwoFunc except for using transforms instead of functions
public:
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_UT_OneOrTwoUT(Generic pparent)
UserTransform(pparent)
if @exch && @howmany == "2"
m1 = new @UT2(this)
m2 = new @UT1(this)
else
m1 = new @uT1(this)
if @howmany == "2"
m2 = new @UT2(this)
endif
endif
endfunc
; complex func Init(complex pz)
; UserTransform.Init(pz)
; m1.Init(pz)
; m2.Init(pz)
; return pz
; endfunc
complex func Iterate(complex pz)
complex t
int n = 0
while n < @nsteps
if @howmany == "1"
t = T1(pz)
elseif @how == "T1+T2"
t = T1(pz) + T2(pz)
elseif @how == "T1-T2"
t = T1(pz) - T2(pz)
elseif @how == "T1*T2"
t = T1(pz) * T2(pz)
elseif @how == "T1/T2"
t = T1(pz) / T2(pz)
elseif @how == "T1^T2"
t = T1(pz) ^ T2(pz)
else;if @how == "T1(T2)"
t = T1(T2(pz))
endif
t = @h*t
if @addrep == "Add", pz = pz + t, else, pz = t, endif
n = n + 1
endwhile
return pz
endfunc
complex func T1(complex z)
return m1.Iterate(@a*z)
endfunc
complex func T2(complex z)
return m2.Iterate(@b*z)
endfunc
protected:
UserTransform m1
UserTransform m2
default:
rating = Recommended
title = "1 or 2 Transforms"
int param version
caption = "Version"
default = 240904
visible = @version < 240904
endparam
heading
text = "(Current is 240904.}"
visible = @version < 240904
endheading
param addrep
caption = "Add or Replace?"
enum = "Add" "Replace"
default = 1
endparam
int param nsteps
caption = " # of steps"
default = 1
min = 1
endparam
float param h
caption = " Step size"
default = 1
endparam
heading
endheading
param howmany
caption = "1 or 2 transforms?"
enum = "1" "2"
default = 1
endparam
param how
caption = "Combine"
default = 5
enum = "T1+T2" "T1-T2" "T1*T2" "T1/T2" "T1^T2" "T1(T2)"
visible = @howmany == "2"
endparam
bool param exch
caption = "Switch T1 and T2?"
default = false
visible = @howmany == "2"
endparam
UserTransform param UT1
caption = "T1(a*z)"
default = JLB_UT_Linear
endparam
complex param a
caption = "a"
default = (1,0)
endparam
UserTransform param UT2
caption = "T2(b*z)"
default = JLB_FTransform
visible = @howmany == "2"
endparam
complex param b
caption = "b"
default = (1,0)
visible = @howmany == "2"
endparam
}
class JLB_FX_OneOrTwoUT(FormulaX) { ; 240904
; New 240904
; Use the OneOrTwo transform as a FormulaX
public:
import "common.ulb"
func JLB_FX_OneOrTwoUT(Generic pparent)
FormulaX(pparent)
m_UT = new @f_UT(this)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
m_UT.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
return m_UT.Iterate(pz) + m_c
endfunc
protected:
UserTransform m_UT
default:
title = "1 or 2 Transforms"
rating = Recommended
int param version
caption = "Version"
default = 240904
visible = @version < 240904
endparam
heading
text = "(Current is 240904.}"
visible = @version < 240904
endheading
heading
endheading
heading
caption = "Transform(s)"
endheading
UserTransform param f_UT
caption = "invisible"
default = JLB_UT_OneOrTwoUT
selectable = false
endparam
}
class JLB_UT_Distance(common.ulb:UserTransform) { ; 240910
; New 240910
; Make a UserTransform out of a Distance
public:
func JLB_UT_Distance(Generic pparent)
UserTransform(pparent)
m_d = new @dist(this)
if @which == "Menu"
m_f = new @ffff(this)
else
m_g = new @gggg(this)
endif
endfunc
func Init(complex pz)
m_d.Init(pz)
;m_d.SetParams(0, true) ; iteration 0, absolute value distance
endfunc
complex func Iterate(complex pz)
float d = m_d.Iterate(pz)
;if d <= 0, d = 1, endif
if @how == "d*z"
return d*pz
elseif @how == "z"
return pz
endif
if @which == "Menu"
if @how == "d*f(z)"
return d*m_f.Iterate(pz)
elseif @how == "f(d*z)"
return m_f.Iterate(d*pz)
else;if @how == "f(z)"
return m_f.Iterate(pz)
endif
else
if @how == "d*f(z)"
return d*m_g.Iterate(pz)
elseif @how == "f(d*z)"
return m_g.Iterate(d*pz)
else;if @how == "f(z)"
return m_g.Iterate(pz)
endif
endif
endfunc
private:
Distance m_d
UserTransform m_f
FT m_g
default:
rating = Recommended
title = "Distance"
int param version
caption = "Version"
default = 240910
visible = @version < 240910
endparam
heading
text = "(Current is 240910.)"
visible = @version < 240910
endheading
param which
caption = "Choose f from"
enum = "Menu" "Plug-in"
default = 0
endparam
param how
caption = "Using"
enum = "d*z" "d*f(z)" "f(d*z)" "z" "f(z)"
default = 0
endparam
UserTransform param ffff ; caption doesn't show
default = JLB_FTransform
selectable = false
visible = @how > 0 && @which == "Menu"
endparam
FT param gggg
caption = "f"
default = JLB_01sin
;selectable = false
visible = @how > 0 && @which == "Plug-in"
endparam
heading
endheading
Distance param dist
caption = "Distance method"
default = JLB_D_SD
endparam
}
class JLB_FX_DistanceUT(FormulaX) { ; 240911
; New 240911
; Use the Distance transform as a FormulaX
public:
import "common.ulb"
func JLB_FX_DistanceUT(Generic pparent)
FormulaX(pparent)
m_UT = new @f_UT(this)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
m_UT.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
return m_UT.Iterate(pz) + m_c
endfunc
protected:
UserTransform m_UT
default:
title = "Distance"
rating = Recommended
int param version
caption = "Version"
default = 240911
visible = @version < 240911
endparam
heading
text = "(Current is 240911.}"
visible = @version < 240911
endheading
heading
endheading
; heading
; caption = "Transform(s)"
; endheading
UserTransform param f_UT
caption = "invisible"
default = JLB_UT_Distance
selectable = false
endparam
}
class JLB_UT_OneFunction(common.ulb:UserTransform) { ; 240915
; New 240914
; Make a UserTransform out of one functions
; with a choice of where to get the function
public:
func JLB_UT_OneFunction(Generic pparent)
UserTransform(pparent)
if @which == "Menu"
m_fm = new @fm(this)
else;if @which == "Plug-in"
m_fp = new @fp(this)
endif
endfunc
complex func Iterate(complex pz)
if @which == "Menu"
return m_fm.Iterate(pz)
else
return m_fp.Iterate(pz)
endif
endfunc
private:
UserTransform m_fm
FT m_fp
default:
rating = Recommended
title = "1 Function"
int param version
caption = "Version"
default = 240914
visible = @version < 240914
endparam
heading
text = "(Current is 240914.)"
visible = @version < 240914
endheading
param which
caption = "Choose f from"
enum = "Menu" "Plug-in"
default = 0
endparam
heading
text = " f"
visible = @which == "Menu"
endheading
UserTransform param fm ; caption doesn't show
default = JLB_FTransform
selectable = false
visible = @which == "Menu"
endparam
FT param fp
caption = " f"
default = JLB_01sin
visible = @which == "Plug-in"
endparam
}
class JLB_DChopperPlus(Distance) { ; 240918
; this is a re-writing and expansion of Chopper in om.ucl
; for use as a plug-in for Color by Distance
public:
import "common.ulb"
func JLB_DChopperPlus(Generic pparent)
Distance(pparent)
m_f = new @f_UT(this)
m_s = new @s_UT(this)
endfunc
; func Init(complex zz)
; sum = 0
; endfunc
float func Iterate(complex zz)
complex v = m_f.Iterate(zz)
v = m_s.Iterate(v)
if @how == "round"
zz = round(zz)
elseif @how == "ceil"
zz = ceil(zz)
elseif @how == "floor"
zz = floor(zz)
elseif @how == "trunc"
zz = trunc(zz)
else;if @how == "trunc*"
float x = real(zz)
if x >= 0, x = ceil(x), else, x = floor(x), endif
float y = imag(zz)
if y >= 0, y = ceil(y), else, y = floor(y), endif
zz = x + flip(y)
endif
float d = cabs(v - zz)
return d
endfunc
private:
UserTransform m_f
UserTransform m_s
default:
title = "ChopperPlus"
rating = Recommended
int param version
caption = "Version"
default = 240918
visible = @version < 240918
endparam
heading
text = "(current is 240918.}"
visible = @version < 240918
endheading
UserTransform param f_UT
caption = "Function"
default = JLB_UT_OneFunction
selectable = false
endparam
heading
endheading
UserTransform param s_UT
caption = "Signs?"
default = JLB_UT_XY_Signs
selectable = false
endparam
heading
endheading
param how
caption = "How?"
enum = "round" "ceil" "floor" "trunc" "trunc*"
default = 0
endparam
heading
endheading
}
class JLB_UT_PowerPlusFunc(common.ulb:UserTransform) { ; 241016
; New 241016
; Make a UserTransform out of a power and a function
; simplified version of "1 or 2 functions"
public:
func JLB_UT_PowerPlusFunc(Generic pparent)
UserTransform(pparent)
if @which == "Menu"
m_fm = new @fm(this)
else;if @which == "Plug-in"
m_fp = new @fp(this)
endif
endfunc
complex func Iterate(complex pz)
if @which == "Menu"
return pz^@p + @a * m_fm.Iterate(@b*pz)
else
return pz^@p + @a * m_fp.Iterate(@b*pz)
endif
endfunc
private:
UserTransform m_fm
FT m_fp
default:
rating = Recommended
title = "Power + Function"
int param version
caption = "Version"
default = 241016
visible = @version < 241016
endparam
heading
text = "(Current is 241016.)"
visible = @version < 241016
endheading
heading
text = " z_new = z^p + a*f(b*z)"
;visible = @which == "Menu"
endheading
complex param p
caption = " p"
default = 2
endparam
param which
caption = "Choose f from"
enum = "Menu" "Plug-in"
default = 0
endparam
; heading
; endheading
complex param a
caption = "a"
default = (1,0)
endparam
UserTransform param fm ; caption doesn't show
default = JLB_FTransform
selectable = false
visible = @which == "Menu"
endparam
FT param fp
caption = " f"
default = JLB_01sin
visible = @which == "Plug-in"
endparam
complex param b
caption = "b"
default = (1,0)
endparam
}
class JLB_FX_PowerPlusFunc(FormulaX) { ; 240904
; New 2401016
; Use the PowerPLusFunc transform as a FormulaX
public:
import "common.ulb"
func JLB_FX_PowerPlusFunc(Generic pparent)
FormulaX(pparent)
m_UT = new @f_UT(this)
endfunc
complex func Init(complex pz)
FormulaX.Init(pz)
m_UT.Init(pz)
return pz
endfunc
complex func Iterate(complex pz)
return m_UT.Iterate(pz) + m_c
endfunc
protected:
UserTransform m_UT
default:
title = "Power + Function"
rating = Recommended
int param version
caption = "Version"
default = 241016
visible = @version < 241016
endparam
heading
text = "(Current is 241016.}"
visible = @version < 241016
endheading
heading
endheading
; heading
; caption = "Function(s)"
; endheading
UserTransform param f_UT
caption = "invisible"
default = JLB_UT_PowerPlusFunc
selectable = false
endparam
}
class JLB_DPoints(Distance) {
; New 241024
; Color by distances from 1, 2, 3, or 4 points
; Inspired by TwoPoints in mt.ucl
public:
import "common.ulb"
func JLB_DPoints(Generic pparent)
Distance(pparent)
m_dist = new @dist(this)
if @N != "1" && @samediff == 0
m1 = m2 = m3 = m4 = new @f(this)
else
m1 = new @f1(this)
m2 = new @f2(this)
m3 = new @f3(this)
m4 = new @f4(this)
endif
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
endfunc
float func Iterate(complex zz)
float d1 = m_dist.Iterate(m1.Iterate(zz)-@p1)
if @N == "1"
return d1
endif
float d2 = m_dist.Iterate(m2.Iterate(zz)-@p2)
if @N == "2"
if @how2 == "Average"
return (d1 + d2) / 2
endif
MyMath.fsort2(d1, d2)
if @how2 == "Min"
return d1
elseif @how2 == "Max"
return d2
else;if @how2 == "Range"
return d2 - d1
endif
endif
float d3 = m_dist.Iterate(m3.Iterate(zz)-@p3)
if @N == "3"
if @how34 == "Average"
return (d1 + d2 + d3) / 3
endif
MyMath.fsort3(d1, d2, d3)
if @how34 == "Min"
return d1
elseif @how34 == "Max"
return d3
elseif @how34 == "Middle"
return d2
else;if @how34 == "Range"
return d3 - d1
endif
endif
float d4 = m_dist.Iterate(m4.Iterate(zz)-@p3)
if @how34 == "Average"
return (d1 + d2 + d3 + d4) / 4
endif
MyMath.fsort4(d1, d2, d3, d4)
if @how34 == "Min"
return d1
elseif @how34 == "Max"
return d4
elseif @how34 == "Middle"
return (d2 + d3) /2
else;if @how34 == "Range"
return d4 - d1
endif
endfunc
private:
Distance m_dist
UserTransform m1
UserTransform m2
UserTransform m3
UserTransform m4
default:
title = "Points"
rating = Recommended
int param version
caption = "Version"
default = 241024
visible = @version < 1024
endparam
heading
text = "(current is 241024.}"
visible = @version < 241024
endheading
param N
caption = "How many points"
enum = "1" "2" "3" "4"
default = 1
endparam
param samediff
caption = "Functions?"
enum = "All the same" "Different"
default = 0
visible = @N > 0
endparam
UserTransform param f
default = JLB_FTransform
selectable = false
visible = @samediff == 0 && @N != "1"
endparam
complex param p1
caption = "Point 1"
default = (1,0)
endparam
UserTransform param f1
default = JLB_FTransform
selectable = false
visible = @N == "1" || @samediff == 1
endparam
heading
visible = @N != "1" && @samediff == 1
endheading
complex param p2
caption = "Point 2"
default = (-1,0)
visible = @N > 0
endparam
UserTransform param f2
default = JLB_FTransform
selectable = false
visible = @N > 0 && @samediff == 1
endparam
heading
visible = @N > 1 && @samediff == 1
endheading
complex param p3
caption = "Point 3"
default = (0,1)
visible = @N > 1
endparam
UserTransform param f3
default = JLB_FTransform
selectable = false
visible = @N > 1 && @samediff == 1
endparam
heading
visible = @N > 2 && @samediff == 1
endheading
complex param p4
caption = "Point 4"
default = (0,-1)
visible = @N == "4"
endparam
UserTransform param f4
default = JLB_FTransform
selectable = false
visible = @N == "4" && @samediff == 1
endparam
heading
endheading
param how2
caption = "Using?"
enum = "Min" "Average" "Max" "Range"
default = 0
visible = @N == 1
endparam
param how34
caption = "Using?"
enum = "Min" "Average" "Middle" "Max" "Range"
default = 0
visible = @N > 1
endparam
heading
endheading
Distance param dist
default = JLB_D_SD
selectable = false
endparam
}
comment{
Group 3: Not recommended classes & etc.
}
class JLB_SwitchFormula(common.ulb:Formula) {
; modified from MMF_SwitchFormula in mmf.ulb
; meant to be used with JLB_SwitchCombo for building switchable combinations of SFormulas.
; works with both convergent and divergent formulas.
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_SwitchFormula(Generic pparent)
Formula.Formula(pparent)
if @v_simpleswitch < 200
if (fType = @p_mandy)
fValue = fConstant = @p_start
else
fValue = fConstant = @p_seed
endif
else
fType = true
fValue = fConstant = @p_start
endif
endfunc
; @param pz the initial location
; @return initial z for iteration
complex func Init(complex pz)
Formula.Init(pz)
if @v_simpleswitch < 200
if fType
fConstant = pz
return fValue
else
return pz
endif
endif
return pz
endfunc
protected:
complex fConstant
complex fValue
bool fType
default:
; no title, so just a base class
rating = NotRecommended
int param v_simpleswitch
caption = "Version (Simple Switch Formula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_simpleswitch < 200
endparam
; all these ignored for version 2
bool param p_mandy
caption = "Mandelbrot ?"
default = true
hint = "Disable for Julia mode."
visible = false
endparam
complex param p_start
caption = "Mandelbrot mode Start Value"
default = (0,0)
visible = @p_mandy
endparam
complex param p_seed
caption = "Julia mode Constant"
default = (0.3,0)
visible = !@p_mandy && @v_simpleswitch < 200
endparam
complex param p_power ; hides the one from base class
caption = "Power"
default = (2,0)
hint = "Defines the primary power for the fractal."
visible = false
endparam
}
; version 1, always starts in M mode
; version 2 each formula choose M or J mode
class JLB_SwitchCombo(JLB_SwitchFormula) {
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_SwitchCombo(Generic pparent)
JLB_SwitchFormula.JLB_SwitchFormula(pparent)
m_SFormula1 = new @f_SFormula1(this)
m_SFormula2 = new @f_SFormula2(this)
; S = new State(#pixel, fValue, @p_bType, @p_divtype, @p_diverge, @p_angle, @p_converge)
S = new State(#pixel, fValue, @p_bType, @p_divtype, @p_diverge, @p_converge)
endfunc
; @param pz the initial location
; @return initial z for iteration
complex func Init(complex pz)
JLB_SwitchFormula.Init(pz)
; following block moved from constructor to here 240112
if @v_switchcombo < 200
fType = @p_mandy
if fType
fValue = fConstant = @p_start
else
fValue = fConstant = @p_seed
endif
else
fType = true
fValue = fConstant = #pixel ;@p_seed
endif
m_count = 0
if @f_SFormula1 == JLB_NothingSFormula ; skip initial formula
m_count = @n1
endif
complex rvalue
if fType ; Mandelbrot type
fConstant = pz
rvalue = fValue
else ; Julia type
rvalue = pz
endif
S.pzold = S.pz = pz
S.pc = fConstant
if @n1 > 0 && @p_ibail ; if formula 1 has its own bail criteria
S.bType = @p_ibType
S.divType = @p_idivtype
S.dValue = @p_idiverge
S.cValue = @p_iconverge
; S.dCos = cos(@p_iangle * #pi/180.0)
; S.dSin = sin(@p_iangle * #pi/180.0)
else ; formulas 1 and 2 have the same criteria
S.bType = @p_bType
S.divType = @p_divtype
S.dValue = @p_diverge
S.cValue = @p_converge
endif
S.iters = 0
S.tooMany = false
S.bailed = false
m_SFormula1.Init(pz, S.pc)
m_SFormula2.Init(pz, S.pc)
return rvalue ; value ignored
endfunc
; Called by Switch Combo Formula in jlb.ufm
; @param f = flag for Mandelbrot or Julia mode, true for Mandelbrots
; @param v the value to be used as the start value or constant
func SetParams(bool f, complex v)
fType = f
fValue = fConstant = v
endfunc
; @param pz
; Iterate--all the work is done in the plug-in.
complex func Iterate(complex pz) ; argument is ignored
; Initial formula
if m_count < @n1
setz()
m_SFormula1.Iterate(S)
m_count = m_count + 1
if S.bailed ; set up for formula 2, which may have different bailing criteria
m_count = @n1
S.bType = @p_bType
S.divType = @p_divtype
S.dValue = @p_diverge
S.cValue = @p_converge
;S.tooMany = false
; S.dCos = cos(@p_angle * #pi/180.0)
; S.dSin = sin(@p_angle * #pi/180.0)
S.bailed = S.IsBailedOut(S.pz) ; check for new bailout criterion
endif
else
; Main formula
setz()
m_SFormula2.Iterate(S)
m_count = m_count + 1
endif
return S.pz
endfunc
func setz ()
if S.iters > 0 && @zdz > 0
zz = S.pz
if @zdz == "z-z_prev"
zz = zz - S.pzold
elseif @zdz == "z/z_prev"
zz = zz / S.pzold
elseif @zdz == "z-pixel"
zz = zz - #pixel
elseif @zdz == "z/pixel"
zz = zz / #pixel
endif
S.pz = zz
endif
endfunc
; @param pz
; @return true if bailed out.
bool func IsBailedOut(complex pz)
return S.bailed
endfunc
protected:
complex fConstant
complex fValue
bool fType
State S
SFormula m_SFormula1
SFormula m_SFormula2
int m_count
default:
title = "SwitchCombo"
rating = NotRecommended
int param v_switchcombo
caption = "Version"
default = 220801 ; changes today don't break old formulas
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_switchcombo < 200
endparam
param zdz
caption = "Use for zz"
enum = "z" "z-z_prev" "z/z_prev" "z-pixel" "z/pixel"
default = 0
visible = true ;@v_switchcombo > 200
endparam
; complex param p_power ; Hide p_power from Formula
; visible = false
; endparam
; this group only for version 100
bool param p_mandy
caption = "Mandelbrot?"
default = true
hint = "Disable for Julia mode."
visible = false ;@p_manual
endparam
complex param p_start
caption = "Mandelbrot Start Value"
default = (0,0)
visible = false ; @p_mandy && @p_manual
; always starts with pz = #pixel
endparam
complex param p_seed
caption = "Julia Constant"
default = (0.3,0)
visible = false ; !@p_mandy && @p_manual
endparam
SFormula param f_SFormula1
caption = "Initial Formula"
default = JLB_NothingSFormula
endparam
int param n1
caption = "Repeats of Initial Formula"
default = 1
min = 0
visible = @f_SFormula1 != JLB_NothingSFormula
endparam
; Heading
; Endheading
bool param p_ibail
caption = "Separate bailout critera?"
default = false
visible = (@f_SFormula1 != JLB_NothingSFormula) && @n1 > 0
endparam
param p_ibType
caption = "How to stop"
enum = "Z diverges" "Z converges" "Either one"
default = 0
visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && @n1 > 0
endparam
float param p_idiverge
caption = "Initial divergence test"
exponential = true
default = 1e4
visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 0 || @p_ibType == 2) && @n1 > 0
hint = "Defines how soon an orbit bails out as z gets large."
endparam
param p_idivtype
caption = "Initial divergence type"
default = 0
enum = "mod" "real" "imag" "or" "and" "manh" \
"real+imag" "real-imag" "real*imag" "max(real,imag)" "min(real,imag)"
visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 0 || @p_ibType == 2) && @n1 > 0
endparam
; float param p_iangle
; caption = "angle"
; default = -45
; hint = "Distance is from a line at this angle. Angle 0 gives same result as imag, \
; 90 same as real, 45 same as manr."
; visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 0 || @p_ibType == 2) && @p_idivtype == 7 && @n1 > 0
; endparam
float param p_iangle
; wasn't used before. keep this to avoid error messages
default = 0
visible = false
endparam
float param p_iconverge
caption = "Initial convergence test"
exponential = true
default = 1e-6
visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 1 || @p_ibType == 2) && @n1 > 0
hint = "Defines how soon an orbit bails out as z converges to a value. \
With multiple formulas, false convergence is possible."
endparam
; Heading
; caption = "End of Initial Formula, start of Main Formula"
; Endheading
SFormula param f_SFormula2
caption = "Main Formula"
default = JLB_MandelbrotSFormula
hint = "Repeat until bailout, convergence, or iteration limit."
endparam
Heading
caption = "Bailout"
Endheading
param p_bType
caption = "How to stop"
enum = "Z diverges" "Z converges" "Either one"
default = 0
endparam
float param p_diverge
caption = "Divergence test"
exponential = true
default = 1e4
visible = @p_btype == 0 || @p_bType == 2
hint = "Defines how soon an orbit bails out as z gets large."
endparam
param p_divtype
caption = "Divergence type"
default = 0
enum = "mod" "real" "imag" "or" "and" "manh" \
"real+imag" "real-imag" "real*imag" "max(real,imag)" "min(real,imag)"
visible = @p_btype == 0 || @p_bType == 2
endparam
float param p_angle
; wasn't used before. keep this to avoid error messages
default = 0
visible = false
endparam
float param p_converge
caption = "Convergence test"
exponential = true
default = 1e-6
visible = @p_btype == 1 || @p_bType == 2
hint = "Defines how soon an orbit bails out as z converges to a value. \
With multiple formulas, false convergence is possible."
endparam
}
; the State of an iteration for a pixel
class State {
public:
; constructor initializes the state
; func State(complex z, complex c, int b, int dt, float dv, float angle, float cv)
func State(complex z, complex c, int b, int dt, float dv, float cv)
pzold = pz = z
pc = c
bType = b ; 0, 1, or 2 for divergence, convergence, or both
divType = dt ; 0 to 8
; dCos = cos(angle * #pi/180.0)
; dSin = sin(angle * #pi/180.0)
dvalue = dv
cvalue = cv
iters = 0
tooMany = false ;
bailed = false
endfunc
; after an iteration has calculated a new z, and possibly a new c, update
bool func Update(const complex z, const complex c)
pzold = pz
pz = z
pc = c
iters = iters + 1
bailed = IsBailedOut(pz)
return bailed
endfunc
bool func IsBailedOut(const complex pz)
tooMany = iters >= #maxiter
if btype == 3
bailed = toomany
return bailed
endif
bool diverged = false
if bType == 0 || bType == 2
float tmp = |pz|
if (isNan(tmp) || isInf(tmp))
return true
endif
float x = real(pz)
float y = imag(pz)
if divType == 0 ; "mod"
diverged = (tmp > dValue)
elseif divType == 1 ;"real"
diverged = (sqr(x) > dValue)
elseif divType == 2 ; "imag"
diverged = (sqr(y) > dValue)
elseif divType == 3 ; "or"
diverged = (sqr(x) > dValue || sqr(y) > dValue)
elseif divType == 4 ; "and"
diverged = (sqr(x) > dValue && sqr(y) > dValue)
elseif divType == 5 ;"manh"
diverged = (sqr(abs(x) + abs(y)) > dValue)
elseif divType == 6 ; "real+imag"
diverged = (sqr(x + y) > dValue)
elseif divType == 7 ; "real-imag"
diverged = (sqr(x - y) > dValue)
elseif divType == 8 ; "real*imag"
diverged = (abs(x * y) > dValue)
elseif divType == 9 ; "max(real,imag)"
if abs(x) >= abs(y)
diverged = (sqr(x) > dValue)
else
diverged = (sqr(y) > dValue)
endif
elseif divType == 10 ; "min(real,imag)"
if abs(x) <= abs(y)
diverged = (sqr(x) > dValue)
else
diverged = (sqr(y) > dValue)
endif
endif
endif
bool converged = false
if bType == 1 || bType == 2
converged = (|pz - pzold| < cValue)
endif
bailed = converged || diverged
return bailed
endfunc
complex pz
complex pc ; version 1, pixel for M-type, seed for J-type
; version 2, not used (each SFormula has its own)
complex pzold ; previous z for testing convergence or for use in formulas
int bType ; test divergence, convergence, or both
int divType ; type of divergence test
; float dCos ; cosine of angle for divergence test
; float dSin ; sine of angle for divergence test
float dValue ; divergence criterion
float cValue ; convergence criterion
int iters ; number of iterations, often not the same as #numiter
bool tooMany ; true if too many iterations
bool bailed ; true if diverged or converged
}
class SFormula(common.ulb:Generic) {
; SFormula base class for use with JLB_SwitchCombo.
; similar to Formula, but uses State
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func SFormula(Generic pparent)
Generic.Generic(pparent)
endfunc
; @param pz
; @param pc
func Init(complex pz, complex pc)
endfunc
; @param State
; @return true if done
bool func Iterate(State S)
return false
endfunc
default:
; no title, just a base class
rating = NotRecommended
int param v_SFormula
caption = "Version (SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_SFormula < 200
endparam
}
class JLB_NothingSFormula(SFormula) {
; A do-nothing SFormula, a place-holder when needed.
public:
; @param pz
; @param pc
bool func Iterate(State S)
return S.bailed
endfunc
default:
title = "Do nothing"
rating = NotRecommended
int param v_NothingzSFormula
caption = "Version (JLB_NothingSFormula)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_NothingzSFormula < 100
endparam
}
class JLB_MandelbrotSFormula(SFormula) {
; The Mandelbrot formula as an SFormula.
; 220213 added the final tweak. Doesn't break old parameter sets.
; 230318 added second power. Doesn't break old parameter sets.
public:
import "common.ulb"
func JLB_MandelbrotSFormula(Generic pparent)
SFormula(pparent)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_MandelbrotSFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex znew
if (@p_std)
;if @v_MandelbrotSFormula < 201 ;|| @v_MandelbrotSFormula > 201
znew = sqr(pz) + ppc
;else
; znew = pz^@p + ppc
;endif
else
znew = @a*pz^@p_power + @b*ppc*pz^@p_power2 + @p_a_old*S.pzold
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
default:
title = "Mandelbrot"
rating = NotRecommended
int param v_MandelbrotSFormula
caption = "Version (Mandelbrot_SFormula)"
default = 220318
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_MandelbrotSFormula < 220318
endparam
bool param p_std
caption = "Standard"
default = true
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_MandelbrotSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.5,0.5)
visible = @v_MandelbrotSFormula > 100 && !@p_Mtype
endparam
heading
caption = "z_new = z^2 + c"
visible = @p_std ;&& @v_MandelbrotSFormula <= 201
endheading
; heading
; caption = "z_new = z^p + c"
; visible = @p_std && @v_MandelbrotSFormula > 201
; endheading
heading
caption = "z_new = a1*z^p + b*c*z^q + a2*z_prev"
visible = !@p_std
endheading
; complex param p
; caption = "p"
; default = 2
; visible = @p_std && @v_MandelbrotSFormula >= 201 ; && @v_MandelbrotSFormula < 220318
; endparam
complex param a
caption = "a1"
default = 1
visible = !@p_std
endparam
complex param p_power
caption = "p"
default = (2,0)
visible = !@p_std
endparam
complex param b
caption = "b"
default = 1
visible = !@p_std
endparam
complex param p_power2
caption = "q"
default = 0
visible = !@p_std
endparam
complex param p_a_old
caption = "a2"
default = 0.0
visible = !@p_std
endparam
heading
caption = "Tweak after each iteration"
visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 && !@p_std
selectable = false
endparam
}
class JLB_MandelbarSFormula(SFormula) {
; The Mandelbar formula as a SFormula.
public:
import "common.ulb"
func JLB_MandelbarSFormula(Generic pparent)
SFormula(pparent)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_MandelbarSFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = conj(S.pz)
complex znew
if (@p_std)
znew = sqr(pz) + ppc
else
znew = @a*pz^@p_power + @b*ppc + @p_a_old*S.pzold
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
default:
title = "Mandelbar"
rating = notrecommended
int param v_MandelbarSFormula
caption = "Version (Mandelbar_SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_MandelbarSFormula < 200
endparam
bool param p_std
caption = "Standard"
hint = "Standard: z_new = sqr(conj(z)) + c"
default = true
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_MandelbarSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_MandelbarSFormula > 100 && !@p_Mtype
endparam
heading
caption = "z_new = conj(z)^2 + c"
visible = @p_std
endheading
heading
caption = "z_new = a1*conj(z)^p + b*c + a2*z_prev"
visible = !@p_std
endheading
complex param a
caption = "Mandelbar a1"
default = 1
visible = !@p_std
endparam
complex param p_power
caption = "Mandelbar p"
default = (2,0)
visible = !@p_std
endparam
complex param b
caption = "Mandelbar b"
default = 1
visible = !@p_std
endparam
complex param p_a_old
caption = "Mandelbar a2"
default = 0.0
visible = !@p_std
endparam
heading
caption = "Tweak after each iteration"
visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
}
class JLB_MandelVar2SFormula(SFormula) {
; The MandelVar2 formula as a SFormula.
public:
import "common.ulb"
func JLB_MandelVar2SFormula(Generic pparent)
SFormula(pparent)
if @addT > 0
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_Mandelvar2SFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
float x = real(pz)
float y = imag(pz)
float x2 = sqr(x)
float xy = x*y
float y2 = sqr(y)
complex znew = (@a_x2*x2 + @a_xy*xy + @a_y2*y2) + flip(@b_x2*x2 + @b_xy*xy + @b_y2*y2) + ppc
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
UtilityTransform finalTransform
complex ppc
default:
title = "MandelVar2"
rating = NotRecommended
int param v_MandelVar2SFormula
caption = "Version (MandelVar2_SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_MandelVar2SFormula < 200
endparam
heading
caption = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)"
endheading
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_Mandelvar2SFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_Mandelvar2SFormula > 100 && !@p_Mtype
endparam
complex param a_x2
caption = "a_x2"
default = 1
;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)"
endparam
complex param a_xy
caption = "a_xy"
default = 0
;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)"
endparam
complex param a_y2
caption = "a_y2"
default = -1
;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)"
endparam
complex param b_x2
caption = "b_x2"
default = 0
;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)"
endparam
complex param b_xy
caption = "b_xy"
default = 2
;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)"
endparam
complex param b_y2
caption = "b_y2"
default = 0
;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)"
endparam
heading
caption = "Tweak after each iteration"
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
}
class JLB_PeacockSFormula(SFormula) {
; The Peacock formula as a SFormula.
; July 2021 added pzold option; changed parameter names for consistency with other Sformulas.
public:
import "common.ulb"
func JLB_PeacockSFormula(Generic pparent)
SFormula(pparent)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_PeacockSFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex znew
if (@p_std)
znew = pz + @a * (pz^@p_power - 1.0)/(pz^@p_power + 1.0) + ppc
else
if @v_PeacockSFormula < 210707
znew = pz + @a * (@f(pz)^@p_power - @b)/(@f(pz)^@p_power + @b) + @a2*ppc
else
znew = pz + @aa1 * (@f(pz)^@p_power - @aa2)/(@f(pz)^@p_power + @aa2) \
+ @bb*ppc + @aa3*S.pzold
endif
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
default:
title = "Peacock"
rating = NotRecommended
int param v_PeacockSFormula
caption = "Version (Peacock_SFormula)"
default = 210707
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PeacockSFormula < 210707
endparam
bool param p_std
caption = "Standard"
default = true
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_PeacockSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_PeacockSFormula > 100 && !@p_Mtype
endparam
heading
caption = "z_new = z + (z^p-1)/(z^p+1) + c"
visible = @p_std
endheading
heading
caption = "z_new = z + a1*(f(z)^p-b)/(f(z)^p+b) + a2*c"
visible = !@p_std && @v_PeacockSFormula < 210707
endheading
heading
caption = "z_new = z + a1*(f(z)^p-a2)/(f(z)^p+a2) + b*c + a3*z_prev"
visible = !@p_std && @v_PeacockSFormula >= 210707
endheading
complex param p_power
caption = "Peacock: p"
default = 2
endparam
func f
caption = "Peacock: f"
default = sqr()
visible = !@p_std
endfunc
complex param a
caption = "Peacock: a1"
default = 1
visible = !@p_std && @v_PeacockSFormula < 210707
endparam
complex param a2
caption = "Peacock: a2"
default = 1
visible = !@p_std && @v_PeacockSFormula < 210707
endparam
complex param b
caption = "Peacock: b"
default = 1
visible = !@p_std && @v_PeacockSFormula < 210707
endparam
; new versions
complex param aa1
caption = "Peacock: a1"
default = 1
visible = !@p_std && @v_PeacockSFormula >= 210707
endparam
complex param aa2
caption = "Peacock: a2"
default = 1
visible = !@p_std && @v_PeacockSFormula >= 210707
endparam
complex param bb
caption = "Peacock: b"
default = 1
visible = !@p_std && @v_PeacockSFormula >= 210707
endparam
complex param aa3
caption = "Peacock: a3"
default = 1
visible = !@p_std && @v_PeacockSFormula >= 210707
endparam
heading
caption = "Tweak after each iteration"
visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 && !@p_std
selectable = false
endparam
}
class JLB_PhoenixSFormula(SFormula) {
; The Phoenix formula as a SFormula.
public:
import "common.ulb"
func JLB_PhoenixSFormula(Generic pparent)
SFormula(pparent)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex znew
if (@p_std)
znew = @a1 * pz^@p1 + @a2 * ppc * pz^@p2 + @a_old * S.pzold
else
znew = @a1 * @f1(pz)^@p1 + @a2 * ppc * @f2(pz)^@p2 + @a_old * S.pzold
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
default:
title = "Phoenix"
rating = NotRecommended
int param v_PhoenixSFormula
caption = "Version (Phoenix_SFormula)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PhoenixSFormula < 100
endparam
bool param p_std
caption = "Standard"
default = true
endparam
bool param p_Mtype
caption = "M-type?"
default = true
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.56667,0) ; to match Phoenix in Standard.ufm
visible = !@p_Mtype
endparam
heading
caption = "z_new = a1*z^p1 + a2*c*z^p2 + a3*z_old"
visible = @p_std
endheading
heading
caption = "z_new = a1*f1(z)^p1 + a2*c*f2(z)^p2 + a3*z_old"
visible = !@p_std
endheading
func f1
caption = "f1"
default = sin()
visible = !@p_std
endfunc
complex param p1
caption = "p1"
default = (2,0)
endparam
complex param a1
caption = "a1"
default = 1
endparam
func f2
caption = "f2"
default = ident()
visible = !@p_std
endfunc
complex param p2
caption = "p2"
default = (0,0)
endparam
complex param a2
caption = "a2"
default = 1
endparam
complex param a_old
caption = "a3"
default = (0.5, 0)
endparam
heading
caption = "Tweak after each iteration"
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
}
class JLB_DualSFormula(SFormula) {
; DualSFormula combines two formulas
; first n1 calls to formula 1
; then n2 calls to formula 2
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_DualSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_SFormula1 = new @f_SFormula1(this)
m_SFormula2 = new @f_SFormula2(this)
endfunc
func Init(complex pz, complex pc)
m_SFormula1.Init(pz, pc)
m_SFormula2.Init(pz, pc)
count = 0
n1 = @p_n1 ; both have min - 0
n2 = @p_n2
if n1 + n2 == 0, n1 = 1, endif
endfunc
bool func Iterate(State S)
if S.bailed
return true
endif
if @v_DualSFormula < 200 ; old version updates #numiter after all done
int i
i = 0
while (i < @p_n1)
if m_SFormula1.Iterate(S)
return true
endif
i = i + 1
endwhile
i = 0
while (i < @p_n2)
if m_SFormula2.Iterate(S)
return true
endif
i = i + 1
endwhile
else ; new version updates #numiter each time
if count < n1
if m_SFormula1.Iterate(S)
return true
endif
else
if m_SFormula2.Iterate(S)
return true
endif
endif
count = count + 1
if count >= n1 + n2 ; only gets to equality
count = 0
n1 = n1 + @delta_n1
n2 = n2 + @delta_n2
if n1 < 0, n1 = 0, endif
if n2 < 0, n2 = 0, endif
if n1 + n2 == 0, n1 = 1, endif
endif
endif
return false
endfunc
protected:
SFormula m_SFormula1
SFormula m_SFormula2
int count
int n1
int n2
default:
rating = NotRecommended
title = "Two Formulas"
int param v_DualSFormula
caption = "Version (DualSFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_DualSFormula < 200
endparam
heading
text = "Do n1 iterations of Formula 1, then n2 iterations of Formula2, then optionally \
change n1 and n2."
endheading
SFormula param f_SFormula1
caption = "Formula 1"
default = JLB_Gnarl3SFormula
endparam
int param p_n1
caption = "Initial n1"
min = 0
default = 1
endparam
heading
endheading
SFormula param f_SFormula2
caption = "Formula 2"
default = JLB_MandelbrotSFormula
endparam
int param p_n2
caption = "Initial n2"
min = 0
default = 1
endparam
heading
endheading
int param delta_n1
caption = "Change in n1"
default = 0
endparam
int param delta_n2
caption = "Change in n2"
default = 0
endparam
}
class JLB_ComboSFormula(SFormula) {
; This does two or three SFormulas and combines them
; with one of the operators +, -, *, /, ^, (). The latter means use as argument to the previous function.
; This allows formulas such as z = (f1 + f2)/f3 + c
; or z = f1(f2(f3())) + c
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_ComboSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_SFormula1 = new @f_SFormula1(this)
m_SFormula2 = new @f_SFormula2(this)
if @order3 > 0
m_SFormula3 = new @f_SFormula3(this)
endif
m_Combine = new Combine()
endfunc
func Init(complex pz, complex pc)
m_SFormula1.Init(pz, pc)
m_SFormula2.Init(pz, pc)
if @order3 > 0
m_SFormula3.Init(pz, pc)
endif
endfunc
; @param pz
; @param pc
; @return new pz
bool func Iterate(State S)
complex pz = S.pz
complex pc = S.pc ; used only to restore in case one of the subsidiary
; User Transform formulas changes it
complex t1
complex t2
complex t3
if (S.bailed)
return true
endif
if @order3 == 0 ;"f1 op f2"
m_SFormula2.Iterate(S)
if @op1a == "( )" ; f1(f2(pz))
m_SFormula1.Iterate(S)
t1 = S.pz
else ; f1(pz) op1 f2(pz)
t2 = S.pz
S.pz = pz, S.pc = pc
m_SFormula1.Iterate(S)
t1 = S.pz
t1 = m_Combine.go(t1, @op1a, t2)
endif
elseif @order3 == "f1 op1 (f2 op2 f3)"
if @op2a == "( )" ; f1(pz) op1 f2(f3(pz))
m_SFormula3.Iterate(S)
t3 = S.pz
m_SFormula2.Iterate(S)
t2 = S.pz
if @op1 == "( )" ; f1(f2(f3(pz)))
S.pz = t2
m_SFormula1.Iterate(S)
t1 = S.pz
else ; f1(pz) op1 f2(f3(pz))
S.pz = pz, S.pc = pc
m_SFormula1.Iterate(S)
t1 = S.pz
t1 = m_Combine.go(t1, @op1, t2)
endif
else
m_SFormula2.Iterate(S)
t2 = S.pz
S.pz = pz, S.pc = pc
m_SFormula3.Iterate(S)
t3 = S.pz
t2 = m_Combine.go(t2, @op2a, t3)
if @op1 == "( )" ; f1(f2(pz) op2a f3(pz))
S.pz = pz, S.pc = pc
m_SFormula1.Iterate(S)
t1 = S.pz
else
S.pz = pz, S.pc = pc
m_SFormula1.Iterate(S)
t1 = S.pz
t1 = m_Combine.go(t1, @op1, t2)
endif
endif
else ;@order3 == "(f1 op1 f2) op2 f3"
; @op3a == "()" not allowed with this ordering
m_SFormula2.Iterate(S)
t2 = S.pz
if @op1 == "( )" ; (f1(f2(pz))) op2b f3(pz)
m_SFormula1.Iterate(S)
t1 = S.pz
else
m_SFormula1.Iterate(S)
t1 = S.pz
t1 = m_Combine.go(t1, @op1, t2)
endif
S.pz = pz, S.pc = pc
m_SFormula3.Iterate(S)
t3 = S.pz
t1 = m_Combine.go(t1, @op2b, t3)
endif
complex znew = @mult * t1
if @v_ComboSFormula >= 201 && @addc
;znew = znew + @cfac*S.pc
complex cc = #pixel
if !@p_Mtype
cc = @p_seed
endif
znew = znew + @cfac*cc
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
SFormula m_SFormula1
SFormula m_SFormula2
SFormula m_SFormula3
Combine m_Combine
default:
rating = NotRecommended
title = "Combo"
int param v_ComboSFormula
caption = "Version (ComboSFormula)"
default = 201
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ComboSFormula < 201
endparam
param order3
caption = "How to combine"
default = 0
enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3"
; hint = "Order of combining can make a big difference!"
endparam
heading
caption = "f1"
endheading
SFormula param f_SFormula1
caption = "Formula 1"
default = JLB_FuncSFormula
endparam
heading
endheading
param op1
caption = "Operator 1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine Formula values."
visible = @order3 > 0
endparam
param op1a
caption = "Operator for Combo"
enum = "+" "-" "*" "/" "^" "( )"
default = 5
hint = "How to combine Formula values."
visible = @order3 == 0
endparam
; heading
; endheading
heading
caption = "f2"
endheading
SFormula param f_SFormula2
default = JLB_LambdaSFormula
caption = "Formula 2"
endparam
param op2a
caption = "Operator 2 for Combo"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
hint = "How to combine Formula values."
visible = (@order3 == 1)
endparam
param op2b
caption = "Operator 2 for Combo"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default = 2
hint = "How to combine Formula values."
visible = (@order3 == 2)
endparam
heading
caption = "f3"
visible = @order3 > 0
endheading
SFormula param f_SFormula3
default = JLB_FuncSFormula
caption = "Formula 3"
visible = @order3 > 0
endparam
heading
caption = "Final"
endheading
complex param mult
caption = "Combo multiplier"
default = (1,0)
visible = @v_ComboSFormula > 100
endparam
bool param addc
caption = "Add c (pixel or seed)?"
default = true
visible = @v_ComboSFormula >= 201
endparam
bool param p_Mtype
caption = "M-type? (add pixel)"
default = true
visible = @v_ComboSFormula >= 201 && @addc
hint = "This is used only for the final 'Add c'"
endparam
complex param p_seed
caption = "Seed"
default = (0.3, 0)
visible = @v_ComboSFormula >= 201 && @addc && !@p_Mtype
hint = "This is used only for the final 'Add c'"
endparam
complex param cfac
caption= "Multiplier of c"
default = 1
visible = false ;@addc && @v_ComboSFormula >= 201
endparam
heading
caption = "End of Combo"
endheading
}
class JLB_FuncSFormula(SFormula) {; Early version, z = a1*f(a2*z) + b*c.
; Later version, z = a1*f(a2*z)^p + b*c.
; July 2021 added a3*z_prev, as in Mandelbrot
public:
import "common.ulb"
func JLB_FuncSFormula(Generic pparent)
SFormula(pparent)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_FuncSFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex znew
if @p_std
znew = @f(pz) + ppc
else
znew = @a1*@f(@a2*pz)^@p + @b*ppc + @a3*S.pzold
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Function"
int param v_FuncSFormula
caption = "Version (Func_SFormula)"
default = 220626
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_FuncSFormula < 220626
endparam
bool param p_std
caption = "Standard?"
default = true
;visible = @v_FuncSFormula >= 220626
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_FuncSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_funcSFormula > 100 && !@p_Mtype
endparam
heading
caption = "z_new = f(z) + c"
visible = @p_std && @v_FuncSFormula >= 220626
endheading
heading
caption = "z_new = a1*f(a2*z)^p + b*c + a3*z_prev"
visible = @v_FuncSFormula >= 201 && !@p_std
endheading
heading
caption = "z_new = a1*f(a2*z) + b*c"
visible = @v_FuncSFormula < 201
endheading
func f
caption = "Function: f"
default = cos()
endfunc
complex param a1
caption = "Function: a1"
default = 1
visible = !@p_std
endparam
complex param a2
caption = "Function: a2"
default = 1
visible = !@p_std
endparam
complex param p
caption = "Function: p"
default = 1
visible = @v_FuncSFormula >= 201 && !@p_std
endparam
complex param b
caption = "Function b"
default = 1
visible = !@p_std
endparam
complex param a3
caption = "Function: a3"
default = 0
visible = @v_FuncSFormula >= 201 && !@p_std
endparam
heading
caption = "Tweak after each iteration"
visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 && !@p_std
selectable = false
endparam
}
class JLB_PowerSFormula(SFormula) {
; 05 June 2021 added UserTransform
public:
import "common.ulb"
func JLB_PowerSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_Combine = new Combine()
m_Transform = new @f_T(this)
m_SFormula = new @f_SFormula(this)
if @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
m_SFormula.Init(pz, pc)
ppc = #pixel
if @v_PowerSFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @return the new pz bool func Iterate(State S)
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex zz
if @v_PowerSFormula < 210627
zz = S.pz - @a2
else
zz = S.pz - @a
endif
if @p_base == 1
zz = @f(zz)
elseif @p_base == 2
zz = m_Transform.Iterate(zz)
endif
complex t1
if @v_PowerSFormula < 210627
t1 = @a0 + @a1 * zz^@p_power
else
t1 = zz^@p_power
endif
complex t2 = @b * ppc
complex znew = m_Combine.go(t1, @op, t2)
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
Combine m_Combine
UserTransform m_Transform
SFormula m_SFormula
complex ppc
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Power"
int param v_PowerSFormula
caption = "Version (Power_SFormula)"
default = 210627
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PowerSFormula < 210627
endparam
; bool param p_std
; caption = "Standard?"
; default = true
; endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_PowerSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_PowerSFormula > 100 && !@p_Mtype
endparam
heading
caption = "z_new = (a0 + a1*(z-a2)^p) op b*c"
visible = @p_base == 0 && @v_PowerSFormula < 210627
endheading
heading
caption = "z_new = (a0 + a1*f(z-a2)^p) op b*c"
visible = @p_base > 0 && @v_PowerSFormula < 210627
endheading
heading
caption = "z_new = (z-a)^p op b*c"
visible = @p_base == 0 && @v_PowerSFormula >= 210627
endheading
heading
caption = "z_new = f(z-a)^p op b*c"
visible = @p_base > 0 && @v_PowerSFormula >= 210627
endheading
param p_base
caption = "Power of"
enum = "z" "Built-in function of z" "Transform of z" "SFormula"
default = 0
endparam
func f
caption = "f Built-in function"
default = sin()
;hint = "Function"
visible = @p_base == 1
endfunc
UserTransform param f_T
caption = "f Transform"
default = JLB_MoebiusUserTransform
visible = @p_base == 2
endparam
SFormula param f_SFormula
caption = "f SFormula"
default = JLB_FuncSFormula
visible = @p_base == 3
endparam
complex param a0
caption = "Power: a0"
default = 0
visible = @v_PowerSFormula < 210627
endparam
complex param a1
caption = "Power: a1"
default = 1
visible = @v_PowerSFormula < 210627
endparam
complex param a2
caption = "Power: a2"
default = 0
visible = @v_PowerSFormula < 210627
endparam
complex param a
caption = "Power: a"
default = 0
visible = @v_PowerSFormula >= 210627
endparam
complex param p_power
caption = "Power: p"
default = 2
endparam
param op
caption = "Power: op"
enum = "+" "-" "*" "/" "^"
default = 0
endparam
complex param b
caption = "Power: b"
default = 1
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ; && !@p_std
selectable = false
endparam
}
class JLB_PolynomialSFormula(SFormula) {
public:
import "common.ulb"
func JLB_PolynomialSFormula(Generic pparent)
SFormula(pparent)
if @p_base == 2
m_Transform = new @zT(this)
endif
if @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_PolynomialSFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @return the new pz bool func Iterate(State S)
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
if @p_base == 1
pz = @f(pz)
elseif@p_base == 2
pz = m_Transform.Iterate(pz)
endif
complex zz = pz
complex z_calc = @a0
if @p_order >= 1
z_calc = z_calc + @a1 * zz
if @p_order >= 2
zz = zz * pz
z_calc = z_calc + @a2 * zz
if @p_order >= 3
zz = zz * pz
z_calc = z_calc + @a3 * zz
if @p_order >= 4
zz = zz * pz
z_calc = z_calc + @a4 * zz
if @p_order >= 5
zz = zz * pz
z_calc = z_calc + @a5 * zz
if @p_order >= 6
zz = zz * pz
z_calc = z_calc + @a6 * zz
endif
endif
endif
endif
endif
endif
; return @p_a_calc*z_calc + @p_a_old*pz + ppc
complex znew = z_calc + @b*ppc + @d * S.pzold
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UserTransform m_Transform
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Polynomial"
int param v_PolynomialSFormula
caption = "Version (Polynomial_SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PolynomialSFormula < 200
endparam
; bool param p_std
; caption = "Standard?"
; default = true
; endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_PolynomialSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_PolynomialSFormula > 100 && !@p_Mtype
endparam
heading
caption = "z_calc = a0 + a1*z + a2*z^2 + ... + b*c + d*z_prev"
visible = @p_base == 0
endheading
heading
caption = "z_calc = a0 + a1*f(z) + a2*f(z)^2 + ... + b*c + d*z_prev"
visible = @p_base == 1
endheading
heading
caption = "z_calc = a0 + a1*T(z) + a2*T(z)^2 + ... + b*c + d*z_prev"
visible = @p_base == 2
endheading
param p_base
caption = "Polynomial in"
enum = "z" "F(z)" "T(z)"
default = 0
endparam
func f
caption = "F (built-in function)"
default = sin()
hint = "Function"
visible = @p_base == 1
endfunc
UserTransform param zT
caption = "T (Transform)"
default = JLB_MoebiusUserTransform
visible = @p_base == 2
endparam
int param p_order
caption = "Max power"
default = 2
min = 0
max = 6
endparam
complex param a0
caption = "a0"
default = 0
endparam
complex param a1
caption = "a1"
default = 1
visible = @p_order >= 1
endparam
complex param a2
caption = "a2"
default = 1
visible = @p_order >= 2
endparam
complex param a3
caption = "a3"
default = 1
visible = @p_order >= 3
endparam
complex param a4
caption = "a4"
default = 1
visible = @p_order >= 4
endparam
complex param a5
caption = "a5"
default = 1
visible = @p_order >= 5
endparam
complex param a6
caption = "a6"
default = 1
visible = @p_order >= 6
endparam
complex param b
caption = "b"
default = 1
endparam
complex param d
caption = "d"
default = 0
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
class JLB_LambdaSFormula(SFormula) {
;The Lambda formula as a SFormula, generalized.
public:
import "common.ulb"
func JLB_LambdaSFormula(Generic pparent)
SFormula(pparent)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_LambdaSFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
if !@p_std && (@p_base == "func(z)")
pz = @f(pz)
endif
complex znew
if @v_LambdaSFormula < 200
if (pz == (0,0)) || (pz == (1,0)) ; avoid unproductive starts
pz = #pixel
endif
endif
if (@p_std)
znew = ppc * pz * (1 - pz)
else
complex z_calc = ppc * (pz^@p_power1) * ((@b-pz)^@p_power)
znew = @p_a_calc * z_calc + @p_a_old * pz
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Lambda"
int param v_LambdaSFormula
caption = "Version (Lambda_SFormula)"
default = 201
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_LambdaSFormula < 201
endparam
bool param p_std
caption = "Standard?"
default = true
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_LambdaSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (1.25, 0)
visible = @v_LambdaSFormula > 100 && !@p_Mtype
endparam
heading
caption = "z_new = c*z*(1-z)"
visible = @p_std
endheading
heading
caption = "z_new = a1*c* z^p1 * (1-z)^(p2-1) + a2*z"
visible = !@p_std && (@v_LambdaSFormula == 200)
endheading
heading
caption = "z_new = a1* (c * z^p1 * (b-z)^p2) + a2*z"
visible = !@p_std && (@p_base == 0) && (@v_LambdaSFormula > 200)
endheading
heading
caption = "z_new = a1* (c * f(z)^p1 * (b-f(z))^p2) + a2*z"
visible = !@p_std && (@p_base == 1) && (@v_LambdaSFormula > 200)
endheading
param p_base
caption = "Power of"
enum = "z" "func(z)"
default = 0
visible = !@p_std
endparam
func f
caption = "Lambda f"
default = sin()
visible = !@p_std && @p_base == 1
endfunc
complex param p_a_calc
caption = "Lambda a1"
default = 1.0
visible = !@p_std
endparam
complex param p_power1
caption = "Lambda p1"
default = 1
visible = !@p_std
endparam
complex param b
caption = "Lambda b"
default = 1
visible = !@p_std
endparam
complex param p_power
caption = "Lambda p2"
default = 1
visible = !@p_std
endparam
complex param p_a_old
caption = "Lambda a2"
default = 0.0
visible = !@p_std
endparam
heading
caption = "Tweak after each iteration"
visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 && !@p_std
selectable = false
endparam
}
class JLB_PolyNewtonSFormula(SFormula) {
; Iteration of polynomial(z) - c = 0 by relaxed Newton's method or other
; iterative method.
public:
import "common.ulb"
func JLB_PolyNewtonSFormula(Generic pparent)
SFormula(pparent)
if (@p_poly_type == "Polynomial")
m_a[0] = @p_a0, m_a[1] = @p_a1, m_a[2] = @p_a2, m_a[3] = @p_a3
m_a[4] = @p_a4, m_a[5] = @p_a5, m_a[6] = @p_a6, m_a[7] = @p_a7
m_a[8] = @p_a8, m_a[9] = @p_a9, m_a[10] = @p_a10
m_a[@p_degree+1] = 0
int i = 0
while (i <= @p_degree)
m_ap[i] = (i+1)*m_a[i+1] ; f' - coefficient of z^i
m_app[i] = (i+2)*(i+1)*m_a[i+2] ; f" - coefficient of z^i
i = i + 1
endwhile
endif
D = new Deriv(@p_kind)
if @p_poly_type == 0
n = @p_degree
else
n = @p_power
endif
if @p_iter_type == "Type 3"
n = 2
endif
if @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_PolyNewtonSFormula > 100 && !@p_Mtype
ppc = - @p_seed ; to be like that in Standard.ufm
endif
endfunc
; @param pz
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex znew
complex f
complex fp
complex fpp = 0 ; avoid compiler warning
if @v_PolyNewtonSFormula < 200
if pz == (0,0) ; avoid unproductive starts
pz = #pixel
endif
endif
int i
if (@p_poly_type == "Polynomial")
; Solving F(z) = 0
D.Set_k(@p_kind)
D.pow_calc(pz, 1)
complex fz = D.f
complex fzp = D.fp
complex fzpp = D.fpp
i = @p_degree
f = m_a[i]
while (i > 0)
i = i - 1
f = m_a[i] + fz * f
endwhile
f = f + @b*ppc
; df/dz
i = @p_degree - 1
complex sum1 = m_ap[i]
while (i > 0)
i = i - 1
sum1 = m_ap[i] + fz * sum1
endwhile
fp = fzp * sum1
if (@p_iter_type > 0)
; d2f/dz2
i = @p_degree - 2
complex sum2 = m_app[i]
while (i > 0)
i = i - 1
sum2 = m_app[i] + fz * sum2
endwhile
fpp = fzpp * sum1 + fzp * fzp * sum2
endif
else;if (@p_poly_type == "Power")
D.Set_k(@p_kind)
D.pow_calc(pz, @p_power)
f = D.f
fp = D.fp
fpp = D.fpp
D.Set_k(@p_kind2)
D.pow_calc(pz, @p_power2)
f = f + @a*D.f + @b*ppc
fp = fp + @a*D.fp
fpp = fpp + @a*D.fpp
endif
if (@p_iter_type == "Newton")
znew = pz - @step * f / fp
elseif (@p_iter_type == "Type 1") ; Halley approx.
znew = pz - @step * (f/fp)*(1 + @p_alpha*f*fpp/(2*fp*fp))
elseif (@p_iter_type == "Type 2") ; Halley's method
znew = pz - @step * (f/fp) / ( 1 - @p_alpha*f*fpp/(2*fp*fp))
else;if (@p_iter_type == "Type 3") ; Laguerre
; see https://mathworld.wolfram.com/LaguerresMethod.html
; G = fp/f, H = G^2-fpp/f
; znew = z - n/max{G+-sqrt[(n-1)(nH-G^2)]}
; Halley's "irrational method" sets n=2
; Laguerre sets n=polynomial degree, alpha = 1
; complex root = sqrt(1-@p_alpha*2*f*fpp/(fp*fp))
complex root = sqrt((n-1)*(n-1-@p_alpha*n*f*fpp/(fp*fp)))
complex d1 = 1 + root
complex d2 = 1 - root
if (|d1| < |d2|), d1 = d2, endif
znew = pz - @step * 2*(f/fp) / d1
endif
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex m_a[12] ; coefficients of polynomial
complex m_ap[12] ; coefficients of first derivative of polynomial
complex m_app[12] ; coefficients of second derivative of polynomial
Deriv D
complex n ; real for polynomial type; complex for powers of functions
complex ppc
UtilityTransform finalTransform
default:
title = "Poly Newton"
rating = NotRecommended
int param v_PolyNewtonSFormula
caption = "Version (PolyNewton_SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PolyNewtonSFormula < 200
endparam
; bool param p_std
; caption = "Standard?"
; default = true
; endparam
bool param p_Mtype
caption = "M-type (c = pixel)?"
default = true
visible = @v_PolyNewtonSFormula > 100
endparam
complex param p_seed
caption = "J-type, c ="
default = (1, 0)
visible = @v_PolyNewtonSFormula > 100 && !@p_Mtype
endparam
heading
caption = "Solve a0 + a1*f(z) + a2*f(z)^2 + ... - b*c = 0"
visible = @p_poly_type == 0
endheading
heading
caption = "Solve f(z)^p + a*g(z)^q - b*c = 0"
visible = @p_poly_type == 1
endheading
param p_poly_type
caption = "Function type"
enum = "Polynomial" "Powers"
default = 0
endparam
; first function
param p_kind
caption = "f"
enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \
"cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \
"tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \
"log(z)" "exp(z)"
default = 1
visible = @v_PolyNewtonSFormula > 100 ; && @p_poly_type == 1
endparam
int param p_degree
caption = "Max power (<=10)"
default = 3
min = 2
max = 10
visible = (@p_poly_type == 0)
endparam
heading
caption = "Coeffients"
visible = (@p_poly_type == 0)
endheading
complex param p_a0
caption = "a0 = constant coef"
default = (1,0)
visible = (@p_poly_type == 0)
endparam
complex param p_a1
caption = "a1 = degree 1 coef"
default = (1,0)
visible = (@p_poly_type == 0)
endparam
complex param p_a2
caption = "a2 = degree 2 coef"
default = (1,0)
visible = (@p_poly_type == 0)
endparam
complex param p_a3
caption = "a3 = degree 3 coef"
default = (1,0)
visible = (@p_degree >= 3) && (@p_poly_type == 0)
endparam
complex param p_a4
caption = "a4 = degree 4 coef"
default = (1,0)
visible = (@p_degree >= 4) && (@p_poly_type == 0)
endparam
complex param p_a5
caption = "a5 = degree 5 coef"
default = (1,0)
visible = (@p_degree >= 5) && (@p_poly_type == 0)
endparam
complex param p_a6
caption = "a6 = degree 6 coef"
default = (1,0)
visible = (@p_degree >= 6) && (@p_poly_type == 0)
endparam
complex param p_a7
caption = "a7 = degree 7 coef"
default = (1,0)
visible = (@p_degree >= 7) && (@p_poly_type == 0)
endparam
complex param p_a8
caption = "a8 = degree 8 coef"
default = (1,0)
visible = (@p_degree >= 8) && (@p_poly_type == 0)
endparam
complex param p_a9
caption = "a9 = degree 9 coef"
default = (1,0)
visible = (@p_degree >= 9) && (@p_poly_type == 0)
endparam
complex param p_a10
caption = "a10 = degree 10 coeff"
default = (1,0)
visible = (@p_degree >= 10) && (@p_poly_type == 0)
endparam
complex param p_power
caption = "p"
default = (3,0)
visible = (@p_poly_type == 1)
endparam
; second function
complex param a
caption = "a"
default = 1
visible = (@p_poly_type == 1)
endparam
param p_kind2
caption = "g"
enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \
"cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \
"tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \
"log(z)" "exp(z)"
default = 0
visible = @v_PolyNewtonSFormula > 100 && @p_poly_type == 1
endparam
complex param p_power2
caption = "q"
default = (2,0)
visible = (@p_poly_type == 1)
endparam
complex param b
caption = "b"
default = 1
endparam
heading
endheading
param p_iter_type
caption = "Iteration type"
enum = "Newton" "Type 1" "Type 2" "Type 3" ;"Type 4"
default = 0
hint = "Newton is the usual, using only the first derivative. \
The other types also use the second derivative. \
Type 1 is Householder iteration; type 2 is Halley's iteration; \
type 3 is Halley's irrational iteration; \
type 4 is Laguerre's method for polynomials (all if alpha = 1)."
endparam
complex param p_alpha
caption = "alpha"
default = (1,0)
; hint = "Nonstandard values may not allow convergence, but can give \
; interesting shapes."
visible = (@p_iter_type > 0)
endparam
param step
caption = "Step size"
default = (1,0)
; hint = "Nonstandard values may not allow \
; convergence, but can give interesting shapes."
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
class JLB_UXSFormula(SFormula) {
; an SFormula that calls a UserTransform
public:
import "common.ulb"
func JLB_UXSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_UX = new @f_UX(this)
if @addT > 0
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex znew = m_UX.Iterate(S.pz)
if @v_UXSFormula >= 221227
znew = znew + ppc
endif
if @addT == "c" ; "c" added 230429
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
UserTransform m_UX
UtilityTransform finalTransform
complex ppc
default:
rating = NotRecommended
title = "UserTransform"
int param v_UXSFormula
caption = "Version (UX_SFormula)"
default = 221227
; hint = "This version parameter is used to detect when a change has \
; been made to the formula that is incompatible with the \
; previous version. When that happens, this field will reflect \
; the old version number to alert you to the fact that an \
; alternate rendering is being used."
visible = @v_UXSFormula < 221227
endparam
heading
text = "(Current is 221227.)"
visible = @v_UXSFormula < 221227
endheading
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_UXSFormula >= 221227
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_UXSFormula >= 221227 && !@p_Mtype
endparam
heading
caption = "znew = T(z) + c"
endheading
UserTransform param f_UX
caption = "Transform T"
default = JLB_BasicUserTransform
endparam
heading
caption = "Tweak after each iteration"
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
}
class JLB_PFSFormula(SFormula) {
; an SFormula that calls a DivergentFormula
public:
import "common.ulb"
import "Standard.ulb"
func JLB_PFSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_PF = new @f_PF(this)
endfunc
func Init(complex pz, complex pc)
m_PF.Init(#pixel)
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
S.pz = m_PF.Iterate(S.pz)
S.Update(S.pz, S.pc)
return S.bailed
endfunc
protected:
Formula m_PF
default:
rating = NotRecommended
title = "Plug-In Formula"
int param v_PFSFormula
caption = "Version (PFSFormula)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PFSFormula < 100
endparam
Formula param f_PF
caption = "Plug-In Formula"
default = Standard_Mandelbrot
endparam
}
class JLB_GnarlSFormula(SFormula) {
; Based on the Gnarl formula from mt.ufm, as a SFormula.
; Calculate dx and dy based on the real or imaginary part of z, then combine.
; Add a multiple of z, #pixell, or a seed.
public:
import "common.ulb"
func JLB_GnarlSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180))
if @type == 1
m_SFormula1 = new @f_SFormula1(this)
m_SFormula2 = new @f_SFormula2(this)
m_SFormula3 = new @f_SFormula3(this)
endif
if @addT > 0
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if (@ctype == "seed")
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if s.bailed
return true
endif
if s.tooMany
return false
endif
complex pz = S.pz
complex znew
float xc
float yc
if (@ctype == "z")
xc = real(pz)
yc = imag(pz)
elseif (@ctype == "seed")
xc = real(ppc)
yc = imag(ppc)
else;if (@ctype == "pixel")
xc = real(#pixel)
yc = imag(#pixel)
endif
complex zrot = pz * m_rot
float x = real(zrot)
float y = imag(zrot)
complex dx
complex dy
if @type == "function"
float px, float py, float qx, float qy
if @args == "x,y"
px = x, qx = xc, py = y, qy = yc
else ; "y,x" the original version
px = y, qx = yc, py = x, qy = xc
endif
if (@mode == 0) ; f(f(f()))
dx = @a1*@f1(@b1*px + @a2*@f2(@b2*px + @a3*@f3(@b3*px))) + @a4*qx
dy = @a1*@f1(@b1*py + @a2*@f2(@b2*py + @a3*@f3(@b3*py))) + @a4*qy
else ; f()+f()+f()
dx = @a1*@f1(@b1*px) + @a2*@f2(@b2*px) + @a3*@f3(@b3*px) + @a4*qx
dy = @a1*@f1(@b1*py) + @a2*@f2(@b2*py) + @a3*@f3(@b3*py) + @a4*qy
endif
if @v_GnarlSFormula <= 100
dx = real(dx)
dy = real(dy)
endif
else ; @type = "formula"
complex zz
float q
if @mode == 0 ; f(f(f()))
if @v_GnarlSFormula <= 100
zz = flip(zrot), q = yc
else
if @args == "x,y"
zz = x, q = xc
else ; "y,x" the original version
zz = y, q = yc
endif
endif
S.pz = zz
m_SFormula3.Iterate(S)
S.pz = zz + @a3 * S.pz
m_SFormula2.Iterate(S)
S.pz = zz + @a2 * S.pz
m_SFormula1.Iterate(S)
dx = @a1*S.pz + @a4*q
if @v_GnarlSFormula <= 100
dx = real(dx) ; real(a1*f1(zz+a2*f2(zz+a3*f3(zz)))+a4*yc)
zz = zrot, q = xc
else
if @args == "x,y"
zz = y, q = yc
else ; "y,x" the original version
zz = x, q = xc
endif
endif
S.pz = zz
m_SFormula3.Iterate(S)
S.pz = zz + @a3 * S.pz
m_SFormula2.Iterate(S)
S.pz = zz + @a2 * S.pz
m_SFormula1.Iterate(S)
dy = @a1*S.pz + @a4*q
if @v_GnarlSFormula <= 100
dy = real(dy) ; real(a1*f1(zz+a2*f2(zz+a3*f3(zz)))+a4*xc)
endif
else ; f()+f()+f()
complex t1
complex t2
complex t3
if @v_GnarlSFormula <= 100
zz = flip(zrot), q = yc
else
if @args == "x,y"
zz = x, q = xc
else ; "y,x" the original version
zz = y, q = yc
endif
endif
S.pz = zz
m_SFormula3.Iterate(S)
t3 = S.pz
S.pz = zz
m_SFormula2.Iterate(S)
t2 = S.pz
S.pz = zz
m_SFormula1.Iterate(S)
t1 = S.pz
dx = @a1*t1 + @a2*t2 + @a3*t3 + @a4*q
if @v_GnarlSFormula <= 100
dx = real(dx)
q = xc
else
if @args == "x,y"
zz = y, q = yc
else ; "y,x" the original version
zz = x, q = xc
endif
endif
S.pz = zz
m_SFormula3.Iterate(S)
t3 = S.pz
S.pz = zz
m_SFormula2.Iterate(S)
t2 = S.pz
S.pz = zz
m_SFormula1.Iterate(S)
t1 = S.pz
dy =@a1*t1 + @a2*t2 + @a3*t3 + @a4*q
if @v_GnarlSFormula <= 100
dy = real(dy)
endif
endif
endif
if (@xop=="-")
dx = -dx
endif
if (@yop=="-")
dy = -dy
endif
znew = pz + @step * (dx + flip(dy))
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex m_rot
SFormula m_SFormula1
SFormula m_SFormula2
SFormula m_SFormula3
complex ppc
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Gnarl"
int param v_GnarlSFormula
caption = "Version (Gnarl_SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_GnarlSFormula < 200
endparam
; bool param p_Mtype
; caption = "M-type?"
; default = true
; visible = @v_GnarlSFormula > 100
; endparam
heading
caption = "Gnarl3 is Recommended instead of Gnarl"
endheading
param type
caption = "type"
enum = "function" "formula"
default = 0
hint = "function = built-in functions, like sin; formula = any SFormula plug-in"
endparam
param mode
caption = "mode"
enum = "f(f(f()))" "f()+f()+f()"
default = 1
endparam
float param theta
caption = "Theta"
default = 0
hint = "First rotate z by this much (360 = full circle)"
endparam
param args
caption = "args"
enum = "x,y" "y,x"
default = 1
endparam
heading
endheading
complex param a1
caption = "Gnarl a1"
default = 1
hint = "multiplies f1"
endparam
complex param b1
caption = "Gnarl b1"
default = 1
hint = "multiplies f1's arg"
visible = @type == 0
endparam
func f1
caption = "Gnarl f1"
default = cos()
hint = "Gnarl left function"
visible = @type == 0
endfunc
SFormula param f_SFormula1
caption = "Gnarl formula 1"
default = JLB_FuncSFormula
visible = @type == 1
endparam
heading
endheading
complex param a2
caption = "Gnarl a2"
default = 2.7
hint = "multiplies f2"
endparam
complex param b2
caption = "Gnarl b2"
default = 2.7
hint = "multiplies f2's arg"
; visible=( (@a1*@a2) != 0)
visible = @type == 0
endparam
func f2
caption = "Gnarl f2"
default = sin()
hint = "second function"
visible = @type == 0
endfunc
SFormula param f_SFormula2
caption = "Gnarl formula 2"
default = JLB_FuncSFormula
visible = @type == 1
endparam
heading
endheading
complex param a3
caption = "Gnarl a3"
default = 0
hint = "multiplies f3"
endparam
complex param b3
caption = "Gnarl b3"
default = 1
hint = "multiplies f3's arg"
visible = @type == 0
endparam
func f3
caption = "Gnarl f3"
default = sqr()
hint = "inmost or right function"
visible = @type == 0
; visible=( (@a1*@a2*@a3) != 0)
endfunc
SFormula param f_SFormula3
caption = "Gnarl formula 3"
default = JLB_FuncSFormula
visible = @type == 1
endparam
heading
endheading
complex param a4
caption = "Gnarl a4"
default = 1.0
hint = "multiplies final addition"
endparam
param ctype
enum = "z" "seed" "pixel"
caption = "final addition"
;hint = "makes a difference sometimes"
default = 0
endparam
complex param p_seed
caption = "Seed"
default = (0.3, 0)
visible = @v_GnarlSFormula > 100 && @ctype==1
endparam
heading
endheading
param step
caption = "Step_size"
default = 0.1
hint = "How much of this to use. z_new = z + Step_size * z_calc"
endparam
param xop
enum = "+" "-"
default = 1
hint = "multiply real part of z_calc"
endparam
param yop
enum = "+" "-"
default = 0
hint = "multiply imaginary part of z_calc"
endparam
heading
caption = "Tweak after each iteration"
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
}
class JLB_Gnarl2SFormula(SFormula) {
; Based on the Gnarl formula from mt.ufm, as a SFormula.
; Calculate dx and dy based on the real or imaginary part of z, then combine.
; Add a multiple of z, #pixell, or a seed.
public:
import "common.ulb"
func JLB_Gnarl2SFormula(Generic pparent)
SFormula.SFormula(pparent)
m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180))
if @type == 1
m_Sf1 = new @f_SFormula1(this)
m_Sf2 = new @f_SFormula2(this)
m_Sf3 = new @f_SFormula3(this)
endif
m_Combine = new Combine()
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if s.bailed
return true
endif
if s.tooMany
return false
endif
complex pz = S.pz
; complex pc = @p_seed
complex znew
float xc
float yc
if @v_Gnarl2SFormula < 220
if (@ctype == "z")
xc = real(pz)
yc = imag(pz)
elseif (@ctype == "seed")
xc = real(@p_seed)
yc = imag(@p_seed)
else;if (@ctype == "pixel")
xc = real(#pixel)
yc = imag(#pixel)
endif
else
if (@ctype1 == "z")
xc = real(pz)
yc = imag(pz)
elseif (@ctype1 == "seed (J-type)")
xc = real(@p_seed)
yc = imag(@p_seed)
else;if (@ctype1 == "pixel(M-type)")
xc = real(#pixel)
yc = imag(#pixel)
endif
endif
complex zrot = pz * m_rot
float x = real(zrot)
float y = imag(zrot)
complex dx = 0 ; satisfy compiler
complex dy = 0 ; ditto
complex tx1, complex tx2, complex tx3
complex ty1, complex ty2; complex ty3
complex px, complex py, complex qx, complex qy
if @args == "x,y"
px = x, qx = xc, py = y, qy = yc
else ; "y,x" the original version, usually better
px = y, qx = yc, py = x, qy = xc
endif
if @mode == 0 ;"f1 op1 f2"
;tx2 = @a2*@f2(@b2*px)
;ty2 = @a2*@f2(@b2*py)
tx2 = iter(2, px, qx, S)
ty2 = iter(2, py, qy, S)
if @op1a == "( )" ; f1(f2(.))
; dx = @a1*@f1(@b1*tx2)
; dy = @a1*@f1(@b1*ty2)
dx = iter(1, @a0*px + tx2, qx, S)
dy = iter(1, @a0*py + ty2, qy, S)
else ; f1(.) op1 f2(.)
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, px, qx, S)
ty1 = iter(1, py, qy, S)
dx = m_Combine.go(tx1, @op1a, tx2)
dy = m_Combine.go(ty1, @op1a, ty2)
endif
elseif @mode == 1 ;"f1 op1 (f2 op2 f3)"
if @op2a == "( )" ; f1 op f2(f3(.))
; tx3 = @a3*@f3(@b3*px)
; ty3 = @a3*@f3(@b3*py)
tx3 = iter(3, px, qx, S)
ty3 = iter(3, py, qy, S)
; tx2 = @a2*@f2(@b2*tx3)
; ty2 = @a2*@f2(@b2*ty3)
tx2 = iter(2, @a0*px + tx3, qx, S)
ty2 = iter(2, @a0*py + ty3, qy, S)
if @op1 == "( )" ; f1(f2(f3(.)))
; dx = @a1*@f1(@b1*tx2)
; dy = @a1*@f1(@b1*ty2)
dx = iter(1, @a0*px + tx2, qx, S)
dy = iter(1, @a0*py + ty2, qy, S)
else ; f1(.) op1 f2(f3(.))
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, px, qx, S)
ty1 = iter(1, py, qy, S)
dx = m_Combine.go(tx1, @op1, tx2)
dy = m_Combine.go(ty1, @op1, ty2)
endif
else
; tx3 = @a3*@f3(@b3*px)
; ty3 = @a3*@f3(@b3*py)
tx3 = iter(3, px, qx, S)
ty3 = iter(3, py, qy, S)
; tx2 = @a2*@f2(@b2*px)
; ty2 = @a2*@f2(@b2*py)
tx2 = iter(2, px, qx, S)
ty2 = iter(2, py, qy, S)
tx2 = m_Combine.go(tx2, @op2a, tx3)
ty2 = m_Combine.go(ty2, @op2a, ty3)
if @op1 == "( )" ; f1(f2(.) op2a f3(.))
; dx = @a1*@f1(@b1*tx2)
; dy = @a1*@f1(@b1*ty2)
dx = iter(1, @a0*px + tx2, qx, S)
dy = iter(1, @a0*py + ty2, qy, S)
else
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, px, qx, S)
ty1 = iter(1, py, qy, S)
dx = m_Combine.go(tx1, @op1, tx2)
dy = m_Combine.go(ty1, @op1, ty2)
endif
endif
else ;@omode == "(f1 op1 f2) op2 f3"
; @op3a == "()" not allowed with this ordering
; tx2 = @a2*@f2(@b2*px)
; ty2 = @a2*@f2(@b2*py)
tx2 = iter(2, px, qx, S)
ty2 = iter(2, py, qy, S)
if @op1 == "( )" ; (f1(f2(.))) op2b f3(.)
; tx1 = @a1*@f1(@b1*tx2)
; ty1 = @a1*@f1(@b1*ty2)
tx1 = iter(1, @a0*px + tx2, qx, S)
ty1 = iter(1, @a0*py + ty2, qy, S)
else
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, px, qx, S)
ty1 = iter(1, py, qy, S)
tx1 = m_Combine.go(tx1, @op1, tx2)
ty1 = m_Combine.go(ty1, @op1, ty2)
endif
; tx3 = @a3*@f3(@b3*px)
; ty3 = @a3*@f3(@b3*py)
tx3 = iter(3, px, qx, S)
ty3 = iter(3, py, qy, S)
dx = m_Combine.go(tx1, @op2b, tx3)
dy = m_Combine.go(ty1, @op2b, ty3)
endif
dx = dx + @a4*qx
dy = dy + @a4*qy
if @v_Gnarl2SFormula < 230
if (@xop=="-")
dx = -dx
endif
if (@yop=="-")
dy = -dy
endif
else
if @xyop == "-dx +dy" || @xyop == "-dx -dy"
dx = -dx
endif
if @xyop == "+dx -dy" || @xyop == "-dx -dy"
dy = -dy
endif
endif
znew = pz + @step * (dx + flip(dy))
S.Update(znew, S.pc)
return S.bailed
endfunc
complex func iter(int n, complex v, complex c, State S)
if @type == 0
if n == 1
return @a1*@f1(@b1*v)
elseif n == 2
return @a2*@f2(@b2*v)
else
return @a3*@f3(@b3*v)
endif
else
complex pz = S.pz ; save these
complex pc = S.pz
S.pc = c
complex t
if n == 1
S.pz = @b1*v
m_Sf1.Iterate(S)
t = @a1*S.pz
elseif n == 2
S.pz = @b2*v
m_Sf2.Iterate(S)
t = @a2*S.pz
else
S.pz = @b3*v
m_Sf3.Iterate(S)
t = @a3*S.pz
endif
S.pz = pz, S.pc = pc
return t
endif
endfunc
;protected:
complex m_rot
SFormula m_Sf1
SFormula m_Sf2
SFormula m_Sf3
Combine m_Combine
default:
rating = NotRecommended
title = "Gnarl2"
int param v_Gnarl2SFormula
caption = "Version (Gnarl2_SFormula)"
default = 230
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_Gnarl2SFormula < 230
endparam
heading
caption = "Gnarl2 doesn't work quite as promised; use Gnarl3 instead."
endheading
param ctype
enum = "z" "seed" "pixel"
caption = "final addition"
;hint = "makes a difference sometimes"
default = 0
visible = @v_Gnarl2SFormula < 220
endparam
complex param p_seed
caption = "Seed"
default = (0.3, 0)
visible = (@ctype==1 || @ctype1 == 1)
endparam
param type
caption = "Type"
enum = "built-in function" "Sformula"
default = 0
;hint = "function = built-in functions, like sin; formula = any SFormula plug-in"
endparam
param mode
caption = "How to combine"
default = 0
enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3"
endparam
complex param a0
caption = "a0"
default = 0
visible = @type == 1 && ( \
(@mode == 0 && @op1a == 5) || \
(@mode == 1 && (@op1 == 5 || @op2a == 5)) || \
(@mode == 2 && @op1 == 5) )
endparam
param op1
caption = "Operator 1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine Formula values."
visible = @mode > 0
endparam
param op1a
caption = "Operator"
enum = "+" "-" "*" "/" "^" "( )"
default = 5
hint = "How to combine Formula values."
visible = @mode == 0
endparam
param op2a
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
hint = "How to combine Formula values."
visible = (@mode == 1)
endparam
param op2b
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default = 2
hint = "How to combine Formula values."
visible = (@mode == 2)
endparam
float param theta
caption = "Theta"
default = 0
hint = "First rotate z by this much (360 = full circle)"
endparam
param args
caption = "args"
enum = "x,y" "y,x"
default = 1
endparam
heading
caption = "a1*f1(b1*v)"
endheading
complex param a1
caption = "Gnarl2 a1"
default = 1
hint = "multiplies f1"
endparam
complex param b1
caption = "Gnarl2 b1"
default = 1
hint = "multiplies f1's arg"
endparam
func f1
caption = "Gnarl2 f1"
default = cos()
hint = "outer or left function"
visible = @type == 0
endfunc
SFormula param f_SFormula1
caption = "Gnarl2 formula 1"
default = JLB_FuncSFormula
visible = @type >= 1
endparam
heading
caption = "a2*f2(b2*v)"
endheading
complex param a2
caption = "Gnarl2 a2"
default = 2.7
hint = "multiplies f2"
endparam
complex param b2
caption = "Gnarl2 b2"
default = 2.7
hint = "multiplies f2's arg"
; visible=( (@a1*@a2) != 0)
endparam
func f2
caption = "Gnarl2 f2"
default = sin()
hint = "second function"
visible = @type == 0
endfunc
SFormula param f_SFormula2
caption = "Gnarl2 formula 2"
default = JLB_FuncSFormula
visible = @type >= 1
endparam
heading
caption = "a3*f3(b3*v)"
visible = @mode > 0
endheading
complex param a3
caption = "Gnarl2 a3"
default = 0
hint = "multiplies f3"
visible = @mode > 0
endparam
complex param b3
caption = "Gnarl2 b3"
default = 1
hint = "multiplies f3's arg"
visible = @mode > 0
endparam
func f3
caption = "Gnarl2 f3"
default = sqr()
hint = "inmost or right function"
visible = @type == 0 && @mode > 0
endfunc
SFormula param f_SFormula3
caption = "Gnarl2 formula3"
default = JLB_FuncSFormula
visible = @type >= 1 && @mode > 0
endparam
heading
caption = "finally..."
endheading
param xyop
enum = "+dx +dy" "+dx -dy" "-dx +dy" "-dx -dy"
default = 1
hint = "final multiplcations of real and imaginary parts of z_calc"
visible = @v_Gnarl2SFormula >= 230
endparam
param ctype1
enum = "pixel (M-type)" "seed (J-type)" "z"
caption = "final addition of c"
default = 0
visible = @v_Gnarl2SFormula >= 230
endparam
; heading
; caption = "multiplies c"
; endheading
complex param a4
caption = "c multiplier"
default = 1.0
hint = "multiplies final addition"
endparam
param step
caption = "Gnarl2 Step_size"
default = 0.1
hint = "How much of this to use. z_new = z + Step_size * z_calc"
endparam
param xop
enum = "+" "-"
default = 1
hint = "multiply real part of z_calc"
visible = @v_Gnarl2SFormula < 230
endparam
param yop
enum = "+" "-"
default = 0
hint = "multiply imaginary part of z_calc"
visible = @v_Gnarl2SFormula < 230
endparam
}
class JLB_Gnarl3SFormula(SFormula) {
; Based on the Gnarl formula from mt.ufm, as a SFormula.
; Calculate dx and dy based on the real or imaginary part of z, then combine.
; Add a multiple of z, #pixel, or a seed.
; Corrected version of Gnarl2, June 2021.
public:
import "common.ulb"
func JLB_Gnarl3SFormula(Generic pparent)
SFormula.SFormula(pparent)
m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180))
if @type == 1
m_Sf1 = new @f_SFormula1(this)
m_Sf2 = new @f_SFormula2(this)
m_Sf3 = new @f_SFormula3(this)
endif
m_Combine = new Combine()
if @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if (@ctype1 == "seed (J-type)")
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if s.bailed
return true
endif
if s.tooMany
return false
endif
complex pz = S.pz
; complex pc = @p_seed
complex znew
float xc
float yc
if (@ctype1 == "z")
xc = real(pz)
yc = imag(pz)
elseif (@ctype1 == "seed (J-type)")
xc = real(ppc)
yc = imag(ppc)
else;if (@ctype1 == "pixel(M-type)")
xc = real(#pixel)
yc = imag(#pixel)
endif
complex zrot = pz * m_rot
float x = real(zrot)
float y = imag(zrot)
complex dx = 0 ; satisfy compiler
complex dy = 0 ; ditto
complex tx1, complex tx2, complex tx3
complex ty1, complex ty2; complex ty3
complex px, complex py, complex qx, complex qy
if @args == "x,y"
px = x, qx = xc, py = y, qy = yc
else ; "y,x" the original version, usually better
px = y, qx = yc, py = x, qy = xc
endif
if @mode == 0 ;"f1 op1 f2"
;tx2 = @a2*@f2(@b2*px)
;ty2 = @a2*@f2(@b2*py)
tx2 = iter(2, @b2*px, qx, S)
ty2 = iter(2, @b2*py, qy, S)
if @op1a == "( )" ; f1(f2(.))
; dx = @a1*@f1(@b1*tx2)
; dy = @a1*@f1(@b1*ty2)
dx = iter(1, @b1*px + tx2, qx, S) ; wrong!
dy = iter(1, @b1*py + ty2, qy, S)
else ; f1(.) op1 f2(.)
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, @b1*px, qx, S)
ty1 = iter(1, @b1*py, qy, S)
dx = m_Combine.go(tx1, @op1a, tx2)
dy = m_Combine.go(ty1, @op1a, ty2)
endif
elseif @mode == 1 ;"f1 op1 (f2 op2 f3)"
if @op2a == "( )" ; f1 op f2(f3(.))
; tx3 = @a3*@f3(@b3*px)
; ty3 = @a3*@f3(@b3*py)
tx3 = iter(3, @b3*px, qx, S)
ty3 = iter(3, @b3*py, qy, S)
; tx2 = @a2*@f2(@b2*tx3)
; ty2 = @a2*@f2(@b2*ty3)
tx2 = iter(2, @b2*px + tx3, qx, S)
ty2 = iter(2, @b2*py + ty3, qy, S)
if @op1 == "( )" ; f1(f2(f3(.)))
; dx = @a1*@f1(@b1*tx2)
; dy = @a1*@f1(@b1*ty2)
dx = iter(1, @b1*px + tx2, qx, S)
dy = iter(1, @b1*py + ty2, qy, S)
else ; f1(.) op1 f2(f3(.))
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, @b1*px, qx, S)
ty1 = iter(1, @b1*py, qy, S)
dx = m_Combine.go(tx1, @op1, tx2)
dy = m_Combine.go(ty1, @op1, ty2)
endif
else
; tx3 = @a3*@f3(@b3*px)
; ty3 = @a3*@f3(@b3*py)
tx3 = iter(3, @b3*px, qx, S)
ty3 = iter(3, @b3*py, qy, S)
; tx2 = @a2*@f2(@b2*px)
; ty2 = @a2*@f2(@b2*py)
tx2 = iter(2, @b2*px, qx, S)
ty2 = iter(2, @b2*py, qy, S)
tx2 = m_Combine.go(tx2, @op2a, tx3)
ty2 = m_Combine.go(ty2, @op2a, ty3)
if @op1 == "( )" ; f1(f2(.) op2a f3(.))
; dx = @a1*@f1(@b1*tx2)
; dy = @a1*@f1(@b1*ty2)
dx = iter(1, @b1*px + tx2, qx, S)
dy = iter(1, @b1*py + ty2, qy, S)
else
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, @b1*px, qx, S)
ty1 = iter(1, @b1*py, qy, S)
dx = m_Combine.go(tx1, @op1, tx2)
dy = m_Combine.go(ty1, @op1, ty2)
endif
endif
else ;@omode == "(f1 op1 f2) op2 f3"
; @op3a == "()" not allowed with this ordering
; tx2 = @a2*@f2(@b2*px)
; ty2 = @a2*@f2(@b2*py)
tx2 = iter(2, @b2*px, qx, S)
ty2 = iter(2, @b2*py, qy, S)
if @op1 == "( )" ; (f1(f2(.))) op2b f3(.)
; tx1 = @a1*@f1(@b1*tx2)
; ty1 = @a1*@f1(@b1*ty2)
tx1 = iter(1, @b1*px + tx2, qx, S)
ty1 = iter(1, @b1*py + ty2, qy, S)
else
; tx1 = @a1*@f1(@b1*px)
; ty1 = @a1*@f1(@b1*py)
tx1 = iter(1, @b1*px, qx, S)
ty1 = iter(1, @b1*py, qy, S)
tx1 = m_Combine.go(tx1, @op1, tx2)
ty1 = m_Combine.go(ty1, @op1, ty2)
endif
; tx3 = @a3*@f3(@b3*px)
; ty3 = @a3*@f3(@b3*py)
tx3 = iter(3, @b3*px, qx, S)
ty3 = iter(3, @b3*py, qy, S)
dx = m_Combine.go(tx1, @op2b, tx3)
dy = m_Combine.go(ty1, @op2b, ty3)
endif
dx = dx + @a4*qx
dy = dy + @a4*qy
if @xyop == "-dx +dy" || @xyop == "-dx -dy"
dx = -dx
endif
if @xyop == "+dx -dy" || @xyop == "-dx -dy"
dy = -dy
endif
znew = pz + @step * (dx + flip(dy))
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
complex func iter(int n, complex v, complex c, State S)
if @type == 0
if n == 1
return @a1*@f1(v)
elseif n == 2
return @a2*@f2(v)
else
return @a3*@f3(v)
endif
else
complex pz = S.pz ; save these
complex pc = S.pz
S.pc = c
complex t
if n == 1
S.pz = v
m_Sf1.Iterate(S)
t = @a1*S.pz
elseif n == 2
S.pz = v
m_Sf2.Iterate(S)
t = @a2*S.pz
else
S.pz = v
m_Sf3.Iterate(S)
t = @a3*S.pz
endif
S.pz = pz, S.pc = pc
return t
endif
endfunc
;protected:
complex m_rot
SFormula m_Sf1
SFormula m_Sf2
SFormula m_Sf3
Combine m_Combine
complex ppc
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Gnarl3"
int param v_Gnarl3SFormula
caption = "Version (Gnarl3_SFormula)"
default = 1
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_Gnarl3SFormula < 1
endparam
; bool param p_std
; caption = "Standard"
; default = true
; endparam
param type
caption = "Type"
enum = "built-in function" "Sformula"
default = 0
;hint = "function = built-in functions, like sin; formula = any SFormula plug-in"
endparam
param mode
caption = "How to combine"
default = 1
enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3"
endparam
param op1
caption = "Operator 1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine Formula values."
visible = @mode > 0
endparam
param op1a
caption = "Operator"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine Formula values."
visible = @mode == 0
endparam
param op2a
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
hint = "How to combine Formula values."
visible = (@mode == 1)
endparam
param op2b
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default = 2
hint = "How to combine Formula values."
visible = (@mode == 2)
endparam
float param theta
caption = "Theta"
default = 0
hint = "First rotate z by this much (360 = full circle)"
endparam
param args
caption = "args"
enum = "x,y" "y,x"
default = 1
endparam
heading
caption = "a1*f1(b1*v)"
endheading
complex param a1
caption = "Gnarl3 a1"
default = 1
hint = "multiplies f1"
endparam
complex param b1
caption = "Gnarl3 b1"
default = 2
hint = "multiplies f1's arg"
endparam
func f1
caption = "Gnarl3 f1"
default = sin()
hint = "outer or left function"
visible = @type == 0
endfunc
SFormula param f_SFormula1
caption = "Gnarl3 formula 1"
default = JLB_FuncSFormula
visible = @type >= 1
endparam
heading
caption = "a2*f2(b2*v)"
endheading
complex param a2
caption = "Gnarl3 a2"
default = 2.7
hint = "multiplies f2"
endparam
complex param b2
caption = "Gnarl3 b2"
default = 2.7
hint = "multiplies f2's arg"
endparam
func f2
caption = "Gnarl3 f2"
default = sin()
hint = "second function"
visible = @type == 0
endfunc
SFormula param f_SFormula2
caption = "Gnarl3 formula 2"
default = JLB_FuncSFormula
visible = @type >= 1
endparam
heading
caption = "a3*f3(b3*v)"
visible = @mode > 0
endheading
complex param a3
caption = "Gnarl3 a3"
default = 0
hint = "multiplies f3"
visible = @mode > 0
endparam
complex param b3
caption = "Gnarl3 b3"
default = 1
hint = "multiplies f3's arg"
visible = @mode > 0
endparam
func f3
caption = "Gnarl3 f3"
default = sqr()
hint = "inmost or right function"
visible = @type == 0 && @mode > 0
endfunc
SFormula param f_SFormula3
caption = "Gnarl3 formula3"
default = JLB_FuncSFormula
visible = @type >= 1 && @mode > 0
endparam
heading
caption = "finally..."
endheading
param xyop
enum = "+dx +dy" "+dx -dy" "-dx +dy" "-dx -dy"
default = 1
hint = "final multiplcations of real and imaginary parts of z_calc"
endparam
param ctype1
enum = "pixel (M-type)" "seed (J-type)" "z"
caption = "final addition of c"
default = 0
endparam
complex param p_seed
caption = "Seed"
default = (0.3, 0)
visible = @ctype1 == 1
endparam
complex param a4
caption = "c multiplier"
default = 1.0
hint = "multiplies final addition"
endparam
param step
caption = "Gnarl3 Step_size"
default = 0.1
hint = "How much of this to use. z_new = z + Step_size * z_calc"
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
class JLB_GnarlySFormula(SFormula) {
; Similar in concept to Dynamical Systems in mt.ufm
public:
import "common.ulb"
func JLB_GnarlySFormula(Generic pparent)
SFormula.SFormula(pparent)
m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180))
m_SFormula1 = new @f_SFormula1(this)
m_SFormula2 = new @f_SFormula2(this)
if @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_GnarlySFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex znew
complex zrot = pz * m_rot
float dx
float dy
S.pz = imag(zrot) + flip(real(zrot))
m_SFormula1.Iterate(S)
dx = real(S.pz)
S.pz = zrot
m_SFormula2.Iterate(S)
dy = real(S.pz)
if (@xop=="-")
dx = -dx
endif
if (@yop=="-")
dy = -dy
endif
znew = pz + @step * (dx + flip(dy)) + ppc
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex m_rot
SFormula m_SFormula1
SFormula m_SFormula2
complex ppc
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Gnarly"
int param v_GnarlySFormula
caption = "Version (Gnarly_SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_GnarlySFormula < 200
endparam
; bool param p_std
; caption = "Standard"
; default = true
; endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_GnarlySFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_GnarlySFormula > 100 && !@p_Mtype
endparam
SFormula param f_SFormula1
caption = "dx formula"
default = JLB_FuncSFormula
endparam
SFormula param f_SFormula2
caption = "dy formula"
default = JLB_FuncSFormula
endparam
float param theta
caption = "Theta"
default = 0
hint = "First rotate z by this much (360 = full circle)"
endparam
param ctype
enum = "z" "c" "pixel"
caption = "c multiplier"
default = 0
endparam
param step
caption = "Step_size"
default = 0.1
hint = "How much of this to use. z_new = z + Step_size * z_calc"
endparam
param xop
enum = "+" "-"
default = 1
hint = "multiply real part of z_calc"
endparam
param yop
enum = "+" "-"
default = 0
hint = "multiply imaginary part of z_calc"
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
; August 2020
; Fixed grad function
; Changed to JLB_Random
; Noise based on #screenpixel, not on pz!
class JLB_Perlin3DNoiseSFormula(SFormula) {
; Code adapted from https://flafla2.github.io/2014/08/09/perlinnoise.html
; (Not Ken Perlin's original version.)
; pc not used
public:
import "common.ulb"
func JLB_Perlin3DNoiseSFormula(Generic pparent)
SFormula.SFormula(pparent)
;m_FractalCoordinate = new FractalCoordinate(this)
r = new JLB_Random(0)
r.Init(@seed)
int i = 0 ; generate random permutation of integers 0 - 255
while i < 256
px[i] = py[i] = i
i = i + 1
endwhile
int tmp
int j
r.SetNMax(256)
j = 0
while j < 256
i = r.RandomIntInRange(0)
tmp = px[i]
px[i] = px[j]
px[j] = tmp
j = j + 1
endwhile
j = 0
while j < 256
i = r.RandomIntInRange(0)
tmp = py[i]
py[i] = py[j]
py[j] = tmp
j = j + 1
endwhile
i = 0
while i < 256
px[i+512] = px[i+256] = px[i]
py[i+512] = py[i+256] = py[i]
i = i + 1
endwhile
px[768] = px[0] ; in case of overflow in grad, bbb line
py[768] = py[0]
endfunc
func Init(complex pz, complex pc)
;m_FractalCoordinate.Init(pz)
endfunc
; @param pz
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex tz = #screenpixel ; NOT m_FractalCoordinate.Iterate(#screenpixel)
float tx = real(tz)
float ty = imag(tz)
m_doingX = true
complex dx = OctavePerlin(tx, ty, @zz-#pi/2) ; @zz always 0
m_doingX = false
complex dy = OctavePerlin(tx, ty, @zz+#pi/2)
; scale so range is about (-1,+1) if strength ~ 1
complex znew = @strength * (2 / #magn) * (dx + flip(dy))
if !@do_dz
znew = S.pz + znew
endif
S.update(znew, S.pc)
return S.bailed
endfunc
float func OctavePerlin(float x, float y, float z)
float total = 0
float freq = @frequency / 100 ; empirical scaling
float amp = 1
float maxValue = 0
int i = 0
while i < @octaves
total = total + amp * perlin(x*freq, y*freq, z*freq)
maxValue = maxValue + amp
amp = amp * @persistence
freq = 2 * freq
i = i + 1
endwhile
return 2*total/maxValue - 1.0
endfunc
float func perlin(float x, float y, float z)
x = x % 256
y = y % 256
z = z % 256
int xi = floor(x) ; Calculate the "unit cube" that the point asked will be located in.
int yi = floor(y) ; The left bound is ( xi, yi, zi) and the right bound is that plus 1.
int zi = floor(z)
float xf = x - floor(x)
float yf = y - floor(y) ; Next we calculate the location (from 0.0 to 1.0) in that cube.
float zf = z - floor(z)
float u = fade(xf); ; We also fade the location to smooth the result.
float v = fade(yf);
float w = fade(zf);
int aaa, int aba, int aab, int abb
int baa, int bba, int bab, int bbb
if m_doingX
aaa = px[px[px[ xi ]+ yi ]+ zi ]
aba = px[px[px[ xi ]+ 1+yi ]+ zi ]
aab = px[px[px[ xi ]+ yi ]+ 1+zi ]
abb = px[px[px[ xi ]+ 1+yi ]+ 1+zi ]
baa = px[px[px[ 1+xi ]+ yi ]+ zi ]
bba = px[px[px[ 1+xi ]+ 1+yi ]+ zi ]
bab = px[px[px[ 1+xi ]+ yi ]+ 1+zi ] ; if inc just adds 1, max index = 3*256
bbb = px[px[px[ 1+xi ]+ 1+yi ]+ 1+zi ] ; so p needs to be 3*256+1 = 769
else
aaa = py[py[py[ xi ]+ yi ]+ zi ]
aba = py[py[py[ xi ]+ 1+yi ]+ zi ]
aab = py[py[py[ xi ]+ yi ]+ 1+zi ]
abb = py[py[py[ xi ]+ 1+yi ]+ 1+zi ]
baa = py[py[py[ 1+xi ]+ yi ]+ zi ]
bba = py[py[py[ 1+xi ]+ 1+yi ]+ zi ]
bab = py[py[py[ 1+xi ]+ yi ]+ 1+zi ] ; if inc just adds 1, max index = 3*256
bbb = py[py[py[ 1+xi ]+ 1+yi ]+ 1+zi ]
endif
; The gradient function calculates the dot product between a pseudorandom gradient vector
; and the vector from the input coordinate to the 8 surrounding points in its unit cube.
; This is all then lerped together as a sort of weighted average based on the faded (u,v,w).
float x1 = lerp(grad (aaa, xf , yf , zf), grad (baa, xf-1, yf , zf), u)
float x2 = lerp(grad (aba, xf , yf-1, zf), grad (bba, xf-1, yf-1, zf), u)
float y1 = lerp(x1, x2, v)
x1 = lerp(grad (aab, xf , yf , zf-1), grad (bab, xf-1, yf , zf-1), u)
x2 = lerp(grad (abb, xf , yf-1, zf-1), grad (bbb, xf-1, yf-1, zf-1), u)
float y2 = lerp (x1, x2, v)
return (lerp (y1, y2, w) + 1) / 2 ; value between 0 and 1
endfunc
; hash is in [0,255]
float func grad(int hash, float x, float y, float z)
int h = hash % 16; ; Use the last 4 bits of hash
if h == 0, return x + y
elseif h == 1, return -x + y
elseif h == 2, return x - y
elseif h == 3, return -x - y
elseif h == 4, return x + z
elseif h == 5, return -x + z
elseif h == 6, return x - z
elseif h == 7, return -x - z
elseif h == 8, return y + z
elseif h == 9, return -y + z
elseif h ==10, return y - z
elseif h ==11, return -y - z
elseif h ==12, return y + x
elseif h ==13, return -y + z
elseif h ==14, return y - x
else , return -y - z
endif
endfunc
; increment num by 1 with roll-over
; int func inc(int num)
; return (num + 1 ) % 256
; endfunc
; Fade function as defined by Ken Perlin. Replaces linear interpolation between 0 and 1,
; providing continuous first and second derivatives at 0 and 1.
; This ends up smoothing the final output.
float func fade(float t)
return t * t * t * (t * (t * 6 - 15) + 10) ; 6t^5 - 15t^4 + 10t^3
endfunc
; linearly interpret between a and b, assuming that t is from 0 to 1, inclusive
float func lerp(float a, float b, float t)
return a + t * (b - a)
endfunc
protected:
int px[769] ; 3*256 + 1
int py[769]
bool m_doingX
JLB_Random r
default:
title = "Perlin 3D Noise"
rating = NotRecommended
int param v_PerlinNoiseSFormula
caption = "Version (PerlinNoise_SFormula)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PerlinNoiseSFormula < 100
endparam
heading
text = "The noise is based on the screen position. Probably this is best used \
for one iteration as the Initial Fractal, or as a texture layer."
endheading
int param seed
caption ="Seed"
hint = "Seed for random numbers"
default = 12345679
endparam
int param octaves
caption = "Octaves"
default = 3
min = 1
hint = "The lowest octave has the largest amplitude and the lowest frequency. \
Subsequent octaves have lower amplitude and higher frequency. \
Noise is the sum of all octaves."
endparam
float param frequency
caption = "Frequency"
hint = "Frequency of lowest octave noise. Lower values give smoother noise, \
higher values less smooth."
default = 1
endparam
float param strength
caption = "Noise Strength"
default = 0.05
endparam
float param persistence
caption = "Persistence"
hint = "Smaller values give smoother noise."
max = 1.0
min = 0.0
default = 0.5
endparam
float param zz
caption = "3D parameter"
;default = 0
visible = false
endparam
bool param do_dz
caption = "Return dz instead of z?"
default = false
visible = false ; just for debugging
endparam
}
class JLB_BarnsleySFormula(SFormula) {
; A version of a Barnsley formula as a SFormula.
public:
import "common.ulb"
func JLB_BarnsleySFormula(Generic pparent)
SFormula(pparent)
if @addT > 0
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if @v_BarnsleySFormula > 100 && !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
float temp = 0 ; avoid compiler warning
if @mode == "real"
temp = real(pz)
elseif @mode == "imaginary"
temp = imag(pz)
elseif @mode == "angle"
temp = atan2(pz)
elseif @mode == "cross+"
temp = real(pz)*imag(ppc) + imag(pz)*real(ppc)
elseif @mode == "cross-"
temp = real(pz)*imag(ppc) - imag(pz)*real(ppc)
elseif @mode == "dot+"
temp = real(pz)*real(ppc) + imag(pz)*imag(ppc)
elseif @mode == "dot-"
temp = real(pz)*real(ppc) - imag(pz)*imag(ppc)
endif
if temp >= @crit
if @type_hi == "times"
pz = (pz^@pow_hi + @off_hi) * ppc
elseif @type_hi == "plus"
pz = (pz^@pow_hi + @off_hi) + ppc
elseif @type_hi == "minus"
pz = (pz^@pow_hi + @off_hi) - ppc
elseif @type_hi == "divided"
pz = (pz^@pow_hi + @off_hi) / ppc
elseif @type_hi == "exponential"
pz = (pz^@pow_hi + @off_hi) ^ ppc
endif
else
if @type_lo == "times"
pz = (pz^@pow_lo + @off_lo) * ppc
elseif @type_lo == "plus"
pz = (pz^@pow_lo + @off_lo) + ppc
elseif @type_lo == "minus"
pz = (pz^@pow_lo + @off_lo) - ppc
elseif @type_lo == "divided"
pz = (pz^@pow_lo + @off_lo) / ppc
elseif @type_lo == "exponential"
pz = (pz^@pow_lo + @off_lo) ^ ppc
endif
endif
complex znew = pz
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
default:
title = "Barnsley"
rating = NotRecommended
int param v_BarnsleySFormula
caption = "Version (Barnsley_SFormula)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_BarnsleySFormula < 200
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_BarnsleySFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = @v_BarnsleySFormula > 100 && !@p_Mtype
endparam
; parameters to calculate the number to compare to the critical value
heading
text = "Use combinations of real and imaginary parts of z and c\
to calculate value to compare with critical value."
endheading
param mode
caption = "mode"
default = 0
enum = "real" "imaginary" "angle" "cross+" "cross-" "dot+" "dot-"
endparam
float param crit
caption = "critical value"
default = 0.0
endparam
heading
caption = "If value >= critical value"
endheading
heading
caption = " z_new = (z^p1 + a1) op1 c"
endheading
complex param pow_hi
caption = "p1"
;hint = "formula contains z^pow_high + off_high"
default = 2
endparam
complex param off_hi
caption = "a1"
;hint = "formula contains z^pow_high + off_high"
default = (0,0)
endparam
param type_hi
caption = "op1"
default = 0
enum = "times" "plus" "minus" "divided" "exponential"
endparam
heading
caption = "If value < critical value"
endheading
heading
caption = " z_new = (z^p2 + a2) op2 c"
endheading
complex param pow_lo
caption = "p2"
;hint = "formula contains z^pow_low + off_low"
default = 2
endparam
complex param off_lo
caption = "a2"
;hint = "formula contains z^pow_low + off_low"
default = (0,0)
endparam
param type_lo
caption = "op2"
default = 0
enum = "times" "plus" "minus" "divided" "exponential"
endparam
heading
caption = "Tweak after each iteration"
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
}
; class FractalCoordinate(UtilityTransform) {
; Use the one in common.ulb
; }
class JLB_PhoenixContraction(Contraction) {
; The Phoenix formula as a Contraction.
public:
; @param pz
; @param pc
func Init(complex pz, complex pc)
z_older = 0 ; pz ?
endfunc
; @param pz
; @param pc
; @return the new pz
complex func Iterate(complex pz, complex pc)
complex z_new
if @p_std
z_new = sqr(pz) + pc + 0.5 * z_older
z_older = pz
return z_new
else
z_new = pz^@p_power + pc*(pz) + @p_a*z_older
z_older = pz
return z_new
endif
endfunc
protected:
complex z_older
default:
title = "Phoenix"
;rating = Recommended
int param v_Phoenixcontraction
caption = "Version (Phoenix_Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_Phoenixcontraction < 100
endparam
bool param p_std
caption = "Standard"
hint = "z_new = sqr(z_old) + c + a * z_older"
default = true
endparam
complex param p_power
caption = "p1"
default = 2
hint = "z_calc = z_old^p1 + c * z_old^p2 + a * z_older"
visible = !@p_std
endparam
complex param p_p2
caption = "p2"
default = 0
hint = "z_calc = z_old^p1 + c * z_old^p2 + a * z_older"
visible = !@p_std
endparam
complex param p_a
caption = "a"
default = 0.5
hint = "z_calc = z_old^p1 + c * z_old^p2 + a * z_older"
visible = !@p_std
endparam
}
class JLB_NovaContraction(Contraction) {
; The Nova formula as a Contraction.
public:
; @param pz
; @param pc
; @return the new pz
complex func Iterate(complex pz, complex pc)
if (@p_std)
return pz - @relax*(pz*pz*pz-1) / (3*pz*pz) + pc
else
return pz - @relax * (pz^@p_power-1) / (@p_power * pz^(@p_power-1)) + pc
endif
endfunc
private:
default:
title = "Nova"
;rating = NotRecommended
int param v_Novacontraction
caption = "Version (Nova_Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_Novacontraction < 100
endparam
bool param p_std
caption = "Standard"
default = true
endparam
param relax
caption = "Relaxation"
default = (1,0)
hint = "This can be used to slow down the convergence of \
the formula."
endparam
complex param p_power
caption = "Power"
default = (3,0)
visible = !@p_std
endparam
}
class JLB_TalisContraction(Contraction) {
; The Talis formulas, part of the "Switch Talis and friends" formula in tma.ulb,
; as a Contraction.
public:
; @param pz
; @param pc
; @return the new pz
complex func Iterate(complex pz, complex pc)
complex tz = pz
complex tc = pc
if (!@p_std)
tz = tz - @p_zoffset
tc = tc - @p_coffset
endif
if @var == "Talis"
tz =@fn1((tz-@p1)*@p1a)*@fn2(tz)/@fn3(@p2+(@fn4(tz)*@p2a))+\
@fn5(tc-@p3)*@p3a
elseif @var == "Talis Var 1"
tz =@fn1(((tz-@p1)*@p1a)*@fn2(tz)-@fn6(tz)) /@fn3(@p2+(@fn4(tz)*@p2a))+\
@fn5(tc-@p3)*@p3a
elseif @var == "Talis Var 2"
tz =@fn1(((tz-@p1)*@p1a)*@fn2(tz)*@fn6(tz)) /@fn3(@p2+(@fn4(tz)*@p2a))+\
@fn5(tc-@p3)*@p3a
elseif @var == "Talis Var 3"
tz =@fn1(((tz-@p1)*@p1a)*@fn2(tz)*@fn6(tz)*tz) /@fn3(@p2+(@fn4(tz)*@p2a)\
*@fn7(tz)-@fn8(tz))+@fn5(tc-@p3)*@p3a
elseif @var == "Talis Var 4"
tz =@fn1(((tz-@p1)*@p1a)*@fn2(tz)*@fn6(tz)) /@fn3(@p2+(@fn4(tz)*@p2a)\
*@fn7(tz)-@fn8(tz))+@fn5(tc-@p3)*@p3a
elseif @var == "Talis Var 5"
tz =@fn1(((tz-@p1)*@p1a)*@fn2(tz)*@fn6(tz)) /@fn3(@p2+(@fn4(tz)*@p2a)\
*@fn7(tz)-@fn8(tz)-tz)+@fn5(tc-@p3)*@p3a
elseif @var == "Talis Var 6"
tz =@fn1(((tz-@p1)*@p1a)*@fn2(tz)*@fn6(tz)) /@fn3(@p2+(@fn4(tz)*@p2a)\
*@fn7(tz)-@fn8(tz)+tz)+@fn5(tc-@p3)*@p3a
endif
return tz
endfunc
private:
default:
title = "Talis"
;rating = NotRecommended
int param v_Taliscontraction
caption = "Version (Talis_Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_Taliscontraction < 100
endparam
param var
caption = "Formula Type"
enum = "Talis" "Talis Var 1" "Talis Var 2" "Talis Var 3" \
"Talis Var 4" "Talis Var 5" "Talis Var 6"
default = 0
visible = !@p_std
endparam
complex param p1
caption = "1st Z Offset"
default = (0,0)
visible = !@p_std
endparam
complex param p1a
caption = "1st Z Strength"
default = (1,0)
visible = !@p_std
endparam
complex param p2
caption = "2nd Z Offset"
default = (1,0)
visible = !@p_std
endparam
complex param p2a
caption = "2nd Z Strength"
default = (1,0)
visible = !@p_std
endparam
complex param p3
caption = "C Offset"
default = (0,0)
visible = !@p_std
endparam
complex param p3a
caption = "C Strength"
default = (1,0)
visible = !@p_std
endparam
func fn1
caption = "1st Z Function"
default = ident ()
visible = !@p_std
endfunc
func fn2
caption = "2nd Z Function"
default = ident ()
visible = !@p_std
endfunc
func fn3
caption = "3rd Z Function"
default = ident ()
visible = !@p_std
endfunc
func fn4
caption = "Another Function"
default = ident ()
visible = !@p_std
endfunc
func fn5
caption = "C Function"
default = ident ()
visible = !@p_std
endfunc
func fn6
caption = "Extra Z Function"
default = ident ()
visible = @var > 0 && !@p_std
endfunc
func fn7
caption = "Extra Z2 Function"
default = ident ()
visible = @var > 2 && !@p_std
endfunc
func fn8
caption = "Extra Z3 Function"
default = ident ()
visible = @var > 2 && !@p_std
endfunc
complex param p_zoffset
caption = "pz offset"
default = (0,0)
visible = !@p_std
endparam
complex param p_coffset
caption = "pc offset"
default = (0,0)
visible = !@p_std
endparam
bool param p_std
caption = "Standard"
default = true
endparam
}
class JLB_SwitchSuper(mmf.ulb:MMF_SwitchDivergentFormula) {
; A wrapper that enables many formulas to be duplicated
; and new ones made. Plug this into David Makin's
; Generic Switch Formula to do Mandelbrot-style and Julia-style
; formulas.
;
public:
import "common.ulb"
import "mmf.ulb"
func JLB_SwitchSuper(Generic pparent)
MMF_SwitchDivergentFormula.MMF_SwitchDivergentFormula(pparent)
m_BailoutFunc = new @f_bailout(this)
m_DualTransform = new @f_DualTransform(this)
m_DualTransformInit = new @f_DualTransformInit(this)
endfunc
; @param pz
; @Initialize
complex func Init(complex pz)
m_BailoutFunc.Init(@p_bailout) ; from parent class
pz = MMF_SwitchDivergentFormula.Init(pz)
m_DualTransformInit.Init(pz)
m_DualTransformInit.Iterate(pz, fConstant) ;do the work
return pz
endfunc
; @param pz
; Iterate--all the work is done in the plug-in.
complex func Iterate(complex pz)
m_DualTransform.Iterate(pz, fConstant)
return pz
endfunc
; @param pz
; @return true if bailed out.
bool func IsBailedOut(complex pz)
return m_BailoutFunc.Iterate(pz)
endfunc
protected:
DualTransform m_DualTransform
DualTransform m_DualTransformInit
Reduction m_BailoutFunc
default:
rating = NotRecommended
title = "Switch Super"
rating = NotRecommended
param p_power ; Overrides p_power from Formula
caption = "Power"
default = (2,0)
visible = false
enabled = false
endparam
int param v_superswitch
caption = "Version (JLB_superswitch)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_superswitch < 100
endparam
Heading
caption = "Start of Switch Super parameters"
Endheading
Heading
Endheading
DualTransform param f_DualTransformInit
caption = "Initialize"
default = JLB_NullDualTransform
endparam
Heading
Endheading
DualTransform param f_DualTransform
caption = "Formula"
default = JLB_MandelbrotDualTransform
endparam
Heading
caption = "Bailout"
Endheading
Reduction param f_bailout
caption = "Bailout Type"
default = JLB_SimpleBailout
endparam
}
class DualTransform(common.ulb:Generic) {
; DualTransform base class. No title, so only used for a base class.
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func DualTransform(Generic pparent)
Generic.Generic(pparent)
endfunc
complex func Init(complex pz)
return pz
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
return true
endfunc
default:
rating = NotRecommended
int param v_DualTransform
caption = "Version (DualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_DualTransform < 100
endparam
}
class JLB_DoubleDualTransform(DualTransform) {
; A wrapper for two DualTransforms
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_DoubleDualTransform(Generic pparent)
DualTransform.DualTransform(pparent)
m_DualTransform1 = new @f_DualTransform1(this)
m_DualTransform2 = new @f_DualTransform2(this)
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
bool result1 = m_DualTransform1.Iterate(pz, pc)
bool result2 = m_DualTransform2.Iterate(pz, pc)
return (result1 && result2)
endfunc
protected:
DualTransform m_DualTransform1
DualTransform m_DualTransform2
default:
rating = NotRecommended
title = "Double DualTransform"
int param v_DoubleDualTransform
caption = "Version (DoubleDualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_DoubleDualTransform < 100
endparam
DualTransform param f_DualTransform1
caption = "First DualTransform"
default = JLB_ZCZDualTransform
; hint = "The default Null DualTransform does nothing."
endparam
Heading
endHeading
DualTransform param f_DualTransform2
caption = "Second DualTransform"
default = JLB_ZCZDualTransform
; hint = "The default Null DualTransform does nothing."
endparam
}
class JLB_NullDualTransform(DualTransform) {
; A DualTransform placeholder that does nothing.
public:
import "common.ulb"
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
return true
endfunc
default:
rating = NotRecommended
title = "Null DualTransform"
int param v_NullDualTransform
caption = "Version (NullDualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_NullDualTransform < 100
endparam
}
class JLB_MandelbrotDualTransform(DualTransform) {
; The Mandelbrot formula as a DualTransform
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_MandelbrotDualTransform(Generic pparent)
DualTransform.DualTransform(pparent)
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
pz = sqr(pz) + pc
return true
endfunc
default:
rating = NotRecommended
title = "Mandelbrot DualTransform"
int param v_MandelbrotDualTransform
caption = "Version (MandelbrotDualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_MandelbrotDualTransform < 100
endparam
}
class JLB_ZZDualTransform(DualTransform) {
; ZZDualTransform does two Z contractions
; p_z1 calls to a function, new z = ZContraction1(z, c)
; p_z2 calls to a function, new z = ZContraction2(z, c)
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_ZZDualTransform(Generic pparent)
DualTransform.DualTransform(pparent)
m_ZContraction1 = new @f_ZContraction1(this)
m_ZContraction2 = new @f_ZContraction2(this)
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
int i
i = 0
while (i < @p_z1)
pz = m_ZContraction1.Iterate(pz, pc)
if (isNan(|pz|))
return true
endif
i = i + 1
endwhile
i = 0
while (i < @p_z2)
pz = m_ZContraction2.Iterate(pz, pc)
if (isNan(|pz|))
return true
endif
i = i + 1
endwhile
return true
endfunc
protected:
Contraction m_ZContraction1
Contraction m_ZContraction2
default:
rating = NotRecommended
title = "ZZ DualTransform"
int param v_ZZDualTransform
caption = "Version (ZZDualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ZZDualTransform < 100
endparam
Heading
Endheading
Heading
caption = "New z based on z and c"
Endheading
int param p_z1
caption = "Times"
min = 0
default = 1
endparam
Contraction param f_ZContraction1
caption = "z/c -> new z"
default = JLB_MandelbrotContraction
; hint = "The default Null Contraction does nothing."
endparam
Heading
caption = "New z based on z and c"
Endheading
int param p_z2
caption = "Times"
min = 0
default = 1
endparam
Contraction param f_ZContraction2
caption = "z/c -> new z"
default = JLB_MandelbrotContraction
; hint = "The default Null Contraction does nothing."
endparam
Heading
Endheading
}
class JLB_ZCZDualTransform(DualTransform) {
; ZCZDualTransform does three functions.
; p_z calls to a function, new z = ZContraction(z, c)
; p_c calls to a function, new c = CContraction(z, c)
; p_t calls to a function, new z = UserTransform(z)
; (Was UtilityTransform in version 100)
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_ZCZDualTransform(Generic pparent)
DualTransform.DualTransform(pparent)
m_ZContraction = new @f_ZContraction(this)
m_CContraction = new @f_CContraction(this)
; m_UserTransform = new @f_UserTransform(this)
if (@v_ZCZDualTransform > 100)
m_UserTransform = new @f_UserTransform(this)
else
m_UtilityTransform = new @f_UtilityTransform(this)
endif
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
int i
i = 0
while (i < @p_z)
pz = m_ZContraction.Iterate(pz, pc)
if (isNan(|pz|))
return true
endif
i = i + 1
endwhile
i = 0
while (i < @p_c)
pc = m_CContraction.Iterate(pz, pc)
i = i + 1
endwhile
if (@v_ZCZDualTransform > 100)
i = 0
while (i < @p_t)
pz = m_UserTransform.Iterate(pz)
if (isNan(|pz|))
return true
endif
i = i + 1
endwhile
else
i = 0
while (i < @p_t)
pz = m_UtilityTransform.Iterate(pz)
if (isNan(|pz|))
return true
endif
i = i + 1
endwhile
endif
return true
endfunc
protected:
Contraction m_ZContraction
Contraction m_CContraction
UserTransform m_UserTransform
UtilityTransform m_UtilityTransform
default:
rating = NotRecommended
title = "ZCZ DualTransform"
int param v_ZCZDualTransform
caption = "Version (ZCZDualTransform)"
default = 101
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ZCZDualTransform < 101
endparam
Heading
Endheading
Heading
caption = "New z based on z and c"
Endheading
int param p_z
caption = "Times"
min = 0
default = 1
endparam
Contraction param f_ZContraction
caption = "z/c -> new z"
default = JLB_MandelbrotContraction
; hint = "The default Null Contraction does nothing."
endparam
Heading
caption = "New c based on z and c"
Endheading
int param p_c
caption = "Times"
min = 0
default = 0
endparam
Contraction param f_CContraction
caption = "z/c -> new c"
default = JLB_NullCContraction
hint = "The default Null Contraction does nothing."
endparam
Heading
caption = "New z based on z"
Endheading
int param p_t
caption = "Times"
min = 0
default = 0
endparam
UserTransform param f_UserTransform
caption = "z -> new z"
default = JLB_NullUserTransform
hint = "The default Null Transform does nothing."
visible = (@v_ZCZDualTransform > 100)
endparam
UtilityTransform param f_UtilityTransform
caption = "z -> new z"
default = JLB_NullUtilityTransform
hint = "The default Null Transform does nothing."
visible = (@v_ZCZDualTransform < 101)
endparam
Heading
Endheading
}
class JLB_BurningShipContraction(Contraction) {
; The Burning Ship formula as a Contraction.
public:
; @param pz
; @param pc
; @return the new pz
complex func Iterate(complex pz, complex pc)
float zx
float zy
if (@p_std)
zx = abs(real(pz))
zy = abs(imag(pz))
return sqr(zx+flip(zy)) + pc
else
zx=abs(real(@xfunction(real(pz-@p_zoffset))))^@xpower
zy=abs(real(@yfunction(imag(pz-@p_zoffset))))^@ypower
return (@xweight*zx+@yweight*flip(zy))^@zpower+(pc - @p_coffset)
endif
endfunc
default:
title = "Burning Ship"
rating = NotRecommended
int param v_BurningShipcontraction
caption = "Version (BurningShip_Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_BurningShipcontraction < 100
endparam
bool param p_std
caption = "Standard"
default = true
endparam
heading
caption="General"
visible = !@p_std
endheading
complex param p_zoffset
caption = "pz offset"
default = (0,0)
visible = !@p_std
endparam
complex param p_coffset
caption = "pc offset"
default = (0,0)
visible = !@p_std
endparam
complex param zpower
caption="power"
default=2
visible = !@p_std
endparam
;
; x parameters
;
heading
caption="X"
visible = !@p_std
endheading
float param xpower
caption="power"
default=1
visible = !@p_std
endparam
func xfunction
caption="function"
default=ident()
visible = !@p_std
endfunc
complex param xweight
caption="weight"
default=1
visible = !@p_std
endparam
;
; y parameters
;
heading
caption="Y"
visible = !@p_std
endheading
float param ypower
caption="power"
default=1
visible = !@p_std
endparam
func yfunction
caption="function"
default=ident()
visible = !@p_std
endfunc
complex param yweight
caption="weight"
default=1
visible = !@p_std
endparam
}
class JLB_ZTweakContraction(Contraction) {
; The Z tweaks, as in Compounding Tweaked Mandelbrot from lkm.ufm,
; as a Contraction.
public:
; @param pz
; @param pc
; @return the new pz
complex func Iterate(complex pz, complex pc)
if (@tweaktype=="fn(c)")
return pz + @tweakage*@tweakfunction(pc)
elseif (@tweaktype=="fn(z)")
return pz + @tweakage*@tweakfunction(pz)
elseif (@tweaktype=="fn(c*z)")
return pz + @tweakage*@tweakfunction(pc*pz)
elseif (@tweaktype=="fn(z/c)")
return pz + @tweakage*@tweakfunction(pz/pc)
else;if (@tweaktype=="fn(c/z)")
return pz + @tweakage*@tweakfunction(pc/pz)
endif
endfunc
default:
title = "Tweak Z"
rating = NotRecommended
int param v_ztweakcontraction
caption = "Version (ztweak_Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ztweakcontraction < 100
endparam
param tweaktype
caption="tweaking type"
default=0
enum= "fn(c)" "fn(z)" "fn(c*z)" "fn(z/c)" "fn(c/z)"
hint="Sets how z gets tweaked."
endparam
param tweakage
caption="tweaking amount"
default=(0.01,0.0)
hint="Usually small."
endparam
func tweakfunction
caption="tweaking function"
default=recip()
hint="Function of the tweaking variable."
endfunc
}
class JLB_CTweakContraction(Contraction) {
; The C tweaks, as in Compounding Tweaked Mandelbrot from lkm.ufm,
; as a Contraction.
public:
; @param pz
; @param pc
; @return the new pz
complex func Iterate(complex pz, complex pc)
if (@tweaktype=="fn(c)")
return pc + @tweakage*@tweakfunction(pc)
elseif (@tweaktype=="fn(z)")
return pc + @tweakage*@tweakfunction(pz)
elseif (@tweaktype=="fn(c*z)")
return pc + @tweakage*@tweakfunction(pc*pz)
elseif (@tweaktype=="fn(z/c)")
return pc + @tweakage*@tweakfunction(pz/pc)
else;if (@tweaktype=="fn(c/z)")
return pc + @tweakage*@tweakfunction(pc/pz)
endif
endfunc
default:
title = "Tweak C"
rating = NotRecommended
int param v_ctweakcontraction
caption = "Version (ztweak_Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ctweakcontraction < 100
endparam
param tweaktype
caption="tweaking type"
default=0
enum= "fn(c)" "fn(z)" "fn(c*z)" "fn(z/c)" "fn(c/z)"
hint="Sets how c gets tweaked."
endparam
param tweakage
caption="tweaking amount"
default=(0.01,0.0)
hint="Usually small."
endparam
func tweakfunction
caption="tweaking function"
default=recip()
hint="Function of the tweaking variable."
endfunc
}
class JLB_NullCContraction(Contraction) {
; A do-nothing C Contraction.
public:
; @param pz
; @param pc
; @return the same pc
complex func Iterate(complex pz, complex pc)
return pc
endfunc
default:
title = "returns c" ;"Null Contraction"
rating = NotRecommended
int param v_nullccontraction
caption = "Version (JLB_NullCContraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_nullccontraction < 100
endparam
}
class JLB_NullZContraction(Contraction) {
; A do-nothing Z Contraction.
public:
; @param pz
; @param pc
; @return the same pc
complex func Iterate(complex pz, complex pc)
return pz
endfunc
default:
title = "returns z" ;"Null Contraction"
rating = NotRecommended
int param v_nullccontraction
caption = "Version (JLB_NullCContraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_nullccontraction < 100
endparam
}
class JLB_NewtonUserTransform(common.ulb:UserTransform) {
; The Newton formula as a Transform.
public:
; @param pz
; @return the new pz
complex func Iterate(complex pz)
if (@p_std)
return (2*sqr(pz)*pz+1)/(3*sqr(pz))
else
; complex pm1 = @p_power - 1
; complex pzp = pz ^ pm1
; return pz * (1-@relax) + \
; @relax * (pm1 * pz * pzp + @r) / (@p_power * pzp)
return pz * (1-@relax) + \
@relax * ((@p_power - 1) * pz^@p_power + @r) / \
(@p_power * pz ^ (@p_power - 1))
endif
endfunc
default:
title = "Newton"
rating = NotRecommended
int param v_NewtonUserTransform
caption = "Version (Newton_UserTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_NewtonUserTransform < 100
endparam
bool param p_std
caption = "Standard"
default = true
endparam
complex param p_power
caption = "Exponent"
default = (3,0)
hint = "Specifies the exponent of the equation that is solved by \
Newton's method. Use real numbers (set the imaginary part \
to zero) to obtain classic Newton fractals."
visible = !@p_std
endparam
param r
caption = "Root"
default = (1,0)
hint = "Specifies the root of the equation that is solved. Use larger \
numbers for slower convergence."
visible = !@p_std
endparam
param relax
caption = "Relaxation"
default = (1,0)
hint = "This can be used to alter the convergence of \
the formula."
visible = !@p_std
endparam
}
class JLB_NullUserTransform(common.ulb:UserTransform) {
; A do-nothing Transform
public:
func JLB_NULLUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
endfunc
; @param pz
; @return the same pz
complex func Iterate(complex pz)
return pz
endfunc
default:
title = "(No change)" ;"Null User Transform"
rating = NotRecommended
int param v_nullUsertransform
caption = "Version (NullUserTransform)"
default = 100
hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used."
visible = @v_nullUsertransform < 100
endparam
}
class JLB_SpiroGlyphicUserTransform(common.ulb:UserTransform) {
; Part of the Spiroglyphics formula, as in tma2.ufm, as a Transform.
public:
func JLB_SpiroGlyphicUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
endfunc
func Init(complex pz)
if @op1 == "++++"
m1=+1, m2=+1, m3=+1, m4=+1
elseif @op1 == "+++-"
m1=+1, m2=+1, m3=+1, m4=-1
elseif @op1 == "++-+"
m1=+1, m2=+1, m3=-1, m4=+1
elseif @op1 == "+-++"
m1=+1, m2=-1, m3=+1, m4=+1
elseif @op1 == "-+++"
m1=-1, m2=+1, m3=+1, m4=+1
elseif @op1 == "++--"
m1=+1, m2=+1, m3=-1, m4=-1
elseif @op1 == "+--+"
m1=+1, m2=-1, m3=-1, m4=+1
elseif @op1 == "--++"
m1=-1, m2=-1, m3=+1, m4=+1
elseif @op1 == "-++-"
m1=-1, m2=+1, m3=+1, m4=-1
elseif @op1 == "+-+-"
m1=+1, m2=-1, m3=+1, m4=-1
elseif @op1 == "-+-+"
m1=-1, m2=+1, m3=-1, m4=+1
elseif @op1 == "+---"
m1=+1, m2=-1, m3=-1, m4=+1
elseif @op1 == "-+--"
m1=-1, m2=+1, m3=-1, m4=-1
elseif @op1 == "--+-"
m1=-1, m2=-1, m3=+1, m4=-1
elseif @op1 == "---+"
m1=-1, m2=-1, m3=-1, m4=+1
else;if @op1 == "----"
m1=-1, m2=-1, m3=-1, m4=-1
endif
if @op2 == "++++"
n1=+1, n2=+1, n3=+1, n4=+1
elseif @op2 == "+++-"
n1=+1, n2=+1, n3=+1, n4=-1
elseif @op2 == "++-+"
n1=+1, n2=+1, n3=-1, n4=+1
elseif @op2 == "+-++"
n1=+1, n2=-1, n3=+1, n4=+1
elseif @op2 == "-+++"
n1=-1, n2=+1, n3=+1, n4=+1
elseif @op2 == "++--"
n1=+1, n2=+1, n3=-1, n4=-1
elseif @op2 == "+--+"
n1=+1, n2=-1, n3=-1, n4=+1
elseif @op2 == "--++"
n1=-1, n2=-1, n3=+1, n4=+1
elseif @op2 == "-++-"
n1=-1, n2=+1, n3=+1, n4=-1
elseif @op2 == "+-+-"
n1=+1, n2=-1, n3=+1, n4=-1
elseif @op2 == "-+-+"
n1=-1, n2=+1, n3=-1, n4=+1
elseif @op2 == "+---"
n1=+1, n2=-1, n3=-1, n4=+1
elseif @op2 == "-+--"
n1=-1, n2=+1, n3=-1, n4=-1
elseif @op2 == "--+-"
n1=-1, n2=-1, n3=+1, n4=-1
elseif @op2 == "---+"
n1=-1, n2=-1, n3=-1, n4=+1
else;if @op2 == "----"
n1=-1, n2=-1, n3=-1, n4=-1
endif
endfunc
; @param pz
; @return the new pz
complex func Iterate(complex pz)
complex x = real(@fnx(pz)) + flip(real(@start/10))
complex y = imag(@fny(pz)) + flip(imag(@start/10))
complex newx = y
complex newy = x
int i = 0
if @chain == "Separate"
while i < @flavor
i = i + 1
newx = y + m1*real(@h2a/10)*@fn1(@a1 * newx) + \
m2*imag(@h2a/10)*@fn3(@a2 * newx)
newy = x + m3*real(@h2b/10)*@fn2(@a3 * newy) + \
m4 *imag(@h2b/10)*@fn4(@a4 * newy)
endwhile
x = x + n1*real(@h1a/10)*@fn5(newx) + n2*imag(@h1a/10)*@fn7(newx)
y = y + n3*real(@h1b/10)*@fn6(newy) + n4*imag(@h1b/10)*@fn8(newy)
elseif @chain == "Ganged"
while i < @flavor
i = i + 1
newx = y + m1*real(@h2/10)*@fn1(@a1 * newx) + \
m2*imag(@h2/10)*@fn3(@a2 * newx)
newy = x + m3*real(@h2/10)*@fn2(@a3 * newy) + \
m4*imag(@h2/10)*@fn4(@a4 * newy)
endwhile
x = x + n1*real(@h1/10)*@fn5(newx) + n2*imag(@h1/10)*@fn7(newx)
y = y + n3*real(@h1/10)*@fn6(newy) + n4*imag(@h1/10)*@fn8(newy)
endif
if @op == "x+y"
pz = @fna(x) + flip(@fnb(y))
elseif @op == "x-y"
pz = @fna(x)- flip(@fnb(y))
else;if @op == "y-x"
pz = flip(@fnb(y)) - @fna(x)
endif
return pz
endfunc
protected:
int m1, int m2, int m3, int m4
int n1, int n2, int n3, int n4
default:
rating = NotRecommended
title = "Spiroglyphic"
int param v_SpiroglyphicUsertransform
caption = "Version (SpiroglyphicUserTransform)"
default = 100
hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used."
visible = @v_SpiroglyphicUsertransform < 100
endparam
int param chain
caption = "Intensity Mode"
enum = "Separate" "Ganged"
default = 0
hint = "Choose whether X/Y intensity and step sizes vary together \
or separately"
endparam
complex param h1a
caption = "Intensity X"
default = (.1,.1)
visible = @chain == 0
endparam
complex param h1b
caption = "Intensity Y"
default = (.1,.1)
visible = @chain == 0
endparam
complex param h2a
caption = "Step Size X"
default = (.8,.8)
visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0))
endparam
complex param h2b
caption = "Step Size Y"
default = (.8,.8)
visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0))
endparam
complex param h1
caption = "Intensity X/Y"
default = (.1, .1)
visible = @chain == 1
endparam
complex param h2
caption = "Step Size X/Y"
default = (.8,.8)
visible = @chain == 1 && @h1 != (0,0)
endparam
complex param start
caption = "Glyph Start"
default = (0,0)
endparam
int param flavor
caption = "Flavor"
default = 2
min = 0
hint = "This is an integer param which works in steps. Higher \
numbers generally create more intense effects"
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a1
caption = "Alpha 1"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a2
caption = "Alpha 2"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a3
caption = "Alpha 3"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a4
caption = "Alpha 4"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
param op
caption = "Main Operator"
enum = "x+y" "x-y" "y-x"
default = 0
endparam
param op1
caption = "Operator 1"
enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \
"-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----"
default = 0
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
param op2
caption = "Operator 2"
enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \
"-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----"
default = 7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
func fn1
caption = "Function 1"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn2
caption = "Function 2"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn3
caption = "Function 3"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn4
caption = "Function 4"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn5
caption = "Function 5"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn6
caption = "Function 6"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn7
caption = "Function 7"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn8
caption = "Function 8"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fna
caption = "Initial X Fn"
default = ident()
endfunc
func fnb
caption = "Initial Y Fn"
default = ident()
endfunc
func fnx
caption = "Global X Fn"
default = ident()
endfunc
func fny
caption = "Global Y Fn"
default = ident()
endfunc
}
class JLB_MoebiusUserTransform(common.ulb:UserTransform) {
; The Moebius Transform, z = (a1*z + a2) / (a3*z + a4).
; Can also be applied to c, of course.
; June 2021 renamed parameters and added quadratic option
public:
; @param pz
; @return the new pz
complex func Iterate(complex pz)
if @fz == 0
return (@a0 + @a1*pz) / (@b0 + @b1*pz)
else
return (@a0 + @a1*@f(@a2*pz)) / (@b0 + @b1*@f(@b2*pz))
endif
endfunc
default:
rating = NotRecommended
title = "Moebius"
int param v_MoebiusUserTransform
caption = "Version (Moebius_UserTransform)"
default = 200
hint = "Old version."
visible = @v_MoebiusUserTransform < 200
endparam
heading
text = "(v can be either z or c)"
endheading
heading
caption = "v_new = (a0+a1*v)/(b0+b1*v)"
visible = @fz == 0
endheading
heading
caption = "v_new = (a0+a1*F(a2*v)/(b0+b1*F(b2*v))"
visible = @fz == 1
endheading
param fz
caption = "v or F(a*v)"
enum = "v" "F(a*v)"
default = 0
endparam
func f
caption = "F"
default = sin()
visible = @fz == 1
endfunc
complex param a0
caption = "Moebius: a0"
default = (0,0)
endparam
complex param a1
caption = "Moebius: a1"
default = (1,0)
endparam
complex param a2
caption = "Moebius: a2"
default = (1,0)
visible = @fz == 1
endparam
complex param b0
caption = "Moebius: b0"
default = (1,0)
endparam
complex param b1
caption = "Moebius: b1"
default = (-1,0)
endparam
complex param b2
caption = "Moebius: b2"
default = (1,0)
visible = @fz == 1
endparam
}
class JLB_ComboDualTransform(DualTransform) {
; ComboDualTransform does two UserTransforms and combines them
; with one of the operators +, -, *, /, ^.
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_ComboDualTransform(Generic pparent)
DualTransform.DualTransform(pparent)
m_UserTransform1 = new @f_UserTransform1(this)
m_UserTransform2 = new @f_UserTransform2(this)
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
complex t1
if (@mode1 == "z")
t1 = m_UserTransform1.Iterate(pz)
else
t1 = m_UserTransform1.Iterate(pc)
endif
complex t2
if (@mode2 == "z")
t2 = m_UserTransform2.Iterate(pz)
else
t2 = m_UserTransform2.Iterate(pc)
endif
if (@op == "+")
t1 = t1 + t2
elseif (@op == "-")
t1 = t1 - t2
elseif (@op == "*")
t1 = t1 * t2
elseif (@op == "/")
t1 = t1 / t2
else;if (@op == "^")
t1 = t1 ^ t2
endif
if (@mode0 == "z")
pz = t1
else
pc = t1
endif
return true
endfunc
protected:
UserTransform m_UserTransform1
UserTransform m_UserTransform2
default:
rating = NotRecommended
title = "Combo Dual Transform"
int param v_ComboDualTransform
caption = "Version (ComboDualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ComboDualTransform < 100
endparam
param mode0
caption = "Change z or c?"
default = 0
enum = "z" "c"
hint = "Which variable to change"
endparam
Heading
caption = "First transform"
Endheading
param mode1
caption = "Based on z or c?"
default = 0
enum = "z" "c"
endparam
UserTransform param f_UserTransform1
caption = "Transform 1"
default = JLB_BasicUserTransform
; hint = "The default Null BasicTransform does nothing."
endparam
Heading
Endheading
param op
caption = "op"
enum = "+" "-" "*" "/" "^"
default = 0
hint = "result = First transform op second transform"
endparam
Heading
caption = "Second transform"
Endheading
param mode2
caption = "Based on z or c?"
default = 1
enum = "z" "c"
endparam
UserTransform param f_UserTransform2
default = JLB_NullUserTransform
caption = "Transform 2"
; hint = "The default Null BasicTransform does nothing."
endparam
}
class JLB_SpiroglyphicContraction(Contraction) {
; Part of the Spiroglyphics formula, as in tma2.ufm, as a Contraction.
public:
; @param pz
; @param pc
; @return the contracted value
complex func Iterate(complex pz, complex pc)
if @select == "z"; select variable type
pz = @fnz(pz-@zg)*@ezg
elseif @select == "z+c"
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z-c"
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "c-z"
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
elseif @select == "z*c"
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z/c"
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z+c|z+c"
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z+c|c-z"
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
elseif @select == "z+c|z*c"
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z+c|z/c"
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z-c|z-c"
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z-c|c-z"
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
elseif @select == "z-c|z*c"
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z-c|z/c"
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "c-z|z*c"
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "c-z|z/c"
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z*c|c-z"
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
elseif @select == "z*c|z*c"
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z/c|z+c"
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z/c|z-c"
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z/c|c-z"
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
elseif @select == "z/c|z/c"
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z*c+(Rz+Iz)"
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
elseif @select == "z/c+(Rz+Iz)"
pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
elseif @select == "z/c-(Rz+Iz)"
pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)-((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
elseif @select == "z*c-+(Rz+Iz)"
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)-((real(pz+@addz)\
*@muzr)\
^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
elseif @select == "z/c-+(Rz+Iz)"
pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)-((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
elseif @select == "z*c+(Rz+Iz)|z+c"
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z*c+(Rz+Iz)|z-c"
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg
elseif @select == "z*c+(Rz+Iz)|c-z"
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg
elseif @select == "z*c+(Rz+Iz)|z*c"
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg
else;if @select == "z*c+(Rz+Iz)|z/c"
pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\
*@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi)
pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg
endif
return pz
endfunc
default:
title = "Spiroglyphic"
rating = NotRecommended
int param v_SpiroglyphicContraction
caption = "Version (TMA_Contraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_SpiroglyphicContraction < 100
endparam
param select
caption = "Z Mode"
enum = "z" "z+c" "z-c" "c-z" "z*c" "z/c" "z+c|z+c" "z+c|c-z" "z+c|z*c"\
"z+c|z/c" "z-c|z-c" "z-c|c-z" "z-c|z*c" "z-c|z/c" "c-z|z*c" "c-z|z/c"\
"z*c|c-z" "z*c|z*c" "z/c|z+c" "z/c|z-c" "z/c|c-z" "z/c|z/c"\
"z*c+(Rz+Iz)" "z/c+(Rz+Iz)" "z/c-(Rz+Iz)" "z*c-+(Rz+Iz)"\
"z/c-+(Rz+Iz)" "z*c+(Rz+Iz)|z+c" "z*c+(Rz+Iz)|z-c" "z*c+(Rz+Iz)|c-z"\
"z*c+(Rz+Iz)|z*c" "z*c+(Rz+Iz)|z/c"
default = 5
hint = "Determines the initial definition of Z"
endparam
complex param zg
caption = "Z Param 1"
default = (0,0)
endparam
complex param ezg
caption = "Z Param 2"
default = (1,0)
endparam
complex param addz
caption = "Z Param 3"
default = (1.0,0.0)
visible = ( ((@select == 22)||(@select == 23)||(@select == 24)||\
(@select == 25)||(@select == 26)|| (@select == 27)||\
(@select == 28)||(@select == 29)||(@select == 30)|| \
(@select == 31))
endparam
complex param muzr
caption = "Z Strength re"
default = (1.0,0.0)
visible = ((@select == 22)||(@select == 23)||(@select == 24)||\
(@select == 25)||(@select == 26)|| (@select == 27)||\
(@select == 28)||(@select == 29)||(@select == 30)|| \
(@select == 31))
endparam
complex param muzi
caption = "Z Strength im"
default = (1.0,0.0)
visible = ((@select == 22)||(@select == 23)||(@select == 24)||\
(@select == 25)||(@select == 26)|| (@select == 27)||\
(@select == 28)||(@select == 29)||(@select == 30)|| \
(@select == 31))
endparam
complex param exzr
caption = "Z Power re"
default = (1.0,0.0)
visible = ((@select == 22)||(@select == 23)||(@select == 24)||\
(@select == 25)||(@select == 26)|| (@select == 27)||\
(@select == 28)||(@select == 29)||(@select == 30)|| \
(@select == 31))
endparam
complex param exzi
caption = "Z Power im"
default = (1.0,0.0)
visible = ((@select == 22)||(@select == 23)||(@select == 24)||\
(@select == 25)||(@select == 26)|| (@select == 27)||\
(@select == 28)||(@select == 29)||(@select == 30)|| \
(@select == 31))
endparam
complex param cg
caption = "C Param 1"
default = (0,0)
visible = @select != 0
endparam
complex param cmg
caption = "C Param 2"
default = (1,0)
visible = @select != 0
endparam
complex param ecg
caption = "C Param 3"
default = (1,0)
visible = @select != 0
endparam
func fnz
caption = "Global Z Func"
default = sin()
hint = "Applies a function to the initial Z"
endfunc
func fnc
caption = "Global C Func"
default = ident()
visible = @select != 0
hint = "Applies a function to the initial C"
endfunc
}
; Here only for compatibility with version 100 of JLB_ZCZDualTransform
class JLB_NullUtilityTransform(common.ulb:UtilityTransform) {
; A do-nothing Transform
public:
func JLB_NULLUtilityTransform(Generic pparent)
UtilityTransform.UtilityTransform(pparent)
endfunc
; @param pz
; @return the same pz
complex func Iterate(complex pz)
return pz
endfunc
default:
rating = NotRecommended
title = "(No change)" ;"Null Utility Transform"
int param v_nullUtilitytransform
caption = "Version (NullUtilityTransform)"
default = 100
hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used."
visible = @v_nullUtilitytransform < 100
endparam
}
; Here only for compatibility with version 100 of JLB_ZCZDualTransform
class JLB_NewtonUtilityTransform(common.ulb:UtilityTransform) {
; The Newton formula as a Transform.
public:
; @param pz
; @return the new pz
complex func Iterate(complex pz)
if (@p_std)
return (2*sqr(pz)*pz+1)/(3*sqr(pz))
else
return pz*(1-@relax) + \
@relax * ((@p_power - 1) * pz^@p_power + @r) / \
(@p_power * pz ^ (@p_power - 1))
endif
endfunc
default:
rating = NotRecommended
title = "Newton"
int param v_NewtonUtilityTransform
caption = "Version (Newton_UtilityTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_NewtonUtilityTransform < 100
endparam
bool param p_std
caption = "Standard"
default = true
endparam
complex param p_power
caption = "Exponent"
default = (3,0)
hint = "Specifies the exponent of the equation that is solved by \
Newton's method. Use real numbers (set the imaginary part \
to zero) to obtain classic Newton fractals."
visible = !@p_std
endparam
param r
caption = "Root"
default = (1,0)
hint = "Specifies the root of the equation that is solved. Use larger \
numbers for slower convergence."
visible = !@p_std
endparam
param relax
caption = "Relaxation"
default = (1,0)
hint = "This can be used to alter the convergence of \
the formula."
visible = !@p_std
endparam
}
; Here only for compatibility with version 100 of JLB_ZCZDualTransform
class JLB_SpiroGlyphicUtilityTransform(common.ulb:UtilityTransform) {
; Part of the Spiroglyphics formula, as in tma2.ufm, as a Transform.
public:
func JLB_SpiroGlyphicUtilityTransform(Generic pparent)
UtilityTransform.UtilityTransform(pparent)
endfunc
func Init(complex pz)
if @op1 == "++++"
m1=+1, m2=+1, m3=+1, m4=+1
elseif @op1 == "+++-"
m1=+1, m2=+1, m3=+1, m4=-1
elseif @op1 == "++-+"
m1=+1, m2=+1, m3=-1, m4=+1
elseif @op1 == "+-++"
m1=+1, m2=-1, m3=+1, m4=+1
elseif @op1 == "-+++"
m1=-1, m2=+1, m3=+1, m4=+1
elseif @op1 == "++--"
m1=+1, m2=+1, m3=-1, m4=-1
elseif @op1 == "+--+"
m1=+1, m2=-1, m3=-1, m4=+1
elseif @op1 == "--++"
m1=-1, m2=-1, m3=+1, m4=+1
elseif @op1 == "-++-"
m1=-1, m2=+1, m3=+1, m4=-1
elseif @op1 == "+-+-"
m1=+1, m2=-1, m3=+1, m4=-1
elseif @op1 == "-+-+"
m1=-1, m2=+1, m3=-1, m4=+1
elseif @op1 == "+---"
m1=+1, m2=-1, m3=-1, m4=+1
elseif @op1 == "-+--"
m1=-1, m2=+1, m3=-1, m4=-1
elseif @op1 == "--+-"
m1=-1, m2=-1, m3=+1, m4=-1
elseif @op1 == "---+"
m1=-1, m2=-1, m3=-1, m4=+1
else;if @op1 == "----"
m1=-1, m2=-1, m3=-1, m4=-1
endif
if @op2 == "++++"
n1=+1, n2=+1, n3=+1, n4=+1
elseif @op2 == "+++-"
n1=+1, n2=+1, n3=+1, n4=-1
elseif @op2 == "++-+"
n1=+1, n2=+1, n3=-1, n4=+1
elseif @op2 == "+-++"
n1=+1, n2=-1, n3=+1, n4=+1
elseif @op2 == "-+++"
n1=-1, n2=+1, n3=+1, n4=+1
elseif @op2 == "++--"
n1=+1, n2=+1, n3=-1, n4=-1
elseif @op2 == "+--+"
n1=+1, n2=-1, n3=-1, n4=+1
elseif @op2 == "--++"
n1=-1, n2=-1, n3=+1, n4=+1
elseif @op2 == "-++-"
n1=-1, n2=+1, n3=+1, n4=-1
elseif @op2 == "+-+-"
n1=+1, n2=-1, n3=+1, n4=-1
elseif @op2 == "-+-+"
n1=-1, n2=+1, n3=-1, n4=+1
elseif @op2 == "+---"
n1=+1, n2=-1, n3=-1, n4=+1
elseif @op2 == "-+--"
n1=-1, n2=+1, n3=-1, n4=-1
elseif @op2 == "--+-"
n1=-1, n2=-1, n3=+1, n4=-1
elseif @op2 == "---+"
n1=-1, n2=-1, n3=-1, n4=+1
else;if @op2 == "----"
n1=-1, n2=-1, n3=-1, n4=-1
endif
endfunc
; @param pz
; @return the new pz
complex func Iterate(complex pz)
complex x = real(@fnx(pz)) + flip(real(@start/10))
complex y = imag(@fny(pz)) + flip(imag(@start/10))
complex newx = y
complex newy = x
int i = 0
if @chain == "Separate"
while i < @flavor
i = i + 1
newx = y + m1*real(@h2a/10)*@fn1(@a1 * newx) + \
m2*imag(@h2a/10)*@fn3(@a2 * newx)
newy = x + m3*real(@h2b/10)*@fn2(@a3 * newy) + \
m4 *imag(@h2b/10)*@fn4(@a4 * newy)
endwhile
x = x + n1*real(@h1a/10)*@fn5(newx) + n2*imag(@h1a/10)*@fn7(newx)
y = y + n3*real(@h1b/10)*@fn6(newy) + n4*imag(@h1b/10)*@fn8(newy)
elseif @chain == "Ganged"
while i < @flavor
i = i + 1
newx = y + m1*real(@h2/10)*@fn1(@a1 * newx) + \
m2*imag(@h2/10)*@fn3(@a2 * newx)
newy = x + m3*real(@h2/10)*@fn2(@a3 * newy) + \
m4*imag(@h2/10)*@fn4(@a4 * newy)
endwhile
x = x + n1*real(@h1/10)*@fn5(newx) + n2*imag(@h1/10)*@fn7(newx)
y = y + n3*real(@h1/10)*@fn6(newy) + n4*imag(@h1/10)*@fn8(newy)
endif
if @op == "x+y"
pz = @fna(x) + flip(@fnb(y))
elseif @op == "x-y"
pz = @fna(x)- flip(@fnb(y))
else;if @op == "y-x"
pz = flip(@fnb(y)) - @fna(x)
endif
return pz
endfunc
protected:
int m1, int m2, int m3, int m4
int n1, int n2, int n3, int n4
default:
rating = NotRecommended
title = "Spiroglyphic"
int param v_SpiroglyphicUtilitytransform
caption = "Version (SpiroglyphicUtilityTransform)"
default = 100
hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used."
visible = @v_SpiroglyphicUtilitytransform < 100
endparam
int param chain
caption = "Intensity Mode"
enum = "Separate" "Ganged"
default = 0
hint = "Choose whether X/Y intensity and step sizes vary together \
or separately"
endparam
complex param h1a
caption = "Intensity X"
default = (.1,.1)
visible = @chain == 0
endparam
complex param h1b
caption = "Intensity Y"
default = (.1,.1)
visible = @chain == 0
endparam
complex param h2a
caption = "Step Size X"
default = (.8,.8)
visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0))
endparam
complex param h2b
caption = "Step Size Y"
default = (.8,.8)
visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0))
endparam
complex param h1
caption = "Intensity X/Y"
default = (.1, .1)
visible = @chain == 1
endparam
complex param h2
caption = "Step Size X/Y"
default = (.8,.8)
visible = @chain == 1 && @h1 != (0,0)
endparam
complex param start
caption = "Glyph Start"
default = (0,0)
endparam
int param flavor
caption = "Flavor"
default = 2
min = 0
hint = "This is an integer param which works in steps. Higher \
numbers generally create more intense effects"
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a1
caption = "Alpha 1"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a2
caption = "Alpha 2"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a3
caption = "Alpha 3"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
float param a4
caption = "Alpha 4"
default = 2.7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
param op
caption = "Main Operator"
enum = "x+y" "x-y" "y-x"
default = 0
endparam
param op1
caption = "Operator 1"
enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \
"-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----"
default = 0
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
param op2
caption = "Operator 2"
enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \
"-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----"
default = 7
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endparam
func fn1
caption = "Function 1"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn2
caption = "Function 2"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn3
caption = "Function 3"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn4
caption = "Function 4"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn5
caption = "Function 5"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn6
caption = "Function 6"
default = sin()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn7
caption = "Function 7"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fn8
caption = "Function 8"
default = cos()
visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \
(@chain == 1 && @h1 != (0,0))
endfunc
func fna
caption = "Initial X Fn"
default = ident()
endfunc
func fnb
caption = "Initial Y Fn"
default = ident()
endfunc
func fnx
caption = "Global X Fn"
default = ident()
endfunc
func fny
caption = "Global Y Fn"
default = ident()
endfunc
}
class JLB_DualTransformContraction(Contraction) {
; A Contraction that calls a DualTransforms
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_DualTransformContraction(Generic pparent)
Contraction.Contraction(pparent)
m_DualTransform = new @f_DualTransform(this)
endfunc
; @param pz
; @param pc
; @return pz
complex func Iterate(complex pz, complex pc)
m_DualTransform.Iterate(pz, pc)
return pz ; ignore possible change in pc
endfunc
protected:
DualTransform m_DualTransform
default:
rating = NotRecommended
title = "DualTransform Contraction"
int param v_DualTransformContraction
caption = "Version (DualTransformContraction)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_DualTransformContraction < 100
endparam
DualTransform param f_DualTransform
caption = "DualTransform"
default = JLB_MandelbrotDualTransform
endparam
}
class JLB_ComboMultiTransform(jlb.ulb:DualTransform) {
; ComboMultiTransform does three UsertTransforms and combines them
; with one of the operators +, -, *, /, ^.
; This allows formulas such as z = (f1 + f2)/f3
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_ComboMultiTransform(Generic pparent)
DualTransform.DualTransform(pparent)
m_UserTransform1 = new @f_UserTransform1(this)
if (@num >= 1)
m_UserTransform2 = new @f_UserTransform2(this)
if (@num >= 2)
m_UserTransform3 = new @f_UserTransform3(this)
endif
endif
m_Combine = new Combine()
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
complex t1
complex t2
complex t3
if (@mode1 == "z")
t1 = m_UserTransform1.Iterate(pz)
else
t1 = m_UserTransform1.Iterate(pc)
endif
if (@num >= 1) ; "2"
if (@mode2 == "z")
t2 = m_UserTransform2.Iterate(pz)
else
t2 = m_UserTransform2.Iterate(pc)
endif
if (@num == "2")
t1 = m_Combine.go(t1, @op1, t2)
else
if (@mode3 == "z")
t3 = m_UserTransform3.Iterate(pz)
else
t3 = m_UserTransform3.Iterate(pc)
endif
if (@order3 == "t1 op1 (t2 op2 t3)" )
t2 = m_Combine.go(t2, @op2, t3)
t1 = m_Combine.go(t1, @op1, t2)
else ;if (@order == "(t1 op1 t2) op2 t3" )
t1 = m_Combine.go(t1, @op1, t2)
t1 = m_Combine.go(t1, @op2, t3)
endif
endif
endif
if (@addc)
t1 = t1 + pc
endif
if (@mode0 == "z")
pz = t1
else
pc = t1
endif
return true
endfunc
protected:
UserTransform m_UserTransform1
UserTransform m_UserTransform2
UserTransform m_UserTransform3
Combine m_Combine
default:
rating = NotRecommended
title = "Combo Multi Transform"
int param v_ComboMultiTransform
caption = "Version (ComboMultiTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ComboMultiTransform < 100
endparam
param mode0
caption = "Change z or c?"
default = 0
enum = "z" "c"
hint = "Which variable to change"
endparam
param num
caption = "Number of transforms"
default = 1
enum = "1" "2" "3"
endparam
param order3
caption = "Ordering"
default = 0
enum = "t1 op1 (t2 op2 t3)" "(t1 op1 t2) op2 t3"
hint = "Order of combining can make a big difference!"
visible = (@num == 2) ; "3"
endparam
Heading
caption = "Transform"
visible = (@num == 0)
Endheading
Heading
caption = "Transform #1"
visible = (@num > 0)
Endheading
param mode1
caption = "Transform z or c?"
default = 0
enum = "z" "c"
endparam
UserTransform param f_UserTransform1
caption = "Transform"
default = JLB_BasicUserTransform
; hint = "The default Null BasicTransform does nothing."
endparam
Heading
caption = "Operator"
visible = (@num == 1)
Endheading
Heading
caption = "Operator #1"
visible = (@num > 1)
Endheading
param op1
caption = "Operator"
enum = "+" "-" "*" "/" "^"
default = 0
hint = "How to combine transform values."
visible = (@num >= 1)
endparam
Heading
caption = "Transform #2"
visible = (@num > 0)
Endheading
param mode2
caption = "Transform z or c?"
default = 0
enum = "z" "c"
visible = (@num > 0)
endparam
UserTransform param f_UserTransform2
default = JLB_BasicUserTransform
caption = "Transform"
visible = (@num > 0)
endparam
Heading
caption = "Operator #2"
visible = (@num > 1)
Endheading
param op2
caption = "Operator"
enum = "+" "-" "*" "/" "^"
default = 0
hint = "How to combine transform values."
visible = (@num > 1)
endparam
Heading
caption = "Transform #3"
visible = (@num > 1)
Endheading
param mode3
caption = "Transform z or c?"
default = 1
enum = "z" "c"
visible = (@num > 1)
endparam
UserTransform param f_UserTransform3
default = JLB_NullUserTransform
caption = "Transform 3"
visible = (@num > 1)
endparam
Heading
caption = "Final addition"
Endheading
bool param addc
default = true
caption = "Add c?"
endparam
}
class JLB_PowerUserTransform(common.ulb:UserTransform) {
; A basic Transform, z = a1+a2*f(a3*z+a4)
; Can also be applied to c, of course.
public:
; @param pz
; @return the new pz
complex func Iterate(complex pz)
return @a1 + @a2*(@a3*pz + @a4)^@power
endfunc
default:
;rating = Recommended
title = "Power"
int param v_PowerUserTransform
caption = "Version (Power_UserTransform)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_PowerUserTransform < 200
endparam
heading
caption = "v_new = a1+a2*(a3*v+a4)^Power"
endheading
complex param power
caption = "Power"
default = (2,0)
;hint = "New v = a1+a2*(a3*v+a4)^Power"
endparam
complex param a1
caption = "a1"
default = (0,0)
;hint = "New v = a1+a2*(a3*v+a4)^Power"
endparam
complex param a2
caption = "a2"
default = (1,0)
;hint = "New v = a1+a2*(a3*v+a4)^Power"
endparam
complex param a3
caption = "a3"
default = (1,0)
;hint = "New v = a1+a2*(a3*v+a4)^Power"
endparam
complex param a4
caption = "a4"
default = (0,0)
;hint = "New v = a1+a2*(a3*v+a4)^Power"
endparam
}
class JLB_DoubleUserTransform(common.ulb:UserTransform) {
; A wrapper for two UserTransforms on one variable.
public:
import "common.ulb"
import "jlb.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_DoubleUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
m_UserTransform1 = new @f_UserTransform1(this)
m_UserTransform2 = new @f_UserTransform2(this)
endfunc
; @param pz
; @return new value
complex func Iterate(complex pz)
if (@type == "regular")
pz = m_UserTransform2.Iterate(m_UserTransform1.Iterate(pz))
else;if @type == "gnarl")
int i = 0
while (i < @num)
complex x = real(pz)
complex y = imag(pz)
float dx = real(m_UserTransform2.Iterate(m_UserTransform1.Iterate(y)))
float dy = real(m_UserTransform2.Iterate(m_UserTransform1.Iterate(x)))
if (@xop=="-")
dx = -dx
endif
if (@yop=="-")
dy = -dy
endif
pz = pz + @step * (dx + flip(dy))
i = i + 1
endwhile
endif
return pz
endfunc
protected:
UserTransform m_UserTransform1
UserTransform m_UserTransform2
default:
rating = NotRecommended
title = "Double UserTransform"
int param v_DoubleUserTransform
caption = "Version (DoubleUserTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_DoubleUserTransform < 100
endparam
param type
caption = "Combining type?"
enum = "regular" "gnarl"
default = 0
endparam
float param num
caption = "Number of Steps"
default = 1
min = 1
visible = (@type == 1)
endparam
float param step
caption = "Step size"
default = 0.1
visible = (@type == 1)
endparam
param xop
enum = "+" "-"
default = 1
visible = (@type == 1)
endparam
param yop
enum = "+" "-"
default = 0
visible = (@type == 1)
endparam
UserTransform param f_UserTransform1
caption = "First Transform"
default = JLB_BasicUserTransform
endparam
UserTransform param f_UserTransform2
caption = "Second Transform"
default = JLB_BasicUserTransform
endparam
}
class JLB_BasicUserTransform(common.ulb:UserTransform) {
; A basic Transform, z = a1+a2*f(a3*z+a4)
; Can also be applied to c, of course.
; June 2020 removed show parameter
public:
import "common.ulb"
; @param pz
; @return the new pz
complex func Iterate(complex pz)
return @a1 + @a2*@f(@a3*pz + @a4)
endfunc
default:
rating = NotRecommended
title = "Basic"
int param v_BasicUserTransform
caption = "Version (Basic_UserTransform)"
default = 200
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_BasicUserTransform < 100
endparam
heading
caption = "v_new = a1+a2*f(a3*v+a4)"
endheading
func f
caption = "f"
default = sqr()
;hint = "New v = a1+a2*f(a3*v+a4)"
endfunc
complex param a1
caption = "a1"
default = (0,0)
;hint = "New v = a1+a2*f(a3*v+a4)"
endparam
complex param a2
caption = "a2"
default = (1,0)
;hint = "New v = a1+a2*f(a3*v+a4)"
endparam
complex param a3
caption = "a3"
default = (1,0)
;hint = "New v = a1+a2*f(a3*v+a4)"
endparam
complex param a4
caption = "a4"
default = (0,0)
;hint = "New v = a1+a2*f(a3*v+a4)"
endparam
}
class JLB_NewtonPolyUserTransform(common.ulb:UserTransform) {
; Iteration of polynomial(z) = root by Newton's method.
; A Transform version of JLB_PolyNewtonContraction
public:
func JLB_NewtonPolyUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
if (@p_poly_type == "Poly")
m_a[0] = @p_a0, m_a[1] = @p_a1, m_a[2] = @p_a2, m_a[3] = @p_a3
m_a[4] = @p_a4, m_a[5] = @p_a5, m_a[6] = @p_a6, m_a[7] = @p_a7
m_a[8] = @p_a8, m_a[9] = @p_a9, m_a[10] = @p_a10
int i = 0
while (i < @p_degree - 1)
m_ap[i] = (i+1)*m_a[i+1]
m_app[i] = (i+2)*(i+1)*m_a[i+2]
i = i + 1
endwhile
i = @p_degree - 1
m_ap[i] = (i+1)*m_a[i+1]
endif
endfunc
; @param pz
; @return the new pz
complex func Iterate(complex pz)
complex f
complex fp
complex fpp = 0 ; to satisfy compiler
int i
if (@p_poly_type == "Poly")
; Solving f(z) = 0
i = @p_degree
f = m_a[i]
while (i > 0)
i = i - 1
f = m_a[i] + pz * f
endwhile
; df/dz
i = @p_degree - 1
fp = m_ap[i]
while (i > 0)
i = i - 1
fp = m_ap[i] + pz * fp
endwhile
if (@p_iter_type > 0)
; d2f/dz2
i = @p_degree - 2
fpp = m_app[i]
while (i > 0)
i = i - 1
fpp = m_app[i] + pz * fpp
endwhile
endif
else;if (@p_poly_type == "Power")
f = pz^@p_power
fp = @p_power*pz^(@p_power-1)
if (@p_iter_type > 0)
fpp = @p_power*(@p_power-1)*pz^(@p_power-2)
endif
endif
if (@p_type == "Constant")
f = f - @p_const
; elseif (@p_type == "C")
; f = f - pc
else;if (@p_type == "Pixel")
f = f - #pixel
endif
if (@p_iter_type == "Newton")
return pz - @relax * f / fp
elseif (@p_iter_type == "Type 1") ; approximate Halley 1/(1-x)~(1+x)
return pz - @relax * (f/fp)*(1 + @p_alpha*f*fpp/(2*fp*fp))
elseif (@p_iter_type == "Type 2") ; Halley
return pz - @relax * (f/fp) / ( 1 - @p_alpha*f*fpp/(2*fp*fp))
else;if (@p_iter_type == "Type 3") ; Laguerre
complex root = sqrt(fp*fp-@p_alpha*2*f*fpp)
complex d1 = fp + root
complex d2 = fp - root
if (|d1| >= |d2|)
return pz - @relax * 2*f / d1
else
return pz - @relax * 2*f / d2
endif
endif
endfunc
protected:
complex m_a[11] ; coefficients of polynomial
complex m_ap[10] ; coefficients of first derivative of polynomial
complex m_app[10] ; coefficients of second derivative of polynomial
default:
rating = NotRecommended
title = "Newton Poly"
int param v_NewtonPolyUserTransform
caption = "Version (NewtonPoly_UserTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_NewtonPolyUserTransform < 100
endparam
param p_poly_type
caption = "Polynomial type"
enum = "Poly" "Power"
default = 1
hint = "Poly: polynomial has real powers, degree 10 or less. \
Power: polynomial is a single power, real or complex."
endparam
int param p_degree
caption = "Highest power"
default = 3
min = 2
max = 10
visible = (@p_poly_type == 0)
endparam
complex param p_a0
caption = "Constant coefficient"
default = (0,0)
visible = (@p_poly_type == 0)
endparam
complex param p_a1
caption = "Degree 1 coefficient"
default = (0,0)
visible = (@p_poly_type == 0)
endparam
complex param p_a2
caption = "Degree 2 coefficient"
default = (0,0)
visible = (@p_poly_type == 0)
endparam
complex param p_a3
caption = "Degree 3 coefficient"
default = (1,0)
visible = (@p_degree >= 3) && (@p_poly_type == 0)
endparam
complex param p_a4
caption = "Degree 4 coefficient"
default = (0,0)
visible = (@p_degree >= 4) && (@p_poly_type == 0)
endparam
complex param p_a5
caption = "Degree 5 coefficient"
default = (0,0)
visible = (@p_degree >= 5) && (@p_poly_type == 0)
endparam
complex param p_a6
caption = "Degree 6 coefficient"
default = (0,0)
visible = (@p_degree >= 6) && (@p_poly_type == 0)
endparam
complex param p_a7
caption = "Degree 7 coefficient"
default = (0,0)
visible = (@p_degree >= 7) && (@p_poly_type == 0)
endparam
complex param p_a8
caption = "Degree 8 coefficient"
default = (0,0)
visible = (@p_degree >= 8) && (@p_poly_type == 0)
endparam
complex param p_a9
caption = "Degree 9 coefficient"
default = (0,0)
visible = (@p_degree >= 9) && (@p_poly_type == 0)
endparam
complex param p_a10
caption = "Degree 10 coefficient"
default = (0,0)
visible = (@p_degree >= 10) && (@p_poly_type == 0)
endparam
complex param p_power
caption = "Power"
default = (3,0)
visible = (@p_poly_type == 1)
endparam
param p_type
caption = "cc"
; enum = "Constant" "C" "Pixel"
enum = "Constant" "Pixel"
default = 0
hint = "Iteration is one step in solving polynomial(z)-cc = 0. Try Pixel \
with Mandelbrot types, Constant with Julia types."
endparam
complex param p_const
caption = "Constant"
default = (1,0)
visible = (@p_type == 0)
endparam
param p_iter_type
caption = "Iteration type"
enum = "Newton" "Type 1" "Type 2" "Type 3"
default = 0
hint = "Newton is the usual, using only the first derivative. \
The other types also use the second derivative. Type 1 is Householder \
iteration if alpha = 1. Type 2 is Halley iteration if alpha = 2 and \
Schroder iteration if alpha = 1. Type 3 is Halley's irrational iteration \
if alpha = 1."
endparam
complex param p_alpha
caption = "alpha"
default = (1,0)
hint = "Nonstandard values of alpha may not allow convergence, but can give \
interesting shapes."
visible = (@p_iter_type > 0)
endparam
param relax
caption = "Relaxation"
default = (1,0)
hint = "The standard value is 1. Nonstandard values may not allow \
convergence, but can give interesting shapes."
endparam
}
class JLB_ContractionDualTransform(jlb.ulb:DualTransform) {
; Wrapper for a Contraction to plug into a DualTransform slot
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_ContractionDualTransform(Generic pparent)
DualTransform.DualTransform(pparent)
m_Contraction = new @f_Contraction(this)
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
pz = m_Contraction.Iterate(pz, pc)
return true
endfunc
protected:
Contraction m_Contraction
default:
rating = NotRecommended
title = "ContractionDualTransform"
int param v_ContractionDualTransform
caption = "Version (ContractionDualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ContractionDualTransform < 100
endparam
Contraction param f_Contraction
caption = "Contraction"
default = JLB_MandelbrotContraction
; hint = "The default Null Contraction does nothing."
endparam
}
class JLB_UserTransformDualTransform(jlb.ulb:DualTransform) {
; Wrapper for a UserTransform to plug into a DualTransform slot
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_UserTransformDualTransform(Generic pparent)
DualTransform.DualTransform(pparent)
m_UserTransform = new @f_UserTransform(this)
endfunc
; @param pz
; @param pc
; @return true if okay; possibly change both arguments
bool func Iterate(complex &pz, complex &pc)
pz = m_UserTransform.Iterate(pz) + @c*pc
return true
endfunc
protected:
UserTransform m_UserTransform
default:
rating = NotRecommended
title = "UserTransformDualTransform"
int param v_UserTransformDualTransform
caption = "Version (UserTransformDualTransform)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_UserTransformDualTransform < 100
endparam
UserTransform param f_UserTransform
caption = "Transform"
default = JLB_PowerUserTransform
; hint = "The default Null Contraction does nothing."
endparam
complex param c
caption = "Const"
default = 1
hint = "New z = transform(z) + const * c"
endparam
}
class JLB_QuadMirror(common.ulb:UserTransform) {
; Pick a block from the image, then repeat it mirroring both
; horizontally and vertically.
public:
import "common.ulb"
func JLB_QuadMirror(Generic pparent)
UserTransform.UserTransform(pparent)
m_PixelCoordinate = new PixelCoordinate(pparent)
m_FractalCoordinate = new FractalCoordinate(pparent)
endfunc
func Init(complex pz)
UserTransform.Init(pz)
m_PixelCoordinate.Init(pz)
m_FractalCoordinate.Init(pz)
int ix = @nx
int iy = @ny
if (@orig)
ix = 1
iy = 1
endif
; block size in pixels (floats)
m_hx = real(#screenmax) / ix
m_hy = imag(#screenmax) / iy
complex z
if (@ssb)
; which block to copy with mirroring
z = m_PixelCoordinate.Iterate(@z_ctr1)
ix = 1 + floor(real(z) / m_hx)
if (ix > @nx)
ix = @nx
elseif (ix < 1)
ix = 1
endif
iy = 1 + floor(imag(z) / m_hy)
if (iy > @ny)
iy = @ny
elseif (iy < 1)
iy = 1
endif
m_x2 = ix * m_hx ; right side of block
m_x1 = m_x2 - m_hx + 1 ; left side
m_y2 = iy * m_hy ; top side
m_y1 = m_y2 - m_hy + 1 ;bottom side
else
; where selected block goes
;z = m_PixelCoordinate.Iterate(@z_ctr2)
m_x1 = #width/2 - m_hx/2
m_x2 = m_x1 + m_hx
m_y1 = #height/2 - m_hy/2
m_y2 = m_y1 + m_hy
endif
endfunc
complex func Iterate(complex pz)
UserTransform.Iterate(pz)
complex tz = #screenpixel
; calculate pixel within source block for mirrored pixel to use
int n
float tx = real(tz)
float dx
if (tx > m_x2)
dx = tx - m_x2
n = floor(dx/m_hx)
dx = dx - n*m_hx
if (n % 2 == 0)
tx = m_x1 + m_hx - dx
else
tx = m_x1 + dx
endif
elseif (tx < m_x1)
dx = m_x1 - tx
n = floor(dx/m_hx)
dx = dx - n * m_hx
if (n % 2 == 0)
tx = m_x1 + dx
else
tx = m_x1 + m_hx - dx
endif
endif ; now m_x1 <= tx <= m_x2
float ty = imag(tz)
float dy
if (ty > m_y2)
dy = ty - m_y2
n = floor(dy/m_hy)
dy = dy - n*m_hy
if (n % 2 == 0)
ty = m_y1 + m_hy - dy
else
ty = m_y1 + dy
endif
elseif (ty < m_y1)
dy = m_y1 - ty
n = floor(dy/m_hy)
dy = dy - n * m_hy
if (n % 2 == 0)
ty = m_y1 + dy
else
ty = m_y1 + m_hy - dy
endif
endif ; now m_y1 <= ty <= m_y2
tz = tx + flip(ty)
complex sz = m_FractalCoordinate.Iterate(tz)
if (!@ssb && !@orig)
sz = sz + @z_ctr2 - #center
endif
return sz
endfunc
protected:
PixelCoordinate m_PixelCoordinate
FractalCoordinate m_FractalCoordinate
float m_hx, float m_hy ; block dimensions in pixels
float m_x2, float m_x1 ; block edges in pixels
float m_y2, float m_y1
default:
title = "QuadMirror"
rating = NotRecommended
heading
caption = "Use QuadMirror2 instead of QuadMirror"
endheading
heading
caption = "How many repeated blocks?"
endheading
int param nx
caption = "Horizontal"
default = 3
min = 1
endparam
int param ny
caption = "Vertical"
default = 2
min = 1
endparam
heading
text = "To make the blocks fit evenly in the resulting image, check here."
endheading
bool param ssb
caption = "Select source block?"
endparam
heading
text = "Choose any point in the source block. In the resulting image, \
this block will be in its original position."
visible = @ssb
endheading
complex param z_ctr1
caption = "Point"
default = #center
visible = @ssb
hint = "Check See Original, use the eyedropper to pick it, or use Explore."
endparam
heading
text = "Select the center point of the source block. In the resulting image, \
the block will be moved to the image center."
visible = !@ssb
endheading
complex param z_ctr2
caption = "Center point"
default = #center
visible = !@ssb
hint = "Check See Original, use the eyedropper to pick it, or use Explore."
endparam
bool param orig
caption = "See Original?"
default = false
hint = "Check the box to see where to set the point"
endparam
}
class JLB_SESFormula(SFormula) {
; z = a*f1(z op1 f2(c)) op2 b*f3(c)
; simplified version of SomethingElseMkII in tma2.ufm, rewritten as an SFormula
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_SESFormula(Generic pparent)
SFormula.SFormula(pparent)
m_Combine = new Combine()
if @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
endfunc
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex t1 = @f2(ppc)
t1 = m_Combine.go(pz, @op1, t1)
t1 = @a*@f1(t1)
complex t2 = @b*@f3(ppc)
znew = m_Combine.go(t1, @op2, t2)
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
Combine m_Combine
complex ppc
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Something Else"
int param v_SESFormula
caption = "Version (SE_SFormula)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_SESFormula < 100
endparam
; bool param p_std
; caption = "Standard?"
; default = true
; endparam
heading
caption = "z_new = a*f1(z op1 f2(c)) op2 b*f3(c)"
endheading
bool param p_Mtype
caption = "M-type?"
default = true
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = !@p_Mtype
endparam
complex param a
caption = "a"
default = 1
endparam
func f1
caption = "f1"
default = cos()
endfunc
param op1
caption = "op1"
default = 4
enum = "+" "-" "*" "/" "^"
endparam
func f2
caption = "f2"
default = ident()
endfunc
heading
endheading
param op2
caption = "op2"
default = 0
enum = "+" "-" "*" "/" "^"
endparam
complex param b
caption = "b"
default = 1
endparam
func f3
caption = "f3"
default = ident()
endfunc
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
class JLB_SetZSFormula(SFormula) {
; Set pz to a value or #pixel. Useful for setting the start value.
public:
bool func Iterate(State S)
S.pz = 0 ; so pzold = 0
if @type == 0
S.Update(@zz, S.pc)
else
S.Update(#pixel, S.pc)
endif
return S.bailed
endfunc
default:
title = "Set z"
rating = NotRecommended
int param v_SetZSFormula
caption = "Version (JLB_SetZSFormula)"
default = 100
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_SetZSFormula < 100
endparam
param type
enum = "value" "pixel"
caption = "Set z to"
default = 0
endparam
complex param zz
caption = "z"
default = (0,0)
visible = @type == 0
endparam
}
class JLB_Smooth(common.ulb:GradientColoring) {
;
; Object version of Smooth in Standard.ucl, slightly generalized.
;
public:
float func ResultIndex(complex pz)
return @a * (m_Iterations + @b - log(log(cabs(pz)))/log(@p))
endfunc
default:
title = "Smooth"
rating = NotRecommended
heading
caption = "index = a*(iters+b-log(log(cabs(z)))/log(p))"
endheading
float param a
caption = "a = overall multiplier"
default = 0.05
endparam
float param b
caption = "b = offset"
default = 0
endparam
float param p
caption = "p = power in main formula"
default = 2
min = 1
endparam
}
class JLB_TwoFuncSFormula(SFormula) {
; Combine two functions
; This is a simpler subset of Combo
;
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_TwoFuncSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_fSFormula = new @f_SFormula(this)
m_gSFormula = new @g_SFormula(this)
m_Combine = new Combine()
if @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
m_fSFormula.Init(pz, pc)
m_gSFormula.Init(pz, pc)
endfunc
; @param pz
; @return true if need to quit
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex pc = S.pc
if !@p_Mtype
pc = @p_seed
endif
complex znew
if @v_TwoFuncSFormula < 201
znew = @f(pz)^@p + @a*@g(pz)^@q
else
complex t2
if @gtype == 0
t2 = @a*(@g(pz))^@q
else
if !@p_Mtypeg
S.pc = @p_seedg
endif
if m_gSFormula.Iterate(S)
return true
endif
t2 = @a*(S.pz)^@q
S.pz = pz
S.pc = pc
endif
if @op == "( )"
if @ftype == 0
znew = @a*(@f(t2))^@p
else
S.pz = t2
if !@p_Mtypef
S.pc = @p_seedf
endif
if m_fSFormula.Iterate(S)
return true
endif
znew = (S.pz)^@p
endif
else
complex t1
if @ftype == 0
t1 = @f(pz)^@p
else
S.pz = pz ; original z value
if !@p_Mtypef
S.pc = @p_seedf
endif
if m_fSFormula.Iterate(S)
return true
endif
t1 = (S.pz)^@p
endif
znew = m_combine.Go(t1, @op, t2)
endif
endif
if !@p_Mtypec
pc = @p_seedc
endif
znew = m_combine.Go(znew, @op2, @b*pc)
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
Combine m_combine
SFormula m_fSFormula
SFormula m_gSFormula
UtilityTransform finalTransform
default:
title = "Two Functions"
rating = NotRecommended
int param v_TwoFuncSFormula
caption = "Version (TwoFuncSFormula)"
default = 201
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_TwoFuncSFormula < 201
endparam
; bool param p_std
; caption = "Standard?"
; default = true
; endparam
heading
caption = "znew = f(z)^p + a*g(z)^q + b*c"
visible = @v_TwoFuncSFormula < 201
endheading
heading
caption = "znew = (f(z)^p) op1 (a*g(z)^q) op2 (b*c)"
visible = @v_TwoFuncSFormula >= 201
endheading
heading
endheading
bool param p_Mtype
caption = "M-type"
default = true
visible = @v_TwoFuncSFormula < 201
endparam
complex param p_seed
caption = "J-type, seed ="
default = (1, 0)
visible = @v_TwoFuncSFormula < 201 && !@p_Mtype
endparam
param ftype
caption = "f function type"
default = 0
enum = "built-in func" "SFormula"
endparam
func f
caption = "f (func)"
default = sin()
visible = @ftype == 0
endfunc
SFormula param f_SFormula
caption = "f (SFormula)"
default = JLB_FuncSFormula
visible = @ftype == 1
endparam
bool param p_Mtypef
caption = "f: M-type"
default = true
visible = @ftype == 1
endparam
complex param p_seedf
caption = "f: J-type seed ="
default = (1, 0)
visible = @ftype == 1 && !@p_Mtypef
endparam
complex param p
caption = "p"
default = (3,0)
endparam
heading
endheading
param op
caption = "op1"
default = 0
enum = "+" "-" "*" "/" "^" "( )"
visible = @v_TwoFuncSFormula >= 201
endparam
heading
endheading
complex param a
caption = "a"
default = 1
endparam
param gtype
caption = "g function type"
default = 0
enum = "built-in func" "SFormula"
endparam
func g
caption = "g (func)"
default = tan()
visible = @gtype == 0
endfunc
SFormula param g_SFormula
caption = "g (SFormula)"
default = JLB_FuncSFormula
visible = @gtype == 1
endparam
bool param p_Mtypeg
caption = "g: M-type"
default = true
visible = @gtype == 1
endparam
complex param p_seedg
caption = "g: J-type seed ="
default = (1, 0)
visible = @gtype == 1 && !@p_Mtypeg
endparam
complex param q
caption = "q"
default = (2,0)
endparam
heading
endheading
param op2
caption = "op2"
default = 0
enum = "+" "-" "*" "/" "^"
visible = @v_TwoFuncSFormula >= 201
endparam
bool param p_Mtypec
caption = "c: M-type"
default = true
visible = @v_TwoFuncSFormula >= 201
endparam
complex param p_seedc
caption = "c: J-type seed ="
default = (1, 0)
visible = @v_TwoFuncSFormula >= 201 && !@p_Mtypec
endparam
complex param b
caption = "b"
default = 1
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
class JLB_ThreeLevelSFormula(SFormula) {
; A Barnsley-like formula as an SFormula, with a non-abrupt transition \
; possible from the upper formula to the middle and lower formulas.
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_ThreeLevelSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_SFormulaU = new @f_SFormulaU(this)
m_SFormulaM = new @f_SFormulaM(this)
m_SFormulaL = new @f_SFormulaL(this)
if @a*@v1 >= @a*@v2
m_critU = @a*@v1
m_critL = @a*@v2
else
m_critU = @a*@v2
m_critL = @a*@v1
endif
m_useM = m_critU > m_critL
if @v_ThreeLevelSFormula < 211003
m_CalcValue = new CalcValue()
; else
; m_CTF2 = new ComplexToFloat2()
endif
mTSmooth = new TSmooth()
endfunc
func Init(complex pz, complex pc)
m_SFormulaU.Init(pz, pc)
;if m_useM
m_SFormulaM.Init(pz, pc)
;endif
m_SFormulaL.Init(pz, pc)
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex pzold = S.pzold
complex pc = S.pc
complex pcc = pc ; this pc value only used for critical value
if !@p_Mtype
pcc = @p_seed
endif
float test
if @v_ThreeLevelSFormula < 211003
test = m_CalcValue.Go(@mode, pz, pcc)
else
test = ComplexToFloat2.go(pz, pcc, @mode2, false)
endif
; find U, M, and L z-values
if m_SFormulaU.Iterate(S)
return true
endif
complex zU = S.pz
S.pz = pz, S.pzold = pzold, S.pc = pc ; use original values
complex zM = 0
if m_useM
if m_SFormulaM.Iterate(S)
return true
endif
zM = S.pz
S.iters = S.iters - 1
endif
S.pz = pz, S.pzold = pzold, S.pc = pc
if m_SFormulaL.Iterate(S)
return true
endif
complex zL = S.pz
S.pzold = pzold
S.iters = S.iters - 1
; if trans == 0, use all of U, M, or L
complex fracU = 0
complex fracM = 0
complex fracL = 0
if @trans == 0
if test > m_critU
fracU = 1
elseif test < m_critL
fracL = 1
endif
else
; otherwise, do a smooth transition using tanh
fracU = mTSmooth.go((test-m_critU)/@trans)
fracL = mTSmooth.go((m_critL-test)/@trans)
endif
fracM = 1 - fracU - fracL
pz = fracU*zU + fracM*zM + fracL*zL
S.pz = S.pzold
S.Update(pz, pc) ; keep original pc, otherwise don't know which to use.
return S.bailed
endfunc
protected:
SFormula m_SFormulaU
SFormula m_SFormulaM
SFormula m_SFormulaL
CalcValue m_CalcValue
TSmooth mTSmooth
; ComplexToFloat2 m_CTF2
float m_critU
float m_critL
bool m_useM
default:
title = "ThreeLevel"
rating = NotRecommended
int param v_ThreeLevelSFormula
caption = "Version (ThreeLevelSFormula)"
default = 211003
hint = "This version parameter is used to detect when a change has \
been made to the formula that is incompatible with the \
previous version. When that happens, this field will reflect \
the old version number to alert you to the fact that an \
alternate rendering is being used."
visible = @v_ThreeLevelSFormula < 211003
endparam
heading
text = "Apply change depending on critical value"
hint = "Use real and imaginary parts of z and c to \
calculate value to compare with critical value."
endheading
bool param p_Mtype
caption = "M-type (for critical value)"
hint = "For calculating the critical value, 'c' is the pixel"
default = true
visible = (@v_ThreeLevelSFormula < 211003 && @mode >= 7) \
|| (@v_ThreeLevelSFormula >= 211003 && @mode2 >= 17)
endparam
complex param p_seed
caption = "Seed (for critical value)"
default = (1, 0)
hint = "For calculating the critical value, 'c' is this seed. \
It is not the 'c' in any of the formulas."
visible = !@p_Mtype && ( \
(@v_ThreeLevelSFormula < 211003 && @mode >= 7) \
|| (@v_ThreeLevelSFormula >= 211003 && @mode2 >= 17) )
endparam
param mode
caption = "mode"
hint = "How to calculate the critical value."
default = 0
enum = "mod" "real" "imag" "real+imag" "real-imag" "real*imag" "z angle" \
"z cross+ c" "z cross- c" "z dot+ c" "z dot- c"
visible = @v_ThreeLevelSFormula < 211003
endparam
param mode2
caption = "mode"
hint = "How to calculate the critical value."
default = 0
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle" "z cross+ c" "z cross- c" "z dot+ c" "z dot- c" "cabs(z*c)"
visible = @v_ThreeLevelSFormula >= 211003
endparam
float param v1
caption = "V1"
default = 1
endparam
float param v2
caption = "V2"
default = -1
endparam
float param a
caption = "V multiplier"
hint = "Upper critical value = larger of a*V1, a*V2; lower critical value =\
the smaller"
default = 1
endparam
float param trans
caption = "Transition parameter"
hint = "Smaller values make a steeper transition. For an abrupt transition, use 0."
default = 1
min = 0
endparam
SFormula param f_SFormulaU
caption = "Upper formula"
default = JLB_FuncSFormula
endparam
heading
text = "Middle formula not needed"
visible = @v1 == @v2
endheading
SFormula param f_SFormulaM
caption = "Middle formula"
default = JLB_MandelbrotSFormula
visible = @v1 != @v2
endparam
SFormula param f_SFormulaL
caption = "Lower formula"
default = JLB_PowerSFormula
endparam
}
class JLB_DExpSmooth(Distance) {
; 21 August 2021 added complications as seen in jlb.ucl "Exponential Smoothing Plus"
; and in ejb.ucl "Smooth colouring EB adjustment"
public:
func JLB_DExpSmooth(Generic pparent)
endfunc
func Init(complex zz)
center = (0,0)
if @ctr == "Screen center"
center = #center
elseif @ctr == "Pixel"
center = #pixel
elseif @ctr == "Point"
center = @pt
endif
scale = @a
endfunc
float func Iterate(complex zz)
float d = ComplexToFloat.go(zz-center, m_mode, m_abs_value)
d = real(@F(d)) ; real matches ejb. cabs maybe better?
d = exp(-scale*d)
scale = @r * scale
return d
endfunc
private:
complex center
float scale
default:
title = "Exponential Smoothing"
rating = NotRecommended
heading
text = "(Exponential Smoothing 2 is the preferred plug-in.)"
endheading
param ctr
caption = "Center"
enum = "Origin" "Screen center" "Pixel" "Point"
default = 0
hint = "Calculate distance from here."
endparam
complex param pt
caption = "Point"
default = (0,0)
visible = @ctr == 3
endparam
func F
caption = "Function of distance"
default = ident()
hint = "Apply this function before exponential."
endfunc
float param a
caption = "Scale"
default = 1
;min = 0
hint = "Large positive values give more emphasis to earlier iterations."
endparam
float param r
caption = "Factor to change scale"
default = 1
endparam
}
class JLB_DExpSmooth2(Distance) {
; 21 August 2021 added complications as seen in jlb.ucl "Exponential Smoothing Plus"
; and in ejb.ucl "Smooth colouring EB adjustment"
public:
func JLB_DExpSmooth2(Generic pparent)
Distance(pparent)
if @version >= 220703
m_dist = new @dist(this)
endif
endfunc
func Init(complex zz)
if @version >= 220703
m_dist.SetParams(0, true)
endif
; 240112 this block moved from constructor
center = (0,0)
if @ctr == "Screen center"
center = #center
elseif @ctr == "Pixel"
center = #pixel
elseif @ctr == "Point"
center = @pt
endif
scale = @a
endfunc
float func Iterate(complex zz)
float d
if @version >= 220703
d = m_dist.Iterate(zz)
else
int mmode = m_mode
if @version < 220619
mmode = @mode
endif
d = ComplexToFloat2.go(zz-center, (0,0), mmode, true)
endif
d = real(@F(d)) ; real matches ejb. cabs maybe better?
d = exp(-scale*d)
scale = @r * scale
return d
endfunc
private:
complex center
float scale
Distance m_dist
default:
title = "Exponential Smoothing 2"
rating = NotRecommended
int param version
caption = "Version"
default = 220703
visible = @version < 220703
endparam
param mode
caption = "Use for distance"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220619
endparam
param ctr
caption = "Center"
enum = "Origin" "Screen center" "Pixel" "Point"
default = 0
hint = "Calculate distance from here."
endparam
complex param pt
caption = "Point"
default = (0,0)
visible = @ctr == 3
endparam
func F
caption = "Function of distance"
default = ident()
hint = "Apply this function before exponential."
endfunc
float param a
caption = "Scale"
default = 1
;min = 0
hint = "Large positive values give more emphasis to earlier iterations."
endparam
float param r
caption = "Factor to change scale"
default = 1
endparam
Distance param dist
default = JLB_DXYZ
selectable = false
endparam
}
class JLB_DGrid(Distance) {
public:
func JLB_DGrid(Generic pparent)
Distance(pparent)
m_dist = new @dist(this)
if @screen_center
ctr = #center
else
ctr = @dcenter
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
; m_CTF = new ComplexToFloat2()
if @type == "Rectangular"
xgrid = abs(real(@grid))
ygrid = abs(imag(@grid))
endif
endfunc
func Init(complex zz)
m_dist.SetParams(0, true)
endfunc
float func Iterate(complex zz)
; Note that floor(v) doesn't work if v > 2147483647, the largest positive integer.
zz = ctr + rot * (zz - ctr)
if @type == "Rectangular"
if real(zz/xgrid) > 2e9 || imag(zz/ygrid) > 2e9 ; not enough precision
return -1
endif
int i = floor(real(zz)/xgrid)
int j = floor(imag(zz)/ygrid)
; zz is in rectangle whose lower left is (i,j)
; dx and dy are non-negative
float dx = real(zz) - i*xgrid
float dy = imag(zz) - j*ygrid
if dx > 0.5 * xgrid
dx = xgrid - dx
endif
if dy > 0.5 * ygrid
dy = ygrid - dy
endif
complex v
if @do_scale
v = dx/xgrid + flip(dy/ygrid)
else
v = dx + flip(dy)
endif
if @version < 220619
if real(v) <= imag(v)
return real(v)
else
return imag(v)
endif
else
;return ComplexToFloat2.go(v/rot,(0,0), m_mode, true)
return m_dist.Iterate(v/rot)^@pow
endif
else
float r = cabs(zz)
if r/@rgrid > 2e9
return -1
endif
int i = floor(r/@rgrid) ; if i==0 use distance to first circle,
float d1 = r - i * @rgrid ; not distance to center
if d1 > 0.5 * @rgrid || i == 0
d1 = @rgrid - d1
endif
;choose angular spacing to make the grid more or less square
int n = round(2 * #pi * (i + 0.5))
float agrid = 2 * #pi / n
float theta = atan2(zz)
if theta < 0, theta = theta + 2*#pi, endif
int j = floor(theta / agrid)
float d2 = theta - j * agrid
if d2 > 0.5 * agrid
d2 = agrid - d2
endif
d2 = r * d2
if @version < 220619
if d1 > d2
d1 = d2
endif
else
if d1 <= d2
v = d1 * zz / r
;d1 = ComplexToFloat2.go(v,(0,0), m_mode, true)
d1 = m_dist.Iterate(v)
else
v = d2 * zz * (0,1) / r ; right angle to zz
;d1 = ComplexToFloat2.go(v,(0,0), m_mode, true)
d1 = m_dist.Iterate(v)
endif
endif
if @do_pscale
d1 = d1 / @rgrid
endif
return d1^@pow
endif
endfunc
private:
complex ctr
complex rot
float xgrid
float ygrid
Distance m_dist
default:
title = "Grid"
rating = NotRecommended
heading
caption = "Use Grid2 instead."
endheading
int param version
caption = "Version"
default = 220619
visible = @version < 220619 ; backwards compatible to 211012
endparam
param type
enum = "Rectangular" " Polar"
caption = "Grid type"
default = 0
endparam
bool param screen_center
caption = "Use screen center?"
default = true
endparam
complex param dcenter
caption = "Center"
default = (0,0)
visible = !@screen_center
endparam
complex param grid
caption = "Grid spacing"
default = (1,1)
visible = @type == 0
endparam
float param rgrid
caption = "Radial spacing"
default = 1
min = 0
visible = @type == 1
endparam
float param angle
caption = "Rotation angle"
default = 0
visible = @type == 0
endparam
bool param do_scale
caption = "Scale to grid?"
default = false
visible = @type == 0
endparam
bool param do_pscale
caption = "Scale to radial spacing?"
default = false
visible = @type == 1
endparam
float param pow
caption = "Power"
default = 1
endparam
Distance param dist
default = JLB_DXYZ
selectable = false
endparam
}
class JLB_DLines(Distance) {
; line is a*x + b*y + c = 0
; a*real(zz) + b*imag(zz) + c = d
public:
func JLB_DLines(Generic pparent)
float t = @angle1*(#pi/180)
a1 = sin(t)
b1 = -cos(t)
c1 = -real(@point1)*sin(t) + imag(@point1)*cos(t)
if @num == " 2"
t = @angle2*(#pi/180)
a2 = sin(t)
b2 = -cos(t)
c2 = -real(@point2)*sin(t) + imag(@point2)*cos(t)
endif
endfunc
float func Iterate(complex zz)
float d = -1
bool okay
float dist1 = a1 * real(zz) + b1 * imag(zz) + c1
if @num == " 1"
if @side == " +"
okay = dist1 > 0
elseif @side == " -"
okay = dist1 < 0
else ; Either side
okay = true
endif
if okay
d = (abs(dist1)/@scale)^@pow
endif
else
float dist2 = a2 * real(zz) + b2 * imag(zz) + c2
if @sides == 0
okay = dist1 > 0 && dist2 > 0
elseif @sides == 1
okay = dist1 > 0 && dist2 < 0
elseif @sides == 2
okay = dist1 < 0 && dist2 > 0
elseif @sides == 3
okay = dist1 < 0 && dist2 < 0
else
okay = true
endif
if okay
d = choose(dist1, dist2)
endif
endif
if okay
d = (d/@scale)^@pow
endif
return d
endfunc
float func choose(float v1, float v2)
if @which == "Larger"
if abs(v1) > abs(v2)
return abs(v1)
else
return abs(v2)
endif
else
if abs(v1) < abs(v2)
return abs(v1)
else
return abs(v2)
endif
endif
endfunc
private:
float a1,float b1, float c1
float a2,float b2, float c2
default:
title = "Lines"
rating = NotRecommended
heading
text = "Lines are defined by a point and an angle. Use iterations only when z is on the \
specified positive or negative side of the line(s)."
endheading
int param version
caption = "Current is 220619"
default = 220619
visible = @version < 220619
endparam
param num
caption = "1 or 2 lines?"
enum = " 1" " 2"
default = 0
endparam
param which
caption = "Smaller / larger distance?"
enum = " Smaller" "Larger"
default = 0
visible = @num == " 2"
hint = "Distances are calculated to each line. Color using the smaller or larger of the two."
endparam
complex param point1
caption = "Point on line 1"
default = (0,0)
endparam
float param angle1
caption = "Angle of line 1"
default = 45
endparam
param side
caption = "Pos. or neg. side"
enum = " +" " -" " Either"
default = 0
visible = @num == " 1"
endparam
complex param point2
caption = "Point on line 2"
default = (0,0)
visible = @num == " 2"
endparam
float param angle2
caption = "Angle of line 2"
default = 0
; min = 0
; max = 180
visible = @num == " 2"
endparam
param sides
caption = "Pos. or neg. sides"
enum = " + +" " + -" " - +" " - -" " Any"
default = 0
visible = @num == " 2"
endparam
float param scale
caption = "Scale (> 0)"
default = 2.0
min = 1e-30
endparam
float param pow
caption = "Distance power"
default = 1
hint = "Positive values emphasize iterations with z farther from the line(s); \
negative values emphasize iterations with z nearer to the line(s)."
endparam
}
class JLB_DQuad(Distance) {
public:
func JLB_DQuad(Generic pparent)
; m_CTF = new ComplexToFloat()
endfunc
func Init(complex zz)
if @screen_center
ctr = #center
else
ctr = @dcenter
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
endfunc
float func Iterate(complex zz)
float d = -1
bool okay = false
complex v
if @version < 220910
v = ctr + rot * (zz - ctr) ; wrong!
else
v = rot * (zz - ctr)
endif
if @quad == " 1"
okay = real(v) > 0 && imag(v) > 0
elseif @quad == " 2"
okay = real(v) < 0 && imag(v) > 0
elseif @quad == " 3"
okay = real(v) < 0 && imag(v) < 0
else;if @quad == " 4"
okay = real(v) > 0 && imag(v) < 0
endif
if okay
d = ComplexToFloat.go(zz, m_mode, true)
endif
return d
endfunc
private:
complex ctr
complex rot
; ComplexToFloat m_ctf
default:
title = "Quadrant"
rating = NotRecommended
heading
text = "(Quadrant2 is the preferred plug-in)."
endheading
int param version
caption = "Version"
default = 220910
visible = @version < 220910 ; backwards compatible to 211012
endparam
heading
text = "(Current is 2220910.)"
visible = @version < 220910
endheading
bool param screen_center
caption = "Use screen center?"
default = true
endparam
complex param dcenter
caption = "Center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Rotation angle"
default = 0
endparam
param quad
caption = "Quadrant"
enum = " 1" " 2" " 3" " 4"
default = 0
hint = "1 is upper right, 2 is upper left, 3 is lower left, 4 is lower right."
endparam
}
class JLB_DQuad2(Distance) {
; 211124 added "Any" option
; 230126 added "Change" option; backwards compatible.
public:
func JLB_DQuad2(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
if @screen_center
ctr = #center
else
ctr = @dcenter
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, m_abs_value)
old_quad = get_quad(rot * (zz - ctr))
endfunc
float func Iterate(complex zz)
if @version < 220910
zz = ctr + rot * (zz - ctr) ; wrong!
else
zz = rot * (zz - ctr)
endif
float d = -MyMath.fmax( 1, |zz|)
int new_quad = get_quad(zz)
bool okay = false
if @quad == "Any"
okay = true
elseif @quad == "Change"
okay = old_quad != new_quad
elseif @quad == "Same"
okay = old_quad == new_quad
else
okay = @quad == new_quad
endif
if okay
int mmode = m_mode
if @version < 220619
mmode = @mode ; set in Distance Coloring
d = ComplexToFloat2.go(zz/rot,(0,0), mmode, true)
else
d = m_dist.Iterate(zz/rot)
endif
if @version < 240224
bool neg = ( d < 0 )
d = abs(d)^@pow
if neg, d = -d, endif
endif
endif
return d
endfunc
int func get_quad(complex zz)
float x = real(zz)
float y = imag(zz)
if x >= 0 && y >= 0
return 0
elseif x <= 0 && y >= 0
return 1
elseif x <= 0 && y <= 0
return 2
else
return 3
endif
endfunc
private:
complex ctr
complex rot
Distance m_dist
int old_quad
default:
title = "Quadrant2"
rating = NotRecommended
heading
caption = "Use Lines2 instead."
endheading
int param version
caption = "Version"
default = 240224
visible = @version < 240224
endparam
heading
text = "(current is 2402241.}"
visible = @version < 240224
endheading
param mode
caption = "Use for distance"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220619
endparam
bool param screen_center
caption = "Use screen center?"
default = true
endparam
complex param dcenter
caption = "Center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Rotation angle"
default = 0
endparam
param quad
caption = "Quadrant"
enum = " 1" " 2" " 3" " 4" "Any" "Change" "Same"
default = 4
hint = "1 is upper right, 2 is upper left, 3 is lower left, 4 is lower right."
endparam
float param pow
caption = "Distance power"
default = 1
hint = "Positive values emphasize iterations with z farther from the line(s); \
negative values emphasize iterations with z nearer to the line(s)."
visible = @version < 240224
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DSquare(Distance) {
; 211124 added"Either" option
; 211229 added Rectangle option
; 230128 added "Change" and "Same" options; backwards compatible
public:
func JLB_DSquare(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
if @screen_center
ctr = #center
else
ctr = @center
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
if @type == "Square"
h = v = 0.5 * @side
else
h = 0.5 * @horiz
v = 0.5 * @vert
endif
scale = 1
if @do_scale
if @version >= 220720
scale = 2*sqrt(h*v)
else
scale = h
if v > h, scale = v, endif
endif
endif
size = sqrt(h*v)
v1 = ctr + h + flip(v) ; upper right corner
v2 = ctr + h - flip(v) ; lower right corner
v3 = ctr - h - flip(v) ; lower left corner
v4 = ctr - h + flip(v) ; upper left corner
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, m_abs_value)
old_inside = IsInside(rot * (zz - ctr))
endfunc
float func Iterate(complex zz)
zz = rot * (zz - ctr)
bool new_inside = IsInside(zz)
if @version < 220916
zz = ctr + zz ; wrong
endif
float d = -MyMath.fmax(1, |zz|)
if @version < 230811 && @method == "Original"
float dist = cabs(zz - ctr)
if new_inside
if @in_out_old == "Inside"|| @in_out_old == "Either"
d = (1-dist/h)^@pow
endif
return d
else; if x > h || y > v
if @in_out_old == "Outside" || @in_out_old == "Either"
d = (1-h/dist)^@pow
endif
endif
else;if @method == "Corrected"
bool okay = false
if @in_out == "Either"
okay = true
elseif @in_out == "Inside"
okay = new_inside
elseif @in_out == "Outside"
okay = !new_inside
elseif @in_out == "Change"
okay = old_inside != new_inside
elseif @in_out == "Same"
okay = old_inside == new_inside
endif
if @version >= 230808 && !okay
if @in_out == "In->In"
okay = old_inside && new_inside
elseif @in_out == "In->Out"
okay = old_inside && !new_inside
elseif @in_out == "Out->In"
okay = !old_inside && new_inside
elseif @in_out == "Out->Out"
okay = !old_inside && !new_inside
endif
endif
old_inside = new_inside
if okay
complex pv = Geometry.ClosestPointToFigure(zz, 4, v1, v2, v3, v4)
if @version >= 230811
pv = zz * cabs(pv)/size ; to be like circle2
endif
d = m_dist.Iterate(pv)/scale
bool neg = ( d < 0 )
d = abs(d)^@pow
if neg, d = -d, endif
endif
endif
return d
endfunc
bool func IsInside(complex zz)
float x = abs(real(zz))
float y = abs(imag(zz))
return (x <= h && y <= v)
endfunc
private:
complex ctr
complex rot
float h
float v
float size
float scale
complex v1, complex v2, complex v3, complex v4
Distance m_dist
bool old_inside
default:
title = "Square"
rating = NotRecommended
heading
caption = "Use 'SimpleShapes' instead."
endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
param type
caption = "Square / Rectangle"
enum = "Square" "Rectangle"
default = 0
endparam
float param side
caption = "Square side length"
default = 2.0
min = 0
visible = @type == 0
endparam
float param horiz
caption = "Rectangle x length"
default = 2
min = 0
visible = @type == 1
endparam
float param vert
caption = "Rectangle y length"
default = 2
min = 0
visible = @type == 1
endparam
bool param screen_center
caption = "Use screen center?"
default = true
endparam
param center
caption = "Square center"
default = (0,0)
visible = !@screen_center
endparam
float param angle
caption = "Rotation angle"
default = 0
endparam
param in_out_old
caption = "Inside/outside the Square"
enum = "Inside" "Outside" "Either"
default = 2 ; changed 230102, was 0
visible = @method == 0
endparam
param in_out
caption = "Inside/outside the Square"
enum = "Inside" "Outside" "Either" "Change" "Same" \
"In->In" "In->Out" "Out->In" "Out->Out"
default = 2
visible = @version >= 230811 || @method == 1
endparam
param method
caption = "Distance method"
enum = "Original" "Corrected"
default = 1
visible = @version < 230811
endparam
float param pow
caption = "Distance power"
default = 1
min = 0
; hint = "Higher values emphasize iterations with z away from the Square edge."
endparam
bool param do_scale
caption = "Scale by size?"
default = true
visible = @version < 240101
endparam
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DSimpleShapes(Distance) {
; 240224 added @standard to Circles and Ellipses to allow for different powers for
; the x and y terms. Does not break earlier fractals, so @version not changed.
public:
func JLB_DSimpleShapes(Generic pparent)
Distance(pparent)
m_dist = new @dist(this)
if @screen_center, ctr = #center, else, ctr = @center, endif
; scale = 1
complex v1 , complex v2 , complex v3 , complex v4
v1 = v2 = v3 = v4 = 1 ; make compiler happy
if @type == "Circle" || @type == "Ellipse"
if @standard
px = py = pxy = @p
else
px = @qx, py = @qy, pxy = (px+py)/2
endif
endif
if @type == "Circle"
h = v = @r
elseif @type == "Ellipse"
h = @hE, v = @vE
elseif @type == "Triangle"
if @equi
v1 = flip(2*@side/3)
rot = cos(#pi*2/3) + flip(sin(#pi*2/3))
v2 = v1 * rot
v3 = v2 * rot
v1 = v1 + ctr, v2 = v2 + ctr, v3 = v3 + ctr
else
v1 = @vt1, v2 = @vt2, v3 = @vt3
endif
v4 = v3 ; simplifies things
else
if @type == "Square"
h = v = 0.5 * @side
else
h = 0.5 * @hR, v = 0.5 * @vR
endif
; if @do_scale, scale = 2*sqrt(h*v), endif
v1 = ctr + h + flip(v) ; upper right corner
v2 = ctr + h - flip(v) ; lower right corner
v3 = ctr - h - flip(v) ; lower left corner
v4 = ctr - h + flip(v) ; upper left corner
endif
rot = 1
if @type != "Circle" || @p != 2
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
endif
if @type >= 2
v1r = ctr + conj(rot)*(v1-ctr)
v2r = ctr + conj(rot)*(v2-ctr)
v3r = ctr + conj(rot)*(v3-ctr)
v4r = ctr + conj(rot)*(v4-ctr)
endif
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, m_abs_value)
if @type == "Circle" || @type == "Ellipse"
float r
old_inside = IsInsideC(rot * (zz - ctr), r) ; calculates r -- ignored
elseif @type == "Triangle"
old_inside = Geometry.PointInTriangle(zz, v1r, v2r, v3r)
else
old_inside = IsInsideS(rot * (zz - ctr))
endif
endfunc
float func Iterate(complex zz)
bool new_inside
float r = 1 ; keep compiler happy
if @type == "Circle" || @type == "Ellipse"
new_inside = IsInsideC(rot * (zz - ctr), r) ; calculates r
elseif @type == "Triangle"
new_inside = Geometry.PointInTriangle(zz, v1r, v2r, v3r)
else
; rotate and shift zz so IsInsideS can be simple
new_inside = IsInsideS(rot * (zz - ctr))
endif
float d = -1
bool okay = false
if @in_out == "Either"
okay = true
elseif @in_out == "Inside"
okay = new_inside
elseif @in_out == "Outside"
okay = !new_inside
elseif @in_out == "Change"
okay = old_inside != new_inside
elseif @in_out == "Same"
okay = old_inside == new_inside
elseif @in_out == "In->In"
okay = old_inside && new_inside
elseif @in_out == "In->Out"
okay = old_inside && !new_inside
elseif @in_out == "Out->In"
okay = !old_inside && new_inside
elseif @in_out == "Out->Out"
okay = !old_inside && !new_inside
elseif @in_out == "Show shape"
zz = #pixel
if @type == "Circle" || @type == "Ellipse"
okay = IsInsideC(rot * (zz - ctr), r) ; calculates r, used below
elseif @type == "Triangle"
okay = Geometry.PointInTriangle(zz, v1r, v2r, v3r)
else ; "Square" or "Rectangle"
okay = IsInsideS(rot*(zz-ctr))
endif
endif
old_inside = new_inside
if !okay
return -1
endif
complex pv
if @type == "Circle" || @type == "Ellipse"
d = r ; needed for Show shape
else
int nv = 3
if @type != "Triangle", nv = 4, endif
pv = Geometry.ClosestPointToFigure(zz, nv, v1r, v2r, v3r, v4r)
d = cabs(pv)
endif
if @in_out == "Show shape"
return d
endif
if @type == "Circle" || @type == "Ellipse"
d = abs(1-r)
endif
zz = d * zz
d = m_dist.Iterate(zz)
; d = (d + cabs(zz)) / 2
return d
endfunc
bool func IsInsideS(complex zz)
float x = abs(real(zz))
float y = abs(imag(zz))
return (x <= h && y <= v)
endfunc
bool func IsInsideC(complex zz, float &r)
float x = abs(real(zz))
float y = abs(imag(zz))
r= ( (x/h)^px + (y/v)^py ) ^ (1/pxy)
return r <= 1
endfunc
private:
complex ctr
complex rot
float h, float v
float px, float py, float pxy
; float scale
complex v1r, complex v2r, complex v3r, complex v4r
Distance m_dist
bool old_inside
default:
title = "Simple Shapes"
rating = NotRecommended
heading ; 240313
caption = "Okay, but superseded by Shape Distance"
endheading
int param version
caption = "Version"
default = 240212
visible = @version < 240212
endparam
heading
text = "(current is 240212.}"
visible = @version < 240212
endheading
param type
caption = "Shape type"
enum = "Circle" "Ellipse" "Triangle" "Square" "Rectangle"
default = 0
endparam
; triangle stuff
bool param equi
caption = "Equilateral triangle?"
default = true
visible = @type == 2
endparam
complex param vt1
caption = "Vertex 1"
default = (0,0)
visible = @type == 2 && !@equi
endparam
complex param vt2
caption = "Vertex 2"
default = (1,0)
visible = @type == 2 && !@equi
endparam
complex param vt3
caption = "Vertex 3"
default = (0,1)
visible = @type == 2 && !@equi
endparam
float param side
caption = "Side length"
default = 2.0
min = 0
visible = (@type == 2 && @equi) || @type == 3
endparam
; circle & ellipse stuff
bool param screen_center
caption = "Use screen center?"
default = true
visible = @type < 2 || (@type == 2 && @equi)
endparam
param center
caption = "Center"
default = (0,0)
; visible = (@type < 2 || (@type == 2 && @equi)) && !@screen_center
visible = (!(@type == 2 && !@equi)) && !@screen_center
endparam
bool param standard
caption = "Standard?"
default = true
visible = @type < 2
endparam
float param p
caption = "Shape power"
default = 2
min = 0.2
visible = @type < 2 && @standard
endparam
float param qx
caption = "X shape power"
default = 2
min = 0.2
visible = @type < 2 && !@standard
endparam
float param qy
caption = "Y shape power"
default = 2
min = 0.2
visible = @type < 2 && !@standard
endparam
float param r
caption = "Circle radius"
default = 1
min = 0
visible = @type == 0
endparam
float param hE
caption = "Ellipse x value"
default = 2
min = 0
visible = @type == 1
endparam
float param vE
caption = "Ellipse y value"
default = 1
min = 0
visible = @type == 1
endparam
; square & rectangle stuff
float param hR
caption = "Rectangle X length"
default = 2
min = 0
visible = @type == 4
endparam
float param vR
caption = "Rectangle Y length"
default = 1
min = 0
visible = @type == 4
endparam
float param angle
caption = "Rotation angle"
default = 0
endparam
param in_out
caption = "Inside/outside/etc."
enum = "Inside" "Outside" "Either" "Change" "Same" \
"In->In" "In->Out" "Out->In" "Out->Out" "Show shape"
default = 2
endparam
heading
endheading
Distance param dist
default = JLB_D_SD ;2
selectable = false
visible = @in_out != "Show shape"
endparam
}
class JLB_DSimple(Distance) {
; Take a complex number as input and return a float
public:
func JLB_Dsimple(Generic pparent)
; m_CTF = new ComplexToFloat()
endfunc
float func Iterate(complex zz)
float ans = ComplexToFloat.go(zz, m_mode, m_abs_value)
return ans
endfunc
private:
; ComplexToFloat2 m_CTF
default:
title = "Simple"
rating = NotRecommended
heading
text = "(Simple2 is the preferred plug-in.)"
endheading
}
class JLB_DSimple2(Distance) {
; Take a complex number as input and return a float
public:
func JLB_DSimple2(Generic pparent)
Distance(pparent)
if @version < 220622
ctr = (0,0)
else
if @screen_center
ctr = #center
else
ctr = @center
endif
endif
if @version >=220703 && @version < 240101
m_dist = new @dist(this)
elseif @version >= 240101
m_dist = new @distnew(this)
endif
endfunc
func Init(complex zz)
if @version >=220703
m_dist.Init(zz)
m_dist.SetParams(0, true)
endif
endfunc
float func Iterate(complex zz)
if @version >= 220703
return m_dist.Iterate(zz)
endif
int mmode = m_mode
if @version < 220619
mmode = @mode
endif
float ans = ComplexToFloat2.go(zz-ctr,(0,0), mmode, true)
return ans
endfunc
private:
complex ctr
Distance m_dist
default:
title = "Simple2"
rating = NotRecommended
heading
text = "Color according to a combination of real and imaginary parts of z."
endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
bool param screen_center
caption = "Use screen center?"
default = true
visible = @version >= 220622
endparam
complex param center
caption = "Center"
default = (0,0)
visible = @version >= 220622 && !@screen_center
endparam
param mode
caption = "Use for distance"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220619
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version >=220703 && @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DMultiple(Distance) {
public:
func JLB_DMultiple(Generic pparent)
Distance(pparent)
fDist1 = new @dist1(this)
if @num >= 2
fDist2 = new @dist2(this)
if @num >= 3
fDist3 = new @dist3(this)
if @num >= 4
fDist4 = new @dist4(this)
if @num >= 5
fDist5 = new @dist5(this)
endif
endif
endif
endif
endfunc
func Init(complex zz)
fDist1.Init(zz)
fDist1.SetParams(0, true)
if @num >= 2
fDist2.Init(zz)
fDist2.SetParams(0, true)
if @num >= 3
fDist3.Init(zz)
fDist3.SetParams(0, true)
if @num >= 4
fDist4.Init(zz)
fDist4.SetParams(0, true)
if @num >= 5
fDist5.Init(zz)
fDist5.SetParams(0, true)
endif
endif
endif
endif
endfunc
float func Iterate(complex zz)
bool okay_d = false
float d = -1
float dd
dd = fDist1.Iterate(zz)
if dd > 0
d = dd, okay_d = true
elseif @how == "All"
return -1
endif
if @num >= 2
dd = fDist2.Iterate(zz)
if dd > 0
if okay_d
if dd < d, d = dd, endif
else
d = dd, okay_d = true
endif
elseif @how == "All"
return -1
endif
endif
if @num >= 3
dd = fDist3.Iterate(zz)
if dd > 0
if okay_d
if dd < d, d = dd, endif
else
d = dd, okay_d = true
endif
elseif @how == "All"
return -1
endif
endif
if @num >= 4
dd = fDist4.Iterate(zz)
if dd > 0
if okay_d
if dd < d, d = dd, endif
else
d = dd, okay_d = true
endif
elseif @how == "All"
return -1
endif
endif
if @num >= 5
dd = fDist5.Iterate(zz)
if dd > 0
if okay_d
if dd < d, d = dd, endif
else
d = dd, okay_d = true
endif
elseif @how == "All"
return -1
endif
endif
return d
endfunc
private:
Distance fDist1
Distance fDist2
Distance fDist3
Distance fDist4
Distance fDist5
default:
title = "Multiple"
rating = NotRecommended
heading
text = "Designed for methods that do Inside/Outside (Circle, Square, etc.), \
but usable for all. Use the minimum distance."
endheading
int param version
caption = "Version"
default = 211021
visible = @version < 211021
endparam
int param num
caption = "How many (max 5)?"
default = 2
min = 1
max = 5
endparam
param how
caption = "Require any or all?"
enum = "Any" "All"
hint = "Allow any distance within range, or require all destances to be within range"
default = 0
endparam
heading
; caption = "Distance method 1"
endheading
Distance param dist1
caption = "Method 1"
default = JLB_DCircle2
endparam
heading
; caption = "Distance method 2"
visible = @num >= 2
endheading
Distance param dist2
caption = "Method 2"
default = JLB_DSquare
visible = @num >= 2
endparam
heading
; caption = "Distance method 3"
visible = @num >= 3
endheading
Distance param dist3
caption = "Method 3"
default = JLB_DGrid2
visible = @num >= 3
endparam
heading
; caption = "Distance method 4"
visible = @num >= 4
endheading
Distance param dist4
caption = "Method 4"
default = JLB_DSquare
visible = @num >= 4
endparam
heading
; caption = "Distance method 5"
visible = @num >= 5
endheading
Distance param dist5
caption = "Method 5"
default = JLB_DSquare
visible = @num >= 5
endparam
}
class JLB_DOverUnder(Distance) {
public:
func JLB_DOverUnder(Generic pparent)
fDistOver = new @distOver(this)
fDistUndr = new @distUndr(this)
endfunc
func Init(complex zz)
fDistOver.Init(zz)
fDistUndr.Init(zz)
if @version < 220703
fDistOver.SetParams(@scoloring1, true)
fDistUndr.SetParams(@scoloring2, true)
endif
endfunc
float func Iterate(complex zz)
float v = ComplexToFloat2.go(zz, (0,0), @mode, false)
if v >= @crit
return fDistOver.Iterate(zz)
else
return fDistUndr.Iterate(zz)
endif
endfunc
private:
Distance fDistOver
Distance fDistUndr
default:
title = "OverUnder"
rating = NotRecommended
heading
text = "Use a distance method depending on a critical value."
hint = "Use real and imaginary parts of z to \
calculate value to compare with critical value."
endheading
int param version
caption = "Version"
default = 220703
visible = @version < 220703
endparam
param mode
caption = "Use for critical value"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
endparam
float param crit
caption = "Critical value"
default = 1
endparam
heading
endheading
param scoloring1
caption = "Use for Over distance"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag| (manh)""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220703 && @distOver != JLB_DTrap
endparam
Distance param distOver
caption = "Over method"
default = JLB_DSimple2
endparam
heading
endheading
param scoloring2
caption = "Use for Under distance"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag| (manh)""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220703 && @distUndr != JLB_DTrap
endparam
Distance param distUndr
caption = "Under method"
default = JLB_DCircle
endparam
}
class JLB_DTri(Distance) {
; distance to nearest triangle vertex
; okay if the triangle is degenerate
; 211124 added "Either" option
public:
func JLB_DTri(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
scale = 1
if @do_scale
scale = (cabs(@v1-@v2) + cabs(@v2-@v3) + cabs(@v3-@v1) ) / 3
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
ctr = (@v1 + @v2 + @v3) / 3
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
zz = ctr + rot * (zz - ctr)
old_inside = Geometry.PointInTriangle(zz, @v1, @v2, @v3)
endfunc
float func Iterate(complex zz)
; if @version < 220910
zz = ctr + rot * (zz - ctr) ; wrong! ?
; else
; zz = rot * zz
; endif
bool new_inside = Geometry.PointInTriangle(zz, @v1, @v2, @v3)
if @method == "Original"
if (new_inside && @in_out_old == "Outside") || (!new_inside && @in_out_old == "Inside")
return -1
endif
float d1 = cabs(zz - @v1)
float d2 = cabs(zz - @v2)
float d3 = cabs(zz - @v3)
if d2 < d1, d1 = d2, endif
if d3 < d1, d1 = d3, endif
return d1
else
float d = -1
bool okay = true ; "Either"
if @in_out == "Inside"
okay = new_inside
elseif @in_out == "Outside"
okay = !new_inside
elseif @in_out == "Change"
okay = old_inside != new_inside
elseif @in_out == "Same"
okay = old_inside == new_inside
endif
old_inside = new_inside
if okay
complex pv = Geometry.ClosestPointToFigure(zz, 3, @v1, @v2, @v3, @v3)
float d = m_dist.Iterate(pv)
bool neg = ( d < 0 )
d = abs(d/scale)^@pow
if neg, d = -d, endif
endif
return d
endif
endfunc
private:
float scale
complex rot
complex ctr
Distance m_dist
bool old_inside
default:
title = "Triangle"
rating = NotRecommended
heading
caption = "Use 'SimpleShapes' instead."
endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
complex param v1
caption = "Vertex 1"
default = (0,0)
endparam
complex param v2
caption = "Vertex 2"
default = (2,0)
endparam
complex param v3
caption = "Vertex 3"
default = (0,2)
endparam
float param angle
caption = "Rotation angle"
default = 0
endparam
param in_out_old
caption = "Inside/outside the Triangle"
enum = "Inside" "Outside" "Either"
default = 2 ; changed 230102, was 0
visible = @method == 0
endparam
param in_out
caption = "Inside/outside the Triangle"
enum = "Inside" "Outside" "Either" "Change" "Same"
default = 2
visible = @method == 1
endparam
param method
caption = "Distance method"
enum = "Original" "Corrected"
default = 1
; visible = @in_out < 2
endparam
float param pow
caption = "Distance power"
default = 1
min = 0
visible = @method == 1
; hint = "Higher values emphasize iterations with z away from the Square edge."
endparam
bool param do_scale
caption = "Scale by side length?"
default = false
visible = @method == 1
endparam
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101
endparam
}
class JLB_DCircle(Distance) {
;211124 added "Either" option
;211229 added Ellipse option and "use screen center" option
;220916 added option to change h and v by @ratio each iteration. backwards compatible.
public:
func JLB_DCircle(Generic pparent)
Distance(pparent)
m_dist = new @dist(this)
if @screen_center
ctr = #center
else
ctr = @center
endif
scale = 1
if @type == "Circle"
h = v = @r
else
h = @horiz, v = @vert
endif
if @do_scale
if @version >= 220720
scale = sqrt(h*v)
else
scale = MyMath.fmax(h, v)
endif
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
endfunc
func Init(complex zz)
m_dist.SetParams(0, true)
endfunc
float func Iterate(complex zz)
float x, float y
zz = rot * (zz - ctr)
x = abs(real(zz))
y = abs(imag(zz))
int iter = GetIter( )
float rr = @ratio^iter
float hh = h*rr
float vv = v*rr
float ss = scale*rr
float q= (x/hh)^@p + (y/vv)^@p
if @version < 220619
; this version has errors
float d = -1
q= q^(1/@p)
if q <= 1 && (@in_out == "Inside" || @in_out == "Either")
d = ((1-q)/ss)^@pow
endif
if q > 1 && (@in_out == "Outside" || @in_out == "Either")
d = ((1-1/q)/ss)^@pow
endif
return d
else
float d1 = -1
if q <= 1 && @in_out != "Outside"
if q == 0
d1 = MyMath.fmin(hh, vv)
else
zz = (1/q-1) * zz
d1 = m_dist.Iterate(zz/rot)/ss
endif
endif
float d2 = -1
if q > 1 && @in_out != "Inside"
zz = (q-1) * zz
d2 = m_dist.Iterate(zz/rot)/ss
endif
; at least one of d1 and d2 is non-negative
if d2 < 0, return d1, endif
if d1 < 0, return d2, endif
return MyMath.fmin(d1, d2)
endif
endfunc
private:
complex ctr
float h
float v
float scale
complex rot
Distance m_dist
default:
title = "Circle"
rating = NotRecommended
heading
text = "Distance to a circle or ellipse. Optionally use only those iterations that are \
inside or outside the shape."
endheading
int param version
caption = "Version"
default = 220720
visible = @version < 220720
endparam
heading
text = "(current is 220720.}"
visible = @version < 220720
endheading
param type
caption = "Circle or ellipse"
enum = "Circle" "Ellipse"
default = 0
endparam
float param p
caption = "Shape power"
default = 2
min = 0
hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square."
endparam
bool param screen_center
caption = "Use screen center?"
default = true
endparam
param center
caption = "Center"
default = (0,0)
visible = !@screen_center
endparam
float param r
caption = "Circle radius"
default = 2.0
min = 0
visible = @type == 0
endparam
float param horiz
caption = "Ellipse x value"
default = 2.0
min = 0
visible = @type == 1
endparam
float param vert
caption = "Ellipse y value"
default = 2.0
min = 0
visible = @type == 1
endparam
float param ratio
caption = "Ratio"
hint = "Change circle radius / ellipse values by this factor each iteration."
default = 1
min = 0
endparam
float param angle
caption = "Rotation angle"
default = 0
visible = @p != 2.0 || (@type == 1 && @horiz != @vert)
endparam
param in_out
caption = "Inside/outside?"
enum = "Inside" "Outside" "Either"
default = 2 ; changed 230102, was 0
endparam
float param pow
caption = "Distance power"
default = 1
min = 0
visible = @version < 220619
; hint = "Higher values emphasize iterations with z away from the Square edge."
endparam
bool param do_scale
caption = "Scale by size?"
default = false
;visible = @version < 220619
endparam
heading
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
endparam
}
class JLB_DCircle2(Distance) {
; 230126 added "Change" option; backwards compatible.
; 230808 added "In->In" & etc. options.
; 231215 changed dist fro JLB_DXYZ to JLB_D_SD
public:
func JLB_DCircle2(Generic pparent)
Distance(pparent)
if @version < 240101
m_dist = new @dist(this)
else
m_dist = new @distnew(this)
endif
if @screen_center, ctr = #center, else, ctr = @center, endif
if @type == "Circle", h = v = @r, else, h = @horiz, v = @vert, endif
scale = 1
if @do_scale
scale = 2 * MyMath.fmax(h, v) ; 2 to be like Square scaling
endif
rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180))
endfunc
func Init(complex zz)
m_dist.Init(zz) ; needed if JLB_D_SD, uses D19 Path Ratio
m_dist.SetParams(0, m_abs_value)
float r
old_inside = IsInside(rot * (zz - ctr), r) ; calculates r -- ignored
endfunc
float func Iterate(complex zz)
zz = rot * (zz - ctr)
float d = -MyMath.fmax(1, |zz|)
float r
bool new_inside = IsInside(zz, r) ; calculates r
complex t
bool okay = false
if @in_out == "Either"
okay = true
elseif @in_out == "Inside"
okay = new_inside
elseif @in_out == "Outside"
okay = !new_inside
elseif @in_out == "Change"
okay = new_inside != old_inside
elseif @in_out == "Same"
okay = new_inside == old_inside
endif
if @version >= 230808
if @in_out == "In->In"
okay = old_inside && new_inside
elseif @in_out == "In->Out"
okay = old_inside && !new_inside
elseif @in_out == "Out->In"
okay = !old_inside && new_inside
elseif @in_out == "Out->Out"
okay = !old_inside && !new_inside
endif
endif
if @in_out == "Show shape"
okay = IsInside(rot*(#pixel-ctr), r) ; calculates r -- used!
endif
if okay
if @in_out == "Show shape"
d = r
else
t = zz * (1-r) / rot
if @version >= 230808 && !new_inside
t = -t
endif
d = m_dist.Iterate(t)/scale
old_inside = new_inside
if @version < 240101
bool neg = ( d < 0 )
d = abs(d)^@pow
if neg, d = -d, endif
endif
endif
endif
return d
endfunc
bool func IsInside(complex zz, float &r)
float x = abs(real(zz))
float y = abs(imag(zz))
r= ( (x/h)^@p + (y/v)^@p ) ^ (1/@p)
return r <= 1
endfunc
private:
complex ctr
float h
float v
float scale
complex rot
bool old_inside
Distance m_dist
default:
title = "Circle2"
rating = NotRecommended
heading
caption = "Use 'SimpleShapes' instead."
endheading
int param version
caption = "Version"
default = 240101
visible = @version < 240101
endparam
heading
text = "(current is 240101.}"
visible = @version < 240101
endheading
param type
caption = "Circle or ellipse"
enum = "Circle" "Ellipse"
default = 0
endparam
float param p
caption = "Shape power"
default = 2
min = 0
hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square."
endparam
bool param screen_center
caption = "Use screen center?"
default = true
endparam
param center
caption = "Center"
default = (0,0)
visible = !@screen_center
endparam
float param r
caption = "Circle radius"
default = 2.0
min = 0
visible = @type == 0
endparam
float param horiz
caption = "Ellipse x value"
default = 2.0
min = 0
visible = @type == 1
endparam
float param vert
caption = "Ellipse y value"
default = 2.0
min = 0
visible = @type == 1
endparam
float param angle
caption = "Rotation angle"
default = 0
visible = @p != 2.0 || (@type == 1 && @horiz != @vert)
endparam
param in_out
caption = "Inside/outside?"
enum = "Inside" "Outside" "Either" "Change" "Same" \
"In->In" "In->Out" "Out->In" "Out->Out" "Show shape"
hint = "Change: use iterations where new inside is different from \
old inside. Same: use iterations where new inside equals \
old inside"
default = 2 ; changed 230102, was 0
endparam
float param pow
caption = "Distance power"
default = 1
min = 0
visible = @version < 240101
; hint = "Higher values emphasize iterations with z away from the circle edge."
endparam
bool param do_scale
caption = "Scale by size?"
default = false
visible = @in_out != "Show shape"
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
visible = @version < 240101
endparam
Distance param distnew
default = JLB_D_SD
selectable = false
visible = @version >= 240101 && @in_out != "Show shape"
endparam
}
class JLB_DCircles(Distance) {
public:
func Init(complex zz)
r[1] = @r1
if @polar
ctr[1] = @rad1*(cos(@ang1*#pi/180) + flip(sin(@ang1*#pi/180)))
else
ctr[1] = @dctr1
endif
if @num >= 2
r[2] = @r2
if @polar
ctr[2] = @rad2*(cos(@ang2*#pi/180) + flip(sin(@ang2*#pi/180)))
else
ctr[2] = @dctr2
endif
if @num >= 3
r[3] = @r3
if @polar
ctr[3] = @rad3*(cos(@ang3*#pi/180) + flip(sin(@ang3*#pi/180)))
else
ctr[3] = @dctr3
endif
if @num >= 4
r[4] = @r4
if @polar
ctr[4] = @rad4*(cos(@ang4*#pi/180) + flip(sin(@ang4*#pi/180)))
else
ctr[4] = @dctr4
endif
if @num >= 5
r[5] = @r5
if @polar
ctr[5] = @rad4*(cos(@ang5*#pi/180) + flip(sin(@ang5*#pi/180)))
else
ctr[5] = @dctr5
endif
endif
endif
endif
endif
endfunc
float func Iterate(complex zz)
float d = -1
float dd
int n = 1
while n <= @num
float x, float y, float rz
x = abs(real(zz-ctr[n]))
y = abs(imag(zz-ctr[n]))
rz = (x^@shape + y^@shape)^(1/@shape)
if @in_out == "Inside"
if rz < r[n]
if @how == "Original"
dd = (1 - rz/r[n])^@pow
else
dd = ((r[n]-rz)/r[n])
endif
if d < 0 ; first one that's inside
d = dd
else
if dd < d, d = dd, endif
endif
endif
else;if @in_out == "Outside"
if rz > r[n]
if @how == "Original"
dd = (1 - r[n]/rz)^@pow
else
dd = ((rz-r[n])/r[n])
endif
if d < 0
d = dd
else
if dd < d, d = dd, endif
endif
endif
endif
n = n + 1
endwhile
return d
endfunc
private:
complex ctr[6]
float r[6]
default:
title = "Circles"
rating = NotRecommended
heading
text = "Use only the iterations that are inside or outside the circle(s), as specified."
endheading
int param num
caption = "How many (max 5)?"
default = 1
min = 1
max = 5
endparam
float param shape
caption = "Circle shape"
default = 2
min = 0
hint = "Use 2 for circle, < 2 for indented, > 2 for shapes nearing a square"
endparam
param how
caption = "How to calculate"
enum = "Original" "Corrected"
default = 0
endparam
bool param polar
caption = "Polar coords, for centers?"
default = false
hint = "Centers may be specified by real and imaginary part or using distance and angle."
endparam
heading
endheading
float param r1
caption = "Circle #1 size"
default = 2.0
min = 0
endparam
param dctr1
caption = "Circle #1 ctr"
default = (0,0)
visible = !@polar
endparam
float param rad1
caption = "Circle #1 ctr. distance"
default = 2
visible = @polar
endparam
float param ang1
caption = "Circle #1 ctr. angle"
default = 0
visible = @polar
endparam
float param r2
caption = "Circle #2 size"
default = 1.0
min = 0
visible = @num >= 2
endparam
param dctr2
caption = "Circle #2 center"
default = (2,0)
visible = @num >= 2 && !@polar
endparam
float param rad2
caption = "Circle #2 ctr. distance"
default = 2
visible = @num >= 2 && @polar
endparam
float param ang2
caption = "Circle #2 ctr. angle"
default = 60
visible = @num >= 2 && @polar
endparam
float param r3
caption = "Circle #3 size"
default = 1.0
min = 0
visible = @num >= 3
endparam
param dctr3
caption = "Circle #3 center"
default = (-2,0)
visible = @num >= 3 && !@polar
endparam
float param rad3
caption = "Circle #3 ctr. distance"
default = 2
visible = @num >= 3 && @polar
endparam
float param ang3
caption = "Circle #3 ctr. angle"
default = 120
visible = @num >= 3 && @polar
endparam
float param r4
caption = "Circle #4 size"
default = 1.0
min = 0
visible = @num >= 4
endparam
param dctr4
caption = "Circle #4 center"
default = (0,2)
visible = @num >= 4 && !@polar
endparam
float param rad4
caption = "Circle #4 ctr. distance"
default = 2
visible = @num >= 4 && @polar
endparam
float param ang4
caption = "Circle #4 ctr. angle"
default = -120
visible = @num >= 4 && @polar
endparam
float param r5
caption = "Circle #5 size"
default = 1.0
min = 0
visible = @num >= 5
endparam
param dctr5
caption = "Circle #5 center"
default = (0,-2)
visible = @num >= 5 && !@polar
endparam
float param rad5
caption = "Circle #5 ctr. distance"
default = 2
visible = @num >= 5 && @polar
endparam
float param ang5
caption = "Circle #5 ctr. angle"
default = -60
visible = @num >= 5 && @polar
endparam
heading
endheading
param in_out
caption = "Inside/outside the circles"
enum = "Inside" "Outside"
default = 0
hint = "Inside means inside any 'circle'; outside means outside any 'circle'."
endparam
float param pow
caption = "Distance power"
default = 1
min = 0
hint = "Higher values emphasize iterations with z away from the circle edge."
visible = @how == 0
endparam
}
class JLB_DistanceColoring(common.ulb:GradientColoring) {
; Accumulate a sum at each step, or at selected steps, of the orbit.
; Use the result to calculate a color index.
;
public:
import "common.ulb"
func JLB_DistanceColoring(Generic pparent)
GradientColoring(pparent)
if @twodist
fDistance1 = new @dist1(this)
fDistance2 = new @dist2(this)
else
fDistance = new @dist(this)
endif
if @version < 220621
zDistance = new @zDist(this)
endif
if @fz == 2
zzTransform = new @fUT(this)
elseif @fz == 1 && @version >= 220801
zzTransform = new @FF(this)
endif
rotation = cos(@angle * #pi/180.0) - flip(sin(@angle * #pi/180.0))
endfunc
func Init(complex pz, complex ppixel)
GradientColoring.Init(pz, ppixel)
if @twodist
fDistance1.init(pz)
fDistance2.init(pz)
if @version < 220703
fDistance1.SetParams(@scoloring1, true)
fDistance2.SetParams(@scoloring2, true)
else
fDistance1.SetParams(0, true)
fDistance2.SetParams(0, true)
endif
else
fDistance.init(pz)
if @version < 220703
fDistance.SetParams(@scoloring, true)
else
fDistance.SetParams(0, true)
endif
endif
cSum = 0, cSum2 = 0, cSumSq = 0
wtSum = 0, wtSum2 = 0
dmin = 1e30
dmax = -1e30
z_prev = pz
iter = 0 ; iter updated each call to Iterate()
iter1 = 1
iter2 = 2000000000 ; largest int is 2147483647
iter3 = -1
iter4 = -1
if @some_all == " Some" || @some_all == " Some + More"
iter1 = @start
iter2 = @start + @howmany - 1
if @some_all == " Some + More"
iter3 = @start2
iter4 = @start2 + @howmany2 - 1
endif
endif
count = 0 ; count update only for succesful distance calculation
icount = 0
endfunc
func Iterate(complex pz)
GradientColoring.Iterate(pz)
iter = iter + 1
bool okay = (iter >= iter1 && iter <= iter2) || (iter >= iter3 && iter <= iter4)
if !okay
return
endif
complex zz = pz
if @zdz == "z-z_prev"
zz = zz - z_prev
elseif @zdz == "z/z_prev"
zz = zz / z_prev
elseif @zdz == "z-pixel"
zz = zz - #pixel
elseif @zdz == "z/pixel"
zz = zz / #pixel
endif
z_prev = pz
zz = zz * rotation
if @fz == "F(a*zz)"
if @version < 220801
zz = @F(@a*zz)
else
zz = zzTransform.Iterate(@a*zz)
endif
elseif @fz == "T(a*zz)"
zz = zzTransform.Iterate(@a*zz)
endif
float d
if @twodist
if icount < @n1
fDistance1.SetIter(iter) ; added 220916 - backwards compatible
d = fDistance1.Iterate(zz)
else
fDistance2.SetIter(iter) ; added 220916 - backwards compatible
d = fDistance2.Iterate(zz)
endif
else
fDistance.SetIter(iter) ; added 220916 - backwards compatible
d = fDistance.Iterate(zz)
endif
if @twodist
icount = icount + 1
if icount == @n1 + @n2
icount = 0
endif
endif
if d <= 0 || (@UseMinMax && (d <= @ddmin || d > @ddmax))
return
endif
complex zd = d
if @version < 220621
if @ctype > 5
if @dmult == "d*zz"
zd = d * zz
elseif @dmult == "d*G(b*zz)"
zd = d * @G(@b*zz)
endif
endif
endif
count = count + 1
if @ctype == 0;"First Distance"
if count == 1
cSum = d
endif
elseif @ctype == 1;"Last Distance"
cSum = d
elseif @ctype == 2;"Smallest Distance"
if d < dmin
cSum = d
dmin = d
endif
elseif @ctype == 3;"Largest Distance"
if d > dmax
cSum = d
dmax = d
endif
endif
if d < dmin, dmin = d, endif
if d > dmax, dmax = d, endif
if @ctype == 4;"Distance range"
cSum = dmax - dmin
elseif @ctype == 5;"Distance ratio"
if dmin > 0
cSum = dmax / dmin
endif
elseif @ctype > 5 ; some kind of average
float w = 1
if @wtype
w = count^@pwt
endif
Accumulate(zd, w)
endif
endfunc
float func ResultIndex(complex pz)
if @solid && count == 0
m_solid = true ; from base class
return 0
endif
if @ctype <= 5
wtsum = 1
else ; averages of some kind
FinalAverage()
endif
float index = real(cSum)
if @version < 220621
if @dmult > 0
if @ctype > 5 && @ctype < 9
index = zDistance.Iterate(csum)
endif
endif
endif
if @ctype == "Count"
index = count / @Cscale
endif
if @final > 0
index = FinalSmooth(index)
endif
if @recip && index != 0
index = 1/index
endif
return index
endfunc
func Accumulate(complex zd, float w)
cSum2 = cSum
if @ctype == "Arithmetic Average"
cSum = cSum + w * zd
elseif @ctype == "Geometric Average"
cSum = cSum + w * log(zd)
elseif @ctype == "Harmonic Average"
cSum = cSum + w / zd
else
cSum = cSum + w*zd
cSumSq = cSumSq + |w*zd| ; real^2+imag^2
endif
wtSum2 = wtSum
wtSum = wtSum + w
endfunc
func FinalAverage()
if count > 0 ; there were some
if @ctype >= 9 || (@ctype > 5 && !@skip_avg)
cSum = cSum / wtSum
if wtSum2 > 0
cSum2 = cSum2 / wtSum2
endif
cSumSq = cSumSq / wtSum
endif
if @ctype == "Geometric Average" ;7
cSum = exp(cSum)
elseif @ctype == "Harmonic Average" ;8
cSum = 1 / cSum
elseif (@ctype == "Variation 1") ;9 "Std. Deviation" ; ignoring the -1 of n-1
cSum = sqrt(cSumSq - |cSum|)
elseif (@ctype == "Variation 2") ;10 "Coef. of Variation"
cSum = sqrt(cSumSq - |cSum|) / cabs(cSum)
elseif (@ctype == "Variation 3") ;11 "Fractal Dimension"
if dmax == dmin
cSum = 0
else
cSum = sqrt(cSumSq - |cSum|) / (dmax-dmin)
endif
endif
endif
endfunc
; Some ftype coloring methods get a final smoothing.
float func FinalSmooth(float ans)
if @final == 1
float il = 1/log(@power)
float lp = log(log(@bailout))
ans = 0.05 * (count - 1 + il*lp - il*log(log(abs(ans)))) ; 0.05 and -1 to agree with original
elseif @final == 2
float il = 1/log(@power) ; as in Triangle in Standard.ulb
float lp = log(log(@bailout)/2.0)
float fac = (1 + il * lp - il*log(log(cabs(#z))))
csum = csum * wtSum / (wtSum + 1) ; to agree with original
csum2 = csum2 * wtSum2 / (wtSum2 + 1)
ans = cabs(cSum2 + (cSum - cSum2) * fac)
endif
return ans
endfunc
private:
complex rotation
Distance fDistance
Distance fDistance1 ; for following the orbit
Distance fDistance2
Distance zDistance ; for coloring the averages
UserTransform zzTransform
complex cSum
complex cSum2
complex cSumsq
float wtSum
float wtSum2
float dmin
float dmax
complex z_prev
int count
int iter, int iter1, int iter2, int iter3, int iter4
int icount
default:
title = "Distance Coloring"
rating = NotRecommended
int param version
caption = "Version"
default = 220801
visible = @version < 220801 ; backward compatible to 220703
endparam
heading
text = "(Current is 220801.)"
visible = @version < 220801
endheading
Heading
caption = "Use 'Color by Distance' instead."
endheading
bool param solid
caption = "Use solid background?"
default = true
endparam
; maybe next as a hint?
; heading
; text = "Pixels for which the formula bails out on the first iteration will have the background color, \
; rather than the zero location of the gradient."
; visible = @solid
; endheading
heading
caption = "Accumulation phase"
endheading
param zdz
caption = "Use for zz "
enum = "z" "z-z_prev" "z/z_prev" "z-pixel" "z/pixel"
default = 0
endparam
float param angle
caption = "Rotate zz by "
default = 0
endparam
heading
caption = "Use zz, F(a*zz), or T(a*zz)"
endheading
param fz
caption = "Which?"
enum = "zz" "F(a*zz)" "T(a*zz)"
default = 0
endparam
complex param a
caption = "a"
default = 1
visible = @fz > 0
endparam
func F
caption = "Function"
default = sinh()
visible = @fz == 1 && @version < 220801
endfunc
UserTransform param FF
default = JLB_FTransform
selectable = false
visible = @fz == 1 && @version >= 220801
endparam
UserTransform param fUT
caption = "Transform"
default = JLB_MoebiusUserTransform
visible = @fz == 2
endparam
heading
visible = @fz > 0
endheading
bool param twodist
caption = "Two distance methods?"
default = false
endparam
; heading
; visible = @twodist
; endheading
bool param UseMinMax
caption = "Min/max distances?"
default = false
endparam
float param ddmin
caption = "Min distance"
default = 1
min = 0
visible = @UseMinMax
endparam
float param ddmax
caption = "Max distance"
default = 100
min = 0
visible = @UseMinMax
endparam
heading
endheading
param scoloring
caption = "Use for distance"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag| (manh)""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220703 && !@twodist && @dist != JLB_DTrap \
&& @dist != JLB_DOverUnder; && @dist != JLB_DCurve
endparam
Distance param dist
caption = "Distance method"
default = JLB_DXYZ ;Simple2
visible = !@twodist
endparam
param scoloring1
caption = "Use for distance 1"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag| (manh)""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220703 && @twodist && @dist != JLB_DTrap \
&& @dist != JLB_DOverUnder; && @dist != JLB_DCurve
endparam
int param n1
caption = "Repetitions for #1"
default = 1
min= 1
visible = @twodist
endparam
Distance param dist1
caption = "Distance method #1"
default = JLB_DXYZ ;Simple2
visible = @twodist
endparam
Distance param zDist
default = JLB_DXYZ ;Simple2
visible = false ; can't change it--maybe selectable=false instead?
endparam
heading
visible = @twodist
endheading
param scoloring2
caption = "Use for distance 2"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
visible = @version < 220703 && @twodist && @dist2 != JLB_DTrap \
&& @dist2 != JLB_DOverUnder; && @dist2 != JLB_DCurve
endparam
int param n2
caption = "Repetitions for #2"
default = 1
min = 0
visible = @twodist
endparam
Distance param dist2
caption = "Distance method #2"
default = JLB_DCircle
visible = @twodist
endparam
heading
endheading
param some_all
enum = " All" " Some" " Some + More"
default = 0
caption = "Use all / some iterations?"
;visible = @type > 0
endparam
int param start
caption = "Starting with iteration?"
default = 4
min = 1
visible = @some_all > 0
endparam
int param howmany
caption = "How many to use?"
default = 100
min = 1
visible = @some_all > 0
endparam
int param start2
caption = "More: starting with?"
default = 1
min = 1
visible = @some_all > 1
endparam
int param howmany2
caption = "More: how many?"
default = 1
min = 0
visible = @some_all > 1
endparam
bool param wtype
caption = "Weighted averages?"
default = false
visible = @ctype > 5
endparam
float param pwt
caption = "Weight power p"
default = 0.5
visible = @wtype == true && @ctype > 5
hint = "Positive p gives more weight to later iterations; negative p gives more weight \
to earlier iterations; p = 0 weights all iterations the same."
endparam
; heading
; visible = @ctype > 5
; endheading
param dmult
caption = "Use distance multiplier?"
default = 0
enum = "d" "d*zz" "d*G(b*zz)"
visible = @version < 220621 && @ctype > 5
endparam
func G
caption = "G"
default = sinh()
visible = @version < 220621 && @dmult == 2 && @ctype > 5
endfunc
complex param b
caption = "b"
default = 1
visible = @version < 220621 && @dmult == 2 && @ctype > 5
endparam
heading
caption = "Final phase of coloring"
endheading
param ctype
caption = "How to color"
enum = "First Distance" "Last Distance" "Smallest Distance" "Largest Distance" \
"Distance range" "Distance ratio" \
"Arithmetic Average" "Geometric Average" "Harmonic Average" \
"Variation 1" "Variation 2" "Variation 3" "Count"
; "Std. Deviation" "Coef. of Variation" "Fractal Dimension"
default = 6
;visible = @final != 1
endparam
int param Cscale
caption = "Count scale"
default = 100
visible = @ctype == 12
endparam
bool param skip_avg ; maybe later if more checking
caption = "Use sum instead of average?"
default = false
visible = @ctype > 5 && @ctype < 9
endparam
param zcoloring
caption = "Average this"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|" "|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle" ; "Count" "First Iteration" "Last Iteration"
visible = @dmult > 0 && @ctype > 5 && @ctype < 9
endparam
param final
caption = "Final smooth"
enum = "None" "Mandelbrot type" "TIA type"
default = 0
endparam
float param power
caption = "Exponent"
default = 2.0
hint = "This should be set to match the exponent of the \
formula you are using."
visible = @final > 0
endparam
float param bailout
caption = "Bailout"
default = 1e20
min = 1
hint = "This should be set to match the bail-out value in the Formula tab. "
visible = @final > 0
endparam
bool param recip
caption = "Use reciprocal?"
default = false
hint = "Color based on, for example, 1/Mod(z) instead of Mod(z)."
endparam
}
class JLB_LinearUserTransform(common.ulb:UserTransform) {
public:
complex func Iterate(complex pz)
return (@a + @b*pz)
endfunc
default:
rating = NotRecommended
title = "Linear"
int param v_LinearUserTransform
caption = "Version (Linear_UserTransform)"
default = 220212
visible = @v_LinearUserTransform < 220212
endparam
heading
caption = "v_new = a + b*v"
endheading
complex param a
caption = "Linear: a"
default = (0,0)
endparam
complex param b
caption = "Linear: b"
default = (1,0)
endparam
}
class Tweak(common.ulb:UtilityTransform) {
public:
import "common.ulb"
func Tweak(Generic pparent)
UtilityTransform(pparent)
if @type == 2
zzTransform = new @uT(pparent)
endif
endfunc
complex func Iterate(complex pz)
complex tmp
if @type == "Linear"
tmp = @e1 + @e2*pz
elseif @type == "Built-in Function"
tmp = @e1 + @e2*@F(@a*pz)
else;if @type == "Transform"
tmp = @e1 + @e2*zzTransform.Iterate(@a*pz)
endif
if @kind == "Add"
pz = pz + tmp
else
pz = tmp
endif
return pz
endfunc
private:
UserTransform zzTransform
default:
title = "Tweak"
param kind
caption = "Add or Replace"
enum = "Add" "Replace"
default = 0
endparam
heading
caption = "v_new = v + e1 + e2*v"
visible = @type == 0 && @kind == 0
endheading
heading
caption = "v_new = e1 + e2*v"
visible = @type == 0 && @kind == 1
endheading
heading
caption = "v_new = v + e1 + e2*F(a*v)"
visible = @type == 1 && @kind == 0
endheading
heading
caption = "v_new = e1 + e2*F(a*v)"
visible = @type == 1 && @kind == 1
endheading
heading
caption = "v_new = v + e1 + e2*T(a*v)"
visible = @type == 2 && @kind == 0
endheading
heading
caption = "v_new = e1 + e2*T(a*v)"
visible = @type == 2 && @kind == 1
endheading
param type
caption = "Tweak type"
enum = "Linear" "Built-in Function" "Transform"
default = 0
endparam
func F
caption = "Tweak Function"
default = ident()
visible = @type == 1
endfunc
UserTransform param uT
caption = "Tweak Transform"
default = JLB_LinearUserTransform
visible = @type == 2
endparam
complex param e1
caption = "Tweak: e1"
default = (0,0)
endparam
complex param e2
caption = "Tweak: e2"
default = (0.1,0)
endparam
complex param a
caption = "a"
default = 1
visible = @type > 0
endparam
}
class JLB_TwoUserTransforms(common.ulb:UserTransform) {
; A wrapper for two UserTransforms on one variable.
public:
import "common.ulb"
func JLB_TwoUserTransforms(Generic pparent)
UserTransform.UserTransform(pparent)
mUT1 = new @fUT1(this)
mUT2 = new @fUT2(this)
m_Combine = new Combine()
endfunc
complex func Iterate(complex pz)
if (@how == "( )")
pz = mUT1.Iterate(mUT2.Iterate(pz))
else
complex z1 = mUT1.Iterate(pz)
complex z2 = mUT2.Iterate(pz)
pz = m_Combine.go(z1, @how, z2)
endif
return pz
endfunc
protected:
UserTransform mUT1
UserTransform mUT2
Combine m_Combine
default:
;rating = Recommended
title = "Two Transforms"
heading
caption = "Use 'Transform Combo' instead."
endheading
int param v_TwoUserTransforms
caption = "Version (Two Transforms)"
default = 220312
visible = @v_TwoUserTransforms < 220312
endparam
param how
caption = "How to combine"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine Transform values."
endparam
UserTransform param fUT1
caption = "First Transform"
default = JLB_LinearUserTransform
endparam
UserTransform param fUT2
caption = "Second Transform"
default = JLB_BasicUserTransform
endparam
}
class JLB_ComboUserTransform(common.ulb:UserTransform) {
; Combine two functions or transforms or one each
public:
import "common.ulb"
func JLB_ComboUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
if (@ww == "T1 F2") || (@ww == "T1 T2")
mUT1 = new @fUT1(this)
endif
if (@ww == "F1 T2") || (@ww == "T1 T2")
mUT2 = new @fUT2(this)
endif
m_Combine = new Combine()
endfunc
complex func Iterate(complex pz)
complex z1
complex z2
if (@ww == "F1 F2") || (@ww == "T1 F2")
z2 = @F2(pz)
else
z2 = mUT2.Iterate(pz)
endif
if (@how == "( )")
if (@ww == "F1 F2") || (@ww == "F1 T2")
pz = @F1(z2)
else
pz = mUT1.Iterate(z2)
endif
else
if (@ww == "F1 F2") || (@ww == "F1 T2")
z1 = @F1(pz)
else
z1 = mUT1.Iterate(pz)
endif
pz = m_Combine.go(z1, @how, z2)
endif
return pz
endfunc
protected:
UserTransform mUT1
UserTransform mUT2
Combine m_Combine
default:
rating = NotRecommended
title = "Combo"
heading
text = "Combo Transform is the preferred formula."
endheading
int param v_ComboUserTransform
caption = "Version (Combo)"
default = 220316
visible = @v_ComboUserTransform < 220316
endparam
heading
caption = "Combine two functions or transforms"
endheading
param ww
caption = "Which to use"
enum = "F1 F2" "F1 T2" "T1 F2" "T1 T2"
default = 0
endparam
param how
caption = "How to combine"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine Transform values."
endparam
func F1
caption = "Function F1"
default = sin()
visible = (@ww == 0) || (@ww == 1)
endfunc
UserTransform param fUT1
caption = "Transform T1"
default = JLB_LinearUserTransform
visible = (@ww == 2) || (@ww == 3)
endparam
func F2
caption = "Function F2"
default = tanh()
visible = (@ww == 0) || (@ww == 2)
endfunc
UserTransform param fUT2
caption = "Transform T2"
default = JLB_BasicUserTransform
visible = (@ww == 1) || (@ww == 3)
endparam
}
class JLB_RotateUserTransform(common.ulb:UserTransform) {
public:
func JLB_RotateUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
;rotate = cos(@degrees*#pi/180) + flip(sin(@degrees*#pi/180))
rotate = exp(flip(@degrees*#pi/180))
endfunc
complex func Iterate(complex pz)
return (rotate*pz)
endfunc
private:
complex rotate
default:
rating = notRecommended
title = "Rotate"
heading
caption = "Use Zoom/Rotate/Twist instead."
endheading
int param v_RotateUserTransform
caption = "Version (Rotate_UserTransform)"
default = 220320
visible = @v_RotateUserTransform < 220320
endparam
heading
caption = "v_new = rotation*v"
endheading
; complex param a
; caption = "Rotate: a"
; default = (0,0)
; endparam
float param degrees
caption = "Rotate: degrees"
default = 45
endparam
}
class JLB_OverUnderUserTransform(common.ulb:UserTransform) {
public:
func JLB_OverUnderUserTransform(Generic pparent)
UserTransform.UserTransform(pparent)
mTO = new @uTO(pparent)
mTU = new @uTU(pparent)
mCalcValue = new CalcValue()
mTSmooth = new TSmooth()
endfunc
complex func Iterate(complex pz)
float test = mCalcValue.Go(@mode, pz, pz)
if @trans == 0
if test >= @crit
return mTO.Iterate(pz)
else
return mTU.Iterate(pz)
endif
else
float x = (test-@crit)/@trans
float frac = mTSmooth.go(x)
return frac*mTO.Iterate(pz) + (1-frac)*mTU.Iterate(pz)
; if x >= 32 ; good to 28 decimals even with 30 added precision
; return mTO.Iterate(pz)
; elseif x <= -32
; return mTU.Iterate(pz)
; else
; float frac = 0.5*(1+tanh(x))
; return frac*mTO.Iterate(pz) + (1-frac)*mTU.Iterate(pz)
; endif
endif
endfunc
private:
CalcValue mCalcValue
TSmooth mTSmooth
UserTransform mTO
UserTransform mTU
default:
;rating = Recommended
title = "OverUnder"
int param v_OverUnderUserTransform
caption = "Version (OverUnderUserTransform)"
default = 220323
visible = @v_OverUnderUserTransform < 220323
endparam
heading
caption = "Apply different transforms if a test value is over or under the critical value."
endheading
float param crit
caption = "Critical value"
default = 0
endparam
param mode
caption = "How to calculate the test value."
default = 0
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
endparam
UserTransform param uTO
caption = "Over Transform"
default = JLB_RotateUserTransform
endparam
UserTransform param uTU
caption = "Under Transform"
default = JLB_LinearUserTransform
endparam
float param trans
caption = "Transition parameter"
hint = "Larger values make a smoother transition. For an abrupt transition, use 0."
default = 0.1
min = 0
endparam
}
class JLB_MaskColoring(common.ulb:DirectColoring) {
; Generate a mask with opacity 1 at the center, going to 0 far away.
public:
func JLB_MaskColoring(Generic pparent)
DirectColoring(pparent)
c = 1
s = 0
if (@shape_type > 0) ;|| (@p != 2.0)
ang = @angle * #pi / 180.0
c = cos(ang)
s = sin(ang)
endif
if @shape_type == 0
rx = ry = @r
else
rx = @xsemi
ry = @ysemi
endif
endfunc
; func Init(complex pz, complex ppixel)
; DirectColoring.Init(pz, ppixel)
; endfunc
; func Iterate(complex pz)
; endfunc
color func Result(complex pz)
if rx == 0 || ry == 0
return rgba(0.5,0.5,1.0, 0.0) ; no mask
endif
float d
;if (@shape_type == "Circle" || @shape_type == "Ellipse")
float x = real(pz-@center)
float y = imag(pz-@center)
float xr = abs(x*c + y*s) / rx
float yr = abs(x*s - y*c) / ry
d = (xr^2 + yr^2)
; d = (xr^@p + yr^@p)
;endif
if @type == 0
d = 1 - d / @scale
if d < 0, d = 0, endif
else
d = exp(-d / @scale)
endif
if @inverse
d = 1.0 - d
endif
return rgba(0,0,0, d)
endfunc
private:
float ang, float c, float s
float rx, float ry
default:
title = "Mask Coloring"
rating = NotRecommended
heading
caption = "'Mask from shape' is preferred."
endheading
heading
text = "Generate a mask with opacity 1 at the center, decaying to 0 far away.\
The formula and the gradient are ignored."
visible = !@inverse
endheading
heading
text = "Generate a mask with opacity 0 at the center, growing to 1 far away.\
The formula and the gradient are ignored."
visible = @inverse
endheading
bool param inverse
caption = "Inverse?"
default = false
endparam
param shape_type
caption = "Shape"
enum = "Circle" "Ellipse"
default = 0
endparam
complex param center
caption = "Center"
default = (0,0)
endparam
; float param p
; caption = "Power"
; default = 2.0
; min = 0.1
; hint = "Use 2 for standard circles or ellipses"
; ;visible = (@shape_type < 2)
; endparam
float param r
caption = "Radius"
default = 1
min = 0.0
visible = @shape_type == 0
endparam
float param xsemi
caption = "X semi-axis"
default = 1
min = 0.0
visible = @shape_type == 1
endparam
float param ysemi
caption = "Y semi-axis"
default = 1
min = 0.0
visible = @shape_type == 1
endparam
float param angle
caption = "Rotation angle"
default = 0.0
visible = (@shape_type > 0) ;|| (@p != 2.0)
endparam
param type
caption = "Type"
enum = "1" "2"
default = 0
endparam
float param scale
caption = "Scale"
default = 1
endparam
}
class JLB_ModularSFormula(SFormula) {
; The Modular formula as an SFormula.
; 220605
public:
import "common.ulb"
func JLB_ModularSFormula(Generic pparent)
SFormula(pparent)
if @v == 2
m_Transform = new @zT(this)
endif
if @addT > 0
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
endfunc
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
if @v == 1
pz = @F(@a*pz)
elseif @v == 2
pz = m_Transform.Iterate(@a*pz)
endif
complex pzn = pz
int n = 1
complex tmp = pz * (1 - pzn)^@p
while n < @nbig
pzn = pz * pzn
tmp = tmp * (1 - pzn)^@p
n = n + 1
endwhile
znew = tmp + ppc
;if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
;endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UserTransform m_Transform
UtilityTransform finalTransform
default:
title = "Modular"
rating = NotRecommended
int param v_ModularSFormula
caption = "Version (Modular_SFormula)"
default = 220604
visible = @v_ModularSFormula < 220604
endparam
; bool param p_std
; caption = "Standard?"
; default = true
; endparam
; heading
; caption = "Set v = F(z)"
; endheading
heading
caption = "z_new = v*((1-v)^p)*((1-v^2)^p)*...*((1-v^n)^p) + c"
endheading
param v
caption = "Use for v"
enum = "z" "F(a*z)" "T(a*z)"
default = 0
endparam
func F
caption = "F (Built-in function)"
default = sin()
;hint = "Function"
visible = @v == 1
endfunc
UserTransform param zT
caption = "T (Transform)"
default = JLB_MoebiusUserTransform
visible = @v == 2
endparam
complex param a
caption = "a"
default = 1
visible = @v > 0
endparam
float param p
caption = "p"
default = 2
min = 1
endparam
int param nbig
caption = "n"
min = 1
endparam
bool param p_Mtype
caption = "M-type?"
default = false
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.5,0.5)
visible = !@p_Mtype
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
class JLB_DXYZ(Distance){
; A distance class similar to ComplexToFloat2
; Unlike ComplexToFloat2, there's an option to scale some distances
; so that the full possible range is (0,1).
public:
func JLB_DXYZ(Generic pparent)
Distance(pparent)
endfunc
float func Iterate(complex zz)
float ans
float x = real(zz), float y = imag(zz)
float ax = abs(x), float ay = abs(y)
float a = cabs(zz), float b = sqrt(2.0)
if @type == "Mod"
ans = a
elseif @type == "Real"
ans = x ; range = (-a,+a)
if @s, ans = (ans+a)/(a+a), endif
elseif @type == "Imag"
ans = y ; range = (-a,+a)
if @s, ans = (ans+a)/(a+a), endif
elseif @type == "Real+Imag"
ans = x+y ; range = (-a,+a*b)
if @s, ans = (ans+a)/(a*b+a), endif
elseif @type == "Real-Imag"
ans = x-y ; range = (-a*b,+a*b)
if @s, ans = (ans+a*b)/(2*a*b), endif
elseif @type == "Real*Imag"
ans = x*y ; range = (-0.5,+0.5)a^2
if @s, ans = (ans+0.5*a^2)/(a^2), endif
elseif @type == "Real/Imag"
ans = x/y
elseif @type == "Imag/Real"
ans = y/x
elseif @type == "Real^Imag"
ans = x^y
elseif @type == "Imag^Real"
ans = y^x
elseif @type == "|Real|+|Imag|"
ans = ax+ay ;range = (a,a*b)
if @s, ans = (ans-a)/(a*b-a), endif
elseif @type == "|Real|-|Imag|"
ans = ax-ay ;range = (-a,a)
if @s, ans = (ans+a)/(a+a), endif
elseif @type == "Max(|Real|,|Imag|)"
ans = ax ; range = (a,a/b)
if ay > ax, ans = ay, endif
if !@s, ans = (ans-a)/(a-a/b), endif
elseif @type == "Max(Real,Imag)"
ans = x ; range = (0,a)
if y > x, ans = y, endif
if @s, ans = (ans)/(a), endif
elseif @type == "Min(|Real|,|Imag|)"
ans = ax ; range = (0,a/b)
if ay < ax, ans = ay, endif
if @s, ans = (ans)/(a/b), endif
elseif @type == "Min(Real,Imag)"
ans = x ; range = (-a,a/b)
if y < x, ans = y, endif
if @s, ans = (ans+a)/(a/b+a), endif
else;if @type == "Angle"
ans = atan2(zz)/ (2 * #pi)
if ans < 0
ans = ans + 1
endif
if @version >= 220809 && !@s
ans = a*ans
endif
endif
if @invert && ans != 0
ans = 1/ans
endif
if @tlog && ans != 0
ans = log(ans)
endif
; if @oneminus ; experiment 220916
; ans = 1 - ans
; endif
if m_abs_value
ans = abs(ans)
endif
return ans
endfunc
private:
default:
title = "XYZ distance"
rating = NotRecommended
heading
caption = "Use 'Simple Distance' instead."
endheading
int param version
caption = "Version"
default = 220809
visible = @version < 220809
endparam
heading
text = "(current is 220809.}"
visible = @version < 220809 ;backward compatible to 220703
endheading
param type
caption = "Use for distance"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
default = 0
endparam
bool param s
caption = "Z scale?"
default = false
visible = @type != 0 && (@type < 6 || @type > 9) && \
!(@version < 220809 && @type == 16)
hint = "Scale answer to be between 0 and 1."
endparam
bool param invert
caption = "Invert?"
default = false
visible = @version >= 220809
endparam
bool param tlog
caption = "Take log?"
default = false
visible = @version >= 220809
endparam
; bool param oneminus
; caption = "1 - distance?"
; default = false
; visible = @version >= 220809
; endparam
}
class JLB_TentSFormula(SFormula) {
; The Tent formula as an SFormula, generalized.
; Original Tent formula in lkm.ufm and reb.ufm
public:
import "common.ulb"
func JLB_TentSFormula(Generic pparent)
SFormula(pparent)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
m_dist = new @dist(this)
if @type == 2 && !@p_std
m_T = new @zT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
if @p_std
tscale = 0, p = 1
else
tscale = @trans, p = @power
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
if !@p_std
if @type == 1
pz = @f(pz)
elseif@type == 2
pz = m_T.Iterate(pz)
endif
endif
complex znew
float test = m_dist.Iterate(pz)
complex z1 = ppc * @scale * pz^p
complex z2 = ppc * @scale * (@top - pz)^p
if tscale == 0
if test <= @crit
znew = z1
else
znew = z2
endif
else
float r = (test-@crit)/tscale
float frac = TSmooth.go(r)
znew = frac*z1 + (1-frac)*z2
endif
if !@p_std
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
UtilityTransform finalTransform
Distance m_dist
UserTransform m_T
float tscale
float p
default:
rating = NotRecommended
title = "Tent"
int param v_TentSFormula
caption = "Version"
default = 220727
visible = @v_TentSFormula < 220727
; changes 220729 backward compatible to 220727
endparam
heading
text = "(Current is 220727.)"
visible = @v_TentSFormula < 220727
endheading
bool param p_std
caption = "Standard?"
default = true
endparam
bool param p_Mtype
caption = "M-type?"
default = true
visible = @v_TentSFormula > 100
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.5, -0.5)
visible = @v_TentSFormula > 100 && !@p_Mtype
endparam
float param crit
caption = "Critical distance"
default = 1
endparam
heading
text = "Use for critical distance:"
endheading
Distance param dist
default = JLB_DXYZ
selectable = false
endparam
heading
caption = ""
endheading
param type
caption = "Tent function type"
enum = "z" "F(z)" "T(z)"
default = 0
visible = !@p_std
endparam
func f
caption = "F (built-in function)"
default = sin()
hint = "Function"
visible = @type == 1 && !@p_std
endfunc
UserTransform param zT
caption = "T (Transform)"
default = JLB_MoebiusUserTransform
visible = @type == 2 && !@p_std
endparam
complex param scale
caption = "Tent scale"
default = 1
endparam
float param top
Caption = "Tent value"
default = 1
endparam
float param power
Caption = "Tent power"
default = 1
visible = !@p_std
endparam
float param trans
caption = "Transition parameter"
hint = "Larger values make a smoother transition. For an abrupt transition, use 0."
default = 0.1
min = 0
visible = !@p_std
endparam
heading
caption = "Tweak after each iteration"
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
heading
caption = ""
endheading
}
class JLB_ComboTransform (common.ulb:UserTransform) {
public:
func JLB_ComboTransform(Generic pparent)
UserTransform(pparent)
m_T1 = new @T1(this)
if @v >= 3
m_T2 = new @T2(this)
endif
endfunc
complex func Iterate(complex pz)
complex z1
if @v == "T(a*z)"
return m_T1.Iterate(@a*pz)
elseif @v == "T(a*z) op pixel"
z1 = Combine.go(@a*pz, @op, #pixel)
return m_T1.Iterate(z1)
elseif @v == "T(a*z op pixel)"
z1 = Combine.go(@a*pz, @op, #pixel)
return m_T1.Iterate(z1)
else ; "T1(a*z) op T2(b*z)"
complex z2 = m_T2.Iterate(@b*pz)
if @op1 == "( )"
return m_T1.Iterate(@a*z2)
else
z1 = m_T1.Iterate(@a*pz)
return Combine.go(z1, @op1, z2)
endif
endif
endfunc
private:
UserTransform m_T1
UserTransform m_T2
default:
rating = NotRecommended
title = "Combo Transform"
int param version
caption = "Version"
default = 220731
visible = @version < 220731
endparam
heading
text = "(Current is 220731.)"
visible = @version < 220731
endheading
param v
caption = "Type"
enum = "T(a*z)" "T(a*z) op pixel" "T(a*z op pixel)" \
"T1(a*z) op T2(b*z)"
;"T1(a*z) op1 (T2(b*z) op2 pixel))" \
;"T1(a*z) op1 (T2(b*z op2 pixel))"
default = 0
endparam
complex param a
caption = "a"
default = (1,0)
endparam
complex param b
caption = "b"
default = (0, 1)
visible = @v >= 3
endparam
param op
caption = "op"
enum = "+" "-" "*" "/" "^"
default = 0
hint = "How to combine."
visible = @v==1 || @v ==2
endparam
param op1
caption = "op1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine."
visible = @v>=3
endparam
; param op2
; caption = "op2"
; enum = "+" "-" "*" "/" "^"
; default = 0
; hint = "How to combine."
; visible = @v>=4
; endparam
UserTransform param T1
default = JLB_FTransform
endparam
UserTransform param T2
default = JLB_FTransform
visible = @v >= 3
endparam
}
class JLB_DCurve(Distance) {
; Curve definitions from
; https://mathcurve.com/courbes2d.gb/courbes2d.shtml
; www.2dcurves/com
; mathworld.wolfram.com/
; with inspiration and some code from Otto Magus, om.ulb
;
; sources vary on what some of the curves are.
; I've changed a^2 many places to just a and b^2 to b,
; added parameters in a sensible way to many curves,
; and omitted any curves with three or more parameters
public:
func JLB_DCurve(Generic pparent)
Distance(pparent)
a = @aa ; to save typing
b = @bb
endfunc
float func Iterate(complex zz)
float x=real(zz)
float y=imag(zz)
if @exch
float t=x, x=y, y=t
endif
float c1 = cabs(zz), float c2 = c1*c1, float c3 = c2*c1, float c4 = c2*c2
float x2 = x^2, float y2 = y^2, float d2 = x2-y2
float d = 0
if @V=="Alain"
d = d2^2 - a*x2 + b*y2
if @s, d = d/c4, endif
elseif @V=="Ampersand"
d = (y2-x2)*(x-a)*(2*x-3*a) - b*(c2-2*x)^2
if @s, d = d/c4, endif
elseif @V=="Anguinea"
d = y*(x2+a^2) - a*b*x
if @s, d = d/c3, endif
elseif @V=="Arachnea"
d = (c2-a*x)^2 - a^2*c2
if @s, d = d/c4, endif
elseif @V=="Arcs of Samothrace"
d = x2*(a*x2-y2)^2 - y2*c2
if @s, d = d/c4/c2, endif
elseif @V=="Astroid"
d = x^@p + y^@p - a^@p
if @s, d = d/c1^@p, endif
elseif @v=="Atripthaloid"
d = x^4*c2 - (a*x2-b)^2
if @s, d = d/c4/c2, endif
elseif @V=="Beetle'"
d = c2*(c2-a*x-a*y) - b*x2*y2
if @s, d = d/c4, endif
elseif @V=="Besace"
d = (x2-b*y)^2 - a*d2
if @s, d = d/c4, endif
elseif @V=="Bicorn"
d = y2*(a-x2) - (x2+2*a*y-a^2)^2
if @s, d = d/c4, endif
elseif @V=="Bicuspid"
d = (x2-a^2)*(x-a)^2 + (y2-a)^2
if @s, d = d/c4, endif
elseif @V=="Bifoliate"
d = x2*x2 + y2*y2 - a*x*y2
if @s, d = d/c4, endif
elseif @V=="Bifolium"
d = c2^2 - (a*x+b*y)*x2
if @s, d = d/c4, endif
elseif @V=="Bow"
d = x2*x2 - a*y*d2
if @s, d = d/c4, endif
elseif @V=="Bow Tie"
d = x2*x2*c2 - a*d2
if @s, d = d/c2/c4, endif
elseif @V=="Bullet-Nose"
d = a^2*y2 - b^2*x*2 - x2*y2
if @s, d = d/c4, endif
elseif @V=="Butterfly"
d = x2^3 + y2^3 - a*x2
if @s, d = d/c2/c4, endif
elseif @V=="Cardioid"
d = (c2-a*x)^2 - a^2*c2
if @s, d = d/c4, endif
elseif @V=="Cassinian Ovals"
d = c2^2 - a*d2 + b^4
if @s, d = d/c4, endif
elseif @V=="Cayley's Sextic"
d = 4*(c2-a*x)^3 - 27*a^2*c2^2
if @s, d = d/c4/c2, endif
elseif @V=="Cissoid of Diocles"
d = x*c2 - a*y2
if @s, d = d/c3, endif
elseif @V=="Conchoid of Nicomedes"
d = (x-a)^2*c2 - b^2*x2
if @s, d = d/c4, endif
elseif @V=="Cornoid"
d = c2^3 + a*(3*x^4 - 6*x2*y2 - 5*y^4) + 8*a^2*y2 - 4*a^3
if @s, d = d/c2/c4, endif
elseif @V=="Cross"
d = x2*y2 - a*x2 - b*y2
if @s, d = d/c4, endif
elseif @V=="Curve of Cramer"
d = x*c2 + (a+b)*x2 - (a-b)*y2
elseif @V=="Cubical Parabola"
d = a^2*y - x^3 + b*x
if @s, d = d/c3, endif
elseif @V=="Cubic of de Sluze"
d = a*(x-a)*c2 - b*x2
if @s, d = d/c3, endif
elseif @V=="Deltoid"
d = c2^2 + 8*a*x*(x2-3*y2) + 18*a^2*c2 - 27*a^4
if @s, d = d/c4, endif
elseif @V=="Dipole"
d = c2^3 - a*x2
if @s, d = d/c2/c3, endif
elseif @V=="Double-Heart"
d = x2*c2 - (a+b)*x2*y + (a-b)^2*y/4
if @s, d = d/c4, endif
elseif @v=="Dumbbell"
d = b*y2 - x^4*(a-x2)
if @s, d = d/c2/c4, endif
elseif @V=="Egg of Granville"
d = x2*y2 - (x-a)*(b-x)
if @s, d = d/c4, endif
elseif @V=="Egg of Kepler"
d = c2^2 - a*x^3
if @s, d = d/c4, endif
elseif @v=="Eight"
d = x^4 - a*d2
if @s, d = d/c4, endif
elseif @V=="Ellipse"
d = b*x2 + a*y2 - a/b
if @s, d = d/c2, endif
elseif @V=="Euler's Cubic"
d = y*(y2-a) - b*x*(x2-a)
if @s, d = d/c3, endif
elseif @V=="Folium of Descartes"
d = x^3 + y^3 - 3*a*x*y
if @s, d = d/c3, endif
elseif @V=="Folium of Durer"
d = c2*(2*c2-a)^2 - a^2*x2
if @s, d = d/c2/c4, endif
elseif @V=="Folium of Kepler"
d = c2*(x*(x-a)+y2) - b*x*y2
if @s, d = d/c4, endif
elseif @V=="Function"
d = y - a*real(@F(b*x))
if @s, d = d/c1, endif
elseif @v=="Heat Capacity"
d = x2*(x-y) + a
if @s, d = d/c3, endif
elseif @V=="Hippopede"
d = c2^2 - a*x2 - b*y2
if @s, d = d/c4, endif
elseif @V=="Humbert's Cubic"
d = x^3 - 3*x*y2 - a
if @s, d = d/c3, endif
elseif @V=="Hyperbola"
d = x2 - a*y2
if @s, d = d/c2, endif
elseif @V=="Kampyle of Eudoxus"
d = x^4 - a*c2
if @s, d = d/c4, endif
elseif @V=="Kappa"
d = x2*c2 - a*y2
if @s, d = d/c4, endif
elseif @V=="Kiepert"
d = c2^3 - a*x*(x2-3*y2)
if @s, d = d/c2/c4, endif
elseif @V=="Kiss"
d = a^2*y2 - (a-x2)^3
if @s, d = d/c2/c4, endif
elseif @V=="Knot"
d = (x2-a)^2 - y2*(3*a+2*y)
if @s, d = d/c4, endif
elseif @v=="Kulp Quartic"
d = x2*y2 - a*(a-y2)
if @s, d = d/c4, endif
elseif @V=="Lemniscate of Bernoulli"
d = c2^2 - a*d2
if @s, d = d/c4, endif
elseif @V=="Limacon of Pascal"
d = (c2-a*x)^2 - b*c2
if @s, d = d/c4, endif
elseif @V=="Maltese Cross"
d = x*y*d2 - a*c2
if @s, d = d/c2/c4, endif
elseif @V=="Nephroid"
d = (c2-a)^3 - b*y2
if @s, d = d/c2/c4, endif
elseif @V=="Nephroid of Freeth"
d = c2*(x*2+y2-a)^2 - 4*a*(c2-a*x)^2
if @s, d = d/c2/c4, endif
elseif @V=="Ophiuride"
d = x*c2 - b*x*y - a*y2
if @s, d = d/c3, endif
elseif @V=="Parabola"
d = y - a*x2
if @s, d = d/c2, endif
elseif @V=="Pear"
d = x*x2*(a-x) - b*y2
if @s, d = d/c4, endif
elseif @V=="Piriform Quartic"
d = b^2*y2 + (x-a)*x^3
if @s, d = d/c4, endif
elseif @V=="Quadrifolium"
d = c2^3 - a*x2*y2
if @s, d = d/c2/c4, endif
elseif @v=="Right Strophoid"
d = x*c2 - a*d2
if @s, d = d/c3, endif
elseif @V=="Semicubical Parabola"
d = y2 - a*x*x2
if @s, d = d/c3, endif
elseif @V=="Serpentine"
d = y*(x+b*y)^2 - a*x
if @s, d = d/c3, endif
elseif @V=="Sextic"
d = c2*(c2-a*y)^2 - x2*d2^2
if @s, d = d/c2/c4, endif
elseif @V=="Tighrope"
d = y2*(a^2*b-x2) - x2*(a-x)^2
if @s, d = d/c4, endif
elseif @V=="Torpedo"
d = c2^2 - a*x*d2
if @s, d = d/c4, endif
elseif @V=="Trifolium"
d = c2^2 - a*x*(x2-b*y2)
if @s, d = d/c4, endif
elseif @V=="Trisectrix of Catalan"
d = b*y2 + x2*(x-a)
if @s, d = d/c3, endif
elseif @V=="Trisectrix of Ceva"
d = c2^3 - a*(b*x2-y2)^2
if @s, d = d/c2/c4, endif
elseif @V=="Trisectrix of Delange"
d = (c2-a)^2 - x2*c2
if @s, d = d/c4, endif
elseif @V=="Trisectrix of Longchamps"
d = x*(x2-3*y2) - a*c2
if @s, d = d/c3, endif
elseif @V=="Trisectrix of Maclaurin"
d = x*c2 - a*(3*x2-y2)
if @s, d = d/c3, endif
elseif @V=="Trott"
d = 144*(x^4+y^4) - 225*c2 + 350*x2*y2 + 81*a
if @s, d = d/c4, endif
elseif @V=="Visiera"
d = x*c2 - a*(x2+2*y2)
if @s, d = d/c3, endif
elseif @V=="Viviani's"
d = y^4 + a*d2 ;mathworld version
if @s, d = d/c4, endif
elseif @V=="Wavy Cross" ; Swastika
d = x2*x2-y2*y2 + a*x*y
if @s, d = d/c4, endif
elseif @V=="Windmill"
d = 4*x2*y2*c2 - a*(x2-b*y2)^2
if @s, d = d/c2/c4, endif
elseif @V=="Witch of Agnesi"
d = x2*y + a^2*(y-a)
if @s, d = d/c3, endif
endif
if m_abs_value
d = abs(d)
endif
return d
endfunc
private:
float a, float b
default:
rating = NotRecommended
title = "Curve"
int param version
caption = "Version"
default = 220804
visible = @version < 220804
endparam
heading
text = "(Current is 220804.)"
visible = @version < 220804
endheading
param V
caption="Curve"
enum="Alain" "Ampersand" "Anguinea" "Arachnea" "Arcs of Samothrace" \
"Astroid" "Atripthaloid" "Beetle'" "Besace" "Bicorn" "Bicuspid" \
"Bifoliate" "Bifolium" "Bow" "Bow Tie" "Bullet-Nose" "Butterfly"\
"Cardioid" "Cassinian Ovals" "Cayley's Sextic" "Cissoid of Diocles" \
"Conchoid of Nicomedes" "Cornoid" "Cross" "Cubical Parabola"\
"Curve of Cramer" "Cubic of de Sluze" "Deltoid" "Dipole" \
"Double-Heart" "Dumbbell""Egg of Granville" "Egg of Kepler" "Eight"\
"Ellipse" "Euler's Cubic" "Folium of Descartes" \
"Folium of Durer" "Folium of Kepler""Function" "Heat Capacity"\
"Hippopede" "Humbert's Cubic" "Hyperbola" "Kampyle of Eudoxus""Kappa" "Kiepert" \
"Kiss" "Knot" "Kulp Quartic" "Lemniscate of Bernoulli"\
"Limacon of Pascal" "Maltese Cross""Nephroid" "Nephroid of Freeth"\
"Ophiuride" "Parabola" "Pear""Piriform Quartic" "Quadrifolium" \
"Right Strophoid""Semicubical Parabola" "Serpentine" "Sextic" \
"Tighrope" "Torpedo" "Trifolium" "Trisectrix of Catalan" \
"Trisectrix of Ceva" "Trisectrix of Delange" "Trisectrix of Longchamps" \
"Trisectrix of Maclaurin""Trott" "Visiera" "Viviani's" "Wavy Cross" \
"Windmill" "Witch of Agnesi"
default=0
endparam
func F
caption = "Function"
default = sin()
visible = @V=="Function"
endfunc
bool param exch
caption = "Switch x and y?"
default = false
visible = @V!="Astroid" && @V!="Folium of Descartes" \
&& @V!="Quadrifolium" && @V!="Trott"
endparam
bool param s
caption = "Z scale?"
default = true ; 221220, was false
endparam
float param aa
caption = "a"
default=1
endparam
float param p
caption = "Power"
default = 0.5
visible = @V=="Astroid"
endparam
float param bb
caption = "b"
default=0.5
visible=@V=="Alain" || @V=="Ampersand" || @V=="Atripthaloid" \
|| @V=="Beetle'" || @V=="Besace" || @V=="Bifolium" || @V=="Bullet-Nose" \
|| @V=="Cassinian Ovals" || @V=="Cross" ||@V=="Cubical Parabola" \
|| @V=="Cubic of de Sluze" || @V=="Conchoid of Nicomedes" \
|| @V=="Curve of Cramer" || @V=="Double-Heart" || @V=="Dumbbell" \
|| @V=="Ellipse" || @V=="Egg of Granville" || @V=="Euler's Cubic" \
|| @V=="Folium of Kepler" ||@V=="Function" || @V=="Hippopede" \
|| @V=="Limacon of Pascal" || @V=="Nephroid" || @V=="Ophiuride" \
|| @V=="Pear" || @V== "Piriform Quartic" || @V=="Serpentine" \
|| @V=="Tighrope" || @V=="Trifolium" || @V=="Trisectrix of Catalan" \
|| @V=="Trisectrix of Ceva" || @V=="Windmill"
endparam
}
class Standard_Decomposition(common.ulb:GradientColoring) {
; copied from Standard.ulb
public:
float func ResultIndex(complex pz)
float d = atan2(pz) ; get angle of z
IF (d < 0) ; it's negative
d = d + #pi * 2 ; make it positive
ENDIF
return d / (#pi * 2)
endfunc
default:
title = "Decomposition"
rating = NotRecommended
}
class JLB_FractaliaSFormula(SFormula) {
; based on the Fractalia formulas in mt.ufm
public:
import "common.ulb" ; for UtilityTransform
func JLB_FractaliaSFormula(Generic pparent)
SFormula.SFormula(pparent)
r1 = new JLB_Random(0)
r1.Init(@seed)
r2 = new JLB_Random(0)
r2.Init(@seed2)
a=@aa, ax=@aax, axx=@aaxx, axy=@aaxy, ay=@aay, ayy=@aayy
b=@bb, bx=@bbx, bxx=@bbxx, bxy=@bbxy, by=@bby, byy=@bbyy
if @randomize > 0
float c = 1, if @randomize == "Replace", c = 0, endif
a = c * a + @scale * r1.RandomFloat2(0), b = c * b + @scale * r1.RandomFloat2(0)
ax = c * ax + @scale * r1.RandomFloat2(0), bx = c * bx + @scale * r1.RandomFloat2(0)
axx = c * axx + @scale * r1.RandomFloat2(0), bxx = c * bxx + @scale * r1.RandomFloat2(0)
axy = c * axy + @scale * r1.RandomFloat2(0), bxy = c * bxy + @scale * r1.RandomFloat2(0)
ay = c * ay + @scale * r1.RandomFloat2(0), by = c * by + @scale * r1.RandomFloat2(0)
ayy = c * ayy + @scale * r1.RandomFloat2(0), byy = c * byy + @scale * r1.RandomFloat2(0)
if @randomize2 > 0
c = 1, if @randomize2 == "Replace", c = 0, endif
a = c * a + @scale2 * r2.RandomFloat2(0), b = c * b + @scale2 * r2.RandomFloat2(0)
ax = c * ax + @scale2 * r2.RandomFloat2(0), bx = c * bx + @scale2 * r2.RandomFloat2(0)
axx = c * axx + @scale2 * r2.RandomFloat2(0), bxx = c * bxx + @scale2 * r2.RandomFloat2(0)
axy = c * axy + @scale2 * r2.RandomFloat2(0), bxy = c * bxy + @scale2 * r2.RandomFloat2(0)
ay = c * ay + @scale2 * r2.RandomFloat2(0), by = c * by + @scale2 * r2.RandomFloat2(0)
ayy = c * ayy + @scale2 * r2.RandomFloat2(0), byy = c * byy + @scale2 * r2.RandomFloat2(0)
endif
endif
if @addT > 0
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @return the new pz bool func Iterate(State S)
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
float x = real(S.pz)
float y = imag(S.pz)
float xx = a + ax*x + axx*x*x + axy*x*y + ay*y + ayy*y*y
float yy = b + bx*x + bxx*x*x + bxy*x*y + by*y + byy*y*y
complex znew = xx + flip(yy) + ppc
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
float a, float ax, float axx, float axy, float ay, float ayy
float b, float bx, float bxx, float bxy, float by, float byy
JLB_Random r1
JLB_Random r2
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Fractalia"
int param version
caption = "Version"
default = 221010
visible = @version < 221010
endparam
bool param p_Mtype
caption = "M-type?"
default = true
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = !@p_Mtype
endparam
bool param hide
caption = "Hide parameters?"
default = true
endparam
heading
caption = "Method"
visible = !@hide
endheading
heading
text = "xnew = a + ax*x + axx*x^2 + axy*x*y + ay*y + ayy*y^2"
visible = !@hide
endheading
heading
text = "ynew = b + bx*x + bxx*x^2 + bxy*x*y + by*y + byy*y^2"
visible = !@hide
endheading
heading
text = "znew = xnew + flip(ynew)"
visible = !@hide
endheading
; heading
; caption = "Parameters"
; endheading
float param aa
caption = "a"
default = 0
visible = !@hide
endparam
float param aax
caption = "ax"
default = 1
visible = !@hide
endparam
float param aaxx
caption = "axx"
default = 0.5
visible = !@hide
endparam
float param aaxy
caption = "axy"
default = 0.4
visible = !@hide
endparam
float param aay
caption = "ay"
default = -0.7
visible = !@hide
endparam
float param aayy
caption = "ayy"
default = 0.9
visible = !@hide
endparam
float param bb
caption = "b"
default = 0
visible = !@hide
endparam
float param bbx
caption = "bx"
default = -0.2
visible = !@hide
endparam
float param bbxx
caption = "bxx"
default = 0.8
visible = !@hide
endparam
float param bbxy
caption = "bxy"
default = 0.9
visible = !@hide
endparam
float param bby
caption = "by"
default = -0.7
visible = !@hide
endparam
float param bbyy
caption = "byy"
default = -0.2
visible = !@hide
endparam
heading
caption = "Randomization"
endheading
param randomize
caption = "Randomize?"
enum = "No" "Replace" "Add to"
default = 0
endparam
int param seed
caption ="Seed"
hint = "Seed for random numbers"
default = 12345679
visible = @randomize > 0
endparam
float param scale
caption = "Randomness size"
default = 1
min = 0
visible = @randomize > 0
endparam
param randomize2
caption = "More?"
enum = "No" "Replace" "Add to"
default = 0
visible = @randomize > 0
endparam
int param seed2
caption ="Second seed"
hint = "Seed for random numbers"
default = 12345679
visible = @randomize2 > 0
endparam
float param scale2
caption = "Randomness size"
default = 0.1
min = 0
visible = @randomize2 > 0
endparam
heading
caption = "Tweak after each iteration"
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0
selectable = false
endparam
}
class JLB_DCurve2(Distance) {
; Curve definitions from
; https://mathcurve.com/courbes2d.gb/courbes2d.shtml
; www.2dcurves/com
; mathworld.wolfram.com/
; with inspiration and some code from Otto Magus, om.ulb
;
; sources vary on what some of the curves are.
; I've changed a^2 many places to just a and b^2 to b,
; added parameters in a sensible way to many curves,
; and omitted any curves with three or more parameters
; 230204 added Heart curve. Backwards compatible.
public:
func JLB_DCurve2(Generic pparent)
Distance(pparent)
if @numpar == "1"
a = @aa
else
a = real(@ab)
b = imag(@ab)
endif
endfunc
float func Iterate(complex zz)
float x=real(zz)
float y=imag(zz)
if @exch
float t=x, x=y, y=t
endif
float c1 = cabs(zz), float c2 = |zz|, float c3 = c2*c1, float c4 = c2*c2
float x2 = x^2, float y2 = y^2, float d2 = x2-y2
float d = 0
if @numpar == "1" ;45
if @V1=="Arachnea"
d = (c2-a*x)^2 - a^2*c2
if @s, d = d/c4, endif
elseif @V1=="Arcs of Samothrace"
d = x2*(a*x2-y2)^2 - y2*c2
if @s, d = d/c4/c2, endif
elseif @V1=="Astroid"
d = x^@p + y^@p - a^@p
if @s, d = d/c1^@p, endif
elseif @V1=="Bicorn"
d = y2*(a-x2) - (x2+2*a*y-a^2)^2
if @s, d = d/c4, endif
elseif @V1=="Bicuspid"
d = (x2-a^2)*(x-a)^2 + (y2-a)^2
if @s, d = d/c4, endif
elseif @V1=="Bifoliate"
d = x2*x2 + y2*y2 - a*x*y2
if @s, d = d/c4, endif
elseif @V1=="Bow"
d = x2*x2 - a*y*d2
if @s, d = d/c4, endif
elseif @V1=="Bow Tie"
d = x2*x2*c2 - a*d2
if @s, d = d/c2/c4, endif
elseif @V1=="Butterfly"
d = x2^3 + y2^3 - a*x2
if @s, d = d/c2/c4, endif
elseif @V1=="Cardioid"
d = (c2-a*x)^2 - a^2*c2
if @s, d = d/c4, endif
elseif @V1=="Cayley's Sextic"
d = 4*(c2-a*x)^3 - 27*a^2*c2^2
if @s, d = d/c4/c2, endif
elseif @V1=="Cissoid of Diocles"
d = x*c2 - a*y2
if @s, d = d/c3, endif
elseif @V1=="Cornoid"
d = c2^3 + a*(3*x^4 - 6*x2*y2 - 5*y^4) + 8*a^2*y2 - 4*a^3
if @s, d = d/c2/c4, endif
elseif @V1=="Deltoid"
d = c2^2 + 8*a*x*(x2-3*y2) + 18*a^2*c2 - 27*a^4
if @s, d = d/c4, endif
elseif @V1=="Dipole"
d = c2^3 - a*x2
if @s, d = d/c2/c3, endif
elseif @V1=="Egg of Kepler"
d = c2^2 - a*x^3
if @s, d = d/c4, endif
elseif @V1=="Eight"
d = x^4 - a*d2
if @s, d = d/c4, endif
elseif @V1=="Folium of Descartes"
d = x^3 + y^3 - 3*a*x*y
if @s, d = d/c3, endif
elseif @V1=="Folium of Durer"
d = c2*(2*c2-a)^2 - a^2*x2
if @s, d = d/c2/c4, endif
elseif @V1=="Heart"
d = (x2+y2-a)^3 - x2*y2*y
if @s, d = d/c3/c3, endif
elseif @V1=="Heat Capacity"
d = x2*(x-y) + a
if @s, d = d/c3, endif
elseif @V1=="Humbert's Cubic"
d = x^3 - 3*x*y2 - a
if @s, d = d/c3, endif
elseif @V1=="Hyperbola"
d = x2 - a*y2
if @s, d = d/c2, endif
elseif @V1=="Kampyle of Eudoxus"
d = x^4 - a*c2
if @s, d = d/c4, endif
elseif @V1=="Kappa"
d = x2*c2 - a*y2
if @s, d = d/c4, endif
elseif @V1=="Kiepert"
d = c2^3 - a*x*(x2-3*y2)
if @s, d = d/c2/c4, endif
elseif @V1=="Kiss"
d = a^2*y2 - (a-x2)^3
if @s, d = d/c2/c4, endif
elseif @V1=="Knot"
d = (x2-a)^2 - y2*(3*a+2*y)
if @s, d = d/c4, endif
elseif @V1=="Kulp Quartic"
d = x2*y2 - a*(a-y2)
if @s, d = d/c4, endif
elseif @V1=="Lemniscate of Bernoulli"
d = c2^2 - a*d2
if @s, d = d/c4, endif
elseif @V1=="Maltese Cross"
d = x*y*d2 - a*c2
if @s, d = d/c2/c4, endif
elseif @V1=="Nephroid of Freeth"
d = c2*(x*2+y2-a)^2 - 4*a*(c2-a*x)^2
if @s, d = d/c2/c4, endif
elseif @V1=="Parabola"
d = y - a*x2
if @s, d = d/c2, endif
elseif @V1=="Quadrifolium"
d = c2^3 - a*x2*y2
if @s, d = d/c2/c4, endif
elseif @V1=="Right Strophoid"
d = x*c2 - a*d2
if @s, d = d/c3, endif
elseif @V1=="Semicubical Parabola"
d = y2 - a*x*x2
if @s, d = d/c3, endif
elseif @V1=="Sextic"
d = c2*(c2-a*y)^2 - x2*d2^2
if @s, d = d/c2/c4, endif
elseif @V1=="Torpedo"
d = c2^2 - a*x*d2
if @s, d = d/c4, endif
elseif @V1=="Trisectrix of Delange"
d = (c2-a)^2 - x2*c2
if @s, d = d/c4, endif
elseif @V1=="Trisectrix of Longchamps"
d = x*(x2-3*y2) - a*c2
if @s, d = d/c3, endif
elseif @V1=="Trisectrix of Maclaurin"
d = x*c2 - a*(3*x2-y2)
if @s, d = d/c3, endif
elseif @V1=="Trott"
d = 144*(x^4+y^4) - 225*c2 + 350*x2*y2 + 81*a
if @s, d = d/c4, endif
elseif @V1=="Visiera"
d = x*c2 - a*(x2+2*y2)
if @s, d = d/c3, endif
elseif @V1=="Viviani's"
d = y^4 + a*d2 ;mathworld version
if @s, d = d/c4, endif
elseif @V1=="Wavy Cross" ; Swastika
d = x2*x2-y2*y2 + a*x*y
if @s, d = d/c4, endif
elseif @V1=="Witch of Agnesi"
d = x2*y + a^2*(y-a)
if @s, d = d/c3, endif
endif
else;if @numpar == "2" ; 32 !!
if @V2=="Alain"
d = d2^2 - a*x2 + b*y2
if @s, d = d/c4, endif
elseif @V2=="Ampersand"
d = (y2-x2)*(x-a)*(2*x-3*a) - b*(c2-2*x)^2
if @s, d = d/c4, endif
elseif @V2=="Anguinea"
d = y*(x2+a^2) - a*b*x
if @s, d = d/c3, endif
elseif @V2=="Atripthaloid"
d = x^4*c2 - (a*x2-b)^2
if @s, d = d/c4/c2, endif
elseif @V2=="Beetle"
d = c2*(c2-a*x-a*y) - b*x2*y2
if @s, d = d/c4, endif
elseif @V2=="Besace"
d = (x2-b*y)^2 - a*d2
if @s, d = d/c4, endif
elseif @V2=="Bifolium"
d = c2^2 - (a*x+b*y)*x2
if @s, d = d/c4, endif
elseif @V2=="Bullet-Nose"
d = a^2*y2 - b^2*x*2 - x2*y2
if @s, d = d/c4, endif
elseif @V2=="Cassinian Ovals"
d = c2^2 - a*d2 + b^4
if @s, d = d/c4, endif
elseif @V2=="Conchoid of Nicomedes"
d = (x-a)^2*c2 - b^2*x2
if @s, d = d/c4, endif
elseif @V2=="Cross"
d = x2*y2 - a*x2 - b*y2
if @s, d = d/c4, endif
elseif @V2=="Cubical Parabola"
d = a^2*y - x^3 + b*x
if @s, d = d/c3, endif
elseif @V2=="Cubic of de Sluze"
d = a*(x-a)*c2 - b*x2
if @s, d = d/c3, endif
elseif @V2=="Curve of Cramer"
d = x*c2 + (a+b)*x2 - (a-b)*y2
if @s, d = d/c3, endif
elseif @V2=="Double-Heart"
d = x2*c2 - (a+b)*x2*y + (a-b)^2*y/4
if @s, d = d/c4, endif
elseif @V2=="Dumbbell"
d = b*y2 - x^4*(a-x2)
if @s, d = d/c2/c4, endif
elseif @V2=="Egg of Granville"
d = x2*y2 - (x-a)*(b-x)
if @s, d = d/c4, endif
elseif @V2=="Ellipse"
d = b*x2 + a*y2 - a/b
if @s, d = d/c2, endif
elseif @V2=="Euler's Cubic"
d = y*(y2-a) - b*x*(x2-a)
if @s, d = d/c3, endif
elseif @V2=="Folium of Kepler"
d = c2*(x*(x-a)+y2) - b*x*y2
if @s, d = d/c4, endif
elseif @V2=="Function"
d = y - a*real(@F(b*x))
if @s, d = d/c1, endif
elseif @V2=="Hippopede"
d = c2^2 - a*x2 - b*y2
if @s, d = d/c4, endif
elseif @V2=="Limacon of Pascal"
d = (c2-a*x)^2 - b*c2
if @s, d = d/c4, endif
elseif @V2=="Nephroid"
d = (c2-a)^3 - b*y2
if @s, d = d/c2/c4, endif
elseif @V2=="Ophiuride"
d = x*c2 - b*x*y - a*y2
if @s, d = d/c3, endif
elseif @V2=="Pear"
d = x*x2*(a-x) - b*y2
if @s, d = d/c4, endif
elseif @V2=="Piriform Quartic"
d = b^2*y2 + (x-a)*x^3
if @s, d = d/c4, endif
elseif @V2=="Serpentine"
d = y*(x+b*y)^2 - a*x
if @s, d = d/c3, endif
elseif @V2=="Tighrope"
d = y2*(a^2*b-x2) - x2*(a-x)^2
if @s, d = d/c4, endif
elseif @V2=="Trifolium"
d = c2^2 - a*x*(x2-b*y2)
if @s, d = d/c4, endif
elseif @V2=="Trisectrix of Ceva"
d = c2^3 - a*(b*x2-y2)^2
if @s, d = d/c2/c4, endif
elseif @V2=="Windmill"
d = 4*x2*y2*c2 - a*(x2-b*y2)^2
if @s, d = d/c2/c4, endif
endif
endif
if (d >= 0 && @how == "Negative") || (d <= 0 && @how == "Positive")
return -1
endif
return abs(d)
; if m_abs_value
; d = abs(d)
; endif
; return d
endfunc
private:
float a, float b
default:
rating = NotRecommended
title = "Curve2"
heading
caption = "Use 'Curve Distance' instead"
endheading
int param version
caption = "Version"
default = 221220
visible = @version < 221220
endparam
heading
text = "(Current is 221220.)"
visible = @version < 221220
endheading
param numpar
caption = "Group"
enum = "1" "2"
default = 0
endparam
param V1 ;45
caption="Curve"
enum= "Arachnea" "Arcs of Samothrace" \
"Astroid" "Bicorn" "Bicuspid" \
"Bifoliate" "Bow" "Bow Tie" "Butterfly" \
"Cardioid" "Cayley's Sextic" "Cissoid of Diocles" \
"Cornoid" "Deltoid" "Dipole" "Egg of Kepler" "Eight" \
"Folium of Descartes" "Folium of Durer" "Heat Capacity" \
"Humbert's Cubic" "Hyperbola" "Kampyle of Eudoxus" "Kappa" "Kiepert" \
"Kiss" "Knot" "Kulp Quartic" "Lemniscate of Bernoulli" \
"Maltese Cross" "Nephroid of Freeth" "Parabola" "Quadrifolium" \
"Right Strophoid" "Semicubical Parabola" "Sextic" \
"Torpedo" "Trisectrix of Delange" "Trisectrix of Longchamps" \
"Trisectrix of Maclaurin" "Trott" "Visiera" "Viviani's" "Wavy Cross" \
"Witch of Agnesi" "Heart"
default=0
visible = @numpar == "1"
endparam
param V2 ;32
caption="Curve"
enum = "Alain" "Ampersand" "Anguinea" "Atripthaloid" \
"Beetle" "Besace" "Bifolium" "Bullet-Nose" \
"Cassinian Ovals" "Conchoid of Nicomedes" "Cross" "Cubical Parabola" \
"Cubic of de Sluze" "Curve of Cramer" "Double-Heart" "Dumbbell" \
"Ellipse" "Egg of Granville" "Euler's Cubic" \
"Folium of Kepler" "Function" "Hippopede" \
"Limacon of Pascal" "Nephroid" "Ophiuride" \
"Pear" "Piriform Quartic" "Serpentine" \
"Tighrope" "Trifolium" \
"Trisectrix of Ceva" "Windmill"
default=0
visible = @numpar == "2"
endparam
func F
caption = "Function"
default = sin()
visible = @numpar=="2" && @V2=="Function"
endfunc
bool param exch
caption = "Switch x and y?"
default = false
visible = @numpar == "2" || \
( @V1 !="Astroid" && @V1 !="Folium of Descartes" \
&& @V1 !="Quadrifolium" && @V1 !="Trott" )
endparam
bool param s
caption = "Z scale?"
default = true ; 221220, was false
endparam
float param aa
caption = "a"
default = 1
visible = @numpar == "1"
endparam
float param p
caption = "Power"
default = 0.5
visible = @numpar == "1" && @V1=="Astroid"
endparam
complex param ab
caption = "a and b"
hint = "a is the real part, b the imaginary part"
default = (1,0.5)
visible = @numpar == "2"
endparam
param how
caption = "How"
enum = "Positive" "Negative" "Both"
default = 2
endparam
}
class JLB_Combo2Transform (common.ulb:UserTransform) {
; 230822 Added variations. Doesn't break old fractals.
public:
func JLB_Combo2Transform(Generic pparent)
UserTransform(pparent)
m_T1 = new @T1(this)
m_T2 = new @T2(this)
if @mode > 0
m_T3 = new @T3(this)
endif
m_Combine = new Combine()
mult = 0
if @variation == "Variation 1"
mult = 1
elseif @variation == "Variation 2"
mult = -1
endif
endfunc
complex func Iterate(complex pz)
float px = real(pz)
float py = imag(pz)
complex dx
complex dy
complex tx1, complex tx2, complex tx3
complex ty1, complex ty2, complex ty3
if @mode == 0 ;"T1 op1 T2"
;tx2 = @a2*@T2(@b2*px)
;ty2 = @a2*@T2(@b2*py)
tx2 = iter(2, @b2*px)
ty2 = iter(2, @b2*py)
if @op1a == "( )" ; T1(T2(.))
; dx = @a1*@T1(@b1*tx2)
; dy = @a1*@T1(@b1*ty2)
dx = iter(1, @b1*tx2 + mult*px)
dy = iter(1, @b1*ty2 + mult*py)
else ; T1(.) op1 T2(.)
; tx1 = @a1*@T1(@b1*px)
; ty1 = @a1*@T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
dx = m_Combine.go(tx1, @op1a, tx2)
dy = m_Combine.go(ty1, @op1a, ty2)
endif
elseif @mode == 1 ;"T1 op1 (T2 op2 T3)"
if @op2a == "( )" ; T1 op T2(T3(.))
; tx3 = @a3*T3(@b3*px)
; ty3 = @a3*T3(@b3*py)
tx3 = iter(3, @b3*px)
ty3 = iter(3, @b3*py)
; tx2 = @a2*T2(@b2*tx3)
; ty2 = @a2*T2(@b2*ty3)
tx2 = iter(2, @b2*tx3 + mult*px)
ty2 = iter(2, @b2*ty3 + mult*py)
if @op1 == "( )" ; T1(T2(T3(.)))
; dx = @a1*T1(@b1*tx2)
; dy = @a1*T1(@b1*ty2)
dx = iter(1, @b1*tx2 + mult*px)
dy = iter(1, @b1*ty2 + mult*py)
else ; T1(.) op1 T2(T3(.))
; tx1 = @a1*T1(@b1*px)
; ty1 = @a1*T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
dx = m_Combine.go(tx1, @op1, tx2)
dy = m_Combine.go(ty1, @op1, ty2)
endif
else;
; tx3 = @a3*T3(@b3*px)
; ty3 = @a3*T3(@b3*py)
tx3 = iter(3, @b3*px)
ty3 = iter(3, @b3*py)
; tx2 = @a2*T2(@b2*px)
; ty2 = @a2*T2(@b2*py)
tx2 = iter(2, @b2*px)
ty2 = iter(2, @b2*py)
tx2 = m_Combine.go(tx2, @op2a, tx3)
ty2 = m_Combine.go(ty2, @op2a, ty3)
if @op1 == "( )" ; T1(T2(.) op2a T3(.))
; dx = @a1*T1(@b1*tx2)
; dy = @a1*T1(@b1*ty2)
dx = iter(1, @b1*tx2 + mult*px)
dy = iter(1, @b1*ty2 + mult*px)
else
; tx1 = @a1*T1(@b1*px)
; ty1 = @a1*T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
dx = m_Combine.go(tx1, @op1, tx2)
dy = m_Combine.go(ty1, @op1, ty2)
endif
endif
else ;@mode == "(T1 op1 T2) op2 T3"
; @op3a == "( )" not allowed with this ordering
; tx2 = @a2*T2(@b2*px)
; ty2 = @a2*T2(@b2*py)
tx2 = iter(2, @b2*px)
ty2 = iter(2, @b2*py)
if @op1 == "( )" ; (T1(T2(.))) op2b T3(.)
; tx1 = @a1*T1(@b1*tx2)
; ty1 = @a1*T1(@b1*ty2)
tx1 = iter(1, @b1*tx2)
ty1 = iter(1, @b1*ty2)
else
; tx1 = @a1*T1(@b1*px)
; ty1 = @a1*T1(@b1*py)
tx1 = iter(1, @b1*px)
ty1 = iter(1, @b1*py)
tx1 = m_Combine.go(tx1, @op1, tx2)
ty1 = m_Combine.go(ty1, @op1, ty2)
endif
; tx3 = @a3*T3(@b3*px)
; ty3 = @a3*T3(@b3*py)
tx3 = iter(3, @b3*px)
ty3 = iter(3, @b3*py)
dx = m_Combine.go(tx1, @op2b, tx3)
dy = m_Combine.go(ty1, @op2b, ty3)
endif
return dx + flip(dy)
endfunc
complex func iter(int n, complex v)
if n == 1
return @a1*m_T1.Iterate(v)
elseif n == 2
return @a2*m_T2.Iterate(v)
else
return @a3*m_T3.Iterate(v)
endif
endfunc
private:
UserTransform m_T1
UserTransform m_T2
UserTransform m_T3
Combine m_Combine
float mult
default:
rating = NotRecommended
title = "Combo T"
int param version
caption = "Version"
default = 230117
visible = @version < 230117
endparam
heading
caption = "Use 'Transform Combo' instead."
endheading
heading
text = "(Current is 230117.)"
visible = @version < 230117
endheading
param mode
caption = "Combining"
default = 0
enum = "T1 op T2" "T1 op1 (T2 op2 T3)" "(T1 op1 T2) op2 T3"
endparam
param op1
caption = "Operator 1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
visible = @mode > 0
endparam
param op1a
caption = "Operator"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
visible = @mode == 0
endparam
param op2a
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
visible = (@mode == 1)
endparam
param op2b
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default = 2
visible = (@mode == 2)
endparam
param variation
enum = "Original" "Variation 1" "Variation 2"
default = 0
visible = ( @mode == 0 && @op1a == "( )" ) || \
( @mode == 1 && ( @op2a == "( )" || @op1 == "( )" ) ) || \
( @mode == 2 && @op1 == "( )" )
endparam
heading
caption = "a1*T1(b1*v)"
endheading
complex param a1
caption = "a1"
default = 1
hint = "multiplies T1"
endparam
complex param b1
caption = "b1"
default = 2
hint = "multiplies T1's arg"
endparam
UserTransform param T1
caption = "T1"
default = JLB_UT_Function
endparam
heading
caption = "a2*T2(b2*v)"
endheading
complex param a2
caption = "a2"
default = 2.7
hint = "multiplies T2"
endparam
complex param b2
caption = "b2"
default = 2.7
hint = "multiplies T2's arg"
endparam
UserTransform param T2
caption = "T2"
default = JLB_UT_Function
endparam
heading
caption = "a3*T3(b3*v)"
visible = @mode > 0
endheading
complex param a3
caption = "a3"
default = 0
hint = "multiplies T3"
visible = @mode > 0
endparam
complex param b3
caption = "b3"
default = 1
hint = "multiplies T3's arg"
visible = @mode > 0
endparam
UserTransform param T3
caption = "T3"
default = JLB_UT_Function
visible = @mode > 0
endparam
}
class JLB_Gnarl5SFormula(SFormula) {
; Based on the Gnarl formula from mt.ufm, as a SFormula.
; Calculate dx and dy based on the real or imaginary part of z, then combine.
; Add a multiple of z, #pixel, or a seed.
; Changed from Gnarl3: omit SFormula; each f now is a UserTransform
public:
import "common.ulb"
func JLB_Gnarl5SFormula(Generic pparent)
SFormula.SFormula(pparent)
m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180))
m_T = new @T(this)
if @addT > 0
m_f4 = new @f4(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if s.bailed
return true
endif
if s.tooMany
return false
endif
complex pz = S.pz
; complex pc = @p_seed
complex znew
float xc = real(ppc)
float yc = imag(ppc)
complex zrot = pz * m_rot
float x = real(zrot)
float y = imag(zrot)
complex px, complex py
if @args == "x,y"
px = x, py = y
else ; "y,x" the original version, usually better
px = y, py = x
endif
complex dz = m_T.Iterate(px+flip(py))
float dx = real(dz)
float dy = imag(dz)
float qx, float qy
if @args == "x,y"
qx = xc, qy = yc
else ; "y,x" the original version, usually better
qx = yc, qy = xc
endif
dx = dx + qx
dy = dy + qy
if @xyop == "-dx +dy" || @xyop == "-dx -dy"
dx = -dx
endif
if @xyop == "+dx -dy" || @xyop == "-dx -dy"
dy = -dy
endif
znew = pz + @step * (dx + flip(dy))
if @addT == "c"
ppc = m_f4.iterate(ppc)
elseif @addT == "z"
znew = m_f4.Iterate(znew)
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex m_rot
UserTransform m_T
complex ppc
UtilityTransform m_f4
default:
rating = NotRecommended
title = "Gnarl5"
int param version
caption = "Version (Gnarl5_SFormula)"
default = 230116
visible = @version < 230116
endparam
bool param p_Mtype
caption = "M-type?"
default = true
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.5,0.5)
visible = !@p_Mtype
endparam
float param theta
caption = "Theta"
default = 0
hint = "First rotate z by this much (360 = full circle)"
endparam
param args
caption = "args"
enum = "x,y" "y,x"
default = 1
endparam
UserTransform param T
caption = "Gnarl5 T"
default = JLB_Combo2Transform
selectable = false ; don't want this changed
endparam
heading
endheading
param xyop
caption = "Gnarl5 dx,dy"
enum = "+dx +dy" "+dx -dy" "-dx +dy" "-dx -dy"
default = 1
hint = "final multiplcations of real and imaginary parts of z_calc"
endparam
param step
caption = "Gnarl5 Step_size"
default = 0.1
hint = "How much of this to use. z_new = z + Step_size * z_calc"
endparam
heading
caption = "Tweak after each iteration"
;visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
;visible = !@p_std
endparam
UtilityTransform param f4
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 ;&& !@p_std
selectable = false
endparam
}
class JLB_ChaoticAttractors(common.ulb:GradientColoring) {
; A re-writing of Latööcarfian Attractors in mt.ucl
; with drastic changes.
; Standard. Alpha, Beta, and Gamma are from mt.ucl;
; the others I've found online.
; http://paulbourke.net/fractals
; https://anaconda.org/jbednar/clifford_attractor/notebook
; https://softologyblog.wordpress.com/2017/03/04/2d-strange-attractors/
public:
import "common.ulb"
$define debug ; only for printing values from Randomize( )
func JLB_ChaoticAttractors(Generic pparent)
GradientColoring(pparent)
m_PixelCoordinate = new PixelCoordinate(pparent)
r = new JLB_Random(0)
r.Init(@seed)
if @version >= 230219
a = real(@ab), b = imag(@ab), c = real(@cd), d = imag(@cd)
else
a = @aa, b = @bb, c = @cc, d = @dd
endif
if @more && @exch && @which == "Type 2"
float t
t = a, a = c, c = t
t = b, b = d, d = t
endif
m1 = new @f1(this)
m2 = new @f2(this)
assign_Fs( )
assign_ab( )
DoTheWork() ; possibly randomize. fill the pix array
endfunc
func Init(complex pz, complex ppixel)
GradientColoring.Init(pz, ppixel)
m_PixelCoordinate.Init(pz)
endfunc
func Iterate(complex pz)
GradientColoring.Iterate(pz)
endfunc
float func ResultIndex(complex pz)
if (pix[#x,#y] == 0)
m_solid = @solid
return 0
endif
; densest gets index of 1
float idx
idx = (log(pix[#x, #y]) / log(max)) ^(1-@contrast/2)
return idx
endfunc
func DoTheWork( )
if @rnd
Randomize( )
endif
int x = 0, int y = 0
; initialize pix array
while x < #width
y = 0
while y < #height
pix[x, y] = 0
y = y + 1
endwhile
x = x + 1
endwhile
max = 0
float xx = 0.1, float yy = 0.1
if @more, xx = real(@start), yy = imag(@start), endif
int i = 0
int iters = #width * #height * @density
while i < iters
float xnew, float ynew
OneIteration(xx, yy, xnew, ynew)
xx = xnew
yy = ynew
complex zz = m_PixelCoordinate.Iterate(xx+flip(yy))
x = round(real(zz))
y = round(imag(zz))
; plot the point only if within the screen
if x >= 0 && x < #width && y >= 0 && y < #height
pix[x, y] = pix[x, y] + 1
if pix[x, y] > max
max = pix[x, y]
endif
endif
i = i + 1
endwhile
if @lprnt
print("Goodness ", L_eval( ))
endif
endfunc
func OneIteration(float xx, float yy, float &xnew, float &ynew)
if @which == "Type 1"
xnew = m11.Iterate(a11*yy) + cd1*m12.Iterate(a12*xx) ; like Standard (any, bbaa, cd),
ynew = m21.Iterate(a21*xx) + cd2*m22.Iterate(a22*yy) ; Clifford (1122, aabb, cd)
else;if @which == "Type 2"
xnew = m11.Iterate(a11*yy) - m12.Iterate(a12*xx) ; like DeJong (1212, ab, cd)
ynew = m21.Iterate(cd1*xx) - m22.Iterate(cd2*yy)
endif
endfunc
func Randomize( ) ; modified code from mt.ucl
; We randomize the parameters in a loop
; until we find a set that has a reasonably
; high Lyapunov exponent.
int times = 0, int tbest = -1
; int maxtimes = 1000
float L = -1, float Lmax = -1
float asave = 0, float bsave = 0, float csave = 0, float dsave = 0
while L < @Lgoal && times < @maxtimes
; Parameters in the range (-@range to +@range)
a = @range * r.RandomFloat2(0)
b = @range * r.RandomFloat2(0)
c = @range * r.RandomFloat2(0)
d = @range * r.RandomFloat2(0)
; keep only 3 decimal places
a = round(1000*a)/1000, b = round(1000*b)/1000
c = round(1000*c)/1000, d = round(1000*d)/1000
assign_ab( )
L = L_eval( )
times = times + 1
if L > Lmax
Lmax = L
asave = a, bsave = b, csave = c, dsave = d
tbest = times
endif
endwhile
L = Lmax
a = asave, b = bsave, c = csave, d = dsave
assign_ab( )
Lmax = round(100*Lmax)/100
if (@prnt || @lprnt) && times >= @maxtimes
print("Best result at try #", tbest,"; goodness ", Lmax)
endif
if @prnt
print("a ", a, " b ", b, " c ", c, " d ", d, " goodness ", Lmax, \
" in ", times, " tries")
endif
endfunc
float func L_eval( )
float L = 0, float Lsum = 0
float lx = 0.1, float ly = 0.1
float xe = lx + 1e-6, float ye = ly
int i = 0
while i < 1000
; Pickover suggests 10 million iterations,
; but this is enough to produce decent
; attractors
float xx, float yy
OneIteration(lx, ly, xx, yy)
float xsave = xx, float ysave = yy, lx = xe, ly = ye
i = i + 1
OneIteration(lx, ly, xx, yy)
float dLx = xx - xsave, float dLy = yy - ysave
float dL2 = dLx * dLx + dLy * dLy
float df = 1e12 * dL2
float rs = 1/sqrt(df)
xe = xsave + rs * (xx - xsave)
ye = ysave + rs * (yy - ysave)
xx = xsave, yy = ysave
Lsum = Lsum + log(df)
L = 0.721347 * Lsum / i
lx = xx
ly = yy
endwhile
return round(100*L)/100
endfunc
func assign_Fs( )
if @more
if @p == "1122"
m11 = m1, m12 = m1, m21 = m2, m22 = m2
elseif @p == "1212"
m11 = m1, m12 = m2, m21 = m1, m22 = m2
elseif @p == "1221"
m11 = m1, m12 = m2, m21 = m2, m22 = m1
elseif @p == "2112"
m11 = m2, m12 = m1, m21 = m1, m22 = m2
elseif @p == "2121"
m11 = m2, m12 = m1, m21 = m2, m22 = m1
else;if @p == "2211"
m11 = m2, m12 = m2, m21 = m1, m22 = m1
endif
else ; default 1212
m11 = m1, m12 = m2, m21 = m1, m22 = m2
endif
endfunc
func assign_ab( )
if @which == "Type 1"
if @qx1 == "aabb" || !@more
a11 = a, a12 = a, a21 = b, a22 = b
elseif @qx1 == "abab"
a11 = a, a12 = b, a21 = a, a22 = b
elseif @qx1 == "abba"
a11 = a, a12 = b, a21 = b, a22 = a
elseif @qx1 == "baab"
a11 = b, a12 = a, a21 = a, a22 = b
elseif @qx1 == "baba"
a11 = b, a12 = a, a21 = b, a22 = a
else;if @qx1 == "bbaa"
a11 = b, a12 = b, a21 = a, a22 = b
endif
endif
if @qx2 == "cd"
cd1 = c, cd2 = d
else;if @qx2 == "dc"
cd1 = d, cd2 = c
endif
if @which == "Type 2"
if @qy == "ab" || !@more
a11 = a, a12 = b
else;if @qy == "ba"
a11 = b, a12 = a
endif
endif
endfunc
private:
PixelCoordinate m_PixelCoordinate
JLB_Random r
float a, float b, float c, float d
float a11, float a12, float a21, float a22
float cd1, float cd2
int pix[#width, #height]
int max
Transfer m1, Transfer m2
Transfer m11, Transfer m12, Transfer m21, Transfer m22
default:
title = "Chaotic Attractors"
;rating = NotRecommended ; too specialized
heading
text = "Use with pixel(jp) formula in jlb.ufm or jp.ufm. Use Plug-In Coloring (Gradient) in jlb.ucl."
endheading
heading
text = "Ignores all Mappings."
endheading
int param version
caption = "Version"
default = 230219
visible = @version < 230219
endparam
heading
text = "(Current is 230219.)"
visible = @version < 230219
endheading
bool param solid
caption = "Use Solid Background?"
default = false
endparam
;render = !@rnd ;false
param which
caption = "Attractor"
enum = "Type 1" "Type 2"
default = 0
endparam
Transfer param f1
caption = "F1"
default = ChaosFunc
enabled = false
endparam
Transfer param f2
caption = "F2"
default = Chaosfunc
enabled = false
endparam
bool param more
caption = "More options?"
default = false
endparam
param p
caption = "F Permutation"
enum = "1122" "1212" "1221" "2112" "2121" "2211"
default = 0
visible = @more
endparam
bool param exch
caption = "Exchange ab and cd?"
default = false
visible = @more && @which == "Type 2"
endparam
param qx1
caption = "ab Permutation"
enum = "aabb" "abab" "abba" "baab" "baba" "bbaa"
default = 0
visible = @more && (@which == "Type 1")
endparam
param qy
caption = "ab Permutation"
enum = "ab" "ba"
default = 0
visible = @more && (@which == "Type 2")
endparam
param qx2
caption = "cd Permutation"
enum = "cd" "dc"
default = 0
visible = @more
endparam
bool param lprnt
caption = "Print goodness value?"
default = false
visible = !@more || !@prnt|| !@rnd
endparam
bool param rnd
caption = "Find good abcd?"
default = false
visible = @more
endparam
bool param prnt
caption = "Print abcd?"
default = false
visible = @rnd
endparam
heading
endheading
int param maxtimes
caption = "How many tries"
default = 100
min = 1
visible = @rnd
endparam
float param range
caption = "Range for searching"
default = 3
min = 1
visible = @rnd
endparam
float param Lgoal
caption = "How good?"
default = 0.25
min = 0
visible = @rnd
endparam
int param seed
caption = "Seed"
default = 12345678
min = 1
visible = @rnd
endparam
heading
text = "a=real(ab), b=imag(ab), c=real(cd), d=imag(cd)"
visible = !@rnd && @version >= 230219
endheading
complex param ab
default = (-1.4, 1.6)
visible = !@rnd && @version >= 230219
endparam
complex param cd
default = (1.0, 0.7)
visible = !@rnd && @version >= 230219
endparam
float param aa
caption = "a"
default = -1.4
visible = !@rnd && @version < 230219
endparam
param bb
caption = "b"
default = 1.6
visible = !@rnd && @version < 230219
endparam
float param cc
caption = "c"
default = 1.0
visible = !@rnd && @version < 230219
endparam
float param dd
caption = "d"
default = 0.7
visible = !@rnd && @version < 230219
endparam
heading
endheading
complex param start
caption = "Starting Point"
default = (0.1,0.1)
visible = @more
endparam
int param density
caption = "Sample Density"
default = 10
min = 1
endparam
float param contrast
caption = "Added Contrast (-1:+1)"
default = 0
min = -1
max = +1
endparam
}
class ChaosFunc(common.ulb:Transfer){
public:
import "common.ulb"
func ChaosFunc(Generic pparent)
Transfer(pparent)
if @version < 230512
type = @w
else
type = @ww
endif
endfunc
float func Iterate(float pr)
float ans
if type == 0, ans = sin(pr)
elseif type == 1, ans = cos(pr)
elseif type == 2, ans = tanh(pr)
elseif type == 3, ans = Math.RealBesselJ0(pr)
elseif type == 4, ans = Math.RealBesselJ1(pr)
elseif type == 5
if pr == 0, ans = 1, else, ans = sin(pr)/pr, endif
else;if type == 6
if @version < 230512
ans = abs(pr)^@p
if pr < 0, ans = -ans, endif
else
ans = pr / (1 + abs(pr)^@pp)
endif
endif
return ans
endfunc
private:
int type
default:
title = "Chaos Function"
int param version
caption = "Version"
default = 230512
visible = @version < 230512
endparam
param w
caption = " F"
enum = "sin" "cos" "tanh" "J0" "J1" "sync" "spower"
default = 0
visible = @version > 230512
endparam
param ww
caption = " F"
enum = "sin" "cos" "tanh" "J0" "J1" "sync" "rational"
default = 0
visible = @version >= 230512
endparam
float param p
caption = "p"
default = 1
visible = @version < 230512 && @w == 6
endparam
float param pp
caption = "power"
default = 1
visible = @version >= 230512 && @ww == 6
endparam
}
class JLB_Simple(common.ulb:GradientColoring) {
func JLB_Simple(Generic pparent)
GradientColoring(pparent)
if @fz == 2
FT = new @fUT(this)
endif
endfunc
float func ResultIndex(complex pz)
complex zz = @a * pz
if @fz == 1
zz = @FF(zz)
elseif @fz == 2
zz = FT.Iterate(zz)
endif
float x = real(zz), float y = imag(zz)
float ax = abs(x), float ay = abs(y)
float a = cabs(zz)
float ans = 0
if @type == "Mod"
ans = a
elseif @type == "Real"
ans = x
elseif @type == "Imag"
ans = y
elseif @type == "Real+Imag"
ans = x+y
elseif @type == "Real-Imag"
ans = x-y
elseif @type == "Real*Imag"
ans = x*y
elseif @type == "Real/Imag"
ans = x/y
elseif @type == "Imag/Real"
ans = y/x
elseif @type == "Real^Imag"
ans = x^y
elseif @type == "Imag^Real"
ans = y^x
elseif @type == "|Real|+|Imag|"
ans = ax+ay
elseif @type == "|Real|-|Imag|"
ans = ax-ay
elseif @type == "Max(|Real|,|Imag|)"
ans = ax
if ay > ax, ans = ay, endif
elseif @type == "Max(Real,Imag)"
ans = x ; range = (0,a)
if y > x, ans = y, endif
elseif @type == "Min(|Real|,|Imag|)"
ans = ax
if ay < ax, ans = ay, endif
elseif @type == "Min(Real,Imag)"
ans = x
if y < x, ans = y, endif
else;if @type == "Angle"
ans = atan2(zz)/ (2 * #pi)
if ans < 0
ans = ans + 1
endif
endif
; make index be in [0,1] even if Repeat Gradient isn't checked
ans = ans - trunc(ans)
if ans < 0
ans = ans + 1
endif
return ans
endfunc
private:
UserTransform FT
default:
title = "Simple Coloring"
rating = NotRecommended
int param version
caption = "Version-Simple Coloring"
default = 230601
visible = @version < 230601
endparam
heading
text = "(current is 230601.}"
visible = @version < 230601
endheading
heading
text = "Color using the last z value. Use a pixel formula if you want to \
color the gradient."
endheading
heading
caption = "Use z, F(a*z), or T(a*z)"
endheading
param fz
caption = "Which?"
enum = "a*z" "F(a*z)" "T(a*z)"
default = 0
endparam
complex param a
caption = "a"
default = 1
endparam
func FF
caption = "Function"
default = sinh()
visible = @fz == 1
endfunc
UserTransform param fUT
caption = "Transform"
default = JLB_MoebiusUserTransform
visible = @fz == 2
endparam
param type
caption = "Color by"
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
"Angle"
default = 0
endparam
}
class JLB_ComboFunction (common.ulb:UserTransform) {
public:
func JLB_ComboFunction(Generic pparent)
UserTransform(pparent)
m_F1 = new @F1(this)
m_F2 = new @F2(this)
if @mode > 0
m_F3 = new @F3(this)
endif
m_Combine = new Combine()
endfunc
complex func Iterate(complex pz)
float px = real(pz)
float py = imag(pz)
complex xx
complex yy
complex xx1, complex xx2, complex xx3
complex yy1, complex yy2, complex yy3
if @mode == 0 ;"F1 op1 F2"
;xx2 = @a2*@F2(@b2*px)
;yy2 = @a2*@F2(@b2*py)
xx2 = iter(2, @b2*px)
yy2 = iter(2, @b2*py)
if @op1 == "( )" ; F1(F2(.))
; xx = @a1*@F1(@b1*xx2)
; yy = @a1*@F1(@b1*yy2)
xx = iter(1, @b1*xx2)
yy = iter(1, @b1*yy2)
else ; F1(.) op1 F2(.)
; xx1 = @a1*@F1(@b1*px)
; yy1 = @a1*@F1(@b1*py)
xx1 = iter(1, @b1*px)
yy1 = iter(1, @b1*py)
xx = m_Combine.go(xx1, @op1, xx2)
yy = m_Combine.go(yy1, @op1, yy2)
endif
elseif @mode == 1 ;"F1 op1 (F2 op2 F3)"
if @op2a == "( )" ; F1 op F2(F3(.))
; xx3 = @a3*F3(@b3*px)
; yy3 = @a3*F3(@b3*py)
xx3 = iter(3, @b3*px)
yy3 = iter(3, @b3*py)
; xx2 = @a2*F2(@b2*xx3)
; yy2 = @a2*F2(@b2*yy3)
xx2 = iter(2, @b2*xx3)
yy2 = iter(2, @b2*yy3)
if @op1 == "( )" ; F1(F2(F3(.)))
; xx = @a1*F1(@b1*xx2)
; yy = @a1*F1(@b1*yy2)
xx = iter(1, @b1*xx2)
yy = iter(1, @b1*yy2)
else ; F1(.) op1 F2(F3(.))
; xx1 = @a1*F1(@b1*px)
; yy1 = @a1*F1(@b1*py)
xx1 = iter(1, @b1*px)
yy1 = iter(1, @b1*py)
xx = m_Combine.go(xx1, @op1, xx2)
yy = m_Combine.go(yy1, @op1, yy2)
endif
else
; xx3 = @a3*F3(@b3*px)
; yy3 = @a3*F3(@b3*py)
xx3 = iter(3, @b3*px)
yy3 = iter(3, @b3*py)
; xx2 = @a2*F2(@b2*px)
; yy2 = @a2*F2(@b2*py)
xx2 = iter(2, @b2*px)
yy2 = iter(2, @b2*py)
xx2 = m_Combine.go(xx2, @op2a, xx3)
yy2 = m_Combine.go(yy2, @op2a, yy3)
if @op1 == "( )" ; F1(F2(.) op2a F3(.))
; xx = @a1*F1(@b1*xx2)
; yy = @a1*F1(@b1*yy2)
xx = iter(1, @b1*xx2)
yy = iter(1, @b1*yy2)
else
; xx1 = @a1*F1(@b1*px)
; yy1 = @a1*F1(@b1*py)
xx1 = iter(1, @b1*px)
yy1 = iter(1, @b1*py)
xx = m_Combine.go(xx1, @op1, xx2)
yy = m_Combine.go(yy1, @op1, yy2)
endif
endif
else ;@omode == "(F1 op1 F2) op2 F3"
; @op3a == "()" not allowed with this ordering
; xx2 = @a2*F2(@b2*px)
; yy2 = @a2*F2(@b2*py)
xx2 = iter(2, @b2*px)
yy2 = iter(2, @b2*py)
if @op1 == "( )" ; (F1(F2(.))) op2b F3(.)
; xx1 = @a1*F1(@b1*xx2)
; yy1 = @a1*F1(@b1*yy2)
xx1 = iter(1, @b1*xx2)
yy1 = iter(1, @b1*yy2)
else
; xx1 = @a1*F1(@b1*px)
; yy1 = @a1*F1(@b1*py)
xx1 = iter(1, @b1*px)
yy1 = iter(1, @b1*py)
xx1 = m_Combine.go(xx1, @op1, xx2)
yy1 = m_Combine.go(yy1, @op1, yy2)
endif
; xx3 = @a3*F3(@b3*px)
; yy3 = @a3*F3(@b3*py)
xx3 = iter(3, @b3*px)
yy3 = iter(3, @b3*py)
xx = m_Combine.go(xx1, @op2b, xx3)
yy = m_Combine.go(yy1, @op2b, yy3)
endif
return xx + flip(yy)
endfunc
complex func iter(int n, complex v)
if n == 1
return @a1*m_F1.Iterate(v)
elseif n == 2
return @a2*m_F2.Iterate(v)
else
return @a3*m_F3.Iterate(v)
endif
endfunc
private:
UserTransform m_F1
UserTransform m_F2
UserTransform m_F3
Combine m_Combine
default:
rating = NotRecommended
title = "ComboF"
int param version
caption = "Version"
default = 230817
visible = @version < 230817
endparam
heading
text = "(Current is 230817.)"
visible = @version < 230817
endheading
param mode
caption = "How to combine"
default = 0
enum = "F1 op F2" "F1 op1 (F2 op2 F3)" "(F1 op1 F2) op2 F3"
endparam
param op1
caption = "Operator 1"
enum = "+" "-" "*" "/" "^" "( )"
default = 0
hint = "How to combine Formula values."
endparam
param op2a
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" "( )"
default = 2
hint = "How to combine Formula values."
visible = (@mode == 1)
endparam
param op2b
caption = "Operator 2"
enum = "+" "-" "*" "/" "^" ; () doesn't make sense
default = 2
hint = "How to combine Formula values."
visible = (@mode == 2)
endparam
heading
caption = "a1*F1(b1*v)"
endheading
complex param a1
caption = "a1"
default = 1
hint = "multiplies F1"
endparam
complex param b1
caption = "b1"
default = 2
hint = "multiplies F1's arg"
endparam
UserTransform param F1
caption = "F1"
default = JLB_FTransform
selectable = false
endparam
heading
caption = "a2*F2(b2*v)"
endheading
complex param a2
caption = "a2"
default = 2.7
hint = "multiplies F2"
endparam
complex param b2
caption = "b2"
default = 2.7
hint = "multiplies F2's arg"
endparam
UserTransform param F2
caption = "F2"
default = JLB_FTransform
selectable = false
endparam
heading
caption = "a3*F3(b3*v)"
visible = @mode > 0
endheading
complex param a3
caption = "a3"
default = 0
hint = "multiplies F3"
visible = @mode > 0
endparam
complex param b3
caption = "b3"
default = 1
hint = "multiplies F3's arg"
visible = @mode > 0
endparam
UserTransform param F3
caption = "F3"
default = JLB_FTransform
visible = @mode > 0
selectable = false
endparam
}
class JLB_FuncsUserTransform(common.ulb:UserTransform) {
public:
func JLB_FuncsUserTransform(Generic pparent)
UserTransform(pparent)
m_fx = new @f1(this)
m_fy = new @f2(this)
endfunc
complex func Iterate(complex pz)
int n = 0
while n < @nmax
complex xa = @bb*ComplexToFloat.go(pz, @xarg, true)
complex ya = @bb*ComplexToFloat.go(pz, @yarg, true)
float xx = real(@aa*m_fx.Iterate(xa))
float yy = real(@aa*m_fy.Iterate(ya))
if @kind == "Add"
pz = pz + xx + flip(yy)
else
pz = xx + flip(yy)
endif
n = n + 1
endwhile
return pz
endfunc
private:
UserTransform m_fx
UserTransform m_fy
default:
rating = NotRecommended
title = "Funcs"
int param version
caption = "Version"
default = 230819
visible = @version < 230819
endparam
heading
text = "(Current is 230819.)"
visible = @version < 230819
endheading
heading
caption = "xnew = aa*F(bb*arg)"
endheading
UserTransform param f1
caption = "X function"
default = JLB_FTransform
;selectable = false
endparam
param xarg
caption = "X arg"
enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \
"Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle"
endparam
heading
caption = "ynew = aa*F(bb*arg)"
endheading
UserTransform param f2
caption = "Y function"
default = JLB_FTransform
;selectable = false
endparam
param yarg
caption = "Y arg"
enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \
"Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle"
endparam
heading
endheading
complex param aa
caption = "aa"
default = 1
endparam
complex param bb
caption = "bb"
default = 1
endparam
int param @nmax
caption = "Iterations"
default = 1
min = 1
endparam
param kind
caption = "Add or Replace"
enum = "Add" "Replace"
default = 1
endparam
}
class JLB_DTwoCircles(Distance) {
public:
func JLB_DTwoCircles(Generic pparent)
Distance(pparent)
; first circle
m_dist[0] = new @dist0(this)
if @screen_center0, ctr[0] = #center, else, ctr[0] = @center0, endif
if @type0 == "Circle", h[0] = v[0] = @r0, else, h[0] = @horiz0, v[0] = @vert0, endif
sp[0] = @p0
scale[0] = 1
if @do_scale0
scale[0] = 2 * MyMath.fmax(h[0], v[0]) ; 2 to be like Square scaling
endif
rot[0] = 1
if @p0 != 2.0 || (@type0 == 1 && @horiz0 != @vert0)
rot[0] = cos(@angle0*#pi/180) + flip(sin(@angle0*#pi/180))
endif
pow[0] = @pow0
inout[0] = @in_out0
;same thing for second circle
m_dist[1] = new @dist1(this)
if @screen_center1, ctr[1] = #center, else, ctr[1] = @center1, endif
if @type1 == "Circle", h[1] = v[1] = @r1, else, h[1] = @horiz1, v[1] = @vert1, endif
sp[1] = @p1
scale[1] = 1
if @do_scale1
scale[1] = 2 * MyMath.fmax(h[1], v[1]) ; 2 to be like Square scaling
endif
rot[1] = 1
if @p1 != 2.0 || (@type1 == 1 && @horiz1 != @vert1)
rot[1] = cos(@angle1*#pi/180) + flip(sin(@angle1*#pi/180))
endif
pow[1] = @pow1
inout[1] = @in_out1
endfunc
func Init(complex zz)
;m_dist.SetParams(0, m_abs_value) ;not needed
float r
old_inside[0] = IsInside(rot[0] * (zz - ctr[0]), r, 0) ; calculates r, not used
old_inside[1] = IsInside(rot[1] * (zz - ctr[1]), r, 1) ; calculates r, not used
endfunc
float func Iterate(complex zz)
float d0 = circle_dist(zz, 0)
float d1 = circle_dist(zz, 1)
float dmin = MyMath.fmin(d0, d1)
float dmax = MyMath.fmax(d0, d1)
if dmin < 0 ; at most one is okay
if @how == "Both"
return dmin ; no good
endif
return dmax ; this one, good or bad
endif
; both are okay
if @which == "Minimum"
return dmin
elseif @which == "Maximum"
return dmax
elseif @which == "Arithmetic Average"
return 0.5*(dmin + dmax)
elseif @which == "Geometric Average"
return sqrt(dmin * dmax)
else;if @which == "Harmonic Average"
return 2 / (1/dmin + 1/dmax)
endif
endfunc
float func circle_dist(complex zz, int n)
zz = rot[n] * (zz - ctr[n])
float d = -MyMath.fmax(1, |zz|)
float r
bool new_inside = IsInside(zz, r, n) ; calculates r
complex t
bool okay = false
if inout[n] == 0 ; "Inside"
okay = new_inside
elseif inout[n] == 1 ; "Outside"
okay = !new_inside
elseif inout[n] == 2 ; "Either"
okay = true
elseif inout[n] == 3 ; "Change"
okay = new_inside != old_inside[n]
elseif inout[n] == 4 ; "Same"
okay = new_inside == old_inside[n]
endif
if !okay
if inout[n] == 5 ; "In->In"
okay = old_inside[n] && new_inside
elseif inout[n] == 6 ; "In->Out"
okay = old_inside[n] && !new_inside
elseif inout[n] == 7 ;"Out->In"
okay = !old_inside[n] && new_inside
elseif inout[n] == 8 ;"Out->Out"
okay = !old_inside[n] && !new_inside
endif
endif
t = 0
if okay
t = zz * (1-r) / rot[n]
if !new_inside
t = -t
endif
d = m_dist[n].Iterate(t)/scale[n]
old_inside[n] = new_inside
;bool neg = ( d < 0 )
d = abs(d)^pow[n]
;if neg, d = -d, endif
endif
return d
endfunc
bool func IsInside(complex zz, float &r, int n)
float x = abs(real(zz))
float y = abs(imag(zz))
r= ( (x/h[n])^sp[n] + (y/v[n])^sp[n] ) ^ (1/sp[n])
return r <= 1
endfunc
private:
complex ctr[2]
float h[2]
float v[2]
float sp[2]
float scale[2]
float pow[2]
complex rot[2]
int inout[2]
bool old_inside[2]
Distance m_dist[2]
default:
title = "TwoCircles"
;rating = Recommended
heading
caption = "Use Shape Distance instead."
endheading
int param version
caption = "Version"
default = 231101
visible = @version < 231101
endparam
heading
text = "(current is 231101.}"
visible = @version < 231101
endheading
heading
caption = "First circle"
endheading
param type0
caption = "Circle or ellipse"
enum = "Circle" "Ellipse"
default = 0
endparam
float param p0
caption = "Shape power"
default = 2
min = 0
hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square."
endparam
bool param screen_center0
caption = "Use screen center?"
default = true
endparam
param center0
caption = "Center"
default = (0,0)
visible = !@screen_center0
endparam
float param r0
caption = "Circle radius"
default = 2.0
min = 0
visible = @type0 == 0
endparam
float param horiz0
caption = "Ellipse x value"
default = 2.0
min = 0
visible = @type0 == 1
endparam
float param vert0
caption = "Ellipse y value"
default = 2.0
min = 0
visible = @type0 == 1
endparam
float param angle0
caption = "Rotation angle"
default = 0
visible = @p0 != 2.0 || (@type0 == 1 && @horiz0 != @vert0)
endparam
param in_out0
caption = "Inside/outside?"
enum = "Inside" "Outside" "Either" "Change" "Same" \
"In->In" "In->Out" "Out->In" "Out->Out"
hint = "Change: use iterations where new inside is different from \
old inside. Same: use iterations where new inside equals \
old inside"
default = 2
endparam
float param pow0
caption = "Distance power"
default = 1
min = 0
; hint = "Higher values emphasize iterations with z away from the circle edge."
endparam
bool param do_scale0
caption = "Scale by size?"
default = false
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist0
default = JLB_DXYZ
selectable = false
endparam
heading
caption = "Second circle"
endheading
param type1
caption = "Circle or ellipse"
enum = "Circle" "Ellipse"
default = 0
endparam
float param p1
caption = "Shape power"
default = 2
min = 0
hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square."
endparam
bool param screen_center1
caption = "Use screen center?"
default = true
endparam
param center1
caption = "Center"
default = (0,0)
visible = !@screen_center1
endparam
float param r1
caption = "Circle radius"
default = 4.0
min = 0
visible = @type1 == 0
endparam
float param horiz1
caption = "Ellipse x value"
default = 4.0
min = 0
visible = @type1 == 1
endparam
float param vert1
caption = "Ellipse y value"
default = 4.0
min = 0
visible = @type1 == 1
endparam
float param angle1
caption = "Rotation angle"
default = 1
visible = @p1 != 2.0 || (@type1 == 1 && @horiz1 != @vert1)
endparam
param in_out1
caption = "Inside/outside?"
enum = "Inside" "Outside" "Either" "Change" "Same" \
"In->In" "In->Out" "Out->In" "Out->Out"
hint = "Change: use iterations where new inside is different from \
old inside. Same: use iterations where new inside equals \
old inside"
default = 0
endparam
float param pow1
caption = "Distance power"
default = 1
min = 0
; hint = "Higher values emphasize iterations with z away from the circle edge."
endparam
bool param do_scale1
caption = "Scale by size?"
default = false
endparam
heading
;text = "Use for distance:"
endheading
Distance param dist1
default = JLB_DXYZ
selectable = false
endparam
heading
caption = "Combine circles?"
endheading
param how
caption = "Either/Both"
enum = "Either" "Both"
default = 0
endparam
param which
caption = "Which?"
enum = "Minimum" "Maximum" "Arithmetic Average" "Geometric Average" "Harmonic Average"
default = 0
endparam
}
class JLB_2Dist_SFormula(SFormula) {
;
public:
import "common.ulb"
func JLB_2Dist_SFormula(Generic pparent)
SFormula(pparent)
m_Dx = new @distx(this)
m_Dy = new @disty(this)
if @addT > 0 && !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
ppc = #pixel
if !@p_Mtype
ppc = @p_seed
endif
endfunc
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
complex pz = S.pz
complex znew
float x = m_Dx.Iterate(pz)
float y = m_Dy.Iterate(pz)
znew = x + flip(y) + ppc
if @addT == "c"
ppc = finalTransform.Iterate(ppc)
elseif @addT == "z"
znew = finalTransform.Iterate(znew)
endif
S.Update(znew, S.pc)
return S.bailed
endfunc
protected:
complex ppc
Distance m_Dx
Distance m_Dy
UtilityTransform finalTransform
default:
rating = NotRecommended
title = "Two Distances"
int param version
caption = "Version"
default = 231111
visible = @version < 231111
endparam
heading
text = "Current version is 231111"
visible = @version < 231111
endheading
bool param p_std
caption = "Standard?"
default = true
endparam
bool param p_Mtype
caption = "M-type?"
default = true
endparam
complex param p_seed
caption = "Seed for J-type"
default = (0.3, 0)
visible = !@p_Mtype
endparam
heading
text = "z_new = Xdistance(z)+flip(Ydistance(z))"
endheading
Distance param distx
caption = "Xdistance"
default = JLB_DCurve2
endparam
Distance param disty
caption = "Ydistance"
default = JLB_DCurve2
endparam
heading
caption = "Tweak after each iteration"
visible = !@p_std
endheading
param addT
caption = "Type"
enum = "none" "c" "z"
default = 0
visible = !@p_std
endparam
UtilityTransform param finalUT
caption = "Tweak transform"
default = Tweak
visible = @addT > 0 && !@p_std
selectable = false
endparam
}
class JLB_D_SD2(Distance){
; same as JLB_D_SD except skip scaling except for |z| and cabs
; ugly but I don't see a cleaner way
public:
func JLB_D_SD2(Generic pparent)
Distance(pparent)
m_SD = new @d_SD(this)
endfunc
func Init(complex zz)
bool do_scale = (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale
if do_scale
m_SD.SetFactor(@factor)
endif
m_SD.SD_Set(0, 0) ; initial path length = 0 - no path yet
m_SD.SetScale(do_scale)
m_z0 = zz
endfunc
float func Iterate(complex zz)
float d = m_SD.Iterate(zz)
; m_abs_value is from Distance base class, default is False
; Color by Distance sets m_abs_value to True
if m_abs_value
d = abs(d)
endif
return d
endfunc
protected:
SD m_SD
complex m_z0 ; used by D019
default:
title = "Simple distance 2"
rating = NotRecommended ; but needed for Simple Shapes coloring.
int param version
caption = "Version"
default = 240209
visible = @version < 240209
endparam
heading
text = "(current is 240209.}"
visible = @version < 240209
endheading
SD param d_SD
caption = "Use for distance"
default = JLB_D01
endparam
bool param scale
caption = "Scale?"
default = true
visible = (@d_SD == JLB_D00 || @d_SD == JLB_D01) ; path length and angle
endparam
float param factor
caption = "Scale divisor"
default = 1
min = 1e-6
visible = (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale
endparam
}
class JLB_AboveBelowSFormula(SFormula) {
; A Barnsley-like formula as an SFormula, with a non-abrupt transition \
; possible from the upper formula to the lower formula.
public:
import "common.ulb"
; @param pparent the parent, generally "this" for the parent, or zero
func JLB_AboveBelowSFormula(Generic pparent)
SFormula.SFormula(pparent)
m_SFormulaA = new @f_SFormulaA(this)
m_SFormulaB = new @f_SFormulaB(this)
m_SD = new @D(this)
zt=(1,0)
endfunc
func Init(complex pz, complex pc)
m_SFormulaA.Init(pz, pc)
m_SFormulaB.Init(pz, pc)
m_SD.SetScale(false)
endfunc
; @param pz
; @param pc
; @return the new pz
bool func Iterate(State S)
if S.bailed
return true
endif
if S.tooMany
return false
endif
; save values
complex pz = S.pz
complex pzold = S.pzold
complex pc = S.pc
float test
if @version < 231202
test = ComplexToFloat2.go(pz, pc, @mode, @absvalue)
else
test = m_SD.Iterate(pz)
endif
; find A and B z-values
; quit if either SFormula says it's done
;if m_SFormulaA.Iterate(S)
bool done = m_SFormulaA.Iterate(S)
if done
return true
endif
complex zA = S.pz
S.pz = pz, S.pzold = pzold, S.pc = pc ; restore
;if m_SFormulaB.Iterate(S)
done = m_SFormulaB.Iterate(S)
if done
return true
endif
complex zB = S.pz
S.pz = pz, S.pzold = pzold, S.pc = pc ; restore
S.iters = S.iters - 1
; if trans == 0, use all of A or B
float frac = 0
if @trans == 0
if test >= @crit
frac = 1
endif
else
; otherwise, do a smooth transition using tanh
frac = TSmooth.go((test-@crit)/@trans)
endif
pz = frac*zA + (1-frac)*zB
S.Update(pz, pc)
return S.bailed
endfunc
protected:
SFormula m_SFormulaA
SFormula m_SFormulaB
CalcValue m_CalcValue
SD m_SD
complex zt
default:
title = "Above/Below"
rating = NotRecommended
int param version
caption = "Version"
default = 231202
visible = @version < 231202
endparam
heading
text = "(Current is 231202.)"
visible = @version < 231202
endheading
heading
text = "Calculate test value V. Use upper/lower formula if test value\
is above/below V."
endheading
SD param D
caption = "V method"
default = JLB_D01
visible = @version >= 231202
endparam
param mode
caption = "V method"
hint = "How to calculate the test value."
default = 0
enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \
"Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \
"|Real|+|Imag|""|Real|-|Imag|" \
"Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\
;"Angle"
visible = @version < 231202
endparam
bool param absvalue
caption = "absolute(test value)?"
default = false
visible = @version < 231202
endparam
float param crit
caption = "V"
default = 1
endparam
float param trans
caption = "Transition parameter"
hint = "Smaller values make a steeper transition. For an abrupt transition, use 0."
default = 1
min = 0
endparam
SFormula param f_SFormulaA
caption = "Above formula"
default = JLB_FuncSFormula
endparam
SFormula param f_SFormulaB
caption = "Below formula"
default = JLB_PowerSFormula
endparam
}
class JLB_DExpAccum(Distance) {
public:
func JLB_DExpAccum(Generic pparent)
Distance(pparent)
m_dist = new @dist(this)
endfunc
func Init(complex zz)
m_dist.Init(zz)
m_dist.SetParams(0, true)
endfunc
float func Iterate(complex zz)
float d = m_dist.Iterate(zz)
d = exp(-@scale*d)
return d
endfunc
private:
Distance m_dist
default:
title = "Exp. Accum."
rating = NotRecommended
int param version
caption = "Version"
default = 240115
visible = @version < 240115
endparam
heading
text = "(current is 240115.}"
visible = @version < 240115
endheading
float param scale
caption = "Scale"
default = 1
;min = 0
hint = "Large positive values give more emphasis to earlier iterations."
endparam
Distance param dist
default = JLB_D_SD
selectable = false
endparam
}