Find overlapping turtle python

Кажется, что python canvas.find_overlapping имеет инвертированную ось Y

Я пытаюсь найти цвет холста под черепахой Python. Я использую canvas.find_overlapping но это только успешно, когда я ycor , подразумевая, что ось y инвертирована в объекте canvas по сравнению с тем, что показано. Есть ли проблема с моим кодом или инвертирована ось y?

import turtle wn = turtle.Screen() maze_drawer = turtle.Turtle() maze_drawer.color("purple") maze_drawer.speed("fastest") path_width = 15 def get_pixel_color(x, y): c = turtle.Screen().getcanvas() # -y should not work?? items = c.find_overlapping(x, -y, x, -y) if len(items) > 0: return c.itemcget(items[0], "fill") # get 0 object (canvas) # draw simplified maze wall_len = 0 for i in range(10): maze_drawer.left(90) wall_len += path_width maze_drawer.forward(wall_len) # navigate maze from center maze_runner = turtle.Turtle() maze_runner.color("green") maze_runner.penup() maze_runner.goto(-path_width, -path_width) # test in y dir: maze_runner.setheading(90) clear = True while(clear): maze_runner.forward(1) color_at_turtle = get_pixel_color(maze_runner.xcor(), maze_runner.ycor()) if (color_at_turtle == "purple"): clear = False wn.exitonclick() 

Модуль turtle инвертирует все координаты y, чтобы получить поведение наведения по оси Y, традиционное для графики черепах. Вы должны сделать инверсию самостоятельно, если вы обходите модуль и используете Tkinter напрямую.

1 ответ

Аккуратное использование обнаружения пикселов tkinter в черепахе! Если перевернутая координата Y назойлива, вы можете перевернуть ее с точки зрения черепахи:

from turtle import Screen, Turtle screen = Screen() width, height = screen.window_width() / 2, screen.window_height() / 2 screen.setworldcoordinates(-width, height, width, -height) # flip Y coordinate 

Тогда ваш код не должен думать о том, чтобы отрицать Y, если вы знаете, что вы перевернуты вверх ногами:

from turtle import Screen, Turtle PATH_WIDTH = 15 def get_pixel_color(x, y): canvas = screen.getcanvas() items = canvas.find_overlapping(x, y, x, y) if items: return canvas.itemcget(items[0], "fill") # get 0 object (canvas) return None screen = Screen() width, height = screen.window_width() / 2, screen.window_height() / 2 screen.setworldcoordinates(-width, height, width, -height) maze_drawer = Turtle(visible=False) maze_drawer.color("purple") maze_drawer.speed("fastest") # draw simplified maze wall_len = 0 for _ in range(20): maze_drawer.left(90) wall_len += PATH_WIDTH maze_drawer.forward(wall_len) # navigate maze from center maze_runner = Turtle() maze_runner.color("dark green", "green") maze_runner.penup() maze_runner.goto(-PATH_WIDTH, -PATH_WIDTH) def run_maze(): maze_runner.forward(1) x, y = maze_runner.position() color_at_turtle = get_pixel_color(x, y) if color_at_turtle == "purple": maze_runner.backward(PATH_WIDTH - 1) maze_runner.left(90) x, y = maze_runner.position() if -width < x < width and -height < y < height: screen.ontimer(run_maze, 10) run_maze() screen.exitonclick() 

Источник

Читайте также:  Чем отличается get от post запроса php

turtle подсчет целочисленных точек внутри и на границе фигуры

Дается фигура в декартовой системе координат и нужно посчитать количество целочисленных координат внутри фигуры и на границе. Написал вот такой код, но он считает только точки внутри фигуры. Как сделать чтобы считались точки не только внутри фигуры, но и на ее границах?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
from turtle import * color("red") k = 20 speed(0) hideturtle() begin_fill() for i in range(6): forward(10*k) right(60) end_fill() c = 0 canvas = getcanvas() for x in range(-100*k, 100*k, k): for y in range(-100*k, 100*k, k): s = canvas.find_overlapping(x, y, x, y) if len(s) == 1 and s[0] == 5: c += 1 print(c) done()

Вывести количество точек, которые находятся внутри окружности либо на ее границе
Вводится x0,y0,r,n Координаты n точак x0,y0-центр окружности r-радиус n-количество точак.

Для заданных точек определите, лежат ли они внутри полосы или на её границе
Имя входного файла: input.txt Имя выходного файла: output.txt Ограничения по времени: 0,2с.

Для заданных точек определите, лежат ли они внутри круга или на его границе
Имя входного файла: input.txt Имя выходного файла: output.txt Ограничения по времени: 0,2с.

