sketch_210607a

NonCircularPacking.pde


class NonCircularPacking {
  
  PGraphics pg;
  PGraphics tmpPg;
  
  ArrayList<AbstractItem> items;
  
  AbstractItem maskItem;
  int margin;
  
  NonCircularPacking() {
    this(null);
  }
  
  NonCircularPacking(AbstractItem maskItem) {
    this(maskItem, 0);
  }
  
  NonCircularPacking(AbstractItem maskItem, int margin) {
    this.margin = margin;
    this.maskItem = maskItem;
    
    pg = createGraphics(width, height);
    pg.beginDraw();
    pg.background(0, 0);
    if (maskItem != null) {
      maskItem.draw(pg, 0);
    }
    pg.endDraw();
    
    // マスクが設定されているときは透明度をひっくり返しておく
    if (maskItem != null) {
      pg.loadPixels();
      for (int k = 0; k < pg.pixels.length; k++) {
        color pixel = pg.pixels[k];
        pg.pixels[k] = color(red(pixel), green(pixel), blue(pixel), 255 - alpha(pixel));
      }
      pg.updatePixels();
    }
    
    tmpPg = createGraphics(pg.width, pg.height);
    tmpPg.beginDraw();
    tmpPg.background(0, 0);
    tmpPg.endDraw();
    
    items = new ArrayList();
  }
  
  boolean isOverlapped(AbstractItem item) {
    
    tmpPg.beginDraw();
    tmpPg.background(0, 0);
    item.draw(tmpPg, 0);
    tmpPg.endDraw();
    
    boolean overlapped = false;
    
    pg.loadPixels();
    tmpPg.loadPixels();
    for (int k = 0; k < pg.pixels.length; k++) {
      float a1 = alpha(pg.pixels[k]);
      float a2 = alpha(tmpPg.pixels[k]);
      
      if (a2 > 0 && a1 > 0) {
        overlapped = true;
        break;
      }
    }
    
    return overlapped;
  }
  
  void addItem(AbstractItem item) {
    tmpPg.beginDraw();
    tmpPg.background(0, 0);
    item.draw(tmpPg, 0);
    for (int k = 0; k < margin; k++) {
      tmpPg.filter(DILATE);
    }
    tmpPg.endDraw();
    
    pg.beginDraw();
    pg.image(tmpPg, 0, 0);
    pg.endDraw();
    
    items.add(item);
  }
  
  void draw(PGraphics g, int t) {
    for (AbstractItem item : items) {
      item.draw(g, t);
    }
  }
}

PackingItems.pde

abstract class AbstractItem {
  abstract void draw(PGraphics pg, int t);
}

class ImageItem extends AbstractItem {
  
  PVector pos;
  float rot;
  float sc;
  
  PImage img;
  
  ImageItem(PImage img, PVector pos) {
    this(img, pos, 0.0, 1.0);
  }
  
  ImageItem(PImage img, PVector pos, float rot, float sc) {
    this.img = img;
    this.pos = pos;
    this.rot = rot;
    this.sc = sc;
  }
  
  void draw(PGraphics pg, int t) {
    pg.imageMode(CENTER);
    pg.pushMatrix();
    pg.translate(pos.x, pos.y);
    pg.rotate(rot);
    pg.scale(sc);
    pg.image(img, pos.x, pos.y);
    pg.popMatrix();
  }
}

class ShapeItem extends AbstractItem {
  
  PVector pos;
  float rot;
  float sc;
  color c;
  
  PShape sh;
  
  ShapeItem(PShape sh, PVector pos) {
    this(sh, pos, 0.0, 1.0);
  }
  
  ShapeItem(PShape sh, PVector pos, float rot, float sc) {
    this(sh, pos, rot, sc, color(75));
  }
  
  ShapeItem(PShape sh, PVector pos, float rot, float sc, color c) {
    this.sh = sh;
    this.pos = pos;
    this.rot = rot;
    this.sc = sc;
    this.c = c;
  }
  
  void draw(PGraphics pg, int t) {
    pg.shapeMode(CENTER);
    pg.pushMatrix();
    pg.translate(pos.x, pos.y);
    pg.rotate(rot);
    pg.scale(sc);
    pg.fill(c);
    pg.noStroke();
    pg.shape(sh);
    pg.popMatrix();
  }
}

sketch_210607a.pde


NonCircularPacking ncp;
PShape[] shapes;

void setup() {
  size(800, 800);
  
  String[] fileList = new String[] {
    "cat.svg",
    "horse.svg",
    "monkey.svg",
    "ツチノコアイコン1.svg",
    "ネズミアイコン.svg",
    "ネッシーアイコン2.svg",
    "フラミンゴアイコン2.svg",
    "ラクダアイコン2.svg",
    "恐竜アイコン2.svg"
  };
  
  shapes = new PShape[fileList.length];
  for (int k = 0; k < fileList.length; k++) {
    shapes[k] = loadShape(fileList[k]);
    shapes[k].disableStyle();
  }
  
  ncp = new NonCircularPacking(null, 16);
  generateItems(ncp);
  
  println("done");
}

void draw() {
  background(220);
  
  ncp.draw(g, frameCount);
}

void generateItems(NonCircularPacking ncp) {
  for (int k = 0; k < 100; k++) {
    PVector pos = new PVector(random(0, width), random(0, height));
    float rot = random(0, TWO_PI);
    color c = color(random(0, 128));
    int idx = (int)random(0, shapes.length);
    
    for (int l = 0; l < 10; l++) {
      float sc = 0.5 * (1.0 - (float)l / 10);
      ShapeItem item = new ShapeItem(shapes[idx], pos, rot, sc, c);
      if (!ncp.isOverlapped(item)) {
        ncp.addItem(item);
        break;
      }
    }
  }
}

void mousePressed() {
  if (mouseButton == LEFT) {
    
    boolean isput = false;
    
    PVector pos = new PVector(mouseX, mouseY);
    float rot = random(0, TWO_PI);
    color c = color(random(0, 128));
    int idx = (int)random(0, shapes.length);
    
    for (int l = 0; l < 10; l++) {
      float sc = 0.5 * (1.0 - (float)l / 10);
      ShapeItem item = new ShapeItem(shapes[idx], pos, rot, sc, c);
      if (!ncp.isOverlapped(item)) {
        ncp.addItem(item);
        isput = true;
        break;
      }
    }
    
    if (isput) {
      println("ok");
    }
    
  } else if (mouseButton == RIGHT) {
    save("example.png");
  }
}