1 /**
2  * Mandelbulber v2, a 3D fractal generator  _%}}i*<.         ______
3  * Copyright (C) 2020 Mandelbulber Team   _>]|=||i=i<,      / ____/ __    __
4  *                                        \><||i|=>>%)     / /   __/ /___/ /_
5  * This file is part of Mandelbulber.     )<=i=]=|=i<>    / /__ /_  __/_  __/
6  * The project is licensed under GPLv3,   -<>>=|><|||`    \____/ /_/   /_/
7  * see also COPYING file in this folder.    ~+{i%+++
8  *
9  * 4D boxbulb, Formula based on Mandelbox (ABox). Extended to 4 dimensions and with variable scale
10  * parameter.
11  * This formula contains aux.color and aux.actualScale
12  */
13 
14 #include "all_fractal_definitions.h"
15 
cFractalTesting4d()16 cFractalTesting4d::cFractalTesting4d() : cAbstractFractal()
17 {
18 	nameInComboBox = "Testing4d";
19 	internalName = "testing4d";
20 	internalID = fractal::testing4d;
21 	DEType = analyticDEType;
22 	DEFunctionType = logarithmicDEFunction;
23 	cpixelAddition = cpixelEnabledByDefault;
24 	defaultBailout = 100.0;
25 	DEAnalyticFunction = analyticFunctionLogarithmic;
26 	coloringFunction = coloringFunctionDefault;
27 }
28 
FormulaCode(CVector4 & z,const sFractal * fractal,sExtendedAux & aux)29 void cFractalTesting4d::FormulaCode(CVector4 &z, const sFractal *fractal, sExtendedAux &aux)
30 {
31 	double colorAdd = 0.0;
32 	double rrCol = 0.0;
33 	CVector4 zCol = z;
34 	CVector4 oldZ = z;
35 
36 	// parabolic.w = paraOffset + iter *slope + (iter *iter *scale)
37 	double paraAddP0 = 0.0;
38 	if (fractal->Cpara.enabledParabFalse)
39 	{
40 		double parabScale = 0.0;
41 		if (fractal->Cpara.parabScale != 0.0)
42 			parabScale = aux.i * aux.i * 0.001 * fractal->Cpara.parabScale;
43 		paraAddP0 = fractal->Cpara.parabOffset0 + (aux.i * fractal->Cpara.parabSlope) + (parabScale);
44 		z.w += paraAddP0;
45 	}
46 
47 	// sinusoidal w
48 	double sinAdd = 0.0;
49 	if (fractal->transformCommon.functionEnabledDFalse)
50 	{
51 		sinAdd = sin((aux.i + fractal->transformCommon.offset0) / fractal->transformCommon.scaleA1)
52 						 * fractal->transformCommon.scaleC1;
53 		z.w += sinAdd;
54 	}
55 
56 	/*	CVector4 temp = fractal->transformCommon.offset0000;
57 		CVector4 temp2 = temp * temp;
58 
59 		z.x += ((8.0 * temp.x * temp2.x) / ((z.x * z.x) + (4.0 * temp2.x)) - 2.0 * temp.x) * sign(z.x) *
60 		fractal->transformCommon.scale1;
61 		z.y += ((8.0 * temp.y * temp2.y) / ((z.y * z.y) + (4.0 * temp2.y)) - 2.0 * temp.y) * sign(z.y) *
62 		fractal->transformCommon.scale1;
63 		z.z += ((8.0 * temp.z * temp2.z) / ((z.z * z.z) + (4.0 * temp2.z)) - 2.0 * temp.z) * sign(z.z) *
64 		fractal->transformCommon.scale1;
65 		z.w += ((8.0 * temp.w * temp2.w) / ((z.w * z.w) + (4.0 * temp2.w)) - 2.0 * temp.w) * sign(z.w) *
66 		fractal->transformCommon.scale1*/
67 
68 	if (aux.i >= fractal->transformCommon.startIterationsB
69 			&& aux.i < fractal->transformCommon.stopIterationsB)
70 	{
71 		oldZ = z;
72 		z.x = fabs(z.x + fractal->transformCommon.offset1111.x)
73 					- fabs(z.x - fractal->transformCommon.offset1111.x) - z.x;
74 		z.y = fabs(z.y + fractal->transformCommon.offset1111.y)
75 					- fabs(z.y - fractal->transformCommon.offset1111.y) - z.y;
76 		z.z = fabs(z.z + fractal->transformCommon.offset1111.z)
77 					- fabs(z.z - fractal->transformCommon.offset1111.z) - z.z;
78 		z.w = fabs(z.w + fractal->transformCommon.offset1111.w)
79 					- fabs(z.w - fractal->transformCommon.offset1111.w) - z.w;
80 		zCol = z;
81 	}
82 	CVector4 temp = fractal->transformCommon.offset0000;
83 	CVector4 temp2 = temp * temp;
84 	// if (z.w < 1e-016) z.w = 1e-016;
85 	if (z.w < 1e-21 && z.w > -1e-21) z.w = (z.w > 0) ? 1e-21 : -1e-21;
86 	z.x += ((8.0 * temp.x * temp2.x) / ((z.x * z.x) + (4.0 * temp2.x)) - 2.0 * temp.x) * sign(z.x)
87 				 * fractal->transformCommon.scale1;
88 	z.y += ((8.0 * temp.y * temp2.y) / ((z.y * z.y) + (4.0 * temp2.y)) - 2.0 * temp.y) * sign(z.y)
89 				 * fractal->transformCommon.scale1;
90 	z.z += ((8.0 * temp.z * temp2.z) / ((z.z * z.z) + (4.0 * temp2.z)) - 2.0 * temp.z) * sign(z.z)
91 				 * fractal->transformCommon.scale1;
92 	z.w += ((8.0 * temp.w * temp2.w) / ((z.w * z.w) + (4.0 * temp2.w)) - 2.0 * temp.w) * sign(z.w)
93 				 * fractal->transformCommon.scale1;
94 
95 	// r power
96 	if (aux.i >= fractal->transformCommon.startIterationsS
97 			&& aux.i < fractal->transformCommon.stopIterationsS)
98 	{
99 		double rr = z.Dot(z);
100 		rrCol = rr;
101 		if (fractal->mandelboxVary4D.rPower != 1.0) rr = pow(rr, fractal->mandelboxVary4D.rPower);
102 
103 		// spherical fold
104 		// z += fractal->transformCommon.offset0000;
105 		if (rr < fractal->transformCommon.minR2p25)
106 		{
107 			z *= fractal->transformCommon.maxMinR2factor;
108 			aux.DE *= fractal->transformCommon.maxMinR2factor;
109 			// colorAdd += fractal->mandelbox.color.factorSp1 * (fractal->transformCommon.minR2p25 - rr);
110 		}
111 		else if (rr < fractal->transformCommon.maxR2d1)
112 		{
113 			z *= fractal->transformCommon.maxR2d1 / rr;
114 			aux.DE *= fractal->transformCommon.maxR2d1 / rr;
115 			// colorAdd += fractal->mandelbox.color.factorSp2 * (rr - fractal->transformCommon.minR2p25);
116 		}
117 		/*else
118 			colorAdd += fractal->mandelbox.color.factorSp2
119 							* (fractal->transformCommon.maxR2d1 - fractal->transformCommon.minR2p25);*/
120 
121 		// z -= fractal->transformCommon.offset0000;
122 	}
123 
124 	// scale
125 	double useScale = 1.0;
126 	if (aux.i >= fractal->transformCommon.startIterationsC
127 			&& aux.i < fractal->transformCommon.stopIterationsC)
128 	{
129 
130 		useScale = aux.actualScaleA + fractal->transformCommon.scale;
131 
132 		z *= useScale;
133 		aux.DE = aux.DE * fabs(useScale);
134 
135 		if (aux.i >= fractal->transformCommon.startIterationsX
136 				&& aux.i < fractal->transformCommon.stopIterationsX)
137 		{
138 			// update actualScale for next iteration
139 			double vary = fractal->transformCommon.scaleVary0
140 										* (fabs(aux.actualScaleA) - fractal->transformCommon.scaleB1);
141 			if (fractal->transformCommon.functionEnabledMFalse)
142 				aux.actualScaleA = -vary;
143 			else
144 				aux.actualScaleA = aux.actualScaleA - vary;
145 		}
146 	}
147 
148 	// 6 plane rotation
149 	if (fractal->transformCommon.functionEnabledRFalse
150 			&& aux.i >= fractal->transformCommon.startIterationsR
151 			&& aux.i < fractal->transformCommon.stopIterationsR)
152 	{
153 		CVector4 tp;
154 		if (fractal->transformCommon.rotation44a.x != 0)
155 		{
156 			tp = z;
157 			double alpha = fractal->transformCommon.rotation44a.x * M_PI_180;
158 			z.x = tp.x * cos(alpha) + tp.y * sin(alpha);
159 			z.y = tp.x * -sin(alpha) + tp.y * cos(alpha);
160 		}
161 		if (fractal->transformCommon.rotation44a.y != 0)
162 		{
163 			tp = z;
164 			double beta = fractal->transformCommon.rotation44a.y * M_PI_180;
165 			z.y = tp.y * cos(beta) + tp.z * sin(beta);
166 			z.z = tp.y * -sin(beta) + tp.z * cos(beta);
167 		}
168 		if (fractal->transformCommon.rotation44a.z != 0)
169 		{
170 			tp = z;
171 			double gamma = fractal->transformCommon.rotation44a.z * M_PI_180;
172 			z.x = tp.x * cos(gamma) + tp.z * sin(gamma);
173 			z.z = tp.x * -sin(gamma) + tp.z * cos(gamma);
174 		}
175 		if (fractal->transformCommon.rotation44b.x != 0)
176 		{
177 			tp = z;
178 			double delta = fractal->transformCommon.rotation44b.x * M_PI_180;
179 			z.x = tp.x * cos(delta) + tp.w * sin(delta);
180 			z.w = tp.x * -sin(delta) + tp.w * cos(delta);
181 		}
182 		if (fractal->transformCommon.rotation44b.y != 0)
183 		{
184 			tp = z;
185 			double epsilon = fractal->transformCommon.rotation44b.y * M_PI_180;
186 			z.y = tp.y * cos(epsilon) + tp.w * sin(epsilon);
187 			z.w = tp.y * -sin(epsilon) + tp.w * cos(epsilon);
188 		}
189 		if (fractal->transformCommon.rotation44b.z != 0)
190 		{
191 			tp = z;
192 			double zeta = fractal->transformCommon.rotation44b.z * M_PI_180;
193 			z.z = tp.z * cos(zeta) + tp.w * sin(zeta);
194 			z.w = tp.z * -sin(zeta) + tp.w * cos(zeta);
195 		}
196 	}
197 	z += fractal->transformCommon.additionConstant0000;
198 
199 	/*CVector4 temp = fractal->transformCommon.offset0000;
200 	CVector4 temp2 = temp * temp;
201 
202 	z.x += ((8.0 * temp.x * temp2.x) / ((z.x * z.x) + (4.0 * temp2.x)) - 2.0 * temp.x) * sign(z.x)
203 				 * fractal->transformCommon.scale1;
204 	z.y += ((8.0 * temp.y * temp2.y) / ((z.y * z.y) + (4.0 * temp2.y)) - 2.0 * temp.y) * sign(z.y)
205 				 * fractal->transformCommon.scale1;
206 	z.z += ((8.0 * temp.z * temp2.z) / ((z.z * z.z) + (4.0 * temp2.z)) - 2.0 * temp.z) * sign(z.z)
207 				 * fractal->transformCommon.scale1;
208 	z.w += ((8.0 * temp.w * temp2.w) / ((z.w * z.w) + (4.0 * temp2.w)) - 2.0 * temp.w) * sign(z.w)
209 				 * fractal->transformCommon.scale1;*/
210 
211 	if (aux.i >= fractal->transformCommon.startIterationsA
212 			&& aux.i < fractal->transformCommon.stopIterationsA)
213 	{
214 		aux.r = z.Length();
215 		aux.DE = aux.r * aux.DE * 16.0 * fractal->analyticDE.scale1
216 							 * sqrt(fractal->foldingIntPow.zFactor * fractal->foldingIntPow.zFactor + 2.0
217 											+ fractal->analyticDE.offset2)
218 							 / SQRT_3
219 						 + fractal->analyticDE.offset1;
220 
221 		z = z * 2.0;
222 		double x2 = z.x * z.x;
223 		double y2 = z.y * z.y;
224 		double z2 = z.z * z.z;
225 		double temp = 1.0 - z2 / (x2 + y2);
226 		CVector4 zTemp;
227 		zTemp.x = (x2 - y2) * temp;
228 		zTemp.y = 2.0 * z.x * z.y * temp;
229 		zTemp.z = -2.0 * z.z * sqrt(x2 + y2);
230 		zTemp.w = z.w;
231 		z = zTemp;
232 		z.z *= fractal->foldingIntPow.zFactor;
233 	}
234 
235 	// color updated v2.13 & mode2 v2.14
236 	if (fractal->foldColor.auxColorEnabledFalse)
237 	{
238 		if (fractal->transformCommon.functionEnabledCxFalse)
239 		{
240 			if (zCol.x != oldZ.x)
241 				colorAdd +=
242 					fractal->mandelbox.color.factor.x * (fabs(zCol.x) - fractal->mandelbox.color.factor4D.x);
243 			if (zCol.y != oldZ.y)
244 				colorAdd +=
245 					fractal->mandelbox.color.factor.y * (fabs(zCol.y) - fractal->mandelbox.color.factor4D.y);
246 			if (zCol.z != oldZ.z)
247 				colorAdd +=
248 					fractal->mandelbox.color.factor.z * (fabs(zCol.z) - fractal->mandelbox.color.factor4D.z);
249 			if (zCol.w != oldZ.w)
250 				colorAdd +=
251 					fractal->mandelbox.color.factor.z * (fabs(zCol.w) - fractal->mandelbox.color.factor4D.w);
252 			if (rrCol < fractal->transformCommon.maxR2d1)
253 			{
254 				if (rrCol < fractal->transformCommon.minR2p25)
255 					colorAdd +=
256 						fractal->mandelbox.color.factorSp1 * (fractal->transformCommon.minR2p25 - rrCol)
257 						+ fractal->mandelbox.color.factorSp2
258 								* (fractal->transformCommon.maxR2d1 - fractal->transformCommon.minR2p25);
259 				else
260 					colorAdd +=
261 						fractal->mandelbox.color.factorSp2 * (fractal->transformCommon.maxR2d1 - rrCol);
262 			}
263 		}
264 		else
265 		{
266 			if (zCol.x != oldZ.x) colorAdd += fractal->mandelbox.color.factor4D.x;
267 			if (zCol.y != oldZ.y) colorAdd += fractal->mandelbox.color.factor4D.y;
268 			if (zCol.z != oldZ.z) colorAdd += fractal->mandelbox.color.factor4D.z;
269 			if (zCol.w != oldZ.w) colorAdd += fractal->mandelbox.color.factor4D.w;
270 			if (rrCol < fractal->transformCommon.minR2p25)
271 				colorAdd += fractal->mandelbox.color.factorSp1;
272 			else if (rrCol < fractal->transformCommon.maxR2d1)
273 				colorAdd += fractal->mandelbox.color.factorSp2;
274 		}
275 		aux.color += colorAdd;
276 	}
277 }
278