Reputation: 445
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
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