Jump to content

Harriss Spiral

From Rosetta Code
Task
Harriss Spiral
You are encouraged to solve this task according to the task description, using any language you may know.

The discovery of the Harriss Spiral was first publicized about 2015. It is the brainchild of Edmund Orme Harriss, a British mathematician, writer and artist. Since 2010 he has been at the Fulbright College of Arts & Sciences at The University of Arkansas in Fayetteville, Arkansas, where he is an Assistant Professor of Arts & Sciences (ARSC) and Mathematical Sciences (MASC). He does research in the Geometry of Tilings and Patterns,a branch of Convex and Discrete Geometry.

In Harriss' own words, his namesake spiral, "…is constructed by taking a rectangle with height 1 and length the real root of x^3-x-1=0. With this rectangle you can cut off a similar rectangle, and then a square to get another similar rectangle. You can repeat this construction on the smaller similar rectangles, in each case getting a square and two more similar rectangles. Now simply adding an arc of a circle to each square (in the right way) gives the spiral, or more correctly the nest of spirals."

Fractal spiral discovered by Edmund Harriss

The Harriss Spiral is a variant of the decomposition for the golden spiral in which a rectangle is decomposed into three smaller units: a rectangle similar to the original rotated 90◦, a square, and a similar rectangle in the same orientation as the original rectangle. As in the golden-spiral decomposition, the individual non-square units can be decomposed further along these lines to create a cascading filling of the rectangle with ever-smaller squares. Unlike in the golden spiral, each square is incident on two smaller regions appearing in the same generation; if arcs are drawn between each square and the square which appeared in its previous generation The result is a branching structure, shown at right.

As with the golden spiral decomposition, the Harriss spiral requires a specific aspect ratio for the original rectangle. While the golden spiral requires an aspect ratio which is a solution to 𝜙2 = 𝜙 + 1 — the Golden Ratio of 1:1.618 — the Harriss spiral requires an aspect ratio 𝜌 satisfying 𝜌3 = 𝜌 + 1, whose real solution is known as the plastic ratio and equals 1:1.3247.

Task
Harriss Spiral
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Create and display a Harriss Spiral in your language.


ALGOL 68

Based on

Translation of: EasyLang
Translation of: Processing

Generates the curve as SVG which is written to standard output - redirect it to an HTML file and open it in a browser that supports SVG or an SVG viewer...

BEGIN # Harriss Spiral in SVG - translation of EasyLang/Processing samples   #

    PROC hex1    = ( INT d )STRING: IF d < 10 THEN REPR( ABS "0" + d ) ELSE REPR( ABS "a" + ( d - 10 ) ) FI;
    PROC hex     = ( INT v )STRING: hex1( v OVER 16 ) + hex1( v MOD 16 );
    PROC rgb     = ( INT r, g, b )STRING: "#" + hex( r ) + hex( g ) + hex( b );
    OP   SIND    = ( REAL x )REAL: sin( x * pi / 180 );
    OP   COSD    = ( REAL x )REAL: cos( x * pi / 180 );
    PRIO FMT = 9;
    OP   FMT = ( REAL v, INT dp )STRING:
         BEGIN
            STRING result = IF ENTIER v = v
                            THEN whole( v, - dp * 16 )
                            ELSE fixed( v, - dp * 16, ABS dp )
                            FI;
            INT v pos := LWB result;
            WHILE result[ v pos ] = " " DO v pos +:= 1 OD;
            result[ v pos : ]
         END # FMT # ;
    PROC point   = ( REAL x, y )STRING: x FMT 2 + " " + y FMT 2;
    PROC move to = ( REAL x, y )STRING: "M " + point( x, y );
    PROC line to = ( REAL x, y )STRING: "L " + point( x, y );
    PROC start path = ( INT r, g, b, REAL line width, x, y )STRING:
         ( "  <path stroke-width='" + line width FMT 2
         + "' stroke='" + rgb( r, g, b ) + "' fill='none' d='" + move to( x, y ) + " "
         );
    PROC line = ( INT r, g, b, REAL line width, REAL x, y, x end, y end )VOID:
         print( ( start path( r, g, b, line width, x, y ), " ", line to( x end, y end ), "'/>"
                , newline
                )
              );
    PROC arc = ( REAL x centre, y centre, ew, eh, start angle, end angle, INT r, g, b, REAL line width )VOID:
         BEGIN
            REAL rx = ew / 2, ry = ( eh / ew ) * eh / 2;
            REAL x     = x centre + rx * COSD start angle, y     = y centre + ry * SIND start angle;
            REAL x end = x centre + rx * COSD end angle,   y end = y centre + ry * SIND end angle;
            print( ( start path( r, g, b, line width, x, y )
                   , "A ", rx FMT 2, " ", ry FMT 2	, " 0 0 1 ", point( x end, y end )
                   , "'/>", newline
                   )
                 )
         END # arc # ;

    REAL h  = 600;   # scalable (may be any value) #
    REAL hr = 1.325; # Harriss Ratio               #

    PROC spiral section = ( REAL   x, y, angle, lngth
                          , INT    iteration
                          , REAL   line width
                          , BOOL   show lines
                          ) VOID:
         IF iteration > 0 THEN
             REAL start angle = angle + 45;
             REAL end angle   = start angle + 90;
             # Calculate end point of lines #
             REAL x end  = x + lngth * COSD angle;
             REAL y end  = y + lngth * SIND angle;
             REAL radius = 1.414 * lngth;
             spiral section( x end, y end, angle + 90, lngth / hr / hr, iteration - 2, line width, show lines );
             IF show lines THEN
                 line( 255, 255, 255, 1, x, y, x end, y end )
             FI;
             INT sn = 1, ew = 2, ns = 3, we = 4;
             INT heading := sn;
             IF ENTIER y end < ENTIER y THEN heading := sn FI;
             IF ENTIER x end < ENTIER x THEN heading := ew FI;
             IF ENTIER y end > ENTIER y THEN heading := ns FI;
             IF ENTIER x end > ENTIER x THEN heading := we FI;
             REAL l2 = lngth / 2;
             IF   heading = sn THEN
                 arc( x - l2, y - l2, radius, radius, start angle, end angle, 255, 255,   0, line width )
             ELIF heading = ew THEN
                 arc( x - l2, y + l2, radius, radius, start angle, end angle, 255,   0,   0, line width )
             ELIF heading = ns THEN
                 arc( x + l2, y + l2, radius, radius, start angle, end angle,   0,   0, 255, line width )
             ELIF heading = we THEN
                 arc( x + l2, y - l2, radius, radius, start angle, end angle,   0,   0,   0, line width )
             FI;
             spiral section( x end, y end, angle - 90, lngth / hr, iteration - 1, line width, show lines )
         FI # spiral section #;

    PROC generate harriss spiral = ( INT c width, c height )VOID:
         BEGIN
            print( ( "<svg xmlns='http://www.w3.org/2000/svg' width='"
                   , whole( c width, 0 ), "' height='", whole( c height, 0 ), "'>", newline
                   , "  <rect width='100%' height='100%' fill='#7f7f7f'/>", newline
                   )
                 );
            REAL start x = c width / 2 + 50;
            REAL start y = c height - 50;
            REAL init len = h / hr / hr;
            spiral section( start x, start y, -90, init len, 16, 2, FALSE );
            print( ( "</svg>", newline ) )
         END # generate harriss spiral #;

    generate harriss spiral( 1000, 800 )

