понедельник, 10 января 2011 г.

Введение в класс SimpleGraph

Класс SimpleGraph: первый пример

Приложение, созданное в этом примере, будет чертить графики двух "вшитых" в код функций, отслеживать положения точек на них, а также показывать расстояние между ними. Использование данного приложения должно помочь в нахождении самого большого расстояния между двумя кривыми - классической задаче из задачника (в реальной жизни данная задача решается с помощью производных).
Цель данного примера – показать возможности использования класса SimpleGraph, позволяющего создавать более сложные приложения.

Простейший пример использования класса SimpleGraph

Самое важное свойство класса SimpleGraph – это свойство board, являющееся экземпляром другого класса – GraphingBoard. После обсуждения данного примера мы рассмотрим возможности использования методов класса GraphingBoard для усовершенствования внешнего вида графиков.

Настройки сцены

В этом приложении нам понадобится слайдер – slX и динамическое текстовое поле txtDistance.

Пишем код

Прежде всего, необходимо импортировать классы пакета flashandmath.as3.tools (SimpleGraph входит в состав данного пакета). Помните, что папка flashandmath должна быть в той же папке, что и исходный файл проекта. Ну и кроме этого импортируем дополнительные самого флеша

package 
{
import flashandmath.as3.tools.*;

import com.bit101.components.HSlider;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.ui.Keyboard;
import teormech.utils.TextUtils;

public class Main extends Sprite 
{

Объявляем необходимые переменные класса:

// Текстовое поле для отображения расстояния между кривыми
private var txtDistance:TextField;

// Горизонтальный слайдер для обеспечения возможности 
// взаимодействия с графиками функций 
private var slX:HSlider;

// Размеры области графика и сам объект класса SimpleGraph 
// для отрисовки графиков
private var bSize:Number = 300;
private var gsimp:SimpleGraph;

// Массивы для хранения координат точек графиков функций
private var arrPx1:Array;
private var arrPx2:Array;

// Маркеры для обозначения текущих точек на графике 
// и расстояния между ними
private var sh1:Shape;
private var sh2:Shape;
private var shLine:Shape;

Рассмотрим упрощенно принципы построения графиков внутри класса SimpleGraph. Т.к. один объект SimpleGraph может отображать несколько графиков различных функций, то для доступа к ним введено понятие "уровня" (если угодно, "глубины") графика i. Для каждого графика создается и сохраняется массив значений координат точек, доступ к которому можно получить, вызвав метод gsimp.getPixData(i) (где i – "уровень" графика). Размер этого массива определяется свойством numPoints объекта SimpleGraph. Поэтому, если у нашего слайдера диапазон значений будет изменяться от 0 до numPoints, то мы сможем использовать значения положения слайдера, как индекс для точки графика, и тем самым обеспечим их прямую связь.

// Фрагмент метода init()

var tempFormat:TextFormat = 
new TextFormat("Arial", "14", "0x000000", true);
tempFormat.align = TextFormatAlign.CENTER;

txtDistance = 
TextUtils.createTextField("", 415, 280, tempFormat, 120, 20);
addChild(txtDistance);

// Создаем экземпляр класса SimpleGraph с областью 
// для отрисовки графиков 300 на 300 пикселей  
gsimp = new SimpleGraph(bSize,bSize);
gsimp.x = 25;
gsimp.y = 10;
addChild(gsimp);

// Устанавливаем количество точек, по которым строится график, 
// равным диапазону значений нашего слайдера (см. далее)
gsimp.setNumPoints(2*bSize);

// Устанавливаем пределы изменения координат на графике
gsimp.setWindow("-pi","sqrt(10)","-1.5","1.5");

// Строим графики двух функций 
// (один синего цвета, второй  - зеленого)
// Заметьте, что первому графику мы задаем значение глубины 
// равным 1, а второму 2. 
// Зная эти значения, мы имеем доступ к этим графикам
gsimp.graphRectangular("sin(x)","x",1,2,0x0000AA);
gsimp.graphRectangular("cos(x)", "x", 2, 2, 0x00AA00);

// Здесь видно, как можно получить данные о координатах 
// точек графика, передавая методу getPixData в качестве 
// аргумента значения глубины графика 
arrPx1 = gsimp.getPixData(1);
arrPx2 = gsimp.getPixData(2);

// Создаем маркеры точек на графиках 
// и строим соединяющую их линию    
sh1 = new Shape();
sh1.graphics.lineStyle(1,0);
sh1.graphics.beginFill(0x0000AA);
sh1.graphics.drawCircle(0,0,6);
sh1.graphics.endFill();

// Здесь видно, как можно получить данные 
// о координатах точек графика.
// Они хранятся в виде вложенных массивов, 
// первыми элементами которых являются значения 
// координаты "x", а вторыми – значения "y" (в пикселях)
sh1.x = arrPx1[0][0];
sh1.y = arrPx1[0][1];

sh2 = new Shape();
sh2.graphics.lineStyle(1,0);
sh2.graphics.beginFill(0x00AA00);
sh2.graphics.drawCircle(0,0,6);
sh2.graphics.endFill();
sh2.x = arrPx2[0][0];
sh2.y = arrPx2[0][1];

shLine = new Shape();
shLine.graphics.lineStyle(2,0x000000);
shLine.graphics.moveTo(sh1.x,sh1.y);
shLine.graphics.lineTo(sh2.x,sh2.y);

// Создаем слайдер, располагаем его под графиком функции, 
// устанавливаем его ширину равной ширине графика, а также 
// задаем ему нужный нам диапазон значений [0; 2 * bSize]
slX = new HSlider(this, 25, 330, update);
slX.setSliderParams(0, 2 * bSize, 0);
slX.width = bSize;

Т.к. свойство board объекта SimpleGraph не является общедоступным, то мы не можем добавлять на него объекты отображения напрямую. Для этого нужно использовать метод addChildToBoard. Преимущество данного способа добавления пользовательской графики в том, что у объекта board есть маска и при использовании метода addChildToBoard она автоматически применяется к ней.

// Функция update вызывается при перетаскивании слайдера. 
// Используя его положение в качестве индекса в массиве 
// значений координат точек, мы можем динамически изменять 
// положения маркеров, отрисовывать линию соединяющую их, 
// и обновлять значение расстояния между точками графиков 
private function update(evt:Event):void 
{
var i:int = slX.value;
sh1.x = arrPx1[i][0];
sh1.y = arrPx1[i][1];
sh2.x = arrPx2[i][0];
sh2.y = arrPx2[i][1];

shLine.graphics.clear();
shLine.graphics.lineStyle(2,0x000000);
shLine.graphics.moveTo(sh1.x,sh1.y);
shLine.graphics.lineTo(sh2.x,sh2.y);
txtDistance.text = getDistance();
}

Функция getDistance используется из-за того, что значение вертикального расстояния между точками должно выводится не в пикселях, а в математических единицах. Для этого используется метод yfromPix (у него есть "собрат" – метод xfromPix, преобразующий значения горизонтальной координаты).

private function getDistance():String {
var dy:Number = Math.abs(gsimp.board.yfromPix(sh1.y) - 
    gsimp.board.yfromPix(sh2.y));
return ("Distance = " + dy.toFixed(2));
}

Теперь рассмотрим некоторые методы класса GraphingBoard.

Настройка внешнего вида графиков с использованием класса GraphingBoard

Как мы видели у объектов класса SimpleGraph есть свойство board, являющееся объектом класса GraphingBoard. Объекты этого класса содержат прямоугольный фон и маску, а также обладают множеством свойств и методов для управления внешним видом графиков.

Немного усовершенствованный пример (внешний вид графика настраивается с помощью методов класса GraphingObject

Пример «Вертикальное расстояние». Второй подход

Созданному нами приложению «Вертикальное расстояние» в том виде, в каком оно сейчас находится, явно не хватает деталей: мы не видим сетки, меток, обозначений осей и не можем оценить расстояния между точками на глаз. Покажем как все это сделать.
Откроем файл приложения, созданного в предыдущем примере, и добавим следующий код в метод init() (сразу за строкой var arrPx2:Array = gsimp.getPixData(2);):

gsimp.board.changeBackColor(0xFFEEEE); 
gsimp.board.changeBorderColorAndThick(0xDDDDDD,4); 
gsimp.board.setAxesColorAndThick(0x777777,2); 
gsimp.board.setCoordsBoxFormat( 0xEEEEEE, 0xDDDDDD, 
                                     0x000000, 12);
gsimp.board.drawAxes(); 
gsimp.board.setGrid(0.5,0.25); 
gsimp.board.drawGrid(); 
gsimp.board.setTicks(1,1,10,10); 
gsimp.board.drawTicks(); 
gsimp.board.addLabels();

Имена методов класса GraphingBoard говорят сами за себя.

На сегодня, думаю, хватит. Вот исходники к рассмотренным здесь примерам.
В следующих нескольких постах мы закончим рассмотрение примеров использования классов пакета flashandmath и перейдем к чему-нибудь новому и, надеюсь, интересному не только мне.

Комментариев нет:

Отправить комментарий