. HOME
 
. Features
. Gallery
. Download
. Documentation
 
. Resources
. Mailing Lists
. Programs
. Feature Voting
. Wishlist
 
. Theory
. Tutorials
 
. Formula DB
 
. Contact
CHAOSPRO 3.2
Release 4.0
.

ChaosPro Formula Database

  
NameFractInt.ccl
Path/Compiler/Compatibility/
TypeColoring
Size17 KB
OwnerMartin Pfingstl
Last Modified:10 Feb 2011
  


comment {
These formulas should imitate FractInt's coloring
options for the different fractal types.
If you encounter problems, please let me know.
Not all FractInt options work.

Enjoy,
	Martin Pfingstl
}

FractInt_Inside {
real z_min,zmodulo;
shared int iEpsilonCross;
int min_iter,current_iter;
parameter int iInside;
parameter int iColorIndex;
// bTruncate must be true in order to mimic FractInt 256-color behaviour
parameter bool bTruncate;
parameter real iEpsCrossDistance;
bool bSearchPeriodicity;
int startSearch,perLength;
int periodicityColor;
complex periodicityZ;
real eps;
parameter real perValue;
real delxx,delxx2,delyy,delyy2,ddelmin;
shared int iPotential;
shared real potMaxCol;
shared int iLogmap;
shared real coloriter;

	double calclog(double idx)
	{
	real lf,range;
	int iMaxiter;
	
		iMaxiter=maxiter+1;
		if  (iLogmap>0)
		{
			if (idx>iMaxiter) {
				idx=iMaxiter;
			}
			// FractInt "new style" logarithmic scaling...
			// iLogmapSetting=1 ==> Standard logmap, >1 ==> Standard logmap, but starting at iteration count "iLogmapSetting"
			if  (iLogmap>1)
			{
				lf = iLogmap;
			}
			else
			{
				lf = 0;
			}
			if  (lf>=iMaxiter)
			{
				lf = iMaxiter-1;
			}
			
			if  (lf>0)
			{
				range = 254 / log(iMaxiter- lf);
			}
			else
			{
				range = 255 / log(iMaxiter);
			}
			
			if  (idx<=lf)
			{
				idx = 1;
			}
			else if  ( (idx - lf) / log(idx - lf) <= range)
			{
				if  (lf>0)
				{
					idx = idx - lf + 1;
				}
				else
				{
					idx = idx - lf;
				}
			}
			else
			{
				idx = range * log(idx - lf)+1;
			}
		}
		else if  (iLogmap == -1)
		{
			if (idx>iMaxiter) {
				idx=iMaxiter;
			}
			if (idx==0)
			{
				idx = 1;
			}
			else
			{
				idx = (255 / log(iMaxiter)) * log(idx)+1;
			}
		}
		else if  (iLogmap<=-2)
		{
			if (idx>iMaxiter) {
				idx=iMaxiter;
			}
			lf = -iLogmap;
			if  (lf >= iMaxiter)
			{
				lf = iMaxiter- 1;
			}
			range = 254 / sqrt(iMaxiter- lf);
			if  (idx <= lf)
			{
				idx = 1;
			}
			else if  ((idx - lf) <= sqr(range))
			{
				idx = idx - lf + 0;
			}
			else
			{
				idx = 1 + range * sqrt(idx - lf);
			}    
		}
		return(idx);
	}
	void init(void)
	{
		iEpsilonCross=0;
		if (iInside=="bof61")
		{		
			min_iter=0;
		}
		else if (iInside=="epsiloncross")
		{
			iEpsilonCross=0; // 0 means, nothing has been done...
		}
		else if (iInside=="periodicity")
		{
			bSearchPeriodicity=true;
			current_iter=1;
			// Calcfrac.c, l 1526
			startSearch=maxiter*4/5;
			// calcfrac.c, l 1596
			perLength=16;
			
			periodicityColor=maxiter;
			periodicityZ=(0,0);
			delxx  = (real(corner_rightbottom) - real(corner_lefttop)) / (width-1);
			delyy  = (imag(corner_lefttop) - imag(corner_rightbottom)) / (height-1);
			delxx2 = (real(corner_lefttop) - real(corner_lefttop)) / (height-1);
			delyy2 = (imag(corner_rightbottom) - imag(corner_rightbottom)) / (width-1);
			ddelmin = abs(delxx);
			if (abs(delxx2) > ddelmin)
			{
				ddelmin = abs(delxx2);
			}
			if (abs(delyy) > abs(delyy2))
			{
				if (abs(delyy) < ddelmin)
				{
					ddelmin = abs(delyy);
				}
			}
			else if (abs(delyy2) < ddelmin)
			{
				ddelmin = abs(delyy2);
			}
			// calcfrac.c, l 616 0.0005
			eps=ddelmin * exp(-log(2) * abs(perValue));
		}
		z_min=100000;
	}
	void loop(void)
	{
		if (iInside=="bof60") // bof60
		{
			zmodulo=|z|;
			if (zmodulo<z_min)
			{
				z_min=zmodulo;
			}
		}
		else if (iInside=="bof61") // bof61
		{
			zmodulo=|z|;
			if (zmodulo<z_min)
			{
				z_min=zmodulo;
				min_iter=numiter+2;
			}
		}
		else if (iInside=="epsiloncross") // epsilon cross
		{
			if (iEpsilonCross==0)
			{
				if (abs(real(z))<iEpsCrossDistance)
				{
					iEpsilonCross=2;
				}
				if (abs(imag(z))<iEpsCrossDistance)
				{
					iEpsilonCross=6;
				}
			}
		}
		else if (iInside=="periodicity") // epsilon cross
		{
			// no periodicity found, but iteration reached?
			if (bSearchPeriodicity && current_iter>=startSearch)
			{
				// ok, now lets search for periodicity
				if (current_iter>startSearch && current_iter<startSearch+perLength)
				{
					// now did we find a cycle?
					if (abs(real(periodicityZ-z))<eps && abs(imag(periodicityZ-z))<eps)
					{
						bSearchPeriodicity=false;
						periodicityColor=current_iter-startSearch;
					}
				}
				else
				{
					periodicityZ=z;
					perLength=perLength+perLength+1;
					startSearch=current_iter;					
				}
			}
			current_iter=current_iter+1;
		}
	}
	void final(void)
	{
		alpha=0;
		if (iInside=="<nnn>")
		{
			if (iColorIndex==-1)
			{
				index=maxiter;
			}
			else
			{
				index=iColorIndex;
			}
		}
		else if (iInside=="maxiter")
		{
			index=maxiter+1;
		}
		else if (iInside=="zmag")
		{
			index = |z|*floor((maxiter+1) / 2)+1;
		}
		else if (iInside=="bof60")
		{
			index = sqrt(z_min) * 75;
		}
		else if (iInside=="bof61")
		{
			index=min_iter;
		}
		else if (iInside=="epsiloncross")
		{
			index = iEpsilonCross;
			if (index==0)
			{
				index=maxiter;
			}
		}
		else if (iInside=="periodicity")
		{
			if (periodicityColor>255) {
				index = 255;
			}
			else {
				index = periodicityColor;
			}
		}
		if (iPotential==1)
		{
			if (iInside!="<nnn>")
			{
				index=potMaxCol;
			}
			if (bTruncate)
			{
				index=trunc(index);
			}
		}
		if (iInside!="<nnn>")
		{
			index=calclog(index);
		}
		if (coloriter!=0)
		{
			index=coloriter;
		}
		if (bTruncate)
		{
			index=trunc(index);
		}
		alpha=0;
		index=((index)%252)/252;
	}
	void description(void)
	{
		this.title="Inside";
		this.helpfile="http://www.chaospro.de/";

		bTruncate.caption="Truncate";
		bTruncate.hint="If set, the resulting color index gets truncated to the nearest color index. Otherwise (i.e. normal behaviour of ChaosPro) the two neighboured colors would be interpolated.";
		bTruncate.default=true;		                  
	
		iInside.caption="Inside Coloring";
		iInside.hint="This option specifies the algorithm to use for inside coloring";
		iInside.enum="<nnn>\nmaxiter\nzmag\nbof60\nbof61\nepsiloncross\nperiodicity";
		iInside.default=0;

		iColorIndex.caption="Color Index";
		iColorIndex.hint="Specifies the color to use. -1 means 'maxiter'. Parameter is used only if Inside-Coloring is set to <nnn>";
		iColorIndex.default=1.0;
		iColorIndex.min=-1.0;
		iColorIndex.max=255.0;
		iColorIndex.visible=iInside=="<nnn>";

		iEpsCrossDistance.caption="Distance";
		iEpsCrossDistance.hint="Valid only for epsilon cross coloring: Specifies the distance from the axis";
		iEpsCrossDistance.default=0.01;
		iEpsCrossDistance.min=0.0000000000000000001;
		iEpsCrossDistance.max=100000;
		iEpsCrossDistance.visible=iInside=="epsiloncross";
		
		perValue.caption="Periodicity Bailin";
		perValue.default=1.0;
		perValue.min=1.0;
		perValue.hint="Defines the bailin value for periodicity";
		perValue.visible=iInside=="periodicity";
	}
}

