Search code examples
javarandompositionpointauto-generate

Generate a random position between 2 corners points


If we have two objects of Vector2 which represents 2 corners of a rectangle, a region:

Vector2 corner1 = new Vector2(-5, -5);
Vector2 corner2 = new Vector2(5, 5);

How can you generate a random position between these two vectors (any where in the rectangle it creates)?

What I thought to do is, the the distance from x1 and x2 and the same for y1 and y2, and do a random value from that range.

But what if the first vector is 5, 5 and second vector is -5, -5? I will have to add a negative distance, am I right?

Whats the most efficient way to do this?


Solution

  • The calculation of x and y use exactly the same method, so let's just focus on x for now.

    Random rand = new Random();
    float x1 = Math.min(corner1.x, corner2.x);
    float x2 = Math.max(corner1.x, corner2.x);
    float deltaX = x2 - x1;
    float offsetX = rand.nextFloat() * deltaX;
    float randomX = x1 + offsetX;
    

    This effectively sorts the x values so that the lesser value is referred to as x1 and the greater as x2, and the difference between them is calculated and stored in deltaX.

    Then a random value is calculated using java.util.Random.nextFloat(), which returns a value between 0.0 (inclusive) and 1.0 (exclusive), and multiplying the random value by the delta. This gives us a random value, offsetX, which is a somewhere between zero and the total difference between the two values.

    Finally we must add this random offset to the minimum x value, x1, so that the random point really does sit within the rectangle, somewhere between x1 (inclusive) and x2 (exclusive).

    Note that I've written this straight into Stack Overflow without any testing, so this is a good chance for you to write some unit tests to make sure that whatever method you use will work for a variety of values (negative, positive, a mix of both, zero coordinates, etc).

    (By the way, I'm assuming that the Vector2 class comes from libgdx API, as there's no such class in the core Java 8 API.)

    Update

    The arithmetic works even without sorting the values using Math.min and Math.max (and I've confirmed this with unit testing) so you can simplify the method:

    public static float pickRandomPointBetween(float corner1, float corner2) {
        if (corner1 == corner2) {
            return corner1;
        }
        float delta = corner2 - corner1;
        float offset = rand.nextFloat() * delta;
        return corner1 + offset;
    }
    

    This same method will work for a pair of either x or y values, and will work whether or not the value of corner1 is less than, greater than, or equal to the value of corner2. Note that the check for corner1 == corner2 is just an efficiency shortcut, and you could remove this if you knew that you would never (or almost never) be passing equal values to this method. (The unit tests pass with or without the shortcut.)

    To complete your requirement, you would create a random point within two rectangle corners like this:

    float randomX = pickRandomPointBetween(corner1.x, corner2.x);
    float randomY = pickRandomPointBetween(corner1.y, corner2.y);
    Vector2 randomPoint = new Vector2(randomX, randomY);
    

    But to keep your code tidy this logic should probably be placed into a dedicated method all of its own, and given a clear name.