1

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 detect rectangle collision.

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

Here is what I have :

my current state

Here is what I Need:

The state I need

And Here is my current code:

    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> 
}

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.

Youssef
  • 11
  • 3

0 Answers0