Harriss Spiral Techniques

The following source code is one technique of drawing a basic Harriss spiral using ninety degree Processing arcs. Each successive arc is the previous arc’s width/height divided by 1.325 going from outer to inner. The colored circles show the center point of its respective arc. There are other methods of drawing an arc, none better than Logo’s Turtle that I have been able to find so far. This demo builds the spiral manually without the aid of a loop or recursion.

void setup() {
  size(600, 600);
  // ======== 1 ========= //
  pushMatrix();
  translate(312, 370);
  noFill();
  strokeWeight(16);
  arc(0, 0, 243, 243, radians(-45), radians(45));
  strokeWeight(1);
  circle(0, 0, 10);
  fill(0);
  text("1", -2, 4);
  popMatrix();
  // ======== 2 ======== //
  pushMatrix();
  translate(334, 350);
  noFill();
  strokeWeight(14);
  stroke(11,123,54);
  arc(0, 0, 183, 183, radians(225), radians(315));
  strokeWeight(1);
  circle(0, 0, 10);
  fill(0);
  text("2", -2, 4);
  popMatrix();
  // ======== 3 ======= //
  pushMatrix();
  translate(319, 333);
  noFill();
  strokeWeight(12);
  stroke(0,0,254);
  arc(0, 0, 138, 138, radians(135), radians(225));
  strokeWeight(1);
  circle(0, 0, 10);
  fill(0);
  text("3", -2, 4);
  popMatrix();
  // ======== 4 ======= //
  pushMatrix();
  translate(308, 345);
  noFill();
  strokeWeight(10);
  stroke(234,193,54);
  arc(0, 0, 104, 104, radians(45), radians(135));
  strokeWeight(1);
  circle(0, 0, 10);
  fill(0);
  text("4", -2, 4);
  popMatrix();
  // ======== 5 ======= //
  pushMatrix();
  translate(316, 355);
  noFill();
  strokeWeight(8);
  stroke(179,23,254);
  arc(0, 0, 79, 79, radians(-45), radians(45));
  strokeWeight(1);
  circle(0, 0, 10);
  fill(0);
  text("5", -2, 4);
  popMatrix();
  // ======= 6 ======== //
  pushMatrix();
  translate(322, 349);
  noFill();
  strokeWeight(6);
  stroke(221,223,54);
  arc(0, 0, 60, 60, radians(225), radians(315));
  strokeWeight(1);
  circle(0, 0, 10);
  fill(0);
  text("6", -2, 4);
  popMatrix();
  // ======== 7 ======= //
  pushMatrix();
  translate(317, 342);
  noFill();
  strokeWeight(4);
  stroke(255,0,54);
  arc(0, 0, 45, 45, radians(135), radians(225));
  strokeWeight(1);
  circle(0, 0, 10);
  fill(0);
  text("7", -2, 4);
  popMatrix();
}

Output:

Technique 2:
The following technique uses recursion and an ArrayList of PVectors with a custom arc drawing method to create a Harriss spiral.

ArrayList<PVector> vectors;

int _wndW = 800;
int _wndH = 800;

float x1 = 0;
float y1 = 0;

void drawArc(float x, float y, float radius, int rotation, float penSize, int iteration) {
  float angle = 0.0;

  rotation += 90;
  if (rotation > 315) {
    rotation = 45;
  }
  radius = radius*1.325;

  if (iteration > 0) {
    iteration -= 1;
    PVector v = vectors.get(iteration);
    println("[" + iteration + "]" + v.x +" : " + v.y);
    pushMatrix();
    translate(v.x, v.y);
    rotate(radians(rotation));
    println("radius = " + radius);
    println("rotation = ", rotation);
    println("====================");
    for ( int i = 0; i < 90; i++ ) {
      angle = radians( i );
      x = cos( angle ) * radius;
      y = sin( angle ) * radius;
      stroke(random(255),random(255),random(255));
      strokeWeight(penSize);
      if ((x>0)&&(y>0)) {
        line(x, y, x1, y1);
      }
      x1 = x;
      y1 = y;
    }
    popMatrix();
    drawArc(x, y, radius, rotation, penSize, iteration);
  }
}

