How do I create regular spirograph curves around an asymmetrical shape

Hello!
I’m desparate for a solution to my problem and very thankful for any kind of help.

I’m new to this program and I need to find a way how to create regular spirograph-like curves around an asymmetrical shape. So no central, single fix point is given, the fix point needs to move with the irregular outline. See the attached image for an example of an irregular shape with regular curves surrounding it.

In the end, I need to export still images of different variations of such asymmetrical shapes with curves surrounding them. Ideally I get to a code I can just change parameters of and generate the varying shapes this way.

I’M FOREVER THANKFUL IF ANYONE CAN HELP ME…
best, Rah

you have made a regular spirograph already?
and ask how to change/bend/ it?

// http://www.math.com/students/wonders/spirographs.html

int d=2, R=50, O=100,r=1;
float oldx, oldy, x=0, y=0, t;

void setup() {
  size(800, 800);
  println("use mouseX mouseY and mouse wheel");
}

void draw() {
  background(200, 200, 0);
  stroke(0, 0, 200);
  strokeWeight(3);
  translate(width/2, height/2);
  R=mouseX/2;
  O=mouseY/2;
  for ( int i=0; i<360; i++) {
    t = TWO_PI * i/360.0;
    oldx=x; 
    oldy=y;
    x = (R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);
    y = (R+r)*sin(t) - (r+O)*sin(((R+r)/r)*t);
    //ellipse(x, y, d, d);
    line(oldx,oldy,x,y);
  }
}


void mouseWheel(MouseEvent event){
 r += event.getCount(); 
 if ( r <= 0 ) r = 1; 
 println("r: "+r+" R: "+R+" O: "+O);
}

and play with it,

x = (x/500+y/500)*(R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);

there could be a way to load a kind of offset array ( that irregular shape in numbers )
and put it in that equation ( additiv i think )

Hi kll!
Thank you for your reply!
The spirograph curve has to be regular/ normal, only the shape inside, which it circulates is irregular, as you can see in my picture (which is handdrawn and therefore quite inexact…).
I don’t have the code for the regular spirograph in processing yet, I only have it in another program but don’t know how to translate it. Maybe it’d work to just make changes in the regular spirographs code to make it asymmetrical…?
Thank you 100 times for your help!!
Rah

use my above code and have a easy start,
use mouse ( X and Y ) and mouseWheel
i only use a screen shot program ( win 7 / snagit )
no export build in

and think about that array ( describing your irregular shape )
to put it in the calculation.


post your code when you have questions.

OK, I will try this now and report! Thank you!!!

do you know how to insert this code into the one you’ve given me? I tried to add it but it doesn’t play. With this, I’m trying to make the curves round instead of squared…

noFill();
stroke(255, 102, 0);
curve(5, 26, 5, 26, 73, 24, 73, 61);
stroke(0);
curve(5, 26, 73, 24, 73, 61, 15, 65);
stroke(255, 102, 0);
curve(73, 24, 73, 61, 15, 65, 15, 65);

it stems from this link: https://processing.org/reference/curve_.html

(irrelevant post, so deleted)

this is my code so far. i now need to make the core that is circled around irregular (with this additive array, but i don’t know how) plus make the curves round instead of squared.

int d=2, R=50, O=100,r=1;
float oldx, oldy, x=0, y=0, t;

void setup() {
size(800, 800);
println(“use mouseX mouseY and mouse wheel”);
}

void draw() {
background(255);
stroke(0);
strokeWeight(1.5);
translate(width/2, height/2);
R=mouseX/10;
O=mouseY/2;
for ( int i=0; i<360; i++) {
t = TWO_PI * i/360.0;
oldx=x;
oldy=y;
x = (x/50+y/50000)*(R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);
y = (R+r)*sin(t) - (r+O)*sin(((R+r)/r)*t);
//ellipse(x, y, d, d);
line(oldx,oldy,x,y);
}
}

void mouseWheel(MouseEvent event){
r += event.getCount();
if ( r <= 10 ) r = 10;
println("r: “+r+” R: “+R+” O: "+0);
}

hi @Rah

  • ok, one of the point here is that it is helpful if you learn how to paste code here.
    when you are in add/edit mode here pls press the

</>

Preformatted text (Ctrl Shift C)
then paste the code inbetween the
‘’’

your code

‘’’
because the one you posted did not run anymore
some " got change on the way.

  • so you play with my first idea
(x/50+y/50000)*

that is partial multiplicativ, happy if it works out.

  • above you show a curve ( shape ) example,
    well yes you can draw all kind of additional stuff,
    but that does not effect the spirals
    ( how to say, its additiv to the display, not to the spiral )

the spiral is made by a for 0 … 359 loop,
so if you want design some data and add OR mult to the spiral
you need a new array , i show you now:

// http://www.math.com/students/wonders/spirographs.html


int d=2, R=50, O=100, r=1;
float oldx, oldy, x=0, y=0, t;

PVector[] irre = new PVector[360];

void make_irre_shape() {
  float a = 30,b=80;
  for (int i = 0; i < 360; i++) {
    irre[i] = new PVector();
    irre[i].x = a*sin(i*TWO_PI/360);
    irre[i].y = b*sin(3*i*TWO_PI/360);
    println(" i "+i+" irre "+irre[i]);
  }
}

void setup() {
  size(600, 600);
  println("use mouseX mouseY and mouse wheel");
  make_irre_shape();
}

