Что не так с моим кодом привязки к сетке?
Вопрос
Прежде всего, я почти уверен, что привязка к сетке довольно проста, однако в этой ситуации я столкнулся с некоторыми странными проблемами, и моя математика слишком слаба, чтобы разобраться конкретно, что не так.
Вот такая ситуация
У меня есть абстрактная концепция сетки с Y шагами на расстоянии ровно Y_STEP друг от друга (x шагов работают нормально, поэтому игнорируйте их пока).
Сетка находится в абстрактном координатном пространстве, и чтобы все выровнять, у меня там есть волшебное смещение, давайте назовем его Y_OFFSET
чтобы привязаться к сетке, у меня есть следующий код (python)
def snapToGrid(originalPos, offset, step):
index = int((originalPos - offset) / step) #truncates the remainder away
return index * gap + offset
итак, я передаю позицию курсора, Y_OFFSET и Y_STEP в эту функцию, и она возвращает мне ближайшую к полу позицию y в сетке
Похоже, что в исходном сценарии это работает нормально, однако, когда я принимаю во внимание тот факт, что представление прокручивается, все становится немного странным.
Прокрутка сделана настолько простой, насколько я могу это понять, у меня есть окно просмотра, которое ведет подсчет расстояния, пройденного по оси Y, и просто компенсирует все, что проходит через него.
Вот фрагмент кода перемещения курсора mouseMotion:
def mouseMotion(self, event):
pixelPos = event.pos[Y]
odePos = Scroll.pixelPosToOdePos(pixelPos)
self.tool.positionChanged(odePos)
Итак, есть две вещи, на которые стоит обратить внимание: сначала перевод модуля прокрутки из положения пикселя в абстрактное координатное пространство, затем функция positionChanged инструмента, которая принимает значение абстрактного координатного пространства и привязывается к ближайшему Y-шагу.
Вот соответствующий код прокрутки
def pixelPosToOdePos(pixelPos):
offsetPixelPos = pixelPos - self.viewPortOffset
return pixelsToOde(offsetPixelPos)
def pixelsToOde(pixels):
return float(pixels) / float(pixels_in_an_ode_unit)
И инструменты обновляют код
def positionChanged(self, newPos):
self.snappedPos = snapToGrid(originalPos, Y_OFFSET, Y_STEP)
Последний релевантный фрагмент - это когда инструмент переходит к рендерингу самого себя.Он проходит через объект прокрутки, который преобразует положение инструмента в пространстве с привязанными координатами в положение пикселя на экране, вот код:
#in Tool
def render(self, screen):
Scroll.render(screen, self.image, self.snappedPos)
#in Scroll
def render(self, screen, image, odePos):
pixelPos = self.odePosToPixelPos(odePos)
screen.blit(image, pixelPos) # screen is a surface from pygame for the curious
def odePosToPixelPos(self.odePos):
offsetPos = odePos + self.viewPortOffset
return odeToPixels(offsetPos)
def odeToPixels(odeUnits):
return int(odeUnits * pixels_in_an_ode_unit)
Фух, это было длинное объяснение.Надеюсь, ты все еще со мной...
Проблема, с которой я сейчас сталкиваюсь, заключается в том, что при прокрутке вверх нарисованное изображение теряет выравнивание по курсору.
Он начинает привязываться к шагу Y ровно на 1 шаг ниже курсора.Кроме того, похоже, что он входит в выравнивание по фазе и выходит из него.
На некоторых свитках он превышен на 1, а на других - на месте.
Он никогда не выходит больше чем на 1 и всегда привязывается к допустимому местоположению сетки.
Лучшее предположение, которое я могу придумать, это то, что где-то я усекаю какие-то данные не в том месте, но понятия не имею, где и как это приводит к такому поведению.
Кто-нибудь знаком с координатными пространствами, прокруткой и привязкой?
Решение
Хорошо, я отвечаю здесь на свой собственный вопрос, как упоминал alexk, использование int для усечения было моей ошибкой.
Поведение, к которому я стремлюсь, лучше всего моделируется math.floor().
Прошу прощения, первоначальный вопрос не содержит достаточной информации, чтобы действительно разобраться, в чем проблема.На тот момент у меня не было дополнительной информации.
Что касается примечания об опечатке, я думаю, что, возможно, я неправильно использую контекст...С точки зрения функции positionChanged(), параметр представляет собой ввод новой позиции.
С точки зрения функции snapToGrid() параметр представляет собой исходную позицию, которая изменяется на привязанную позицию.Язык такой, потому что часть его находится в моем коде обработки событий, а другая часть - в моем коде общих служб.Я должен был изменить это для примера
Другие советы
У вас есть опечатка в positionChanged()?
def positionChanged(self, newPos):
self.snappedPos = snapToGrid(newPos, Y_OFFSET, Y_STEP)
Я предполагаю, что вы ошиблись на один пиксель из-за проблем с точностью при делении с плавающей точкой.Попробуйте изменить ваш snapToGrid () на этот:
def snapToGrid(originalPos, offset, step):
EPS = 1e-6
index = int((originalPos - offset) / step + EPS) #truncates the remainder away
return index * gap + offset
Спасибо за ответ, возможно, здесь опечатка, но я ее не вижу...
К сожалению, изменение в snapToGrid ничего не изменило, так что я не думаю, что проблема в этом.
Он отключен не на один пиксель, а скорее на Y_STEP.Поиграв с этим еще немного, я обнаружил, что я не могу точно определить, в какой момент экран прокручивается вверх, а также что это происходит в верхней части экрана, что, как я подозреваю, является нулевой позицией ODE, поэтому я предполагаю, что моя проблема связана с малыми или отрицательными значениями.