END
Output:

The borders have been cropped in this image.

EasyLang

Translation of: Processing
# Harris Spiral - translated from the Processing sample
# 
# the EasyLang canvas is 100x100 with 0,0 at bottom left, 100,100 at top right
# the following maps the Processing canvas to the EasyLang one
cWidth = 100
cHeight = 100
func scaleX v s .
   return (v * 100 / s)
.
func scaleY v s .
   return 100 - (v * 100 / s)
.
proc scaledMove x y . .
   move scaleX x cWidth scaleY y cHeight
.
proc scaledLine x y . .
   line scaleX x cWidth scaleY y cHeight
.
# 
# the following implements equivalents for some Processing functions and Boolean literals
# false = 0
true = 1
proc size w h . .
   cWidth = w
   cHeight = h
.
proc strokeWidth w . .
   linewidth w / 18
.
proc stroke rb gb bb . .
   color3 rb / 255 gb / 255 bb / 255
.
proc arc xCenter yCenter eWidth eHeight p1Angle p2Angle . .
   rx = eWidth / 2
   ry = (eHeight / eWidth) * eHeight / 2
   arcAngle = p2Angle - p1Angle
   angleStep = arcAngle / 720
   angle = p1Angle
   x = xCenter + rx * cos angle
   y = yCenter + ry * sin angle
   scaledMove x y
   for s = 0 to 720
      x = xCenter + rx * cos angle
      y = yCenter + ry * sin angle
      scaledLine x y
      angle = angle + angleStep
   .
.
# 
# Harris Spiral - translation of the Processing sample
# EasyLang angles are in degrees, so conversion to radians is not needed
# some values have been tweaked
# 
h = 600 ; # scalable (may be any value)
HR = 1.325 ; # Harriss Ratio
_wndW = 1000
_wndH = 1000
showLines = true ; # was false in the Processing sample
proc drawHarriss x y dAngle lngth iteration lineW . .
   if iteration > 0
      startAngle = dAngle + 45
      endAngle = startAngle + 90
      # Calculate end point of lines
      xEnd = x + lngth * cos dAngle
      yEnd = y + lngth * sin dAngle
      if floor yEnd < floor y
         heading$ = "SN"
      .
      if floor xEnd < floor x
         heading$ = "EW"
      .
      if floor yEnd > floor y
         heading$ = "NS"
      .
      if floor xEnd > floor x
         heading$ = "WE"
      .
      if showLines = true
         stroke 255 255 255
         strokeWidth 3
         scaledMove x y
         scaledLine xEnd yEnd
      .
      radius = 1.414 * lngth
      if heading$ = "SN"
         cntrX = x - lngth / 2
         cntrY = y - lngth / 2
         stroke 255 255 0
         strokeWidth lineW
      .
      if heading$ = "EW"
         cntrX = x - lngth / 2
         cntrY = y + lngth / 2
         stroke 255 0 0
         strokeWidth lineW
      .
      if heading$ = "NS"
         cntrX = x + lngth / 2
         cntrY = y + lngth / 2
         stroke 0 0 255
         strokeWidth lineW
      .
      if heading$ = "WE"
         cntrX = x + lngth / 2
         cntrY = y - lngth / 2
         stroke 0 0 0
         strokeWidth lineW
      .
      arc cntrX cntrY radius radius startAngle endAngle
      drawHarriss xEnd yEnd dAngle - 90 lngth / HR iteration - 1 lineW
   .
.
proc setup . .
   size _wndW _wndH
   background 555
   clear
   startX = _wndW / 2 + 50
   startY = _wndH - 50
   initLen = h / HR / HR
   # Reverse Order Hides Joints
   drawHarriss startX - (initLen / HR + initLen / HR / HR / HR) startY - initLen / HR / HR / HR / HR / HR / HR / HR / HR 180 initLen / HR / HR / HR / HR / HR / HR 2 6.0 ; # level 3
   drawHarriss startX - (initLen / HR + initLen / HR / HR / HR) startY - (initLen + initLen / HR / HR) 270 initLen / HR / HR / HR / HR / HR 3 6.0 ; # level 3
   drawHarriss startX + initLen / HR / HR / HR / HR startY - (initLen + initLen / HR / HR) 270 initLen / HR / HR / HR / HR / HR 3 6.0 ; # level 3
   drawHarriss startX + initLen / HR startY - (initLen + initLen / HR / HR) 0 initLen / HR / HR / HR / HR 4 6.0 ; # level 3 rt-upper
   drawHarriss startX - initLen / HR / HR / HR / HR startY - initLen / HR 0 initLen / HR / HR / HR / HR / HR 2 10.0 ; # level 2 mid-upper
   drawHarriss startX - initLen / HR / HR / HR / HR startY - initLen / HR / HR / HR (-270) initLen / HR / HR / HR / HR 3 12.0 ; # level 2 mid-lower
   drawHarriss startX - initLen / HR startY - initLen / HR / HR / HR 180 initLen / HR / HR / HR 4 12.0 ; # level 2 lt-lower
   drawHarriss startX - initLen / HR startY - initLen 270 initLen / HR / HR 5 14.0 ; # level 2 lt-upper
   drawHarriss startX startY - initLen 0 initLen / HR 6 14.0 ; # level 2 rt-upper
   drawHarriss startX startY (-90) initLen 7 18.0 ; # level 1 base spiral
.
setup
Output:

(the EasyLang canvas is square, the unused upper portion has been cropped)

FutureBasic

Special credit for this code goes to Steven Van Voorst who, in his own words, "spent countless hours on this project because it is so much fun." Steve developed a working prototype of the Harriss Spiral using the cross-platform Processing IDE. The Processing software is free and open source and runs on Mac OS, Windows, and Linux. Processing's Rossetta Code home page is: https://rosettacode.org/wiki/Category:Processing. The Processing home page is: https://processing.org/.

Steve programs in a variety of languages. He kindly shared his Processing source code which was translated into this FB task solution for macOS. Steve's contribution is greatly appreciated.

#define HR 1.3247   // Harriss ratio
#define LINES NO

_window = 1
begin enum 1
  _harrissView
end enum


void local fn BuildWindow
  NSInteger wndStyle =¬
  NSWindowStyleMaskTitled +¬
  NSWindowStyleMaskClosable +¬
  NSWindowStyleMaskResizable +¬
  NSWindowStyleMaskMiniaturizable
  
  CGRect r = fn CGRectMake( 0, 0, 1000, 800 )
  window _window, @"Harriss Spiral in FutureBasic for Macintosh", r, wndStyle
  
  subclass view _harrissView, r, _window
  ViewSetFlipped( _harrissView, YES )
  ViewSetAutoresizingMask( _harrissView, NSViewWidthSizable + NSViewHeightSizable )