FractInt_Decomp(OUTSIDE) {
real lowestIter,range;
real z_angle;
parameter int iDecomp;
parameter int iLogmapSetting;
parameter bool bTruncate;

	void final(void)
	{
		z_angle = atan2(z);
	
		if (z_angle<0)
		{
			z_angle = z_angle + 2*pi;
		}

		if  (iDecomp<256)
		{
			index = 1;
		}
		else
		{
			index = 0;
		}

		if  (bTruncate)
		{
			index = index + (z_angle * (iDecomp - index)) / (2 * pi);
		}
		else
		{

			index = index + trunc((z_angle * iDecomp) / (2 * pi));
		}

		if  (iLogmapSetting != 0 && index > maxiter)
		{
			index = maxiter;
		}    

		if  (iLogmapSetting>0)
		{
			// iLogmapSetting=1 ==> Standard logmap, >1 ==> Standard logmap, but starting at iteration count <iLogmapSetting>
			if  (iLogmapSetting>1)
			{
				lowestIter = iLogmapSetting;
			}
			else
			{
				lowestIter = 0;
			}
			// Lets initialize a helper variable for the available range (from lowestIter upto maxiter)
			// In order to avoid math errors, let us restrict lowestIter to a value smaller than maxiter...
			if  (lowestIter>=maxiter)
			{
				lowestIter = maxiter-1;
			}
			if  (lowestIter>0)
			{
				range = 255 / log(maxiter - lowestIter);
			}
			else
			{
				range = 256 / log(maxiter);
			}
			if  (index<=lowestIter)
			{
				index = 1;
			}
			else if  ( (index - lowestIter) / log(index - lowestIter) <= range)
			{
				if  (lowestIter>0)
				{
					index = index - lowestIter + 1;
				}
				else
				{
					index = index - lowestIter;
				}
			}
			else
			{
				index = 1 + range * log(index - lowestIter);
			}
		}
		else if  (iLogmapSetting == -1)
		{
			if (index==0)
			{
				index = 1;
			}
			else
			{
				index = 1 + (256 / log(150)) * log(index);
			}
		}
		else if  (iLogmapSetting < -1)
		{
			lowestIter = -iLogmapSetting;
			if  (lowestIter >= maxiter)
			{
				lowestIter = maxiter - 1;
			}
			range = 256 / sqrt(maxiter - lowestIter);
			if  (index <= lowestIter)
			{
				index = 1;
			}
			else if  ((index - lowestIter) <= sqr(range))
			{
				index = index - lowestIter + 1;
			}
			else
			{
				index = 1 + range * sqrt(index - lowestIter);
			}    
		}

		index = (index % 252) / 252;

	}
	void description(void)
	{
		this.title = "Decomposition";
		this.helpfile="http://www.chaospro.de/";

		iDecomp.caption = "Decomposition";
		iDecomp.hint = "This is the Decomp Option parameter in Fractint.";
		iDecomp.default = 256;
		iDecomp.min = 0;
		iDecomp.max = 256;

		iLogmapSetting.caption = "Log Palette";
		iLogmapSetting.hint = "Imitates the Log Palette value in Fractint. 0=no, 1=yes, -1=old, +n=cmprsd, -n=sqrt.";
		iLogmapSetting.default = 0;

		bTruncate.caption="Truncate";
		bTruncate.hint="If set, the resulting color index gets truncated to the nearest color index. Otherwise (i.e. normal behaviour of ChaosPro) the two neighboured colors would be interpolated.";
		bTruncate.default=true;		                  
	
	}
}

