Flip diagrams when that results in shorter line distances.

This commit is contained in:
Robbie Gleichman 2016-01-19 03:08:53 -08:00
parent 97c84d27e5
commit 0985291c80
2 changed files with 42 additions and 21 deletions

View File

@ -18,7 +18,12 @@ import Icons
import Rendering
-- todo: Find out how to hide unqualified names such that recursive drawings are connected correctly
-- todo: Flip and rotate the icons after placement to minimize line distances to ports.
-- todo: Rotate based on difference from ideal tangent angle, not line distance.
-- todo: layout and rotate considering external connections.
-- todo: add port to bottom of guard.
-- todo: give GraphViz square or circular icons such that rotation can not cause icons to inersect.
-- todo: use constants for icon name strings in Main
-- todo: figure out local vs. global icon positions
applyDia = apply0Dia
-- --apply0A = "A" .>> applyDia
@ -127,7 +132,8 @@ factIcons = toNames
("recurAp", Apply0Icon),
("*Ap1", Apply0Icon),
("*Ap2", Apply0Icon),
("arg", BranchIcon)
("arg", BranchIcon),
("res", ResultIcon)
]
factEdges = [
@ -138,10 +144,12 @@ factEdges = [
iconToPort "one" "g0" 2,
portToPort "*Ap2" 2 "g0" 4,
portToPort "*Ap1" 2 "*Ap2" 0,
portToPort "recurAp" 2 "*Ap1" 3,
iconToPort "arg" "eq0Ap" 3,
portToPort "recurAp" 2 "*Ap1" 1,
iconToPort "arg" "eq0Ap" 1,
iconToPort "arg" "-1Ap" 1,
iconToPort "arg" "*Ap2" 1
iconToPort "arg" "*Ap2" 1,
portToPort "-1Ap" 2 "recurAp" 1,
iconToPort "res" "g0" 0
]
factDrawing = Drawing factIcons factEdges []

View File

@ -82,7 +82,8 @@ totalLenghtOfLines angle myLocation edges = sum $ map edgeDist edges
where
--edgeDist :: (P2 a, P2 a) -> Double
edgeDist (relativePortLocation, iconLocation) =
(norm $ absPortVec ^-^ iconLocationVec)
-- The squaring here is arbitrary. Distance should be replaced with angle diff.
(norm $ absPortVec ^-^ iconLocationVec) ** 2
where
-- todo: is there a better way to convert from Points to vectors?
relPortVec = r2 $ unp2 relativePortLocation
@ -90,12 +91,17 @@ totalLenghtOfLines angle myLocation edges = sum $ map edgeDist edges
myLocVec = r2 $ unp2 myLocation
absPortVec = myLocVec ^+^ (rotateBy angle relPortVec)
angleWithMinDist :: P2 Double -> [(P2 Double, P2 Double)] -> Double
-- | returns (angle, total distance)
angleWithMinDist :: P2 Double -> [(P2 Double, P2 Double)] -> (Double, Double)
angleWithMinDist myLocation edges =
fst $ minimumBy (compare `on` snd) $ map totalLength [0,(1/40)..1]
minimumBy (compare `on` snd) $ map totalLength [0,(1/40)..1]
where
totalLength angle = (angle, totalLenghtOfLines angle myLocation edges)
-- constant
scaleFactor = 0.025
getFromMapAndScale posMap name = scaleFactor *^ (posMap ! name)
-- | rotateNodes rotates the nodes such that the distance of its connecting lines
-- are minimized.
@ -103,29 +109,36 @@ angleWithMinDist myLocation edges =
-- todo: confirm precondition (or use a newtype)
rotateNodes positionMap nameDiagramMap edges = map rotateDiagram nameDiagramMap
where
rotateDiagram (name, dia) = (name, rotateBy minAngle dia)
rotateDiagram (name, dia) = (name, diaToUse)
where
flippedDia = reflectX dia
(unflippedAngle, unflippedDist) = minAngleForDia dia
(flippedAngle, flippedDist) = minAngleForDia flippedDia
diaToUse = if flippedDist < unflippedDist
then rotateBy flippedAngle flippedDia
else rotateBy unflippedAngle dia
minAngleForDia :: Diagram B -> (Double, Double)
minAngleForDia dia = minAngle where
--ports = Debug.Trace.trace ((show $ names dia) ++ "\n") $ names dia
ports = names dia
namesOfPortsWithLines = connectedPorts edges name
portEdges = map makePortEdge $ filter iconInMap namesOfPortsWithLines
iconInMap (_, otherIconName, _) = Map.member otherIconName positionMap
makePortEdge (portInt, otherIconName, _) = (getPortPoint portInt, positionMap ! otherIconName)
getPortPoint :: Int -> P2 Double
getPortPoint x = head $ fromMaybe
(error "port not found")
(lookup (name .> x) ports)
minAngle = angleWithMinDist (positionMap ! name) portEdges
ports = names dia
namesOfPortsWithLines = connectedPorts edges name
portEdges = map makePortEdge $ filter iconInMap namesOfPortsWithLines
iconInMap (_, otherIconName, _) = Map.member otherIconName positionMap
makePortEdge (portInt, otherIconName, _) = (getPortPoint portInt, getFromMapAndScale positionMap otherIconName)
getPortPoint :: Int -> P2 Double
getPortPoint x = head $ fromMaybe
(error "port not found")
(lookup (name .> x) ports)
minAngle = angleWithMinDist (getFromMapAndScale positionMap name) portEdges
placeNodes layoutResult nameDiagramMap edges = mconcat placedNodes
where
(positionMap, _) = getGraph layoutResult
rotatedNameDiagramMap = rotateNodes positionMap nameDiagramMap edges
placedNodes = map placeNode rotatedNameDiagramMap
--placedNodes = map placeNode nameDiagramMap
-- todo: Not sure if the diagrams should already be centered at this point.
placeNode (name, diagram) = place (diagram # centerXY) (scaleFactor *^ (positionMap ! name))
-- constant
scaleFactor = 0.025
doGraphLayout graph nameDiagramMap connectNodes edges = do
layoutResult <- layoutGraph' layoutParams Neato graph