Задание 3

53 views
Skip to first unread message

Erbol Gabdullin

unread,
Apr 15, 2015, 4:10:23 PM4/15/15
to swi...@googlegroups.com
Вот нашел хорошее описание для алгоритма перехода из инфиксной нотации в постфиксную

Сканируем инфиксное выражение слева направо, то для хранения операторов будем использовать стек. На вершине стека всегда будет последний сохранённый оператор. Когда бы мы не прочитали новый оператор, мы должны сравнить его по приоритету с операторами в стеке (если таковые имеются).

Предположим, что инфиксное выражение есть строка токенов, разделённых пробелами. Токенами операторов являются *, /, + и - вместе с правой и левой скобками, ( и ). Токены операндов - это однобуквенные идентификаторы A, B, C и так далее. Следующая последовательность шагов даст строку токенов в постфиксном порядке.

1. Создать пустой стек с названием opstack для хранения операторов. 
2. Создать пустой список для вывода.
3. Преобразовать инфиксную строку в список, используя строковый метод split.
4. Сканировать список токенов слева направо.
5. Если токен является операндом, то добавить его в конец выходного списка.
6. Если токен является левой скобкой, положить его в opstack.
7. Если токен является правой скобкой, то выталкивать элементы из opstack пока не будет найдена соответствующая левая скобка. Каждый оператор добавлять в конец выходного списка.
8. Если токен является оператором *, /, + или -, поместить его в opstack. Однако, перед этим вытолкнуть любой из операторов, уже находящихся в opstack, если он имеет больший или равный приоритет, и добавить его в результирующий список.
9. Когда входное выражение будет полностью обработано, проверить opstack. Любые операторы, всё ещё находящиеся в нём, следует вытолкнуть и добавить в конец итогового списка.

Erbol Gabdullin

unread,
Apr 18, 2015, 12:09:39 PM4/18/15
to swi...@googlegroups.com
Код написал для выборки числа из входного массива

//: Playground - noun: a place where people can play

extension String {

    func toDouble() -> Double? {

        // numberFromString это метод класса NSNumberFormatter, он извлекает из строки число

        // возвращает либо число либо nil

        // Этот метод имеет свойство doubleValue

        return NSNumberFormatter().numberFromString(self)?.doubleValue

    }

}


import Cocoa



var opStack = [Double]()

var str = "123,4Hello, play345,65ground"

var parse = Array(str)



func numberIs(symbol:String){

    // Делаем клон входного массива

    var temp = parse.map(){String($0)}

    // Добавляем к нему слева анализируемый символ

    temp.insert(symbol, atIndex: 0)

    // Удаляем все элементы из массива которые не образуют число, справа-налево

    while true {

        let total = temp.reduce("") {

            return  $0 + $1

        }

        

        if let oo = total.toDouble(){

            break

        }else{

            temp.removeLast()

        }

    }

    

    // Вычисляем число

    let number = temp.reduce("") {

        return  $0 + $1

    }

    // Помещаем его в выходной стек

    opStack += [number.toDouble()!]

    

    // Удаляем из входного массива все элементы числа  переданного в выходной массив

    let count = temp.count - 1

    for var i=0; i < count; ++i {

        parse.removeAtIndex(0)

    }

    

}


numberIs("4")

parse

 

Erbol Gabdullin

unread,
Apr 20, 2015, 12:34:07 AM4/20/15
to swi...@googlegroups.com

8. Если токен является оператором *, /, + или -, поместить его в opstack. Однако, перед этим вытолкнуть любой из операторов, уже находящихся в opstack, если он имеет больший или равный приоритет, и добавить его в результирующий список.


     private func precedenceCompare(s:Int){

        // Создаем отображение массива stack

        var ref = stack.map{$0.precedence}

        //Удаляем все элементы которые больше s слева направо до тех пор пока s <= clone.first

        while !ref.isEmpty {

            if s <= ref.first {

                ref.removeAtIndex(0)

            }else{

                break

            }

        }

        // Считаем разницу между длинами массивов

        let n = stack.count - ref.count

        // Удаляем из stack количество элементов n

        // и вставляем их в opStack

        for var i=0;i<n;++i{

            let oo = stack.removeAtIndex(0)

            if let operation = knownOps[oo.description]{

                opStack += [operation]

            }else{}

        }

    }

Erbol Gabdullin

unread,
Apr 20, 2015, 11:11:07 AM4/20/15
to swi...@googlegroups.com
Нарисовать ось координат можно так

        var scale: CGFloat = 2.0 { didSet { setNeedsDisplay() } }

        var origin: CGPoint = CGPoint(x: 190, y: 340) { didSet { setNeedsDisplay() } }


        AxesDrawer(contentScaleFactor: contentScaleFactor)

            .drawAxesInRect(bounds, origin: origin, pointsPerUnit: sale)


http://cs193p.m2m.at/cs193p-project-3-assignment-3-task-7-winter-2015/

Erbol Gabdullin

unread,
Apr 22, 2015, 12:33:57 PM4/22/15
to swi...@googlegroups.com
Относительно манипуляций над графиком и осями координат

1. Размеры и положение rect (области рисования) не меняем 
2. Меняем положение origin (точки отсчета) для системы координат от плюс до минус бесконечности по ширине
и от плюс до минус бесконечности по высоте
3. Меняем масштаб для графика и для системы координат одновременно 

Erbol Gabdullin

unread,
Apr 23, 2015, 7:24:59 AM4/23/15
to swi...@googlegroups.com
Вот так рисую график

import UIKit


class Draw2D2: UIView {


    var graph = CalculatorGraphic()



    override func drawRect(rect: CGRect) {


        // 1. Размеры и положение rect не меняем 

        // 2. Меняем положение origin для системы координат от плюс бесконечности до минус бесконечности по ширине

        // и от плюс до минус бесконечности по высоте

        // 3. Меняем масштаб для графика и для системы координат одновременно

        

        let origin: CGPoint = CGPointMake(self.center.x - 30 , self.center.y - 10 )


        // Вычисляем функцию по точкам на оси Х внутри rect и рисуем график

        let scale: CGFloat = 1.2

        let str = "200*cos(M*0.03)"

        // Рисуем график

        drawGraphicFunction(rect,origin: origin,scale: scale, str: str)

        

        // Рисуем оси координат внутри rect

        drawAxes(rect, origin: origin, scale: scale)


        // Рисуем текст

        drawText(str)

        

        

    }

    

    func drawGraphicFunction(rect: CGRect,origin : CGPoint, scale : CGFloat, str: String){


        // Строим стек для расчета функции

        graph.parseString(str)

        // Для создания графика функции надо определить диапазоны отрицательных и положительных значений

        // Известны положения двух точек 

        // original - точка отсчета рисуемых на view осей системы координат

        // rect.original - точка отсчета системы координат прямоугольника области построения графика

        

        let context = UIGraphicsGetCurrentContext()

        CGContextSetLineWidth(context, 2.0)

        CGContextSetStrokeColorWithColor(context,

            UIColor.blueColor().CGColor)




        // расстояние по оси х от левой границы rect до точки начала координат рисуемых осей

        // В нашем случае rect.origin.x всегда равно нулю

        // Положение точки origin задается относительно rect.origin

        // Поэтому если origin находится левее rect.origin left будет положительным

        // и наоборот если origin находится правее rect.origin то left будет отрицательным

        let left:Int = Int((rect.minX - origin.x)/scale)


        // расстояние по оси х от точки начала координат рисуемых осей до правой границы прямоугольника построения

        //let right:Int = Int((rect.origin.x + rect.width - origin.x)/scale)

        let right:Int = Int((rect.maxX - origin.x)/scale)

        

        // Рассчитываем функцию

        var data = graph.graphData(left,right: right)


        // Рисуем функцию

        while !data.isEmpty {

            let point = data.removeAtIndex(0)

            println(point.x)

            println(point.y)

            if (point.x == CGFloat(left)) {

                //----------------------------------------------

                CGContextMoveToPoint(context, point.x*scale+origin.x, -point.y*scale+origin.y)

            }

            else {

                CGContextAddLineToPoint(context, point.x*scale+origin.x, -point.y*scale+origin.y)

            }

        }


        CGContextStrokePath(context)

        

    }

    

    func drawAxes(rect : CGRect, origin : CGPoint, scale: CGFloat){


        let bounds = rect


        AxesDrawer(contentScaleFactor: contentScaleFactor)

        .drawAxesInRect(bounds, origin: origin, pointsPerUnit: scale)

        


    }

    


    

    func drawText(str: String){

        let numberOne = str

        let numberOneRect = CGRectMake(self.bounds.maxX - 360, self.bounds.maxY - 80, 350, 50)

        let font = UIFont(name: "Academy Engraved LET", size: 24)

        let textStyle = NSMutableParagraphStyle.defaultParagraphStyle()

        let numberOneAttributes = [

            NSFontAttributeName: font!]

        numberOne.drawInRect(numberOneRect,

            withAttributes:numberOneAttributes)

    }

    



}


 

