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