简体   繁体   English

填充Pygame中两个Circle的交集区域

[英]Fill the area of intersection of two Circles in Pygame

I am working on a pygame project and I encountered a problem.我正在做一个 pygame 项目,我遇到了一个问题。 I have two circles A and B as shown below.我有两个圆圈 A 和 B,如下所示。 Which are overlapped Now I want to fill only some part of the circle which is common to both circles.哪些是重叠的现在我只想填充两个圆圈共有的圆圈的一部分。 Is there any way to achieve that?有什么办法可以实现吗?

I know I can fill circle B with red colour and circle A with white, but there is a certain area and circle A goes outside that area.我知道我可以用红色填充圆 B,用白色填充圆 A,但是有一个特定的区域,而圆 A 超出了该区域。 So I cannot implement that.所以我无法实施。

The image of circles and filled position is mentioned in this image:此图像中提到了圆圈和填充 position 的图像:在此处输入图像描述

Create 2 pygame.Surface objects with per pixel alpha ( pygame.SRCALPHA ):创建 2 个具有每个像素 alpha 的pygame.Surface对象( pygame.SRCALPHA ):

surf1 = pygame.Surface((500, 500), pygame.SRCALPHA)
surf2 = pygame.Surface((500, 500), pygame.SRCALPHA)

Define the center point and radius of the 2 circles:定义 2 个圆的中心点和半径:

pos1, rad1 = (250, 200), 100
pos2, rad2 = (250, 250), 80

Draw the circles on the 2 surfaces, with the same color:用相同的颜色在 2 个表面上绘制圆圈:

pygame.draw.circle(surf1, (255, 0, 0, 255), pos1, rad1)
pygame.draw.circle(surf2, (255, 0, 0, 255), pos2, rad2)

Blend one surface on the other, using the blend mode pygame.BLEND_RGBA_MIN :使用混合模式pygame.BLEND_RGBA_MIN混合一个表面到另一个表面:

surf1.blit(surf2, (0, 0), special_flags = pygame.BLEND_RGBA_MIN)

At this point surf1 contains the intersection area of the 2 circles.此时surf1包含 2 个圆的相交区域。

To get the outer section, another step is required.要获得外部部分,还需要另一个步骤。 Blend surf1 on surf2 , using the blend mode pygame.BLEND_RGBA_MIN :surf1上混合surf2 ,使用混合模式pygame.BLEND_RGBA_MIN

surf2.blit(surf1, (0, 0), special_flags = pygame.BLEND_RGBA_SUB)

Now surf2 contains the the part of circle B which is left if circle A is subtracted:现在surf2包含圆 B中减去圆 A后剩下的部分:


Minimal example:最小的例子: repl.it/@Rabbid76/PyGame-CircleIntersection repl.it/@Rabbid76/PyGame-CircleIntersection

import pygame

pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()

pos1, rad1 = (250, 200), 100
pos2, rad2 = (250, 250), 80

surf1 = pygame.Surface((500, 500), pygame.SRCALPHA)
surf2 = pygame.Surface((500, 500), pygame.SRCALPHA)

pygame.draw.circle(surf1, (255, 0, 0, 255), pos1, rad1)
pygame.draw.circle(surf2, (255, 0, 0, 255), pos2, rad2)

surf1.blit(surf2, (0, 0), special_flags = pygame.BLEND_RGBA_MIN)
surf2.blit(surf1, (0, 0), special_flags = pygame.BLEND_RGBA_SUB)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            print(pygame.key.name(event.key))
 
    window.fill((255, 255, 255))

    window.blit(surf2, (0, 0))     
    pygame.draw.circle(window, (128, 128, 128), pos1, rad1+1, 3)
    pygame.draw.circle(window, (128, 128, 128), pos2, rad2+1, 3)

    pygame.display.flip()

I couldn't find a way to do it with pygame functions, so I made a quick demo on how to do it yourself here:我找不到使用pygame函数的方法,所以我在这里做了一个关于如何自己做的快速演示:

import pygame
import math
import time

# Screen dimensions
WIDTH = 600
HEIGHT = 400

# Circle and screen colours
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# Circle data
BIGGER_POS = (300, 150)
SMALLER_POS = (300, 220)
BIGGER_RADIUS = 130
SMALLER_RADIUS = 100
BIGGER_COLOUR = GREEN
SMALLER_COLOUR = BLUE
INTERSECTION_COLOUR = RED


def prepare_screen():
    """
    Create the initial screen.
    """
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill(WHITE)
    return screen


def draw_circles(screen):
    """
    Draw the circles and wait to visually inspect what they look like.
    """
    bigger = pygame.draw.circle(screen, BIGGER_COLOUR, BIGGER_POS, BIGGER_RADIUS)
    smaller = pygame.draw.circle(screen, SMALLER_COLOUR, SMALLER_POS, SMALLER_RADIUS)
    pygame.display.update()
    time.sleep(3)
    return bigger, smaller


def calculate_distance(p1: tuple, p2: tuple):
    """
    Calculate distance between two points p1 and p2.
    """
    return math.sqrt(((p1[0] - p2[0])**2) + ((p1[1] - p2[1])**2))


def draw_intersection(screen, bigger, smaller):
    """
    Animation to mark intersecting points with red.
    
    Ideally this should only go through colliding points, but I'm lazy and made it iterate through all pixels
    instead.
    """
    for x in range(WIDTH):
        for y in range(HEIGHT):
            print("Checking point", x, y)
            
            # A point is in the intersection if it's within the radius-es of both circles
            if calculate_distance(bigger.center, (x, y)) <= BIGGER_RADIUS and \
                    calculate_distance(smaller.center, (x, y)) <= SMALLER_RADIUS:
                screen.set_at((x, y), INTERSECTION_COLOUR)
                pygame.display.update()


# Get screen to draw on
screen = prepare_screen()

# Draw some initial circles
bigger, smaller = draw_circles(screen)

# Draw the intersection
draw_intersection(screen, bigger, smaller)

# Finally sleep some to allow visual inspection, and quit
time.sleep(3)
pygame.quit()

Feel free to adjust as needed - note that various places can be optimised, made more readable etc.根据需要随意调整 - 请注意,可以优化各个地方,使其更具可读性等。

Result:结果:

上面代码的结果

Let me know if anything's unclear.让我知道是否有任何不清楚的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM