Home > front end >  My position generation method doesn't work
My position generation method doesn't work

Time:02-01

I have a method that is supposed to generate a certain number of Vector3 at a distance not less than specified.

   // Generate random point based on plane area
    public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
    {
        float entireArea = 0f;
        List<AreasWeight> areasWeights = new List<AreasWeight>();
        List<Vector3> positions = new List<Vector3>();

        foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
        {
            entireArea  = plane.GetArea();
        }
        foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
        {
            float weight = plane.GetArea() / entireArea;
            int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
            areasWeights.Add(new(plane, weight, numOfPositionsInArea));
        }

        foreach (AreasWeight areaWeight in areasWeights)
        {
            for (int i = 0; i < areaWeight.NumOfPointsInArea; i  )
            {
                Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();

                foreach (Vector3 position in positions)
                {
                    int attempts = 1;

                    while ((position - generatedPoint).magnitude < minDistanceBetweenPositions)
                    {
                        generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
                        attempts  ;

                        if (attempts > 2000)
                        {
                            Debug.Log("Can't generate all positions.");
                            break;
                        }
                    }

                }
                positions.Add(generatedPoint);
            }
        }

        return positions;
    }

Get random point method:

 public Vector3 GetRandomPointOnPlane()
    {
        float xPosition = Random.Range(Mathf.Min(DownPoint.x, DownPointHelper.x), Mathf.Max(DownPoint.x, DownPointHelper.x));
        float zPosition = Random.Range(Mathf.Min(DownPoint.z, UpPointHelper.z), Mathf.Max(DownPoint.z, UpPointHelper.z));

        return new(xPosition, DownPoint.y   0.002f, zPosition);
    }

But when i Instantiate objects based on these Vector3. Objects still have a distance less than the specified. What am i doing wrong?

CodePudding user response:

For what I can see the issue should be around the range of values you allow on GetRandomPointOnPlane()

(position - generatedPoint).magnitude < minDistanceBetweenPositions shouldn't allow you to keep generatedPoint with distances less than minDistanceBetweenPositions between any other position, but if you try 2000 times you actually keep the last generatedPosition.

So if you can miss some positions, you could try using a bool to manage what positions are kept.

for (int i = 0; i < areaWeight.NumOfPointsInArea; i  )
{
   Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
   bool positionFound = true;

   foreach (Vector3 position in positions)
   {
      int attempts = 1;

      while ((position - generatedPoint).magnitude < minDistanceBetweenPositions)
      {
         generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
         attempts  ;

         if (attempts > 2000)
         {
            Debug.Log("Can't generate all positions.");
            //here you break to the next position keeping an unwanted value
            positionFound = false;
            break;
         }
      }
   }

   if(positionFound)
   {
      positions.Add(generatedPoint);
   }
}

CodePudding user response:

I found a solution. The problem was a bad loop structure. When the algorithm confirmed that the distance was too small and generated a new one, it did not check whether the generated position had a gap from the previous positions on the list. It only confirmed that the gap was preserved and the program continued to execute.

I moved the code that makes sure that the distances are saved to the public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions) method in the GeneratorPlane class. I also added a private Vector3 PickRandomPos() method to it, just to return the generated position.

Methods in the public class GeneratorPlane:

public Vector3 GetRandomPointOnPlane(List<Vector3> alreadyGeneratedPoints, float minDistnaceBetweenPositions)
    {
        if (alreadyGeneratedPoints.Count != 0)
        {
            int attemps = 1;
            bool pointFound = false;
            Vector3 posToReturn = new();

            while (!pointFound)
            {
                pointFound = true;
                posToReturn = PickRandomPos();
                foreach (Vector3 position in alreadyGeneratedPoints)
                {
                    if (Vector3.Distance(position, posToReturn) < minDistnaceBetweenPositions)
                    {
                        pointFound = false;
                        attemps  ;
                        if (attemps > 2000)
                        {
                            Debug.LogError("Points cannot be generated. Too little available space");
                            return Vector3.zero;
                        }
                        break;
                    }
                }
            }
            
            return posToReturn;
        }
        else
        {

            Debug.Log("First point generated");
            return PickRandomPos();
        }
    }

    private Vector3 PickRandomPos()
    {
        float xPosition = Random.Range(Mathf.Min(DownPoint.x, DownPointHelper.x), Mathf.Max(DownPoint.x, DownPointHelper.x));
        float zPosition = Random.Range(Mathf.Min(DownPoint.z, UpPointHelper.z), Mathf.Max(DownPoint.z, UpPointHelper.z));

        return new(xPosition, DownPoint.y   0.002f, zPosition);
    }

Method to generate and return a certain number of items:

public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
    {
        float entireArea = 0f;
        List<AreasWeight> areasWeights = new();
        List<Vector3> positions = new();

        foreach (GeneratorPlane plane in PlanesGenerator.GetCollectionAsList())
        {
            entireArea  = plane.GetArea();
        }

        foreach (GeneratorPlane plane in PlanesGenerator.GetCollectionAsList())
        {
            float weight = plane.GetArea() / entireArea;
            int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
            areasWeights.Add(new(plane, weight, numOfPositionsInArea));
        }

        foreach (AreasWeight areaWeight in areasWeights)
        {
            for (int i = 0; i < areaWeight.NumOfPointsInArea; i  )
            {
                Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane(positions, minDistanceBetweenPositions);
                positions.Add(generatedPoint);
            }
        }

        return positions;
    }
  • Related