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 = "Power" default = (2,0) hint = "Defines the primary power for the fractal." visible = false endparam } ; version 1, always starts in M mode ; version 2 each formula choose M or J mode class JLB_SwitchCombo(JLB_SwitchFormula) { public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_SwitchCombo(Generic pparent) JLB_SwitchFormula.JLB_SwitchFormula(pparent) m_SFormula1 = new @f_SFormula1(this) m_SFormula2 = new @f_SFormula2(this) ; S = new State(#pixel, fValue, @p_bType, @p_divtype, @p_diverge, @p_angle, @p_converge) S = new State(#pixel, fValue, @p_bType, @p_divtype, @p_diverge, @p_converge) endfunc ; @param pz the initial location ; @return initial z for iteration complex func Init(complex pz) JLB_SwitchFormula.Init(pz) ; following block moved from constructor to here 240112 if @v_switchcombo < 200 fType = @p_mandy if fType fValue = fConstant = @p_start else fValue = fConstant = @p_seed endif else fType = true fValue = fConstant = #pixel ;@p_seed endif m_count = 0 if @f_SFormula1 == JLB_NothingSFormula ; skip initial formula m_count = @n1 endif complex rvalue if fType ; Mandelbrot type fConstant = pz rvalue = fValue else ; Julia type rvalue = pz endif S.pzold = S.pz = pz S.pc = fConstant if @n1 > 0 && @p_ibail ; if formula 1 has its own bail criteria S.bType = @p_ibType S.divType = @p_idivtype S.dValue = @p_idiverge S.cValue = @p_iconverge ; S.dCos = cos(@p_iangle * #pi/180.0) ; S.dSin = sin(@p_iangle * #pi/180.0) else ; formulas 1 and 2 have the same criteria S.bType = @p_bType S.divType = @p_divtype S.dValue = @p_diverge S.cValue = @p_converge endif S.iters = 0 S.tooMany = false S.bailed = false m_SFormula1.Init(pz, S.pc) m_SFormula2.Init(pz, S.pc) return rvalue ; value ignored endfunc ; Called by Switch Combo Formula in jlb.ufm ; @param f = flag for Mandelbrot or Julia mode, true for Mandelbrots ; @param v the value to be used as the start value or constant func SetParams(bool f, complex v) fType = f fValue = fConstant = v endfunc ; @param pz ; Iterate--all the work is done in the plug-in. complex func Iterate(complex pz) ; argument is ignored ; Initial formula if m_count < @n1 setz() m_SFormula1.Iterate(S) m_count = m_count + 1 if S.bailed ; set up for formula 2, which may have different bailing criteria m_count = @n1 S.bType = @p_bType S.divType = @p_divtype S.dValue = @p_diverge S.cValue = @p_converge ;S.tooMany = false ; S.dCos = cos(@p_angle * #pi/180.0) ; S.dSin = sin(@p_angle * #pi/180.0) S.bailed = S.IsBailedOut(S.pz) ; check for new bailout criterion endif else ; Main formula setz() m_SFormula2.Iterate(S) m_count = m_count + 1 endif return S.pz endfunc func setz () if S.iters > 0 && @zdz > 0 zz = S.pz if @zdz == "z-z_prev" zz = zz - S.pzold elseif @zdz == "z/z_prev" zz = zz / S.pzold elseif @zdz == "z-pixel" zz = zz - #pixel elseif @zdz == "z/pixel" zz = zz / #pixel endif S.pz = zz endif endfunc ; @param pz ; @return true if bailed out. bool func IsBailedOut(complex pz) return S.bailed endfunc protected: complex fConstant complex fValue bool fType State S SFormula m_SFormula1 SFormula m_SFormula2 int m_count default: title = "SwitchCombo" rating = NotRecommended int param v_switchcombo caption = "Version" default = 220801 ; changes today don't break old formulas hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_switchcombo < 200 endparam param zdz caption = "Use for zz" enum = "z" "z-z_prev" "z/z_prev" "z-pixel" "z/pixel" default = 0 visible = true ;@v_switchcombo > 200 endparam ; complex param p_power ; Hide p_power from Formula ; visible = false ; endparam ; this group only for version 100 bool param p_mandy caption = "Mandelbrot?" default = true hint = "Disable for Julia mode." visible = false ;@p_manual endparam complex param p_start caption = "Mandelbrot Start Value" default = (0,0) visible = false ; @p_mandy && @p_manual ; always starts with pz = #pixel endparam complex param p_seed caption = "Julia Constant" default = (0.3,0) visible = false ; !@p_mandy && @p_manual endparam SFormula param f_SFormula1 caption = "Initial Formula" default = JLB_NothingSFormula endparam int param n1 caption = "Repeats of Initial Formula" default = 1 min = 0 visible = @f_SFormula1 != JLB_NothingSFormula endparam ; Heading ; Endheading bool param p_ibail caption = "Separate bailout critera?" default = false visible = (@f_SFormula1 != JLB_NothingSFormula) && @n1 > 0 endparam param p_ibType caption = "How to stop" enum = "Z diverges" "Z converges" "Either one" default = 0 visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && @n1 > 0 endparam float param p_idiverge caption = "Initial divergence test" exponential = true default = 1e4 visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 0 || @p_ibType == 2) && @n1 > 0 hint = "Defines how soon an orbit bails out as z gets large." endparam param p_idivtype caption = "Initial divergence type" default = 0 enum = "mod" "real" "imag" "or" "and" "manh" \ "real+imag" "real-imag" "real*imag" "max(real,imag)" "min(real,imag)" visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 0 || @p_ibType == 2) && @n1 > 0 endparam ; float param p_iangle ; caption = "angle" ; default = -45 ; hint = "Distance is from a line at this angle. Angle 0 gives same result as imag, \ ; 90 same as real, 45 same as manr." ; visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 0 || @p_ibType == 2) && @p_idivtype == 7 && @n1 > 0 ; endparam float param p_iangle ; wasn't used before. keep this to avoid error messages default = 0 visible = false endparam float param p_iconverge caption = "Initial convergence test" exponential = true default = 1e-6 visible = (@f_SFormula1 != JLB_NothingSFormula) && @p_ibail && (@p_ibtype == 1 || @p_ibType == 2) && @n1 > 0 hint = "Defines how soon an orbit bails out as z converges to a value. \ With multiple formulas, false convergence is possible." endparam ; Heading ; caption = "End of Initial Formula, start of Main Formula" ; Endheading SFormula param f_SFormula2 caption = "Main Formula" default = JLB_MandelbrotSFormula hint = "Repeat until bailout, convergence, or iteration limit." endparam Heading caption = "Bailout" Endheading param p_bType caption = "How to stop" enum = "Z diverges" "Z converges" "Either one" default = 0 endparam float param p_diverge caption = "Divergence test" exponential = true default = 1e4 visible = @p_btype == 0 || @p_bType == 2 hint = "Defines how soon an orbit bails out as z gets large." endparam param p_divtype caption = "Divergence type" default = 0 enum = "mod" "real" "imag" "or" "and" "manh" \ "real+imag" "real-imag" "real*imag" "max(real,imag)" "min(real,imag)" visible = @p_btype == 0 || @p_bType == 2 endparam float param p_angle ; wasn't used before. keep this to avoid error messages default = 0 visible = false endparam float param p_converge caption = "Convergence test" exponential = true default = 1e-6 visible = @p_btype == 1 || @p_bType == 2 hint = "Defines how soon an orbit bails out as z converges to a value. \ With multiple formulas, false convergence is possible." endparam } ; the State of an iteration for a pixel class State { public: ; constructor initializes the state ; func State(complex z, complex c, int b, int dt, float dv, float angle, float cv) func State(complex z, complex c, int b, int dt, float dv, float cv) pzold = pz = z pc = c bType = b ; 0, 1, or 2 for divergence, convergence, or both divType = dt ; 0 to 8 ; dCos = cos(angle * #pi/180.0) ; dSin = sin(angle * #pi/180.0) dvalue = dv cvalue = cv iters = 0 tooMany = false ; bailed = false endfunc ; after an iteration has calculated a new z, and possibly a new c, update bool func Update(const complex z, const complex c) pzold = pz pz = z pc = c iters = iters + 1 bailed = IsBailedOut(pz) return bailed endfunc bool func IsBailedOut(const complex pz) tooMany = iters >= #maxiter if btype == 3 bailed = toomany return bailed endif bool diverged = false if bType == 0 || bType == 2 float tmp = |pz| if (isNan(tmp) || isInf(tmp)) return true endif float x = real(pz) float y = imag(pz) if divType == 0 ; "mod" diverged = (tmp > dValue) elseif divType == 1 ;"real" diverged = (sqr(x) > dValue) elseif divType == 2 ; "imag" diverged = (sqr(y) > dValue) elseif divType == 3 ; "or" diverged = (sqr(x) > dValue || sqr(y) > dValue) elseif divType == 4 ; "and" diverged = (sqr(x) > dValue && sqr(y) > dValue) elseif divType == 5 ;"manh" diverged = (sqr(abs(x) + abs(y)) > dValue) elseif divType == 6 ; "real+imag" diverged = (sqr(x + y) > dValue) elseif divType == 7 ; "real-imag" diverged = (sqr(x - y) > dValue) elseif divType == 8 ; "real*imag" diverged = (abs(x * y) > dValue) elseif divType == 9 ; "max(real,imag)" if abs(x) >= abs(y) diverged = (sqr(x) > dValue) else diverged = (sqr(y) > dValue) endif elseif divType == 10 ; "min(real,imag)" if abs(x) <= abs(y) diverged = (sqr(x) > dValue) else diverged = (sqr(y) > dValue) endif endif endif bool converged = false if bType == 1 || bType == 2 converged = (|pz - pzold| < cValue) endif bailed = converged || diverged return bailed endfunc complex pz complex pc ; version 1, pixel for M-type, seed for J-type ; version 2, not used (each SFormula has its own) complex pzold ; previous z for testing convergence or for use in formulas int bType ; test divergence, convergence, or both int divType ; type of divergence test ; float dCos ; cosine of angle for divergence test ; float dSin ; sine of angle for divergence test float dValue ; divergence criterion float cValue ; convergence criterion int iters ; number of iterations, often not the same as #numiter bool tooMany ; true if too many iterations bool bailed ; true if diverged or converged } class SFormula(common.ulb:Generic) { ; SFormula base class for use with JLB_SwitchCombo. ; similar to Formula, but uses State public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func SFormula(Generic pparent) Generic.Generic(pparent) endfunc ; @param pz ; @param pc func Init(complex pz, complex pc) endfunc ; @param State ; @return true if done bool func Iterate(State S) return false endfunc default: ; no title, just a base class int param v_SFormula caption = "Version (SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_SFormula < 200 endparam } class JLB_NothingSFormula(SFormula) { ; A do-nothing SFormula, a place-holder when needed. public: ; @param pz ; @param pc bool func Iterate(State S) return S.bailed endfunc default: title = "Do nothing" rating = NotRecommended int param v_NothingzSFormula caption = "Version (JLB_NothingSFormula)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_NothingzSFormula < 100 endparam } class JLB_MandelbrotSFormula(SFormula) { ; The Mandelbrot formula as an SFormula. ; 220213 added the final tweak. Doesn't break old parameter sets. ; 230318 added second power. Doesn't break old parameter sets. public: import "common.ulb" func JLB_MandelbrotSFormula(Generic pparent) SFormula(pparent) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_MandelbrotSFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex znew if (@p_std) ;if @v_MandelbrotSFormula < 201 ;|| @v_MandelbrotSFormula > 201 znew = sqr(pz) + ppc ;else ; znew = pz^@p + ppc ;endif else znew = @a*pz^@p_power + @b*ppc*pz^@p_power2 + @p_a_old*S.pzold if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform default: title = "Mandelbrot" rating = NotRecommended int param v_MandelbrotSFormula caption = "Version (Mandelbrot_SFormula)" default = 220318 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_MandelbrotSFormula < 220318 endparam bool param p_std caption = "Standard" default = true endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_MandelbrotSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.5,0.5) visible = @v_MandelbrotSFormula > 100 && !@p_Mtype endparam heading caption = "z_new = z^2 + c" visible = @p_std ;&& @v_MandelbrotSFormula <= 201 endheading ; heading ; caption = "z_new = z^p + c" ; visible = @p_std && @v_MandelbrotSFormula > 201 ; endheading heading caption = "z_new = a1*z^p + b*c*z^q + a2*z_prev" visible = !@p_std endheading ; complex param p ; caption = "p" ; default = 2 ; visible = @p_std && @v_MandelbrotSFormula >= 201 ; && @v_MandelbrotSFormula < 220318 ; endparam complex param a caption = "a1" default = 1 visible = !@p_std endparam complex param p_power caption = "p" default = (2,0) visible = !@p_std endparam complex param b caption = "b" default = 1 visible = !@p_std endparam complex param p_power2 caption = "q" default = 0 visible = !@p_std endparam complex param p_a_old caption = "a2" default = 0.0 visible = !@p_std endparam heading caption = "Tweak after each iteration" visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 && !@p_std selectable = false endparam } class JLB_MandelbarSFormula(SFormula) { ; The Mandelbar formula as a SFormula. public: import "common.ulb" func JLB_MandelbarSFormula(Generic pparent) SFormula(pparent) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_MandelbarSFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = conj(S.pz) complex znew if (@p_std) znew = sqr(pz) + ppc else znew = @a*pz^@p_power + @b*ppc + @p_a_old*S.pzold if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform default: title = "Mandelbar" rating = Rnotecommended int param v_MandelbarSFormula caption = "Version (Mandelbar_SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_MandelbarSFormula < 200 endparam bool param p_std caption = "Standard" hint = "Standard: z_new = sqr(conj(z)) + c" default = true endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_MandelbarSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_MandelbarSFormula > 100 && !@p_Mtype endparam heading caption = "z_new = conj(z)^2 + c" visible = @p_std endheading heading caption = "z_new = a1*conj(z)^p + b*c + a2*z_prev" visible = !@p_std endheading complex param a caption = "Mandelbar a1" default = 1 visible = !@p_std endparam complex param p_power caption = "Mandelbar p" default = (2,0) visible = !@p_std endparam complex param b caption = "Mandelbar b" default = 1 visible = !@p_std endparam complex param p_a_old caption = "Mandelbar a2" default = 0.0 visible = !@p_std endparam heading caption = "Tweak after each iteration" visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam } class JLB_MandelVar2SFormula(SFormula) { ; The MandelVar2 formula as a SFormula. public: import "common.ulb" func JLB_MandelVar2SFormula(Generic pparent) SFormula(pparent) if @addT > 0 finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_Mandelvar2SFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz float x = real(pz) float y = imag(pz) float x2 = sqr(x) float xy = x*y float y2 = sqr(y) complex znew = (@a_x2*x2 + @a_xy*xy + @a_y2*y2) + flip(@b_x2*x2 + @b_xy*xy + @b_y2*y2) + ppc if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif S.Update(znew, S.pc) return S.bailed endfunc protected: UtilityTransform finalTransform complex ppc default: title = "MandelVar2" rating = NotRecommended int param v_MandelVar2SFormula caption = "Version (MandelVar2_SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_MandelVar2SFormula < 200 endparam heading caption = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)" endheading bool param p_Mtype caption = "M-type?" default = true visible = @v_Mandelvar2SFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_Mandelvar2SFormula > 100 && !@p_Mtype endparam complex param a_x2 caption = "a_x2" default = 1 ;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)" endparam complex param a_xy caption = "a_xy" default = 0 ;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)" endparam complex param a_y2 caption = "a_y2" default = -1 ;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)" endparam complex param b_x2 caption = "b_x2" default = 0 ;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)" endparam complex param b_xy caption = "b_xy" default = 2 ;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)" endparam complex param b_y2 caption = "b_y2" default = 0 ;hint = "z_new = (a_x2*x^2 + a_xy*x*y + a_y2*y^2) + i*(b_x2*x^2 + b_xy*x*y + b_y2*y^2)" endparam heading caption = "Tweak after each iteration" endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam } class JLB_PeacockSFormula(SFormula) { ; The Peacock formula as a SFormula. ; July 2021 added pzold option; changed parameter names for consistency with other Sformulas. public: import "common.ulb" func JLB_PeacockSFormula(Generic pparent) SFormula(pparent) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_PeacockSFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex znew if (@p_std) znew = pz + @a * (pz^@p_power - 1.0)/(pz^@p_power + 1.0) + ppc else if @v_PeacockSFormula < 210707 znew = pz + @a * (@f(pz)^@p_power - @b)/(@f(pz)^@p_power + @b) + @a2*ppc else znew = pz + @aa1 * (@f(pz)^@p_power - @aa2)/(@f(pz)^@p_power + @aa2) \ + @bb*ppc + @aa3*S.pzold endif if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform default: title = "Peacock" rating = NotRecommended int param v_PeacockSFormula caption = "Version (Peacock_SFormula)" default = 210707 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_PeacockSFormula < 210707 endparam bool param p_std caption = "Standard" default = true endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_PeacockSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_PeacockSFormula > 100 && !@p_Mtype endparam heading caption = "z_new = z + (z^p-1)/(z^p+1) + c" visible = @p_std endheading heading caption = "z_new = z + a1*(f(z)^p-b)/(f(z)^p+b) + a2*c" visible = !@p_std && @v_PeacockSFormula < 210707 endheading heading caption = "z_new = z + a1*(f(z)^p-a2)/(f(z)^p+a2) + b*c + a3*z_prev" visible = !@p_std && @v_PeacockSFormula >= 210707 endheading complex param p_power caption = "Peacock: p" default = 2 endparam func f caption = "Peacock: f" default = sqr() visible = !@p_std endfunc complex param a caption = "Peacock: a1" default = 1 visible = !@p_std && @v_PeacockSFormula < 210707 endparam complex param a2 caption = "Peacock: a2" default = 1 visible = !@p_std && @v_PeacockSFormula < 210707 endparam complex param b caption = "Peacock: b" default = 1 visible = !@p_std && @v_PeacockSFormula < 210707 endparam ; new versions complex param aa1 caption = "Peacock: a1" default = 1 visible = !@p_std && @v_PeacockSFormula >= 210707 endparam complex param aa2 caption = "Peacock: a2" default = 1 visible = !@p_std && @v_PeacockSFormula >= 210707 endparam complex param bb caption = "Peacock: b" default = 1 visible = !@p_std && @v_PeacockSFormula >= 210707 endparam complex param aa3 caption = "Peacock: a3" default = 1 visible = !@p_std && @v_PeacockSFormula >= 210707 endparam heading caption = "Tweak after each iteration" visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 && !@p_std selectable = false endparam } class JLB_PhoenixSFormula(SFormula) { ; The Phoenix formula as a SFormula. public: import "common.ulb" func JLB_PhoenixSFormula(Generic pparent) SFormula(pparent) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex znew if (@p_std) znew = @a1 * pz^@p1 + @a2 * ppc * pz^@p2 + @a_old * S.pzold else znew = @a1 * @f1(pz)^@p1 + @a2 * ppc * @f2(pz)^@p2 + @a_old * S.pzold if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform default: title = "Phoenix" rating = NotRecommended int param v_PhoenixSFormula caption = "Version (Phoenix_SFormula)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_PhoenixSFormula < 100 endparam bool param p_std caption = "Standard" default = true endparam bool param p_Mtype caption = "M-type?" default = true endparam complex param p_seed caption = "Seed for J-type" default = (0.56667,0) ; to match Phoenix in Standard.ufm visible = !@p_Mtype endparam heading caption = "z_new = a1*z^p1 + a2*c*z^p2 + a3*z_old" visible = @p_std endheading heading caption = "z_new = a1*f1(z)^p1 + a2*c*f2(z)^p2 + a3*z_old" visible = !@p_std endheading func f1 caption = "f1" default = sin() visible = !@p_std endfunc complex param p1 caption = "p1" default = (2,0) endparam complex param a1 caption = "a1" default = 1 endparam func f2 caption = "f2" default = ident() visible = !@p_std endfunc complex param p2 caption = "p2" default = (0,0) endparam complex param a2 caption = "a2" default = 1 endparam complex param a_old caption = "a3" default = (0.5, 0) endparam heading caption = "Tweak after each iteration" endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam } class JLB_DualSFormula(SFormula) { ; DualSFormula combines two formulas ; first n1 calls to formula 1 ; then n2 calls to formula 2 public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_DualSFormula(Generic pparent) SFormula.SFormula(pparent) m_SFormula1 = new @f_SFormula1(this) m_SFormula2 = new @f_SFormula2(this) endfunc func Init(complex pz, complex pc) m_SFormula1.Init(pz, pc) m_SFormula2.Init(pz, pc) count = 0 n1 = @p_n1 ; both have min - 0 n2 = @p_n2 if n1 + n2 == 0, n1 = 1, endif endfunc bool func Iterate(State S) if S.bailed return true endif if @v_DualSFormula < 200 ; old version updates #numiter after all done int i i = 0 while (i < @p_n1) if m_SFormula1.Iterate(S) return true endif i = i + 1 endwhile i = 0 while (i < @p_n2) if m_SFormula2.Iterate(S) return true endif i = i + 1 endwhile else ; new version updates #numiter each time if count < n1 if m_SFormula1.Iterate(S) return true endif else if m_SFormula2.Iterate(S) return true endif endif count = count + 1 if count >= n1 + n2 ; only gets to equality count = 0 n1 = n1 + @delta_n1 n2 = n2 + @delta_n2 if n1 < 0, n1 = 0, endif if n2 < 0, n2 = 0, endif if n1 + n2 == 0, n1 = 1, endif endif endif return false endfunc protected: SFormula m_SFormula1 SFormula m_SFormula2 int count int n1 int n2 default: rating = NotRecommended title = "Two Formulas" int param v_DualSFormula caption = "Version (DualSFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_DualSFormula < 200 endparam heading text = "Do n1 iterations of Formula 1, then n2 iterations of Formula2, then optionally \ change n1 and n2." endheading SFormula param f_SFormula1 caption = "Formula 1" default = JLB_Gnarl3SFormula endparam int param p_n1 caption = "Initial n1" min = 0 default = 1 endparam heading endheading SFormula param f_SFormula2 caption = "Formula 2" default = JLB_MandelbrotSFormula endparam int param p_n2 caption = "Initial n2" min = 0 default = 1 endparam heading endheading int param delta_n1 caption = "Change in n1" default = 0 endparam int param delta_n2 caption = "Change in n2" default = 0 endparam } class JLB_ComboSFormula(SFormula) { ; This does two or three SFormulas and combines them ; with one of the operators +, -, *, /, ^, (). The latter means use as argument to the previous function. ; This allows formulas such as z = (f1 + f2)/f3 + c ; or z = f1(f2(f3())) + c public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_ComboSFormula(Generic pparent) SFormula.SFormula(pparent) m_SFormula1 = new @f_SFormula1(this) m_SFormula2 = new @f_SFormula2(this) if @order3 > 0 m_SFormula3 = new @f_SFormula3(this) endif m_Combine = new Combine() endfunc func Init(complex pz, complex pc) m_SFormula1.Init(pz, pc) m_SFormula2.Init(pz, pc) if @order3 > 0 m_SFormula3.Init(pz, pc) endif endfunc ; @param pz ; @param pc ; @return new pz bool func Iterate(State S) complex pz = S.pz complex pc = S.pc ; used only to restore in case one of the subsidiary ; User Transform formulas changes it complex t1 complex t2 complex t3 if (S.bailed) return true endif if @order3 == 0 ;"f1 op f2" m_SFormula2.Iterate(S) if @op1a == "( )" ; f1(f2(pz)) m_SFormula1.Iterate(S) t1 = S.pz else ; f1(pz) op1 f2(pz) t2 = S.pz S.pz = pz, S.pc = pc m_SFormula1.Iterate(S) t1 = S.pz t1 = m_Combine.go(t1, @op1a, t2) endif elseif @order3 == "f1 op1 (f2 op2 f3)" if @op2a == "( )" ; f1(pz) op1 f2(f3(pz)) m_SFormula3.Iterate(S) t3 = S.pz m_SFormula2.Iterate(S) t2 = S.pz if @op1 == "( )" ; f1(f2(f3(pz))) S.pz = t2 m_SFormula1.Iterate(S) t1 = S.pz else ; f1(pz) op1 f2(f3(pz)) S.pz = pz, S.pc = pc m_SFormula1.Iterate(S) t1 = S.pz t1 = m_Combine.go(t1, @op1, t2) endif else m_SFormula2.Iterate(S) t2 = S.pz S.pz = pz, S.pc = pc m_SFormula3.Iterate(S) t3 = S.pz t2 = m_Combine.go(t2, @op2a, t3) if @op1 == "( )" ; f1(f2(pz) op2a f3(pz)) S.pz = pz, S.pc = pc m_SFormula1.Iterate(S) t1 = S.pz else S.pz = pz, S.pc = pc m_SFormula1.Iterate(S) t1 = S.pz t1 = m_Combine.go(t1, @op1, t2) endif endif else ;@order3 == "(f1 op1 f2) op2 f3" ; @op3a == "()" not allowed with this ordering m_SFormula2.Iterate(S) t2 = S.pz if @op1 == "( )" ; (f1(f2(pz))) op2b f3(pz) m_SFormula1.Iterate(S) t1 = S.pz else m_SFormula1.Iterate(S) t1 = S.pz t1 = m_Combine.go(t1, @op1, t2) endif S.pz = pz, S.pc = pc m_SFormula3.Iterate(S) t3 = S.pz t1 = m_Combine.go(t1, @op2b, t3) endif complex znew = @mult * t1 if @v_ComboSFormula >= 201 && @addc ;znew = znew + @cfac*S.pc complex cc = #pixel if !@p_Mtype cc = @p_seed endif znew = znew + @cfac*cc endif S.Update(znew, S.pc) return S.bailed endfunc protected: SFormula m_SFormula1 SFormula m_SFormula2 SFormula m_SFormula3 Combine m_Combine default: rating = NotRecommended title = "Combo" int param v_ComboSFormula caption = "Version (ComboSFormula)" default = 201 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ComboSFormula < 201 endparam param order3 caption = "How to combine" default = 0 enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3" ; hint = "Order of combining can make a big difference!" endparam heading caption = "f1" endheading SFormula param f_SFormula1 caption = "Formula 1" default = JLB_FuncSFormula endparam heading endheading param op1 caption = "Operator 1" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine Formula values." visible = @order3 > 0 endparam param op1a caption = "Operator for Combo" enum = "+" "-" "*" "/" "^" "( )" default = 5 hint = "How to combine Formula values." visible = @order3 == 0 endparam ; heading ; endheading heading caption = "f2" endheading SFormula param f_SFormula2 default = JLB_LambdaSFormula caption = "Formula 2" endparam param op2a caption = "Operator 2 for Combo" enum = "+" "-" "*" "/" "^" "( )" default = 2 hint = "How to combine Formula values." visible = (@order3 == 1) endparam param op2b caption = "Operator 2 for Combo" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default = 2 hint = "How to combine Formula values." visible = (@order3 == 2) endparam heading caption = "f3" visible = @order3 > 0 endheading SFormula param f_SFormula3 default = JLB_FuncSFormula caption = "Formula 3" visible = @order3 > 0 endparam heading caption = "Final" endheading complex param mult caption = "Combo multiplier" default = (1,0) visible = @v_ComboSFormula > 100 endparam bool param addc caption = "Add c (pixel or seed)?" default = true visible = @v_ComboSFormula >= 201 endparam bool param p_Mtype caption = "M-type? (add pixel)" default = true visible = @v_ComboSFormula >= 201 && @addc hint = "This is used only for the final 'Add c'" endparam complex param p_seed caption = "Seed" default = (0.3, 0) visible = @v_ComboSFormula >= 201 && @addc && !@p_Mtype hint = "This is used only for the final 'Add c'" endparam complex param cfac caption= "Multiplier of c" default = 1 visible = false ;@addc && @v_ComboSFormula >= 201 endparam heading caption = "End of Combo" endheading } class JLB_FuncSFormula(SFormula) {; Early version, z = a1*f(a2*z) + b*c. ; Later version, z = a1*f(a2*z)^p + b*c. ; July 2021 added a3*z_prev, as in Mandelbrot public: import "common.ulb" func JLB_FuncSFormula(Generic pparent) SFormula(pparent) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_FuncSFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex znew if @p_std znew = @f(pz) + ppc else znew = @a1*@f(@a2*pz)^@p + @b*ppc + @a3*S.pzold if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform default: rating = NotRecommended title = "Function" int param v_FuncSFormula caption = "Version (Func_SFormula)" default = 220626 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_FuncSFormula < 220626 endparam bool param p_std caption = "Standard?" default = true ;visible = @v_FuncSFormula >= 220626 endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_FuncSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_funcSFormula > 100 && !@p_Mtype endparam heading caption = "z_new = f(z) + c" visible = @p_std && @v_FuncSFormula >= 220626 endheading heading caption = "z_new = a1*f(a2*z)^p + b*c + a3*z_prev" visible = @v_FuncSFormula >= 201 && !@p_std endheading heading caption = "z_new = a1*f(a2*z) + b*c" visible = @v_FuncSFormula < 201 endheading func f caption = "Function: f" default = cos() endfunc complex param a1 caption = "Function: a1" default = 1 visible = !@p_std endparam complex param a2 caption = "Function: a2" default = 1 visible = !@p_std endparam complex param p caption = "Function: p" default = 1 visible = @v_FuncSFormula >= 201 && !@p_std endparam complex param b caption = "Function b" default = 1 visible = !@p_std endparam complex param a3 caption = "Function: a3" default = 0 visible = @v_FuncSFormula >= 201 && !@p_std endparam heading caption = "Tweak after each iteration" visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 && !@p_std selectable = false endparam } class JLB_PowerSFormula(SFormula) { ; 05 June 2021 added UserTransform public: import "common.ulb" func JLB_PowerSFormula(Generic pparent) SFormula.SFormula(pparent) m_Combine = new Combine() m_Transform = new @f_T(this) m_SFormula = new @f_SFormula(this) if @addT > 0 ;&& !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) m_SFormula.Init(pz, pc) ppc = #pixel if @v_PowerSFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @return the new pz bool func Iterate(State S) bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex zz if @v_PowerSFormula < 210627 zz = S.pz - @a2 else zz = S.pz - @a endif if @p_base == 1 zz = @f(zz) elseif @p_base == 2 zz = m_Transform.Iterate(zz) endif complex t1 if @v_PowerSFormula < 210627 t1 = @a0 + @a1 * zz^@p_power else t1 = zz^@p_power endif complex t2 = @b * ppc complex znew = m_Combine.go(t1, @op, t2) ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc protected: Combine m_Combine UserTransform m_Transform SFormula m_SFormula complex ppc UtilityTransform finalTransform default: rating = NotRecommended title = "Power" int param v_PowerSFormula caption = "Version (Power_SFormula)" default = 210627 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_PowerSFormula < 210627 endparam ; bool param p_std ; caption = "Standard?" ; default = true ; endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_PowerSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_PowerSFormula > 100 && !@p_Mtype endparam heading caption = "z_new = (a0 + a1*(z-a2)^p) op b*c" visible = @p_base == 0 && @v_PowerSFormula < 210627 endheading heading caption = "z_new = (a0 + a1*f(z-a2)^p) op b*c" visible = @p_base > 0 && @v_PowerSFormula < 210627 endheading heading caption = "z_new = (z-a)^p op b*c" visible = @p_base == 0 && @v_PowerSFormula >= 210627 endheading heading caption = "z_new = f(z-a)^p op b*c" visible = @p_base > 0 && @v_PowerSFormula >= 210627 endheading param p_base caption = "Power of" enum = "z" "Built-in function of z" "Transform of z" "SFormula" default = 0 endparam func f caption = "f Built-in function" default = sin() ;hint = "Function" visible = @p_base == 1 endfunc UserTransform param f_T caption = "f Transform" default = JLB_MoebiusUserTransform visible = @p_base == 2 endparam SFormula param f_SFormula caption = "f SFormula" default = JLB_FuncSFormula visible = @p_base == 3 endparam complex param a0 caption = "Power: a0" default = 0 visible = @v_PowerSFormula < 210627 endparam complex param a1 caption = "Power: a1" default = 1 visible = @v_PowerSFormula < 210627 endparam complex param a2 caption = "Power: a2" default = 0 visible = @v_PowerSFormula < 210627 endparam complex param a caption = "Power: a" default = 0 visible = @v_PowerSFormula >= 210627 endparam complex param p_power caption = "Power: p" default = 2 endparam param op caption = "Power: op" enum = "+" "-" "*" "/" "^" default = 0 endparam complex param b caption = "Power: b" default = 1 endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ; && !@p_std selectable = false endparam } class JLB_PolynomialSFormula(SFormula) { public: import "common.ulb" func JLB_PolynomialSFormula(Generic pparent) SFormula(pparent) if @p_base == 2 m_Transform = new @zT(this) endif if @addT > 0 ;&& !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_PolynomialSFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @return the new pz bool func Iterate(State S) bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz if @p_base == 1 pz = @f(pz) elseif@p_base == 2 pz = m_Transform.Iterate(pz) endif complex zz = pz complex z_calc = @a0 if @p_order >= 1 z_calc = z_calc + @a1 * zz if @p_order >= 2 zz = zz * pz z_calc = z_calc + @a2 * zz if @p_order >= 3 zz = zz * pz z_calc = z_calc + @a3 * zz if @p_order >= 4 zz = zz * pz z_calc = z_calc + @a4 * zz if @p_order >= 5 zz = zz * pz z_calc = z_calc + @a5 * zz if @p_order >= 6 zz = zz * pz z_calc = z_calc + @a6 * zz endif endif endif endif endif endif ; return @p_a_calc*z_calc + @p_a_old*pz + ppc complex znew = z_calc + @b*ppc + @d * S.pzold ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UserTransform m_Transform UtilityTransform finalTransform default: rating = NotRecommended title = "Polynomial" int param v_PolynomialSFormula caption = "Version (Polynomial_SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_PolynomialSFormula < 200 endparam ; bool param p_std ; caption = "Standard?" ; default = true ; endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_PolynomialSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_PolynomialSFormula > 100 && !@p_Mtype endparam heading caption = "z_calc = a0 + a1*z + a2*z^2 + ... + b*c + d*z_prev" visible = @p_base == 0 endheading heading caption = "z_calc = a0 + a1*f(z) + a2*f(z)^2 + ... + b*c + d*z_prev" visible = @p_base == 1 endheading heading caption = "z_calc = a0 + a1*T(z) + a2*T(z)^2 + ... + b*c + d*z_prev" visible = @p_base == 2 endheading param p_base caption = "Polynomial in" enum = "z" "F(z)" "T(z)" default = 0 endparam func f caption = "F (built-in function)" default = sin() hint = "Function" visible = @p_base == 1 endfunc UserTransform param zT caption = "T (Transform)" default = JLB_MoebiusUserTransform visible = @p_base == 2 endparam int param p_order caption = "Max power" default = 2 min = 0 max = 6 endparam complex param a0 caption = "a0" default = 0 endparam complex param a1 caption = "a1" default = 1 visible = @p_order >= 1 endparam complex param a2 caption = "a2" default = 1 visible = @p_order >= 2 endparam complex param a3 caption = "a3" default = 1 visible = @p_order >= 3 endparam complex param a4 caption = "a4" default = 1 visible = @p_order >= 4 endparam complex param a5 caption = "a5" default = 1 visible = @p_order >= 5 endparam complex param a6 caption = "a6" default = 1 visible = @p_order >= 6 endparam complex param b caption = "b" default = 1 endparam complex param d caption = "d" default = 0 endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } class JLB_LambdaSFormula(SFormula) { ;The Lambda formula as a SFormula, generalized. public: import "common.ulb" func JLB_LambdaSFormula(Generic pparent) SFormula(pparent) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_LambdaSFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz if !@p_std && (@p_base == "func(z)") pz = @f(pz) endif complex znew if @v_LambdaSFormula < 200 if (pz == (0,0)) || (pz == (1,0)) ; avoid unproductive starts pz = #pixel endif endif if (@p_std) znew = ppc * pz * (1 - pz) else complex z_calc = ppc * (pz^@p_power1) * ((@b-pz)^@p_power) znew = @p_a_calc * z_calc + @p_a_old * pz if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform default: rating = NotRecommended title = "Lambda" int param v_LambdaSFormula caption = "Version (Lambda_SFormula)" default = 201 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_LambdaSFormula < 201 endparam bool param p_std caption = "Standard?" default = true endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_LambdaSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (1.25, 0) visible = @v_LambdaSFormula > 100 && !@p_Mtype endparam heading caption = "z_new = c*z*(1-z)" visible = @p_std endheading heading caption = "z_new = a1*c* z^p1 * (1-z)^(p2-1) + a2*z" visible = !@p_std && (@v_LambdaSFormula == 200) endheading heading caption = "z_new = a1* (c * z^p1 * (b-z)^p2) + a2*z" visible = !@p_std && (@p_base == 0) && (@v_LambdaSFormula > 200) endheading heading caption = "z_new = a1* (c * f(z)^p1 * (b-f(z))^p2) + a2*z" visible = !@p_std && (@p_base == 1) && (@v_LambdaSFormula > 200) endheading param p_base caption = "Power of" enum = "z" "func(z)" default = 0 visible = !@p_std endparam func f caption = "Lambda f" default = sin() visible = !@p_std && @p_base == 1 endfunc complex param p_a_calc caption = "Lambda a1" default = 1.0 visible = !@p_std endparam complex param p_power1 caption = "Lambda p1" default = 1 visible = !@p_std endparam complex param b caption = "Lambda b" default = 1 visible = !@p_std endparam complex param p_power caption = "Lambda p2" default = 1 visible = !@p_std endparam complex param p_a_old caption = "Lambda a2" default = 0.0 visible = !@p_std endparam heading caption = "Tweak after each iteration" visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 && !@p_std selectable = false endparam } ; Calculate function f(z)^n and its first two derivatives. ; Derivatives courtesy of https://www.derivative-calculator.net/ class Deriv { public: ; constructor initializes the state func Deriv(int k) kind = k ; don't break old version endfunc func Set_k(int k) kind = k endfunc func pow_calc(complex z, complex n) complex c = 0 complex s = 0 complex q = 0 complex t = 0 if kind == 0 ; z f = z^n fp = n*z^(n-1) fpp = n*(n-1)*z^(n-2) elseif kind == 1 ; sin(z) s = sin(z) c = cos(z) f = s^n fp = n*c*s^(n-1) fpp = n*(n-1)*c*c*s^(n-2) - n*f elseif kind == 2 ; sinh(z) s = sinh(z) c = cosh(z) f = s^n fp = n*c*s^(n-1) fpp = n*(n-1)*c*c*s^(n-2) + n*f elseif kind == 3 ; asin(z) s = asin(z) q = sqrt(1-z*z) f = s^n fp = n*s^(n-1)/q fpp = n*(n-1)*s^(n-2)/q^2 + n*z*s^(n-1)/q^3 elseif kind == 4 ; asinh(z) s = asinh(z) q = sqrt(1+z*z) f = s^n fp = n*s^(n-1)/q fpp = n*(n-1)*s^(n-2)/q^2 - n*z*s^(n-1)/q^3 elseif kind == 5 ; cos(z) s = sin(z) c = cos(z) f = c^n fp = -n*s*c^(n-1) fpp = n*(n-1)*s*s*c^(n-2) - n*f elseif kind == 6 ; cosh(z) s = sinh(z) c = cosh(z) f = c^n fp = n*s*c^(n-1) fpp = n*(n-1)*s*s*c^(n-2) + n*f elseif kind == 7 ; acos(z) c = acos(z) q = sqrt(1-z*z) f = c^n fp = -n*c^(n-1)/q fpp = n*(n-1)*c^(n-2)/q^2 - n*z*c^(n-1)/q^3 elseif kind == 8 ; acosh(z) c = acosh(z) q = sqrt(z*z-1) f = c^n fp = n*c^(n-1)/q fpp = n*(n-1)*c^(n-2)/q^2 - n*z*c^(n-1)/q^3 elseif kind == 9 ; tan(z) t = tan(z) s = 1/cos(z) ;sec(z) f = t^n fp = n*s*s*t^(n-1) fpp = n*(n-1)*s*s*s*s*t^(n-2) + 2*n*s*s*f elseif kind == 10 ; tanh(z) t = tanh(z) s = 1/cosh(z) ;sech(z) f = t^n fp = n*s*s*t^(n-1) fpp = n*(n-1)*s*s*s*s*t^(n-2) - 2*n*s*s*f elseif kind == 11 ; atan(z) t = atan(z) q = 1 + z*z f = t^n fp = n*t^(n-1)/q fpp = n*(n-1)*t^(n-2)/q^2 - 2*n*z*t^(n-1)/q^2 elseif kind == 12 ; atanh(z) t = atanh(z) q = 1 - z*z f = t^n fp = n*t^(n-1)/q fpp = n*(n-1)*t^(n-2)/q^2 + 2*n*z*t^(n-1)/q^2 elseif kind == 13 ;cotan(z) c = cotan(z) s = 1/sin(z) ;csq(z) f = c^n fp = -n*s*s*c^(n-1) fpp = n*(n-1)*s*s*s*s*c^(n-2) + 2*n*s*s*f elseif kind == 14 ;cotanh(z) c = cotanh(z) s = 1/sinh(z) ;csch (z) f = c^n fp = -n*s*s*c^(n-1) fpp = n*(n-1)*s*s*s*s*c^(n-2) + 2*n*s*s*f elseif kind == 15 ; log(z) q = log(z) f = q^n fp = n*q^(n-1)/z fpp = ( n*(n-1)*q^(n-2) - n*q^(n-1) ) / z^2 elseif kind == 16 ; exp(z) f = exp(n*z) fp = n*f fpp = n*n*f endif endfunc int kind complex f complex fp complex fpp } class JLB_PolyNewtonSFormula(SFormula) { ; Iteration of polynomial(z) - c = 0 by relaxed Newton's method or other ; iterative method. public: import "common.ulb" func JLB_PolyNewtonSFormula(Generic pparent) SFormula(pparent) if (@p_poly_type == "Polynomial") m_a[0] = @p_a0, m_a[1] = @p_a1, m_a[2] = @p_a2, m_a[3] = @p_a3 m_a[4] = @p_a4, m_a[5] = @p_a5, m_a[6] = @p_a6, m_a[7] = @p_a7 m_a[8] = @p_a8, m_a[9] = @p_a9, m_a[10] = @p_a10 m_a[@p_degree+1] = 0 int i = 0 while (i <= @p_degree) m_ap[i] = (i+1)*m_a[i+1] ; f' - coefficient of z^i m_app[i] = (i+2)*(i+1)*m_a[i+2] ; f" - coefficient of z^i i = i + 1 endwhile endif D = new Deriv(@p_kind) if @p_poly_type == 0 n = @p_degree else n = @p_power endif if @p_iter_type == "Type 3" n = 2 endif if @addT > 0 ;&& !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_PolyNewtonSFormula > 100 && !@p_Mtype ppc = - @p_seed ; to be like that in Standard.ufm endif endfunc ; @param pz ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex znew complex f complex fp complex fpp = 0 ; avoid compiler warning if @v_PolyNewtonSFormula < 200 if pz == (0,0) ; avoid unproductive starts pz = #pixel endif endif int i if (@p_poly_type == "Polynomial") ; Solving F(z) = 0 D.Set_k(@p_kind) D.pow_calc(pz, 1) complex fz = D.f complex fzp = D.fp complex fzpp = D.fpp i = @p_degree f = m_a[i] while (i > 0) i = i - 1 f = m_a[i] + fz * f endwhile f = f + @b*ppc ; df/dz i = @p_degree - 1 complex sum1 = m_ap[i] while (i > 0) i = i - 1 sum1 = m_ap[i] + fz * sum1 endwhile fp = fzp * sum1 if (@p_iter_type > 0) ; d2f/dz2 i = @p_degree - 2 complex sum2 = m_app[i] while (i > 0) i = i - 1 sum2 = m_app[i] + fz * sum2 endwhile fpp = fzpp * sum1 + fzp * fzp * sum2 endif else;if (@p_poly_type == "Power") D.Set_k(@p_kind) D.pow_calc(pz, @p_power) f = D.f fp = D.fp fpp = D.fpp D.Set_k(@p_kind2) D.pow_calc(pz, @p_power2) f = f + @a*D.f + @b*ppc fp = fp + @a*D.fp fpp = fpp + @a*D.fpp endif if (@p_iter_type == "Newton") znew = pz - @step * f / fp elseif (@p_iter_type == "Type 1") ; Halley approx. znew = pz - @step * (f/fp)*(1 + @p_alpha*f*fpp/(2*fp*fp)) elseif (@p_iter_type == "Type 2") ; Halley's method znew = pz - @step * (f/fp) / ( 1 - @p_alpha*f*fpp/(2*fp*fp)) else;if (@p_iter_type == "Type 3") ; Laguerre ; see https://mathworld.wolfram.com/LaguerresMethod.html ; G = fp/f, H = G^2-fpp/f ; znew = z - n/max{G+-sqrt[(n-1)(nH-G^2)]} ; Halley's "irrational method" sets n=2 ; Laguerre sets n=polynomial degree, alpha = 1 ; complex root = sqrt(1-@p_alpha*2*f*fpp/(fp*fp)) complex root = sqrt((n-1)*(n-1-@p_alpha*n*f*fpp/(fp*fp))) complex d1 = 1 + root complex d2 = 1 - root if (|d1| < |d2|), d1 = d2, endif znew = pz - @step * 2*(f/fp) / d1 endif ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex m_a[12] ; coefficients of polynomial complex m_ap[12] ; coefficients of first derivative of polynomial complex m_app[12] ; coefficients of second derivative of polynomial Deriv D complex n ; real for polynomial type; complex for powers of functions complex ppc UtilityTransform finalTransform default: title = "Poly Newton" rating = NotRecommended int param v_PolyNewtonSFormula caption = "Version (PolyNewton_SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_PolyNewtonSFormula < 200 endparam ; bool param p_std ; caption = "Standard?" ; default = true ; endparam bool param p_Mtype caption = "M-type (c = pixel)?" default = true visible = @v_PolyNewtonSFormula > 100 endparam complex param p_seed caption = "J-type, c =" default = (1, 0) visible = @v_PolyNewtonSFormula > 100 && !@p_Mtype endparam heading caption = "Solve a0 + a1*f(z) + a2*f(z)^2 + ... - b*c = 0" visible = @p_poly_type == 0 endheading heading caption = "Solve f(z)^p + a*g(z)^q - b*c = 0" visible = @p_poly_type == 1 endheading param p_poly_type caption = "Function type" enum = "Polynomial" "Powers" default = 0 endparam ; first function param p_kind caption = "f" enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \ "cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \ "tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \ "log(z)" "exp(z)" default = 1 visible = @v_PolyNewtonSFormula > 100 ; && @p_poly_type == 1 endparam int param p_degree caption = "Max power (<=10)" default = 3 min = 2 max = 10 visible = (@p_poly_type == 0) endparam heading caption = "Coeffients" visible = (@p_poly_type == 0) endheading complex param p_a0 caption = "a0 = constant coef" default = (1,0) visible = (@p_poly_type == 0) endparam complex param p_a1 caption = "a1 = degree 1 coef" default = (1,0) visible = (@p_poly_type == 0) endparam complex param p_a2 caption = "a2 = degree 2 coef" default = (1,0) visible = (@p_poly_type == 0) endparam complex param p_a3 caption = "a3 = degree 3 coef" default = (1,0) visible = (@p_degree >= 3) && (@p_poly_type == 0) endparam complex param p_a4 caption = "a4 = degree 4 coef" default = (1,0) visible = (@p_degree >= 4) && (@p_poly_type == 0) endparam complex param p_a5 caption = "a5 = degree 5 coef" default = (1,0) visible = (@p_degree >= 5) && (@p_poly_type == 0) endparam complex param p_a6 caption = "a6 = degree 6 coef" default = (1,0) visible = (@p_degree >= 6) && (@p_poly_type == 0) endparam complex param p_a7 caption = "a7 = degree 7 coef" default = (1,0) visible = (@p_degree >= 7) && (@p_poly_type == 0) endparam complex param p_a8 caption = "a8 = degree 8 coef" default = (1,0) visible = (@p_degree >= 8) && (@p_poly_type == 0) endparam complex param p_a9 caption = "a9 = degree 9 coef" default = (1,0) visible = (@p_degree >= 9) && (@p_poly_type == 0) endparam complex param p_a10 caption = "a10 = degree 10 coeff" default = (1,0) visible = (@p_degree >= 10) && (@p_poly_type == 0) endparam complex param p_power caption = "p" default = (3,0) visible = (@p_poly_type == 1) endparam ; second function complex param a caption = "a" default = 1 visible = (@p_poly_type == 1) endparam param p_kind2 caption = "g" enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \ "cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \ "tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \ "log(z)" "exp(z)" default = 0 visible = @v_PolyNewtonSFormula > 100 && @p_poly_type == 1 endparam complex param p_power2 caption = "q" default = (2,0) visible = (@p_poly_type == 1) endparam complex param b caption = "b" default = 1 endparam heading endheading param p_iter_type caption = "Iteration type" enum = "Newton" "Type 1" "Type 2" "Type 3" ;"Type 4" default = 0 hint = "Newton is the usual, using only the first derivative. \ The other types also use the second derivative. \ Type 1 is Householder iteration; type 2 is Halley's iteration; \ type 3 is Halley's irrational iteration; \ type 4 is Laguerre's method for polynomials (all if alpha = 1)." endparam complex param p_alpha caption = "alpha" default = (1,0) ; hint = "Nonstandard values may not allow convergence, but can give \ ; interesting shapes." visible = (@p_iter_type > 0) endparam param step caption = "Step size" default = (1,0) ; hint = "Nonstandard values may not allow \ ; convergence, but can give interesting shapes." endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } class JLB_UXSFormula(SFormula) { ; an SFormula that calls a UserTransform public: import "common.ulb" func JLB_UXSFormula(Generic pparent) SFormula.SFormula(pparent) m_UX = new @f_UX(this) if @addT > 0 finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex znew = m_UX.Iterate(S.pz) if @v_UXSFormula >= 221227 znew = znew + ppc endif if @addT == "c" ; "c" added 230429 ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif S.Update(znew, S.pc) return S.bailed endfunc protected: UserTransform m_UX UtilityTransform finalTransform complex ppc default: rating = NotRecommended title = "UserTransform" int param v_UXSFormula caption = "Version (UX_SFormula)" default = 221227 ; hint = "This version parameter is used to detect when a change has \ ; been made to the formula that is incompatible with the \ ; previous version. When that happens, this field will reflect \ ; the old version number to alert you to the fact that an \ ; alternate rendering is being used." visible = @v_UXSFormula < 221227 endparam heading text = "(Current is 221227.)" visible = @v_UXSFormula < 221227 endheading bool param p_Mtype caption = "M-type?" default = true visible = @v_UXSFormula >= 221227 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_UXSFormula >= 221227 && !@p_Mtype endparam heading caption = "znew = T(z) + c" endheading UserTransform param f_UX caption = "Transform T" default = JLB_BasicUserTransform endparam heading caption = "Tweak after each iteration" endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam } class JLB_PFSFormula(SFormula) { ; an SFormula that calls a DivergentFormula public: import "common.ulb" import "Standard.ulb" func JLB_PFSFormula(Generic pparent) SFormula.SFormula(pparent) m_PF = new @f_PF(this) endfunc func Init(complex pz, complex pc) m_PF.Init(#pixel) endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif S.pz = m_PF.Iterate(S.pz) S.Update(S.pz, S.pc) return S.bailed endfunc protected: Formula m_PF default: rating = NotRecommended title = "Plug-In Formula" int param v_PFSFormula caption = "Version (PFSFormula)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_PFSFormula < 100 endparam Formula param f_PF caption = "Plug-In Formula" default = Standard_Mandelbrot endparam } class JLB_GnarlSFormula(SFormula) { ; Based on the Gnarl formula from mt.ufm, as a SFormula. ; Calculate dx and dy based on the real or imaginary part of z, then combine. ; Add a multiple of z, #pixell, or a seed. public: import "common.ulb" func JLB_GnarlSFormula(Generic pparent) SFormula.SFormula(pparent) m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180)) if @type == 1 m_SFormula1 = new @f_SFormula1(this) m_SFormula2 = new @f_SFormula2(this) m_SFormula3 = new @f_SFormula3(this) endif if @addT > 0 finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if (@ctype == "seed") ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if s.bailed return true endif if s.tooMany return false endif complex pz = S.pz complex znew float xc float yc if (@ctype == "z") xc = real(pz) yc = imag(pz) elseif (@ctype == "seed") xc = real(ppc) yc = imag(ppc) else;if (@ctype == "pixel") xc = real(#pixel) yc = imag(#pixel) endif complex zrot = pz * m_rot float x = real(zrot) float y = imag(zrot) complex dx complex dy if @type == "function" float px, float py, float qx, float qy if @args == "x,y" px = x, qx = xc, py = y, qy = yc else ; "y,x" the original version px = y, qx = yc, py = x, qy = xc endif if (@mode == 0) ; f(f(f())) dx = @a1*@f1(@b1*px + @a2*@f2(@b2*px + @a3*@f3(@b3*px))) + @a4*qx dy = @a1*@f1(@b1*py + @a2*@f2(@b2*py + @a3*@f3(@b3*py))) + @a4*qy else ; f()+f()+f() dx = @a1*@f1(@b1*px) + @a2*@f2(@b2*px) + @a3*@f3(@b3*px) + @a4*qx dy = @a1*@f1(@b1*py) + @a2*@f2(@b2*py) + @a3*@f3(@b3*py) + @a4*qy endif if @v_GnarlSFormula <= 100 dx = real(dx) dy = real(dy) endif else ; @type = "formula" complex zz float q if @mode == 0 ; f(f(f())) if @v_GnarlSFormula <= 100 zz = flip(zrot), q = yc else if @args == "x,y" zz = x, q = xc else ; "y,x" the original version zz = y, q = yc endif endif S.pz = zz m_SFormula3.Iterate(S) S.pz = zz + @a3 * S.pz m_SFormula2.Iterate(S) S.pz = zz + @a2 * S.pz m_SFormula1.Iterate(S) dx = @a1*S.pz + @a4*q if @v_GnarlSFormula <= 100 dx = real(dx) ; real(a1*f1(zz+a2*f2(zz+a3*f3(zz)))+a4*yc) zz = zrot, q = xc else if @args == "x,y" zz = y, q = yc else ; "y,x" the original version zz = x, q = xc endif endif S.pz = zz m_SFormula3.Iterate(S) S.pz = zz + @a3 * S.pz m_SFormula2.Iterate(S) S.pz = zz + @a2 * S.pz m_SFormula1.Iterate(S) dy = @a1*S.pz + @a4*q if @v_GnarlSFormula <= 100 dy = real(dy) ; real(a1*f1(zz+a2*f2(zz+a3*f3(zz)))+a4*xc) endif else ; f()+f()+f() complex t1 complex t2 complex t3 if @v_GnarlSFormula <= 100 zz = flip(zrot), q = yc else if @args == "x,y" zz = x, q = xc else ; "y,x" the original version zz = y, q = yc endif endif S.pz = zz m_SFormula3.Iterate(S) t3 = S.pz S.pz = zz m_SFormula2.Iterate(S) t2 = S.pz S.pz = zz m_SFormula1.Iterate(S) t1 = S.pz dx = @a1*t1 + @a2*t2 + @a3*t3 + @a4*q if @v_GnarlSFormula <= 100 dx = real(dx) q = xc else if @args == "x,y" zz = y, q = yc else ; "y,x" the original version zz = x, q = xc endif endif S.pz = zz m_SFormula3.Iterate(S) t3 = S.pz S.pz = zz m_SFormula2.Iterate(S) t2 = S.pz S.pz = zz m_SFormula1.Iterate(S) t1 = S.pz dy =@a1*t1 + @a2*t2 + @a3*t3 + @a4*q if @v_GnarlSFormula <= 100 dy = real(dy) endif endif endif if (@xop=="-") dx = -dx endif if (@yop=="-") dy = -dy endif znew = pz + @step * (dx + flip(dy)) ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex m_rot SFormula m_SFormula1 SFormula m_SFormula2 SFormula m_SFormula3 complex ppc UtilityTransform finalTransform default: rating = NotRecommended title = "Gnarl" int param v_GnarlSFormula caption = "Version (Gnarl_SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_GnarlSFormula < 200 endparam ; bool param p_Mtype ; caption = "M-type?" ; default = true ; visible = @v_GnarlSFormula > 100 ; endparam heading caption = "Gnarl3 is Recommended instead of Gnarl" endheading param type caption = "type" enum = "function" "formula" default = 0 hint = "function = built-in functions, like sin; formula = any SFormula plug-in" endparam param mode caption = "mode" enum = "f(f(f()))" "f()+f()+f()" default = 1 endparam float param theta caption = "Theta" default = 0 hint = "First rotate z by this much (360 = full circle)" endparam param args caption = "args" enum = "x,y" "y,x" default = 1 endparam heading endheading complex param a1 caption = "Gnarl a1" default = 1 hint = "multiplies f1" endparam complex param b1 caption = "Gnarl b1" default = 1 hint = "multiplies f1's arg" visible = @type == 0 endparam func f1 caption = "Gnarl f1" default = cos() hint = "Gnarl left function" visible = @type == 0 endfunc SFormula param f_SFormula1 caption = "Gnarl formula 1" default = JLB_FuncSFormula visible = @type == 1 endparam heading endheading complex param a2 caption = "Gnarl a2" default = 2.7 hint = "multiplies f2" endparam complex param b2 caption = "Gnarl b2" default = 2.7 hint = "multiplies f2's arg" ; visible=( (@a1*@a2) != 0) visible = @type == 0 endparam func f2 caption = "Gnarl f2" default = sin() hint = "second function" visible = @type == 0 endfunc SFormula param f_SFormula2 caption = "Gnarl formula 2" default = JLB_FuncSFormula visible = @type == 1 endparam heading endheading complex param a3 caption = "Gnarl a3" default = 0 hint = "multiplies f3" endparam complex param b3 caption = "Gnarl b3" default = 1 hint = "multiplies f3's arg" visible = @type == 0 endparam func f3 caption = "Gnarl f3" default = sqr() hint = "inmost or right function" visible = @type == 0 ; visible=( (@a1*@a2*@a3) != 0) endfunc SFormula param f_SFormula3 caption = "Gnarl formula 3" default = JLB_FuncSFormula visible = @type == 1 endparam heading endheading complex param a4 caption = "Gnarl a4" default = 1.0 hint = "multiplies final addition" endparam param ctype enum = "z" "seed" "pixel" caption = "final addition" ;hint = "makes a difference sometimes" default = 0 endparam complex param p_seed caption = "Seed" default = (0.3, 0) visible = @v_GnarlSFormula > 100 && @ctype==1 endparam heading endheading param step caption = "Step_size" default = 0.1 hint = "How much of this to use. z_new = z + Step_size * z_calc" endparam param xop enum = "+" "-" default = 1 hint = "multiply real part of z_calc" endparam param yop enum = "+" "-" default = 0 hint = "multiply imaginary part of z_calc" endparam heading caption = "Tweak after each iteration" endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam } class JLB_Gnarl2SFormula(SFormula) { ; Based on the Gnarl formula from mt.ufm, as a SFormula. ; Calculate dx and dy based on the real or imaginary part of z, then combine. ; Add a multiple of z, #pixell, or a seed. public: import "common.ulb" func JLB_Gnarl2SFormula(Generic pparent) SFormula.SFormula(pparent) m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180)) if @type == 1 m_Sf1 = new @f_SFormula1(this) m_Sf2 = new @f_SFormula2(this) m_Sf3 = new @f_SFormula3(this) endif m_Combine = new Combine() endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if s.bailed return true endif if s.tooMany return false endif complex pz = S.pz ; complex pc = @p_seed complex znew float xc float yc if @v_Gnarl2SFormula < 220 if (@ctype == "z") xc = real(pz) yc = imag(pz) elseif (@ctype == "seed") xc = real(@p_seed) yc = imag(@p_seed) else;if (@ctype == "pixel") xc = real(#pixel) yc = imag(#pixel) endif else if (@ctype1 == "z") xc = real(pz) yc = imag(pz) elseif (@ctype1 == "seed (J-type)") xc = real(@p_seed) yc = imag(@p_seed) else;if (@ctype1 == "pixel(M-type)") xc = real(#pixel) yc = imag(#pixel) endif endif complex zrot = pz * m_rot float x = real(zrot) float y = imag(zrot) complex dx = 0 ; satisfy compiler complex dy = 0 ; ditto complex tx1, complex tx2, complex tx3 complex ty1, complex ty2; complex ty3 complex px, complex py, complex qx, complex qy if @args == "x,y" px = x, qx = xc, py = y, qy = yc else ; "y,x" the original version, usually better px = y, qx = yc, py = x, qy = xc endif if @mode == 0 ;"f1 op1 f2" ;tx2 = @a2*@f2(@b2*px) ;ty2 = @a2*@f2(@b2*py) tx2 = iter(2, px, qx, S) ty2 = iter(2, py, qy, S) if @op1a == "( )" ; f1(f2(.)) ; dx = @a1*@f1(@b1*tx2) ; dy = @a1*@f1(@b1*ty2) dx = iter(1, @a0*px + tx2, qx, S) dy = iter(1, @a0*py + ty2, qy, S) else ; f1(.) op1 f2(.) ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, px, qx, S) ty1 = iter(1, py, qy, S) dx = m_Combine.go(tx1, @op1a, tx2) dy = m_Combine.go(ty1, @op1a, ty2) endif elseif @mode == 1 ;"f1 op1 (f2 op2 f3)" if @op2a == "( )" ; f1 op f2(f3(.)) ; tx3 = @a3*@f3(@b3*px) ; ty3 = @a3*@f3(@b3*py) tx3 = iter(3, px, qx, S) ty3 = iter(3, py, qy, S) ; tx2 = @a2*@f2(@b2*tx3) ; ty2 = @a2*@f2(@b2*ty3) tx2 = iter(2, @a0*px + tx3, qx, S) ty2 = iter(2, @a0*py + ty3, qy, S) if @op1 == "( )" ; f1(f2(f3(.))) ; dx = @a1*@f1(@b1*tx2) ; dy = @a1*@f1(@b1*ty2) dx = iter(1, @a0*px + tx2, qx, S) dy = iter(1, @a0*py + ty2, qy, S) else ; f1(.) op1 f2(f3(.)) ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, px, qx, S) ty1 = iter(1, py, qy, S) dx = m_Combine.go(tx1, @op1, tx2) dy = m_Combine.go(ty1, @op1, ty2) endif else ; tx3 = @a3*@f3(@b3*px) ; ty3 = @a3*@f3(@b3*py) tx3 = iter(3, px, qx, S) ty3 = iter(3, py, qy, S) ; tx2 = @a2*@f2(@b2*px) ; ty2 = @a2*@f2(@b2*py) tx2 = iter(2, px, qx, S) ty2 = iter(2, py, qy, S) tx2 = m_Combine.go(tx2, @op2a, tx3) ty2 = m_Combine.go(ty2, @op2a, ty3) if @op1 == "( )" ; f1(f2(.) op2a f3(.)) ; dx = @a1*@f1(@b1*tx2) ; dy = @a1*@f1(@b1*ty2) dx = iter(1, @a0*px + tx2, qx, S) dy = iter(1, @a0*py + ty2, qy, S) else ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, px, qx, S) ty1 = iter(1, py, qy, S) dx = m_Combine.go(tx1, @op1, tx2) dy = m_Combine.go(ty1, @op1, ty2) endif endif else ;@omode == "(f1 op1 f2) op2 f3" ; @op3a == "()" not allowed with this ordering ; tx2 = @a2*@f2(@b2*px) ; ty2 = @a2*@f2(@b2*py) tx2 = iter(2, px, qx, S) ty2 = iter(2, py, qy, S) if @op1 == "( )" ; (f1(f2(.))) op2b f3(.) ; tx1 = @a1*@f1(@b1*tx2) ; ty1 = @a1*@f1(@b1*ty2) tx1 = iter(1, @a0*px + tx2, qx, S) ty1 = iter(1, @a0*py + ty2, qy, S) else ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, px, qx, S) ty1 = iter(1, py, qy, S) tx1 = m_Combine.go(tx1, @op1, tx2) ty1 = m_Combine.go(ty1, @op1, ty2) endif ; tx3 = @a3*@f3(@b3*px) ; ty3 = @a3*@f3(@b3*py) tx3 = iter(3, px, qx, S) ty3 = iter(3, py, qy, S) dx = m_Combine.go(tx1, @op2b, tx3) dy = m_Combine.go(ty1, @op2b, ty3) endif dx = dx + @a4*qx dy = dy + @a4*qy if @v_Gnarl2SFormula < 230 if (@xop=="-") dx = -dx endif if (@yop=="-") dy = -dy endif else if @xyop == "-dx +dy" || @xyop == "-dx -dy" dx = -dx endif if @xyop == "+dx -dy" || @xyop == "-dx -dy" dy = -dy endif endif znew = pz + @step * (dx + flip(dy)) S.Update(znew, S.pc) return S.bailed endfunc complex func iter(int n, complex v, complex c, State S) if @type == 0 if n == 1 return @a1*@f1(@b1*v) elseif n == 2 return @a2*@f2(@b2*v) else return @a3*@f3(@b3*v) endif else complex pz = S.pz ; save these complex pc = S.pz S.pc = c complex t if n == 1 S.pz = @b1*v m_Sf1.Iterate(S) t = @a1*S.pz elseif n == 2 S.pz = @b2*v m_Sf2.Iterate(S) t = @a2*S.pz else S.pz = @b3*v m_Sf3.Iterate(S) t = @a3*S.pz endif S.pz = pz, S.pc = pc return t endif endfunc ;protected: complex m_rot SFormula m_Sf1 SFormula m_Sf2 SFormula m_Sf3 Combine m_Combine default: rating = NotRecommended title = "Gnarl2" int param v_Gnarl2SFormula caption = "Version (Gnarl2_SFormula)" default = 230 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_Gnarl2SFormula < 230 endparam heading caption = "Gnarl2 doesn't work quite as promised; use Gnarl3 instead." endheading param ctype enum = "z" "seed" "pixel" caption = "final addition" ;hint = "makes a difference sometimes" default = 0 visible = @v_Gnarl2SFormula < 220 endparam complex param p_seed caption = "Seed" default = (0.3, 0) visible = (@ctype==1 || @ctype1 == 1) endparam param type caption = "Type" enum = "built-in function" "Sformula" default = 0 ;hint = "function = built-in functions, like sin; formula = any SFormula plug-in" endparam param mode caption = "How to combine" default = 0 enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3" endparam complex param a0 caption = "a0" default = 0 visible = @type == 1 && ( \ (@mode == 0 && @op1a == 5) || \ (@mode == 1 && (@op1 == 5 || @op2a == 5)) || \ (@mode == 2 && @op1 == 5) ) endparam param op1 caption = "Operator 1" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine Formula values." visible = @mode > 0 endparam param op1a caption = "Operator" enum = "+" "-" "*" "/" "^" "( )" default = 5 hint = "How to combine Formula values." visible = @mode == 0 endparam param op2a caption = "Operator 2" enum = "+" "-" "*" "/" "^" "( )" default = 2 hint = "How to combine Formula values." visible = (@mode == 1) endparam param op2b caption = "Operator 2" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default = 2 hint = "How to combine Formula values." visible = (@mode == 2) endparam float param theta caption = "Theta" default = 0 hint = "First rotate z by this much (360 = full circle)" endparam param args caption = "args" enum = "x,y" "y,x" default = 1 endparam heading caption = "a1*f1(b1*v)" endheading complex param a1 caption = "Gnarl2 a1" default = 1 hint = "multiplies f1" endparam complex param b1 caption = "Gnarl2 b1" default = 1 hint = "multiplies f1's arg" endparam func f1 caption = "Gnarl2 f1" default = cos() hint = "outer or left function" visible = @type == 0 endfunc SFormula param f_SFormula1 caption = "Gnarl2 formula 1" default = JLB_FuncSFormula visible = @type >= 1 endparam heading caption = "a2*f2(b2*v)" endheading complex param a2 caption = "Gnarl2 a2" default = 2.7 hint = "multiplies f2" endparam complex param b2 caption = "Gnarl2 b2" default = 2.7 hint = "multiplies f2's arg" ; visible=( (@a1*@a2) != 0) endparam func f2 caption = "Gnarl2 f2" default = sin() hint = "second function" visible = @type == 0 endfunc SFormula param f_SFormula2 caption = "Gnarl2 formula 2" default = JLB_FuncSFormula visible = @type >= 1 endparam heading caption = "a3*f3(b3*v)" visible = @mode > 0 endheading complex param a3 caption = "Gnarl2 a3" default = 0 hint = "multiplies f3" visible = @mode > 0 endparam complex param b3 caption = "Gnarl2 b3" default = 1 hint = "multiplies f3's arg" visible = @mode > 0 endparam func f3 caption = "Gnarl2 f3" default = sqr() hint = "inmost or right function" visible = @type == 0 && @mode > 0 endfunc SFormula param f_SFormula3 caption = "Gnarl2 formula3" default = JLB_FuncSFormula visible = @type >= 1 && @mode > 0 endparam heading caption = "finally..." endheading param xyop enum = "+dx +dy" "+dx -dy" "-dx +dy" "-dx -dy" default = 1 hint = "final multiplcations of real and imaginary parts of z_calc" visible = @v_Gnarl2SFormula >= 230 endparam param ctype1 enum = "pixel (M-type)" "seed (J-type)" "z" caption = "final addition of c" default = 0 visible = @v_Gnarl2SFormula >= 230 endparam ; heading ; caption = "multiplies c" ; endheading complex param a4 caption = "c multiplier" default = 1.0 hint = "multiplies final addition" endparam param step caption = "Gnarl2 Step_size" default = 0.1 hint = "How much of this to use. z_new = z + Step_size * z_calc" endparam param xop enum = "+" "-" default = 1 hint = "multiply real part of z_calc" visible = @v_Gnarl2SFormula < 230 endparam param yop enum = "+" "-" default = 0 hint = "multiply imaginary part of z_calc" visible = @v_Gnarl2SFormula < 230 endparam } class JLB_Gnarl3SFormula(SFormula) { ; Based on the Gnarl formula from mt.ufm, as a SFormula. ; Calculate dx and dy based on the real or imaginary part of z, then combine. ; Add a multiple of z, #pixel, or a seed. ; Corrected version of Gnarl2, June 2021. public: import "common.ulb" func JLB_Gnarl3SFormula(Generic pparent) SFormula.SFormula(pparent) m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180)) if @type == 1 m_Sf1 = new @f_SFormula1(this) m_Sf2 = new @f_SFormula2(this) m_Sf3 = new @f_SFormula3(this) endif m_Combine = new Combine() if @addT > 0 ;&& !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if (@ctype1 == "seed (J-type)") ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if s.bailed return true endif if s.tooMany return false endif complex pz = S.pz ; complex pc = @p_seed complex znew float xc float yc if (@ctype1 == "z") xc = real(pz) yc = imag(pz) elseif (@ctype1 == "seed (J-type)") xc = real(ppc) yc = imag(ppc) else;if (@ctype1 == "pixel(M-type)") xc = real(#pixel) yc = imag(#pixel) endif complex zrot = pz * m_rot float x = real(zrot) float y = imag(zrot) complex dx = 0 ; satisfy compiler complex dy = 0 ; ditto complex tx1, complex tx2, complex tx3 complex ty1, complex ty2; complex ty3 complex px, complex py, complex qx, complex qy if @args == "x,y" px = x, qx = xc, py = y, qy = yc else ; "y,x" the original version, usually better px = y, qx = yc, py = x, qy = xc endif if @mode == 0 ;"f1 op1 f2" ;tx2 = @a2*@f2(@b2*px) ;ty2 = @a2*@f2(@b2*py) tx2 = iter(2, @b2*px, qx, S) ty2 = iter(2, @b2*py, qy, S) if @op1a == "( )" ; f1(f2(.)) ; dx = @a1*@f1(@b1*tx2) ; dy = @a1*@f1(@b1*ty2) dx = iter(1, @b1*px + tx2, qx, S) ; wrong! dy = iter(1, @b1*py + ty2, qy, S) else ; f1(.) op1 f2(.) ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, @b1*px, qx, S) ty1 = iter(1, @b1*py, qy, S) dx = m_Combine.go(tx1, @op1a, tx2) dy = m_Combine.go(ty1, @op1a, ty2) endif elseif @mode == 1 ;"f1 op1 (f2 op2 f3)" if @op2a == "( )" ; f1 op f2(f3(.)) ; tx3 = @a3*@f3(@b3*px) ; ty3 = @a3*@f3(@b3*py) tx3 = iter(3, @b3*px, qx, S) ty3 = iter(3, @b3*py, qy, S) ; tx2 = @a2*@f2(@b2*tx3) ; ty2 = @a2*@f2(@b2*ty3) tx2 = iter(2, @b2*px + tx3, qx, S) ty2 = iter(2, @b2*py + ty3, qy, S) if @op1 == "( )" ; f1(f2(f3(.))) ; dx = @a1*@f1(@b1*tx2) ; dy = @a1*@f1(@b1*ty2) dx = iter(1, @b1*px + tx2, qx, S) dy = iter(1, @b1*py + ty2, qy, S) else ; f1(.) op1 f2(f3(.)) ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, @b1*px, qx, S) ty1 = iter(1, @b1*py, qy, S) dx = m_Combine.go(tx1, @op1, tx2) dy = m_Combine.go(ty1, @op1, ty2) endif else ; tx3 = @a3*@f3(@b3*px) ; ty3 = @a3*@f3(@b3*py) tx3 = iter(3, @b3*px, qx, S) ty3 = iter(3, @b3*py, qy, S) ; tx2 = @a2*@f2(@b2*px) ; ty2 = @a2*@f2(@b2*py) tx2 = iter(2, @b2*px, qx, S) ty2 = iter(2, @b2*py, qy, S) tx2 = m_Combine.go(tx2, @op2a, tx3) ty2 = m_Combine.go(ty2, @op2a, ty3) if @op1 == "( )" ; f1(f2(.) op2a f3(.)) ; dx = @a1*@f1(@b1*tx2) ; dy = @a1*@f1(@b1*ty2) dx = iter(1, @b1*px + tx2, qx, S) dy = iter(1, @b1*py + ty2, qy, S) else ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, @b1*px, qx, S) ty1 = iter(1, @b1*py, qy, S) dx = m_Combine.go(tx1, @op1, tx2) dy = m_Combine.go(ty1, @op1, ty2) endif endif else ;@omode == "(f1 op1 f2) op2 f3" ; @op3a == "()" not allowed with this ordering ; tx2 = @a2*@f2(@b2*px) ; ty2 = @a2*@f2(@b2*py) tx2 = iter(2, @b2*px, qx, S) ty2 = iter(2, @b2*py, qy, S) if @op1 == "( )" ; (f1(f2(.))) op2b f3(.) ; tx1 = @a1*@f1(@b1*tx2) ; ty1 = @a1*@f1(@b1*ty2) tx1 = iter(1, @b1*px + tx2, qx, S) ty1 = iter(1, @b1*py + ty2, qy, S) else ; tx1 = @a1*@f1(@b1*px) ; ty1 = @a1*@f1(@b1*py) tx1 = iter(1, @b1*px, qx, S) ty1 = iter(1, @b1*py, qy, S) tx1 = m_Combine.go(tx1, @op1, tx2) ty1 = m_Combine.go(ty1, @op1, ty2) endif ; tx3 = @a3*@f3(@b3*px) ; ty3 = @a3*@f3(@b3*py) tx3 = iter(3, @b3*px, qx, S) ty3 = iter(3, @b3*py, qy, S) dx = m_Combine.go(tx1, @op2b, tx3) dy = m_Combine.go(ty1, @op2b, ty3) endif dx = dx + @a4*qx dy = dy + @a4*qy if @xyop == "-dx +dy" || @xyop == "-dx -dy" dx = -dx endif if @xyop == "+dx -dy" || @xyop == "-dx -dy" dy = -dy endif znew = pz + @step * (dx + flip(dy)) ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc complex func iter(int n, complex v, complex c, State S) if @type == 0 if n == 1 return @a1*@f1(v) elseif n == 2 return @a2*@f2(v) else return @a3*@f3(v) endif else complex pz = S.pz ; save these complex pc = S.pz S.pc = c complex t if n == 1 S.pz = v m_Sf1.Iterate(S) t = @a1*S.pz elseif n == 2 S.pz = v m_Sf2.Iterate(S) t = @a2*S.pz else S.pz = v m_Sf3.Iterate(S) t = @a3*S.pz endif S.pz = pz, S.pc = pc return t endif endfunc ;protected: complex m_rot SFormula m_Sf1 SFormula m_Sf2 SFormula m_Sf3 Combine m_Combine complex ppc UtilityTransform finalTransform default: rating = NotRecommended title = "Gnarl3" int param v_Gnarl3SFormula caption = "Version (Gnarl3_SFormula)" default = 1 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_Gnarl3SFormula < 1 endparam ; bool param p_std ; caption = "Standard" ; default = true ; endparam param type caption = "Type" enum = "built-in function" "Sformula" default = 0 ;hint = "function = built-in functions, like sin; formula = any SFormula plug-in" endparam param mode caption = "How to combine" default = 1 enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3" endparam param op1 caption = "Operator 1" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine Formula values." visible = @mode > 0 endparam param op1a caption = "Operator" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine Formula values." visible = @mode == 0 endparam param op2a caption = "Operator 2" enum = "+" "-" "*" "/" "^" "( )" default = 2 hint = "How to combine Formula values." visible = (@mode == 1) endparam param op2b caption = "Operator 2" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default = 2 hint = "How to combine Formula values." visible = (@mode == 2) endparam float param theta caption = "Theta" default = 0 hint = "First rotate z by this much (360 = full circle)" endparam param args caption = "args" enum = "x,y" "y,x" default = 1 endparam heading caption = "a1*f1(b1*v)" endheading complex param a1 caption = "Gnarl3 a1" default = 1 hint = "multiplies f1" endparam complex param b1 caption = "Gnarl3 b1" default = 2 hint = "multiplies f1's arg" endparam func f1 caption = "Gnarl3 f1" default = sin() hint = "outer or left function" visible = @type == 0 endfunc SFormula param f_SFormula1 caption = "Gnarl3 formula 1" default = JLB_FuncSFormula visible = @type >= 1 endparam heading caption = "a2*f2(b2*v)" endheading complex param a2 caption = "Gnarl3 a2" default = 2.7 hint = "multiplies f2" endparam complex param b2 caption = "Gnarl3 b2" default = 2.7 hint = "multiplies f2's arg" endparam func f2 caption = "Gnarl3 f2" default = sin() hint = "second function" visible = @type == 0 endfunc SFormula param f_SFormula2 caption = "Gnarl3 formula 2" default = JLB_FuncSFormula visible = @type >= 1 endparam heading caption = "a3*f3(b3*v)" visible = @mode > 0 endheading complex param a3 caption = "Gnarl3 a3" default = 0 hint = "multiplies f3" visible = @mode > 0 endparam complex param b3 caption = "Gnarl3 b3" default = 1 hint = "multiplies f3's arg" visible = @mode > 0 endparam func f3 caption = "Gnarl3 f3" default = sqr() hint = "inmost or right function" visible = @type == 0 && @mode > 0 endfunc SFormula param f_SFormula3 caption = "Gnarl3 formula3" default = JLB_FuncSFormula visible = @type >= 1 && @mode > 0 endparam heading caption = "finally..." endheading param xyop enum = "+dx +dy" "+dx -dy" "-dx +dy" "-dx -dy" default = 1 hint = "final multiplcations of real and imaginary parts of z_calc" endparam param ctype1 enum = "pixel (M-type)" "seed (J-type)" "z" caption = "final addition of c" default = 0 endparam complex param p_seed caption = "Seed" default = (0.3, 0) visible = @ctype1 == 1 endparam complex param a4 caption = "c multiplier" default = 1.0 hint = "multiplies final addition" endparam param step caption = "Gnarl3 Step_size" default = 0.1 hint = "How much of this to use. z_new = z + Step_size * z_calc" endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } ; 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 = NotRecommended title = "Gnarly" int param v_GnarlySFormula caption = "Version (Gnarly_SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_GnarlySFormula < 200 endparam ; bool param p_std ; caption = "Standard" ; default = true ; endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_GnarlySFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_GnarlySFormula > 100 && !@p_Mtype endparam SFormula param f_SFormula1 caption = "dx formula" default = JLB_FuncSFormula endparam SFormula param f_SFormula2 caption = "dy formula" default = JLB_FuncSFormula endparam float param theta caption = "Theta" default = 0 hint = "First rotate z by this much (360 = full circle)" endparam param ctype enum = "z" "c" "pixel" caption = "c multiplier" default = 0 endparam param step caption = "Step_size" default = 0.1 hint = "How much of this to use. z_new = z + Step_size * z_calc" endparam param xop enum = "+" "-" default = 1 hint = "multiply real part of z_calc" endparam param yop enum = "+" "-" default = 0 hint = "multiply imaginary part of z_calc" endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } ; August 2020 ; Fixed grad function ; Changed to JLB_Random ; Noise based on #screenpixel, not on pz! class JLB_Perlin3DNoiseSFormula(SFormula) { ; Code adapted from https://flafla2.github.io/2014/08/09/perlinnoise.html ; (Not Ken Perlin's original version.) ; pc not used public: import "common.ulb" func JLB_Perlin3DNoiseSFormula(Generic pparent) SFormula.SFormula(pparent) ;m_FractalCoordinate = new FractalCoordinate(this) r = new JLB_Random(0) r.Init(@seed) int i = 0 ; generate random permutation of integers 0 - 255 while i < 256 px[i] = py[i] = i i = i + 1 endwhile int tmp int j r.SetNMax(256) j = 0 while j < 256 i = r.RandomIntInRange(0) tmp = px[i] px[i] = px[j] px[j] = tmp j = j + 1 endwhile j = 0 while j < 256 i = r.RandomIntInRange(0) tmp = py[i] py[i] = py[j] py[j] = tmp j = j + 1 endwhile i = 0 while i < 256 px[i+512] = px[i+256] = px[i] py[i+512] = py[i+256] = py[i] i = i + 1 endwhile px[768] = px[0] ; in case of overflow in grad, bbb line py[768] = py[0] endfunc func Init(complex pz, complex pc) ;m_FractalCoordinate.Init(pz) endfunc ; @param pz ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex tz = #screenpixel ; NOT m_FractalCoordinate.Iterate(#screenpixel) float tx = real(tz) float ty = imag(tz) m_doingX = true complex dx = OctavePerlin(tx, ty, @zz-#pi/2) ; @zz always 0 m_doingX = false complex dy = OctavePerlin(tx, ty, @zz+#pi/2) ; scale so range is about (-1,+1) if strength ~ 1 complex znew = @strength * (2 / #magn) * (dx + flip(dy)) if !@do_dz znew = S.pz + znew endif S.update(znew, S.pc) return S.bailed endfunc float func OctavePerlin(float x, float y, float z) float total = 0 float freq = @frequency / 100 ; empirical scaling float amp = 1 float maxValue = 0 int i = 0 while i < @octaves total = total + amp * perlin(x*freq, y*freq, z*freq) maxValue = maxValue + amp amp = amp * @persistence freq = 2 * freq i = i + 1 endwhile return 2*total/maxValue - 1.0 endfunc float func perlin(float x, float y, float z) x = x % 256 y = y % 256 z = z % 256 int xi = floor(x) ; Calculate the "unit cube" that the point asked will be located in. int yi = floor(y) ; The left bound is ( xi, yi, zi) and the right bound is that plus 1. int zi = floor(z) float xf = x - floor(x) float yf = y - floor(y) ; Next we calculate the location (from 0.0 to 1.0) in that cube. float zf = z - floor(z) float u = fade(xf); ; We also fade the location to smooth the result. float v = fade(yf); float w = fade(zf); int aaa, int aba, int aab, int abb int baa, int bba, int bab, int bbb if m_doingX aaa = px[px[px[ xi ]+ yi ]+ zi ] aba = px[px[px[ xi ]+ 1+yi ]+ zi ] aab = px[px[px[ xi ]+ yi ]+ 1+zi ] abb = px[px[px[ xi ]+ 1+yi ]+ 1+zi ] baa = px[px[px[ 1+xi ]+ yi ]+ zi ] bba = px[px[px[ 1+xi ]+ 1+yi ]+ zi ] bab = px[px[px[ 1+xi ]+ yi ]+ 1+zi ] ; if inc just adds 1, max index = 3*256 bbb = px[px[px[ 1+xi ]+ 1+yi ]+ 1+zi ] ; so p needs to be 3*256+1 = 769 else aaa = py[py[py[ xi ]+ yi ]+ zi ] aba = py[py[py[ xi ]+ 1+yi ]+ zi ] aab = py[py[py[ xi ]+ yi ]+ 1+zi ] abb = py[py[py[ xi ]+ 1+yi ]+ 1+zi ] baa = py[py[py[ 1+xi ]+ yi ]+ zi ] bba = py[py[py[ 1+xi ]+ 1+yi ]+ zi ] bab = py[py[py[ 1+xi ]+ yi ]+ 1+zi ] ; if inc just adds 1, max index = 3*256 bbb = py[py[py[ 1+xi ]+ 1+yi ]+ 1+zi ] endif ; The gradient function calculates the dot product between a pseudorandom gradient vector ; and the vector from the input coordinate to the 8 surrounding points in its unit cube. ; This is all then lerped together as a sort of weighted average based on the faded (u,v,w). float x1 = lerp(grad (aaa, xf , yf , zf), grad (baa, xf-1, yf , zf), u) float x2 = lerp(grad (aba, xf , yf-1, zf), grad (bba, xf-1, yf-1, zf), u) float y1 = lerp(x1, x2, v) x1 = lerp(grad (aab, xf , yf , zf-1), grad (bab, xf-1, yf , zf-1), u) x2 = lerp(grad (abb, xf , yf-1, zf-1), grad (bbb, xf-1, yf-1, zf-1), u) float y2 = lerp (x1, x2, v) return (lerp (y1, y2, w) + 1) / 2 ; value between 0 and 1 endfunc ; hash is in [0,255] float func grad(int hash, float x, float y, float z) int h = hash % 16; ; Use the last 4 bits of hash if h == 0, return x + y elseif h == 1, return -x + y elseif h == 2, return x - y elseif h == 3, return -x - y elseif h == 4, return x + z elseif h == 5, return -x + z elseif h == 6, return x - z elseif h == 7, return -x - z elseif h == 8, return y + z elseif h == 9, return -y + z elseif h ==10, return y - z elseif h ==11, return -y - z elseif h ==12, return y + x elseif h ==13, return -y + z elseif h ==14, return y - x else , return -y - z endif endfunc ; increment num by 1 with roll-over ; int func inc(int num) ; return (num + 1 ) % 256 ; endfunc ; Fade function as defined by Ken Perlin. Replaces linear interpolation between 0 and 1, ; providing continuous first and second derivatives at 0 and 1. ; This ends up smoothing the final output. float func fade(float t) return t * t * t * (t * (t * 6 - 15) + 10) ; 6t^5 - 15t^4 + 10t^3 endfunc ; linearly interpret between a and b, assuming that t is from 0 to 1, inclusive float func lerp(float a, float b, float t) return a + t * (b - a) endfunc protected: int px[769] ; 3*256 + 1 int py[769] bool m_doingX JLB_Random r default: title = "Perlin 3D Noise" rating = NotRecommended int param v_PerlinNoiseSFormula caption = "Version (PerlinNoise_SFormula)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_PerlinNoiseSFormula < 100 endparam heading text = "The noise is based on the screen position. Probably this is best used \ for one iteration as the Initial Fractal, or as a texture layer." endheading int param seed caption ="Seed" hint = "Seed for random numbers" default = 12345679 endparam int param octaves caption = "Octaves" default = 3 min = 1 hint = "The lowest octave has the largest amplitude and the lowest frequency. \ Subsequent octaves have lower amplitude and higher frequency. \ Noise is the sum of all octaves." endparam float param frequency caption = "Frequency" hint = "Frequency of lowest octave noise. Lower values give smoother noise, \ higher values less smooth." default = 1 endparam float param strength caption = "Noise Strength" default = 0.05 endparam float param persistence caption = "Persistence" hint = "Smaller values give smoother noise." max = 1.0 min = 0.0 default = 0.5 endparam float param zz caption = "3D parameter" ;default = 0 visible = false endparam bool param do_dz caption = "Return dz instead of z?" default = false visible = false ; just for debugging endparam } class JLB_BarnsleySFormula(SFormula) { ; A version of a Barnsley formula as a SFormula. public: import "common.ulb" func JLB_BarnsleySFormula(Generic pparent) SFormula(pparent) if @addT > 0 finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if @v_BarnsleySFormula > 100 && !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz float temp = 0 ; avoid compiler warning if @mode == "real" temp = real(pz) elseif @mode == "imaginary" temp = imag(pz) elseif @mode == "angle" temp = atan2(pz) elseif @mode == "cross+" temp = real(pz)*imag(ppc) + imag(pz)*real(ppc) elseif @mode == "cross-" temp = real(pz)*imag(ppc) - imag(pz)*real(ppc) elseif @mode == "dot+" temp = real(pz)*real(ppc) + imag(pz)*imag(ppc) elseif @mode == "dot-" temp = real(pz)*real(ppc) - imag(pz)*imag(ppc) endif if temp >= @crit if @type_hi == "times" pz = (pz^@pow_hi + @off_hi) * ppc elseif @type_hi == "plus" pz = (pz^@pow_hi + @off_hi) + ppc elseif @type_hi == "minus" pz = (pz^@pow_hi + @off_hi) - ppc elseif @type_hi == "divided" pz = (pz^@pow_hi + @off_hi) / ppc elseif @type_hi == "exponential" pz = (pz^@pow_hi + @off_hi) ^ ppc endif else if @type_lo == "times" pz = (pz^@pow_lo + @off_lo) * ppc elseif @type_lo == "plus" pz = (pz^@pow_lo + @off_lo) + ppc elseif @type_lo == "minus" pz = (pz^@pow_lo + @off_lo) - ppc elseif @type_lo == "divided" pz = (pz^@pow_lo + @off_lo) / ppc elseif @type_lo == "exponential" pz = (pz^@pow_lo + @off_lo) ^ ppc endif endif complex znew = pz if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform default: title = "Barnsley" rating = NotRecommended int param v_BarnsleySFormula caption = "Version (Barnsley_SFormula)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_BarnsleySFormula < 200 endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_BarnsleySFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = @v_BarnsleySFormula > 100 && !@p_Mtype endparam ; parameters to calculate the number to compare to the critical value heading text = "Use combinations of real and imaginary parts of z and c\ to calculate value to compare with critical value." endheading param mode caption = "mode" default = 0 enum = "real" "imaginary" "angle" "cross+" "cross-" "dot+" "dot-" endparam float param crit caption = "critical value" default = 0.0 endparam heading caption = "If value >= critical value" endheading heading caption = " z_new = (z^p1 + a1) op1 c" endheading complex param pow_hi caption = "p1" ;hint = "formula contains z^pow_high + off_high" default = 2 endparam complex param off_hi caption = "a1" ;hint = "formula contains z^pow_high + off_high" default = (0,0) endparam param type_hi caption = "op1" default = 0 enum = "times" "plus" "minus" "divided" "exponential" endparam heading caption = "If value < critical value" endheading heading caption = " z_new = (z^p2 + a2) op2 c" endheading complex param pow_lo caption = "p2" ;hint = "formula contains z^pow_low + off_low" default = 2 endparam complex param off_lo caption = "a2" ;hint = "formula contains z^pow_low + off_low" default = (0,0) endparam param type_lo caption = "op2" default = 0 enum = "times" "plus" "minus" "divided" "exponential" endparam heading caption = "Tweak after each iteration" endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam } ; class FractalCoordinate(UtilityTransform) { ; Use the one in common.ulb ; } class 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 = NotRecommended param p_power ; Overrides p_power from Formula caption = "Power" default = (2,0) visible = false enabled = false endparam int param v_superswitch caption = "Version (JLB_superswitch)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_superswitch < 100 endparam Heading caption = "Start of Switch Super parameters" Endheading Heading Endheading DualTransform param f_DualTransformInit caption = "Initialize" default = JLB_NullDualTransform endparam Heading Endheading DualTransform param f_DualTransform caption = "Formula" default = JLB_MandelbrotDualTransform endparam Heading caption = "Bailout" Endheading Reduction param f_bailout caption = "Bailout Type" default = JLB_SimpleBailout endparam } class DualTransform(common.ulb:Generic) { ; DualTransform base class. No title, so only used for a base class. public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func DualTransform(Generic pparent) Generic.Generic(pparent) endfunc complex func Init(complex pz) return pz endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) return true endfunc default: rating = NotRecommended int param v_DualTransform caption = "Version (DualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_DualTransform < 100 endparam } class JLB_DoubleDualTransform(DualTransform) { ; A wrapper for two DualTransforms public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_DoubleDualTransform(Generic pparent) DualTransform.DualTransform(pparent) m_DualTransform1 = new @f_DualTransform1(this) m_DualTransform2 = new @f_DualTransform2(this) endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) bool result1 = m_DualTransform1.Iterate(pz, pc) bool result2 = m_DualTransform2.Iterate(pz, pc) return (result1 && result2) endfunc protected: DualTransform m_DualTransform1 DualTransform m_DualTransform2 default: rating = NotRecommended title = "Double DualTransform" int param v_DoubleDualTransform caption = "Version (DoubleDualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_DoubleDualTransform < 100 endparam DualTransform param f_DualTransform1 caption = "First DualTransform" default = JLB_ZCZDualTransform ; hint = "The default Null DualTransform does nothing." endparam Heading endHeading DualTransform param f_DualTransform2 caption = "Second DualTransform" default = JLB_ZCZDualTransform ; hint = "The default Null DualTransform does nothing." endparam } class JLB_NullDualTransform(DualTransform) { ; A DualTransform placeholder that does nothing. public: import "common.ulb" ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) return true endfunc default: rating = NotRecommended title = "Null DualTransform" int param v_NullDualTransform caption = "Version (NullDualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_NullDualTransform < 100 endparam } class JLB_MandelbrotDualTransform(DualTransform) { ; The Mandelbrot formula as a DualTransform public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_MandelbrotDualTransform(Generic pparent) DualTransform.DualTransform(pparent) endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) pz = sqr(pz) + pc return true endfunc default: rating = NotRecommended title = "Mandelbrot DualTransform" int param v_MandelbrotDualTransform caption = "Version (MandelbrotDualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_MandelbrotDualTransform < 100 endparam } class JLB_ZZDualTransform(DualTransform) { ; ZZDualTransform does two Z contractions ; p_z1 calls to a function, new z = ZContraction1(z, c) ; p_z2 calls to a function, new z = ZContraction2(z, c) public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_ZZDualTransform(Generic pparent) DualTransform.DualTransform(pparent) m_ZContraction1 = new @f_ZContraction1(this) m_ZContraction2 = new @f_ZContraction2(this) endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) int i i = 0 while (i < @p_z1) pz = m_ZContraction1.Iterate(pz, pc) if (isNan(|pz|)) return true endif i = i + 1 endwhile i = 0 while (i < @p_z2) pz = m_ZContraction2.Iterate(pz, pc) if (isNan(|pz|)) return true endif i = i + 1 endwhile return true endfunc protected: Contraction m_ZContraction1 Contraction m_ZContraction2 default: rating = NotRecommended title = "ZZ DualTransform" int param v_ZZDualTransform caption = "Version (ZZDualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ZZDualTransform < 100 endparam Heading Endheading Heading caption = "New z based on z and c" Endheading int param p_z1 caption = "Times" min = 0 default = 1 endparam Contraction param f_ZContraction1 caption = "z/c -> new z" default = JLB_MandelbrotContraction ; hint = "The default Null Contraction does nothing." endparam Heading caption = "New z based on z and c" Endheading int param p_z2 caption = "Times" min = 0 default = 1 endparam Contraction param f_ZContraction2 caption = "z/c -> new z" default = JLB_MandelbrotContraction ; hint = "The default Null Contraction does nothing." endparam Heading Endheading } class JLB_ZCZDualTransform(DualTransform) { ; ZCZDualTransform does three functions. ; p_z calls to a function, new z = ZContraction(z, c) ; p_c calls to a function, new c = CContraction(z, c) ; p_t calls to a function, new z = UserTransform(z) ; (Was UtilityTransform in version 100) public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_ZCZDualTransform(Generic pparent) DualTransform.DualTransform(pparent) m_ZContraction = new @f_ZContraction(this) m_CContraction = new @f_CContraction(this) ; m_UserTransform = new @f_UserTransform(this) if (@v_ZCZDualTransform > 100) m_UserTransform = new @f_UserTransform(this) else m_UtilityTransform = new @f_UtilityTransform(this) endif endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) int i i = 0 while (i < @p_z) pz = m_ZContraction.Iterate(pz, pc) if (isNan(|pz|)) return true endif i = i + 1 endwhile i = 0 while (i < @p_c) pc = m_CContraction.Iterate(pz, pc) i = i + 1 endwhile if (@v_ZCZDualTransform > 100) i = 0 while (i < @p_t) pz = m_UserTransform.Iterate(pz) if (isNan(|pz|)) return true endif i = i + 1 endwhile else i = 0 while (i < @p_t) pz = m_UtilityTransform.Iterate(pz) if (isNan(|pz|)) return true endif i = i + 1 endwhile endif return true endfunc protected: Contraction m_ZContraction Contraction m_CContraction UserTransform m_UserTransform UtilityTransform m_UtilityTransform default: rating = NotRecommended title = "ZCZ DualTransform" int param v_ZCZDualTransform caption = "Version (ZCZDualTransform)" default = 101 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ZCZDualTransform < 101 endparam Heading Endheading Heading caption = "New z based on z and c" Endheading int param p_z caption = "Times" min = 0 default = 1 endparam Contraction param f_ZContraction caption = "z/c -> new z" default = JLB_MandelbrotContraction ; hint = "The default Null Contraction does nothing." endparam Heading caption = "New c based on z and c" Endheading int param p_c caption = "Times" min = 0 default = 0 endparam Contraction param f_CContraction caption = "z/c -> new c" default = JLB_NullCContraction hint = "The default Null Contraction does nothing." endparam Heading caption = "New z based on z" Endheading int param p_t caption = "Times" min = 0 default = 0 endparam UserTransform param f_UserTransform caption = "z -> new z" default = JLB_NullUserTransform hint = "The default Null Transform does nothing." visible = (@v_ZCZDualTransform > 100) endparam UtilityTransform param f_UtilityTransform caption = "z -> new z" default = JLB_NullUtilityTransform hint = "The default Null Transform does nothing." visible = (@v_ZCZDualTransform < 101) endparam Heading Endheading } class JLB_BurningShipContraction(Contraction) { ; The Burning Ship formula as a Contraction. public: ; @param pz ; @param pc ; @return the new pz complex func Iterate(complex pz, complex pc) float zx float zy if (@p_std) zx = abs(real(pz)) zy = abs(imag(pz)) return sqr(zx+flip(zy)) + pc else zx=abs(real(@xfunction(real(pz-@p_zoffset))))^@xpower zy=abs(real(@yfunction(imag(pz-@p_zoffset))))^@ypower return (@xweight*zx+@yweight*flip(zy))^@zpower+(pc - @p_coffset) endif endfunc default: title = "Burning Ship" rating = NotRecommended int param v_BurningShipcontraction caption = "Version (BurningShip_Contraction)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_BurningShipcontraction < 100 endparam bool param p_std caption = "Standard" default = true endparam heading caption="General" visible = !@p_std endheading complex param p_zoffset caption = "pz offset" default = (0,0) visible = !@p_std endparam complex param p_coffset caption = "pc offset" default = (0,0) visible = !@p_std endparam complex param zpower caption="power" default=2 visible = !@p_std endparam ; ; x parameters ; heading caption="X" visible = !@p_std endheading float param xpower caption="power" default=1 visible = !@p_std endparam func xfunction caption="function" default=ident() visible = !@p_std endfunc complex param xweight caption="weight" default=1 visible = !@p_std endparam ; ; y parameters ; heading caption="Y" visible = !@p_std endheading float param ypower caption="power" default=1 visible = !@p_std endparam func yfunction caption="function" default=ident() visible = !@p_std endfunc complex param yweight caption="weight" default=1 visible = !@p_std endparam } class JLB_ZTweakContraction(Contraction) { ; The Z tweaks, as in Compounding Tweaked Mandelbrot from lkm.ufm, ; as a Contraction. public: ; @param pz ; @param pc ; @return the new pz complex func Iterate(complex pz, complex pc) if (@tweaktype=="fn(c)") return pz + @tweakage*@tweakfunction(pc) elseif (@tweaktype=="fn(z)") return pz + @tweakage*@tweakfunction(pz) elseif (@tweaktype=="fn(c*z)") return pz + @tweakage*@tweakfunction(pc*pz) elseif (@tweaktype=="fn(z/c)") return pz + @tweakage*@tweakfunction(pz/pc) else;if (@tweaktype=="fn(c/z)") return pz + @tweakage*@tweakfunction(pc/pz) endif endfunc default: title = "Tweak Z" rating = NotRecommended int param v_ztweakcontraction caption = "Version (ztweak_Contraction)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ztweakcontraction < 100 endparam param tweaktype caption="tweaking type" default=0 enum= "fn(c)" "fn(z)" "fn(c*z)" "fn(z/c)" "fn(c/z)" hint="Sets how z gets tweaked." endparam param tweakage caption="tweaking amount" default=(0.01,0.0) hint="Usually small." endparam func tweakfunction caption="tweaking function" default=recip() hint="Function of the tweaking variable." endfunc } class JLB_CTweakContraction(Contraction) { ; The C tweaks, as in Compounding Tweaked Mandelbrot from lkm.ufm, ; as a Contraction. public: ; @param pz ; @param pc ; @return the new pz complex func Iterate(complex pz, complex pc) if (@tweaktype=="fn(c)") return pc + @tweakage*@tweakfunction(pc) elseif (@tweaktype=="fn(z)") return pc + @tweakage*@tweakfunction(pz) elseif (@tweaktype=="fn(c*z)") return pc + @tweakage*@tweakfunction(pc*pz) elseif (@tweaktype=="fn(z/c)") return pc + @tweakage*@tweakfunction(pz/pc) else;if (@tweaktype=="fn(c/z)") return pc + @tweakage*@tweakfunction(pc/pz) endif endfunc default: title = "Tweak C" rating = NotRecommended int param v_ctweakcontraction caption = "Version (ztweak_Contraction)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ctweakcontraction < 100 endparam param tweaktype caption="tweaking type" default=0 enum= "fn(c)" "fn(z)" "fn(c*z)" "fn(z/c)" "fn(c/z)" hint="Sets how c gets tweaked." endparam param tweakage caption="tweaking amount" default=(0.01,0.0) hint="Usually small." endparam func tweakfunction caption="tweaking function" default=recip() hint="Function of the tweaking variable." endfunc } class JLB_NullCContraction(Contraction) { ; A do-nothing C Contraction. public: ; @param pz ; @param pc ; @return the same pc complex func Iterate(complex pz, complex pc) return pc endfunc default: title = "returns c" ;"Null Contraction" rating = NotRecommended int param v_nullccontraction caption = "Version (JLB_NullCContraction)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_nullccontraction < 100 endparam } class JLB_NullZContraction(Contraction) { ; A do-nothing Z Contraction. public: ; @param pz ; @param pc ; @return the same pc complex func Iterate(complex pz, complex pc) return pz endfunc default: title = "returns z" ;"Null Contraction" rating = NotRecommended int param v_nullccontraction caption = "Version (JLB_NullCContraction)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_nullccontraction < 100 endparam } class JLB_NewtonUserTransform(common.ulb:UserTransform) { ; The Newton formula as a Transform. public: ; @param pz ; @return the new pz complex func Iterate(complex pz) if (@p_std) return (2*sqr(pz)*pz+1)/(3*sqr(pz)) else ; complex pm1 = @p_power - 1 ; complex pzp = pz ^ pm1 ; return pz * (1-@relax) + \ ; @relax * (pm1 * pz * pzp + @r) / (@p_power * pzp) return pz * (1-@relax) + \ @relax * ((@p_power - 1) * pz^@p_power + @r) / \ (@p_power * pz ^ (@p_power - 1)) endif endfunc default: title = "Newton" rating = NotRecommended int param v_NewtonUserTransform caption = "Version (Newton_UserTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_NewtonUserTransform < 100 endparam bool param p_std caption = "Standard" default = true endparam complex param p_power caption = "Exponent" default = (3,0) hint = "Specifies the exponent of the equation that is solved by \ Newton's method. Use real numbers (set the imaginary part \ to zero) to obtain classic Newton fractals." visible = !@p_std endparam param r caption = "Root" default = (1,0) hint = "Specifies the root of the equation that is solved. Use larger \ numbers for slower convergence." visible = !@p_std endparam param relax caption = "Relaxation" default = (1,0) hint = "This can be used to alter the convergence of \ the formula." visible = !@p_std endparam } class JLB_NullUserTransform(common.ulb:UserTransform) { ; A do-nothing Transform public: func JLB_NULLUserTransform(Generic pparent) UserTransform.UserTransform(pparent) endfunc ; @param pz ; @return the same pz complex func Iterate(complex pz) return pz endfunc default: title = "(No change)" ;"Null User Transform" rating = NotRecommended int param v_nullUsertransform caption = "Version (NullUserTransform)" default = 100 hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used." visible = @v_nullUsertransform < 100 endparam } class JLB_SpiroGlyphicUserTransform(common.ulb:UserTransform) { ; Part of the Spiroglyphics formula, as in tma2.ufm, as a Transform. public: func JLB_SpiroGlyphicUserTransform(Generic pparent) UserTransform.UserTransform(pparent) endfunc func Init(complex pz) if @op1 == "++++" m1=+1, m2=+1, m3=+1, m4=+1 elseif @op1 == "+++-" m1=+1, m2=+1, m3=+1, m4=-1 elseif @op1 == "++-+" m1=+1, m2=+1, m3=-1, m4=+1 elseif @op1 == "+-++" m1=+1, m2=-1, m3=+1, m4=+1 elseif @op1 == "-+++" m1=-1, m2=+1, m3=+1, m4=+1 elseif @op1 == "++--" m1=+1, m2=+1, m3=-1, m4=-1 elseif @op1 == "+--+" m1=+1, m2=-1, m3=-1, m4=+1 elseif @op1 == "--++" m1=-1, m2=-1, m3=+1, m4=+1 elseif @op1 == "-++-" m1=-1, m2=+1, m3=+1, m4=-1 elseif @op1 == "+-+-" m1=+1, m2=-1, m3=+1, m4=-1 elseif @op1 == "-+-+" m1=-1, m2=+1, m3=-1, m4=+1 elseif @op1 == "+---" m1=+1, m2=-1, m3=-1, m4=+1 elseif @op1 == "-+--" m1=-1, m2=+1, m3=-1, m4=-1 elseif @op1 == "--+-" m1=-1, m2=-1, m3=+1, m4=-1 elseif @op1 == "---+" m1=-1, m2=-1, m3=-1, m4=+1 else;if @op1 == "----" m1=-1, m2=-1, m3=-1, m4=-1 endif if @op2 == "++++" n1=+1, n2=+1, n3=+1, n4=+1 elseif @op2 == "+++-" n1=+1, n2=+1, n3=+1, n4=-1 elseif @op2 == "++-+" n1=+1, n2=+1, n3=-1, n4=+1 elseif @op2 == "+-++" n1=+1, n2=-1, n3=+1, n4=+1 elseif @op2 == "-+++" n1=-1, n2=+1, n3=+1, n4=+1 elseif @op2 == "++--" n1=+1, n2=+1, n3=-1, n4=-1 elseif @op2 == "+--+" n1=+1, n2=-1, n3=-1, n4=+1 elseif @op2 == "--++" n1=-1, n2=-1, n3=+1, n4=+1 elseif @op2 == "-++-" n1=-1, n2=+1, n3=+1, n4=-1 elseif @op2 == "+-+-" n1=+1, n2=-1, n3=+1, n4=-1 elseif @op2 == "-+-+" n1=-1, n2=+1, n3=-1, n4=+1 elseif @op2 == "+---" n1=+1, n2=-1, n3=-1, n4=+1 elseif @op2 == "-+--" n1=-1, n2=+1, n3=-1, n4=-1 elseif @op2 == "--+-" n1=-1, n2=-1, n3=+1, n4=-1 elseif @op2 == "---+" n1=-1, n2=-1, n3=-1, n4=+1 else;if @op2 == "----" n1=-1, n2=-1, n3=-1, n4=-1 endif endfunc ; @param pz ; @return the new pz complex func Iterate(complex pz) complex x = real(@fnx(pz)) + flip(real(@start/10)) complex y = imag(@fny(pz)) + flip(imag(@start/10)) complex newx = y complex newy = x int i = 0 if @chain == "Separate" while i < @flavor i = i + 1 newx = y + m1*real(@h2a/10)*@fn1(@a1 * newx) + \ m2*imag(@h2a/10)*@fn3(@a2 * newx) newy = x + m3*real(@h2b/10)*@fn2(@a3 * newy) + \ m4 *imag(@h2b/10)*@fn4(@a4 * newy) endwhile x = x + n1*real(@h1a/10)*@fn5(newx) + n2*imag(@h1a/10)*@fn7(newx) y = y + n3*real(@h1b/10)*@fn6(newy) + n4*imag(@h1b/10)*@fn8(newy) elseif @chain == "Ganged" while i < @flavor i = i + 1 newx = y + m1*real(@h2/10)*@fn1(@a1 * newx) + \ m2*imag(@h2/10)*@fn3(@a2 * newx) newy = x + m3*real(@h2/10)*@fn2(@a3 * newy) + \ m4*imag(@h2/10)*@fn4(@a4 * newy) endwhile x = x + n1*real(@h1/10)*@fn5(newx) + n2*imag(@h1/10)*@fn7(newx) y = y + n3*real(@h1/10)*@fn6(newy) + n4*imag(@h1/10)*@fn8(newy) endif if @op == "x+y" pz = @fna(x) + flip(@fnb(y)) elseif @op == "x-y" pz = @fna(x)- flip(@fnb(y)) else;if @op == "y-x" pz = flip(@fnb(y)) - @fna(x) endif return pz endfunc protected: int m1, int m2, int m3, int m4 int n1, int n2, int n3, int n4 default: rating = NotRecommended title = "Spiroglyphic" int param v_SpiroglyphicUsertransform caption = "Version (SpiroglyphicUserTransform)" default = 100 hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used." visible = @v_SpiroglyphicUsertransform < 100 endparam int param chain caption = "Intensity Mode" enum = "Separate" "Ganged" default = 0 hint = "Choose whether X/Y intensity and step sizes vary together \ or separately" endparam complex param h1a caption = "Intensity X" default = (.1,.1) visible = @chain == 0 endparam complex param h1b caption = "Intensity Y" default = (.1,.1) visible = @chain == 0 endparam complex param h2a caption = "Step Size X" default = (.8,.8) visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0)) endparam complex param h2b caption = "Step Size Y" default = (.8,.8) visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0)) endparam complex param h1 caption = "Intensity X/Y" default = (.1, .1) visible = @chain == 1 endparam complex param h2 caption = "Step Size X/Y" default = (.8,.8) visible = @chain == 1 && @h1 != (0,0) endparam complex param start caption = "Glyph Start" default = (0,0) endparam int param flavor caption = "Flavor" default = 2 min = 0 hint = "This is an integer param which works in steps. Higher \ numbers generally create more intense effects" visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a1 caption = "Alpha 1" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a2 caption = "Alpha 2" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a3 caption = "Alpha 3" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a4 caption = "Alpha 4" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam param op caption = "Main Operator" enum = "x+y" "x-y" "y-x" default = 0 endparam param op1 caption = "Operator 1" enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \ "-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----" default = 0 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam param op2 caption = "Operator 2" enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \ "-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----" default = 7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam func fn1 caption = "Function 1" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn2 caption = "Function 2" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn3 caption = "Function 3" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn4 caption = "Function 4" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn5 caption = "Function 5" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn6 caption = "Function 6" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn7 caption = "Function 7" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn8 caption = "Function 8" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fna caption = "Initial X Fn" default = ident() endfunc func fnb caption = "Initial Y Fn" default = ident() endfunc func fnx caption = "Global X Fn" default = ident() endfunc func fny caption = "Global Y Fn" default = ident() endfunc } class JLB_MoebiusUserTransform(common.ulb:UserTransform) { ; The Moebius Transform, z = (a1*z + a2) / (a3*z + a4). ; Can also be applied to c, of course. ; June 2021 renamed parameters and added quadratic option public: ; @param pz ; @return the new pz complex func Iterate(complex pz) if @fz == 0 return (@a0 + @a1*pz) / (@b0 + @b1*pz) else return (@a0 + @a1*@f(@a2*pz)) / (@b0 + @b1*@f(@b2*pz)) endif endfunc default: rating = NotRecommended title = "Moebius" int param v_MoebiusUserTransform caption = "Version (Moebius_UserTransform)" default = 200 hint = "Old version." visible = @v_MoebiusUserTransform < 200 endparam heading text = "(v can be either z or c)" endheading heading caption = "v_new = (a0+a1*v)/(b0+b1*v)" visible = @fz == 0 endheading heading caption = "v_new = (a0+a1*F(a2*v)/(b0+b1*F(b2*v))" visible = @fz == 1 endheading param fz caption = "v or F(a*v)" enum = "v" "F(a*v)" default = 0 endparam func f caption = "F" default = sin() visible = @fz == 1 endfunc complex param a0 caption = "Moebius: a0" default = (0,0) endparam complex param a1 caption = "Moebius: a1" default = (1,0) endparam complex param a2 caption = "Moebius: a2" default = (1,0) visible = @fz == 1 endparam complex param b0 caption = "Moebius: b0" default = (1,0) endparam complex param b1 caption = "Moebius: b1" default = (-1,0) endparam complex param b2 caption = "Moebius: b2" default = (1,0) visible = @fz == 1 endparam } class JLB_ComboDualTransform(DualTransform) { ; ComboDualTransform does two UserTransforms and combines them ; with one of the operators +, -, *, /, ^. public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_ComboDualTransform(Generic pparent) DualTransform.DualTransform(pparent) m_UserTransform1 = new @f_UserTransform1(this) m_UserTransform2 = new @f_UserTransform2(this) endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) complex t1 if (@mode1 == "z") t1 = m_UserTransform1.Iterate(pz) else t1 = m_UserTransform1.Iterate(pc) endif complex t2 if (@mode2 == "z") t2 = m_UserTransform2.Iterate(pz) else t2 = m_UserTransform2.Iterate(pc) endif if (@op == "+") t1 = t1 + t2 elseif (@op == "-") t1 = t1 - t2 elseif (@op == "*") t1 = t1 * t2 elseif (@op == "/") t1 = t1 / t2 else;if (@op == "^") t1 = t1 ^ t2 endif if (@mode0 == "z") pz = t1 else pc = t1 endif return true endfunc protected: UserTransform m_UserTransform1 UserTransform m_UserTransform2 default: rating = NotRecommended title = "Combo Dual Transform" int param v_ComboDualTransform caption = "Version (ComboDualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ComboDualTransform < 100 endparam param mode0 caption = "Change z or c?" default = 0 enum = "z" "c" hint = "Which variable to change" endparam Heading caption = "First transform" Endheading param mode1 caption = "Based on z or c?" default = 0 enum = "z" "c" endparam UserTransform param f_UserTransform1 caption = "Transform 1" default = JLB_BasicUserTransform ; hint = "The default Null BasicTransform does nothing." endparam Heading Endheading param op caption = "op" enum = "+" "-" "*" "/" "^" default = 0 hint = "result = First transform op second transform" endparam Heading caption = "Second transform" Endheading param mode2 caption = "Based on z or c?" default = 1 enum = "z" "c" endparam UserTransform param f_UserTransform2 default = JLB_NullUserTransform caption = "Transform 2" ; hint = "The default Null BasicTransform does nothing." endparam } class JLB_SpiroglyphicContraction(Contraction) { ; Part of the Spiroglyphics formula, as in tma2.ufm, as a Contraction. public: ; @param pz ; @param pc ; @return the contracted value complex func Iterate(complex pz, complex pc) if @select == "z"; select variable type pz = @fnz(pz-@zg)*@ezg elseif @select == "z+c" pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z-c" pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "c-z" pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg elseif @select == "z*c" pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z/c" pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z+c|z+c" pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z+c|c-z" pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg elseif @select == "z+c|z*c" pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z+c|z/c" pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z-c|z-c" pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z-c|c-z" pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg elseif @select == "z-c|z*c" pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z-c|z/c" pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "c-z|z*c" pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "c-z|z/c" pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z*c|c-z" pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg elseif @select == "z*c|z*c" pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z/c|z+c" pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z/c|z-c" pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z/c|c-z" pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg elseif @select == "z/c|z/c" pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z*c+(Rz+Iz)" pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) elseif @select == "z/c+(Rz+Iz)" pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) elseif @select == "z/c-(Rz+Iz)" pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)-((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) elseif @select == "z*c-+(Rz+Iz)" pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)-((real(pz+@addz)\ *@muzr)\ ^@exzr+(imag(pz+@addz)*@muzi)^@exzi) pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) elseif @select == "z/c-+(Rz+Iz)" pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)-((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) pz = (@fnz(pz-@zg)*@ezg/@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) elseif @select == "z*c+(Rz+Iz)|z+c" pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) pz = @fnz(pz-@zg)*@ezg + @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z*c+(Rz+Iz)|z-c" pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) pz = @fnz(pz-@zg)*@ezg - @fnc((pc-@cg)*@cmg)^@ecg elseif @select == "z*c+(Rz+Iz)|c-z" pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) pz = @fnc((pc-@cg)*@cmg)^@ecg - @fnz(pz-@zg)*@ezg elseif @select == "z*c+(Rz+Iz)|z*c" pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) pz = @fnz(pz-@zg)*@ezg * @fnc((pc-@cg)*@cmg)^@ecg else;if @select == "z*c+(Rz+Iz)|z/c" pz = (@fnz(pz-@zg)*@ezg*@fnc((pc-@cg)*@cmg)^@ecg)+((real(pz+@addz)\ *@muzr)^@exzr+(imag(pz+@addz)*@muzi)^@exzi) pz = @fnz(pz-@zg)*@ezg / @fnc((pc-@cg)*@cmg)^@ecg endif return pz endfunc default: title = "Spiroglyphic" rating = NotRecommended int param v_SpiroglyphicContraction caption = "Version (TMA_Contraction)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_SpiroglyphicContraction < 100 endparam param select caption = "Z Mode" enum = "z" "z+c" "z-c" "c-z" "z*c" "z/c" "z+c|z+c" "z+c|c-z" "z+c|z*c"\ "z+c|z/c" "z-c|z-c" "z-c|c-z" "z-c|z*c" "z-c|z/c" "c-z|z*c" "c-z|z/c"\ "z*c|c-z" "z*c|z*c" "z/c|z+c" "z/c|z-c" "z/c|c-z" "z/c|z/c"\ "z*c+(Rz+Iz)" "z/c+(Rz+Iz)" "z/c-(Rz+Iz)" "z*c-+(Rz+Iz)"\ "z/c-+(Rz+Iz)" "z*c+(Rz+Iz)|z+c" "z*c+(Rz+Iz)|z-c" "z*c+(Rz+Iz)|c-z"\ "z*c+(Rz+Iz)|z*c" "z*c+(Rz+Iz)|z/c" default = 5 hint = "Determines the initial definition of Z" endparam complex param zg caption = "Z Param 1" default = (0,0) endparam complex param ezg caption = "Z Param 2" default = (1,0) endparam complex param addz caption = "Z Param 3" default = (1.0,0.0) visible = ( ((@select == 22)||(@select == 23)||(@select == 24)||\ (@select == 25)||(@select == 26)|| (@select == 27)||\ (@select == 28)||(@select == 29)||(@select == 30)|| \ (@select == 31)) endparam complex param muzr caption = "Z Strength re" default = (1.0,0.0) visible = ((@select == 22)||(@select == 23)||(@select == 24)||\ (@select == 25)||(@select == 26)|| (@select == 27)||\ (@select == 28)||(@select == 29)||(@select == 30)|| \ (@select == 31)) endparam complex param muzi caption = "Z Strength im" default = (1.0,0.0) visible = ((@select == 22)||(@select == 23)||(@select == 24)||\ (@select == 25)||(@select == 26)|| (@select == 27)||\ (@select == 28)||(@select == 29)||(@select == 30)|| \ (@select == 31)) endparam complex param exzr caption = "Z Power re" default = (1.0,0.0) visible = ((@select == 22)||(@select == 23)||(@select == 24)||\ (@select == 25)||(@select == 26)|| (@select == 27)||\ (@select == 28)||(@select == 29)||(@select == 30)|| \ (@select == 31)) endparam complex param exzi caption = "Z Power im" default = (1.0,0.0) visible = ((@select == 22)||(@select == 23)||(@select == 24)||\ (@select == 25)||(@select == 26)|| (@select == 27)||\ (@select == 28)||(@select == 29)||(@select == 30)|| \ (@select == 31)) endparam complex param cg caption = "C Param 1" default = (0,0) visible = @select != 0 endparam complex param cmg caption = "C Param 2" default = (1,0) visible = @select != 0 endparam complex param ecg caption = "C Param 3" default = (1,0) visible = @select != 0 endparam func fnz caption = "Global Z Func" default = sin() hint = "Applies a function to the initial Z" endfunc func fnc caption = "Global C Func" default = ident() visible = @select != 0 hint = "Applies a function to the initial C" endfunc } ; Here only for compatibility with version 100 of JLB_ZCZDualTransform class JLB_NullUtilityTransform(common.ulb:UtilityTransform) { ; A do-nothing Transform public: func JLB_NULLUtilityTransform(Generic pparent) UtilityTransform.UtilityTransform(pparent) endfunc ; @param pz ; @return the same pz complex func Iterate(complex pz) return pz endfunc default: rating = NotRecommended title = "(No change)" ;"Null Utility Transform" int param v_nullUtilitytransform caption = "Version (NullUtilityTransform)" default = 100 hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used." visible = @v_nullUtilitytransform < 100 endparam } ; Here only for compatibility with version 100 of JLB_ZCZDualTransform class JLB_NewtonUtilityTransform(common.ulb:UtilityTransform) { ; The Newton formula as a Transform. public: ; @param pz ; @return the new pz complex func Iterate(complex pz) if (@p_std) return (2*sqr(pz)*pz+1)/(3*sqr(pz)) else return pz*(1-@relax) + \ @relax * ((@p_power - 1) * pz^@p_power + @r) / \ (@p_power * pz ^ (@p_power - 1)) endif endfunc default: rating = NotRecommended title = "Newton" int param v_NewtonUtilityTransform caption = "Version (Newton_UtilityTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_NewtonUtilityTransform < 100 endparam bool param p_std caption = "Standard" default = true endparam complex param p_power caption = "Exponent" default = (3,0) hint = "Specifies the exponent of the equation that is solved by \ Newton's method. Use real numbers (set the imaginary part \ to zero) to obtain classic Newton fractals." visible = !@p_std endparam param r caption = "Root" default = (1,0) hint = "Specifies the root of the equation that is solved. Use larger \ numbers for slower convergence." visible = !@p_std endparam param relax caption = "Relaxation" default = (1,0) hint = "This can be used to alter the convergence of \ the formula." visible = !@p_std endparam } ; Here only for compatibility with version 100 of JLB_ZCZDualTransform class JLB_SpiroGlyphicUtilityTransform(common.ulb:UtilityTransform) { ; Part of the Spiroglyphics formula, as in tma2.ufm, as a Transform. public: func JLB_SpiroGlyphicUtilityTransform(Generic pparent) UtilityTransform.UtilityTransform(pparent) endfunc func Init(complex pz) if @op1 == "++++" m1=+1, m2=+1, m3=+1, m4=+1 elseif @op1 == "+++-" m1=+1, m2=+1, m3=+1, m4=-1 elseif @op1 == "++-+" m1=+1, m2=+1, m3=-1, m4=+1 elseif @op1 == "+-++" m1=+1, m2=-1, m3=+1, m4=+1 elseif @op1 == "-+++" m1=-1, m2=+1, m3=+1, m4=+1 elseif @op1 == "++--" m1=+1, m2=+1, m3=-1, m4=-1 elseif @op1 == "+--+" m1=+1, m2=-1, m3=-1, m4=+1 elseif @op1 == "--++" m1=-1, m2=-1, m3=+1, m4=+1 elseif @op1 == "-++-" m1=-1, m2=+1, m3=+1, m4=-1 elseif @op1 == "+-+-" m1=+1, m2=-1, m3=+1, m4=-1 elseif @op1 == "-+-+" m1=-1, m2=+1, m3=-1, m4=+1 elseif @op1 == "+---" m1=+1, m2=-1, m3=-1, m4=+1 elseif @op1 == "-+--" m1=-1, m2=+1, m3=-1, m4=-1 elseif @op1 == "--+-" m1=-1, m2=-1, m3=+1, m4=-1 elseif @op1 == "---+" m1=-1, m2=-1, m3=-1, m4=+1 else;if @op1 == "----" m1=-1, m2=-1, m3=-1, m4=-1 endif if @op2 == "++++" n1=+1, n2=+1, n3=+1, n4=+1 elseif @op2 == "+++-" n1=+1, n2=+1, n3=+1, n4=-1 elseif @op2 == "++-+" n1=+1, n2=+1, n3=-1, n4=+1 elseif @op2 == "+-++" n1=+1, n2=-1, n3=+1, n4=+1 elseif @op2 == "-+++" n1=-1, n2=+1, n3=+1, n4=+1 elseif @op2 == "++--" n1=+1, n2=+1, n3=-1, n4=-1 elseif @op2 == "+--+" n1=+1, n2=-1, n3=-1, n4=+1 elseif @op2 == "--++" n1=-1, n2=-1, n3=+1, n4=+1 elseif @op2 == "-++-" n1=-1, n2=+1, n3=+1, n4=-1 elseif @op2 == "+-+-" n1=+1, n2=-1, n3=+1, n4=-1 elseif @op2 == "-+-+" n1=-1, n2=+1, n3=-1, n4=+1 elseif @op2 == "+---" n1=+1, n2=-1, n3=-1, n4=+1 elseif @op2 == "-+--" n1=-1, n2=+1, n3=-1, n4=-1 elseif @op2 == "--+-" n1=-1, n2=-1, n3=+1, n4=-1 elseif @op2 == "---+" n1=-1, n2=-1, n3=-1, n4=+1 else;if @op2 == "----" n1=-1, n2=-1, n3=-1, n4=-1 endif endfunc ; @param pz ; @return the new pz complex func Iterate(complex pz) complex x = real(@fnx(pz)) + flip(real(@start/10)) complex y = imag(@fny(pz)) + flip(imag(@start/10)) complex newx = y complex newy = x int i = 0 if @chain == "Separate" while i < @flavor i = i + 1 newx = y + m1*real(@h2a/10)*@fn1(@a1 * newx) + \ m2*imag(@h2a/10)*@fn3(@a2 * newx) newy = x + m3*real(@h2b/10)*@fn2(@a3 * newy) + \ m4 *imag(@h2b/10)*@fn4(@a4 * newy) endwhile x = x + n1*real(@h1a/10)*@fn5(newx) + n2*imag(@h1a/10)*@fn7(newx) y = y + n3*real(@h1b/10)*@fn6(newy) + n4*imag(@h1b/10)*@fn8(newy) elseif @chain == "Ganged" while i < @flavor i = i + 1 newx = y + m1*real(@h2/10)*@fn1(@a1 * newx) + \ m2*imag(@h2/10)*@fn3(@a2 * newx) newy = x + m3*real(@h2/10)*@fn2(@a3 * newy) + \ m4*imag(@h2/10)*@fn4(@a4 * newy) endwhile x = x + n1*real(@h1/10)*@fn5(newx) + n2*imag(@h1/10)*@fn7(newx) y = y + n3*real(@h1/10)*@fn6(newy) + n4*imag(@h1/10)*@fn8(newy) endif if @op == "x+y" pz = @fna(x) + flip(@fnb(y)) elseif @op == "x-y" pz = @fna(x)- flip(@fnb(y)) else;if @op == "y-x" pz = flip(@fnb(y)) - @fna(x) endif return pz endfunc protected: int m1, int m2, int m3, int m4 int n1, int n2, int n3, int n4 default: rating = NotRecommended title = "Spiroglyphic" int param v_SpiroglyphicUtilitytransform caption = "Version (SpiroglyphicUtilityTransform)" default = 100 hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used." visible = @v_SpiroglyphicUtilitytransform < 100 endparam int param chain caption = "Intensity Mode" enum = "Separate" "Ganged" default = 0 hint = "Choose whether X/Y intensity and step sizes vary together \ or separately" endparam complex param h1a caption = "Intensity X" default = (.1,.1) visible = @chain == 0 endparam complex param h1b caption = "Intensity Y" default = (.1,.1) visible = @chain == 0 endparam complex param h2a caption = "Step Size X" default = (.8,.8) visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0)) endparam complex param h2b caption = "Step Size Y" default = (.8,.8) visible = @chain == 0 && (@h1a != (0,0) || @h1b != (0,0)) endparam complex param h1 caption = "Intensity X/Y" default = (.1, .1) visible = @chain == 1 endparam complex param h2 caption = "Step Size X/Y" default = (.8,.8) visible = @chain == 1 && @h1 != (0,0) endparam complex param start caption = "Glyph Start" default = (0,0) endparam int param flavor caption = "Flavor" default = 2 min = 0 hint = "This is an integer param which works in steps. Higher \ numbers generally create more intense effects" visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a1 caption = "Alpha 1" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a2 caption = "Alpha 2" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a3 caption = "Alpha 3" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam float param a4 caption = "Alpha 4" default = 2.7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam param op caption = "Main Operator" enum = "x+y" "x-y" "y-x" default = 0 endparam param op1 caption = "Operator 1" enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \ "-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----" default = 0 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam param op2 caption = "Operator 2" enum = "++++" "+++-" "++-+" "+-++" "-+++" "++--" "+--+" "--++" \ "-++-" "+-+-" "-+-+" "+---" "-+--" "--+-" "---+" "----" default = 7 visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endparam func fn1 caption = "Function 1" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn2 caption = "Function 2" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn3 caption = "Function 3" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn4 caption = "Function 4" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn5 caption = "Function 5" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn6 caption = "Function 6" default = sin() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn7 caption = "Function 7" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fn8 caption = "Function 8" default = cos() visible = (@chain == 0 && @h1a != (0,0) || @h1b != (0,0) ) || \ (@chain == 1 && @h1 != (0,0)) endfunc func fna caption = "Initial X Fn" default = ident() endfunc func fnb caption = "Initial Y Fn" default = ident() endfunc func fnx caption = "Global X Fn" default = ident() endfunc func fny caption = "Global Y Fn" default = ident() endfunc } class 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 = NotRecommended title = "Basic" int param v_BasicUserTransform caption = "Version (Basic_UserTransform)" default = 200 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_BasicUserTransform < 100 endparam heading caption = "v_new = a1+a2*f(a3*v+a4)" endheading func f caption = "f" default = sqr() ;hint = "New v = a1+a2*f(a3*v+a4)" endfunc complex param a1 caption = "a1" default = (0,0) ;hint = "New v = a1+a2*f(a3*v+a4)" endparam complex param a2 caption = "a2" default = (1,0) ;hint = "New v = a1+a2*f(a3*v+a4)" endparam complex param a3 caption = "a3" default = (1,0) ;hint = "New v = a1+a2*f(a3*v+a4)" endparam complex param a4 caption = "a4" default = (0,0) ;hint = "New v = a1+a2*f(a3*v+a4)" endparam } class JLB_NewtonPolyUserTransform(common.ulb:UserTransform) { ; Iteration of polynomial(z) = root by Newton's method. ; A Transform version of JLB_PolyNewtonContraction public: func JLB_NewtonPolyUserTransform(Generic pparent) UserTransform.UserTransform(pparent) if (@p_poly_type == "Poly") m_a[0] = @p_a0, m_a[1] = @p_a1, m_a[2] = @p_a2, m_a[3] = @p_a3 m_a[4] = @p_a4, m_a[5] = @p_a5, m_a[6] = @p_a6, m_a[7] = @p_a7 m_a[8] = @p_a8, m_a[9] = @p_a9, m_a[10] = @p_a10 int i = 0 while (i < @p_degree - 1) m_ap[i] = (i+1)*m_a[i+1] m_app[i] = (i+2)*(i+1)*m_a[i+2] i = i + 1 endwhile i = @p_degree - 1 m_ap[i] = (i+1)*m_a[i+1] endif endfunc ; @param pz ; @return the new pz complex func Iterate(complex pz) complex f complex fp complex fpp = 0 ; to satisfy compiler int i if (@p_poly_type == "Poly") ; Solving f(z) = 0 i = @p_degree f = m_a[i] while (i > 0) i = i - 1 f = m_a[i] + pz * f endwhile ; df/dz i = @p_degree - 1 fp = m_ap[i] while (i > 0) i = i - 1 fp = m_ap[i] + pz * fp endwhile if (@p_iter_type > 0) ; d2f/dz2 i = @p_degree - 2 fpp = m_app[i] while (i > 0) i = i - 1 fpp = m_app[i] + pz * fpp endwhile endif else;if (@p_poly_type == "Power") f = pz^@p_power fp = @p_power*pz^(@p_power-1) if (@p_iter_type > 0) fpp = @p_power*(@p_power-1)*pz^(@p_power-2) endif endif if (@p_type == "Constant") f = f - @p_const ; elseif (@p_type == "C") ; f = f - pc else;if (@p_type == "Pixel") f = f - #pixel endif if (@p_iter_type == "Newton") return pz - @relax * f / fp elseif (@p_iter_type == "Type 1") ; approximate Halley 1/(1-x)~(1+x) return pz - @relax * (f/fp)*(1 + @p_alpha*f*fpp/(2*fp*fp)) elseif (@p_iter_type == "Type 2") ; Halley return pz - @relax * (f/fp) / ( 1 - @p_alpha*f*fpp/(2*fp*fp)) else;if (@p_iter_type == "Type 3") ; Laguerre complex root = sqrt(fp*fp-@p_alpha*2*f*fpp) complex d1 = fp + root complex d2 = fp - root if (|d1| >= |d2|) return pz - @relax * 2*f / d1 else return pz - @relax * 2*f / d2 endif endif endfunc protected: complex m_a[11] ; coefficients of polynomial complex m_ap[10] ; coefficients of first derivative of polynomial complex m_app[10] ; coefficients of second derivative of polynomial default: rating = NotRecommended title = "Newton Poly" int param v_NewtonPolyUserTransform caption = "Version (NewtonPoly_UserTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_NewtonPolyUserTransform < 100 endparam param p_poly_type caption = "Polynomial type" enum = "Poly" "Power" default = 1 hint = "Poly: polynomial has real powers, degree 10 or less. \ Power: polynomial is a single power, real or complex." endparam int param p_degree caption = "Highest power" default = 3 min = 2 max = 10 visible = (@p_poly_type == 0) endparam complex param p_a0 caption = "Constant coefficient" default = (0,0) visible = (@p_poly_type == 0) endparam complex param p_a1 caption = "Degree 1 coefficient" default = (0,0) visible = (@p_poly_type == 0) endparam complex param p_a2 caption = "Degree 2 coefficient" default = (0,0) visible = (@p_poly_type == 0) endparam complex param p_a3 caption = "Degree 3 coefficient" default = (1,0) visible = (@p_degree >= 3) && (@p_poly_type == 0) endparam complex param p_a4 caption = "Degree 4 coefficient" default = (0,0) visible = (@p_degree >= 4) && (@p_poly_type == 0) endparam complex param p_a5 caption = "Degree 5 coefficient" default = (0,0) visible = (@p_degree >= 5) && (@p_poly_type == 0) endparam complex param p_a6 caption = "Degree 6 coefficient" default = (0,0) visible = (@p_degree >= 6) && (@p_poly_type == 0) endparam complex param p_a7 caption = "Degree 7 coefficient" default = (0,0) visible = (@p_degree >= 7) && (@p_poly_type == 0) endparam complex param p_a8 caption = "Degree 8 coefficient" default = (0,0) visible = (@p_degree >= 8) && (@p_poly_type == 0) endparam complex param p_a9 caption = "Degree 9 coefficient" default = (0,0) visible = (@p_degree >= 9) && (@p_poly_type == 0) endparam complex param p_a10 caption = "Degree 10 coefficient" default = (0,0) visible = (@p_degree >= 10) && (@p_poly_type == 0) endparam complex param p_power caption = "Power" default = (3,0) visible = (@p_poly_type == 1) endparam param p_type caption = "cc" ; enum = "Constant" "C" "Pixel" enum = "Constant" "Pixel" default = 0 hint = "Iteration is one step in solving polynomial(z)-cc = 0. Try Pixel \ with Mandelbrot types, Constant with Julia types." endparam complex param p_const caption = "Constant" default = (1,0) visible = (@p_type == 0) endparam param p_iter_type caption = "Iteration type" enum = "Newton" "Type 1" "Type 2" "Type 3" default = 0 hint = "Newton is the usual, using only the first derivative. \ The other types also use the second derivative. Type 1 is Householder \ iteration if alpha = 1. Type 2 is Halley iteration if alpha = 2 and \ Schroder iteration if alpha = 1. Type 3 is Halley's irrational iteration \ if alpha = 1." endparam complex param p_alpha caption = "alpha" default = (1,0) hint = "Nonstandard values of alpha may not allow convergence, but can give \ interesting shapes." visible = (@p_iter_type > 0) endparam param relax caption = "Relaxation" default = (1,0) hint = "The standard value is 1. Nonstandard values may not allow \ convergence, but can give interesting shapes." endparam } class JLB_ContractionDualTransform(jlb.ulb:DualTransform) { ; Wrapper for a Contraction to plug into a DualTransform slot public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_ContractionDualTransform(Generic pparent) DualTransform.DualTransform(pparent) m_Contraction = new @f_Contraction(this) endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) pz = m_Contraction.Iterate(pz, pc) return true endfunc protected: Contraction m_Contraction default: rating = NotRecommended title = "ContractionDualTransform" int param v_ContractionDualTransform caption = "Version (ContractionDualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ContractionDualTransform < 100 endparam Contraction param f_Contraction caption = "Contraction" default = JLB_MandelbrotContraction ; hint = "The default Null Contraction does nothing." endparam } class JLB_UserTransformDualTransform(jlb.ulb:DualTransform) { ; Wrapper for a UserTransform to plug into a DualTransform slot public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_UserTransformDualTransform(Generic pparent) DualTransform.DualTransform(pparent) m_UserTransform = new @f_UserTransform(this) endfunc ; @param pz ; @param pc ; @return true if okay; possibly change both arguments bool func Iterate(complex &pz, complex &pc) pz = m_UserTransform.Iterate(pz) + @c*pc return true endfunc protected: UserTransform m_UserTransform default: rating = NotRecommended title = "UserTransformDualTransform" int param v_UserTransformDualTransform caption = "Version (UserTransformDualTransform)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_UserTransformDualTransform < 100 endparam UserTransform param f_UserTransform caption = "Transform" default = JLB_PowerUserTransform ; hint = "The default Null Contraction does nothing." endparam complex param c caption = "Const" default = 1 hint = "New z = transform(z) + const * c" endparam } class JLB_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: func JLB_Cells(Generic pparent) GradientColoring.GradientColoring(pparent) g = new Geometry ; only used for triangles StartRandom(100) MinArea = 0.01 * @pMinArea * #width * #height ; convert from percent MinSide = @pMinSide * #width MinSideSq = sqr(MinSide) xb = @pXBorder * #width yb = @pYBorder * #width lw = @B * #width NumSmall = 0 if @pWhich == 0 FirstTriangles() else NumCells = 1 V1[0] = xb + flip(yb) V2[0] = #width-xb + flip(#height-yb) Check(0) endif int tries = 0 ; just in case of disaster while NumSmall < NumCells && NumCells < @pMaxCells && tries < @pMaxCells if @pWhich == 0 Divide3() else Divide4() endif tries = tries + 1 endwhile Shuffle() endfunc func FirstTriangles() int num = 2 if @pFirstDiv == "3" && @pMaxCells >= 3 num = 3 endif if @pFirstDiv == "4" && @pMaxCells >= 4 num = 4 endif complex vul = xb + flip(yb) complex vur = #width-xb + flip(yb) complex vll = xb + flip(#height-yb) complex vlr = #width-xb + flip(#height-yb) if num == 2 ; two triangles if r.RandomFloat(0) < 0.5 V1[0] = vul, V2[0] = vur, V3[0] = vll V1[1] = vlr, V2[1] = vur, V3[1] = vll else V1[0] = vll, V2[0] = vul, V3[0] = vlr V1[1] = vur, V2[1] = vul, V3[1] = vlr endif elseif num == 3 ; first choose which side to divide float w = #width - 2*xb float h = #height - 2*yb int k if @pChoose == "Random" k = r.RandomIntInRange2(0, 4) elseif @pChoose == "Larger" float x = 2*(w+h)*r.RandomFloat(0) if x <= w k = 1 elseif x <= w + h k = 2 elseif x <= 2*w + h k = 3 else k = 4 endif else ; "Largest" if w == h k = r.RandomIntInRange2(0, 4) else k = 1 if w < h k = 2 endif if r.RandomFloat(0) > 0.5 k = k + 2 endif endif endif float frac = 0.5 if @pSlop > 0 frac = 0.5 + @pSlop*r.RandomFloat2(0) endif complex vvv if k == 1 ; top vvv = vul + frac*(vur-vul) V1[0] = vul, V2[0] = vvv, V3[0] = vll V1[1] = vlr, V2[1] = vvv, V3[1] = vll V1[2] = vur, V2[2] = vvv, V3[2] = vlr elseif k == 2 ; right vvv = vur + frac*(vlr-vur) V1[0] = vul, V2[0] = vvv, V3[0] = vll V1[1] = vul, V2[1] = vvv, V3[1] = vur V1[2] = vll, V2[2] = vvv, V3[2] = vlr elseif k == 3 ; bottom vvv = vll + frac*(vlr-vll) V1[0] = vul, V2[0] = vvv, V3[0] = vll V1[1] = vul, V2[1] = vvv, V3[1] = vur V1[2] = vur, V2[2] = vvv, V3[2] = vlr else ; left vvv = vul + frac*(vll-vul) V1[0] = vul, V2[0] = vvv, V3[0] = vur V1[1] = vlr, V2[1] = vvv, V3[1] = vur V1[2] = vll, V2[2] = vvv, V3[2] = vlr endif else ; four triangles float frac = 0.5 if @pSlop > 0 frac = 0.5 + @pSlop*r.RandomFloat2(0) endif float xc = xb + frac*(#width-2*xb) if @pSlop > 0 frac = 0.5 + @pSlop*r.RandomFloat2(0) endif float yc = yb + frac*(#height-2*yb) complex vc = xc + flip(yc) ; the center vertex V1[0] = vul, V2[0] = vur, V3[0] = vc V1[1] = vll, V2[1] = vul, V3[1] = vc V1[2] = vll, V2[2] = vlr, V3[2] = vc V1[3] = vlr, V2[3] = vur, V3[3] = vc endif NumCells = num int i = 0 while i < NumCells Check(i) i = i + 1 endwhile endfunc func Init(complex pz, complex ppixel) GradientColoring.Init(pz, ppixel) endfunc func Divide3() int n = Choose() float frac if NumCells+3 > @pMaxCells || r.RandomFloat(0) > @pDivide4 ; divide into 2 triangles frac = 0.5 if @pSlop > 0 frac = 0.5 + @pSlop*r.RandomFloat2(0) endif ; divide longest side. later maybe other possibilities int k = g.LongestSide(V1[n], V2[n], V3[n]) complex w1, complex w2, complex w3 if k == 1 ; side v1v2 is longest; divide it w1 = V3[n], w2 = V1[n], w3 = V2[n] elseif k == 2 ; side v2v3 is longest w1 = V1[n], w2 = V3[n], w3 = V2[n] else ; side v3v1 is longest w1 = V2[n], w2 = V1[n], w3 = V3[n] endif complex w4 = w2 + frac*(w3-w2) V1[n] = w1, V2[n] = w2, V3[n] = w4 int m = NumCells V1[m] = w1, V2[m] = w3, V3[m] = w4 ; are the new cells divisible? Check(n) Check(m) NumCells = NumCells + 1 else ; divide into 4 triangles complex p1 = V1[n] complex p2 = V2[n] complex p3 = V3[n] frac = 0.5 + @pSlop*r.RandomFloat2(0) complex p4 = p1 + frac*(p2-p1) frac = 0.5 + @pSlop*r.RandomFloat2(0) complex p5 = p2 + frac*(p3-p2) frac = 0.5 + @pSlop*r.RandomFloat2(0) complex p6 = p3 + frac*(p1-p3) V1[n] = p1, V2[n] = p4, V3[n] = p6, Check(n) m = NumCells V1[m] = p3, V2[m] = p5, V3[m] = p6, Check(m) m = m + 1 V1[m] = p2, V2[m] = p4, V3[m] = p5, Check(m) m = m + 1 V1[m] = p4, V2[m] = p5, V3[m] = p6, Check(m) NumCells = NumCells + 3 endif endfunc func Divide4() int n = Choose() float frac if NumCells+4 > @pMaxCells || r.RandomFloat(0) >= @pDivide5 ; divide into 2 cells frac = 0.5 + @pSlop*r.RandomFloat2(0) bool divideX if Small[n] == 2 divideX = true elseif Small[n] == 1 divideX = false else float xx = real(V2[n]-V1[n]) float yy = imag(V2[n]-V1[n]) if xx != yy && r.RandomFloat(0) < @pPreferLong divideX = (xx >= yy) else divideX = r.RandomFloat(0) <= @pXFrac endif endif if divideX ; n is left part, new is right part V1[NumCells] = real(V1[n]+frac*(V2[n]-V1[n])) + flip(imag(V1[n])) V2[NumCells] = V2[n] ;V1[n] unchanged V2[n] = real(V1[NumCells]) + flip(imag(V2[n])) else ; n is top part, new is bottom part V1[NumCells] = real(V1[n]) + flip(imag(V1[n]+frac*(V2[n]-V1[n]))) V2[NumCells] = V2[n] ;V1[n] unchanged V2[n] = real(V2[n]) + flip(imag(V1[NumCells])) endif Check(n) Check(NumCells) NumCells = NumCells + 1 else ; divide into 5 cells float x1 = real(V1[n]), float y1 = imag(V1[n]) float x2 = real(V2[n]), float y2 = imag(V2[n]) ; if all the fracs are the same, the inner rectangle is centered. frac = (1+@pSlop*r.RandomFloat2(0))/3 float x3 = x1 + frac*(x2-x1) ;frac = (1+@pSlop*r.RandomFloat2(0))/3 float x4 = x2 - frac*(x2-x1) ;frac = (1+@pSlop*r.RandomFloat2(0))/3 float y3 = y1 + frac*(y2-y1) ;frac = (1+@pSlop*r.RandomFloat2(0))/3 float y4 = y2 - frac*(y2-y1) ; clockwise or counter-clockwise int m if r.RandomFloat2(0) > @pCW V1[n] = x1+flip(y1), V2[n] = x4+flip(y3), Check(n), m = NumCells V1[m] = x4+flip(y1), V2[m] = x2+flip(y4), Check(m), m = m + 1 V1[m] = x3+flip(y4), V2[m] = x2+flip(y2), Check(m), m = m + 1 V1[m] = x1+flip(y3), V2[m] = x3+flip(y2), Check(m), m = m + 1 V1[m] = x3+flip(y3), V2[m] = x4+flip(y4), Check(m) else V1[n] = x1+flip(y1), V2[n] = x3+flip(y4), Check(n), m = NumCells V1[m] = x3+flip(y1), V2[m] = x2+flip(y3), Check(m), m = m + 1 V1[m] = x4+flip(y3), V2[m] = x2+flip(y2), Check(m), m = m + 1 V1[m] = x1+flip(y4), V2[m] = x4+flip(y2), Check(m), m = m + 1 V1[m] = x3+flip(y3), V2[m] = x4+flip(y4), Check(m) endif NumCells = NumCells + 4 endif endfunc ; select cell to divide int func Choose() int n int nLarge = MakeLargeList() if LargestArea > @pRatio*SmallestArea int m = r.RandomIntInRange2(0, nLarge) - 1 return Large[m] endif if @pChoose == 0 ; any available cell is okay; uniform probability per cell ;r.SetNMax(NumCells) repeat n = r.RandomIntInRange2(0, NumCells) - 1 until Small[n] < 3 elseif @pChoose == 1 ; prefer to divide larger cells; probability proportional to area repeat repeat float x = r.RandomFloat(0)*#width float y = r.RandomFloat(0)*#height n = CellNum(x, y) until n >= 0 ; rounding can make the point be not in any triangle. until Small[n] < 3 else ; only do one of the largest ones. (Guaranteed to be dividable.) int m = r.RandomIntInRange2(0, nLarge) - 1 n = Large[m] endif return n endfunc int func MakeLargeList() SmallestArea = LargestArea = Area(0) Large[0] = 0 int count = 1 int i = 1 while i < NumCells float tmp = Area(i) if tmp < SmallestArea SmallestArea = tmp endif float ratio = tmp/LargestArea if ratio > 1+@eps count = 1 Large[0] = i LargestArea = tmp elseif ratio > 1-@eps ; essentially the same area Large[count] = i count = count + 1 endif i = i + 1 endwhile return count endfunc float func Area(int n) if @pWhich == 0 return g.TriangleArea(V1[n], V2[n], V3[n]) else return real(V2[n]-V1[n])*imag(V2[n]-V1[n]) endif endfunc ; is cell n too small to divide? func Check(int n) int i = 0 if Area(n) < 2*MinArea i = 4 elseif @pWhich == 0 if |V1[n]-V2[n]| < 2*MinSideSq i = 3 elseif |V2[n]-V3[n]| < 2*MinSideSq i = 3 elseif |V3[n]-V1[n]| < 2*MinSideSq i = 3 endif else if real(V2[n]-V1[n]) < 2*MinSide || @pXFrac == 0.0 i = 1 endif if imag(V2[n]-V1[n]) < 2*MinSide || @pXFrac == 1.0 i = i + 2 endif endif if i >= 3 NumSmall = NumSmall + 1 endif Small[n] = i endfunc func Iterate(complex pz) GradientColoring.Iterate(pz) endfunc float func ResultIndex(complex pz) float x = real(#screenpixel) float y = imag(#screenpixel) int n = CellNum(x, y) if @pLines ; just show cell border lines if n < 0 ; the point is in the outside border, maybe close enough to be in the line if (x<=xb && x>=xb-lw && y>=yb-lw && y<=#height-yb+lw) ; left outer line return 0 elseif (y<=yb && y>=yb-lw && x>=xb-lw && x<=#width-xb+lw) ; top outer line return 0 elseif (y>=#height-yb && y<=#height-yb+lw && x>=xb-lw && x<=#width-xb+lw) ; bottom outer line return 0 elseif (x>=#width-xb && x<=#width-xb+lw && y>=yb-lw && y<=#height-yb+lw) ; right outer line return 0 else return 0.667 ; usually this will be transparent endif else ; the point is inside a cell, is it near an edge? if @pWhich == 0 if g.DistancePointToLine(#screenpixel, V1[n], V2[n]) <= lw + @eps return 0 elseif g.DistancePointToLine(#screenpixel, V2[n], V3[n]) <= lw + @eps return 0 elseif g.DistancePointToLine(#screenpixel, V3[n], V1[n]) <= lw + @eps return 0 endif elseif x<=real(V1[n])+lw || x>=real(V2[n])-lw || y<=imag(V1[n])+lw || y>=imag(V2[n])-lw return 0 endif return 0.333 ; usually this will be transparent endif else ; not doing cell lines if n < 0 m_Solid = true ; m_Solid inherited through GradientColoring class ; from Coloring class return -1 ; m_Solid dominates #index in Coloring else return Perm[n]/NumCells endif endif endfunc int func CellNum(float x, float y) if x#width-xb || y#height-yb ; in the outer border return -1 endif int i = 0 while i < NumCells bool yes if @pWhich == 0 yes = g.PointInTriangle(x+flip(y), V1[i], V2[i], V3[i]) else yes = x >= real(V1[i]) && x <= real(V2[i]) && y >= imag(V1[i]) && y <= imag(V2[i]) endif if yes return i endif i = i + 1 ; endwhile return -1 ; should never get here endfunc func StartRandom(int n) ; this seems to improve the random sequence r = new JLB_Random(0) r.Init(@seed) int i = 0 while i < n r.RandomInt(0) i = i + 1 endwhile endfunc func Shuffle( ) int n = 0 while n < NumCells Perm[n] = n n = n + 1 endwhile int times = 0 while times < @pRandomColor int n = 0 while n < NumCells int m = r.RandomIntInRange2(0, NumCells) - 1 int tmp = Perm[n] Perm[n] = Perm[m] Perm[m] = tmp n = n + 1 endwhile times = times + 1 endwhile endfunc private: JLB_Random r int NumCells int NumSmall ; if triangles, V1, V2, V3 = the 3 vertices ; if rectangles, V1 = upper left corner of cell, V2 = lower right corner of cell, V3 not used complex V1[@pMaxCells] complex V2[@pMaxCells] complex V3[@pMaxCells] int Small[@pMaxCells] ; 0 = okay, 1 = small in X, 2 = in Y, 3 = both, 4 in area int Large[@pMaxCells] ; list of largest cell. Doesn't need to be this big, but ... float SmallestArea float LargestArea int Perm[@pMaxCells] ; permutation used for randomizing colors ; float MinXSize ; used only for rectangles ; float MinYSize float MinArea float MinSide float MinSideSq ; square of minimum side length for triangles only float xb, float yb ; border widths float lw ; line width Geometry g default: title = "Cells" ;rating = Recommended ; heading ; caption = "Use a pixel formula" ; endheading ; heading ; caption = "Distances are from 0 to 1." ; endheading int param v_cells caption = "Version (Cells)" default = 100 hint = "This version parameter is used to detect when a change has been made \ to the formula that is incompatible with the previous version. When that \ happens, this field will reflect the old version number to alert you to the fact \ that an alternate rendering is being used." visible = @v_cells < 100 endparam param pWhich caption = "Cell type" enum = "Triangles" "Rectangles" default = 1 endparam int param pMaxCells caption = "Maximum # of cells" default = 25 min = 1 endparam int param seed caption = "Seed" hint = "Seed for the random number generator" default = 12345 endparam float param pXBorder caption = "Left and right borders" hint = "as fraction of width" default = 0 min = 0 max = 0.3 endparam float param pYBorder caption = "Top and bottom borders" hint = "as fraction of width (not height!)" default = 0 min = 0 max = 0.3 endparam param pFirstDiv caption = "First divide" hint = "Divide initial rectangle in 2, 3, or 4 parts" default = 1 enum = "2" "3" "4" visible = @pWhich == 0 && @pMaxCells >= 3 endparam param pChoose caption = "How to choose a cell" enum = "Random" "Larger" "Largest" hint = "Larger: larger cells are more likely to be divided. \ Largest: only the largest cells will be divided." default = 1 endparam float param pRatio caption = "Max ratio of areas" default = 4 min = 1 visible = @pChoose != 2 endparam float param pDivide5 caption = "Divide 5 fraction" default = 0.125 min = 0 max = 1 hint = "Fraction of the time to divide cells into 5 cells instead of 2." visible = @pWhich == 1 endparam float param pCW caption = "Preference for clockwise" hint = "Fraction of the time for 5 cell divisions to go clockwise instead of \ counter-clockwise." min = 0 max = 1 default = 0.5 visible = @pWhich == 1 && @pDivide5 > 0 endparam float param pDivide4 caption = "Divide 4 fraction" default = 0.125 min = 0 max = 1 hint = "Fraction of the time to divide triangles into 4 triangles\ instead of 2." visible = @pWhich == 0 endparam float param pPreferLong caption = "Longer side preference" hint = "Fraction of time to divide the longer side" default = 0.75 min = 0 max = 1 visible = @pWhich == 1 endparam float param pXFrac caption = "Horizontal divide fraction" hint = "Fraction of cells divided left to right; the rest divided top to bottom" default = 0.5 min = 0 max = 1 visible = @pWhich == 1 endparam float param pSlop caption = "Divide tolerance" default = 0.05 hint = "How much off the nominal value a cell division can be." min = 0 max = 0.49 endparam float param pMinSide caption = "Minimum side length" hint = "Cells with a side less than twice this cannot be divided" default = 0.05 ;min = 0.001 ;visible = @pWhich == 0 endparam float param pMinArea caption = "Minimum cell area (%)" hint = "Cells less than twice this area cannot be divided." default = 0.1 max = 25 endparam int param pRandomColor caption = "Shuffle colors" hint = "See which you prefer." min = 0 default = 1 visible = !@pLines endparam bool param pLines caption = "Show lines?" default = false hint = "If true, cell lines are colored as #index 0, \ cell interiors as 0.333, and outer border as 0.667." endparam float param B caption = "Half-width of edge lines" hint = "Width as a fraction of horizontal dimension" default = 0.004 min = 0 max = 0.25 visible = @pLines endparam float param eps ; slop for Large calculation default = 1.e-6 visible = false endparam } class JLB_SESFormula(SFormula) { ; z = a*f1(z op1 f2(c)) op2 b*f3(c) ; simplified version of SomethingElseMkII in tma2.ufm, rewritten as an SFormula public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_SESFormula(Generic pparent) SFormula.SFormula(pparent) m_Combine = new Combine() if @addT > 0 ;&& !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif endfunc bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex t1 = @f2(ppc) t1 = m_Combine.go(pz, @op1, t1) t1 = @a*@f1(t1) complex t2 = @b*@f3(ppc) znew = m_Combine.go(t1, @op2, t2) ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc protected: Combine m_Combine complex ppc UtilityTransform finalTransform default: rating = NotRecommended title = "Something Else" int param v_SESFormula caption = "Version (SE_SFormula)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_SESFormula < 100 endparam ; bool param p_std ; caption = "Standard?" ; default = true ; endparam heading caption = "z_new = a*f1(z op1 f2(c)) op2 b*f3(c)" endheading bool param p_Mtype caption = "M-type?" default = true endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = !@p_Mtype endparam complex param a caption = "a" default = 1 endparam func f1 caption = "f1" default = cos() endfunc param op1 caption = "op1" default = 4 enum = "+" "-" "*" "/" "^" endparam func f2 caption = "f2" default = ident() endfunc heading endheading param op2 caption = "op2" default = 0 enum = "+" "-" "*" "/" "^" endparam complex param b caption = "b" default = 1 endparam func f3 caption = "f3" default = ident() endfunc heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } class JLB_SetZSFormula(SFormula) { ; Set pz to a value or #pixel. Useful for setting the start value. public: bool func Iterate(State S) S.pz = 0 ; so pzold = 0 if @type == 0 S.Update(@zz, S.pc) else S.Update(#pixel, S.pc) endif return S.bailed endfunc default: title = "Set z" rating = NotRecommended int param v_SetZSFormula caption = "Version (JLB_SetZSFormula)" default = 100 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_SetZSFormula < 100 endparam param type enum = "value" "pixel" caption = "Set z to" default = 0 endparam complex param zz caption = "z" default = (0,0) visible = @type == 0 endparam } class JLB_Smooth(common.ulb:GradientColoring) { ; ; Object version of Smooth in Standard.ucl, slightly generalized. ; public: float func ResultIndex(complex pz) return @a * (m_Iterations + @b - log(log(cabs(pz)))/log(@p)) endfunc default: title = "Smooth" rating = NotRecommended heading caption = "index = a*(iters+b-log(log(cabs(z)))/log(p))" endheading float param a caption = "a = overall multiplier" default = 0.05 endparam float param b caption = "b = offset" default = 0 endparam float param p caption = "p = power in main formula" default = 2 min = 1 endparam } class JLB_TwoFuncSFormula(SFormula) { ; Combine two functions ; This is a simpler subset of Combo ; public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_TwoFuncSFormula(Generic pparent) SFormula.SFormula(pparent) m_fSFormula = new @f_SFormula(this) m_gSFormula = new @g_SFormula(this) m_Combine = new Combine() if @addT > 0 ;&& !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) m_fSFormula.Init(pz, pc) m_gSFormula.Init(pz, pc) endfunc ; @param pz ; @return true if need to quit bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex pc = S.pc if !@p_Mtype pc = @p_seed endif complex znew if @v_TwoFuncSFormula < 201 znew = @f(pz)^@p + @a*@g(pz)^@q else complex t2 if @gtype == 0 t2 = @a*(@g(pz))^@q else if !@p_Mtypeg S.pc = @p_seedg endif if m_gSFormula.Iterate(S) return true endif t2 = @a*(S.pz)^@q S.pz = pz S.pc = pc endif if @op == "( )" if @ftype == 0 znew = @a*(@f(t2))^@p else S.pz = t2 if !@p_Mtypef S.pc = @p_seedf endif if m_fSFormula.Iterate(S) return true endif znew = (S.pz)^@p endif else complex t1 if @ftype == 0 t1 = @f(pz)^@p else S.pz = pz ; original z value if !@p_Mtypef S.pc = @p_seedf endif if m_fSFormula.Iterate(S) return true endif t1 = (S.pz)^@p endif znew = m_combine.Go(t1, @op, t2) endif endif if !@p_Mtypec pc = @p_seedc endif znew = m_combine.Go(znew, @op2, @b*pc) ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc protected: Combine m_combine SFormula m_fSFormula SFormula m_gSFormula UtilityTransform finalTransform default: title = "Two Functions" rating = NotRecommended int param v_TwoFuncSFormula caption = "Version (TwoFuncSFormula)" default = 201 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_TwoFuncSFormula < 201 endparam ; bool param p_std ; caption = "Standard?" ; default = true ; endparam heading caption = "znew = f(z)^p + a*g(z)^q + b*c" visible = @v_TwoFuncSFormula < 201 endheading heading caption = "znew = (f(z)^p) op1 (a*g(z)^q) op2 (b*c)" visible = @v_TwoFuncSFormula >= 201 endheading heading endheading bool param p_Mtype caption = "M-type" default = true visible = @v_TwoFuncSFormula < 201 endparam complex param p_seed caption = "J-type, seed =" default = (1, 0) visible = @v_TwoFuncSFormula < 201 && !@p_Mtype endparam param ftype caption = "f function type" default = 0 enum = "built-in func" "SFormula" endparam func f caption = "f (func)" default = sin() visible = @ftype == 0 endfunc SFormula param f_SFormula caption = "f (SFormula)" default = JLB_FuncSFormula visible = @ftype == 1 endparam bool param p_Mtypef caption = "f: M-type" default = true visible = @ftype == 1 endparam complex param p_seedf caption = "f: J-type seed =" default = (1, 0) visible = @ftype == 1 && !@p_Mtypef endparam complex param p caption = "p" default = (3,0) endparam heading endheading param op caption = "op1" default = 0 enum = "+" "-" "*" "/" "^" "( )" visible = @v_TwoFuncSFormula >= 201 endparam heading endheading complex param a caption = "a" default = 1 endparam param gtype caption = "g function type" default = 0 enum = "built-in func" "SFormula" endparam func g caption = "g (func)" default = tan() visible = @gtype == 0 endfunc SFormula param g_SFormula caption = "g (SFormula)" default = JLB_FuncSFormula visible = @gtype == 1 endparam bool param p_Mtypeg caption = "g: M-type" default = true visible = @gtype == 1 endparam complex param p_seedg caption = "g: J-type seed =" default = (1, 0) visible = @gtype == 1 && !@p_Mtypeg endparam complex param q caption = "q" default = (2,0) endparam heading endheading param op2 caption = "op2" default = 0 enum = "+" "-" "*" "/" "^" visible = @v_TwoFuncSFormula >= 201 endparam bool param p_Mtypec caption = "c: M-type" default = true visible = @v_TwoFuncSFormula >= 201 endparam complex param p_seedc caption = "c: J-type seed =" default = (1, 0) visible = @v_TwoFuncSFormula >= 201 && !@p_Mtypec endparam complex param b caption = "b" default = 1 endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } class JLB_MoveCenter(common.ulb:UserTransform) { ; Move the fractal to a new center public: import "common.ulb" func JLB_MoveCenter(Generic pparent) UserTransform.UserTransform(pparent) m_FractalCoordinate = new FractalCoordinate(pparent) endfunc func Init(complex pz) UserTransform.Init(pz) m_FractalCoordinate.Init(pz) complex new_center = @horiz*#width + flip(@vert*#height) offset = #center - m_FractalCoordinate.Iterate(new_center) if @clip float xctr = @horiz * real(#screenmax) float yctr = @vert * imag(#screenmax) xmin = xctr - 0.5 * @xclip * real(#screenmax) xmax = xctr + 0.5 * @xclip * real(#screenmax) ymin = yctr - 0.5 * @yclip * imag(#screenmax) ymax = yctr + 0.5 * @yclip * imag(#screenmax) endif endfunc complex func Iterate(complex pz) UserTransform.Iterate(pz) if @clip if real(#screenpixel) < xmin || real(#screenpixel) > xmax \ || imag(#screenpixel) < ymin || imag(#screenpixel) > ymax m_solid = true endif endif return pz + offset endfunc protected: FractalCoordinate m_FractalCoordinate complex offset float xmin, float xmax float ymin, float ymax default: title = "MoveCenter" rating = Recommended int param vMoveCenter caption = "Version" default = 220716 visible = @vMoveCenter < 220716 ; backwards compatible endparam heading caption = "Move the fractal to a new center." endheading heading caption = "Optionally clip a rectangle around it." endheading heading caption = "Upper left is (0,0), lower right is (1,1)" endheading float param horiz caption = "Horizontal" default = 0.25 min = 0 max = 1 endparam float param vert caption = "Vertical" default = 0.25 min = 0 max = 1 endparam bool param clip caption = "Clip outside?" default = false endparam float param xclip caption = "Horizontal width" default = 0.25 min = 0 max = 1 visible = @clip endparam float param yclip caption = "Vertical width" default = 0.25 min = 0 max = 1 visible = @clip endparam } class CalcValue { public: func CalcValue() endfunc static float func go(const int mode, const complex pz, const complex pc) if mode == 0 ; "cabs" or mod return cabs(pz) elseif mode == 1 ; "real" return real(pz) elseif mode == 2 ; "imag" return imag(pz) elseif mode == 3 ; "real+imag" return real(pz) + imag(pz) elseif mode == 4 ; "real-imag" return real(pz) - imag(pz) elseif mode == 4 ; "real*imag" return real(pz) * imag(pz) elseif mode == 5 ; "z angle" return atan2(pz) elseif mode == 6 ; "z cross+ c" return real(pz)*imag(pc) + imag(pz)*real(pc) elseif mode == 7 ; "z cross- c" return real(pz)*imag(pc) - imag(pz)*real(pc) elseif mode == 8 ;"z dot+ c" return real(pz)*real(pc) + imag(pz)*imag(pc) else ; "z dot- c" return real(pz)*real(pc) - imag(pz)*imag(pc) endif endfunc } class JLB_ThreeLevelSFormula(SFormula) { ; A Barnsley-like formula as an SFormula, with a non-abrupt transition \ ; possible from the upper formula to the middle and lower formulas. public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_ThreeLevelSFormula(Generic pparent) SFormula.SFormula(pparent) m_SFormulaU = new @f_SFormulaU(this) m_SFormulaM = new @f_SFormulaM(this) m_SFormulaL = new @f_SFormulaL(this) if @a*@v1 >= @a*@v2 m_critU = @a*@v1 m_critL = @a*@v2 else m_critU = @a*@v2 m_critL = @a*@v1 endif m_useM = m_critU > m_critL if @v_ThreeLevelSFormula < 211003 m_CalcValue = new CalcValue() ; else ; m_CTF2 = new ComplexToFloat2() endif mTSmooth = new TSmooth() endfunc func Init(complex pz, complex pc) m_SFormulaU.Init(pz, pc) ;if m_useM m_SFormulaM.Init(pz, pc) ;endif m_SFormulaL.Init(pz, pc) endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex pzold = S.pzold complex pc = S.pc complex pcc = pc ; this pc value only used for critical value if !@p_Mtype pcc = @p_seed endif float test if @v_ThreeLevelSFormula < 211003 test = m_CalcValue.Go(@mode, pz, pcc) else test = ComplexToFloat2.go(pz, pcc, @mode2, false) endif ; find U, M, and L z-values if m_SFormulaU.Iterate(S) return true endif complex zU = S.pz S.pz = pz, S.pzold = pzold, S.pc = pc ; use original values complex zM = 0 if m_useM if m_SFormulaM.Iterate(S) return true endif zM = S.pz S.iters = S.iters - 1 endif S.pz = pz, S.pzold = pzold, S.pc = pc if m_SFormulaL.Iterate(S) return true endif complex zL = S.pz S.pzold = pzold S.iters = S.iters - 1 ; if trans == 0, use all of U, M, or L complex fracU = 0 complex fracM = 0 complex fracL = 0 if @trans == 0 if test > m_critU fracU = 1 elseif test < m_critL fracL = 1 endif else ; otherwise, do a smooth transition using tanh fracU = mTSmooth.go((test-m_critU)/@trans) fracL = mTSmooth.go((m_critL-test)/@trans) endif fracM = 1 - fracU - fracL pz = fracU*zU + fracM*zM + fracL*zL S.pz = S.pzold S.Update(pz, pc) ; keep original pc, otherwise don't know which to use. return S.bailed endfunc protected: SFormula m_SFormulaU SFormula m_SFormulaM SFormula m_SFormulaL CalcValue m_CalcValue TSmooth mTSmooth ; ComplexToFloat2 m_CTF2 float m_critU float m_critL bool m_useM default: title = "ThreeLevel" rating = NotRecommended int param v_ThreeLevelSFormula caption = "Version (ThreeLevelSFormula)" default = 211003 hint = "This version parameter is used to detect when a change has \ been made to the formula that is incompatible with the \ previous version. When that happens, this field will reflect \ the old version number to alert you to the fact that an \ alternate rendering is being used." visible = @v_ThreeLevelSFormula < 211003 endparam heading text = "Apply change depending on critical value" hint = "Use real and imaginary parts of z and c to \ calculate value to compare with critical value." endheading bool param p_Mtype caption = "M-type (for critical value)" hint = "For calculating the critical value, 'c' is the pixel" default = true visible = (@v_ThreeLevelSFormula < 211003 && @mode >= 7) \ || (@v_ThreeLevelSFormula >= 211003 && @mode2 >= 17) endparam complex param p_seed caption = "Seed (for critical value)" default = (1, 0) hint = "For calculating the critical value, 'c' is this seed. \ It is not the 'c' in any of the formulas." visible = !@p_Mtype && ( \ (@v_ThreeLevelSFormula < 211003 && @mode >= 7) \ || (@v_ThreeLevelSFormula >= 211003 && @mode2 >= 17) ) endparam param mode caption = "mode" hint = "How to calculate the critical value." default = 0 enum = "mod" "real" "imag" "real+imag" "real-imag" "real*imag" "z angle" \ "z cross+ c" "z cross- c" "z dot+ c" "z dot- c" visible = @v_ThreeLevelSFormula < 211003 endparam param mode2 caption = "mode" hint = "How to calculate the critical value." default = 0 enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" "z cross+ c" "z cross- c" "z dot+ c" "z dot- c" "cabs(z*c)" visible = @v_ThreeLevelSFormula >= 211003 endparam float param v1 caption = "V1" default = 1 endparam float param v2 caption = "V2" default = -1 endparam float param a caption = "V multiplier" hint = "Upper critical value = larger of a*V1, a*V2; lower critical value =\ the smaller" default = 1 endparam float param trans caption = "Transition parameter" hint = "Smaller values make a steeper transition. For an abrupt transition, use 0." default = 1 min = 0 endparam SFormula param f_SFormulaU caption = "Upper formula" default = JLB_FuncSFormula endparam heading text = "Middle formula not needed" visible = @v1 == @v2 endheading SFormula param f_SFormulaM caption = "Middle formula" default = JLB_MandelbrotSFormula visible = @v1 != @v2 endparam SFormula param f_SFormulaL caption = "Lower formula" default = JLB_PowerSFormula endparam } class Distance(common.ulb:Generic) { ; ; Distance base class. No title, so only used for a base class. ; Given a complex value, return a float. public: import "common.ulb" func Distance(Generic pparent) Generic.Generic(pparent) endfunc func Init(complex zz) m_mode = 0 m_abs_value = false endfunc func SetParams(int m, bool a) m_mode = m m_abs_value = a endfunc func SetIter(int k) m_iter = k endfunc int func GetIter( ) return m_iter endfunc float func Iterate(complex zz) return cabs(zz) endfunc protected: int m_mode bool m_abs_value int m_iter default: int param v_Distance caption = "Version (Distance)" default = 211019 visible = false endparam } class JLB_DExpSmooth(Distance) { ; 21 August 2021 added complications as seen in jlb.ucl "Exponential Smoothing Plus" ; and in ejb.ucl "Smooth colouring EB adjustment" public: func JLB_DExpSmooth(Generic pparent) endfunc func Init(complex zz) center = (0,0) if @ctr == "Screen center" center = #center elseif @ctr == "Pixel" center = #pixel elseif @ctr == "Point" center = @pt endif scale = @a endfunc float func Iterate(complex zz) float d = ComplexToFloat.go(zz-center, m_mode, m_abs_value) d = real(@F(d)) ; real matches ejb. cabs maybe better? d = exp(-scale*d) scale = @r * scale return d endfunc private: complex center float scale default: title = "Exponential Smoothing" rating = NotRecommended heading text = "(Exponential Smoothing 2 is the preferred plug-in.)" endheading param ctr caption = "Center" enum = "Origin" "Screen center" "Pixel" "Point" default = 0 hint = "Calculate distance from here." endparam complex param pt caption = "Point" default = (0,0) visible = @ctr == 3 endparam func F caption = "Function of distance" default = ident() hint = "Apply this function before exponential." endfunc float param a caption = "Scale" default = 1 ;min = 0 hint = "Large positive values give more emphasis to earlier iterations." endparam float param r caption = "Factor to change scale" default = 1 endparam } class JLB_DExpSmooth2(Distance) { ; 21 August 2021 added complications as seen in jlb.ucl "Exponential Smoothing Plus" ; and in ejb.ucl "Smooth colouring EB adjustment" public: func JLB_DExpSmooth2(Generic pparent) Distance(pparent) if @version >= 220703 m_dist = new @dist(this) endif endfunc func Init(complex zz) if @version >= 220703 m_dist.SetParams(0, true) endif ; 240112 this block moved from constructor center = (0,0) if @ctr == "Screen center" center = #center elseif @ctr == "Pixel" center = #pixel elseif @ctr == "Point" center = @pt endif scale = @a endfunc float func Iterate(complex zz) float d if @version >= 220703 d = m_dist.Iterate(zz) else int mmode = m_mode if @version < 220619 mmode = @mode endif d = ComplexToFloat2.go(zz-center, (0,0), mmode, true) endif d = real(@F(d)) ; real matches ejb. cabs maybe better? d = exp(-scale*d) scale = @r * scale return d endfunc private: complex center float scale Distance m_dist default: title = "Exponential Smoothing 2" rating = NotRecommended int param version caption = "Version" default = 220703 visible = @version < 220703 endparam param mode caption = "Use for distance" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220619 endparam param ctr caption = "Center" enum = "Origin" "Screen center" "Pixel" "Point" default = 0 hint = "Calculate distance from here." endparam complex param pt caption = "Point" default = (0,0) visible = @ctr == 3 endparam func F caption = "Function of distance" default = ident() hint = "Apply this function before exponential." endfunc float param a caption = "Scale" default = 1 ;min = 0 hint = "Large positive values give more emphasis to earlier iterations." endparam float param r caption = "Factor to change scale" default = 1 endparam Distance param dist default = JLB_DXYZ selectable = false endparam } class JLB_DGaussianInteger(Distance) { ; The essential part of Kerry Mitchell's code in Standard.ucl ; 220921 allowed real and imag parts to use different types. ; backward compatible. public: func JLB_DGaussianInteger(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) endfunc float func Iterate(complex zz) complex temp zz = @a * zz if @p_std if @how == 0 temp = aux(real(zz), @type) + flip(aux(imag(zz), @type)) zz = zz - temp ; x and y are in (-1,+1) return m_dist.Iterate(zz-temp) else;if @how == 1 float r0 = cabs(zz) float r = r0 - aux(r0, @type) ; r is in (-1,+1) zz = zz * r / r0 return m_dist.Iterate(zz) endif else temp = aux(real(zz), @xtype) + flip(aux(imag(zz), @ytype)) return m_dist.Iterate(zz-temp) endif endfunc float func aux(float v, int t) if t == 0 return round(v) elseif t == 1 return trunc(v) elseif t == 2 return floor(v) elseif t == 3 return ceil(v) else if v >= 0, return ceil(v), else, return floor(v), endif endif endfunc private: Distance m_dist default: title = "Gaussian Integer" rating = Recommended int param version caption = "Version" default = 240301 visible = @version < 240301 endparam heading text = "(Curent is 240301.}" visible = @version < 240301 endheading complex param a ; added 240310. backward compatible. caption = "Z multiplier" default = 1 endparam param how caption = "Method" enum = "X and Y" "Radius" ; maybe something like "angle" default = 0 endparam bool param p_std ; this was an unnecessary complication caption = "Standard?" default = true visible = @version < 240209 endparam param xtype caption="Real Type" default=0 enum="round" "trunc" "floor" "ceil" "trunc*" visible = !@p_std endparam param ytype caption="Imag Type" default=0 enum="round" "trunc" "floor" "ceil" "trunc*" visible = !@p_std endparam param type caption="Integer Type" default=0 enum="round" "trunc" "floor" "ceil" "trunc*" visible = @p_std endparam heading ;text = "Use for distance:" endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DGrid(Distance) { public: func JLB_DGrid(Generic pparent) Distance(pparent) m_dist = new @dist(this) if @screen_center ctr = #center else ctr = @dcenter endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) ; m_CTF = new ComplexToFloat2() if @type == "Rectangular" xgrid = abs(real(@grid)) ygrid = abs(imag(@grid)) endif endfunc func Init(complex zz) m_dist.SetParams(0, true) endfunc float func Iterate(complex zz) ; Note that floor(v) doesn't work if v > 2147483647, the largest positive integer. zz = ctr + rot * (zz - ctr) if @type == "Rectangular" if real(zz/xgrid) > 2e9 || imag(zz/ygrid) > 2e9 ; not enough precision return -1 endif int i = floor(real(zz)/xgrid) int j = floor(imag(zz)/ygrid) ; zz is in rectangle whose lower left is (i,j) ; dx and dy are non-negative float dx = real(zz) - i*xgrid float dy = imag(zz) - j*ygrid if dx > 0.5 * xgrid dx = xgrid - dx endif if dy > 0.5 * ygrid dy = ygrid - dy endif complex v if @do_scale v = dx/xgrid + flip(dy/ygrid) else v = dx + flip(dy) endif if @version < 220619 if real(v) <= imag(v) return real(v) else return imag(v) endif else ;return ComplexToFloat2.go(v/rot,(0,0), m_mode, true) return m_dist.Iterate(v/rot)^@pow endif else float r = cabs(zz) if r/@rgrid > 2e9 return -1 endif int i = floor(r/@rgrid) ; if i==0 use distance to first circle, float d1 = r - i * @rgrid ; not distance to center if d1 > 0.5 * @rgrid || i == 0 d1 = @rgrid - d1 endif ;choose angular spacing to make the grid more or less square int n = round(2 * #pi * (i + 0.5)) float agrid = 2 * #pi / n float theta = atan2(zz) if theta < 0, theta = theta + 2*#pi, endif int j = floor(theta / agrid) float d2 = theta - j * agrid if d2 > 0.5 * agrid d2 = agrid - d2 endif d2 = r * d2 if @version < 220619 if d1 > d2 d1 = d2 endif else if d1 <= d2 v = d1 * zz / r ;d1 = ComplexToFloat2.go(v,(0,0), m_mode, true) d1 = m_dist.Iterate(v) else v = d2 * zz * (0,1) / r ; right angle to zz ;d1 = ComplexToFloat2.go(v,(0,0), m_mode, true) d1 = m_dist.Iterate(v) endif endif if @do_pscale d1 = d1 / @rgrid endif return d1^@pow endif endfunc private: complex ctr complex rot float xgrid float ygrid Distance m_dist default: title = "Grid" rating = NotRecommended heading caption = "Use Grid2 instead." endheading int param version caption = "Version" default = 220619 visible = @version < 220619 ; backwards compatible to 211012 endparam param type enum = "Rectangular" " Polar" caption = "Grid type" default = 0 endparam bool param screen_center caption = "Use screen center?" default = true endparam complex param dcenter caption = "Center" default = (0,0) visible = !@screen_center endparam complex param grid caption = "Grid spacing" default = (1,1) visible = @type == 0 endparam float param rgrid caption = "Radial spacing" default = 1 min = 0 visible = @type == 1 endparam float param angle caption = "Rotation angle" default = 0 visible = @type == 0 endparam bool param do_scale caption = "Scale to grid?" default = false visible = @type == 0 endparam bool param do_pscale caption = "Scale to radial spacing?" default = false visible = @type == 1 endparam float param pow caption = "Power" default = 1 endparam Distance param dist default = JLB_DXYZ selectable = false endparam } class JLB_DGrid2(Distance) { ; ??? backwards compatible ??? public: func JLB_DGrid2(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif if @screen_center ctr = #center else ctr = @dcenter endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) xgrid = abs(real(@grid)) ygrid = abs(imag(@grid)) if @type == "Hexagonal" a3 = 1.5 * xgrid v = 0.5 * sqrt(3.0) * ygrid endif endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) if @type == "Rectangular" || @type == "Triangular" Get_Rect(zz, old_even, old_up) endif endfunc float func Iterate(complex zz) if @version < 220910 zz = ctr + rot * (zz - ctr) ; wrong! else zz = rot * (zz - ctr) endif ; Note that floor(v) doesn't work if v > 2147483647, the largest positive integer. complex grid_ctr float d1, float d2 complex tmp if @type == "Rectangular" || @type == "Triangular" complex za = abs(zz) if real(za/xgrid) > 2e9 || imag(za/ygrid) > 2e9 ; not enough precision return -1 endif ; zz is in the rectangle whose lower left is (i,j) ; find coordinates of the rectangle bool new_even, bool new_up Get_Rect(zz, new_even, new_up) if @type == "Rectangular" if @parity == "Odd" && new_even return -1 endif if @parity == "Even" && !new_even return -1 endif if @parity == "Change" && new_even == old_even return -1 endif if @parity == "Same" && new_even != old_even return -1 endif old_even = new_even if @type2 == "Center" grid_ctr = 0.5*(x1+x2) + flip(0.5*(y1+y2)) tmp = zz - grid_ctr elseif @type2 == "Edge" tmp = Geometry.ClosestPointToFigure(zz, 4, v1, v2, v3, v4) else;if @type2 == "Corner" tmp = Geometry.ClosestPointToVertex(zz, 4, v1, v2, v3, v4) endif else if @tri == "Up" && !new_up return -1 endif if @tri == "Down" && new_up return -1 endif if @tri == "Change" && new_up == old_up return -1 endif if @tri == "Same" && new_up != old_up return -1 endif old_up = new_up ; the point is in the triangle (v1, v2, v3) if @type2 == "Center" tmp = zz - (v1 + v2 + v3) / 3 elseif @type2 == "Edge" tmp = Geometry.ClosestPointToFigure(zz, 3, v1, v2, v3, v3) ; last arg not used else;if @type2 == "Corner" tmp = Geometry.ClosestPointToVertex(zz, 3, v1, v2, v3, v3) endif endif if @do_scale tmp = real(tmp)/xgrid + flip(imag(tmp)/ygrid) endif if @version < 220619 return MyMath.fmin(real(tmp), imag(tmp)) else float t = m_dist.Iterate(tmp/rot) ;^@pow return t endif elseif @type == "Hexagonal" int j = floor(abs(imag(zz))/v ) int i = floor(abs(real(zz))/a3) complex ctr1 complex ctr2 if j % 2 == 1 ; odd band if i % 2 == 1 ctr1 = (i )*a3 + flip((j )*v) ctr2 = (i+1)*a3 + flip((j+1)*v) else ctr1 = (i )*a3 + flip((j+1)*v) ctr2 = (i+1)*a3 + flip((j )*v) endif else ; even band if i % 2 == 1 ctr1 = (i )*a3 + flip((j+1)*v) ctr2 = (i+1)*a3 + flip((j )*v) else ctr1 = (i )*a3 + flip((j )*v) ctr2 = (i+1)*a3 + flip((j+1)*v) endif endif zz = abs(zz) tmp = ctr2-zz if |ctr1-zz| <= |ctr2-zz| tmp = ctr1-zz endif return m_dist.Iterate(tmp/rot) ; ^@pow ; end heaxagonal else;if @type == "Polar" float r = cabs(zz) if r/@rgrid > 2e9 return -1 endif int i = floor(r/@rgrid) float r1 = i*@rgrid, float r2 = r1+@rgrid ; angular spacing chosen to make the grid more or less square, except inmost one, ; with each grid about the same area. int n = 6*i+3 float agrid = 2*#pi / n float offset = (@angle + i * @delta) * #pi/180 float theta = atan2(zz) + offset if theta < 0, theta = theta + 2*#pi, endif ;if theta >= 2*#pi, theta = theta - 2*#pi, endif int j = floor(theta / agrid) ; j >= 0 float theta1 = j*agrid - offset float theta2 = theta1+agrid ; okay if >2*#pi if @type2 == "Center" grid_ctr = (r1+0.5*@rgrid) * exp(flip((theta1+0.5*agrid))) tmp = zz - grid_ctr else v1 = r1 * exp(flip(theta1)) ; v1-v2 is straight v2 = r2 * exp(flip(theta1)) ; v2-v3 is outer arc v3 = r2 * exp(flip(theta2)) ; v3-v4 is straight v4 = r1 * exp(flip(theta2)) ; v4-v1 is inner arc if @type2 == "Corner" tmp = Geometry.ClosestPointToVertex(zz, 4, v1, v2, v3, v4) else;if @type == "Edge" tmp = Geometry.ClosestPointToLIneSegment(zz, v1, v2) d1 = |tmp| vv = zz - r2 * exp(flip((theta))) ; outer arc d2 = |vv| if d2 < d1 d1 = d2, tmp = vv endif complex vv = Geometry.ClosestPointToLIneSegment(zz, v3, v4) d2 = |vv| if d2 < d1 d1 = d2, tmp = vv endif vv = zz - r1 * exp(flip((theta))) ; inner arc d2 = |vv| if d2 < d1 tmp = vv endif endif ; polar endif d1 = m_dist.Iterate(tmp) if @do_pscale d1 = d1 / @rgrid endif return d1 ;^@pow endif ; @type endfunc func Get_Rect(complex zz, bool &even, bool &up) float xx = real(zz) float i = floor(xx/xgrid) x1 = i * xgrid x2 = x1 + xgrid float yy = imag(zz) float j = floor(yy/ygrid) y1 = j * ygrid y2 = y1 + ygrid even = (i + j) % 2 == 0 v1 = x1 + flip(y1) ; lower left corner v2 = x2 + flip(y1) ; lower right corne v3 = x2 + flip(y2) ; upper right corner v4 = x1 + flip(y2) ; upper left corner if @type == "Triangular" ; which of the triangles contains the point? Assign v1, v2, v3 to its vertices up = false if @ttype == "Left" if Geometry.PointInTriangle(zz, v1, v2, v4) v3 = v4 ; 4-3 else ; |\| v1 = v4 ; 1-2 up = true endif else;if @ttype == "Right" if Geometry.PointInTriangle(zz, v1, v4, v3) v2 = v4 ; 4-3 up = true; |/| ; 1-2 ;else it's in the original 1, 2, 3 endif endif endif endfunc private: complex ctr complex rot float xgrid, float ygrid complex v1, complex v2, complex v3, complex v4 bool old_even, bool old_up float x1, float x2 float y1, float y2 Distance m_dist float a3, float v default: title = "Grid2" ;rating = Recommended heading text = "Divide the plane into a grid. Calculate the distance to the \ nearest grid edge or grid center." endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading bool param screen_center caption = "Use screen center?" default = true endparam complex param dcenter caption = "Center" default = (0,0) visible = !@screen_center endparam param type enum = "Rectangular" "Polar" "Hexagonal" "Triangular" caption = "Grid type" default = 0 endparam param parity enum = "Even" "Odd" "Either" "Change" "Same" caption = "Which rectangles?" default = 2 visible = @type == 0 endparam param ttype enum = "Left" "Right" caption = "Split the rectangle" default = 0 visible = @type == "Triangular" endparam param tri enum = "Up" "Down" "Either" "Change" "Same" caption = "Which half" default = 2 visible = @type == "Triangular" endparam param type2 enum = "Edge" "Center" "Corner" caption = "Distance to" default = 0 visible = @type !=2 endparam complex param grid caption = "Grid spacing" default = (1,1) visible = @type == 0 || @type >= 2 endparam float param rgrid caption = "Radial spacing" default = 1 min = 0 visible = @type == 1 endparam float param angle caption = "Rotation angle" default = 0 endparam float param delta caption = "Delta angle" default = 0 visible = @type == 1 endparam bool param do_scale caption = "Scale to grid?" default = false visible = @type == 0 || @type == 3 endparam bool param do_pscale caption = "Scale to radial spacing?" default = false visible = @type == 1 endparam ; float param pow ; caption = "Power" ; default = 1 ; endparam heading endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DLines(Distance) { ; line is a*x + b*y + c = 0 ; a*real(zz) + b*imag(zz) + c = d public: func JLB_DLines(Generic pparent) float t = @angle1*(#pi/180) a1 = sin(t) b1 = -cos(t) c1 = -real(@point1)*sin(t) + imag(@point1)*cos(t) if @num == " 2" t = @angle2*(#pi/180) a2 = sin(t) b2 = -cos(t) c2 = -real(@point2)*sin(t) + imag(@point2)*cos(t) endif endfunc float func Iterate(complex zz) float d = -1 bool okay float dist1 = a1 * real(zz) + b1 * imag(zz) + c1 if @num == " 1" if @side == " +" okay = dist1 > 0 elseif @side == " -" okay = dist1 < 0 else ; Either side okay = true endif if okay d = (abs(dist1)/@scale)^@pow endif else float dist2 = a2 * real(zz) + b2 * imag(zz) + c2 if @sides == 0 okay = dist1 > 0 && dist2 > 0 elseif @sides == 1 okay = dist1 > 0 && dist2 < 0 elseif @sides == 2 okay = dist1 < 0 && dist2 > 0 elseif @sides == 3 okay = dist1 < 0 && dist2 < 0 else okay = true endif if okay d = choose(dist1, dist2) endif endif if okay d = (d/@scale)^@pow endif return d endfunc float func choose(float v1, float v2) if @which == "Larger" if abs(v1) > abs(v2) return abs(v1) else return abs(v2) endif else if abs(v1) < abs(v2) return abs(v1) else return abs(v2) endif endif endfunc private: float a1,float b1, float c1 float a2,float b2, float c2 default: title = "Lines" rating = NotRecommended heading text = "Lines are defined by a point and an angle. Use iterations only when z is on the \ specified positive or negative side of the line(s)." endheading int param version caption = "Current is 220619" default = 220619 visible = @version < 220619 endparam param num caption = "1 or 2 lines?" enum = " 1" " 2" default = 0 endparam param which caption = "Smaller / larger distance?" enum = " Smaller" "Larger" default = 0 visible = @num == " 2" hint = "Distances are calculated to each line. Color using the smaller or larger of the two." endparam complex param point1 caption = "Point on line 1" default = (0,0) endparam float param angle1 caption = "Angle of line 1" default = 45 endparam param side caption = "Pos. or neg. side" enum = " +" " -" " Either" default = 0 visible = @num == " 1" endparam complex param point2 caption = "Point on line 2" default = (0,0) visible = @num == " 2" endparam float param angle2 caption = "Angle of line 2" default = 0 ; min = 0 ; max = 180 visible = @num == " 2" endparam param sides caption = "Pos. or neg. sides" enum = " + +" " + -" " - +" " - -" " Any" default = 0 visible = @num == " 2" endparam float param scale caption = "Scale (> 0)" default = 2.0 min = 1e-30 endparam float param pow caption = "Distance power" default = 1 hint = "Positive values emphasize iterations with z farther from the line(s); \ negative values emphasize iterations with z nearer to the line(s)." endparam } class JLB_DLines2(Distance) { ; line is a*x + b*y + c = 0 ; a*real(zz) + b*imag(zz) + c = d public: func JLB_DLines2(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif float t = @angle1*(#pi/180) a1 = sin(t) b1 = -cos(t) c1 = -real(@point1)*sin(t) + imag(@point1)*cos(t) if @num == " 2" t = @angle2*(#pi/180) a2 = sin(t) b2 = -cos(t) c2 = -real(@point2)*sin(t) + imag(@point2)*cos(t) endif endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) float tmp old_side = Get_Side(zz, a1, b1, c1, tmp) if @num == " 2" old_side = old_side + 10 * Get_Side(zz, a2, b2, c2, tmp) endif endfunc float func Iterate(complex zz) float d = -MyMath.fmax( 1, |zz| ) float d1, float d2 bool okay = false new_side = Get_Side(zz, a1, b1, c1, d1) ; calculates d1 if @num == " 1" if @side == "Either" okay = true elseif @side == " +" okay = d1 >= 0 elseif @side == " -" okay = d1 < 0 elseif @side == "Change" okay = old_side != new_side else;if @side == "Same" okay = old_side == new_side endif if okay d1 = abs(d1) if @version < 240224 zz = (a1+flip(b1)) * d1 ;WRONG! all thes perpendiculars are parallel else zz = d1 * zz endif endif else new_side = new_side + 10 * Get_Side(zz, a2, b2, c2, d2) ; calculates d2 if @sides == "Any" okay = true elseif @sides == 0 okay = d1 > 0 && d2 > 0 elseif @sides == 1 okay = d1 > 0 && d2 < 0 elseif @sides == 2 okay = d1 < 0 && d2 > 0 elseif @sides == 3 okay = d1 < 0 && d2 < 0 elseif @sides == "Change" okay = old_side != new_side else;if @sides == "Same" okay = old_side == new_side endif if okay d1 = MyMath.fmin(abs(d1),abs(d2)) if @version < 240224 zz = d1 * (a1+flip(b1)) ; again WRONG else zz = d1 * zz endif endif endif old_side = new_side if okay d = m_dist.Iterate(zz) if @version < 240224 d = d / @scale bool neg = ( d < 0 ) d = abs(d)^@pow if neg, d = -d, endif else d = abs(d) endif endif return d endfunc int func Get_Side(complex zz, float a, float b, float c, float &d) float x = real(zz) float y = imag(zz) d = a * x + b * y + c if d >= 0 return 1 else return 0 endif endfunc private: float a1,float b1, float c1 float a2,float b2, float c2 Distance m_dist int old_side int new_side default: title = "Lines2" rating = Recommended ; heading ; text = "Lines are defined by a point and an angle. " ; endheading int param version caption = "Version" default = 240224 visible = @version < 240224 endparam heading text = "(Curent is 240224.}" visible = @version < 240224 endheading param num caption = "1 or 2 lines?" enum = " 1" " 2" default = 0 endparam complex param point1 caption = "Point on line 1" default = (2,0) endparam float param angle1 caption = "Angle of line 1" default = 90 endparam param side caption = "Pos./neg. side/etc." enum = " +" " -" "Either" "Change" "Same" default = 2 visible = @num == " 1" endparam complex param point2 caption = "Point on line 2" default = (0,0) visible = @num == " 2" endparam float param angle2 caption = "Angle of line 2" default =45 visible = @num == " 2" endparam param sides caption = "Pos. or neg. sides" enum = " + +" " + -" " - +" " - -" "Any" "Change" "Same" default = 4 visible = @num == " 2" endparam float param scale caption = "Scale (> 0)" default = 1 min = 1e-30 visible = @version < 240224 endparam float param pow caption = "Distance power" default = 1 hint = "Positive values emphasize iterations with z farther from the line(s); \ negative values emphasize iterations with z nearer to the line(s)." visible = @version < 240224 endparam heading ;text = "Use for distance:" endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD2 selectable = false visible = @version >= 240101 endparam } class JLB_DQuad(Distance) { public: func JLB_DQuad(Generic pparent) ; m_CTF = new ComplexToFloat() endfunc func Init(complex zz) if @screen_center ctr = #center else ctr = @dcenter endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) endfunc float func Iterate(complex zz) float d = -1 bool okay = false complex v if @version < 220910 v = ctr + rot * (zz - ctr) ; wrong! else v = rot * (zz - ctr) endif if @quad == " 1" okay = real(v) > 0 && imag(v) > 0 elseif @quad == " 2" okay = real(v) < 0 && imag(v) > 0 elseif @quad == " 3" okay = real(v) < 0 && imag(v) < 0 else;if @quad == " 4" okay = real(v) > 0 && imag(v) < 0 endif if okay d = ComplexToFloat.go(zz, m_mode, true) endif return d endfunc private: complex ctr complex rot ; ComplexToFloat m_ctf default: title = "Quadrant" rating = NotRecommended heading text = "(Quadrant2 is the preferred plug-in)." endheading int param version caption = "Version" default = 220910 visible = @version < 220910 ; backwards compatible to 211012 endparam heading text = "(Current is 2220910.)" visible = @version < 220910 endheading bool param screen_center caption = "Use screen center?" default = true endparam complex param dcenter caption = "Center" default = (0,0) visible = !@screen_center endparam float param angle caption = "Rotation angle" default = 0 endparam param quad caption = "Quadrant" enum = " 1" " 2" " 3" " 4" default = 0 hint = "1 is upper right, 2 is upper left, 3 is lower left, 4 is lower right." endparam } class JLB_DQuad2(Distance) { ; 211124 added "Any" option ; 230126 added "Change" option; backwards compatible. public: func JLB_DQuad2(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif if @screen_center ctr = #center else ctr = @dcenter endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, m_abs_value) old_quad = get_quad(rot * (zz - ctr)) endfunc float func Iterate(complex zz) if @version < 220910 zz = ctr + rot * (zz - ctr) ; wrong! else zz = rot * (zz - ctr) endif float d = -MyMath.fmax( 1, |zz|) int new_quad = get_quad(zz) bool okay = false if @quad == "Any" okay = true elseif @quad == "Change" okay = old_quad != new_quad elseif @quad == "Same" okay = old_quad == new_quad else okay = @quad == new_quad endif if okay int mmode = m_mode if @version < 220619 mmode = @mode ; set in Distance Coloring d = ComplexToFloat2.go(zz/rot,(0,0), mmode, true) else d = m_dist.Iterate(zz/rot) endif if @version < 240224 bool neg = ( d < 0 ) d = abs(d)^@pow if neg, d = -d, endif endif endif return d endfunc int func get_quad(complex zz) float x = real(zz) float y = imag(zz) if x >= 0 && y >= 0 return 0 elseif x <= 0 && y >= 0 return 1 elseif x <= 0 && y <= 0 return 2 else return 3 endif endfunc private: complex ctr complex rot Distance m_dist int old_quad default: title = "Quadrant2" rating = NotRecommended heading caption = "Use Lines2 instead." endheading int param version caption = "Version" default = 240224 visible = @version < 240224 endparam heading text = "(Curent is 2402241.}" visible = @version < 240224 endheading param mode caption = "Use for distance" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220619 endparam bool param screen_center caption = "Use screen center?" default = true endparam complex param dcenter caption = "Center" default = (0,0) visible = !@screen_center endparam float param angle caption = "Rotation angle" default = 0 endparam param quad caption = "Quadrant" enum = " 1" " 2" " 3" " 4" "Any" "Change" "Same" default = 4 hint = "1 is upper right, 2 is upper left, 3 is lower left, 4 is lower right." endparam float param pow caption = "Distance power" default = 1 hint = "Positive values emphasize iterations with z farther from the line(s); \ negative values emphasize iterations with z nearer to the line(s)." visible = @version < 240224 endparam heading ;text = "Use for distance:" endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DSpiral(Distance) { ; log spiral: r = a * exp(b * angle) ; Power spiral: r = a * angle^p public: func JLB_DSpiral(Generic pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif if @screen_center sctr = #center else sctr = @ctr endif aa = abs(@a); scale = 1 if @do_scale scale = aa endif twopi = 2*#pi endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) endfunc float func Iterate(complex zz) zz = zz - sctr float theta = atan2(zz) if @a > 0 if theta < 0, theta = theta + twopi, endif ; theta in [0, twopi) else if theta > 0, theta = theta - twopi, endif ; theta in (-twopi, 0] theta = abs(theta) endif float r = cabs(zz) float tmp if @type == 0 tmp = ((r/aa)^(1/@p) - theta) / twopi else tmp = (log(r/aa)/@b - theta) / twopi endif int k = floor(tmp) if k < 0, k = 0, endif ; inside first arm or lack of precision float r1, float r2 if @type == 0 r1 = aa * (theta + k*twopi )^@p r2 = aa * (theta + k*twopi + twopi)^@p else r1 = aa * exp(@b*(theta + k*twopi )) r2 = aa * exp(@b*(theta + k*twopi + twopi) ) endif float d if k == 0 ; inside first arm d = 1 - r/r2 if d < 0 || d > 1 ; failure because of lack of precision return -1 endif else d = (r - r1) / (r2 - r1) if d < 0 || d > 1 ; failure because of lack of precision return -1 endif if d > 0.5, d = 1 - d, endif ; distance to closer arm endif ; d is between 0 and 1 d = d * scale zz = d * zz / cabs(zz) ;d = ComplexToFloat2.go(zz, (0,0), m_mode, true) d = m_dist.Iterate(zz) return d endfunc private: float scale float twopi complex sctr float aa Distance m_dist default: title = "Spiral" rating = Recommended heading text = "Color by distance to closest arm of the spiral." endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading param type caption = "Spiral type" default = 0 enum = "power" "log" endparam bool param screen_center caption = "Use screen center?" default = true endparam param ctr caption = "Spiral center" default = (0,0) visible = !@screen_center endparam float param a caption = "Spiral multiplier" default = 1 hint = "If negative, spiral goes in the opposite direction." endparam float param p caption = "Spiral power" min = 1e-4 default = 1 hint = "Useful values mostly between 0.5 and 2." visible = @type == 0 endparam float param b caption = "Coefficient" default = 0.1 min = 1e-6 visible = @type == 1 endparam bool param do_scale caption = "Scale by multiplier?" default = true visible = @a != 1 endparam heading ;text = "Use for distance:" endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DSquare(Distance) { ; 211124 added"Either" option ; 211229 added Rectangle option ; 230128 added "Change" and "Same" options; backwards compatible public: func JLB_DSquare(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif if @screen_center ctr = #center else ctr = @center endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) if @type == "Square" h = v = 0.5 * @side else h = 0.5 * @horiz v = 0.5 * @vert endif scale = 1 if @do_scale if @version >= 220720 scale = 2*sqrt(h*v) else scale = h if v > h, scale = v, endif endif endif size = sqrt(h*v) v1 = ctr + h + flip(v) ; upper right corner v2 = ctr + h - flip(v) ; lower right corner v3 = ctr - h - flip(v) ; lower left corner v4 = ctr - h + flip(v) ; upper left corner endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, m_abs_value) old_inside = IsInside(rot * (zz - ctr)) endfunc float func Iterate(complex zz) zz = rot * (zz - ctr) bool new_inside = IsInside(zz) if @version < 220916 zz = ctr + zz ; wrong endif float d = -MyMath.fmax(1, |zz|) if @version < 230811 && @method == "Original" float dist = cabs(zz - ctr) if new_inside if @in_out_old == "Inside"|| @in_out_old == "Either" d = (1-dist/h)^@pow endif return d else; if x > h || y > v if @in_out_old == "Outside" || @in_out_old == "Either" d = (1-h/dist)^@pow endif endif else;if @method == "Corrected" bool okay = false if @in_out == "Either" okay = true elseif @in_out == "Inside" okay = new_inside elseif @in_out == "Outside" okay = !new_inside elseif @in_out == "Change" okay = old_inside != new_inside elseif @in_out == "Same" okay = old_inside == new_inside endif if @version >= 230808 && !okay if @in_out == "In->In" okay = old_inside && new_inside elseif @in_out == "In->Out" okay = old_inside && !new_inside elseif @in_out == "Out->In" okay = !old_inside && new_inside elseif @in_out == "Out->Out" okay = !old_inside && !new_inside endif endif old_inside = new_inside if okay complex pv = Geometry.ClosestPointToFigure(zz, 4, v1, v2, v3, v4) if @version >= 230811 pv = zz * cabs(pv)/size ; to be like circle2 endif d = m_dist.Iterate(pv)/scale bool neg = ( d < 0 ) d = abs(d)^@pow if neg, d = -d, endif endif endif return d endfunc bool func IsInside(complex zz) float x = abs(real(zz)) float y = abs(imag(zz)) return (x <= h && y <= v) endfunc private: complex ctr complex rot float h float v float size float scale complex v1, complex v2, complex v3, complex v4 Distance m_dist bool old_inside default: title = "Square" rating = NotRecommended heading caption = "Use 'SimpleShapes' instead." endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading param type caption = "Square / Rectangle" enum = "Square" "Rectangle" default = 0 endparam float param side caption = "Square side length" default = 2.0 min = 0 visible = @type == 0 endparam float param horiz caption = "Rectangle x length" default = 2 min = 0 visible = @type == 1 endparam float param vert caption = "Rectangle y length" default = 2 min = 0 visible = @type == 1 endparam bool param screen_center caption = "Use screen center?" default = true endparam param center caption = "Square center" default = (0,0) visible = !@screen_center endparam float param angle caption = "Rotation angle" default = 0 endparam param in_out_old caption = "Inside/outside the Square" enum = "Inside" "Outside" "Either" default = 2 ; changed 230102, was 0 visible = @method == 0 endparam param in_out caption = "Inside/outside the Square" enum = "Inside" "Outside" "Either" "Change" "Same" \ "In->In" "In->Out" "Out->In" "Out->Out" default = 2 visible = @version >= 230811 || @method == 1 endparam param method caption = "Distance method" enum = "Original" "Corrected" default = 1 visible = @version < 230811 endparam float param pow caption = "Distance power" default = 1 min = 0 ; hint = "Higher values emphasize iterations with z away from the Square edge." endparam bool param do_scale caption = "Scale by size?" default = true visible = @version < 240101 endparam Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DSimpleShapes(Distance) { ; 240224 added @standard to Circles and Ellipses to allow for different powers for ; the x and y terms. Does not break earlier fractals, so @version not changed. public: func JLB_DSimpleShapes(Generic pparent) Distance(pparent) m_dist = new @dist(this) if @screen_center, ctr = #center, else, ctr = @center, endif ; scale = 1 complex v1 , complex v2 , complex v3 , complex v4 v1 = v2 = v3 = v4 = 1 ; make compiler happy if @type == "Circle" || @type == "Ellipse" if @standard px = py = pxy = @p else px = @qx, py = @qy, pxy = (px+py)/2 endif endif if @type == "Circle" h = v = @r elseif @type == "Ellipse" h = @hE, v = @vE elseif @type == "Triangle" if @equi v1 = flip(2*@side/3) rot = cos(#pi*2/3) + flip(sin(#pi*2/3)) v2 = v1 * rot v3 = v2 * rot v1 = v1 + ctr, v2 = v2 + ctr, v3 = v3 + ctr else v1 = @vt1, v2 = @vt2, v3 = @vt3 endif v4 = v3 ; simplifies things else if @type == "Square" h = v = 0.5 * @side else h = 0.5 * @hR, v = 0.5 * @vR endif ; if @do_scale, scale = 2*sqrt(h*v), endif v1 = ctr + h + flip(v) ; upper right corner v2 = ctr + h - flip(v) ; lower right corner v3 = ctr - h - flip(v) ; lower left corner v4 = ctr - h + flip(v) ; upper left corner endif rot = 1 if @type != "Circle" || @p != 2 rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) endif if @type >= 2 v1r = ctr + conj(rot)*(v1-ctr) v2r = ctr + conj(rot)*(v2-ctr) v3r = ctr + conj(rot)*(v3-ctr) v4r = ctr + conj(rot)*(v4-ctr) endif endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, m_abs_value) if @type == "Circle" || @type == "Ellipse" float r old_inside = IsInsideC(rot * (zz - ctr), r) ; calculates r -- ignored elseif @type == "Triangle" old_inside = Geometry.PointInTriangle(zz, v1r, v2r, v3r) else old_inside = IsInsideS(rot * (zz - ctr)) endif endfunc float func Iterate(complex zz) bool new_inside float r = 1 ; keep compiler happy if @type == "Circle" || @type == "Ellipse" new_inside = IsInsideC(rot * (zz - ctr), r) ; calculates r elseif @type == "Triangle" new_inside = Geometry.PointInTriangle(zz, v1r, v2r, v3r) else ; rotate and shift zz so IsInsideS can be simple new_inside = IsInsideS(rot * (zz - ctr)) endif float d = -1 bool okay = false if @in_out == "Either" okay = true elseif @in_out == "Inside" okay = new_inside elseif @in_out == "Outside" okay = !new_inside elseif @in_out == "Change" okay = old_inside != new_inside elseif @in_out == "Same" okay = old_inside == new_inside elseif @in_out == "In->In" okay = old_inside && new_inside elseif @in_out == "In->Out" okay = old_inside && !new_inside elseif @in_out == "Out->In" okay = !old_inside && new_inside elseif @in_out == "Out->Out" okay = !old_inside && !new_inside elseif @in_out == "Show shape" zz = #pixel if @type == "Circle" || @type == "Ellipse" okay = IsInsideC(rot * (zz - ctr), r) ; calculates r, used below elseif @type == "Triangle" okay = Geometry.PointInTriangle(zz, v1r, v2r, v3r) else okay = IsInsideS(rot*(zz-ctr)) endif endif old_inside = new_inside if !okay return -1 endif complex pv if @type == "Circle" || @type == "Ellipse" d = r ; needed for Show shape else int nv = 3 if @type != "Triangle", nv = 4, endif pv = Geometry.ClosestPointToFigure(zz, nv, v1r, v2r, v3r, v4r) d = cabs(pv) endif if @in_out == "Show shape" return d endif if @type == "Circle" || @type == "Ellipse" d = abs(1-r) endif zz = d * zz d = m_dist.Iterate(zz) ; d = (d + cabs(zz)) / 2 return d endfunc bool func IsInsideS(complex zz) float x = abs(real(zz)) float y = abs(imag(zz)) return (x <= h && y <= v) endfunc bool func IsInsideC(complex zz, float &r) float x = abs(real(zz)) float y = abs(imag(zz)) r= ( (x/h)^px + (y/v)^py ) ^ (1/pxy) return r <= 1 endfunc private: complex ctr complex rot float h, float v float px, float py, float pxy ; float scale complex v1r, complex v2r, complex v3r, complex v4r Distance m_dist bool old_inside default: title = "Simple Shapes" rating = Recommended int param version caption = "Version" default = 240212 visible = @version < 240212 endparam heading text = "(Curent is 240212.}" visible = @version < 240212 endheading param type caption = "Shape type" enum = "Circle" "Ellipse" "Triangle" "Square" "Rectangle" default = 0 endparam ; triangle stuff bool param equi caption = "Equilateral triangle?" default = true visible = @type == 2 endparam complex param vt1 caption = "Vertex 1" default = (0,0) visible = @type == 2 && !@equi endparam complex param vt2 caption = "Vertex 2" default = (1,0) visible = @type == 2 && !@equi endparam complex param vt3 caption = "Vertex 3" default = (0,1) visible = @type == 2 && !@equi endparam float param side caption = "Side length" default = 2.0 min = 0 visible = (@type == 2 && @equi) || @type == 3 endparam ; circle & ellipse stuff bool param screen_center caption = "Use screen center?" default = true visible = @type < 2 || (@type == 2 && @equi) endparam param center caption = "Center" default = (0,0) ; visible = (@type < 2 || (@type == 2 && @equi)) && !@screen_center visible = (!(@type == 2 && !@equi)) && !@screen_center endparam bool param standard caption = "Standard?" default = true endparam float param p caption = "Shape power" default = 2 min = 0.2 visible = @type < 2 && @standard endparam float param qx caption = "X shape power" default = 2 min = 0.2 visible = @type < 2 && !@standard endparam float param qy caption = "Y shape power" default = 2 min = 0.2 visible = @type < 2 && !@standard endparam float param r caption = "Circle radius" default = 1 min = 0 visible = @type == 0 endparam float param hE caption = "Ellipse x value" default = 2 min = 0 visible = @type == 1 endparam float param vE caption = "Ellipse y value" default = 1 min = 0 visible = @type == 1 endparam ; square & rectangle stuff float param hR caption = "Rectangle X length" default = 2 min = 0 visible = @type == 4 endparam float param vR caption = "Rectangle Y length" default = 1 min = 0 visible = @type == 4 endparam float param angle caption = "Rotation angle" default = 0 endparam param in_out caption = "Inside/outside/etc." enum = "Inside" "Outside" "Either" "Change" "Same" \ "In->In" "In->Out" "Out->In" "Out->Out" "Show shape" default = 2 endparam heading endheading Distance param dist default = JLB_D_SD ;2 selectable = false visible = @in_out != "Show shape" endparam } class JLB_DSimple(Distance) { ; Take a complex number as input and return a float public: func JLB_Dsimple(Generic pparent) ; m_CTF = new ComplexToFloat() endfunc float func Iterate(complex zz) float ans = ComplexToFloat.go(zz, m_mode, m_abs_value) return ans endfunc private: ; ComplexToFloat2 m_CTF default: title = "Simple" rating = NotRecommended heading text = "(Simple2 is the preferred plug-in.)" endheading } class JLB_DSimple2(Distance) { ; Take a complex number as input and return a float public: func JLB_DSimple2(Generic pparent) Distance(pparent) if @version < 220622 ctr = (0,0) else if @screen_center ctr = #center else ctr = @center endif endif if @version >=220703 && @version < 240101 m_dist = new @dist(this) elseif @version >= 240101 m_dist = new @distnew(this) endif endfunc func Init(complex zz) if @version >=220703 m_dist.Init(zz) m_dist.SetParams(0, true) endif endfunc float func Iterate(complex zz) if @version >= 220703 return m_dist.Iterate(zz) endif int mmode = m_mode if @version < 220619 mmode = @mode endif float ans = ComplexToFloat2.go(zz-ctr,(0,0), mmode, true) return ans endfunc private: complex ctr Distance m_dist default: title = "Simple2" rating = NotRecommended heading text = "Color according to a combination of real and imaginary parts of z." endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading bool param screen_center caption = "Use screen center?" default = true visible = @version >= 220622 endparam complex param center caption = "Center" default = (0,0) visible = @version >= 220622 && !@screen_center endparam param mode caption = "Use for distance" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220619 endparam heading ;text = "Use for distance:" endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version >=220703 && @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DMultiple(Distance) { public: func JLB_DMultiple(Generic pparent) Distance(pparent) fDist1 = new @dist1(this) if @num >= 2 fDist2 = new @dist2(this) if @num >= 3 fDist3 = new @dist3(this) if @num >= 4 fDist4 = new @dist4(this) if @num >= 5 fDist5 = new @dist5(this) endif endif endif endif endfunc func Init(complex zz) fDist1.Init(zz) fDist1.SetParams(0, true) if @num >= 2 fDist2.Init(zz) fDist2.SetParams(0, true) if @num >= 3 fDist3.Init(zz) fDist3.SetParams(0, true) if @num >= 4 fDist4.Init(zz) fDist4.SetParams(0, true) if @num >= 5 fDist5.Init(zz) fDist5.SetParams(0, true) endif endif endif endif endfunc float func Iterate(complex zz) bool okay_d = false float d = -1 float dd dd = fDist1.Iterate(zz) if dd > 0 d = dd, okay_d = true elseif @how == "All" return -1 endif if @num >= 2 dd = fDist2.Iterate(zz) if dd > 0 if okay_d if dd < d, d = dd, endif else d = dd, okay_d = true endif elseif @how == "All" return -1 endif endif if @num >= 3 dd = fDist3.Iterate(zz) if dd > 0 if okay_d if dd < d, d = dd, endif else d = dd, okay_d = true endif elseif @how == "All" return -1 endif endif if @num >= 4 dd = fDist4.Iterate(zz) if dd > 0 if okay_d if dd < d, d = dd, endif else d = dd, okay_d = true endif elseif @how == "All" return -1 endif endif if @num >= 5 dd = fDist5.Iterate(zz) if dd > 0 if okay_d if dd < d, d = dd, endif else d = dd, okay_d = true endif elseif @how == "All" return -1 endif endif return d endfunc private: Distance fDist1 Distance fDist2 Distance fDist3 Distance fDist4 Distance fDist5 default: title = "Multiple" rating = NotRecommended heading text = "Designed for methods that do Inside/Outside (Circle, Square, etc.), \ but usable for all. Use the minimum distance." endheading int param version caption = "Version" default = 211021 visible = @version < 211021 endparam int param num caption = "How many (max 5)?" default = 2 min = 1 max = 5 endparam param how caption = "Require any or all?" enum = "Any" "All" hint = "Allow any distance within range, or require all destances to be within range" default = 0 endparam heading ; caption = "Distance method 1" endheading Distance param dist1 caption = "Method 1" default = JLB_DCircle2 endparam heading ; caption = "Distance method 2" visible = @num >= 2 endheading Distance param dist2 caption = "Method 2" default = JLB_DSquare visible = @num >= 2 endparam heading ; caption = "Distance method 3" visible = @num >= 3 endheading Distance param dist3 caption = "Method 3" default = JLB_DGrid2 visible = @num >= 3 endparam heading ; caption = "Distance method 4" visible = @num >= 4 endheading Distance param dist4 caption = "Method 4" default = JLB_DSquare visible = @num >= 4 endparam heading ; caption = "Distance method 5" visible = @num >= 5 endheading Distance param dist5 caption = "Method 5" default = JLB_DSquare visible = @num >= 5 endparam } class JLB_DOverUnder(Distance) { public: func JLB_DOverUnder(Generic pparent) fDistOver = new @distOver(this) fDistUndr = new @distUndr(this) endfunc func Init(complex zz) fDistOver.Init(zz) fDistUndr.Init(zz) if @version < 220703 fDistOver.SetParams(@scoloring1, true) fDistUndr.SetParams(@scoloring2, true) endif endfunc float func Iterate(complex zz) float v = ComplexToFloat2.go(zz, (0,0), @mode, false) if v >= @crit return fDistOver.Iterate(zz) else return fDistUndr.Iterate(zz) endif endfunc private: Distance fDistOver Distance fDistUndr default: title = "OverUnder" rating = NotRecommended heading text = "Use a distance method depending on a critical value." hint = "Use real and imaginary parts of z to \ calculate value to compare with critical value." endheading int param version caption = "Version" default = 220703 visible = @version < 220703 endparam param mode caption = "Use for critical value" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" endparam float param crit caption = "Critical value" default = 1 endparam heading endheading param scoloring1 caption = "Use for Over distance" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag| (manh)""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220703 && @distOver != JLB_DTrap endparam Distance param distOver caption = "Over method" default = JLB_DSimple2 endparam heading endheading param scoloring2 caption = "Use for Under distance" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag| (manh)""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220703 && @distUndr != JLB_DTrap endparam Distance param distUndr caption = "Under method" default = JLB_DCircle endparam } class JLB_DTri(Distance) { ; distance to nearest triangle vertex ; okay if the triangle is degenerate ; 211124 added "Either" option public: func JLB_DTri(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif scale = 1 if @do_scale scale = (cabs(@v1-@v2) + cabs(@v2-@v3) + cabs(@v3-@v1) ) / 3 endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) ctr = (@v1 + @v2 + @v3) / 3 endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) zz = ctr + rot * (zz - ctr) old_inside = Geometry.PointInTriangle(zz, @v1, @v2, @v3) endfunc float func Iterate(complex zz) ; if @version < 220910 zz = ctr + rot * (zz - ctr) ; wrong! ? ; else ; zz = rot * zz ; endif bool new_inside = Geometry.PointInTriangle(zz, @v1, @v2, @v3) if @method == "Original" if (new_inside && @in_out_old == "Outside") || (!new_inside && @in_out_old == "Inside") return -1 endif float d1 = cabs(zz - @v1) float d2 = cabs(zz - @v2) float d3 = cabs(zz - @v3) if d2 < d1, d1 = d2, endif if d3 < d1, d1 = d3, endif return d1 else float d = -1 bool okay = true ; "Either" if @in_out == "Inside" okay = new_inside elseif @in_out == "Outside" okay = !new_inside elseif @in_out == "Change" okay = old_inside != new_inside elseif @in_out == "Same" okay = old_inside == new_inside endif old_inside = new_inside if okay complex pv = Geometry.ClosestPointToFigure(zz, 3, @v1, @v2, @v3, @v3) float d = m_dist.Iterate(pv) bool neg = ( d < 0 ) d = abs(d/scale)^@pow if neg, d = -d, endif endif return d endif endfunc private: float scale complex rot complex ctr Distance m_dist bool old_inside default: title = "Triangle" rating = NotRecommended heading caption = "Use 'SimpleShapes' instead." endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading complex param v1 caption = "Vertex 1" default = (0,0) endparam complex param v2 caption = "Vertex 2" default = (2,0) endparam complex param v3 caption = "Vertex 3" default = (0,2) endparam float param angle caption = "Rotation angle" default = 0 endparam param in_out_old caption = "Inside/outside the Triangle" enum = "Inside" "Outside" "Either" default = 2 ; changed 230102, was 0 visible = @method == 0 endparam param in_out caption = "Inside/outside the Triangle" enum = "Inside" "Outside" "Either" "Change" "Same" default = 2 visible = @method == 1 endparam param method caption = "Distance method" enum = "Original" "Corrected" default = 1 ; visible = @in_out < 2 endparam float param pow caption = "Distance power" default = 1 min = 0 visible = @method == 1 ; hint = "Higher values emphasize iterations with z away from the Square edge." endparam bool param do_scale caption = "Scale by side length?" default = false visible = @method == 1 endparam Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DTriangle(Distance) { public: func JLB_DTriangle(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) first = true endfunc ; The insides of Triangle Inequality Average float func Iterate(complex zz) if first first = false ; to agree with the original return -1 endif float ac = m_dist.Iterate(#pixel) float bc = m_dist.Iterate(zz-#pixel) float cc = m_dist.Iterate(zz) float least = abs(bc - ac) float most = bc + ac if most <= least return -1 endif return (cc - least) / (most - least) endfunc private: bool first Distance m_dist default: title = "TIA Distance" rating = Recommended ; heading ; text = "Standard Triangle Inequality Average coloring. Using TIA type as the Final smooth \ ; may be useful." ; endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_DCircle(Distance) { ;211124 added "Either" option ;211229 added Ellipse option and "use screen center" option ;220916 added option to change h and v by @ratio each iteration. backwards compatible. public: func JLB_DCircle(Generic pparent) Distance(pparent) m_dist = new @dist(this) if @screen_center ctr = #center else ctr = @center endif scale = 1 if @type == "Circle" h = v = @r else h = @horiz, v = @vert endif if @do_scale if @version >= 220720 scale = sqrt(h*v) else scale = MyMath.fmax(h, v) endif endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) endfunc func Init(complex zz) m_dist.SetParams(0, true) endfunc float func Iterate(complex zz) float x, float y zz = rot * (zz - ctr) x = abs(real(zz)) y = abs(imag(zz)) int iter = GetIter( ) float rr = @ratio^iter float hh = h*rr float vv = v*rr float ss = scale*rr float q= (x/hh)^@p + (y/vv)^@p if @version < 220619 ; this version has errors float d = -1 q= q^(1/@p) if q <= 1 && (@in_out == "Inside" || @in_out == "Either") d = ((1-q)/ss)^@pow endif if q > 1 && (@in_out == "Outside" || @in_out == "Either") d = ((1-1/q)/ss)^@pow endif return d else float d1 = -1 if q <= 1 && @in_out != "Outside" if q == 0 d1 = MyMath.fmin(hh, vv) else zz = (1/q-1) * zz d1 = m_dist.Iterate(zz/rot)/ss endif endif float d2 = -1 if q > 1 && @in_out != "Inside" zz = (q-1) * zz d2 = m_dist.Iterate(zz/rot)/ss endif ; at least one of d1 and d2 is non-negative if d2 < 0, return d1, endif if d1 < 0, return d2, endif return MyMath.fmin(d1, d2) endif endfunc private: complex ctr float h float v float scale complex rot Distance m_dist default: title = "Circle" rating = NotRecommended heading text = "Distance to a circle or ellipse. Optionally use only those iterations that are \ inside or outside the shape." endheading int param version caption = "Version" default = 220720 visible = @version < 220720 endparam heading text = "(Curent is 220720.}" visible = @version < 220720 endheading param type caption = "Circle or ellipse" enum = "Circle" "Ellipse" default = 0 endparam float param p caption = "Shape power" default = 2 min = 0 hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square." endparam bool param screen_center caption = "Use screen center?" default = true endparam param center caption = "Center" default = (0,0) visible = !@screen_center endparam float param r caption = "Circle radius" default = 2.0 min = 0 visible = @type == 0 endparam float param horiz caption = "Ellipse x value" default = 2.0 min = 0 visible = @type == 1 endparam float param vert caption = "Ellipse y value" default = 2.0 min = 0 visible = @type == 1 endparam float param ratio caption = "Ratio" hint = "Change circle radius / ellipse values by this factor each iteration." default = 1 min = 0 endparam float param angle caption = "Rotation angle" default = 0 visible = @p != 2.0 || (@type == 1 && @horiz != @vert) endparam param in_out caption = "Inside/outside?" enum = "Inside" "Outside" "Either" default = 2 ; changed 230102, was 0 endparam float param pow caption = "Distance power" default = 1 min = 0 visible = @version < 220619 ; hint = "Higher values emphasize iterations with z away from the Square edge." endparam bool param do_scale caption = "Scale by size?" default = false ;visible = @version < 220619 endparam heading endheading Distance param dist default = JLB_DXYZ selectable = false endparam } class JLB_DCircle2(Distance) { ; 230126 added "Change" option; backwards compatible. ; 230808 added "In->In" & etc. options. ; 231215 changed dist fro JLB_DXYZ to JLB_D_SD public: func JLB_DCircle2(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif if @screen_center, ctr = #center, else, ctr = @center, endif if @type == "Circle", h = v = @r, else, h = @horiz, v = @vert, endif scale = 1 if @do_scale scale = 2 * MyMath.fmax(h, v) ; 2 to be like Square scaling endif rot = cos(@angle*#pi/180) + flip(sin(@angle*#pi/180)) endfunc func Init(complex zz) m_dist.Init(zz) ; needed if JLB_D_SD, uses D19 Path Ratio m_dist.SetParams(0, m_abs_value) float r old_inside = IsInside(rot * (zz - ctr), r) ; calculates r -- ignored endfunc float func Iterate(complex zz) zz = rot * (zz - ctr) float d = -MyMath.fmax(1, |zz|) float r bool new_inside = IsInside(zz, r) ; calculates r complex t bool okay = false if @in_out == "Either" okay = true elseif @in_out == "Inside" okay = new_inside elseif @in_out == "Outside" okay = !new_inside elseif @in_out == "Change" okay = new_inside != old_inside elseif @in_out == "Same" okay = new_inside == old_inside endif if @version >= 230808 if @in_out == "In->In" okay = old_inside && new_inside elseif @in_out == "In->Out" okay = old_inside && !new_inside elseif @in_out == "Out->In" okay = !old_inside && new_inside elseif @in_out == "Out->Out" okay = !old_inside && !new_inside endif endif if @in_out == "Show shape" okay = IsInside(rot*(#pixel-ctr), r) ; calculates r -- used! endif if okay if @in_out == "Show shape" d = r else t = zz * (1-r) / rot if @version >= 230808 && !new_inside t = -t endif d = m_dist.Iterate(t)/scale old_inside = new_inside if @version < 240101 bool neg = ( d < 0 ) d = abs(d)^@pow if neg, d = -d, endif endif endif endif return d endfunc bool func IsInside(complex zz, float &r) float x = abs(real(zz)) float y = abs(imag(zz)) r= ( (x/h)^@p + (y/v)^@p ) ^ (1/@p) return r <= 1 endfunc private: complex ctr float h float v float scale complex rot bool old_inside Distance m_dist default: title = "Circle2" rating = NotRecommended heading caption = "Use 'SimpleShapes' instead." endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading param type caption = "Circle or ellipse" enum = "Circle" "Ellipse" default = 0 endparam float param p caption = "Shape power" default = 2 min = 0 hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square." endparam bool param screen_center caption = "Use screen center?" default = true endparam param center caption = "Center" default = (0,0) visible = !@screen_center endparam float param r caption = "Circle radius" default = 2.0 min = 0 visible = @type == 0 endparam float param horiz caption = "Ellipse x value" default = 2.0 min = 0 visible = @type == 1 endparam float param vert caption = "Ellipse y value" default = 2.0 min = 0 visible = @type == 1 endparam float param angle caption = "Rotation angle" default = 0 visible = @p != 2.0 || (@type == 1 && @horiz != @vert) endparam param in_out caption = "Inside/outside?" enum = "Inside" "Outside" "Either" "Change" "Same" \ "In->In" "In->Out" "Out->In" "Out->Out" "Show shape" hint = "Change: use iterations where new inside is different from \ old inside. Same: use iterations where new inside equals \ old inside" default = 2 ; changed 230102, was 0 endparam float param pow caption = "Distance power" default = 1 min = 0 visible = @version < 240101 ; hint = "Higher values emphasize iterations with z away from the circle edge." endparam bool param do_scale caption = "Scale by size?" default = false visible = @in_out != "Show shape" endparam heading ;text = "Use for distance:" endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 && @in_out != "Show shape" endparam } class JLB_DCircles(Distance) { public: func Init(complex zz) r[1] = @r1 if @polar ctr[1] = @rad1*(cos(@ang1*#pi/180) + flip(sin(@ang1*#pi/180))) else ctr[1] = @dctr1 endif if @num >= 2 r[2] = @r2 if @polar ctr[2] = @rad2*(cos(@ang2*#pi/180) + flip(sin(@ang2*#pi/180))) else ctr[2] = @dctr2 endif if @num >= 3 r[3] = @r3 if @polar ctr[3] = @rad3*(cos(@ang3*#pi/180) + flip(sin(@ang3*#pi/180))) else ctr[3] = @dctr3 endif if @num >= 4 r[4] = @r4 if @polar ctr[4] = @rad4*(cos(@ang4*#pi/180) + flip(sin(@ang4*#pi/180))) else ctr[4] = @dctr4 endif if @num >= 5 r[5] = @r5 if @polar ctr[5] = @rad4*(cos(@ang5*#pi/180) + flip(sin(@ang5*#pi/180))) else ctr[5] = @dctr5 endif endif endif endif endif endfunc float func Iterate(complex zz) float d = -1 float dd int n = 1 while n <= @num float x, float y, float rz x = abs(real(zz-ctr[n])) y = abs(imag(zz-ctr[n])) rz = (x^@shape + y^@shape)^(1/@shape) if @in_out == "Inside" if rz < r[n] if @how == "Original" dd = (1 - rz/r[n])^@pow else dd = ((r[n]-rz)/r[n]) endif if d < 0 ; first one that's inside d = dd else if dd < d, d = dd, endif endif endif else;if @in_out == "Outside" if rz > r[n] if @how == "Original" dd = (1 - r[n]/rz)^@pow else dd = ((rz-r[n])/r[n]) endif if d < 0 d = dd else if dd < d, d = dd, endif endif endif endif n = n + 1 endwhile return d endfunc private: complex ctr[6] float r[6] default: title = "Circles" rating = NotRecommended heading text = "Use only the iterations that are inside or outside the circle(s), as specified." endheading int param num caption = "How many (max 5)?" default = 1 min = 1 max = 5 endparam float param shape caption = "Circle shape" default = 2 min = 0 hint = "Use 2 for circle, < 2 for indented, > 2 for shapes nearing a square" endparam param how caption = "How to calculate" enum = "Original" "Corrected" default = 0 endparam bool param polar caption = "Polar coords, for centers?" default = false hint = "Centers may be specified by real and imaginary part or using distance and angle." endparam heading endheading float param r1 caption = "Circle #1 size" default = 2.0 min = 0 endparam param dctr1 caption = "Circle #1 ctr" default = (0,0) visible = !@polar endparam float param rad1 caption = "Circle #1 ctr. distance" default = 2 visible = @polar endparam float param ang1 caption = "Circle #1 ctr. angle" default = 0 visible = @polar endparam float param r2 caption = "Circle #2 size" default = 1.0 min = 0 visible = @num >= 2 endparam param dctr2 caption = "Circle #2 center" default = (2,0) visible = @num >= 2 && !@polar endparam float param rad2 caption = "Circle #2 ctr. distance" default = 2 visible = @num >= 2 && @polar endparam float param ang2 caption = "Circle #2 ctr. angle" default = 60 visible = @num >= 2 && @polar endparam float param r3 caption = "Circle #3 size" default = 1.0 min = 0 visible = @num >= 3 endparam param dctr3 caption = "Circle #3 center" default = (-2,0) visible = @num >= 3 && !@polar endparam float param rad3 caption = "Circle #3 ctr. distance" default = 2 visible = @num >= 3 && @polar endparam float param ang3 caption = "Circle #3 ctr. angle" default = 120 visible = @num >= 3 && @polar endparam float param r4 caption = "Circle #4 size" default = 1.0 min = 0 visible = @num >= 4 endparam param dctr4 caption = "Circle #4 center" default = (0,2) visible = @num >= 4 && !@polar endparam float param rad4 caption = "Circle #4 ctr. distance" default = 2 visible = @num >= 4 && @polar endparam float param ang4 caption = "Circle #4 ctr. angle" default = -120 visible = @num >= 4 && @polar endparam float param r5 caption = "Circle #5 size" default = 1.0 min = 0 visible = @num >= 5 endparam param dctr5 caption = "Circle #5 center" default = (0,-2) visible = @num >= 5 && !@polar endparam float param rad5 caption = "Circle #5 ctr. distance" default = 2 visible = @num >= 5 && @polar endparam float param ang5 caption = "Circle #5 ctr. angle" default = -60 visible = @num >= 5 && @polar endparam heading endheading param in_out caption = "Inside/outside the circles" enum = "Inside" "Outside" default = 0 hint = "Inside means inside any 'circle'; outside means outside any 'circle'." endparam float param pow caption = "Distance power" default = 1 min = 0 hint = "Higher values emphasize iterations with z away from the circle edge." visible = @how == 0 endparam } class JLB_DTrap(Distance) { ; Use a trap shape to calculate a distance public: import "common.ulb" import "Standard.ulb" func JLB_DTrap(Generic pparent) fShape = new @shape(this) endfunc func Init(complex zz) fShape.init(zz) endfunc float func Iterate(complex zz) float ans = fshape.iterate(zz) return abs(ans) endfunc private: TrapShape fShape default: title = "Trap" rating = Recommended heading text = "Use a trap shape for calculating distance." endheading TrapShape param shape caption = "Trap Shape" default = Standard_TrapShapeCross hint = "Selects the shape of the orbit trap." endparam } class ComplexToFloat{ public: func ComplexToFloat() endfunc static float func go(const complex zz, int mode, bool abs_value) float ans float r = real(zz) float i = imag(zz) float rabs = abs(r) float iabs = abs(i) if mode == 0 ; "Mod" ans = sqrt(r^2 + i^2) elseif mode == 1 ; "Real" ans = r elseif mode == 2 ; "Imag" ans = i elseif mode == 3 ; "Real+Imag" ans = r+i elseif mode == 4 ; "Real-Imag" ans = r-i elseif mode == 5 ; "Real*Imag" ans = abs(r*i) elseif mode == 6 ; "Real/Imag" ans = r/i elseif mode == 7 ; "Real^Imag" ans = r^i elseif mode == 8 ; "Imag/Real" ans = i/r elseif mode == 9 ; "Imag^Real" ans = i^r elseif mode == 10 ; "|Real|+|Imag|" ans = rabs+iabs elseif mode == 11 ; "|Real|-|Imag|" ans = rabs-iabs elseif mode == 12 ; "Max(Real,Imag)" ans = MyMath.fmax(i, r) elseif mode == 13 ;"Min(Real,Imag)" ans = MyMath.fmin(i, r) elseif mode == 14 ; "Max(|Real|,|Imag|)" ans = MyMath.fmax(iabs, rabs) elseif mode == 15 ; "Min(|Real|,|Imag|)" ans = MyMath.fmin(iabs, rabs) else;if mode == 16 ; "Angle" ans = atan2(zz)/ (2 * #pi) if ans < 0 ans = ans + 1 endif endif if abs_value ans = abs(ans) endif return ans endfunc } ; an auxiliary function ; 211003 corrected #12 to #15, added cc argument and more cases class ComplexToFloat2{ public: func ComplexToFloat2() endfunc static float func go(const complex zz, const complex cc, int mode, bool abs_value) float ans float r = real(zz) , float i = imag(zz) float rabs = abs(r), float iabs = abs(i) float rc = real(cc), float ic = imag(cc) if mode == 0 ; "Cabs" ans = sqrt(r^2 + i^2) elseif mode == 1 ; "Real" ans = r elseif mode == 2 ; "Imag" ans = i elseif mode == 3 ; "Real+Imag" ans = r+i elseif mode == 4 ; "Real-Imag" ans = r-i elseif mode == 5 ; "Real*Imag" ans = r*i ;ans = abs(r*i) (old version used abs for no good reason) elseif mode == 6 ; "Real/Imag" ans = r/i elseif mode == 7 ; "Real^Imag" ans = r^i elseif mode == 8 ; "Imag/Real" ans = i/r elseif mode == 9 ; "Imag^Real" ans = i^r elseif mode == 10 ; "|Real|+|Imag|" ans = rabs+iabs elseif mode == 11 ; "|Real|-|Imag|" ans = rabs-iabs elseif mode == 12 ; "Max(|Real|,|Imag|)" ans = rabs if iabs > rabs, ans = iabs, endif elseif mode == 13 ; "Max(Real,Imag)" ans = r if i > r, ans = i, endif elseif mode == 14 ; "Min(|Real|,|Imag|)" ans = rabs if iabs < rabs, ans = iabs, endif elseif mode == 15 ;"Min(Real,Imag)" ans = rabs if i < r, ans = i, endif elseif mode == 16 ; "Angle" ans = atan2(zz)/ (2 * #pi) if ans < 0 ans = ans + 1 endif elseif mode == 17 ; "z cross+ c" ans = r*ic + i*rc elseif mode == 18 ; "z cross- c" ans = r*ic - i*rc elseif mode == 19 ;"z dot+ c" ans = r*rc + i*ic elseif mode == 20 ; "z dot- c" ans = r*rc - i*ic else;if mode == 21 ; cabs(z*c) ans = cabs(zz*cc) endif if abs_value ans = abs(ans) endif return ans endfunc } class JLB_DistanceColoring(common.ulb:GradientColoring) { ; Accumulate a sum at each step, or at selected steps, of the orbit. ; Use the result to calculate a color index. ; public: import "common.ulb" func JLB_DistanceColoring(Generic pparent) GradientColoring(pparent) if @twodist fDistance1 = new @dist1(this) fDistance2 = new @dist2(this) else fDistance = new @dist(this) endif if @version < 220621 zDistance = new @zDist(this) endif if @fz == 2 zzTransform = new @fUT(this) elseif @fz == 1 && @version >= 220801 zzTransform = new @FF(this) endif rotation = cos(@angle * #pi/180.0) - flip(sin(@angle * #pi/180.0)) endfunc func Init(complex pz, complex ppixel) GradientColoring.Init(pz, ppixel) if @twodist fDistance1.init(pz) fDistance2.init(pz) if @version < 220703 fDistance1.SetParams(@scoloring1, true) fDistance2.SetParams(@scoloring2, true) else fDistance1.SetParams(0, true) fDistance2.SetParams(0, true) endif else fDistance.init(pz) if @version < 220703 fDistance.SetParams(@scoloring, true) else fDistance.SetParams(0, true) endif endif cSum = 0, cSum2 = 0, cSumSq = 0 wtSum = 0, wtSum2 = 0 dmin = 1e30 dmax = -1e30 z_prev = pz iter = 0 ; iter updated each call to Iterate() iter1 = 1 iter2 = 2000000000 ; largest int is 2147483647 iter3 = -1 iter4 = -1 if @some_all == " Some" || @some_all == " Some + More" iter1 = @start iter2 = @start + @howmany - 1 if @some_all == " Some + More" iter3 = @start2 iter4 = @start2 + @howmany2 - 1 endif endif count = 0 ; count update only for succesful distance calculation icount = 0 endfunc func Iterate(complex pz) GradientColoring.Iterate(pz) iter = iter + 1 bool okay = (iter >= iter1 && iter <= iter2) || (iter >= iter3 && iter <= iter4) if !okay return endif complex zz = pz if @zdz == "z-z_prev" zz = zz - z_prev elseif @zdz == "z/z_prev" zz = zz / z_prev elseif @zdz == "z-pixel" zz = zz - #pixel elseif @zdz == "z/pixel" zz = zz / #pixel endif z_prev = pz zz = zz * rotation if @fz == "F(a*zz)" if @version < 220801 zz = @F(@a*zz) else zz = zzTransform.Iterate(@a*zz) endif elseif @fz == "T(a*zz)" zz = zzTransform.Iterate(@a*zz) endif float d if @twodist if icount < @n1 fDistance1.SetIter(iter) ; added 220916 - backwards compatible d = fDistance1.Iterate(zz) else fDistance2.SetIter(iter) ; added 220916 - backwards compatible d = fDistance2.Iterate(zz) endif else fDistance.SetIter(iter) ; added 220916 - backwards compatible d = fDistance.Iterate(zz) endif if @twodist icount = icount + 1 if icount == @n1 + @n2 icount = 0 endif endif if d <= 0 || (@UseMinMax && (d <= @ddmin || d > @ddmax)) return endif complex zd = d if @version < 220621 if @ctype > 5 if @dmult == "d*zz" zd = d * zz elseif @dmult == "d*G(b*zz)" zd = d * @G(@b*zz) endif endif endif count = count + 1 if @ctype == 0;"First Distance" if count == 1 cSum = d endif elseif @ctype == 1;"Last Distance" cSum = d elseif @ctype == 2;"Smallest Distance" if d < dmin cSum = d dmin = d endif elseif @ctype == 3;"Largest Distance" if d > dmax cSum = d dmax = d endif endif if d < dmin, dmin = d, endif if d > dmax, dmax = d, endif if @ctype == 4;"Distance range" cSum = dmax - dmin elseif @ctype == 5;"Distance ratio" if dmin > 0 cSum = dmax / dmin endif elseif @ctype > 5 ; some kind of average float w = 1 if @wtype w = count^@pwt endif Accumulate(zd, w) endif endfunc float func ResultIndex(complex pz) if @solid && count == 0 m_solid = true ; from base class return 0 endif if @ctype <= 5 wtsum = 1 else ; averages of some kind FinalAverage() endif float index = real(cSum) if @version < 220621 if @dmult > 0 if @ctype > 5 && @ctype < 9 index = zDistance.Iterate(csum) endif endif endif if @ctype == "Count" index = count / @Cscale endif if @final > 0 index = FinalSmooth(index) endif if @recip && index != 0 index = 1/index endif return index endfunc func Accumulate(complex zd, float w) cSum2 = cSum if @ctype == "Arithmetic Average" cSum = cSum + w * zd elseif @ctype == "Geometric Average" cSum = cSum + w * log(zd) elseif @ctype == "Harmonic Average" cSum = cSum + w / zd else cSum = cSum + w*zd cSumSq = cSumSq + |w*zd| ; real^2+imag^2 endif wtSum2 = wtSum wtSum = wtSum + w endfunc func FinalAverage() if count > 0 ; there were some if @ctype >= 9 || (@ctype > 5 && !@skip_avg) cSum = cSum / wtSum if wtSum2 > 0 cSum2 = cSum2 / wtSum2 endif cSumSq = cSumSq / wtSum endif if @ctype == "Geometric Average" ;7 cSum = exp(cSum) elseif @ctype == "Harmonic Average" ;8 cSum = 1 / cSum elseif (@ctype == "Variation 1") ;9 "Std. Deviation" ; ignoring the -1 of n-1 cSum = sqrt(cSumSq - |cSum|) elseif (@ctype == "Variation 2") ;10 "Coef. of Variation" cSum = sqrt(cSumSq - |cSum|) / cabs(cSum) elseif (@ctype == "Variation 3") ;11 "Fractal Dimension" if dmax == dmin cSum = 0 else cSum = sqrt(cSumSq - |cSum|) / (dmax-dmin) endif endif endif endfunc ; Some ftype coloring methods get a final smoothing. float func FinalSmooth(float ans) if @final == 1 float il = 1/log(@power) float lp = log(log(@bailout)) ans = 0.05 * (count - 1 + il*lp - il*log(log(abs(ans)))) ; 0.05 and -1 to agree with original elseif @final == 2 float il = 1/log(@power) ; as in Triangle in Standard.ulb float lp = log(log(@bailout)/2.0) float fac = (1 + il * lp - il*log(log(cabs(#z)))) csum = csum * wtSum / (wtSum + 1) ; to agree with original csum2 = csum2 * wtSum2 / (wtSum2 + 1) ans = cabs(cSum2 + (cSum - cSum2) * fac) endif return ans endfunc private: complex rotation Distance fDistance Distance fDistance1 ; for following the orbit Distance fDistance2 Distance zDistance ; for coloring the averages UserTransform zzTransform complex cSum complex cSum2 complex cSumsq float wtSum float wtSum2 float dmin float dmax complex z_prev int count int iter, int iter1, int iter2, int iter3, int iter4 int icount default: title = "Distance Coloring" rating = NotRecommended int param version caption = "Version" default = 220801 visible = @version < 220801 ; backward compatible to 220703 endparam heading text = "(Current is 220801.)" visible = @version < 220801 endheading Heading caption = "Use 'Color by Distance' instead." endheading bool param solid caption = "Use solid background?" default = true endparam ; maybe next as a hint? ; heading ; text = "Pixels for which the formula bails out on the first iteration will have the background color, \ ; rather than the zero location of the gradient." ; visible = @solid ; endheading heading caption = "Accumulation phase" endheading param zdz caption = "Use for zz " enum = "z" "z-z_prev" "z/z_prev" "z-pixel" "z/pixel" default = 0 endparam float param angle caption = "Rotate zz by " default = 0 endparam heading caption = "Use zz, F(a*zz), or T(a*zz)" endheading param fz caption = "Which?" enum = "zz" "F(a*zz)" "T(a*zz)" default = 0 endparam complex param a caption = "a" default = 1 visible = @fz > 0 endparam func F caption = "Function" default = sinh() visible = @fz == 1 && @version < 220801 endfunc UserTransform param FF default = JLB_FTransform selectable = false visible = @fz == 1 && @version >= 220801 endparam UserTransform param fUT caption = "Transform" default = JLB_MoebiusUserTransform visible = @fz == 2 endparam heading visible = @fz > 0 endheading bool param twodist caption = "Two distance methods?" default = false endparam ; heading ; visible = @twodist ; endheading bool param UseMinMax caption = "Min/max distances?" default = false endparam float param ddmin caption = "Min distance" default = 1 min = 0 visible = @UseMinMax endparam float param ddmax caption = "Max distance" default = 100 min = 0 visible = @UseMinMax endparam heading endheading param scoloring caption = "Use for distance" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag| (manh)""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220703 && !@twodist && @dist != JLB_DTrap \ && @dist != JLB_DOverUnder; && @dist != JLB_DCurve endparam Distance param dist caption = "Distance method" default = JLB_DXYZ ;Simple2 visible = !@twodist endparam param scoloring1 caption = "Use for distance 1" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag| (manh)""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220703 && @twodist && @dist != JLB_DTrap \ && @dist != JLB_DOverUnder; && @dist != JLB_DCurve endparam int param n1 caption = "Repetitions for #1" default = 1 min= 1 visible = @twodist endparam Distance param dist1 caption = "Distance method #1" default = JLB_DXYZ ;Simple2 visible = @twodist endparam Distance param zDist default = JLB_DXYZ ;Simple2 visible = false ; can't change it--maybe selectable=false instead? endparam heading visible = @twodist endheading param scoloring2 caption = "Use for distance 2" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" visible = @version < 220703 && @twodist && @dist2 != JLB_DTrap \ && @dist2 != JLB_DOverUnder; && @dist2 != JLB_DCurve endparam int param n2 caption = "Repetitions for #2" default = 1 min = 0 visible = @twodist endparam Distance param dist2 caption = "Distance method #2" default = JLB_DCircle visible = @twodist endparam heading endheading param some_all enum = " All" " Some" " Some + More" default = 0 caption = "Use all / some iterations?" ;visible = @type > 0 endparam int param start caption = "Starting with iteration?" default = 4 min = 1 visible = @some_all > 0 endparam int param howmany caption = "How many to use?" default = 100 min = 1 visible = @some_all > 0 endparam int param start2 caption = "More: starting with?" default = 1 min = 1 visible = @some_all > 1 endparam int param howmany2 caption = "More: how many?" default = 1 min = 0 visible = @some_all > 1 endparam bool param wtype caption = "Weighted averages?" default = false visible = @ctype > 5 endparam float param pwt caption = "Weight power p" default = 0.5 visible = @wtype == true && @ctype > 5 hint = "Positive p gives more weight to later iterations; negative p gives more weight \ to earlier iterations; p = 0 weights all iterations the same." endparam ; heading ; visible = @ctype > 5 ; endheading param dmult caption = "Use distance multiplier?" default = 0 enum = "d" "d*zz" "d*G(b*zz)" visible = @version < 220621 && @ctype > 5 endparam func G caption = "G" default = sinh() visible = @version < 220621 && @dmult == 2 && @ctype > 5 endfunc complex param b caption = "b" default = 1 visible = @version < 220621 && @dmult == 2 && @ctype > 5 endparam heading caption = "Final phase of coloring" endheading param ctype caption = "How to color" enum = "First Distance" "Last Distance" "Smallest Distance" "Largest Distance" \ "Distance range" "Distance ratio" \ "Arithmetic Average" "Geometric Average" "Harmonic Average" \ "Variation 1" "Variation 2" "Variation 3" "Count" ; "Std. Deviation" "Coef. of Variation" "Fractal Dimension" default = 6 ;visible = @final != 1 endparam int param Cscale caption = "Count scale" default = 100 visible = @ctype == 12 endparam bool param skip_avg ; maybe later if more checking caption = "Use sum instead of average?" default = false visible = @ctype > 5 && @ctype < 9 endparam param zcoloring caption = "Average this" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|" "|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" ; "Count" "First Iteration" "Last Iteration" visible = @dmult > 0 && @ctype > 5 && @ctype < 9 endparam param final caption = "Final smooth" enum = "None" "Mandelbrot type" "TIA type" default = 0 endparam float param power caption = "Exponent" default = 2.0 hint = "This should be set to match the exponent of the \ formula you are using." visible = @final > 0 endparam float param bailout caption = "Bailout" default = 1e20 min = 1 hint = "This should be set to match the bail-out value in the Formula tab. " visible = @final > 0 endparam bool param recip caption = "Use reciprocal?" default = false hint = "Color based on, for example, 1/Mod(z) instead of Mod(z)." endparam } class JLB_LinearUserTransform(common.ulb:UserTransform) { public: complex func Iterate(complex pz) return (@a + @b*pz) endfunc default: rating = NotRecommended title = "Linear" int param v_LinearUserTransform caption = "Version (Linear_UserTransform)" default = 220212 visible = @v_LinearUserTransform < 220212 endparam heading caption = "v_new = a + b*v" endheading complex param a caption = "Linear: a" default = (0,0) endparam complex param b caption = "Linear: b" default = (1,0) endparam } class Tweak(common.ulb:UtilityTransform) { public: import "common.ulb" func Tweak(Generic pparent) UtilityTransform(pparent) if @type == 2 zzTransform = new @uT(pparent) endif endfunc complex func Iterate(complex pz) complex tmp if @type == "Linear" tmp = @e1 + @e2*pz elseif @type == "Built-in Function" tmp = @e1 + @e2*@F(@a*pz) else;if @type == "Transform" tmp = @e1 + @e2*zzTransform.Iterate(@a*pz) endif if @kind == "Add" pz = pz + tmp else pz = tmp endif return pz endfunc private: UserTransform zzTransform default: title = "Tweak" param kind caption = "Add or Replace" enum = "Add" "Replace" default = 0 endparam heading caption = "v_new = v + e1 + e2*v" visible = @type == 0 && @kind == 0 endheading heading caption = "v_new = e1 + e2*v" visible = @type == 0 && @kind == 1 endheading heading caption = "v_new = v + e1 + e2*F(a*v)" visible = @type == 1 && @kind == 0 endheading heading caption = "v_new = e1 + e2*F(a*v)" visible = @type == 1 && @kind == 1 endheading heading caption = "v_new = v + e1 + e2*T(a*v)" visible = @type == 2 && @kind == 0 endheading heading caption = "v_new = e1 + e2*T(a*v)" visible = @type == 2 && @kind == 1 endheading param type caption = "Tweak type" enum = "Linear" "Built-in Function" "Transform" default = 0 endparam func F caption = "Tweak Function" default = ident() visible = @type == 1 endfunc UserTransform param uT caption = "Tweak Transform" default = JLB_LinearUserTransform visible = @type == 2 endparam complex param e1 caption = "Tweak: e1" default = (0,0) endparam complex param e2 caption = "Tweak: e2" default = (0.1,0) endparam complex param a caption = "a" default = 1 visible = @type > 0 endparam } class JLB_TwoUserTransforms(common.ulb:UserTransform) { ; A wrapper for two UserTransforms on one variable. public: import "common.ulb" func JLB_TwoUserTransforms(Generic pparent) UserTransform.UserTransform(pparent) mUT1 = new @fUT1(this) mUT2 = new @fUT2(this) m_Combine = new Combine() endfunc complex func Iterate(complex pz) if (@how == "( )") pz = mUT1.Iterate(mUT2.Iterate(pz)) else complex z1 = mUT1.Iterate(pz) complex z2 = mUT2.Iterate(pz) pz = m_Combine.go(z1, @how, z2) endif return pz endfunc protected: UserTransform mUT1 UserTransform mUT2 Combine m_Combine default: ;rating = Recommended title = "Two Transforms" heading caption = "Use 'Transform Combo' instead." endheading int param v_TwoUserTransforms caption = "Version (Two Transforms)" default = 220312 visible = @v_TwoUserTransforms < 220312 endparam param how caption = "How to combine" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine Transform values." endparam UserTransform param fUT1 caption = "First Transform" default = JLB_LinearUserTransform endparam UserTransform param fUT2 caption = "Second Transform" default = JLB_BasicUserTransform endparam } class JLB_ComboUserTransform(common.ulb:UserTransform) { ; Combine two functions or transforms or one each public: import "common.ulb" func JLB_ComboUserTransform(Generic pparent) UserTransform.UserTransform(pparent) if (@ww == "T1 F2") || (@ww == "T1 T2") mUT1 = new @fUT1(this) endif if (@ww == "F1 T2") || (@ww == "T1 T2") mUT2 = new @fUT2(this) endif m_Combine = new Combine() endfunc complex func Iterate(complex pz) complex z1 complex z2 if (@ww == "F1 F2") || (@ww == "T1 F2") z2 = @F2(pz) else z2 = mUT2.Iterate(pz) endif if (@how == "( )") if (@ww == "F1 F2") || (@ww == "F1 T2") pz = @F1(z2) else pz = mUT1.Iterate(z2) endif else if (@ww == "F1 F2") || (@ww == "F1 T2") z1 = @F1(pz) else z1 = mUT1.Iterate(pz) endif pz = m_Combine.go(z1, @how, z2) endif return pz endfunc protected: UserTransform mUT1 UserTransform mUT2 Combine m_Combine default: rating = NotRecommended title = "Combo" heading text = "Combo Transform is the preferred formula." endheading int param v_ComboUserTransform caption = "Version (Combo)" default = 220316 visible = @v_ComboUserTransform < 220316 endparam heading caption = "Combine two functions or transforms" endheading param ww caption = "Which to use" enum = "F1 F2" "F1 T2" "T1 F2" "T1 T2" default = 0 endparam param how caption = "How to combine" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine Transform values." endparam func F1 caption = "Function F1" default = sin() visible = (@ww == 0) || (@ww == 1) endfunc UserTransform param fUT1 caption = "Transform T1" default = JLB_LinearUserTransform visible = (@ww == 2) || (@ww == 3) endparam func F2 caption = "Function F2" default = tanh() visible = (@ww == 0) || (@ww == 2) endfunc UserTransform param fUT2 caption = "Transform T2" default = JLB_BasicUserTransform visible = (@ww == 1) || (@ww == 3) endparam } class JLB_RotateUserTransform(common.ulb:UserTransform) { public: func JLB_RotateUserTransform(Generic pparent) UserTransform.UserTransform(pparent) rotate = cos(@degrees*#pi/180) + flip(sin(@degrees*#pi/180)) endfunc ; func Init(complex pz) ; rotate = cos(@degrees*#pi/180) + flip(sin(@degrees*#pi/180)) ; endfunc complex func Iterate(complex pz) return (rotate*pz) endfunc private: complex rotate default: rating = Recommended title = "Rotate" int param v_RotateUserTransform caption = "Version (Rotate_UserTransform)" default = 220320 visible = @v_RotateUserTransform < 220320 endparam heading caption = "v_new = rotation*v" endheading ; complex param a ; caption = "Rotate: a" ; default = (0,0) ; endparam float param degrees caption = "Rotate: degrees" default = 45 endparam } class JLB_OverUnderUserTransform(common.ulb:UserTransform) { public: func JLB_OverUnderUserTransform(Generic pparent) UserTransform.UserTransform(pparent) mTO = new @uTO(pparent) mTU = new @uTU(pparent) mCalcValue = new CalcValue() mTSmooth = new TSmooth() endfunc complex func Iterate(complex pz) float test = mCalcValue.Go(@mode, pz, pz) if @trans == 0 if test >= @crit return mTO.Iterate(pz) else return mTU.Iterate(pz) endif else float x = (test-@crit)/@trans float frac = mTSmooth.go(x) return frac*mTO.Iterate(pz) + (1-frac)*mTU.Iterate(pz) ; if x >= 32 ; good to 28 decimals even with 30 added precision ; return mTO.Iterate(pz) ; elseif x <= -32 ; return mTU.Iterate(pz) ; else ; float frac = 0.5*(1+tanh(x)) ; return frac*mTO.Iterate(pz) + (1-frac)*mTU.Iterate(pz) ; endif endif endfunc private: CalcValue mCalcValue TSmooth mTSmooth UserTransform mTO UserTransform mTU default: ;rating = Recommended title = "OverUnder" int param v_OverUnderUserTransform caption = "Version (OverUnderUserTransform)" default = 220323 visible = @v_OverUnderUserTransform < 220323 endparam heading caption = "Apply different transforms if a test value is over or under the critical value." endheading float param crit caption = "Critical value" default = 0 endparam param mode caption = "How to calculate the test value." default = 0 enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" endparam UserTransform param uTO caption = "Over Transform" default = JLB_RotateUserTransform endparam UserTransform param uTU caption = "Under Transform" default = JLB_LinearUserTransform endparam float param trans caption = "Transition parameter" hint = "Larger values make a smoother transition. For an abrupt transition, use 0." default = 0.1 min = 0 endparam } ; make a smooth transition avoiding tanh overflow class TSmooth { public: func TSmooth() endfunc ; return 0.5*(1+tanh(x)) while avoiding overflow static float func go(const float x) float xx = 2*x float t ;t = tanh(x) if xx >= 0 t= (1 - exp(-xx))/(1 + exp(-xx)) else t = (exp(xx)-1)/(exp(xx)+1) endif return 0.5 * (1 + t) endfunc } ; tanh(z) avoiding tanh overflow class TanhZ { public: func TanhZ() endfunc static complex func go(complex z) z = z*2 if real(z) >= 0 return (1 - exp(-z))/(1 + exp(-z)) else return (exp(z)-1)/(exp(z)+1) endif endfunc } class JLB_MaskColoring(common.ulb:DirectColoring) { ; Generate a mask with opacity 1 at the center, going to 0 far away. public: func JLB_MaskColoring(Generic pparent) DirectColoring(pparent) c = 1 s = 0 if (@shape_type > 0) ;|| (@p != 2.0) ang = @angle * #pi / 180.0 c = cos(ang) s = sin(ang) endif if @shape_type == 0 rx = ry = @r else rx = @xsemi ry = @ysemi endif endfunc ; func Init(complex pz, complex ppixel) ; DirectColoring.Init(pz, ppixel) ; endfunc ; func Iterate(complex pz) ; endfunc color func Result(complex pz) if rx == 0 || ry == 0 return rgba(0.5,0.5,1.0, 0.0) ; no mask endif float d ;if (@shape_type == "Circle" || @shape_type == "Ellipse") float x = real(pz-@center) float y = imag(pz-@center) float xr = abs(x*c + y*s) / rx float yr = abs(x*s - y*c) / ry d = (xr^2 + yr^2) ; d = (xr^@p + yr^@p) ;endif if @type == 0 d = 1 - d / @scale if d < 0, d = 0, endif else d = exp(-d / @scale) endif if @inverse d = 1.0 - d endif return rgba(0,0,0, d) endfunc private: float ang, float c, float s float rx, float ry default: title = "Mask Coloring" rating = NotRecommended heading caption = "'Mask from shape' is preferred." endheading heading text = "Generate a mask with opacity 1 at the center, decaying to 0 far away.\ The formula and the gradient are ignored." visible = !@inverse endheading heading text = "Generate a mask with opacity 0 at the center, growing to 1 far away.\ The formula and the gradient are ignored." visible = @inverse endheading bool param inverse caption = "Inverse?" default = false endparam param shape_type caption = "Shape" enum = "Circle" "Ellipse" default = 0 endparam complex param center caption = "Center" default = (0,0) endparam ; float param p ; caption = "Power" ; default = 2.0 ; min = 0.1 ; hint = "Use 2 for standard circles or ellipses" ; ;visible = (@shape_type < 2) ; endparam float param r caption = "Radius" default = 1 min = 0.0 visible = @shape_type == 0 endparam float param xsemi caption = "X semi-axis" default = 1 min = 0.0 visible = @shape_type == 1 endparam float param ysemi caption = "Y semi-axis" default = 1 min = 0.0 visible = @shape_type == 1 endparam float param angle caption = "Rotation angle" default = 0.0 visible = (@shape_type > 0) ;|| (@p != 2.0) endparam param type caption = "Type" enum = "1" "2" default = 0 endparam float param scale caption = "Scale" default = 1 endparam } class JLB_ModularSFormula(SFormula) { ; The Modular formula as an SFormula. ; 220605 public: import "common.ulb" func JLB_ModularSFormula(Generic pparent) SFormula(pparent) if @v == 2 m_Transform = new @zT(this) endif if @addT > 0 finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif endfunc bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz if @v == 1 pz = @F(@a*pz) elseif @v == 2 pz = m_Transform.Iterate(@a*pz) endif complex pzn = pz int n = 1 complex tmp = pz * (1 - pzn)^@p while n < @nbig pzn = pz * pzn tmp = tmp * (1 - pzn)^@p n = n + 1 endwhile znew = tmp + ppc ;if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif ;endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UserTransform m_Transform UtilityTransform finalTransform default: title = "Modular" rating = NotRecommended int param v_ModularSFormula caption = "Version (Modular_SFormula)" default = 220604 visible = @v_ModularSFormula < 220604 endparam ; bool param p_std ; caption = "Standard?" ; default = true ; endparam ; heading ; caption = "Set v = F(z)" ; endheading heading caption = "z_new = v*((1-v)^p)*((1-v^2)^p)*...*((1-v^n)^p) + c" endheading param v caption = "Use for v" enum = "z" "F(a*z)" "T(a*z)" default = 0 endparam func F caption = "F (Built-in function)" default = sin() ;hint = "Function" visible = @v == 1 endfunc UserTransform param zT caption = "T (Transform)" default = JLB_MoebiusUserTransform visible = @v == 2 endparam complex param a caption = "a" default = 1 visible = @v > 0 endparam float param p caption = "p" default = 2 min = 1 endparam int param nbig caption = "n" min = 1 endparam bool param p_Mtype caption = "M-type?" default = false endparam complex param p_seed caption = "Seed for J-type" default = (0.5,0.5) visible = !@p_Mtype endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } class JLB_DXYZ(Distance){ ; A distance class similar to ComplexToFloat2 ; Unlike ComplexToFloat2, there's an option to scale some distances ; so that the full possible range is (0,1). public: func JLB_DXYZ(Generic pparent) Distance(pparent) endfunc float func Iterate(complex zz) float ans float x = real(zz), float y = imag(zz) float ax = abs(x), float ay = abs(y) float a = cabs(zz), float b = sqrt(2.0) if @type == "Mod" ans = a elseif @type == "Real" ans = x ; range = (-a,+a) if @s, ans = (ans+a)/(a+a), endif elseif @type == "Imag" ans = y ; range = (-a,+a) if @s, ans = (ans+a)/(a+a), endif elseif @type == "Real+Imag" ans = x+y ; range = (-a,+a*b) if @s, ans = (ans+a)/(a*b+a), endif elseif @type == "Real-Imag" ans = x-y ; range = (-a*b,+a*b) if @s, ans = (ans+a*b)/(2*a*b), endif elseif @type == "Real*Imag" ans = x*y ; range = (-0.5,+0.5)a^2 if @s, ans = (ans+0.5*a^2)/(a^2), endif elseif @type == "Real/Imag" ans = x/y elseif @type == "Imag/Real" ans = y/x elseif @type == "Real^Imag" ans = x^y elseif @type == "Imag^Real" ans = y^x elseif @type == "|Real|+|Imag|" ans = ax+ay ;range = (a,a*b) if @s, ans = (ans-a)/(a*b-a), endif elseif @type == "|Real|-|Imag|" ans = ax-ay ;range = (-a,a) if @s, ans = (ans+a)/(a+a), endif elseif @type == "Max(|Real|,|Imag|)" ans = ax ; range = (a,a/b) if ay > ax, ans = ay, endif if !@s, ans = (ans-a)/(a-a/b), endif elseif @type == "Max(Real,Imag)" ans = x ; range = (0,a) if y > x, ans = y, endif if @s, ans = (ans)/(a), endif elseif @type == "Min(|Real|,|Imag|)" ans = ax ; range = (0,a/b) if ay < ax, ans = ay, endif if @s, ans = (ans)/(a/b), endif elseif @type == "Min(Real,Imag)" ans = x ; range = (-a,a/b) if y < x, ans = y, endif if @s, ans = (ans+a)/(a/b+a), endif else;if @type == "Angle" ans = atan2(zz)/ (2 * #pi) if ans < 0 ans = ans + 1 endif if @version >= 220809 && !@s ans = a*ans endif endif if @invert && ans != 0 ans = 1/ans endif if @tlog && ans != 0 ans = log(ans) endif ; if @oneminus ; experiment 220916 ; ans = 1 - ans ; endif if m_abs_value ans = abs(ans) endif return ans endfunc private: default: title = "XYZ distance" rating = NotRecommended heading caption = "Use 'Simple Distance' instead." endheading int param version caption = "Version" default = 220809 visible = @version < 220809 endparam heading text = "(Curent is 220809.}" visible = @version < 220809 ;backward compatible to 220703 endheading param type caption = "Use for distance" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" default = 0 endparam bool param s caption = "Z scale?" default = false visible = @type != 0 && (@type < 6 || @type > 9) && \ !(@version < 220809 && @type == 16) hint = "Scale answer to be between 0 and 1." endparam bool param invert caption = "Invert?" default = false visible = @version >= 220809 endparam bool param tlog caption = "Take log?" default = false visible = @version >= 220809 endparam ; bool param oneminus ; caption = "1 - distance?" ; default = false ; visible = @version >= 220809 ; endparam } class JLB_TentSFormula(SFormula) { ; The Tent formula as an SFormula, generalized. ; Original Tent formula in lkm.ufm and reb.ufm public: import "common.ulb" func JLB_TentSFormula(Generic pparent) SFormula(pparent) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif m_dist = new @dist(this) if @type == 2 && !@p_std m_T = new @zT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif if @p_std tscale = 0, p = 1 else tscale = @trans, p = @power endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz if !@p_std if @type == 1 pz = @f(pz) elseif@type == 2 pz = m_T.Iterate(pz) endif endif complex znew float test = m_dist.Iterate(pz) complex z1 = ppc * @scale * pz^p complex z2 = ppc * @scale * (@top - pz)^p if tscale == 0 if test <= @crit znew = z1 else znew = z2 endif else float r = (test-@crit)/tscale float frac = TSmooth.go(r) znew = frac*z1 + (1-frac)*z2 endif if !@p_std if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc UtilityTransform finalTransform Distance m_dist UserTransform m_T float tscale float p default: rating = NotRecommended title = "Tent" int param v_TentSFormula caption = "Version" default = 220727 visible = @v_TentSFormula < 220727 ; changes 220729 backward compatible to 220727 endparam heading text = "(Current is 220727.)" visible = @v_TentSFormula < 220727 endheading bool param p_std caption = "Standard?" default = true endparam bool param p_Mtype caption = "M-type?" default = true visible = @v_TentSFormula > 100 endparam complex param p_seed caption = "Seed for J-type" default = (0.5, -0.5) visible = @v_TentSFormula > 100 && !@p_Mtype endparam float param crit caption = "Critical distance" default = 1 endparam heading text = "Use for critical distance:" endheading Distance param dist default = JLB_DXYZ selectable = false endparam heading caption = "" endheading param type caption = "Tent function type" enum = "z" "F(z)" "T(z)" default = 0 visible = !@p_std endparam func f caption = "F (built-in function)" default = sin() hint = "Function" visible = @type == 1 && !@p_std endfunc UserTransform param zT caption = "T (Transform)" default = JLB_MoebiusUserTransform visible = @type == 2 && !@p_std endparam complex param scale caption = "Tent scale" default = 1 endparam float param top Caption = "Tent value" default = 1 endparam float param power Caption = "Tent power" default = 1 visible = !@p_std endparam float param trans caption = "Transition parameter" hint = "Larger values make a smoother transition. For an abrupt transition, use 0." default = 0.1 min = 0 visible = !@p_std endparam heading caption = "Tweak after each iteration" endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam heading caption = "" endheading } class JLB_TwoDistances(common.ulb:UserTransform) { ; Make a UserTransform out of two Distance formulas public: ;import "common.ulb" func JLB_TwoDistances(Generic pparent) UserTransform.UserTransform(pparent) mx = new @fx(this) my = new @fy(this) if @version < 221224 xyswitch = @switch else xyswitch = @switch2 == 1 || @switch2 == 3 endif endfunc func Init(complex pz) UserTransform.Init(pz) mx.Init(pz) my.Init(pz) mx.SetParams(0, false) my.SetParams(0, false) endfunc complex func Iterate(complex pz) float x = mx.Iterate(pz) float y = my.Iterate(pz) if xyswitch pz = y + flip(x) else pz = x + flip(y) endif if @version >= 221224 && @switch2 > 1 xyswitch = !xyswitch endif return pz endfunc protected: Distance mx Distance my bool xyswitch default: rating = Recommended title = "Two Distances" int param version caption = "Version" default = 221224 visible = @version < 221224 endparam heading text = "(Current is 221224.)" visible = @version < 221224 endheading ; heading ; caption = "Make a transform from two Distances." ; endheading bool param switch caption = "Switch X and Y distances?" default = false visible = @version < 221224 endparam param switch2 caption = "X/Y switch?" enum = "No" "Yes" "No/Yes/No . . ." "Yes/No/Yes . . ." default = 0 visible = @version >= 221224 endparam Distance param fx caption = "X Distance" default = JLB_DSimple2 endparam Distance param fy caption = "Y Distance" default = JLB_DCircle endparam } class JLB_FTransform(common.ulb:UserTransform) { ; Inspired by Bona Spallona in OM.ulb ; A Transform replacement of UF's built-in functions ; First trig and hyperbolic, completing UF's built-in set, ; then then the rest of UF's standard set, ; then a few extras from OM.ulb ; ; Many interesting complications are possible using Combo Transform. public: complex func Iterate(complex pz) if @F == "sin" pz = sin(pz) elseif @F == "sinh" pz = sinh(pz) elseif @F == "asin" pz = asin(pz) elseif @F == "asinh" pz = asinh(pz) elseif @F == "cos" pz = cos(pz) elseif @F == "cosh" pz = cosh(pz) elseif @F == "acos" pz = acos(pz) elseif @F == "acosh" pz = acosh(pz) elseif @F == "tan" pz = tan(pz) elseif @F == "tanh" pz = tanh(pz) elseif @F == "atan" pz = atan(pz) elseif @F == "atanh" pz = atanh(pz) elseif @F == "cotan" pz = cotan(pz) elseif @F == "cotanh" pz = cotanh(pz) elseif @F == "acotan" pz = atan(1/pz) elseif @F == "acotanh" pz = atanh(1/pz) elseif @F == "sec" pz = 1/cos(pz) elseif @F == "sech" pz = 1/cosh(pz) elseif @F == "asec" pz = acos(1/pz) elseif @F == "asech" pz = acosh(1/pz) elseif @F == "cosec" pz = 1/sin(pz) elseif @F == "cosech" pz = 1/sinh(pz) elseif @F == "acosec" pz = asin(1/pz) elseif @F == "acosech" pz = asinh(1/pz) elseif @F == "sqr" pz = sqr(pz) elseif @F == "sqrt" pz = sqrt(pz) elseif @F == "log" pz = log(pz) elseif @F == "exp" pz = exp(pz) elseif @F == "abs" pz = abs(pz) elseif @F == "cabs" pz = cabs(pz) elseif @F == "conj" pz = conj(pz) elseif @F == "flip" pz = flip(pz) elseif @F == "ident" pz = ident(pz) elseif @F == "zero" pz = 0 elseif @F == "recip" pz = recip(pz) elseif @F == "ceil" pz = ceil(pz) elseif @F == "floor" pz = floor(pz) elseif @F == "trunc" pz = trunc(pz) elseif @F == "trunc*" float x = real(pz) if x >= 0, x = ceil(x), else, x = floor(x), endif float y = imag(pz) if y >= 0, y = ceil(y), else, y = floor(y), endif pz = x + flip(y) elseif @F == "round" pz = round(pz) elseif @F == "power" pz = pz^@p elseif @F == "gd" ;Gudermannian (Wikipedia) pz = asin(tanh(pz)) elseif @F == "agd" ; inverse Gudermannian pz = atanh(sin(pz)) elseif @F == "logit" pz = log(pz/(1-pz)) elseif @F == "expit" pz = 1/(1+exp(-pz)) elseif @F == "gauss" pz = exp(-sqr(pz)) elseif @F == "softplus" pz = log(1+exp(pz)) elseif @F == "asoftplus" pz = log(exp(pz)-1) elseif @F == "softminus" pz = pz-log(1+exp(pz)) elseif @F == "asoftminus" pz = pz-log(1-exp(pz)) elseif @F == "sinc" if pz == 0 pz = 1 else pz = sin(pz)/pz endif endif return pz endfunc default: rating = NotRecommended title = "Function" heading caption = "'Function Transform' is better" endheading int param version caption = "Version" default = 220730 visible = @version < 220730 endparam heading text = "(Current is 220730.)" visible = @version < 220730 endheading param F caption="Function" enum = "sin" "sinh" "asin" "asinh" "cos" "cosh" "acos" "acosh" \ "tan" "tanh" "atan" "atanh" "cotan" "cotanh" "acotan" "acotanh" \ "sec" "sech" "asec" "asech" "cosec" "cosech" "acosec" "acosech" \ "sqr" "sqrt" "log" "exp" "abs" "cabs" "conj"\ "flip" "ident" "zero" "recip" "ceil" "floor" "trunc" "trunc*" "round" \ "power" "gd" "agd" "logit" "expit" "gauss" \ "softplus" "softminus" "asoftplus" "asoftminus" "sinc" default=0 endparam complex param p caption = "Power" default = 2 visible = @F == "power" endparam } class JLB_ComboTransform (common.ulb:UserTransform) { public: func JLB_ComboTransform(Generic pparent) UserTransform(pparent) m_T1 = new @T1(this) if @v >= 3 m_T2 = new @T2(this) endif endfunc complex func Iterate(complex pz) complex z1 if @v == "T(a*z)" return m_T1.Iterate(@a*pz) elseif @v == "T(a*z) op pixel" z1 = Combine.go(@a*pz, @op, #pixel) return m_T1.Iterate(z1) elseif @v == "T(a*z op pixel)" z1 = Combine.go(@a*pz, @op, #pixel) return m_T1.Iterate(z1) else ; "T1(a*z) op T2(b*z)" complex z2 = m_T2.Iterate(@b*pz) if @op1 == "( )" return m_T1.Iterate(@a*z2) else z1 = m_T1.Iterate(@a*pz) return Combine.go(z1, @op1, z2) endif endif endfunc private: UserTransform m_T1 UserTransform m_T2 default: rating = NotRecommended title = "Combo Transform" int param version caption = "Version" default = 220731 visible = @version < 220731 endparam heading text = "(Current is 220731.)" visible = @version < 220731 endheading param v caption = "Type" enum = "T(a*z)" "T(a*z) op pixel" "T(a*z op pixel)" \ "T1(a*z) op T2(b*z)" ;"T1(a*z) op1 (T2(b*z) op2 pixel))" \ ;"T1(a*z) op1 (T2(b*z op2 pixel))" default = 0 endparam complex param a caption = "a" default = (1,0) endparam complex param b caption = "b" default = (0, 1) visible = @v >= 3 endparam param op caption = "op" enum = "+" "-" "*" "/" "^" default = 0 hint = "How to combine." visible = @v==1 || @v ==2 endparam param op1 caption = "op1" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine." visible = @v>=3 endparam ; param op2 ; caption = "op2" ; enum = "+" "-" "*" "/" "^" ; default = 0 ; hint = "How to combine." ; visible = @v>=4 ; endparam UserTransform param T1 default = JLB_FTransform endparam UserTransform param T2 default = JLB_FTransform visible = @v >= 3 endparam } class JLB_DCurve(Distance) { ; Curve definitions from ; https://mathcurve.com/courbes2d.gb/courbes2d.shtml ; www.2dcurves/com ; mathworld.wolfram.com/ ; with inspiration and some code from Otto Magus, om.ulb ; ; sources vary on what some of the curves are. ; I've changed a^2 many places to just a and b^2 to b, ; added parameters in a sensible way to many curves, ; and omitted any curves with three or more parameters public: func JLB_DCurve(Generic pparent) Distance(pparent) a = @aa ; to save typing b = @bb endfunc float func Iterate(complex zz) float x=real(zz) float y=imag(zz) if @exch float t=x, x=y, y=t endif float c1 = cabs(zz), float c2 = c1*c1, float c3 = c2*c1, float c4 = c2*c2 float x2 = x^2, float y2 = y^2, float d2 = x2-y2 float d = 0 if @V=="Alain" d = d2^2 - a*x2 + b*y2 if @s, d = d/c4, endif elseif @V=="Ampersand" d = (y2-x2)*(x-a)*(2*x-3*a) - b*(c2-2*x)^2 if @s, d = d/c4, endif elseif @V=="Anguinea" d = y*(x2+a^2) - a*b*x if @s, d = d/c3, endif elseif @V=="Arachnea" d = (c2-a*x)^2 - a^2*c2 if @s, d = d/c4, endif elseif @V=="Arcs of Samothrace" d = x2*(a*x2-y2)^2 - y2*c2 if @s, d = d/c4/c2, endif elseif @V=="Astroid" d = x^@p + y^@p - a^@p if @s, d = d/c1^@p, endif elseif @v=="Atripthaloid" d = x^4*c2 - (a*x2-b)^2 if @s, d = d/c4/c2, endif elseif @V=="Beetle'" d = c2*(c2-a*x-a*y) - b*x2*y2 if @s, d = d/c4, endif elseif @V=="Besace" d = (x2-b*y)^2 - a*d2 if @s, d = d/c4, endif elseif @V=="Bicorn" d = y2*(a-x2) - (x2+2*a*y-a^2)^2 if @s, d = d/c4, endif elseif @V=="Bicuspid" d = (x2-a^2)*(x-a)^2 + (y2-a)^2 if @s, d = d/c4, endif elseif @V=="Bifoliate" d = x2*x2 + y2*y2 - a*x*y2 if @s, d = d/c4, endif elseif @V=="Bifolium" d = c2^2 - (a*x+b*y)*x2 if @s, d = d/c4, endif elseif @V=="Bow" d = x2*x2 - a*y*d2 if @s, d = d/c4, endif elseif @V=="Bow Tie" d = x2*x2*c2 - a*d2 if @s, d = d/c2/c4, endif elseif @V=="Bullet-Nose" d = a^2*y2 - b^2*x*2 - x2*y2 if @s, d = d/c4, endif elseif @V=="Butterfly" d = x2^3 + y2^3 - a*x2 if @s, d = d/c2/c4, endif elseif @V=="Cardioid" d = (c2-a*x)^2 - a^2*c2 if @s, d = d/c4, endif elseif @V=="Cassinian Ovals" d = c2^2 - a*d2 + b^4 if @s, d = d/c4, endif elseif @V=="Cayley's Sextic" d = 4*(c2-a*x)^3 - 27*a^2*c2^2 if @s, d = d/c4/c2, endif elseif @V=="Cissoid of Diocles" d = x*c2 - a*y2 if @s, d = d/c3, endif elseif @V=="Conchoid of Nicomedes" d = (x-a)^2*c2 - b^2*x2 if @s, d = d/c4, endif elseif @V=="Cornoid" d = c2^3 + a*(3*x^4 - 6*x2*y2 - 5*y^4) + 8*a^2*y2 - 4*a^3 if @s, d = d/c2/c4, endif elseif @V=="Cross" d = x2*y2 - a*x2 - b*y2 if @s, d = d/c4, endif elseif @V=="Curve of Cramer" d = x*c2 + (a+b)*x2 - (a-b)*y2 elseif @V=="Cubical Parabola" d = a^2*y - x^3 + b*x if @s, d = d/c3, endif elseif @V=="Cubic of de Sluze" d = a*(x-a)*c2 - b*x2 if @s, d = d/c3, endif elseif @V=="Deltoid" d = c2^2 + 8*a*x*(x2-3*y2) + 18*a^2*c2 - 27*a^4 if @s, d = d/c4, endif elseif @V=="Dipole" d = c2^3 - a*x2 if @s, d = d/c2/c3, endif elseif @V=="Double-Heart" d = x2*c2 - (a+b)*x2*y + (a-b)^2*y/4 if @s, d = d/c4, endif elseif @v=="Dumbbell" d = b*y2 - x^4*(a-x2) if @s, d = d/c2/c4, endif elseif @V=="Egg of Granville" d = x2*y2 - (x-a)*(b-x) if @s, d = d/c4, endif elseif @V=="Egg of Kepler" d = c2^2 - a*x^3 if @s, d = d/c4, endif elseif @v=="Eight" d = x^4 - a*d2 if @s, d = d/c4, endif elseif @V=="Ellipse" d = b*x2 + a*y2 - a/b if @s, d = d/c2, endif elseif @V=="Euler's Cubic" d = y*(y2-a) - b*x*(x2-a) if @s, d = d/c3, endif elseif @V=="Folium of Descartes" d = x^3 + y^3 - 3*a*x*y if @s, d = d/c3, endif elseif @V=="Folium of Durer" d = c2*(2*c2-a)^2 - a^2*x2 if @s, d = d/c2/c4, endif elseif @V=="Folium of Kepler" d = c2*(x*(x-a)+y2) - b*x*y2 if @s, d = d/c4, endif elseif @V=="Function" d = y - a*real(@F(b*x)) if @s, d = d/c1, endif elseif @v=="Heat Capacity" d = x2*(x-y) + a if @s, d = d/c3, endif elseif @V=="Hippopede" d = c2^2 - a*x2 - b*y2 if @s, d = d/c4, endif elseif @V=="Humbert's Cubic" d = x^3 - 3*x*y2 - a if @s, d = d/c3, endif elseif @V=="Hyperbola" d = x2 - a*y2 if @s, d = d/c2, endif elseif @V=="Kampyle of Eudoxus" d = x^4 - a*c2 if @s, d = d/c4, endif elseif @V=="Kappa" d = x2*c2 - a*y2 if @s, d = d/c4, endif elseif @V=="Kiepert" d = c2^3 - a*x*(x2-3*y2) if @s, d = d/c2/c4, endif elseif @V=="Kiss" d = a^2*y2 - (a-x2)^3 if @s, d = d/c2/c4, endif elseif @V=="Knot" d = (x2-a)^2 - y2*(3*a+2*y) if @s, d = d/c4, endif elseif @v=="Kulp Quartic" d = x2*y2 - a*(a-y2) if @s, d = d/c4, endif elseif @V=="Lemniscate of Bernoulli" d = c2^2 - a*d2 if @s, d = d/c4, endif elseif @V=="Limacon of Pascal" d = (c2-a*x)^2 - b*c2 if @s, d = d/c4, endif elseif @V=="Maltese Cross" d = x*y*d2 - a*c2 if @s, d = d/c2/c4, endif elseif @V=="Nephroid" d = (c2-a)^3 - b*y2 if @s, d = d/c2/c4, endif elseif @V=="Nephroid of Freeth" d = c2*(x*2+y2-a)^2 - 4*a*(c2-a*x)^2 if @s, d = d/c2/c4, endif elseif @V=="Ophiuride" d = x*c2 - b*x*y - a*y2 if @s, d = d/c3, endif elseif @V=="Parabola" d = y - a*x2 if @s, d = d/c2, endif elseif @V=="Pear" d = x*x2*(a-x) - b*y2 if @s, d = d/c4, endif elseif @V=="Piriform Quartic" d = b^2*y2 + (x-a)*x^3 if @s, d = d/c4, endif elseif @V=="Quadrifolium" d = c2^3 - a*x2*y2 if @s, d = d/c2/c4, endif elseif @v=="Right Strophoid" d = x*c2 - a*d2 if @s, d = d/c3, endif elseif @V=="Semicubical Parabola" d = y2 - a*x*x2 if @s, d = d/c3, endif elseif @V=="Serpentine" d = y*(x+b*y)^2 - a*x if @s, d = d/c3, endif elseif @V=="Sextic" d = c2*(c2-a*y)^2 - x2*d2^2 if @s, d = d/c2/c4, endif elseif @V=="Tighrope" d = y2*(a^2*b-x2) - x2*(a-x)^2 if @s, d = d/c4, endif elseif @V=="Torpedo" d = c2^2 - a*x*d2 if @s, d = d/c4, endif elseif @V=="Trifolium" d = c2^2 - a*x*(x2-b*y2) if @s, d = d/c4, endif elseif @V=="Trisectrix of Catalan" d = b*y2 + x2*(x-a) if @s, d = d/c3, endif elseif @V=="Trisectrix of Ceva" d = c2^3 - a*(b*x2-y2)^2 if @s, d = d/c2/c4, endif elseif @V=="Trisectrix of Delange" d = (c2-a)^2 - x2*c2 if @s, d = d/c4, endif elseif @V=="Trisectrix of Longchamps" d = x*(x2-3*y2) - a*c2 if @s, d = d/c3, endif elseif @V=="Trisectrix of Maclaurin" d = x*c2 - a*(3*x2-y2) if @s, d = d/c3, endif elseif @V=="Trott" d = 144*(x^4+y^4) - 225*c2 + 350*x2*y2 + 81*a if @s, d = d/c4, endif elseif @V=="Visiera" d = x*c2 - a*(x2+2*y2) if @s, d = d/c3, endif elseif @V=="Viviani's" d = y^4 + a*d2 ;mathworld version if @s, d = d/c4, endif elseif @V=="Wavy Cross" ; Swastika d = x2*x2-y2*y2 + a*x*y if @s, d = d/c4, endif elseif @V=="Windmill" d = 4*x2*y2*c2 - a*(x2-b*y2)^2 if @s, d = d/c2/c4, endif elseif @V=="Witch of Agnesi" d = x2*y + a^2*(y-a) if @s, d = d/c3, endif endif if m_abs_value d = abs(d) endif return d endfunc private: float a, float b default: rating = NotRecommended title = "Curve" int param version caption = "Version" default = 220804 visible = @version < 220804 endparam heading text = "(Current is 220804.)" visible = @version < 220804 endheading param V caption="Curve" enum="Alain" "Ampersand" "Anguinea" "Arachnea" "Arcs of Samothrace" \ "Astroid" "Atripthaloid" "Beetle'" "Besace" "Bicorn" "Bicuspid" \ "Bifoliate" "Bifolium" "Bow" "Bow Tie" "Bullet-Nose" "Butterfly"\ "Cardioid" "Cassinian Ovals" "Cayley's Sextic" "Cissoid of Diocles" \ "Conchoid of Nicomedes" "Cornoid" "Cross" "Cubical Parabola"\ "Curve of Cramer" "Cubic of de Sluze" "Deltoid" "Dipole" \ "Double-Heart" "Dumbbell""Egg of Granville" "Egg of Kepler" "Eight"\ "Ellipse" "Euler's Cubic" "Folium of Descartes" \ "Folium of Durer" "Folium of Kepler""Function" "Heat Capacity"\ "Hippopede" "Humbert's Cubic" "Hyperbola" "Kampyle of Eudoxus""Kappa" "Kiepert" \ "Kiss" "Knot" "Kulp Quartic" "Lemniscate of Bernoulli"\ "Limacon of Pascal" "Maltese Cross""Nephroid" "Nephroid of Freeth"\ "Ophiuride" "Parabola" "Pear""Piriform Quartic" "Quadrifolium" \ "Right Strophoid""Semicubical Parabola" "Serpentine" "Sextic" \ "Tighrope" "Torpedo" "Trifolium" "Trisectrix of Catalan" \ "Trisectrix of Ceva" "Trisectrix of Delange" "Trisectrix of Longchamps" \ "Trisectrix of Maclaurin""Trott" "Visiera" "Viviani's" "Wavy Cross" \ "Windmill" "Witch of Agnesi" default=0 endparam func F caption = "Function" default = sin() visible = @V=="Function" endfunc bool param exch caption = "Switch x and y?" default = false visible = @V!="Astroid" && @V!="Folium of Descartes" \ && @V!="Quadrifolium" && @V!="Trott" endparam bool param s caption = "Z scale?" default = true ; 221220, was false endparam float param aa caption = "a" default=1 endparam float param p caption = "Power" default = 0.5 visible = @V=="Astroid" endparam float param bb caption = "b" default=0.5 visible=@V=="Alain" || @V=="Ampersand" || @V=="Atripthaloid" \ || @V=="Beetle'" || @V=="Besace" || @V=="Bifolium" || @V=="Bullet-Nose" \ || @V=="Cassinian Ovals" || @V=="Cross" ||@V=="Cubical Parabola" \ || @V=="Cubic of de Sluze" || @V=="Conchoid of Nicomedes" \ || @V=="Curve of Cramer" || @V=="Double-Heart" || @V=="Dumbbell" \ || @V=="Ellipse" || @V=="Egg of Granville" || @V=="Euler's Cubic" \ || @V=="Folium of Kepler" ||@V=="Function" || @V=="Hippopede" \ || @V=="Limacon of Pascal" || @V=="Nephroid" || @V=="Ophiuride" \ || @V=="Pear" || @V== "Piriform Quartic" || @V=="Serpentine" \ || @V=="Tighrope" || @V=="Trifolium" || @V=="Trisectrix of Catalan" \ || @V=="Trisectrix of Ceva" || @V=="Windmill" endparam } class Standard_Decomposition(common.ulb:GradientColoring) { ; copied from Standard.ulb public: float func ResultIndex(complex pz) float d = atan2(pz) ; get angle of z IF (d < 0) ; it's negative d = d + #pi * 2 ; make it positive ENDIF return d / (#pi * 2) endfunc default: title = "Decomposition" rating = NotRecommended } class GammaBlend{ public: func GammaBlend( ) gamma = 2.2 ; default value endfunc func SetGamma(float gam) gamma = gam endfunc func Zero() rr = 0, gg = 0, bb = 0, aa = 0, ff = 0 ;gamma = 2 endfunc func AddOne(color c, float f) rr = rr + f * red(c)^gamma gg = gg + f * green(c)^gamma bb = bb + f * blue(c)^gamma aa = aa + f * alpha(c) ff = ff + f endfunc color func Final( ) rr = (rr / ff)^(1/gamma) gg = (gg / ff)^(1/gamma) bb = (bb / ff)^(1/gamma) aa = (aa / ff) return rgba(rr, gg, bb, aa) endfunc color func Blend2(color c1, float f1, color c2, float f2) float rr = ((f1* red(c1)^gamma + f2* red(c2)^gamma)/(f1+f2))^(1/gamma) float gg = ((f1*green(c1)^gamma + f2*green(c2)^gamma)/(f1+f2))^(1/gamma) float bb = ((f1* blue(c1)^gamma + f2* blue(c2)^gamma)/(f1+f2))^(1/gamma) float aa = (f1*alpha(c1) + f2*alpha(c2) ) /(f1+f2) return rgba(rr, gg, bb, aa) endfunc protected: float rr, float gg, float bb, float aa, float ff float gamma } class JLB_FractaliaSFormula(SFormula) { ; based on the Fractalia formulas in mt.ufm public: import "common.ulb" ; for UtilityTransform func JLB_FractaliaSFormula(Generic pparent) SFormula.SFormula(pparent) r1 = new JLB_Random(0) r1.Init(@seed) r2 = new JLB_Random(0) r2.Init(@seed2) a=@aa, ax=@aax, axx=@aaxx, axy=@aaxy, ay=@aay, ayy=@aayy b=@bb, bx=@bbx, bxx=@bbxx, bxy=@bbxy, by=@bby, byy=@bbyy if @randomize > 0 float c = 1, if @randomize == "Replace", c = 0, endif a = c * a + @scale * r1.RandomFloat2(0), b = c * b + @scale * r1.RandomFloat2(0) ax = c * ax + @scale * r1.RandomFloat2(0), bx = c * bx + @scale * r1.RandomFloat2(0) axx = c * axx + @scale * r1.RandomFloat2(0), bxx = c * bxx + @scale * r1.RandomFloat2(0) axy = c * axy + @scale * r1.RandomFloat2(0), bxy = c * bxy + @scale * r1.RandomFloat2(0) ay = c * ay + @scale * r1.RandomFloat2(0), by = c * by + @scale * r1.RandomFloat2(0) ayy = c * ayy + @scale * r1.RandomFloat2(0), byy = c * byy + @scale * r1.RandomFloat2(0) if @randomize2 > 0 c = 1, if @randomize2 == "Replace", c = 0, endif a = c * a + @scale2 * r2.RandomFloat2(0), b = c * b + @scale2 * r2.RandomFloat2(0) ax = c * ax + @scale2 * r2.RandomFloat2(0), bx = c * bx + @scale2 * r2.RandomFloat2(0) axx = c * axx + @scale2 * r2.RandomFloat2(0), bxx = c * bxx + @scale2 * r2.RandomFloat2(0) axy = c * axy + @scale2 * r2.RandomFloat2(0), bxy = c * bxy + @scale2 * r2.RandomFloat2(0) ay = c * ay + @scale2 * r2.RandomFloat2(0), by = c * by + @scale2 * r2.RandomFloat2(0) ayy = c * ayy + @scale2 * r2.RandomFloat2(0), byy = c * byy + @scale2 * r2.RandomFloat2(0) endif endif if @addT > 0 finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @return the new pz bool func Iterate(State S) bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif float x = real(S.pz) float y = imag(S.pz) float xx = a + ax*x + axx*x*x + axy*x*y + ay*y + ayy*y*y float yy = b + bx*x + bxx*x*x + bxy*x*y + by*y + byy*y*y complex znew = xx + flip(yy) + ppc if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc float a, float ax, float axx, float axy, float ay, float ayy float b, float bx, float bxx, float bxy, float by, float byy JLB_Random r1 JLB_Random r2 UtilityTransform finalTransform default: rating = NotRecommended title = "Fractalia" int param version caption = "Version" default = 221010 visible = @version < 221010 endparam bool param p_Mtype caption = "M-type?" default = true endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = !@p_Mtype endparam bool param hide caption = "Hide parameters?" default = true endparam heading caption = "Method" visible = !@hide endheading heading text = "xnew = a + ax*x + axx*x^2 + axy*x*y + ay*y + ayy*y^2" visible = !@hide endheading heading text = "ynew = b + bx*x + bxx*x^2 + bxy*x*y + by*y + byy*y^2" visible = !@hide endheading heading text = "znew = xnew + flip(ynew)" visible = !@hide endheading ; heading ; caption = "Parameters" ; endheading float param aa caption = "a" default = 0 visible = !@hide endparam float param aax caption = "ax" default = 1 visible = !@hide endparam float param aaxx caption = "axx" default = 0.5 visible = !@hide endparam float param aaxy caption = "axy" default = 0.4 visible = !@hide endparam float param aay caption = "ay" default = -0.7 visible = !@hide endparam float param aayy caption = "ayy" default = 0.9 visible = !@hide endparam float param bb caption = "b" default = 0 visible = !@hide endparam float param bbx caption = "bx" default = -0.2 visible = !@hide endparam float param bbxx caption = "bxx" default = 0.8 visible = !@hide endparam float param bbxy caption = "bxy" default = 0.9 visible = !@hide endparam float param bby caption = "by" default = -0.7 visible = !@hide endparam float param bbyy caption = "byy" default = -0.2 visible = !@hide endparam heading caption = "Randomization" endheading param randomize caption = "Randomize?" enum = "No" "Replace" "Add to" default = 0 endparam int param seed caption ="Seed" hint = "Seed for random numbers" default = 12345679 visible = @randomize > 0 endparam float param scale caption = "Randomness size" default = 1 min = 0 visible = @randomize > 0 endparam param randomize2 caption = "More?" enum = "No" "Replace" "Add to" default = 0 visible = @randomize > 0 endparam int param seed2 caption ="Second seed" hint = "Seed for random numbers" default = 12345679 visible = @randomize2 > 0 endparam float param scale2 caption = "Randomness size" default = 0.1 min = 0 visible = @randomize2 > 0 endparam heading caption = "Tweak after each iteration" endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 selectable = false endparam } class JLB_BubbleTransform(common.ulb:UserTransform) { ; public: func JLB_BubbleTransform(Generic pparent) UserTransform.UserTransform(pparent) if @use_ctr ctr = #center else ctr = @center endif if @xfer == 0 ctr2 = ctr else ctr2 = @ectr endif r0 = @rad0 r1 = r0 if @mode == "Linear" r1 = r0 * @rfac endif rot = exp(flip(@angle*#pi/180)) b_rot = 1 if @b != 2 b_rot = exp(flip(@b_angle*#pi/180)) endif endfunc complex func Iterate(complex pz) complex tmp = b_rot * (pz-ctr) float x = abs(real(tmp)) float y = abs(imag(tmp)) float r = (x^@b + y^@b)^(1/@b) float term = @s * (r/r0)^@p if r <= r0 complex pznew = ctr2 + term * (pz-ctr) * rot return pznew endif if @mode == "None" return pz endif float keep if @mode == "Linear" if r >= r1 return pz endif keep = 1 - (r-r0)/(r1-r0) elseif @mode == "Exponential" keep = exp(-@a*(r/r0-1)) else;if @mode == "Gaussian" keep = exp(-@a*(r/r0-1)^2) endif float ang = keep * @angle complex pznew = (1-keep) * pz + \ keep * (ctr2 + term * (pz-ctr) * exp(flip(ang*#pi/180))) return pznew endfunc private: complex ctr complex ctr2 float r0 float r1 complex b_rot complex rot default: title = "Bubble" rating = Recommended param use_ctr caption = "Use Screen Center" default = true endparam complex param center caption = "Bubble center" default = (0, 0) visible = !@use_ctr endparam float param rad0 caption = "Bubble size" default = 0.25/#magn ;min = 0 endparam float param b caption = "Bubble shape" default = 2 min = 0.25 ; best value? endparam float param b_angle caption = "Bubble rotation" default = 0 visible = @b != 2 endparam heading endheading param xfer caption = "Transfer from" enum = "Bubble" "Elsewhere" default = 0 endparam complex param ectr caption = "Elsewhere center" default = #center visible = @xfer == 1 endparam float param s caption = "Strength" default = 2 ;min = 0 endparam float param p caption = "Power"; from center" default = 2 ;min = 0 endparam float param angle caption = "Rotation angle" default = 0 endparam param mode caption = "Fade mode" enum = "None" "Linear" "Exponential" "Gaussian" default = 0 endparam float param rfac caption = "Fade distance factor" default = 1.5 min = 1 visible = @mode == 1 endparam float param a caption = "Fade strength" default = 5 min = 0 visible = @mode > 1 endparam } class JLB_DCurve2(Distance) { ; Curve definitions from ; https://mathcurve.com/courbes2d.gb/courbes2d.shtml ; www.2dcurves/com ; mathworld.wolfram.com/ ; with inspiration and some code from Otto Magus, om.ulb ; ; sources vary on what some of the curves are. ; I've changed a^2 many places to just a and b^2 to b, ; added parameters in a sensible way to many curves, ; and omitted any curves with three or more parameters ; 230204 added Heart curve. Backwards compatible. public: func JLB_DCurve2(Generic pparent) Distance(pparent) if @numpar == "1" a = @aa else a = real(@ab) b = imag(@ab) endif endfunc float func Iterate(complex zz) float x=real(zz) float y=imag(zz) if @exch float t=x, x=y, y=t endif float c1 = cabs(zz), float c2 = |zz|, float c3 = c2*c1, float c4 = c2*c2 float x2 = x^2, float y2 = y^2, float d2 = x2-y2 float d = 0 if @numpar == "1" ;45 if @V1=="Arachnea" d = (c2-a*x)^2 - a^2*c2 if @s, d = d/c4, endif elseif @V1=="Arcs of Samothrace" d = x2*(a*x2-y2)^2 - y2*c2 if @s, d = d/c4/c2, endif elseif @V1=="Astroid" d = x^@p + y^@p - a^@p if @s, d = d/c1^@p, endif elseif @V1=="Bicorn" d = y2*(a-x2) - (x2+2*a*y-a^2)^2 if @s, d = d/c4, endif elseif @V1=="Bicuspid" d = (x2-a^2)*(x-a)^2 + (y2-a)^2 if @s, d = d/c4, endif elseif @V1=="Bifoliate" d = x2*x2 + y2*y2 - a*x*y2 if @s, d = d/c4, endif elseif @V1=="Bow" d = x2*x2 - a*y*d2 if @s, d = d/c4, endif elseif @V1=="Bow Tie" d = x2*x2*c2 - a*d2 if @s, d = d/c2/c4, endif elseif @V1=="Butterfly" d = x2^3 + y2^3 - a*x2 if @s, d = d/c2/c4, endif elseif @V1=="Cardioid" d = (c2-a*x)^2 - a^2*c2 if @s, d = d/c4, endif elseif @V1=="Cayley's Sextic" d = 4*(c2-a*x)^3 - 27*a^2*c2^2 if @s, d = d/c4/c2, endif elseif @V1=="Cissoid of Diocles" d = x*c2 - a*y2 if @s, d = d/c3, endif elseif @V1=="Cornoid" d = c2^3 + a*(3*x^4 - 6*x2*y2 - 5*y^4) + 8*a^2*y2 - 4*a^3 if @s, d = d/c2/c4, endif elseif @V1=="Deltoid" d = c2^2 + 8*a*x*(x2-3*y2) + 18*a^2*c2 - 27*a^4 if @s, d = d/c4, endif elseif @V1=="Dipole" d = c2^3 - a*x2 if @s, d = d/c2/c3, endif elseif @V1=="Egg of Kepler" d = c2^2 - a*x^3 if @s, d = d/c4, endif elseif @V1=="Eight" d = x^4 - a*d2 if @s, d = d/c4, endif elseif @V1=="Folium of Descartes" d = x^3 + y^3 - 3*a*x*y if @s, d = d/c3, endif elseif @V1=="Folium of Durer" d = c2*(2*c2-a)^2 - a^2*x2 if @s, d = d/c2/c4, endif elseif @V1=="Heart" d = (x2+y2-a)^3 - x2*y2*y if @s, d = d/c3/c3, endif elseif @V1=="Heat Capacity" d = x2*(x-y) + a if @s, d = d/c3, endif elseif @V1=="Humbert's Cubic" d = x^3 - 3*x*y2 - a if @s, d = d/c3, endif elseif @V1=="Hyperbola" d = x2 - a*y2 if @s, d = d/c2, endif elseif @V1=="Kampyle of Eudoxus" d = x^4 - a*c2 if @s, d = d/c4, endif elseif @V1=="Kappa" d = x2*c2 - a*y2 if @s, d = d/c4, endif elseif @V1=="Kiepert" d = c2^3 - a*x*(x2-3*y2) if @s, d = d/c2/c4, endif elseif @V1=="Kiss" d = a^2*y2 - (a-x2)^3 if @s, d = d/c2/c4, endif elseif @V1=="Knot" d = (x2-a)^2 - y2*(3*a+2*y) if @s, d = d/c4, endif elseif @V1=="Kulp Quartic" d = x2*y2 - a*(a-y2) if @s, d = d/c4, endif elseif @V1=="Lemniscate of Bernoulli" d = c2^2 - a*d2 if @s, d = d/c4, endif elseif @V1=="Maltese Cross" d = x*y*d2 - a*c2 if @s, d = d/c2/c4, endif elseif @V1=="Nephroid of Freeth" d = c2*(x*2+y2-a)^2 - 4*a*(c2-a*x)^2 if @s, d = d/c2/c4, endif elseif @V1=="Parabola" d = y - a*x2 if @s, d = d/c2, endif elseif @V1=="Quadrifolium" d = c2^3 - a*x2*y2 if @s, d = d/c2/c4, endif elseif @V1=="Right Strophoid" d = x*c2 - a*d2 if @s, d = d/c3, endif elseif @V1=="Semicubical Parabola" d = y2 - a*x*x2 if @s, d = d/c3, endif elseif @V1=="Sextic" d = c2*(c2-a*y)^2 - x2*d2^2 if @s, d = d/c2/c4, endif elseif @V1=="Torpedo" d = c2^2 - a*x*d2 if @s, d = d/c4, endif elseif @V1=="Trisectrix of Delange" d = (c2-a)^2 - x2*c2 if @s, d = d/c4, endif elseif @V1=="Trisectrix of Longchamps" d = x*(x2-3*y2) - a*c2 if @s, d = d/c3, endif elseif @V1=="Trisectrix of Maclaurin" d = x*c2 - a*(3*x2-y2) if @s, d = d/c3, endif elseif @V1=="Trott" d = 144*(x^4+y^4) - 225*c2 + 350*x2*y2 + 81*a if @s, d = d/c4, endif elseif @V1=="Visiera" d = x*c2 - a*(x2+2*y2) if @s, d = d/c3, endif elseif @V1=="Viviani's" d = y^4 + a*d2 ;mathworld version if @s, d = d/c4, endif elseif @V1=="Wavy Cross" ; Swastika d = x2*x2-y2*y2 + a*x*y if @s, d = d/c4, endif elseif @V1=="Witch of Agnesi" d = x2*y + a^2*(y-a) if @s, d = d/c3, endif endif else;if @numpar == "2" ; 32 !! if @V2=="Alain" d = d2^2 - a*x2 + b*y2 if @s, d = d/c4, endif elseif @V2=="Ampersand" d = (y2-x2)*(x-a)*(2*x-3*a) - b*(c2-2*x)^2 if @s, d = d/c4, endif elseif @V2=="Anguinea" d = y*(x2+a^2) - a*b*x if @s, d = d/c3, endif elseif @V2=="Atripthaloid" d = x^4*c2 - (a*x2-b)^2 if @s, d = d/c4/c2, endif elseif @V2=="Beetle" d = c2*(c2-a*x-a*y) - b*x2*y2 if @s, d = d/c4, endif elseif @V2=="Besace" d = (x2-b*y)^2 - a*d2 if @s, d = d/c4, endif elseif @V2=="Bifolium" d = c2^2 - (a*x+b*y)*x2 if @s, d = d/c4, endif elseif @V2=="Bullet-Nose" d = a^2*y2 - b^2*x*2 - x2*y2 if @s, d = d/c4, endif elseif @V2=="Cassinian Ovals" d = c2^2 - a*d2 + b^4 if @s, d = d/c4, endif elseif @V2=="Conchoid of Nicomedes" d = (x-a)^2*c2 - b^2*x2 if @s, d = d/c4, endif elseif @V2=="Cross" d = x2*y2 - a*x2 - b*y2 if @s, d = d/c4, endif elseif @V2=="Cubical Parabola" d = a^2*y - x^3 + b*x if @s, d = d/c3, endif elseif @V2=="Cubic of de Sluze" d = a*(x-a)*c2 - b*x2 if @s, d = d/c3, endif elseif @V2=="Curve of Cramer" d = x*c2 + (a+b)*x2 - (a-b)*y2 if @s, d = d/c3, endif elseif @V2=="Double-Heart" d = x2*c2 - (a+b)*x2*y + (a-b)^2*y/4 if @s, d = d/c4, endif elseif @V2=="Dumbbell" d = b*y2 - x^4*(a-x2) if @s, d = d/c2/c4, endif elseif @V2=="Egg of Granville" d = x2*y2 - (x-a)*(b-x) if @s, d = d/c4, endif elseif @V2=="Ellipse" d = b*x2 + a*y2 - a/b if @s, d = d/c2, endif elseif @V2=="Euler's Cubic" d = y*(y2-a) - b*x*(x2-a) if @s, d = d/c3, endif elseif @V2=="Folium of Kepler" d = c2*(x*(x-a)+y2) - b*x*y2 if @s, d = d/c4, endif elseif @V2=="Function" d = y - a*real(@F(b*x)) if @s, d = d/c1, endif elseif @V2=="Hippopede" d = c2^2 - a*x2 - b*y2 if @s, d = d/c4, endif elseif @V2=="Limacon of Pascal" d = (c2-a*x)^2 - b*c2 if @s, d = d/c4, endif elseif @V2=="Nephroid" d = (c2-a)^3 - b*y2 if @s, d = d/c2/c4, endif elseif @V2=="Ophiuride" d = x*c2 - b*x*y - a*y2 if @s, d = d/c3, endif elseif @V2=="Pear" d = x*x2*(a-x) - b*y2 if @s, d = d/c4, endif elseif @V2=="Piriform Quartic" d = b^2*y2 + (x-a)*x^3 if @s, d = d/c4, endif elseif @V2=="Serpentine" d = y*(x+b*y)^2 - a*x if @s, d = d/c3, endif elseif @V2=="Tighrope" d = y2*(a^2*b-x2) - x2*(a-x)^2 if @s, d = d/c4, endif elseif @V2=="Trifolium" d = c2^2 - a*x*(x2-b*y2) if @s, d = d/c4, endif elseif @V2=="Trisectrix of Ceva" d = c2^3 - a*(b*x2-y2)^2 if @s, d = d/c2/c4, endif elseif @V2=="Windmill" d = 4*x2*y2*c2 - a*(x2-b*y2)^2 if @s, d = d/c2/c4, endif endif endif if (d >= 0 && @how == "Negative") || (d <= 0 && @how == "Positive") return -1 endif return abs(d) ; if m_abs_value ; d = abs(d) ; endif ; return d endfunc private: float a, float b default: rating = NotRecommended title = "Curve2" heading caption = "Use 'Curve Distance' instead" endheading int param version caption = "Version" default = 221220 visible = @version < 221220 endparam heading text = "(Current is 221220.)" visible = @version < 221220 endheading param numpar caption = "Group" enum = "1" "2" default = 0 endparam param V1 ;45 caption="Curve" enum= "Arachnea" "Arcs of Samothrace" \ "Astroid" "Bicorn" "Bicuspid" \ "Bifoliate" "Bow" "Bow Tie" "Butterfly" \ "Cardioid" "Cayley's Sextic" "Cissoid of Diocles" \ "Cornoid" "Deltoid" "Dipole" "Egg of Kepler" "Eight" \ "Folium of Descartes" "Folium of Durer" "Heat Capacity" \ "Humbert's Cubic" "Hyperbola" "Kampyle of Eudoxus" "Kappa" "Kiepert" \ "Kiss" "Knot" "Kulp Quartic" "Lemniscate of Bernoulli" \ "Maltese Cross" "Nephroid of Freeth" "Parabola" "Quadrifolium" \ "Right Strophoid" "Semicubical Parabola" "Sextic" \ "Torpedo" "Trisectrix of Delange" "Trisectrix of Longchamps" \ "Trisectrix of Maclaurin" "Trott" "Visiera" "Viviani's" "Wavy Cross" \ "Witch of Agnesi" "Heart" default=0 visible = @numpar == "1" endparam param V2 ;32 caption="Curve" enum = "Alain" "Ampersand" "Anguinea" "Atripthaloid" \ "Beetle" "Besace" "Bifolium" "Bullet-Nose" \ "Cassinian Ovals" "Conchoid of Nicomedes" "Cross" "Cubical Parabola" \ "Cubic of de Sluze" "Curve of Cramer" "Double-Heart" "Dumbbell" \ "Ellipse" "Egg of Granville" "Euler's Cubic" \ "Folium of Kepler" "Function" "Hippopede" \ "Limacon of Pascal" "Nephroid" "Ophiuride" \ "Pear" "Piriform Quartic" "Serpentine" \ "Tighrope" "Trifolium" \ "Trisectrix of Ceva" "Windmill" default=0 visible = @numpar == "2" endparam func F caption = "Function" default = sin() visible = @numpar=="2" && @V2=="Function" endfunc bool param exch caption = "Switch x and y?" default = false visible = @numpar == "2" || \ ( @V1 !="Astroid" && @V1 !="Folium of Descartes" \ && @V1 !="Quadrifolium" && @V1 !="Trott" ) endparam bool param s caption = "Z scale?" default = true ; 221220, was false endparam float param aa caption = "a" default = 1 visible = @numpar == "1" endparam float param p caption = "Power" default = 0.5 visible = @numpar == "1" && @V1=="Astroid" endparam complex param ab caption = "a and b" hint = "a is the real part, b the imaginary part" default = (1,0.5) visible = @numpar == "2" endparam param how caption = "How" enum = "Positive" "Negative" "Both" default = 2 endparam } class JLB_DTransform(Distance) { public: import "common.ulb" func JLB_DTransform(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif zzTransform = new @T(this) endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, m_abs_value) endfunc float func Iterate(complex zz) zz = zzTransform.Iterate(@a*zz) float d = m_dist.Iterate(zz) return d endfunc private: Distance m_dist UserTransform zzTransform default: title = "Transform" rating = Recommended int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading heading caption = "z_new = T(a*z)" endheading complex param a caption = "a" default = 1 endparam UserTransform param T caption = "Transform T" default = JLB_UT_Function endparam heading endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_Combo2Transform (common.ulb:UserTransform) { ; 230822 Added variations. Doesn't break old fractals. public: func JLB_Combo2Transform(Generic pparent) UserTransform(pparent) m_T1 = new @T1(this) m_T2 = new @T2(this) if @mode > 0 m_T3 = new @T3(this) endif m_Combine = new Combine() mult = 0 if @variation == "Variation 1" mult = 1 elseif @variation == "Variation 2" mult = -1 endif endfunc complex func Iterate(complex pz) float px = real(pz) float py = imag(pz) complex dx complex dy complex tx1, complex tx2, complex tx3 complex ty1, complex ty2, complex ty3 if @mode == 0 ;"T1 op1 T2" ;tx2 = @a2*@T2(@b2*px) ;ty2 = @a2*@T2(@b2*py) tx2 = iter(2, @b2*px) ty2 = iter(2, @b2*py) if @op1a == "( )" ; T1(T2(.)) ; dx = @a1*@T1(@b1*tx2) ; dy = @a1*@T1(@b1*ty2) dx = iter(1, @b1*tx2 + mult*px) dy = iter(1, @b1*ty2 + mult*py) else ; T1(.) op1 T2(.) ; tx1 = @a1*@T1(@b1*px) ; ty1 = @a1*@T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) dx = m_Combine.go(tx1, @op1a, tx2) dy = m_Combine.go(ty1, @op1a, ty2) endif elseif @mode == 1 ;"T1 op1 (T2 op2 T3)" if @op2a == "( )" ; T1 op T2(T3(.)) ; tx3 = @a3*T3(@b3*px) ; ty3 = @a3*T3(@b3*py) tx3 = iter(3, @b3*px) ty3 = iter(3, @b3*py) ; tx2 = @a2*T2(@b2*tx3) ; ty2 = @a2*T2(@b2*ty3) tx2 = iter(2, @b2*tx3 + mult*px) ty2 = iter(2, @b2*ty3 + mult*py) if @op1 == "( )" ; T1(T2(T3(.))) ; dx = @a1*T1(@b1*tx2) ; dy = @a1*T1(@b1*ty2) dx = iter(1, @b1*tx2 + mult*px) dy = iter(1, @b1*ty2 + mult*py) else ; T1(.) op1 T2(T3(.)) ; tx1 = @a1*T1(@b1*px) ; ty1 = @a1*T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) dx = m_Combine.go(tx1, @op1, tx2) dy = m_Combine.go(ty1, @op1, ty2) endif else; ; tx3 = @a3*T3(@b3*px) ; ty3 = @a3*T3(@b3*py) tx3 = iter(3, @b3*px) ty3 = iter(3, @b3*py) ; tx2 = @a2*T2(@b2*px) ; ty2 = @a2*T2(@b2*py) tx2 = iter(2, @b2*px) ty2 = iter(2, @b2*py) tx2 = m_Combine.go(tx2, @op2a, tx3) ty2 = m_Combine.go(ty2, @op2a, ty3) if @op1 == "( )" ; T1(T2(.) op2a T3(.)) ; dx = @a1*T1(@b1*tx2) ; dy = @a1*T1(@b1*ty2) dx = iter(1, @b1*tx2 + mult*px) dy = iter(1, @b1*ty2 + mult*px) else ; tx1 = @a1*T1(@b1*px) ; ty1 = @a1*T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) dx = m_Combine.go(tx1, @op1, tx2) dy = m_Combine.go(ty1, @op1, ty2) endif endif else ;@mode == "(T1 op1 T2) op2 T3" ; @op3a == "( )" not allowed with this ordering ; tx2 = @a2*T2(@b2*px) ; ty2 = @a2*T2(@b2*py) tx2 = iter(2, @b2*px) ty2 = iter(2, @b2*py) if @op1 == "( )" ; (T1(T2(.))) op2b T3(.) ; tx1 = @a1*T1(@b1*tx2) ; ty1 = @a1*T1(@b1*ty2) tx1 = iter(1, @b1*tx2) ty1 = iter(1, @b1*ty2) else ; tx1 = @a1*T1(@b1*px) ; ty1 = @a1*T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) tx1 = m_Combine.go(tx1, @op1, tx2) ty1 = m_Combine.go(ty1, @op1, ty2) endif ; tx3 = @a3*T3(@b3*px) ; ty3 = @a3*T3(@b3*py) tx3 = iter(3, @b3*px) ty3 = iter(3, @b3*py) dx = m_Combine.go(tx1, @op2b, tx3) dy = m_Combine.go(ty1, @op2b, ty3) endif return dx + flip(dy) endfunc complex func iter(int n, complex v) if n == 1 return @a1*m_T1.Iterate(v) elseif n == 2 return @a2*m_T2.Iterate(v) else return @a3*m_T3.Iterate(v) endif endfunc private: UserTransform m_T1 UserTransform m_T2 UserTransform m_T3 Combine m_Combine float mult default: rating = NotRecommended title = "Combo T" int param version caption = "Version" default = 230117 visible = @version < 230117 endparam heading caption = "Use 'Transform Combo' instead." endheading heading text = "(Current is 230117.)" visible = @version < 230117 endheading param mode caption = "Combining" default = 0 enum = "T1 op T2" "T1 op1 (T2 op2 T3)" "(T1 op1 T2) op2 T3" endparam param op1 caption = "Operator 1" enum = "+" "-" "*" "/" "^" "( )" default = 0 visible = @mode > 0 endparam param op1a caption = "Operator" enum = "+" "-" "*" "/" "^" "( )" default = 0 visible = @mode == 0 endparam param op2a caption = "Operator 2" enum = "+" "-" "*" "/" "^" "( )" default = 2 visible = (@mode == 1) endparam param op2b caption = "Operator 2" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default = 2 visible = (@mode == 2) endparam param variation enum = "Original" "Variation 1" "Variation 2" default = 0 visible = ( @mode == 0 && @op1a == "( )" ) || \ ( @mode == 1 && ( @op2a == "( )" || @op1 == "( )" ) ) || \ ( @mode == 2 && @op1 == "( )" ) endparam heading caption = "a1*T1(b1*v)" endheading complex param a1 caption = "a1" default = 1 hint = "multiplies T1" endparam complex param b1 caption = "b1" default = 2 hint = "multiplies T1's arg" endparam UserTransform param T1 caption = "T1" default = JLB_UT_Function endparam heading caption = "a2*T2(b2*v)" endheading complex param a2 caption = "a2" default = 2.7 hint = "multiplies T2" endparam complex param b2 caption = "b2" default = 2.7 hint = "multiplies T2's arg" endparam UserTransform param T2 caption = "T2" default = JLB_UT_Function endparam heading caption = "a3*T3(b3*v)" visible = @mode > 0 endheading complex param a3 caption = "a3" default = 0 hint = "multiplies T3" visible = @mode > 0 endparam complex param b3 caption = "b3" default = 1 hint = "multiplies T3's arg" visible = @mode > 0 endparam UserTransform param T3 caption = "T3" default = JLB_UT_Function visible = @mode > 0 endparam } class JLB_Gnarl5SFormula(SFormula) { ; Based on the Gnarl formula from mt.ufm, as a SFormula. ; Calculate dx and dy based on the real or imaginary part of z, then combine. ; Add a multiple of z, #pixel, or a seed. ; Changed from Gnarl3: omit SFormula; each f now is a UserTransform public: import "common.ulb" func JLB_Gnarl5SFormula(Generic pparent) SFormula.SFormula(pparent) m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180)) m_T = new @T(this) if @addT > 0 m_f4 = new @f4(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if s.bailed return true endif if s.tooMany return false endif complex pz = S.pz ; complex pc = @p_seed complex znew float xc = real(ppc) float yc = imag(ppc) complex zrot = pz * m_rot float x = real(zrot) float y = imag(zrot) complex px, complex py if @args == "x,y" px = x, py = y else ; "y,x" the original version, usually better px = y, py = x endif complex dz = m_T.Iterate(px+flip(py)) float dx = real(dz) float dy = imag(dz) float qx, float qy if @args == "x,y" qx = xc, qy = yc else ; "y,x" the original version, usually better qx = yc, qy = xc endif dx = dx + qx dy = dy + qy if @xyop == "-dx +dy" || @xyop == "-dx -dy" dx = -dx endif if @xyop == "+dx -dy" || @xyop == "-dx -dy" dy = -dy endif znew = pz + @step * (dx + flip(dy)) if @addT == "c" ppc = m_f4.iterate(ppc) elseif @addT == "z" znew = m_f4.Iterate(znew) endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex m_rot UserTransform m_T complex ppc UtilityTransform m_f4 default: rating = NotRecommended title = "Gnarl5" int param version caption = "Version (Gnarl5_SFormula)" default = 230116 visible = @version < 230116 endparam bool param p_Mtype caption = "M-type?" default = true endparam complex param p_seed caption = "Seed for J-type" default = (0.5,0.5) visible = !@p_Mtype endparam float param theta caption = "Theta" default = 0 hint = "First rotate z by this much (360 = full circle)" endparam param args caption = "args" enum = "x,y" "y,x" default = 1 endparam UserTransform param T caption = "Gnarl5 T" default = JLB_Combo2Transform selectable = false ; don't want this changed endparam heading endheading param xyop caption = "Gnarl5 dx,dy" enum = "+dx +dy" "+dx -dy" "-dx +dy" "-dx -dy" default = 1 hint = "final multiplcations of real and imaginary parts of z_calc" endparam param step caption = "Gnarl5 Step_size" default = 0.1 hint = "How much of this to use. z_new = z + Step_size * z_calc" endparam heading caption = "Tweak after each iteration" ;visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 ;visible = !@p_std endparam UtilityTransform param f4 caption = "Tweak transform" default = Tweak visible = @addT > 0 ;&& !@p_std selectable = false endparam } class JLB_MaskShape(common.ulb:DirectColoring) { ; some code copied from Bubble transform and Circle2 ; public: func JLB_MaskShape(Generic pparent) DirectColoring(pparent) if @use_ctr, ctr = #center, else, ctr = @center, endif if @type == "Circle", h = v = @rad, else, h = @horiz, v = @vert, endif rot = exp(flip(-@angle*#pi/180)) rr = red(gradient(0)) gg = green(gradient(0)) bb = blue(gradient(0)) endfunc func Init(complex pz, complex ppixel) DirectColoring.Init(pz, ppixel) endfunc func Iterate(complex pz) endfunc color func Result(complex pz) m_solid = false complex tmp = rot * (pz-ctr) float x = abs(real(tmp)) float y = abs(imag(tmp)) float r= ( (x/h)^@p + (y/v)^@p ) ^ (1/@p) float opacity = 0 if r <= 1 opacity = 1 else if @mode == "Linear" if r > @rfade opacity = 0 else opacity = 1 - (r-1)/(@rfade-1) endif elseif @mode == "Exponential" opacity = exp(-@a*(r-1)) elseif @mode == "Gaussian" opacity = exp(-@a*(r-1)^2) endif endif if @invert opacity = 1 - opacity endif return rgba(rr, gg, bb, opacity) endfunc private: complex ctr complex rot float h, float v float rr, float gg, float bb default: title = "Mask from shape" rating = Recommended bool param invert caption = "Invert mask shape?" default = false endparam param use_ctr caption = "Use Screen Center" default = true endparam complex param center caption = "Shape center" default = (0, 0) visible = !@use_ctr endparam param type caption = "Shape type" enum = "Circle" "Ellipse" default = 0 endparam float param p caption = "Shape power" default = 2 min = 0 hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square." endparam float param rad caption = "Circle radius" default = 2.0 min = 0 visible = @type == 0 endparam float param horiz caption = "Ellipse x value" default = 2.0 min = 0 visible = @type == 1 endparam float param vert caption = "Ellipse y value" default = 2.0 min = 0 visible = @type == 1 endparam float param angle caption = "Rotation angle" default = 0 visible = @p != 2.0 || (@type == 1 && @horiz != @vert) endparam param mode caption = "Fade mode" enum = "None" "Linear" "Exponential" "Gaussian" default = 0 endparam float param rfade caption = "Fade distance factor" default = 1.5 min = 1 visible = @mode == 1 endparam float param a caption = "Fade strength" default = 5 min = 0 visible = @mode > 1 endparam } class JLB_ChaoticAttractors(common.ulb:GradientColoring) { ; A re-writing of Latööcarfian Attractors in mt.ucl ; with drastic changes. ; Standard. Alpha, Beta, and Gamma are from mt.ucl; ; the others I've found online. ; http://paulbourke.net/fractals ; https://anaconda.org/jbednar/clifford_attractor/notebook ; https://softologyblog.wordpress.com/2017/03/04/2d-strange-attractors/ public: import "common.ulb" $define debug ; only for printing values from Randomize( ) func JLB_ChaoticAttractors(Generic pparent) GradientColoring(pparent) m_PixelCoordinate = new PixelCoordinate(pparent) r = new JLB_Random(0) r.Init(@seed) if @version >= 230219 a = real(@ab), b = imag(@ab), c = real(@cd), d = imag(@cd) else a = @aa, b = @bb, c = @cc, d = @dd endif if @more && @exch && @which == "Type 2" float t t = a, a = c, c = t t = b, b = d, d = t endif m1 = new @f1(this) m2 = new @f2(this) assign_Fs( ) assign_ab( ) DoTheWork() ; possibly randomize. fill the pix array endfunc func Init(complex pz, complex ppixel) GradientColoring.Init(pz, ppixel) m_PixelCoordinate.Init(pz) endfunc func Iterate(complex pz) GradientColoring.Iterate(pz) endfunc float func ResultIndex(complex pz) if (pix[#x,#y] == 0) m_solid = @solid return 0 endif ; densest gets index of 1 float idx idx = (log(pix[#x, #y]) / log(max)) ^(1-@contrast/2) return idx endfunc func DoTheWork( ) if @rnd Randomize( ) endif int x = 0, int y = 0 ; initialize pix array while x < #width y = 0 while y < #height pix[x, y] = 0 y = y + 1 endwhile x = x + 1 endwhile max = 0 float xx = 0.1, float yy = 0.1 if @more, xx = real(@start), yy = imag(@start), endif int i = 0 int iters = #width * #height * @density while i < iters float xnew, float ynew OneIteration(xx, yy, xnew, ynew) xx = xnew yy = ynew complex zz = m_PixelCoordinate.Iterate(xx+flip(yy)) x = round(real(zz)) y = round(imag(zz)) ; plot the point only if within the screen if x >= 0 && x < #width && y >= 0 && y < #height pix[x, y] = pix[x, y] + 1 if pix[x, y] > max max = pix[x, y] endif endif i = i + 1 endwhile if @lprnt print("Goodness ", L_eval( )) endif endfunc func OneIteration(float xx, float yy, float &xnew, float &ynew) if @which == "Type 1" xnew = m11.Iterate(a11*yy) + cd1*m12.Iterate(a12*xx) ; like Standard (any, bbaa, cd), ynew = m21.Iterate(a21*xx) + cd2*m22.Iterate(a22*yy) ; Clifford (1122, aabb, cd) else;if @which == "Type 2" xnew = m11.Iterate(a11*yy) - m12.Iterate(a12*xx) ; like DeJong (1212, ab, cd) ynew = m21.Iterate(cd1*xx) - m22.Iterate(cd2*yy) endif endfunc func Randomize( ) ; modified code from mt.ucl ; We randomize the parameters in a loop ; until we find a set that has a reasonably ; high Lyapunov exponent. int times = 0, int tbest = -1 ; int maxtimes = 1000 float L = -1, float Lmax = -1 float asave = 0, float bsave = 0, float csave = 0, float dsave = 0 while L < @Lgoal && times < @maxtimes ; Parameters in the range (-@range to +@range) a = @range * r.RandomFloat2(0) b = @range * r.RandomFloat2(0) c = @range * r.RandomFloat2(0) d = @range * r.RandomFloat2(0) ; keep only 3 decimal places a = round(1000*a)/1000, b = round(1000*b)/1000 c = round(1000*c)/1000, d = round(1000*d)/1000 assign_ab( ) L = L_eval( ) times = times + 1 if L > Lmax Lmax = L asave = a, bsave = b, csave = c, dsave = d tbest = times endif endwhile L = Lmax a = asave, b = bsave, c = csave, d = dsave assign_ab( ) Lmax = round(100*Lmax)/100 if (@prnt || @lprnt) && times >= @maxtimes print("Best result at try #", tbest,"; goodness ", Lmax) endif if @prnt print("a ", a, " b ", b, " c ", c, " d ", d, " goodness ", Lmax, \ " in ", times, " tries") endif endfunc float func L_eval( ) float L = 0, float Lsum = 0 float lx = 0.1, float ly = 0.1 float xe = lx + 1e-6, float ye = ly int i = 0 while i < 1000 ; Pickover suggests 10 million iterations, ; but this is enough to produce decent ; attractors float xx, float yy OneIteration(lx, ly, xx, yy) float xsave = xx, float ysave = yy, lx = xe, ly = ye i = i + 1 OneIteration(lx, ly, xx, yy) float dLx = xx - xsave, float dLy = yy - ysave float dL2 = dLx * dLx + dLy * dLy float df = 1e12 * dL2 float rs = 1/sqrt(df) xe = xsave + rs * (xx - xsave) ye = ysave + rs * (yy - ysave) xx = xsave, yy = ysave Lsum = Lsum + log(df) L = 0.721347 * Lsum / i lx = xx ly = yy endwhile return round(100*L)/100 endfunc func assign_Fs( ) if @more if @p == "1122" m11 = m1, m12 = m1, m21 = m2, m22 = m2 elseif @p == "1212" m11 = m1, m12 = m2, m21 = m1, m22 = m2 elseif @p == "1221" m11 = m1, m12 = m2, m21 = m2, m22 = m1 elseif @p == "2112" m11 = m2, m12 = m1, m21 = m1, m22 = m2 elseif @p == "2121" m11 = m2, m12 = m1, m21 = m2, m22 = m1 else;if @p == "2211" m11 = m2, m12 = m2, m21 = m1, m22 = m1 endif else ; default 1212 m11 = m1, m12 = m2, m21 = m1, m22 = m2 endif endfunc func assign_ab( ) if @which == "Type 1" if @qx1 == "aabb" || !@more a11 = a, a12 = a, a21 = b, a22 = b elseif @qx1 == "abab" a11 = a, a12 = b, a21 = a, a22 = b elseif @qx1 == "abba" a11 = a, a12 = b, a21 = b, a22 = a elseif @qx1 == "baab" a11 = b, a12 = a, a21 = a, a22 = b elseif @qx1 == "baba" a11 = b, a12 = a, a21 = b, a22 = a else;if @qx1 == "bbaa" a11 = b, a12 = b, a21 = a, a22 = b endif endif if @qx2 == "cd" cd1 = c, cd2 = d else;if @qx2 == "dc" cd1 = d, cd2 = c endif if @which == "Type 2" if @qy == "ab" || !@more a11 = a, a12 = b else;if @qy == "ba" a11 = b, a12 = a endif endif endfunc private: PixelCoordinate m_PixelCoordinate JLB_Random r float a, float b, float c, float d float a11, float a12, float a21, float a22 float cd1, float cd2 int pix[#width, #height] int max Transfer m1, Transfer m2 Transfer m11, Transfer m12, Transfer m21, Transfer m22 default: title = "Chaotic Attractors" rating = NotRecommended ; too specialized heading text = "Use with pixel(jp) formula in jlb.ufm or jp.ufm. Use Plug-In Coloring (Gradient) in jlb.ucl." endheading heading text = "Ignores all Mappings." endheading int param version caption = "Version" default = 230219 visible = @version < 230219 endparam heading text = "(Current is 230219.)" visible = @version < 230219 endheading bool param solid caption = "Use Solid Background?" default = false endparam ;render = !@rnd ;false param which caption = "Attractor" enum = "Type 1" "Type 2" default = 0 endparam Transfer param f1 caption = "F1" default = ChaosFunc enabled = false endparam Transfer param f2 caption = "F2" default = Chaosfunc enabled = false endparam bool param more caption = "More options?" default = false endparam param p caption = "F Permutation" enum = "1122" "1212" "1221" "2112" "2121" "2211" default = 0 visible = @more endparam bool param exch caption = "Exchange ab and cd?" default = false visible = @more && @which == "Type 2" endparam param qx1 caption = "ab Permutation" enum = "aabb" "abab" "abba" "baab" "baba" "bbaa" default = 0 visible = @more && (@which == "Type 1") endparam param qy caption = "ab Permutation" enum = "ab" "ba" default = 0 visible = @more && (@which == "Type 2") endparam param qx2 caption = "cd Permutation" enum = "cd" "dc" default = 0 visible = @more endparam bool param lprnt caption = "Print goodness value?" default = false visible = !@more || !@prnt|| !@rnd endparam bool param rnd caption = "Find good abcd?" default = false visible = @more endparam bool param prnt caption = "Print abcd?" default = false visible = @rnd endparam heading endheading int param maxtimes caption = "How many tries" default = 100 min = 1 visible = @rnd endparam float param range caption = "Range for searching" default = 3 min = 1 visible = @rnd endparam float param Lgoal caption = "How good?" default = 0.25 min = 0 visible = @rnd endparam int param seed caption = "Seed" default = 12345678 min = 1 visible = @rnd endparam heading text = "a=real(ab), b=imag(ab), c=real(cd), d=imag(cd)" visible = !@rnd && @version >= 230219 endheading complex param ab default = (-1.4, 1.6) visible = !@rnd && @version >= 230219 endparam complex param cd default = (1.0, 0.7) visible = !@rnd && @version >= 230219 endparam float param aa caption = "a" default = -1.4 visible = !@rnd && @version < 230219 endparam param bb caption = "b" default = 1.6 visible = !@rnd && @version < 230219 endparam float param cc caption = "c" default = 1.0 visible = !@rnd && @version < 230219 endparam float param dd caption = "d" default = 0.7 visible = !@rnd && @version < 230219 endparam heading endheading complex param start caption = "Starting Point" default = (0.1,0.1) visible = @more endparam int param density caption = "Sample Density" default = 10 min = 1 endparam float param contrast caption = "Added Contrast (-1:+1)" default = 0 min = -1 max = +1 endparam } class ChaosFunc(common.ulb:Transfer){ public: import "common.ulb" func ChaosFunc(Generic pparent) Transfer(pparent) if @version < 230512 type = @w else type = @ww endif endfunc float func Iterate(float pr) float ans if type == 0, ans = sin(pr) elseif type == 1, ans = cos(pr) elseif type == 2, ans = tanh(pr) elseif type == 3, ans = Math.RealBesselJ0(pr) elseif type == 4, ans = Math.RealBesselJ1(pr) elseif type == 5 if pr == 0, ans = 1, else, ans = sin(pr)/pr, endif else;if type == 6 if @version < 230512 ans = abs(pr)^@p if pr < 0, ans = -ans, endif else ans = pr / (1 + abs(pr)^@pp) endif endif return ans endfunc private: int type default: title = "Chaos Function" int param version caption = "Version" default = 230512 visible = @version < 230512 endparam param w caption = " F" enum = "sin" "cos" "tanh" "J0" "J1" "sync" "spower" default = 0 visible = @version > 230512 endparam param ww caption = " F" enum = "sin" "cos" "tanh" "J0" "J1" "sync" "rational" default = 0 visible = @version >= 230512 endparam float param p caption = "p" default = 1 visible = @version < 230512 && @w == 6 endparam float param pp caption = "power" default = 1 visible = @version >= 230512 && @ww == 6 endparam } class JLB_Waves(common.ulb:UserTransform) { public: func JLB_Waves(Generic pparent) Generic.Generic(pparent) hfreq = real(@freq) vfreq = imag(@freq) phase = @p*#pi/180 rot = exp(flip(@dir*#pi/180)) ctr = #center if !@center ctr = @ctr endif endfunc complex func Iterate(complex pz) ; if mapping, called with pz = #pixel float factor = 1 if @fade > 0 factor = 0 float dist = cabs(pz - ctr) if @fade == "Power" if dist < @distance factor = (1 - dist/@distance)^@power endif elseif @fade == "Exponential" float t = dist/@distance factor = exp(-t) else;if @fade == "Gaussian" float t = sqr(dist/@distance) factor = exp(-t) endif endif if factor > 0 float x = real(pz-ctr), float y = imag(pz-ctr) float arg = phase if @type == 1 || @type == 3 arg = arg + @hfac * real(@FH(hfreq*x)) else arg = arg + hfreq*x endif if @type == 2 || @type == 3 arg = arg + @vfac * real(@FV(vfreq*y)) else arg = arg + vfreq*y endif float delta = @a * real(@F(arg)) pz = pz + delta * rot * factor endif return pz endfunc private: float hfreq, float vfreq float phase complex rot complex ctr default: title = "Waves" rating = Recommended int param version caption = "Version-Waves" default = 230601 visible = @version < 230601 endparam heading text = "(Curent is 230601.}" visible = @version < 230601 endheading bool param center caption = "Use screen center?" default = true endparam complex param ctr caption = "Center" default = (0,0) visible = !@center endparam float param a caption = "Amplitude" default = 0.5 endparam float param dir caption = "Direction (degrees)" hint = "90 means vertical" default = 90 endparam func F caption = "Function" default = sin() endfunc complex param freq caption = "H && V frequencies" default = (1,1) endparam float param p caption = "Phase (degrees)" default = 0 endparam param type caption = "Modification" enum = "none" "H" "V" "both" default = 0 endparam func FH caption = "H modification" default = ident() visible = @type == 1 || @type == 3 endfunc float param hfac caption = "H factor" default = 1 visible = @type == 1 || @type == 3 endparam func FV caption = "V modification" default = ident() visible = @type == 2 || @type == 3 endfunc float param vfac caption = "V factor" default = 1 visible = @type == 2 || @type == 3 endparam heading visible = @fade > 0 endheading param fade caption = "Decay?" enum = "None" "Power" "Exponential" "Gaussian" default = 0 endparam float param distance caption = "Distance" default = 1 min = 0 visible = @fade > 0 endparam float param power caption = "Decay power" default = 2 min = 0 visible = @fade == 1 endparam } class JLB_Simple(common.ulb:GradientColoring) { func JLB_Simple(Generic pparent) GradientColoring(pparent) if @fz == 2 FT = new @fUT(this) endif endfunc float func ResultIndex(complex pz) complex zz = @a * pz if @fz == 1 zz = @FF(zz) elseif @fz == 2 zz = FT.Iterate(zz) endif float x = real(zz), float y = imag(zz) float ax = abs(x), float ay = abs(y) float a = cabs(zz) float ans = 0 if @type == "Mod" ans = a elseif @type == "Real" ans = x elseif @type == "Imag" ans = y elseif @type == "Real+Imag" ans = x+y elseif @type == "Real-Imag" ans = x-y elseif @type == "Real*Imag" ans = x*y elseif @type == "Real/Imag" ans = x/y elseif @type == "Imag/Real" ans = y/x elseif @type == "Real^Imag" ans = x^y elseif @type == "Imag^Real" ans = y^x elseif @type == "|Real|+|Imag|" ans = ax+ay elseif @type == "|Real|-|Imag|" ans = ax-ay elseif @type == "Max(|Real|,|Imag|)" ans = ax if ay > ax, ans = ay, endif elseif @type == "Max(Real,Imag)" ans = x ; range = (0,a) if y > x, ans = y, endif elseif @type == "Min(|Real|,|Imag|)" ans = ax if ay < ax, ans = ay, endif elseif @type == "Min(Real,Imag)" ans = x if y < x, ans = y, endif else;if @type == "Angle" ans = atan2(zz)/ (2 * #pi) if ans < 0 ans = ans + 1 endif endif ; make index be in [0,1] even if Repeat Gradient isn't checked ans = ans - trunc(ans) if ans < 0 ans = ans + 1 endif return ans endfunc private: UserTransform FT default: title = "Simple Coloring" rating = NotRecommended int param version caption = "Version-Simple Coloring" default = 230601 visible = @version < 230601 endparam heading text = "(Curent is 230601.}" visible = @version < 230601 endheading heading text = "Color using the last z value. Use a pixel formula if you want to \ color the gradient." endheading heading caption = "Use z, F(a*z), or T(a*z)" endheading param fz caption = "Which?" enum = "a*z" "F(a*z)" "T(a*z)" default = 0 endparam complex param a caption = "a" default = 1 endparam func FF caption = "Function" default = sinh() visible = @fz == 1 endfunc UserTransform param fUT caption = "Transform" default = JLB_MoebiusUserTransform visible = @fz == 2 endparam param type caption = "Color by" enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ "Angle" default = 0 endparam } class JLB_DFuncs(Distance) { public: import "common.ulb" func JLB_DFuncs(Generic pparent) Distance(pparent) if @version < 240101 m_dist = new @dist(this) else m_dist = new @distnew(this) endif m_fx = new @f1(this) m_fy = new @f2(this) endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) endfunc float func Iterate(complex zz) int n = 0 while n < @nmax complex xa = @b*ComplexToFloat.go(zz, @xarg, true) complex ya = @b*ComplexToFloat.go(zz, @yarg, true) float xx = real(@a*m_fx.Iterate(xa)) float yy = real(@a*m_fy.Iterate(ya)) if @kind == "Add" zz = zz + xx + flip(yy) else zz = xx + flip(yy) endif n = n + 1 endwhile return m_dist.Iterate(zz) endfunc private: Distance m_dist UserTransform m_fx UserTransform m_fy default: title = "Funcs" rating = Recommended int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "(Curent is 240101.}" visible = @version < 240101 endheading heading caption = "xnew = a*F(b*arg)" endheading UserTransform param f1 caption = "X function" default = JLB_UT_Function ;selectable = false endparam param xarg caption = "X arg" enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \ "Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle" endparam heading caption = "ynew = a*F(b*arg)" endheading UserTransform param f2 caption = "Y function" default = JLB_UT_Function ;selectable = false endparam param yarg caption = "Y arg" enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \ "Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle" endparam heading endheading complex param a caption = "a" default = 1 endparam complex param b caption = "b" default = 1 endparam int param @nmax caption = "Iterations" default = 1 min = 1 endparam param kind caption = "Add or Replace" enum = "Add" "Replace" default = 0 endparam heading endheading heading ;text = "Use for distance:" endheading Distance param dist default = JLB_DXYZ selectable = false visible = @version < 240101 endparam Distance param distnew default = JLB_D_SD selectable = false visible = @version >= 240101 endparam } class JLB_ComboFunction (common.ulb:UserTransform) { public: func JLB_ComboFunction(Generic pparent) UserTransform(pparent) m_F1 = new @F1(this) m_F2 = new @F2(this) if @mode > 0 m_F3 = new @F3(this) endif m_Combine = new Combine() endfunc complex func Iterate(complex pz) float px = real(pz) float py = imag(pz) complex xx complex yy complex xx1, complex xx2, complex xx3 complex yy1, complex yy2, complex yy3 if @mode == 0 ;"F1 op1 F2" ;xx2 = @a2*@F2(@b2*px) ;yy2 = @a2*@F2(@b2*py) xx2 = iter(2, @b2*px) yy2 = iter(2, @b2*py) if @op1 == "( )" ; F1(F2(.)) ; xx = @a1*@F1(@b1*xx2) ; yy = @a1*@F1(@b1*yy2) xx = iter(1, @b1*xx2) yy = iter(1, @b1*yy2) else ; F1(.) op1 F2(.) ; xx1 = @a1*@F1(@b1*px) ; yy1 = @a1*@F1(@b1*py) xx1 = iter(1, @b1*px) yy1 = iter(1, @b1*py) xx = m_Combine.go(xx1, @op1, xx2) yy = m_Combine.go(yy1, @op1, yy2) endif elseif @mode == 1 ;"F1 op1 (F2 op2 F3)" if @op2a == "( )" ; F1 op F2(F3(.)) ; xx3 = @a3*F3(@b3*px) ; yy3 = @a3*F3(@b3*py) xx3 = iter(3, @b3*px) yy3 = iter(3, @b3*py) ; xx2 = @a2*F2(@b2*xx3) ; yy2 = @a2*F2(@b2*yy3) xx2 = iter(2, @b2*xx3) yy2 = iter(2, @b2*yy3) if @op1 == "( )" ; F1(F2(F3(.))) ; xx = @a1*F1(@b1*xx2) ; yy = @a1*F1(@b1*yy2) xx = iter(1, @b1*xx2) yy = iter(1, @b1*yy2) else ; F1(.) op1 F2(F3(.)) ; xx1 = @a1*F1(@b1*px) ; yy1 = @a1*F1(@b1*py) xx1 = iter(1, @b1*px) yy1 = iter(1, @b1*py) xx = m_Combine.go(xx1, @op1, xx2) yy = m_Combine.go(yy1, @op1, yy2) endif else ; xx3 = @a3*F3(@b3*px) ; yy3 = @a3*F3(@b3*py) xx3 = iter(3, @b3*px) yy3 = iter(3, @b3*py) ; xx2 = @a2*F2(@b2*px) ; yy2 = @a2*F2(@b2*py) xx2 = iter(2, @b2*px) yy2 = iter(2, @b2*py) xx2 = m_Combine.go(xx2, @op2a, xx3) yy2 = m_Combine.go(yy2, @op2a, yy3) if @op1 == "( )" ; F1(F2(.) op2a F3(.)) ; xx = @a1*F1(@b1*xx2) ; yy = @a1*F1(@b1*yy2) xx = iter(1, @b1*xx2) yy = iter(1, @b1*yy2) else ; xx1 = @a1*F1(@b1*px) ; yy1 = @a1*F1(@b1*py) xx1 = iter(1, @b1*px) yy1 = iter(1, @b1*py) xx = m_Combine.go(xx1, @op1, xx2) yy = m_Combine.go(yy1, @op1, yy2) endif endif else ;@omode == "(F1 op1 F2) op2 F3" ; @op3a == "()" not allowed with this ordering ; xx2 = @a2*F2(@b2*px) ; yy2 = @a2*F2(@b2*py) xx2 = iter(2, @b2*px) yy2 = iter(2, @b2*py) if @op1 == "( )" ; (F1(F2(.))) op2b F3(.) ; xx1 = @a1*F1(@b1*xx2) ; yy1 = @a1*F1(@b1*yy2) xx1 = iter(1, @b1*xx2) yy1 = iter(1, @b1*yy2) else ; xx1 = @a1*F1(@b1*px) ; yy1 = @a1*F1(@b1*py) xx1 = iter(1, @b1*px) yy1 = iter(1, @b1*py) xx1 = m_Combine.go(xx1, @op1, xx2) yy1 = m_Combine.go(yy1, @op1, yy2) endif ; xx3 = @a3*F3(@b3*px) ; yy3 = @a3*F3(@b3*py) xx3 = iter(3, @b3*px) yy3 = iter(3, @b3*py) xx = m_Combine.go(xx1, @op2b, xx3) yy = m_Combine.go(yy1, @op2b, yy3) endif return xx + flip(yy) endfunc complex func iter(int n, complex v) if n == 1 return @a1*m_F1.Iterate(v) elseif n == 2 return @a2*m_F2.Iterate(v) else return @a3*m_F3.Iterate(v) endif endfunc private: UserTransform m_F1 UserTransform m_F2 UserTransform m_F3 Combine m_Combine default: rating = NotRecommended title = "ComboF" int param version caption = "Version" default = 230817 visible = @version < 230817 endparam heading text = "(Current is 230817.)" visible = @version < 230817 endheading param mode caption = "How to combine" default = 0 enum = "F1 op F2" "F1 op1 (F2 op2 F3)" "(F1 op1 F2) op2 F3" endparam param op1 caption = "Operator 1" enum = "+" "-" "*" "/" "^" "( )" default = 0 hint = "How to combine Formula values." endparam param op2a caption = "Operator 2" enum = "+" "-" "*" "/" "^" "( )" default = 2 hint = "How to combine Formula values." visible = (@mode == 1) endparam param op2b caption = "Operator 2" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default = 2 hint = "How to combine Formula values." visible = (@mode == 2) endparam heading caption = "a1*F1(b1*v)" endheading complex param a1 caption = "a1" default = 1 hint = "multiplies F1" endparam complex param b1 caption = "b1" default = 2 hint = "multiplies F1's arg" endparam UserTransform param F1 caption = "F1" default = JLB_FTransform selectable = false endparam heading caption = "a2*F2(b2*v)" endheading complex param a2 caption = "a2" default = 2.7 hint = "multiplies F2" endparam complex param b2 caption = "b2" default = 2.7 hint = "multiplies F2's arg" endparam UserTransform param F2 caption = "F2" default = JLB_FTransform selectable = false endparam heading caption = "a3*F3(b3*v)" visible = @mode > 0 endheading complex param a3 caption = "a3" default = 0 hint = "multiplies F3" visible = @mode > 0 endparam complex param b3 caption = "b3" default = 1 hint = "multiplies F3's arg" visible = @mode > 0 endparam UserTransform param F3 caption = "F3" default = JLB_FTransform visible = @mode > 0 selectable = false endparam } class JLB_FuncsUserTransform(common.ulb:UserTransform) { public: func JLB_FuncsUserTransform(Generic pparent) UserTransform(pparent) m_fx = new @f1(this) m_fy = new @f2(this) endfunc complex func Iterate(complex pz) int n = 0 while n < @nmax complex xa = @bb*ComplexToFloat.go(pz, @xarg, true) complex ya = @bb*ComplexToFloat.go(pz, @yarg, true) float xx = real(@aa*m_fx.Iterate(xa)) float yy = real(@aa*m_fy.Iterate(ya)) if @kind == "Add" pz = pz + xx + flip(yy) else pz = xx + flip(yy) endif n = n + 1 endwhile return pz endfunc private: UserTransform m_fx UserTransform m_fy default: rating = NotRecommended title = "Funcs" int param version caption = "Version" default = 230819 visible = @version < 230819 endparam heading text = "(Current is 230819.)" visible = @version < 230819 endheading heading caption = "xnew = aa*F(bb*arg)" endheading UserTransform param f1 caption = "X function" default = JLB_FTransform ;selectable = false endparam param xarg caption = "X arg" enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \ "Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle" endparam heading caption = "ynew = aa*F(bb*arg)" endheading UserTransform param f2 caption = "Y function" default = JLB_FTransform ;selectable = false endparam param yarg caption = "Y arg" enum = "Mod" "x" "y" "x+y" "x-y" "x*y" "x/y" "y/x" "x^y" "y^x" "|x|+|y|" "|x|-|y|" \ "Max(|x|,|y|)" "Max(x,y)" "Min(|x|,|y|)" "Min(x,y)" "Angle" endparam heading endheading complex param aa caption = "aa" default = 1 endparam complex param bb caption = "bb" default = 1 endparam int param @nmax caption = "Iterations" default = 1 min = 1 endparam param kind caption = "Add or Replace" enum = "Add" "Replace" default = 1 endparam } class JLB_DTwoCircles(Distance) { public: func JLB_DTwoCircles(Generic pparent) Distance(pparent) ; first circle m_dist[0] = new @dist0(this) if @screen_center0, ctr[0] = #center, else, ctr[0] = @center0, endif if @type0 == "Circle", h[0] = v[0] = @r0, else, h[0] = @horiz0, v[0] = @vert0, endif sp[0] = @p0 scale[0] = 1 if @do_scale0 scale[0] = 2 * MyMath.fmax(h[0], v[0]) ; 2 to be like Square scaling endif rot[0] = 1 if @p0 != 2.0 || (@type0 == 1 && @horiz0 != @vert0) rot[0] = cos(@angle0*#pi/180) + flip(sin(@angle0*#pi/180)) endif pow[0] = @pow0 inout[0] = @in_out0 ;same thing for second circle m_dist[1] = new @dist1(this) if @screen_center1, ctr[1] = #center, else, ctr[1] = @center1, endif if @type1 == "Circle", h[1] = v[1] = @r1, else, h[1] = @horiz1, v[1] = @vert1, endif sp[1] = @p1 scale[1] = 1 if @do_scale1 scale[1] = 2 * MyMath.fmax(h[1], v[1]) ; 2 to be like Square scaling endif rot[1] = 1 if @p1 != 2.0 || (@type1 == 1 && @horiz1 != @vert1) rot[1] = cos(@angle1*#pi/180) + flip(sin(@angle1*#pi/180)) endif pow[1] = @pow1 inout[1] = @in_out1 endfunc func Init(complex zz) ;m_dist.SetParams(0, m_abs_value) ;not needed float r old_inside[0] = IsInside(rot[0] * (zz - ctr[0]), r, 0) ; calculates r, not used old_inside[1] = IsInside(rot[1] * (zz - ctr[1]), r, 1) ; calculates r, not used endfunc float func Iterate(complex zz) float d0 = circle_dist(zz, 0) float d1 = circle_dist(zz, 1) float dmin = MyMath.fmin(d0, d1) float dmax = MyMath.fmax(d0, d1) if dmin < 0 ; at most one is okay if @how == "Both" return dmin ; no good endif return dmax ; this one, good or bad endif ; both are okay if @which == "Minimum" return dmin elseif @which == "Maximum" return dmax elseif @which == "Arithmetic Average" return 0.5*(dmin + dmax) elseif @which == "Geometric Average" return sqrt(dmin * dmax) else;if @which == "Harmonic Average" return 2 / (1/dmin + 1/dmax) endif endfunc float func circle_dist(complex zz, int n) zz = rot[n] * (zz - ctr[n]) float d = -MyMath.fmax(1, |zz|) float r bool new_inside = IsInside(zz, r, n) ; calculates r complex t bool okay = false if inout[n] == 0 ; "Inside" okay = new_inside elseif inout[n] == 1 ; "Outside" okay = !new_inside elseif inout[n] == 2 ; "Either" okay = true elseif inout[n] == 3 ; "Change" okay = new_inside != old_inside[n] elseif inout[n] == 4 ; "Same" okay = new_inside == old_inside[n] endif if !okay if inout[n] == 5 ; "In->In" okay = old_inside[n] && new_inside elseif inout[n] == 6 ; "In->Out" okay = old_inside[n] && !new_inside elseif inout[n] == 7 ;"Out->In" okay = !old_inside[n] && new_inside elseif inout[n] == 8 ;"Out->Out" okay = !old_inside[n] && !new_inside endif endif t = 0 if okay t = zz * (1-r) / rot[n] if !new_inside t = -t endif d = m_dist[n].Iterate(t)/scale[n] old_inside[n] = new_inside ;bool neg = ( d < 0 ) d = abs(d)^pow[n] ;if neg, d = -d, endif endif return d endfunc bool func IsInside(complex zz, float &r, int n) float x = abs(real(zz)) float y = abs(imag(zz)) r= ( (x/h[n])^sp[n] + (y/v[n])^sp[n] ) ^ (1/sp[n]) return r <= 1 endfunc private: complex ctr[2] float h[2] float v[2] float sp[2] float scale[2] float pow[2] complex rot[2] int inout[2] bool old_inside[2] Distance m_dist[2] default: title = "TwoCircles" rating = Recommended int param version caption = "Version" default = 231101 visible = @version < 231101 endparam heading text = "(Curent is 231101.}" visible = @version < 231101 endheading heading caption = "First circle" endheading param type0 caption = "Circle or ellipse" enum = "Circle" "Ellipse" default = 0 endparam float param p0 caption = "Shape power" default = 2 min = 0 hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square." endparam bool param screen_center0 caption = "Use screen center?" default = true endparam param center0 caption = "Center" default = (0,0) visible = !@screen_center0 endparam float param r0 caption = "Circle radius" default = 2.0 min = 0 visible = @type0 == 0 endparam float param horiz0 caption = "Ellipse x value" default = 2.0 min = 0 visible = @type0 == 1 endparam float param vert0 caption = "Ellipse y value" default = 2.0 min = 0 visible = @type0 == 1 endparam float param angle0 caption = "Rotation angle" default = 0 visible = @p0 != 2.0 || (@type0 == 1 && @horiz0 != @vert0) endparam param in_out0 caption = "Inside/outside?" enum = "Inside" "Outside" "Either" "Change" "Same" \ "In->In" "In->Out" "Out->In" "Out->Out" hint = "Change: use iterations where new inside is different from \ old inside. Same: use iterations where new inside equals \ old inside" default = 2 endparam float param pow0 caption = "Distance power" default = 1 min = 0 ; hint = "Higher values emphasize iterations with z away from the circle edge." endparam bool param do_scale0 caption = "Scale by size?" default = false endparam heading ;text = "Use for distance:" endheading Distance param dist0 default = JLB_DXYZ selectable = false endparam heading caption = "Second circle" endheading param type1 caption = "Circle or ellipse" enum = "Circle" "Ellipse" default = 0 endparam float param p1 caption = "Shape power" default = 2 min = 0 hint = "Power = 2 for circle, < 2 for indented, < 1 for astroid, > 2 for shapes nearing a square." endparam bool param screen_center1 caption = "Use screen center?" default = true endparam param center1 caption = "Center" default = (0,0) visible = !@screen_center1 endparam float param r1 caption = "Circle radius" default = 4.0 min = 0 visible = @type1 == 0 endparam float param horiz1 caption = "Ellipse x value" default = 4.0 min = 0 visible = @type1 == 1 endparam float param vert1 caption = "Ellipse y value" default = 4.0 min = 0 visible = @type1 == 1 endparam float param angle1 caption = "Rotation angle" default = 1 visible = @p1 != 2.0 || (@type1 == 1 && @horiz1 != @vert1) endparam param in_out1 caption = "Inside/outside?" enum = "Inside" "Outside" "Either" "Change" "Same" \ "In->In" "In->Out" "Out->In" "Out->Out" hint = "Change: use iterations where new inside is different from \ old inside. Same: use iterations where new inside equals \ old inside" default = 0 endparam float param pow1 caption = "Distance power" default = 1 min = 0 ; hint = "Higher values emphasize iterations with z away from the circle edge." endparam bool param do_scale1 caption = "Scale by size?" default = false endparam heading ;text = "Use for distance:" endheading Distance param dist1 default = JLB_DXYZ selectable = false endparam heading caption = "Combine circles?" endheading param how caption = "Either/Both" enum = "Either" "Both" default = 0 endparam param which caption = "Which?" enum = "Minimum" "Maximum" "Arithmetic Average" "Geometric Average" "Harmonic Average" default = 0 endparam } class JLB_DAboveBelow(Distance) { public: func JLB_DAboveBelow(Generic pparent) Distance(pparent) if @sw m_1 = new @dist_below(this) m_2 = new @dist_above(this) else m_1 = new @dist_above(this) m_2 = new @dist_below(this) endif m_SD = new @f_SD(this) endfunc func Init(complex zz) m_SD.SetScale(false) m_1.Init(zz) m_2.Init(zz) count = 0 endfunc float func Iterate(complex zz) float test = count count = count + 1 if @mode == 0 test = m_SD.Iterate(zz) endif if @trans == 0 ; abrupt transition if test >= @crit return m_1.Iterate(zz) else return m_2.Iterate(zz) endif endif ; smooth transition using tanh float frac = TSmooth.go((test-@crit)/@trans) float d1 = m_1.Iterate(zz) float d2 = m_2.Iterate(zz) return frac * d1 + (1-frac) * d2 endfunc private: Distance m_1 Distance m_2 int count SD m_SD default: title = "AboveBelow" rating = Recommended heading text = "Use a distance method depending on a critical value." ; hint = "Use real and imaginary parts of z to \ ; calculate value to compare with critical value." endheading int param version caption = "Version" default = 240101 visible = @version < 240101 endparam heading text = "Current version is 240101" visible = @version < 240101 endheading float param crit caption = "Critical value" default = 1 endparam bool param sw caption = "Switch above and below methods" default = false endparam param mode caption = "Use for critical value" enum = "Z distance" "Iteration number" default = 0 endparam SD param f_SD caption = "Method" default = JLB_D01 visible = @mode == 0 endparam float param trans caption = "Transition parameter" default = 0.5 min = 0 endparam Distance param dist_above caption = "Above method" default = JLB_DSimpleShapes endparam Distance param dist_below caption = "Below method" default = JLB_DSimpleShapes endparam } class JLB_2Dist_SFormula(SFormula) { ; public: import "common.ulb" func JLB_2Dist_SFormula(Generic pparent) SFormula(pparent) m_Dx = new @distx(this) m_Dy = new @disty(this) if @addT > 0 && !@p_std finalTransform = new @finalUT(this) endif endfunc func Init(complex pz, complex pc) ppc = #pixel if !@p_Mtype ppc = @p_seed endif endfunc bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif complex pz = S.pz complex znew float x = m_Dx.Iterate(pz) float y = m_Dy.Iterate(pz) znew = x + flip(y) + ppc if @addT == "c" ppc = finalTransform.Iterate(ppc) elseif @addT == "z" znew = finalTransform.Iterate(znew) endif S.Update(znew, S.pc) return S.bailed endfunc protected: complex ppc Distance m_Dx Distance m_Dy UtilityTransform finalTransform default: rating = NotRecommended title = "Two Distances" int param version caption = "Version" default = 231111 visible = @version < 231111 endparam heading text = "Current version is 231111" visible = @version < 231111 endheading bool param p_std caption = "Standard?" default = true endparam bool param p_Mtype caption = "M-type?" default = true endparam complex param p_seed caption = "Seed for J-type" default = (0.3, 0) visible = !@p_Mtype endparam heading text = "z_new = Xdistance(z)+flip(Ydistance(z))" endheading Distance param distx caption = "Xdistance" default = JLB_DCurve2 endparam Distance param disty caption = "Ydistance" default = JLB_DCurve2 endparam heading caption = "Tweak after each iteration" visible = !@p_std endheading param addT caption = "Type" enum = "none" "c" "z" default = 0 visible = !@p_std endparam UtilityTransform param finalUT caption = "Tweak transform" default = Tweak visible = @addT > 0 && !@p_std selectable = false endparam } class JLB_PolynomialUserTransform(common.ulb:UserTransform) { public: func JLB_PolynomialUserTransform(Generic pparent) UserTransform.UserTransform(pparent) if (@p_poly_type == "Poly") m_a[0] = @p_a0, m_a[1] = @p_a1, m_a[2] = @p_a2, m_a[3] = @p_a3 m_a[4] = @p_a4, m_a[5] = @p_a5, m_a[6] = @p_a6 endif endfunc ; @param pz ; @return the new pz complex func Iterate(complex pz) complex f int i if (@p_poly_type == "Poly") i = @p_degree f = m_a[i] while (i > 0) i = i - 1 f = m_a[i] + pz * f endwhile else;if (@p_poly_type == "Power") f = pz^@p_power endif return f endfunc protected: complex m_a[7] ; coefficients of polynomial default: rating = Recommended title = "Polynomial Transform" int param version caption = "Version (Polynomial_UserTransform)" default = 231111 visible = @version < 231111 endparam heading text = "Current version is 231111" visible = @version < 231111 endheading param p_poly_type caption = "Polynomial type" enum = "Poly" "Power" default = 0 hint = "Poly: polynomial has real powers, degree 6 or less. \ Power: polynomial is a single power, real or complex." endparam int param p_degree caption = "Highest power" default = 3 min = 0 max = 6 visible = (@p_poly_type == 0) endparam complex param p_a0 caption = "Constant coefficient" default = (1,0) visible = (@p_poly_type == 0) endparam complex param p_a1 caption = "Degree 1 coefficient" default = (1,0) visible = (@p_degree >= 1) && (@p_poly_type == 0) endparam complex param p_a2 caption = "Degree 2 coefficient" default = (1,0) visible = (@p_degree >= 2) && (@p_poly_type == 0) endparam complex param p_a3 caption = "Degree 3 coefficient" default = (1,0) visible = (@p_degree >= 3) && (@p_poly_type == 0) endparam complex param p_a4 caption = "Degree 4 coefficient" default = (1,0) visible = (@p_degree >= 4) && (@p_poly_type == 0) endparam complex param p_a5 caption = "Degree 5 coefficient" default = (1,0) visible = (@p_degree >= 5) && (@p_poly_type == 0) endparam complex param p_a6 caption = "Degree 6 coefficient" default = (1,0) visible = (@p_degree >= 6) && (@p_poly_type == 0) endparam complex param p_power caption = "Power" default = (3,0) visible = (@p_poly_type == 1) endparam } class JLB_UT_Function(common.ulb:UserTransform) { public: func JLB_UT_Function(Generic pparent) UserTransform(pparent) m = new @T(this) endfunc complex func Iterate(complex pz) return m.Iterate(pz) endfunc private: FT m default: ;rating = Recommended title = "Function Transform" FT param T caption = "Function" default = JLB_05cos endparam } class FT(common.ulb:Generic) { ; ; FT base class. No title, so only used for a base class. ; Given a complex value, return a complex. ; ; Useful for replacing function calls, so the effect is visible as thumbnails. public: import "common.ulb" func FT(Generic pparent) Generic.Generic(pparent) endfunc complex func Iterate(complex pz) return pz endfunc } class JLB_00ident(FT) { ;yes, this is a duplicate of "33 ident" public: complex func Iterate(complex pz) return pz endfunc default: title = "00 ident" } class JLB_01sin(FT) { public: complex func Iterate(complex pz) return sin(pz) endfunc default: title = "01 sin" } class JLB_02sinh(FT) { public: complex func Iterate(complex pz) return sinh(pz) endfunc default: title = "02 sinh" } class JLB_03asin(FT) { public: complex func Iterate(complex pz) return asin(pz) endfunc default: title = "03 asin" } class JLB_04asinh(FT) { public: complex func Iterate(complex pz) return asinh(pz) endfunc default: title = "04 asinh" } class JLB_05cos(FT) { public: complex func Iterate(complex pz) return cos(pz) endfunc default: title = "05 cos" } class JLB_06cosh(FT) { public: complex func Iterate(complex pz) return cosh(pz) endfunc default: title = "06 cosh" } class JLB_07acos(FT) { public: complex func Iterate(complex pz) return acos(pz) endfunc default: title = "07 acos" } class JLB_08acosh(FT) { public: complex func Iterate(complex pz) return acosh(pz) endfunc default: title = "08 acosh" } class JLB_09tan(FT) { public: complex func Iterate(complex pz) return tan(pz) endfunc default: title = "09 tan" } class JLB_10tanh(FT) { public: complex func Iterate(complex pz) return tanh(pz) endfunc default: title = "10 tanh" } class JLB_11atan(FT) { public: complex func Iterate(complex pz) return atan(pz) endfunc default: title = "11 atan" } class JLB_12atanh(FT) { public: complex func Iterate(complex pz) return atanh(pz) endfunc default: title = "12 atanh" } class JLB_13cotan(FT) { public: complex func Iterate(complex pz) return cotan(pz) endfunc default: title = "13 cotan" } class JLB_14cotanh(FT) { public: complex func Iterate(complex pz) return cotanh(pz) endfunc default: title = "14 cotanh" } class JLB_15acotan(FT) { public: complex func Iterate(complex pz) return atan(1/pz) endfunc default: title = "15 acotan" } class JLB_16acotanh(FT) { public: complex func Iterate(complex pz) return atanh(1/pz) endfunc default: title = "16 acotanh" } class JLB_17sec(FT) { public: complex func Iterate(complex pz) return 1/cos(pz) endfunc default: title = "17 sec" } class JLB_18sech(FT) { public: complex func Iterate(complex pz) return 1/cosh(pz) endfunc default: title = "18 sech" } class JLB_19asec(FT) { public: complex func Iterate(complex pz) return acos(1/pz) endfunc default: title = "19 asec" } class JLB_20asech(FT) { public: complex func Iterate(complex pz) return acosh(1/pz) endfunc default: title = "20 asech" } class JLB_21cosec(FT) { public: complex func Iterate(complex pz) return 1/sin(pz) endfunc default: title = "21 cosec" } class JLB_22cosech(FT) { public: complex func Iterate(complex pz) return 1/sinh(pz) endfunc default: title = "22 cosech" } class JLB_23acosec(FT) { public: complex func Iterate(complex pz) return asin(1/pz) endfunc default: title = "23 acosec" } class JLB_24acosech(FT) { public: complex func Iterate(complex pz) return asinh(1/pz) endfunc default: title = "24 acosech" } class JLB_25sqr(FT) { public: complex func Iterate(complex pz) return sqr(pz) endfunc default: title = "25 sqr" } class JLB_26sqrt(FT) { public: complex func Iterate(complex pz) return sqrt(pz) endfunc default: title = "26 sqrt" } class JLB_27log(FT) { public: complex func Iterate(complex pz) return log(pz) endfunc default: title = "27 log" } class JLB_28exp(FT) { public: complex func Iterate(complex pz) return exp(pz) endfunc default: title = "28 exp" } class JLB_29abs(FT) { public: complex func Iterate(complex pz) return abs(pz) endfunc default: title = "29 abs" } class JLB_30cabs(FT) { public: complex func Iterate(complex pz) return cabs(pz) endfunc default: title = "30 cabs" } class JLB31conj(FT) { public: complex func Iterate(complex pz) return conj(pz) endfunc default: title = "31 conj" } class JLB_32flip(FT) { public: complex func Iterate(complex pz) return flip(pz) endfunc default: title = "32 flip" } class JLB_33capident(FT) { public: complex func Iterate(complex pz) float size = cabs(pz) if size > @cap return pz * @cap / size else return pz endif endfunc default: title = "33 capped ident" float param cap caption = "Cap" default = 1 min = 0 endparam } class JLB_34zero(FT) { public: complex func Iterate(complex pz) return zero(pz) endfunc default: title = "34 zero" } class JLB_35recip(FT) { public: complex func Iterate(complex pz) return recip(pz) endfunc default: title = "35 recip" } class JLB_36ceil(FT) { public: complex func Iterate(complex pz) return ceil(pz) endfunc default: title = "36 ceil" } class JLB_37floor(FT) { public: complex func Iterate(complex pz) return floor(pz) endfunc default: title = "37 floor" } class JLB_38trunc(FT) { public: complex func Iterate(complex pz) return trunc(pz) endfunc default: title = "38 trunc" } class JLB_39trunc*(FT) { public: complex func Iterate(complex pz) float x = real(pz) if x >= 0, x = ceil(x), else, x = floor(x), endif float y = imag(pz) if y >= 0, y = ceil(y), else, y = floor(y), endif return x + flip(y) endfunc default: title = "39 trunc*" } class JLB_40round(FT) { public: complex func Iterate(complex pz) return round(pz) endfunc default: title = "40 round" } class JLB_41power(FT) { public: complex func Iterate(complex pz) return pz^@p endfunc default: title = "41 power" complex param p caption = "Power" default = 2 endparam } class JLB42gd(FT) { public: complex func Iterate(complex pz) return asin(tanh(pz)) endfunc default: title = "42 gd" } class JLB_43agd(FT) { public: complex func Iterate(complex pz) return atanh(sin(pz)) endfunc default: title = "43 agd" } class JLB_44logit(FT) { public: complex func Iterate(complex pz) return log(pz/(1-pz)) endfunc default: title = "44 logit" } class JLB_45expit(FT) { public: complex func Iterate(complex pz) return 1/(1+exp(-pz)) endfunc default: title = "45 expit" } class JLB_46gauss(FT) { public: complex func Iterate(complex pz) return exp(-sqr(pz)) endfunc default: title = "46 gauss" } class JLB_47softplus(FT) { public: complex func Iterate(complex pz) return log(1+exp(pz)) endfunc default: title = "47 softplus" } class JLB_48asoftplus(FT) { public: complex func Iterate(complex pz) return log(exp(pz)-1) endfunc default: title = "48 asoftplus" } class JLB_49softminus(FT) { public: complex func Iterate(complex pz) return pz-log(1+exp(pz)) endfunc default: title = "49 softminus" } class JLB_50asoftminus(FT) { public: complex func Iterate(complex pz) return pz-log(1-exp(pz)) endfunc default: title = "50 asoftminus" } class JLB_51sinc(FT) { public: complex func Iterate(complex pz) if pz == 0 return 1 else return sin(pz)/pz endif endfunc default: title = "51 sinc" } class JLB_D_SD(Distance){ ; A distance class similar to ComplexToFloat2 ; using plug-ins from class SD ; used for critical value in JLB_FX_AboveBelow ; and as defaultin many Distance classes public: func JLB_D_SD(Generic pparent) Distance(pparent) m_SD = new @d_SD(this) endfunc func Init(complex zz) if (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale m_SD.SetFactor(@factor) endif ; if @d_SD == JLB_D19 m_SD.SD_Set(0, 0) ; initial path length = 0 - no path yet ;endif m_SD.SetScale(@scale) m_z0 = zz endfunc float func Iterate(complex zz) float d = m_SD.Iterate(zz) ; m_abs_value is from Distance base class, default is False ; Color by Distance sets m_abs_value to True if m_abs_value d = abs(d) endif if @version < 240209 && @invert && d != 0 d = 1/d endif return d endfunc protected: SD m_SD complex m_z0 ; used by D019 default: title = "Simple distance" rating = Recommended int param version caption = "Version" default = 240209 visible = @version < 240209 endparam heading text = "(Curent is 240209.}" visible = @version < 240209 endheading SD param d_SD caption = "Use for distance" default = JLB_D01 endparam bool param scale caption = "Scale?" default = true visible = @d_SD != JLB_D19 && @d_SD != JLB_D20 endparam float param factor caption = "Scale divisor" default = 1 min = 1e-6 visible = (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale endparam bool param invert ; eliminate, now part of Color by Distance caption = "Use reciprocal?" default = false visible = @version < 240209 endparam } class JLB_D_SD2(Distance){ ; same as JLB_D_SD except skip scaling except for |z| and cabs ; ugly but I don't see a cleaner way public: func JLB_D_SD2(Generic pparent) Distance(pparent) m_SD = new @d_SD(this) endfunc func Init(complex zz) bool do_scale = (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale if do_scale m_SD.SetFactor(@factor) endif m_SD.SD_Set(0, 0) ; initial path length = 0 - no path yet m_SD.SetScale(do_scale) m_z0 = zz endfunc float func Iterate(complex zz) float d = m_SD.Iterate(zz) ; m_abs_value is from Distance base class, default is False ; Color by Distance sets m_abs_value to True if m_abs_value d = abs(d) endif return d endfunc protected: SD m_SD complex m_z0 ; used by D019 default: title = "Simple distance 2" rating = NotRecommended ; but needed for Simple Shapes coloring. int param version caption = "Version" default = 240209 visible = @version < 240209 endparam heading text = "(Curent is 240209.}" visible = @version < 240209 endheading SD param d_SD caption = "Use for distance" default = JLB_D01 endparam bool param scale caption = "Scale?" default = true visible = (@d_SD == JLB_D00 || @d_SD == JLB_D01) endparam float param factor caption = "Scale divisor" default = 1 min = 1e-6 visible = (@d_SD == JLB_D00 || @d_SD == JLB_D01) && @scale endparam } class SD(common.ulb:Generic) { ; ; SD base class. No title, so only used for a base class. ; A variation of sorts on the Distance class ; Given a complex value, return a float. ; Optionally scale the float to 0..1 ; Designed for use in Color by Distance ; ; Useful for seeing the effect visible as thumbnails in Browse mode. ; Note that in the titles of class members, |Real| rmeans to abs(real(pz)), not its square. public: import "common.ulb" func SD(Generic pparent) Generic.Generic(pparent) m_scale = false endfunc func SD_Set(int m, float f) m_iter = m, m_pathlength = f endfunc func SetScale(bool scale) m_scale = scale endfunc func SetFactor(float factor) m_factor = factor endfunc float func Iterate(complex pz) return 1 endfunc protected: int m_iter float m_pathlength ; used by D19 bool m_scale float m_factor ; used by D00 and D01 complex m_z0 } class JLB_D00(SD) { public: float func Iterate(complex pz) float d = |pz| if m_scale d = real(TanhZ.Go(d / m_factor)) ; range 0 to 1 endif return d endfunc default: title = "D00 |z|" } class JLB_D01(SD) { public: float func Iterate(complex pz) float d = cabs(pz) if m_scale d = real(TanhZ.Go(d / m_factor)) ; range 0 to 1 endif return d endfunc default: title = "D01 cabs" } class JLB_D02(SD) { public: float func Iterate(complex pz) float d = real(pz) if m_scale d = d/cabs(pz) ; range -1 to +1 d = (d + 1)/2 endif return d endfunc default: title = "D02 Real" } class JLB_D03(SD) { public: float func Iterate(complex pz) float d = imag(pz) if m_scale d = d/cabs(pz) ; range -1 to +1 d = (d+1)/2 endif return d endfunc default: title = "D03 Imag" } class JLB_D04(SD) { public: float func Iterate(complex pz) float d = abs(real(pz))+abs(imag(pz)) if m_scale d = d/cabs(pz) ; range 1 to sqrt(2) d = (d-1)/(sqrt(2)-1) endif return d endfunc default: title = "D04 |Real|+|Imag|" } class JLB_D05(SD) { public: float func Iterate(complex pz) float d = real(pz)+imag(pz) if m_scale d = d/cabs(pz) ; range -sqrt(2) to sqrt(2) d = (d+sqrt(2))/(2*sqrt(2)) endif return d endfunc default: title = "D05 Real+Imag" } class JLB_D06(SD) { public: float func Iterate(complex pz) float d = abs(real(pz))-abs(imag(pz)) if m_scale d = d/cabs(pz) ; range -1 to 1 d = (d+1)/2 endif return d endfunc default: title = "D06 |Real|-|Imag|" } class JLB_D07(SD) { public: float func Iterate(complex pz) float d = abs(imag(pz))-abs(real(pz)) if m_scale d = d/cabs(pz) ; range -1 to 1 d = (d+1)/2 endif return d endfunc default: title = "D07 |Imag|-|Real|" } class JLB_D08(SD) { public: float func Iterate(complex pz) float d = real(pz)-imag(pz) if m_scale d = d/cabs(pz) ; range -sqrt(2) to sqrt(2) d = (d+sqrt(2))/(2*sqrt(2)) endif return d endfunc default: title = "D08 Real-Imag" } class JLB_D09(SD) { public: float func Iterate(complex pz) float d = imag(pz)-real(pz) if m_scale d = d/cabs(pz) ; range -sqrt(2) to sqrt(2) d = (d+sqrt(2))/(2*sqrt(2)) endif return d endfunc default: title = "D09 Imag-Real" } class JLB_D10(SD) { public: float func Iterate(complex pz) float d = real(pz)*imag(pz) if m_scale d = d/|pz| ; range -0.5 to 0.5 d = (d+0.5) endif return d endfunc default: title = "D10 Real*Imag" } class JLB_D11(SD) { public: float func Iterate(complex pz) float d if !m_scale d = real(pz)/imag(pz) else d = real(pz)/cabs(pz) ; range -1 to +1 d = (d + 1)/2 ; range 0 to 1 float a = 1+abs(imag(pz)) ; range 1 to infinity d = d/a ; range 0 to 1 endif return d endfunc default: title = "D11 Real/Imag" } class JLB_D12(SD) { public: float func Iterate(complex pz) float d if !m_scale d = imag(pz)/real(pz) else d = imag(pz)/cabs(pz) ; range -1 to +1 d = (d + 1)/2 ; range 0 to 1 float a = 1+abs(real(pz)) ; range 1 to infinity d = d/a ; range 0 to 1 endif return d endfunc default: title = "D12 Imag/Real" } ; ; Note: for real x and y, for x^y UF does abs(x)^y ; class JLB_D13(SD) { public: float func Iterate(complex pz) float d if !m_scale d = real(pz)^imag(pz) else d = real(pz)/cabs(pz) ; range -1 to +1 d = (d + 1)/2 ; range 0 to 1 d = d^abs(imag(pz)) endif return d endfunc default: title = "D13 Real^Imag" } class JLB_D14(SD) { public: float func Iterate(complex pz) float d if !m_scale d = imag(pz)^real(pz) else d = imag(pz)/cabs(pz) ; range -1 to +1 d = (d + 1)/2 ; range 0 to 1 d = d^abs(real(pz)) endif return d endfunc default: title = "D14 Imag^Real" } class JLB_D15(SD) { public: float func Iterate(complex pz) float d = MyMath.fmax(abs(real(pz)),abs(imag(pz))) if m_scale d = d/cabs(pz) ; range sqrt(0.5) to 1 d = (d-sqrt(0.5))/(1-sqrt(0.5)) endif return d endfunc default: title = "D15 Max(|Real|,|Imag|)" } class JLB_D16(SD) { public: float func Iterate(complex pz) float d = MyMath.fmax(real(pz),imag(pz)) if m_scale d = d/cabs(pz) ; range 0 to 1 endif return d endfunc default: title = "D16 Max(Real,Imag)" } class JLB_D17(SD) { public: float func Iterate(complex pz) float d = MyMath.fmin(abs(real(pz)),abs(imag(pz))) if m_scale d = d/cabs(pz) ; range 0 to sqrt(0.5) d = d/sqrt(0.5) endif return d endfunc default: title = "D17 Min(|Real|,|Imag|)" } class JLB_D18(SD) { public: float func Iterate(complex pz) float d = MyMath.fmin(real(pz),imag(pz)) if m_scale d = d/cabs(pz) ; range -1 to sqrt(0.5) d = (d+1)/(sqrt(0.5)+1) endif return d endfunc default: title = "D18 Min(Real,Imag)" } class JLB_D19(SD) { ; only mathematically correct if all iterations used for coloring public: float func Iterate(complex pz) if m_pathlength == 0 ; first time pz_old = m_z0 ; set in Init of SD endif float a = cabs(pz-pz_old) ; incremental path length pz_old = pz m_pathlength = m_pathlength + a float d = cabs(pz-m_z0)/m_pathlength ; range 0 to 1, 1 on first entry return d endfunc private: complex pz_old default: title = "D19 Path ratio" ; heading ; text = " (Already scaled to 0..1)" ; endheading } class JLB_D20(SD) { public: float func Iterate(complex pz) float d = atan2(pz)/(2*#pi) ; range -0.5 to +0.5 if @type == 0 if d < 0, d = d + 1, endif ; range 0 to 1 else d = d + 0.5 ; range 0 to 1 endif return d endfunc default: title = "D20 Angle" param type caption = "Type" enum = "1" "2" default = 0 endparam } class JLB_AboveBelowSFormula(SFormula) { ; A Barnsley-like formula as an SFormula, with a non-abrupt transition \ ; possible from the upper formula to the lower formula. public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_AboveBelowSFormula(Generic pparent) SFormula.SFormula(pparent) m_SFormulaA = new @f_SFormulaA(this) m_SFormulaB = new @f_SFormulaB(this) m_SD = new @D(this) zt=(1,0) endfunc func Init(complex pz, complex pc) m_SFormulaA.Init(pz, pc) m_SFormulaB.Init(pz, pc) m_SD.SetScale(false) endfunc ; @param pz ; @param pc ; @return the new pz bool func Iterate(State S) if S.bailed return true endif if S.tooMany return false endif ; save values complex pz = S.pz complex pzold = S.pzold complex pc = S.pc float test if @version < 231202 test = ComplexToFloat2.go(pz, pc, @mode, @absvalue) else test = m_SD.Iterate(pz) endif ; find A and B z-values ; quit if either SFormula says it's done ;if m_SFormulaA.Iterate(S) bool done = m_SFormulaA.Iterate(S) if done return true endif complex zA = S.pz S.pz = pz, S.pzold = pzold, S.pc = pc ; restore ;if m_SFormulaB.Iterate(S) done = m_SFormulaB.Iterate(S) if done return true endif complex zB = S.pz S.pz = pz, S.pzold = pzold, S.pc = pc ; restore S.iters = S.iters - 1 ; if trans == 0, use all of A or B float frac = 0 if @trans == 0 if test >= @crit frac = 1 endif else ; otherwise, do a smooth transition using tanh frac = TSmooth.go((test-@crit)/@trans) endif pz = frac*zA + (1-frac)*zB S.Update(pz, pc) return S.bailed endfunc protected: SFormula m_SFormulaA SFormula m_SFormulaB CalcValue m_CalcValue SD m_SD complex zt default: title = "Above/Below" rating = NotRecommended int param version caption = "Version" default = 231202 visible = @version < 231202 endparam heading text = "(Current is 231202.)" visible = @version < 231202 endheading heading text = "Calculate test value V. Use upper/lower formula if test value\ is above/below V." endheading SD param D caption = "V method" default = JLB_D01 visible = @version >= 231202 endparam param mode caption = "V method" hint = "How to calculate the test value." default = 0 enum = "Mod" "Real" "Imag" "Real+Imag" "Real-Imag" "Real*Imag" \ "Real/Imag" "Imag/Real" "Real^Imag" "Imag^Real" \ "|Real|+|Imag|""|Real|-|Imag|" \ "Max(|Real|,|Imag|)" "Max(Real,Imag)" "Min(|Real|,|Imag|)" "Min(Real,Imag)"\ ;"Angle" visible = @version < 231202 endparam bool param absvalue caption = "absolute(test value)?" default = false visible = @version < 231202 endparam float param crit caption = "V" default = 1 endparam float param trans caption = "Transition parameter" hint = "Smaller values make a steeper transition. For an abrupt transition, use 0." default = 1 min = 0 endparam SFormula param f_SFormulaA caption = "Above formula" default = JLB_FuncSFormula endparam SFormula param f_SFormulaB caption = "Below formula" default = JLB_PowerSFormula endparam } class JLB_UT_Tweak(common.ulb:UserTransform) { public: ;Simport "common.ulb" func JLB_UT_Tweak(Generic pparent) UserTransform(pparent) if @type > 0 m_zT = new @uT(pparent) endif endfunc complex func Iterate(complex pz) complex tmp if @type == "Linear" tmp = @e1 + @e2*pz else tmp = @e1 + @e2*m_zT.Iterate(@a*pz) endif if @kind == "Add" pz = pz + tmp else pz = tmp endif return pz endfunc private: UserTransform m_zT default: title = "Tweak" rating = Recommended param kind caption = "Add or Replace" enum = "Add" "Replace" default = 0 endparam heading caption = "z_new = z + e1 + e2*z" visible = @type == 0 && @kind == 0 endheading heading caption = "z_new = e1 + e2*z" visible = @type == 0 && @kind == 1 endheading heading caption = "z_new = z + e1 + e2*T(a*z)" visible = @type > 0 && @kind == 0 endheading heading caption = "z_new = e1 + e2*T(a*z)" visible = @type > 0 && @kind == 1 endheading param type caption = "Tweak type" enum = "Linear" "Transform" default = 0 endparam UserTransform param uT caption = "Transform" default = JLB_UT_Function visible = @type > 0 endparam complex param e1 caption = "e1" default = (0,0) endparam complex param e2 caption = "e2" default = (0.1,0) endparam complex param a caption = "a" default = 1 visible = @type > 0 endparam } class ZZ(common.ulb:Generic) { ; ; ZZ base class. No title, so only used for a base class. ; Used at the beginning of Distance Coloring 2 ; Useful for seeing the effect visible as thumbnails in Browse mode. public: func ZZ(Generic pparent) Generic.Generic(pparent) endfunc complex func Go(complex zz, complex zzprev, complex pixel) return zz endfunc } class JLB_Z01(ZZ) { public: complex func Go(complex zz, complex zzprev, complex pixel) return zz endfunc default: rating = Recommended title = "Z01 z" } class JLB_Z02(ZZ) { public: complex func Go(complex zz, complex zzprev, complex pixel) return zz-zzprev endfunc default: rating = Recommended title = "Z02 z - zprev" } class JLB_Z03(ZZ) { public: complex func Go(complex zz, complex zzprev, complex pixel) return zz/zzprev endfunc default: rating = Recommended title = "Z03 z / zprev" } class JLB_Z04(ZZ) { public: complex func Go(complex zz, complex zzprev, complex pixel) return zz-pixel endfunc default: rating = Recommended title = "Z04 z - pixel" } class JLB_Z05(ZZ) { public: complex func Go(complex zz, complex zzprev, complex pixel) return zz/pixel endfunc default: rating = Recommended title = "Z05 z / pixel" } class CT(common.ulb:Generic) { ; ; CT base class. No title, so only used for a base class. ; Used in Color by Distance for Coloring Type ; Useful for seeing the effect visible as thumbnails in Browse mode. public: func CT(Generic pparent) Generic.Generic(pparent) endfunc func Accumulate(float d, float &dsum, float &dsumsq, int count) endfunc func Aux(float &dsum, float dmin, float dmax, int &count) endfunc func FinalAverage(float &dsum, float dsumsq, int &count) endfunc } class JLB_C01(CT) { public: func Accumulate(float d, float &dsum, float &dsumsq, int count) if count == 1, dsum = d, endif endfunc func Aux(float &dsum, float dmin, float dmax, int &count) count = 1 endfunc ; func FinalAverage(float &dsum, float dsumsq, int &count) ; endfunc default: rating = Recommended title = "C01 First distance" } class JLB_C02(CT) { public: func Accumulate(float d, float &dsum, float &dsumsq, int count) dsum = d endfunc func Aux(float &dsum, float dmin, float dmax, int &count) count = 1 endfunc ; func FinalAverage(float &dsum, float dsumsq, int &count) ; endfunc default: rating = Recommended title = "C02 Last distance" } class JLB_C03(CT) { public: ; func Accumulate(float d, float &dsum, float &dsumsq, int count) ; endfunc func Aux(float &dsum, float dmin, float dmax, int &count) dsum = dmin count = 1 endfunc ; func FinalAverage(float &dsum, float dsumsq, int &count) ; endfunc default: rating = Recommended title = "C03 Smallest distance" } class JLB_C04(CT) { public: ; func Accumulate(float d, float &dsum, float &dsumsq, int count) ; endfunc func Aux(float &dsum, float dmin, float dmax, int &count) dsum = dmax count = 1 endfunc func FinalAverage(float &dsum, float dsumsq, int &count) count = 1 endfunc default: rating = Recommended title = "C04 Largest distance" } class JLB_C05(CT) { public: ; func Accumulate(float d, float &dsum, float &dsumsq, int count) ; endfunc func Aux(float &dsum, float dmin, float dmax, int &count) dsum = dmax - dmin count = 1 endfunc func FinalAverage(float &dsum, float dsumsq, int &count) count = 1 endfunc default: rating = Recommended title = "C05 Distance range" } class JLB_C06(CT) { public: ; func Accumulate(float d, float &dsum, float &dsumsq, int count) ; endfunc func Aux(float &dsum, float dmin, float dmax, int &count) dsum = dmax / dmin ; dmin guaranteed > 0 count = 1 endfunc func FinalAverage(float &dsum, float dsumsq, int &count) count = 1 endfunc default: rating = Recommended title = "C06 Distance ratio" } class JLB_C07(CT) { public: ; func Accumulate(float d, float &dsum, float &dsumsq, int count) ; endfunc ; func Aux(float &dsum, float dmin, float dmax, int &count) ; endfunc func FinalAverage(float &dsum, float dsumsq, int &count) dsum = count / @scale count = 1 endfunc default: rating = Recommended title = "C07 Iteration count" heading text = "(Ignores any distance method plug-in)" endheading float param scale caption = "Scale" default = 100 min = 1 endparam } class JLB_C08(CT) { public: func Accumulate(float d, float &dsum, float &dsumsq, int count) dsum = dsum + d endfunc ; func Aux(float &dsum, float dmin, float dmax, int &count) ; endfunc ; func FinalAverage(float &dsum, float dsumsq, int &count) ; endfunc default: rating = Recommended title = "C08 Arithmetic average" } class JLB_C09(CT) { ; instead doing nth root of the product, average the logs and then exponentiate public: func Accumulate(float d, float &dsum, float &dsumsq, int count) dsum = dsum + log(d) ; d guaranteed > 0 endfunc ; func Aux(float &dsum, float dmin, float dmax, int &count) ; endfunc func FinalAverage(float &dsum, float dsumsq, int &count) dsum = exp(dsum) endfunc default: rating = Recommended title = "C09 Geometric average" } class JLB_C10(CT) { public: func Accumulate(float d, float &dsum, float &dsumsq, int count) dsum = dsum + 1 / d ; d guaranteed > 0 endfunc ; func Aux(float &dsum, float dmin, float dmax, int &count) ; endfunc func FinalAverage(float &dsum, float dsumsq, int &count) dsum = 1 / dsum endfunc default: rating = Recommended title = "C10 Harmonic average" } class JLB_C11(CT) { ; "Std. Deviation" ignoring -1 public: func Accumulate(float d, float &dsum, float &dsumsq, int count) dsum = dsum + d dsumsq = dsumsq + d * d endfunc ; func Aux(float &dsum, float dmin, float dmax, int &count) ; endfunc func FinalAverage(float &dsum, float dsumsq, int &count) dsum = sqrt(dsumsq - sqr(dsum)) endfunc default: rating = Recommended title = "C11 Variation 1" } class JLB_C12(CT) { ; "Coefficient of Variation" public: func Accumulate(float d, float &dsum, float &dsumsq, int count) dsum = dsum + d dsumsq = dsumsq + d * d endfunc ; func Aux(float &dsum, float dmin, float dmax, int &count) ; endfunc func FinalAverage(float &dsum, float dsumsq, int &count) dsum = sqrt(dsumsq - sqr(dsum)) / dsum endfunc default: rating = Recommended title = "C12 Variation 2" } class JLB_C13(CT) { ; "Fractal Dimension" -- more or less public: func Accumulate(float d, float &dsum, float &dsumsq, int count) dsum = dsum + d dsumsq = dsumsq + d * d endfunc func Aux(float &dsum, float dmin, float dmax, int &count) ddmin = dmin, ddmax = dmax endfunc func FinalAverage(float &dsum, float dsumsq, int &count) if ddmax == ddmin dsum = 0 else dsum = sqrt(dsumsq - sqr(dsum)) / (ddmax - ddmin) endif endfunc private: float ddmin float ddmax default: rating = Recommended title = "C13 Variation 3" } ; class JLB_C16(CT) { ; public: ; func Accumulate(float d, float &dsum, float &dsumsq, int count) ; dsum = d ; endfunc ; func Aux(float &dsum, float dmin, float dmax, int &count) ; count = 1 ; endfunc ; ; func FinalAverage(float &dsum, float dsumsq, int &count) ; ; endfunc ; default: ; rating = Recommended ; title = "C16 Shape" ; } class JLB_DColoring(common.ulb:GradientColoring) { ; Accumulate a sum at each step, or at selected steps, of the orbit. ; Use the result to calculate a color index. ; 231203 added pathlength public: import "common.ulb" func JLB_DColoring(Generic pparent) GradientColoring(pparent) m_dist = new @fdist(this) m_ct = new @fct(this) rotation = 1 min_d_use = 0, max_d_use = 1e30 z_off = (0,0) if !@Basic m_BP1 = new @fBP1(this) m_BP2 = new @fBP2(this) m_ZZ = new @fZZ(this) if @fz > 0 m_zT = new @fUT(this) endif rotation = cos(@angle * #pi/180.0) - flip(sin(@angle * #pi/180.0)) if (@version < 240224 && @UseMinMax ) || \ (@version >= 240224 && @someDist == "Some") min_d_use = @ddmin, max_d_use = @ddmax endif z_off = @offset endif endfunc func Init(complex pz, complex ppixel) GradientColoring.Init(pz, ppixel) m_dist.init(pz) m_dist.SetParams(0, true) ; iteration 0, absolute value distance dsum = dsum_prev = dsumsq = dmin = dmax = 0 z_prev = pz iter = 0 ; iter updated each call to Iterate() iter1 = 1 iter2 = 2000000000 ; largest int is 2147483647 if !@Basic && @some_all > 0 iter1 = @start iter2 = @start + @howmany - 1 endif count = 0 ; count updates only for succesful distance calculation endfunc func Iterate(complex pz) GradientColoring.Iterate(pz) iter = iter + 1 bool okay = (iter >= iter1 && iter <= iter2) if !okay return endif complex zz = pz if !@Basic zz = m_ZZ.Go(pz, z_prev, #pixel) endif z_prev = pz zz = zz * rotation if !@Basic && @fz > 0 zz = m_zT.Iterate(@a*zz) ; zz = m_zT.Iterate(zz) endif m_dist.SetIter(iter) dsum_prev = dsum float d = m_dist.Iterate(zz - z_off) if d < min_d_use || d > max_d_use return endif if !@Basic && d != 0 float t = @b1 if @fBP1 == JLB_BP99, t = @n1, endif d = m_BP1.Go(d, t, @p1) endif count = count + 1 if count == 1 dmin = dmax = d else if d < dmin, dmin = d, endif if d > dmax, dmax = d, endif dsum_prev = dsum endif m_ct.Accumulate(d, dsum, dsumsq, count) endfunc float func ResultIndex(complex pz) ; use the final distance by default if @Basic || (!@Basic && @dofinal) Iterate(pz) endif if @solid && count == 0 m_solid = true ; from base class return 0 endif m_ct.Aux(dsum, dmin, dmax, count) if count > 0 dsum = dsum / count ; average "d" dsumsq = dsumsq / count ; average sqr(d) endif if count > 1 dsum_prev = dsum_prev / (count-1) ; only needed for TIA smoothing endif m_ct.FinalAverage(dsum, dsumsq, count) if @final > 0 && count > 0 ; && !@Basic is possible FinalSmooth( ) endif float d = dsum ; two old versions have been superceded. if @version < 240108 && !@Basic && @recip && d != 0 d = 1/d endif if @version >= 240108 && !@Basic && @version < 240224 && d != 0 if @lastgasp == "Reciprocal" d = 1/d elseif @lastgasp == "Power" d = d^@p_lastgasp endif endif if @version >= 240224 && !@Basic && d != 0 float t = @b2 if @fBP2 == JLB_BP99, t = @n2, endif d = m_BP2.Go(d, t, @p2) endif return d endfunc func FinalSmooth( ) if @final == 1 float il = 1/log(@power) float lp = log(log(@bailout)) ; 0.05 to agree with original Smooth (Mandelbrot) ; dsum = 0.05 * (count - 1 + il*lp - il*log(log(abs(dsum)))) float d = 0.05 * (iter + il*lp - il*log(log(dsum))) dsum = d elseif @final == 2 float il = 1/log(@power) ; as in Triangle in Standard.ulb float lp = log(log(@bailout)/2.0) float fac = il * lp - il*log(log(cabs(#z))) ;dsum = dsum * count / (count+1) ; to agree with original ;dsum_prev = dsum_prev * (count-1) / count float d = cabs(dsum_prev + (dsum - dsum_prev) * (fac + 1)) dsum = d endif endfunc private: complex rotation Distance m_dist CT m_ct ZZ m_ZZ BP m_BP1 BP m_BP2 UserTransform m_zT float dsum float dsum_prev ; used by TIA smoothing float dsumsq ; used by Variations 1, 2, 3 float dmin, float dmax float min_d_use, float max_d_use complex z_off complex z_prev int count int iter, int iter1, int iter2 default: title = "Color by Distance" rating = Recommended int param version caption = "Version" default = 240224 visible = @version < 240224 endparam heading text = "(Curent is 240224.}" visible = @version < 240224 endheading bool param solid caption = "Use solid background?" default = true endparam bool param Basic caption = "Basic version?" default = true endparam heading caption = "Accumulation phase" endheading bool param dofinal caption = "Use final distance?" default = true visible =!@Basic endparam ZZ param fZZ caption = "Use for zz " visible = !@Basic endparam float param angle caption = "Rotate zz by " default = 0 visible = !@Basic endparam heading caption = "Use zz or T(a*zz)" ; caption = "Use zz or T(zz)" visible = !@Basic endheading param fz caption = "Which?" enum = "zz" "T(a*zz)" ; enum = "zz" "T(zz)" default = 0 visible = !@Basic endparam heading visible = !@Basic endheading complex param a caption = "a" default = 1 visible = !@Basic && @fz > 0 endparam UserTransform param fUT caption = "Transform" default = JLB_UT_Function visible = !@Basic && @fz > 0 endparam complex param offset caption = "ZZ Offset" default = (0,0) visible = !@Basic endparam heading visible = !@Basic endheading heading caption = "Distance plug-in" endheading Distance param fdist caption = "Plug-in" default = JLB_D_SD visible = @fct != JLB_C07 endparam heading caption = "End of distance plug-in" endheading BP param fBP1 caption = "Distance adjustment" visible = !@Basic default = JLB_BP00 endparam float param b1 caption = "Factor b" default = 1 min = 0 visible = !@Basic && @fBP1 != JLB_BP00 && @fBP1 != JLB_BP99 endparam float param p1 caption = "Power p" default = 1 visible = !@Basic && @fBP1 != JLB_BP00 && @fBP1 != JLB_BP99 endparam int param n1 caption = "Number of values" default = 4 min = 2 visible = !@Basic && @fBP1 == JLB_BP99 endparam heading visible = !@Basic endheading param someDist caption = "Use all / some distances?" enum = "All" "Some" default = 0 visible = !@Basic && @version >= 240224 endparam bool param UseMinMax caption = "Min/max distances?" default = false visible = !@Basic && @version < 240224 endparam float param ddmin caption = "Minimum distance" default = 0 min = 0 visible = !@Basic && ( (@version < 240224 && @UseMinMax) || \ (@version >= 240224 && @someDist == "Some") ) endparam float param ddmax caption = "Maximum distance" default = 100 min = 0 visible = !@Basic && ( (@version < 240224 && @UseMinMax) || \ (@version >= 240224 && @someDist == "Some") ) endparam heading visible = !@Basic endheading param some_all enum = " All" " Some" ;" Some + More" default = 0 caption = "Use all / some iterations?" visible = !@Basic endparam int param start caption = "Starting with iteration?" default = 4 min = 1 visible = !@Basic && @some_all > 0 endparam int param howmany caption = "How many to use?" default = 100 min = 1 visible = !@Basic && @some_all > 0 endparam heading caption = "Final phase of coloring" endheading CT param fct caption = "How to color" default = JLB_C05 endparam heading endheading param final caption = "Final smooth" enum = "None" "Mandelbrot type" "TIA type" default = 0 ; visible = !@Basic ; possible endparam float param power caption = "Smoothing exponent" default = 2.0 visible = @final > 0 ; && !@Basic is possible endparam float param bailout caption = "Smoothing bailout" default = 100 min = 1 visible = @final > 0 ; && !@Basic is possible endparam heading visible = !@Basic endheading bool param recip caption = "Use reciprocal?" default = false ;hint = "Color based on, for example, 1/Mod(z) instead of Mod(z)." visible = @version < 240108 && !@Basic endparam param lastgasp caption = "Last gasp change" enum = "None" "Reciprocal" "Power" default = 0 visible = @version >= 240108 && !@Basic endparam float param p_lastgasp caption = "Power" default = 1 visible = @version >= 240108 && !@Basic && @lastgasp == 2 endparam BP param fBP2 caption = "Final adjustment" visible = !@Basic && @version >= 240224 default = JLB_BP00 endparam float param b2 caption = "Factor b" default = 1 min = 0 visible = !@Basic && @fBP2 != JLB_BP00 && @fBP2 != JLB_BP99 endparam float param p2 caption = "Power p" default = 2 visible = !@Basic && @version >= 240224 && @fBP2 != JLB_BP00 && @fBP2 != JLB_BP99 endparam int param n2 caption = "Number of values" default = 4 min = 2 visible = !@Basic && @version >= 240224 && @fBP2 == JLB_BP99 endparam } class JLB_UT_Basic(common.ulb:UserTransform) { public: func JLB_UT_Basic(Generic pparent) UserTransform.UserTransform(pparent) m_T = new @f_T(this) endfunc func Init(complex pz) m_T.Init(pz) endfunc complex func Iterate(complex pz) return @a1 + @a2*m_T.Iterate(@a3*pz) endfunc private: UserTransform m_T default: rating = Recommended title = "Basic Transform" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "znew = a1+a2*f(a3*z)" endheading complex param a1 caption = "a1" default = (0,0) endparam complex param a2 caption = "a2" default = (1,0) endparam complex param a3 caption = "a3" default = (1,0) endparam UserTransform param f_T default = JLB_UT_Function selectable = false endparam } class JLB_UT_Moebius(common.ulb:UserTransform) { public: func JLB_UT_Moebius(Generic pparent) UserTransform.UserTransform(pparent) if @fz > 0 m_t = new @fT(this) endif endfunc complex func Iterate(complex pz) complex zz = pz if @fz > 0 zz = m_t.Iterate(@ab*zz) endif return (@a0 + @a1*zz) / (@b0 + @b1*zz) endfunc private: UserTransform m_t default: rating = Recommended title = "Moebius Transform" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading caption = "z_new = (a0+a1*zz)/(b0+b1*zz)" endheading ; heading ; text = "zz = z or T(ab*z)" ; endheading param fz caption = "zz?" enum = "zz = z" "zz = T(ab*z)" default = 0 endparam UserTransform param fT caption = "Transform" default = JLB_UT_Function visible = @fz > 0 endparam complex param a0 caption = "a0" default = (1,0) endparam complex param a1 caption = "a1" default = (1,0) endparam complex param b0 caption = "b0" default = (1,0) endparam complex param b1 caption = "b1" default = (-1,0) endparam complex param ab caption = "ab" default = (1,0) visible = @fz > 0 endparam } class JLB_UT_Linear(common.ulb:UserTransform) { ; simplified version of Moebius! public: func JLB_UT_Linear(Generic pparent) UserTransform.UserTransform(pparent) if @fz > 0 m_t = new @fT(this) endif endfunc complex func Iterate(complex pz) complex zz = pz if @fz > 0 zz = m_t.Iterate(@b*zz) endif return @a + @b * zz endfunc private: UserTransform m_t default: rating = Recommended title = "Linear Transform" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading caption = "z_new = (a+b*zz)" endheading param fz caption = "zz?" enum = "zz = z" "zz = T(ab*z)" default = 0 endparam UserTransform param fT caption = "Transform" default = JLB_UT_Function visible = @fz > 0 endparam complex param a caption = "a" default = (1,0) endparam complex param b caption = "b" default = (1,0) endparam } ; combine two complex values in various ways class CombineXY { public: func CombineXY() endfunc static complex func go(complex zx, complex zy, int i) float x, float y if i == 0, x = +real(zx), y = +real(zy), elseif i == 1, x = +real(zx), y = -real(zy), elseif i == 2, x = +real(zx), y = +imag(zy), elseif i == 3, x = +real(zx), y = -imag(zy), elseif i == 4, x = -real(zx), y = +real(zy), elseif i == 5, x = -real(zx), y = -real(zy), elseif i == 6, x = -real(zx), y = +imag(zy), elseif i == 7, x = -real(zx), y = -imag(zy), elseif i == 0, x = +real(zx), y = +real(zy), elseif i == 9, x = +imag(zx), y = -real(zy), elseif i == 10, x = +imag(zx), y = +imag(zy), elseif i == 11, x = +imag(zx), y = -imag(zy), elseif i == 12, x = -imag(zx), y = +real(zy), elseif i == 13, x = -imag(zx), y = -real(zy), elseif i == 14, x = -imag(zx), y = +imag(zy), else, x = -imag(zx), y = -imag(zy), endif return x + flip(y) endfunc } class JLB_UT_XY(common.ulb:UserTransform) { public: func JLB_UT_XY(Generic pparent) UserTransform(pparent) m_fx = new @f_Tx(this) m_fy = new @f_Ty(this) m_PM = new @f_PM(this) endfunc complex func Iterate(complex pz) complex zx = m_fx.Iterate(pz) complex zy = m_fy.Iterate(pz) complex znew = m_PM.go(zx, zy) if @how == "Add" znew = pz + @step * znew endif return znew endfunc private: UserTransform m_fx UserTransform m_fy PM m_PM default: rating = Recommended title = "X and Y Transforms" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "znew: +-r/i(Tx), +-r/i(Ty)" endheading UserTransform param f_Tx caption = "Tx" default = JLB_UT_Function endparam UserTransform param f_Ty caption = "Ty" default = JLB_UT_Function endparam heading caption = "Combining" endheading PM param f_PM caption = "dx dy" default = JLB_PRPI endparam param how caption = "How?" enum = "Add" "Replace" default = 0 endparam param step caption = "Step_size" default = 0.1 visible = @how == 0 endparam } class JLB_Switch(common.ulb:Formula) { public: import "Standard.ulb" ; for the default plug-in, Standard Mandelbrot func JLB_Switch(Generic pparent) Formula.Formula(pparent) if @hasbail == "Yes" m_Formula = new @f_Formula (this) else m_FormulaX = new @f_FormulaX(this) m_BB = new @f_BB(this) endif if !@Basic if @pre , m_pre = new @preUT(this) , endif if @post, m_post = new @postUT(this), endif ; if @change_c && @hasbail == "No", m_chg = new @changeUT(this), endif endif endfunc complex func Init(complex pz) ; over-rides the func in Formula Formula.Init(pz) if @hasbail == "Yes" pz = m_Formula.Init(pz) else pz = m_FormulaX.Init(pz) endif pzold = pz return pz endfunc complex func Iterate(complex pz) ; over-rides the func in Formula pzold = pz if !@Basic && @pre && m_iterations == 0 ; m_iterations from Formula pz = m_pre.Iterate(pz) endif m_iterations = m_iterations + 1 if @hasbail == "Yes" pz = m_Formula.Iterate(pz) else pz = m_FormulaX.Iterate(pz) endif if !@Basic && @post pz = m_post.Iterate(pz) endif return pz endfunc bool func IsBailedOut(complex pz) ; over-rides the func in Formula if @hasbail == "Yes" return m_Formula.IsBailedOut(pz) endif ; handle bailout here if (@how == "Divergent" || @how == "Either") && m_BB.Go(pz, @Dbailout) ; if @Diverging && m_BB.Go(pz, @Dbailout) return true endif if (@how == "Convergent" || @how == "Either") && cabs(pz - pzold) < @Cbailout ; if @Converging && cabs(pz - pzold) < @Cbailout return true endif return false endfunc protected: Formula m_Formula FormulaX m_FormulaX UserTransform m_post UserTransform m_pre ; UserTransform m_chg BB m_BB complex pzold default: title = "Switch Formula" rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "Does Formula do its own bailout test?" endheading param hasbail caption = " " enum = "Yes" "No" default = 1 endparam param how caption = "Bailout type" enum = "Divergent" "Convergent" "Either" default = 0 visible = @hasbail == 1 endparam BB param f_BB caption = "Divergent bailout method" default = JLB_B00 visible = @hasbail > 0 && (@how == 0 || @how == 2) endparam float param Dbailout caption = "Divergent bailout value" default = 100 min = 1 visible = @hasbail > 0 && (@how == 0 || @how == 2) endparam float param Cbailout caption = "Convergent bailout value" default = 1e-4 visible = @hasbail > 0 && (@how == 1 || @how == 2) endparam bool param Basic caption = "Basic version of Switch Formula?" default = true endparam bool param pre caption = "Tweak z before first iteration?" default = false visible = !@Basic endparam UserTransform param preUT caption = "Tweak transform" default = JLB_UT_Tweak visible = @pre && !@Basic selectable = false endparam heading caption = "End of pre-tweaking" visible = !@Basic && @pre endheading Formula param f_Formula caption = "Formula" default = Standard_Mandelbrot visible = @hasbail == 0 endparam FormulaX param f_FormulaX caption = "FormulaX" default = JLB_FX_Mandelbrot visible = @hasbail == 1 endparam heading visible = !@Basic endheading bool param post caption = "Tweak z after each iteration?" default = false visible = !@Basic endparam UserTransform param postUT caption = "Tweak transform" default = JLB_UT_Tweak visible = @post && !@Basic selectable = false endparam heading visible = @hasbail > 0 endheading complex param p_power ; not used; over-rides Formula visible = false endparam } class BB(common.ulb:Generic) { ; BB base class. No title, so only used for a base class. ; Given a complex and a float, return a bool. ; Return true if some functin of the complex is larger than the float. ; Designed to be used for bailout calculation, so the effect is visible as thumbnails. public: import "common.ulb" func BB(Generic pparent) Generic.Generic(pparent) endfunc bool func Go(complex pz, float v) return false endfunc } class JLB_B00(BB) { public: bool func Go(complex pz, float v) return |pz| > v endfunc default: title = "B00 |z|" } class JLB_B01(BB) { public: bool func Go(complex pz, float v) return cabs(pz) > v endfunc default: title = "B01 cabs" } class JLB_B02(BB) { public: bool func Go(complex pz, float v) return abs(real(pz)) > v endfunc default: title = "B02 |Real|" } class JLB_B03(BB) { public: bool func Go(complex pz, float v) return abs(imag(pz)) > v endfunc default: title = "B03 |Imag|" } class JLB_B04(BB) { public: bool func Go(complex pz, float v) return (abs(real(pz)) > v) && (abs(imag(pz)) > v) endfunc default: title = "B04 |Real| and |Imag|" } class JLB_B05(BB) { public: bool func Go(complex pz, float v) return (abs(real(pz)) > v) || (abs(imag(pz)) > v) endfunc default: title = "B05 |Real| or |Imag|" } class JLB_B06(BB) { public: bool func Go(complex pz, float v) return abs(real(pz)) + abs(imag(pz)) > v endfunc default: title = "B06 |Real|+|Imag|" } class JLB_B07(BB) { public: bool func Go(complex pz, float v) return abs(real(pz) * imag(pz)) > v*v endfunc default: title = "B07 |Real*Imag|" } class JLB_B08(BB) { public: bool func Go(complex pz, float v) return MyMath.fmax(abs(real(pz)), abs(imag(pz))) > v endfunc default: title = "B08 max(|Real|,|Imag|)" } class JLB_B09(BB) { public: bool func Go(complex pz, float v) return MyMath.fmin(abs(real(pz)), abs(imag(pz))) > v endfunc default: title = "B09 min(|Real|,|Imag|)" } class FormulaX(common.ulb:Formula) { ; a variation on Formula. Has the "c" value, hides p-power public: complex func Init(complex pz) Formula.Init(pz) m_c = #pixel if !@p_Mtype, m_c = @p_seed, endif return pz endfunc complex func GetC( ) ; in case a plug-in wants it return m_c endfunc func SetC(complex c) ; in case a plug-in wants it m_c = c endfunc protected: complex m_c default: bool param p_Mtype caption = "M-type?" default = true endparam complex param p_seed caption = "Seed for J-type" default = (1.0,-0.5) visible = !@p_Mtype endparam complex param p_power visible = false ; hide it! endparam } class JLB_FX_Mandelbrot(FormulaX) { public: import "common.ulb" import "jlb.ulb" func JLB_FX_Mandelbrot(Generic pparent) Formula(pparent) endfunc complex func Init(complex pz) FormulaX.Init(pz) return pz endfunc complex func Iterate(complex pz) complex znew if (@Basic) znew = pz^2 + m_c else znew = pz^@p + m_c endif m_iterations = m_iterations + 1 return znew endfunc default: title = "Mandelbrot" rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading bool param Basic caption = "Basic Mandelbrot?" default = true endparam heading caption = "z_new = z^2 + c" visible = @Basic endheading heading caption = "z_new = z^p + c" ; F(z) or T(z) ? visible = !@Basic endheading complex param p caption = "p" default = (2,0) visible = !@Basic endparam } class JLB_FX_Lambda(FormulaX) { public: import "common.ulb" func JLB_FX_Lambda(Generic pparent) Formula(pparent) if !@Basic && @version >= 240205 m_T = new @T(this) endif endfunc complex func Init(complex pz) FormulaX.Init(pz) return pz endfunc complex func Iterate(complex pz) complex znew if (@Basic) znew = m_c * pz * (1 - pz) else complex zz = pz if @version >= 240205 zz = m_T.Iterate(pz) endif znew = m_c * zz^@p * (@a - zz)^@q endif return znew endfunc protected: UserTransform m_T default: title = "Lambda" ;rating = Recommended int param version caption = "Version" default = 240205 visible = @version < 240205 endparam heading text = "(Current is 240205.}" visible = @version < 240205 endheading bool param Basic caption = "Basic Lambda?" default = true endparam heading caption = "z_new = c * z * (1 - z)" visible = @Basic endheading heading caption = "z_new = c * z^p * (a - z)^q" visible = !@Basic && @version < 240205 endheading heading caption = "z_new = c * T(z)^p * (a - T(z))^q" visible = !@Basic && @version >= 240205 endheading UserTransform param T caption = "T" default = JLB_UT_Function visible = !@Basic endparam complex param p caption = "p" default = 1 visible = !@Basic endparam complex param a caption = "a" default = 1 visible = !@Basic endparam complex param q caption = "q" default = 1 visible = !@Basic endparam } class JLB_FX_Nova(FormulaX) { public: func JLB_FX_Nova(Generic pparent) Formula(pparent) endfunc complex func Init(complex pz) FormulaX.Init(pz) return pz endfunc complex func Iterate(complex pz) complex znew ;if (@Basic) znew = pz - @step * (pz^3-1) / (3 * pz^2) + m_c ;endif return znew endfunc protected: default: title = "Nova" ;rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading ; bool param Basic ; caption = "Basic Nova?" ; default = true ; endparam heading caption = "z_new = z - step * (z^3-1) / (3*z*2) + c" ;visible = @Basic endheading complex param step caption = "Step size" default = (1,0) ; hint = "This can be used to slow down the convergence of \ ; the formula." endparam ; heading ; caption = "z_new = c * z^p * (a - z)^q" ; visible = !@Basic ; endheading ; complex param p ; caption = "p" ; default = 1 ; visible = !@Basic ; endparam ; complex param a ; caption = "a" ; default = 1 ; visible = !@Basic ; endparam ; complex param q ; caption = "q" ; default = 1 ; visible = !@Basic ; endparam } class JLB_FX_AboveBelow(FormulaX) { public: import "common.ulb" func JLB_FX_AboveBelow(Generic pparent) Formula(pparent) if @sw m_1 = new @f_FXbelow(this) m_2 = new @f_FXabove(this) else m_1 = new @f_FXabove(this) m_2 = new @f_FXbelow(this) endif type = 0 ; SD if @version < 240207 && @mode == "Iteration" type = 2 endif if @version >= 240207 if @mode2 == "Distance" type = 1 elseif @mode2 == "Iteration" type = 2 endif endif if type == 0 m_SD = new @f_SD(this) elseif type == 1 m_D = new @f_D(this) endif endfunc complex func Init(complex pz) if type == 0 m_SD.SetScale(false) elseif type == 1 m_D.Init(pz) ;m_abs_value set to False endif m_1.Init(pz) m_2.Init(pz) count = 0 return pz endfunc complex func Iterate(complex pz) float test = count count = count + 1 if type == 0 test = m_SD.Iterate(pz) elseif type == 1 test = m_D.Iterate(pz) endif if @trans == 0 ; abrupt transition if test >= @crit return m_1.Iterate(pz) else return m_2.Iterate(pz) endif endif ; smooth transition using tanh float frac = TSmooth.go((test-@crit)/@trans) complex zabove = m_1.Iterate(pz) complex zbelow = m_2.Iterate(pz) complex znew = frac * zabove + (1-frac) * zbelow return znew endfunc private: FormulaX m_1 FormulaX m_2 SD m_SD Distance m_D int count int type ; 0 for SD, 1 for D, 2 for iteration default: title = "AboveBelow" ;rating = Recommended int param version caption = "Version" default = 240207 visible = @version < 240207 endparam heading text = "(Current is 240207.}" visible = @version < 240207 endheading ; heading ; endheading float param crit caption = "Critical value" default = 1 endparam bool param sw caption = "Switch Above and Below formulas" default = false endparam param mode caption = "Use for test value" enum = "Method" "Iteration" default = 0 visible = @version < 240207 endparam param mode2 caption = "Use for test value" enum = "Simple" "Distance" "Iteration" default = 0 visible = @version >= 240207 endparam SD param f_SD caption = "Method" default = JLB_D02 visible = (@version < 240207 && @mode == 0) || \ (@version >= 240207 && @mode2 == 0) endparam Distance param f_D caption = "Distance Method" default = JLB_DCircle2 visible = @version >= 240207 && @mode2 == 1 endparam float param trans caption = "Transition parameter" default = 0 ;min = 0 endparam heading caption = "End of test value section" endheading FormulaX param f_FXabove caption = "Above formula" default = JLB_FX_Mandelbrot endparam FormulaX param f_FXbelow caption = "Below formula" default = JLB_FX_Poly endparam bool param p_Mtype visible = false ; hide, as the two FXs have their own endparam complex param p_seed visible = false ; hide, as the two FXs have their own endparam } class JLB_FX_Gnarly(FormulaX) { ; use one FX for the new x, another for the new y ; 2402 -- needs work public: import "common.ulb" func JLB_FX_Gnarly(Generic pparent) Formula(pparent) m_FXx = new @f_FXx(this) m_FXy = new @f_FXy(this) m_PM = new @f_PM(this) endfunc complex func Init(complex pz) m_FXx.Init(pz) m_FXy.Init(pz) return pz endfunc complex func Iterate(complex pz) complex zx = m_FXx.Iterate(pz) complex zy = m_FXy.Iterate(pz) ;znew = CombineXY.go(zx, zy, @xytype) complex znew = m_PM.go(zx, zy) if @how == "Add" znew = pz + @step * znew endif return znew endfunc private: FormulaX m_FXx FormulaX m_FXy PM m_PM default: title = "Gnarly" ;rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading ; heading ; endheading FormulaX param f_FXx caption = "x formula" default = JLB_FX_Mandelbrot endparam FormulaX param f_FXy caption = "y formula" default = JLB_FX_Lambda endparam heading caption = "Combining" endheading PM param f_PM caption = "dx dy" default = JLB_PRPI endparam param how caption = "How?" enum = "Add" "Replace" default = 0 endparam param step caption = "Step_size" default = 0.1 visible = @how == 0 endparam bool param p_Mtype visible = false ; hide, as the two FXs have their own endparam complex param p_seed visible = false ; hide, as the two FXs have their own endparam } class JLB_FX_Combo(FormulaX) { ; This does two or three FormulaXs and combines them ; with one of the operators +, -, *, /, ^, ( ). ; The latter means use as argument to the previous function. ; This allows formulas such as z = (f1 + f2)/f3 + c ; or z = f1(f2(f3())) + c public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_FX_Combo(Generic pparent) Formula.Formula(pparent) m_FX1 = new @f_FX1(this) m_FX2 = new @f_FX2(this) if @how ==1 || @how == 2 || @how == 5 m_FX3 = new @f_FX3(this) endif endfunc complex func Init(complex pz) m_FX1.Init(pz) m_FX2.Init(pz) if @how ==1 || @how == 2 || @how == 5 m_FX3.Init(pz) endif return pz endfunc ; @param pz ; @param pc ; @return new pz complex func Iterate(complex pz) complex z1 complex z2 complex z3 if @how == 3 ;"f1 only" z1 = m_FX1.Iterate(pz) elseif @how == 4 ;"f2 only" z1 = m_FX2.Iterate(pz) elseif @how == 5 ;"f3 only" z1 = m_FX3.Iterate(pz) elseif @how == 0 ;"f1 op f2" z2 = m_FX2.Iterate(pz) if @op1a == "( )" ; f1(f2(pz)) z1 = m_FX1.Iterate(z2) else ; f1(pz) op1 f2(pz) z1 = m_FX1.Iterate(pz) z1 = Combine.go(z1, @op1a, z2) endif elseif @how == 1 ;"f1 op1 (f2 op2 f3)" if @op2a == "( )" ; f1(pz) op1 f2(f3(pz)) z3 = m_FX3.Iterate(pz) z2 = m_FX2.Iterate(z3) if @op1 == "( )" ; f1(f2(f3(pz))) z1 = m_FX1.Iterate(z2) else ; f1(pz) op1 f2(f3(pz)) z1 = m_FX1.Iterate(pz) z1 = Combine.go(z1, @op1, z2) endif else ; op2 != () z3 = m_FX3.Iterate(pz) z2 = m_FX2.Iterate(pz) z2 = Combine.go(z2, @op2a, z3) if @op1 == "( )" ; f1(f2(pz) op2a f3(pz)) z1 = m_FX1.Iterate(z2) else z1 = m_FX1.Iterate(pz) z1 = Combine.go(z1, @op1, z2) endif endif else;if @how == 2 ;"(f1 op1 f2) op2 f3" ; op2 of "()" not allowed with this ordering z2 = m_FX2.Iterate(pz) if @op1 == "( )" ; (f1(f2(pz))) op2b f3(pz) z1 = m_FX1.Iterate(z2) else z1 = m_FX1.Iterate(pz) z1 = Combine.go(z1, @op1, z2) endif z3 = m_FX3.Iterate(pz) z1 = Combine.go(z1, @op2b, z3) endif complex znew = z1 return znew endfunc protected: FormulaX m_FX1 FormulaX m_FX2 FormulaX m_FX3 default: rating = Recommended title = "Combo FormulaX" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading param how caption = "Combos" default = 0 enum = "f1 op f2" "f1 op1 (f2 op2 f3)" "(f1 op1 f2) op2 f3" \ "f1 only" "f2 only" "f3 only" endparam param op1 caption = "Op1" enum = "+" "-" "*" "/" "^" "( )" default = 0 visible = @how ==1 || @how == 2 endparam param op1a caption = "Op" enum = "+" "-" "*" "/" "^" "( )" default = 2 visible = @how == 0 endparam param op2a caption = "Op2" enum = "+" "-" "*" "/" "^" "( )" default = 2 visible = (@how == 1) endparam param op2b caption = "Op2" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default = 2 visible = (@how == 2) endparam heading caption = "f1" visible = @how < 4 endheading FormulaX param f_FX1 caption = "Formula 1" default = JLB_FX_Mandelbrot visible = @how < 4 endparam heading endheading ; heading ; endheading heading caption = "f2" visible = @how < 3 || @how == 4 endheading FormulaX param f_FX2 default = JLB_FX_Poly caption = "Formula 2" visible = @how < 3 || @how == 4 endparam heading caption = "f3" visible = @how ==1 || @how == 2 || @how == 5 endheading FormulaX param f_FX3 default = JLB_FX_Mandelbrot caption = "Formula 3" visible = @how ==1 || @how == 2 || @how == 5 endparam ; hide these bool param p_Mtype visible = false endparam complex param p_seed visible = false endparam } class JLB_FX_Transform(FormulaX) { public: import "common.ulb" func JLB_FX_Transform(Generic pparent) Formula(pparent) m_UT = new @f_UT(this) endfunc complex func Init(complex pz) FormulaX.Init(pz) m_UT.Init(pz) return pz endfunc complex func Iterate(complex pz) complex znew = (m_UT.Iterate(pz))^@p + m_c return znew endfunc protected: UserTransform m_UT default: title = "Transform" rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "z_new = T(z)^p + c" ;visible = @Basic endheading float param p caption = "p" default = 2 endparam UserTransform param f_UT caption = "Transform T" default = JLB_PolynomialUserTransform endparam } class JLB_FX_ComboUT(FormulaX) { ; This does two or three UTs and combines them ; with one of the operators +, -, *, /, ^, ( ). ; The latter means use as argument to the previous function. ; This allows formulas such as z = (T1 + T2)/T3 + c ; or z = T1(T2(T3())) + c public: import "common.ulb" ; @param pparent the parent, generally "this" for the parent, or zero func JLB_FX_ComboUT(Generic pparent) Formula.Formula(pparent) m_UT1 = new @f_UT1(this) m_UT2 = new @f_UT2(this) if @how ==1 || @how == 2 || @how == 5 m_UT3 = new @f_UT3(this) endif endfunc complex func Init(complex pz) FormulaX.Init(pz) m_UT1.Init(pz) m_UT2.Init(pz) if @how ==1 || @how == 2 || @how == 5 m_UT3.Init(pz) endif return pz endfunc ; @param pz ; @param pc ; @return new pz complex func Iterate(complex pz) complex z1 complex z2 complex z3 if @how == 3 ;"T1 only" z1 = m_UT1.Iterate(pz) elseif @how == 4 ;"T2 only" z1 = m_UT2.Iterate(pz) elseif @how == 5 ;"T3 only" z1 = m_UT3.Iterate(pz) elseif @how == 0 ;"T1 op T2" z2 = m_UT2.Iterate(pz) if @op1a == "( )" ; T1(T2(pz)) z1 = m_UT1.Iterate(z2) else ; T1(pz) op1 T2(pz) z1 = m_UT1.Iterate(pz) z1 = Combine.go(z1, @op1a, z2) endif elseif @how == 1 ;"T1 op1 (T2 op2 T3)" if @op2a == "( )" ; T1(pz) op1 T2(T3(pz)) z3 = m_UT3.Iterate(pz) z2 = m_UT2.Iterate(z3) if @op1 == "( )" ; T1(T2(T3(pz))) z1 = m_UT1.Iterate(z2) else ; T1(pz) op1 T2(T3(pz)) z1 = m_UT1.Iterate(pz) z1 = Combine.go(z1, @op1, z2) endif else ; op2 != () z3 = m_UT3.Iterate(pz) z2 = m_UT2.Iterate(pz) z2 = Combine.go(z2, @op2a, z3) if @op1 == "( )" ; T1(T2(pz) op2a T3(pz)) z1 = m_UT1.Iterate(z2) else z1 = m_UT1.Iterate(pz) z1 = Combine.go(z1, @op1, z2) endif endif else;if @how == 2 ;"(T1 op1 T2) op2 T3" ; op2 of "()" not allowed with this ordering z2 = m_UT2.Iterate(pz) if @op1 == "( )" ; (T1(T2(pz))) op2b T3(pz) z1 = m_UT1.Iterate(z2) else z1 = m_UT1.Iterate(pz) z1 = Combine.go(z1, @op1, z2) endif z3 = m_UT3.Iterate(pz) z1 = Combine.go(z1, @op2b, z3) endif if @version >= 240130 z1 = z1 + m_c endif return z1 endfunc protected: UserTransform m_UT1 UserTransform m_UT2 UserTransform m_UT3 default: rating = Recommended title = "Combo UT Formula" int param version caption = "Version" default = 240130 visible = @version < 240130 endparam heading text = "(Current is 240130.}" visible = @version < 240130 endheading param how caption = "Combos" default = 0 enum = "T1 op T2 + c" "T1 op1 (T2 op2 T3) + c" "(T1 op1 T2) op2 T3 + c" \ "T1 + c only" "T2 + c only" "T3 + c only" endparam param op1 caption = "Op1" enum = "+" "-" "*" "/" "^" "( )" default = 0 visible = @how ==1 || @how == 2 endparam param op1a caption = "Op" enum = "+" "-" "*" "/" "^" "( )" default = 2 visible = @how == 0 endparam param op2a caption = "Op2" enum = "+" "-" "*" "/" "^" "( )" default = 2 visible = (@how == 1) endparam param op2b caption = "Op2" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default = 2 visible = (@how == 2) endparam heading caption = "T1" visible = @how < 4 endheading UserTransform param f_UT1 caption = "Transform 1" default = JLB_UT_Basic visible = @how < 4 endparam heading endheading ; heading ; endheading heading caption = "T2" visible = @how < 3 || @how == 4 endheading UserTransform param f_UT2 default = JLB_PolynomialUserTransform caption = "Transform 2" visible = @how < 3 || @how == 4 endparam heading caption = "T3" visible = @how ==1 || @how == 2 || @how == 5 endheading UserTransform param f_UT3 default = JLB_PolynomialUserTransform caption = "Transform 3" visible = @how ==1 || @how == 2 || @how == 5 endparam } class JLB_FX_Magnet(FormulaX) { ; combines Magnet 1 and Magnet 2 from Standard.ulb public: func JLB_FX_Magnet(Generic pparent) Formula(pparent) endfunc complex func Init(complex pz) FormulaX.Init(pz) return pz endfunc complex func Iterate(complex pz) complex znew if @type == "1" znew = sqr( (pz^2+m_c-1) / (2*pz+m_c-2) ) else znew = sqr( (pz^3 + 3 * (m_c-1) * pz + (m_c-1) * (m_c-2)) \ / (3 * pz^2 + 3 * (m_c-2) * pz + (m_c-1) * (m_c-2) + 1) ) endif return znew endfunc protected: default: title = "Magnet" ;rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading ; heading ; caption = "Convergent formula" ; endheading param type caption = "Magnet type?" enum = "1" "2" default = 0 endparam heading caption = "z_new = sqr((z^2+c-1)/(2*z+c-2))" visible = @type == 0 endheading heading caption = "z_new = (like type 1, but cubic)" ; caption = "z_new = sqr((z^3+3*(c-1)*z+(c-1)*(c-2))/ \ ; (3*z^2+3*(c-2)*z+(c-1)*(c-2)+1))" visible = @type == 1 endheading } class JLB_FX_Newton(FormulaX) { ; Iteration of polynomial(z) - c = 0 by relaxed Newton's method or other ; iterative method. public: func JLB_FX_Newton(Generic pparent) Formula(pparent) if (@poly_type == "Polynomial") a[0] = @a0, a[1] = @a1, a[2] = @a2, a[3] = @a3 a[4] = @a4, a[5] = @a5, a[6] = @a6 a[@degree+1] = a[@degree+2] = 0 int i = 0 while (i <= @degree) ap[i] = (i+1)*a[i+1] ; f' - coefficient of z^i app[i] = (i+2)*(i+1)*a[i+2] ; f" - coefficient of z^i i = i + 1 endwhile endif D = new Deriv(0) endfunc complex func Init(complex pz) FormulaX.Init(pz) iter = 0 return pz endfunc complex func Iterate(complex pz) complex znew complex f complex fp complex fpp = 0 ; avoid compiler warning if (@poly_type == "Polynomial") ; Solving F(z) = 0 D.Set_k(@kind) D.pow_calc(pz, 1) complex fz = D.f complex fzp = D.fp complex fzpp = D.fpp int i = @degree f = a[i] while (i > 0) i = i - 1 f = a[i] + fz * f endwhile f = f + m_c ; df/dz i = @degree - 1 complex sum1 = ap[i] while (i > 0) i = i - 1 sum1 = ap[i] + fz * sum1 endwhile fp = fzp * sum1 if (@iter_type > 0) ; d2f/dz2 i = @degree - 2 complex sum2 = app[i] while (i > 0) i = i - 1 sum2 = app[i] + fz * sum2 endwhile fpp = fzpp * sum1 + fzp * fzp * sum2 endif else;if (@poly_type == "Two Powers") D.Set_k(@kind1) D.pow_calc(pz, @power) f = D.f fp = D.fp fpp = D.fpp D.Set_k(@kind2) D.pow_calc(pz, @power2) f = f + @a*D.f + m_c fp = fp + @a*D.fp fpp = fpp + @a*D.fpp endif if (@iter_type == "Newton") znew = pz - @step * f / fp elseif (@iter_type == "Type 1") ; Halley's method approx. znew = pz - @step * (f/fp)*(1 + f*fpp/(2*fp*fp)) elseif (@iter_type == "Type 2") ; Halley's method znew = pz - @step * (f/fp) / ( 1 - f*fpp/(2*fp*fp)) else;if (@iter_type == "Type 3") ; Laguerre ; see https://mathworld.wolfram.com/LaguerresMethod.html ; G = fp/f, H = G^2-fpp/f ; znew = z - n/max{G+-sqrt[(n-1)(nH-G^2)]} ; Halley's "irrational method" sets n=2 ; Laguerre sets n=polynomial degree, but no good for Two Powers version ; where p and q and be complex and not the same ; complex root = sqrt(1-2*f*fpp/(fp*fp)) int n = 2 if @poly_type == 0, n = @degree, endif complex root = sqrt((n-1)*(n-1-n*f*fpp/(fp*fp))) complex d1 = 1 + root complex d2 = 1 - root if (|d1| < |d2|), d1 = d2, endif znew = pz - @step * 2*(f/fp) / d1 endif iter = iter + 1 return znew endfunc protected: complex a[9] ; coefficients of polynomial complex ap[9] ; coefficients of first derivative of polynomial complex app[9] ; coefficients of second derivative of polynomial Deriv D complex n ; real for polynomial type; complex for powers of functions int iter default: title = "Poly Newton" rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "Solve a0 + a1*f(zz) + a2*f(zz)^2 + ... - c = 0" visible = @poly_type == 0 endheading heading caption = "Solve f1(z)^p + a*f2(z)^q - c = 0" visible = @poly_type == 1 endheading param poly_type caption = "Function type" enum = "Polynomial" "Two Powers" default = 0 endparam ; Polynomial params int param degree caption = "Degree (<=6)" default = 3 min = 2 max = 6 visible = (@poly_type == 0) endparam param kind caption = "zz" ; These are the ones with calculated derivatives in the Deriv class enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \ "cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \ "tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \ "log(z)" "exp(z)" default = 0 visible = @poly_type == 0 endparam heading caption = "Coeffients" visible = (@poly_type == 0) endheading complex param a0 caption = "a0 = constant coef" default = (0,0) visible = (@poly_type == 0) endparam complex param a1 caption = "a1 = degree 1 coef" default = (1,0) visible = (@poly_type == 0) endparam complex param a2 caption = "a2 = degree 2 coef" default = (1,0) visible = (@poly_type == 0) endparam complex param a3 caption = "a3 = degree 3 coef" default = (1,0) visible = (@degree >= 3) && (@poly_type == 0) endparam complex param a4 caption = "a4 = degree 4 coef" default = (1,0) visible = (@degree >= 4) && (@poly_type == 0) endparam complex param a5 caption = "a5 = degree 5 coef" default = (1,0) visible = (@degree >= 5) && (@poly_type == 0) endparam complex param a6 caption = "a6 = degree 6 coef" default = (1,0) visible = (@degree >= 6) && (@poly_type == 0) endparam ; Two powers params param kind1 caption = "f1" enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \ "cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \ "tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \ "log(z)" "exp(z)" default = 0 visible = @poly_type == 1 endparam complex param power caption = "p" default = (3,0) visible = (@poly_type == 1) endparam ; second function complex param a caption = "a" default = 1 visible = (@poly_type == 1) endparam param kind2 caption = "f2" enum = "z" "sin(z)" "sinh(z)" "asin(z)" "asinh(z)" \ "cos(z)" "cosh(z)" "acos(z)" "acosh(z)" \ "tan(z)" "tanh(z)" "atan(z)" "atanh(z)" \ "log(z)" "exp(z)" default = 0 visible = @poly_type == 1 endparam complex param power2 caption = "q" default = (2,0) visible = (@poly_type == 1) endparam heading endheading param iter_type caption = "Iteration type" enum = "Newton" "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." endparam param step caption = "Step size" default = (1,0) ; hint = "Nonstandard values may not allow \ ; convergence, but can give interesting shapes." endparam } class JLB_FX_Poly(FormulaX) { public: import "common.ulb" func JLB_FX_Poly(Generic pparent) Formula(pparent) if @poly_type == "Two Powers" m1 = new @T1(this) m2 = new @T2(this) else a[0] = @a0, a[1] = @a1, a[2] = @a2, a[3] = @a3 a[4] = @a4, a[5] = @a5, a[6] = @a6 if @poly_type == "Polynomial in T(z)" m0 = new @T0(this) endif endif endfunc complex func Init(complex pz) FormulaX.Init(pz) return pz endfunc complex func Iterate(complex pz) complex znew if @poly_type == "Two Powers" znew = m1.Iterate(pz)^@p + m2.Iterate(pz)^@q + m_c else complex zz = pz if @poly_type == "Polynomial in T(z)" zz = m0.Iterate(pz) endif int i = @degree complex sum = a[i] while (i > 0) i = i - 1 sum = a[i] + zz * sum endwhile znew = sum + m_c endif m_iterations = m_iterations + 1 return znew endfunc protected: complex a[7] ; coefficients of polynomial UserTransform m0 UserTransform m1 UserTransform m2 default: title = "Polynomial" rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "z_new = a0 + a1*z + a2*z^2 + ... + c" visible = @poly_type == 0 endheading heading caption = "z_new = a0 + a1*T(z) + a2*T(z)^2 + ... + c" visible = @poly_type == 1 endheading heading caption = "z_new = T1(z)^p + T2(z)^q + c" visible = @poly_type == 2 endheading param poly_type caption = "Function type" enum = "Polynomial in z" "Polynomial in T(z)" "Two Powers" default = 0 endparam UserTransform param T0 caption = "T" default = JLB_UT_Function visible = @poly_type == 1 endparam ; Polynomial params int param degree caption = "Degree (<=6)" default = 3 min = 1 max = 6 visible = (@poly_type < 2) endparam heading caption = "Coeffients" visible = (@poly_type < 2) endheading complex param a0 caption = "a0 = constant coef" default = (2,0) visible = (@poly_type < 2) endparam complex param a1 caption = "a1 = degree 1 coef" default = (1,0) visible = (@poly_type < 2) endparam complex param a2 caption = "a2 = degree 2 coef" default = (1,0) visible = (@degree >= 2) && (@poly_type < 2) endparam complex param a3 caption = "a3 = degree 3 coef" default = (1,0) visible = (@degree >= 3) && (@poly_type < 2) endparam complex param a4 caption = "a4 = degree 4 coef" default = (1,0) visible = (@degree >= 4) && (@poly_type < 2) endparam complex param a5 caption = "a5 = degree 5 coef" default = (1,0) visible = (@degree >= 5) && (@poly_type < 2) endparam complex param a6 caption = "a6 = degree 6 coef" default = (1,0) visible = (@degree >= 6) && (@poly_type < 2) endparam ; Two powers params UserTransform param T1 caption = "T1" default = JLB_UT_Function visible = @poly_type == 2 endparam complex param p caption = "p" default = (3,0) visible = (@poly_type == 2) endparam UserTransform param T2 caption = "T2" default = JLB_UT_Function visible = @poly_type == 2 endparam complex param q caption = "q" default = (2,0) visible = (@poly_type == 2) endparam } class JLB_FX_Gnarl(FormulaX) { ; Based on the Gnarl formula from mt.ufm, as a FormulaX. ; Calculate dx and dy based on the real or imaginary parts ; of z and c, then combine. public: import "common.ulb" func JLB_FX_Gnarl(Generic pparent) Formula(pparent) ; m_rot = cos(@theta*#pi/180) + flip(sin(@theta*#pi/180)) m_T = new @T(this) endfunc complex func Init(complex pz) FormulaX.Init(pz) return pz endfunc complex func Iterate(complex pz) complex znew float xc = real(m_c) float yc = imag(m_c) complex zrot = pz ;* m_rot float x = real(zrot) float y = imag(zrot) complex px, complex py px = y, py = x complex dz = m_T.Iterate(px+flip(py)) float dx = real(dz) float dy = imag(dz) float qx, float qy qx = yc, qy = xc dx = dx + qx dy = dy + qy znew = pz + @step * (dx + flip(dy)) + @cstep * m_c return znew endfunc protected: complex m_rot UserTransform m_T default: rating = Recommended title = "Gnarl" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "Combo in action" endheading UserTransform param T ;caption = "Gnarl T" default = JLB_UT_Combo selectable = false ; don't want this changed endparam heading caption = "Z step size" endheading param step caption = "Step size" default = 0.1 hint = "How much of this to use. z_new = z + Step_size * z_calc" endparam heading caption = "C step size" endheading float param cstep caption = "Step size" default = 0.1 endparam } class JLB_UT_Combo(common.ulb:UserTransform) { func JLB_UT_Combo(Generic pparent) UserTransform(pparent) m_T1 = new @T1(this) m_T2 = new @T2(this) if @mode > 0 m_T3 = new @T3(this) endif endfunc complex func Iterate(complex pz) float px = real(pz) float py = imag(pz) complex dx, complex dy complex tx1, complex tx2, complex tx3 complex ty1, complex ty2, complex ty3 if @mode == 0 ;"T1 op1 T2" ;tx2 = @a2*@T2(@b2*px) ;ty2 = @a2*@T2(@b2*py) tx2 = iter(2, @b2*px) ty2 = iter(2, @b2*py) if @op1a == "( )" ; T1(T2(.)) ; dx = @a1*@T1(@b1*tx2) ; dy = @a1*@T1(@b1*ty2) dx = iter(1, @b1*tx2 + @mult*px) dy = iter(1, @b1*ty2 + @mult*py) else ; T1(.) op1 T2(.) ; tx1 = @a1*@T1(@b1*px) ; ty1 = @a1*@T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) dx = Combine.go(tx1, @op1a, tx2) dy = Combine.go(ty1, @op1a, ty2) endif elseif @mode == 1 ;"T1 op1 (T2 op2 T3)" if @op2a == "( )" ; T1 op T2(T3(.)) ; tx3 = @a3*T3(@b3*px) ; ty3 = @a3*T3(@b3*py) tx3 = iter(3, @b3*px) ty3 = iter(3, @b3*py) ; tx2 = @a2*T2(@b2*tx3) ; ty2 = @a2*T2(@b2*ty3) tx2 = iter(2, @b2*tx3 + @mult*px) ty2 = iter(2, @b2*ty3 + @mult*py) if @op1 == "( )" ; T1(T2(T3(.))) ; dx = @a1*T1(@b1*tx2) ; dy = @a1*T1(@b1*ty2) dx = iter(1, @b1*tx2 + @mult*px) dy = iter(1, @b1*ty2 + @mult*py) else ; T1(.) op1 T2(T3(.)) ; tx1 = @a1*T1(@b1*px) ; ty1 = @a1*T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) dx = Combine.go(tx1, @op1, tx2) dy = Combine.go(ty1, @op1, ty2) endif else; ; tx3 = @a3*T3(@b3*px) ; ty3 = @a3*T3(@b3*py) tx3 = iter(3, @b3*px) ty3 = iter(3, @b3*py) ; tx2 = @a2*T2(@b2*px) ; ty2 = @a2*T2(@b2*py) tx2 = iter(2, @b2*px) ty2 = iter(2, @b2*py) tx2 = Combine.go(tx2, @op2a, tx3) ty2 = Combine.go(ty2, @op2a, ty3) if @op1 == "( )" ; T1(T2(.) op2a T3(.)) ; dx = @a1*T1(@b1*tx2) ; dy = @a1*T1(@b1*ty2) dx = iter(1, @b1*tx2 + @mult*px) dy = iter(1, @b1*ty2 + @mult*px) else ; tx1 = @a1*T1(@b1*px) ; ty1 = @a1*T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) dx = Combine.go(tx1, @op1, tx2) dy = Combine.go(ty1, @op1, ty2) endif endif else ;@mode == "(T1 op1 T2) op2 T3" ; @op3a == "( )" not allowed with this ordering ; tx2 = @a2*T2(@b2*px) ; ty2 = @a2*T2(@b2*py) tx2 = @a2*m_T2.Iterate(@b2*px) ;tx2 = iter(2, @b2*px) ty2 = iter(2, @b2*py) if @op1 == "( )" ; (T1(T2(.))) op2b T3(.) ; tx1 = @a1*T1(@b1*tx2) ; ty1 = @a1*T1(@b1*ty2) tx1 = iter(1, @b1*tx2) ty1 = iter(1, @b1*ty2) else ; tx1 = @a1*T1(@b1*px) ; ty1 = @a1*T1(@b1*py) tx1 = iter(1, @b1*px) ty1 = iter(1, @b1*py) tx1 = Combine.go(tx1, @op1, tx2) ty1 = Combine.go(ty1, @op1, ty2) endif ; tx3 = @a3*T3(@b3*px) ; ty3 = @a3*T3(@b3*py) tx3 = iter(3, @b3*px) ty3 = iter(3, @b3*py) dx = Combine.go(tx1, @op2b, tx3) dy = Combine.go(ty1, @op2b, ty3) endif return dx + flip(dy) endfunc complex func iter(int n, complex v) if n == 1 return real( @a1*m_T1.Iterate(v) ) elseif n == 2 return real( @a2*m_T2.Iterate(v) ) else return real( @a3*m_T3.Iterate(v) ) endif endfunc protected: UserTransform m_T1 UserTransform m_T2 UserTransform m_T3 default: rating = Recommended title = "Transform Combo" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading param mode caption = "Combining" default = 0 enum = "T1 op T2" "T1 op1 (T2 op2 T3)" "(T1 op1 T2) op2 T3" endparam param op1 caption = "Operator 1" enum = "+" "-" "*" "/" "^" "( )" default = 5 hint = "How to combine Transform values." visible = @mode > 0 endparam param op1a caption = "Operator" enum = "+" "-" "*" "/" "^" "( )" default = 5 hint = "How to combine Transform values." visible = @mode == 0 endparam param op2a caption = "Operator 2" enum = "+" "-" "*" "/" "^" "( )" default = 5 hint = "How to combine Transform values." visible = (@mode == 1) endparam param op2b caption = "Operator 2" enum = "+" "-" "*" "/" "^" ; () doesn't make sense default =0 hint = "How to combine Transform values." visible = (@mode == 2) endparam heading caption = "a1*T1(b1*v)" endheading complex param a1 caption = "a1" default = 1 hint = "multiplies T1" endparam complex param b1 caption = "b1" default = 2 hint = "multiplies T1's arg" endparam UserTransform param T1 caption = "T1" default = JLB_UT_Function ;JLB_FTransform endparam heading caption = "a2*T2(b2*v)" endheading complex param a2 caption = "a2" default = 2.7 hint = "multiplies T2" endparam complex param b2 caption = "b2" default = 2.7 hint = "multiplies T2's arg" endparam UserTransform param T2 caption = "T2" default = JLB_UT_Function ;JLB_FTransform endparam heading caption = "a3*T3(b3*v)" visible = @mode > 0 endheading complex param a3 caption = "a3" default = 0 hint = "multiplies T3" visible = @mode > 0 endparam complex param b3 caption = "b3" default = 1 hint = "multiplies T3's arg" visible = @mode > 0 endparam UserTransform param T3 caption = "T3" default = JLB_UT_Function ;JLB_FTransform visible = @mode > 0 endparam heading endheading float param mult ; maybe use this someday. doesn't seem useful. caption = "( ) parameter" default = 0 ; visible = ( @mode == 0 && @op1a == "( )" ) || \ ; ( @mode == 1 && ( @op2a == "( )" || @op1 == "( )" ) ) || \ ; ( @mode == 2 && @op1 == "( )" ) visible = false endparam } class JLB_FX_Dual(FormulaX) { public: import "common.ulb" func JLB_FX_Dual(Generic pparent) Formula(pparent) if @sw m_FX1 = new @f_FX2(this) m_FX2 = new @f_FX1(this) else m_FX1 = new @f_FX1(this) m_FX2 = new @f_FX2(this) endif endfunc complex func Init(complex pz) m_FX1.Init(pz) m_FX2.Init(pz) count = 0 return pz endfunc complex func Iterate(complex pz) if @n1 + @n2 == 0 return m_FX1.Iterate(pz) endif complex znew if count < @n1 znew = m_FX1.Iterate(pz) else znew = m_FX2.Iterate(pz) endif count = count + 1 if count == @n1 + @n2 count = 0 endif return znew endfunc private: FormulaX m_FX1 FormulaX m_FX2 int count default: title = "Two Formulas" rating = Recommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading bool param sw caption = "Switch formulas 1 and 2?" default = false endparam heading endheading int param n1 caption = "Formula 1 iterations" default = 1 min = 0 endparam FormulaX param f_FX1 caption = "Formula 1" default = JLB_FX_Mandelbrot endparam heading endheading int param n2 caption = "Formula 2 iterations" default = 1 min = 0 endparam FormulaX param f_FX2 caption = "Formula 2" default = JLB_FX_Mandelbrot endparam bool param p_Mtype visible = false ; hide, as the two FXs have their own endparam complex param p_seed visible = false ; hide, as the two FXs have their own endparam } class CD(common.ulb:Generic) { ; ; CD base class. No title, so only used for a base class. ; A variation of sorts on the Distance class ; Given a complex value, return a float. ; Optionally scale the float by the largest power of the argument ; Designed for use in Color by Distance ; ; Useful for seeing the effect visible as thumbnails in Browse mode. public: import "common.ulb" func CD(Generic pparent) Generic.Generic(pparent) endfunc func SetScale(bool scale) m_scale = scale endfunc func SetAB(float aa, float bb) a = aa, b = bb endfunc func Setp(float pp) p = pp endfunc func SetAll(complex zz, bool exch) ; not all of these are needed for all plug-ins, but simplify, simplify, simplify c1 = cabs(zz), c2 = c1*c1, c3 = c2*c1, c4 = c2*c2 x = real(zz), y = imag(zz) if exch, float t=x, x=y, y=t, endif x2 = x^2, y2 = y^2, d2 = x2-y2 endfunc float func Iterate(complex zz) return 1 endfunc protected: ;int m_iter bool m_scale float c1, float c2, float c3, float c4 float x, float y, float x2, float y2, float d2 float a, float b, float p } ; these two are the same as the parent, but can be treated differently ; CD1 has one parameter, CD2 has two parameters class CD1(CD) { public: func CD1(Generic pparent) CD.CD(pparent) endfunc } class CD2(CD) { public: func CD2(Generic pparent) CD.CD(pparent) endfunc } class JLB_D_CD(Distance){ ; A distance class using Curve plug-ins from class CD public: func JLB_D_CD(Generic pparent) Distance(pparent) if @numpar == "1" m_CD1 = new @d_CD1(this) else m_CD2 = new @d_CD2(this) endif endfunc func Init(complex zz) if @numpar == "1" m_CD1.SetAB(@a, 1) ; m_CD1.SetScale(@scale) ; if @d_CD1 == JLB_CD103 ; Astroid ; m_CD1.SetP(@p) ; endif else m_CD2.SetAB(@a, @b) ; m_CD2.SetScale(@scale) endif endfunc float func Iterate(complex zz) float d if @numpar == "1" m_CD1.SetAll(zz, @exch) d = m_CD1.Iterate(zz) else m_CD2.SetAll(zz, @exch) d = m_CD2.Iterate(zz) endif ; m_abs_value is from Distance base class, default is False ; Distance Coloring methods set m_abs_value to True if m_abs_value d = abs(d) endif if @version < 240224 if @invert && d != 0 d = 1/d endif endif return d endfunc protected: CD1 m_CD1 CD2 m_CD2 default: title = "Curve Distance" rating = Recommended int param version caption = "Version" default = 240224 visible = @version < 240224 endparam heading text = "(Current is 240224.)" visible = @version < 240224 endheading heading text = "Scaling is often useful, as is Mandelbrot smoothing." endheading param numpar caption = "# parameters" enum = "1" "2" default = 0 endparam CD1 param d_CD1 caption = "Curve" default = JLB_CD101 visible = @numpar == "1" endparam CD2 param d_CD2 caption = "Curve" default = JLB_CD201 visible = @numpar == "2" endparam ; float param p ; caption = "Power" ; default = 0.5 ; visible = @d_CD1 == JLB_CD103 ; Astroid ; endparam bool param exch caption = "Exchange x and y?" default = false visible = (@numpar == "1" \ && @d_CD1 != JLB_CD118 \ && @d_CD1 != JLB_CD133 \ && @d_CD1 != JLB_CD141 ) || \ (@numpar == "2" \ && @d_CD2 != JLB_CD203a \ && @d_CD2 != JLB_CD205 \ && @d_CD2 != JLB_CD232) ; Folium of Descartes, Quadrifolium, Trott ; Astroid, Beetle, Windmill endparam bool param scale caption = "Scale?" default = true endparam float param a caption = "Parameter a" default = 1.0 endparam float param b caption = "Parameter b" default = 1.0 visible = @numpar == "2" endparam bool param invert ; moved to Color by Distance caption = "Use reciprocal?" default = false visible = @version < 240224 endparam } class JLB_CD101(CD1) { public: float func Iterate(complex zz) float d = (c2-a*x)^2 - a^2*c2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD101 Arachnea" } class JLB_CD102(CD1) { public: float func Iterate(complex zz) float d = x2*(a*x2-y2)^2 - y2*c2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD102 Arcs of Samothrace" } class JLB_CD103(CD1) { public: float func Iterate(complex zz) float d = (a*x2+y)^2 + x2*(x2-1) if m_scale, d = d/c4, endif return d endfunc default: title = "CD103 Besace" } class JLB_CD104(CD1) { public: float func Iterate(complex zz) float d = y2*(a-x2) - (x2+2*a*y-a^2)^2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD104 Bicorn" } class JLB_CD105(CD1) { public: float func Iterate(complex zz) float d = (x2-a^2)*(x-a)^2 + (y2-a)^2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD105 Bicuspid" } class JLB_CD106(CD1) { public: float func Iterate(complex zz) float d = x2*x2 + y2*y2 - a*x*y2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD106 Bifoliate" } class JLB_CD107(CD1) { public: float func Iterate(complex zz) float d = (x2-a^2)*(x-a)^2 + (y2-a)^2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD107 Bow" } class JLB_CD108(CD1) { public: float func Iterate(complex zz) float d = x2*x2*c2 - a*d if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD108 Bow Tie" } class JLB_CD109(CD1) { public: float func Iterate(complex zz) float d = x2^3 + y2^3 - a*x2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD109 Butterfly" } class JLB_CD110(CD1) { public: float func Iterate(complex zz) float d = (c2-a*x)^2 - a^2*c2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD110 Cardioid" } class JLB_CD111(CD1) { public: float func Iterate(complex zz) float d = 4*(c2-a*x)^3 - 27*a^2*c2^2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD111 Cayley's Sextic" } class JLB_CD112(CD1) { public: float func Iterate(complex zz) float d = x*c2 - a*y2 if m_scale, d = d/c3, endif return d endfunc default: title = "CD112 Cissoid of Diocles" } class JLB_CD113(CD1) { public: float func Iterate(complex zz) float d = c2^3 + a*(3*x^4 - 6*x2*y2 - 5*y^4) + 8*a^2*y2 - 4*a^3 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD113 Cornoid" } class JLB_CD114(CD1) { public: float func Iterate(complex zz) float d = c2^2 + 8*a*x*(x2-3*y2) + 18*a^2*c2 - 27*a^4 if m_scale, d = d/c4, endif return d endfunc default: title = "CD114 Deltoid" } class JLB_CD115(CD1) { public: float func Iterate(complex zz) float d = c2^3 - a*x2 if m_scale, d = d/c4/c2, endif ; curve 2 had d/c3/c3, wrong return d endfunc default: title = "CD115 Dipole" } class JLB_CD116(CD1) { public: float func Iterate(complex zz) float d = c2^2 - a*x^3 if m_scale, d = d/c4, endif return d endfunc default: title = "CD116 Egg of Kepler" } class JLB_CD117(CD1) { public: float func Iterate(complex zz) float d = x^4 - a*d2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD117 Eight" } class JLB_CD118(CD1) { public: float func Iterate(complex zz) float d = x^3 + y^3 - 3*a*x*y if m_scale, d = d/c3, endif return d endfunc default: title = "CD118 Folium of Descartes" } class JLB_CD119(CD1) { public: float func Iterate(complex zz) float d = c2*(2*c2-a)^2 - a^2*x2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD119 Folium of Durer" } class JLB_CD120(CD1) { public: float func Iterate(complex zz) float d = (x2+y2-a)^3 - x2*y2*y if m_scale, d = d/c3/c3, endif return d endfunc default: title = "CD120 Heart" } class JLB_CD121(CD1) { public: float func Iterate(complex zz) float d = x2*(x-y) + a if m_scale, d = d/c3, endif return d endfunc default: title = "CD121 Heat Capacity" } class JLB_CD122(CD1) { public: float func Iterate(complex zz) float d = x^3 - 3*x*y2 - a if m_scale, d = d/c3, endif return d endfunc default: title = "CD122 Humbert's Cubic" } class JLB_CD123(CD1) { public: float func Iterate(complex zz) float d = x2 - a*y2 if m_scale, d = d/c2, endif return d endfunc default: title = "CD123 Hyperbola" } class JLB_CD124(CD1) { public: float func Iterate(complex zz) float d = x^4 - a*c2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD124 Kampyle of Eudoxus" } class JLB_CD125(CD1) { public: float func Iterate(complex zz) float d = x2*c2 - a*y2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD125 Kappa" } class JLB_CD126(CD1) { public: float func Iterate(complex zz) float d = c2^3 - a*x*(x2-3*y2) if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD126 Kiepert" } class JLB_CD127(CD1) { public: float func Iterate(complex zz) float d = a^2*y2 - (a-x2)^3 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD127 Kiss" } class JLB_CD128(CD1) { public: float func Iterate(complex zz) float d = (x2-a)^2 - y2*(3*a+2*y) if m_scale, d = d/c4, endif return d endfunc default: title = "CD128 Knot" } class JLB_CD129(CD1) { public: float func Iterate(complex zz) float d = x2*y2 - a*(a-y2) if m_scale, d = d/c4, endif return d endfunc default: title = "CD129 Lemniscate of Bernoulli" } class JLB_CD130(CD1) { public: float func Iterate(complex zz) float d = x*y*d2 - a*c2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD130 Maltese Cross" } class JLB_CD131(CD1) { public: float func Iterate(complex zz) float d = c2*(x*2+y2-a)^2 - 4*a*(c2-a*x)^2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD131 Nephroid of Freeth" } class JLB_CD132(CD1) { public: float func Iterate(complex zz) float d = y - a*x2 if m_scale, d = d/c2, endif return d endfunc default: title = "CD132 Parabola" } class JLB_CD133(CD1) { public: float func Iterate(complex zz) float d = c2^3 - a*x2*y2 if m_scale, d = d/c2/c4, endif return d endfunc default: title = "CD133 Quadrifolium" } class JLB_CD134(CD1) { public: float func Iterate(complex zz) float d = x*c2 - a*d2 if m_scale, d = d/c3, endif return d endfunc default: title = "CD134 Right Strophoid" } class JLB_CD135(CD1) { public: float func Iterate(complex zz) float d = y2 - a*x*x2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD135 Semicubical Parabola" } class JLB_CD136(CD1) { public: float func Iterate(complex zz) float d = c2*(c2-a*y)^2 - x2*d2^2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD136 Sextic" } class JLB_CD137(CD1) { public: float func Iterate(complex zz) float d = c2^2 - a*x*d2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD137 Torpedo" } class JLB_CD138(CD1) { public: float func Iterate(complex zz) float d = (c2-a)^2 - x2*c2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD138 Trisectrix of Delange" } class JLB_CD139(CD1) { public: float func Iterate(complex zz) float d = x*(x2-3*y2) - a*c2 if m_scale, d = d/c3, endif return d endfunc default: title = "CD139 Trisectrix of Longchamps" } class JLB_CD140(CD1) { public: float func Iterate(complex zz) float d = x*c2 - a*(3*x2-y2) if m_scale, d = d/c3, endif return d endfunc default: title = "CD140 Trisectrix of Maclaurin" } class JLB_CD141(CD1) { public: float func Iterate(complex zz) float d = 144*(x^4+y^4) - 225*c2 + 350*x2*y2 + 81*a if m_scale, d = d/c4, endif return d endfunc default: title = "CD141 Trott" } class JLB_CD142(CD1) { public: float func Iterate(complex zz) float d = x*c2 - a*(x2+2*y2) if m_scale, d = d/c3, endif return d endfunc default: title = "CD142 Visiera" } class JLB_CD143(CD1) { public: float func Iterate(complex zz) float d = y^4 + a*d2 ;mathworld version if m_scale, d = d/c4, endif return d endfunc default: title = "CD143 Viviani's" } class JLB_CD144(CD1) { public: float func Iterate(complex zz) float d = x2*x2-y2*y2 + a*x*y if m_scale, d = d/c4, endif return d endfunc default: title = "CD144 Wavy Cross" } class JLB_CD145(CD1) { public: float func Iterate(complex zz) float d = x2*y + a^2*(y-a) if m_scale, d = d/c3, endif return d endfunc default: title = "CD145 Witch of Agnesi" } class JLB_CD201(CD2) { public: float func Iterate(complex zz) float d = d2^2 - a*x2 + b*y2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD201 Alain" } class JLB_CD202(CD2) { public: float func Iterate(complex zz) float d = (y2-x2)*(x-a)*(2*x-3*a) - b*(c2-2*x)^2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD202 Ampersand" } class JLB_CD203(CD2) { public: float func Iterate(complex zz) float d = y*(x2+a^2) - a*b*x if m_scale, d = d/c3, endif return d endfunc default: title = "CD203 Anguinea" } class JLB_CD203a(CD2) { public: float func Iterate(complex zz) float d = x^b + y^b - a^b if m_scale, d = d/c1^b, endif return d endfunc default: title = "CD203a Astroid" } class JLB_CD204(CD2) { public: float func Iterate(complex zz) float d = x^4*c2 - (a*x2-b)^2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD204 Atripthaloid" } class JLB_CD205(CD2) { public: float func Iterate(complex zz) float d = c2*(c2-a*x-a*y) - b*x2*y2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD205 Beetle" } class JLB_CD206(CD2) { public: float func Iterate(complex zz) float d = (x2-b*y)^2 - a*d2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD206 Besace" } class JLB_CD207(CD2) { public: float func Iterate(complex zz) float d = c2^2 - (a*x+b*y)*x2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD207 Bifolium" } class JLB_CD208(CD2) { public: float func Iterate(complex zz) float d = a^2*y2 - b^2*x*2 - x2*y2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD208 Bullet-Nose" } class JLB_CD209(CD2) { public: float func Iterate(complex zz) float d = c2^2 - a*d2 + b^4 if m_scale, d = d/c4, endif return d endfunc default: title = "CD209 Cassinian Ovals" } class JLB_CD210(CD2) { public: float func Iterate(complex zz) float d = (x-a)^2*c2 - b^2*x2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD210 Conchoid of Nicomedes" } class JLB_CD211(CD2) { public: float func Iterate(complex zz) float d = x2*y2 - a*x2 - b*y if m_scale, d = d/c4, endif return d endfunc default: title = "CD211 Cross" } class JLB_CD212(CD2) { public: float func Iterate(complex zz) float d = a^2*y - x^3 + b*x if m_scale, d = d/c3, endif return d endfunc default: title = "CD212 Cubical Parabola" } class JLB_CD213(CD2) { public: float func Iterate(complex zz) float d = a*(x-a)*c2 - b*x2 if m_scale, d = d/c3, endif return d endfunc default: title = "CD213 Cubic of de Sluze" } class JLB_CD214(CD2) { public: float func Iterate(complex zz) float d = x*c2 + (a+b)*x2 - (a-b)*y2 if m_scale, d = d/c3, endif return d endfunc default: title = "CD214 Curve of Cramer" } class JLB_CD215(CD2) { public: float func Iterate(complex zz) float d = x2*c2 - (a+b)*x2*y + (a-b)^2*y/4 if m_scale, d = d/c4, endif return d endfunc default: title = "CD215 Double Heart" } class JLB_CD216(CD2) { public: float func Iterate(complex zz) float d = b*y2 - x2*x2*(a-x2) if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD216 Dumbbell" } class JLB_CD217(CD2) { public: float func Iterate(complex zz) float d = x2*y2 - (x-a)*(b-x) if m_scale, d = d/c4, endif return d endfunc default: title = "CD217 Egg of Granville" } class JLB_CD218(CD2) { public: float func Iterate(complex zz) float d = b*x2 + a*y2 - a*b ; original was a/b ; properly for an ellipse, a*2 and b*2 if m_scale, d = d/c2, endif return d endfunc default: title = "CD218 Ellipse" } class JLB_CD219(CD2) { public: float func Iterate(complex zz) float d = y*(y2-a) - b*x*(x2-a) if m_scale, d = d/c3, endif return d endfunc default: title = "CD219 Euler's Cubic" } class JLB_CD220(CD2) { public: float func Iterate(complex zz) float d = c2*(x*(x-a)+y2) - b*x*y2 if m_scale, d = d/c3, endif return d endfunc default: title = "CD220 Folium of Kepler" } class JLB_CD221(CD2) { public: float func Iterate(complex zz) float d = y - a*real(sin(b*x)) ; sin = @F if m_scale, d = d/c1, endif return d endfunc default: title = "CD221 Function" ;stuff goes here } class JLB_CD222(CD2) { public: float func Iterate(complex zz) float d = c2^2 - a*x2 - b*y2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD222 Hippopede" } class JLB_CD223(CD2) { public: float func Iterate(complex zz) float d = (c2-a*x)^2 - b*c2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD223 Limacon of Pascal" } class JLB_CD224(CD2) { public: float func Iterate(complex zz) float d = (c2-a)^3 - b*y2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD224 Nephroid" } class JLB_CD225(CD2) { public: float func Iterate(complex zz) float d = x*c2 - b*x*y - a*y2 if m_scale, d = d/c3, endif return d endfunc default: title = "CD225 Ophiuride" } class JLB_CD226(CD2) { public: float func Iterate(complex zz) float d = x*x2*(a-x) - b*y2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD226 Pear" } class JLB_CD227(CD2) { public: float func Iterate(complex zz) float d = b^2*y2 + (x-a)*x^3 if m_scale, d = d/c4, endif return d endfunc default: title = "CD227 Piriform Quartic" } class JLB_CD228(CD2) { public: float func Iterate(complex zz) float d = y*(x+b*y)^2 - a*x if m_scale, d = d/c3, endif return d endfunc default: title = "CD228 Serpentine" } class JLB_CD229(CD2) { public: float func Iterate(complex zz) float d = y2*(a^2*b-x2) - x2*(a-x)^2 if m_scale, d = d/c4, endif return d endfunc default: title = "CD229 Tighrope" } class JLB_CD220(CD2) { public: float func Iterate(complex zz) float d = c2^2 - a*x*(x2-b*y2) if m_scale, d = d/c4, endif return d endfunc default: title = "CD220 Trifolium" } class JLB_CD231(CD2) { public: float func Iterate(complex zz) float d = c2^3 - a*(b*x2-y2)^2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD231 Trisectrix of Ceva" } class JLB_CD232(CD2) { public: float func Iterate(complex zz) float d = 4*x2*y2*c2 - a*(x2-b*y2)^2 if m_scale, d = d/c4/c2, endif return d endfunc default: title = "CD232 Windmill" } class JLB_UT_CD(common.ulb:UserTransform) { public: func JLB_UT_CD(Generic pparent) UserTransform(pparent) m_Dx = new @f_Dx(this) m_Dy = new @f_Dy(this) endfunc func Init(complex pz) m_Dx.Init(pz) m_Dy.Init(pz) endfunc complex func Iterate(complex pz) float x = m_Dx.Iterate(pz) float y = m_Dy.Iterate(pz) if @xytype == "- +" || @xytype == "- -", x = -x, endif if @xytype == "+ -" || @xytype == "- -", y = -y, endif pz= x+flip(y) return pz endfunc private: Distance m_Dx Distance m_Dy default: rating = Recommended title = "X and Y Distances" int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Current is 240115.}" visible = @version < 240115 endheading heading caption = "znew = +-Dx, +-flip(Dy)" endheading ; heading ; caption = "X and Y combining" ; endheading param xytype caption = "Dx Dy signs" enum = "+ +" "+ -" "- +" "- -" default = 0 endparam heading endheading Distance param f_Dx caption = "Dx" default = JLB_D_CD endparam heading endheading Distance param f_Dy caption = "Dy" default = JLB_D_CD endparam heading endheading } class PM(common.ulb:Generic) { ; PM base class. No title, so only used for a base class. ; CombineXY as a class. Make a complex from one part of zx and one part of zy. public: complex func go(complex zx, complex zy) return 1 endfunc } ; 16 possibilities class JLB_PRPR(PM) { public: complex func go(complex zx, complex zy) return +real(zx) + flip(real(zy)) endfunc default: title = "+r+r" } class JLB_PRMR(PM) { public: complex func go(complex zx, complex zy) return +real(zx) - flip(real(zy)) endfunc default: title = "+r-r" } class JLB_PRPI(PM) { public: complex func go(complex zx, complex zy) return +real(zx) + flip(imag(zy)) endfunc default: title = "+r+i" } class JLB_PRMI(PM) { public: complex func go(complex zx, complex zy) return +real(zx) - flip(imag(zy)) endfunc default: title = "+r-i" } class JLB_MRPR(PM) { public: complex func go(complex zx, complex zy) return -real(zx) + flip(real(zy)) endfunc default: title = "-r+r" } class JLB_MRMR(PM) { public: complex func go(complex zx, complex zy) return -real(zx) - flip(real(zy)) endfunc default: title = "-r-r" } class JLB_MRPI(PM) { public: complex func go(complex zx, complex zy) return -real(zx) + flip(imag(zy)) endfunc default: title = "-r+i" } class JLB_MRMI(PM) { public: complex func go(complex zx, complex zy) return -real(zx) - flip(imag(zy)) endfunc default: title = "-r-i" } class JLB_PIPR(PM) { public: complex func go(complex zx, complex zy) return +imag(zx) + flip(real(zy)) endfunc default: title = "+i+r" } class JLB_PIMR(PM) { public: complex func go(complex zx, complex zy) return +imag(zx) - flip(real(zy)) endfunc default: title = "+i-r" } class JLB_PIPI(PM) { public: complex func go(complex zx, complex zy) return +imag(zx) + flip(imag(zy)) endfunc default: title = "+i+i" } class JLB_PIMI(PM) { public: complex func go(complex zx, complex zy) return +imag(zx) - flip(imag(zy)) endfunc default: title = "+i-i" } class JLB_MIPR(PM) { public: complex func go(complex zx, complex zy) return -imag(zx) + flip(real(zy)) endfunc default: title = "-i+r" } class JLB_MIMR(PM) { public: complex func go(complex zx, complex zy) return -imag(zx) - flip(real(zy)) endfunc default: title = "-i-r" } class JLB_MIPI(PM) { public: complex func go(complex zx, complex zy) return -imag(zx) + flip(imag(zy)) endfunc default: title = "-i+i" } class JLB_MIMI(PM) { public: complex func go(complex zx, complex zy) return -imag(zx) - flip(imag(zy)) endfunc default: title = "-i-i" } class JLB_DExpAccum(Distance) { public: func JLB_DExpAccum(Generic pparent) Distance(pparent) m_dist = new @dist(this) endfunc func Init(complex zz) m_dist.Init(zz) m_dist.SetParams(0, true) endfunc float func Iterate(complex zz) float d = m_dist.Iterate(zz) d = exp(-@scale*d) return d endfunc private: Distance m_dist default: title = "Exp. Accum." rating = NotRecommended int param version caption = "Version" default = 240115 visible = @version < 240115 endparam heading text = "(Curent is 240115.}" visible = @version < 240115 endheading float param scale caption = "Scale" default = 1 ;min = 0 hint = "Large positive values give more emphasis to earlier iterations." endparam Distance param dist default = JLB_D_SD selectable = false endparam } class BP(common.ulb:Generic) { ; BP base class. No title, so only used for a base class. ; Given a positive float and two parameters, return a positive float. public: import "common.ulb" func BP(Generic pparent) Generic.Generic(pparent) endfunc float func Go(float d, float b, float p) return d endfunc } class JLB_BP00(BP) { public: float func Go(float d, float b, float p) return d endfunc default: title = "BP00 no change" } class JLB_BP01(BP) { public: float func Go(float d, float b, float p) return b * d^p endfunc default: title = "BP01 power" } class JLB_BP02(BP) { public: float func Go(float d, float b, float p) return (0.5*(1-cos(b*d*#pi)))^p endfunc default: title = "BP02 haversine" } class JLB_BP03(BP) { public: float func Go(float d, float b, float p) return (tanh(b*d))^p endfunc default: title = "BP03 tanh" } class JLB_BP99(BP) { public: float func Go(float d, float b, float p) int n = round(b) return round(n*d)/n endfunc default: title = "BP99 discontinuous" }