void draw() {
  background(200, 200, 0);
//  stroke(0, 0, 200);
//  strokeWeight(3);
// RAH theme
  background(255);
  stroke(0);
  strokeWeight(1.5);

  
  
  translate(width/2, height/2);
  scale(0.5);
  R=mouseX/2;
  O=mouseY/2;
  for ( int i=0; i<360; i++) {
    t = TWO_PI * i/360.0;
    oldx=x; 
    oldy=y;
    x = irre[i].x + (R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);
    y = irre[i].y + (R+r)*sin(t) - (r+O)*sin(((R+r)/r)*t);
    //ellipse(x, y, d, d);
    line(oldx, oldy, x, y);
  }
}


void mouseWheel(MouseEvent event) {
  r += event.getCount(); 
  if ( r <= 0 ) r = 1; 
  println("r: "+r+" R: "+R+" O: "+O);
}

just for understanding, if you want the inner irregular shape to be a rectangle you must add it in the circular way.
so need points of that shape ( as x,y ) for each if the 360 deg angle steps.

now that above added function just use some math to filll that array,
a other way would be that you find a way to make that list
0 , 0

30, 0

30, 30

0,0
? by spreadsheet and save to a CSV file.
if you WANT and CAN do that i will replace the
above math function by a load spreadsheet function.

  • mouse and wheel
    i think you need that now for experimenting,
    but to have a still picture that not goes crazy when you move the mouse
    that should be changed to: read mouse X Y as ( R and O variables ) on mouse click only? no problem ( r as mouse wheel no need click)

  • even mouse can adjust
    O , R , r ( in a certain range )
    i still worry if i covered all possible spiral types.
    ( actually if the designer of that spiral function at
    math.com/students/wonders/spirographs.html
    got it fully covered )

  • one add thing is that i use lines from x,y old to x,y new,
    so at small “r” ( like r = 1 ) get interesting graphic, but no round
    shapes anymore, here need to experiment with the courveVertex

// http://www.math.com/students/wonders/spirographs.html

// v0.2 use RAH theme and irre[0 .. 359] filled by math
// v0.3 change to mouse click XY
//      adjustable buffer for array and spiral loop now 360 to 720
//      use curveVertex but not sure the show is better
//      change r to float and mouseWheel to very small steps

int buffer = 720;

int d=5, R=50, O=100;
float r=1;
float oldx, oldy, x=0, y=0, t;

PVector[] irre = new PVector[buffer];

void make_irre_shape() {
  float a = 20, b=80;
  for (int i = 0; i < buffer; i++) {
    irre[i] = new PVector();
    irre[i].x = a*sin(i*TWO_PI/buffer);
    irre[i].y = b*sin(1*i*TWO_PI/buffer)+2*b*sin(3*i*TWO_PI/buffer)+0.5*b*sin(5*i*TWO_PI/buffer);  // add sinus harmonics to make a rectangle (fourier)
    println(" i "+i+" irre "+irre[i]);
  }
}

void setup() {
  size(600, 600);
  println("use mouseX mouseY and mouse wheel");
  make_irre_shape();
}

void draw() {
  background(200, 200, 0);
  //  stroke(0, 0, 200);
  //  strokeWeight(3);
  // RAH theme
  background(255);
  stroke(0);
  //  strokeWeight(1.5);

  strokeWeight(3);  // kll change back because now scale smaller

  translate(width/2, height/2);
  scale(0.2);
  //  R=mouseX/2;
  //  O=mouseY/2;

  beginShape();
  for ( int i=0; i<buffer; i++) {
    t = TWO_PI * i/buffer;
    oldx=x; 
    oldy=y;
    // kll add a shape from a array
    x = irre[i].x + (R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);
    y = irre[i].y + (R+r)*sin(t) - (r+O)*sin(((R+r)/r)*t);
    // draw options:
    //ellipse(x, y, d, d);
    //line(oldx, oldy, x, y);
    curveVertex(x, y);                  // try this, but i still like the line more!
  }
  endShape(CLOSE);
}


void mouseReleased() {   //kll now must click mouse to change R and O
  R=mouseX;
  O=mouseY;
  println("r: "+nf(r,1,1)+" R: "+R+" O: "+O);

}


void mouseWheel(MouseEvent event) {
  r += event.getCount()/10.0; 
  if ( r == 0 ) r = 1; 
  println("r: "+nf(r,1,1)+" R: "+R+" O: "+O);
}

This below is my attempt to address your question. I also did some minor changes. This could come handy. I also think these links could be relevant to your question:

https://processing.org/examples/additivewave.html
https://forum.processing.org/two/discussion/21356/how-to-draw-waves-like-those-in-the-pictures
Wave displaced circle

Your question is an interesting challenge. I might give it a try this weekend if you are still looking for help.

@kll Your demo produces interesting patterns :raising_hand_man:

Kf

int d=2,  r=1;
float  x=0, y=0, t;

void setup() {
  size(800, 800);
  surface.setTitle("Use mouseX mouseY and mouse wheel");
  
  stroke(0);
  strokeWeight(1.5);
}

void draw() {
  background(255);  
  translate(width/2, height/2);
  
  float R=mouseX/10;
  float O=mouseY/2;
  
  beginShape();
  for ( int i=0; i<360; i++) {
    t = radians(i);
    x = (x/50+y/50000)*(R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);
    y = (R+r)*sin(t) - (r+O)*sin(((R+r)/r)*t);
    curveVertex(x,y);
  }
  endShape();
}