Erbol Gabdullin

unread,
Apr 25, 2015, 7:59:33 AM4/25/15
to swi...@googlegroups.com
Сделал жест Pan

Теперь можно график перемещать по экрану

Erbol Gabdullin

unread,
Apr 30, 2015, 8:17:21 AM4/30/15
to swi...@googlegroups.com
Можно посмотреть как калькулятор работает с  splitViewController

Erbol Gabdullin

unread,
May 6, 2015, 2:14:09 PM5/6/15
to swi...@googlegroups.com
Класс AxesDrawer

Непонятно зачем нужен этот код

// Если начало координат не находится внутри фрейма

            // ???

            if !CGRectContainsPoint(bounds, origin) {

                

                let leftx = max(origin.x - bounds.maxX, 0)

                println("leftx = \(max(origin.x - bounds.maxX, 0))")

                let rightx = max(bounds.minX - origin.x, 0)

                println("rightx = \(max(bounds.minX - origin.x, 0))")

                let downy = max(origin.y - bounds.minY, 0)

                println("downy = \(max(origin.y - bounds.minY, 0))")

                let upy = max(bounds.maxY - origin.y, 0)

                println("upy = \(max(bounds.maxY - origin.y, 0))")

                // Определили startingHashmarkRadius как минимум из минимумов min(min(leftx, rightx), min(downy, upy))

                startingHashmarkRadius = min(min(leftx, rightx), min(downy, upy)) / pointsPerHashmark + 1

                println("min(leftx, rightx) = \(min(leftx, rightx))")

                println("min(downy, upy) = \(min(downy, upy))")

                println("min = \(min(min(leftx, rightx), min(downy, upy)) / pointsPerHashmark)")

                //println("startingHashmarkRadius = \(startingHashmarkRadius)")

            }

 

Это выражение всегда равно нулю

min(min(leftx, rightx), min(downy, upy))

Erbol Gabdullin

unread,
May 7, 2015, 3:21:53 AM5/7/15
to swi...@googlegroups.com
Алгоритм работы программы Axesdrawer

1. Определяем минимальное расстояние между метками шкалы на осях системы координат в пикселях => 40 пикселов
2. Находим цену деления шкалы в единицах шкалы (юнитах)
3. Находим расстояние между метками шкалы в пикселах
4. Вычисляем размер стороны "минимального квадрата" с центром в начале координат, который пересекает своими сторонами деления шкалы

"сторона квадрата" = 2 x "расстояние между делениями шкалы в пикселях"

5. Рисуем на осях метки шкалы и их величину в юнитах на расстояниях от начала координат равных половине размера стороны квадрата

6. Увеличиваем размер стороны квадрата в цикле на 2 юнита в пикселях, опять рисуем метки
7. Продолжаем до тех пор пока квадрат не выходит за границы фрейма

tatiana.kornilova

unread,
May 7, 2015, 3:46:23 AM5/7/15
to swi...@googlegroups.com, erbo...@gmail.com
Добрый день.
Зачем вы изучаете класс AvesDrawer? Вам он дан профессором для того, чтобы вы не тратили время на "рутину". Я мельком взглянула на ваши решения выше и вижу, что вы, извините, вообще не понимаете, как должен выглядеть графический калькулятор. Я не готова сейчас дать вам рецензию, может быть через 3-4 дня, когда закончу с заданием 3, но зачем вы повторяете код CalculatorBrain в CalculatorGraphic? Это должны быть разные классы и они должны взаимодействовать на принципах MVC. Читайте Задание 3 - там ясно сказано: класс  CalculatorBrain не трогать. Вам знакомо объектно-ориентированное программирование и его понятия: класс, свойства, экземпляр класса, наследование и т.д.? Прежде чем приступать к Заданию 3, нужно досконально изучить лекции 5, 6, 7 и 8. Я выложила первую часть Задания 3 в Github. Попробуйте понять, что как делается. В ближайшие дни выложу пост на сайте.

четверг, 7 мая 2015 г., 10:21:53 UTC+3 пользователь Erbol Gabdullin написал:


Erbol Gabdullin

unread,
May 7, 2015, 4:26:47 AM5/7/15
to swi...@googlegroups.com, erbo...@gmail.com
Ладно

Спасибо за критику

Подождем Вашу статью с решением задания

четверг, 7 мая 2015 г., 13:46:23 UTC+6 пользователь tatiana.kornilova написал:
Reply all
Reply to author
Forward
0 new messages