#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# ArrayList

edited April 2017

I have this code that draws a parametric line animation on the screen:

float t; int lines = 15;

``````void setup(){
size(500, 500);
}

void draw(){
background(0);
translate(width/2, height/2);
strokeWeight(5);
for(int i = 0; i < lines; i++){
stroke(255);
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.1;
}

float x1(float t){
return sin(t/10)*100;
}

float y1(float t){
return cos(t/10)*100;
}

float x2(float t){
return sin(t/20)*200;
}

float y2(float t){
return cos(t/20)*200;
}
``````

I was wondering if I could use an ArrayList in order to store this parametric function and call it in the draw function? I would setup the for loop and the (x1, x2, y1, y2) functions in a class and then store that curve in index  of the array. I'm asking this, because I want to make two or three different functions that could be stored in indices  &  of the array so that a user could select or delete a certain curve via some key press event.

If that won't work I suppose I could still have a key press event in the draw function and setup multiple for loops for each function. If that's the case I'd ask if it's possible to set up a key press statement where you press a key and the function is drawn, then if you press the key again the function is deleted or stops drawing itself?

Tagged:

«1

• this

I would setup the for loop and the (x1, x2, y1, y2) functions in a class and then store that curve in index  of the array.

is a nice idea and would work

• Got it. I just decided to go with a standard array:

Main

``````Parametric[] functions = new Parametric;

void setup(){
size(600, 500);
functions = new Parametric();
}

void draw(){
background(0);
translate(width/2, height/2);
stroke(255);
if(keyPressed){
if (key == '1'){
functions.draw_function1();
}
}
}
``````

Class

``````class Parametric {
float t;
static final int lines = 15;

Parametric() {
t = 0;
}

void draw_function1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.1;
}

float x1(float t) {
return sin(t/10)*100;
}

float y1(float t) {
return cos(t/10)*100;
}

float x2(float t) {
return sin(t/20)*200;
}

float y2(float t) {
return cos(t/20)*200;
}

}
``````

Now I'm back to the issue of key pressing. I want to have it where the user can press the key '1' and the curve will start drawing, then if the user presses '1' again the curve will stop drawing. I imagine it'll be some combination of `keyPressed()`and a boolean value. I noticed you have to hold down the key when you use that function, though.

• keyPressed (te variable) might behave differently as it is based on OS and user keyboard configuration.

For your challenge, I'd use keyReleased(). Using a boolean value sounds perfect. You can add this value inside your class.

Kf

• when you want the function graph to grow visibly, you can use the fact that draw() in itself loops automatically. 1 starts and stops it.

Also, you need a key to change this:

``````   functions.draw_function1();
``````

in my opinion use an int index variable and change its value on key

``````   functions[indexFunction].draw_function1();
``````
• Alright, so this worked for 1 function, but for 2 it's not exactly doing what I want.

Main

``````Parametric[] functions = new Parametric;
boolean one, two;
int n1, n2;

void setup(){
size(600, 500);
functions = new Parametric();
functions = new Parametric();
n1 = 1;
n2 = 1;
}

void draw(){
background(0);
translate(width/2, height/2);
if(one){
stroke(255);
functions.draw_function(1.5);
}
if(two){
stroke(250, 200, 255);
functions.draw_function(-1.5);
}
}

void keyReleased(){
if(key == '1' && functions.user_key(n1)){
one = true;
}
else{
one = false;
}

if(key == '2' && functions.user_key(n2)){
two = true;
}
else{
two = false;
}

n1 = n1 * -1;
n2 = n2 * -1;
}
``````

Class

``````class Parametric {
float t;
static final int lines = 15;
boolean input;

Parametric() {
t = 0;
}

void draw_function(float k) {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
line(x1(k*i+t), y1(k*i+t), x2(k*i+t), y2(k*i+t));
}
t+=0.1;
}

float x1(float t) {
return sin(t/10)*100;
}

float y1(float t) {
return cos(t/10)*100;
}

float x2(float t) {
return sin(t/20)*200;
}

float y2(float t) {
return cos(t/20)*200;
}

boolean user_key(int n){
t = n;
if(t == 1){
input = true;
}
if(t == -1){
input = false;
}
return input;
}
}
``````

It works, but my logic isn't quite clever enough. I want each function to stay up with the others as long as the button has been pressed. So, if there are 4 functions and the user presses '1' '2' '3' '4' all 4 functions will be on the screen. And if the user then presses '3' again the function 3 disappears. Basically each will be independent of the others.

• as said, just change `indexFunction` in this:

`functions[indexFunction].draw_function1();`

• ??

it's much complicater than this, you need a different formula for each object from the class.

this is an example: `class State`

``````    class Button{
int x,y;
Button(int ix, int iy){
x=ix;
y=iy;
}
void draw(){
fill(0,0,255);
rect(x,y,20,20);
}
void onMousePress(){
if(mouseX>x&&mouseX<x+20&&mouseY>y&&mouseY<y+20){
println("click");
}
}
}

class LargeButton extends Button{
LargeButton(int ix, int iy){
super(ix,iy);
}
void draw(){
fill(0,0,255);
rect(x,y,40,40);
}
void onMousePress(){
if(mouseX>x&&mouseX<x+40&&mouseY>y&&mouseY<y+40){
println("CLICK");
}
}
}

class NextButton extends Button{
NextButton(int ix, int iy){
super(ix,iy);
}
void draw(){
fill(255,0,255);
rect(x,y,40,40);
}
void onMousePress(){
if(mouseX>x&&mouseX<x+40&&mouseY>y&&mouseY<y+40){
currentState++;
}
}
}

class State {
int id;
State() {
id = states.size();
println("Base class State constructor - created State " + id );
}
void draw() {
}
void onMousePress() {
}
}

class StartScreenState extends State {
String welcomeText;
StartScreenState() {
super();
welcomeText = "Welcome to the Start Screen State!";
}
void draw() {
background(0);
fill(255);
text(welcomeText, 20, 20);
}
void onMousePress() {
currentState++;
}
}

class CounterState extends State {
int counter;
CounterState() {
super();
}
void draw() {
background(64);
fill(255);
text(counter, 20, 20);
}
void onMousePress() {
counter++;
if (counter==11) {
currentState++;
}
}
}

class ButtonState extends State {
ArrayList<Button> buttons;
ButtonState() {
super();
buttons = new ArrayList();
}
void draw() {
background(128,0,0);
for(int i=0; i<buttons.size();  buttons.get(i++).draw() );
}
void onMousePress() {
for(int i=0; i<buttons.size();  buttons.get(i++).onMousePress() );
}
}

class EndState extends State {
EndState() {
super();
}
void draw() {
background(128);
fill(255);
text("DONE", 20, 20);
}
void onMousePress() {
}
}

ArrayList<State> states = new ArrayList();
int currentState = 0;

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

void draw() {
states.get(currentState).draw();
}

void mousePressed() {
states.get(currentState).onMousePress();
}
``````
• Alright, so I definitely need to switch to an ArrayList first. but I see how it's a bit more complex.

The example should hopefully help. Thanks.

• edited April 2017

Sorry, I've never dealt with the extend method.

In my example does that mean I only need to write my x1,x2,y1,y2 functions in the base class and then can access in every other class by using extend?

• I don't know

I guess so

• extend is not a method, it is a keyword. I don't know exactly what it's called though. Maybe @GoToLoop will know?
In any case,
`class B extends A{` means that B is a sublclass of A. Which means that all functions in A can also be used in B. Same for variables. Read about inheritance in Java for more info.

• edited April 2017

I've implements parts of what's been suggested. Had to use some `abstract` methods to get it to work correctly. Here is the basic layout so far:

``````ArrayList<Parametric> parametrics = new ArrayList();

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

void draw(){
background(0);
translate(width/2, height/2);
if(keyPressed){
if(key == '1'){
parametrics.get(0).function1();
}
}

if(keyPressed){
if(key == '2'){
parametrics.get(0).function2();
}
}
}

abstract class Parametric {
float t;
int lines = 15;

Parametric() {
t = 0;
}

abstract void function1();
abstract void function2();

float x1(float t) {
return sin(t/10)*100;
}

float y1(float t) {
return cos(t/10)*100;
}

float x2(float t) {
return sin(t/20)*200;
}

float y2(float t) {
return cos(t/20)*200;
}
}

class Functions extends Parametric {
void function1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(255);
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.1;
}

void function2(){
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(250, 200, 255);
line(x1(t-1.5*i), y1(t-1.5*i), x2(t-1.5*i), y2(t-1.5*i));
}
t+=0.1;
}
}
``````
• I edited my above code. It works now, but I'm still working out how to get all functions to independently draw and stop drawing to the screen via pushing a number key. I'll try using `keyRelease()` again with a Boolean value.

• you are doing it wrong.

in your approach, the ArrayList holds only one member, not many.

maybe one of the gurus can shed a light here

this is wrong:

``````    class Functions extends Parametric {
void function1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(255);
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.1;
}

void function2(){
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(250, 200, 255);
line(x1(t-1.5*i), y1(t-1.5*i), x2(t-1.5*i), y2(t-1.5*i));
}
t+=0.1;
}
}
``````

it should be independent classes:

``````    class FunctionHyperbolic extends Parametric {

@ Override void function() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(255);
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.1;
}
} // end of class!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

class FunctionSomethingFancy extends Parametric {

@ Override void function() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(250, 200, 255);
line(x1(t-1.5*i), y1(t-1.5*i), x2(t-1.5*i), y2(t-1.5*i));
}
t+=0.1;
}
} // end of class!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
``````

the trick is although you have independent classes, they can all be in the same ArrayList since they all have the same base class Parametric

a link has been given to you by gotoloop

there you'll find a similar example:

``````    // https : // forum.Processing.org/two/discussion/21321/change-method#Item_5
// GoToLoop (2017-Mar-31)

static final int BOTS = 3;
final Bot[] bots = new Bot[BOTS];

void setup() {
size(500, 400);
noLoop();

noStroke();
rectMode(CORNER);
ellipseMode(CENTER);

createBots();
}

void draw() {
clear();
for (final Bot b : bots)  b.ai();
}

void createBots() {
final int x2 = width  >> 1, x3 = width  / 3;
final int h2 = height >> 1, h3 = height / 3;

bots = new TargetBot(25, h2 - h3/2, h3, #0000FF);
bots = new FriendlyBot(x2, h2, h3, #FFFF00);
bots = new EnemyBot(2*x3, h2 - h3/2, h3, #FF0000);
}

abstract class Bot {
int x, y, d, c;

Bot(int px, int py, int pd, color pc) {
x = px;
y = py;
d = pd;
c = pc;
}

abstract void ai();
}

class TargetBot extends Bot {
TargetBot(int x, int y, int d, color c) {
super(x, y, d, c);
}

@ Override void ai() {
fill(c);
rect(x, y, d, d);
}
}

class FriendlyBot extends Bot {
FriendlyBot(int x, int y, int d, color c) {
super(x, y, d, c);
}

@ Override void ai() {
fill(c);
ellipse(x, y, d, d);
}
}

class EnemyBot extends Bot {
EnemyBot(int x, int y, int d, color c) {
super(x, y, d, c);
}

@ Override void ai() {
fill(c);
rect(x, y, d, d*1.5);
}
}
``````
• but based on your approach:

``````ArrayList<Parametric> parametrics = new ArrayList();

int indexForFunctions=0;

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

void draw() {
background(0);

fill(255);
text("Press 1 or 2 ", 19, 19);

translate(width/2, height/2);
switch(indexForFunctions) {
case 0:
parametrics.get(0).function1();
break;
case 1:
parametrics.get(0).function2();
break;
}//switch
}

void keyPressed() {

if (key == '1') {
indexForFunctions=0;
} else if (key == '2') {
indexForFunctions=1;
}
}

// ==============================================

abstract class Parametric {
float t;
int lines = 15;

Parametric() {
t = 0;
}

abstract void function1();
abstract void function2();

float x1(float t) {
return sin(t/10)*100;
}

float y1(float t) {
return cos(t/10)*100;
}

float x2(float t) {
return sin(t/20)*200;
}

float y2(float t) {
return cos(t/20)*200;
}
}

class Functions extends Parametric {

void function1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(255);
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.1;
}

void function2() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(250, 200, 255);
line(x1(t-1.5*i), y1(t-1.5*i), x2(t-1.5*i), y2(t-1.5*i));
}
t+=0.1;
}
}
``````
• @Chrisir To prevent your "@Override" from becoming a link, put a space between @ and Override.

While your example is right, I feel it is a bit incomplete - there's barely any point in making two classes for the same thing.

• @PRouse what is your aim here? If it is indeed what I think, even despite @Chrsir's additions it wouldn't be quite okay.

• Lord_of_the_Galaxy:

I fixed the @ Override issue thanks.

you also wrote:

there's barely any point in making two classes for the same thing.

that was merely an example as how to write the functions (post 8:37 am). Of course they must later hold different functions like the ai's in gotoloops example

Maybe the `extend` approach is too complicate

instead you could have a `switch` for function type and then store all into one class

• Sorry, I'm still learning to get everything clean and concise with my code. Thanks for the input.

@Lord_of_the_Galaxy: As far as what I'm trying to do -- I was making a program where a user can independently press multiple number keys and get different parametric functions to draw on the screen, and then if they press the number again it stops drawing. I'm also going to allow the user to control the number of lines (just now implemented that), and I want the user to be able to pick from a few different colors for each set of lines.

• Based on Wikipedia's definition of "function"

In mathematics, a function is a relation between a set of inputs and a set of permissible outputs with the property that each input is related to exactly one output.

I would say that all you really need is an interface `Function`.

``````interface Function{
float f(float x);//renamed to f
}
``````
• @Chrisir I suppose that you're in the right, our OP's approach has probably been wrong in the first place.

• @Lord_of_the_Galaxy Yea, I know what a function is.

I know my approach is likely wrong, as I having to pick this up as I go. What's needed first is to get something that works, and so far it's working correctly. I'll clean it up as I go, which is why I appreciate the input.

• I never said you didn't know what a function is. I always assume the worst, so in case someone doesn't know, for them it's there. In any case, the point was that a single interface is all you should be using. Try it, it looks a lot better.

• @PRouse

Can you add a second piece of code showing what a second parametric function will look like?

Now:

If that won't work I suppose I could still have a key press event in the draw function and setup multiple for loops for each function. If that's the case I'd ask if it's possible to set up a key press statement where you press a key and the function is drawn, then if you press the key again the function is deleted or stops drawing itself?

I will manage the keyEvent at the draw level. You are setting up an array that has your functions. Based on keyEvents, you choose what array to show. I don't understand your delete events though. Do you want to delete a parametric function or lines drawn when you have selected one of those parametric functions? I would suggest instead of deleting, you can hide. I will need to understand your concept before going further.

Here is my attempted to show what you can do with your code. As soon as you clarify some of my doubts, I could show you a better approach of doing this, even maybe using interfaces.

Kf

``````//INSTRUCTIONS: Press a key from 1 to 3

ArrayList<Function> functions = new ArrayList();
int currentFunction = 0;
boolean one;

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

void draw() {
background(0);
translate(width/2, height/2);

strokeWeight(5);
stroke(255);
functions.get(currentFunction).drawFunction1();
surface.setTitle("Selection: "+currentFunction);
}

//boolean function_choice() {
//  functions.get(currentFunction).keyReleased();
//  if (currentFunction == 1) {
//    one = true;
//  } else {
//    one = false;
//  }
//}

void keyReleased() {

//Maps from char "numeric" to array position
int pos=key-'1';
if (pos>=0&&pos<functions.size())
currentFunction=pos;
}

class Function {
float t;
int lines;

Function() {
t = 0;
lines = 15;
}

float x1(float t) {
return sin(t/10)*100;
}

float y1(float t) {
return cos(t/10)*100;
}

float x2(float t) {
return sin(t/20)*200;
}

float y2(float t) {
return cos(t/20)*200;
}

public void drawFunction1() {
text("Not implemented", 0, 0);
}
}

class Function_One extends Function {

Function_One() {
super();
}

@ Override
void drawFunction1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.1;
text("Fun1", 0, 0);
}
}

class Function_X extends Function {

Function_X() {
super();
}

@ Override
void drawFunction1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.80;
text("FunX", 0, 0);
}
}
``````
• I tried some of the ideas suggested. The switch doesn't seem to be working, when I press 1 or 2 nothing shows up. Also the interface Function throws an error when I try to set it up.

Error: The member interface Function can only be defined inside a top-level class or interface or in a static context.

``````ArrayList<Parametric> parametrics = new ArrayList();
int indexFunctions = 0;
int numLines;
static final int maxLines = 85;

void setup(){
size(700, 700);
numLines = 5;
}

void draw(){
background(0);
fill(255);
text("Press 1 or 2", 19, 19);
translate(width/2, height/2);

switch(indexFunctions){
case 0:
parametrics.get(0).function_1();
break;
case 1:
parametrics.get(0).function_2();
break;
}
}

void keyPressed(){
if(key == '1'){
indexFunctions = 0;
} else if (key == '2') {
indexFunctions = 1;
}

//allows lines number to be changed
if(key == CODED){
if(keyCode == UP && (numLines <= maxLines)){
numLines++;
}
}
if(key == CODED){
if(keyCode == DOWN && (numLines > 1)){
numLines--;
}
}
}

class Functions extends Parametric {
int lines;

void set_lines(int l){
lines = l;
}

void function_1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(255); //white
line(f1(x+1.5*i), f2(x+1.5*i), f3(x+1.5*i), f4(x+1.5*i));
}
x+=0.05;
}

void function_2(){
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(198, 226, 255); //blue
line(f1(x-1.5*i), f2(x-1.5*i), f3(x-1.5*i), f4(x-1.5*i));
}
x+=0.05;
}
}

abstract class Parametric{
float x;

Parametric(){
x = 0;
}

abstract void set_lines(int l);
abstract void function_1();
abstract void function_2();

//interface Function{
float f1(float x){
return sin(x/10)*100;
}
float f2(float x){
return cos(x/10)*100;
}
float f3(float x){
return sin(x/20)*200;
}
float f4(float x){
return cos(x/20)*200;
}
//}
}
``````
• Apparently I'm confusing everyone about what I want done, so here's the code that does exactly that (it's probably not clean and concise, but it works):

``````ArrayList<Parametric> parametrics = new ArrayList();
int n1, n2, numLines;
static final int maxLines = 15;
boolean one, two;

void setup(){
numLines = 5;
size(700, 700);
n1 = 1; n2 = n1;
}

void draw(){
background(0);
fill(255);
text("Press 1 or 2 for animation. Press again to hide animation", 19, 19);
text("Press UP or Down key to increase or decrease number of lines", 19, 30);
translate(width/2, height/2);
parametrics.get(0).set_lines(numLines);
if(one){
parametrics.get(0).function_1();
}
if(two){
parametrics.get(0).function_2();
}
}

void keyPressed(){
if(key == CODED){
if(keyCode == UP && (numLines <= maxLines)){
numLines++;
}
}
if(key == CODED){
if(keyCode == DOWN && (numLines > 1)){
numLines--;
}
}
}

void keyReleased(){
if(key == '1' && n1 == 1){
one = true;
n1 = n1 * -1;
}
else if(key == '1' && n1 == -1){
one = false;
n1 = n1 * -1;
}

if(key == '2' && n2 == 1){
two = true;
n2 = n2 * -1;
}
else if(key == '2' && n2 == -1){
two = false;
n2 = n2 * -1;
}
}

class Functions extends Parametric {
int lines;

void set_lines(int l){
lines = l;
}

void function_1() {
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(255); //white
line(x1(t+1.5*i), y1(t+1.5*i), x2(t+1.5*i), y2(t+1.5*i));
}
t+=0.05;
}

void function_2(){
strokeWeight(5);
for (int i = 0; i < lines; i++) {
stroke(198, 226, 255); //blue
line(x1(t-1.5*i), y1(t-1.5*i), x2(t-1.5*i), y2(t-1.5*i));
}
t+=0.05;
}
}

abstract class Parametric{
float t;

Parametric(){
t = 0;
}

abstract void set_lines(int l);
abstract void function_1();
abstract void function_2();

float x1(float t) {
return sin(t/10)*100;
}
float y1(float t) {
return cos(t/10)*100;
}
float x2(float t) {
return sin(t/20)*200;
}
float y2(float t) {
return cos(t/20)*200;
}
}
``````

I also wanted to ask, with the `text()`, can you add a variable in? For example, if I wanted to print the number of lines via the numLines variable.

• `text(""+numLines ,posX,posY);`

Kf

• Notice my last code in my post had an error due to the forum formatting. Make sure the code reads "@Override" as I had to add a space so it wasn't changed by the forum formatting. Or you can remove those lines. There are two of them.

One needs to understand better the function of your code before trying to design the class layout.

You have two features in your code:

1. You draw a n number of lines per function
2. You draw those lines where their position are defined by a parametric equation

In concept you only need a class called function.

Notice that the difference between function 1 and 2 is the direction of the parametric calculation. In concept you will have:

class fun{ maxLines.....make it int final parametric values... the x()'s and y()'s functions number of lines dir....either +1 or -1 color visibleStatus...Boolean void drawLine() }

In setup():
Add functions to your array. A function is defined by nLines,dir,visible status,color

In draw():
You traverse your array and show those lines with the visible flag set to true.

In key Event:
1. Increase decrease the number of lines (all the objects in the array or just the one being shown?)
2. Toggle what lines to show in the array

However, this approach only works if you function uses only x1,y1,x2,y2 definitions and you want to create multiples objects with the same values.

If you want to include some other parametric equation then you need to modify the function above. In the constructor, you need to define those values as well. Easy and done. Another approach (you don't have to) is to use OOP.

One parent class defines what you need. Any subclasses re-defines what is defined in the parent class. Now the parent class can be a class or an interface. But it really depends on your requirement. If you provide a better description of what a parametric line is in your context, or how many models you want to implement, then one could suggest if you should stick to a single class or if it is worth it to migrate to using extended classes. From what you show in your last code, I will stick to a simple class as I discussed above.

Kf

• You're correct, though I want one last feature:

1. Allow user to change color of each set of lines.

I'll have a list of colors to pick from, and set up small squares somewhere on the screen that show the current color for each set (those squares will pop up and disappear along with each function).

As far as increasing and decreasing the lines, I'll stick with all the functions.

I'm only using x1, y1, x2, y2, but I am going to use additions of sines and cosines to give the lines a more unique path. I also have 8 different functions, each unique. I was just using the current two while getting the program to work. It still seem's easier to set all 8 functions up in one extended class, since they all use the same variables (t and lines) and the x1, y1, x2, y2, and use the parent class to define x1, y1, x2, y2, and the variables used. I don't quite understand how interfaces work and what makes them better to use, so I think I'll stick with the abstract class.

• Or you could try using the QScript library by @quark.

http://www.lagers.org.uk/qscript/index.html

• It still seem's easier to set all 8 functions up in one extended class, since they all use the same variables (t and lines) and the x1, y1, x2, y2, and use the parent class to define x1, y1, x2, y2, and the variables used.

I don't think you need to use extended or abstract classes. When you build an object of your design, you only need to define:

1. The set of cos/sin functions associated to the curve
2. The dt step length
3. The color
4. A visibility flag
5. Number of lines

You define all these values in the object constructor and then call the object's `display()`function (equivalent to your `drawFunction1();` ) in draw.

Then you manage the number of lines, visible curves and their color in the main draw() function.

At the bottom on the left menu there is also a discussion about abstract classes.

About the buttons, you can use something like the following class. You need to adapt it to manage color after a click action.

Kf

``````Button b1;
String onClickStr="";
int counter=0;

void setup() {
size(600, 400);
rectMode(CORNER);
textAlign(CENTER, CENTER);
b1=new Button("Tap me!", width*0.2, 200, width*0.6, 50);
}

void draw() {
background(92);
b1.Draw();

if (b1.MouseIsOver()==true) {
text("On button", width/2.0, height*0.75);
} else {
text("Away from button", width/2.0, height*0.75);
}

if (counter>0) {
text(onClickStr, width/2.0, height*0.9);
counter--;
}
}

void mouseReleased() {
if (b1.MouseIsOver()==true) {
onClickStr="Clicked on Button!!!";
} else {
onClickStr="Clicked outside of button";
}
counter=60;  //Display message for about 2 secs
}

class Button {
String label;
float x;
float y;
float w;
float h;

// constructor
Button(String labelB, float xpos, float ypos, float widthB, float heightB) {
label = labelB;
x = xpos;
y = ypos;
w = widthB;
h = heightB;
}

void Draw() {
fill(218);
stroke(141);
rect(x, y, w, h, 10);
textAlign(CENTER, CENTER);
fill(0);
text(label, x + (w / 2), y + (h / 2));
}

boolean MouseIsOver() {
if (mouseX > x && mouseX < (x + w) && mouseY > y && mouseY < (y + h)) {
return true;
}
return false;
}
}
``````
• So, I changed things up a bit. Instead of having different functions I just made a bunch of equations that can be used in sets. I tried using the constructor to pass arguments and do the bulk in the Parametric class, but there's a few problems. It skips through the number of lines too quickly, which is because it's doing it all at once in `draw()`, but I need to use the `keyPressed()` method for selection. It's the same with picking the set of equations and dt. I also need to figure out how to use my flags correctly in order to have one function show up at a time, starting with zero. And translate doesn't seem to be working correctly. There are lines showing up at the corners of the screen.

``````Parametric p;
int numLines = 1;
int equationSet = 1;

void setup(){
size(700, 700);
p = new Parametric(numLines);
}

void draw(){
background(0);

fill(255);
text("Press 1 through 4 for animation. Press again to hide animation", 19, 20);
text("Press UP or Down key to increase or decrease number of lines", 19, 40);
text("Lines = " + p.draw_lines1(), 19, 50);
text("Press Right or Left key to change equation set", 19, 70);
text("Set = " + p.draw_lines2(), 19, 80);
text("Press Spacebar to increase speed", 19, 100);
text("Speed " + p.speed(), 19, 110);

p.keyPressed();
translate(width/2, height/2);
p.draw_lines1();
p.draw_lines2();
}

class Parametric {
Functions x;
int lines, n1, n2, n3, n4, set;
static final int maxLines = 25;
float dt, t, a, b, c, d;

Parametric(int numLines) {
x = new Functions();
n1 = 1; n2 = 1; n3 = 1; n4 = 1;
a = 1; b = 1; c = 1; d = 1;
lines = numLines;
set = 1;
}

float speed(){
return dt;
}

int draw_lines1() {
strokeWeight(3);
stroke(255);

if (set == 1) {
for (int i = 0; i < lines; i++) {
line(x.f1(i*a+t*b), x.f2(i*a+t*b), x.f3(i*a+t*b), x.f4(i*a+t*b));
}
t += dt;
} else if (set == 2) {
for (int i = 0; i < lines; i++) {
line(x.f5(i*a+t*b), x.f6(i*a+t*b), x.f7(i*a+t*b), x.f8(i*a+t*b));
}
t += dt;
} else if (set == 3) {
for (int i = 0; i < lines; i++) {
line(x.f9(i*a+t*b), x.f10(i*a+t*b), x.f11(i*a+t*b), x.f12(i*a+t*b));
}
t += dt;
} else if (set == 4) {
for (int i = 0; i < lines; i++) {
line(x.f13(i*a+t*b), x.f14(i*a+t*b), x.f15(i*a+t*b), x.f16(i*a+t*b));
}
t += dt;
}
return lines;
}

int draw_lines2() {
strokeWeight(3);
stroke(255);

if (set == 1) {
for (int i = 0; i < lines; i++) {
line(x.f1(d*i+t*c), x.f2(d*i+t*c), x.f3(d*i+t*c), x.f4(d*i+t*c));
}
t += 0.2;
} else if (set == 2) {
for (int i = 0; i < lines; i++) {
line(x.f5(d*i+t*c), x.f6(d*i+t*c), x.f7(d*i+t*c), x.f8(d*i+t*c));
}
t += 0.2;
} else if (set == 3) {
for (int i = 0; i < lines; i++) {
line(x.f9(d*i+t*c), x.f10(d*i+t*c), x.f11(d*i+t*c), x.f12(d*i+t*c));
}
t += 0.2;
} else if (set == 4) {
for (int i = 0; i < lines; i++) {
line(x.f13(d*i+t*c), x.f14(d*i+t*c), x.f15(d*i+t*c), x.f16(d*i+t*c));
}
t += 0.2;
}
return set;
}

void keyPressed() {
if (key == CODED) {
if (keyCode == UP && (lines < maxLines)) {
lines++;
}
}
if (key == CODED) {
if (keyCode == DOWN && (lines > 1)) {
lines--;
}
}
if (key == CODED) {
if (keyCode == LEFT && (set > 1)) {
set--;
}
}
if (key == CODED) {
if (keyCode == RIGHT && (set < 4)) {
set++;
}
}

if (key == ' ') {
dt+=0.02;
}
if (dt > 0.1) {
dt = 0;
}

if (key == '1' && n1 == 1) {
n1 = n1 * -1;
a = 1.5;
b = 1;
} else if (key == '1' && n1 == -1) {
n1 = n1 * -1;
}
if (key == '2' && n2 == 1) {
n2 = n2 * -1;
a = -1.5;
b = -1;
} else if (key == '2' && n2 == -1) {
n2 = n2 * -1;
}
if (key == '3' && n3 == 1) {
n3 = n3 * -1;
c = 0.5;
d = -1;
} else if (key == '3' && n3 == -1) {
n3 = n3 * -1;
}
if (key == '4' && n4 == 1) {
n4 = n4 * -1;
c = -0.5;
d = 1;
} else if (key == '4' && n4 == -1) {
n4 = n4 * -1;
}
}
}

class Functions {

float f1(float x) {
return sin(x/20)*100 + sin(x/5)*20;
}
float f2(float x) {
return cos(x/10)*100 + cos(x/2)*2;
}
float f3(float x) {
return sin(x/10)*200 + sin(x/2)*2;
}
float f4(float x) {
return sin(x/20)*200 + cos(x/12)*20;
}
float f5(float x) {
return sin(x/15)*100 + sin(x/2);
}
float f6(float x) {
return cos(x/25)*200 + cos(x/4)*10;
}
float f7(float x) {
return sin(x/25)*200 + sin(x/8)*10;
}
float f8(float x) {
return cos(x/15)*100 + cos(x/16);
}
float f9(float x) {
return sin(x/10)*100 + sin(x/4)*12;
}
float f10(float x) {
return cos(x/20)*100 + cos(x/10);
}
float f11(float x) {
return sin(x/20)*200 + sin(x/4)*12;
}
float f12(float x) {
return cos(x/10)*200 + cos(x/10);
}
float f13(float x) {
return sin(x/10)*100 + sin(x/5)*20;
}
float f14(float x) {
return cos(x/10)*100 + cos(x);
}
float f15(float x) {
return sin(x/10)*200 + sin(x)*2;
}
float f16(float x) {
return cos(x/20)*200 + cos(x/12)*20;
}
}
``````
• This code works exactly how I want it to, other than adding color selection. However, I don't know if it's good practice to write it this way.

``````Parametric p;
int numLines = 5;
int equationSet = 1;
int n1, n2, n3, n4;
static final int maxLines = 25;
float dt = 0, a, b, c;
boolean visible1, visible2, visible3, visible4;

void setup() {
size(700, 700);
n1 = 1; n2 = 1; n3 = 1; n4 = 1;
a = 1.5; b = 0.5; c = 1;
p = new Parametric();
}

void draw() {
background(0);

fill(255);
text("Press 1 through 4 for animation. Press again to hide animation", 19, 20);
text("Press UP or Down key to increase or decrease number of lines", 19, 40);
text("Lines = " + numLines, 19, 50);
text("Press Right or Left key to change equation set", 19, 70);
text("Set = " + equationSet, 19, 80);
text("Press Spacebar to increase speed", 19, 100);
text("Speed " + dt, 19, 110);

translate(width/2, height/2);
if (visible1) {
p.draw_lines1(equationSet, numLines, dt, a, c);
} if (visible2) {
p.draw_lines1(equationSet, numLines, dt, -a, -c);
} if (visible3) {
p.draw_lines2(equationSet, numLines, dt, b, -c);
} if (visible4) {
p.draw_lines2(equationSet, numLines, dt, -b, c);
}
}

void keyPressed() {
if (key == CODED) {
if (keyCode == UP && (numLines < maxLines)) {
numLines++;
}
}
if (key == CODED) {
if (keyCode == DOWN && (numLines > 1)) {
numLines--;
}
}
if (key == CODED) {
if (keyCode == LEFT && (equationSet > 1)) {
equationSet--;
}
}
if (key == CODED) {
if (keyCode == RIGHT && (equationSet < 4)) {
equationSet++;
}
}

if(key == ' '){
dt+=0.02;
}
if(dt > 0.1){
dt = 0;
}

if (key == '1' && n1 == 1) {
visible1 = true;
n1 = n1 * -1;
} else if (key == '1' && n1 == -1) {
visible1 = false;
n1 = n1 * -1;
}
if (key == '2' && n2 == 1) {
visible2 = true;
n2 = n2 * -1;
} else if (key == '2' && n2 == -1) {
visible2 = false;
n2 = n2 * -1;
}
if (key == '3' && n3 == 1) {
visible3 = true;
n3 = n3 * -1;
} else if (key == '3' && n3 == -1) {
visible3 = false;
n3 = n3 * -1;
}
if (key == '4' && n4 == 1) {
visible4 = true;
n4 = n4 * -1;
} else if (key == '4' && n4 == -1) {
visible4 = false;
n4 = n4 * -1;
}
}

class Parametric {
Functions x;
int lines, set;
float t, a, b, c, d;

Parametric() {
x = new Functions();
}

void draw_lines1(int equationSet, int numLines, float dt, float multi_a, float multi_b) {
strokeWeight(3);
stroke(255);
a = multi_a;
b = multi_b;
lines = numLines;
set = equationSet;

if (set == 1) {
for (int i = 0; i < lines; i++) {
line(x.f1(i*a+t*b), x.f2(i*a+t*b), x.f3(i*a+t*b), x.f4(i*a+t*b));
}
t += dt;
} else if (set == 2) {
for (int i = 0; i < lines; i++) {
line(x.f5(i*a+t*b), x.f6(i*a+t*b), x.f7(i*a+t*b), x.f8(i*a+t*b));
}
t += dt;
} else if (set == 3) {
for (int i = 0; i < lines; i++) {
line(x.f9(i*a+t*b), x.f10(i*a+t*b), x.f11(i*a+t*b), x.f12(i*a+t*b));
}
t += dt;
} else if (set == 4) {
for (int i = 0; i < lines; i++) {
line(x.f13(i*a+t*b), x.f14(i*a+t*b), x.f15(i*a+t*b), x.f16(i*a+t*b));
}
t += dt;
}
}

void draw_lines2(int equationSet, int numLines, float dt, float multi_c, float multi_d) {
strokeWeight(3);
stroke(255);
c = multi_c;
d = multi_d;
lines = numLines;
set = equationSet;

if (set == 1) {
for (int i = 0; i < lines; i++) {
line(x.f1(d*i+t*c), x.f2(d*i+t*c), x.f3(d*i+t*c), x.f4(d*i*c));
}
t += dt;
} else if (set == 2) {
for (int i = 0; i < lines; i++) {
line(x.f5(d*i+t*c), x.f6(d*i+t*c), x.f7(d*i+t*c), x.f8(d*i+t*c));
}
t += dt;
} else if (set == 3) {
for (int i = 0; i < lines; i++) {
line(x.f9(d*i+t*c), x.f10(d*i+t*c), x.f11(d*i+t*c), x.f12(d*i+t*c));
}
t += dt;
} else if (set == 4) {
for (int i = 0; i < lines; i++) {
line(x.f13(d*i+t*c), x.f14(d*i+t*c), x.f15(d*i+t*c), x.f16(d*i+t*c));
}
t += dt;
}
}
}

class Functions {

float f1(float x) {
return sin(x/20)*100 + sin(x/5)*20;
}
float f2(float x) {
return cos(x/10)*100 + cos(x/2)*2;
}
float f3(float x) {
return sin(x/10)*200 + sin(x/2)*2;
}
float f4(float x) {
return sin(x/20)*200 + cos(x/12)*20;
}
float f5(float x) {
return sin(x/15)*100 + sin(x/2);
}
float f6(float x) {
return cos(x/25)*200 + cos(x/4)*10;
}
float f7(float x) {
return sin(x/25)*200 + sin(x/8)*10;
}
float f8(float x) {
return cos(x/15)*100 + cos(x/16);
}
float f9(float x) {
return sin(x/10)*100 + sin(x/4)*12;
}
float f10(float x) {
return cos(x/20)*100 + cos(x/10);
}
float f11(float x) {
return sin(x/20)*200 + sin(x/4)*12;
}
float f12(float x) {
return cos(x/10)*200 + cos(x/10);
}
float f13(float x) {
return sin(x/10)*100 + sin(x/5)*20;
}
float f14(float x) {
return cos(x/10)*100 + cos(x);
}
float f15(float x) {
return sin(x/10)*200 + sin(x)*2;
}
float f16(float x) {
return cos(x/20)*200 + cos(x/12)*20;
}
}
``````
• To be true, it's certainly not good practice to write it in this way. It's really difficult to se what you're trying to do here. Are you trying to graph some functions? In fact, if I were to guess, there's completely no point in using classes the way you're doing it.

• @PRouse -- beautiful animation once you turn all the segments on, increase the line count to 25, speed up the steps, and then cycle through the sets.

• @Lord_of_the_Galaxy

Nope, not trying to graph anything. If that were the case I'd need to actually draw a graph with some sort of coordinate system, my code has nothing of the sort in it. Just trying to do some neat mathematical animations and allowing the user some input as @jeremydouglass pointed out (thanks by the way).

I was using classes because that was suggested as a better method, and it allows me to break things up into tabs instead of just writing 221 lines of code straight. I'm not sure if you can see the whole discussion thread or not, but I've listed multiple times what I'm attempting to do with the code. The last code I gave in my previous post works nicely and does what I want other than color options (which I'm working on). But I guess it is, as you say, not good practice in the way it is written. My apologies, I'm still learning...which is why I've appreciated all the advice up to now.

• edited April 2017

Finished it. Everything surprisingly works well. Thanks @kfrajer for suggesting the button class example, it worked out nicely.

``````Parametric p;
Button b1;

int numLines = 10;
static final int maxLines = 25;
int equationSet = 1;
float dt, a, b, c;
int n1, n2, n3, n4;
boolean visible1, visible2, visible3, visible4;
int counter1, counter2, counter3, counter4;
color col1, col2, col3, col4;

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

n1 = 1; n2 = 1; n3 = 1; n4 = 1;
a = 1.5; b = 0.5; c = 1;
col1 = color(#FFFFFF);
col2 = color(#FFFFFF);
col3 = color(#FFFFFF);
col4 = color(#FFFFFF);
counter1 = 2;
counter2 = 2;
counter3 = 2;
counter4 = 2;

p = new Parametric();
b1 = new Button(20, 20);
}

void draw() {
background(0);

//directions for user input
fill(255);
text("Press 1 through 4 to make lines and color boxes visible. Press again to hide.", 19, 20);
text("Press Up or Down key to increase or decrease number of lines", 19, 40);
text("Lines = " + numLines, 19, 50);
text("Press Right or Left key to change equation set", 19, 70);
text("Set = " + equationSet, 19, 80);
text("Press Spacebar to increase speed", 19, 100);
text("Speed = " + dt, 19, 110);
text("Click on a numbered box to change line color", 19, 140);

if (visible1){
b1.draw_button("1", col1, 20, 160);
}
if (visible2){
b1.draw_button("2", col2, 20, 200);
}
if (visible3){
b1.draw_button("3", col3, 20, 240);
}
if (visible4){
b1.draw_button("4", col4, 20, 280);
}

translate(width/2, height/2);
if (visible1) {
p.draw_lines1(col1, equationSet, numLines, dt, a, c);
} if (visible2) {
p.draw_lines1(col2, equationSet, numLines, dt, -a, -c);
} if (visible3) {
p.draw_lines2(col3, equationSet, numLines, dt, b, -c);
} if (visible4) {
p.draw_lines2(col4, equationSet, numLines, dt, -b, c);
}
}

//for controlling line color
void mouseReleased(){
if(b1.mouse_is_over(20, 160) == true){
if(counter1 == 1){
col1 = color(#FFFFFF);
}
else if(counter1 == 2){
col1 = color(#C6E2FF);
}
else if(counter1 == 3){
col1 = color(#F6546A);
}
else if(counter1 == 4){
col1 = color(#D2B4FF);
}
else if(counter1 == 5){
col1 = color(#D3FFCE);
}
else if(counter1 == 6){
col1 = color(#FFF68F);
}
else if(counter1 == 7){
col1 = color(#FFC390);
}
counter1++;
if(counter1 > 7){
counter1 = 1;
}
}

if(b1.mouse_is_over(20, 200)  == true){
if(counter2 == 1){
col2 = color(#FFFFFF);
}
else if(counter2 == 2){
col2 = color(#C6E2FF);
}
else if(counter2 == 3){
col2 = color(#F6546A);
}
else if(counter2 == 4){
col2 = color(#D2B4FF);
}
else if(counter2 == 5){
col2 = color(#D3FFCE);
}
else if(counter2 == 6){
col2 = color(#FFF68F);
}
else if(counter2 == 7){
col2 = color(#FFC390);
}
counter2++;
if(counter2 > 7){
counter2 = 1;
}
}

if(b1.mouse_is_over(20, 240)  == true){
if(counter3 == 1){
col3 = color(#FFFFFF);
}
else if(counter3 == 2){
col3 = color(#C6E2FF);
}
else if(counter3 == 3){
col3 = color(#F6546A);
}
else if(counter3 == 4){
col3 = color(#D2B4FF);
}
else if(counter3 == 5){
col3 = color(#D3FFCE);
}
else if(counter3 == 6){
col3 = color(#FFF68F);
}
else if(counter3 == 7){
col3 = color(#FFC390);
}
counter3++;
if(counter3 > 7){
counter3 = 1;
}
}

if(b1.mouse_is_over(20, 280)  == true){
if(counter4 == 1){
col4 = color(#FFFFFF);
}
else if(counter4 == 2){
col4 = color(#C6E2FF);
}
else if(counter4 == 3){
col4 = color(#F6546A);
}
else if(counter4 == 4){
col4 = color(#D2B4FF);
}
else if(counter4 == 5){
col4 = color(#D3FFCE);
}
else if(counter4 == 6){
col4 = color(#FFF68F);
}
else if(counter4 == 7){
col4 = color(#FFC390);
}
counter4++;
if(counter4 > 7){
counter4 = 1;
}
}
}

//for controlling animation visibility, number of lines, equation set
void keyPressed() {
if (key == CODED) {
if (keyCode == UP && (numLines < maxLines)) {
numLines++;
}
}
if (key == CODED) {
if (keyCode == DOWN && (numLines > 1)) {
numLines--;
}
}
if (key == CODED) {
if (keyCode == LEFT && (equationSet > 1)) {
equationSet--;
}
}
if (key == CODED) {
if (keyCode == RIGHT && (equationSet < 4)) {
equationSet++;
}
}

if(key == ' '){
dt+=0.02;
}
if(dt > 0.06){
dt = 0;
}

if (key == '1' && n1 == 1) {
visible1 = true;
n1 = n1 * -1;
} else if (key == '1' && n1 == -1) {
visible1 = false;
n1 = n1 * -1;
}
if (key == '2' && n2 == 1) {
visible2 = true;
n2 = n2 * -1;
} else if (key == '2' && n2 == -1) {
visible2 = false;
n2 = n2 * -1;
}
if (key == '3' && n3 == 1) {
visible3 = true;
n3 = n3 * -1;
} else if (key == '3' && n3 == -1) {
visible3 = false;
n3 = n3 * -1;
}
if (key == '4' && n4 == 1) {
visible4 = true;
n4 = n4 * -1;
} else if (key == '4' && n4 == -1) {
visible4 = false;
n4 = n4 * -1;
}
}

class Button{
float w, h;
color c;

Button(float widthB, float heightB){
w = widthB;
h = heightB;
}

void draw_button(String num, color col, float xpos, float ypos){
fill(col);
stroke(255);
rect(xpos, ypos, w, h);
fill(255);
text(num, xpos + 30, ypos + 20);
}

boolean mouse_is_over(float mx, float my) {
if (mouseX > mx && mouseX < (mx + w) && mouseY > my && mouseY < (my + h)) {
return true;
}else{
return false;
}
}
}

class Equations {

//set 1
float f1(float x) {
return sin(x/20)*100 + sin(x/5)*20;
}
float f2(float x) {
return cos(x/10)*100 + cos(x/2)*2;
}
float f3(float x) {
return sin(x/10)*200 + sin(x/2)*2;
}
float f4(float x) {
return sin(x/20)*200 + cos(x/12)*20;
}

//set 2
float f5(float x) {
return sin(x/15)*100 + sin(x/2);
}
float f6(float x) {
return cos(x/25)*200 + cos(x/4)*10;
}
float f7(float x) {
return sin(x/25)*200 + sin(x/8)*10;
}
float f8(float x) {
return cos(x/15)*100 + cos(x/16);
}

//set 3
float f9(float x) {
return sin(x/10)*100 + sin(x/4)*12;
}
float f10(float x) {
return cos(x/20)*100 + cos(x/10);
}
float f11(float x) {
return sin(x/20)*200 + sin(x/4)*12;
}
float f12(float x) {
return cos(x/10)*200 + cos(x/10);
}

//set 4
float f13(float x) {
return sin(x/10)*100 + sin(x/5)*20;
}
float f14(float x) {
return cos(x/10)*100 + cos(x);
}
float f15(float x) {
return sin(x/10)*200 + sin(x)*2;
}
float f16(float x) {
return cos(x/20)*200 + cos(x/12)*20;
}
}

class Parametric {
Equations x;
int lines, set;
float t, a, b, c, d; //a b, c, and d are for the multiplicative constants
// used in the draw lines methods.

Parametric() {
x = new Equations();
}

void draw_lines1(color col1, int equationSet, int numLines, float dt, float multi_a, float multi_b) {
strokeWeight(3);
stroke(col1);
a = multi_a;
b = multi_b;
lines = numLines;
set = equationSet;

if (set == 1) {
for (int i = 0; i < lines; i++) {
line(x.f1(i*a+t*b), x.f2(i*a+t*b), x.f3(i*a+t*b), x.f4(i*a+t*b));
}
t += dt;
} else if (set == 2) {
for (int i = 0; i < lines; i++) {
line(x.f5(i*a+t*b), x.f6(i*a+t*b), x.f7(i*a+t*b), x.f8(i*a+t*b));
}
t += dt;
} else if (set == 3) {
for (int i = 0; i < lines; i++) {
line(x.f9(i*a+t*b), x.f10(i*a+t*b), x.f11(i*a+t*b), x.f12(i*a+t*b));
}
t += dt;
} else if (set == 4) {
for (int i = 0; i < lines; i++) {
line(x.f13(i*a+t*b), x.f14(i*a+t*b), x.f15(i*a+t*b), x.f16(i*a+t*b));
}
t += dt;
}
}

void draw_lines2(color col2, int equationSet, int numLines, float dt, float multi_c, float multi_d) {
strokeWeight(3);
stroke(col2);
c = multi_c;
d = multi_d;
lines = numLines;
set = equationSet;

if (set == 1) {
for (int i = 0; i < lines; i++) {
line(x.f1(d*i+t*c), x.f2(d*i+t*c), x.f3(d*i+t*c), x.f4(d*i*c));
}
t += dt;
} else if (set == 2) {
for (int i = 0; i < lines; i++) {
line(x.f5(d*i+t*c), x.f6(d*i+t*c), x.f7(d*i+t*c), x.f8(d*i+t*c));
}
t += dt;
} else if (set == 3) {
for (int i = 0; i < lines; i++) {
line(x.f9(d*i+t*c), x.f10(d*i+t*c), x.f11(d*i+t*c), x.f12(d*i+t*c));
}
t += dt;
} else if (set == 4) {
for (int i = 0; i < lines; i++) {
line(x.f13(d*i+t*c), x.f14(d*i+t*c), x.f15(d*i+t*c), x.f16(d*i+t*c));
}
t += dt;
}
}
}
``````
• Actually, you don't need to use classes to break up your code into tabs L-)

• Yea, I guess I just thought classes would make it a little more organized. I'm working on coding it correctly, as I know you're supposed to pass all variables via the constructor and do the bulk in those classes. I do too much in `setup()` and `draw()` and should not really be passing variables to the methods inside the classes.

I suppose I could do nothing but functions, but I feel like that would be unorganized.

• @Prouse -- nice sketch results. Reviewing your code I notice that you have hard-coded parameter arguments as special cases everywhere.

My main suggestion for improvement would be, given that your parametrics all take the form `sin|cos(x/div1)*mult1 + sin|cos(x/div2)*mult2` you should simplify your equation class a lot and then get rid of all the special cases for equations that you have everywhere.

Here is an example of an Equation object -- it stores its arguments and returns the two wave components when you call Object.f(x):

``````class Equation {
String wav1, wav2;
float div1, div2, mult1, mult2;
Equation(String wav1_, float div1_, float mult1_, String wav2_, float div2_, float mult2_) {
wav1 = wav1_;  div1 = div1_;  mult1 = mult1_;
wav2 = wav2_;  div2 = div2_;  mult2 = mult2_;
}
float f(float x) {
return component(x, wav1, div1, mult1) + component(x, wav2, div2, mult2);
}
float component(float x, String wav, float div, float mult) {
if (wav.equals("sin") == true) { return sin(x/div)*mult; }
else { return cos(x/div)*mult; }
}
}
``````

Here is a global array of 4 sets of 4 equations each:

``````Equation[][] eqSets = new Equation;
``````

...and here is setup() code that defines each of your Equations using their parameters:

``````  eqSets = new Equation("sin", 20, 100, "sin", 5, 20);
eqSets = new Equation("cos", 10, 100, "cos", 2, 2);
eqSets = new Equation("sin", 10, 100, "sin", 2, 2);
eqSets = new Equation("sin", 20, 200, "cos", 12, 20);

eqSets = new Equation("sin", 15, 100, "sin", 2, 1);
eqSets = new Equation("cos", 25, 200, "cos", 4, 10);
eqSets = new Equation("sin", 25, 200, "sin", 8, 10);
eqSets = new Equation("cos", 15, 100, "cos", 16, 1);

eqSets = new Equation("sin", 10, 100, "sin", 4, 12);
eqSets = new Equation("cos", 20, 100, "cos", 10, 1);
eqSets = new Equation("sin", 20, 200, "sin", 4, 12);
eqSets = new Equation("cos", 10, 200, "cos", 10, 1);

eqSets = new Equation("sin", 10, 100, "sin", 5, 20);
eqSets = new Equation("cos", 10, 100, "cos", 1, 1);
eqSets = new Equation("sin", 10, 200, "sin", 1, 2);
eqSets = new Equation("cos", 20, 200, "cos", 12, 20);
``````

The final step is to rethink the parametric drawing. This could be a Parametric class object or it could be a function. You could pass it a single equation (`eqSets`) or pass it a set of equations(`eqSets`). In any case, the object doesn't contain multiple sets of special rules for specifically named equation sets -- it treats all equations equally, something like (untested):

``````float t = 0;
void draw_lines(Equation x, color col, int lines, float dt, float c, float d) {
strokeWeight(3);
stroke(col);
for (int i = 0; i < lines; i++) {
line(x.f(d*i+t*c), x.f(d*i+t*c), x.f(d*i+t*c), x.f(d*i*c));
}
t += dt;
}
``````
• Beautifully done, @jeremydouglass

• Thank you @jeremydouglass, that helped cut down on lines needed quite a bit. I cut down some lines a few other places too. I think this is formatted a little better.

A few problems though:

1) The key and mouse events I call to `draw()` are looping through to the end or beginning instead of going through one at a time. Is there a way to fix this, or do I need to do all mouse and key events outside of the class?

2) Even through I initially pass the color white for the buttons, when they become visible the fill is still black for all of them.

3) To print out the number of lines, the current set of equations in use, and the speed of the lines, I need the variables for those in the `text()` functions. So, I need a way to pass those from the Parametric class where they are updated.

``````Parametric p1, p2, p3, p4;

int numLines, n1, n2, n3, n4;
color col1, col2, col3, col4;
boolean show1, show2, show3, show4;

void setup(){
size(800, 800);
numLines = 10;
n1 = 1; n2 = 1; n3 = 1; n4 = 1;
col1 = color(#FFFFFF);
col2 = color(#FFFFFF);
col3 = color(#FFFFFF);
col4 = color(#FFFFFF);

p1 = new Parametric(numLines, col1, 1.5, 1);
p2 = new Parametric(numLines, col2, -1.5, -1);
p3 = new Parametric(numLines, col3, -1, 0.5);
p4 = new Parametric(numLines, col4, 1, -0.5);
}

void draw(){
background(0);

//directions for user input
fill(255);
text("Press 1 through 4 to make lines and color boxes visible. Press again to hide", 19, 20);
text("Press Up or Down key to increase or decrease number of lines", 19, 40);
text("Lines = ", 19, 50);
text("Press Right or Left key to change equation set", 19, 70);
text("Set = ", 19, 80);
text("Press Spacebar to increase speed", 19, 100);
text("Speed = ", 19, 110);
text("Click on a numbered box to change line color", 19, 140);

if (show1) {
p1.mouseReleased();
p1.draw_button1();
} if (show2) {
p2.mouseReleased();
p2.draw_button2();
} if (show3) {
p3.mouseReleased();
p3.draw_button3();
} if (show4) {
p4.mouseReleased();
p4.draw_button4();
}

translate(width/2, height/2);
if (show1) {
p1.keyPressed();
p1.draw_lines();
} if (show2) {
p2.keyPressed();
p2.draw_lines();
} if (show3) {
p3.keyPressed();
p3.draw_lines();
} if (show4) {
p4.keyPressed();
p4.draw_lines();
}
}

void keyPressed(){
if (key == '1' && n1 == 1) {
show1 = true;
n1 = n1 * -1;
} else if (key == '1' && n1 == -1) {
show1 = false;
n1 = n1 * -1;
}
if (key == '2' && n2 == 1) {
show2 = true;
n2 = n2 * -1;
} else if (key == '2' && n2 == -1) {
show2 = false;
n2 = n2 * -1;
}
if (key == '3' && n3 == 1) {
show3 = true;
n3 = n3 * -1;
} else if (key == '3' && n3 == -1) {
show3 = false;
n3 = n3 * -1;
}
if (key == '4' && n4 == 1) {
show4 = true;
n4 = n4 * -1;
} else if (key == '4' && n4 == -1) {
show4 = false;
n4 = n4 * -1;
}
}

class Parametric {
Button b1, b2, b3, b4;
Equation[][] set = new Equation;

int lines, equationSet, counter;
int maxLines = 15;
float a, b, t, dt;
color col;

Parametric(int num_lines, color col_n, float mult_a, float mult_b) {
lines = num_lines;
col = col_n;
a = mult_a;
b = mult_b;
t = 0;
equationSet = 1;
counter = 2;

b1 = new Button("1", col, 20, 160, 20, 20);
b2 = new Button("2", col, 20, 200, 20, 20);
b3 = new Button("3", col, 20, 240, 20, 20);
b4 = new Button("4", col, 20, 280, 20, 20);

set = new Equation("sin", 20, 100, "sin", 5, 20);
set = new Equation("cos", 10, 100, "cos", 2, 2);
set = new Equation("sin", 10, 100, "sin", 2, 2);
set = new Equation("sin", 20, 200, "cos", 12, 20);

set = new Equation("sin", 15, 100, "sin", 2, 1);
set = new Equation("cos", 25, 200, "cos", 4, 10);
set = new Equation("sin", 25, 200, "sin", 8, 10);
set = new Equation("cos", 15, 100, "cos", 16, 1);

set = new Equation("sin", 10, 100, "sin", 4, 12);
set = new Equation("cos", 20, 100, "cos", 10, 1);
set = new Equation("sin", 20, 200, "sin", 4, 12);
set = new Equation("cos", 10, 200, "cos", 10, 1);

set = new Equation("sin", 10, 100, "sin", 5, 20);
set = new Equation("cos", 10, 100, "cos", 1, 1);
set = new Equation("sin", 10, 200, "sin", 1, 2);
set = new Equation("cos", 20, 200, "cos", 12, 20);
}

void draw_button1(){
b1.draw_button();
}
void draw_button2(){
b2.draw_button();
}
void draw_button3(){
b3.draw_button();
}
void draw_button4(){
b4.draw_button();
}

void draw_lines() {
strokeWeight(3);
stroke(col);
if (equationSet == 1) {
for (int i = 0; i < lines; i++) {
line(set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b));
}
t+=dt;
} else if (equationSet == 2) {
for (int i = 0; i < lines; i++) {
line(set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b));
}
t+=dt;
} else if (equationSet == 3) {
for (int i = 0; i < lines; i++) {
line(set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b));
}
t+=dt;
} else if (equationSet == 4) {
for (int i = 0; i < lines; i++) {
line(set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b), set.f(a*i+t*b));
}
t+=dt;
}
}

void keyPressed() {
if (key == CODED) {
if (keyCode == UP && (lines < maxLines)) {
lines++;
}
}
if (key == CODED) {
if (keyCode == DOWN && (lines > 1)) {
lines--;
}
}
if (key == CODED) {
if (keyCode == LEFT && (equationSet > 1)) {
equationSet--;
}
}
if (key == CODED) {
if (keyCode == RIGHT && (equationSet < 4)) {
equationSet++;
}
}

if (key == ' ') {
dt+=0.02;
}
if (dt > 0.06) {
dt = 0;
}
}

void mouseReleased(){
if(b1.mouse_is_over() == true || b2.mouse_is_over() == true || b3.mouse_is_over() == true || b4.mouse_is_over() == true){
if(counter == 1){
col = color(#FFFFFF);
}
else if(counter == 2){
col = color(#C6E2FF);
}
else if(counter == 3){
col = color(#F6546A);
}
else if(counter == 4){
col = color(#D2B4FF);
}
else if(counter == 5){
col = color(#D3FFCE);
}
else if(counter == 6){
col = color(#FFF68F);
}
else if(counter == 7){
col = color(#FFC390);
}
counter++;
if(counter > 7){
counter = 1;
}
}
}
}

class Button{
String num;
float x, y, w, h;
float c;

Button(String num_, color col, float xpos, float ypos, float width_, float height_){
num = num_;
c = col;
x = xpos; y = ypos;
w = width_; h = height_;
}

void draw_button(){
fill(c);
stroke(255);
rect(x, y, w, h);
fill(255);
text(num, x+30, y+20);
}

boolean mouse_is_over(){
if(mouseX > x && mouseX < (x+w) && mouseY > y && mouseY < (y+h)){
return true;
}else{
return false;
}
}
}

class Equation{
String trig1, trig2;
float d1, d2, m1, m2;
Equation(String trig1_, float div1_, float mult1_, String trig2_, float div2_, float mult2_){
trig1 = trig1_; d1 = div1_; m1 = mult1_;
trig2 = trig2_; d2 = div2_; m2 = mult2_;
}
float f(float x){
return component(x, trig1, d1, m1) + component(x, trig2, d2, m2);
}
float component(float x, String trig, float div, float mult){
if(trig.equals("sin") == true){
return sin(x/div)*mult;
}else{
return cos(x/div)*mult;
}
}
}
``````
• Oh dear. Your code is so damn repetitive. @jeremydouglass may help set it right.

• @Lord_of_the_Galaxy

Not sure what I did to piss you off my Lord, but I apologize. I'd rather get some suggestions or advice, but if insults are your thing...have at it I guess.

• I'm not exactly pissed off, just commenting that despite being given an example, you resort to not using arrays. If you felt insulted, my apologies.

• Lines 159-178 can be replaced with this -

``````  for (int i = 0; i < lines; i++) {
line(set[equationSet-1].f(a*i+t*b), set[equationSet-1].f(a*i+t*b), set[equationSet-1].f(a*i+t*b), set[equationSet-1].f(a*i+t*b));
}
t+=dt;
``````
• lines 214-234 can be replaced by - `cols[counter-1]`, and at the top of the program, declare the array and initialise it with the required values, which I hope you know how to do, and thus leave to you.

• And in lines 183-202 do you notice how each of the four conditions check if `key==CODED`? That means that you can use an `if(key==CODED){` as on outer condition for all inner conditions at once.

• This is much smaller, and I certainly wouldn't expect a beginner to set it, but there's nothing wrong in learning. So lines 264-267 can be replaced with `return (mouseX > x && mouseX < (x+w) && mouseY > y && mouseY < (y+h));`. The outer brackets exist purely to help one see it properly.