Assembler
Нужно нарисовать в Tasm'e 16bit круг, при наличие радиуса и координат.
перепробовал всё... есть только одна формула у меня r**2=(x-a)**2+(y-b)**2
Кто знает, прошу помощи.
А и ешё нужно нарисовать квадрат и заставить его крутиться.
Квадрат нарисовать могу, сделать Delay тоже а вот крутиться, только на 90 градусов...
Спасибо заранее =)
Круг можно рисовать алгоритмом Брезенхема для генерации окружностей.
Квадрат - перенести так, чтобы центр был в начале координат, потом перевести координаты вершин в полярные, добавить угол поворота, потом опять в декартовы координаты, перенести на исходную позицию и нарисовать четыре линии.
x = cos(a)*r + x0
y = sin(a)*r + y0,
где a - угол поворота (менять в цикле от 0 до 2*Pi), r - радиус, x0,y0 - координаты центра окружности.
Окружность:
x = cos(a)*r + x0
y = sin(a)*r + y0,
где a - угол поворота (менять в цикле от 0 до 2*Pi), r - радиус, x0,y0 - координаты центра окружности.
Проблема в том что я не знаю как в assem'e вычислить косинус и синус угла...
fanto: в круге под асм
Проблема в том что я не знаю как в assem'e вычислить косинус и синус угла...
fanto: в круге под асм
Синус и косинус на ассемблере знать и не надо (в этом случае). Делается это так:
Составляется таблица синусов для углов (0-90) на Си++, например. Все остальные углы другие функции (косинус, тангес и пр.) можно посчитать, юзая учебник по Алгебре за 9 класс - формулы приведения, кажется, т.е.: sin(-PI/2) = -sin(PI/2); cos(alpha) = sin(PI/2-alpha) или че-то в этом роде.
Вобще круг можно нарисовать более простым способом (я где-то видел), но сейчас под рукой у меня этой книги (где описан простой способ) нету. Дойду до дома, может напишу. Но этого (таблицы синусов) вполне достаточно - когда я этой задачей забивал себе голову первый раз, так и делал.
Вспомним, как рисуется прямая линия - там у нас есть dx и dy, отношение которых показывает, сколько нужно пройти точек по одной оси, чтобы по другой оси пройти всего лишь одну точку.
Так же и с кругом.
Для того, чтобы нарисовать круг, достаточно нарисовать дугу (угол дуги - 90 градусов), допустим от (x0,y0-R) до (x0+R,y0), где (x0, y0) - центр круга, а R - радиус.
Подготовка.
Бирём за начальную точку - (x0,y0-R).
Мы знаем, что двигаться мы будем вправо-вниз, рисуя точки либо справа (относительно текущей), либо снизу (точек справа-снизу мы ставить не буем).
Таким образом на каждом шаге у нас есть выбор из двух вариантов (пойти вниз или вправо). Чтобы выбрать один из вариантов, будет для каждого из них определять на сколько будующая точка будет отстаять от центра круга - соответственно, та точка, для которой это расстояние ближе к R, ту мы и рисуем.
Как определить расстояние до точки?
1) s = sqrt((X0-X)**2 + (Y0-Y)**2) - ясное дело, что для Ассемблера это не катит
2) Т.к. растояние мы сравниваем с радиусом, мы получаем первое упращение: s**2 = (X0-X)**2 + (Y0-Y)** - эту байду мы будем сравнивать не с радиусом, а с R**2 (который считается только однажды).
Возводить в квадрат всё, что двигается нам тоже не в кайф, поэтому думаем дальше.
Пусть Mx = (X-X0)**2, а Sx = (X-X0), тогда, если то же проделать и с Y-ком, то мы получим: s**2 = Mx+My - проще только "NOP". Так вот именно Mx+My для нижней и для правой точек мы и будет сравнивать с уже посчитанным (вначале программы) R**2. Как определить для точки Mx и My, и для чего у нас Sx и Sy???
Т.к. умножать и делить мы не хотим (по крайней мере я не хочу - у меня с детства боязнь к операциям умножения на асме), будем думать, как можно обойтись только сложением и вычитанием (ну и может ещё чем простым).
Зная Mx и Sx для текущей точки, как узнать их для правой и нижней точек? Очень просто.
Для правой точки: Sx = Sx+1, Mx* = (Sx+1)**2 = Sx**2 + 2*Sx + 1 = Mx + 2*Sx +1 (для тех, кто изучает ассемблер самостоятельно без книжки и компьютера: чтобы умножить число на степень двойки, нужно "сдвинуть" его влево на эту самую степень, т.е. X*2 <=> SHL X,1).
То же и для нижней точки: My* = My + 2*Sy + 1.
Мы получили два выражения, из которых нужно выбрать то, значение которого по модулю меньше:
Точка справа: (Mx + 2*Sx + 1) + My - R**2 = Mx* + My - R**2
Точка снизу: Mx + (My + 2*Sy + 1) - R**2 = Mx + My* - R**2
Реализация:
1) При инициализации мы находим Mx, My, 2*Sx, 2*Sy, R**2 для точки (X0, Y0-R)
2) На каждой итерации мы считаем:
Mx*, My* по формуле "Mi* = Mi + 2*Si + 1";
abs(sr), abs(sb) - разница между квадратом расстояния до правой или нижней точки (соответственно) и квадратом радиуса взятая по модулю.
Сравнить abs(sr) и abs(sb):
Если abs(sr) меньше, то Mx = Mx*, 2*Sx = 2*Sx+2 (для тех же самоучек, сложение с двойкой выполняется медленнее двух увеличений на 1 - на асме две команды "INC"), x = x+1.
Если abs(sb) меньше, то My = My*, 2*Sy = 2*Sy+2, y = y+1.
3) Цикл повторяется, пока x<=(x0+R) и y<=(y0) (В принципе, на том же асме, проще будет следить только за одной координатой).
Кстати, на Си рисование круга выглядет гораздо красивей, в то время, как код прогаммы не будет ни медленнее, ни длиннее.
После того, как всё это написал, ещё малость подумал и понял, что в той книжке, скорее всего так и было - там алгоритм не объяснялся - только код с комментариями был, в котором я нифига не поня, но понял, что умножений и делений нету.
Так что даже не знаю, сам я придумал этот способ или он у меня в подсознании сохранился, когда я книжку смотрел, а сейчас в сознании реализовался :D .
Что касается квадрата, то это делается с помощью матриц поворота - для каждой вершины многоугольника расчитываются новые координаты используя матрицу поворота. На асме могу только посоветовать сделать функцию рисования квадрата по вершинам (придется сделать ещё функцию рисования линии), затем для каждой вершины расчитывать координаты использую таблицу синусов: x* = cos(alpha)*L; y = sin(alpha)*L, где L - расстояние от центра поворота до текущей вершины, alpha - угол поворота. Естественно тут тоже можно всё упростить, но лучше подобным заниматься на Си.
Книжку я не нашёл - видать она не моя была. Но я малость по думал и вот что придумал:
Вспомним, как рисуется прямая линия - там у нас есть dx и dy, отношение которых показывает, сколько нужно пройти точек по одной оси, чтобы по другой оси пройти всего лишь одну точку.
Так же и с кругом.
Для того, чтобы нарисовать круг, достаточно нарисовать дугу (угол дуги - 90 градусов), допустим от (x0,y0-R) до (x0+R,y0), где (x0, y0) - центр круга, а R - радиус.
Подготовка.
Бирём за начальную точку - (x0,y0-R).
Мы знаем, что двигаться мы будем вправо-вниз, рисуя точки либо справа (относительно текущей), либо снизу (точек справа-снизу мы ставить не буем).
Таким образом на каждом шаге у нас есть выбор из двух вариантов (пойти вниз или вправо). Чтобы выбрать один из вариантов, будет для каждого из них определять на сколько будующая точка будет отстаять от центра круга - соответственно, та точка, для которой это расстояние ближе к R, ту мы и рисуем.
Как определить расстояние до точки?
1) s = sqrt((X0-X)**2 + (Y0-Y)**2) - ясное дело, что для Ассемблера это не катит
2) Т.к. растояние мы сравниваем с радиусом, мы получаем первое упращение: s**2 = (X0-X)**2 + (Y0-Y)** - эту байду мы будем сравнивать не с радиусом, а с R**2 (который считается только однажды).
Возводить в квадрат всё, что двигается нам тоже не в кайф, поэтому думаем дальше.
Пусть Mx = (X-X0)**2, а Sx = (X-X0), тогда, если то же проделать и с Y-ком, то мы получим: s**2 = Mx+My - проще только "NOP". Так вот именно Mx+My для нижней и для правой точек мы и будет сравнивать с уже посчитанным (вначале программы) R**2. Как определить для точки Mx и My, и для чего у нас Sx и Sy???
Т.к. умножать и делить мы не хотим (по крайней мере я не хочу - у меня с детства боязнь к операциям умножения на асме), будем думать, как можно обойтись только сложением и вычитанием (ну и может ещё чем простым).
Зная Mx и Sx для текущей точки, как узнать их для правой и нижней точек? Очень просто.
Для правой точки: Sx = Sx+1, Mx* = (Sx+1)**2 = Sx**2 + 2*Sx + 1 = Mx + 2*Sx +1 (для тех, кто изучает ассемблер самостоятельно без книжки и компьютера: чтобы умножить число на степень двойки, нужно "сдвинуть" его влево на эту самую степень, т.е. X*2 <=> SHL X,1).
То же и для нижней точки: My* = My + 2*Sy + 1.
Мы получили два выражения, из которых нужно выбрать то, значение которого по модулю меньше:
Точка справа: (Mx + 2*Sx + 1) + My - R**2 = Mx* + My - R**2
Точка снизу: Mx + (My + 2*Sy + 1) - R**2 = Mx + My* - R**2
Реализация:
1) При инициализации мы находим Mx, My, 2*Sx, 2*Sy, R**2 для точки (X0, Y0-R)
2) На каждой итерации мы считаем:
Mx*, My* по формуле "Mi* = Mi + 2*Si + 1";
abs(sr), abs(sb) - разница между квадратом расстояния до правой или нижней точки (соответственно) и квадратом радиуса взятая по модулю.
Сравнить abs(sr) и abs(sb):
Если abs(sr) меньше, то Mx = Mx*, 2*Sx = 2*Sx+2 (для тех же самоучек, сложение с двойкой выполняется медленнее двух увеличений на 1 - на асме две команды "INC"), x = x+1.
Если abs(sb) меньше, то My = My*, 2*Sy = 2*Sy+2, y = y+1.
3) Цикл повторяется, пока x<=(x0+R) и y<=(y0) (В принципе, на том же асме, проще будет следить только за одной координатой).
Кстати, на Си рисование круга выглядет гораздо красивей, в то время, как код прогаммы не будет ни медленнее, ни длиннее.
После того, как всё это написал, ещё малость подумал и понял, что в той книжке, скорее всего так и было - там алгоритм не объяснялся - только код с комментариями был, в котором я нифига не поня, но понял, что умножений и делений нету.
Так что даже не знаю, сам я придумал этот способ или он у меня в подсознании сохранился, когда я книжку смотрел, а сейчас в сознании реализовался :D .
Что касается квадрата, то это делается с помощью матриц поворота - для каждой вершины многоугольника расчитываются новые координаты используя матрицу поворота. На асме могу только посоветовать сделать функцию рисования квадрата по вершинам (придется сделать ещё функцию рисования линии), затем для каждой вершины расчитывать координаты использую таблицу синусов: x* = cos(alpha)*L; y = sin(alpha)*L, где L - расстояние от центра поворота до текущей вершины, alpha - угол поворота. Естественно тут тоже можно всё упростить, но лучше подобным заниматься на Си.
спасибо!