end fn


local fn DrawArcSegment( x as CGFloat, y as CGFloat, angle as CGFloat, length as CGFloat, iteration as int, arcColor as ColorRef, lineWidth as CGFloat, showLines as BOOL, showArcs  as BOOL )
  CFStringRef heading
  CGFloat radius, cntrX, cntrY
  
  if ( iteration > 0 )
    float startAngle = angle + 45
    float endAngle = startAngle + 90
    
    float xEnd = x + length * cos( angle * (M_PI/180.0) )
    float yEnd = y + length * sin( angle * (M_PI/180.0) )
    
    if( fn floor(yEnd) < fn floor(y) ) then heading = @"SN" // 6
    if( fn floor(xEnd) < fn floor(x) ) then heading = @"EW" // 5
    if( fn floor(yEnd) > fn floor(y) ) then heading = @"NS" // 4
    if( fn floor(xEnd) > fn floor(x) ) then heading = @"WE" // 3
    
    if ( showLines ) then BezierPathStrokeLine( fn CGPointMake( x, y ), fn CGPointMake( xEnd, yEnd ), 1.0, fn ColorBlack )
    
    // radius = 0.7 * length
    radius = 0.70710678 * length // for higher precision miter and butt intersections
    
    if( showArcs == YES )
      
      if( fn StringIsEqual( heading, @"SN" ) == YES )
        cntrX = x - length/2
        cntrY = y - length/2
        if rnd(2) == 1 then arcColor = fn ColorYellow else arcColor = fn ColorGreen
      end if
      
      if( fn StringIsEqual( heading, @"EW" ) == YES )
        cntrX = x - length/2
        cntrY = y + length/2
        arcColor = fn ColorRed
      end if
      
      if( fn StringIsEqual( heading, @"NS" ) == YES )
        cntrX = x + length/2
        cntrY = y + length/2
        arcColor = fn ColorBlue
      end if
      
      if( fn StringIsEqual( heading, @"WE" ) == YES )
        cntrX = x + length/2
        cntrY = y - length/2
        if rnd(2) == 1 then arcColor = fn ColorOrange else arcColor = fn ColorBlack
      end if
      
      BezierPathRef path = fn BezierPathInit
      BezierPathAppendPathWithArcWithCenter( path, fn CGPointMake( cntrX, cntrY ), radius, startAngle, endAngle, NO )
      BezierPathSetLineJoinStyle( path, NSLineJoinStyleMiter )
      BezierPathSetLineCapStyle(  path, NSLineCapStyleRound  )
      BezierPathStrokeFill(       path, lineWidth, arcColor, NULL )
    end if
    
    fn DrawArcSegment( xEnd, yEnd, angle - 90, length/HR, iteration - 1, arcColor, lineWidth, showLines, showArcs )
    
  end if
end fn

local fn DrawHarrissSpiral
  BezierPathFillRect( fn ViewFrame( _harrissView ), fn ColorGray )
  
  CGRect r = fn WindowFrame( _window )
  int         h = 600
  float  startX = r.size.width / 2 + 80
  float  startY = r.size.height - 140
  float initLen = h/HR/HR
  
  fn DrawArcSegment( startX + initLen/HR,                      startY - (initLen + initLen/HR/HR),          0.0, initLen/HR/HR/HR/HR,       4, fn ColorGreen,   6.0, LINES, YES )
  fn DrawArcSegment( startX + initLen/HR/HR/HR/HR,             startY - (initLen + initLen/HR/HR),        270.0, initLen/HR/HR/HR/HR/HR,    3, fn ColorBlack,   6.0, LINES, YES )
  fn DrawArcSegment( startX - (initLen/HR + initLen/HR/HR/HR), startY - (initLen + initLen/HR/HR),        270.0, initLen/HR/HR/HR/HR/HR,    3, fn ColorBlack,   6.0, LINES, YES )
  fn DrawArcSegment( startX - (initLen/HR + initLen/HR/HR/HR), startY - initLen/HR/HR/HR/HR/HR/HR/HR/HR,  180.0, initLen/HR/HR/HR/HR/HR/HR, 2, fn ColorBlue,    6.0, LINES, YES )
  fn DrawArcSegment( startX - initLen/HR/HR/HR/HR,             startY - initLen/HR/HR/HR,                -270.0, initLen/HR/HR/HR/HR,       3, fn ColorBlue,    8.0, LINES, YES )
  fn DrawArcSegment( startX - initLen/HR/HR/HR/HR,             startY - initLen/HR,                         0.0, initLen/HR/HR/HR/HR/HR,    2, fn ColorGreen,   8.0, LINES, YES )
  fn DrawArcSegment( startX - initLen/HR,                      startY - initLen,                          270.0, initLen/HR/HR,             5, fn ColorRed,    12.0, LINES, YES )
  fn DrawArcSegment( startX - initLen/HR,                      startY - initLen/HR/HR/HR,                 180.0, initLen/HR/HR/HR,          4, fn ColorBlack,  12.0, LINES, YES )
  fn DrawArcSegment( startX,                                   startY - initLen,                            0.0, initLen/HR,                6, fn ColorBlack,  16.0, LINES, YES )
  fn DrawArcSegment( startX,                                   startY,                                    -90.0, initLen,                   7, fn ColorOrange, 16.0, LINES, YES )
end fn


void local fn DoDialog( ev as long, tag as long, wnd as long )
  
  select ( ev )
    case _viewDrawRect
      select ( tag )
        case _harrissView : fn DrawHarrissSpiral
      end select
    case _windowWillClose : end
  end select
end fn

on dialog fn DoDialog

fn BuildWindow

HandleEvents

Standard file output in FB below. Background color easily changed. At bottom, FB file showing construction lines.

Output:

Harris Spiral in FutureBasic Harriss Spiral showing construction lines

Java

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.concurrent.ThreadLocalRandom;

import javax.swing.JComponent;
import javax.swing.JFrame;

public final class HarrissSpiral extends JComponent {

	public static void main(String[] args) {
        EventQueue.invokeLater( () -> {
        	JFrame.setDefaultLookAndFeelDecorated(true);
            JFrame frame = new JFrame("Harriss Spiral");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setPreferredSize( new Dimension(WIDTH, HEIGHT) );
            frame.setResizable(false);
            frame.add( new HarrissSpiral() );
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        } );
    }
	
