Processing.js

Neighborhood

By Ira Greenberg Draw a neighborhood of houses using Door, Window, Roof and House classes. Good example of class composition, with component Door, Window, Roof class references encapsulated within House class. This arrangement allows House class to handle placement and sizing of its components, while still allowing user customization of the individual components.

Original Processing.org Example: Neighborhood

// All Examples Written by Casey Reas and Ben Fry
// unless otherwise stated.
void setup(){
  size(200, 200);
  background(190);
  smooth();
  // Ground plane
  int groundHeight = 10;
  fill(0);
  rect(0, height-groundHeight, width, groundHeight);
  fill(255);
  
  // Center the houses
  translate(12, 0);

  // Houses
  Door door1 = new Door(20, 40);
  Window window1 = new Window(50, 62, false, Window.DOUBLE);
  Roof roof1 = new Roof(Roof.DOME);
  House house1 = new House(75, 75, door1, window1, roof1, House.MIDDLE_DOOR);
  house1.drawHouse(0, height-groundHeight-house1.h, true);

  Door door2 = new Door(20, 40);
  Window window2 = new Window(50, 62, true, Window.QUAD);
  Roof roof2 = new Roof(Roof.GAMBREL);
  House house2 = new House(100, 60, door2, window2, roof2, House.LEFT_DOOR);
  house2.drawHouse(house1.x + house1.w, height-groundHeight-house2.h, true);
}

class Door{
  //door properties
  int x;
  int y;
  int w;
  int h;

  // for knob
  int knobLoc = 1;
  //constants
  final static int RT = 0;
  final static int LFT = 1;

  // constructor
  Door(int w, int h){
    this.w = w;
    this.h = h;
  }

  // draw the door
  void drawDoor(int x, int y) {
    rect(x, y, w, h);
    int knobsize = w/10;
    if (knobLoc == 0){
      //right side
      ellipse(x+w-knobsize, y+h/2, knobsize, knobsize);
    }
    else {
      //left side
      ellipse(x+knobsize, y+h/2, knobsize, knobsize);
    }
  }

  // set knob position
  void setKnob(int knobLoc){
    this. knobLoc = knobLoc;
  }
}

class Window{
  //window properties
  int x;
  int y;
  int w;
  int h;

  // customized features
  boolean hasSash = false;

  // single, double, quad pane
  int style = 0;
  //constants
  final static int SINGLE = 0;
  final static int DOUBLE = 1;
  final static int QUAD = 2;

  // constructor 1
  Window(int w, int h){
    this.w = w;
    this.h = h;
  }
  // constructor 2
  Window(int w, int h, int style){
    this.w = w;
    this.h = h;
    this.style = style;
  }
  // constructor 3
  Window(int w, int h, boolean hasSash, int style){
    this.w = w;
    this.h = h;
    this.hasSash = hasSash;
    this.style = style;
  }

  // draw the window
  void drawWindow(int x, int y) {
    //local variables
    int margin = 0;
    int winHt = 0;
    int winWdth = 0;

    if (hasSash){
      margin = w/15;
    }

    switch(style){
    case 0:
      //outer window (sash)
      rect(x, y, w, h);
      //inner window
      rect(x+margin, y+margin, w-margin*2, h-margin*2);
      break;
    case 1:
      winHt = (h-margin*3)/2;
      //outer window (sash)
      rect(x, y, w, h);
      //inner window (top)
      rect(x+margin, y+margin, w-margin*2, winHt);
      //inner windows (bottom)
      rect(x+margin, y+winHt+margin*2, w-margin*2, winHt);
      break;
    case 2:
      winWdth = (w-margin*3)/2;
      winHt = (h-margin*3)/2;
      //outer window (sash)
      rect(x, y, w, h);
      //inner window (top-left)
      rect(x+margin, y+margin, winWdth, winHt);
      //inner window (top-right)
      rect(x+winWdth+margin*2,  y+margin, winWdth, winHt);
      //inner windows (bottom-left)
      rect(x+margin, y+winHt+margin*2, winWdth, winHt);
      //inner windows (bottom-right)
      rect(x+winWdth+margin*2,  y+winHt+margin*2, winWdth, winHt);
      break;
    }
  }

  // set window style (number of panes)
  void setStyle(int style){
    this.style = style;
  }
}

class Roof{
  //roof properties
  int x;
  int y;
  int w;
  int h;

  // roof style
  int style = 0;
  //constants  
  final static int CATHEDRAL = 0;
  final static int GAMBREL = 1;
  final static int DOME = 2;

  // default constructor
  Roof(){
  }
   
   // constructor 2
   Roof(int style){
    this.style = style;
  }

  // draw the roof
  void drawRoof(int x, int y, int w, int h) {
    switch(style){
    case 0:
      beginShape();
      vertex(x, y);
      vertex(x+w/2, y-h/3);
      vertex(x+w, y);
      endShape(CLOSE);
      break;
    case 1:
     beginShape();
      vertex(x, y);
      vertex(x+w/7, y-h/4);
      vertex(x+w/2, y-h/2);
      vertex(x+(w-w/7), y-h/4);
      vertex(x+w, y);
      endShape(CLOSE);
      break;
    case 2:
      ellipseMode(CORNER);
      arc(x, y-h/2, w, h, PI, TWO_PI);
      line(x, y, x+w, y);
      break;
    }

  }

  // set roof style
  void setStyle(int style){
    this.style = style;
  }
}

class House{
  //house properties
  int x;
  int y;
  int w;
  int h;

  //component reference variables
  Door door;
  Window window;
  Roof roof;

  //optional autosize variable
  boolean AutoSizeComponents = false;

  //door placement
  int doorLoc = 0;
  //constants
  final static int MIDDLE_DOOR = 0;
  final static int LEFT_DOOR = 1;
  final static int RIGHT_DOOR = 2;

  //constructor
  House(int w, int h, Door door, Window window, Roof roof, int doorLoc) {
    this.w = w;
    this.h = h;
    this.door = door;
    this.window = window;
    this.roof = roof;
    this.doorLoc = doorLoc;
  }

  void drawHouse(int x, int y, boolean AutoSizeComponents) {
    this.x = x;
    this.y =y;
    this.AutoSizeComponents = AutoSizeComponents;

    //automatically sizes doors and windows
    if(AutoSizeComponents){
      //autosize door
      door.h = h/4;
      door.w = door.h/2;

      //autosize windows
      window.h = h/3;
      window.w = window.h/2;

    }
    // draw bldg block
    rect(x, y, w, h);

    // draw door
    switch(doorLoc){
    case 0:
      door.drawDoor(x+w/2-door.w/2, y+h-door.h);
      break;
    case 1:
      door.drawDoor(x+w/8, y+h-door.h);
      break;
    case 2:
      door.drawDoor(x+w-w/8-door.w,  y+h-door.h);
      break;
    }

    // draw windows
    int windowMargin = (w-window.w*2)/3;
    window.drawWindow(x+windowMargin, y+h/6);
    window.drawWindow(x+windowMargin*2+window.w, y+h/6);

    // draw roof
    roof.drawRoof(x, y, w, h);
  }

  // catch drawHouse method without boolean argument
  void drawHouse(int x, int y){
    // recall with required 3rd argument
    drawHouse(x, y, false);
  }
}