import PIL.ImageDraw as ImageDraw,PIL.Image as Image, PIL.ImageShow as ImageShow
#that s my class Point(2D)
class Pnt(namedtuple('Pnt', 'x y')):
__slots__ = ()
def __init__(self, *args):
super(Pnt, self).__init__(*args)
Here is the vector of the vertices(convex polygon)
vertix = []
vertix.append(Pnt(50, 100))
vertix.append(Pnt(100, 200))
vertix.append(Pnt(200, 200))
vertix.append(Pnt(300, 0))
vertix.append(Pnt(250, -200))
vertix.append(Pnt(100, -100))
Here I want to draw the polygon. The problem is it is not centered, so almost half the polynom is outside the frame.
im = Image.new("RGB", (600,800))
draw = ImageDraw.Draw(im)
draw.polygon(vertix, fill=230, outline=255)
im.show()
If you want to center your polygon in the Image you can
1) determine the bounding box of your polygon,
2) calculate the coordinates of the center of the bounding box,
3) calculate the vector required to translate the center of the bounding box to the center of the Image rectangle,
4) create a new polygon by translating the coords of the vertices of the old poly by the vector found in step 3.
Related
I am using Pygame and have an image. I can clip a rectangle from it:
image = pygame.transform.scale(pygame.image.load('example.png'), (32, 32))
handle_surface = image.copy()
handle_surface.set_clip(pygame.Rect(0, 0, 32, 16))
clipped_image = surface.subsurface(handle_surface.get_clip())
I have tried to use subsurface by passing a Surface:
handle_surface = image.copy()
hole = pygame.Surface((32, 32))
pygame.draw.circle(hole, (255, 255, 255), (0, 0), 32)
handle_surface.set_clip(hole)
image = surface.subsurface(handle_surface.get_clip())
surf = image.copy()
But I get the error:
ValueError: invalid rectstyle object
This error is because despite its name, subsurface expects a Rect, not a Surface. Is there a way to clip another shape from this image and have collidepoint work correctly?
You cannot use pygame.Surface.subsurface because a Surface is always rectangular and cannot have a circular shape. pygame.Rect.collidepoint detects if a point is inside a rectangular area and therefore cannot help you either.
Collision detection between a circle and a point can be calculated using the distance between the pointer and the center of the circle. Calculate the square of the Euclidean distance (dx*dx + dy*dy) from the point to the center of the circle. Check that the square of the distance is less than the square of the radius. In the following code the coordinates of the point are (px, py) and the circle is defined by its center (cx, cy) and its radius (radius).
dx = px - cx
dy = py - cy
if dx*dx + dy*dy <= radius*radius:
print('hit')
An alternative solution could be PyGame collision with masks. Also pygame.sprite.collide_circle could help, but then you would have to create a pygame.sprite.Sprite object for the point with radius 1, which seems to overcomplicate the problem.
If you want to clip a circular area from a pygame.Surface, see:
how to make circular surface in PyGame
How do I focus light or how do I only draw certain circular parts of the window in pygame?
How do I display a large black rectangle with a moveable transparent circle in pygame?
Can I use an image on a moving object within Pygame as opposed to to a color?
Short instruction:
Create a rectangular partial area from the image (only if the circle does not fill the whole image). However, the image must have an alpha channel. If it does not have one, this can be achieved with convert_alpha.
Create a transparent (pygame.SRCALPHA) mask with the size of the image
Draw a white opaque circle on the mask (I use pygame.draw.ellipse here, because it is easier to set the dimension)
Blend the circular mask with the image using the blend mode pygame.BLEND_RGBA_MIN. (see pygame.Surface.blit)
sub_image = image.subsurface(pygame.Rect(x, y, w, h)).convert_alpha()
mask_image = pygame.Surface(sub_image.get_size(), pygame.SRCALPHA)
pygame.draw.ellipse(mask_image, (255, 255, 255, 255), sub_image.get_rect())
sub_image.blit(mask_image, (0, 0), special_flags=pygame.BLEND_RGBA_MIN)
I am busy with something witch is not so familiar to me. Trying to design a small logo to be displayed on a Oled display sh1106, 128x64
I am using PIL and Luma libraries.
I am battling to position a small arc in the right position.
that small little arc in the yellow circle should be positioned where the arrow is pointing.
This is the code I am using for the arc:
shape = [(32, 32), (36,36)]
draw.arc(shape, start = 160, end = 20, fill ="white")
As soon as I change any of the parameters in those two lines above, the shape, size of the arc changes. Even the position changes, but I assume is because of the size change. Thats not I won't.
Is there any other parameter which I am missing to position the arc in the right place?
Hopefully this little example will show you how it works. The bbox specifies the top-left and bottom-right corners of the bounding box that encloses the arc. I have drawn in the bounding box of each arc in the same colour:
#!/usr/bin/env python3
from PIL import Image, ImageDraw
# Create black image and get drawing context
im = Image.new("RGB", (200, 100))
draw = ImageDraw.Draw(im)
# Draw white arc with bbox
bbox = [(10, 20), (80, 60)]
draw.arc(bbox, start=180, end=360, fill='white')
draw.rectangle(bbox, outline='white')
# Draw red arc with bbox
bbox = [(60, 30), (190, 90)]
draw.arc(bbox, start=180, end=360, fill='red')
draw.rectangle(bbox, outline='red')
# Save result
im.save('result.png')
I know how to mask images. But if I simply want to create a circle and mask it, it would be annoying to create an image of a simple circle outside of my code, especially when I need to create different kinds of circles. Appearantly you can create Rect objects in pygame but there is no class Circle.
pygame.mask.from_surface requires a surface. Can I pass a non-image type surface as a parameter? If so how can I mask circles and/or other objects?
Here's something I imagined which obviously throws an error:
circle = pygame.Circle((10, 10), 5) # (center coordinates), radius
pygame.mask.from_surface(circle)
There is no way to create a circular mask directly. See pygame.mask. You need to draw a circle on a Surface. Create a function that creates a Surface and draw a circle on the Surface:
def circleSurface(color, radius):
shape_surf = pygame.Surface((radius * 2, radius * 2), pygame.SRCALPHA)
pygame.draw.circle(shape_surf, color, (radius, radius), radius)
return shape_surf
Create the Mask from the Surface:
circle = circleSurface((255, 255, 255), 5) # (center coordinates), radius
pygame.mask.from_surface(circle)
However, if you want to use a circle to clip an area of the display, see the answers to the following questions:
how to make circular surface in PyGame
How to fill only certain circular parts of the window in PyGame?
I want to centre an image inside a rect note that I am using the image rect but asseperate rect to mount the image on.
rect_1 = pygame.Rect(1, 1, 178, 178)
...
cross = pygame.image.load("cross.png").convert_alpha()
cross_minified = pygame.transform.rotozoom(cross, 0, 0.25)
...
screen.blit(cross_minified, rect_1)
and after these codes I cannot find a way to center my x to the middle of the rect_1
it looks somewhat like this
Use the functionality of pygame.Rect. Get a rectangle with the size of the image by pygame.Surface.get_rect and set its center by the keyword argument center from the center of rect_1:
cross_rect = cross_minified.get_rect(center = rect_1.center)
screen.blit(cross_minified, cross_rect)
I have created a triangle positioned in the centre of the screen.
from PIL import Image, ImageDraw
GRAY = (190, 190, 190)
im = Image.new('RGBA', (400, 400), WHITE)
points = (250, 250), (100, 250), (250, 100)
draw = ImageDraw.Draw(im)
draw.polygon(points, GRAY)
How do I duplicate this image and reflect it along each sides of the triangle at different random points. For example...
Plan: First find a random point on the edge of the big triangle where to put a smaller one, and then rotate it so it fits properly on the edge.
Suppose we can access the points of the triangle with something like this
triangle.edges[0].x,
triangle.edges[0].y,
triangle.edges[1].x,
etc
We can then find an arbitrary point by first selecting an edge, and "walk a random distance to the next edge":
r = randInt(3) # random integer between 0 and 2
first_edge = triangle.edges[r]
second_edge = r == 2 ? triangle.edges[0] : triangle.edges[r + 1]
## The next lines is kind of pseudo-code
r = randFloat(1)
random_point = (second_edge - first_edge)*r + first_edge
Our next problem is how to rotate a triangle. If you have done some algebra you might recognise this:
def rotatePointAroundOrigin(point, angle):
new_point = Point()
new_point.x = cos(angle)*point.x - sin(angle)*point.y
new_point.y = sin(angle).point.x + cos(angle)*point.y
return new_point
(see https://en.wikipedia.org/wiki/Rotation_matrix)
In addition to this you need to determine just how much to rotate the triangle, and then apply the function above to all of the points.