Метод DrawGraph для приложения «Построение графиков производной»
Данный пример покажет возможность непосредственного использования метода drawGraph класса GraphingBoard. Этот метод, с помощью которого вы можете создать массив парных значений (в математических единицах), а затем передать его объекту класса GraphingBoard для непосредственной отрисовки на графике. Т.к. методы класса SimpleGraph позволяют строить лишь несколько предопределенных типов графиков (графики функций в декартовых и полярных координатах, а также параметрических функций), то понимание метода drawGraph класса GraphingBoard даст Вам более гибкие возможности для построения собственных графиков.
Настройка сцены
Настройка сцены заключается в расположении на ней кнопки, слайдера, пяти текстовых полей для ввода текста и одного динамического текстового поля, а также ряда статических полей, поясняющих значение полей ввода (см. рис. 1). Для кнопки назначаем имя btnGraph, для слайдера – slX. Имена пяти текстовых полей: txtFunc, txtXmain, txtXmax, txtYmin, txtYmax. Динамическому текстовому полю, расположенному внизу, задаем имя txtSlope, его ширина должна быть достаточна, чтобы отобразить строку "Slope = -999.99" (уклон касательной).
Добавляем следующий код (здесь я опускаю импорт необходимых классов, смотрите исходники):
public class Main extends Sprite { // Размеры объекта SimpleGraph private var bSize:Number = 300; // Длина (в пикселях) касательной private var lineLength:Number = 100; // Переменные для настройки графика private var xticks:Number = 1; private var yticks:Number = 1; private var xgrids:Number = 1; private var ygrids:Number = 1; // Необходимые текстовые поля private var txtFunc:TextField; private var txtXmin:TextField; private var txtXmax:TextField; private var txtYmin:TextField; private var txtYmax:TextField; private var txtSlope:TextField; private var gderiv:SimpleGraph; private var slX:HSlider; private var btnGraph:PushButton; // Массивы, хранящие данные о координатах точек // графика функции и ее производной private var arrPx:Array; private var arrSlopes:Array; // Маркеры на графике private var shTan:Shape = new Shape(); private var shPoint:Shape = new Shape();
gderiv = new SimpleGraph(bSize,bSize); gderiv.x = 40; gderiv.y = 50; // Чтобы с помощью слайдера можно было отслеживать точку // на графике функции, число точек графика должно быть // равно диапазону значений слайдера gderiv.setNumPoints(bSize); gderiv.board.changeBackColor(0xFFEEEE); gderiv.board.setCoordsBoxFormat(0xEEEEEE, 0xDDDDDD, 0x000000, 12); gderiv.board.setGrid(xgrids,ygrids); gderiv.board.setTicks(xticks,yticks,10,10); addChild(gderiv); slX = new HSlider(this, gderiv.x, gderiv.y + bSize + 10, update); slX.setSliderParams(0, bSize, 0); slX.width = bSize; slX.visible = false; shTan.graphics.lineStyle(1,0x000000); shTan.graphics.beginFill(0xCC0000,0.8); shTan.graphics.drawRect(-2,-lineLength/2, 4, lineLength); shTan.graphics.endFill(); shTan.graphics.beginFill(0xAAAAAA); shTan.graphics.drawCircle(0,0,4); shTan.graphics.endFill(); shTan.visible = false; shPoint.graphics.lineStyle(1,0); shPoint.graphics.beginFill(0x007700); shPoint.graphics.drawCircle(0,0,5); shPoint.graphics.endFill(); shPoint.visible = false; gderiv.addChildToBoard(shTan); gderiv.addChildToBoard(shPoint); // Исходное состояние графика txtFunc.text = "sin(x) + cos(x)"; txtXmin.text = "-pi"; txtXmax.text = "pi"; txtYmin.text = "-1.5"; txtYmax.text = "1.5"; drawGraph(); }
Маркер shTan – это вытянутый прямоугольник с точкой регистрации (внутренней точкой отсчета), расположенной в его центре. Чтобы использовать данные об углах наклона кривой, хранящихся в массиве gderiv.getPixData(), для точного позиционирования маркера необходимо, чтобы в исходном состоянии маркер должен быть вертикальным. Итак, маркер shTan будет показывать касательную к графику функции f, введенной пользователем, а маркер shPoint – точку на графике производной функции f.
Для добавления маркеров shTan и shPoint в список отображения объекта gderiv.board мы используем метод addChildtoBoard. Если бы мы использовали метод gderiv.addChild, то к этим маркерам не применилась бы маска объекта gderiv.board, и они оставались бы видимыми даже при выходе за область отрисовки графика:
gderiv.board.addChildToBoard(shTan); gderiv.board.addChildToBoard(shPoint);
private function setup():void { slX.visible = false; shTan.visible = false; shPoint.visible = false; gderiv.setWindow(txtXmin.text, txtXmax.text, txtYmin.text, txtYmax.text); if (gderiv.hasError()) return; gderiv.board.drawGrid(); gderiv.board.drawAxes(); gderiv.board.drawTicks(); gderiv.board.addLabels(); }
private function update(evt:Event):void { var i:int = slX.value; shTan.x = arrPx[i][0]; shTan.y = arrPx[i][1]; shTan.rotation = arrPx[i][2]; shPoint.x = shTan.x; shPoint.y = gderiv.board.ytoPix(arrSlopes[i][1]); txtSlope.text = "Slope = " + arrSlopes[i][1].toFixed(2); }
private function btnGraphClicked(mevt:MouseEvent):void { drawGraph(); } private function drawGraph():void { var i:int; var thisX:Number; // Если нет функции для построения графика, // то и делать ничего не нужно if (txtFunc.text.length == 0) return; setup(); // при возникновении ошибки график мы не строим if (gderiv.hasError()) return; // Вычерчиваем график функции, введенной в поле txtFunc gderiv.graphRectangular(txtFunc.text,"x",1,2,0x0000AA); if (gderiv.hasError()) return; gderiv.board.drawGrid(); gderiv.board.drawAxes(); gderiv.board.drawTicks(); gderiv.board.addLabels(); // arrPx – это массив, состоящий из массивов по три элемента: // координаты точек и углы наклона касательных в данных точках arrPx = gderiv.getPixData(1); arrSlopes = new Array(arrPx.length); // Заполняем массив точек, по которым будет // строиться график производной функции for (i=0; i < arrSlopes.length; i++) { thisX = gderiv.board.xfromPix(arrPx[i][0]); arrSlopes[i] = [thisX, getSlope(thisX)]; } // Вычерчиваем график производной функции толщиной в 2 // пикселя на 2 уровне. // График самой функции вычерчивается на уровне 1 gderiv.board.drawGraph(2,2,arrSlopes,0x007700); shTan.visible = true; shPoint.visible = true; slX.visible = true; slX.value = 0; // Располагаем маркеры shTan и shPoint // и обновляем отображаемый текст shTan.x = arrPx[0][0]; shTan.y = arrPx[0][1]; shTan.rotation = arrPx[0][2]; shPoint.x = shTan.x; shPoint.y = gderiv.board.ytoPix(arrSlopes[0][1]); txtSlope.text = "Slope = " + arrSlopes[0][1].toFixed(2); }
private function getSlope(xval:Number):Number { var dx:Number = 0.0000001; var y1:Number = gderiv.rectangularValueAt(1,xval - dx); var y2:Number = gderiv.rectangularValueAt(1,xval + dx); return ((y2 - y1)/(2*dx)); }
Использование класса RangeParser для отрисовки графиков в полярных координатах
В этом примере мы построим простой график функции r = f(θ) в полярных координатах (см. рис. 2). Для этого мы используем метод drawPolar объекта SimpleGraph, но кроме этого нам понадобится кое-что еще: чтобы слайдер мог изменять значения координаты θ в заданных пользователем пределах, мы воспользуемся возможностями класса RangeParser.
Настройка сцены
На сцене вокруг области отрисовки графиков необходимо расположить множество объектов (текстовые поля для ввода текста, динамические текстовые поля, слайдер). Сама область графиков будет имеет размеры 300х300. Расположение этих объектов не так критично, главное чтобы они не накладывались поверх графика. Пишем код Вы сразу же заметите, что мы импортируем классы из папок parsers и tools, чтобы иметь доступ к классам SimpleGraph, RangeParser и RangeObject. Объекты класса RangeParser будут использоваться для получения из текстовых полей максимальных и минимальных значений угла θ.
import flashandmath.as3.parsers.*; import flashandmath.as3.tools.*;
private var bSize:Number = 320; var arrPx:Array; var tmin:Number; var tmax:Number; // Фрагмент метода init private function init(e:Event = null):void { … // Добавляем кнопки btnGraph = new PushButton(this, 456, 398, "ЧЕРТИТЬ", btnGraphClicked); btnGraph.width = 82; btnGraph.height = 24; btnReset = new PushButton(this, 547, 398, "СБРОС", clearGraph); btnReset.width = 82; btnReset.height = 24; // Добавляем слайдер slT = new HSlider(this, 50, 510, update); slT.setSliderParams(0, 2*bSize, 0); slT.width = 300; gpolar = new SimpleGraph(bSize, bSize); gpolar.x = 40; gpolar.y = 100; // Количество точек графика, по которым он строится, // должно быть равным диапазону значений слайдера gpolar.setNumPoints(slT.maximum); addChild(gpolar); // Создаем маркер точки на графике shTrace = new Shape(); shTrace.graphics.lineStyle(1,0x000000); shTrace.graphics.drawCircle(0,0,5); shTrace.graphics.moveTo(-5,0); shTrace.graphics.lineTo(5,0); shTrace.graphics.moveTo(0,-5); shTrace.graphics.lineTo(0, 5); // Добавляем маркер в список отображения gpolar.addChildToBoard(shTrace); shTrace.visible = false; slT.visible = false; … drawGraph(); }
private function update(evt:Event):void { var i:int = slT.value; var curt:Number = tmin + i*(tmax-tmin)/ (slT.maximum - slT.minimum); var curr:Number = gpolar.polarValueAt(1, curt); shTrace.x = arrPix[i][0]; shTrace.y = arrPix[i][1]; var curx:Number = gpolar.board.xfromPix(shTrace.x); var cury:Number = gpolar.board.yfromPix(shTrace.y); txtX.text = curx.toFixed(2); txtY.text = cury.toFixed(2); txtT.text = curt.toFixed(2); txtR.text = curr.toFixed(2); }
private function btnGraphClicked(mevt:MouseEvent):void { drawGraph(); }
private function drawGraph():void { var stR:String; var stMin:String; var stMax:String; var curx:Number; var cury:Number; var curt:Number; var curr:Number; // Создаем объект класса RangeParser для получения // значений границ диапазона изменения координаты θ var rp:RangeParser = new RangeParser(); var ro:RangeObject; // Просто скрываем графические элементы до тех пор, // пока не убедимся в отсутствии ошибок shTrace.visible = false; slT.visible = false; txtX.text = ""; txtY.text = ""; txtT.text = ""; txtR.text = ""; gpolar.setWindow(txtXmin.text, txtXmax.text, txtYmin.text, txtYmax.text); if (gpolar.hasError()) return; } setupBoard(); stR = txtFunR.text; stMin = txtTmin.text; stMax = txtTmax.text; gpolar.graphPolar(stR, "theta", stMin, stMax, 1, 2, 0x0000AA); if (gpolar.hasError()) return; // Используем объект класса RangeParser для получения // численных значенией границ изменения угловой координаты, // введенных в текстовые поля txtTmin и txtTmax. ro = rp.parseRangeTwo(stMin, stMax); if (ro.errorStatus == 1) return; // Получаем численные значения границ графика функции tmin = rp.parseRangeTwo(stMin, stMax).Values[0]; tmax = rp.parseRangeTwo(stMin, stMax).Values[1]; // Получаем массив координат точек графика, // который мы можем использовать в дальнейшем arrPix = gpolar.getPixData(1); // Если выполнение функции не прекратилось до сих пор, // то ошибок пользовательского ввода не возникло, // и мы можем сделать видимыми скрытые ранее // графические элементы и настроить начальное положение маркера shTrace.visible = true; slT.visible = true; slT.value = 0; shTrace.x = arrPix[0][0]; shTrace.y = arrPix[0][1]; curx = gpolar.board.xfromPix(shTrace.x); cury = gpolar.board.yfromPix(shTrace.y); curt = tmin; curr = gpolar.polarValueAt(1, curt); txtX.text = curx.toFixed(2); txtY.text = cury.toFixed(2); txtT.text = curt.toFixed(2); txtR.text = curr.toFixed(2); }
private function clearGraph(e:MouseEvent):void { shTrace.visible = false; slT.visible = false; txtX.text = ""; txtY.text = ""; txtT.text = ""; txtR.text = ""; gpolar.removeGraph(1); gpolar.setWindow(txtXmin.text, txtXmax.text, txtYmin.text, txtYmax.text); }
private function setupBoard():void { gpolar.board.changeBackColor(0xFFFFEE); gpolar.board.setCoordsBoxFormat(0xEEEEEE, 0xDDDDDD, 0x000000, 12); gpolar.board.drawAxes(); gpolar.board.setTicks(1,1,10,10); gpolar.board.drawTicks(); }
Комментариев нет:
Отправить комментарий