void mouseWheel(MouseEvent event) {
  r += event.getCount();
  if ( r <= 10 ) r = 10;
  println("r: “+r+” R: “+R+” O: "+0);
}
1 Like

now still load shape array from math,
but with key [f] can load a csv file

make a subdir
/data/
inthere make a file irre.csv with this content:

0.00,-200.00
0.00,-200.67
0.00,-201.27
0.00,-201.82
0.00,-202.30
0.00,-202.73
0.00,-203.09
0.00,-203.39
0.00,-203.63
0.00,-203.81
0.00,-203.93
0.00,-203.99
0.00,-203.99
0.00,-203.93
0.00,-203.81
0.00,-203.63
0.00,-203.39
0.00,-203.09
0.00,-202.73
0.00,-202.31
0.00,-201.83
0.00,-201.29
0.00,-200.70
0.00,-200.05
0.00,-199.34
0.00,-198.58
0.00,-197.75
0.00,-196.88
0.00,-195.94
0.00,-194.95
0.00,-193.91
0.00,-192.81
0.00,-191.66
0.00,-190.46
0.00,-189.20
0.00,-187.89
0.00,-186.52
0.00,-185.11
0.00,-183.65
0.00,-182.13
0.00,-180.57
0.00,-178.96
0.00,-177.30
0.00,-175.59
0.00,-173.84
0.00,-172.04
0.00,-170.19
0.00,-168.30
0.00,-166.37
0.00,-164.39
0.00,-162.37
0.00,-160.31
0.00,-158.20
0.00,-156.06
0.00,-153.88
0.00,-151.66
0.00,-149.40
0.00,-147.10
0.00,-144.77
0.00,-142.40
0.00,-140.00
0.00,-137.57
0.00,-135.10
0.00,-132.60
0.00,-130.07
0.00,-127.51
0.00,-124.92
0.00,-122.30
0.00,-119.66
0.00,-116.99
0.00,-114.29
0.00,-111.57
0.00,-108.83
0.00,-106.06
0.00,-103.27
0.00,-100.46
0.00,-97.64
0.00,-94.79
0.00,-91.93
0.00,-89.05
0.00,-86.15
0.00,-83.24
0.00,-80.32
0.00,-77.38
0.00,-74.44
0.00,-71.48
0.00,-68.51
0.00,-65.54
0.00,-62.55
0.00,-59.56
0.00,-56.57
0.00,-53.57
0.00,-50.57
0.00,-47.56
0.00,-44.56
0.00,-41.55
0.00,-38.55
0.00,-35.54
0.00,-32.54
0.00,-29.55
0.00,-26.55
0.00,-23.57
0.00,-20.59
0.00,-17.62
0.00,-14.66
0.00,-11.70
0.00,-8.76
0.00,-5.83
0.00,-2.92
0.00,-0.02
0.00,2.87
0.00,5.74
0.00,8.60
0.00,11.44
0.00,14.25
0.00,17.05
0.00,19.83
0.00,22.59
0.00,25.32
0.00,28.03
0.00,30.72
0.00,33.38
0.00,36.01
0.00,38.62
0.00,41.20
0.00,43.75
0.00,46.28
0.00,48.77
0.00,51.23
0.00,53.66
0.00,56.05
0.00,58.41
0.00,60.74
0.00,63.03
0.00,65.29
0.00,67.51
0.00,69.69
0.00,71.84
0.00,73.94
0.00,76.01
0.00,78.03
0.00,80.02
0.00,81.96
0.00,83.86
0.00,85.72
0.00,87.53
0.00,89.30
0.00,91.03
0.00,92.71
0.00,94.34
0.00,95.93
0.00,97.47
0.00,98.97
0.00,100.41
0.00,101.81
0.00,103.16
0.00,104.46
0.00,105.71
0.00,106.91
0.00,108.06
0.00,109.15
0.00,110.20
0.00,111.20
0.00,112.14
0.00,113.03
0.00,113.87
0.00,114.66
0.00,115.39
0.00,116.07
0.00,116.69
0.00,117.27
0.00,117.78
0.00,118.25
0.00,118.66
0.00,119.01
0.00,119.32
0.00,119.56
0.00,119.75
0.00,119.89
0.00,119.97
0.00,120.00
0.00,119.97
0.00,119.89
0.00,119.75
0.00,119.56
0.00,119.32
0.00,119.01
0.00,118.66
0.00,118.25
0.00,117.78
0.00,117.27
0.00,116.69
0.00,116.07
0.00,115.39
0.00,114.66
0.00,113.87
0.00,113.03
0.00,112.14
0.00,111.20
0.00,110.20
0.00,109.15
0.00,108.06
0.00,106.91
0.00,105.71
0.00,104.46
0.00,103.16
0.00,101.81
0.00,100.41
0.00,98.97
0.00,97.47
0.00,95.93
0.00,94.34
0.00,92.71
0.00,91.03
0.00,89.30
0.00,87.53
0.00,85.72
0.00,83.86
0.00,81.96
0.00,80.02
0.00,78.03
0.00,76.01
0.00,73.94
0.00,71.84
0.00,69.69
0.00,67.51
0.00,65.29
0.00,63.04
0.00,60.74
0.00,58.42
0.00,56.05
0.00,53.66
0.00,51.23
0.00,48.77
0.00,46.28
0.00,43.75
0.00,41.20
0.00,38.62
0.00,36.01
0.00,33.38
0.00,30.72
0.00,28.03
0.00,25.32
0.00,22.59
0.00,19.83
0.00,17.05
0.00,14.25
0.00,11.44
0.00,8.60
0.00,5.74
0.00,2.87
0.00,-0.01
0.00,-2.92
0.00,-5.83
0.00,-8.76
0.00,-11.70
0.00,-14.66
0.00,-17.62
0.00,-20.59
0.00,-23.57
0.00,-26.55
0.00,-29.54
0.00,-32.54
0.00,-35.54
0.00,-38.55
0.00,-41.55
0.00,-44.56
0.00,-47.56
0.00,-50.57
0.00,-53.57
0.00,-56.57
0.00,-59.56
0.00,-62.55
0.00,-65.53
0.00,-68.51
0.00,-71.48
0.00,-74.44
0.00,-77.38
0.00,-80.32
0.00,-83.24
0.00,-86.15
0.00,-89.05
0.00,-91.93
0.00,-94.79
0.00,-97.64
0.00,-100.46
0.00,-103.27
0.00,-106.06
0.00,-108.83
0.00,-111.57
0.00,-114.29
0.00,-116.99
0.00,-119.66
0.00,-122.30
0.00,-124.92
0.00,-127.51
0.00,-130.07
0.00,-132.60
0.00,-135.10
0.00,-137.56
0.00,-140.00
0.00,-142.40
0.00,-144.77
0.00,-147.10
0.00,-149.40
0.00,-151.65
0.00,-153.88
0.00,-156.06
0.00,-158.20
0.00,-160.30
0.00,-162.37
0.00,-164.39
0.00,-166.36
0.00,-168.30
0.00,-170.19
0.00,-172.04
0.00,-173.84
0.00,-175.59
0.00,-177.30
0.00,-178.96
0.00,-180.57
0.00,-182.13
0.00,-183.65
0.00,-185.11
0.00,-186.52
0.00,-187.89
0.00,-189.20
0.00,-190.46
0.00,-191.66
0.00,-192.81
0.00,-193.91
0.00,-194.95
0.00,-195.94
0.00,-196.88
0.00,-197.75
0.00,-198.58
0.00,-199.34
0.00,-200.05
0.00,-200.70
0.00,-201.29
0.00,-201.83
0.00,-202.31
0.00,-202.73
0.00,-203.09
0.00,-203.39
0.00,-203.63
0.00,-203.81
0.00,-203.93
0.00,-203.99
0.00,-203.99
0.00,-203.93
0.00,-203.81
0.00,-203.63
0.00,-203.39
0.00,-203.09
0.00,-202.73
0.00,-202.30
0.00,-201.82
0.00,-201.27
0.00,-200.67
0.00,-200.00
0.00,-199.27
0.00,-198.48
0.00,-197.63
0.00,-196.72
0.00,-195.75
0.00,-194.72
0.00,-193.63
0.00,-192.47
0.00,-191.26
0.00,-189.99
0.00,-188.66
0.00,-187.27
0.00,-185.82
0.00,-184.31
0.00,-182.74
0.00,-181.12
0.00,-179.44
0.00,-177.70
0.00,-175.90
0.00,-174.05
0.00,-172.14
0.00,-170.17
0.00,-168.15
0.00,-166.08
0.00,-163.95
0.00,-161.76
0.00,-159.53
0.00,-157.24
0.00,-154.89
0.00,-152.50
0.00,-150.06
0.00,-147.56
0.00,-145.01
0.00,-142.42
0.00,-139.77
0.00,-137.08
0.00,-134.34
0.00,-131.56
0.00,-128.73
0.00,-125.85
0.00,-122.93
0.00,-119.96
0.00,-116.95
0.00,-113.90
0.00,-110.81
0.00,-107.67
0.00,-104.50
0.00,-101.29
0.00,-98.04
0.00,-94.75
0.00,-91.42
0.00,-88.06
0.00,-84.67
0.00,-81.24
0.00,-77.78
0.00,-74.28
0.00,-70.76
0.00,-67.20
0.00,-63.62
0.00,-60.00
0.00,-56.36
0.00,-52.69
0.00,-49.00
0.00,-45.28
0.00,-41.54
0.00,-37.78
0.00,-33.99
0.00,-30.19
0.00,-26.36
0.00,-22.52
0.00,-18.66
0.00,-14.78
0.00,-10.89
0.00,-6.98
0.00,-3.06
0.00,0.87
0.00,4.81
0.00,8.76
0.00,12.72
0.00,16.69
0.00,20.67
0.00,24.65
0.00,28.63
0.00,32.62
0.00,36.61
0.00,40.61
0.00,44.60
0.00,48.59
0.00,52.58
0.00,56.57
0.00,60.55
0.00,64.53
0.00,68.50
0.00,72.46
0.00,76.41
0.00,80.36
0.00,84.29
0.00,88.21
0.00,92.12
0.00,96.01
0.00,99.89
0.00,103.75
0.00,107.60
0.00,111.42
0.00,115.23
0.00,119.02
0.00,122.78
0.00,126.52
0.00,130.24
0.00,133.93
0.00,137.60
0.00,141.24
0.00,144.86
0.00,148.44
0.00,151.99
0.00,155.52
0.00,159.01
0.00,162.47
0.00,165.89
0.00,169.28
0.00,172.63
0.00,175.95
0.00,179.23
0.00,182.47
0.00,185.67
0.00,188.84
0.00,191.96
0.00,195.03
0.00,198.07
0.00,201.06
0.00,204.01
0.00,206.91
0.00,209.76
0.00,212.57
0.00,215.33
0.00,218.04
0.00,220.70
0.00,223.31
0.00,225.87
0.00,228.38
0.00,230.84
0.00,233.24
0.00,235.59
0.00,237.89
0.00,240.13
0.00,242.31
0.00,244.44
0.00,246.51
0.00,248.52
0.00,250.48
0.00,252.37
0.00,254.21
0.00,255.99
0.00,257.71
0.00,259.36
0.00,260.96
0.00,262.49
0.00,263.97
0.00,265.38
0.00,266.72
0.00,268.01
0.00,269.23
0.00,270.38
0.00,271.47
0.00,272.50
0.00,273.46
0.00,274.36
0.00,275.19
0.00,275.96
0.00,276.66
0.00,277.29
0.00,277.86
0.00,278.36
0.00,278.79
0.00,279.16
0.00,279.46
0.00,279.70
0.00,279.87
0.00,279.97
0.00,280.00
0.00,279.97
0.00,279.87
0.00,279.70
0.00,279.46
0.00,279.16
0.00,278.79
0.00,278.36
0.00,277.86
0.00,277.29
0.00,276.66
0.00,275.96
0.00,275.19
0.00,274.36
0.00,273.46
0.00,272.50
0.00,271.47
0.00,270.38
0.00,269.23
0.00,268.01
0.00,266.72
0.00,265.38
0.00,263.97
0.00,262.50
0.00,260.96
0.00,259.37
0.00,257.71
0.00,255.99
0.00,254.21
0.00,252.38
0.00,250.48
0.00,248.52
0.00,246.51
0.00,244.44
0.00,242.31
0.00,240.13
0.00,237.89
0.00,235.59
0.00,233.24
0.00,230.84
0.00,228.39
0.00,225.88
0.00,223.32
0.00,220.71
0.00,218.04
0.00,215.33
0.00,212.57
0.00,209.77
0.00,206.91
0.00,204.01
0.00,201.06
0.00,198.07
0.00,195.04
0.00,191.96
0.00,188.84
0.00,185.68
0.00,182.48
0.00,179.23
0.00,175.96
0.00,172.64
0.00,169.28
0.00,165.89
0.00,162.47
0.00,159.01
0.00,155.52
0.00,152.00
0.00,148.44
0.00,144.86
0.00,141.25
0.00,137.61
0.00,133.94
0.00,130.24
0.00,126.53
0.00,122.78
0.00,119.02
0.00,115.23
0.00,111.43
0.00,107.60
0.00,103.76
0.00,99.89
0.00,96.02
0.00,92.12
0.00,88.21
0.00,84.29
0.00,80.36
0.00,76.42
0.00,72.46
0.00,68.50
0.00,64.53
0.00,60.55
0.00,56.57
0.00,52.58
0.00,48.59
0.00,44.60
0.00,40.61
0.00,36.62
0.00,32.63
0.00,28.64
0.00,24.65
0.00,20.67
0.00,16.70
0.00,12.73
0.00,8.77
0.00,4.81
0.00,0.87
0.00,-3.06
0.00,-6.98
0.00,-10.89
0.00,-14.78
0.00,-18.66
0.00,-22.52
0.00,-26.36
0.00,-30.18
0.00,-33.99
0.00,-37.77
0.00,-41.54
0.00,-45.28
0.00,-49.00
0.00,-52.69
0.00,-56.36
0.00,-60.00
0.00,-63.61
0.00,-67.20
0.00,-70.75
0.00,-74.28
0.00,-77.77
0.00,-81.24
0.00,-84.67
0.00,-88.06
0.00,-91.42
0.00,-94.75
0.00,-98.03
0.00,-101.29
0.00,-104.50
0.00,-107.67
0.00,-110.80
0.00,-113.90
0.00,-116.95
0.00,-119.96
0.00,-122.92
0.00,-125.85
0.00,-128.72
0.00,-131.56
0.00,-134.34
0.00,-137.08
0.00,-139.77
0.00,-142.42
0.00,-145.01
0.00,-147.56
0.00,-150.05
0.00,-152.50
0.00,-154.89
0.00,-157.23
0.00,-159.52
0.00,-161.76
0.00,-163.95
0.00,-166.07
0.00,-168.15
0.00,-170.17
0.00,-172.14
0.00,-174.05
0.00,-175.90
0.00,-177.70
0.00,-179.44
0.00,-181.12
0.00,-182.74
0.00,-184.31
0.00,-185.82
0.00,-187.27
0.00,-188.66
0.00,-189.99
0.00,-191.26
0.00,-192.47
0.00,-193.62
0.00,-194.72
0.00,-195.75
0.00,-196.72
0.00,-197.63
0.00,-198.48
0.00,-199.27

so you start with my fourier math shape and on press [f]
to load a new CSV file shape

that file content you now can design by excel… to any shape you want
on my blog can also now download the complete set ( incl the excel file )

and still have the math shape way
? what was the way to make a triangle wave?
rectangle was:

a*sin(f) + b*sin(3f)+ c*sin(5f)...

ok found it:

a*sin(f) - b*sin(2f) + c*sin(3f)

i found that there are small shades inbetween r values so i allow a fine adjust:
mouseWheel ( r ± 0.1 ) mouseWheel pressed (r ±0.01 )


// http://www.math.com/students/wonders/spirographs.html
// https://discourse.processing.org/t/how-do-i-create-regular-spirograph-curves-around-an-asymmetrical-shape/5501/11?u=kll


// v0.2 use RAH theme and irre[0 .. 359] filled by math
// v0.3 change to mouse click XY
//      adjustable buffer for array and spiral loop now 360 to 720
//      use curveVertex but not sure the show is better
//      change r to float and mouseWheel to very small steps
// v0.4 https://discourse.processing.org/t/how-do-i-create-regular-spirograph-curves-around-an-asymmetrical-shape/5501/10?u=kll
//      add load csv file as string, 720 lines with 0.0,0.0,   on key [f] press
//      make fine adjust of "r" bei mouse (wheel) pressed ( change by 0.01 only)
// v0.5 key [r] start record [p] print  save display to /data/spiro.svg !! [r] selects datetime filename / no overwrite warning
//      theme selector key [1] RAH [2] KLL
//      key [q] select fill math shape with rect or triangle online
//      key [h] helptext

import processing.svg.*;
boolean SVGfile = false;


int buffer = 720;

String irrefile = "irre.csv";  // see /data/irre.csv
String svgfile="";
String[] coordinates;

int d=5, R=50, O=100;
float r=1;
float oldx, oldy, x=0, y=0, t;
boolean dbug = false;
int theme = 1;   // 1 = RAH, 2 = KLL

PVector[] irre = new PVector[buffer];
boolean shaperect = true;

void make_irre_array() {
  for (int i = 0; i < buffer; i++)
    irre[i] = new PVector();
}


void make_irre_shape() {  // by math
  float a = 0, b=100;
  float w = TWO_PI/buffer;
  for (int i = 0; i < buffer; i++) {
    //    irre[i] = new PVector();
    irre[i].x = a*sin(i*w);
    if (shaperect) irre[i].y = b*sin(1*i*w)+1.5*b*sin(3*i*w)+0.4*b*sin(5*i*w);  // add sinus harmonics to make a rectangle (fourier)
    else           irre[i].y = b*sin(1*i*w)-2*b*sin(2*i*w)+0.3*b*sin(3*i*w);    // add sinus harmonics to make a triangle (fourier)
    if (dbug) println(" i "+i+" irre "+irre[i]);
  }
}


void load_irre_shape() {           // array exists already , so we just overwrite it
  println(" load shape from file"+irrefile);
  coordinates = loadStrings(irrefile);  // also could use loadtable
  if (dbug) println("Loaded " + coordinates.length + " coordinates:");
  for (int i = 0; i < coordinates.length; i++) {
    String[] ordinate = splitTokens(coordinates[i], ",");
    irre[i].x = float(ordinate[0]);
    irre[i].y = float(ordinate[1]);
    if (dbug) println(i, ": ", String.format("%.5f %.5f", irre[i].x, irre[i].y));
  }
}

void helptext() {
  println("use mouseX (R) mouseY (O) (now must click) ");
  println("and mouseWheel (r +-0.1) fine adjust mouseWheel pressed(r +-0.01");
  println("use key [q] can select between two math shapes");
  println("use key [f] to load shape from file: /data/irre.csv");
  println("use key[r] record & key[p] print to save to /data/spiro.svg");
  println("use key[1] for black on white [2] blue on yellow");
  println("use key[h] for this text");
}

void setup() {
  size(600, 600);

  make_irre_array(); 
  make_irre_shape();  // now can later select with key[q]

  helptext();
}

void set_theme() {
  if (theme == 1) {         // RAH theme
    background(255);
    stroke(0);
    strokeWeight(1.5);
    noFill();
  } else if (theme == 2) {  // KLL theme
    background(200, 200, 0); 
    stroke(0, 0, 200);
    strokeWeight(5);
    fill(200, 200, 0);
  }
}


void draw() {
  set_theme();
  translate(width/2, height/2);
  scale(0.2);

  beginShape();
  for ( int i=0; i<buffer; i++) {
    t = TWO_PI * i/buffer;
    //oldx=x; 
    //oldy=y;

    //    x = irre[i].x + (x/50+y/50000)*(R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);  // RAH TWIST
    x = irre[i].x + (R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t);      // default
    y = irre[i].y + (R+r)*sin(t) - (r+O)*sin(((R+r)/r)*t);
    // draw options:
    //ellipse(x, y, d, d);
    //line(oldx, oldy, x, y);
    curveVertex(x, y);                  // try this, but i still like the line more!
  }
  endShape(CLOSE);
}


void mouseReleased() {   //kll now must click mouse to change R and O
  if ( mouseButton == LEFT ) {
    R=mouseX;
    O=mouseY;
    println("r: "+nf(r, 1, 2)+" R: "+R+" O: "+O);
  }
}


void mouseWheel(MouseEvent event) {
  if ( mousePressed ) {
    r += event.getCount()/100.0;
  } else {
    r += event.getCount()/10.0; 
    if ( r == 0 ) r = 1;
  }
  println("r: "+nf(r, 1, 2)+" R: "+R+" O: "+O);
}

void keyReleased() {
  if ( key == 'f' )  load_irre_shape();                        // load file /data/irre.svg
  if ( key == 'r' ) {                                          // start recording drawings
    SVGfile = true;
    svgfile= "data/spiro_"+year()+month()+day()+"_"+hour()+minute()+second()+".svg";
    beginRecord(SVG, svgfile);
    println(" start recording ");
  }
  if ( key == 'p' ) {                                           // save recording to /data/spiro_yyyymmdd_hhmmss.svg ( time from pressing key[r] )
    if ( SVGfile ) endRecord();
    println(" save recording "+svgfile);
  }

  if ( key == '1' ) theme = 1;
  if ( key == '2' ) theme = 2;
  if ( key == 'q' ) { 
    shaperect = !shaperect;
    make_irre_shape();
  }
  if ( key == 'h' ) helptext();
  
}

THANK YOU SO MUCH!!! this looks amazing and i will spend some time now trying out all your tips!! and i’ll report in the end :slight_smile:

yes, many new features,

you understand the new SVG export?
for me it ( the files ) look a little bit THIN in my browser,
but i choose the SVG export as that looks perfect, even made or shown at any size,
not like that pixel graves.

but what i hope is that you get that external shape creation ( to CSV file ) going
i did not think about the required ?excel? work or if there are other tools?

i haven’t checked out the svg export yet.
i need good resolution of the shapes in the end as i need to work on with them in adobe illustrator and finally print the whole image very large.
i’ll report once i’m a little further :wink:

Hello everyone who helped me! Thank you again!! I found a code that did the job!!
in case u’re interested:

// v0.2 use RAH theme and irre[0 … 359] filled by math

// v0.3 change to mouse click XY

// adjustable buffer for array and spiral loop now 360 to 720

// use curveVertex but not sure the show is better

// change r to float and mouseWheel to very small steps

// v0.4 How do I create regular spirograph curves around an asymmetrical shape

// add load csv file as string, 720 lines with 0.0,0.0, on key [f] press

// make fine adjust of “r” bei mouse (wheel) pressed ( change by 0.01 only)

// v0.5 key [r] start record [p] print save display to /data/spiro.svg !! [r] selects datetime filename / no overwrite warning

// theme selector key [1] RAH [2] KLL

// key [q] select fill math shape with rect or triangle online

// key [h] helptext

import processing.svg.*;

boolean SVGfile = false;

static int buffer = 720;

String irrefile = “irre.csv”; // see data/irre.csv

String svgfile="";

String[] coordinates;

int d=5, R=560, O=60;

float r=2;

float oldx, oldy, x=0, y=0, t;

boolean test = true;

boolean close = false;

int theme = 1; // 1 = RAH, 2 = KLL

int type = 2; // 0: KLL 1: PLAIN 2: Epicycloid

PVector[] irre = new PVector[buffer];

boolean shaperect = true;

int scale = 20;

void make_irre_array() {

for (int i = 0; i < buffer; i++)

irre[i] = new PVector();

}

void make_irre_shape() { // by math

float a = 0, b=100;

float w = TWO_PI/buffer;

for (int i = 0; i < buffer; i++) {

irre[i].x = a*sin(i*w);

if (shaperect) irre[i].y = b*sin(1*i*w)+1.5*b*sin(3*i*w)+0.4*b*sin(5*i*w);  // add sinus harmonics to make a rectangle (fourier)

else           irre[i].y = b*sin(1*i*w)-2*b*sin(2*i*w)+0.3*b*sin(3*i*w);    // add sinus harmonics to make a triangle (fourier)

}

}

void load_irre_shape() { // array exists already , so we just overwrite it

irrefile = “path” + (shape+1) + “.csv”;

println(" load shape from file "+irrefile);

coordinates = loadStrings(irrefile); // also could use loadtable

println(“Loaded " + coordinates.length + " coordinates”);

float sumx = 0, sumy = 0;

for (int i = 0; i < coordinates.length && i < buffer; i++) {

String[] ordinate = splitTokens(coordinates[i], ",");

irre[i].x = float(ordinate[0])*scale;

irre[i].y = float(ordinate[1])*scale;

sumx += irre[i].x;

sumy += irre[i].y;

}

// do center the svg

PVector svgcenter = new PVector(sumx / buffer, sumy / buffer);

for (int i = 0; i < coordinates.length && i < buffer; i++) {

irre[i].x -= svgcenter.x;

irre[i].y -= svgcenter.y;

}

}

