Newton Fractal Sketch

@villares @solub @tabreturn Jörg Kantel has been at it again on his blog, I picked up his NewtonFractal sketch and translated it for JRubyArt here:-

# frozen_string_literal: true

IMGX = 512
IMGY = 512
MAXIT = 20 # max iterations allowed
EPS = 1e-3 # max error allowed
COMPLEX = Complex(1e-6, 1e-6) # step increment

attr_reader :xa, :xb, :ya, :yb, :z

def settings
  size(IMGX, IMGY)
end

def setup
  sketch_title 'Newton Fractal'
  color_mode(HSB)
  # Drawing area
  @xa = -1.0
  @xb = 1.0
  @ya = -1.0
  @yb = 1.0
  no_loop
end

def draw
  load_pixels
  grid(IMGY, IMGX) do |y, x|
    zy = y * (yb - ya) / (IMGY - 1) + ya
    zx = x * (xb - xa) / (IMGX - 1) + xa
    @z = Complex(zx, zy)
    (0...MAXIT).each do |i|
      # Newton iteration
      z0 =  z - func(z) / ((func(z + COMPLEX) - func(z)) / COMPLEX)
      break if (z0 - z).abs < EPS

      @z = z0
      # pixels[x + y * width] = color(i % 5 * 64, i % 17 * 16, i % 9 * 32)
      pixels[x + y * width] = color(i%5*64, i%9*32, i%17*16)
    end
  end
  update_pixels
end

def func(z)
  # z**3 - 1.0
  z**4 - 1.0
end

Here is what his suggested variation looks like:-

7 Likes

In principle you can explore any number of roots of unity eg z**8:-


Here I’ve expanded the drawing area to -2 to 2 get a wider perspective.

1 Like

Then if you substitute for some other funky cubic function there is this:-


Or this view:-

2 Likes

Thank you so much @monkstone! It is lovely!

# from https://discourse.processing.org/t/newton-fractal-sketch/24211
IMGX = 512
IMGY = 512
MAXIT = 20  # max iterations allowed
EPS = 1e-3  # max error allowed, could use Processing's EPSILON constant
COMPLEX = complex(1e-6, 1e-6)  # step increment

def settings():
    size(IMGX, IMGY)

def setup():
    global xa, xb, ya, yb
    this.surface.setTitle('Newton Fractal')
    colorMode(HSB)
    # Drawing area
    xa = -1.0
    xb = 1.0
    ya = -1.0
    yb = 1.0
    noLoop()

def draw():
    loadPixels()
    for y in range(IMGY):
        for x in range(IMGX):
            zy = y * (yb - ya) / (IMGY - 1) + ya
            zx = x * (xb - xa) / (IMGX - 1) + xa
            z = complex(zx, zy)
            for i in range(MAXIT):
                # Newton iteration
                z0 = z - func(z) / ((func(z + COMPLEX) - func(z)) / COMPLEX)
                if abs(z0 - z) < EPS:
                    break
                z = z0
                # pixels[x + y * width] = color(i % 5 * 64, i % 17 * 16, i % 9 * 32)
                pixels[x + y * width] = color(i %
                                              5 * 64, i % 9 * 32, i % 17 * 16)
    updatePixels()

def func(z):
    # return z**3 - 1.0
    return z ** 4 - 1.0

1 Like

Here’s another variation with a complex polynomial function (ie 4+3i):-


Or this with -0.5+3:-

2 Likes

In this sketch I take advantage of the built in support for complex numbers in ruby. But this got me thinking that I’ve yet to take advantage of ruby refinements (a different sort of monkey patching that does not pollute global namespace. I reasoned that it might be quite interesting to explore refinements with the Vec2D class see my recent blog entry. This is akin to vec2 glsl code in my droste.glsl.

1 Like