The many sine curves surround the circle.
Description of this creative coding animation.
This is a creative coding animation work made with the 'Processing'.
It draws many sine curves surround the circle with blendMode(SCREEN) and draw a black circle with blendMode(BLEND) on these to express the eclipse.
I pursued OOP in this code. Did I do this well? I think NO, it's TOO MUCH! I feel it's too difficult to balance on.
The 'Processing' example code.
Please feel free to use this example code under the terms of the GPL.
To see other works based on my code is my pleasure. And my honor.
* It's so slow to draw!
// Total Eclipse of the Heart. // @author @deconbatch // @version 0.4 // Processing 3.2.1 // 2018.07.21 /* WaveMaker ---------- */ public class WaveMaker { private Calculator ct; private float noiseStart; WaveMaker(Calculator ct) { this.ct = ct; noiseStart = random(100.0); } public void drawWave(float frequency, float frequencyRate,float phase) { noiseStart += 0.0005; for (float beltRate = 0.0; beltRate <= 1.0; beltRate += ct.beltRateDiv) { float noiseParam = noiseStart; ct.setFactor(frequency, frequencyRate, phase, beltRate); for (float radianRate = 0; radianRate <= 1.0; radianRate += ct.radianRateDiv) { plot(radianRate, noiseParam); noiseParam += 0.005; } } } private void plot(float radianRate, float noiseParam) { WaveParticle wp = ct.calcAll(radianRate, noiseParam); fill( (wp.hue + 360.0) % 360.0, wp.saturation, wp.brightness, 100.0 ); pushMatrix(); rotate(2.0 * PI * radianRate); ellipse( 0.0, wp.amplitude + height * 0.28, wp.size, wp.size ); popMatrix(); } } /* Abstract Calculator ---------- */ public abstract class Calculator { protected float radianRateDiv; protected float beltRateDiv; protected float frequency; protected float frequencyRate; protected float phase; protected float beltRate; protected float hueBase; protected WaveParticle wp; Calculator(float hueBase) { this.wp = new WaveParticle(); this.hueBase = hueBase; radianRateDiv = 1.0; beltRateDiv = 1.0; frequency = 1.0; frequencyRate = 1.0; phase = 0.0; beltRate = 1.0; } public void setFactor(float frequency, float frequencyRate, float phase, float beltRate) { this.frequency = frequency; this.frequencyRate = frequencyRate; this.phase = phase; this.beltRate = beltRate; } public WaveParticle calcAll(float radianRate, float noiseParam) { calcHue(radianRate, noiseParam); calcSaturation(radianRate, noiseParam); calcBrightness(radianRate, noiseParam); calcAmplitude(radianRate, noiseParam); calcSize(radianRate, noiseParam); return this.wp; } protected abstract void calcHue(float radianRate, float noiseParam); protected abstract void calcSaturation(float radianRate, float noiseParam); protected abstract void calcBrightness(float radianRate, float noiseParam); protected abstract void calcAmplitude(float radianRate, float noiseParam); protected abstract void calcSize(float radianRate, float noiseParam); } /* Concrete Calculators ---------- */ public class Chromosphere extends Calculator { Chromosphere(float hueBase) { super(hueBase); radianRateDiv = 0.0005; beltRateDiv = 0.05; } @Override protected void calcHue(float radianRate, float noiseParam) { wp.hue = hueBase + map(frequencyRate, 0.0, 1.0, 0.0, 30.0) + sin(2.0 * PI * noise(noiseParam)) * 15.0; // animate color with noise } @Override protected void calcSaturation(float radianRate, float noiseParam) { wp.saturation = 40.0; } @Override protected void calcBrightness(float radianRate, float noiseParam) { wp.brightness = map(frequencyRate, 0.0, 1.0, 1.0, 3.0) * sin(PI * (0.1 + 0.9 * radianRate)) // darker in center and end * sin(PI * map(beltRate, 0.0, 1.0, 0.1, 0.5)); // brighter with beltRate } @Override protected void calcAmplitude(float radianRate, float noiseParam) { wp.amplitude = setAmpBase() * sin(2.0 * PI * (-phase + frequency * radianRate)) // sine wave * sin(PI * map(beltRate, 0.0, 1.0, 0.1, 0.5)); // bigger wave with beltRate if (wp.amplitude < 0.0) { wp.amplitude = height * 2.0; // do not draw } } protected float setAmpBase() { return height * 0.08 * pow(map(frequencyRate, 0.0, 1.0, 1.0, 0.5), 2); } @Override protected void calcSize(float radianRate, float noiseParam) { wp.size = 1.0 + pow(sin(2.0 * PI * (phase + frequency * radianRate)), 4); } } /* Concrete Calculators ---------- */ public class Photosphere extends Chromosphere { Photosphere(float hueBase) { super(hueBase); } @Override protected float setAmpBase() { return height * 0.05 * pow(map(frequencyRate, 0.0, 1.0, 1.0, 0.1), 2); } } /* Concrete Calculators ---------- */ public class Corona extends Calculator { Corona(float hueBase) { super(hueBase); radianRateDiv = 0.02; beltRateDiv = 0.1; } @Override protected void calcHue(float radianRate, float noiseParam) { wp.hue = hueBase + map(frequencyRate, 0.0, 1.0, 0.0, 30.0); } @Override protected void calcSaturation(float radianRate, float noiseParam) { wp.saturation = 60.0; } @Override protected void calcBrightness(float radianRate, float noiseParam) { wp.brightness = pow(map(frequencyRate, 0.0, 1.0, 1.0, 0.1), 2) * abs(sin(2.0 * PI * radianRate)) // darker in center, start and end * sin(PI * map(beltRate, 0.0, 1.0, 0.3, 0.5)); // little brighter with beltRate } @Override protected void calcAmplitude(float radianRate, float noiseParam) { wp.amplitude = abs( height * 0.4 * pow(map(frequencyRate, 0.0, 1.0, 1.0, 0.2), 2) * sin(2.0 * PI * (-phase + frequency * radianRate)) // sine wave * sin(PI * map(beltRate, 0.0, 1.0, 0.1, 0.5)) // bigger wave with beltRate ); } @Override protected void calcSize(float radianRate, float noiseParam) { wp.size = pow(sin(PI * (phase + frequency * radianRate)), 2) * 30.0 + noise(noiseParam) * 50.0; // animate corona size with noise } } /* Concrete Calculators ---------- */ public class Prominence extends Calculator { Prominence(float hueBase) { super(hueBase); radianRateDiv = 0.001; beltRateDiv = 0.01; } @Override protected void calcHue(float radianRate, float noiseParam) { wp.hue = hueBase + sin(1.0 * PI * (phase + frequency * radianRate)) * 30.0; // animate color with phase } @Override protected void calcSaturation(float radianRate, float noiseParam) { wp.saturation = 10.0 + sin(1.0 * PI * (phase + frequency * radianRate)) * 20.0; } @Override protected void calcBrightness(float radianRate, float noiseParam) { wp.brightness = pow(map(frequencyRate, 0.0, 1.0, 1.0, 0.0), 2) // brighter in low frequency wave * sin(PI * map(beltRate, 0.0, 1.0, 0.1, 0.5)); // brighter with beltRate } @Override protected void calcAmplitude(float radianRate, float noiseParam) { wp.amplitude = abs( height * 0.2 * map(frequencyRate, 0.0, 1.0, 1.0, 0.5) * sin(2.0 * PI * (-phase + frequency * radianRate)) // sine wave * sin(PI * map(beltRate, 0.0, 1.0, 0.5, 0.3)) // smaller wave with beltRate * 10.0 * pow(noise(0.002 * radianRate, noiseParam), 4) // waving animation with noise ); } @Override protected void calcSize(float radianRate, float noiseParam) { wp.size = pow(sin(PI * (phase + frequency * radianRate)), 4) * 2.0; } } /* Calculate Results ---------- */ public class WaveParticle { // wave public float amplitude; public float radian; // particle public float hue; public float saturation; public float brightness; public float size; WaveParticle() { amplitude = 0.0; radian = 0.0; hue = 0.0; saturation = 0.0; brightness = 0.0; size = 0.0; } } /* Main ---------- */ void setup() { size(720, 720); colorMode(HSB, 360, 100, 100, 100); blendMode(ADD); smooth(); noLoop(); noStroke(); } void draw() { translate(width / 2, height / 2); float hueBase = random(360.0); int chromosphereNo = 5; int photosphereNo = 6; int coronaNo = 3; int prominenceNo = 1; int frameCntMax = ceil(15 * 6.5); // 15fps x 6.5s WaveMaker[] ph = newWaveMaker(chromosphereNo, new Chromosphere(hueBase), hueBase); WaveMaker[] pl = newWaveMaker(photosphereNo, new Photosphere(hueBase), hueBase); WaveMaker[] rd = newWaveMaker(coronaNo, new Corona(hueBase), hueBase); WaveMaker[] fl = newWaveMaker(prominenceNo, new Prominence(hueBase), hueBase); for (int frameCnt = 0; frameCnt < frameCntMax; ++frameCnt) { background(hueBase, 100, 5, 100); float phase = map(frameCnt, 0, frameCntMax, 0.0, 0.5); // animate sine wave with phase drawFrame(ph, chromosphereNo, phase); drawFrame(pl, photosphereNo, phase); drawFrame(rd, coronaNo, phase); drawFrame(fl, prominenceNo, phase); saveFrame("frames/" + String.format("%04d", frameCnt) + ".png"); } exit(); } WaveMaker[] newWaveMaker(int instanceNo, Calculator ct, float hueBase) { WaveMaker[] wm = new WaveMaker[instanceNo]; for (int i = 0; i < instanceNo; ++i) { wm[i] = new WaveMaker(ct); } return wm; } void drawFrame(WaveMaker[] wm, float rotateCntMax, float phase) { pushMatrix(); for (int rotateCnt = 0; rotateCnt < rotateCntMax; ++rotateCnt) { rotate(2.0 * PI / (rotateCntMax * 1.0)); drawWave(wm[rotateCnt], phase); } popMatrix(); } void drawWave(WaveMaker wm, float phase) { float frequencyMin = 3.0; float frequencyMax = 12.0; for (float frequency = frequencyMin; frequency <= frequencyMax; frequency += 1.0) { float frequencyRate = map(frequency, frequencyMin, frequencyMax, 0.0, 1.0); wm.drawWave(frequency, frequencyRate, phase); } } /* Copyright (C) 2018- 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/> */
Yet another example image.