Jump to content

Thorn Fractal (WIP)


Recommended Posts

I'm working on a new plugin. I have to wonder why is it all black? Also, I don't really plan to add all features as I don't know how to implement them in context of c#, so I will only add predefined formula from the g'mic-qt version.

 

For context, in the codelab version, the window are defined by looping within subwindow rather than applying it to a enlarged image, and averaged out.

 

Codelab

Spoiler



// Name:
// Submenu:
// Author:
// Title:
// Version:
// Desc:
// Keywords:
// URL:
// Help:
#region UICode
ListBoxControl vf_choice = 0; // Thorn Fractal|Normal|Normal Inverted|Arctangent|Tangent|Tanh Stroke|Asymphological Vibrato|Asymphological Basic|Asymphological Basic 2|Asymphochaos|Petallian|Semi-Thorny Petallian|Thorny Petal 1,Thorny Petal 2|Inflation|Inflation 2|Chaotic Creation|Earthing|Acrylic Earthing|Unearthing Origami|Cubic Unearthing|Webbing Cubic Unearthing|Chaotic Hooks|Echo Wide|Echo Squircle|Echo Hall|Echo Hall 2|Liquid Parabolic|Chaos-Vibrato|Chaos Deep-Vibrato|Chaos Spacetime|Parabolic|Parabolic Chaos|Cubic-Diamond Chaos|C-Line|Contour Chaos|Spiderweb-Diamond|Acrylica|Refractive Space|Smooth-Artistry|Ferrofluid|Triangular Interweaving|Fabric Chaos|Reverse Tangent Division|Chaotic Tangent|Alternating Chaos 1 (Legacy)|Alternating Chaos 2 (Legacy)|Alternating Chaos 3 (Legacy)|Alternating Chaos 4 (Legacy)|Alternating Chaos 1|Alternating Chaos 2|Alternating Chaos 3|Alternating Chaos 4
IntSliderControl escape = 10000; // [5,3000000] Escape Value
IntSliderControl max_iter = 255; // [1,1024] Loop Limitation
IntSliderControl sublevel = 2; // [1,10] Subsampling Level
DoubleSliderControl dx = 0; // [-50,50] Distortion X
DoubleSliderControl dy = 0; // [-50,50] Distortion Y
DoubleSliderControl r_x = 1; // [0.1,15] Scaling X-Axis
DoubleSliderControl r_y = 1; // [0.1,15] Scaling Y-Axis
DoubleSliderControl r_xy = 1; // [0.1,15] Zoom
CheckboxControl r_pi = true; // PI-Based Scaling
PanSliderControl Offset = Pair.Create(0.0,0.0); // Offset
AngleControl angle = 45; // [-180,180] Angle
#endregion

int [,] Thorn_Fractal;

double vf(double a,double b,int f,int c){
    bool axis = c == 0;
    switch(f){
        case 0: 
         if(axis) {return a/Math.Cos(b);}
         else     {return b/Math.Sin(a);}
        case 1: 
         if(axis) {return a/Math.Sin(b);}
         else     {return b/Math.Cos(a);}
        case 2: 
         if(axis) {return a/Math.Atan(b);}
         else     {return b/Math.Atan(a);}
         case 3: 
         if(axis) {return a/Math.Tan(b);}
         else     {return b/Math.Tan(a);}
        case 4: 
         if(axis) {return a/Math.Cos(b)*Math.Sin(b);}
         else     {return b/Math.Sin(a)*Math.Cos(a);}
        case 5: 
         if(axis) {return a*Math.Tan(a*b)/Math.Sin(b);}
         else     {return b*Math.Tan(a*b)/Math.Cos(a);}

         default:break;
    }
         if(axis) {return a/Math.Cos(b);}
         else     {return b/Math.Sin(a);}
}

void PreRender(Surface dst, Surface src)
{
    double d_escape = (double)(escape);
    int w = src.Width;
    int h = src.Height;
    bool sd_cond = w>h;
    bool resize_w = w%2 == 0;
    bool resize_h = h%2 == 0;
    if (resize_w) {w++;}
    if (resize_h) {h++;}
    if (Thorn_Fractal == null){Thorn_Fractal = new int [w,h];}
    else {Array.Clear(Thorn_Fractal, 0, w*h);}
    double dw = (double)(w);
    double dh = (double)(h);
    double sd = Math.Max(w,h)/Math.Min(w,h);
    double sx = w > h ? sd : 1  ;
    double sy = w > h ? 1  : sd ;
    int sub_w=w*sublevel;
    int sub_h=h*sublevel;
    int windows=sublevel * sublevel;
    double rpi = r_pi ? Math.PI : 1 ;
    double szx = rpi * r_x * r_xy;
    double szy = rpi * r_y * r_xy;
    double ang = angle / 180 * Math.PI;
    double cos_ang = Math.Cos(ang);
    double sin_ang = Math.Sin(ang);
    double ox = Offset.First * cos_ang - Offset.Second * sin_ang;
    double oy = Offset.First * sin_ang + Offset.Second * cos_ang;
    int v_sum=0;
    int sub_x,sub_y,nx,ny,v;
    double ev,xx,yy,zx,zy,vx,vy,a,b;
    for ( int y = 0 ; y < h ; y++){
        if (IsCancelRequested) return;
        ny = y * sublevel;
        for (int x = 0 ; x < w ; x++){
            nx = x * sublevel;
            v_sum=0;
            for (sub_y = 0 ; sub_y < sublevel ; sub_y++){
                yy = (double) (2 * ((ny+sub_y)/sub_h-.5));
                yy*=sy;
                for (sub_x = 0 ; sub_x < sublevel ; sub_x++){
                    xx = (double) (2 * ((nx + sub_x)/sub_w-.5));
                    xx*=sx;
                    zx = szx * ((xx*cos_ang-yy*sin_ang)+ox);
                    zy = szy * ((xx*sin_ang+yy*cos_ang)+oy);
                    vx = zx;
                    vy = zy;
                    for (v=0 ; v<max_iter ; v++){
                        a=vx;
                        b=vy;
                        vx=vf(a,b,vf_choice,0);
                        vy=vf(a,b,vf_choice,1);
                        vx+=dx;
                        vy+=dy;
                        if ((vx*vx+vy*vy)>d_escape){break;}
                    }
                    v_sum+=v;
                }                
            }
            ev = (double)(v_sum)/(double)(windows);
            Thorn_Fractal[x,y] = (int) (Math.Round(ev));
        }
    }
}

