Mathematical Morphogenesis: De Jong Attractors on Polar Coordinates
A Unique Approach to De Jong Attractors
This generative artwork was created using Processing.
I wanted to explore the visual possibilities of mapping De Jong attractors onto polar coordinates. While there are many ways to implement polar transformations, I opted for the following approach:
// De Jong Attractor formula
float currX = sin(TWO_PI * djA * prevY) - cos(TWO_PI * djB * prevX);
float currY = sin(TWO_PI * djC * prevX) - cos(TWO_PI * djD * prevY);
// Mapping to polar coordinates
float dX = width * 0.15 * currX;
float dY = height * 0.15 * currX;
float dR = rBase * currY;
float px = dX * cos(dR) - dY * sin(dR);
float py = dY * cos(dR) + dX * sin(dR);
Managing Convergence
There is a convergence problem in drawing attractors. I tried to avoid this by changing the attractor parameter in recurrence.
// Re-randomizing to prevent convergence (triggered at 60% of max points)
if (pCnt == floor(pMax * 0.6)){
djA = random(-1.0, 1.0);
djB = 1.0;
djC = random(-1.0, 1.0);
djD = 1.0;
}
Visual Variations
1. The "Ball" Formation
float px = width * sin(_x * _y) * cos(_r * _x);
float py = height * cos(_x * _y) * sin(_r * _y);
2. The "Square" Formation
float px = width * sin(_x) * cos(PI * _x);float py = height * cos(_y) * sin(PI * _y);
3. The "Cloth" Texture
float px = width * sin(_y) * cos(PI * _x);float py = height * cos(_x) * sin(PI * _y);
The Processing Example Code
This code is designed for offline rendering; it saves high-quality frames directly to your /frames directory rather than rendering to the screen in real-time.
This code is released under the GPL license. Please feel free to experiment with it—I’m always honored and excited to see new works inspired by my implementations.
/**
* Just Another Nervous Wreck.
*
* A creative coding that draws De Jong attractors on polar coordinates.
*
* Processing 3.5.3
* @author @deconbatch
* @version 0.1
* created 0.1 2020.01.26
*/
void setup() {
size(980, 980);
colorMode(HSB, 360, 100, 100, 100);
rectMode(CENTER);
smooth();
noLoop();
}
void draw() {
int frmMax = 3;
float hueBase = random(360);
translate(width / 2, height / 2);
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
blendMode(DIFFERENCE);
background(0.0, 0.0, 90.0, 100.0);
hueBase += 90.0;
pushMatrix();
rotate(random(PI));
drawWreck(hueBase);
popMatrix();
blendMode(BLEND);
casing(hueBase);
saveFrame("frames/" + String.format("%04d", frmCnt + 1) + ".png");
}
exit();
}
/**
* drawWreck : draws De Jong attractors on polar coordinates
* @param _hueBase : drawing color.
*/
void drawWreck(float _hueBase) {
float hueBase = _hueBase;
// De Jong Attractor parameters
float djA = 1.0;
float djB = random(-1.0, 1.0);
float djC = 1.0;
float djD = random(-1.0, 1.0);
float prevX = random(-2.0, 2.0);
float prevY = random(-2.0, 2.0);
float rBase = random(0.2, 0.5) * HALF_PI;
float sBase = 0.25;
int pMax = 12000000;
noStroke();
for (int pCnt = 0; pCnt < pMax; pCnt++) {
// for avoid convergence (as much as possible)
if (pCnt == floor(pMax * 0.6)){
djA = random(-1.0, 1.0);
djB = 1.0;
djC = random(-1.0, 1.0);
djD = 1.0;
hueBase += 30.0;
}
// De Jong Attractors
float currX = sin(TWO_PI * djA * prevY) - cos(TWO_PI * djB * prevX);
float currY = sin(TWO_PI * djC * prevX) - cos(TWO_PI * djD * prevY);
// polar coordinates
float dX = width * 0.15 * currX;
float dY = height * 0.15 * currX;
float dR = rBase * currY;
float px = dX * cos(dR) - dY * sin(dR);
float py = dY * cos(dR) + dX * sin(dR);
float ps = sBase * (1.0 + dist(px, py, 0.0, 0.0) * 2.0 / width);
fill(hueBase % 360.0, 40.0, 15.0, 100.0);
ellipse(px, py, ps, ps);
prevX = currX;
prevY = currY;
}
}
/**
* casing : draw fancy casing
* @param _hueBase : casing color.
*/
private void casing(float _hueBase) {
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(40.0);
stroke(_hueBase, 60.0, 20.0, 100.0);
rect(0.0, 0.0, width, height);
strokeWeight(30.0);
stroke(0.0, 0.0, 95.0, 100.0);
rect(0.0, 0.0, width, height);
}
/*
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/>
*/
Gallery: Further Examples
Here are a few more outputs generated with this specific algorithm.







