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/> */




