Elements self positioning in equilateral triangle arrangement

Hi all,

I’m trying to produce a red draggable circle with two other circles dynamically adapting their positions to create equilateral triangle. Could you please suggest a better solution than the one i paste here?

Ideally, in the final code, all the circles should be draggable.
Thanks in advance for your help.

let x1 = 400;
let y1 = 200;
let x2 = 350;
let y2 = 350;
let x3 = 200;
let y3 = 350;
let spd = 3;


function setup() {
  createCanvas(800, 800);
}

function draw() {
  background(0);
  stroke(255);
  strokeWeight(4);
  let r = 20;
  push();
  fill('red');
  circle(x1, y1, r);
  pop();
  push();
  fill('blue');
  circle(x2, y2, r);
  pop();
  push();
  fill('green');
  circle(x3, y3, r);
  pop();
  

  if (mouseIsPressed) {
    
    var red_blue = createVector(x2 - x1, y2 - y1);
    var blue_green = createVector(x2 - x3, y2 - y3);
    var green_red = createVector(x3 - x1, y3 - y1);
   
    red_blue.normalize();
    blue_green.normalize();
    green_red.normalize();

    let d_rb = dist(x1, y1, x2, y2);
    let d_bg = dist(x2, y2, x3, y3);
    let d_gr = dist(x1, y1, x3, y3);
  
      if (d_rb - d_bg > 5) {
        x2 += blue_green.x * spd;
        y2 += blue_green.y * spd;
        x2 -= red_blue.x * spd;
        y2 -= red_blue.y * spd;
      } else if (d_rb - d_bg < -5){
        x2 -= blue_green.x * spd;
        y2 -= blue_green.y * spd;
        x2 += red_blue.x * spd;
        y2 += red_blue.y * spd;
      } 

      if (d_gr - d_rb > -5) {
        x3 -= green_red.x * spd;
        y3 -= green_red.y * spd;
        x3 -= blue_green.x * spd;
        y3 -= blue_green.y * spd;
      } else {
        x3 += green_red.x * spd;
        y3 += green_red.y * spd;
        x3 += blue_green.x * spd;
        y3 += blue_green.y * spd;
      }
  }
}


// To drag the red circle
function mouseDragged() {
  x1 = mouseX;
  y1 = mouseY;
}

1 Like

Replace with array of PVector

Then you can for loop over it

PVector[] list = new PVector[3]; (or whatever it is in p5.js)

Or make a class TriangleCorner that has a PVector in it and functions show() and mouseDragged()

The class represents one corner / circle

1 Like

Thank you Chrisir,

I think that if I create a triangle then all the circles will move at the same time (right?). The effect that I’m looking for is to move the red and then the other two will run to reach the right position and stop there.
Anyway I’ll try your suggestion …

I rather meant an array of the 3 points

1 Like

This is a really challenging problem and if I was to code this I would want to create a class to represent the ‘cicle’. Although it could be coded without the need for class it would be a real challenge and the code would be large, hard to maintain and difficult to scale up.
IIt’s made harder with this requirement -

Have you created classes in p5.js before?

3 Likes

here is a quick demo with an array of corner objects (of a class).

  • You can drag all 3 points.
  • You can see that draw() is much shorter now.
  • You have more of the intelligence of the Sketch inside the class
  • -1 means NONE or undefined

BUT

  • the points don’t move on their own (your part)
  • it’s processing java flavor, not p5.js
TriangleCorner[] list = new TriangleCorner[3];  
int drag_index = -1; 

// ------------------------------------------------------------------------------------------

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

  background(0);
  stroke(255); 

  list[0] = new TriangleCorner(400, 200, color(255, 0, 0)); 
  list[1] = new TriangleCorner(350, 350, color(0, 255, 0));
  list[2] = new TriangleCorner(200, 350, color(0, 0, 255));
}

void  draw() {
  background(0);

  // dragging ? 
  if  (drag_index != -1) {
    list[drag_index].setToMouse();
  } //if  

  // show lines 
  linePVector(list[0].pos, list[1].pos);
  linePVector(list[1].pos, list[2].pos);
  linePVector(list[2].pos, list[0].pos);

  // show circles
  for (TriangleCorner tc : list) {
    tc.show();
  }//for
} // func 

// ------------------------------------------------------------------------------------------

void mousePressed() {
  // search circle 

  drag_index=-1; // reset

  int i=0;
  for (TriangleCorner tc : list) {
    if (tc.nearMouse()) {
      drag_index=i; // set 
      return;
    }//if
    i++;
  }// for
}//func 

void mouseReleased() {
  drag_index=-1; // end dragging
}

void linePVector (PVector pv1, PVector pv2) {
  line(pv1.x, pv1.y, 
    pv2.x, pv2.y);
}//func 

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

class TriangleCorner {
  // 
  PVector pos;
  float r = 20;
  color col;

  //constr
  TriangleCorner (float x_, float y_, 
    color col_) {
    pos = new PVector(x_, y_);
    col = col_;
  }//constr

  void show() {
    fill(col);
    ellipse(pos.x, pos.y, r, r);
  }

  void setToMouse() {
    pos.x=mouseX; 
    pos.y=mouseY;
  }

  boolean nearMouse() {
    // returns true or false 
    return 
      dist(mouseX, mouseY, pos.x, pos.y) < 20;
  }//method
  //
}//class
// 

2 Likes

Thank you Quark, I have created classes but in general I’m a very beginner … I’ll try to explore the thing a little more.

Ahhh … now I understand.
Ok thank you for the code, it seems a nice inspiration.

1 Like

When looking at a problem like this it is good to try and describe the system / solution algorithms in natural language so here I go. I will call them balls for clarity.

Problem statement

  1. We have a system of 3 balls positioned at the vertices of an equilateral triangle.
  2. When any one of the balls is dragged then the other two will move to maintain their relative positions
  3. The 2 following balls movement will exhibit some form of inertia so arrive at the correct position some time after the dragged ball stops.

Initial thoughts
Since any ball can be dragged then there is no significant difference between balls and so we can have a single class to represent them. The only difference is in the behaviour between dragged and following balls.

Any realistic solution should be able to

  • handle any number of balls i.e. scalable.
  • any arrangement of stationary balls, not just the equilateral triangle

Possible mechanism
To simplify the discussion we will restrict ourselves to the 3 ball system. In out system we will have 4 objects, the 3 balls and a fourth which I will call the anchor which is invisible. To keep everything simple the anchor will be represented by another class which has the following attributes

  • position [x,y]
  • array of balls in the system - each ball remembers its current position on the screen
  • array of ball at rest positions [rx, ry] these are relative to the anchor position [x,y]

On every frame we update the balls position with the following algorithm

for every ball
  if the ball is being dragged then
    calculate the new position of the ball
    move the anchor so the ball is at its correct rest position relative to the ball
  if the ball is not being dragged then
    if the ball is not at its rest position relative to the anchor then move towards it. 

I would create this system in stages

  1. Create the Ball class with the basic attributes
    • a vector for its current screen position
  2. Create the Anchor class with the basic attributes - a vector its position
    • a vector for its current screen position
    • an array of balls making up the system
    • an array of vectors for the rest position for each ball
  3. Add a draw method to the Ball class
  4. Add a method to the Anchor to add a ball and its relative at rest postion
  5. Test this by creating and displaying simple systems (different arrangements of balls)
  6. Add a method to enable a ball to be dragged (several ways to do this)
  7. Add the update method to the Ball class but move the following balls instantaneously to their correct position
  8. Test the ball drag
  9. Modify the update method to add ‘inertia’ for the following balls
  10. Test it all out

I think you willl find this quite a challenge but it makes for a nice roadmap :smile:

2 Likes

Wow, thank you for the suggestions.
Let me see what I can do.

Have a wonderful weekend Peter.

1 Like

Here is a first experiment:
https://kunelab.webflow.io/resources/sysgame

It needs a little more work and in the end we don’t need to have every node draggable.

2 Likes

It looks great - well done :smile:

1 Like