The node garden technique creates a jewel box.
Digital art of beautiful geometrical shapes.
It's a creative coding digital art animation. The code is written in the 'Processing' programming language.
When I was playing with the code using the 'node garden' technique, I found it can draw an interesting shape with lines between some nodes. And I built it into jewel box style digital art.
But I wonder a still image possibly be better than animation for this digital art?
This code does not display any images on the screen but just generates image files. You can make an animation with these files.
The 'Processing' code example.
Please feel free to use this examplse code under the terms of the GPL. To see other works based on my code is my pleasure. And my honor.
/**
* Desert Rose.
* draw desert roses in the jewel box.
*
* Processing 3.2.1
* @author @deconbatch
* @version 0.1
* created 0.1 2019.03.31
*/
void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
smooth();
noLoop();
}
void draw() {
int frameCntMax = 24 * 6; // for 24fps x 6sec animation
int colCntMax = 4;
float gap = 2.0;
float colWidth = (width - (colCntMax + 1) * gap) * 1.0 / colCntMax;
float hueBase = random(360.0);
float hueDiv = 90.0;
// shape parameters
float[][] pCorner = new float[colCntMax][colCntMax];
float[][] pJoint = new float[colCntMax][colCntMax];
float[][] pSoft = new float[colCntMax][colCntMax];
float[][] pRotate = new float[colCntMax][colCntMax];
float[][] pHue = new float[colCntMax][colCntMax];
// make colCntMax x colCntMax cells
background(0.0, 0.0, 60.0, 100.0);
blendMode(BLEND);
for (int colCnt = 0; colCnt < colCntMax; ++colCnt) {
for (int rowCnt = 0; rowCnt < colCntMax; ++rowCnt) {
pCorner[colCnt][rowCnt] = random(1.0);
pJoint[colCnt][rowCnt] = random(1.0);
pSoft[colCnt][rowCnt] = random(1.0);
pRotate[colCnt][rowCnt] = random(1.0);
pHue[colCnt][rowCnt] = ((colCnt + rowCnt) % 3) * hueDiv * 0.25
+ ((colCnt + rowCnt * colCntMax) * 1.0 / (colCntMax * colCntMax - 1)) * hueDiv * 0.5;
fill((hueBase + pHue[colCnt][rowCnt] + 270.0) % 360.0, 40.0, 15.0, 100.0);
rect(gap + (gap + colWidth) * colCnt, gap + (gap + colWidth) * rowCnt, colWidth, colWidth);
}
}
noFill();
// for drawing animation
blendMode(SCREEN);
for (int frameCnt = 1; frameCnt < frameCntMax; ++frameCnt) {
float frameRatio = map(frameCnt, 1, frameCntMax, 0.0, 1.0);
for (int colCnt = 0; colCnt < colCntMax; ++colCnt) {
for (int rowCnt = 0; rowCnt < colCntMax; ++rowCnt) {
float roseX = gap + colWidth * 0.5 + (gap + colWidth) * colCnt;
float roseY = gap + colWidth * 0.5 + (gap + colWidth) * rowCnt;
int roseCorners = floor(map(pCorner[colCnt][rowCnt], 0.0, 1.0, 2.5, 7.5));
int roseJoints = floor(map(pJoint[colCnt][rowCnt], 0.0, 1.0, 2.0, 6.0));
float roseSize = colWidth * map(pJoint[colCnt][rowCnt], 0.0, 1.0, 0.6, 0.4);
float roseSoft = map(pSoft[colCnt][rowCnt], 0.0, 1.0, 0.02, 0.15);
float roseHue = hueBase + pHue[colCnt][rowCnt];
pushMatrix();
translate(roseX, roseY);
rotate(HALF_PI * pRotate[colCnt][rowCnt]);
drawRose(roseCorners, roseJoints, roseSize, roseSoft, roseHue, frameRatio);
popMatrix();
}
}
saveFrame("frames/" + String.format("%04d", frameCnt) + ".png");
}
// make 24fps x 1sec no moving images
for (int frameCnt = frameCntMax; frameCnt < frameCntMax + 24 * 1.5; ++frameCnt) {
saveFrame("frames/" + String.format("%04d", frameCnt) + ".png");
}
// make twitter thumbnail image
saveFrame("frames/0000.png");
exit();
}
/**
* drawRose : draw rose image.
* @param _corners : corner count of rose.
* @param _joints : joint count of rose.
* @param _roseSize : size of rose.
* @param _softness : 0.02 - 0.2 : shape softness.
* @param _hueBase : hue value of rose.
* @param _drawRatio : 0.0 - 1.0 : drawing ratio of the total.
* too many parameters!
*/
private void drawRose(int _corners, int _joints, float _roseSize, float _softness, float _hueBase, float _drawRatio) {
// make node list
NodeList[] jointNodes = new NodeList[_joints];
for (int jointCnt = 0; jointCnt < _joints; ++jointCnt) {
float jointRatio = map(jointCnt, 0, _joints, 0.0, 1.0);
jointNodes[jointCnt] = new NodeList();
for (int cornerCnt = 0; cornerCnt < _corners; ++cornerCnt) {
float cornerRatio = map(cornerCnt, 0, _corners, 0.0, 1.0);
float shapeFactor = sin(TWO_PI * (cornerRatio + _drawRatio));
float centerSize = noise(_hueBase * _corners + _joints) * 0.6; // random center hole size
float direction = noise(_hueBase * _joints + _corners) < 0.5 ? 1.0 : -1.0; // random rotate direction
float nRadius = _roseSize * (centerSize + (1.0 - centerSize) * jointRatio);
float nRadian = direction * TWO_PI * (cornerRatio + map(shapeFactor, -1.0, 1.0, -_softness, _softness));
float nX = nRadius * cos(nRadian);
float nY = nRadius * sin(nRadian);
Node joint = new Node(new PVector(nX, nY));
jointNodes[jointCnt].add(joint);
}
}
// draw lines with node lists
for (int jointCnt = 0; jointCnt < _joints - 1; ++jointCnt) {
float jointRatio = map(jointCnt, 0, _joints - 1, 0.0, 1.0);
jointNodes[jointCnt].drawLines(jointNodes[jointCnt + 1], _hueBase, jointRatio, 5.0 / (_corners + _joints));
}
}
/**
* Keep node information.
* @param _position : node position
*/
class Node {
PVector position;
Node(PVector _position) {
position = new PVector();
position.set(_position);
}
}
/**
* Keep nodes in one joint.
* number of nodes = number of corners.
* draw lines from some joint to other joint.
* @param _otherNodes : draw lines to this nodes.
* @param _hueBase : hue value of lines.
* @param _jointRatio : 0.0 - 1.0 : joint ratio of the total. from center to outer.
* @param _density : 0.0 - 1.0 : to control stroke weight. bigger = thick.
*/
import java.util.Iterator;
class NodeList extends ArrayList<Node> {
void drawLines(NodeList _otherNodes, float _hueBase, float _jointRatio, float _density) {
Iterator<Node> itNode = this.iterator();
Iterator<Node> itOther = _otherNodes.iterator();
strokeWeight(0.2 + _jointRatio * map(_density, 0.0, 1.0, 0.0, 1.2));
stroke(
(_hueBase + map(_jointRatio, 0.0, 1.0, -15.0, 15.0)) % 360.0,
60.0 - 20.0 * _jointRatio,
50.0 - 20.0 * _jointRatio,
100.0
);
beginShape();
while (itNode.hasNext()) {
Node node = itNode.next();
vertex(node.position.x, node.position.y);
if ((itOther.hasNext())) {
Node other = itOther.next();
vertex(other.position.x, other.position.y);
}
}
endShape(CLOSE);
}
}
/*
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/>
*/