Mandelbrot set: Difference between revisions

Content added Content deleted
m (Made two small cuts.)
m (Added comments and explanations about the Stripe Average algorithm.)
Line 8,037: Line 8,037:
'''Smoothing, Normalization and Distance Estimation'''
'''Smoothing, Normalization and Distance Estimation'''


This is a translation of the corresponding Python section: see there for more explanations. The ''e^(-|z|)-smoothing'', ''normalized iteration count'' and ''exterior distance estimation'' algorithms are used. Partial antialiasing is used for boundary detection.
This is a translation of the corresponding Python section: see there for more explanations. The ''e^(-|z|)-smoothing'', ''normalized iteration count'' and ''exterior distance estimation'' algorithms are used, partial antialiasing is used for boundary detection.
<syntaxhighlight lang="julia">using Plots
<syntaxhighlight lang="julia">using Plots
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
Line 8,082: Line 8,082:
'''Normal Map Effect and Stripe Average Coloring'''
'''Normal Map Effect and Stripe Average Coloring'''


The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). See also the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy.
The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). See also the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy. To get a stripe pattern similar to that of Arnaud Chéritat, the stripe density can be increased to 8, cos can be used instead of sin, and the color map can be set to binary instead of bone_1.
<syntaxhighlight lang="julia">using Plots
<syntaxhighlight lang="julia">using Plots
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
Line 8,103: Line 8,103:
for k in 1:n
for k in 1:n
M = abs.(Z) .< r
M = abs.(Z) .< r
S[M], T[M] = S[M] .+ cos.(stripes .* angle.(Z[M])), T[M] .+ 1
S[M], T[M] = S[M] .+ sin.(stripes .* angle.(Z[M])), T[M] .+ 1
Z[M], dZ[M], ddZ[M] = Z[M] .^ 2 .+ C[M], 2 .* Z[M] .* dZ[M] .+ 1, 2 .* (dZ[M] .^ 2 .+ Z[M] .* ddZ[M])
Z[M], dZ[M], ddZ[M] = Z[M] .^ 2 .+ C[M], 2 .* Z[M] .* dZ[M] .+ 1, 2 .* (dZ[M] .^ 2 .+ Z[M] .* ddZ[M])
end
end


N = abs.(Z) .>= r # normal map effect 1 (equipotential lines)
N = abs.(Z) .>= r # basic normal map effect with stripe average coloring (normalized iteration count)
P, Q = S[N] ./ T[N], (S[N] .+ cos.(stripes .* angle.(Z[N]))) ./ (T[N] .+ 1)
P, Q = S[N] ./ T[N], (S[N] .+ sin.(stripes .* angle.(Z[N]))) ./ (T[N] .+ 1)
U, V = Z[N] ./ dZ[N], 1 .+ (Q .+ (P .- Q) .* log2.(log.(abs.(Z[N])) ./ log(r))) ./ damping
U, V = Z[N] ./ dZ[N], 1 .+ (log2.(log.(abs.(Z[N])) ./ log(r)) .* (P .- Q) .+ Q) ./ damping
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors and unit vector
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors (equipotential lines) and light
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ V .* height) ./ (1 + height), 0)
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ V .* height) ./ (1 + height), 0)


Line 8,116: Line 8,116:
savefig("Mandelbrot_normal_map_1.png")
savefig("Mandelbrot_normal_map_1.png")


N = abs.(Z) .> 2 # normal map effect 2 (equidistant lines)
N = abs.(Z) .> 2 # advanced normal map effect using second derivatives (exterior distance estimation)
U = Z[N] .* dZ[N] .* ((1 .+ log.(abs.(Z[N]))) .* conj.(dZ[N] .^ 2) .- log.(abs.(Z[N])) .* conj.(Z[N] .* ddZ[N]))
U = Z[N] .* dZ[N] .* ((1 .+ log.(abs.(Z[N]))) .* conj.(dZ[N] .^ 2) .- log.(abs.(Z[N])) .* conj.(Z[N] .* ddZ[N]))
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors and unit vector
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors (equidistant lines) and light
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ height) ./ (1 + height), 0)
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ height) ./ (1 + height), 0)


Line 8,133: Line 8,133:
n, r = 8000, 10000 # number of iterations and escape radius (r > 2)
n, r = 8000, 10000 # number of iterations and escape radius (r > 2)


a = -.743643887037158704752191506114774 # try: a, b, n = -1.748764520194788535, 3e-13, 800
a = -.743643887037158704752191506114774 # https://mathr.co.uk/web/m-location-analysis.html
b = 0.131825904205311970493132056385139 # https://mathr.co.uk/web/m-location-analysis.html
b = 0.131825904205311970493132056385139 # try: a, b, n = -1.748764520194788535, 3e-13, 800


x = range(0, 2, length=d+1)
x = range(0, 2, length=d+1)
Line 11,055: Line 11,055:
'''Normal Map Effect and Stripe Average Coloring'''
'''Normal Map Effect and Stripe Average Coloring'''


The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). Note that the second derivative (ddZ) grows very fast, so the second method can only be used for small iteration numbers (n <= 400). See also the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy.
The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). Note that the second derivative (ddZ) grows very fast, so the second method can only be used for small iteration numbers (n <= 400). See also the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy. To get a stripe pattern similar to that of Arnaud Chéritat, the stripe density can be increased to 8, cos can be used instead of sin, and the color map can be set to binary instead of bone.
<syntaxhighlight lang="python">import numpy as np
<syntaxhighlight lang="python">import numpy as np
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
Line 11,076: Line 11,076:
for k in range(n):
for k in range(n):
M = abs(Z) < r
M = abs(Z) < r
S[M], T[M] = S[M] + np.cos(stripes * np.angle(Z[M])), T[M] + 1
S[M], T[M] = S[M] + np.sin(stripes * np.angle(Z[M])), T[M] + 1
Z[M], dZ[M], ddZ[M] = Z[M] ** 2 + C[M], 2 * Z[M] * dZ[M] + 1, 2 * (dZ[M] ** 2 + Z[M] * ddZ[M])
Z[M], dZ[M], ddZ[M] = Z[M] ** 2 + C[M], 2 * Z[M] * dZ[M] + 1, 2 * (dZ[M] ** 2 + Z[M] * ddZ[M])


N = abs(Z) >= r # normal map effect 1 (equipotential lines)
N = abs(Z) >= r # basic normal map effect with stripe average coloring (normalized iteration count)
P, Q = S[N] / T[N], (S[N] + np.cos(stripes * np.angle(Z[N]))) / (T[N] + 1)
P, Q = S[N] / T[N], (S[N] + np.sin(stripes * np.angle(Z[N]))) / (T[N] + 1)
U, V = Z[N] / dZ[N], 1 + (Q + (P - Q) * np.log2(np.log(np.abs(Z[N])) / np.log(r))) / damping
U, V = Z[N] / dZ[N], 1 + (np.log2(np.log(np.abs(Z[N])) / np.log(r)) * (P - Q) + Q) / damping
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors and unit vector
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors (equipotential lines) and light
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + V * height) / (1 + height), 0)
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + V * height) / (1 + height), 0)


Line 11,088: Line 11,088:
plt.savefig("Mandelbrot_normal_map_1.png", dpi=200)
plt.savefig("Mandelbrot_normal_map_1.png", dpi=200)


N = abs(Z) > 2 # normal map effect 2 (equidistant lines)
N = abs(Z) > 2 # advanced normal map effect using second derivatives (exterior distance estimation)
U = Z[N] * dZ[N] * ((1 + np.log(abs(Z[N]))) * np.conj(dZ[N] ** 2) - np.log(abs(Z[N])) * np.conj(Z[N] * ddZ[N]))
U = Z[N] * dZ[N] * ((1 + np.log(abs(Z[N]))) * np.conj(dZ[N] ** 2) - np.log(abs(Z[N])) * np.conj(Z[N] * ddZ[N]))
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors and unit vector
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors (equidistant lines) and light
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + height) / (1 + height), 0)
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + height) / (1 + height), 0)


Line 11,105: Line 11,105:
n, r = 8000, 10000 # number of iterations and escape radius (r > 2)
n, r = 8000, 10000 # number of iterations and escape radius (r > 2)


a = -.743643887037158704752191506114774 # try: a, b, n = -1.748764520194788535, 3e-13, 800
a = -.743643887037158704752191506114774 # https://mathr.co.uk/web/m-location-analysis.html
b = 0.131825904205311970493132056385139 # https://mathr.co.uk/web/m-location-analysis.html
b = 0.131825904205311970493132056385139 # try: a, b, n = -1.748764520194788535, 3e-13, 800


x = np.linspace(0, 2, num=d+1)
x = np.linspace(0, 2, num=d+1)