/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://cd3d.sketchpad.cc/sp/pad/view/ro.52tKjQHt9Cl/rev.1
*
* authors:
* Raphael Gaudy
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
/*
This simple program draws a curve by the flow of
the circular field
Pascal Romon 2016-09-30
with contribution of Celine Noel for building the curve with the mouse
*/
/*
Start drawing a curve by pressing 'c';
if a curve already eists, it is erased and a new one is created
Finish by 'c' for a closing the curve
Flow by 'f' (only if the curve exists)
*/
int vertexSize = 10; // circle size for drawing vertices
Curve C;
int n;
float tau = 0.1;
boolean pause = false; // control the mouse during the flow
boolean make_curve = false; // set to true to create the curve
boolean startFlow = false; // set to true to start the flow
float Lstart = 0;
void setup() {
frameRate(10);
size(300, 300);
background(100);
C = new Curve();
}
void draw() {
translate(width/2, height/2); // sets the origin of the coordinates in the center of the frame
if (C.vertices.size() > 0) {
C.drawCurve();
}
if (startFlow && !pause) {
background(100);
C.drawCurve();
ArrayList<Vector> flow = new ArrayList<Vector>();
//flow = badRotationFlow(C);
flow = badCurvatureFlow(C);
C.shift(flow);
float L = C.length();
ArrayList<Vector> homot = homotFlow(C, Lstart/L);
C.shift(homot);
println(L);
}
}
ArrayList<Vector> badRotationFlow(Curve Ctemp) {
ArrayList<Vector> ts = new ArrayList<Vector>();
for (int i = 0; i < Ctemp.vertices.size(); i++) {
Vector v = new Vector();
v.x = Ctemp.vertices.get(i).x;
v.y = Ctemp.vertices.get(i).y;
v.rot();
v.mult(tau);
ts.add(v);
}
return(ts);
}
ArrayList<Vector> badCurvatureFlow(Curve Ctemp) {
ArrayList<Vector> ts = new ArrayList<Vector>();
int n = Ctemp.vertices.size();
for (int i = 0; i < n; i++) {
Vector v = new Vector(Ctemp.vertices.get(i).x, Ctemp.vertices.get(i).y);
Vector next = new Vector();
next.x = Ctemp.vertices.get((i+1) % n).x;
next.y = Ctemp.vertices.get((i+1) % n).y;
next.sub(v);
next.normalize();
Vector previous = new Vector();
previous.x = Ctemp.vertices.get((i-1 + n) % n).x;
previous.y = Ctemp.vertices.get((i-1 + n) % n).y;
previous.sub(v);
previous.normalize();
v.x = previous.x + next.x;
v.y = previous.y + next.y;
//v.x = 2*(previous.x + next.x)/(previous.norm() + next.norm());
//v.y = 2*(previous.y + next.y)/(previous.norm() + next.norm());
v.mult(tau);
ts.add(v);
}
return ts;
}
ArrayList<Vector> homotFlow(Curve Ctemp, float lambda) {
ArrayList<Vector> ret = new ArrayList<Vector>();
for (int i = 0; i < Ctemp.vertices.size(); i++) {
Vector homo_x = new Vector((lambda - 1)*(Ctemp.vertices.get(i).x - 0),
(lambda - 1)*(Ctemp.vertices.get(i).y - 0));
ret.add(homo_x);
}
return ret;
}
void mouseClicked() {
if (make_curve) {
C.addVertex(mouseX - width / 2, mouseY - height / 2);
Lstart = C.length();
}
if (startFlow) {
pause = !pause; // during the flow, clicking pause and restarts the process
}
}
void keyReleased() {
if (key == 'c') {
startFlow = false; //interrupts flow
if (make_curve && C.vertices.size() >= 3) { // we close the loop
C.loop = true;
} else { // we start a new loop
background(100);
C.vertices.clear();
C.loop = false;
}
make_curve = !make_curve;
}
if (key == 'f' && make_curve == false) {
startFlow = true;
}
}
class Vector {
float x = 0.0;
float y = 0.0;
Vector() {
}
Vector(float xi, float yi) {
x = xi;
y = yi;
}
void homo(Vector origin, float k) {
x += (k-1)*(x-origin.x) ;
y += (k-1)*(y-origin.y);
}
void add(Vector v) {
x += v.x;
y += v.y;
}
void sub(Vector v) {
x-= v.x;
y-= v.y;
}
void mult(float c) {
x = x*c;
y = y*c;
}
float det(Vector v) {
return (x * v.y - y *v.x);
}
float scal(Vector v) {
return (x * v.x + y *v.y);
}
float norm() {
return(sqrt((x*x+y*y)));
}
float normsq() {
return((x*x+y*y));
}
void normalize() {
float mag = sqrt ((float)(x*x+y*y));
x = x/mag;
y= y/mag;
}
void rot() {
float u, v;
u=x;
v=y;
x= -v;
y = u;
}
}
class Curve {
ArrayList<Vector> vertices = new ArrayList<Vector>();
boolean loop; // if true, indicate only n vertices
void drawCurve() {
int n = vertices.size();
Vector current, next;
//first: lines
for (int i=0; i < n-1; i++) {
current = vertices.get(i);
next = vertices.get(i+1);
line((float)current.x, (float)current.y, (float)next.x, (float)next.y);
}
current = vertices.get(n-1); // last point
if (loop) {
next = vertices.get(0);
line((float)current.x, (float)current.y, (float)next.x, (float)next.y);
}
// second: vertices
for (int i=0; i < n-1; i++) {
current = vertices.get(i);
next = vertices.get(i+1);
//println(i,current.x, current.y);
ellipse((float)current.x, (float)current.y, vertexSize, vertexSize);
}
current = vertices.get(n-1); // last point
ellipse((float)current.x, (float)current.y, vertexSize, vertexSize);
}
void addVertex(float xnew, float ynew) { // adds a vertex
Vector v = new Vector(xnew, ynew);
vertices.add(v);
}
void shift(ArrayList<Vector> shifts) {
// one should check that the size of both list is the same ...
//Vector v,s;
for (int i = 0; i < vertices.size(); i++) {
Vector v = vertices.get(i);
Vector s = shifts.get(i);
//vertices.get(i).add(s);
v.x += s.x;
v.y += s.y;
}
}
float length() {
float ret = 0;
for (int i = 0; i < vertices.size(); i++) {
Vector p = vertices.get(i);
Vector q = vertices.get((i+1) % vertices.size());
ret += sqrt((p.x - q.x)*(p.x - q.x) + (p.y - q.y)*(p.y - q.y));
}
return ret;
}
}