void helptext() {

println("use mouseX ® mouseY (O) (now must click) ");

println(“and mouseWheel (r ±0.1) fine adjust mouseWheel pressed(r ±0.01”);

println(“use key [q] can select between two math shapes”);

println(“use key [f] to load shape from file: data/irre.csv”);

println(“use key[r] record & key[p] print to save to data/spiro.svg”);

println(“use key[1] for black on white [2] blue on yellow”);

println(“use key[h] for this text”);

}

void setup() {

size(600, 600);

make_irre_array();

load_irre_shape(); // now can later select with key[q]

helptext();

}

void set_theme() {

if (theme == 1) { // RAH theme

background(255);

stroke(0);

strokeWeight(1.5);

noFill();

} else if (theme == 2) { // KLL theme

background(200, 200, 0); 

stroke(0, 0, 200);

strokeWeight(5);

fill(200, 200, 0);

}

}

void draw() {

set_theme();

translate(width/2, height/2);

scale(0.2);

if ( type == 0 ) {

beginShape();

for ( int i=0; i&lt;buffer; i++) {

  t = TWO_PI * i/buffer;

  x = irre[i].x + (r)*cos(t) - (r+O)*cos(((R+r)/r)*t);

  y = irre[i].y + (r)*sin(t) - (r+O)*sin(((R+r)/r)*t);

  curveVertex(x, y);

}

endShape(CLOSE);

stroke(255, 0, 255);

strokeWeight(2);

beginShape();

for ( int i=0; i&lt;buffer; i++) {

  vertex(irre[i].x + cos(t), irre[i].y + sin(t));

}

  endShape(close ? CLOSE : OPEN);

} else {

if( type == 1) {

  beginShape();

  // O : 360 = x : 2PI

  float angleStep = TWO_PI * O / 360;

  for ( int i=0; i&lt;buffer; i++) {

    x = irre[i].x + r*cos(i*angleStep);

    y = irre[i].y + r*sin(i*angleStep);

    curveVertex(x, y);

  }

  endShape(close ? CLOSE : OPEN);

}

else {

  // Epyicycloid!

  beginShape();

  // O : 360 = x : 2PI

  float angleStep = TWO_PI * O / 360;

  PVector[] initialPoint = new PVector[4];

  for ( int i=0; i&lt;buffer; i++) {

    float shapeAnglePoint = 0;

    if(type == 3) {

      shapeAnglePoint = atan2(irre[i].y, irre[i].x);

    } else {

      PVector prevPoint = irre[(i-1+buffer) % buffer];

      PVector nextPoint = irre[(i+1) % buffer];

      float xDiff = prevPoint.x - nextPoint.x;

      float yDiff = prevPoint.y - nextPoint.y;

      shapeAnglePoint = atan2(yDiff, xDiff) - PI/2;

    }

    x = irre[i].x + r*(cos(i*angleStep) + cos(shapeAnglePoint));

    y = irre[i].y + r*(sin(i*angleStep) + sin(shapeAnglePoint));

    curveVertex(x, y);

    if(i&lt;4) {

      initialPoint[i] = new PVector(x, y);

    }

  }

  if(test) {

   curveVertex(initialPoint[0].x, initialPoint[0].y);

   curveVertex(initialPoint[1].x, initialPoint[1].y);

   curveVertex(initialPoint[2].x, initialPoint[2].y);

   curveVertex(initialPoint[3].x, initialPoint[3].y);

  }

  endShape(close ? CLOSE : OPEN);

}

if(!SVGfile) {

  stroke(255, 0, 255);

  strokeWeight(2);

  beginShape();

  for ( int i=0; i&lt;buffer; i++) {

    vertex(irre[i].x, irre[i].y);

  }

  endShape(CLOSE);

}

}

}

void mouseReleased() { //kll now must click mouse to change R and O

if ( mouseButton == LEFT ) {

R=mouseX;

O=mouseY;

println("r: "+nf(r, 1, 2)+" R: "+R+" O: "+O);

}

}

void mouseWheel(MouseEvent event) {

if ( mousePressed ) {

r += event.getCount()/100.0;

} else {

r += event.getCount()/10.0; 

if ( r == 0 ) r = 1;

}

println("r: “+nf(r, 1, 2)+” R: “+R+” O: "+O);

}

int shape = 0;

int shapes_count = 33;

void keyReleased() {

if ( key == ‘f’ ) { shape = (shape + 1) % shapes_count; load_irre_shape(); }

if ( key == ‘+’ ) { scale++; load_irre_shape(); };

if ( key == ‘-’ ) { scale–; load_irre_shape(); };

if( key == ‘l’ ) {

type = (type+1) % 4;

switch(type) {

  case 0: println("KLL's Spyrograph"); break;

  case 1: println("Giovanni's Spyrograph"); break;

  case 2: println("Epycicloid"); break;

  case 3: println("Tangent Epycicloid"); break;

}

r = type == 0? 2 : 200; // reset the value for r

}

if ( key == ‘p’ ) {

SVGfile = true;

svgfile = "out/spiro_"+year()+month()+day()+"_"+hour()+minute()+second()+".svg";

beginRecord(SVG, svgfile);

draw();

endRecord();

SVGfile = false;

println("file saved " + svgfile);

}

if ( key == ‘o’ ) {

svgfile = "out/spiro_"+year()+month()+day()+"_"+hour()+minute()+second()+".svg";

beginRecord(SVG, svgfile);

draw();

endRecord();

println("file saved " + svgfile);

}

if ( key == ‘1’ ) theme = 1;

if ( key == ‘2’ ) theme = 2;

if ( key == ‘q’ ) {

shaperect = !shaperect;

make_irre_shape();

}

if( key == ‘c’) {

close = !close;

}

if ( key == ‘h’ ) helptext();

if ( key == ‘t’ ) {

test = !test;

}

}

hm, that looks still like the older version?
no, found many improvements/options, will take some time to merge it.
thanks for the feedback.
try anyhow:
http://kll.engineering-news.org/kllfusion01/downloads/shape_spirograph.zip
where i even made the excel file for you…

so, can you already show/link us your final work?

yes! it’s even already printed and will be shown as a flag in the center of munich!

2 Likes