Sutcliffe Pentagons

Hi,
I am trying to draw a Sutcliffe Pentagons and just get started with processing. I want to start with drawing a recursive pentagon which is in the middle of the Sutcliffe Pentagons but my code only draw one for me. Does anyone know why? Thanks!

image007

Pentagon pentagon;
void setup() {
  size(600, 600);
  background(255);

  pentagon = new Pentagon();

}

void draw() {
  translate(300, 300);
  if (pentagon.getCount() < 5) {
    pentagon.render();
    pentagon.nextLevel();
  }
}
class Pentagon{
  PVector[] ori;
  PVector center;
  float scale;
  int count;

  Pentagon() {
    center = new PVector(0, 0);
    scale = 0.6;
    
    ori = new PVector[5];
    for(int i = 0; i < 5; i++) {
      ori [i] = new PVector(0, 100);
      ori [i].rotate(i * (2 * PI/5));
    }
  }
  
  void nextLevel() {
    ori = generate(ori);
    count++;
  }
  
  PVector [] generate(PVector [] before) {
    PVector [] next = new PVector[5];
    for(int i = 0; i < 5; i++) {
      next [i] = center.sub(before [i]);
      next [i].mult(scale);
    }
    return next;
  }
  
  void render() {
    noFill();
    stroke(0);
    beginShape();
    for(int i = 0; i < 5; i++) {
      vertex(ori[i].x, ori[i].y);
    }
    endShape(CLOSE); 
  }
  
  int getCount() {
    return count;
  }
}

Just draw it.

void setup(){
  size(400,400);
}

void draw(){
  background(255);
  translate(200,200);
  stroke(0);
  pentagon(180);
  rotate(PI);
  pentagon(90);
  rotate(PI);
  pentagon(45);
}

void pentagon(float r){
  for( int i = 0; i < 5; i++){
    line(
      r * cos( TWO_PI/5.0 *  i    ), r * sin( TWO_PI/5.0 *  i    ), 
      r * cos( TWO_PI/5.0 * (i+1) ), r * sin( TWO_PI/5.0 * (i+1) )
    );
  }
}
2 Likes

I kind fancied this problem so I knocked up JRubyArt example, that you could use to give you an idea before you cheat and look up C.Andrews on openprocessing.

# After an openprocessing sketch by C.Andrews
attr_reader :strut_factor, :renderer

def setup
  sketch_title 'Recursive Pentagons'
  @strut_factor = 0.2
  @renderer = AppRender.new self # so we can send Vec2D :to_vertex
  background(255)
  no_loop
end

def draw
  translate(width / 2, height / 2)
  angle = TWO_PI / 5
  radius = width / 2
  points = (0...5).map do |i|
    x = radius * cos(angle * i)
    y = radius * sin(angle * i)
    Vec2D.new(x, y)
  end
  fractal = Pentagon.new(points, 4)
  fractal.draw
end

def settings
  size(800, 800)
end

# Here we include Processing::Proxy to mimic vanilla processing inner class
# access.
class Pentagon
  include Processing::Proxy
  attr_reader :points ,:branches, :level, :midpoints, :innerpoints

  def initialize(points, levels)
    @points = points
    @level = levels
    return if level.zero? # so called guard clause in ruby simplifies code
    # find the midpoints on each edge
    @midpoints = (0...5).map do |i|
      midpoint(points[i], points[(i + 1) % 5])
    end
    # find the inner points
    @innerpoints = (0...5).map do |i|
      opposite = points[(i + 3) % 5]
      x = midpoints[i].x + (opposite.x - midpoints[i].x) * strut_factor
      y = midpoints[i].y + (opposite.y - midpoints[i].y) * strut_factor
      Vec2D.new(x, y)
    end
    # Create the Pentagon objects representing the six inner
    # pentagons
    # the shape is very regular, so we can build the ring of five
    @branches = (0...5).map do |i|
      p = [
        midpoints[i],
        innerpoints[i],
        innerpoints[(i + 1) % 5],
        midpoints[(i + 1) % 5],
        points[(i + 1) % 5]
      ]
      Pentagon.new(p, level - 1)
    end
    # add the final innermost pentagon
    branches << Pentagon.new(innerpoints, level - 1)
  end
  # This is a simple helper function that takes in two points (as Vec2D) and
  # returns the midpoint between them as Vec2D.
  def midpoint(point1, point2)
    (point2 + point1) * 0.5
  end
  # This draws the fractal. If this is on level 0, we just draw the
  # pentagon formed by the points. When not level 0, iterate through the
  # six branches and tell them to draw themselves.
  def draw
    if level.zero?
      no_fill
      begin_shape
      points.each do |point|
        point.to_vertex(renderer)
      end
      points[0].to_vertex(renderer)
      end_shape
    else
      branches.each(&:draw)
    end
  end
end

1 Like

That’s cool! Thanks!

Thanks for your suggestion! I have read C. Andrews’s code and it is inspiring!

I particularly liked the use of modulus to navigate around the pentagon, however there can be a simplification of the drawing code (by using endShape(CLOSE) and changing how the pentagon fractals get drawn). Hint such refactoring will make it possible to alter the style (color / strokeWidth) of the fractal at each level. Another interesting thing to try is to vary the strut length.