ZELLNERPLUS/HOUCK


CODING URBAN CHINA

中国城市编码

Generating a National City

生成一个国家的城市

We imagine a potentially limitless, sprawling yet dense URBAN China composed from an archive of almost endless architectural varieties and unlimited typological re-compositions. We imagine in China a nationalized urbanism- general in ambition yet specific in execution.

We aimed to create a model for a cohesive national urban fabric in which public and private spaces could be freely swapped or interchanged without disrupting either the individual house or the larger block. In particular we sought to inject each city block with private as well as public functions, creating an ambiguous quality to block interiors and edges.

We hoped to generate these conditions without immediately over determining intention or resorting to simple (e.g. analog) methods of iteration and reiteration to produce an artificial rendition of variation. Ultimately, we sought to invent a strategy for developing a randomized, generative pattern language that could automatically edited according to a predetermined set of constraints and rule sets.


我们想象一个潜在无限的,但庞大人口密集的城市组成,从中国的存档几乎是无限的建筑品种和无限的类型学重新组成。我们可以想象在中国城市化一收归国有,一般在特定的野心尚未执行。

我们的目的是创造一个模式,有凝聚力的国家城市结构的公共和私人空间可自由更换或互换而不破坏或者个人的房屋或较大的区块。特别是,我们力求每个城市注入区块与私人以及公共职能,创造了一个模棱两可的质量块内部和边缘。

我们希望产生这些条件而不立即确定了意向或诉诸简单的(例如,模拟)方法迭代和重复生产的人工移交逃犯的变化。归根结底,我们试图发明一种开发战略的随机生成模式语言,可以自动编辑根据预先设定的限制和规则集。

A Constraint Satisfaction Problem

To shape this experiment we developed a self generating routine or code (see programming code at left) that treats the competition brief as a constraint satisfaction problem.

In computing constraint satisfaction problems (CSPs) are:

“…mathematical problems defined as a set of objects whose state must satisfy a number of constraints or limitations.

CSPs represent the entities in a problem as a homogeneous collection of finite constraints over variables, which is solved by constraint satisfaction methods…

CSPs often exhibit high complexity, requiring a combination of heuristics and combinatorial search methods to be solved in a reasonable time.”1

Applying a constraint satisfaction problem to the challenge of generating multiple courtyard houses within an endless courtyard garden city challenges privileged architectural notions such as composition, typological development and urban array. Understood in relationship to constraint satisfaction problem these traditional tools become problems of recursive algorithmic exploration within a limited set of variables, a fixed domain of values, and a well stated set of constraints.

1. Constraint satisfaction problem in the Wikipedia Free Encyclopedia, http://en.wikipedia.org/wiki/Constraint_satisfaction_problem (accessed November 18, 2008).

Process:

From a highly limited rule set (see below and right), we algorithmically auto-generated 3102 hypothetical city blocks across a 66 x 47 city grid or a 6,235,866 square meter quadrant of a hypothetically limitless urban fabric.

The algorithmic rule set we developed for this generative process automated the restrictions set by the competition brief and established another layer of constraints intended to promulgate variety and eliminate obvious defects and unsuccessful mutations within each city block.

Thus, 3102 functional city blocks were culled from an initial batch of 6281 generated test blocks. City blocks exhibiting defects or mutations such as inadequate circulation, distortions to the shape of the unitary houses or gardens or missing components were automatically eliminated according to the preference instructions written into the self generating routine or code.

CODING URBAN CHINA : PLAN TEST

http://supersatellites.burb.tv/_f/o/00/02/29_CODING_URBANCHINA.gif

Team: ZELLNERPLUS / HOUCK

Kurt Franz
John Houck
Tomohiko Sakai
Peter Zellner

CODE

import processing.core.*;
import processing.xml.*;

import processing.opengl.*;
import processing.pdf.*;
import damkjer.ocd.*;
import javax.swing.*;
import javax.media.opengl.*;

import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
import java.util.regex.*;

