WTF is this?

The images you see on this blog are output from various Ulam spiral generators I built in Flash, Python and most recently using Arduino. Generally, each dot in an image represents a number with integer 1 at center. In addition to writing algorithms to test each number for primality within a set I have discovered that an infinite number of calculations can be performed to create new designs and animation algorithms. The simplicity and speed of these algorithms make them an ideal fit for embedded systems graphics, scientific, mathematical and artistic explorations.

Thursday, July 31, 2014

Displaying Ulam Spirals with Arduino Yun and 128x160 Display


I just set up a small 128x160 LCD display with an Arduino Yun running full animations of the Ulam Spiral. 
Here's the adafruit tutorial I used to get going: http://www.adafruit.com/products/358

Notes: the redraw rate is pretty slow, around 1 frame per 3 seconds or so. Definitely not as fast as the LED panel I wired up. It's still very interesting to watch the spirals develop like this and much faster then Flash. The other cool thing about this build is the Yun, which I have connected to a wireless network. It's very easy to update the board remotely. 

Here's the code from my sketch: 

//spiral algo written by arlo emerson arloemerson@gmail.com
//adapted from the ulam spiral aglorithm
//2014
//http://ulamspiral.blogspot.com/

#define PI 3.1415926535897932384626433832795

#define sclk 4
#define mosi 5
#define cs   6
#define dc   7
#define rst  8 


#include    // Core graphics library
#include // Hardware-specific library
#include

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, mosi, sclk, rst);

#define Neutral 0
#define Press 1
#define Up 2
#define Down 3
#define Right 4
#define Left 5


float _piCounter = .005;
int _globalCounter = 2;

void setup(void) {
  Serial.begin(9600);

  tft.initR(INITR_BLACKTAB); 

  uint16_t time = millis();
  tft.fillScreen(ST7735_BLACK);
  time = millis() - time;

  tft.drawPixel(tft.width() / 2, tft.height() / 2, ST7735_GREEN);

  printWelcomeText();

  initSpiral();
}

void loop()
{

  initSpiral();

  _piCounter += .001;
  delay(200);
  _globalCounter += 1;

  if (_globalCounter == 10)
  {
    printWelcomeText();
    _globalCounter = 0;

  }
}


void initSpiral()
{
  int posX = tft.width() / 2;
  int posY = tft.height() / 2;
  int numberCounter = 1;
  int _spacer = 1;
  int legLength = 0;

  //establish the first dot
  tft.drawPixel(posX, posY, ST7735_WHITE);

  for (int i = 1; i < 60; i++)
  {
    for (int k = 0; k <= legLength; k++)
    {
      numberCounter += 1;
      posX += _spacer;
      testNumber(numberCounter, posX, posY);
    }

    for (int k = 0; k <= legLength; k++)
    {
      numberCounter += 1;
      posY -= _spacer;
      testNumber(numberCounter, posX, posY);
    }

    legLength += 1;

    for (int k = 0; k <= legLength; k++)
    {
      numberCounter += 1;
      posX -= _spacer;
      testNumber(numberCounter, posX, posY);
    }

    for (int k = 0; k <= legLength; k++)
    {
      numberCounter += 1;
      posY += _spacer;
      testNumber(numberCounter, posX, posY);
    }

    legLength += 1;
  }
}

void testNumber(int pNumber, int pX, int pY)
{
  //int tmpMultiplier = _piCounter * 1.1;
  //if (round(sqrt(pow(pNumber,2))*(1.6180339887*PI)/2)%2==0)
  //if (round(  pow(sqrt(pNumber)/PI, tmpGradient) )%2==0)
  //Serial.println(_piCounter);
  //if (round( sqrt( pow(pNumber, 2 ))*_piCounter * PI) % 2 == 0)
  //if (round(sqrt(pow(pNumber,2))*((.9 * _piCounter) *PI)/2)%2==0)
  if (  round( (pX*pY)* pow(sqrt(pNumber)/PI, 1.23456789)*_piCounter )%3==0)
  {
    //    matrix.drawPixel(pX, pY, matrix.Color333(_bigNumber.charAt(pX), _bigNumber.charAt(pY), _bigNumber.charAt(_globalCounter)));

    tft.drawPixel(pX, pY, ST7735_WHITE);
  }
  else
  {
    tft.drawPixel(pX, pY, ST7735_RED);
  }
}

void printWelcomeText()
{
  tft.setCursor(0, 0);
  tft.fillScreen(ST7735_BLACK);
  tft.setTextColor(ST7735_YELLOW);
  tft.setTextSize(2);
  tft.println("Ulam");
  tft.setTextColor(ST7735_WHITE);
  tft.println("Spirals");
  tft.setTextColor(ST7735_RED);
  tft.println("Forever");
  delay(3000);
  tft.fillScreen(ST7735_BLACK);
}




Wednesday, July 30, 2014

Ulam Spirals Using Arduino and LED Displays


Here's an animated gif of my Arduino-powered 32x16 LED screen. I wired this up using the Adafruit tutorial at https://learn.adafruit.com/32x16-32x32-rgb-led-matrix/wiring-the-16x32-matrix

The code to generate the spiral. Note this is unoptimized. You can probably do it better. The basic nugget to get the spiral is this line: round( sqrt( pow(pNumber, 2 ))*_piCounter*PI)%2==0).

void loop()
{
   initSpiral();
  _piCounter += .001;
  delay(200);
  _globalCounter += 1;
}

void initSpiral()
{
  int posX = 15;
  int posY = 7;
  int numberCounter = 1;
  int _spacer = 1;
  int legLength = 0;

  //establish the first dot
  //matrix.drawPixel(x, y, matrix.Color333(r, g, b));
  matrix.drawPixel(posX, posY, matrix.Color333(3, 4, 5));


  for (int i=1;i<17 font="" i="">
  {
    for (int k=0;k<=legLength;k++)
    {
      numberCounter += 1;
      posX += _spacer;
      testNumber(numberCounter, posX, posY);
    }

    for (int k=0;k<=legLength;k++)
    {
      numberCounter += 1;
      posY -= _spacer;
      testNumber(numberCounter, posX, posY);
    }    

    legLength += 1;

    for (int k=0;k<=legLength;k++)
    {
      numberCounter += 1;
      posX -= _spacer;
      testNumber(numberCounter, posX, posY);
    }

    for (int k=0;k<=legLength;k++)
    {
      numberCounter += 1;
      posY += _spacer;
      testNumber(numberCounter, posX, posY);
    }

    legLength += 1;
  }
}


String _bigNumber = "01234567012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567";


void testNumber(int pNumber, int pX, int pY)
{
  if (round( sqrt( pow(pNumber, 2 ))*_piCounter*PI)%2==0)
  {
    matrix.drawPixel(pX, pY, matrix.Color333(_bigNumber.charAt(pX), _bigNumber.charAt(pY), _bigNumber.charAt(_globalCounter)));
  }
  else
  {
    matrix.drawPixel(pX, pY, matrix.Color333(3, 0, 2));
  }
}

Interesting note: these 32x16 panels are so incredibly bright they are painful to look at. So I'm using two sheets of paper to stop down the light, which also has a nice diffusion effect.