FractInt_Outside(OUTSIDE) {
bool bSkip;
parameter int iOutside;
parameter real iColorIndex;
parameter bool bTruncate;
parameter bool bRestrict;
parameter int iLogmapSetting;
parameter real rBiomorphSetting;
int iterations;
parameter real outsideMult;
parameter real slope;
parameter int iDecomp;
parameter bool bDecomp;
shared int iEpsilonCross;
real z_angle;
parameter int version;
shared int iPotential;
shared real potMaxCol;
shared int iLogmap;
shared real formulaBailout;
shared real rBiomorph;
shared real coloriter;
real distance;
complex prevZ;

	double calclog(double idx)
	{
	real lf,range;
	int iMaxiter;
	
		/*if (!idx)
		{
			return(0);
		}*/
		iMaxiter=maxiter+1;
		if  (iLogmap>0)
		{
			if (idx>iMaxiter) {
				idx=iMaxiter;
			}
			// FractInt "new style" logarithmic scaling...
			// iLogmapSetting=1 ==> Standard logmap, >1 ==> Standard logmap, but starting at iteration count "iLogmapSetting"
			if  (iLogmap>1)
			{
				lf = iLogmap;
			}
			else
			{
				lf = 0;
			}
			if  (lf>=iMaxiter)
			{
				lf = iMaxiter-1;
			}
			
			if  (lf>0)
			{
				range = 254 / log(iMaxiter- lf);
			}
			else
			{
				range = 255 / log(iMaxiter);
			}
			
			if  (idx<=lf)
			{
				// Egg should use 0...but why?
				idx = 1;
			}
			else if  ( (idx - lf) / log(idx - lf) <= range)
			{
				if  (lf>0)
				{
					idx = idx - lf + 1;
				}
				else
				{
					idx = idx - lf;
				}
			}
			else
			{
				idx = range * log(idx - lf)+1;
			}
		}
		else if  (iLogmap == -1)
		{
			if (idx>iMaxiter) {
				idx=iMaxiter;
			}
			if (idx==0)
			{
				idx = 1;
			}
			else
			{
				idx = (255 / log(iMaxiter)) * log(idx)+1;
			}
		}
		else if  (iLogmap<=-2)
		{
			if (idx>iMaxiter) {
				idx=iMaxiter;
			}
			lf = -iLogmap;
			if  (lf >= iMaxiter)
			{
				lf = iMaxiter- 1;
			}
			range = 254 / sqrt(iMaxiter- lf);
			if  (idx <= lf)
			{
				idx = 1;
			}
			else if  ((idx - lf) <= sqr(range))
			{
				idx = idx - lf + 0;
			}
			else
			{
				idx = 1 + range * sqrt(idx - lf);
			}    
		}
		return(idx);
	}
	double potential(double mag,double PotMaxCol,double PotSlope)
	{
	double pot;
	int l_pot;

		// NYUF009 will iterations+3
		// NYUF008 will iterations+3
		// AtomicGlow will iterations+3
		pot = iterations+3;
		if (pot <= 0 || mag <= 1.0) {
			pot = 0.0;
		}
		else {
			pot = log(mag)/(2^pot);
		}
		if (pot > 0.0) {
			pot = sqrt(pot);
			pot = PotMaxCol - pot*PotSlope - 1.0;
		}
		else {
			pot = PotMaxCol - 1.0;
		}
		if (pot < 1.0) {
			pot = 1.0;
		}
		return(pot);
	}
	void init_once(void)
	{
		iPotential=0;
		iLogmap=iLogmapSetting;
		rBiomorph=rBiomorphSetting;
		if (iOutside=="potential")
		{
			iPotential=1;
			potMaxCol=outsideMult;
		}
		formulaBailout=-1;
	}
	void init(void)
	{
		distance=0;
		prevZ=z;
		if (formulaBailout<0) {
			formulaBailout=100;
		}
	}
	void loop(void)
	{
		if (iOutside=="tdis")
		{
			distance=distance+cabs(z-prevZ);
			prevZ=z;
		}
	}
	void final(void)
	{
		if (bDecomp && iOutside!="potential")
		{
			z_angle = atan2(z);
			if (z_angle<0) {
				z_angle = z_angle + 2*pi;
			}
			if  (iDecomp<256) {
				index = 1;
			}
			else {
				index = 0;
			}
	
			if  (bTruncate) {
				index = index + trunc((z_angle * iDecomp) / (2 * pi));
			}
			else {
				index = index + (z_angle * (iDecomp - index)) / (2 * pi);
			}
			if  (iLogmapSetting != 0 && index > maxiter)
			{
				index = maxiter;
			}    
		}
		else
		{
			bSkip= (iOutside==1);
			alpha=numiter%2;
			index=1+numiter;
			// iOutside: 0 ==> <nnn>
			//           1 ==> iter^
			//           2 ==> real
			//					 3 ==> imag
			//           4 ==> mult
			//           5 ==> mult
			//           6 ==> summ
			//           7 ==> atan
			if (iOutside=="real")
			{
				if (bTruncate)
				{
					index=index+7+trunc(real(z));
				}
				else
				{
					index=index+7+real(z);
				}
			}
			else if (iOutside=="imag")
			{
				if (bTruncate)
				{
					index=index+7+trunc(imag(z));
				}
				else
				{
					index=index+7+imag(z);
				}
			}
			else if (iOutside=="mult")
			{
				if (bTruncate)
				{
					index=trunc(index*real(z)/imag(z));
				}
				else
				{
					index=index*real(z)/imag(z);
				}
			}
			else if (iOutside=="summ")
			{
				if (bTruncate)
				{
					index=index+trunc(real(z)+imag(z));
				}
				else
				{
					index=index+real(z)+imag(z);
				}
			}
			else if (iOutside=="atan")
			{
				if (bTruncate)
				{
					index=trunc(abs(atan2(z)*180/pi));
				}
				else
				{
					index=abs(atan2(z)*180/pi);
				}
			}
			else if (iOutside=="potential")
			{
				iterations=numiter;
				index=abs(potential(|z|,outsideMult,slope));
				if (bTruncate)
				{
					index=trunc(index);
				}
			}
			else if (iOutside=="tdis")
			{
				index=distance;
				if (bTruncate)
				{
					index=trunc(index);
				}
			}
	
			if  (rBiomorphSetting>=0 && ( abs(real(z))<=sqrt(formulaBailout) || abs(imag(z))<=sqrt(formulaBailout) ) )
			{
				index = rBiomorphSetting;
				bSkip = false;
			}
			if (iOutside!="potential")
			{
				if  (index<=0 || index>maxiter)
				{
					if (version<1961)
					{
						index = 0;
					}
					else
					{
						index = 1;
					}
				}
			}
		}
		if (iOutside==0 && !bDecomp)
		{
			index=iColorIndex;
		}
		else
		{
			index=calclog(index);
		}
		if (coloriter!=0)
		{
			index=coloriter;
		}
		// epscross also affects outside colorings!
		if (iEpsilonCross>0) {
			index=iEpsilonCross;
			bSkip=false;
		}
		if  (bSkip)
		{
			index = (1 + (index - 1)%252) / 252;
		}
		else
		{
			index = (index % 252) / 252;
		}
	}
	void description(void)
	{
		this.title="Outside";
		this.helpfile="http://www.chaospro.de/";

		iOutside.caption="Outside Coloring";
		iOutside.hint="This option specifies the algorithm to use for outside coloring";
		iOutside.enum="<nnn>\niter\nreal\nimag\nmult\nsumm\natan\npotential\ntdis";
		iOutside.default=1;

		outsideMult.caption="Max Color";
		outsideMult.default=1.0;
		outsideMult.visible=(iOutside==7);
		
		slope.caption="Slope";
		slope.default=1.0;
		slope.visible=(iOutside==7);
		
		iColorIndex.caption="Color Index";
		iColorIndex.hint="Specifies the color to use. Parameter is used only if Outside-Coloring is set to <nnn>";
		iColorIndex.default=1;
		iColorIndex.min=0;
		iColorIndex.max=255;
		iColorIndex.visible=(iOutside==0);

		bTruncate.caption="Truncate";
		bTruncate.hint="If set, the resulting color index gets truncated to the nearest color index. Otherwise (i.e. normal behaviour of ChaosPro) the two neighboured colors would be interpolated.";
		bTruncate.default=true;		                  

		bRestrict.caption="Cut Colors";
		bRestrict.hint="If set, the resulting index value is restricted to 0..maxiter: If it falls outside, it is set to 0 or maxiter.";
		bRestrict.default=false;

		iLogmapSetting.caption = "Log Palette";
		iLogmapSetting.hint = "Imitates the Log Palette value in Fractint. 0=no, 1=yes, -1=old, +n=cmprsd, -n=sqrt.";
		iLogmapSetting.default = 0;

		rBiomorphSetting.caption = "Biomorph Color";
		rBiomorphSetting.hint = "Reconstructs the biomorph option from FractInt. -1 turns biomorph coloring off (default). A color value (0..255) turns it on using the specified color.";
		rBiomorphSetting.default = -1;
		rBiomorphSetting.min = -1;
		rBiomorphSetting.max = 255;

		version.caption="FractInt Version";
		version.default=1960;
		version.hint="Specifies the FractInt version.";
	}
}