public class nine_sq_comp_02 extends PApplet {

final int SCRN_WIDTH = 700;
final int SCRN_HEIGHT = 700;

boolean record;
boolean isAuto;
PGraphicsOpenGL pgl;
GL gl;
String saveToFolder = null;

Grid grid;
CSPSolver currSolver;

/**
* setup
*/
public void setup() {
size(SCRN_WIDTH, SCRN_HEIGHT);

grid = new Grid(150, 150);
currSolver = new Solver01();

ellipseMode(CENTER);
frameRate(30);
}

/**
*
*/
public void draw() {
background(255);
if (record) {
// Note that #### will be replaced with the frame number. Fancy!
beginRecord(PDF, saveToFolder + "/frame-####.pdf");
}

if (isAuto) {
currSolver.clear();
currSolver.solve();
if (currSolver.isSolved) {
if (saveToFolder == null) {
saveToFolder = selectFolder(); // Opens file chooser
if (saveToFolder == null) {
// If a folder was not selected
println("No folder was selected...");
}
else {
// If a folder was selected, print path to folder
println(saveToFolder);
}
}
beginRecord(PDF, saveToFolder + "/frame-####.pdf");
grid.draw();
currSolver.draw();
endRecord();
}

//delay(1000);

}
else {
grid.draw();
currSolver.draw();
}

if (record) {
endRecord();
record = false;
println("pdf saved...");
}

}

/**
* key pressed
*/
public void keyPressed() {
if (key == ' ') {
currSolver.clear();
currSolver.solve();
if (currSolver.isSolved) {
println("complete solution.....");
}
}
if (key == 'c') {
currSolver.clear();
}
if (key == 'p') {
if (saveToFolder == null) {
saveToFolder = selectFolder(); // Opens file chooser
if (saveToFolder == null) {
// If a folder was not selected
println("No folder was selected...");
}
else {
// If a folder was selected, print path to folder
println(saveToFolder);
}
}
record = true;
println("saving pdf...");
}
if (key == 'a') {
isAuto = !isAuto;
println("is auto: " + isAuto);
}

}

//
// constraint satisfaction solver
//
abstract class CSPSolver {
int TRY_THIS_MANY = 2000;
ProgressMonitor progressMonitor;
boolean isSolved;

//
//
public CSPSolver() {
} // end CSPSolver ()

//
//
//
public void solve() {}

//
//
//
public void draw() {}

//
//
//
public void clear() {}

//
//
//
public void start() {
println("started...");
}

//
//
//
public void finish() {
println("finished...");
println();
}
}

/**
* represents an individual cell in the grid
*/
class Cell {

int x, y, w, h;
int fillC = color(255, 0, 0, 100);
int strokeC = color(255, 0, 0, 100);
boolean isOn;

//
//
public Cell(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}

//
//
public Cell(Cell c) {
this.x = c.x;
this.y = c.y;
this.w = c.w;
this.h = c.h;
}

//
//
//
public void draw() {
if (isOn) {
fill(fillC);
stroke(strokeC);
}
rect(x, y, w, h);
}

//
//
//
public String toString() {
return "(x, y, w, h): (" + x + ", " + y + ", " + w + ", " + h + ")";
}
}

/**
*
*/
class Grid {
float NUM_X = 4;
float NUM_Y = 4;
float currX, currY;
float stepX = 100;
float stepY = 100;
float offsetX = 0;
float offsetY = 0;
int gridStrokeC = color(210);
int gridFillC = color(240);

ArrayList cells = new ArrayList();

//
//
//
public Grid(float offx, float offy) {
this.offsetX = offx;
this.offsetY = offy;

for (int y=(int) offsetY; y<NUM_Y*stepY+offsetY; y+=stepY) {
for (int x=(int) offsetX; x<NUM_X*stepX+offsetX; x+=stepX) {
cells.add(new Cell((int) x, (int) y, (int) stepX, (int) stepY));
}
}

}

//
//
//
public void draw() {
for (int i=0; i<cells.size(); i++) {
Cell c = (Cell) cells.get(i);
fill(gridFillC);
stroke(gridStrokeC);
c.draw();
}

}

//
// starting from upper left corner, 1, 1
//
public void fillCell(int x, int y) {
Cell c = (Cell) cells.get((y-1)*3+x-1);
c.isOn = true;
}

//
// return cell at x, y cell coords
//
public Cell getCell(int x, int y) {
return (Cell) cells.get((y-1)*4+x-1);
}

//
// returns x, y number, starting from 1 of specified coordinates
//
public int [] getCellNum(int x, int y) {
int [] xy = new int[2];
for (int i=0; i<cells.size(); i++) {
Cell c = (Cell) cells.get(i);
if (c.x == x && c.y == y) {
xy[0] = i%4 + 1;
xy[1] = i/4 + 1;
}
}

return xy;
}

//
// returns rand adjacent cell in, no diagonal cells though
//
public Cell getAdjacentCell(int x, int y) {
if (x > 4 || x < 1 || y > 4 || y < 1) {
return null;
}

Cell c = null;
Cell cCurr = grid.getCell(x, y);

while (c == null) {
int i = (int) random(0, 4);
if (i == 0 && y != 1) { // above
c = new Cell(cCurr.x, cCurr.y - cCurr.h, cCurr.w, cCurr.h);
}
else if (i == 1 && x != 1) { // to the left
c = new Cell(cCurr.x - cCurr.w, cCurr.y, cCurr.w, cCurr.h);
}
else if (i == 2 && y != 4) { // below
c = new Cell(cCurr.x, cCurr.y + cCurr.h, cCurr.w, cCurr.h);
}
else if (i == 3 && x != 4) { // to the right
c = new Cell(cCurr.x + cCurr.w, cCurr.y, cCurr.w, cCurr.h);
}
}

return c;
}

}

/**
*
*/
class House {

boolean isDrawShadows = true;
int shadowC = color(80, 250);

float houseX, houseY, houseW, houseH;
float gargX, gargY, gargW, gargH;
float gardX, gardY, gardW, gardH;
int numCars;
int numLevels;
int cellX, cellY;

int houseC = color(179, 185, 206);
int houseCstrk = color(159, 165, 186);
int gargC = color(144, 145, 159);
int gargCstrk = color(124, 125, 139);
int gardC = color(219, 232, 213);
int gardCstrk = color(173, 191, 175);

ArrayList cells = new ArrayList();

//
// constructor, takes starting x and y cell position, 1 based, not 0 based
public House(int cellX, int cellY) {
this.cellX = cellX;
this.cellY = cellY;

// simple version, set house coords to cell specified
Cell c = grid.getCell(cellX, cellY);
houseX = c.x;
houseY = c.y;
houseW = c.w;
houseH = c.h;
cells.add(new Cell(c));

setRandLotCover();

//this.numLevels = (int) random(1, 4);
//this.numLevels = 1;

Cell gargCell = grid.getAdjacentCell(cellX, cellY);
gargX = gargCell.x;
gargY = gargCell.y;
gargW = gargCell.w;
gargH = gargCell.h;
setGarageSize();
cells.add(new Cell(gargCell));

int [] xyHouse = grid.getCellNum(c.x, c.y);
int [] xyGarg = grid.getCellNum(gargCell.x, gargCell.y);

Cell c3 = grid.getAdjacentCell(xyHouse[0], xyHouse[1]);
while(c3.x == gargX && c3.y == gargY) {
c3 = grid.getAdjacentCell(xyHouse[0], xyHouse[1]);
}
cells.add(c3);

Cell c4 = grid.getAdjacentCell(xyGarg[0], xyGarg[1]);
while (c4.x == houseX && c4.y == houseY) {
c4 = grid.getAdjacentCell(xyGarg[0], xyGarg[1]);
}
cells.add(c4);
}

//
//
//
public boolean isCollision(House h) {
//
// based on number of cells occupied
for (int i=0; i<cells.size(); i++) {
Cell c = (Cell) cells.get(i);
for (int j=0; j<h.cells.size(); j++) {
Cell c2 = (Cell) h.cells.get(j);
if (c.x == c2.x && c.y == c2.y) {
return true;
}
}
}

return false;
}

//
//
public void drawGarden() {
// render garden
for (int i=0; i<cells.size(); i++) {
Cell c = (Cell) cells.get(i);
fill(gardC);
stroke(gardCstrk);
rect(c.x, c.y, c.w, c.h);
}
}

//
//
public void drawHouses() {
noStroke();
fill(shadowC);

float shadowL = 1.3f;
float houseShadow = .3f * numLevels + 1.0f;

beginShape();
vertex(houseX + houseW, houseY);
vertex(houseX + houseW*houseShadow, houseY + houseH*(houseShadow-1.0f));
vertex(houseX + houseW*houseShadow, houseY + houseH*houseShadow);
vertex(houseX + houseW*(houseShadow-1.0f), houseY + houseH*houseShadow);
vertex(houseX, houseY + houseH);
vertex(houseX + houseW, houseY + houseH);
endShape();

fill(gargC);
stroke(gargCstrk);
rect(gargX, gargY, gargW, gargH);

fill(houseC);
stroke(houseCstrk);
rect(houseX, houseY, houseW, houseH);
}

//
//
public void drawGarg() {
noStroke();
fill(shadowC);

float shadowL = 1.3f;
float houseShadow = .3f * numLevels + 1.0f;

beginShape();
vertex(gargX + gargW, gargY);
vertex(gargX + gargW*shadowL, gargY + gargH*(shadowL-1.0f));
vertex(gargX + gargW*shadowL, gargY + gargH*shadowL);
vertex(gargX + gargW*(shadowL-1.0f), gargY + gargH*shadowL);
vertex(gargX, gargY + gargH);
vertex(gargX + gargW, gargY + gargH);
endShape();
}

//
//
//
public void setGarageSize() {
int i = (int) random(1,5);
switch(i) {
case 1: // just W
gargW = (float) gargW * 1/3;
break;
case 2:
gargW = (float) gargW * 2/3;
break;
case 3: // just W
gargH = (float) gargH * 1/3;
break;
case 4:
gargH = (float) gargH * 2/3;
break;
}
}

//
//
//
public void setRandLotCover() {
// divide house w or h
int i = (int) random(1, 9);
switch(i) {
case 1: // just W
numLevels = 1;
break;
case 2:
houseW = (float) houseW * 1/2;
numLevels = 3;
break;
case 3:
houseW = (float) houseW * 2/3;
numLevels = 2;
break;
case 4:
houseW = (float) houseW * 3/4;
numLevels = 2;
case 5: // just H
houseH = (float) houseH * 1/2;
numLevels = 3;
break;
case 6:
houseH = (float) houseH * 2/3;
numLevels = 2;
break;
case 7:
houseH = (float) houseH * 3/4;
numLevels = 2;
case 8: // both W and H
houseH = (float) houseH * 3/4;
houseW = (float) houseW * 3/4;
numLevels = 2;
}
}

//
//
//
public void shiftOnLot() {
int i = (int) random(1, 5);
switch(i) {
case 1:
if (houseW < (int) grid.stepX) {
houseX += grid.stepX - houseW;
}
break;
case 2:
if (houseH < (int) grid.stepY) {
houseY += grid.stepY - houseH;
}
break;
case 3:
if (gargW < (int) grid.stepX) {
gargX += grid.stepX - gargW;
}
break;
case 4:
if (gargH < (int) grid.stepY) {
gargY += grid.stepY - gargH;
}
break;
}
}

//
//
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("House contains cells: \n" );
for (int i=0; i<cells.size(); i++) {
Cell c = (Cell) cells.get(i);
buf.append("\t " + c.toString() + "\n");
}

return buf.toString();
}

}

/**
*
*/
class Solver01 extends CSPSolver {
House h1, h2, h3, h4;

public void solve() {
super.start();
isSolved = false;

int i = 1;
for (i=1; i<TRY_THIS_MANY; i++) {
//for (i=1; i<3; i++) {

int cellX = (int) random(1, 5);
int cellY = (int) random(1, 5);

if (h1 == null) {
h1 = new House(cellX, cellY);
h1.gardC = color(188, 229, 206);
}
else if (h2 == null) {
House test = new House(cellX, cellY);
if (!h1.isCollision(test)) {
//h2 = new House(cellX, cellY);
h2 = test;
h2.gardC = color(218, 237, 201);
}
}
else if (h3 == null) {
House test = new House(cellX, cellY);
if (!h1.isCollision(test) && !h2.isCollision(test)) {
h3 = test;
h3.gardC = color(239, 245, 200);
}
}
else if (h4 == null) {
House test = new House(cellX, cellY);
if (!h1.isCollision(test) && !h2.isCollision(test) && !h3.isCollision(test)) {
h4 = test;
h4.gardC = color(154, 224, 206);
}
}
else {
println("found solution...");
h1.shiftOnLot();
h2.shiftOnLot();
h3.shiftOnLot();
h4.shiftOnLot();
isSolved = true;
break;
}
}

super.finish();
}

//
//
//
public void clear() {
h1 = null;
h2 = null;
h3 = null;
h4 = null;
}

public void draw() {
if (h1 != null && h1.isDrawShadows) {
if (h1 != null) {
h1.drawGarden();
}
if (h2 != null) {
h2.drawGarden();
}
if (h3 != null) {
h3.drawGarden();
}
if (h4 != null) {
h4.drawGarden();
}
}

if (h1 != null) {
h1.drawGarg();
}
if (h2 != null) {
h2.drawGarg();
}
if (h3 != null) {
h3.drawGarg();
}
if (h4 != null) {
h4.drawGarg();
}

if (h1 != null) {
h1.drawHouses();
}
if (h2 != null) {
h2.drawHouses();
}
if (h3 != null) {
h3.drawHouses();
}
if (h4 != null) {
h4.drawHouses();
}

if (h1 != null) {
h1.draw();
}
if (h2 != null) {
h2.draw();
}
if (h3 != null) {
h3.draw();
}
if (h4 != null) {
h4.draw();
}
}
}

static public void main(String args[]) {
PApplet.main(new String[] { "nine_sq_comp_02" });
}
}

Owned by Peter Zellner / Added by Peter Zellner / 1.2 years ago / 777 hits / 54 minutes view time

New Entries


Contribute

Login to post an entry to this node.