Random points are not generated inside brep despite a correct code

Hello guys,

So I’m this code to make boids inside a brep and everything seems to work just fine except that I’m using a correct code to generate points inside a brep.
yet it doesn’t work.
can anybody tell me why > ?
here is the code :

public class FlockSystem
{
public List Agents;

    public double Timestep;
    public double NeighbourhoodRadius;
    public double AlignmentStrength;
    public double CohesionStrength;
    public double SeparationStrength;
    public double SeparationDistance;
    public List<Circle> Repellers;
    public bool UseParallel;
    public Brep Brep;
    Random random = new Random();

    public Box BBox { get; set; }  
    public Point3d Min { get; set; }
    public Point3d Max { get; set; }
    public FlockSystem(int agentCount,Brep brep)
    {
        Brep = brep;
        Agents = new List<FlockAgent>();

        var box = Box.Unset;
        brep.GetBoundingBox(Plane.WorldXY, out box);
        var min = box.PointAt(0,0,0);
        var max = box.PointAt(1, 1, 1);

        BBox = box;
        this.Min = min;
        this.Max = max;

      //for(int i =0;i<agentCount;i++)
        Parallel.For(0, agentCount, (i, loopState) =>
        {
            //var randPt = Util.GetRandomPoint(min.X, max.Y, min.Z, max.X, min.Y, max.Z);
            var randPt = box.PointAt(random.NextDouble(), random.NextDouble(), random.NextDouble());


            if (Brep.IsPointInside(randPt, 0.01, false))
            {
                FlockAgent agent = new FlockAgent(
                randPt,
                Util.GetRandomUnitVector() * 4.0);
                agent.FlockSystem = this;
                Agents.Add(agent);
            }
            if (Agents.Count == agentCount)
            {
                loopState.Break();
            }
        });
    }

thanks a lot :wink:

If the code is right, then the input (geometry) is wrong. Check that the brep is a closed brep and has its normals outwards.

the brep is closed and does have it’s normals in the right direction

however

this line generates points

 var randPt = Util.GetRandomPoint(min.X, max.Y, min.Z, max.X, min.Y, max.Z);

which is this method

public static Point3d GetRandomPoint(double minX, double maxX, double minY, double maxY, double minZ, double maxZ)
{
  double x = minX + (maxX - minX) * random.NextDouble();
  double y = minY + (maxY - minY) * random.NextDouble();
  double z = minZ + (maxZ - minZ) * random.NextDouble(); 
  return new Point3d(x, y, z);
}

but if I move my brep away from the origin the points are not generated

and this line

 var randPt = box.PointAt(random.NextDouble(), random.NextDouble(), random.NextDouble());

doesn’t seem to show points at all

It could be that Brep.IsPointInside() has a bug as well. The goal now is to find a specific point which yields the wrong result given your specific brep, and then upload those so we can replicate the problem and hopefully fix it.

Edit: I’m also not at all sure that IsPointInside is thread safe.

Are you sure that’s doing what you think it’s doing?

How about:

var box = Brep.GetBoundingBox(true);
1 Like

I’d start with this, see if it works. Then slowly adding in your bells and whistles until it breaks.

public class FlockSystem
{
  //public double Timestep;
  //public double NeighbourhoodRadius;
  //public double AlignmentStrength;
  //public double CohesionStrength;
  //public double SeparationStrength;
  //public double SeparationDistance;
  //public List<Circle> Repellers;
  //public bool UseParallel;

  // These properties are readonly now.
  public Brep Shape { get; }
  public BoundingBox ShapeBounds { get; }  
  public List<FlockAgent> Agents {get; }

  public FlockSystem(Brep shape)
  {
    Shape = shape ?? throw new ArgumentNullException(nameof(shape));
    ShapeBounds = shape.GetBoundingBox(true);
    Agents = new List<FlockAgent>();
  }

  public void PopulateShapeWithRandomAgents(int count, int seed)
  {
    Agents.Clear();
    var random = new Random(seed);

    for (int attempts = 0; attempts < 1000000; i++)
    {
      double dx = random.NextDouble();
      double dy = random.NextDouble();
      double dz = random.NextDouble();

      var point = box.PointAt(dx, dy, dz);
      if (Shape.IsPointInside(point, 0.01, false))
      {
        var motion = Util.GetRandomUnitVector() * 4.0;
        FlockAgent agent = new FlockAgent(point, motion);
        agent.FlockSystem = this;
        Agents.Add(agent);
        if (Agents.Count == count)
          break;
        continue;
      }
    }
  }
}
1 Like

@DavidRutten
the issue was “the bounding box command you just corrected”

also, IsPointInside wasn’t thread safe it fails on certains points.
the usual for loop fixed that.

your solution worked points correctly in their random places , however they to always go towards the origin ,

do you know why ?

thank you

I’m guessing this is suspect:

var motion = Util.GetRandomUnitVector() * 4.0;

I haven’t seen the code for that method, but it could well have a bias.

that is the method (gets a random unitzed vector in 3d randomly):

   public static Vector3d GetRandomUnitVector()
        {
            double phi = 2.0 * Math.PI * random.NextDouble();
            double theta = Math.Acos(2.0 * random.NextDouble() - 1.0);

            double x = Math.Sin(theta) * Math.Cos(phi);
            double y = Math.Sin(theta) * Math.Sin(phi);
            double z = Math.Cos(theta);

            return new Vector3d(x, y, z);

@DavidRutten I think the culprit is in the containment behavior . yet it’s code is correct, it worked this morning only when breps were near the origin.

it’s this part from the agent code

  if (!FlockSystem.Brep.IsPointInside(Position, 0.01, false))
                    desiredVelocity += new Vector3d(-Position.X * bounceMultiplier, -Position.Y * bounceMultiplier, -Position.Z * bounceMultiplier);

now when I use this the point bounce off one side and go towards the origin

  using System.Collections.Generic;
    using System.Threading.Tasks;
    using Rhino.Geometry;

    namespace SurfaceTrails2.FlockingInBrep
    {
        public class FlockAgent
        {
            public Point3d Position;
            public Vector3d Velocity;

            public FlockSystem FlockSystem;

            private Vector3d desiredVelocity;

            public FlockAgent(Point3d position, Vector3d velocity)
            {
                Position = position;
                Velocity = velocity;
            }
             
            public void UpdateVelocityAndPosition()
            {
                Velocity = 0.97 * Velocity + 0.03 * desiredVelocity;

                if (Velocity.Length > 8.0) Velocity *= 8.0 / Velocity.Length;
                else if (Velocity.Length < 4.0) Velocity *= 4.0 / Velocity.Length;

                Position += Velocity * FlockSystem.Timestep;
            }



            public void ComputeDesiredVelocity(List<FlockAgent> neighbours)
            {
                // First, reset the desired velocity to 0
                desiredVelocity = new Vector3d(0.0, 0.0, 0.0);
                var bounceMultiplier =30;
                // ===============================================================================
                // Pull the agent back if it gets out of the bounding box 
                // ===============================================================================

                //double boundingBoxSize = 30.0;

                //if (Position.X < FlockSystem.Min.X)
                //    desiredVelocity += new Vector3d((FlockSystem.Max.X - Position.X) * bounceMultiplier, FlockSystem.Min.Y, FlockSystem.Min.Z);

                //else if (Position.X > FlockSystem.Max.X)
                //    desiredVelocity += new Vector3d(-Position.X * bounceMultiplier, FlockSystem.Min.Y, FlockSystem.Min.Z);


                //if (Position.Y < FlockSystem.Min.Y)
                //    desiredVelocity += new Vector3d(FlockSystem.Min.X, (FlockSystem.Max.Y - Position.Y) * bounceMultiplier, FlockSystem.Min.Z);

                //else if (Position.Y > FlockSystem.Max.Y)
                //    desiredVelocity += new Vector3d(FlockSystem.Min.X, (-Position.Y) * bounceMultiplier, FlockSystem.Min.Z);


                //if (Position.Z < FlockSystem.Min.Z)
                //desiredVelocity += new Vector3d(FlockSystem.Min.X, FlockSystem.Min.Y, FlockSystem.Max.Z - Position.Z);

                //else if (Position.Z > FlockSystem.Max.Z)
                //    desiredVelocity += new Vector3d(FlockSystem.Min.X, FlockSystem.Min.Y, -Position.Z);


                if (!FlockSystem.Brep.IsPointInside(Position, 0.01, false))
                    desiredVelocity += new Vector3d(-Position.X * bounceMultiplier, -Position.Y * bounceMultiplier, -Position.Z * bounceMultiplier);



                // ===============================================================================
                // If there are no neighbours nearby, the agent will maintain its veloctiy,
                // else it will perform the "alignment", "cohension" and "separation" behaviours
                // ===============================================================================

                if (neighbours.Count == 0)
                    desiredVelocity += Velocity; // maintain the current velocity
                else
                {
                    // -------------------------------------------------------------------------------
                    // "Alignment" behavior 
                    // -------------------------------------------------------------------------------

                    Vector3d alignment = Vector3d.Zero;

                    foreach (FlockAgent neighbour in neighbours)
                        alignment += neighbour.Velocity;

                    // We divide by the number of neighbours to actually get their average velocity
                    alignment /= neighbours.Count;

                    desiredVelocity += FlockSystem.AlignmentStrength * alignment;


                    // -------------------------------------------------------------------------------
                    // "Cohesion" behavior 
                    // -------------------------------------------------------------------------------

                    Point3d centre = Point3d.Origin;

                    foreach (FlockAgent neighbour in neighbours)
                        centre += neighbour.Position;

                    // We divide by the number of neighbours to actually get their centre of mass
                    centre /= neighbours.Count;

                    Vector3d cohesion = centre - Position;

                    desiredVelocity += FlockSystem.CohesionStrength * cohesion;


                    // -------------------------------------------------------------------------------
                    // "Separation" behavior 
                    // -------------------------------------------------------------------------------

                    Vector3d separation = Vector3d.Zero;

                    foreach (FlockAgent neighbour in neighbours)
                    {
                        double distanceToNeighbour = Position.DistanceTo(neighbour.Position);

                        if (distanceToNeighbour < FlockSystem.SeparationDistance)
                        {
                            Vector3d getAway = Position - neighbour.Position;

                            /* We scale the getAway vector by inverse of distanceToNeighbour to make 
                               the getAway vector bigger as the agent gets closer to its neighbour */
                            separation += getAway / (getAway.Length * distanceToNeighbour);
                        }


                    }

                    desiredVelocity += FlockSystem.SeparationStrength * separation;
                }


                // ===============================================================================
                // Avoiding the obstacles (repellers)
                // ===============================================================================

                foreach (Circle repeller in FlockSystem.Repellers)
                {
                    double distanceToRepeller = Position.DistanceTo(repeller.Center);

                    Vector3d repulsion = Position - repeller.Center;

                    // Repulstion gets stronger as the agent gets closer to the repeller
                    repulsion /= (repulsion.Length * distanceToRepeller);

                    // Repulsion strength is also proportional to the radius of the repeller circle/sphere
                    // This allows the user to tweak the repulsion strength by tweaking the radius
                    repulsion *= 30.0 * repeller.Radius;

                    desiredVelocity += repulsion;

                }
            }
        }
    }