void Render(Surface dst, Surface src, Rectangle rect)
{
    int val;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {        
        for (int x = rect.Left; x < rect.Right; x++)
        {
            val = Thorn_Fractal[x,y];
            dst[x,y]=ColorBgra.FromBgraClamped(val,val,val,255);
        }
    }
}

 

 

G'MIC-QT version

Spoiler



#@cli rep_tfrac: eq. to 'rep_thorn_fractal' : (+)
rep_tfrac: rep_thorn_fractal $*
#@cli rep_thorn_fractal: -inf<=style<=47,_escape>0,_iteration>0,_subsampling_level>=1,_dx,_dy,_r_xy>0,_r_x>0,_r_y>0,_r_pi= { 0=r_xy multiplied by 1 | 1=r_xy multiplied by pi },_o_x,_o_y,_function_angle,_vx,_vy,..._vx_n,vy_n : \ : \ -inf<=style<=47,_escape>0,_iteration>0,_subsampling_level>=1,_dx,_dy,_r_xy>0,_r_x>0,_r_y>0,_r_pi= { 0=r_xy multiplied by 1 | 1=r_xy multiplied by pi },_o_x,_o_y,_function_angle,_vx,_vy,..._vx_n,vy_n,ovx,ovy,overload_freq>=1 : \ : \ -inf<=style<=47,_escape>0,_iteration>0,_subsampling_level>=1,_dx,_dy,_r_xy>0,_r_x>0,_r_y>0,_r_pi= { 0=r_xy multiplied by 1 | 1=r_xy multiplied by pi },_o_x,_o_y,_function_angle,_vx,_vy,..._vx_n,vy_n,ovx,ovy,cfa,cfb,overload_freq>=1
#@cli : Thorn Fractal is the fractal attributed to Andrew Wayne Graff, alternatively named the "Secant Sea". The code was adapted from Sample C source code provided by Adam Majewski.\n
#@cli : Source - http://paulbourke.net/fractals/thorn/#dane\n
#@cli : Alternating Chaos Formula are alternating formula founded by MadJik and are originally implemented in Fractal Attractor Plugin for Paint.NET. They use overload functions rather than a simple switch.\n
#@cli : (eq. to 'rep_tfrac').\n
#@cli : 'style' variable is used to define how the thorn fractal will look like with predefined formula. Use a integer value less than 0 to use custom formula, and use a integer value less than -1 to use custom alternating formula. See lists of available style and their corresponding id below.
#@cli : 'escape' variable is used to define the minimum value to escape from the iterative loop.
#@cli : 'iteration' variable defines how much repetition of loop used to find the end value.
#@cli : 'subsampling_level' defines the subsampling level of image.
#@cli : 'dx' is a number used to add to a variable involving distortion within the x-axis during the loop used for fractal generation.
#@cli : 'dy' is a number used to add to a variable involving distortion within the y-axis during the loop used for fractal generation.
#@cli : 'r_xy' defines how much the general infinite line boundary will repeat within the xy axis.
#@cli : 'r_x' defines how much the general infinite line boundary will repeat within the x axis.
#@cli : 'r_y' defines how much the general infinite line boundary will repeat within the y axis.
#@cli : 'r_pi' is used as a multiple to r_xy or to normalize the xmin and xmax to pi ranges.
#@cli : 'o_x' offset the resulting image within the x-direction.
#@cli : 'o_y' offset the resulting image within the y-direction.
#@cli : 'ang' defines the function angle of the thorn fractal.
#@cli : 'vx' variable is used to define custom formula for vx variable for the thorn fractal formula by default.
#@cli : 'vy' variable is used to define custom formula for vy variable for the thorn fractal formula by default.
#@cli : 'vx_n' variable defines a custom formula used for vx variable depending on altern number.
#@cli : 'vy_n' variable defines a custom formula used for vy variable depending on altern number.
#@cli : 'ovx' variable defines a custom formula to be used when the altern is greater than the range of cardinality of set of set[vx,vy]. 'o' in ovx stands for overload.
#@cli : 'ovx' variable defines a custom formula to be used when the altern is greater than the range of cardinality of set of set[vx,vy]. 'o' in ovx stands for overload.
#@cli : 'cfa' variable defines a variable that is used by overload formulas. Used as a temporary constant for each number that exceed the cardinality of set of set[vx,vy].
#@cli : 'cfb' variable defines a variable that is used by overload formulas. Used as a temporary constant for each number that exceed the cardinality of set of set[vx,vy].
#@cli : 'overload_freq' defines how much the ovx,and ovy formula will be applied when altern is greater than the range of cardinality of set of set[vx,vy].
#@cli : - Note on custom formula usage -\n
#@cli : Available adjustible variable: vx,vy,a,b\n
#@cli : 'a' defines result of number defined by vx equation based on the number of repeats needed to escape from the iterative loop to check when resulting value is greater than escape number.
#@cli : 'b' defines result of number defined by vy equation based on the number of repeats needed to escape from the iterative loop to check when resulting value is greater than escape number.
#@cli : 'vx' defines the formula used to distort by the x-axis.
#@cli : 'vy' defines the formula used to distort by the y-axis.\n
#@cli : Multiple expressions are supported, and they are separated by the character semicolon-[;]. Furthermore, the usage of commas-[,] requires you to wrap them around with quotation marks-["]. See example of usage with commas. If it the only expression, then it would be used for calculation of vx or vy. Otherwise, the first expression may be the only one used for calculation of vx or vy.\n
#@cli : - End of Note on custom formula usage -\n
#@cli : - Style List -\n
#@cli : List here below contains all the list of style. The 'asterisk' or * means the line contains a note.\n
#@cli : \ \ n<-1* = Custom Alternating Formula
#@cli : \ \ -1 = Custom Formula
#@cli : \ \ 0 \ = Normal
#@cli : \ \ 1 \ = Normal Inverted
#@cli : \ \ 2 \ = Arcangent
#@cli : \ \ 3 \ = Tangent
#@cli : \ \ 4 \ = Tanh Stroke
#@cli : \ \ 5 \ = Asymphological Vibrato
#@cli : \ \ 6 \ = Asymphological Basic
#@cli : \ \ 7 \ = Asymphological Basic 2
#@cli : \ \ 8 \ = Asymphochaos
#@cli : \ \ 9 = Petallian
#@cli : \ \ 10 = Semi-Thorny Petallian
#@cli : \ \ 11 = Thorny Petal
#@cli : \ \ 12 = Thorny Petal 2
#@cli : \ \ 13 = Inflation
#@cli : \ \ 14 = Inflation 2
#@cli : \ \ 15 = Chaotic Creation
#@cli : \ \ 16 = Earthing
#@cli : \ \ 17 = Acrylic Earthing
#@cli : \ \ 18 = Unearthing Origami
#@cli : \ \ 19 = Cubic Unearthing
#@cli : \ \ 20 = Webbing Cubic Unearthing
#@cli : \ \ 21 = Chaotic Hooks
#@cli : \ \ 22 = Echo Wide
#@cli : \ \ 23 = Echo Squircle
#@cli : \ \ 24 = Echo Hall
#@cli : \ \ 25 = Echo Hall 2
#@cli : \ \ 26 = Liquid Parabolic
#@cli : \ \ 27 = Chaos-Vibrato
#@cli : \ \ 28 = Chaos Deep-Vibrato
#@cli : \ \ 29 = Chaos Spacetime
#@cli : \ \ 30 = Parabolic
#@cli : \ \ 31 = Parabolic Chaos
#@cli : \ \ 32 = Cubic-Diamond Chaos
#@cli : \ \ 33 = C-Line
#@cli : \ \ 34 = Contour Chaos
#@cli : \ \ 35 = Spiderweb-Diamond
#@cli : \ \ 36 = Acrylica
#@cli : \ \ 37 = Refractive Space
#@cli : \ \ 38 = Smooth-Artistry
#@cli : \ \ 39 = Ferrofluid
#@cli : \ \ 40 = Triangular Interweaving
#@cli : \ \ 41 = Fabric Chaos
#@cli : \ \ 42 = Reverse Tangent Division
#@cli : \ \ 43 = Chaotic Tangent
#@cli : \ \ 44 = Alternating Chaos 1 (Legacy)
#@cli : \ \ 45 = Alternating Chaos 2 (Legacy)
#@cli : \ \ 46 = Alternating Chaos 3 (Legacy)
#@cli : \ \ 47 = Alternating Chaos 4 (Legacy)
#@cli : \ \ 48 = Alternating Chaos 1
#@cli : \ \ 49 = Alternating Chaos 2
#@cli : \ \ 50 = Alternating Chaos 3
#@cli : \ \ 51 = Alternating Chaos 4\n
#@cli : * = The absolute of value is the numbers of vx,vy next to '_function_angle'. Per loop, every two different functions are assigned instead.\n
#@cli : - End Style List -\n
#@cli : Author: Reptorian.\n
#@cli : Default values: '_escape=50000','_iteration=255','_subsampling_level=4','_dx=0','_dy=0','_r_xy=1','_r_x=1','_r_y=1','_r_pi=1','_o_x=0','_o_y=0','_function_angle=0','_custom_x=','_custom_y='
#@cli : $ 1024,1024 rep_thorn_fractal -1,10000,255,4,2.544,-5.2424,1,1,1/2,1,0,0,30,atan2(a"^"2\,b"^"2)/cos(b),b/sin(a)
rep_thorn_fractal:
skip ${2=50000},${3=255},${4=4},${5=0},${6=0},${7=1},${8=1},${9=1},${10=1},${11=0},${12=0},${13=0},${14=},${15=}
if $1<0 if !(narg($14)&&narg($15)) error "When using custom formula, there must be an arguments into custom_x and custom_y variables" fi fi
if $1>51 error "Formula variable cannot be greater than 47" fi
if $2<=0 error "Escape Variable cannot be zero or less than zero!" fi
if $3<1 error "Iteration Variable must be at least 1!" fi
if $4<1 error "Subsampling level must be at least 1!" fi
if !(($7>0&&$8>0)&&$9>0) error "Repeat variables cannot be 0!" fi
if $1>47
 chaos_a=a/cfb
 chaos_b=b/cfa
else
 chaos_a=a
 chaos_b=b
fi
if $1<0
 bounds=abs($1)*2
 if narg($*)==18+$bounds activate_overload=2
 elif narg($*)==16+$bounds activate_overload=1
 else activate_overload=0
 fi
else activate_overload=0
fi
if $activate_overload!=2&&$1<0
 repeat narg(${14--1})
  $=t
  it=${t{$>+14}}
  n={$>+14}
  strcontains $it,cfa
  if ${} error \$\-1!=2?!incl(\$$n,cfa):T==F fi
  strcontains $it,cfb
  if ${} error \$\-1!=2?!incl(\$$n,cfb):T==F fi
  if ('$it'=='cfa')||('$it'=='cfb') error overload!=2?str_incl(cfa):T==F fi
 done
fi
if $activate_overload
 fta=$-3;
 ftb=$-2;
else
 fta=atan(vx)
 ftb=atan(vy)
fi
repeat $! l[$>]

ww={w}
hh={h}

r {$4*100}%,{$4*100}%,1,1,0
r {!(w%2)?w+1:w},{!(h%2)?h+1:h},1,1,0

if w>h sd=xx*=sd;
else sd=yy*=sd;
fi

f "begin(altern=0;
 const chaos=$1>43;
 const ang=pi*($13/180);
 const sd=max(w,h)/min(w,h);
 const cos_ang=cos(ang);
 const sin_ang=sin(ang);
 const ox=$11*cos_ang-$12*sin_ang;
 const oy=$11*sin_ang+$12*cos_ang;
 const rpi=($10?pi:1);
 const szx=$8*rpi*$7;
 const szy=$9*rpi*$7;
 const overload="$activate_overload";
 const activate_alt_bool=chaos||$1<-1||($1==-1&&overload);
 const use_altlim=($1<0&&(overload==2))||$1>47;
 if(chaos
  ,const altlim=3;
  ,const altlim=abs($1)-1;
   const overlim=altlim+1;
 );
 cfa=0;
 cfb=0;
 vx=0;
 vy=0;
 fta()="$fta";
 ftb()="$ftb";
 if(overload
  ,const count_overload=abs($-1);
  ,const count_overload=0;
 );
 if(chaos
 ,if(use_altlim
  ,const ff=$1-44;
  ,const ff=$1-40;
  );
 ,const ff=abs($1)-1+count_overload;
 );
 if($1<-1||($1==-1&&overload),
  if(overload,
   if(use_altlim,
    vxf(a,b)=([${14--4}])[min(altern,overlim)*2];
    vyf(a,b)=([${14--4}])[min(altern,overlim)*2+1];
   ,
    vxf(a,b)=([${14--2}])[min(altern,overlim)*2];
    vyf(a,b)=([${14--2}])[min(altern,overlim)*2+1];
   );,
 vxf(a,b)=([${14--1}])[altern*2];
 vyf(a,b)=([${14--1}])[altern*2+1];
 );,
 if($1==-1,
  vxf(a,b)=$14;
  vyf(a,b)=$15;,
 if($1==0,
  vxf(a,b)=a/cos(b);
  vyf(a,b)=b/sin(a);,
 if($1==1,
  vxf(a,b)=a/sin(b);
  vyf(a,b)=b/cos(a);,
 if($1==2,
  vxf(a,b)=a/atan(b);
  vyf(a,b)=b/atan(a);,
 if($1==3,
  vxf(a,b)=a/tan(b);
  vyf(a,b)=b/tan(a);,
 if($1==4,
  vxf(a,b)=(a/cos(b))*sin(b);
  vyf(a,b)=(b/sin(a))*cos(a);,
 if($1==5,
  vxf(a,b)=(a*tan(a*b))/sin(b);
  vyf(a,b)=(b*tan(a*b))/cos(a);,
 if($1==6,
  vxf(a,b)=(a+tan(a*b))/sin(b);
  vyf(a,b)=(b+tan(a*b))/cos(a);,
 if($1==7,
  vxf(a,b)=(a-tan(a*b))/sin(b);
  vyf(a,b)=(b-tan(a*b))/cos(a);,
 if($1==8,
  vxf(a,b)=(a/(cos(b)))+(a/(sin(b)));
  vyf(a,b)=(b/(cos(a)))+(b/(sin(a)));,
 if($1==9,
  vxf(a,b)=a/(cos(b)*sin(b));
  vyf(a,b)=b/(sin(a)*cos(a));,
 if($1==10,
  vxf(a,b)=a/(cos(tan(b))*sin(tan(b)));
  vyf(a,b)=b/(sin(tan(a))*cos(tan(a)));,
 if($1==11,
  vxf(a,b)=(tan(a)+b)/(cos(tan(b))*sin(tan(b)));
  vyf(a,b)=(tan(b)+a)/(sin(tan(a))*cos(tan(a)));,
 if($1==12,
  vxf(a,b)=(a+tan(a)+tan(b))/(cos(tan(b))*sin(tan(b)));
  vyf(a,b)=(b+tan(a)+tan(b))/(sin(tan(a))*cos(tan(a)));,
 if($1==13,
  vxf(a,b)=(a+tan(a)+tan(b))/cos(a);
  vyf(a,b)=(b+tan(a)+tan(b))/sin(a);,
 if($1==14,
  vxf(a,b)=(a+tan(a)+tan(b))/sin(b);
  vyf(a,b)=(b+tan(a)+tan(b))/cos(a);,
 if($1==15,
  vxf(a,b)=a/sin(cos(b)*sin(b));
  vyf(a,b)=b/cos(sin(a)*cos(a));,
 if($1==16,
  vxf(a,b)=(a+tan(a)/tan(b))/cos(a);
  vyf(a,b)=(b+tan(a)/tan(b))/sin(b);,
 if($1==17,
  vxf(a,b)=(b+tan(a)/tan(b))/cos(a);
  vyf(a,b)=(a+tan(a)/tan(b))/sin(b);,
 if($1==18,
  vxf(a,b)=(b+tan(b)/tan(a))/cos(a);
  vyf(a,b)=(a+tan(a)/tan(b))/sin(b);,
 if($1==19,
  vxf(a,b)=(b+tan(b)/tan(a))/cos(a);
  vyf(a,b)=(a+tan(b)/tan(a))/sin(b);,
 if($1==20,
  vxf(a,b)=(b+tan(a)/tan(a))/cos(a);
  vyf(a,b)=(a+tan(b)/tan(a))/sin(b);,
 if($1==21,
  vxf(a,b)=b+tan(a)/(a/(cos(b)))+(a/(sin(b)));
  vyf(a,b)=a+tan(b)/(b/(cos(a)))+(b/(sin(a)));,
 if($1==22,
  vxf(a,b)=a/sin(a/sin(b));
  vyf(a,b)=b/cos(b/cos(a));,
 if($1==23,
  vxf(a,b)=a/cos(a/sin(b));
  vyf(a,b)=b/sin(b/cos(a));,
 if($1==24,
  vxf(a,b)=a/cos(a/atan(sin(b)));
  vyf(a,b)=b/sin(b/atan(cos(a)));,
 if($1==25,
  vxf(a,b)=a/sin(a/atan(cos(b)));
  vyf(a,b)=b/cos(b/atan(sin(a)));,
 if($1==26,
  vxf(a,b)=a/atan(cos(b));
  vyf(a,b)=b/atan(sin(a));,
 if($1==27,
  vxf(a,b)=(a+tanh(a*b))/cos(b);
  vyf(a,b)=(b+tanh(a*b))/sin(a);,
 if($1==28,
  vxf(a,b)=b+tan(b)/(a/(cos(b)))+(a/(sin(a)));
  vyf(a,b)=a+tan(a)/(b/(cos(a)))+(b/(sin(b)));,
 if($1==29,
  vxf(a,b)=(a+tanh(a+b))/cos(b);
  vyf(a,b)=(b+tanh(a+b))/sin(a);,
 if($1==30,
  vxf(a,b)=(a/sin(b))/tan(b);
  vyf(a,b)=(b/cos(a))/tan(a);,
 if($1==31,
  vxf(a,b)=a/(tan(b)*cos(b)*sin(b));
  vyf(a,b)=b/(tan(a)*cos(a)*sin(a));,
 if($1==32,
  vxf(a,b)=a/tan(cos(b));
  vyf(a,b)=b/tan(sin(a));,
 if($1==33,
  vxf(a,b)=(a+tanh(a*b))/(cos(b)*sin(a));
  vyf(a,b)=(b+tanh(a*b))/(sin(b)*cos(a));,
 if($1==34,
  vxf(a,b)=(a+tan(cos(a)*sin(b)))/cos(a);
  vyf(a,b)=(b+tan(sin(a)*cos(b)))/sin(b);,
 if($1==35,
  vxf(a,b)=(tan(a+b)*b)/cos(b);
  vyf(a,b)=(tan(a-b)*a)/sin(a);,
 if($1==36,
  vxf(a,b)=(a/cos(b))*sin(a);
  vyf(a,b)=(b/sin(a))*cos(b);,
 if($1==37,
  vxf(a,b)=a/tan(cos(b)+sin(b));
  vyf(a,b)=b/tan(cos(a)+sin(a));,
 if($1==38,
  vxf(a,b)=a+(tanh(a+b)/cos(b));
  vyf(a,b)=b+(tanh(a+b)/sin(a));,
 if($1==39,
  vxf(a,b)=(a/(cos(b)))/(b/(sin(a)));
  vyf(a,b)=(b/(cos(a)))/(a/(sin(b)));,
 if($1==40,
  vxf(a,b)=(a*tan(a+b))/sin(b);
  vyf(a,b)=(b*tan(a+b))/cos(a);,
 if($1==41,
  vxf(a,b)=a/(atan2(b^2,a^2)*tan(b));
  vyf(a,b)=b/(atan2(b^2,a^2)*tan(a));,
 if($1==42,
  vxf(a,b)=tan(a)/b;
  vyf(a,b)=tan(b)/a;,
 if($1==43,
  vxf(a,b)=a/atan(b/cos(a/sin(a)));
  vyf(a,b)=b/atan(a/sin(b/cos(b)));,
 if($1>43,
  vxf(a,b)=(
   if(altern==0,a/cos(b);,
   if(altern==1,a/sin(b);,
   if(altern==2,a/tan(b);,
   if(altern==3,a/atan(b);,"$chaos_a"
   );
   );
   );
   );
  );
  vyf(a,b)=(
   if(altern==0,b/sin(a);,
   if(altern==1,b/cos(a);,
   if(altern==2,b/tan(a);,
   if(altern==3,b/atan(a);,"$chaos_b"
   );
   );
   );
   );
  );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
 );
);
xx=2*((x/w)-.5);
yy=2*((y/h)-.5);
"$sd";
zx=szx*((xx*cos_ang-yy*sin_ang)+ox);
zy=szy*((xx*sin_ang+yy*cos_ang)+oy);
vx=zx;
vy=zy;
for(v=0,v<$3,v++,
 a=vx;
 b=vy;
 vx=vxf(a,b);
 vy=vyf(a,b);
 if(use_altlim,if(altern==altlim,cfa=fta();cfb=ftb();););
 vx+=$5;
 vy+=$6;
 if(activate_alt_bool,
  altern++;
  if(altern>ff,altern=0);
 );
 if((vx^2+vy^2)>$2,break());
);
abs(zx)!=0&&abs(zy)!=0?v;
"
r {$ww},{$hh},1,1,5
endl done

 

 

Edited by Reptillian

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Link to comment
Share on other sites

10 minutes ago, MJW said:

 

Without looking in detail at the code, I'll ask if the values are being scaled to the 0-255 range, as they need to be for color components, of if they're in the 0 to 1 range.

I think they need to be in 0-1 range, then normalized to 0-255 on render. I don't think I have that factored in, so there may be details.

Edited by Reptillian

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Link to comment
Share on other sites

7 minutes ago, Reptillian said:

I think they need to be in 0-1 range, then normalized to 0-255 on render.

 

It can be done either in PreRender, when they're added to the array, or in Render, as they're output. But it doesn't seem to be done in either place. Also. if they're written into an integer array, they'd better be rescaled first.

Link to comment
Share on other sites

I'm thinking of using maxnum which I did for Popcorn Fractal. It seems that the answer is to v / (maxnum*windows). Probably not.

Edited by Reptillian

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Link to comment
Share on other sites

26 minutes ago, Reptillian said:

I'm thinking of using maxnum which I did for Popcorn Fractal. It seems that the answer is to v / (maxnum*windows). Probably not.

 

That sort of thing is okay, assuming maxnum is chosen correctly, but why not just,

 

            ev = (double)(v_sum)/(double)(windows);
            Thorn_Fractal[x,y] = (int) (Math.Round(255.0 * ev));


or 

            ev = (double)(v_sum)/(double)(windows);
            Thorn_Fractal[x,y] = (int)(255.0 * ev + 0.5));

 

(That is, assuming the range produced for ev is actually 0 to 1.)

 

Why make it more confusing than it needs to be?

 

In any event, I think it's usually better to multiply by some magic constant than to divided by one. It seems clearer.

 

Link to comment
Share on other sites

Ev isn't 0-1 that's the thing. I'm not exactly experienced with c#, so I might not know the best approach.

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Link to comment
Share on other sites

7 minutes ago, Reptillian said:

Ev isn't 0-1 that's the thing. I'm not exactly experienced with c#, so I might not know the best approach.

 Whatever range it is, you obviously need to rescale it to 0-255, since that's the range of color components. If you know the max value, you need to multiply by 255 divided by that value, then convert it to an integer. That's true for C# or any other language.

Link to comment
Share on other sites

If you don't know the max value, you could use  a double or float array to save the values, and keep track of the maximum value as you store them into the array. Then at the end of PreRender, you could compute a scaling factor of 255 divided by the max value. In Render, you could scale the values taken out of the array before converting to a color.

 

Something like,

 

PreRender:

            ev = (double)(v_sum)/(double)(windows);
            Thorn_Fractal[x,y] = ev;
            if (ev > maxEv)
                maxEv = ev;
	.
	.
	.

            evScale = (maxEv == 0.0) ? 1.0 : 255.0 / maxEv;

 

Render:

            int val = (int)(evScale * Thorn_Fractal[x,y] + 0.5);
            dst[x,y]=ColorBgra.FromBgraClamped(val,val,val,255);

 

(If I were writing it, I'd use floats instead of doubles. I showed it with doubles for simplicity.)

Link to comment
Share on other sites

Finished code

 

Spoiler

// Name:
// Submenu:
// Author:
// Title:
// Version:
// Desc:
// Keywords:
// URL:
// Help:
#region UICode
ListBoxControl vf_choice = 0; // Thorn Fractal|Normal|Normal Inverted|Arctangent|Tangent|Tanh Stroke|Asymphological Vibrato|Asymphological Basic|Asymphological Basic 2|Asymphochaos|Petallian|Semi-Thorny Petallian|Thorny Petal 1|Thorny Petal 2|Inflation|Inflation 2|Chaotic Creation|Earthing|Acrylic Earthing|Unearthing Origami|Cubic Unearthing|Webbing Cubic Unearthing|Chaotic Hooks|Echo Wide|Echo Squircle|Echo Hall|Echo Hall 2|Liquid Parabolic|Chaos-Vibrato|Chaos Deep-Vibrato|Chaos Spacetime|Parabolic|Parabolic Chaos|Cubic-Diamond Chaos|C-Line|Contour Chaos|Spiderweb-Diamond|Acrylica|Refractive Space|Smooth-Artistry|Ferrofluid|Triangular Interweaving|Fabric Chaos|Reverse Tangent Division|Chaotic Tangent|Alternating Chaos 1 (Legacy)|Alternating Chaos 2 (Legacy)|Alternating Chaos 3 (Legacy)|Alternating Chaos 4 (Legacy)|Alternating Chaos 1|Alternating Chaos 2|Alternating Chaos 3|Alternating Chaos 4
IntSliderControl escape = 10000; // [5,3000000] Escape Value
IntSliderControl max_iter = 255; // [1,1024] Loop Limitation
IntSliderControl sublevel = 2; // [1,10] Subsampling Level
DoubleSliderControl dx = 0; // [-50,50] Distortion X
DoubleSliderControl dy = 0; // [-50,50] Distortion Y
DoubleSliderControl r_x = 1; // [0.1,15] Scaling X-Axis
DoubleSliderControl r_y = 1; // [0.1,15] Scaling Y-Axis
DoubleSliderControl r_xy = 1; // [0.1,15] Zoom
CheckboxControl r_pi = true; // PI-Based Scaling
PanSliderControl Offset = Pair.Create(0.0,0.0); // Offset
AngleControl angle = 0; // [-180,180] Angle
#endregion

float [,] Thorn_Fractal;
float maxnum;
int altern;
bool use_chaos_mode;
double cfa,cfb;

double vf(double a,double b,int f,int c){
    bool axis = c == 0;
    switch(f){
        case 0: 
            if(axis) {return a/Math.Cos(b);}
            else     {return b/Math.Sin(a);}
        case 1: 
            if(axis) {return a/Math.Sin(b);}
            else     {return b/Math.Cos(a);}
        case 2: 
            if(axis) {return a/Math.Atan(b);}
            else     {return b/Math.Atan(a);}
        case 3: 
            if(axis) {return a/Math.Tan(b);}
            else     {return b/Math.Tan(a);}
        case 4: 
            if(axis) {return a/Math.Cos(b)*Math.Sin(b);}
            else     {return b/Math.Sin(a)*Math.Cos(a);}
        case 5: 
            if(axis) {return a*Math.Tan(a*b)/Math.Sin(b);}
            else     {return b*Math.Tan(a*b)/Math.Cos(a);}
        case 6:
            if(axis) {return (a+Math.Tan(a*b))/Math.Sin(b);}
            else     {return (b+Math.Tan(a*b))/Math.Cos(a);}
        case 7:
            if(axis) {return (a-Math.Tan(a*b))/Math.Sin(b);}
            else     {return (b-Math.Tan(a*b))/Math.Cos(a);}
        case 8:
            if(axis) {return a/(Math.Cos(b))+a/Math.Sin(b);}
            else     {return b/(Math.Cos(a))+b/Math.Sin(a);}
        case 9:
            if(axis) {return a/(Math.Cos(b)*Math.Sin(b));}
            else     {return b/(Math.Cos(a)*Math.Sin(a));}
        case 10:
            if(axis) {return a/(Math.Cos(Math.Tan(b))*Math.Sin(Math.Tan(b)));}
            else     {return b/(Math.Sin(Math.Tan(a))*Math.Cos(Math.Tan(a)));}
        case 11:
            if(axis) {return (Math.Tan(a)+b)/(Math.Cos(Math.Tan(b))*Math.Sin(Math.Tan(b)));}
            else     {return (Math.Tan(b)+a)/(Math.Sin(Math.Tan(a))*Math.Cos(Math.Tan(a)));}
        case 12:
            if(axis) {return (a+Math.Tan(a)+Math.Tan(b))/(Math.Cos(Math.Tan(b))*Math.Sin(Math.Tan(b)));}
            else     {return (b+Math.Tan(a)+Math.Tan(b))/(Math.Sin(Math.Tan(a))*Math.Cos(Math.Tan(a)));}
        case 13:
            if(axis) {return (a+Math.Tan(a)+Math.Tan(b))/Math.Cos(a);}
            else     {return (b+Math.Tan(a)+Math.Tan(b))/Math.Sin(a);}
        case 14:
            if(axis) {return (a+Math.Tan(a)+Math.Tan(b))/Math.Sin(b);}
            else     {return (b+Math.Tan(a)+Math.Tan(b))/Math.Cos(a);}
        case 15:
            if(axis) {return a/Math.Sin(Math.Cos(b)*Math.Sin(b));}
            else     {return b/Math.Cos(Math.Sin(a)*Math.Cos(a));}
        case 16:
            if(axis) {return (a+Math.Tan(a)/Math.Tan(b))/Math.Cos(a);}
            else     {return (b+Math.Tan(a)/Math.Tan(b))/Math.Sin(b);}
        case 17:
            if(axis) {return (b+Math.Tan(a)/Math.Tan(b))/Math.Cos(a);}
            else     {return (a+Math.Tan(a)/Math.Tan(b))/Math.Sin(b);}
        case 18:
            if(axis) {return (b+Math.Tan(b)/Math.Tan(a))/Math.Cos(a);}
            else     {return (a+Math.Tan(a)/Math.Tan(b))/Math.Sin(b);}
        case 19:
            if(axis) {return (b+Math.Tan(b)/Math.Tan(a))/Math.Cos(a);}
            else     {return (a+Math.Tan(b)/Math.Tan(a))/Math.Sin(b);}
        case 20:
            if(axis) {return (b+Math.Tan(a)/Math.Tan(a))/Math.Cos(a);}
            else     {return (a+Math.Tan(b)/Math.Tan(a))/Math.Sin(b);}
        case 21:
            if(axis) {return b+Math.Tan(a)/(a/(Math.Cos(b)))+(a/(Math.Sin(b)));}
            else     {return a+Math.Tan(b)/(b/(Math.Cos(a)))+(b/(Math.Sin(a)));}
        case 22:
            if(axis) {return a/Math.Sin(a/Math.Sin(b));}
            else     {return b/Math.Cos(b/Math.Cos(a));}
        case 23:
            if(axis) {return a/Math.Cos(a/Math.Sin(b));}
            else     {return b/Math.Sin(b/Math.Cos(a));}
        case 24:
            if(axis) {return a/Math.Cos(a/Math.Atan(Math.Sin(b)));}
            else     {return b/Math.Sin(b/Math.Atan(Math.Cos(a)));}
        case 25:
            if(axis) {return a/Math.Sin(a/Math.Atan(Math.Cos(b)));}
            else     {return b/Math.Cos(b/Math.Atan(Math.Sin(a)));}
        case 26:
            if(axis) {return a/Math.Atan(Math.Cos(b));}
            else     {return b/Math.Atan(Math.Sin(a));}
        case 27:
            if(axis) {return (a+Math.Tanh(a*b))/Math.Cos(b);}
            else     {return (b+Math.Tanh(a*b))/Math.Sin(a);}
        case 28:
            if(axis) {return b+Math.Tan(b)/(a/(Math.Cos(b)))+(a/(Math.Sin(a)));}
            else     {return a+Math.Tan(a)/(b/(Math.Cos(a)))+(b/(Math.Sin(b)));}
        case 29:
            if(axis) {return (a+Math.Tanh(a+b))/Math.Cos(b);}
            else     {return (b+Math.Tanh(a+b))/Math.Sin(a);}
        case 30:
        if(axis) {return (a/Math.Sin(b))/Math.Tan(b);}
            else     {return (b/Math.Cos(a))/Math.Tan(a);}
        case 31:
            if(axis) {return a/(Math.Tan(b)*Math.Cos(b)*Math.Sin(b));}
            else     {return b/(Math.Tan(a)*Math.Cos(a)*Math.Sin(a));}
        case 32:
            if(axis) {return a/Math.Tan(Math.Cos(b));}
            else     {return b/Math.Tan(Math.Sin(a));}
        case 33:
            if(axis) {return (a+Math.Tanh(a*b))/(Math.Cos(b)*Math.Sin(a));}
            else     {return (b+Math.Tanh(a*b))/(Math.Sin(b)*Math.Cos(a));}
        case 34:
            if(axis) {return (a+Math.Tan(Math.Cos(a)*Math.Sin(b)))/Math.Cos(a);}
            else     {return (b+Math.Tan(Math.Sin(a)*Math.Cos(b)))/Math.Sin(b);}
        case 35:
            if(axis) {return (Math.Tan(a+b)*b)/Math.Cos(b);}
            else     {return (Math.Tan(a-b)*a)/Math.Sin(a);}
        case 36:
            if(axis) {return (a/Math.Cos(b))*Math.Sin(a);}
            else     {return (b/Math.Sin(a))*Math.Cos(b);}
        case 37:
            if(axis) {return a/Math.Tan(Math.Cos(b)+Math.Sin(b));}
            else     {return b/Math.Tan(Math.Cos(a)+Math.Sin(a));}
        case 38:
            if(axis) {return a+(Math.Tanh(a+b)/Math.Cos(b));}
            else     {return b+(Math.Tanh(a+b)/Math.Sin(a));}
        case 39:
            if(axis) {return (a/(Math.Cos(b)))/(b/(Math.Sin(a)));}
            else     {return (b/(Math.Cos(a)))/(a/(Math.Sin(b)));}
        case 40:
            if(axis) {return (a*Math.Tan(a+b))/Math.Sin(b);}
            else     {return (b*Math.Tan(a+b))/Math.Cos(a);}
            case 41:
            if(axis) {return a/(Math.Atan2(b*b,a*a)*Math.Tan(b));}
            else     {return b/(Math.Atan2(b*b,a*a)*Math.Tan(a));}
        case 42:
            if(axis) {return Math.Tan(a)/b;}
            else     {return Math.Tan(b)/a;}
        case 43:
            if(axis) {return a/Math.Atan(b/Math.Cos(a/Math.Sin(a)));}
            else     {return b/Math.Atan(a/Math.Sin(b/Math.Cos(b)));}
        default:
            switch(altern){
                case 0:
                    if(axis) {return a/Math.Cos(b);}
                    else     {return b/Math.Sin(a);}
                case 1:
                    if(axis) {return a/Math.Sin(b);}
                    else     {return b/Math.Cos(a);}
                    case 2:
                    if(axis) {return a/Math.Tan(b);}
                    else     {return b/Math.Tan(a);}
                    case 3:
                    if(axis) {return a/Math.Atan(b);}
                    else     {return b/Math.Atan(a);}
                    default:
                    if(use_chaos_mode){
                        if(axis) {return a/cfb;}
                        else     {return b/cfa;}
                    }
                    
                    else{
                        if(axis) {return a;}
                        else     {return b;}
                    }                    
            }
    }
}

void PreRender(Surface dst, Surface src)
{
    int ff;
    int altlim=3;
    altern=0;
    use_chaos_mode = vf_choice > 47;
    if(use_chaos_mode) {ff = vf_choice - 44;}
    else     {ff = vf_choice - 40;}
    bool use_altern = vf_choice > 43;
    double d_escape = (double)(escape);
    int w = src.Width;
    int h = src.Height;
    bool sd_cond = w>h;
    bool resize_w = w%2 == 0;
    bool resize_h = h%2 == 0;
    if (resize_w) {w++;}
    if (resize_h) {h++;}
    if (Thorn_Fractal == null){Thorn_Fractal = new float [w,h];}
    else     { Array.Clear(Thorn_Fractal, 0, w*h);}
    double dw = (double)(w);
    double dh = (double)(h);
    double sd = Math.Max(w,h)/Math.Min(w,h);
    double sx = w > h ? sd : 1  ;
    double sy = w > h ? 1  : sd ;
    int sub_w=w*sublevel;
    int sub_h=h*sublevel;
    bool resize_sub_w = sub_w%2 == 0;
    bool resize_sub_h = sub_h%2 == 0;
    if (resize_sub_w) {sub_w++;}
    if (resize_sub_h) {sub_h++;}
    int windows=sublevel * sublevel;
    double rpi = r_pi ? Math.PI : 1 ;
    double szx = rpi * r_x * r_xy;
    double szy = rpi * r_y * r_xy;
    double ang = angle / 180 * Math.PI;
    double cos_ang = Math.Cos(ang);
    double sin_ang = Math.Sin(ang);
    double ox = Offset.First * cos_ang - Offset.Second * sin_ang;
    double oy = Offset.First * sin_ang + Offset.Second * cos_ang;
    int v_sum=0;
    maxnum = 0;
    float ev;
    int sub_x,sub_y,nx,ny,v;
    double xx,yy,zx,zy,vx,vy,a,b;
    for ( int y = 0 ; y < h ; y++){
        if (IsCancelRequested) return;
        ny = y * sublevel;
        for (int x = 0 ; x < w ; x++){
            nx = x * sublevel;
            v_sum=0;
            for (sub_y = 0 ; sub_y < sublevel ; sub_y++){
                yy = (double) (2 * (((double)(ny)+(double)(sub_y))/(double)(sub_h)-.5));
                yy*=sy;
                for (sub_x = 0 ; sub_x < sublevel ; sub_x++){
                    xx = (double) (2 * (((double)(nx) + (double)(sub_x))/(double)(sub_w)-.5));
                    xx*=sx;
                    zx = szx * ((xx*cos_ang-yy*sin_ang)+ox);
                    zy = szy * ((xx*sin_ang+yy*cos_ang)+oy);
                    vx = zx;
                    vy = zy;
                    for (v=0 ; v<max_iter ; v++){
                        a=vx;
                        b=vy;
                        vx=vf(a,b,vf_choice,0);
                        vy=vf(a,b,vf_choice,1);
                        if(use_chaos_mode){if(altern==altlim){
                            cfa = Math.Atan(vx);
                            cfb = Math.Atan(vy);
                            }
                        }
                        vx+=dx;
                        vy+=dy;
                        if (use_altern){altern++;if(altern>ff){altern=0;}}
                        if ((vx*vx+vy*vy)>d_escape){break;}
                    }
                    v = zx!=0&&zy!=0?v:0;
                    v_sum+=v;
                }                
            }
            ev = (float)(v_sum)/(float)(windows);
            if (ev > maxnum) { maxnum = ev;}
            Thorn_Fractal[x,y] = ev;
        }
    }
}

void Render(Surface dst, Surface src, Rectangle rect)
{
    float TF_val;
    int val;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {        
        for (int x = rect.Left; x < rect.Right; x++)
        {
            TF_val = Thorn_Fractal[x,y] / maxnum * 255;
            val = (int)(Math.Round(TF_val));
            dst[x,y]=ColorBgra.FromBgraClamped(val,val,val,255);
        }
    }
}

 

 

Edited by Reptillian
I forgotten cfa, and cfb. Now fixed.

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...