In Java, how can I write a generative formula?
How can we...?
You can generate a function dynamically with the Function constructor in p5.js.
Generative formula that generates generative art?
I wrote a JavaScript function dynamically in this article. And you can run the code.
How about in Processing? In Java, how do we generate a function dynamically?
'Interface'? No. 'Reflection'? Maybe no.
I think I need to take it easy.
The program code in Java is only a text file. So we can cook it whatever we like!
So I thought.
I thought that I can write some shell script that writes Java class code as a text file.
shell script --(write formula)--> Formula.class
Then I can use that Formula.class in Vector field calculation.
A drawing class that has a Formula.class.
Draw.class ◇--- Formula.class
But I couldn't write a shell script that generates formula.
So I decided to write a Java code that generates formula and prints it to STDOUT.
And I wrote a shell script that runs Java code and redirects STDOUT to Formula.class.
And so, I made that shell script runs Draw.class after formula generation.
Implementation in Processing.
I wrote these codes in this directory structure.
run.sh |- Draw/ | |- Draw.pde | |- Formula.pde | |- Generate/ |- Generate.pde
And here are my example codes.
run.sh
#!/bin/bash export DISPLAY=:0 pathGenerate="/home/deconbatch/somedir/Generate" pathDraw="/home/deconbatch/somedir/Draw" formulaClass="Formula.pde" cd "${pathGenerate}" ifsBackup=$IFS IFS=$'\n' stdout=($(/home/deconbatch/processingdir/processing-java --force --sketch=${pathGenerate}/ --run)) IFS=${ifsBackup} echo "${stdout[0]}" > ${pathDraw}/${formulaClass} echo "${stdout[1]}" >> ${pathDraw}/${formulaClass} echo "${stdout[2]}" >> ${pathDraw}/${formulaClass} cd "${pathDraw}" /home/deconbatch/processingdir/processing-java --force --sketch=${pathDraw}/ --run "${stdout[1]}"
Formula.pde
// // An empty file that has writable permission //
Draw.pde
/** * Draw a Vector field with generated formula in Formula.pde * * @author @deconbatch * @version 0.1 * Processing 3.2.1 * created 2019.09.20 * */ void setup() { size(980, 605); colorMode(HSB, 360, 100, 100, 100); smooth(); noLoop(); } void draw() { Formula fm = new Formula(); int lineMax = 20000; float plotMult = 4; float plotDiv = 0.0002; float initHue = random(360); background(0.0, 0.0, 90.0, 100.0); noStroke(); for (int lineCnt = 0; lineCnt < lineMax; ++lineCnt) { float xPrev = random(0.025, 0.975); float yPrev = random(0.025, 0.975); float xCurr = xPrev; float yCurr = yPrev; float lineRatio = map(lineCnt, 0, lineMax, 0.0, 1.0); float baseHue = initHue + floor(((xPrev * yPrev) * 10000.0) % 4.0) * 20.0; float baseSiz = 0.5 + lineRatio; int plotMax = 200 + floor(lineRatio * 400); for (int plotCnt = 0; plotCnt < plotMax; ++plotCnt) { float plotRatio = map(plotCnt, 0, plotMax, 0.0, 1.0); // vector field with generated formula xCurr += plotDiv * cos(fm.calc(yPrev, xPrev) * plotMult); yCurr += plotDiv * sin(fm.calc(xPrev, yPrev) * plotMult); xPrev = xCurr; yPrev = yCurr; float pHue = (baseHue + plotRatio * 30.0) % 360.0; float pSat = map(plotRatio, 0.0, 1.0, 0.0, 50.0); float pBri = map(plotRatio, 0.0, 1.0, 90.0, 20.0); float pSiz = sin(PI * plotRatio) * baseSiz; fill(pHue, pSat, pBri, 20.0); ellipse(xCurr * width, yCurr * height, pSiz, pSiz); } } casing(); // write generated formula fill(0.0, 0.0, 0.0, 100.0); textAlign(CENTER); textSize (16); text(args[0], width * 0.5, height - 10.0); saveFrame("frames/####.png"); exit(); } /** * casing : draw fancy casing */ private void casing() { fill(0.0, 0.0, 0.0, 0.0); strokeWeight(60.0); stroke(0.0, 0.0, 0.0, 100.0); rect(0.0, 0.0, width, height); strokeWeight(50.0); stroke(0.0, 0.0, 100.0, 100.0); rect(0.0, 0.0, width, height); noStroke(); noFill(); }
Generate.pde
/** * Generate formula and print it to STDOUT * * @author @deconbatch * @version 0.1 * Processing 3.2.1 * created 2019.09.20 * */ void setup() { size(720, 720); // dummy // parameters ArrayList<string> prm = new ArrayList<string>() { { add("_a"); add("_b"); } }; // operators ArrayList<string> ope = new ArrayList<string>() { { add(" + "); add(" - "); add(" * "); add(" % "); } }; // Math functions ArrayList<string> fnc = new ArrayList<string>() { { add("sin(%s)"); add("cos(%s)"); add("asin(%s)"); add("acos(%s)"); add("atan(%s)"); add("exp(%s)"); add("sqrt(%s)"); add("log(%s)"); add("pow(%s, 2)"); add("pow(%s, -2)"); } }; String formula = String.format(fnc.get(floor(random(fnc.size()))), prm.get(floor(random(prm.size())))); int fncCnt = floor(random(5, 12)); for (int i = 0; i < fncCnt; i++) { formula += ope.get(floor(random(ope.size()))); formula += String.format(fnc.get(floor(random(fnc.size()))), prm.get(floor(random(prm.size())))); } // print Java class code. println("public class Formula { public float calc(float _a, float _b) {return "); println(formula); println(";}}"); exit(); }
/* Copyright (C) 2019- deconbatch This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/> */