====== 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]; }