Calculation formulas involving trigonometric functions can generate stunning dances.
Vivid dance with some interesting calculation formula.
It's a creative coding animation made with 'Processing'. I found an interesting formula that creates some funny dance of particles.
This calculation makes points an interesting location moving.
// magic calculation for the vivid dance
float theta = PI * cos(divX + divY) * sin(divY) + sin(divX + divY) * cos(divX);
divX = cos(theta);
divY = sin(theta);
x += divX;
y += divY;
And I drew the points with 'TRIANGLE_STRIP', then it looked like a vivid dance of wireframe object.
beginShape(TRIANGLE_STRIP);
for (PVector p : _p) {
vertex(p.x * _mult, p.y * _mult);
}
An example source code of 'Processing'.
This code does not display any images on the screen but generates image files in frames directory. You can make an animation with these files.
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.
/**
* Neutron Dance.
* vivid dance with some interesting calculation formula.
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2020.10.04
*/
void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
rectMode(CENTER);
noLoop();
}
void draw() {
int frmMax = 24 * 8; // 24fps x 8sec animation
int objectMax = 3;
float radius = 70.0;
float baseTheta = random(0.28, 0.40); // for nice dancing
float rotation = random(PI);
translate(width * 0.5, height * 0.5);
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
float frmRatio = map(frmCnt, 0, frmMax, 0.0, 1.0);
float easeRatio = InOutCubic(frmRatio);
background(0.0, 0.0, 90.0, 100.0);
// draw orbits
strokeWeight(1.0);
noFill();
for (int i = 1; i <= 6; i++) {
stroke(0.0, 0.0, 50.0 + i * 5.0, 100.0);
ellipse(0.0, 0.0, radius * 2.0 * i, radius * 2.0 * i);
}
// calculate object shape and location
ArrayList<ArrayList<PVector>> objects = new ArrayList<ArrayList<PVector>>();
for (int objectCnt = 0; objectCnt < objectMax; objectCnt++) {
float objectRatio = map(objectCnt, 0, objectMax, 0.0, 1.0);
float theta = TWO_PI * (objectRatio + baseTheta);
float divX = cos(theta + easeRatio * TWO_PI / objectMax);
float divY = sin(theta + easeRatio * TWO_PI / objectMax);
ArrayList<PVector> points = getPoints(5, divX, divY);
objects.add(points);
}
// draw background particles
for (ArrayList<PVector> points : objects) {
pushMatrix();
rotate(rotation + HALF_PI + frmRatio * TWO_PI);
for (int i = 1; i <= 2; i++) {
rotate(PI);
drawJoints(points, radius * i * 2.0, 30.0);
}
popMatrix();
}
// draw dancing objects
for (ArrayList<PVector> points : objects) {
pushMatrix();
rotate(rotation);
drawBones(points, radius);
drawJoints(points, radius, 60.0);
popMatrix();
}
casing();
saveFrame("frames/" + String.format("%04d", frmCnt) + ".png");
}
exit();
}
/**
* getPoints
* @param _pMax : points number to calculate
* @param _dX, _dY : distance between points
* @return : array of points location.
*/
private ArrayList<PVector> getPoints(int _pMax, float _dX, float _dY) {
float divX = _dX;
float divY = _dY;
float x = 0.0;
float y = 0.0;
ArrayList<PVector> points = new ArrayList<PVector>();
for (int pCnt = 0; pCnt < _pMax; pCnt++) {
// magic calculation for the vivid dance
float theta = PI * cos(divX + divY) * sin(divY) + sin(divX + divY) * cos(divX);
divX = cos(theta);
divY = sin(theta);
x += divX;
y += divY;
points.add(new PVector(x, y));
}
return points;
}
/**
* drawBones
* @param _p : array of points to draw
* @param _mult : object size
*/
private void drawBones(ArrayList<PVector> _p, float _mult) {
strokeWeight(2.0);
stroke(0.0, 0.0, 50.0, 100.0);
noFill();
beginShape(TRIANGLE_STRIP);
for (PVector p : _p) {
vertex(p.x * _mult, p.y * _mult);
}
endShape();
}
/**
* drawJoints
* @param _p : array of points to draw
* @param _mult : object size
* @param _sat : saturation value with drawing
*/
private void drawJoints(ArrayList<PVector> _p, float _mult, float _sat) {
float margin = 5.0;
for (PVector p : _p) {
float siz = map(sin(0.5 * (p.x * p.y)), -1.0, 1.0, 10.0, 25.0);
strokeWeight(margin);
stroke(0.0, 0.0, 90.0, 100.0);
fill(360.0 * abs(sin(0.4 * (p.x + p.y))) % 360, _sat, 80.0, 100.0);
ellipse(p.x * _mult, p.y * _mult, siz, siz);
if (sin(0.2 * (p.x * p.y)) > 0.5) {
strokeWeight(2);
stroke(0.0, 0.0, 50.0, 100.0);
noFill();
ellipse(p.x * _mult, p.y * _mult, siz + margin, siz + margin);
}
}
}
/**
* easeInOutCubic easing function.
* @param _t : 0.0 - 1.0 : linear value.
* @return : 0.0 - 1.0 : eased value.
*/
private float InOutCubic(float _t) {
_t *= 2.0;
if (_t < 1.0) {
return pow(_t, 3) / 2.0;
}
_t -= 2.0;
return (pow(_t, 3) + 2.0) / 2.0;
}
/**
* casing : draw fancy casing
*/
public void casing() {
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(30.0);
stroke(0.0, 0.0, 50.0, 100.0);
rect(0.0, 0.0, width, height);
strokeWeight(28.0);
stroke(0.0, 0.0, 100.0, 100.0);
rect(0.0, 0.0, width, height);
}
/*
Copyright (C) 2020- 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/>
*/