Для заданных точек определите, лежат ли они внутри квадрата или на его границе
Имя входного файла: input.txt Имя выходного файла: output.txt Ограничения по времени: 0,2с.

Слушай, не уверен, что понял точно задание, но сделал исходя из своего понимания
def count_points_in_figure(coords):
"""
Подсчитать количество целых координат внутри данной фигуры.

Аргументы:
Координаты: список пар координат, представляющих вершины фигуры.

возвращает:
Количество целочисленных координат внутри фигуры и на ее границе.
"""
min_x = min(x for x, y in coords)
max_x = max(x for x, y in coords)
min_y = min(y for x, y in coords)
max_y = max(y for x, y in coords)

count = 0
for x in range(min_x, max_x+1):
for y in range(min_y, max_y+1):
if is_inside_figure(x, y, coords):
count += 1
elif is_on_boundary(x, y, coords):
count += 1

def is_inside_figure(x, y, coords):
"""
Проверить, находится ли заданная точка внутри фигуры.

Аргументы:
x: x - координата точки.
y: Y - координата точки.
Координаты список пар координат, представляющих вершины фигуры.

Возвращает:
True, если точка находится внутри фигуры, False в противном случае.
"""
num_vertices = len(coords)
j = num_vertices - 1
odd_nodes = False
for i in range(num_vertices):
if (coords[i][1] < y and coords[j][1] >= y) or (coords[j][1] < y and coords[i][1] >= y):
if coords[i][0] + (y - coords[i][1]) / (coords[j][1] - coords[i][1]) * (coords[j][0] - coords[i][0]) < x:
odd_nodes = not odd_nodes
j = i
return odd_nodes

def is_on_boundary(x, y, coords):
"""
Проверить, находится ли заданная точка на границе.

Аргументы:
x: x - координата точки.
y: Y - координата точки.
Координаты: список пар координат, представляющих вершины фигуры.

Возвраты:
True, если точка находится на определенной фигуре, False в противном случае.
"""
for i in range(len(coords)):
x1, y1 = coords[i]
x2, y2 = coords[(i + 1) % len(coords)]
if x == x1 and y == y1:
return True
elif x == x2 and y == y2:
return True
elif (y - y1) * (x2 - x1) == (y2 - y1) * (x - x1):
if min(x1, x2) return True
return False

# Пример использования
coords = [(0,0), (0,5), (5,5), (5,0)]
num_points = count_points_in_figure(coords)
print(f"Количество целых точек внутри или на границе фигуры: ")

Источник

Canvas, рисование графики ч.3 / tkinter 20

В продолжение предыдущего материала о поиске ближайшего элемента стоит отметить, что существует также возможность определять, пересекается ли один прямоугольник с другим. Этого можно добиться благодаря тому, что все элементы заключены в прямоугольные контейнеры. А для определения пересечений используется метод find_overlapping() из класса Canvas .

Это приложение расширяет возможности предыдущего за счет четырех новых прямоугольников, добавленных на полотно. Подсвечиваться будет тот, с которым пересечется синий. Управлять последним можно с помощью клавиш стрелок:

Определение пересечений между элементами

Поскольку код во многом повторяет предыдущий, отметим лишь те части кода, которые отвечают за создание новых прямоугольников и вызов метода canvas.find_overlapping() :

 
import tkinter as tk

class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Обнаружение пересечений между предметами")

self.canvas = tk.Canvas(self, bg="white")
self.canvas.pack()
self.update()
self.width = w = self.canvas.winfo_width()
self.height = h = self.canvas.winfo_height()

pos = (w / 2 - 15, h / 2 - 15, w / 2 + 15, h / 2 + 15)
self.item = self.canvas.create_rectangle(*pos, fill="blue")
positions = [(60, 60), (w - 60, 60), (60, h - 60), (w - 60, h - 60)]
for x, y in positions:
self.canvas.create_rectangle(x - 10, y - 10, x + 10, y + 10,
fill="green")

self.pressed_keys = <>
self.bind("", self.key_press)
self.bind("", self.key_release)
self.process_movements()

def key_press(self, event):
self.pressed_keys[event.keysym] = True

def key_release(self, event):
self.pressed_keys.pop(event.keysym, None)

def process_movements(self):
all_items = self.canvas.find_all()
for item in filter(lambda i: i is not self.item, all_items):
self.canvas.itemconfig(item, fill="green")

x0, y0, x1, y1 = self.canvas.coords(self.item)
items = self.canvas.find_overlapping(x0, y0, x1, y1)
for item in filter(lambda i: i is not self.item, items):
self.canvas.itemconfig(item, fill="yellow")

off_x, off_y = 0, 0
speed = 3
if 'Right' in self.pressed_keys:
off_x += speed
if 'Left' in self.pressed_keys:
off_x -= speed
if 'Down' in self.pressed_keys:
off_y += speed
if 'Up' in self.pressed_keys:
off_y -= speed

pos_x = x0 + (x1 - x0) / 2 + off_x
pos_y = y0 + (y1 - y0) / 2 + off_y
if 0 self.canvas.move(self.item, off_x, off_y)

self.after(10, self.process_movements)

if __name__ == "__main__":
app = App()
app.mainloop()

Как определяются пересечения

До пересечения цвет заполнения всех прямоугольников на полотне, кроме управляемого пользователем, будет зеленым. Идентификаторы этих элементов можно получить с помощью метода canvas.find_all() :

 
def process_movements(self):
all_items = self.canvas.find_all()
for item in filter(lambda i: i is not self.item, all_items):
self.canvas.itemconfig(item, fill="green")

Когда цвета элемента сброшены, вызываем canvas.find_overlapping() для получения всех элементов, которые пересекаются с двигающимся. Он, в свою очередь, из цикла исключен, а цвет остальных пересекающихся элементов (если такие имеются) меняется на желтый:

 
def process_movements(self):
# . x0, y0, x1, y1 = self.canvas.coords(self.item)
items = self.canvas.find_overlapping(x0, y0, x1, y1)
for item in filter(lambda i: i is not self.item, items):
self.canvas.itemconfig(item, fill="yellow")

Метод продолжает выполнение, перемещая синий прямоугольник на заданный показатель сдвига, и планируя себя же снова с помощью process_movements() .

Если нужно определить, когда движущийся элемент полностью перекрывает другой (а не частично), то стоит воспользоваться методом canvas.find_enclosed() вместо canvas.find_overlapping() с теми же параметрами.

Удаление элементов с полотна

Помимо добавления и изменения элементов полотна их также можно удалять с помощью метода delete() класса Canvas . Хотя в принципах его работы нет каких-либо особенностей, существуют кое-какие паттерны, которые будут рассмотрены дальше.

Стоит учитывать, что чем больше элементов на полотне, тем дольше Tkinter будет рендерить виджет. Таким образом важно удалять неиспользуемые для улучшения производительности.

В этом примере создадим приложение, которое случайным образом выбирает несколько кругов на полотне. Каждый кружок будет удаляться по клику. Одна кнопка в нижней части виджета сбрасывает состояние полотна, а вторая — удаляет все элементы.

Canvas, рисование графики ч.3 / tkinter 20

Чтобы случайным образом размещать элементы на полотне, будем генерировать координаты с помощью функции randint модуля random . Цвет элемента будет выбираться случайным образом с помощью вызова choice и определенного набора цветов.

После генерации элементы можно будет удалить с помощью обработчика on_click или кнопки Clearitems , которая, в свою очередь, вызывает функцию обратного вызова clear_all . Внутри этот метод вызывает canvas.delete() с нужными параметрами:

 
import random
import tkinter as tk

class App(tk.Tk):
colors = ("red", "yellow", "green", "blue", "orange")

def __init__(self):
super().__init__()
self.title("Удаление элементов холста")

self.canvas = tk.Canvas(self, bg="white")
frame = tk.Frame(self)
generate_btn = tk.Button(frame, text="Создавать элементы",
command=self.generate_items)
clear_btn = tk.Button(frame, text="Удалить элементы",
command=self.clear_items)

self.canvas.pack()
frame.pack(fill=tk.BOTH)
generate_btn.pack(side=tk.LEFT, expand=True, fill=tk.BOTH)
clear_btn.pack(side=tk.LEFT, expand=True, fill=tk.BOTH)

self.update()
self.width = self.canvas.winfo_width()
self.height = self.canvas.winfo_height()

self.canvas.bind("", self.on_click)
self.generate_items()

def on_click(self, event):
item = self.canvas.find_withtag(tk.CURRENT)
self.canvas.delete(item)

def generate_items(self):
self.clear_items()
for _ in range(10):
x = random.randint(0, self.width)
y = random.randint(0, self.height)
color = random.choice(self.colors)
self.canvas.create_oval(x, y, x + 20, y + 20, fill=color)

def clear_items(self):
self.canvas.delete(tk.ALL)

if __name__ == "__main__":
app = App()
app.mainloop()

Как работает удаление элементов

Метод canvas.delete() принимает один аргумент, который может быть идентификатором элемента или тегом, и удаляет один или несколько соответствующих элементов (поскольку тег может быть использован несколько раз).

В обработчике on_click() можно увидеть пример удаления элемента по идентификатору:

Источник

Оцените статью