bzier
bzier

Reputation: 445

Python - generate all points in a rectangle

I have written a method that will generate each pixel/point in a rectangle, given the min/max x/y coordinates of the given rectangle (proceeding clock-wise from the upper-left corner). It works as expected, but contains four distinct blocks of extremely similar code. It seems like there should be a more 'pythonic' way to achieve this with less repeated code. I realize this is could be considered an open-ended/subjective question, but hopefully it is useful enough to warrant a few answers/suggestions.

Note: The code here is actually generating points for 2x2 pixels

def _generate_points(self, min_x, min_y, max_x, max_y):
    # TODO: I'm sure this can/should be more pythonic somehow

    # Top
    for i in range((max_x - min_x) / 2):
        x_val = min_x + i*2
        y_val = min_y
        yield [(x_val, y_val), (x_val + 1, y_val), (x_val, y_val + 1), (x_val + 1, y_val + 1)]

    # Right-side
    for i in range((max_y - min_y) / 2):
        x_val = max_x
        y_val = min_y + i*2
        yield [(x_val, y_val), (x_val + 1, y_val), (x_val, y_val + 1), (x_val + 1, y_val + 1)]

    # Bottom
    for i in range((max_x - min_x) / 2):
        x_val = max_x - i*2
        y_val = max_y
        yield [(x_val, y_val), (x_val + 1, y_val), (x_val, y_val + 1), (x_val + 1, y_val + 1)]

    # Left-side
    for i in range((max_y - min_y) / 2):
        x_val = min_x
        y_val = max_y - i*2
        yield [(x_val, y_val), (x_val + 1, y_val), (x_val, y_val + 1), (x_val + 1, y_val + 1)]

Upvotes: 0

Views: 1131

Answers (1)

abarnert
abarnert

Reputation: 365707

One way you can refactor this is to loop over four delta pairs, and then the inner loop can use the current one. For example:

def perimeter(min_x, min_y, max_x, max_y):
    x, y = min_x, min_y
    for dx, dy in (1, 0), (0, 1), (-1, 0), (0, -1):
        while x in range(min_x, max_x+1) and y in range(min_y, max_y+1):
            yield (x, y)
            x += dx
            y += dy
        x -= dx
        y -= dy

This isn't the cleanest way to write this, but I think it gets the idea across the best.

And a nice advantage is that you can pretty easily adapt it to handle totally different shapes. Making it work with 2x2 pixels just means doubling the deltas. Making it work with pentagons means… well, you have to decide how you want to handle fractional points, but other than that it's just a matter of picking five evenly-rotated unit vectors instead of four.

Upvotes: 1

Related Questions