Circle packing clock ideas?

Here is the code for a clock using the circle packing from a youtube tutorial. I am looking for any ideas of what to add to this project or any ideas of how to improve my code here (I know it's messy).

int grid = 50;
Screen hrscreen;
Screen mnscreen;
int circleamn;
char mn2;
char mn1;
char hr1;
char hr2;
int currentmin;
ArrayList<Circle> circles;

void setup() {
  background(0);
  size(1000, 1000);
  frameRate(120);
  surface.setResizable(true);
  circles = new ArrayList<Circle>();
  circleamn = 0;
  currentmin = minute();
}

void draw() {
  background(80);
  grid = width / 26;

  String hr = str(hour());
  String mn = str(minute());
  char colon = 'c';

  if (int(hr) > 12) {
    hr = str(int(hr) - 12);
  }

  if (int(mn) > 9)
  {
    mn1 = mn.charAt(0);
    mn2 = mn.charAt(1);
  } else {
    mn1 = '0';
    mn2 = mn.charAt(0);
  }

  if (int(hr) > 9)
  {
    hr1 = hr.charAt(0);
    hr2 = hr.charAt(1);
  } else {
    hr1 = '0';
    hr2 = hr.charAt(0);
  }

  if (currentmin == int(mn))
  {
    Screen hrscreen = new Screen(hr1, "hr");
    Screen hr2screen = new Screen(hr2, "hr2");
    Screen mnscreen = new Screen(mn1, "mn");
    Screen mn2screen = new Screen(mn2, "mn2");
    Screen colonscreen = new Screen(colon, "colon");

    drawCircles(hrscreen);
    drawCircles(hr2screen);
    drawCircles(mnscreen);
    drawCircles(mn2screen);
    drawCircles(colonscreen);
  } else {
    circles.clear();
    currentmin = int(mn);
  }
}

Circle newCircle(ArrayList<PVector> spots) {

  int r = int(random(0, spots.size()));
  PVector spot = spots.get(r);
  float x = spot.x;
  float y = spot.y;
  boolean valid = true;

  for (Circle c : circles) {
    float d = dist(x, y, c.x, c.y);
    if (d < c.r + 10) {
      valid = false;
      break;
    }
  }

  if (valid) {
    return new Circle(x, y);
  } else {
    return null;
  }
}

void drawCircles(Screen screen) {
  int circlesperframe = 10;
  for (int i = 0; i < circlesperframe; i++) {
    Circle newC = newCircle(screen.spots);
    if (newC != null) {
      circles.add(newC);
    }
  }

  for (Circle c : circles) {
    if (c.growing) {
      if (c.edges()) {
        c.growing = false;
      } else {
        for (Circle other : circles) {
          if (c != other) {
            float d = dist(c.x, c.y, other.x, other.y);
            if (d - 2 < c.r + other.r) {
              c.growing = false;
              break;
            }
          }
        }
      }
    }
    c.show();
    c.grow();
  }
}

class Circle {
  float x;
  float y;
  float r;

  boolean growing = true;

  Circle(float x_, float y_) {
    x = x_;
    y = y_;
    r = 1;
  }

  void show() {
    stroke(100 + (y/grid * 10), 0 + (y/grid * 10), 255 + (y/grid * 10));
    strokeWeight(2);
    fill(100 + (y/grid * 10), 0 + (y/grid * 10), 255 + (y/grid * 10), 80);
    ellipse(x, y, r*2, r*2);
  }

  boolean edges() {
    return (x + r > width || x - r < 0 || y + r > height || y - r < 0);
  }

  void grow() {
    if (growing) {
      r = r + 1;
    }
  }
}

class Screen {
  char imagename;
  PImage img;
  ArrayList<PVector> spots;
  String type;
  int positionx = 0;
  int positiony = 0;

  Screen(char imgnm, String type_) {
    type = type_;
    imagename = imgnm;
    spots = new ArrayList<PVector>();
    img = loadImage(sketchPath("") + "/" + "source/images/" + str(imagename) + ".PNG");

    switch(type) {
    case "hr":
      img.resize(5 * grid, 8 * grid);
      img.loadPixels();
      positionx = 0;
      break;
    case "hr2":
      img.resize(5 * grid, 8 * grid);
      img.loadPixels();
      positionx = grid * 6;
      break;
    case "mn":
      img.resize(5 * grid, 8 * grid);
      img.loadPixels();
      positionx = grid * 15;
      break;
    case "mn2":
      img.resize(5 * grid, 8 * grid);
      img.loadPixels();
      positionx = grid * 21;
      break;
    case "colon":
      img.resize(2 * grid, 0);
      img.loadPixels();
      positionx = grid * 12;
      positiony = grid * 2;
      break;
    }

    for (int x = 0; x < img.width; x++) {
      for (int y = 0; y < img.height; y++) {
        int index = x + y * img.width;
        color c = img.pixels[index];
        float b = brightness(c);
        if (b < 100) {
          spots.add(new PVector(x + positionx, y + (height / 2 - grid * 4) + positiony));
        }
      }
    }
  }
}

Comments

  • edited September 2017

    I just realized that if someone were to try to put this code in an application it would fail. If you want to use/test it you need to have a folder in your project folder with the path source/images and in that folder have a .PNG for every number 0-9 and one for a colon named c.PNG.

    i.e. source/images/0.PNG

  • if (int(hr) > 9) ...
    

    Look at nf() in the reference

  • Don't load images in draw. Don't resize images in draw. (You do both via the Screen constructor)

    And why set the frame rate to 120 when nothing changes more than once or twice a second.

  • ok, it's looping because it's updating the screen constantly. but it doesn't need to be 120 fps - i don't want my pc fan whirring like a helicopter because it's running a clock.

    img = loadImage(sketchPath("") + "/" + "source/images/" + str(imagename) + ".PNG");
    

    what's up with putting the files in the data directory like normal?

    char mn2;
    char mn1;
    char hr1;
    char hr2;
    

    why are these global when they are only used in draw? and all that converting / casting between char and int and string makes my head spin.

  • and i think this is wrong

    if (currentmin == int(mn)) {
      Screen hrscreen = new Screen(hr1, "hr");
      Screen hr2screen = new Screen(hr2, "hr2");
      Screen mnscreen = new Screen(mn1, "mn");
      Screen mn2screen = new Screen(mn2, "mn2");
      Screen colonscreen = new Screen(colon, "colon");
    

    you only need to recreate the digits if the minute has changed, not if it's the same. as it is you are doing this, which is loading the images and extracting the pixels from them, 120 times a second. they change once a minute...

Sign In or Register to comment.