AABB moving towards a center collision response

This is a physics problem*

So I have a group of rectangles I am trying to movie towards a point. I wanted to prevent them from getting into each other so I developed a custom physics engine that detects rectangle collision.

my problem here is that I can’t seem to get the wanted behaviour at all.

Here is what I have :

Here is what I need as a result:

And Here is my current code and Gh file:

private void RunScript(int iterations, List<Rectangle3d> spaces, Polyline boundary, List<int> lineStartIndices, List<int> lineEndIndices, List<int> viewIndex, List<int> orientationIndex, List<Point3d> cardinals, double moveDistance, double collisionDistance, double approximationMultiplier, double orientationMultiplier, List<double> spaceProximityMultipliers, List<double> spaceOrientationMultipliers, bool iterationMode, bool start, bool reset, ref object Vectors, ref object A, ref object B, ref object C)
  {
    List<Line> collisionDisplay = new List<Line>();
    List<Line> collisionDisplay2 = new List<Line>();
    if(iterationMode)
    {
      tempSpaces = spaces;
      //--------------------------------------------------------------------
      //iterate is start button is set to true
      //--------------------------------------------------------------------

      for(int i = 0; i < iterations;i++)
        //    Parallel.For(0, iterations, i =>
      {
        var collision = new RectangleCollider(moveDistance, collisionDistance,
          approximationMultiplier, orientationMultiplier, boundary, tempSpaces);
        collision.MoveRectangles();
        collision.ApplyMove();

        tempSpaces = collision.ResultingSpacesArr.ToList();
      }
    }
    else
    {
      //--------------------------------------------------------------------
      //reset loop on switch press
      //--------------------------------------------------------------------
      if(reset || counter == 0)
      {
        tempSpaces = spaces;
        velocity = moveDistance;
        counter = 0;
      }
      //--------------------------------------------------------------------
      //iterate is start button is set to true
      //--------------------------------------------------------------------
      if(start)
      {
        GrasshopperDocument.ScheduleSolution(10, ScheduleSolutionCallback);
        //loop logic if start is true
        var collision = new RectangleCollider(velocity, collisionDistance,
          approximationMultiplier, orientationMultiplier, boundary, tempSpaces);
        collision.MoveRectangles();

        collision.CollideRectangles();
        collision.ApplyMove();

        tempSpaces = collision.ResultingSpacesArr.ToList();
        velocity = collision.MoveDistance;
        counter++;
        //output
        Vectors = collision.MovementVectors;
      }
    }

    //--------------------------------------------------------------------
    //output
    //--------------------------------------------------------------------
    //gh conversion
    var ghRects = new List<GH_Rectangle>();
    for(int i = 0; i < tempSpaces.Count; i++)
      ghRects.Add(new GH_Rectangle(tempSpaces[i]));
    var ghCollisionDisplay = new List<GH_Line>();
    for(int i = 0; i < collisionDisplay.Count; i++)
      ghCollisionDisplay.Add(new GH_Line(collisionDisplay[i]));
    var ghCollisionDisplay2 = new List<GH_Line>();
    for(int i = 0; i < collisionDisplay2.Count; i++)
      ghCollisionDisplay2.Add(new GH_Line(collisionDisplay2[i]));

    A = ghRects;
    B = ghCollisionDisplay;
    C = ghCollisionDisplay2;

    //display no of iterations on console
    Print("Iterations: " + (counter).ToString());
    Print("velocity: " + (velocity).ToString());
  }

  // <Custom additional code> 
  //params
  List<Rectangle3d> tempSpaces = new List<Rectangle3d>();
  double velocity;

  int counter;
  //iteration logic
  public void ScheduleSolutionCallback(GH_Document doc)
  {
    this.Component.ExpireSolution(false);
  }

  //--------------------------------------------------------------------
  //Collision class
  //--------------------------------------------------------------------
  public class RectangleCollider
  {
    public double MoveDistance;
    public double CollisionDistance;
    public double ApproximationMultiplier;
    public double OrientationMultiplier;
    public Polyline Boundary;
    public Point3d Center;
    public List<Rectangle3d> Spaces;
    public Rectangle3d[] ResultingSpacesArr;
    public Vector3d[ ] MovementVectors;
    public bool IsColliding = false;

    public RectangleCollider(double moveDistance, double collisionDistance,
      double approximationMultiplier, double orientationMultiplier,
      Polyline boundary, List<Rectangle3d> spaces)
    {
      MoveDistance = moveDistance;
      CollisionDistance = collisionDistance;
      ApproximationMultiplier = approximationMultiplier;
      OrientationMultiplier = orientationMultiplier;
      Boundary = boundary;
      Spaces = spaces;

      Center = boundary.CenterPoint();
      MovementVectors = new Vector3d[spaces.Count];
    }
    //Move Points
    public void MoveRectangles()
    {
      for(int i = 0; i < Spaces.Count; i++)
      {
        if(Spaces[i].Center.DistanceTo(Center) > 1 && !IsColliding)
        {

          Vector3d translationVector = Center - Spaces[i].Center;
          if(Math.Abs(Center.X - Spaces[i].Center.X) > Math.Abs(Center.Y - Spaces[i].Center.Y))
          {
            var xVector = new Vector3d(translationVector.X, 0, 0);
            xVector.Unitize();
            MovementVectors[i] += xVector * 0.5;
          }
          else
          {
            var yVector = new Vector3d(0, translationVector.Y, 0);
            yVector.Unitize();
            MovementVectors[i] += yVector * 0.5;
          }
        }
      }
    }
    //collide rectangles
    public void CollideRectangles()
    {
      Parallel.For(0, Spaces.Count, i =>
        {
        for(int j = 0; j < Spaces.Count; j++)
        {
          if(i != j)
          {
            var rect1MinX = Spaces[i].Corner(0).X;
            var rect1MaxX = Spaces[i].Corner(2).X;
            var rect1MinY = Spaces[i].Corner(0).Y;
            var rect1MaxY = Spaces[i].Corner(2).Y;
            var rect1Center = Spaces[i].Center;

            var rect2MinX = Spaces[j].Corner(0).X;
            var rect2MaxX = Spaces[j].Corner(2).X;
            var rect2MinY = Spaces[j].Corner(0).Y;
            var rect2MaxY = Spaces[j].Corner(2).Y;
            var rect2Center = Spaces[j].Center;

            if((rect1MinX < rect2MaxX && rect1MaxX > rect2MinX) &&
              (rect1MinY < rect2MaxY && rect1MaxY > rect2MinY))
            {
              //stop if they collide
              IsColliding = true;

              //if they collide in x
              if ( rect1MinX < rect2MaxX && rect1MaxX > rect2MinX )
              {

                MovementVectors[j].X += -MovementVectors[j].X;
              }
              //if they collide in y
              if ( rect1MinY < rect2MaxY && rect1MaxY > rect2MinY )
              {

                MovementVectors[j].Y += -MovementVectors[j].Y;
              }
            }
            else {
              IsColliding = false;
            }
          }
        }
        }
        );
    }

    //apply move
    public void ApplyMove()
    {
      var spacesArr = Spaces.ToArray();
      for(int i = 0; i < Spaces.Count; i++)
      {
        var move = Transform.Translation(MovementVectors[i]);
        spacesArr[i].Transform(move);
      }
      ResultingSpacesArr = spacesArr;
    }
  }

  // </Custom additional code> 
}