void setup() {
  size(_wndW, _wndH);
  background(209);
  vectors = new ArrayList<PVector>();
  vectors.add(new PVector(290, 430)); // 0 Outside
  vectors.add(new PVector(334, 390)); // 1
  vectors.add(new PVector(305, 355)); // 2
  vectors.add(new PVector(278, 376)); // 3
  vectors.add(new PVector(293, 398)); // 4
  vectors.add(new PVector(309, 387)); // 5
  vectors.add(new PVector(301, 375)); // 6 Inside
  for (int i = 0; i < vectors.size(); i++) {
    PVector v = vectors.get(i);
    println("[" + i + "]" + v.x +" : " + v.y);
  }
  println(" ================== ");
  noLoop(); // uses recursion
}

void draw() {
  //draws from inside out
  drawArc(291, 430, 34, 45, 15, 7); // initial x,y values irrelevant; vectors start with 6
}

Output:

Technique 3:

// Harriss rectangle is subdivided into squares.
// Each square's dimension is equal to the preceding dimension divided by 1.325
// Center point of each arc is calculated using Pythagorean Theorem

class Square {
  float x, y, w;

  Square(float xpos, float ypos, float dimension) {
    x = xpos;
    y = ypos;
    w = dimension;
  }

  void display() {
    noFill();
    stroke(0);
    rect(x, y, w, w);
  }
}

Square s;

ArrayList<Square> squares;

int _wndH = 600;
float w = _wndH*1.325; // Harriss rectangle to start
int _wndW = (int)w;

int startDegrees = 0;
int stopDegrees = 0;
float cntrX = 0;
float cntrY = 0;

void drawArc(int id) {
  s = squares.get(id);
  float radius = 0.7*s.w;
  println("radius =", radius);
  float d = sqrt((radius*radius)-(s.w/2*s.w/2));
  println("d =", d);
  noFill();
  stroke(0);
  strokeWeight(10);
  switch(id) {
  case 0:
    startDegrees = -45;
    stopDegrees = 45;
    cntrX = s.x - d;
    cntrY = s.y + s.w/2;
    break;
  case 1:
    startDegrees = 225;
    stopDegrees = 315;
    cntrX = s.x + s.w/2;
    cntrY = s.y + s.w + d;
    break;
  case 2:
    startDegrees = 135;
    stopDegrees = 225;
    cntrX = s.x + s.w + d;
    cntrY = s.y + s.w/2;    
    break;
  case 3:
    startDegrees = 45;
    stopDegrees = 135;
    cntrX = s.x + s.w/2;
    cntrY = s.y - d;
    break;
  case 4:
    startDegrees = -45;
    stopDegrees = 45;
    cntrX = s.x - d;
    cntrY =  s.y + s.w/2;;
    break;
  case 5:
    startDegrees = 225;
    stopDegrees = 315;
    cntrX = s.x + s.w/2;
    cntrY = s.y + s.w + d;
    break;
  case 6:
    startDegrees = 135;
    stopDegrees = 225;
    cntrX = s.x + s.w + d;
    cntrY = s.y + s.w/2;   
    break;
  }
  arc(cntrX, cntrY, 2*radius, 2*radius, radians(startDegrees), radians(stopDegrees));
  strokeWeight(1);
  circle(cntrX, cntrY, 13);
  textSize(12);
  text(str(id),cntrX-3, cntrY+4);
}

void setup() {
  size(_wndW, _wndH);
  background(209);
  squares = new ArrayList<Square>();
  squares.add(new Square(452.83017, 258.24136, 342.16983));
  squares.add(new Square(194.6649, 0.0, 258.16528));
  squares.add(new Square(0.0, 258.16528, 194.6649));
  squares.add(new Square(194.6649, 452.8302, 146.9169));
  squares.add(new Square(341.5818, 341.94952, 111.0141));
  squares.add(new Square(257.82227, 258.16528, 83.75952));
  squares.add(new Square(194.6649, 341.9248, 63.157375));
  noLoop();
}

void draw() {
  for (int i = 0; i < squares.size(); i++) {
    Square s = squares.get(i);
    s.display();
    textSize(16);
    fill(0);
    text(str(squares.indexOf(s)), s.x + 32, s.y + 16);
    drawArc(i);
  }
}

Output:

Technique 4:

This is the most automated of all the techniques shown so far. All that the user has to provide is the window height and an initial arc rotation and the source code will do the rest.

/*
 Uses an ArrayList of Square class squares
 Arcs are derived from squares, each decreased by a factor of 1.325 (outer -> inner)
 Ninety degree arcs are drawn clockwise using recursion (inner -> outer)
 Arc centers are calculated with Pythagorean Theorem
*/

int h = 600;  // Scalable (may be any value)
float wndW = h*1.325; // Start with Harriss rectangle based on window height

int _wndW = (int)wndW;
int _wndH = h;

float l = _wndH/1.325;
float w = l/1.325;
float t = w/1.325;

float x = 0;
float y = 0;

int rotation = 45; // Initial rotation
float angle = 0.0;
float cntrX = 0;
float cntrY = 0;

class Square {
  float x, y, w;

  Square(float xpos, float ypos, float dimension) {
    x = xpos;
    y = ypos;
    w = dimension;
  }

  void display() {
    noFill();
    stroke(0);
    strokeWeight(1);
    rect(x, y, w, w);
  }
}

Square s;

ArrayList<Square> squares;

void drawMyArc(int iteration) {
  if (iteration > 0) {
    iteration -= 1;
    println("id =", iteration);
    s = squares.get(iteration);
    float radius = 0.7*s.w;
    println("radius =", radius);
    float d = sqrt((radius*radius)-(s.w/2*s.w/2));
    println("d =", d);
    rotation += 90;
    if (rotation > 315) {
      rotation = 45;
    }
    println("radius = " + radius);
    println("rotation = ", rotation);
    switch(iteration) {
    case 0:
      cntrX = s.x - d;
      cntrY = s.y + s.w/2;
      break;
    case 1:
      cntrX = s.x + s.w/2;
      cntrY = s.y + s.w + d;
      break;
    case 2:
      cntrX = s.x + s.w + d;
      cntrY = s.y + s.w/2;
      break;
    case 3:
      cntrX = s.x + s.w/2;
      cntrY = s.y - d;
      break;
    case 4:
      cntrX = s.x - d;
      cntrY =  s.y + s.w/2;
      break;
    case 5:
      cntrX = s.x + s.w/2;
      cntrY = s.y + s.w + d;
      break;
    case 6:
      cntrX = s.x + s.w + d;
      cntrY = s.y + s.w/2;
      break;
    }
    println("cntrX = " + cntrX + " : cntrY = " + cntrY);
    println("====================");
    pushMatrix();
    translate(cntrX, cntrY);
    rotate(radians(rotation));
    for ( int i = 0; i < 90; i++ ) {
      angle = radians( i );
      x = cos( angle ) * radius;
      y = sin( angle ) * radius;
      stroke(0, 0, 255);
      strokeWeight(15);
      point(x, y);
    }
    popMatrix();
    drawMyArc(iteration); // recursion
  }
}

void setup() {
  size(_wndW, _wndH);
  background(255);
  squares = new ArrayList<Square>();
  squares.add(new Square(l, t, w));
  w = w/1.325;
  squares.add(new Square(l-w, t-w, w));
  w = w/1.325;
  squares.add(new Square(0.0, t, w));
  w = w/1.325;
  squares.add(new Square(w*1.325, t+w*1.325, w));
  w = w/1.325;
  squares.add(new Square((w*1.325)+1.325*(w*1.325), t+w*1.325*1.325-w, w));
  w = w/1.325;
  squares.add(new Square((w*1.325)+1.325*(w*1.325), t, w));
  w = w/1.325;
  squares.add(new Square((w*1.325)+1.325*(w*1.325), t+w*1.325, w));
  noLoop();
}

void draw() {
  drawMyArc(squares.size());
  /*
  for(int i = 0; i < squares.size(); i++) {
   s = squares.get(i);
   s.display();
  }
  */
}

Output:

5 Likes