	@Override
	protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
        Graphics2D graphics2D = (Graphics2D) graphics;
        graphics2D.setColor(SHOW_LINES ? Color.WHITE : Color.DARK_GRAY);
        graphics2D.fill(SCREEN);
        drawHarrissSpiral(graphics2D);
	}
	
	private static void drawHarrissSpiral(Graphics2D graphics2D) {
		final double HR2 = HR * HR;
		final double HR3 = HR2 * HR;
		final double HR4 = HR2 * HR2;
		final double HR5 = HR4 * HR;
		final double HR6 = HR4 * HR2;
		final double HR8 = HR4 * HR4;
		final double startX = WIDTH / 2.0 + 50.0;
		final double startY = HEIGHT - 75.0;		
		final double initialLength = 600 / HR2;
	
		drawArcSegment(startX + initialLength / HR, startY - ( initialLength + initialLength / HR2 ),
			0.0, initialLength / HR4, 4, 6, graphics2D);
		
		drawArcSegment(startX + initialLength / HR4, startY - ( initialLength + initialLength / HR2 ),
			270.0, initialLength / HR5, 3, 6, graphics2D);
		
		drawArcSegment(startX - ( initialLength / HR + initialLength / HR3 ), 
			startY - ( initialLength + initialLength / HR2 ), 270.0, initialLength / HR5, 3, 6, graphics2D);
		
		drawArcSegment(startX - ( initialLength / HR + initialLength / HR3 ),
			startY - initialLength / HR8, 180.0, initialLength / HR6, 2, 6, graphics2D);
		
		drawArcSegment(startX - initialLength / HR4, startY - initialLength / HR3,
			-270.0, initialLength / HR4, 3, 8, graphics2D);
		
		drawArcSegment(startX - initialLength / HR4, startY - initialLength / HR, 
			0.0, initialLength / HR5, 2, 8, graphics2D);
		
		drawArcSegment(startX - initialLength / HR, startY - initialLength, 
			270.0, initialLength / HR2, 5, 12, graphics2D);
		
		drawArcSegment(startX - initialLength / HR, startY - initialLength / HR3,
			180.0, initialLength / HR3, 4, 12, graphics2D);
		
		drawArcSegment(startX, startY - initialLength, 0.0, initialLength / HR, 6, 16, graphics2D);
		
		drawArcSegment(startX, startY, -90.0, initialLength, 7, 16, graphics2D);
	}
	
	private static void drawArcSegment(double x, double y, double angle, double length,
		                               int iteration, int lineWidth, Graphics2D graphics2D) {		
		String heading = "";	
		Color arcColor = Color.WHITE;
		  
	    if ( iteration > 0 ) {	
	    	
		    final double xEnd = x + length * Math.cos(Math.toRadians(angle));
		    final double yEnd = y + length * Math.sin(Math.toRadians(angle));
		    
		    if ( Math.floor(yEnd) < Math.floor(y) ) { heading = "RIGHT"; }
		    if ( Math.floor(xEnd) < Math.floor(x) ) { heading = "UPPER"; }
		    if ( Math.floor(yEnd) > Math.floor(y) ) { heading = "LEFT"; }
		    if ( Math.floor(xEnd) > Math.floor(x) ) { heading = "LOWER"; }
		   
		    if ( SHOW_LINES ) {
		    	graphics2D.setColor(Color.BLACK);
		    	graphics2D.setStroke( new BasicStroke(1) );
			    graphics2D.drawLine((int) x, (int) y, (int) xEnd, (int) yEnd);
		    }	
		    
		    double centreX = 0.0, centreY = 0.0;
				    
		    switch ( heading ) {
			    case "RIGHT" -> {
			        centreX = x - length / 2.0;
			        centreY = y - length / 2.0;
			        arcColor = ( RANDOM.nextInt(2) == 1 ) ? Color.YELLOW : Color.GREEN;
			    }		      
			    case "UPPER" -> {
			        centreX = x - length / 2.0;
			        centreY = y + length / 2.0;
			        angle += 180;
			        arcColor = Color.RED;
			    }
			    case "LEFT" -> {
			        centreX = x + length / 2.0;
			        centreY = y + length / 2.0;
			        arcColor = Color.BLUE;
			    }
			    case "LOWER" -> {
			        centreX = x + length / 2.0;
			        centreY = y - length / 2.0;
			        angle += 180;
			        arcColor = ( RANDOM.nextInt(2) == 1 ) ? Color.ORANGE : Color.BLACK;
			    }			   
		    }
		   
		    final double radius = 0.7 * length;
		    
		    graphics2D.setColor(arcColor);
		    graphics2D.setStroke( new BasicStroke(lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL) );
		    graphics2D.drawArc((int) ( centreX - radius ), (int) ( centreY - radius ),
		    		           (int) radius * 2, (int) radius * 2, (int) angle + 45, 90);		    
		    
		    if ( heading.equals("UPPER") || heading.equals("LOWER") ) { angle -= 180; }
		   
		    drawArcSegment(xEnd, yEnd, angle - 90, length / HR, iteration - 1, lineWidth, graphics2D);		   
	    }		
	}	
	
	private static final int WIDTH = 1_000;
	private static final int HEIGHT = 750;
	private static final double HR = 1.3247; // Harriss ratio	
	private static final boolean SHOW_LINES = false;
	private static final Rectangle SCREEN = new Rectangle(0, 0, WIDTH, HEIGHT);
	private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
	
}

Julia

Translation of: Processing
""" https://rosettacode.org/wiki/Harriss_Spiral """

using Luxor

const HR = 1.324718 # The Harriss Ratio, aka Ian Stewart's "plastic number"
const SHOW_LINES = false

""" Recursively draw the Harriss spiral for `iteration` iterations, with radius sqrt(2) smaller each iteration. """
function harriss(x, y, angle, len, iteration, linew, radius = 0.0, cntrx = 0.0, cntry = 0.0)
    iteration < 1 && return
    startangle = angle + 45
    endangle = startangle + 90
    # Calculate end point of lines
    xend = x + len * cospi(angle / 180)
    yend = y + len * sinpi(angle / 180)
    heading = yend < y ? "SN" : xend < x ? "EW" : yend > y ? "NS" : xend > x ? "WE" : "error"
    if SHOW_LINES
        sethue(0, 0, 0)
        setline(1)
        line(Point(x, y), Point(xend, yend), action = :stroke)
    end
    radius = len / sqrt(2)
    if heading == "SN"
        cntrx = x - len / 2
        cntry = y - len / 2
        sethue(255, 255, 0)
        setline(linew)
    elseif heading == "EW"
        cntrx = x - len / 2
        cntry = y + len / 2
        sethue(255, 0, 0)
        setline(linew)
    elseif heading == "NS"
        cntrx = x + len / 2
        cntry = y + len / 2
        sethue(0, 0, 255)
        setline(linew)
    elseif heading == "WE"
        cntrx = x + len / 2
        cntry = y - len / 2
        sethue(0, 0, 0)
        setline(linew)
    end
    arc(cntrx, cntry, radius, π * startangle / 180, π * endangle / 180, action = :stroke)
    harriss(xend, yend, angle - 90, len / HR, iteration - 1, linew, radius, cntrx, cntry)
end


""" Draw the Harriss spiral several times in its fractal "nest of spirals" format """
function draw()
    Drawing()
    background(211/255, 211/255, 211/255) # light gray
    origin()
    startx = 50
    starty = 280
    init_len = 525 / HR / HR
    # Reverse Order Hides Joints
    harriss(startx - (init_len / HR + init_len / HR^3), starty - init_len / HR^7, 180, init_len / HR^6, 2, 6.0) # level 3
    harriss(startx - (init_len / HR + init_len / HR^3), starty - (init_len + init_len / HR^2), 270, init_len / HR^5, 3, 6.0) # level 3
    harriss(startx + init_len / HR^4, starty - (init_len + init_len / HR^2), 270, init_len / HR^5, 3, 6.0) # level 3
    harriss(startx + init_len / HR, starty - (init_len + init_len / HR^2), 0, init_len / HR^4, 4, 6.0) # level 3 rt-upper
    harriss(startx - init_len / HR^4, starty - init_len / HR, 0, init_len / HR^5, 2, 10.0) # level 2 mid-upper
    harriss(startx - init_len / HR^4, starty - init_len / HR^3, -270, init_len / HR^4, 3, 12.0) # level 2 mid-lower
    harriss(startx - init_len / HR, starty - init_len / HR^3, 180, init_len / HR^3, 4, 12.0) # level 2 lt-lower
    harriss(startx - init_len / HR, starty - init_len, 270, init_len / HR^2, 5, 14.0) # level 2 lt-upper
    harriss(startx, starty - init_len, 0, init_len / HR, 6, 14.0) # level 2 rt-upper
    harriss(startx, starty, -90, init_len, 7, 18.0) # level 1 base spiral
    finish()
    preview()
end

draw()

Phix

Recursive approach, probably deserves a few more tweaks. No colours yet. I plan to add a run online link once finished, but since xpGUI.js is some way off being ready that might not be soon.

-- demo\rosetta\Harriss_Spiral.exw
with javascript_semantics
requires("1.0.6") -- (not yet shipped, this triggered a few bugfixes in gCanvasArc() for one)
include xpGUI.e

constant title = "Harriss Spiral",
         help_text = """
Harriss Spiral demo.
Cycle construction line display with 'L',
  or NSQR for None/Single/sQuare/Rect.
Toggle the initial line with 'I'.
Toggle termination style with 'T'.
Toggle diagnostic info with 'D'.
Increase or decrease depth with +/-.""",
        HARRIS_RATIO = 1.3247,
        IHR = 1/(1+HARRIS_RATIO),
        HHR = HARRIS_RATIO*IHR

integer show_lines = 0, // 0:none, 1=line, 2=square, 3=rect. cycle with 'l'
        max_depth = 1
bool initial = true,
     termination = false, // true = match line tails of other rc entries 
     diagnostics = false  // true = show side(level) in each rectangle

procedure draw_harris(gdx canvas, integer x,y,w,h, side=1, depth=max_depth)
    -- x,y is the pre-rotated top left corner, with side 1..4:
    --  1: horizontal, upright, so x,y top left and square is lower right
    --  2: on left edge, so x,y btm left and the square is at the top right
    --  3: horizontal upside down edge, so x,y btm right and square top left
    --  4: on right edge, so x,y top right and the square is in the lower left
    --  or graphically, with XX/XX representing the position of the square:
    --           3
    --    x,y +----+--+         +--+--+      +--+--+        +--+--+ x,y 
    --        |    |  |         |  |XX|      |XX|  |        |     |
    --        +    +--+ 4/h     |  |XX| w    |XX|  | h      +--+--+ w
    --      2 |    |XX|     or  +--+--+   or +--+  +    or  |XX|  |
    --        |    |XX|         |     |      |  |  |        |XX|  |
    --        +----+--+     x,y +--+--+      +--+--+ x,y    +--+--+
    --           1/w              2/h          3/w            4/h
    --
    -- note that w,h are pre-rotated... max(w,h)/min(w,h) ~= HARRIS_RATIO.
    --
    -- first off calculate [sub]square side and left/mid/right top/mid/low:
    integer ss = round(min(h,w)*HHR),
            sss = ss-round(ss*IHR),
            ss2 = floor(ss/2),
            sss2 = floor(sss/2),
            {lx,mx,rx} = {{x,x+w-ss,x+w-1},
                          {x-w,x-w+ss,x}}[floor((side+1)/2)],
            {ty,my,ly} = {{y,y+h-ss,y+h},
                          {y-h,y-h+ss,y}}[odd(floor(side/2))+1]
    if diagnostics then
        integer {w2,h2} = sq_floor_div({w,h},2),
                {sx,sy} = {{x+w2,y+h2},
                           {x+w2,y-h2},
                           {x-w2,y-h2},
                           {x+w2,y+h2}}[side]
        gCanvasText(canvas,sx,sy,sprintf("%d(%d)",{side,depth}),XPG_C)
    end if
    if show_lines then
        -- x1,y1 is the middle T point
        -- x2,y2 is where the botton of the T hits the edge
        -- x3,y3 is the opposite square corner to x1,y1
        integer {x1,y1,x2,y2,x3,y3} = {{mx,my,rx,my,rx,ly},
                                       {mx,my-1,mx,ty-1,rx,ty-1},
                                       {lx,my,mx,my,mx,ty},
                                       {mx,my,mx,ly-1,lx,ly-1}}[side]
        if show_lines=2 then
            gCanvasRect(canvas, x1,x3, y1,y3)
        elsif show_lines=3 then
            gCanvasLine(canvas, x1,y1, x2,y2)
            {x1,y1,x2,y2} = {{mx,ty,mx,ly},
                             {lx,my,rx,my}}[even(side)+1]
            gCanvasRect(canvas, x,x3, y,y3)
            gCanvasLine(canvas, x1,y1, x2,y2) -- divider (top of T)
        end if
    end if
    integer {cx,cy,a1,a2} = {{mx-ss2,my+ss2,315,45},
                             {mx+ss2,my+ss2,225,315},
                             {mx+ss2,my-ss2,135,225},
                             {mx-ss2,my-ss2,45,135}}[side]
    atom r = sqrt(2)*ss
    if initial or depth<max_depth then
        if show_lines=1 then
            integer {ex,ey} = {{mx,my+ss},
                               {mx+ss,my},
                               {mx,my-ss},
                               {mx-ss,my}}[side]
            gCanvasLine(canvas, mx,my, ex,ey)
        end if
        gCanvasArc(canvas,cx,cy,r,r,a1,a2,width:=depth+1)
    end if
    if depth>1 or not termination then
        if show_lines=1 then
            integer {ex,ey} = {{mx+sss,my},
                               {mx,my-sss},
                               {mx-sss,my},
                               {mx,my+sss}}[side]
            gCanvasLine(canvas, mx,my, ex,ey)
        end if
        {cx,cy,a1,a2} = {{mx+sss2,my-sss2,45,135},
                         {mx-sss2,my-sss2,315,45},
                         {mx-sss2,my+sss2,225,315},
                         {mx+sss2,my+sss2,135,225}}[side]
        r = sqrt(2)*sss
        gCanvasArc(canvas,cx,cy,r,r,a1,a2,width:=depth)
    end if
    if depth>1 then
        switch side
            case 1: draw_harris(canvas, mx,ty,ss,h-ss, 1, depth-1)
                    draw_harris(canvas, lx,ly,w-ss,h,  2, depth-1)
            case 2: draw_harris(canvas, lx,my,w-ss,ss, 2, depth-1)
                    draw_harris(canvas, rx,ly,w,h-ss,  3, depth-1)
            case 3: draw_harris(canvas, mx,ly,ss,h-ss, 3, depth-1)
                    draw_harris(canvas, rx,ty,w-ss,h,  4, depth-1)
            case 4: draw_harris(canvas, rx,my,w-ss,ss, 4, depth-1)
                    draw_harris(canvas, lx,ty,w,h-ss,  1, depth-1)
        end switch
    end if
end procedure

procedure redraw(gdx canvas, integer w,h)
    --- determine margins for a horizontal centred harris ratio rectangle:
    integer {mw,mh} = iff(h>w/HARRIS_RATIO?{0,floor((h-w/HARRIS_RATIO)/2)}
                                          :{floor((w-h*HARRIS_RATIO)/2),0})
    gCanvasRect(canvas, mw, w-mw, mh, h-mh, true, colour:=XPG_PARCHMENT)
    w -= mw*2
    h -= mh*2
    draw_harris(canvas, mw, mh, w, h)
    gdx dlg = gGetParent(canvas)
    gSetAttribute(dlg,"TITLE","%s (max_depth %d)",{title,max_depth})
end procedure

function show_help(gdx dlg)
    gMsgBox(dlg,"Help",help_text)
    return XPG_IGNORE -- (don't open browser help!)
end function

function key_handler(gdx dlg, integer c)
    if c=VK_ESC then return XPG_CLOSE end if -- (standard practice for me)
    if c=VK_F5 then return XPG_DEFAULT end if -- (let browser reload work)
    if c=VK_F1 then return show_help(dlg) end if
    switch upper(c)
        case 'L': show_lines = rmdr(show_lines+1,4)
        case 'N': show_lines = 0
        case 'S': show_lines = 1
        case 'Q': show_lines = 2
        case 'R': show_lines = 3
        case 'I': initial = not initial
        case 'T': termination = not termination
        case 'D': diagnostics = not diagnostics
        case '+','=': max_depth = min(max_depth+1,7)
        case '-','_': max_depth = max(max_depth-1,1)
    end switch
    gRedraw(dlg)
    return XPG_DEFAULT
end function

gdx canvas = gCanvas(redraw)
gdx dialog = gDialog(canvas,title,"SIZE=510x540, MINSIZE=273x58")
gSetHandler(dialog, `KEY`, key_handler)
gShow(dialog)
gMainLoop()

Processing

Steve Van Voorst's original source code. Free open source cross-platform IDE can be downloaded here: https://processing.org/

// ======== start ========== //
int h = 600; // scalable (may be any value)

final float HR = 1.325; // Harriss Ratio

int _wndW = 1000;
int _wndH = 800;

float cntrX = 0;
float cntrY = 0;
float radius = 0;
String heading = "";
boolean showLines = false;

void drawHarriss(float x, float y, float angle, float len, int iteration, float lineW) {
  if (iteration > 0) {
    float startAngle = angle + 45;
    float endAngle = startAngle + 90;
    // Calculate end point of lines
    float xEnd = x + len * cos(radians(angle));
    float yEnd = y + len * sin(radians(angle));
    if ((int)yEnd < (int)y) {
      heading = "SN";
    }  //6
    if ((int)xEnd < (int)x) {
      heading = "EW" ;
    } //5
    if ((int)yEnd > (int)y) {
      heading = "NS";
    }  //4
    if ((int)xEnd > (int)x) {
      heading = "WE";
    }  //3
    if (showLines) {
      stroke(0);
      strokeWeight(1);
      line(x, y, xEnd, yEnd);
    }
    radius = 1.414*len;
    if (heading == "SN") {
      cntrX = x - len/2;
      cntrY = y - len/2;
      stroke(255, 255, 0);
      strokeWeight(lineW);
    }
    if (heading == "EW") {
      cntrX = x - len/2;
      cntrY = y + len/2;
      stroke(255, 0, 0);
      strokeWeight(lineW);
    }
    if (heading == "NS") {
      cntrX = x + len/2;
      cntrY = y + len/2;
      stroke(0, 0, 255);
      strokeWeight(lineW);
    }
    if (heading == "WE") {
      cntrX = x + len/2;
      cntrY = y - len/2;
      stroke(0);
      strokeWeight(lineW);
    }
    arc(cntrX, cntrY, radius, radius, radians(startAngle), radians(endAngle), OPEN);
    drawHarriss( xEnd, yEnd, angle - 90, len/HR, iteration - 1, lineW);
  }
}

void setup() {
  size(_wndW, _wndH);
  background(140);
  noFill();
  float startX = _wndW/2 + 50;
  float startY = _wndH - 50;
  float initLen = h/HR/HR;
  // Reverse Order Hides Joints
  drawHarriss(startX - (initLen/HR + initLen/HR/HR/HR), startY - initLen/HR/HR/HR/HR/HR/HR/HR/HR, 180, initLen/HR/HR/HR/HR/HR/HR, 2, 6.0); // level 3
  drawHarriss(startX - (initLen/HR + initLen/HR/HR/HR), startY - (initLen+initLen/HR/HR), 270, initLen/HR/HR/HR/HR/HR, 3, 6.0); // level 3
  drawHarriss(startX + initLen/HR/HR/HR/HR, startY - (initLen + initLen/HR/HR), 270, initLen/HR/HR/HR/HR/HR, 3, 6.0); // level 3
  drawHarriss(startX + initLen/HR, startY - (initLen + initLen/HR/HR), 0, initLen/HR/HR/HR/HR, 4, 6.0); // level 3 rt-upper
  drawHarriss(startX - initLen/HR/HR/HR/HR, startY - initLen/HR, 0, initLen/HR/HR/HR/HR/HR, 2, 10.0); // level 2 mid-upper
  drawHarriss(startX - initLen/HR/HR/HR/HR, startY - initLen/HR/HR/HR, -270, initLen/HR/HR/HR/HR, 3, 12.0); // level 2 mid-lower
  drawHarriss(startX - initLen/HR, startY - initLen/HR/HR/HR, 180, initLen/HR/HR/HR, 4, 12.0); // level 2 lt-lower
  drawHarriss(startX - initLen/HR, startY - initLen, 270, initLen/HR/HR, 5, 14.0); // level 2 lt-upper
  drawHarriss(startX, startY - initLen, 0, initLen/HR, 6, 14.0); // level 2 rt-upper
  drawHarriss(startX, startY, -90, initLen, 7, 18.0); // level 1 base spiral
}

void draw() {
}
// ======== end =========== //

Python

Translation of: Java
Library: Pygame

Note: This code is compatible with Python versions 3.10 or later.

import math
import random

import pygame

WIDTH, HEIGHT = 1000, 750
HR = 1.3247
SHOW_LINES = False


def draw_arc_segment(
    x: float,
    y: float,
    angle: float,
    length: float,
    iteration: int,
    line_width: int,
    surface: pygame.Surface,
):
    if iteration <= 0:
        return

    heading = ""
    arc_color = (255, 255, 255)

    x_end = x + length * math.cos(math.radians(angle))
    y_end = y + length * math.sin(math.radians(angle))

    if math.floor(y_end) < math.floor(y):
        heading = "RIGHT"

    if math.floor(x_end) < math.floor(x):
        heading = "UPPER"

    if math.floor(y_end) > math.floor(y):
        heading = "LEFT"

    if math.floor(x_end) > math.floor(x):
        heading = "LOWER"

    if SHOW_LINES:
        pygame.draw.line(surface, (0, 0, 0), (x, y), (x_end, y_end))

    centre_x, centre_y = 0, 0

    match heading:
        case "RIGHT":
            centre_x = x - length / 2
            centre_y = y - length / 2
            arc_color = random.choice(((255, 255, 0), (0, 255, 0)))

        case "UPPER":
            centre_x = x - length / 2
            centre_y = y + length / 2
            angle += 180
            arc_color = (255, 0, 0)

        case "LEFT":
            centre_x = x + length / 2
            centre_y = y + length / 2
            arc_color = (0, 0, 255)

        case "LOWER":
            centre_x = x + length / 2
            centre_y = y - length / 2
            angle += 180
            arc_color = random.choice(((255, 175, 0), (0, 0, 0)))

    radius = 0.7 * length
    pygame.draw.arc(
        surface,
        arc_color,
        pygame.Rect(
            int(centre_x - radius),
            int(centre_y - radius),
            int(radius * 2),
            int(radius * 2),
        ),
        math.radians(angle + 45),
        math.radians(angle + 45 + 90),
    )

    if heading == "LOWER" or heading == "UPPER":
        angle -= 180

    draw_arc_segment(
        x_end, y_end, angle - 90, length / HR, iteration - 1, line_width, surface
    )


def draw_harriss_spiral(surface: pygame.Surface):
    HR2 = HR * HR
    HR3 = HR2 * HR
    HR4 = HR2 * HR2
    HR5 = HR4 * HR
    HR6 = HR4 * HR2
    HR8 = HR4 * HR4

    start_x = WIDTH / 2.0 + 50.0
    start_y = HEIGHT - 75.0
    initial_length = 600 / HR2

    draw_arc_segment(
        start_x + initial_length / HR,
        start_y - (initial_length + initial_length / HR2),
        0,
        initial_length / HR4,
        4,
        6,
        surface,
    )
    draw_arc_segment(
        start_x + initial_length / HR4,
        start_y - (initial_length + initial_length / HR2),
        270.0,
        initial_length / HR5,
        3,
        6,
        surface,
    )
    draw_arc_segment(
        start_x - (initial_length / HR + initial_length / HR3),
        start_y - (initial_length + initial_length / HR2),
        270.0,
        initial_length / HR5,
        3,
        6,
        surface,
    )
    draw_arc_segment(
        start_x - (initial_length / HR + initial_length / HR3),
        start_y - initial_length / HR8,
        180.0,
        initial_length / HR6,
        2,
        6,
        surface,
    )
    draw_arc_segment(
        start_x - initial_length / HR4,
        start_y - initial_length / HR3,
        -270.0,
        initial_length / HR4,
        3,
        8,
        surface,
    )
    draw_arc_segment(
        start_x - initial_length / HR4,
        start_y - initial_length / HR,
        0.0,
        initial_length / HR5,
        2,
        8,
        surface,
    )
    draw_arc_segment(
        start_x - initial_length / HR,
        start_y - initial_length,
        270.0,
        initial_length / HR2,
        5,
        12,
        surface,
    )
    draw_arc_segment(
        start_x - initial_length / HR,
        start_y - initial_length / HR3,
        180.0,
        initial_length / HR3,
        4,
        12,
        surface,
    )
    draw_arc_segment(
        start_x, start_y - initial_length, 0.0, initial_length / HR, 6, 16, surface
    )
    draw_arc_segment(start_x, start_y, -90.0, initial_length, 7, 16, surface)


def main():
    pygame.init()
    pygame.display.set_caption("Harriss Spiral")

    screen = pygame.display.set_mode((WIDTH, HEIGHT))

    running = True

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        screen.fill((255, 255, 255) if not SHOW_LINES else (100, 100, 100))
        draw_harriss_spiral(screen)
        pygame.display.flip()

    pygame.quit()


if __name__ == "__main__":
    main()
Output:

Wren

Translation of: FutureBasic
Library: DOME
Library: Wren-ellipse

Note that some of the colors are random and consequently the output may not necessarily match the FutureBasic example. Also DOME uses its own color palette which differs from standard RGB colors.

import "dome" for Window
import "graphics" for Canvas, Color
import "math" for M
import "random" for Random
import "./ellipse" for Circle

var HR  = 1.3247  // Harriss ratio
var HR2 = HR * HR
var HR3 = HR2 * HR
var HR4 = HR2 * HR2
var HR5 = HR4 * HR
var HR6 = HR4 * HR2
var HR8 = HR4 * HR4
var LINES = false  // set to true to show construction lines
var Rand = Random.new()

class HarrissSpiral {
    construct new(width, height) {
        Window.title = "Harriss spiral"
        Window.resize(width, height)
        Canvas.resize(width, height)
        if (LINES) Canvas.cls(Color.white) else Canvas.cls(Color.darkgray)
        _w = width
        _h = height
    }

    // We always show the arcs so no need for a parameter for that.
    drawArcSegment(x, y, angle, length, iteration, arcColor, lineWidth, showLines) {
        var heading
        var radius
        var cx
        var cy
        var circle
        var adj
        if (iteration > 0) {
            var startAngle = angle + 45
            var endAngle = startAngle + 90

            var xEnd = x + length * M.cos(angle * Num.pi / 180)
            var yEnd = y + length * M.sin(angle * Num.pi / 180)

            if (M.floor(yEnd) < M.floor(y)) heading = "SN"  // 6
            if (M.floor(xEnd) < M.floor(x)) heading = "EW"  // 5
            if (M.floor(yEnd) > M.floor(y)) heading = "NS"  // 4
            if (M.floor(xEnd) > M.floor(x)) heading = "WE"  // 3

            if (showLines) Canvas.line(x, y, xEnd, yEnd, Color.black)

            radius = 0.70710678 * length

            if (heading == "SN") {
                cx = x - length / 2
                cy = y - length / 2
                arcColor = (Rand.int(2) == 1) ? Color.yellow : Color.green
            } else if (heading == "EW") {
                cx = x - length / 2
                cy = y + length / 2
                arcColor = Color.red
            } else if (heading == "NS") {
                cx = x + length / 2
                cy = y + length / 2
                arcColor = Color.blue
            } else if (heading == "WE") {
                cx = x + length / 2
                cy = y - length / 2
                arcColor = (Rand.int(2) == 1) ? Color.orange : Color.black
            }
            for (i in -lineWidth/2...lineWidth/2) {
                circle = Circle.new(cx, cy, radius + i)
                adj = lineWidth/8 - (i < 0 ? -i/4 : (i+1)/4)
                circle.drawArc(arcColor, startAngle - adj, endAngle + adj)
            }
            drawArcSegment(xEnd, yEnd, angle-90, length/HR, iteration-1, arcColor, lineWidth, showLines)
        }
    }

    drawSpiral() {
        var h = 600
        var sx = (_w/2 + 80) // starting x
        var sy = (_h - 140)  // starting y
        var il = h / HR2     // initial length

        drawArcSegment(sx + il/HR,  sy - (il + il/HR2),   0, il / HR4, 4, Color.green, 6, LINES)
        drawArcSegment(sx + il/HR4, sy - (il + il/HR2), 270, il / HR5, 3, Color.black, 6, LINES)
        drawArcSegment(sx - (il/HR + il/HR3), sy - (il + il/HR2), 270, il / HR5, 3, Color.black, 6, LINES)
        drawArcSegment(sx - (il/HR + il/HR3), sy - il/HR8, 180, il / HR6, 2, Color.blue, 6, LINES)
        drawArcSegment(sx - il/HR4, sy - il/HR3, -270, il / HR4, 3, Color.blue, 8, LINES)
        drawArcSegment(sx - il/HR4, sy - il/HR, 0, il / HR5, 2, Color.green, 8, LINES)
        drawArcSegment(sx - il/HR, sy - il, 270, il / HR2, 5, Color.red, 12, LINES)
        drawArcSegment(sx - il/HR, sy - il/HR3, 180, il / HR3, 4, Color.black, 12, LINES)
        drawArcSegment(sx, sy - il, 0, il / HR, 6, Color.black, 16, LINES)
        drawArcSegment(sx, sy, -90, il, 7, Color.orange, 16, LINES)
    }

    init() { drawSpiral() }

    update() {}

    draw(dt) {}
}

var Game = HarrissSpiral.new(1000, 800)
Output:

Harris Spiral

Harriss Spiral showing construction lines

XPL0

Translation of: Wren
include xpllib;         \for InitDraw, DrawRectangle, DrawCircle, color names

def  LINES = false;     \set to 'true' to show construction lines
def  ScrW=1024, ScrH=768;
def  HR = 1.3247;       \Harriss Ratio
def  HR2 = HR * HR;
def  HR3 = HR2 * HR;
def  HR4 = HR2 * HR2;
def  HR5 = HR4 * HR;
def  HR6 = HR4 * HR2;
def  HR8 = HR4 * HR4;

proc DrawArcSeg(X, Y, Angle, Length, Iter, ArcColor, LineW, ShowLines);
real X, Y, Angle, Length; int Iter, ArcColor, LineW, ShowLines;
real XEnd, YEnd, Radius, CX, CY;
int  Heading;
def  \Heading\ SN, EW, NS, WE;
[if Iter <= 0 then return;

XEnd:= X + Length * Cos(Angle*Pi/180.);
YEnd:= Y + Length * Sin(Angle*Pi/180.);

if Floor(YEnd) < Floor(Y) then Heading:= SN;
if Floor(XEnd) < Floor(X) then Heading:= EW;
if Floor(YEnd) > Floor(Y) then Heading:= NS;
if Floor(XEnd) > Floor(X) then Heading:= WE;

if ShowLines then [Move(fix(X), fix(Y));  Line(fix(XEnd), fix(YEnd), Black)];

Radius:= 0.7 * Length;

case Heading of
  SN:   [CX:= X - Length/2.;
         CY:= Y - Length/2.;
         ArcColor:= if Ran(2) = 1 then Yellow else Green;
        ];
  EW:   [CX:= X - Length/2.;
         CY:= Y + Length/2.;
         ArcColor:= Red;
        ];
  NS:   [CX:= X + Length/2.;
         CY:= Y + Length/2.;
         ArcColor:= Blue;
        ];
  WE:   [CX:= X + Length/2.;
         CY:= Y - Length/2.;
         ArcColor:= if Ran(2) = 1 then Brown else Black;
        ]
other   [];

case rem( fix(Angle+3600.) / 360 ) / 90 of
  0:    ArcSegs:= %1111_1001;
  1:    ArcSegs:= %1110_0111;
  2:    ArcSegs:= %1001_1111;
  3:    ArcSegs:= %0111_1110
other   ArcSegs:= %1010_1010;

LineWidth:= LineW/2;
DrawCircle(fix(CX), fix(CY), fix(Radius), ArcColor, false \fill\);

DrawArcSeg(XEnd, YEnd, Angle-90., Length/HR, Iter-1, ArcColor, LineW, ShowLines);
];

proc DrawHarrissSpiral;
def  H = 600.;
def  SX = float(ScrW/2 + 80);           \Starting X
def  SY = float(ScrH   - 80);           \Starting Y
def  IL = H / HR2;                      \Initial Length
[
DrawArcSeg(SX+(IL/HR),        SY-(IL+IL/HR2),   0., IL/HR4, 4, Green,  6, LINES);
DrawArcSeg(SX+(IL/HR4),       SY-(IL+IL/HR2), 270., IL/HR5, 3, Black,  6, LINES);
DrawArcSeg(SX-(IL/HR+IL/HR3), SY-(IL+IL/HR2), 270., IL/HR5, 3, Black,  6, LINES);
DrawArcSeg(SX-(IL/HR+IL/HR3), SY-(IL/HR8),    180., IL/HR6, 2, Blue,   6, LINES);
DrawArcSeg(SX-(IL/HR4),       SY-(IL/HR3),   -270., IL/HR4, 3, Blue,   8, LINES);
DrawArcSeg(SX-(IL/HR4),       SY-(IL/HR),       0., IL/HR5, 2, Green,  8, LINES);
DrawArcSeg(SX-(IL/HR),        SY-(IL),        270., IL/HR2, 5, Red,   12, LINES);
DrawArcSeg(SX-(IL/HR),        SY-(IL/HR3),    180., IL/HR3, 4, Black, 12, LINES);
DrawArcSeg(SX,                SY-(IL),          0., IL/HR,  6, Black, 16, LINES);
DrawArcSeg(SX,                SY,             -90., IL,     7, Brown, 16, LINES);
];

[SetVid($105);          \1024x768x8
InitDraw;
DrawRectangle(0, 0, ScrW, ScrH, if LINES then White else Gray, true \fill\);
Attrib($0E0E);          \yellow
Cursor(1024/8/2-8, 0);  Text(6, " Harriss Spiral ");
DrawHarrissSpiral;
]
Output:

Cookies help us deliver our services. By using our services, you agree to our use of cookies.