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  * MengerV3Iteration
10  * Based on a fractal proposed by Buddhi, with a DE outlined by Knighty:
11  * http://www.fractalforums.com/3d-fractal-generation/revenge-of-the-half-eaten-menger-sponge/
12  */
13 
14 #include "all_fractal_definitions.h"
15 
cFractalMengerV3()16 cFractalMengerV3::cFractalMengerV3() : cAbstractFractal()
17 {
18 	nameInComboBox = "Menger V3";
19 	internalName = "menger_v3";
20 	internalID = fractal::mengerV3;
21 	DEType = analyticDEType;
22 	DEFunctionType = customDEFunction;
23 	cpixelAddition = cpixelDisabledByDefault;
24 	defaultBailout = 100.0;
25 	DEAnalyticFunction = analyticFunctionCustomDE;
26 	coloringFunction = coloringFunctionDefault;
27 }
28 
FormulaCode(CVector4 & z,const sFractal * fractal,sExtendedAux & aux)29 void cFractalMengerV3::FormulaCode(CVector4 &z, const sFractal *fractal, sExtendedAux &aux)
30 {
31 	// abs z
32 	if (fractal->transformCommon.functionEnabledAx) z.x = fabs(z.x);
33 	if (fractal->transformCommon.functionEnabledAy) z.y = fabs(z.y);
34 	if (fractal->transformCommon.functionEnabledAzFalse) z.z = fabs(z.z);
35 	// folds
36 	if (fractal->transformCommon.functionEnabledFalse)
37 	{
38 		// polyfold
39 		if (fractal->transformCommon.functionEnabledPFalse)
40 		{
41 			z.x = fabs(z.x);
42 			double psi = M_PI / fractal->transformCommon.int6;
43 			psi = fabs(fmod(atan2(z.y, z.x) + psi, 2.0 * psi) - psi);
44 			double len = sqrt(z.x * z.x + z.y * z.y);
45 			z.x = cos(psi) * len;
46 			z.y = sin(psi) * len;
47 		}
48 		// abs offsets
49 		if (fractal->transformCommon.functionEnabledCFalse)
50 		{
51 			double xOffset = fractal->transformCommon.offsetC0;
52 			if (z.x < xOffset) z.x = fabs(z.x - xOffset) + xOffset;
53 		}
54 		if (fractal->transformCommon.functionEnabledDFalse)
55 		{
56 			double yOffset = fractal->transformCommon.offsetD0;
57 			if (z.y < yOffset) z.y = fabs(z.y - yOffset) + yOffset;
58 		}
59 	}
60 
61 	// scale
62 	z *= fractal->transformCommon.scale1;
63 	aux.DE *= fabs(fractal->transformCommon.scale1);
64 
65 	// DE
66 	CVector4 zc = z;
67 
68 	if (aux.i >= fractal->transformCommon.startIterations
69 			&& aux.i < fractal->transformCommon.stopIterations1)
70 	{
71 		double rr = 0.0;
72 		CVector4 one = CVector4(1.0, 1.0, 1.0, 0.0);
73 		swap(zc.y, zc.z);
74 		zc += one;
75 		double modOff = fractal->transformCommon.offset3;
76 		aux.DE += fractal->analyticDE.offset0;
77 		int count = fractal->transformCommon.int8X;
78 		for (int k = 0; k < count && rr < 10.0; k++)
79 		{
80 			double pax = fmod(zc.x * aux.DE, modOff) - 0.5 * modOff;
81 			double pay = fmod(zc.y * aux.DE, modOff) - 0.5 * modOff;
82 			double paz = fmod(zc.z * aux.DE, modOff) - 0.5 * modOff;
83 			CVector4 pp = CVector4(pax, pay, paz, 0.0);
84 
85 			pp += fractal->transformCommon.offsetA000;
86 			rr = pp.Dot(pp);
87 
88 			// rotation
89 			if (fractal->transformCommon.functionEnabledRFalse
90 					&& k >= fractal->transformCommon.startIterationsR
91 					&& k < fractal->transformCommon.stopIterationsR)
92 			{
93 				pp = fractal->transformCommon.rotationMatrix.RotateVector(pp);
94 			}
95 			aux.DE0 = max(aux.DE0, (fractal->transformCommon.offset1 - pp.Length()) / aux.DE);
96 			aux.DE *= fractal->transformCommon.scale3;
97 		}
98 		if (!fractal->transformCommon.functionEnabledAFalse)
99 		{
100 			// Use this to crop to a sphere:
101 			double e;
102 			if (!fractal->transformCommon.functionEnabledBFalse)
103 				e = z.Length();
104 			else
105 				e = zc.Length();
106 			e = clamp(e - fractal->transformCommon.offset2, 0.0, 100.0);
107 			aux.dist = max(aux.DE0, e);
108 		}
109 		else
110 		{
111 			aux.dist = aux.DE0;
112 		}
113 		aux.dist *= fractal->analyticDE.scale1;
114 	}
115 }
116