diff --git a/app/Main.hs b/app/Main.hs index 85bc6f5..fee6ecf 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -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 [] diff --git a/app/Rendering.hs b/app/Rendering.hs index e4c4222..bd1d0e7 100644 --- a/app/Rendering.hs +++ b/app/Rendering.hs @@ -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