211003-01-RectangleCollisionProblem-YA.gh (20.6 KB)

I will also be tagging @DanielPiker @Dani_Abalde @DavidRutten @PeterFotiadis
since you guys might have knowledge of this topic.

please tell me anything you know. As have been stuck in this for months and researched it so much on many engines but didn’t find the right answer(or didn’t have enough understanding)

thank you in advance.strong text

FYI I edited your post to have the code properly enclode in tripple backticks.

I haven’t posted in years, forgot about the indentation. thank you :pray:

Well … I have various similar (2D/3D) things in practice but … guess what? Today is (a) WSB [very bad results for Rea so far] (b) BSB [so-so for O’Halloran] and (c) MotoGP [good signs for Mark] day. I’m sure that until Monday Daniel (and/or the others) could provide solution(s) for that one.

I think here is the problem:
image

MovementVectors[j].X += -MovementVectors[j].X;
Something - something = 0. You have to take the quantity in X and in Y that intersects, divide it by two, and subtract this from one rectangle and add this to the other for them to separate.

Anyway, I don’t think collisions should be treated the same as forces, because they are not the same conceptually. With collisions I directly change the position of the agents in a different loop/process-step instead of changing their acceleration (and update the magnitude of the velocity if the collider gets some energy). I’m not sure but I think Kangaroo does consider them as forces but solves this by weighting them (the strength) so that the collision always dominates.