User 12692182
User 12692182

Reputation: 981

How to draw a rectangle around two points

I am using pygame and the math module to try and draw a rectangle around two points. Here's what I mean by that:

Rectangle-controlled-by-two-points

The distance from the points to the ends of the rectangles is specified as an attribute of the class. I have tried a lot to get this to where it is, and the angle shown is probably the only working angle. Here is my class for the rectangle:

def Pol(x, y):
    """Converts rectangular coordinates into polar ones"""
    if x == 0: # This might be the source of my problems, but without it, it raises ZeroDivisionErrors at certain places
        if y >= 0:
            return [y, 90]
        else:
            return [-y, 270]
    r     = math.sqrt(x**2+y**2)
    angle = (math.degrees(math.atan((y/x))))%360
    return [r, angle]

class Path(pygame.sprite.Sprite):
    def __init__(self, start, end, color, width, **options):
        self.__dict__.update(options)
        self.start = start
        self.end = end
        self.color=color
        # Call the parent class (Sprite) constructor
        super().__init__()

        # Pass in the color of the blob, and its x and y position, width and height
        # Set the background color and make it transparent
        self.width = width

        # Draw the path
        self.redraw()

        # Fetch the rectangle object that has the dimensions of the image.
        self.rect = self.image.get_rect()
        self.rect.x, self.rect.y = (self.start[0]-self.width//2+self.ix,
                                    self.start[1]-self.width//2+self.iy)
        if self.inversed:
            self.rect.y-=(math.ceil(self.image.get_rect()[3]/2)-self.iy)

    def redraw(self):
        dis, angle = Pol(self.end[0]-self.start[0], self.end[1]-self.start[1])
        dis += self.width
        _image = pygame.Surface([dis, self.width])
        _image.fill([255, 255, 255])
        _image.set_colorkey([255, 255, 255])
        pygame.draw.rect(_image, self.color, pygame.Rect(0, 0, dis, self.width))
        nangle = (180-angle)%360
        self.inversed = nangle>=180
        self.image = pygame.transform.rotate(_image, nangle)
        i1 = _image.get_rect()
        i2 = self.image.get_rect()
        ix = i2[2]-i1[2]
        iy = i2[3]-i1[2]
        self.ix = ix//2
        self.iy = iy//2

So, I pass it some points, and it takes care of all the heavy lifting, and drawing. The points I passed it in the image were (100, 100) and (200, 200). I then tried it with (300, 300) and (200, 200), and it performed semi-successfully:

failed test

The code is above, you can try it out with other values, but you'll see that it quickly becomes problematic. To wrap it up, my question is, is there a robust way to draw a rectangle around given two points? I have tried:

Upvotes: 5

Views: 1262

Answers (1)

Rabbid76
Rabbid76

Reputation: 210909

The issue is the function math.atan() which returns an angle in range [-pi/2, +pi/2].
Use math.atan2() (see math) which returns an angle in range [-pi,+pi]. Hence this function gives the correct angle at once, and you don't need any corrections:

angle = (math.degrees(math.atan((y/x))))%360

angle = math.degrees(math.atan2(y, x))

See also What is the difference between atan and atan2 in C++?

Upvotes: 5

Related Questions