Различия между версиями 7 и 8
Версия 7 от 2015-01-17 18:03:31
Размер: 3004
Редактор: FrBrGeorge
Комментарий:
Версия 8 от 2015-01-17 18:44:53
Размер: 3961
Редактор: FrBrGeorge
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 13: Строка 13:
  return float(X0-A0)/(B0-A0)*(B1-A1)+A1    return float(X0-A0)/(B0-A0)*(B1-A1)+A1
Строка 19: Строка 19:
  up()
  goto(A,y)
  down()
  stamp()
  goto(x,y)
  stamp()
  goto(B,y)
  stamp()
  up()
   up()
   goto(A,y)
    down()
   stamp()
   goto(x,y)
    stamp()
   goto(B,y)
    stamp()
    up()
Строка 50: Строка 50:
  X=M[0]*cos(A)-M[1]*sin(A)
  Y=M[1]*cos(A)+M[0]*sin(A)
  return X,Y
   X=M[0]*cos(A)-M[1]*sin(A)
    Y=M[1]*cos(A)+M[0]*sin(A)
    return X,Y
Строка 55: Строка 55:
Проверим: Проверим. Зададим функцию рисования ломаной по точкам:
{{{#!python
def draw(line):
    up()
    goto(*line[0])
    down()
    for x,y in line[1:]:
        goto(x,y)
    up()
}}}

Убедимся, что поворот на угол, близкий к `pi` относительно (0,0) переносит фигуру из первого в третий квадрант (при повороте ровно на `pi` будет наблюдаться центральная симметрия):
{{{#!python
l = [(100,200),(200,50),(50,100),(150,50)]
ll = [rotate(m,2.75) for m in l]
draw(l)
draw(ll)
}}}

== Перенос + масштабирование + поворот ==

Осталось решить, какая точка в операции «перенос + масштабирование + поворот» будет служить началом координат.

Перенос, масштабирование и вращение

Масштабирование

При работе с растровой графикой очень частая операция — масштабирование объектов. Суть операции в том, чтобы число X0 в диапазоне от A0 до B0 превратить в число X1 в диапазоне от A1 до B1 с соблюдением пропорций:

a0b0xa1b1.png

Значение X0 сначала надо нормализовать: перевести из диапазона A0…B0 в диапазон 0…1. Для чего из X0 надо вычесть нижнюю границу диапазона A0 и поделить результат на длину диапазона B0-A0: X=(X0-A0)/(B0-A0)

Затем перевести в новый диапазон A1…B1 теми же операциями в обратном порядке. Получаем функцию переноса с масштабированием scale():

   1 def scale(A0,B0,A1,B1,x):
   2     return float(X0-A0)/(B0-A0)*(B1-A1)+A1

Проверим, как это выглядит с помощью Черепашки:

   1 def AxB(A,B,x,y):
   2     up()
   3     goto(A,y)
   4     down()
   5     stamp()
   6     goto(x,y)
   7     stamp()
   8     goto(B,y)
   9     stamp()
  10     up()
  11 
  12 A0,B0,X0 = -50,120,81
  13 AxB(A0,B0,X0,40)
  14 # Теперь масштабируем X0
  15 A1,B1 = -100,200
  16 X1 = scale(A0,B0,A1,B1,X0)
  17 AxB(A1,B1,X1,-40)

Поворот

Более подробно см Поворот в Википедии.

Вспомним¸ что sin угла и cos угла — это длины противолежащего и прилежащего катетов в прямоугольном треугольнике с единичной гипотенузой:

attachemnt:sincos.png

Обратим внимание, что картинка также иллюстрирует поворот на угол A против часовой стрелки точки пересечения положительной полуоси абсцисс и единичной окружности с центром в начале координат.

Сравнительно несложно (поворотом этой картинки на произвольный угол) доказать, что поворот любой точки на единичной окружности аналогичен, и получить следующую функцию поворота точки M на угол A относительно точки (0,0):

   1 def rotate(M,A):
   2     X=M[0]*cos(A)-M[1]*sin(A)
   3     Y=M[1]*cos(A)+M[0]*sin(A)
   4     return X,Y

Проверим. Зададим функцию рисования ломаной по точкам:

   1 def draw(line):
   2     up()
   3     goto(*line[0])
   4     down()
   5     for x,y in line[1:]:
   6         goto(x,y)
   7     up()

Убедимся, что поворот на угол, близкий к pi относительно (0,0) переносит фигуру из первого в третий квадрант (при повороте ровно на pi будет наблюдаться центральная симметрия):

   1 l = [(100,200),(200,50),(50,100),(150,50)]
   2 ll = [rotate(m,2.75) for m in l]
   3 draw(l)
   4 draw(ll)

Перенос + масштабирование + поворот

Осталось решить, какая точка в операции «перенос + масштабирование + поворот» будет служить началом координат.

TODO

FrBrGeorge/PythonScaleAndRotate (последним исправлял пользователь FrBrGeorge 2015-01-18 20:42:33)