How to connect ellipses with a line or with a pointing arrow?

edited January 2017 in Questions about Code

Hello everyone!

Before I ask a question I want to say that I am new on this forum and a newbie who just start to programm and who need some help. I go through eraser peel tutorial on Youtube and that's it. Oh and yes, I also watched some of the thenewboston tutorials on YT about HTML and CSS. Level of my Javascript knowladge is very low.

So, here is my question:

Right now, I can draw as many ellipses I want in my Sketch with mousePressed() function. This is my code:

And output(link)

What I want, and I don't know how to do, it to draw two ellipses, lets say Ellipse A and Ellipse B, and connect those two ellipses with line or pointing arrow. Something like that(click).

Thank you.

Tagged:

Answers

  • edited January 2017 Answer ✓

    Your sketch already draws a line, so I assume you understand that the line() function draws a line between two points.

    What you're really asking is: How can I remember the points?

    The answer is that you will need to remember the points.

    And you remember them with additional variables.

    You will need two additional variables for every point you want to remember. One is for the x-position of the point, and the other is for the y-position of the point.

    Here is a sketch with two variables. Notice how it can remember one point?

    float point_x_0;
    float point_y_0;
    
    void setup(){
      size(400,400);
      ellipseMode(CENTER);
    }
    
    void draw(){
      background(0);
      fill(255);
      ellipse(point_x_0, point_y_0, 10, 10);
    }
    
    void mousePressed(){
      point_x_0 = mouseX;
      point_y_0 = mouseY;
    }
    
  • edited January 2017 Answer ✓

    But being able to remember only one point is very limiting! You really want to remember a lot of points. So really you need a lot of additional variables.

    And then you also have to keep track of which variables to use next!

    And how many variables you are actually using!

    And what if you don't have enough? Or too many?

    What a pain!

    What you really need is a LIST of variables that you can add more onto as needed.

    Thankfully there is such a thing. It's called an ArrayList.

    You can add a new thing to an ArrayList with the .add() function.

    You can access the things in the ArrayList with the .get() function.

    You can know how many things are in the ArrayList with the .size() function (this is helpful for looping over the things in the ArrayList).

  • Answer ✓

    Here is an example:

    ArrayList x_positions = new ArrayList();
    ArrayList y_positions = new ArrayList();
    
    void setup() {
      size(400, 400);
      ellipseMode(CENTER);
    }
    
    void draw() {
      background(0);
      fill(255);
      for ( int i = 0; i < x_positions.size(); i++) {
        ellipse( (int) x_positions.get(i), (int) y_positions.get(i), 10, 10);
      }
    }
    
    void mousePressed() {
      x_positions.add( mouseX );
      y_positions.add( mouseY );
    }
    

    The first two lines define two different lists of numbers (1), and create those lists.

    In draw(), we now do a loop the happens however many times there are things in the x_positions ArrayList. For each thing in that list, we get the x-position (and also a y-position from the other list because we know they have the same lengths(2)), and then draw a spot at that position.

    When the mouse is pressed, we remember where it was pressed by adding those numbers to the correct ArrayLists.

    1) Actually there's a catch here. The one downside of ArraLists is that they have NO IDEA what kind of thing they are storing in them. WE know that what we are storing is a number, and that's why we have to cast (covert) the thing to a int when we get() it from the list.

    2) They have the same length because when we add a thing to one list, we also add a thing to the other list!

  • Answer ✓

    But anyway, adding lines is just doing another loop over the list of stored points.

    ArrayList x_positions = new ArrayList();
    ArrayList y_positions = new ArrayList();
    
    void setup() {
      size(400, 400);
      ellipseMode(CENTER);
    }
    
    void draw() {
      background(0);
      stroke(0,0,255);
      for ( int i = 0; i < x_positions.size()-1; i++) { // Also try i+=2 
        line( (int) x_positions.get(i), (int) y_positions.get(i), (int) x_positions.get(i+1), (int) y_positions.get(i+1) );    
      }
      noStroke();
      fill(255);
      for ( int i = 0; i < x_positions.size(); i++) {
        ellipse( (int) x_positions.get(i), (int) y_positions.get(i), 10, 10);
      }
    }
    
    void mousePressed() {
      x_positions.add( mouseX );
      y_positions.add( mouseY );
    }
    
  • Woow you guys are awesome! I didn't expect so quick respond! Thank you very much @TfGuy44 for the code and for explaination! Now I will go through this code and try to learn and analyze it. Really appreciate your help. Also thank you to @GoToLoop for additional literature.

  • edited January 2017

    So if I understand this correctly, every time I pressed on sketch, integer number of mouse position x is stored in ArrayList called x_positions and the same goes for y positions.

    And to get this numbers from ArrayList I need to call get method? And the size method tells me how many integer number are stored in Arraylist?

    Why in code line #12 we substract one from position.size() ?

  • I know the answer. -1 means every time go to the last index in ArrayList is that right?

  • edited January 2017 Answer ✓

    Let's say that there are three numbers in our list:

    [ 10, 21, 32 ]

    How many numbers in the list? Three.

    What's the first number? 10.

    How do you get the first number? .get(0)

    Notice that the first number, (1st number) is NOT at index 1! It is at index 0!

    How do I get the last number? .get(2)

    Notice that even though the list has a size of 3, I shouldn't do .get(3)!

    This is because .get(3) gets the fourth number - and there isn't a fourth number in the list.

    In short: Trying to access the size-th item in a list is a mistake. The indexes of the items go from 0 to size-1.

    Usually when looping, you make sure that your index is < the size (not <=, because it can't be equal to it!).

    But the loop that starts on line 12 is a little different. Look at the body of the loop. Inside the loop, I do a .get(i+1).

    Back to the three items case. If my index, i, goes from 0 to 2, and I try to .get(2+1), that's trying to .get(3)! Oh dear!


    That explanation wasn't so great. Simple version: That loop draws a line between the current point and the NEXT point. The first time the loop happens, it draws the line FROM the first TO the second point. The last time it happens, it needs to draw a line TO the last point - not FROM the last point. Where would such a line go? There is no NEXT point for the LAST point! We already covered the line going TO the last point when we did the second to last point! That's why this loop is "one less" than the other.


    Still hard to explain. Okay. So you have three points. You loop over them to draw them. 0. 1. 2. You don't loop a fourth time with index 3 because .get(3) gets the fourth things and there is no fourth thing. You loop runs while your index is less than size.

    You have three points. You want to do lines between them. You do 0 to 1. you do 1 to 2. Then you stop. You don't loop a third time for three things because you only draw two lines for three things. Your loop runs while your index is less than (one less than the size).

  • edited January 2017

    Great explanation. I understand it. Thank you very much. ^:)^

    Can you help me with this next thing: I would like, for the line between ellipse A and ellipse B, to disapear, when I add ellipse C (which crates the line between B and C). So that the penultimate line always disapear.

    I'll probably have to use if statment?

  • Yes. Only draw the line if the current index is not... well, try it yourself. Post the code of your attempt for more help.

  • edited January 2017

    I'm struggling. Give me one more clue. I know how if statments works, but don't know how to use it in this case.

    Do I need to use x_positions.remove() method? So when I add index 2 in my ArrayList, index 0 is removed. Again, I know how this method work, but don't know how to use it here.

  • Only draw the line if the current index is not... what?

    if( index != ........) {
        // draw 
    }
    
  • If I want to draw a line between 2nd and 3rd ellipse, I need index 1 and 2, and if I want to draw a line between 3rd and 4th ellipse, I need index 2 and 3. That's what I'm getting and what the program is doing all the time. Is that correct? I think it is.

    So, to delete previous line I need to delete previous index from ArrayList?

    I've asked all my school mates about solution of this condition you @Chrisir posted and nobody knows the answer. :))

  • I was just repeating what TfGuy44 posted....

  • edited January 2017

    There's no need to "delete" a line from your scene. Just don't draw it in the first place.

    It's a small detail I didn't mention, but your original code relies and what was drawn in the previous frame in order to draw the next frame. This is not a good practice - instead, you should redraw your entire scene every frame.

    This is why I added a call to background(). This clears away everything that was drawn previously. It's like a painter starting with a blank canvas.

    If you only want to draw one line, you only need to do so between two points. If your line is between the last point and the second to last point, those points are at indexes (size-1) and (size-2) on your list, right? You shouldn't even need to do a loop - just draw the one line with a call to line().

  • edited January 2017

    I've made progress thanks to you @TfGuy44. :)>-

    Now on my Sketch appears line between the last point and the second to last point. That's what I wanted.

    ArrayList x_positions = new ArrayList();
    ArrayList y_positions = new ArrayList();
     
    void setup() {
      size(400, 400);
      ellipseMode(CENTER); 
    }
    
    void draw() {
      background(0);
      stroke(0,0,255);
      for ( int i = 0; i < x_positions.size()-1; i++) { 
        line( (int) x_positions.get(x_positions.size()-1), (int) y_positions.get(y_positions.size()-1), (int) x_positions.get(x_positions.size()-2), (int) y_positions.get(x_positions.size()-2) );    
    }
      noStroke();
      fill(255);
      for ( int i = 0; i < x_positions.size(); i++) {
        ellipse( (int) x_positions.get(i), (int) y_positions.get(i), 10, 10);
      }
    }
     
    void mousePressed() {
      x_positions.add( mouseX );
      y_positions.add( mouseY );
    }
    

    But I also want that on my Sketch appears only the last ellipse and the second to last ellipse.

    I think that at ellipses I need to use background() but don't know how.

  • There are two ways to this.
    One:

    final static float ELLIPSE_SIZE = 10;
    float x = 0, y = 0, px = 0, py = 0;
    
    boolean current = false;
    boolean started = false;
    
    void setup(){
      size(400, 400);
      ellipseMode(CENTER);//its default really
    }
    
    void draw(){
      //change if you want
      background(0);
    
      if(started){
          //style however you want the ellipses
          ellipse(x, y, ELLIPSE_SIZE, ELLIPSE_SIZE);
          ellipse(px, py, ELLIPSE_SIZE, ELLIPSE_SIZE);
    
          //style for lines
          line(px, py, x, y);
      }
    }
    
    void mousePressed(){
      if(current){
        started = true;//start drawing
        x = mouseX;
        y = mouseY;
      }else{
        px = mouseX;
        py = mouseY;
      }
      current = !current;
    }  
    
  • edited January 2017

    @Lord_of_the_Galaxy thank you very much for the code. I'm really grateful for your help and to others for helping me. You guys are awesome!!!

    Can you explain me line 1 and line 35? What kind of data type is final static? What is this?

    And also now I am curious what's the second way to do such thing?

  • For line 1 - I did think I shouldn't have put that - it's not essential. They are both just keywords, not a data type. The data type is just float.
    For more info - final and static.

    As to line 35, it just sets the value of the Boolean variable current to its opposite, i.e. false if it was true and true otherwise.

  • In line 27, if I write if(current == true) gives me the same results as if(current)?

  • Is there any method to draw pointing arrow instead of line or do I need to draw another two lines to make a pointing arrow?

  • Yes, you have to draw two more lines to a pointing arrow.
    However, you can encapsulate it inside a function.

    void arrow(float x1, float y1, float x2, float y2, float s){
      line(x1, y1, x2, y2);
      pushMatrix();
      translate(x2, y2);
      float a = atan2(x1-x2, y2-y1);
      rotate(a);
      line(0, 0, -s, -s);
      line(0, 0, s, -s);
      popMatrix();
    } 
    

    (Adapted from here.)

  • Wow awesome! Don't know exactly what is atan but ok.

  • edited January 2017

    @kevo1414 -

    atan() is short for "arctangent" which means "the inverse trigonometric function of the tangent" -- in other words "the arc whose tangent = x"

    Here is the Processing reference page and demo sketch for atan2():

    Calculates the angle (in radians) from a specified point to the coordinate origin as measured from the positive x-axis. ... The atan2() function is most often used for orienting geometry to the position of the cursor.

    So LoG's solutions says:

    void arrow(float x1, float y1, float x2, float y2, float s){
      line(x1, y1, x2, y2); // draw a line
      pushMatrix(); // make temporary changes to the frame of reference
      translate(x2, y2); // move the drawing origin to the end of the line segment
      float a = atan2(x1-x2, y2-y1); // calculate the angle from the beginning of the line to the current origin (the end of the line)
      rotate(a); // rotate that amount -- now the line is straight up-and-down
      line(0, 0, -s, -s); // draw a 45 degree angle down ( left half of up-arrow )
      line(0, 0, s, -s); // draw a 45 degree angle (complimentary right half of up-arrow)
      popMatrix(); // move back to the original frame of reference, un-rotate -- now the line and arrow head are no longer straight up
    } 
    
  • Thank you! That's makes things clear for me. :-bd

  • And the pushMatrix is required in order to call popMatrix.
    https://processing.org/tutorials/transform2d/
    P.S. I don't know if you know about transformations, so there.

Sign In or Register to comment.