Создание удобного ввода для разделения квадрата на координаты

Я работаю над программой (на Python), которая предполагает разрезание квадрата на более мелкие части. Пользователь должен ввести «код», который программа автоматически преобразует в координаты каждого отдельного прямоугольника. Каждый прямоугольник также имеет связанное с ним значение.

На данный момент я придумал следующий код:

1                         # the entire square
0.5;0.5                   # square split in half from top to bottom
1:0.5,0.5                 # square split in half from side to side
0.5;0.5:0.15,0.35,0.5     # square split in half from top to bottom, with the right side being further subdivided

; обрабатывает подразделения слева направо, а :+, обрабатывает подразделения сверху вниз.

Проблема, с которой я столкнулся, заключается в том, что с помощью этого текущего метода невозможно представить что-то относительно простое:

Единственное, что я могу придумать для решения этой проблемы, — это какой-то рекурсивный алгоритм, который будет обрабатывать какой-то код и генерировать координаты при появлении запроса. Приоритетом является то, чтобы это оставалось максимально удобным для пользователя, поскольку эти коды можно вводить много раз, а запутанный/длинный код сводит на нет его цель (можно просто ввести вложенный dict/list). Я до сих пор не могу понять, как такое вообще может работать...

Другим решением было бы использовать какой-нибудь tkinter графический интерфейс. Я использую его для своего проекта и в качестве входных данных для этого кода, поэтому какое-то интерактивное окно (например, те сайты, где в середине есть ползунок, показывающий, что было до и после?) тоже подойдет.

Ваше здоровье!

ПРИМЕЧАНИЕ 0:

Эта часть программы занимается разделением японского кандзи (漢字) на составляющие радикалы/части. Большую часть кандзи уже можно представить с помощью моего решения, но есть множество других, которые не могут! Символы отображаются на объекте tkinter Canvas, за каждым радикалом нарисованы прямоугольники. Пользователь выбирает мышкой некоторое количество этих радикалов (эту часть я уже сделал).

ПРИМЕЧАНИЕ 1:

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

[[0.5,[[1,1]]],[0.5,[[0.15,1],[0.35,1],[0.5,1]]]] # generated from the fourth example
          ^ assigmed value ^        ^       ^

Координаты были рассчитаны на основе длины стороны объекта Canvas.

ПРИМЕЧАНИЕ 2:

Хотя это и не является строго необходимым, но способ объединить эти прямоугольники в коде/с виджетом tkinter был бы чрезвычайно полезен, поскольку некоторые радикалы могут иметь странные формы (например, L) или даже обтекать все (например, 口).

Просто чтобы уточнить: ищете ли вы способ представить различные способы разрезания прямоугольника на более мелкие прямоугольники? Или вы спрашиваете, как представить метод с помощью tkinter? Кстати, о StackOverflow, избегайте задавать несколько вопросов в одном сообщении. Я бы посоветовал сделать 2 отдельных поста с двумя разными вопросами.

TheLizzard 01.09.2024 21:13

Да, разрезаем прямоугольник на более мелкие. Если реализация с использованием текста слишком сложна, вместо нее можно использовать виджет tkinter, но вопрос заключался в разделении прямоугольника.

Leo 01.09.2024 21:23
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это довольно сложно объяснить, поэтому поиграйте с примерами или дайте мне больше фигур для кодирования. Также вы можете сохранить/загрузить этот метод кодирования, используя встроенную библиотеку json Python.

import tkinter as tk


def cut(direction, cuts, left, right, top, bottom):
    if direction == "v":
        start, end = left, right
    elif direction == "h":
        start, end = top, bottom
    else:
        raise ValueError("Direction must be vertical/horizontal ('v' or 's')")

    total = 0
    last_loc = 0
    for fraction, sub_cuts in cuts:
        total += fraction
        loc = start + (end-start)*total

        # Calculate the (x1,y1), (x2,y2) of the line that will be displayed
        if direction == "v":
            x1 = x2 = loc
            y1, y2 = top, bottom
            cut("h", sub_cuts, last_loc, loc, top, bottom) # recursively cut
        elif direction == "h":
            y1 = y2 = loc
            x1, x2 = left, right
            cut("v", sub_cuts, left, right, last_loc, loc) # recursively cut

        canvas.create_line(x1, y1, x2, y2) # create the line
        last_loc = loc


WIDTH = 400
HEIGHT = 400

root = tk.Tk()
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT)
canvas.pack()


# No cuts
cuts = []

# Cut it vertically 50%
cuts = [(0.5,[])]

# Cut it 50% vertically and for the left small rectangle cut it horizontally 50%
cuts = [(0.5, [(0.5,[])])]

# Cut it 50% vertically and leave the left part.
# The right part gets cut twice more at 15% and at (15+35)%
cuts = [(0.5,[]), (0.5, [(0.15,[]), (0.35,[])])]

# Cut it vertically right at the end (does nothing - except now we can cut horizontally)
# Then cut it hotizontally at 50%. The top part gets cut vertically at 50%
cuts = [(1, [(0.5, [(0.5, [])])])]

# Cut 50% vertically and do nothing right the left part.
# The right part (other 50% of the total area) gets cut horizontally at 50%
# And the top part of that gets cuts 50% vertically again
cuts = [(0.5,[]), (0.5,[(0.5,[(0.5,[])])])]

cut("v", cuts, 0, WIDTH, 0, HEIGHT)

Сначала я заметил, что вы делаете (несколько) вертикальных разрезов, а затем (несколько) горизонтальных разрезов. Вы чередуете вертикальные и горизонтальные разрезы. Таким образом, для каждого разреза в моем списке хранятся дроби, а также список дальнейших разрезов в противоположном направлении.

Поэтому, если вы хотите разрезать его на 3 части (по вертикали), вы должны использовать [(1/3,[]), (1/3,[])] (сделав 2 разреза по 1/3 каждый и используя пустой список, чтобы обозначить отсутствие дальнейших разрезов).

Чтобы разрезать на 3 части (по горизонтали), используйте то же самое, но заверните внутрь [(1, <list from previous example>)]. Это делает разрез в крайнем правом углу (по сути, ничего не делая), а затем разрезает его по горизонтали.

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

Обновлено: возникает небольшая проблема, когда вы разрезаете в самом конце (вертикально или горизонтально), линия все равно отображается. Это потому, что в физической сфере вы не можете делать разрезы прямо на краю чего-либо (в отличие от математической сферы). Чтобы это исправить, вы можете закодировать эти дроби, используя None (представляющий последний подпрямоугольник), а затем просто пропустить canvas.create_line после замены переменной franction на 1-total.

Редактировать 2: Дополнительные примеры:

Разрезаем на сетку из 9:

# Cut vertically into 3rds and then in sub_cuts cut horizontally into 3rds again
sub_cuts = [(1/3,[]), (1/3,[])]
cuts = [(1/3,sub_cuts), (1/3,sub_cuts), (1/3,sub_cuts)]

Разрезаем на сетку 2х3:

# Cut vertically into 3rds and then in sub_cuts cut horizontally into 2 halfs
sub_cuts = [(1/2,[])]
cuts = [(1/3,sub_cuts), (1/3,sub_cuts), (1/3,sub_cuts)]

Разрезаем на сетку 3x2:

# Cut vertically into halfs and then in sub_cuts cut horizontally into 3rds
sub_cuts = [(1/3,[]), (1/3,[])]
cuts = [(1/2,sub_cuts), (1/2,sub_cuts)]

Более сложный пример:

third_sub_cuts = [(1/3,[])]*2
sixth_sub_cuts = [(1/6,[])]*5
cuts = [(0.25,sixth_sub_cuts), (0.5,third_sub_cuts), (0.25,sixth_sub_cuts)]

Привет @TheLizzard, спасибо за твою помощь. Алгоритм очень хорошо работает для создания разрезов, однако я до сих пор не уверен, как пользователь мог ввести этот код в обычное текстовое поле. Не могли бы вы предложить «код», который мог бы ввести пользователь?

Leo 02.09.2024 20:02

@Leo Можете ли вы использовать tkinter.Entry вызов встроенной функции eval для его содержимого, чтобы получить сокращения? Если вам нужен графический редактор для сокращений, это потребует много кода и будет полноценным проектом. На этом этапе я предлагаю изменить ваши требования так, чтобы принимались все непересекающиеся прямоугольники вместо используемого вами метода разрезов.

TheLizzard 02.09.2024 20:58

Другие вопросы по теме