How to code 3 magnets?

Hi, what i need is less an actualy magnet, than an object that attracts at a higher distance and pushes back if closer. Though not as simple as that.

It should basically end up being stuck on a perimeter around the 2st magnet, but if the third ones attraction becomes greater, that position should shift towards it, again being stuck inbetween all 3 magnets… Like where the center of a triangle would be. But i need it for many more magnets later on…

I’m stuck on this for over a month now… I remade 8 sketches all over again, just in hopes it would end up good…

The problem i keep getting every time, is that the 3rd magnet, even though it seems to take into account its distance to the 2nd magnet, still ends up inside it… I don’t know how or why…

Now, as mentioned, i have 8 sketches, but they are all basically useless… I also already asked something similar once, but that didn’t bring me much closer…

Anything like some formula to calculate this, or an actual code/class, or even a p5.js (my project is not p5.js) that implements this would be very much appreciated.

Also, the code/s i have so far can just be scrapped, and don’t do much else, except fail, so there’s no real use in posting them…

Might be a bit confusing, but it actually just comes down to a simulation of 3 magnets. Also, should be 2D, but 3D would also be appreciated :sweat_smile:

Also, i found some p5.js (just as a reference on how to do it) on openProcessing, but that doesn’t make much sense to me…

1 Like

I am not an expert in physics libraries, but I would guess they could have a way to implement something like this. Physics library always manage forces. Gravity is the most common one. I would think some physic library could implement repel/attractive forces at the same time but also honoring object’s spatial dimensions. This last part, when the particles that are being attracted touch each other, then the objects should stop advancing towards each other as internal (repelling) EM forces would take over.

On the other hand, you could implement this yourself if you take simple a approach. For instance, if you limit your objects to move along a line. I am assuming you have round magnets (like coin shape) and one side is N and the opposite side is south. If you get two magnets facing each other in a way that north is align to north, you experience a repelling force. Otherwise you will get an attractive force. Notice that if you have a repelling force, theoretically your objects will fly apart forever, unless you introduce some sort of air fiction or you limit the force range and limit the object position in your canvas.

Notice that working with objects along a straight line is just a trivial case. It will help you develop your algorithm if you don’t want to use the physics libraries. After you understand and master the linear sketch, then you can move to a second sketch where you implement something more complex.

Now, if you share the sketch that is more relevant (out of the 8 ones) to your problem, that is a good start as it will show your approach and you could get feedback based on this code.

Kf

2 Likes

I didn’t really explain it well, but even though i said magnet, they don’t have north or south poles. They just repel at a distance/ attract if far enough away. And the further they are the less the force is. In math terms it would be something like Repulsion = sqrt(distance) and attraction = 10/distance. So they would be equal at a certain point, in this case at 2.16~.

And this part i totally got to work, though the representation is still lacking, but it works. The problem is, that the 3rd object didn’t notice that it works… I’ll just add the latest code (i messed with it earlier and didn’t get it back to have the points really stand out… i think i did it with sqrt, but it did just say NaN after i tried to put it in again, and i just didn’t find a reason…)

Note that it’s not my most beatiful work, but after the 8th time redoing… well…

final PVector GRID_DISTANCE = new PVector(10, 10);
final PVector GRID_SIZE = new PVector(100, 50);
final PVector GRID_POSITION = new PVector(5, 5);

float[][] values = new float[int(GRID_SIZE.x)][int(GRID_SIZE.y)];
PVector[] points = {new PVector(40, 20), new PVector(30, 30), new PVector(50, 30), new PVector(10, 40)};

float valueMultiplier = 1;

String mode = "";

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

