{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE CPP #-}
module Text.AsciiDiagram.DiagramCleaner
( isShapePossible
) where
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid( mempty )
import Control.Applicative( Applicative, (<*>), (<$>) )
#endif
import Control.Applicative( liftA2 )
import Data.List( tails )
import Text.AsciiDiagram.Geometry
import Linear( V2( V2 )
, (^-^)
)
compareDirections :: Applicative f
=> (Int -> Int -> Bool) -> f Int -> f Int -> f Bool
compareDirections f = liftA2 diffSign
where
diffSign 0 0 = True
diffSign aa bb = f aa bb
checkRoundedCorners :: (Int -> Int -> Bool)
-> Segment -> Point -> Point -> Segment
-> Bool
checkRoundedCorners f s1 ap1 ap2 s2 = okX && okY
where
V2 dirX dirY = ap2 ^-^ ap1
fromS1 = _segEnd s1 ^-^ ap1
fromS2 = _segStart s2 ^-^ ap2
signDirs = signum <$> V2 dirY dirX
V2 okX okY = (&&)
<$> (compareDirections f signDirs (signum <$> fromS1))
<*> (compareDirections f signDirs (signum <$> fromS2))
checkClosedShape :: Shape -> Bool
checkClosedShape shape = all checkClosed elements where
elements =
(++ shapeElements shape) <$> tails (shapeElements shape)
checkClosed :: [ShapeElement] -> Bool
checkClosed
( ShapeSegment s1
: ShapeAnchor ap1 AnchorFirstDiag
: ShapeAnchor ap2 AnchorSecondDiag
: ShapeSegment s2
: _) = checkRoundedCorners (==) s1 ap1 ap2 s2
checkClosed
( ShapeSegment s1
: ShapeAnchor ap1 AnchorSecondDiag
: ShapeAnchor ap2 AnchorFirstDiag
: ShapeSegment s2
: _) = checkRoundedCorners (/=) s1 ap1 ap2 s2
checkClosed
( ShapeAnchor _ AnchorFirstDiag
: ShapeAnchor _ AnchorSecondDiag
: ShapeAnchor _ AnchorFirstDiag
: ShapeAnchor _ AnchorSecondDiag
: _) = False
checkClosed
( ShapeAnchor _ AnchorSecondDiag
: ShapeAnchor _ AnchorFirstDiag
: ShapeAnchor _ AnchorSecondDiag
: ShapeAnchor _ AnchorFirstDiag
: _) = False
checkClosed _ = True
isBullet :: ShapeElement -> Bool
isBullet (ShapeAnchor _ AnchorBullet) = True
isBullet _ = False
checkOpened :: [ShapeElement] -> Bool
checkOpened
[ ShapeAnchor _ AnchorFirstDiag
, ShapeAnchor _ AnchorSecondDiag] = False
checkOpened [ ShapeAnchor _ AnchorSecondDiag
, ShapeAnchor _ AnchorFirstDiag] = False
checkOpened (all isBullet -> True) = False
checkOpened
( ShapeAnchor ap1 AnchorFirstDiag
: ShapeAnchor ap2 AnchorSecondDiag
: ShapeSegment s2
: _) = checkRoundedCorners (==) s1 ap1 ap2 s2
where s1 = mempty { _segEnd = ap1 }
checkOpened
( ShapeAnchor ap1 AnchorSecondDiag
: ShapeAnchor ap2 AnchorFirstDiag
: ShapeSegment s2
: _) = checkRoundedCorners (/=) s1 ap1 ap2 s2
where s1 = mempty { _segEnd = ap1 }
checkOpened _ = True
checkOpenedShape :: Shape -> Bool
checkOpenedShape = checkOpened . shapeElements
isShapePossible :: Shape -> Bool
isShapePossible shape
| shapeIsClosed shape = checkClosedShape shape
| otherwise = checkOpenedShape shape