cga/Graphics/Diagram/AlgoDiags.hs
hasufell 2ccb52eb62
VEC: Fix the inRange function
It now takes a PROPER square, as in ((xmin, ymin), (xmax, ymax))
instead of ((xmin, xmax), (ymin, ymax)) and also works
with negative values.

Because the meaning of the arguments has changed, we also
had to fix all uses of it.
2014-12-17 03:35:33 +01:00

246 lines
7.7 KiB
Haskell

{-# OPTIONS_HADDOCK ignore-exports #-}
module Graphics.Diagram.AlgoDiags where
import Algebra.Vector(PT,Square,dimToSquare)
import Algorithms.GrahamScan
import Algorithms.QuadTree
import Algorithms.KDTree
import Algorithms.PolygonIntersection
import Data.Maybe
import Data.Monoid
import Data.Tree
import Diagrams.Backend.Cairo
import Diagrams.Prelude hiding ((<>))
import Diagrams.TwoD.Layout.Tree
import Graphics.Diagram.Core
import Parser.PathParser
import Safe
-- |Draw the lines of the polygon.
polyLines :: Diag
polyLines = Diag f
where
f _ = foldl (\x y -> x <> strokePoly y) mempty
where
strokePoly x' = fromVertices $ x' ++ (maybeToList . headMay $ x')
-- |Show the intersection points of two polygons as red dots.
polyIntersection :: Diag
polyIntersection = Diag f
where
f p [x, y] = drawP vtpi (dotSize p) # fc red # lc red
where
vtpi = intersectionPoints . sortLexPolys $ (sortLexPoly x, sortLexPoly y)
f _ _ = mempty
-- |Show the coordinate text of the intersection points of two polygons.
polyIntersectionText :: Diag
polyIntersectionText = Diag f
where
f p [x, y]
| showCoordText p = position . zip vtpi $ (pointToTextCoord # fc red <$> vtpi)
# translate (r2 (0, 10))
| otherwise = mempty
where
vtpi = intersectionPoints
. sortLexPolys
$ (sortLexPoly x,
sortLexPoly y)
f _ _ = mempty
-- |Create a diagram which shows the points of the convex hull.
convexHP :: Diag
convexHP = Diag f
where
f p vts = drawP (grahamCH (concat vts)) (dotSize p) # fc red # lc red
-- |Show coordinates as text above the convex hull points.
convexHPText :: Diag
convexHPText = Diag f
where
f p vts
| showCoordText p =
(position . zip vtch $ (pointToTextCoord <$> vtch))
# translate (r2 (0, 10))
| otherwise = mempty
where
vtch = grahamCH (concat vts)
-- |Create a diagram which shows the lines along the convex hull
-- points.
convexHLs :: Diag
convexHLs = Diag f
where
f _ vts =
(fromVertices
. flip (++) (maybeToList . headMay . grahamCH $ vt)
. grahamCH
$ vt
) # lc red
where
vt = mconcat vts
-- |Create list of diagrama which describe the lines along points of a half
-- convex hull, for each iteration of the algorithm. Which half is chosen
-- depends on the input.
convexHStepsLs :: Diag
convexHStepsLs = GifDiag f
where
f _ col g vt = fmap (\x -> fromVertices x # lc col) (g vt)
-- |Create a diagram that shows all squares of the RangeSearch algorithm
-- from the quad tree.
squares :: Diag
squares = Diag f
where
f p vts =
mconcat
$ (uncurry rectByDiagonal # lw ultraThin)
<$>
(quadTreeSquares (diagDimSquare p)
. quadTree (mconcat vts)
$ diagDimSquare p)
-- |Draw the squares of the kd-tree.
kdSquares :: Diag
kdSquares = Diag f
where
f p vts =
mconcat
. fmap (uncurry (~~))
$ kdLines (kdTree (mconcat vts) Horizontal)
(diagDimSquare p)
where
-- Gets all lines that make up the kdSquares. Every line is
-- described by two points, start and end respectively.
kdLines :: KDTree PT -> Square -> [(PT, PT)]
kdLines (KTNode ln pt Horizontal rn) ((xmin, ymin), (xmax, ymax)) =
(\(x, _) -> [(p2 (x, ymin), p2 (x, ymax))])
(unp2 pt)
++ kdLines ln ((xmin, ymin), (x', ymax))
++ kdLines rn ((x', ymin), (xmax, ymax))
where
(x', _) = unp2 pt
kdLines (KTNode ln pt Vertical rn) ((xmin, ymin), (xmax, ymax)) =
(\(_, y) -> [(p2 (xmin, y), p2 (xmax, y))])
(unp2 pt)
++ kdLines ln ((xmin, ymin), (xmax, y'))
++ kdLines rn ((xmin, y'), (xmax, ymax))
where
(_, y') = unp2 pt
kdLines _ _ = []
-- |Draw the range rectangle and highlight the points inside that range.
kdRange :: Diag
kdRange = Diag f
where
f p vts =
(uncurry rectByDiagonal # lc red) (rangeSquare p)
<> drawP ptsInRange (dotSize p) # fc red # lc red
where
ptsInRange = fst
. rangeSearch (kdTree (mconcat vts) Vertical)
$ rangeSquare p
-- |The kd-tree visualized as binary tree.
kdTreeDiag :: Diag
kdTreeDiag = Diag f
where
f p vts =
-- HACK: in order to give specific nodes a specific color
renderTree (\n -> case n of
'*':'*':_ -> (text n # fontSizeL 5.0)
<> rect 50.0 20.0 # fc green
'*':_ -> (text n # fontSizeL 5.0)
<> rect 50.0 20.0 # fc red
_ -> (text n # fontSizeL 5.0)
<> rect 50.0 20.0 # fc white)
(~~)
(symmLayout' (with & slHSep .~ 60 & slVSep .~ 40) roseTree)
# scale 2 # alignT # bg white
where
roseTree = snd
. rangeSearch (kdTree (mconcat vts) Vertical)
$ rangeSquare p
-- |Get the quad tree corresponding to the given points and diagram properties.
qt :: [PT] -> DiagProp -> QuadTree PT
qt vt p = quadTree vt (diagDimSquare p)
-- |Create a diagram that shows a single square of the RangeSearch algorithm
-- from the quad tree in red, according to the given path in quadPath.
quadPathSquare :: Diag
quadPathSquare = Diag f
where
f p vts =
(uncurry rectByDiagonal # lw thin # lc red)
(getSquare (stringToQuads (quadPath p)) (qt (mconcat vts) p, []))
where
getSquare :: [Either Quad Orient] -> QTZipper PT -> Square
getSquare [] z = getSquareByZipper (diagDimSquare p) z
getSquare (q:qs) z = case q of
Right x -> getSquare qs (fromMaybe z (findNeighbor x z))
Left x -> getSquare qs (fromMaybe z (goQuad x z))
-- |Create a list of diagrams that show the walk along the given path
-- through the quad tree.
gifQuadPath :: Diag
gifQuadPath = GifDiag f
where
f p col _ vt =
(uncurry rectByDiagonal # lw thick # lc col)
<$> getSquares (stringToQuads (quadPath p)) (qt vt p, [])
where
getSquares :: [Either Quad Orient] -> QTZipper PT -> [Square]
getSquares [] z = [getSquareByZipper (diagDimSquare p) z]
getSquares (q:qs) z = case q of
Right x -> getSquareByZipper (diagDimSquare p) z :
getSquares qs (fromMaybe z (findNeighbor x z))
Left x -> getSquareByZipper (diagDimSquare p) z :
getSquares qs (fromMaybe z (goQuad x z))
-- |A diagram that shows the full Quad Tree with nodes.
treePretty :: Diag
treePretty = Diag f
where
f p vts =
prettyRoseTree (quadTreeToRoseTree
. flip getCurQT (qt (mconcat vts) p, [])
. stringToQuads
. quadPath
$ p)
where
getCurQT :: [Either Quad Orient] -> QTZipper PT -> QTZipper PT
getCurQT [] z = z
getCurQT (q:qs) z = case q of
Right x -> getCurQT qs (fromMaybe z (findNeighbor x z))
Left x -> getCurQT qs (fromMaybe z (goQuad x z))
prettyRoseTree :: Tree String -> Diagram Cairo R2
prettyRoseTree tree =
-- HACK: in order to give specific nodes a specific color
renderTree (\n -> case head n of
'*' -> (text n # fontSizeL 5.0)
<> rect 50.0 20.0 # fc red
_ -> (text n # fontSizeL 5.0)
<> rect 50.0 20.0 # fc white)
(~~)
(symmLayout' (with & slHSep .~ 60 & slVSep .~ 40) tree)
# scale 2 # alignT # bg white