void draw() {
  background(0);
  fill(0);
  text(valueMultiplier, GRID_SIZE.x*GRID_DISTANCE.x/2, GRID_SIZE.y*GRID_DISTANCE.y-220, 400);
  fill(255);
  continuousKeyEvent();
  //rotateX(radians(45));
  //translate(0, -200, -200);
  camera(GRID_SIZE.x*GRID_DISTANCE.x/2, GRID_SIZE.y*GRID_DISTANCE.y, 600, GRID_SIZE.x*GRID_DISTANCE.x/2, GRID_SIZE.y*GRID_DISTANCE.y/2, 0, 0, 1, 0);
  points[0].set(map(mouseX, 0, width, 0, GRID_SIZE.x), map(mouseY, 0, height, 0, GRID_SIZE.y));
  createGrid();
  updateMesh();
  testMovement();
  drawPoints();
  println(getAverageValue());
  println(values[(int)points[0].x][(int)points[0].y]);
}

float getAverageValue() {
  float average = 0;
  for (int i = 0; i < values.length; i++) {
    for (int j = 0; j < values[i].length; j++) {
      average += values[i][j];
    }
  }
  average /= GRID_SIZE.x*GRID_SIZE.y;
  return average;
}

void drawPoints() {
  for (int i = 0; i < points.length; i++) {
    translate(points[i].x*GRID_DISTANCE.x + GRID_POSITION.x, points[i].y*GRID_DISTANCE.y + GRID_POSITION.y, values[(int)points[i].x][(int)points[i].y]);
    stroke(255, 0, 0);
    sphere(5);
    translate(-points[i].x*GRID_DISTANCE.x + GRID_POSITION.x, -points[i].y*GRID_DISTANCE.y + GRID_POSITION.y, -values[(int)points[i].x][(int)points[i].y]);
  }
}

void testMovement() {
  points[3].set(points[3].x + getMin(0), points[3].y + getMin(1));
  points[3].set(constrain(points[3].x, 5, GRID_SIZE.x-5), constrain(points[3].y, 5, GRID_SIZE.y-5));
}

int getMin(int a) {
  float min = values[(int)points[3].x][(int)points[3].y-1] < values[(int)points[3].x][(int)points[3].y] ? values[(int)points[3].x][(int)points[3].y-1] : values[(int)points[3].x][(int)points[3].y];
  int x = 0;
  int y = 1;
  if (values[(int)points[3].x][(int)points[3].y+1] < min && values[(int)points[3].x][(int)points[3].y+1] < 50) {
    min = values[(int)points[3].x][(int)points[3].y+1];
    y = -1;
  }
  if (values[(int)points[3].x-1][(int)points[3].y] < min && values[(int)points[3].x-1][(int)points[3].y] < 50) {
    min = values[(int)points[3].x-1][(int)points[3].y];
    x = 1;
  }
  if (values[(int)points[3].x+1][(int)points[3].y] < min && values[(int)points[3].x+1][(int)points[3].y] < 50) {
    min = values[(int)points[3].x+1][(int)points[3].y];
    x = -1;
  }
  return a == 0 ? x : a == 1 ? y : 0;
}

void createGrid() {
  stroke(0, 0, 255);
  noFill();
  for (int x = 0; x<GRID_SIZE.x; x++) {
    beginShape();
    for (int y = 0; y< GRID_SIZE.y; y++) {
      //stroke(map(values[x][y], getAverageValues()-getAverageValues()/10, getAverageValues()+ getAverageValues()/10, 0,100)*2);
      vertex( (x)*GRID_DISTANCE.x + GRID_POSITION.x, (y)*GRID_DISTANCE.y+GRID_POSITION.y, values[x][y]);
    }
    endShape();
  }
  for (int y = 0; y<GRID_SIZE.y; y++) {
    beginShape();
    for (int x = 0; x<GRID_SIZE.x; x++) {
      vertex( (x)*GRID_DISTANCE.x+GRID_POSITION.x, (y)*GRID_DISTANCE.y+GRID_POSITION.y, values[x][y]);
    }
    endShape();
  }
}

