Назад в раздел
Программное рисование во Flash MX. Управление кривыми.(Часть I)
div.main {margin-left: 20pt; margin-right: 20pt}
Программное рисование во Flash MX. Управление кривыми.(Часть I)
Программное рисование во Flash MX. Управление кривыми. (Часть I)
Вместо вступления.
Наконец-то!!! Теперь во Flash MX мы можем рисовать по средствам программного кода: создавать и удалять клипы, делать различные градиентные заливки, свободно управлять размером, местоположением и прочими характеристиками текста и, конечно же, рисовать прямые и кривые линии.
Но вслед за восторгом от новшеств вскоре приходят некоторые проблемы. Кривая, заданая тремя точками (начальная является концом предыдущей линии или может быть задана с помощью метода moveTo), ведёт себя совершенно непонятно - через точку (ControlX, ControlY) она даже не проходит, и может возникнуть проблема с рисованием даже простой окружности.
Не спешите "выбрасывать на свалку" инструмент curveTo, отчаявшись научиться им управлять. В этой статье будет рассказано о том, что же рисует curveTo, а также о том, как можно облегчить себе жизнь, создав несколько собственных инструментов рисования.
Что рисует curveTo().
По сути данная кривая всего-навсего CV NURBS из трёх точек, каждая с весом 1, кривая степени 2. Для тех, кто изучал 3D-Studio MAX R2 или выше или какую-либо другую программу создания 3D-графики и анимации этого достаточно (Poser и Bryce3D в расчёт не беруться, т.к. Я их не видел и наличие там NURBS гарантировать не могу). Для всех остальных потребуются пояснения. Control Vertex Non-Uniform Rational Basic Splines (сокращённо CV NURBS) - это линии, состоящие из частей кривых различного порядка (т.е. заданых математическими уравнениями некоторой степени), форма которых определяется направляющими векторами, концы которых находятся в задаваемых пользователем точках. В Flash MX эти составляющие имеют степень 2, т.е. это могут быть параболы, гиперболы и эллипсы. Но так как вес точки (коэффициэнт, влияющий на то, как близко к этой точке подходит кривая) постоянен и равен единице, то линия, создаваемая curveTo() является частью параболы. Из этого следует, что просто нарисовать обычную окружность или эллипс нельзя, а можно лишь нарисовать кривую, которая будет на них похожа. Ввиду ограниченности кол-ва задаваемых точек, сложную кривую нужно создавать по частям, рассчитывая точки так, чтобы не было изломов. Однако есть и свои плюсы. Направляющие векторы в нашем случае - это касательные к параболе в двух точках её графика, а точка (ControlX, ControlY) - пересечение этих касательных.
Это позволяет получить условие построения более сложной кривой без изломов. Для этого нужно, чтобы контрольная (сontrol) и якорная (anchor) точки первой кривой и контрольная точка второй кривой находились на одной прямой.
Однако хотелось бы, чтобы Flash сам рисовал кривые кривые любой сложности, а нам лишь нужно было задавать контрольные точки. Поэтому переходим к следующему пункту...
Метод рисование сложной кривой multicurveTo().
Данный метод позволит нам рисовать почти полноценный CV NURBS. Почти, потому что мы не сможем менять вес точки (всегда равный единице) и устанавливать степень кривой больше 2. Будет ещё одна оговорка, но о ней чуть позднее. Итак, программный код метода:
function Multicurve(Xargs, Yargs, closed){ var Xmid = Xargs.slice(0); var Ymid = Yargs.slice(0); if ((Xmid.length != Ymid.length) || (Xmid.length < 2)){ trace('Wrong Arguments'); return this }; if (Xmid.length == 2){ this.moveTo(Xmid[0], Ymid[0]); this.lineTo(Xmid[1], Ymid[1]); delete Xmid; delete Ymid; return this; }; var Xpoint = new Array(); var Ypoint = new Array(); for (var i = 1; i < Xmid.length-2; i++){ Xpoint[i] = 0.5*(Xmid[i+1]+Xmid[i]); Ypoint[i] = 0.5*(Ymid[i+1]+Ymid[i]); }; if (closed){ Xpoint[0] = 0.5*(Xmid[1]+Xmid[0]); Ypoint[0] = 0.5*(Ymid[1]+Ymid[0]); Xpoint[i] = 0.5*(Xmid[i+1]+Xmid[i]); Ypoint[i] = 0.5*(Ymid[i+1]+Ymid[i]); Xpoint[i+1] = 0.5*(Xmid[i+1]+Xmid[0]); Ypoint[i+1] = 0.5*(Ymid[i+1]+Ymid[0]); Xmid[i+2] = Xmid[0]; Ymid[i+2] = Ymid[0]; Xpoint[i+2] = Xpoint[0]; Ypoint[i+2] = Ypoint[0]; } else { Xpoint[0] = Xmid[0]; Ypoint[0] = Ymid[0]; Xpoint[i] = Xmid[i+1]; Ypoint[i] = Ymid[i+1]; Xmid.pop(); Ymid.pop(); }; this.moveTo (Xpoint[0], Ypoint[0]); for (var i = 1; i < Xmid.length; i++){ this.curveTo(Xmid[i], Ymid[i], Xpoint[i], Ypoint[i]); }; delete Xmid; delete Ymid; delete Xpoint; delete Ypoint; return this; } Object.prototype.multicurveTo = Multicurve;
Теперь разберём всё по порядку:
function Multicurve(Xargs, Yargs, closed){
В качестве аргументов передаём два массива - координаты контрольных точек кривой по х и по у, а также параметр closed, который показывает, какую мы хотим получить кривую. Если кривая замкнута, то линия не имеет начала и конца, все заданные точки используются как контрольные (значение closed равно true), в противном случае нулевая (исходя из индекса в массиве) и последняя заданные точки являются началом и концом кривой(значение closed равно false). Можно было бы сделать проверку на замкнутость автоматической, но иногда бывают случаи, когда нужно, чтобы линия имела совпадающие начало и конец.
var Xmid = Xargs.slice(0); var Ymid = Yargs.slice(0);
Возможно, Вам в дальнейшем потребуются массивы, которые вы задали как параметры функции. Если производить с аргументами Xargs и Yargs какие-нибудь преобразования, то изменятся и сами передаваемые массивы. Поэтому создаются их локальные копии (на локальность указывает слово var). Если Вы уверены, что передаваемые массивы нигде больше использоваться не будут, можно удалить эти две строчки, а первую строку записать как function Multicurve(Xmid, Ymid, closed){.
if ((Xmid.length != Ymid.length) || (Xmid.length < 2)){ trace('Wrong Arguments'); return this };
Проверка на отсутствие ошибок. Если задано меньше двух точек, или количество координат по X не равно количеству координат по Y, то метод заканчивается с передачей ссылки на себя и выводит в режиме теста соответствующее сообщение. Если проверка наличия хотя-бы двух точек - простая формальность, то проверка различного числа координат может быть весьма полезной. При желании строчку trace('Wrong Arguments'); можно заменить на что-нибудь вроде trace('Wrong Arguments: '+(Xmid.length-Ymid.length)), чтобы знать, сколько и каких координат не достаёт.
if (Xmid.length == 2){ this.moveTo(Xmid[0], Ymid[0]); this.lineTo(Xmid[1], Ymid[1]); delete Xmid; delete Ymid; return this; };
Ещё одна проверка. Если задано всего две точки, то мы просто рисуем соединяющий их отрезок и заканчиваем выполнение метода. Данная проверка обязательна, т.к. иначе используемый далее метод curveTo() просто не получит достаточное количество параметров. Слово this используется для того, чтобы данный метод, применённый к любому клипу перенимал все его свойства и действовал в его пределах. Обращаю Ваше внимание на следующие строки:
delete Xmid; delete Ymid;
В них удаляются из памяти локальные массивы. В ActionScript эти строчки не обязательны, т.к. "сборщик мусора" сам с ними разберётся.
Теперь вся подготовительная работа выполнена и можно начинать создание массивов данных для построения кривой:
var Xpoint = new Array(); var Ypoint = new Array(); for (var i = 1; i < Xmid.length-2; i++){ Xpoint[i] = 0.5*(Xmid[i+1]+Xmid[i]); Ypoint[i] = 0.5*(Ymid[i+1]+Ymid[i]); };
Cоздаём ещё два локальных массива, Xpoint и Ypoint, которые будут содержать координаты всех якорных точек. Далее в цикле происходит рассчёт координат этих якорных точек. Здесь и появляется та самая оговорка. В оригинале в CV NURBS координаты таких точек зависят от того, насколько далеко от концов кривой они находятся. Но подобный способ получения координат во Flash себя не оправдывает, и вот почему. В нашем методе мы создаём якорные точки на середине отрезка, соединяющего соседние контрольные точки. Максимальное отклонение "реального" местоположения якорных точек от середины отрезка меньше 0,58 % длины самого отрезка. Так что этим вполне можно пренебречь. Отмечу, что рассчёт координат происходит для точек с первой по предпоследнюю, так как координаты первой и последней рассчитываются в зависимости от того, замкнута кривая или нет.
if (closed){ Xpoint[0] = 0.5*(Xmid[1]+Xmid[0]); Ypoint[0] = 0.5*(Ymid[1]+Ymid[0]); Xpoint[i] = 0.5*(Xmid[i+1]+Xmid[i]); Ypoint[i] = 0.5*(Ymid[i+1]+Ymid[i]); Xpoint[i+1] = 0.5*(Xmid[i+1]+Xmid[0]); Ypoint[i+1] = 0.5*(Ymid[i+1]+Ymid[0]); Xmid[i+2] = Xmid[0]; Ymid[i+2] = Ymid[0]; Xpoint[i+2] = Xpoint[0]; Ypoint[i+2] = Ypoint[0]; }
Если кривая замкнута, то мы создаём нулевую якорную точку на середине отрезка между нулевой и первой контрольными точками, последнюю - между предпоследней и последней. И нам потребуются координаты ещё нескольких якорных точек: точки, находящейся на середине отрезка, соединяющего последнюю контрольную точку с первой, и копии координат нулевых якорной и контрольной точек. Это делается для того, чтобы объединить в один код рисование замкнутой и не замкнутой кривых. Используемая в индексах переменная i после окончания цикла имела значение Xmid.length-2, поэтому, следуя нашей организации массивов, Xpoint[i], Ypoint[i] - это координаты якорной точки, находящейся между предпоследней и последней контрольными (если здесь вообще уместно говорить, какая точка первая, а какая - последняя), Xpoint[i+1], Ypoint[i+1] - между последней и первой, Xpoint[i+2], Ypoint[i+2] - копии координат.
} else { Xpoint[0] = Xmid[0]; Ypoint[0] = Ymid[0]; Xpoint[i] = Xmid[i+1]; Ypoint[i] = Ymid[i+1]; Xmid.pop(); Ymid.pop(); };
Если же кривая не замкнута, то мы просто делаем нулевую и последнюю контрольные точки нулевой и последней якорной. Снова используем переменную i: Xmid[i+1], Ymid[i+1] являются поледними элементами массивов, т.к. i+1 = Xmid.length-1. Далее мы удаляем последний элемент в массивах координат контрольных точек, но оставляем первый затем, чтобы каждой паре якорных точек [i-1], [i] соответствовала [i]-ая контрольная точка, как и в случае замкнутой кривой.
Нахождение координат точек завершено и начинается процесс рисования кривой:
this.moveTo (Xpoint[0], Ypoint[0]); for (var i = 1; i < Xmid.length; i++){ this.curveTo(Xmid[i], Ymid[i], Xpoint[i], Ypoint[i]); };
Сначала указываем начальную точку. Затем начинаем рисовать кривые, где для каждой i-ой кривой начальная точка имеет координаты (Xpoint[i-1], Ypoint[i-1]), контрольная - (Xmid[i], Ymid[i]), а конечная - (Xpoint[i], Ypoint[i]). Искомая линия построена!!!
delete Xmid; delete Ymid; delete Xpoint; delete Ypoint; return this; }
Удаление массивов и окончание метода. Без комментариев.
В последней строчке Object.prototype.multicurveTo = Multicurve; мы добавляем наш метод к набору имеющихся методов класса Object.
В завершении...
Метод описан, можете смело его использовать. Для простоты рекомендую поместить весь программный код в текстовый файл с расширением .as и в каждом новом клипе, где этот метод может пригодиться, в корне (_root) написать строку
#include path
где path - это абсолютный или относительный путь к файлу с кодом. Заметьте, что после #include точка с запятой НЕ ставится. Лично у меня это выглядит так:
#include "D:/Flash/aibdraw.as"
Если для написания программного кода вы используете встроеный во Flash редактор, то, возможно, Вам пригодиться следущее: -- Заходите в корневой каталог Flash, далее First RunActionsPanel -- Открываете файл ActionsPanel.xml, находите <ifdef mode="FEATURE_DRAWING_API"> -- Перед </folder> прописываете подобную строчку: <string name="multicurveTo" tiptext="Draws a multipoint curve from the first to the last point" object="MovieClip" text=".multicurveTo(% [pointsX], [pointsY], Closed? %)" type="procedure" version="6" /> После этого в левом столбике редактора ActionScript и всплывающих подсказках появится multicurveTo().
Напоследок могу предложить вашему вниманию результат применения multicurveTo() с различными параметрами, а также небольшую картинку, созданную с его помощью и весящию в .swf 1628 байт.
Продолжение следует...
Copyleft: Aib |
Автор: © Aib Источник:
http://www.flasher.ru
|
|
|
|