====== Steve Wang's Generative Flower ======
by [[steve-wang|Steve Wang]]
We wrote the code in [[https://p5js.org/|p5.js]] and the code was written in [[https://en.wikipedia.org/wiki/JavaScript|Javascript]]
//A note from Dr. Bell: try looking at this at different times of day. It varies according to time.//
===== Code ====
This is the code that was used.
//3 improvements made
//do allignment
var time = 0;
let colors = ["black", "gray", "red", "white"];
let shapes = ["ellipse", "rect", "triangle"];
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
move(xDistance, yDistance) {
return new Point(this.x + xDistance, this.y + yDistance);
}
moveByAngle(angle, distance) {
let r = (angle * Math.PI) / 180;
return new Point(
this.x + distance * Math.sin(r),
this.y + distance * Math.cos(r)
);
}
}
class Leaf{
constructor(positionOfLeaf,rotation){
this.leafXY=positionOfLeaf;
this.rotation=rotation
}
draw(){
translate(this.leafXY.x,this.leafXY.y)
rotate(this.rotation)
bezier(0,0, 0-47, 0, 0-35, 0+40, 0, 0);
line(0,0,0-34,0+16);
line(0-8,0+0.5,0-12,0+5.5);
line(0-6,0+6.5,0-12,0+5.5);
line(0-17,0+3,0-20,0+9);
line(0-13,0+12,0-20,0+10);
line(0-23,0+5,0-27,0+12.8);
line(0-20,0+16,0-27,0+12.8);
resetMatrix()
}
}
let canvasSize = new Point(1700, 800);
class Star {
constructor() {
this.starX = randomRange(0, canvasSize.x*5);
this.starY = randomRange(0, canvasSize.y*5);
this.starColor = randomRange(190, 255);
}
draw() {
scale(0.6)
this.starColor = randomRange(190, 255);
fill(color(this.starColor, this.starColor, 0));
noStroke();
circle(28 + this.starX, 39 + this.starY, 27);
triangle(
18 + this.starX,
29 + this.starY,
28 + this.starX,
14 + this.starY,
38 + this.starX,
29 + this.starY
);
triangle(
18 + this.starX,
29 + this.starY,
3 + this.starX,
39 + this.starY,
18 + this.starX,
49 + this.starY
);
triangle(
18 + this.starX,
49 + this.starY,
28 + this.starX,
64 + this.starY,
38 + this.starX,
49 + this.starY
);
triangle(
38 + this.starX,
49 + this.starY,
53 + this.starX,
39 + this.starY,
38 + this.starX,
29 + this.starY
);
resetMatrix();
}
}
class RandomShape {
constructor(x) {
this.position = x;
this.shape = pick(shapes);
this.color = pick(colors);
this.size = randomRange(10, 100);
this.width = this.size;
this.height = this.size;
}
draw() {
if (this.shape == "ellipse") {
fill(this.color);
ellipseMode(CENTER);
ellipse(this.position.x, this.position.y, this.width, this.height);
}
if (this.shape == "rect") {
fill(this.color);
ellipseMode(CENTER);
rect(this.position.x, this.position.y, this.width, this.height);
}
if (this.shape == "triangle") {
fill(this.color);
ellipseMode(CENTER);
triangle(
this.position.x,
this.position.y,
this.position.x + this.width / 2,
this.position.y + this.height,
this.position.x + this.width,
this.position.y
);
}
}
}
function pick(inputArray) {
return inputArray[Math.floor(inputArray.length * Math.random())];
}
function randomRange(min, max) {
return min + (max - min) * Math.random();
}
function setup() {
time= hour();
createCanvas(canvasSize.x, canvasSize.y);
frameRate(20);
}
function buildArray(n, fillFunction) {
let outputArray = [];
for (let i = 0; i < n; i++) {
outputArray.push(fillFunction(i));
}
return outputArray;
}
function gridPattern(nOfRows, nInRow, itemX, itemY, startX, startY) {
let yP = startY;
let returnA = [];
for (let i = 0; i < nOfRows; i++) {
yP += itemY + 2;
for (let b = 0; b < nInRow[i]; b++) {
returnA.push(new Point((itemX + 5) * b + startX, yP));
}
}
return returnA;
}
function randomPattern(nOfItems, minX, minY, maxX, maxY) {
let returnA = [];
for (let i = 0; i < nOfItems; i++) {
returnA.push(new Point(randomRange(minX, maxX), randomRange(minY, maxY)));
}
return returnA;
}
function crossPatterns(nOfCrosses, crossPosition, widthOfCross, shapeSize) {
let realShapeSize = shapeSize + 2;
let returnArray = [];
let angle = 0;
for (let i = 0; i < nOfCrosses; i++) {
returnArray.push(new Point(crossPosition[i].x, crossPosition[i].y));
for (let b = 0; b < 4; b++) {
angle += 90;
if (b == 0) {
angle = 0;
}
for (let a = 0; a <= widthOfCross[i]; a++) {
returnArray.push(
crossPosition[i].moveByAngle(angle, realShapeSize * a)
);
}
}
}
return returnArray;
}
function circularPositions(nOfCircle, positions, nOfShapes, cSize) {
let arrayToReturn = [];
for (let i = 0; i < nOfCircle; i++) {
let positionArray = buildArray(
nOfShapes[i],
(b) => new Point(positions[i].x, positions[i].y)
);
let testCircle = circlePattern(cSize, positionArray);
arrayToReturn = arrayToReturn.concat(testCircle);
}
return arrayToReturn;
}
function circlePattern(cSize, cPosition) {
let angle = 360 / cPosition.length;
return cPosition.map((p, i) => {
return p.moveByAngle(i * angle, cSize);
});
}
function duplicateArray(times, arrayToCopy) {
let returnArray = [];
for (let i = 0; i < times; i++) {
returnArray.push(arrayToCopy);
}
return returnArray;
}
//Replace in arrow function in 156
let reducer = (previousValue, currentValue) => previousValue + currentValue;
function addingWholeArray(arrayToAdd) {
return arrayToAdd.reduce(reducer);
}
let i = 0;
class fantasticFlower {
constructor(flowerXY,flowerNumberCounter) {
this.flowerX = flowerXY.x;
this.flowerY = flowerXY.y;
this.flowerColor = pick(colors);
this.petalsColor = pick(colors);
this.flowerSize = randomRange(10, 45);
this.petalWidth = randomRange(10, 30);
this.petalHeight = randomRange(this.flowerSize-35, 55);
if (flowerNumberCounter==1){
this.petalWidth *= 11;
this.petalHeight *= 15;
this.petalsColor = "yellow";
this.flowerColor = "orange";
this.flowerX = randomRange(100,800);
this.flowerY = randomRange(200,400);
}
if (flowerNumberCounter==2){
this.flowerSize *=1
this.petalWidth *= 6;
this.petalHeight *= 9;
this.petalsColor = "magenta";
this.flowerColor = "blue";
this.flowerX = randomRange(810,1600);
this.flowerY = randomRange(200,400);
}
this.nOfPetals = randomRange(1, 10);
this.nOfLeaves=randomRange(1, 5)
this.counterForLeafColor=1
this.counterForPetalHeight=1
this.leafXY=new Point(this.flowerX+10,this.flowerY+6)
this.stemLeaf=[]
this.stemSize=0
this.yToAddToLeaf=0
this.BellLeaf=[new Leaf(new Point(this.flowerX+35,this.flowerY+25),0), new Leaf(new Point(this.flowerX-30,this.flowerY+25),-90)]
this.leafToConcat=[]
for (let i = 0; i < this.nOfLeaves; i++) {
if (i%2==0){this.yToAddToLeaf=30*i;
this.BellLeaf=this.BellLeaf.concat([new Leaf(new Point(this.flowerX+35,this.flowerY+25+this.yToAddToLeaf),0)])}
else{
this.leafToConcat=[ new Leaf(new Point(this.flowerX-30,this.flowerY+25+this.yToAddToLeaf),-90)]}
this.BellLeaf=this.BellLeaf.concat(this.leafToConcat)
}
if (this.nOfLeaves>2){
this.stemSize=this.petalHeight*4+120}
else{this.stemSize=this.petalHeight*3}
for (let i = 0; i < this.counterForLeafColor; i++) {
if(this.flowerColor==this.petalsColor){this.petalsColor=pick(colors);this.counterForLeafColor+=1}}
if (this.stemSize<50){this.stemSize=150}
this.stemWidth=this.stemSize/45
if (flowerNumberCounter==1){
this.stemWidth*=1.1
}
if (flowerNumberCounter==2){
this.stemWidth*=1.1
}
}
draw() {
this.BellLeaf.forEach(x=>x.draw())
fill("green");
rect(this.flowerX, this.flowerY, this.stemWidth,this.stemSize);
resetMatrix()
i += 1
translate(this.flowerX, this.flowerY);
rotate(i);
fill(this.petalsColor);
let petalsRotate = 360 / this.nOfPetals;
for (let a = 0; a < this.nOfPetals; a++) {
rotate(petalsRotate);
ellipse(0, -10, 10 + this.petalWidth, 20 + this.petalHeight);
}
fill(this.flowerColor);
circle(0, 0, this.flowerSize);
circle(0, 0, this.flowerSize - 10);
let drawLeaf=new Leaf(new Point(this.flowerX,this.flowerY),0)
drawLeaf.draw();
resetMatrix();
}
}
function arrayRandomPicker(arraytoPickFrom1, arraytoPickFrom2) {
if (arraytoPickFrom1.length != arraytoPickFrom2.length) {
return "The legnth of both arrays are not the same", false;
}
let returnArray = [];
let pick = 0;
for (let b = 0; b < arraytoPickFrom1.length; b++) {
pick = randomRange(0, 2);
if (pick == 0) {
returnArray.push(arraytoPickFrom1[b]);
} else {
returnArray.push(arraytoPickFrom2[b]);
}
}
return returnArray;
}
function iInLoopedArray(shorterArray, longerArray) {
let returnArray = [];
for (let a = 0; a < longerArray.length; a++) {
returnArray.push(shorterArray[a % shorterArray.length]);
}
return returnArray;
}
class FlowerField {
constructor(patternName, positionArray, itemSize, widthArray) {
if (positionArray.length != widthArray.length) {
if (positionArray.length < widthArray.length) {
this.widthArray = widthArray;
this.positionArray = iInLoopedArray(positionArray, widthArray);
} else {
this.widthArray = iInLoopedArray(widthArray, positionArray);
this.positionArray = positionArray;
}
} else {
this.positionArray = positionArray;
this.widthArray = widthArray;
}
this.itemSize = itemSize;
this.newPositions = this.adjustPosition(
patternName,
canvasSize,
this.positionArray,
this.itemSize,
this.widthArray
);
this.shapesXY = buildArray(this.newPositions.length, this.XYSet);
this.shapesNow = this.shapesXY.map((x) => new RandomShape(x));
this.flowersXY = buildArray(this.newPositions.length, this.XYSet);
this.flowersArray = this.shapesXY.map((x) => new fantasticFlower(x));
this.flowersArray.forEach((b, i) => {
this.flowersArray[i].flowerX = this.newPositions[i].x;
});
this.flowersArray.forEach((b, i) => {
this.flowersArray[i].flowerY = this.newPositions[i].y;
});
this.shapesNow.forEach((b, i) => {
this.shapesNow[i].position = this.newPositions[i];
});
this.flowersArray = arrayRandomPicker(this.flowersArray, this.shapesNow);
return this.flowersArray;
}
help(patternName) {
console.log("patternHelp Output:");
console.log(
"If unsure what format to type arguments in here are the formats for arguments: (string, Point class, array filled with Point class, number, number, array)"
);
console.log(
"These are the instructions for:",
patternName,
"Instructions will alow you to understand what to type for each argument"
);
if (patternName.includes("cross")) {
console.log(
"(Specify Pattern name,totalItems(number), Positon of crosses, Position between each shape, itemSize, Width of cross"
);
} else if (patternName.includes("circle")) {
console.log(
"(Specify Pattern name, totalItems, Positon of circles, Position between the shapes that outline circle, itemSize, An array with the amount of items that will outline each circle"
);
} else if (patternName.includes("random")) {
console.log(
"(Specify Pattern name, totalItems, Invalid because random positions,Invalid because randomPosition, itemSize, Invalid because each item will be on their own"
);
} else if (patternName.includes("grid")) {
console.log(
"(Specify Pattern name, totalItems, where to start drawing grid (array with a point class), the size of each item (number), nO amount of items on each row"
);
} else {
console.log(
"Invalid pattern name: the only patterns are cross, circle, grid, random",
"End of pattenHelp"
);
return false;
}
return "End of pattenHelp";
}
adjustPosition(
patternName /*(string)*/,
canvasSize /*(Point class)*/,
midPoints /*(array filled with Point class)*/,
itemSize /*(number)*/,
PatternWidth /*(array)*/
) {
if (
patternName.includes("cross") ||
patternName.includes("circle") ||
patternName.includes("random") ||
patternName.includes("grid")
) {
if (patternName.includes("cross")) {
let nOfCrosses = midPoints.length;
let totalWidths = addingWholeArray(PatternWidth);
let shapeSize = itemSize;
let returnArray = [];
return crossPatterns(nOfCrosses, midPoints, PatternWidth, shapeSize);
}
if (patternName.includes("circle")) {
let arrayToReturn = [];
let shapeSize = itemSize;
let nOfCircle = midPoints.length;
let nOfShapes = PatternWidth;
console.log(nOfCircle);
let ps = circularPositions(
nOfCircle,
midPoints,
PatternWidth,
shapeSize
);
console.log(ps);
for (let b = 0; b < ps.length; b++) {
arrayToReturn = arrayToReturn.concat(ps[b]);
}
console.log(arrayToReturn);
return arrayToReturn;
}
if (patternName.includes("random")) {
let arrayToReturn = [];
for (let i = 0; i < midPoints.length; i++) {
let minXY = new Point(itemSize + 10, itemSize + 10);
let maxX = 0;
let maxY = 0;
maxX = itemSize;
maxY = itemSize;
if (itemSize > canvasSize.x || itemSize > canvasSize.y) {
if (itemSize > canvasSize.x) {
maxX = canvasSize.x;
}
if (itemSize > canvasSize.y) {
maxY = canvasSize.y;
}
}
let maxXY = new Point(canvasSize.x, canvasSize.y);
let arrayToJoin = randomPattern(
PatternWidth[i],
minXY.x,
minXY.y,
maxXY.x,
maxXY.y
);
arrayToReturn = arrayToReturn.concat(arrayToJoin);
}
return arrayToReturn;
}
if (patternName.includes("grid")) {
let arrayToReturn = [];
for (let i = 0; i < midPoints.length; i++) {
let rowNumber = PatternWidth[i];
let gridInfo = duplicateArray(rowNumber, PatternWidth[i]);
let itemXYsizes = new Point(itemSize, itemSize);
let startXY = new Point(midPoints[i].x, midPoints[i].y);
let arrayToJoin = gridPattern(
gridInfo.length,
gridInfo,
itemXYsizes.x,
itemXYsizes.y,
startXY.x,
startXY.y
);
arrayToReturn = arrayToReturn.concat(arrayToJoin);
}
return arrayToReturn;
} else {
console.log(
"Invalid patternName",
"If help needed please type: patternHelp(patternName)"
);
return false;
}
}
}
XYSet(i) {
return new Point(
randomRange(0, canvasSize.x),
randomRange(0, canvasSize.y)
);
}
}
class SkyColor{
constructor(time){
this.time=time
this.colorSet=0
this.starOrNot=""
}
draw(){
if (this.time>6 && this.time<17){this.colorSet=50*(this.time-6)}
else if (this.time>17){this.colorSet=225-(50*(this.time-17))}
else (this.colorSet=0)
if(this.time>21||this.time<6){this.starOrNot="yes"}
return [0,this.colorSet,this.colorSet,this.starOrNot]
}
star(){
this.starX = randomRange(0, canvasSize.x);
this.starY = randomRange(0, canvasSize.y);
this.starColor = randomRange(190, 255);
this.starColor = randomRange(190, 255);
fill(color(this.starColor, this.starColor, 0));
noStroke();
circle(28 + this.starX, 39 + this.starY, 27);
triangle(
18 + this.starX,
29 + this.starY,
28 + this.starX,
14 + this.starY,
38 + this.starX,
29 + this.starY
);
triangle(
18 + this.starX,
29 + this.starY,
3 + this.starX,
39 + this.starY,
18 + this.starX,
49 + this.starY
);
triangle(
18 + this.starX,
49 + this.starY,
28 + this.starX,
64 + this.starY,
38 + this.starX,
49 + this.starY
);
triangle(
38 + this.starX,
49 + this.starY,
53 + this.starX,
39 + this.starY,
38 + this.starX,
29 + this.starY
);
}
}
let nOfFlower=100
let flowersArray = buildArray(
nOfFlower,
(x) =>
new fantasticFlower(new Point(randomRange(0, 1700), randomRange(0, 800)),nOfFlower-x)
);
let starArray = buildArray(90, (x) => new Star());
function draw() {
let backgroundColor=new SkyColor(time);
let backgroundColor2=backgroundColor.draw()
background(backgroundColor2[0], backgroundColor2[1], backgroundColor2[2]);
if (backgroundColor2[3]=="yes"){
starArray.forEach((x) => x.draw());}
stroke(2);
flowersArray.forEach((x) => x.draw());
}
function shapeFromPoints(pointArray) {
beginShape();
pointArray.forEach((p) => vertex(p.x, p.y));
endShape(CLOSE);
}
function buildArray2(n, fillFunction) {
let outputArray = [];
for (let i = 0; i < n; i++) {
outputArray.push(fillFunction);
}
return outputArray;
}
function randomRange(min, max) {
return Math.floor(min + (max - min) * Math.random());
}
function head(array) {
return array.splice(0, 1)[0];
}
//Last item of array
function last(array) {
return array.splice(array.length - 1, 1)[0];
}