void updateMesh() {
  for (int x=0; x < values.length; x++) {
    for (int y=0; y < values[x].length; y++) {
      values[x][y] = 0;
      for (int i = 0; i < points.length; i++) {
        values[x][y] -= dist(points[i].x, points[i].y, x, y);
      }
      values[x][y] = map(1/values[x][y], 0, 1, 0, -200);
      values[x][y] *= valueMultiplier;
    }
  }
}

void continuousKeyEvent() {
  if (keyPressed) {
    if (!(key ==CODED)) {
      switch (key) {
      case 'm' :
        mode = "Value Multiplier";
        break;
      case ENTER :
        println("b");
        break;
      }
    } else {
      switch (keyCode) {
      case UP :
        if (mode.equals("Value Multiplier")) {
          valueMultiplier += 0.1;
        }
        break;
      case DOWN :
        if (mode.equals("Value Multiplier")) {
          valueMultiplier -= 0.1;
        }
        break;
      }
    }
  }
}
1 Like

What you are talking about is a system of magnets and if you consider a particular magnet then you must accumulate the forces on it from all the other magnets.

The sketch below demonstrates one way of doing this. You will probably want to modify it to suit your own purpose.

final int NBR_MAGNETS = 20;

Magnet[] magnet = new Magnet[NBR_MAGNETS];

void setup() {
  size(400, 400, P2D);
  initMagnets();
}

/**
 * Create enough magnets to fill the array.
 */
void initMagnets() {
  for (int m = 0; m < magnet.length; m++) {
    magnet[m] = new Magnet(random(width), random(height));
  }
}

void draw() {
  background(0, 0, 64);
  fill(200, 200, 255);
  text("Click mouse to start again", 10, 20);
  calculateMagnetInteractionForces();
  for (int m = 0; m < magnet.length; m++) {
    magnet[m].move();
    magnet[m].render();
  }
}

/**
 * Create new magnets when the mouse is clicked.
 */
void mouseClicked() {
  initMagnets();
}

/**
 * For each unique pair of magnets calculate the force between them
 * and accumulate them to give an overall force.
 */
void calculateMagnetInteractionForces() {
  for (int i = 0; i < magnet.length - 1; i++) {
    for (int j = i + 1; j < magnet.length; j++) {
      magnet[i].addForceFromMagnet(magnet[j]);
      magnet[j].addForceFromMagnet(magnet[i]);
    }
  }
}

/**
 * Simple class to represent a magnet.
 */
public class Magnet {

  private PVector pos = new PVector();
  private PVector force  = new PVector();
  // Experiment with this value to give a pleasing visual effect
  private float forceScale = 0.006f;

  public Magnet(float x, float y) {
    pos.x = x;
    pos.y = y;
  }

  /**
   *  Calculate the force being applied to this magnet by another and 
   *  accumulate the value so we get the overall force for this magnet.
   */
  public void addForceFromMagnet(Magnet m) {
    // Calculate distance between magnets
    PVector fvec = PVector.sub(pos, m.pos);
    float dist = fvec.mag(); // distance to other magnet
    // Create a unit vector in the direction of the force
    fvec.div(dist);
    // Calculate magnitude of attractive force
    float forceMagnitude = sqrt(dist) - 100f / (dist + 0.0001f);
    forceMagnitude *= forceScale;
    // Calculate the overall force from the other magnet
    fvec.mult(forceMagnitude);
    // Accumulate magnetic forces to get overall force on this magnet
    force.add(fvec);
  }

  /**
   * Move the magnet based on the accumulated forces from all other magnets
   */
  public void move() {
    pos.sub(force);
    force.set(0, 0); // reset for next time step
  }

  /**
   * Display the magnet
   */
  public void render() {
    pushMatrix();
    translate(pos.x, pos.y);
    fill(255, 64, 64);
    noStroke();
    ellipse(0, 0, 4, 4);
    popMatrix();
  }
}
3 Likes

Thanks, thats exactly what i needed :sweat_smile:

1 Like