All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mdr.ascii.diagram.parser.UnicodeEdgeParser.scala Maven / Gradle / Ivy

The newest version!
package com.github.mdr.ascii.diagram.parser

import com.github.mdr.ascii._
import com.github.mdr.ascii.common.Direction._
import com.github.mdr.ascii.common._
import com.github.mdr.ascii.diagram._
import scala.annotation.tailrec
import scala.PartialFunction.cond

/**
 * Follow an edge drawn using Unicode box-drawing characters.
 */
trait UnicodeEdgeParser { self: DiagramParser ⇒

  /**
   * @param points -- non-empty list of points in the edge so far, in reverse order
   * @param direction -- direction taken to reach the tip of the edge
   * @return Some(edge) if the edge is well-formed and terminates at a box, otherwise None.
   */
  @tailrec
  protected final def followUnicodeEdge(points: List[Point], direction: Direction): Option[EdgeImpl] = {
    val currentPoint = points.head
    if (!inDiagram(currentPoint))
      return None
    if (isBoxEdge(currentPoint))
      return Some(new EdgeImpl(points.reverse))
    val c = charAt(currentPoint)
    if (isStraightAhead(c, direction) || isCrossing(c) || isAheadArrow(c, direction))
      followUnicodeEdge(currentPoint.go(direction) :: points, direction)
    else if (isLeftTurn(c, direction) || isLeftArrow(c, direction))
      followUnicodeEdge(currentPoint.go(direction.turnLeft) :: points, direction.turnLeft)
    else if (isRightTurn(c, direction) || isRightArrow(c, direction))
      followUnicodeEdge(currentPoint.go(direction.turnRight) :: points, direction.turnRight)
    else
      None
  }

  protected def isEdgeStart(c: Char, direction: Direction): Boolean = cond(c, direction) {
    case ('╤' | '┬', Down)         ⇒ true
    case ('╪' | '┼', Up | Down)    ⇒ true
    case ('╧' | '┴', Up)           ⇒ true
    case ('╟' | '├', Right)        ⇒ true
    case ('╫' | '┼', Right | Left) ⇒ true
    case ('╢' | '┤', Left)         ⇒ true
  }

  private def isStraightAhead(c: Char, direction: Direction): Boolean = cond(c, direction) {
    case ('─', Right | Left) ⇒ true
    case ('│', Up | Down)    ⇒ true
  }

  private def isLeftArrow(c: Char, direction: Direction) = isAheadArrow(c, direction.turnLeft)

  private def isRightArrow(c: Char, direction: Direction) = isAheadArrow(c, direction.turnRight)

  private def isAheadArrow(c: Char, direction: Direction): Boolean = cond(c, direction) {
    case ('^', Up)         ⇒ true
    case ('v' | 'V', Down) ⇒ true
    case ('<', Left)       ⇒ true
    case ('>', Right)      ⇒ true
  }

  private def isRightTurn(c: Char, direction: Direction): Boolean = cond(c, direction) {
    case ('╮' | '┐', Right) ⇒ true
    case ('╯' | '┘', Down)  ⇒ true
    case ('╭' | '┌', Up)    ⇒ true
    case ('╰' | '└', Left)  ⇒ true
  }

  private def isLeftTurn(c: Char, direction: Direction): Boolean = isRightTurn(c, direction.turnRight)

  private def isCrossing(c: Char): Boolean = c == '┼'

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy