Advertisement
Guest User

Untitled

a guest
Feb 26th, 2020
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.37 KB | None | 0 0
  1. using Makie
  2. using GeometryTypes
  3.  
  4. println()
  5. println("---------------------------NEW RUN---------------------------")
  6. println()
  7. # Константы
  8. const openBranch = "("
  9. const closeBranch = ")"
  10.  
  11. const SHIRINA = 1500 # ширина (x)
  12. const VISOTA = 800 # высота (y)
  13. RADIUS = 30
  14.  
  15. # Входная строка
  16. inputStr = "(((a+b)*(c+(d-(-b))))-(a*(d-(-b))))"
  17. # inputStr = "((-b)-(-c))"
  18. # inputStr = "((a+b)*(b+a))"
  19.  
  20. # Структука "вершина"
  21. # n - номер вершины
  22. # childLeft - номер вершины левого ребенка
  23. # childRight - номер вершины правого ребенка
  24. # textShort - текст "развернутой" вершины
  25. # textFull - текст "свернутой" вершины
  26. # level - уровень
  27. # xLeft - левая граница по X
  28. # xRight - правая граница по X
  29. # x - координата x точки ((xLeft + xRight) / 2)
  30. # y - координата y точки
  31. # needChanged - нужно ли перерасчитывать вершину (для интерактивности), 1 - нужно, 0 - не нужно
  32. mutable struct Vertex
  33. index
  34. childLeft
  35. childRight
  36. textShort
  37. textFull
  38. level
  39. xLeft
  40. xRight
  41. x
  42. y
  43. needChanged
  44. end
  45.  
  46. # Массив с вершинами (изначальный)
  47. verteces = []
  48.  
  49. # Массив с вершинами (текущий)
  50. vertecesCurrent = []
  51.  
  52. function printVerteces()
  53. println("verteces:")
  54. for i = 1:length(verteces)
  55. println(verteces[i])
  56. end
  57. end
  58.  
  59. function printVertecesCurrent()
  60. println("vertecesCurrent:")
  61. for i = 1:length(vertecesCurrent)
  62. println(vertecesCurrent[i])
  63. end
  64. end
  65.  
  66. # разбивает строку вида (arg1[+*-/]arg2) на 2 аргумента и знак и возвращает arg1, sign, arg2
  67. # (arg1 может отсутствовать (Например "(-b)"), в таком случае arg1 = "")
  68. function bracketParse(str)
  69. # Изначально flag = 0
  70. # При встрече открывающей скобки (всегда первый элемент) переключаем flag = 1
  71. # Пока flag = 1, добавляем символы в arg1
  72. # При встрече одного из знаков [+*-/], переключаем flag = 2 и записываем текущий сивмол в sign
  73. # Пока flag = 2, добавляем символы в arg2
  74. # При встрече закрывающей скобки (всегда последний элемент) завершаем работу
  75. flag = 0
  76.  
  77. sign = ""
  78. arg1 = ""
  79. arg2 = ""
  80.  
  81. for i = 1:length(str)
  82. symbol = SubString(str, i, i)
  83.  
  84. if symbol == openBranch
  85. flag = 1
  86. elseif occursin(r"[+*-/]", symbol)
  87. flag = 2
  88. sign = symbol
  89. elseif symbol == closeBranch
  90. break
  91. elseif flag == 1
  92. arg1 = arg1 * symbol
  93. elseif flag == 2
  94. arg2 = arg2 * symbol
  95. end
  96.  
  97. end
  98.  
  99. return arg1, sign, arg2
  100. end
  101.  
  102. # Проверяет наличие выражения в массиве (сравнение идет по атрибуту textFull)
  103. function checkExpInTextFull(exp)
  104. for i = 1:length(verteces)
  105. v = verteces[i]
  106. if v.textFull == exp
  107. return true
  108. end
  109. end
  110. return false
  111. end
  112.  
  113. # Расчитывает массив verteces
  114. function calculateVerteces(str)
  115. # Не открывающая скобка может быть только после последней замены, когда строка принимает вид vertex_X
  116. # В таком случае замена не нужна
  117. if SubString(str, 1, 1) == openBranch
  118. haveBranch = false
  119. indexStart = 1
  120.  
  121. # Начальное количество элементов в массиве
  122. # Необходимо для замены новых добавившихся элментов
  123. startLengthVerteces = length(verteces)
  124.  
  125. # Идем по строке, пока не встретим конструкцию "(arg1*sign*arg2)"
  126. for i = 1:length(str)
  127. symbol = SubString(str, i, i)
  128.  
  129. if symbol == openBranch
  130. indexStart = i
  131. haveBranch = true
  132. elseif symbol == closeBranch && haveBranch
  133. # Вытаскиываем выражение из строки
  134. branchExp = SubString(str, indexStart, i)
  135.  
  136. # Разбиваем выражение на аргументы и знак (arg1 может быть равен пустой строке). Например (-b)
  137. arg1, sign, arg2 = bracketParse(branchExp)
  138. indexLeft = 0
  139. indexRight = 0
  140.  
  141. isArgsEqual = false
  142.  
  143. # Если первый и второй аргументы равны, тогда добавляем в массив только второй аргумент
  144. if arg1 != arg2
  145. if arg1 != ""
  146. # Если аргумент не иммеет вид "vertex_X"
  147. # Аргумент имеет такой вид только в том случае, если он уже был заменен
  148. if !occursin(r"^vertex_[0-9]+", arg1)
  149. # Если аргумент новый, то мы вычисляем его атрибуты и добавлем в массив
  150. indexLeft = length(verteces) + 1
  151. childLeft = 0
  152. childRight = 0
  153. textShort = arg1
  154. textFull = arg1
  155.  
  156. level = 0
  157. xLeft = 0
  158. xRight = 0
  159. x = 0
  160. y = 0
  161. needChanged = 0
  162. push!(verteces, Vertex(indexLeft, childLeft, childRight, textShort, textFull, level, xLeft, xRight, x, y, needChanged))
  163. else
  164. # Если аргумент старый, то мы его не добавляем в массив.
  165. # Вычисляем какой это аргумент по номеру и запоминаем этот номер для добавления ссылки на этот аргумент при занесении всего выражения
  166. indexLeft = parse(Int64, SubString(arg1, 8, length(arg1)))
  167. end
  168. end
  169. else
  170. isArgsEqual = true
  171. end
  172.  
  173. # Все аналогично arg1, за исключением проверки на пустую строку, т.к. arg2 всегда присутствует
  174. if !occursin(r"^vertex_[0-9]+", arg2)
  175. indexRight = length(verteces) + 1
  176. childLeft = 0
  177. childRight = 0
  178. textShort = arg2
  179. textFull = arg2
  180.  
  181. level = 0
  182. xLeft = 0
  183. xRight = 0
  184. x = 0
  185. y = 0
  186. needChanged = 0
  187. push!(verteces, Vertex(indexRight, childLeft, childRight, textShort, textFull, level, xLeft, xRight, x, y, needChanged))
  188. else
  189. indexRight = parse(Int64, SubString(arg2, 8, length(arg2)))
  190. end
  191.  
  192. # Если аргументы одинаковые, то мы добавляем только второй аргумент
  193. # В таком случае индекс левого и правого ребенка совпадает
  194. if isArgsEqual
  195. indexLeft = indexRight
  196. end
  197.  
  198. # Высчитываем атрибуты для всего выражения
  199. index = length(verteces) + 1
  200. childLeft = indexLeft
  201. childRight = indexRight
  202. textShort = sign
  203.  
  204. textFull = "("
  205. # Если arg1 отсутсвует, тогда в полное выражение его не добавляем
  206. if childLeft != 0
  207. textFull = textFull * verteces[childLeft].textFull
  208. end
  209. textFull = textFull * sign * verteces[childRight].textFull * ")"
  210.  
  211. level = 0
  212. xLeft = 0
  213. xRight = 0
  214. x = 0
  215. y = 0
  216. needChanged = 0
  217. push!(verteces, Vertex(index, childLeft, childRight, textShort, textFull, level, xLeft, xRight, x, y, needChanged))
  218.  
  219. # Заменяем добавленные выражения
  220. # Сначала заменяем последнее, т.к. оно включает предыдущие (если были)
  221. oldExp = branchExp
  222. newExp = "vertex_$(verteces[end].index)"
  223. str = replace(str, oldExp => newExp)
  224.  
  225. # Если sign = "+|*", то мы замеянем не только arg1*sign*arg2, но и arg2*sign*arg1
  226. if occursin(r"[+*]", sign)
  227. oldExp = "(" * arg2 * sign * arg1 * ")"
  228. newExp = "vertex_$(verteces[end].index)"
  229. str = replace(str, oldExp => newExp)
  230. end
  231.  
  232. # После этого заменяем остальные (если были)
  233. for i = startLengthVerteces + 1:length(verteces) - 1
  234. oldExp = verteces[i].textFull
  235. newExp = "vertex_$(verteces[i].index)"
  236. str = replace(str, oldExp => newExp)
  237. end
  238.  
  239. # println(str)
  240. # Запускаем рекурсию для обновленной строки
  241. calculateVerteces(str)
  242.  
  243. break
  244. end
  245.  
  246. end
  247.  
  248.  
  249. else
  250. # Удаляет внешние скобки у выражений, т.к. они лишние
  251. for i = 1:length(verteces)
  252. v = verteces[i]
  253. if SubString(v.textFull, 1, 1) == openBranch
  254. v.textFull = SubString(v.textFull, 2, length(v.textFull) - 1)
  255. end
  256. end
  257. end
  258. end
  259.  
  260. # Рассчитывает уровни в массиве verteces
  261. # Рассчитывает границы по X в массиве verteces
  262. function calculateVertecesLevelsAndBordersX(index, level, xLeft, xRight)
  263. v = verteces[index]
  264.  
  265. # Если уровень равен нулю, значит он еще не инициализирован, в таком случае инициализриуем его и границы
  266. # Если уровень меньше текущего, тогда заменяем его на новый, и заменяекм границы
  267. if v.level == 0 || v.level < level
  268. v.level = level
  269. v.xLeft = xLeft
  270. v.xRight = xRight
  271. end
  272.  
  273. # Рекурсия для левого
  274. childLeft = v.childLeft
  275. if childLeft != 0
  276. calculateVertecesLevelsAndBordersX(childLeft, level + 1, xLeft, xLeft + (xRight - xLeft) / 2)
  277. end
  278.  
  279. # Рекурсия для правого
  280. childRight = v.childRight
  281. if childRight != 0
  282. if childLeft != 0
  283. calculateVertecesLevelsAndBordersX(childRight, level + 1, xLeft + (xRight - xLeft) / 2, xRight)
  284. else
  285. # Если childLeft == 0, т.е. всего один ребенок, то тогда границы не меняются
  286. calculateVertecesLevelsAndBordersX(childRight, level + 1, xLeft, xRight)
  287. end
  288. end
  289. end
  290.  
  291. # Рассчитывает уровни в массиве vertecesCurrent
  292. # Рассчитывает границы по X в массиве vertecesCurrent
  293. function calculateVertecesCurrentLevelsAndBordersX(index, level, xLeft, xRight)
  294. v = vertecesCurrent[index]
  295.  
  296. # Если уровень равен нулю, значит он еще не инициализирован, в таком случае инициализриуем его и границы
  297. # Если уровень меньше текущего, тогда заменяем его на новый, и заменяекм границы
  298. if v.needChanged == 1
  299. if v.level == 0 || v.level < level
  300. v.level = level
  301. v.xLeft = xLeft
  302. v.xRight = xRight
  303. end
  304. end
  305.  
  306. # Рекурсия для левого
  307. childLeft = v.childLeft
  308. if childLeft != 0
  309. calculateVertecesCurrentLevelsAndBordersX(childLeft, level + 1, xLeft, xLeft + (xRight - xLeft) / 2)
  310. end
  311.  
  312. # Рекурсия для правого
  313. childRight = v.childRight
  314. if childRight != 0
  315. if childLeft != 0
  316. calculateVertecesCurrentLevelsAndBordersX(childRight, level + 1, xLeft + (xRight - xLeft) / 2, xRight)
  317. else
  318. # Если childLeft == 0, т.е. всего один ребенок, то тогда границы не меняются
  319. calculateVertecesCurrentLevelsAndBordersX(childRight, level + 1, xLeft, xRight)
  320. end
  321. end
  322. end
  323.  
  324. # Инициализирует массив vertecesCurrent
  325. function initVertecesCurrent()
  326. for i = 1:length(verteces)
  327. v = verteces[i]
  328. # Создаем копию объекта, чтобы не было ссылки
  329. push!(
  330. vertecesCurrent,
  331. Vertex(v.index, v.childLeft, v.childRight, v.textShort, v.textFull, v.level, v.xLeft, v.xRight, v.x, v.y, v.needChanged)
  332. )
  333. end
  334. end
  335.  
  336. # Очищает уровни и позиции всех вершин, у которых needChanged = 1 в массиве vertecesCurrent для перерасчета
  337. function clearLevelsAndPosVertecesCurrent()
  338. for i = 1:length(vertecesCurrent)
  339. v = vertecesCurrent[i]
  340. if v.needChanged == 1
  341. v.level = 0
  342. v.xLeft = 0
  343. v.xRight = 0
  344. v.x = 0
  345. v.y = 0
  346. end
  347. end
  348. end
  349.  
  350. # Перерасчиывает массив vertecesCurrent
  351. function recalcVertecesCurrent()
  352. clearLevelsAndPosVertecesCurrent()
  353. calculateVertecesCurrentLevelsAndBordersX(length(vertecesCurrent), 1, 0, SHIRINA)
  354. calculatePosVertecesCurrent()
  355. setNeedChangedZero()
  356. end
  357.  
  358. # Возвращает максимальный уровень из массива verteces
  359. function getMaxLevelVerteces()
  360. level = 1
  361. for i = 1:length(verteces)
  362. if verteces[i].level > level
  363. level = verteces[i].level
  364. end
  365. end
  366. return level
  367. end
  368.  
  369. # Возвращает максимальный уровень из массива vertecesCurrent
  370. function getMaxLevelVertecesCurrent()
  371. level = 1
  372. for i = 1:length(vertecesCurrent)
  373. if vertecesCurrent[i].level > level
  374. level = vertecesCurrent[i].level
  375. end
  376. end
  377. return level
  378. end
  379.  
  380. # Расчитывает позицию (x, y) вершины массива verteces
  381. function calculatePosVerteces()
  382. maxLevel = getMaxLevelVerteces()
  383.  
  384. for i = 1:length(verteces)
  385. v = verteces[i]
  386. v.x = (v.xLeft + v.xRight) / 2
  387. v.y = VISOTA / (maxLevel + 1) * (maxLevel - v.level + 1)
  388. end
  389. end
  390.  
  391. # Расчитывает позицию (x, y) вершины массива vertecesCurrent
  392. function calculatePosVertecesCurrent()
  393. # maxLevel = getMaxLevelVertecesCurrent()
  394. maxLevel = getMaxLevelVerteces()
  395.  
  396. for i = 1:length(vertecesCurrent)
  397. v = vertecesCurrent[i]
  398. if v.needChanged == 1
  399. v.x = (v.xLeft + v.xRight) / 2
  400. v.y = VISOTA / (maxLevel + 1) * (maxLevel - v.level + 1)
  401. end
  402. end
  403. end
  404.  
  405. # Проверяет, лежит ли точка (x, y) внутри круга с центром в точке (xc, yc) и радиусом (радиус задан как глобальная константа)
  406. function checkVertexInCircle(x, y, xc, yc)
  407. if (x - xc) ^ 2 + (y - yc) ^ 2 <= RADIUS ^ 2
  408. return true
  409. else
  410. return false
  411. end
  412. end
  413.  
  414. # Проверяет, лежит ли точка (x, y) внутри какой-либо вершины из массива verteces
  415. function checkPointInVertecesCurrent(x, y)
  416. for i = 1:length(vertecesCurrent)
  417. v = vertecesCurrent[i]
  418. if checkVertexInCircle(x, y, v.x, v.y)
  419. return i
  420. end
  421. end
  422. return -1
  423. end
  424.  
  425. # После перерасчета устанавливает needChanged = 0 у всех
  426. function setNeedChangedZero()
  427. for i = 1:length(vertecesCurrent)
  428. v = vertecesCurrent[i]
  429. v.needChanged = 0
  430. end
  431. end
  432.  
  433. # Устанавливает у вершины с данным индексом и у всех ее детей needChanged = 1
  434. function setNeedChangedOnChildren(index)
  435. v = vertecesCurrent[index]
  436. v.needChanged = 1
  437. if v.childLeft != 0
  438. setNeedChangedOnChildren(v.childLeft)
  439. end
  440. if v.childRight != 0
  441. setNeedChangedOnChildren(v.childRight)
  442. end
  443. end
  444.  
  445. # Интерактивность
  446. function interactivity(scene, index)
  447. v = vertecesCurrent[index]
  448.  
  449. # Развертка
  450. if v.childLeft == 0 && v.childRight == 0
  451. v.childLeft = verteces[index].childLeft
  452. if v.childLeft != 0
  453. setNeedChangedOnChildren(v.childLeft)
  454. end
  455. v.childRight = verteces[index].childRight
  456. if v.childRight != 0
  457. setNeedChangedOnChildren(v.childRight)
  458. end
  459. v.textShort = verteces[index].textShort
  460. else # Свертка
  461. # Обозначаем needChanged = 1 у всех детей, для того, чтобы пересчитать координаты
  462. if v.childLeft != 0
  463. setNeedChangedOnChildren(v.childLeft)
  464. end
  465. if v.childRight != 0
  466. setNeedChangedOnChildren(v.childRight)
  467. end
  468.  
  469. v.childLeft = 0
  470. v.childRight = 0
  471. v.textShort = v.textFull
  472. end
  473.  
  474. recalcVertecesCurrent()
  475. drawGraph(scene)
  476. end
  477.  
  478. # Очищает сцену
  479. function clearScene(scene)
  480. arr = Point{2,Float32}[]
  481. xLeft = 0
  482. xRight = 500
  483. yTop = 500
  484. yBot = 0
  485. mas = []
  486. push!(arr, Point2f0(xLeft, yBot))
  487. push!(arr, Point2f0(xLeft, yTop))
  488. push!(arr, Point2f0(xRight, yTop))
  489. push!(arr, Point2f0(xRight, yBot))
  490. push!(arr, Point2f0(xLeft, yBot))
  491. poly!(scene, arr, color = :white, strokewidth = 10000, strokecolor = :white)
  492. end
  493.  
  494. # Рисует круг в точке (x, y) с текстом "text" внутри
  495. function drawCircleWithText(scene, x, y, text)
  496. radius = convert(Float32, RADIUS)
  497.  
  498. points = decompose(Point2f0, Circle(Point2f0(x, y), radius))
  499. poly!(scene, points, color = :white, strokewidth = 2, strokecolor = :black)
  500.  
  501. text!(scene, text, textsize = 20, position = (x, y), align = (:center, :center))
  502. end
  503.  
  504. # Рисует линию из точки (x1, y1) в точку (x2, y2)
  505. function drawLine(scene, x1, y1, x2, y2)
  506. linesegments!(scene, [Point(x1,y1)=> Point(x2,y2)] )
  507. end
  508.  
  509. # Рисует все вершины
  510. function drawCircles(scene, index)
  511. v = vertecesCurrent[index]
  512. drawCircleWithText(scene, v.x, v.y, v.textShort)
  513.  
  514. if v.childLeft != 0
  515. drawCircles(scene, v.childLeft)
  516. end
  517.  
  518. if v.childRight != 0
  519. drawCircles(scene, v.childRight)
  520. end
  521. end
  522.  
  523. # Переводит градусы в радианы
  524. function degreeToRad(degree)
  525. return degree * pi / 180
  526. end
  527.  
  528. # Рисует ребра графа от заданной вершины, а так же все ребра "детей" этой вершины
  529. function drawEdges(scene, index)
  530. # Угол, на который смещаются ребра относительно оси OX
  531. offsetAngle = 75
  532.  
  533. v = vertecesCurrent[index]
  534. x = v.x
  535. y = v.y
  536.  
  537. if v.childLeft != 0
  538. vLeft = vertecesCurrent[v.childLeft]
  539.  
  540. xLeft1 = x - RADIUS * cos(degreeToRad(offsetAngle))
  541. yLeft1 = y - RADIUS * sin(degreeToRad(offsetAngle))
  542.  
  543. xLeft2 = vLeft.x
  544. yLeft2 = vLeft.y + RADIUS
  545.  
  546. drawLine(scene, xLeft1, yLeft1, xLeft2, yLeft2)
  547. drawEdges(scene, v.childLeft)
  548. end
  549.  
  550. if v.childRight != 0
  551. if v.childLeft != 0
  552. vRight = vertecesCurrent[v.childRight]
  553.  
  554. xRight1 = x + RADIUS * cos(degreeToRad(offsetAngle))
  555. yRight1 = y - RADIUS * sin(degreeToRad(offsetAngle))
  556.  
  557. xRight2 = vRight.x
  558. yRight2 = vRight.y + RADIUS
  559.  
  560. drawLine(scene, xRight1, yRight1, xRight2, yRight2)
  561. drawEdges(scene, v.childRight)
  562. else
  563. vRight = vertecesCurrent[v.childRight]
  564.  
  565. xRight1 = x
  566. yRight1 = y - RADIUS
  567.  
  568. xRight2 = vRight.x
  569. yRight2 = vRight.y + RADIUS
  570.  
  571. drawLine(scene, xRight1, yRight1, xRight2, yRight2)
  572. drawEdges(scene, v.childRight)
  573. end
  574.  
  575.  
  576. end
  577. end
  578.  
  579. # Рисует граф
  580. function drawGraph(scene)
  581. clearScene(scene)
  582. drawCircles(scene, length(vertecesCurrent))
  583. drawEdges(scene, length(vertecesCurrent))
  584. end
  585.  
  586. calculateVerteces(inputStr)
  587.  
  588. calculateVertecesLevelsAndBordersX(length(verteces), 1, 0, SHIRINA)
  589.  
  590. calculatePosVerteces()
  591. printVerteces()
  592.  
  593. initVertecesCurrent()
  594. printVertecesCurrent()
  595.  
  596. scene = Scene(resolution = (SHIRINA, VISOTA))
  597.  
  598. # Добавляем события на кнопки мыши
  599. on(scene.events.mousebuttons) do buttons
  600. if ispressed(scene, Mouse.left)
  601. pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
  602.  
  603. numberVertex = checkPointInVertecesCurrent(pos[1], pos[2])
  604. if numberVertex != -1
  605. interactivity(scene, numberVertex)
  606. end
  607. end
  608. return
  609. end
  610.  
  611. drawGraph(scene)
  612. # Без этого не рисуется ????????????????????????
  613. clicks = Node(Point2f0[(0,0)])
  614. scatter!(scene, clicks, color = :red, marker = '+', markersize = 0)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement