> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.dENaDUSP$Yg/rev.3370
 * 
 * authors: 
 *   
 *   frederic.vernier

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



float ANG = PI/3;
int R     = 16;
int RAD   ;

int abu[]   = new int[6];
int def[]   = new int[6];
int pri[]   = new int[6];
int par[]   = new int[6];
int sab[]   = new int[6];
String title[] = {"E", "SE", "SW", "W", "NW", "NE"};
int mind  = 0;
int maxd  = 1;
int dec   = 1;
float bestAbundant = 0;
boolean propSize = false;
PFont font8, font16;

// determines the number of factors
int numFactors(int number) { 
  if (number==1) 
    return 1;
  int factorCount = 0;
  float sqrtNum = sqrt(number);
  for (int i=1; i<=sqrtNum; i++) 
    if (number%i == 0) 
      factorCount++;
  return factorCount;
}

//determines the sum of factors (perfect numbers have a sum equal to itself)
int sumFactors(int number) { 
  if (number==1) 
    return 1;
  int factorSum = 0;
  float sqrtNum = sqrt(number);
  for (int i=2; i< number; i++) 
    if (number%i == 0) 
      factorSum += i;
  return factorSum+1;
}

void setup() {
  bestAbundant = 0;
  //for (int i=0; i<20; i++)
  //  println(""+i+" => "+ sumFactors(i*496)/(i*496));    
  RAD   = 240/R;
  mind  = 0;
  maxd  = 1;
  dec = 5000/R;
  size(900, 800); 

  // initialize array for densities  
  for (int i=0; i<6; i++) {
    def[i]=0;
    abu[i]=0;
    pri[i]=0;
    par[i]=0;
    sab[i]=0;
  }

  frameRate(5);
  strokeWeight(2);
  background(255);
  loop();
  colorMode(HSB);  
  font8 = createFont("Arial", 8);
  font16 = createFont("Arial", 16);
  textAlign(CENTER, CENTER);
} 

void drawHexa(int x, int y, int R, int v, float a, int j, int ii, int k, int maxi) {
    pushMatrix();
    int sf = sumFactors(v);
    boolean sa = false;
    if (v!=0 && sf/v> bestAbundant){
      bestAbundant = sf/v;
      sa=true;
    }
    
    if (k==maxi-1) {
        noStroke();
      fill(216, 255);
      beginShape();
      for (int i=0; i<=6; i++) {
        float x0 = x+R*cos(i*ANG);
        float y0 = y+R*sin(i*ANG);
        vertex(x0, y0);
      } 
      endShape();
    } 
    
    if (v==0){
    } else if (sf==1)     
       pri[ii]++;
    else if (sf<v) 
       def[ii]++;
    else if (sa)
      sab[ii]++;
    else if (sf>v) 
      abu[ii]++;
    else
      par[ii]++;
      
    stroke(0);
    if (sf==1) {
      if (propSize) scale(0.98*sf/v); 
      fill  (0, 255, 255); 
    } else if (sf<v) {
      if (propSize) scale(0.98*sf/v); 
      fill  (0, 128, 255); 
    }  else if (sa) {
      if (propSize) scale(0.98*v/sf);
      fill  (150, 255, 255); 
    }  else if (sf>v) {
      if (propSize) scale(0.98*v/sf);
      fill  (128, 128, 255); 
    } else {
      scale(0.98); 
      fill  (192, 128, 255); 
    }
    if (R<3) noStroke();
    strokeWeight(1);
    beginShape();
    for (int i=0; i<=6; i++) {
      float x0 = x+R*cos(i*ANG);
      float y0 = y+R*sin(i*ANG);
      vertex(x0, y0);
    }

   endShape();
   stroke(1);
   popMatrix(); 
   rotate(-a);
   fill(0,0,0);
   if (R>6)
   text(v, -1, 0);
   rotate(a);
}

void draw()  {

  int c = RAD+1;
  int v = 0;
  float a = -1*PI/3;
  pushMatrix();
  translate(width/2, height/2);
  textFont(font8);
  if (0>=mind && 0<=maxd) {
      drawHexa(0, 0, R, v, 0, 0, 0, 0, 0);
      fill(0);
      textFont(font16);
      text("Press + or - to zoom in or out",width/2-120, -height/2+20);
      text("Press p to relate size and distance to perfection",width/2-180, -height/2+40);
  }
  textFont(font8);
  translate(R*1.5, R*(sqrt(3)/2));
  //rotate(PI/3);
  
  for (int j=1; j<RAD; j++) {
    for (int i=0; i<6; i++)  {
      int maxl = j;
      //if (i==5) maxl++;
      //if (i==0) maxl--;
      if (i!=0)rotate(PI/3);
      a = (a+PI/3)%TWO_PI;
      
      for (int k=0; k<maxl; k++) {
        v++;
        stroke(196);
        if(k!=0||i!=0) translate(0, R*sqrt(3));
        if (v>mind && v<=maxd) {
          dec = max(dec, j/2);
          drawHexa(0, 0, R, v, a, j, i, k, maxl);
          stroke(255, 128);
          if(k!=0||i!=0) line(0,0, 0, -R*sqrt(3));
          else line(0,0, -R*1.5, -R*(sqrt(3)/2));
          rotate(-a);
          fill(0,0,0);
          if (R>6)
          text(v, -1, 0);
          rotate(a);
        }
        
      }
    }
    translate(0, R*sqrt(3));
    rotate(PI/3);
  }
  
  popMatrix();
  float prop = R*R/60;
  strokeWeight(1);
  stroke(0);
  for (int i=0; i<6; i++) {
     
    fill  (0, 255, 255); 
    rect(i*30, height-pri[i]*prop, 30, pri[i]*prop);
    fill  (0, 128, 255);  
    rect(i*30, height-(pri[i]+def[i])*prop, 30, def[i]*prop);
    fill  (192, 128, 255); 
    rect(i*30, height-(pri[i]+def[i]+par[i])*prop, 30, par[i]*prop);
    fill  (128, 128, 255);  
    rect(i*30, height-(pri[i]+def[i]+par[i]+abu[i])*prop, 30, abu[i]*prop);
    fill  (150, 255, 255);  
    rect(i*30, height-(pri[i]+def[i]+par[i]+abu[i]+sab[i])*prop, 30, sab[i]*prop);

    fill(0, 255); 
    textFont(font8);
    if (abu[i]+def[i]+pri[i]+par[i]!=0){
      text( (100*abu[i])/(abu[i]+def[i]+pri[i]+par[i]), i*30+15, height-(pri[i]+def[i]+par[i])*prop-abu[i]*prop/2);
      text( (100*def[i])/(abu[i]+def[i]+pri[i]+par[i]), i*30+15, height-pri[i]*prop-def[i]*prop/2);
      text( (100*pri[i])/(abu[i]+def[i]+pri[i]+par[i]), i*30+15, height-pri[i]*prop/2);
      text(title[i], i*30+15, height-def[i]*prop-abu[i]*prop-pri[i]*prop-par[i]*prop-sab[i]*prop+8);
    }
  }
  mind = maxd;
  maxd += dec;
}

void keyTyped(){
  if (key==43 && R<65){
   R++;
   setup();
  } else if (key==45 && R>1){
   R--;
   setup();
  } else if (key==112){
   propSize = ! propSize;
   setup();
  }else {
    println("key "+key+" not recognized");  
  }
}