hizlik-book
Year One is a book of cityscapes. Each city represents the daily volume of text messages that my girlfriend and I sent each other during our first year of dating. There are 366 total cities (I included both our first day, and first anniversary), and each building represents an hour in the day (24 total buildings, at most), in the manner of a bar chart.
Each city is rendered with a watercolor/painted effect. The book was mainly generated using Processing, but other programming languages were used as well, which served various purposes in the creation of the imagery within the pages.
As described in the process video (below), I wanted to create a project based on the texts that my girlfriend sent to each other during our first year of dating, which was long-distance for most of the time. The other thing I wanted to do was create generative cityscapes (I have a fascination with cities). After being unable to pick between the two concepts, I put them together. Essentially, the total significance of all the texts per hour (so not the amount of texts, but the total content length) dictates the height of a building, while the number of images sent are represented by the various attachments to the buildings (antennas, water towers, balconies, “blocks/vents” on the roof, etc. I used multiple languages to create this project, detailed below. One of the significant issues for this was creating the painterly effect, which in the end I think turned out exactly as I had hoped it would. I took inspiration from artist Michael Tompsett for the artistic style of my generated imagery.
The most time-consuming process was the creation of the variety of buildings and building parameters. Each building consists of differently modified versions of vertex-based shapes. I believe I succeeded in everything I intended to do, which surprises me because normally I either run out of time or am unable to achieve my vision. This was one of the more multi-step and complicated projects I’ve undertaken, so I was surprised I was able to not only achieve the exact image I had in my head, but also within record time (I started Wednesday night, finished by Saturday afternoon). I love how the buildings look, am pleased with their variety (although it could always use more) and love the way the watercolor effect looks. If I had to change anything, I would change the % possibility for some types of more unique buildings (to a lower chance), and also add more brush types and more “floors” the buildings rest on, for more variety. (You can see some repetition if you pay attention).
The numbers at the bottom of each page represent the total number of text messages, and total volume of characters that we exchanged. Golan expressed surprise that we sent each other (in some cases) hundreds of text messages per day. It’s true.
Here’s a video of Golan flipping through the book:
FILES
Short excerpt of the book (8MB PDF): hizlik_book_short.pdf
You can download this PDF and all the source code from my GitHub repo.
CODE
Shell/Bash Script: Export text messages from Apple Messages SQLite database
if [ $# -lt 1 ]; then
echo "Enter a iMessage account (email of phone number i.e +33616.....) "
fi
login=$1
sqlite3 ~/Library/Messages/chat.db "
select '[str][' as 'ph1',datetime(date + strftime('%s', '2001-01-01 00:00:00'), 'unixepoch', 'localtime') as date,']' as 'ph2','[' as 'ph2',is_from_me,']' as 'ph2',NULL as 'filename',text from message where handle_id=(
select handle_id from chat_handle_join where chat_id=(
select ROWID from chat where guid='iMessage;-;$1')
)
union all
select '[att][' as 'ph1',datetime(date + strftime('%s', '2001-01-01 00:00:00'), 'unixepoch', 'localtime') as date,']' as 'ph2','[' as 'ph3',is_from_me,']' as 'ph2',NULL as 'text',filename from attachment,message_attachment_join,message where attachment.rowid = message_attachment_join.attachment_id and message_attachment_join.message_id = message.rowid and message.cache_has_attachments=1 and message.handle_id=(
select handle_id from chat_handle_join where chat_id=(
select ROWID from chat where guid='iMessage;-;$1')
) order by date" | sed 's/\|1\|/H/g;s/\|0\|/N/g;s/\|//g' > iMessages$1.txt
Python: Analyze texts for number, total characters, and amount of attachments sent (per hour)
# -*- coding: utf-8 -*-
import glob
import os
import re
import string
from datetime import datetime,timedelta
filenames = []
texts = []
data = {}
metadata = {
'total_N_str': 0,
'total_N_att': 0,
'total_N_str_len': 0,
'max_N_len': 0,
'total_H_str': 0,
'total_H_att': 0,
'total_H_str_len': 0,
'max_H_len': 0
}
def getLogs():
cwd = os.getcwd()
os.system("cd '" + cwd + """'
./imbfull.sh +19084212107
./imbfull.sh nicole.hladick@gmail.com""")
def getFileNames():
for filename in glob.glob('*.txt'):
if "iMessage" in filename: filenames.append(filename)
def displayFileList():
print len(filenames),"files found:"
print '\n'.join(filenames)
def openFile(s):
print "Openning file...",
with open(s, 'r') as f:
readList = f.readlines()
print " File successfully open."
return readList
def parseText(text):
# search for [type][YYYY-MM-DD HH:MM:SS][FROM]
pattern = re.compile('^\[[a-z]{3}\]\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\]\[[A-Z]\]')
meta = re.search(pattern, text).group()
t_type = meta[1:4]
t_from = meta[-2:-1]
t_date = datetime.strptime(meta[6:25], '%Y-%m-%d %H:%M:%S')
t_str = text.replace(meta,"").rstrip()
return t_type, t_from, t_date, t_str
def listTexts(file, filename):
print "Listing messages...",
# search for [type][YYYY-MM-DD HH:MM:SS][FROM]
pattern = re.compile('^\[[a-z]{3}\]\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\]\[[A-Z]\]')
for line in file:
line = line.rstrip()
if re.match(pattern, line):
texts.append(line)
else:
texts[-1] += line
print " Messages successfully listed."
def runMessageExtractor(s):
print "\nExtracting text IDs on %s:"%(s)
listTexts(openFile(s), s)
# H_att,N_att,H_txt,N_txt = countTexts(readList,s)
# texts.append((H_att,N_att,H_txt,N_txt))
def analyze():
global total_N_str, total_N_att, total_H_str, total_H_att
print "Analyzing messages...",
#initialize time range
start_date = datetime.strptime("2014-05-02", '%Y-%m-%d')
while start_date < datetime.strptime("2015-05-03", '%Y-%m-%d'):
data[start_date.strftime('%Y-%m-%d %H')] = {
'H': { 'txt_count':0, 'len':0, 'att_count':0 },
'N': { 'txt_count':0, 'len':0, 'att_count':0 }
}
start_date += timedelta(hours=1)
#populate data
for text in texts:
t_type, t_from, t_date, t_str = parseText(text)
if t_type == "str":
if t_from == "H":
metadata['total_H_str'] += 1
metadata['total_H_str_len'] += len(t_str)
metadata['max_H_len'] = max(metadata['max_H_len'],len(t_str))
else:
metadata['total_N_str'] += 1
metadata['total_N_str_len'] += len(t_str)
metadata['max_N_len'] = max(metadata['max_N_len'],len(t_str))
else:
if t_from == "H":
metadata['total_H_att'] += 1
else:
metadata['total_N_att'] += 1
if t_date.strftime('%Y-%m-%d %H') in data:
data[t_date.strftime('%Y-%m-%d %H')][t_from]['txt_count'] += 1
if t_type == "att":
data[t_date.strftime('%Y-%m-%d %H')][t_from]['att_count'] += 1
else:
data[t_date.strftime('%Y-%m-%d %H')][t_from]['len'] += len(t_str)
print " Analysis complete."
def writeData():
print "Writing data...",
with open("h_data.txt", 'w') as f:
start_date = datetime.strptime("2014-05-02", '%Y-%m-%d')
prev_day = -1
while start_date < datetime.strptime("2015-05-03", '%Y-%m-%d'): if prev_day != start_date.day: if prev_day >= 0:
f.write("\n")
f.write(start_date.strftime("%B %d").lstrip("0").replace(" 0", " "))
prev_day = start_date.day
txt_count = data[start_date.strftime('%Y-%m-%d %H')]['H']['txt_count']
t_len = data[start_date.strftime('%Y-%m-%d %H')]['H']['len']
att_count = data[start_date.strftime('%Y-%m-%d %H')]['H']['att_count']
f.write("-%d&%d&%d"%(txt_count, t_len, att_count))
start_date += timedelta(hours=1)
f.close()
with open("n_data.txt", 'w') as f:
start_date = datetime.strptime("2014-05-02", '%Y-%m-%d')
prev_day = -1
while start_date < datetime.strptime("2015-05-03", '%Y-%m-%d'): if prev_day != start_date.day: if prev_day >= 0:
f.write("\n")
f.write(start_date.strftime("%B %d").lstrip("0").replace(" 0", " "))
prev_day = start_date.day
txt_count = data[start_date.strftime('%Y-%m-%d %H')]['N']['txt_count']
t_len = data[start_date.strftime('%Y-%m-%d %H')]['N']['len']
att_count = data[start_date.strftime('%Y-%m-%d %H')]['N']['att_count']
f.write("-%d&%d&%d"%(txt_count, t_len, att_count))
start_date += timedelta(hours=1)
f.close()
print " Write complete."
def writeDataTogether():
print "Writing data...",
with open("data.txt", 'w') as f:
start_date = datetime.strptime("2014-05-02", '%Y-%m-%d')
prev_day = -1
while start_date < datetime.strptime("2015-05-03", '%Y-%m-%d'): if prev_day != start_date.day: if prev_day >= 0:
f.write("\n")
f.write(start_date.strftime("%B %d, %Y").lstrip("0").replace(" 0", " "))
prev_day = start_date.day
txt_count = data[start_date.strftime('%Y-%m-%d %H')]['H']['txt_count'] + data[start_date.strftime('%Y-%m-%d %H')]['N']['txt_count']
t_len = data[start_date.strftime('%Y-%m-%d %H')]['H']['len'] + data[start_date.strftime('%Y-%m-%d %H')]['N']['len']
att_count = data[start_date.strftime('%Y-%m-%d %H')]['H']['att_count'] + data[start_date.strftime('%Y-%m-%d %H')]['N']['att_count']
f.write("-%d&%d&%d"%(txt_count, t_len, att_count))
start_date += timedelta(hours=1)
f.close()
print " Write complete."
def runTextCounter():
getLogs()
getFileNames()
displayFileList()
print "\nBeginning chatlog indexing..."
for chatlog in filenames:
runMessageExtractor(chatlog)
print ""
analyze()
writeDataTogether()
# only within time range
non0len_H = 0
non0count_H = 0
maxlen_H = 0
non0len_N = 0
non0count_N = 0
maxlen_N = 0
start_date = datetime.strptime("2014-05-02", '%Y-%m-%d')
while start_date < datetime.strptime("2015-05-03", '%Y-%m-%d'): t_len = data[start_date.strftime('%Y-%m-%d %H')]['H']['len'] if t_len > 0:
non0len_H += t_len
non0count_H += 1
maxlen_H = max(maxlen_H, t_len)
t_len = data[start_date.strftime('%Y-%m-%d %H')]['N']['len']
if t_len > 0:
non0len_N += t_len
non0count_N += 1
maxlen_N = max(maxlen_N, t_len)
start_date += timedelta(hours=1)
print "\nChatlog indexing is complete.\n"
print "%d total messages: %d by Hizal and %d by Nicole."%(metadata['total_H_str']+metadata['total_N_str'], metadata['total_H_str'], metadata['total_N_str'])
print "%d total attachments: %d by Hizal and %d by Nicole."%(metadata['total_H_att']+metadata['total_N_att'], metadata['total_H_att'], metadata['total_N_att'])
print "%d ave characters: %d for Hizal (max %d) and %d for Nicole (max %d)"%((metadata['total_H_str_len']+metadata['total_N_str_len'])*1.0/(metadata['total_H_str']+metadata['total_N_str']), metadata['total_H_str_len']*1.0/metadata['total_H_str'], metadata['max_H_len'], metadata['total_N_str_len']*1.0/metadata['total_N_str'], metadata['max_N_len'])
print "%d ave characters per hour: %d for Hizal (max %d) and %d for Nicole (max %d)"%((non0len_H + non0len_N)*1.0/(non0count_H + non0count_N), non0len_H*1.0/non0count_H, maxlen_H, non0len_N*1.0/non0count_N, maxlen_N)
runTextCounter()
Processing: Generating cityscape masks using brush strokes and random buildings based on text analysis
import java.util.*;
boolean debug = false;
ArrayList<String[][]> texts = new ArrayList<String[][]>();
int index = 0;
int hour = 0;
boolean var3used = false;
boolean var4used = false;
boolean thinused = false;
// VARIATIONS
float overlap = 10;
float ignore = 10;
float xscap = 25;
float smallcap = 50;
float medcap = 200;
float tallcap = 500;
// CITY VARIABLES
float citystartx;
float citystarty;
float building_width;
ArrayList trees = new ArrayList();
// PAINT
ArrayList floors = new ArrayList();
ArrayList lefts = new ArrayList();
ArrayList rights = new ArrayList();
ArrayList mids = new ArrayList();
void setup() {
size(1700,1700); //start 350 in from 1700
String[] fileLines = loadStrings("../txtcounter/data.txt");
for(int i=0; i<fileLines.length; i++)
texts.add(parseData(fileLines[i]));
// trees
for(int i=0; i<12; i++)
trees.add(loadImage("greenery/s_treeTop"+i+".png"));
// floors
for(int i=0; i<10; i++)
floors.add(loadImage("brushes/floors/floor"+i+".png"));
// lefts
for(int i=0; i<12; i++)
lefts.add(loadImage("brushes/lefts/left"+i+".png"));
// rights
for(int i=0; i<12; i++)
rights.add(loadImage("brushes/rights/right"+i+".png"));
// mids
for(int i=0; i<46; i++) mids.add(loadImage("brushes/mids/mid"+i+".png")); citystartx = 350; citystarty = (height-350)-(height-700)/3.0; building_width = (width-700)/24.0; background(255); //buildCity(texts.get(index)); println(getMetadata(texts.get(index))); } void draw() { // draw background if(hour == 0) { int floor = int(random(floors.size())); image(floors.get(floor),0,-2); int left = int(random(lefts.size())); if(round(random(2))>0)
image(lefts.get(left),0,0);
int right = int(random(rights.size()));
if(round(random(2))>0)
image(rights.get(right),0,0);
for(int i=0; i<round(random(4,6)); i++) { int mid = int(random(mids.size())); image(mids.get(mid),random(-100,100),0); } hour ++; } // draw template String[][] data = texts.get(index); if(hour>0 && hour<data.length) {
buildCity(data, hour);
hour++;
}
}
void reset() {
hour = 0;
background(255);
var3used = false;
var4used = false;
thinused = false;
}
void keyPressed() {
if (key == 'b' || key == 'B') {
index--;
if(index<0) index = texts.size()-1; println(getMetadata(texts.get(index))); reset(); } if (key == 'n' || key == 'N') { index++; if(index >= texts.size()) index = 0;
println(getMetadata(texts.get(index)));
reset();
}
if (key == 's' || key == 'S') {
String filename = "drawings/"+index+" "+texts.get(index)[0][0]+".png";
saveFrame(filename);
}
if (key == 'r' || key == 'R') {
reset();
}
}
String getMetadata(String[][] data){
String info = data[0][0]+" ";
int texts = 0;
int att = 0;
for(int i=1; i<data.length; i++) {
texts += parseInt(data[i][0]);
att += parseInt(data[i][2]);
}
info += "("+texts+" texts, "+att+" attachments)";
return info;
}
void buildCity(String[][] data, int i) {
overlap = random(10);
float limitter = 8000; //ave 755
float hval = map(parseInt(data[i][1]), 0, limitter, 0, height/2);
if(hval < smallcap) { //is small fill(255,0,0,128); } else if(hval >= smallcap && hval < medcap) { //is med fill(0,255,0,128); } else if(hval >= medcap && hval < tallcap) { //is tall
fill(0,0,255,128);
}
else { //is super tall
fill(128,128,128,128);
}
if(debug) {
noStroke();
rect(citystartx+building_width*(i-1)-overlap, citystarty, building_width+overlap, random(-100,-200));
}
if(hval != 0) {
if(hval <= ignore && parseInt(data[i][2])>0)
attGroup0(citystartx+building_width*(i-1)-overlap, citystarty, building_width+overlap, parseInt(data[i][2]));
else
randomBuilding(citystartx+building_width*(i-1)-overlap, citystarty, building_width+overlap, hval, parseInt(data[i][2]));
}
}
void randomBuilding(float startx, float starty, float w, float h, int numAtt) {
// is too small
if(h <= ignore) {
var11(startx, starty, w, h, numAtt);
}
// is xs
else if(h < xscap) {
if(round(random(1)) == 0)
var11(startx, starty, w, h, numAtt);
else
var13(startx, starty, w, h, numAtt);
}
// is small
else if(h < smallcap) {
int choice = int(random(100));
if(choice < 30)
var9(startx, starty, w, h, numAtt);
else if(choice < 60)
oldRoof(startx, starty, w, h, numAtt);
else if(choice < 90)
slantRoof(startx, starty, w, h, numAtt);
else
basic(startx, starty, w, h, numAtt);
}
// is medium
else if(h < medcap) {
int choice = int(random(8));
if(choice == 0)
oldRoof(startx, starty, w, h, numAtt);
else if(choice == 1) {
if(thinused)
randomBuilding(startx, starty, w, h, numAtt);
else
thin(startx, starty, w, h, numAtt);
}
else if(choice == 2)
slantRoof(startx, starty, w, h, numAtt);
else if(choice == 3)
basic(startx, starty, w, h, numAtt);
else if(choice == 4)
stairstep(startx, starty, w, h, numAtt);
else if(choice == 5)
angled(startx, starty, w, h, numAtt);
else if(choice == 6)
bevel(startx, starty, w, h, numAtt);
else
roundRoof(startx, starty, w, h, numAtt);
}
// is tall
else if(h < tallcap) {
int choice = int(random(14));
if(choice == 0)
var1(startx, starty, w, h, numAtt);
else if(choice == 1) {
if(var3used)
randomBuilding(startx, starty, w, h, numAtt);
else
var3(startx, starty, w, h, numAtt);
}
else if(choice == 2) {
if(var4used)
randomBuilding(startx, starty, w, h, numAtt);
else
var4(startx, starty, w, h, numAtt);
}
else if(choice == 3)
var8(startx, starty, w, h, numAtt);
else if(choice == 4)
slant(startx, starty, w, h, numAtt);
else if(choice == 5)
stairstep(startx, starty, w, h, numAtt);
else if(choice == 6)
bevel(startx, starty, w, h, numAtt);
else if(choice == 7)
slice(startx, starty, w, h, numAtt);
else if(choice == 8)
angled(startx, starty, w, h, numAtt);
else if(choice == 9)
blockRoof(startx, starty, w, h, numAtt);
else if(choice == 10)
triangleRoof(startx, starty, w, h, numAtt);
else if(choice == 11)
basic(startx, starty, w, h, numAtt);
else if(choice == 12) {
if(thinused)
randomBuilding(startx, starty, w, h, numAtt);
else
thin(startx, starty, w, h, numAtt);
}
else
var2(startx, starty, w, h, numAtt);
}
// is super tall
else {
int choice = int(random(100));
if(choice < 20)
var1(startx, starty, w, h, numAtt);
else if(choice < 40)
var5(startx, starty, w, h, numAtt);
else if(choice < 60)
var7(startx, starty, w, h, numAtt);
else if(choice < 80)
stairstep(startx, starty, w, h, numAtt);
else
var8(startx, starty, w, h, numAtt);
}
}
String[][] parseData(String texts) {
String[][] hourlyData = new String[25][3];
String[] hours = texts.split("-");
hourlyData[0] = new String[1];
hourlyData[0][0] = hours[0];
for(int i=1; i<hours.length; i++) { hourlyData[i] = hours[i].split("&"); } return hourlyData; } // ******************** VARIATION DESIGNS ********************* // void basic(float startx, float starty, float w, float h, int numAtt) { noStroke(); fill(0); rect(startx, starty, w, -1*h); if(numAtt>0)
attGroup1(startx, starty, w, h, numAtt);
}
void slant(float startx, float starty, float w, float h, int numAtt) {
int both = round(random(2));
int left = round(random(1));
float xr = random(w/6, w/3);
float xl = random(w/6, w/3);
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
if(both==1) {
vertex(startx+xl, starty-h);
vertex(startx+w-xr, starty-h);
}
else {
if(left==1) {
vertex(startx+xl, starty-h);
vertex(startx+w, starty-h);
}
else {
vertex(startx, starty-h);
vertex(startx+w-xr, starty-h);
}
}
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt > 0) {
if(both == 1)
attGroup1(startx+xl, starty, w-(xr+xl), h, numAtt);
else if(left == 1)
attGroup1(startx+xl, starty, w-xl, h, numAtt);
else
attGroup1(startx, starty, w-xr, h, numAtt);
}
}
void bevel(float startx, float starty, float w, float h, int numAtt) {
int both = round(random(2));
int left = round(random(1));
float x1 = random(w/6, w/3); // width of slant
float y1 = random(h/5); // height of slant
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
if(both==1) {
vertex(startx, starty-h+y1);
vertex(startx+x1, starty-h);
vertex(startx+w-x1, starty-h);
vertex(startx+w, starty-h+y1);
}
else {
if(left==1) {
vertex(startx, starty-h+y1);
vertex(startx+x1, starty-h);
vertex(startx+w, starty-h);
}
else {
vertex(startx, starty-h);
vertex(startx+w-x1, starty-h);
vertex(startx+w, starty-h+y1);
}
}
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt > 0) {
if(both == 1)
attGroup1(startx+x1, starty, w-x1*2, h, numAtt);
else if(left == 1)
attGroup1(startx+x1, starty, w-x1, h, numAtt);
else
attGroup1(startx, starty, w-x1, h, numAtt);
}
}
void slice(float startx, float starty, float w, float h, int numAtt) {
int left = round(random(1));
float y1 = random(h/8, h/3); // height of slant
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
if(left==1) {
vertex(startx, starty-h);
vertex(startx+w, starty-h+y1);
}
else {
vertex(startx, starty-h+y1);
vertex(startx+w, starty-h);
}
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt>0)
attGroup2(startx+10+random(w-20), starty-h+y1, w, random(h/6, h/4), startx, starty, numAtt);
}
void angled(float startx, float starty, float w, float h, int numAtt) {
float x1 = random(w/4, w-w/4); // corner point
float yl = constrain(random(h/3),0,10); // height of left
float yr = constrain(random(h/3),0,10); // height of right
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
vertex(startx, starty-h+yl);
vertex(startx+x1, starty-h);
vertex(startx+w, starty-h+yr);
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt>0)
attGroup2(startx+10+random(w-20), starty-h+max(yl,yr), w, random(h/8, h/5), startx, starty, numAtt);
}
void stairstep(float startx, float starty, float w, float h, int numAtt) {
int single = round(random(3));
int left = round(random(1));
float x1; //width of left
float y1; //height of left
if(single == 0) { // is both
x1 = random(w/5, w/2);
y1 = random(h/8, h/3);
}
else {
x1 = random(w/4, w-w/4);
y1 = random(h/8, h/3);
}
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
if(single==0) {
stairLeft(startx, starty, w, h, x1, y1);
stairRight(startx, starty, w, h, x1, y1);
}
else if(left == 1) {
stairLeft(startx, starty, w, h, x1, y1);
vertex(startx+w, starty-h);
}
else {
vertex(startx, starty-h);
stairRight(startx, starty, w, h, x1, y1);
}
vertex(startx+w, starty);
endShape(CLOSE);
numAtt = attGroup3(startx, starty, w, h-y1, numAtt);
if(numAtt > 0) {
if(single==0)
attGroup0(startx, starty, w, numAtt);
else if(left == 1)
attGroup1(startx+x1, starty, w-x1, h, numAtt);
else
attGroup1(startx, starty, w-x1, h, numAtt);
}
}
void stairLeft(float startx, float starty, float w, float h, float x1, float y1) {
int steps = round(random(4,6));
for(int i=0; i<=steps; i++) {
float x = startx + ((x1/steps)*i);
float y = (starty-h+y1) - ((y1/steps)*i);
vertex(x,y);
vertex(x+(x1/steps),y);
}
}
void stairRight(float startx, float starty, float w, float h, float x2, float y2) {
int steps = round(random(4,6));
for(int i=0; i<steps; i++) {
float x = startx + (w-x2) + ((x2/steps)*i);
float y = (starty - h) + ((y2/steps)*i);
vertex(x,y);
vertex(x+(x2/steps),y);
}
}
void blockRoof(float startx, float starty, float w, float h, int numAtt) {
float y = random(h/2); // height of block
if(y<20) y = 20; float space = random(5,13); //spacing between steps noStroke(); fill(0); beginShape(); vertex(startx, starty); vertex(startx, starty-h+y); vertex(startx+(w/space), starty-h+y); vertex(startx+(w/space), starty-h+y/2); vertex(startx+((w/space)*2), starty-h+y/2); vertex(startx+((w/space)*2), starty-h); //mid vertex(startx+w-((w/space)*2), starty-h); vertex(startx+w-((w/space)*2), starty-h+y/2); vertex(startx+w-(w/space), starty-h+y/2); vertex(startx+w-(w/space), starty-h+y); vertex(startx+w, starty-h+y); vertex(startx+w, starty); endShape(CLOSE); numAtt = attGroup3(startx, starty, w, h-y, numAtt); if(numAtt>0)
attGroup2(startx+((w/space)*2)+5+random((startx+w-((w/space)*2))-(startx+((w/space)*2))-10), starty-h, w, random(h/6, h/4), startx, starty, numAtt);
}
void triangleRoof(float startx, float starty, float w, float h, int numAtt) {
float y = random(h/15,h/5);
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
vertex(startx, starty-h+y);
vertex(startx+w/2, starty-h);
vertex(startx+w, starty-h+y);
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt>0)
attGroup2(startx+w/2, starty, w, h+random(h/6, h/4), startx, starty, numAtt);
}
void roundRoof(float startx, float starty, float w, float h, int numAtt) {
float y = random(h/5);
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
vertex(startx, starty-h+y);
bezierVertex(startx, starty-h, startx+w/2, starty-h, startx+w/2, starty-h);
bezierVertex(startx+w, starty-h, startx+w, starty-h+y, startx+w, starty-h+y);
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt>0)
attGroup2(startx+5+random(w-10), starty, w, h+random(h/8, h/5), startx, starty, numAtt);
}
void oldRoof(float startx, float starty, float w, float h, int numAtt) {
float x1 = overlap*0.75; //distance from edge
float y1 = smallcap/4; //height
float y2 = 3; //edge height
if(h<=smallcap) { h = map(h, 0, smallcap, smallcap-smallcap/3, smallcap); float div = random(0.8, 1.8); startx += overlap*div; w -= (overlap*div)*2; x1 /= 3; y1 /= 3; y2 /= 3; } noStroke(); fill(0); beginShape(); vertex(startx, starty); vertex(startx, starty-h+y1-y2); vertex(startx+y2, starty-h+y1-y2); vertex(startx+y2, starty-h+y1); vertex(startx+x1, starty-h+y1); vertex(startx+x1, starty-h+y2); vertex(startx+x1-y2, starty-h); //mid vertex(startx+w-x1+y2, starty-h); vertex(startx+w-x1, starty-h+y2); vertex(startx+w-x1, starty-h+y1); vertex(startx+w-y2, starty-h+y1); vertex(startx+w-y2, starty-h+y1-y2); vertex(startx+w, starty-h+y1-y2); vertex(startx+w, starty); endShape(CLOSE); numAtt = attGroup3(startx, starty, w, h-y1, numAtt); if(numAtt > 0)
attGroup4(startx, starty, w, h, numAtt);
}
void slantRoof(float startx, float starty, float w, float h, int numAtt) {
float x1 = random(3,8); //horizontal size
float y1 = random(3,15); //vertical size
if(h<=smallcap) { h = map(h, 0, smallcap, smallcap-smallcap/3, smallcap); float div = random(0.8, 1.8); startx += overlap*div; w -= (overlap*div)*2; x1 /= 3; y1 /= 3; } noStroke(); fill(0); beginShape(); vertex(startx, starty); vertex(startx, starty-h+y1); vertex(startx-x1, starty-h); vertex(startx+w+x1, starty-h); vertex(startx+w, starty-h+y1); vertex(startx+w, starty); endShape(CLOSE); numAtt = attGroup3(startx, starty, w, h-y1, numAtt); } void thin(float startx, float starty, float w, float h, int numAtt) { thinused = true; float x1 = random(w/10, w/3); // start point of thin float x2 = random(w/2, w*.75); // width of thin float y1 = random(h/5, h/3); // height of first float y2 = random(h/4, h/2); // height of second noStroke(); fill(0); randomBuilding(startx+x1, starty, x2, h, numAtt); randomBuilding(startx-overlap/2, starty, overlap/2+x1+x2/2, y1, 0); randomBuilding(startx+x1+x2/2, starty, w-(x1+x2/2)+overlap/2, y2, 0); } // ******************** FULL DESIGNS ********************* // void var1(float startx, float starty, float w, float h, int numAtt) { startx -= overlap/3; w += (overlap/3)*2; float x1 = random(w/6, w/4); //slant width float y1 = random(h/4, h-h/4); //left slant start float y2 = random(20); //slant height float y1r = random(h/4,h-h/4); //right slant start int uneven = round(random(5)); noStroke(); fill(0); beginShape(); vertex(startx, starty); vertex(startx, starty-y1); vertex(startx+x1, starty-y1-y2); vertex(startx+x1, starty-h); vertex(startx+w-x1, starty-h); if(uneven > 0) {
vertex(startx+w-x1, starty-y1r-y2);
vertex(startx+w, starty-y1r);
}
else {
vertex(startx+w-x1, starty-y1-y2);
vertex(startx+w, starty-y1);
}
vertex(startx+w, starty);
endShape(CLOSE);
attGroup1(startx+x1, starty, w-x1*2, h, numAtt);
}
void var2(float startx, float starty, float w, float h, int numAtt) {
float x1 = random(w/6, w/4); //slant width
float y1 = random(h-h/3); //bottom left slant start
float y2 = random(20); //slant height
float y1r = random(h-h/4); //bottom right slant start
float y3 = random(h/3); //top height
y1=constrain(y1,h/5,h-y3);
y1r=constrain(y1,h/5,h-y3);
int uneven = round(random(1));
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
vertex(startx, starty-y1);
vertex(startx+x1, starty-y1-y2);
vertex(startx+x1, starty-(h-y3-y2*2));
vertex(startx+w/4, starty-(h-y3-y2));
vertex(startx+w/4, starty-(h-y2));
//mid
vertex(startx+w/2, starty-h);
vertex(startx+w/2+w/4, starty-(h-y2));
vertex(startx+w/2+w/4, starty-(h-y3-y2));
vertex(startx+w-x1, starty-(h-y3-y2*2));
if(uneven == 1) {
vertex(startx+w-x1, starty-y1r-y2);
vertex(startx+w, starty-y1r);
}
else {
vertex(startx+w-x1, starty-y1-y2);
vertex(startx+w, starty-y1);
}
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt>0)
attGroup2(startx+w/2, starty-h, w, random(h/7, h/4), startx, starty, numAtt);
}
void var3(float startx, float starty, float w, float h, int numAtt) {
var3used = true;
startx -= overlap/2;
w += overlap;
float y1 = random(h/5, h/2); // start of curve
float x1 = random(5,w/4); // gap
int bridges = round(random(1,5));
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
vertex(startx, starty-h+y1);
bezierVertex(startx, starty-h, startx+(w-x1)/2, starty-h, startx+(w-x1)/2, starty-h);
vertex(startx+(w-x1)/2, starty);
endShape(CLOSE);
beginShape();
vertex(startx+w, starty);
vertex(startx+w, starty-h+y1);
bezierVertex(startx+w, starty-h, (startx+w)-(w-x1)/2, starty-h, (startx+w)-(w-x1)/2, starty-h);
vertex((startx+w)-(w-x1)/2, starty);
endShape(CLOSE);
boolean top = true;
for(int i=0; i<bridges; i++) { float y2 = random(h/2); //height on building float x3 = random(3,8); //thickness if(top) { y2 = h-y2; top = false; } else top = true; rect(startx+(w-x1)/2,starty-y2,x1,x3); } if(numAtt>0)
attGroup0(startx, starty, w, numAtt);
}
void var4(float startx, float starty, float w, float h, int numAtt) {
var4used = true;
float left = round(random(1));
float xl = random(w/4, w/2); // left "waist" amount
float xr = random(w/4, w/2); // right "waist" amount
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
if(left == 1)
vertex(startx+xl, starty-h/2);
vertex(startx, starty-h);
vertex(startx+w, starty-h);
if(left == 0)
vertex((startx+w)-xr, starty-h/2);
vertex(startx+w, starty);
endShape(CLOSE);
float weight = random(1.5,5);
strokeWeight(weight);
stroke(0);
if(left==1)
line(startx+weight, starty-weight, startx+weight, starty-h+weight);
else
line(startx+w-weight, starty-weight, startx+w-weight, starty-h+weight);
if(numAtt>0)
attGroup1(startx, starty, w, h, numAtt);
}
void var5(float startx, float starty, float w, float h, int numAtt) {
float x1 = random(w/3, w*.75); //width of curve
int left = round(random(1));
w += x1/2; // *2?
noStroke();
fill(0);
beginShape();
if(left == 1) {
startx -= x1/2;
vertex(startx, starty);
bezierVertex(startx+x1, starty, startx+x1, starty-h, startx+x1, starty-h);
vertex(startx+w, starty-h);
vertex(startx+w, starty);
}
else {
vertex(startx+w, starty);
bezierVertex(startx+w-x1, starty, startx+w-x1, starty-h, startx+w-x1, starty-h);
vertex(startx, starty-h);
vertex(startx, starty);
}
endShape(CLOSE);
if(numAtt>0) {
if(left == 1)
attGroup1(startx+x1, starty, w-x1, h, numAtt);
else
attGroup1(startx, starty, w-x1, h, numAtt);
}
}
void var7(float startx, float starty, float w, float h, int numAtt) {
float x1 = random(w/10, w/3); // width of side
float x2 = random(w/10, w/3);
float y1 = random(h); // height of side
float y2 = random(h);
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
vertex(startx, starty-h+y1);
vertex(startx+x1, starty-h);
vertex(startx+w-x2, starty-h);
vertex(startx+w, starty-h+y2);
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt>0)
attGroup1(startx+x1, starty, w-x1-x2, h, numAtt);
}
void var8(float startx, float starty, float w, float h, int numAtt) {
float y1 = random(h-h/4, h); // height of angle corner
float y2 = random(h/3, h/2); // height of start angle
int left = round(random(1));
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
if(left == 1) {
vertex(startx, starty-y2);
vertex(startx+w/3, starty-y1);
vertex(startx+w, starty-h);
}
else {
vertex(startx, starty-h);
vertex(startx+w-w/3, starty-y1);
vertex(startx+w, starty-y2);
}
vertex(startx+w, starty);
endShape(CLOSE);
if(numAtt>0) {
if(left == 1)
attGroup2(startx+5+w/3+random(w-w/3-5), starty-y1, w, random(h/5, h/3), startx, starty, numAtt);
else
attGroup2(startx+random(w-w/3-5), starty-y1, w, random(h/5, h/3), startx, starty, numAtt);
}
}
void var9(float startx, float starty, float w, float h, int numAtt) {
float origW = w;
w = random(w-w/4, w);
float y1 = random(8); // side slant height
float y2 = 8; // top slant height
float y3 = 10; // tower base height
float x1 = w/3; // inward amount
constrain(h, y1+y2+y3+5, smallcap);
noStroke();
fill(0);
beginShape();
vertex(startx, starty);
vertex(startx, starty-h+y2+y3+y1);
vertex(startx+x1, starty-h+y2+y3);
vertex(startx+x1, starty-h+y2);
vertex(startx+w/2, starty-h);
//mid
vertex(startx+w-w/2, starty-h);
vertex(startx+w-x1, starty-h+y2);
vertex(startx+w-x1, starty-h+y2+y3);
vertex(startx+w, starty-h+y2+y3+y1);
vertex(startx+w, starty);
endShape(CLOSE);
fill(255);
if(round(random(2)) > 0)
ellipse(startx+w/2, starty-h+y2+y3/2, x1/3, x1/3);
if(numAtt>0)
attGroup0(startx, starty, origW, numAtt);
}
void var11(float startx, float starty, float w, float h, int numAtt) {
float x1 = w/4; // width
float x2 = random(3); // "wing"
noStroke();
fill(0);
beginShape();
vertex(startx+w/2-x1/2, starty);
vertex(startx+w/2-x1/2, starty-h);
vertex(startx+w/2-x1/2-x2, starty-h);
vertex(startx+w/2, starty-h-random(4,10));
vertex(startx+w/2+x1/2+x2, starty-h);
vertex(startx+w/2+x1/2, starty-h);
vertex(startx+w/2+x1/2, starty);
endShape(CLOSE);
if(numAtt>0)
attGroup0(startx, starty, w, numAtt);
}
void var13(float startx, float starty, float w, float h, int numAtt) {
float x1 = random(w/4,w); // width
float x2 = random(3); // "wing"
float y1 = random(4, 10);
float start = startx + w/2;
noStroke();
fill(0);
beginShape();
vertex(start - x1/2, starty);
vertex(start - x1/2, starty-h);
vertex(start - x1/2 - x2, starty-h);
vertex(start - x1/2 + x2*2, starty-h-y1);
vertex(start + x1/2 - x2*2, starty-h-y1);
vertex(start + x1/2 + x2, starty-h);
vertex(start + x1/2, starty-h);
vertex(start + x1/2, starty);
endShape(CLOSE);
if(round(random(1)) == 1) {
beginShape();
vertex(start - x2, starty-h-y1);
vertex(start, starty-h-y1-y1/2);
vertex(start + x2, starty-h-y1);
endShape(CLOSE);
}
if(numAtt>0)
attGroup0(startx, starty, w, numAtt);
}
// ******************** ATTACHMENT DESIGNS ********************* //
// limits to greenery
void attGroup0(float startx, float starty, float w, int numAtt) {
while(numAtt>0) {
tree(startx+random(w), starty);
numAtt -= 10;
}
}
// limits to blocks, antennas, greenery
void attGroup1(float startx, float starty, float w, float h, int numAtt) { //h = total height
boolean antennaDone = false;
while(numAtt > 0) {
int doAntenna = round(random(1));
int doSimple = round(random(1));
if(numAtt>0 && doAntenna==1 && doSimple==0 && !antennaDone) { //two levels
complexAntenna(constrain(startx+random(w),startx+10, (startx+w)-10), starty-h, random(h/7, h/4));
numAtt -= 10;
antennaDone = true;
}
if(numAtt>0 && doAntenna==1 && !antennaDone) {
antenna(startx+5+random(w-10), starty-h, random(h/9, h/5));
numAtt -= 10;
antennaDone = true;
}
if(numAtt>0) {
block(startx, startx+w, starty-h);
numAtt -= 10;
}
//draw greenery, last resort
}
}
// limits to single antenna starting at various heights (calculated beforehand), then greenery
void attGroup2(float startx, float starty, float w, float h, float treeStartx, float treeStarty, int numAtt) {
antenna(startx, starty, h);
numAtt -= 10;
if(numAtt>0)
attGroup0(treeStartx, treeStarty, w, numAtt);
}
// draws balconies alongside the two vertical edges, returns adjusted numAtt value
int attGroup3(float startx, float starty, float w, float h, int numAtt) {
if(numAtt > 10) {
balcony(startx, starty, h);
balcony(startx+w, starty, h);
return numAtt - 20;
}
return numAtt;
}
// limits to blocks, dishes, watertowers, and greenery
void attGroup4(float startx, float starty, float w, float h, int numAtt) { //h = total height
boolean towerDone = false;
boolean dishDone = false;
while(numAtt > 0) {
int doTower = round(random(5));
int doDish = round(random(5));
if(!towerDone && doTower == 1) {
watertower(startx+5+random(w-25), starty-h, constrain(map(h,0,medcap,.1,.9), .1, .9));
numAtt -= 10;
towerDone = true;
}
if(!dishDone && doDish == 1 && numAtt > 0) {
dish(startx+15+random(w-30), starty-h, constrain(map(h,0,medcap,.5,1), .5, 1));
numAtt -= 10;
dishDone = true;
}
if(numAtt>0) {
block(startx+5, startx+w-10, starty-h);
numAtt -= 10;
}
//draw greenery, last resort
}
}
void antenna(float startx, float starty, float h) {
strokeWeight(random(1.5,3));
stroke(0);
line(startx, starty, startx, starty-h);
}
void complexAntenna(float startx, float starty, float h) {
float x1 = random(3,8); // distance between beams
float y1 = random(h/7, h-h/4); // height of secondary beam
float y2 = random(y1); //connector beam heights
float y3 = random(y1);
if(round(random(1))==1) x1 *= -1;
strokeWeight(random(1.5,3));
stroke(0);
line(startx, starty, startx, starty-h);
strokeWeight(random(1.5,3));
line(startx+x1, starty, startx+x1, starty-y1);
line(startx, starty-y2, startx+x1, starty-y2);
line(startx, starty-y3, startx+x1, starty-y3);
}
void block(float startx, float endx, float starty) {
float w = random(8, (endx-startx)-(endx-startx)/4); //width
float h = -1*random(4, w/2); //height
float x1 = random(startx, endx-w); //start position
noStroke();
fill(0);
rect(x1, starty, w, h);
}
void balcony(float startx, float starty, float hval) {
int amount = int(map(hval, 0, tallcap, 0, 40));
float w = 8;
float h = w/2;
float x1 = random(w/3,w/2);
noStroke();
fill(0);
for(int i=0; i<amount; i++) {
rect(startx-x1, starty-(hval/amount)*i-h, w, h);
}
}
void watertower(float startx, float starty, float scale) {
float h = 22*scale;
float w = 15*scale;
float y1 = h/5.5; // barrel start
float y2 = h/10; // barrel roof height
float x1 = w*.8; // barrel width
noStroke();
fill(0);
beginShape();
vertex(startx, starty-y1);
vertex(startx, starty-h+y2);
bezierVertex(startx, starty-h,startx+x1/2, starty-h,startx+x1/2, starty-h);
bezierVertex(startx+x1, starty-h,startx+x1, starty-h+y2,startx+x1, starty-h+y2);
vertex(startx+x1, starty-y1);
endShape(CLOSE);
strokeWeight(2*scale);
stroke(0);
line(startx, starty, startx+w*.1, starty-y1);
line(startx+x1, starty, (startx+x1)-w*.1, starty-y1);
line(startx+x1/2, starty, startx+x1/2, starty-y1);
strokeWeight(1.5*scale);
line(startx+w, starty, startx+w, starty-h+y2);
line(startx+w, starty-h+y2*2, startx+w-w*.3, starty-h+y2*2);
}
void dish(float startx, float starty, float scale) {
float side = 25*scale;
noFill();
strokeWeight(2*scale);
stroke(0);
if(round(random(1)) == 1) {
arc(startx, starty-side/2-5, side, side, PI/2, PI);
line(startx-side*.35, starty, startx-side*.35, starty-side*.35);
line(startx-side*.35, starty-side*.35, startx-side*.35+side*.2, starty-side*.35-side*.2);
}
else {
arc(startx, starty-side/2-5, side, side, 0, PI-PI/2);
line(startx+side*.35, starty, startx+side*.35, starty-side*.35);
strokeWeight(1.5*scale);
line(startx+side*.35, starty-side*.35, startx+side*.35-side*.2, starty-side*.35-side*.2);
}
}
void tree(float startx, float starty) {
int treeIndex = int(random(trees.size()));
//int y = round(random(25, 50));
PImage tree = trees.get(treeIndex);
//tree.resize(0,y);
image(tree, startx-tree.width/2, starty-tree.height+1);
}
Processing: Modified version of Justin Livi’s code for generating watercolor paintings
/*
* WatercolorSediment
* May, 2011
*
* Copyright 2011 Justin Livi
* justinlivi.net
* Written in Processing
*
*/
int seedcount = 10; // default = 50
float h, maxh, start; // overall distance from center
float vspeed, rspeed;
float theta = 0;
float speed = 1;
float rot;
boolean up = false;
float[] hm; // hue array
float[] sm; // saturation array
float[] lm; // lightness array
float[] dhm; // delta hue array
float[] dsm; // delta saturation array
float[] dlm; // delta lightness array
float[] dm; // distance array
float[] stm; // streakiness array
HSL hsl = new HSL();
int count = 0;
boolean a = true;
boolean pause;
void setup() {
size(1700, 1700);
smooth();
noStroke();
background(255);
if(width > height)
maxh = height;
else
maxh = width;
hm = new float[seedcount];
sm = new float[seedcount];
lm = new float[seedcount];
dhm = new float[seedcount];
dsm = new float[seedcount];
dlm = new float[seedcount];
dm = new float[seedcount];
stm = new float[seedcount];
reset();
}
void draw() {
if(pause) { return; }
if (theta < width) {
pushMatrix();
translate(theta, 0);
rotate(PI/2);
generate();
popMatrix();
theta++;
}
else if(count<400) {
if(a) {
saveFrame("paintings/painting-"+count+"_a.png");
a = false;
}
else {
saveFrame("paintings/painting-"+count+"_b.png");
a = true;
count++;
}
reset();
}
}
void mousePressed() {
pause = !pause;
//background(255);
//reset();
}
void reset() {
seedcount = (int)random(8, seedcount);
float centerhue = random(0, 360);
float variance = random(10, 40);
for(int count = 0; count < seedcount; count++) {
hm[count] = random(centerhue-variance, centerhue+variance);
sm[count] = random(45, 70);
lm[count] = random(20, 90);
dhm[count] = hm[count];
dsm[count] = sm[count];
dlm[count] = lm[count];
dm[count] = random(maxh);
stm[count] = random(.1, 1);
}
dm[0] = 0;
dm[seedcount-1] = height;
dm = sort(dm, seedcount);
h = 0;
start = h;
theta = -20;
vspeed = random(1, 9);
rspeed = random(1, 4);
}
void generate() {
for(int count = 0; count < seedcount; count++) { changeDm(count); fill(hsl.toRGB(dhm[count],dsm[count],dlm[count],100)); blend(count, dm[count]); } dm = sort(dm, seedcount); } // ---------------------- POSITION! ------------------------------------ // void changeDm(int count) { int prev = 0; int next = seedcount-1; if(count > 0)
prev = count-1;
if(count < seedcount-1)
next = count+1;
if(count == seedcount-1)
prev = seedcount-1;
if(count == 0)
next = 0;
dm[count] = constrain(dm[count]+random(-1, 1), 0, height);
if (count == 0)
dm[count] = 0;
else if (count == seedcount-1)
dm[count] = height;
}
// ---------------------- BLEND! ------------------------------------ //
void blend(int count, float distance) {
int prev = seedcount-1;
if(count < seedcount-1)
prev = count+1;
float formax = abs(dm[prev]-distance);
changeColor(count);
for(int count2 = 0; count2 < formax; count2++) {
for(int count3 = 0; count3 < (10/3.0*stm[count]+5/3.0); count3++) {
float hi = (dhm[prev]-dhm[count])/formax;
float si = (dsm[prev]-dsm[count])/formax;
float li = (dlm[prev]-dlm[count])/formax;
fill(hsl.toRGB(dhm[count]+random(-1,1)+(count2*hi),
dsm[count]+random(-.5,.5)+(count2*si),
dlm[count]+random(-.5,.5)+(count2*li), random(2, 10)));
pushMatrix();
translate(distance+count2+random(-1,1), random(-stm[count]*10,stm[count]*10));
rotate(random(PI*2));
ellipse(0, 0, random(2, 10+5*stm[count]), random(2, 10+5*stm[count]));
popMatrix();
}
}
}
void changeColor(int count) {
stm[count] += random(-.01, .01);
stm[count] = constrain(stm[count], .1, 1);
dhm[count] += random(-stm[count], stm[count]);
dhm[count] = constrain(dhm[count], hm[count]-20, hm[count]+20);
dsm[count] += random(-stm[count], stm[count]);
dsm[count] = constrain(dsm[count], sm[count]-20, sm[count]+20);
dlm[count] += random(-stm[count], stm[count]);
dlm[count] = constrain(dlm[count], lm[count]-20, lm[count]+20);
}
class HSL {
color toRGB(float H, float S, float L) {
float R = 0, G = 0, B = 0;
H /= 360;
S /= 100;
L /= 100;
float temp1 = 0, temp2 = 0, Rtemp3 = 0, Gtemp3 = 0, Btemp3 = 0;
if (S == 0) {
R = L;
G = L;
B = L;
}
else {
if (L < 0.5) temp2 = L*(1.0+S); else if (L >= 0.5)
temp2 = L+S-L*S;
temp1 = 2.0*L-temp2;
Rtemp3 = H+1.0/3.0;
if (Rtemp3 < 0) Rtemp3 = Rtemp3 + 1.0; if (Rtemp3 > 1)
Rtemp3 = Rtemp3 - 1.0;
Gtemp3 = H;
if (Gtemp3 < 0) Gtemp3 = Gtemp3 + 1.0; if (Gtemp3 > 1)
Gtemp3 = Gtemp3 - 1.0;
Btemp3 = H-1.0/3.0;
if (Btemp3 < 0) Btemp3 = Btemp3 + 1.0; if (Btemp3 > 1)
Btemp3 = Btemp3 - 1.0;
if (6.0*Rtemp3 < 1)
R = temp1+(temp2-temp1)*6.0*Rtemp3;
else if (2.0*Rtemp3 < 1)
R = temp2;
else if (3.0*Rtemp3 < 2)
R = temp1+(temp2-temp1)*((2.0/3.0)-Rtemp3)*6.0;
else
R = temp1;
if (6.0*Gtemp3 < 1)
G = temp1+(temp2-temp1)*6.0*Gtemp3;
else if (2.0*Gtemp3 < 1)
G = temp2;
else if (3.0*Gtemp3 < 2)
G = temp1+(temp2-temp1)*((2.0/3.0)-Gtemp3)*6.0;
else
G = temp1;
if (6.0*Btemp3 < 1)
B = temp1+(temp2-temp1)*6.0*Btemp3;
else if (2.0*Btemp3 < 1)
B = temp2;
else if (3.0*Btemp3 < 2)
B = temp1+(temp2-temp1)*((2.0/3.0)-Btemp3)*6.0;
else
B = temp1;
}
R *= 255;
B *= 255;
G *= 255;
return color((int)R, (int)G, (int)B);
}
color toRGB(float H, float S, float L, float A) {
float R = 0, G = 0, B = 0;
H /= 360;
S /= 100;
L /= 100;
float temp1 = 0, temp2 = 0, Rtemp3 = 0, Gtemp3 = 0, Btemp3 = 0;
if (S == 0) {
R = L;
G = L;
B = L;
}
else {
if (L < 0.5) temp2 = L*(1.0+S); else if (L >= 0.5)
temp2 = L+S-L*S;
temp1 = 2.0*L-temp2;
Rtemp3 = H+1.0/3.0;
if (Rtemp3 < 0) Rtemp3 = Rtemp3 + 1.0; if (Rtemp3 > 1)
Rtemp3 = Rtemp3 - 1.0;
Gtemp3 = H;
if (Gtemp3 < 0) Gtemp3 = Gtemp3 + 1.0; if (Gtemp3 > 1)
Gtemp3 = Gtemp3 - 1.0;
Btemp3 = H-1.0/3.0;
if (Btemp3 < 0) Btemp3 = Btemp3 + 1.0; if (Btemp3 > 1)
Btemp3 = Btemp3 - 1.0;
if (6.0*Rtemp3 < 1)
R = temp1+(temp2-temp1)*6.0*Rtemp3;
else if (2.0*Rtemp3 < 1)
R = temp2;
else if (3.0*Rtemp3 < 2)
R = temp1+(temp2-temp1)*((2.0/3.0)-Rtemp3)*6.0;
else
R = temp1;
if (6.0*Gtemp3 < 1)
G = temp1+(temp2-temp1)*6.0*Gtemp3;
else if (2.0*Gtemp3 < 1)
G = temp2;
else if (3.0*Gtemp3 < 2)
G = temp1+(temp2-temp1)*((2.0/3.0)-Gtemp3)*6.0;
else
G = temp1;
if (6.0*Btemp3 < 1)
B = temp1+(temp2-temp1)*6.0*Btemp3;
else if (2.0*Btemp3 < 1)
B = temp2;
else if (3.0*Btemp3 < 2)
B = temp1+(temp2-temp1)*((2.0/3.0)-Btemp3)*6.0;
else
B = temp1;
}
R *= 255;
B *= 255;
G *= 255;
return color((int)R, (int)G, (int)B, (int)A);
}
}
Processing: Combining city masks and paintings to create final images
PImage painting;
PImage drawing;
int index = 17;
int savedIndex = -1;
String file = "../Watercolor_JustinLivi/paintings/painting-"+int(random(400))+"_a.png";
ArrayList used = new ArrayList();
void setup() {
size(1700,1700);
reload();
}
void draw() {
}
void keyPressed() {
if (key == 'b' || key == 'B') {
index--;
if(index<0) index = 365; reload(); } if (key == 'n' || key == 'N') { index++; if(index >= 366) index = 0;
reload();
}
if (key == 's' || key == 'S') {
String filename = "renders/render"+index+".png";
saveFrame(filename);
if(savedIndex == index)
used.remove(index);
used.add(index, file);
savedIndex = index;
}
if (key == 'r' || key == 'R') {
reload();
}
}
void reload() {
background(255);
String prevFile = file;
while(used.contains(file) || prevFile.equals(file)) {
if(round(random(1)) == 1)
file = "../Watercolor_JustinLivi/paintings/painting-"+int(random(400))+"_a.png";
else
file = "../Watercolor_JustinLivi/paintings/painting-"+int(random(400))+"_b.png";
}
println("drawing"+index+".png + "+ file);
painting = loadImage(file);
drawing = loadImage("../city_generator/drawings/drawing"+index+".png");
drawing.filter(INVERT);
painting.mask(drawing);
image(painting, 0, 0);
}
Javascript/Basil.js: Create final Indesign/PDF file
#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";
var StringData = b.loadString("data.txt");
var data = b.loadString('data.txt').split("\n");
var side = 7.5*72;
var img;
function parseData(texts) {
var hourlyData = [];
var hours = texts.split("-");
hourlyData.push([hours[0]]);
for(var i=1; i<hours.length; i++)
hourlyData.push(hours[i].split("&"));
return hourlyData;
}
function getMetaData(hourlyData){
var info = [];
info.push(hourlyData[0][0]);
var texts = 0;
var chars = 0;
var atts = 0;
for(var i=1; i<hourlyData.length; i++) {
texts += parseInt(hourlyData[i][0]);
chars += parseInt(hourlyData[i][1]);
atts += parseInt(hourlyData[i][2]);
}
info.push(texts);
info.push(chars);
info.push(atts);
return info;
}
function setup() {
b.clear (b.doc());
b.noStroke();
img = b.image("dedication_s.png", 0, 0, side, side);
b.fill(255,255,255);
b.textSize(12);
b.textFont("Avenir","Light");
b.textAlign(Justification.CENTER_ALIGN);
b.text("for nicole", 0, side/2-8, side, 16);
// b.fill(175,175,175);
// b.textSize(13);
// b.text("special thanks to", 0, side/2-58, side, 16);
// b.textSize(10);
// b.text("golan levin", 0, side/2-8, side, 16);
// b.text("justin livi", 0, side/2+12, side, 16);
// b.text("adam knuckey", 0, side/2+32, side, 16);
return
for(var i=0; i<data.length; i++) {
b.addPage();
var date = getMetaData(parseData(data[i]))[0].split(",")[0].split(" ");
var date_space = 10;
b.fill(175,175,175);
var tbh = 30;
b.textSize(tbh-5);
b.textFont("Avenir","Light");
b.textAlign(Justification.RIGHT_ALIGN);
b.text(date[0].toUpperCase().substring(0,3), 0, side/2-tbh/2, side/2-date_space/2, tbh);
b.textFont("Avenir","Black");
b.textAlign(Justification.LEFT_ALIGN);
b.text(date[1], side/2+date_space/2, side/2-tbh/2, side/2, tbh);
var y = side-72;
var iconHeight = 15;
var chatWidth = iconHeight*1.6;
var leftSpace = 5;
var typeX = chatWidth+leftSpace+chatWidth*1.5;
var clipX = typeX+chatWidth+leftSpace+chatWidth*2;
var totalWidth = clipX + chatWidth*0.55 + leftSpace + chatWidth*2;
var x = side/2-totalWidth/2;
b.textSize(10);
b.fill(220,220,220);
b.textFont("Avenir","Black");
img = b.image("chat.png", x, y, chatWidth, iconHeight);
b.text(getMetaData(parseData(data[i]))[1], x+chatWidth+leftSpace, y+1.5, chatWidth*1.5, 15);
img = b.image("type.png", x+ typeX, y+1.5, chatWidth, iconHeight*.8);
b.text(getMetaData(parseData(data[i]))[2], x+typeX+chatWidth+leftSpace, y+1.5, chatWidth*2, 15);
img = b.image("clip.png", x+ clipX, y+1.5, chatWidth*0.55, iconHeight*.8);
b.text(getMetaData(parseData(data[i]))[3], x+clipX+chatWidth*0.55+leftSpace, y+1.5, chatWidth*2, 15);
b.addPage();
img = b.image("renders/render"+i+".png", 0, 0, side, side);
}
}
b.go();