Comment{
jlb.ulb
jimblue66@gmail.com
}
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 = "Exponent"
default = (2,0)
hint = "Defines the primary exponent 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)
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_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)
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 = recommended
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
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 = recommended
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 = Recommended
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 = "Mandelbrot a1"
default = 1
visible = !@p_std
endparam
complex param p_power
caption = "Mandelbrot p"
default = (2,0)
visible = !@p_std
endparam
complex param b
caption = "Mandelbrot b"
default = 1
visible = !@p_std
endparam
complex param p_power2
caption = "Mandelbrot q"
default = 0
visible = !@p_std
endparam
complex param p_a_old
caption = "Mandelbrot 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 = Recommended
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 = Recommended
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 + a1*(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 = Recommended
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 = Recommended
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 = Recommended
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 = Recommended
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 = Recommended
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 = Recommended
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
}
; Calculate function 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
}
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 @addT > 0 ;&& !@p_std
finalTransform = new @finalUT(this)
endif
endfunc
func Init(complex pz, complex pc)
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
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")
znew = pz - @step * (f/fp)*(1 + @p_alpha*f*fpp/(2*fp*fp))
elseif (@p_iter_type == "Type 2")
znew = pz - @step * 2*(f/fp) / ( 2 - @p_alpha*f*fpp/(fp*fp))
else;if (@p_iter_type == "Type 3")
; 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 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 = Recommended
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 = Recommended
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 = Recommended
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
}
; 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 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 = Recommended
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 = Recommended
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 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_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 = recommended
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_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 = Recommended
title = "Moebius"
int param v_MoebiusUserTransform
caption = "Version (Moebius_UserTransform)"
default = 200
hint = "Old version."
visible = @v_MoebiusUserTransform < 200
endparam
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 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 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 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 = Recommended
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_SwitchSuperCD(mmf.ulb:MMF_SwitchConvergentDivergentFormula) {
; 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. Both convergent and divergent formulas can be used.
;
public:
import "common.ulb"
import "mmf.ulb"
func JLB_SwitchSuperCD(Generic pparent)
MMF_SwitchConvergentDivergentFormula.MMF_SwitchConvergentDivergentFormula(pparent)
if (@p_InitType == "Contraction")
m_InitContraction = new @f_InitContraction(this)
elseif (@p_InitType == "DualTransform")
m_InitDualTransform = new @f_InitDualTransform(this)
elseif (@p_InitType == "Transform")
m_InitUserTransform = new @f_InitUserTransform(this)
endif
if (@p_IterType == "Contraction")
m_IterContraction = new @f_IterContraction(this)
elseif (@p_IterType == "DualTransform")
m_IterDualTransform = new @f_IterDualTransform(this)
else;if (@p_IterType == "Transform")
m_IterUserTransform = new @f_IterUserTransform(this)
endif
endfunc
; @param pz
; @Initialize
complex func Init(complex pz)
m_IsBad = false
pz = MMF_SwitchConvergentDivergentFormula.Init(pz)
if (@p_InitType == "Contraction")
pz = m_InitContraction.Iterate(pz, fConstant)
elseif (@p_InitType == "DualTransform")
m_InitDualTransform.Iterate(pz, fConstant)
elseif (@p_InitType == "Transform")
pz = m_InitUserTransform.Iterate(pz)
endif
return pz
endfunc
; @param pz
; Iterate--all the work is done in the plug-in.
complex func Iterate(complex pz)
pz = MMF_SwitchConvergentDivergentFormula.Iterate(pz)
if (m_IsBad)
return pz
endif
if (@p_IterType == "Contraction")
pz = m_IterContraction.Iterate(pz, fConstant)
elseif (@p_IterType == "DualTransform")
m_IterDualTransform.Iterate(pz, fConstant)
else;if (@p_IterType == "Transform")
pz = m_IterUserTransform.Iterate(pz) + fConstant
endif
return pz
endfunc
; ; @param pz
; ; @return true if bailed out.
bool func IsBailedOut(complex pz)
; First check to see if iteration has gone bad
float tmp = 0 ; to satisfy compiler
if (!m_IsBad)
if (@p_CorDBailout == "Convergent")
tmp = |pz-m_ZOld|
else;if (@p_CorDBailout == "Divergent")
tmp = |pz|
endif
m_IsBad = IsInf(tmp) || IsNan(tmp)
endif
if (m_IsBad)
if (@p_CorDBailout == "Convergent")
return false
else;if (@p_CorDBailout == "Divergent")
return true
endif
endif
; pz is still okay
; The bailout code is slightly adapted from Ron Barnett's code, where it
; appears in several places.
if (@p_CorDBailout == "Convergent")
complex dif = pz - m_ZOld
if @bailout_type == "mod"
return (tmp < @p_lowerbailout)
elseif @bailout_type == "real"
return (sqr(real(dif)) < @p_lowerbailout)
elseif @bailout_type == "imag"
return (sqr(imag(dif)) < @p_lowerbailout)
elseif @bailout_type == "or"
return (sqr(real(dif)) < @p_lowerbailout || sqr(imag(dif)) < @p_lowerbailout)
elseif @bailout_type == "and"
return (sqr(real(dif)) < @p_lowerbailout && sqr(imag(dif)) < @p_lowerbailout)
elseif @bailout_type == "manh"
return (sqr(abs(real(dif)) + abs(imag(dif))) < @p_lowerbailout)
else;if @bailout_type == "manr"
return (sqr(real(dif) + imag(dif)) < @p_lowerbailout)
endif
else
if @bailout_type == "mod"
return (tmp > @p_upperbailout)
elseif @bailout_type == "real"
return (sqr(real(pz)) > @p_upperbailout)
elseif @bailout_type == "imag"
return (sqr(imag(pz)) > @p_upperbailout)
elseif @bailout_type == "or"
return (sqr(real(pz)) > @p_upperbailout || sqr(imag(pz)) > @p_upperbailout)
elseif @bailout_type == "and"
return (sqr(real(pz)) > @p_upperbailout && sqr(imag(pz)) > @p_upperbailout)
elseif @bailout_type == "manh"
return (sqr(abs(real(pz)) + abs(imag(pz))) > @p_upperbailout)
else;if @bailout_type == "manr"
return (sqr(real(pz) + imag(pz)) > @p_upperbailout)
endif
endif
endfunc
protected:
UserTransform m_IterUserTransform
UserTransform m_InitUserTransform
DualTransform m_IterDualTransform
DualTransform m_InitDualTransform
Contraction m_IterContraction
Contraction m_InitContraction
bool m_IsBad
default:
rating = notRecommended
title = "Switch Super CD"
;rating = recommended
param p_power ; Overrides p_power from Formula
caption = "Power"
default = (2,0)
visible = false
enabled = false
endparam
int param v_superswitchcd
caption = "Version (JLB_superswitchcd)"
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_superswitchcd < 100
endparam
Heading
caption = "Start of Switch Super CD parameters"
Endheading
Heading
Endheading
param p_InitType
caption = "Initialization type"
default = 0
enum = "None" "Contraction" "DualTransform" "Transform"
hint = "A Contraction produces a new z from the old z and c. \
A DualTransform can produce a new z, a new c, or both \
from the old z and c. A Transform produces a new z from the old z."
endparam
Contraction param f_InitContraction
caption = "Formula"
default = JLB_NullZContraction
visible = @p_InitType == 1
endparam
DualTransform param f_InitDualTransform
caption = "Formula"
default = JLB_NullDualTransform
visible = @p_InitType == 2
endparam
UserTransform param f_InitUserTransform
caption = "Formula"
default = JLB_NullUserTransform
visible = @p_InitType == 3
endparam
Heading
Endheading
param p_IterType
caption = "Formula type"
default = 0
enum = "Contraction" "DualTransform" "Transform"
hint = "A Contraction produces a new z from the old z and c. \
A DualTransform can produce a new z, a new c, or both \
from the old z and c. A Transform produces a new z from the old z; \
for iterations, c is added."
endparam
Contraction param f_IterContraction
caption = "Formula"
default = JLB_MandelbrotContraction
visible = @p_IterType == 0
endparam
DualTransform param f_IterDualTransform
caption = "Formula"
default = JLB_MandelbrotDualTransform
visible = @p_IterType == 1
endparam
UserTransform param f_IterUserTransform
caption = "Formula"
default = JLB_BasicUserTransform
visible = @p_IterType == 2
endparam
Heading
caption = "Bailout"
Endheading
param p_CorDBailout
enum = "Convergent" "Divergent"
caption = "Fractal type"
default = 1
endparam
param bailout_type
caption = "Bailout test type"
default = 0
enum = "mod" "real" "imag" "or" "and" "manh" "manr"
hint = "mod gives the usual behavior, same as the Standard bailout"
; visible = !@p_SimpleBailout
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")
return pz - @relax * (f/fp)*(1 + @p_alpha*f*fpp/(2*fp*fp))
elseif (@p_iter_type == "Type 2")
return pz - @relax * 2*(f/fp) / ( 2 - @p_alpha*f*fpp/(fp*fp))
else;if (@p_iter_type == "Type 3")
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_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 Geometry {
; Perhaps the start of a general Geometry class.
; Original version 03 November 2012
; Latest change 14 March 2023
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 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{
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
}
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_QuadMirror2(common.ulb:UserTransform) {
; Pick a block from the image, then repeat it mirroring both
; horizontally and vertically.
public:
import "common.ulb"
func JLB_QuadMirror2(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 = 1
if (@bpos > 1)
ix = 2
endif
int iy = 1
if (@bpos == 1 || @bpos == 3)
iy = 2
endif
; block size in pixels (floats)
m_bx = real(#screenmax) / @nx
m_by = imag(#screenmax) / @ny
m_pix_c = m_PixelCoordinate.Iterate(@z_c)
if (@show == 1)
m_x1 = real(#screenmax)/2 - m_bx/2
m_y1 = imag(#screenmax)/2 - 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
complex func Iterate(complex pz)
UserTransform.Iterate(pz)
complex tz = #screenpixel
float tx = real(tz)
float ty = imag(tz)
if (@show == 0)
return pz
elseif (@show == 1)
if (tx >= m_x1 && tx <= m_x2 && ty >= m_y1 && ty <= m_y2)
return m_FractalCoordinate.Iterate(tz + m_pix_c - #screenmax/2)
else
return @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"
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:
;$define debug
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