Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using Makie
- using GeometryTypes
- println("---------------------------NEW RUN---------------------------")
- println()
- # inputStr = "(((a+b)*(c+(d-(-b))))*a)"
- # inputStr = "(((a+b)*(c+(d-(-b))))-(a*(d-(-b))))"
- # inputStr = "(a+b)"
- inputStr = "(((a+b)*(c+(d+b)))-(a*(d+b)))"
- println(inputStr)
- println()
- openBranch = "("
- closeBranch = ")"
- const SHIRINA = 1500 # ширина (x)
- const VISOTA = 800 # высота (y)
- RADIUS = 30
- # sign - знак выражения (+,-,*,/)
- # arg1 - первый аргумент
- # arg2 - второй аргумент
- mutable struct Bracket
- sign
- arg1
- arg2
- end
- # index - номер
- # x - координата x
- # y - координата y
- # text - текст в вершине
- # left - левая вершина (может отсутствовать, в этом случае равна 0)
- # right - правая вершина
- mutable struct VertexGraph
- index
- x
- y
- text
- left
- right
- end
- # Содержит выражения по уровням
- allLevelsExpression = Array{String,1}[]
- # Выводит на экран массив allLevelsExpression
- function allLevelsExpressionPrint()
- println("allLevelsExpression:")
- for i = 1:length(allLevelsExpression)
- println("level_$i:")
- println(allLevelsExpression[i])
- end
- end
- # Содержит "Bracket-ы" по уровням
- allLevelsBracket = Array{Bracket,1}[]
- # Выводит на экран массив allLevelsBracket
- function allLevelsBracketPrint()
- println("allLevelsBracket:")
- for i = 1:length(allLevelsBracket)
- println("level_$i:")
- println(allLevelsBracket[i])
- end
- end
- # Содержит все вершины графа
- allVertex = []
- # Выводит на экран массив allVertex
- function allVertexPrint()
- println("allVertex:")
- for i = 1:length(allVertex)
- println(allVertex[i])
- end
- end
- # Содержит текущие вершины графа
- curentVertex = []
- # Выводит на экран массив curentVertex
- function curentVertexPrint()
- println("curentVertex:")
- for i = 1:length(curentVertex)
- println(curentVertex[i])
- end
- end
- # разбивает строку вида (arg1[+*-/]arg2) на аргументы, знак и заносит их в структуру
- # (arg1 может отсутствовать (Например "(-b)"), в таком случае bracket.arg1 = "")
- function bracketParse(str)
- flag = 0
- bracket = Bracket("", "", "")
- for i = 1:length(str)
- symbol = SubString(str, i, i)
- if symbol == openBranch
- flag = 1
- elseif occursin(r"[+*-/]", symbol)
- flag = 2
- bracket.sign = symbol
- elseif symbol == closeBranch
- break
- elseif flag == 1
- bracket.arg1 = bracket.arg1 * symbol
- elseif flag == 2
- bracket.arg2 = bracket.arg2 * symbol
- end
- end
- return bracket
- end
- # из строки вида "l_levelNubmer_bracketNumber" вытаскивает и возвращает значения levelNubmer и bracketNumber
- function levelNameParse(str)
- # начинаем с 3 символа, т.к. первые два это "l_"
- levelString = "";
- bracketNubmerString = "";
- indexUnderscore = 0;
- for i = 3:length(str)
- symbol = SubString(str, i, i)
- if symbol == "_"
- indexUnderscore = i
- break
- end
- end
- levelString = SubString(str, 3, indexUnderscore - 1)
- bracketNubmerString = SubString(str, indexUnderscore + 1, length(str))
- levelInt = parse(Int, levelString)
- bracketNumberInt = parse(Int, bracketNubmerString)
- levelInt, bracketNumberInt
- end
- # Проверяет наличие символа в массиве
- function checkSymbolInArray(arr, symbol)
- for i = 1:length(arr)
- arrSymbol = arr[i]
- if symbol == arrSymbol
- return true
- end
- end
- return false
- end
- # Проверяет наличие Bracket-а в массиве
- function checkBracketInArray(arr, bracket)
- for i = 1:length(arr)
- bracketInArray = arr[i]
- if bracketInArray.sign == bracket.sign &&
- bracketInArray.arg1 == bracket.arg1 &&
- bracketInArray.arg2 == bracket.arg2
- return true
- end
- end
- return false
- end
- # Возвращает номера детей элемента по индексу из массива allVertex
- function checkChildrenInAllVertex(index)
- v = allVertex[getNumberVertexInAllVertexByIndex(index)]
- return v.left, v.right
- end
- # Возвращает позицию элемента по index (атрибут) в массиве allVertex
- # Если нужного значения в массиве нет, возвращает -1
- function getNumberVertexInAllVertexByIndex(index)
- for i = 1:length(allVertex)
- if allVertex[i].index == index
- return i
- end
- end
- return -1
- end
- # Возвращает позицию элемента по index (атрибут) в массиве curentVertex
- # Если нужного значения в массиве нет, возвращает -1
- function getNumberVertexInCurentVertexByIndex(index)
- for i = 1:length(curentVertex)
- if curentVertex[i].index == index
- return i
- end
- end
- return -1
- end
- # Удаляет из массива curentVertex все элементы, где совпадает index
- function deleteFromCurentVertexByIndex(index)
- curentVertexCopy = []
- for i = 1:length(curentVertex)
- if curentVertex[i].index != index
- push!(curentVertexCopy, curentVertex[i])
- end
- end
- global curentVertex = curentVertexCopy
- end
- # Проверяет, лежит ли точка (x, y) внутри круга с центром в точке (xc, yc) и радиусом (радиус задан как глобальная константа)
- function checkVertexInCircle(x, y, xc, yc)
- if (x - xc) ^ 2 + (y - yc) ^ 2 <= RADIUS ^ 2
- return true
- else
- return false
- end
- end
- # TODO добавить, что элементы могут быть многозначными
- # Вытаскивае все "буквы" из строки и заменяет их на "l_1_i", где i - порядок встретивовшегося элемента
- function level1(str)
- levelOneArrayExpression = String[]
- for i = 1:length(str)
- symbol = SubString(str, i, i)
- if (occursin(r"[a-z]|[A-Z]", symbol))
- if !checkSymbolInArray(levelOneArrayExpression, symbol)
- push!(levelOneArrayExpression, string(symbol))
- end
- end
- end
- #добавляем в массив allLevelsExpression, первый уровень (т.е. обычные элементы)
- push!(allLevelsExpression, levelOneArrayExpression)
- #заменяем все элементы строки на l_НомерУровня_НомерЭлементаВмассивеТекущегоУровня
- for i = 1:length(levelOneArrayExpression)
- levelString = "l_1_$(i)"
- str = replace(str, levelOneArrayExpression[i] => levelString)
- end
- #первый уровень в allLevelsBracket всегда пустой
- levelOneArrayBracket = Bracket[]
- push!(allLevelsBracket, levelOneArrayBracket)
- println(str);
- return str
- end
- # Для всех уровней кроме 1
- function otherLevels(str, levelNumber)
- # строка всегда начинается со скобки, кроме самого последнего уровня
- # если строка начинается не со скобки, значит это последний уровень и функция завершает свою работу
- if SubString(str, 1, 1) != openBranch
- thisLevelArrayExpression = String[]
- push!(thisLevelArrayExpression, str)
- push!(allLevelsExpression, thisLevelArrayExpression)
- return
- end
- thisLevelArrayExpression = String[]
- thisLevelArrayBracket = Bracket[]
- indexStart = 1
- haveBranch = false
- for i = 1:length(str)
- symbol = SubString(str, i, i)
- if symbol == openBranch
- indexStart = i
- haveBranch = true
- elseif symbol == closeBranch && haveBranch
- symbolsInBrances = SubString(str, indexStart, i)
- if !checkSymbolInArray(thisLevelArrayExpression, symbolsInBrances)
- push!(thisLevelArrayExpression, string(symbolsInBrances))
- end
- haveBranch = false
- end
- end
- # добавляем массив выражений данного "уровня" в массив "уровней"
- push!(allLevelsExpression, thisLevelArrayExpression)
- # создает "bracket-ы" и добавляет их в массив
- for i = 1:length(thisLevelArrayExpression)
- bracket = bracketParse(thisLevelArrayExpression[i])
- if !checkBracketInArray(thisLevelArrayBracket, bracket)
- push!(thisLevelArrayBracket, bracket)
- end
- end
- # добавляем массив "bracket-ов" данного "уровня" в массив "уровней"
- push!(allLevelsBracket, thisLevelArrayBracket)
- # заменяем все элементы строки на l_НомерУровня_НомерЭлементаВмассивеТекущегоУровня
- for i = 1:length(thisLevelArrayExpression)
- levelNumber = levelNumber #для того, что в цикле был доступ к levelNubmber
- levelString = "l_$(levelNumber)_$(i)"
- str = replace(str, thisLevelArrayExpression[i] => levelString)
- end
- println(str);
- # вызываем функцию для новой строки и следующего уровня
- otherLevels(str, levelNumber + 1)
- end
- inputStr = level1(inputStr)
- otherLevels(inputStr, 2)
- println()
- allLevelsExpressionPrint()
- println()
- allLevelsBracketPrint()
- # Рисует круг в точке (x, y) с текстом "text" внутри
- function drawCircleWithText(scene, x, y, text)
- radius = convert(Float32, RADIUS)
- points = decompose(Point2f0, Circle(Point2f0(x, y), radius))
- poly!(scene, points, color = :white, strokewidth = 2, strokecolor = :black)
- text!(scene, text, textsize = 20, position = (x, y), align = (:center, :center))
- end
- # Рисует линию из точки (x1, y1) в точку (x2, y2)
- function drawLine(scene, x1, y1, x2, y2)
- linesegments!(scene, [Point(x1,y1)=> Point(x2,y2)] )
- end
- # Высчитывает вершины графа
- function calculatedGraph(bracket, xLeft, xRight, currentLevel)
- # индекс вершины
- global graphIndex = graphIndex + 1
- thisIndex = graphIndex
- countLevels = length(allLevelsBracket)
- x = (xLeft + xRight) / 2
- y = VISOTA / (countLevels + 1) * currentLevel
- # индексы "детей" вершины
- indexLeft = 0
- indexRight = 0
- if bracket.sign != ""
- text = bracket.sign
- # если есть "левая ветка"
- if bracket.arg1 != ""
- level1 = levelNameParse(bracket.arg1)[1]
- index1 = levelNameParse(bracket.arg1)[2]
- # println("Left from $bracket")
- # для первого уровня нету Bracket, поэтому мы создаем Bracket в котором sign = "", arg1 = "", arg2 = "Буква_которую надо написать"
- if level1 == 1
- indexLeft = calculatedGraph(Bracket("", "", allLevelsExpression[level1][index1]), xLeft, xLeft + (xRight - xLeft) / 2, currentLevel - 1)
- else
- indexLeft = calculatedGraph(allLevelsBracket[level1][index1], xLeft, xLeft + (xRight - xLeft) / 2, currentLevel - 1)
- end
- end
- level2 = levelNameParse(bracket.arg2)[1]
- index2 = levelNameParse(bracket.arg2)[2]
- # для первого уровня нету Bracket, поэтому мы создаем Bracket в котором sign = "", arg1 = "", arg2 = "Буква_которую надо написать"
- if level2 == 1
- if bracket.arg1 != ""
- indexRight = calculatedGraph(Bracket("", "", allLevelsExpression[level2][index2]), xLeft + (xRight - xLeft) / 2, xRight, currentLevel - 1)
- else
- indexRight = calculatedGraph(Bracket("", "", allLevelsExpression[level2][index2]), xLeft, xRight, currentLevel - 1)
- end
- else
- if bracket.arg1 != ""
- indexRight = calculatedGraph(allLevelsBracket[level2][index2], xLeft + (xRight - xLeft) / 2, xRight, currentLevel - 1)
- else
- indexRight = calculatedGraph(allLevelsBracket[level2][index2], xLeft, xRight, currentLevel - 1)
- end
- end
- else
- text = bracket.arg2
- end
- push!(allVertex, VertexGraph(thisIndex, x, y, text, indexLeft, indexRight))
- return thisIndex
- end
- # Рисует все вершины
- function drawCircles(scene)
- for i = 1:length(curentVertex)
- v = curentVertex[i]
- drawCircleWithText(scene, v.x, v.y, v.text)
- end
- end
- # Очищает сцену
- function clearScene(scene)
- arr = Point{2,Float32}[]
- xLeft = 0
- xRight = 500
- yTop = 500
- yBot = 0
- mas = []
- push!(arr, Point2f0(xLeft, yBot))
- push!(arr, Point2f0(xLeft, yTop))
- push!(arr, Point2f0(xRight, yTop))
- push!(arr, Point2f0(xRight, yBot))
- push!(arr, Point2f0(xLeft, yBot))
- poly!(scene, arr, color = :white, strokewidth = 10000, strokecolor = :white)
- end
- # Рисует ребра графа от заданной вершины, а так же все ребра "детей" этой вершины
- function drawEdges(scene, index)
- # index = -1 если такой вершины нету
- if index != -1
- v1 = curentVertex[index]
- x1 = v1.x
- y1 = v1.y - RADIUS
- if v1.left != 0
- leftIndex = getNumberVertexInCurentVertexByIndex(v1.left)
- v2 = curentVertex[leftIndex]
- x2 = v2.x
- y2 = v2.y + RADIUS
- drawLine(scene, x1, y1, x2, y2)
- drawEdges(scene, leftIndex)
- end
- if v1.right != 0
- rightIndex = getNumberVertexInCurentVertexByIndex(v1.right)
- v2 = curentVertex[rightIndex]
- x2 = v2.x
- y2 = v2.y + RADIUS
- drawLine(scene, x1, y1, x2, y2)
- drawEdges(scene, rightIndex)
- end
- end
- end
- # Проверяет, лежит ли точка (x, y) внутри какой-либо вершины из массива curentVertex
- # Если не лежит, возвращает -1
- function checkPointInVertices(x, y)
- for i = 1:length(curentVertex)
- v = curentVertex[i]
- if checkVertexInCircle(x, y, v.x, v.y)
- println("Эта точка лежит в вершине $(v.index)")
- return v.index
- end
- end
- println("Эта точка не лежит ни в одной вершине")
- return -1
- end
- # Развертывание графа
- function reamer(scene, numberVertex)
- v = curentVertex[getNumberVertexInCurentVertexByIndex(numberVertex)]
- left, right = checkChildrenInAllVertex(numberVertex)
- if left != 0 || right != 0
- if left != 0
- vLeft = allVertex[getNumberVertexInAllVertexByIndex(left)]
- # добавляем копии атрибутов, чтобы не было ссылки на элемент из allVertex
- # добавляем left = 0, right = 0, т.к. не известно, есть ли у них свои дети и надо это проверить
- push!(curentVertex, VertexGraph(vLeft.index, vLeft.x, vLeft.y, vLeft.text, 0, 0))
- # обозначаем левого ребенка
- v.left = left
- # запускаем проверку детей у левого ребенка
- reamer(scene, left)
- end
- if right != 0
- vRight = allVertex[getNumberVertexInAllVertexByIndex(right)]
- # добавляем копии атрибутов, чтобы не было ссылки на элемент из allVertex
- # добавляем left = 0, right = 0, т.к. не известно, есть ли у них свои дети и надо это проверить
- push!(curentVertex, VertexGraph(vRight.index, vRight.x, vRight.y, vRight.text, 0, 0))
- # обозначаем правого ребенка
- v.right = right
- # запускаем проверку детей у правого ребенка
- reamer(scene, right)
- end
- end
- end
- # Свертка графа
- function convolution(scene, numberVertex)
- v = curentVertex[getNumberVertexInCurentVertexByIndex(numberVertex)]
- # leftFormula = ""
- # rightFormula = ""
- # Если есть левый ребенок
- if v.left != 0
- # Запускаем проверку детей у левого ребенка
- convolution(scene, v.left)
- # Удаляем левого ребенка
- deleteFromCurentVertexByIndex(v.left)
- # Показываем, что левого ребенка нет
- v.left = 0
- end
- if v.right != 0
- # Запускаем проверку детей у правого ребенка
- convolution(scene, v.right)
- # Удаляем правого ребенка
- deleteFromCurentVertexByIndex(v.right)
- # Показываем, что левого правого нет
- v.right = 0
- end
- # return leftFormula * v.text * rightFormula
- end
- # Интерактивность
- function interactivity(scene, numberVertex)
- v = curentVertex[getNumberVertexInCurentVertexByIndex(numberVertex)]
- # Разворачивание
- # Если детей нет
- if v.left == 0 & v.right == 0
- left, right = checkChildrenInAllVertex(numberVertex)
- if left != 0 || right != 0
- reamer(scene, numberVertex)
- drawGraph(scene)
- end
- # Сворачивание
- # Если есть дети
- elseif v.left != 0 || v.right != 0
- convolution(scene, numberVertex)
- drawGraph(scene)
- end
- end
- # Рисует граф
- function drawGraph(scene)
- println()
- curentVertexPrint()
- clearScene(scene)
- drawCircles(scene)
- drawEdges(scene, getNumberVertexInCurentVertexByIndex(1))
- end
- graphIndex = 0
- calculatedGraph(allLevelsBracket[length(allLevelsBracket)][1],
- 0, SHIRINA, length(allLevelsBracket));
- println()
- allVertexPrint()
- scene = Scene(resolution = (SHIRINA, VISOTA))
- # Добавляем события на кнопки мыши
- on(scene.events.mousebuttons) do buttons
- if ispressed(scene, Mouse.left)
- pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
- println("Кликнули сюда $pos")
- numberVertex = checkPointInVertices(pos[1], pos[2])
- if numberVertex != -1
- interactivity(scene, numberVertex)
- end
- end
- return
- end
- # Инициализируем массив текущих вершин
- for i = 1:length(allVertex)
- # Создаем копии объектов, чтобы не было ссылок
- v = allVertex[i]
- push!(curentVertex, VertexGraph(v.index, v.x, v.y, v.text, v.left, v.right))
- end
- # curentVertex = allVertex
- drawGraph(scene)
- # Без этого не рисуется ????????????????????????
- clicks = Node(Point2f0[(0,0)])
- scatter!(scene, clicks, color = :red, marker = '+', markersize = 0)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement